Parallel copy

Started by Amit Kapilaalmost 6 years ago236 messages
#1Amit Kapila
amit.kapila16@gmail.com

This work is to parallelize the copy command and in particular "Copy
<table_name> from 'filename' Where <condition>;" command.

Before going into how and what portion of 'copy command' processing we
can parallelize, let us see in brief what are the top-level operations
we perform while copying from the file into a table. We read the file
in 64KB chunks, then find the line endings and process that data line
by line, where each line corresponds to one tuple. We first form the
tuple (in form of value/null array) from that line, check if it
qualifies the where condition and if it qualifies, then perform
constraint check and few other checks and then finally store it in
local tuple array. Once we reach 1000 tuples or consumed 64KB
(whichever occurred first), we insert them together via
table_multi_insert API and then for each tuple insert into the
index(es) and execute after row triggers.

So if we see here we do a lot of work after reading each 64K chunk.
We can read the next chunk only after all the tuples are processed in
the previous chunk we read. This brings us an opportunity to
parallelize each 64K chunk processing. I think we can do this in more
than one way.

The first idea is that we allocate each chunk to a worker and once the
worker has finished processing the current chunk, it can start with
the next unprocessed chunk. Here, we need to see how to handle the
partial tuples at the end or beginning of each chunk. We can read the
chunks in dsa/dsm instead of in local buffer for processing.
Alternatively, if we think that accessing shared memory can be costly
we can read the entire chunk in local memory, but copy the partial
tuple at the beginning of a chunk (if any) to a dsa. We mainly need
partial tuple in the shared memory area. The worker which has found
the initial part of the partial tuple will be responsible to process
the entire tuple. Now, to detect whether there is a partial tuple at
the beginning of a chunk, we always start reading one byte, prior to
the start of the current chunk and if that byte is not a terminating
line byte, we know that it is a partial tuple. Now, while processing
the chunk, we will ignore this first line and start after the first
terminating line.

To connect the partial tuple in two consecutive chunks, we need to
have another data structure (for the ease of reference in this email,
I call it CTM (chunk-tuple-map)) in shared memory where we store some
per-chunk information like the chunk-number, dsa location of that
chunk and a variable which indicates whether we can free/reuse the
current entry. Whenever we encounter the partial tuple at the
beginning of a chunk we note down its chunk number, and dsa location
in CTM. Next, whenever we encounter any partial tuple at the end of
the chunk, we search CTM for next chunk-number and read from
corresponding dsa location till we encounter terminating line byte.
Once we have read and processed this partial tuple, we can mark the
entry as available for reuse. There are some loose ends here like how
many entries shall we allocate in this data structure. It depends on
whether we want to allow the worker to start reading the next chunk
before the partial tuple of the previous chunk is processed. To keep
it simple, we can allow the worker to process the next chunk only when
the partial tuple in the previous chunk is processed. This will allow
us to keep the entries equal to a number of workers in CTM. I think
we can easily improve this if we want but I don't think it will matter
too much as in most cases by the time we processed the tuples in that
chunk, the partial tuple would have been consumed by the other worker.

Another approach that came up during an offlist discussion with Robert
is that we have one dedicated worker for reading the chunks from file
and it copies the complete tuples of one chunk in the shared memory
and once that is done, a handover that chunks to another worker which
can process tuples in that area. We can imagine that the reader
worker is responsible to form some sort of work queue that can be
processed by the other workers. In this idea, we won't be able to get
the benefit of initial tokenization (forming tuple boundaries) via
parallel workers and might need some additional memory processing as
after reader worker has handed the initial shared memory segment, we
need to somehow identify tuple boundaries and then process them.

Another thing we need to figure out is the how many workers to use for
the copy command. I think we can use it based on the file size which
needs some experiments or may be based on user input.

I think we have two related problems to solve for this (a) relation
extension lock (required for extending the relation) which won't
conflict among workers due to group locking, we are working on a
solution for this in another thread [1]/messages/by-id/CAD21AoCmT3cFQUN4aVvzy5chw7DuzXrJCbrjTU05B+Ss=Gn1LA@mail.gmail.com, (b) Use of Page locks in Gin
indexes, we can probably disallow parallelism if the table has Gin
index which is not a great thing but not bad either.

To be clear, this work is for PG14.

Thoughts?

[1]: /messages/by-id/CAD21AoCmT3cFQUN4aVvzy5chw7DuzXrJCbrjTU05B+Ss=Gn1LA@mail.gmail.com

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#2Thomas Munro
thomas.munro@gmail.com
In reply to: Amit Kapila (#1)
Re: Parallel copy

On Fri, Feb 14, 2020 at 9:12 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

This work is to parallelize the copy command and in particular "Copy
<table_name> from 'filename' Where <condition>;" command.

Nice project, and a great stepping stone towards parallel DML.

The first idea is that we allocate each chunk to a worker and once the
worker has finished processing the current chunk, it can start with
the next unprocessed chunk. Here, we need to see how to handle the
partial tuples at the end or beginning of each chunk. We can read the
chunks in dsa/dsm instead of in local buffer for processing.
Alternatively, if we think that accessing shared memory can be costly
we can read the entire chunk in local memory, but copy the partial
tuple at the beginning of a chunk (if any) to a dsa. We mainly need
partial tuple in the shared memory area. The worker which has found
the initial part of the partial tuple will be responsible to process
the entire tuple. Now, to detect whether there is a partial tuple at
the beginning of a chunk, we always start reading one byte, prior to
the start of the current chunk and if that byte is not a terminating
line byte, we know that it is a partial tuple. Now, while processing
the chunk, we will ignore this first line and start after the first
terminating line.

That's quiet similar to the approach I took with a parallel file_fdw
patch[1]/messages/by-id/CA+hUKGKZu8fpZo0W=POmQEN46kXhLedzqqAnt5iJZy7tD0x6sw@mail.gmail.com, which mostly consisted of parallelising the reading part of
copy.c, except that...

To connect the partial tuple in two consecutive chunks, we need to
have another data structure (for the ease of reference in this email,
I call it CTM (chunk-tuple-map)) in shared memory where we store some
per-chunk information like the chunk-number, dsa location of that
chunk and a variable which indicates whether we can free/reuse the
current entry. Whenever we encounter the partial tuple at the
beginning of a chunk we note down its chunk number, and dsa location
in CTM. Next, whenever we encounter any partial tuple at the end of
the chunk, we search CTM for next chunk-number and read from
corresponding dsa location till we encounter terminating line byte.
Once we have read and processed this partial tuple, we can mark the
entry as available for reuse. There are some loose ends here like how
many entries shall we allocate in this data structure. It depends on
whether we want to allow the worker to start reading the next chunk
before the partial tuple of the previous chunk is processed. To keep
it simple, we can allow the worker to process the next chunk only when
the partial tuple in the previous chunk is processed. This will allow
us to keep the entries equal to a number of workers in CTM. I think
we can easily improve this if we want but I don't think it will matter
too much as in most cases by the time we processed the tuples in that
chunk, the partial tuple would have been consumed by the other worker.

... I didn't use a shm 'partial tuple' exchanging mechanism, I just
had each worker follow the final tuple in its chunk into the next
chunk, and have each worker ignore the first tuple in chunk after
chunk 0 because it knows someone else is looking after that. That
means that there was some double reading going on near the boundaries,
and considering how much I've been complaining about bogus extra
system calls on this mailing list lately, yeah, your idea of doing a
bit more coordination is a better idea. If you go this way, you might
at least find the copy.c part of the patch I wrote useful as stand-in
scaffolding code in the meantime while you prototype the parallel
writing side, if you don't already have something better for this?

Another approach that came up during an offlist discussion with Robert
is that we have one dedicated worker for reading the chunks from file
and it copies the complete tuples of one chunk in the shared memory
and once that is done, a handover that chunks to another worker which
can process tuples in that area. We can imagine that the reader
worker is responsible to form some sort of work queue that can be
processed by the other workers. In this idea, we won't be able to get
the benefit of initial tokenization (forming tuple boundaries) via
parallel workers and might need some additional memory processing as
after reader worker has handed the initial shared memory segment, we
need to somehow identify tuple boundaries and then process them.

Yeah, I have also wondered about something like this in a slightly
different context. For parallel query in general, I wondered if there
should be a Parallel Scatter node, that can be put on top of any
parallel-safe plan, and it runs it in a worker process that just
pushes tuples into a single-producer multi-consumer shm queue, and
then other workers read from that whenever they need a tuple. Hmm,
but for COPY, I suppose you'd want to push the raw lines with minimal
examination, not tuples, into a shm queue, so I guess that's a bit
different.

Another thing we need to figure out is the how many workers to use for
the copy command. I think we can use it based on the file size which
needs some experiments or may be based on user input.

It seems like we don't even really have a general model for that sort
of thing in the rest of the system yet, and I guess some kind of
fairly dumb explicit system would make sense in the early days...

Thoughts?

This is cool.

[1]: /messages/by-id/CA+hUKGKZu8fpZo0W=POmQEN46kXhLedzqqAnt5iJZy7tD0x6sw@mail.gmail.com

#3Amit Kapila
amit.kapila16@gmail.com
In reply to: Thomas Munro (#2)
Re: Parallel copy

On Fri, Feb 14, 2020 at 3:36 PM Thomas Munro <thomas.munro@gmail.com> wrote:

On Fri, Feb 14, 2020 at 9:12 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

This work is to parallelize the copy command and in particular "Copy
<table_name> from 'filename' Where <condition>;" command.

Nice project, and a great stepping stone towards parallel DML.

Thanks.

The first idea is that we allocate each chunk to a worker and once the
worker has finished processing the current chunk, it can start with
the next unprocessed chunk. Here, we need to see how to handle the
partial tuples at the end or beginning of each chunk. We can read the
chunks in dsa/dsm instead of in local buffer for processing.
Alternatively, if we think that accessing shared memory can be costly
we can read the entire chunk in local memory, but copy the partial
tuple at the beginning of a chunk (if any) to a dsa. We mainly need
partial tuple in the shared memory area. The worker which has found
the initial part of the partial tuple will be responsible to process
the entire tuple. Now, to detect whether there is a partial tuple at
the beginning of a chunk, we always start reading one byte, prior to
the start of the current chunk and if that byte is not a terminating
line byte, we know that it is a partial tuple. Now, while processing
the chunk, we will ignore this first line and start after the first
terminating line.

That's quiet similar to the approach I took with a parallel file_fdw
patch[1], which mostly consisted of parallelising the reading part of
copy.c, except that...

To connect the partial tuple in two consecutive chunks, we need to
have another data structure (for the ease of reference in this email,
I call it CTM (chunk-tuple-map)) in shared memory where we store some
per-chunk information like the chunk-number, dsa location of that
chunk and a variable which indicates whether we can free/reuse the
current entry. Whenever we encounter the partial tuple at the
beginning of a chunk we note down its chunk number, and dsa location
in CTM. Next, whenever we encounter any partial tuple at the end of
the chunk, we search CTM for next chunk-number and read from
corresponding dsa location till we encounter terminating line byte.
Once we have read and processed this partial tuple, we can mark the
entry as available for reuse. There are some loose ends here like how
many entries shall we allocate in this data structure. It depends on
whether we want to allow the worker to start reading the next chunk
before the partial tuple of the previous chunk is processed. To keep
it simple, we can allow the worker to process the next chunk only when
the partial tuple in the previous chunk is processed. This will allow
us to keep the entries equal to a number of workers in CTM. I think
we can easily improve this if we want but I don't think it will matter
too much as in most cases by the time we processed the tuples in that
chunk, the partial tuple would have been consumed by the other worker.

... I didn't use a shm 'partial tuple' exchanging mechanism, I just
had each worker follow the final tuple in its chunk into the next
chunk, and have each worker ignore the first tuple in chunk after
chunk 0 because it knows someone else is looking after that. That
means that there was some double reading going on near the boundaries,

Right and especially if the part in the second chunk is bigger, then
we might need to read most of the second chunk.

and considering how much I've been complaining about bogus extra
system calls on this mailing list lately, yeah, your idea of doing a
bit more coordination is a better idea. If you go this way, you might
at least find the copy.c part of the patch I wrote useful as stand-in
scaffolding code in the meantime while you prototype the parallel
writing side, if you don't already have something better for this?

No, I haven't started writing anything yet, but I have some ideas on
how to achieve this. I quickly skimmed through your patch and I think
that can be used as a starting point though if we decide to go with
accumulating the partial tuple or all the data in shm, then the things
might differ.

Another approach that came up during an offlist discussion with Robert
is that we have one dedicated worker for reading the chunks from file
and it copies the complete tuples of one chunk in the shared memory
and once that is done, a handover that chunks to another worker which
can process tuples in that area. We can imagine that the reader
worker is responsible to form some sort of work queue that can be
processed by the other workers. In this idea, we won't be able to get
the benefit of initial tokenization (forming tuple boundaries) via
parallel workers and might need some additional memory processing as
after reader worker has handed the initial shared memory segment, we
need to somehow identify tuple boundaries and then process them.

Yeah, I have also wondered about something like this in a slightly
different context. For parallel query in general, I wondered if there
should be a Parallel Scatter node, that can be put on top of any
parallel-safe plan, and it runs it in a worker process that just
pushes tuples into a single-producer multi-consumer shm queue, and
then other workers read from that whenever they need a tuple.

The idea sounds great but the past experience shows that shoving all
the tuples through queue might add a significant overhead. However, I
don't know how exactly you are planning to use it?

Hmm,
but for COPY, I suppose you'd want to push the raw lines with minimal
examination, not tuples, into a shm queue, so I guess that's a bit
different.

Yeah.

Another thing we need to figure out is the how many workers to use for
the copy command. I think we can use it based on the file size which
needs some experiments or may be based on user input.

It seems like we don't even really have a general model for that sort
of thing in the rest of the system yet, and I guess some kind of
fairly dumb explicit system would make sense in the early days...

makes sense.

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#4Alastair Turner
minion@decodable.me
In reply to: Amit Kapila (#3)
Re: Parallel copy

On Fri, 14 Feb 2020 at 11:57, Amit Kapila <amit.kapila16@gmail.com> wrote:

On Fri, Feb 14, 2020 at 3:36 PM Thomas Munro <thomas.munro@gmail.com>
wrote:

On Fri, Feb 14, 2020 at 9:12 PM Amit Kapila <amit.kapila16@gmail.com>

wrote:

...

Another approach that came up during an offlist discussion with Robert
is that we have one dedicated worker for reading the chunks from file
and it copies the complete tuples of one chunk in the shared memory
and once that is done, a handover that chunks to another worker which
can process tuples in that area. We can imagine that the reader
worker is responsible to form some sort of work queue that can be
processed by the other workers. In this idea, we won't be able to get
the benefit of initial tokenization (forming tuple boundaries) via
parallel workers and might need some additional memory processing as
after reader worker has handed the initial shared memory segment, we
need to somehow identify tuple boundaries and then process them.

Parsing rows from the raw input (the work done by CopyReadLine()) in a
single process would accommodate line returns in quoted fields. I don't
think there's a way of getting parallel workers to manage the
in-quote/out-of-quote state required. A single worker could also process a
stream without having to reread/rewind so it would be able to process input
from STDIN or PROGRAM sources, making the improvements applicable to load
operations done by third party tools and scripted \copy in psql.

...

Another thing we need to figure out is the how many workers to use for
the copy command. I think we can use it based on the file size which
needs some experiments or may be based on user input.

It seems like we don't even really have a general model for that sort
of thing in the rest of the system yet, and I guess some kind of
fairly dumb explicit system would make sense in the early days...

makes sense.

The ratio between chunking or line parsing processes and the parallel
worker pool would vary with the width of the table, complexity of the data
or file (dates, encoding conversions), complexity of constraints and
acceptable impact of the load. Being able to control it through user input
would be great.

--
Alastair

#5Amit Kapila
amit.kapila16@gmail.com
In reply to: Alastair Turner (#4)
Re: Parallel copy

On Fri, Feb 14, 2020 at 7:16 PM Alastair Turner <minion@decodable.me> wrote:

On Fri, 14 Feb 2020 at 11:57, Amit Kapila <amit.kapila16@gmail.com> wrote:

On Fri, Feb 14, 2020 at 3:36 PM Thomas Munro <thomas.munro@gmail.com> wrote:

On Fri, Feb 14, 2020 at 9:12 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

...

Another approach that came up during an offlist discussion with Robert
is that we have one dedicated worker for reading the chunks from file
and it copies the complete tuples of one chunk in the shared memory
and once that is done, a handover that chunks to another worker which
can process tuples in that area. We can imagine that the reader
worker is responsible to form some sort of work queue that can be
processed by the other workers. In this idea, we won't be able to get
the benefit of initial tokenization (forming tuple boundaries) via
parallel workers and might need some additional memory processing as
after reader worker has handed the initial shared memory segment, we
need to somehow identify tuple boundaries and then process them.

Parsing rows from the raw input (the work done by CopyReadLine()) in a single process would accommodate line returns in quoted fields. I don't think there's a way of getting parallel workers to manage the in-quote/out-of-quote state required.

AFAIU, the whole of this in-quote/out-of-quote state is manged inside
CopyReadLineText which will be done by each of the parallel workers,
something on the lines of what Thomas did in his patch [1]/messages/by-id/CA+hUKGKZu8fpZo0W=POmQEN46kXhLedzqqAnt5iJZy7tD0x6sw@mail.gmail.com.
Basically, we need to invent a mechanism to allocate chunks to
individual workers and then the whole processing will be done as we
are doing now except for special handling for partial tuples which I
have explained in my previous email. Am, I missing something here?

...

Another thing we need to figure out is the how many workers to use for
the copy command. I think we can use it based on the file size which
needs some experiments or may be based on user input.

It seems like we don't even really have a general model for that sort
of thing in the rest of the system yet, and I guess some kind of
fairly dumb explicit system would make sense in the early days...

makes sense.

The ratio between chunking or line parsing processes and the parallel worker pool would vary with the width of the table, complexity of the data or file (dates, encoding conversions), complexity of constraints and acceptable impact of the load. Being able to control it through user input would be great.

Okay, I think one simple way could be that we compute the number of
workers based on filesize (some experiments are required to determine
this) unless the user has given the input. If the user has provided
the input then we can use that with an upper limit to
max_parallel_workers.

[1]: /messages/by-id/CA+hUKGKZu8fpZo0W=POmQEN46kXhLedzqqAnt5iJZy7tD0x6sw@mail.gmail.com

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#6Alastair Turner
minion@decodable.me
In reply to: Amit Kapila (#5)
Re: Parallel copy

On Sat, 15 Feb 2020 at 04:55, Amit Kapila <amit.kapila16@gmail.com> wrote:

On Fri, Feb 14, 2020 at 7:16 PM Alastair Turner <minion@decodable.me> wrote:

...

Parsing rows from the raw input (the work done by CopyReadLine()) in a single process would accommodate line returns in quoted fields. I don't think there's a way of getting parallel workers to manage the in-quote/out-of-quote state required.

AFAIU, the whole of this in-quote/out-of-quote state is manged inside
CopyReadLineText which will be done by each of the parallel workers,
something on the lines of what Thomas did in his patch [1].
Basically, we need to invent a mechanism to allocate chunks to
individual workers and then the whole processing will be done as we
are doing now except for special handling for partial tuples which I
have explained in my previous email. Am, I missing something here?

The problem case that I see is the chunk boundary falling in the
middle of a quoted field where
- The quote opens in chunk 1
- The quote closes in chunk 2
- There is an EoL character between the start of chunk 2 and the closing quote

When the worker processing chunk 2 starts, it believes itself to be in
out-of-quote state, so only data between the start of the chunk and
the EoL is regarded as belonging to the partial line. From that point
on the parsing of the rest of the chunk goes off track.

Some of the resulting errors can be avoided by, for instance,
requiring a quote to be preceded by a delimiter or EoL. That answer
fails when fields end with EoL characters, which happens often enough
in the wild.

Recovering from an incorrect in-quote/out-of-quote state assumption at
the start of parsing a chunk just seems like a hole with no bottom. So
it looks to me like it's best done in a single process which can keep
track of that state reliably.

--
Aastair

#7Amit Kapila
amit.kapila16@gmail.com
In reply to: Alastair Turner (#6)
Re: Parallel copy

On Sat, Feb 15, 2020 at 4:08 PM Alastair Turner <minion@decodable.me> wrote:

On Sat, 15 Feb 2020 at 04:55, Amit Kapila <amit.kapila16@gmail.com> wrote:

On Fri, Feb 14, 2020 at 7:16 PM Alastair Turner <minion@decodable.me> wrote:

...

Parsing rows from the raw input (the work done by CopyReadLine()) in a single process would accommodate line returns in quoted fields. I don't think there's a way of getting parallel workers to manage the in-quote/out-of-quote state required.

AFAIU, the whole of this in-quote/out-of-quote state is manged inside
CopyReadLineText which will be done by each of the parallel workers,
something on the lines of what Thomas did in his patch [1].
Basically, we need to invent a mechanism to allocate chunks to
individual workers and then the whole processing will be done as we
are doing now except for special handling for partial tuples which I
have explained in my previous email. Am, I missing something here?

The problem case that I see is the chunk boundary falling in the
middle of a quoted field where
- The quote opens in chunk 1
- The quote closes in chunk 2
- There is an EoL character between the start of chunk 2 and the closing quote

When the worker processing chunk 2 starts, it believes itself to be in
out-of-quote state, so only data between the start of the chunk and
the EoL is regarded as belonging to the partial line. From that point
on the parsing of the rest of the chunk goes off track.

Some of the resulting errors can be avoided by, for instance,
requiring a quote to be preceded by a delimiter or EoL. That answer
fails when fields end with EoL characters, which happens often enough
in the wild.

Recovering from an incorrect in-quote/out-of-quote state assumption at
the start of parsing a chunk just seems like a hole with no bottom. So
it looks to me like it's best done in a single process which can keep
track of that state reliably.

Good point and I agree with you that having a single process would
avoid any such stuff. However, I will think some more on it and if
you/anyone else gets some idea on how to deal with this in a
multi-worker system (where we can allow each worker to read and
process the chunk) then feel free to share your thoughts.

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#8David Fetter
david@fetter.org
In reply to: Amit Kapila (#7)
Re: Parallel copy

On Sat, Feb 15, 2020 at 06:02:06PM +0530, Amit Kapila wrote:

On Sat, Feb 15, 2020 at 4:08 PM Alastair Turner <minion@decodable.me> wrote:

On Sat, 15 Feb 2020 at 04:55, Amit Kapila <amit.kapila16@gmail.com> wrote:

On Fri, Feb 14, 2020 at 7:16 PM Alastair Turner <minion@decodable.me> wrote:

...

Parsing rows from the raw input (the work done by CopyReadLine()) in a single process would accommodate line returns in quoted fields. I don't think there's a way of getting parallel workers to manage the in-quote/out-of-quote state required.

AFAIU, the whole of this in-quote/out-of-quote state is manged inside
CopyReadLineText which will be done by each of the parallel workers,
something on the lines of what Thomas did in his patch [1].
Basically, we need to invent a mechanism to allocate chunks to
individual workers and then the whole processing will be done as we
are doing now except for special handling for partial tuples which I
have explained in my previous email. Am, I missing something here?

The problem case that I see is the chunk boundary falling in the
middle of a quoted field where
- The quote opens in chunk 1
- The quote closes in chunk 2
- There is an EoL character between the start of chunk 2 and the closing quote

When the worker processing chunk 2 starts, it believes itself to be in
out-of-quote state, so only data between the start of the chunk and
the EoL is regarded as belonging to the partial line. From that point
on the parsing of the rest of the chunk goes off track.

Some of the resulting errors can be avoided by, for instance,
requiring a quote to be preceded by a delimiter or EoL. That answer
fails when fields end with EoL characters, which happens often enough
in the wild.

Recovering from an incorrect in-quote/out-of-quote state assumption at
the start of parsing a chunk just seems like a hole with no bottom. So
it looks to me like it's best done in a single process which can keep
track of that state reliably.

Good point and I agree with you that having a single process would
avoid any such stuff. However, I will think some more on it and if
you/anyone else gets some idea on how to deal with this in a
multi-worker system (where we can allow each worker to read and
process the chunk) then feel free to share your thoughts.

I see two pieces of this puzzle: an input format we control, and the
ones we don't.

In the former case, we could encode all fields with base85 (or
something similar that reduces the input alphabet efficiently), then
reserve bytes that denote delimiters of various types. ASCII has
separators for file, group, record, and unit that we could use as
inspiration.

I don't have anything to offer for free-form input other than to agree
that it looks like a hole with no bottom, and maybe we should just
keep that process serial, at least until someone finds a bottom.

Best,
David.
--
David Fetter <david(at)fetter(dot)org> http://fetter.org/
Phone: +1 415 235 3778

Remember to vote!
Consider donating to Postgres: http://www.postgresql.org/about/donate

#9Andrew Dunstan
andrew.dunstan@2ndquadrant.com
In reply to: Amit Kapila (#7)
Re: Parallel copy

On 2/15/20 7:32 AM, Amit Kapila wrote:

On Sat, Feb 15, 2020 at 4:08 PM Alastair Turner <minion@decodable.me> wrote:

On Sat, 15 Feb 2020 at 04:55, Amit Kapila <amit.kapila16@gmail.com> wrote:

On Fri, Feb 14, 2020 at 7:16 PM Alastair Turner <minion@decodable.me> wrote:

...

Parsing rows from the raw input (the work done by CopyReadLine()) in a single process would accommodate line returns in quoted fields. I don't think there's a way of getting parallel workers to manage the in-quote/out-of-quote state required.

AFAIU, the whole of this in-quote/out-of-quote state is manged inside
CopyReadLineText which will be done by each of the parallel workers,
something on the lines of what Thomas did in his patch [1].
Basically, we need to invent a mechanism to allocate chunks to
individual workers and then the whole processing will be done as we
are doing now except for special handling for partial tuples which I
have explained in my previous email. Am, I missing something here?

The problem case that I see is the chunk boundary falling in the
middle of a quoted field where
- The quote opens in chunk 1
- The quote closes in chunk 2
- There is an EoL character between the start of chunk 2 and the closing quote

When the worker processing chunk 2 starts, it believes itself to be in
out-of-quote state, so only data between the start of the chunk and
the EoL is regarded as belonging to the partial line. From that point
on the parsing of the rest of the chunk goes off track.

Some of the resulting errors can be avoided by, for instance,
requiring a quote to be preceded by a delimiter or EoL. That answer
fails when fields end with EoL characters, which happens often enough
in the wild.

Recovering from an incorrect in-quote/out-of-quote state assumption at
the start of parsing a chunk just seems like a hole with no bottom. So
it looks to me like it's best done in a single process which can keep
track of that state reliably.

Good point and I agree with you that having a single process would
avoid any such stuff. However, I will think some more on it and if
you/anyone else gets some idea on how to deal with this in a
multi-worker system (where we can allow each worker to read and
process the chunk) then feel free to share your thoughts.

IIRC, in_quote only matters here in CSV mode (because CSV fields can
have embedded newlines). So why not just forbid parallel copy in CSV
mode, at least for now? I guess it depends on the actual use case. If we
expect to be parallel loading humungous CSVs then that won't fly.

cheers

andrew

--
Andrew Dunstan https://www.2ndQuadrant.com
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

#10Amit Kapila
amit.kapila16@gmail.com
In reply to: Andrew Dunstan (#9)
Re: Parallel copy

On Sun, Feb 16, 2020 at 12:21 PM Andrew Dunstan
<andrew.dunstan@2ndquadrant.com> wrote:

On 2/15/20 7:32 AM, Amit Kapila wrote:

On Sat, Feb 15, 2020 at 4:08 PM Alastair Turner <minion@decodable.me> wrote:

The problem case that I see is the chunk boundary falling in the
middle of a quoted field where
- The quote opens in chunk 1
- The quote closes in chunk 2
- There is an EoL character between the start of chunk 2 and the closing quote

When the worker processing chunk 2 starts, it believes itself to be in
out-of-quote state, so only data between the start of the chunk and
the EoL is regarded as belonging to the partial line. From that point
on the parsing of the rest of the chunk goes off track.

Some of the resulting errors can be avoided by, for instance,
requiring a quote to be preceded by a delimiter or EoL. That answer
fails when fields end with EoL characters, which happens often enough
in the wild.

Recovering from an incorrect in-quote/out-of-quote state assumption at
the start of parsing a chunk just seems like a hole with no bottom. So
it looks to me like it's best done in a single process which can keep
track of that state reliably.

Good point and I agree with you that having a single process would
avoid any such stuff. However, I will think some more on it and if
you/anyone else gets some idea on how to deal with this in a
multi-worker system (where we can allow each worker to read and
process the chunk) then feel free to share your thoughts.

IIRC, in_quote only matters here in CSV mode (because CSV fields can
have embedded newlines).

AFAIU, that is correct.

So why not just forbid parallel copy in CSV
mode, at least for now? I guess it depends on the actual use case. If we
expect to be parallel loading humungous CSVs then that won't fly.

I am not sure about this part. However, I guess we should at the very
least have some extendable solution that can deal with csv, otherwise,
we might end up re-designing everything if someday we want to deal
with CSV. One naive idea is that in csv mode, we can set up the
things slightly differently like the worker, won't start processing
the chunk unless the previous chunk is completely parsed. So each
worker would first parse and tokenize the entire chunk and then start
writing it. So, this will make the reading/parsing part serialized,
but writes can still be parallel. Now, I don't know if it is a good
idea to process in a different way for csv mode.

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#11Ants Aasma
ants@cybertec.at
In reply to: Amit Kapila (#7)
Re: Parallel copy

On Sat, 15 Feb 2020 at 14:32, Amit Kapila <amit.kapila16@gmail.com> wrote:

Good point and I agree with you that having a single process would
avoid any such stuff. However, I will think some more on it and if
you/anyone else gets some idea on how to deal with this in a
multi-worker system (where we can allow each worker to read and
process the chunk) then feel free to share your thoughts.

I think having a single process handle splitting the input into tuples makes
most sense. It's possible to parse csv at multiple GB/s rates [1]https://github.com/geofflangdale/simdcsv/, finding
tuple boundaries is a subset of that task.

My first thought for a design would be to have two shared memory ring buffers,
one for data and one for tuple start positions. Reader process reads the CSV
data into the main buffer, finds tuple start locations in there and writes
those to the secondary buffer.

Worker processes claim a chunk of tuple positions from the secondary buffer and
update their "keep this data around" position with the first position. Then
proceed to parse and insert the tuples, updating their position until they find
the end of the last tuple in the chunk.

Buffer size, maximum and minimum chunk size could be tunable. Ideally the
buffers would be at least big enough to absorb one of the workers getting
scheduled out for a timeslice, which could be up to tens of megabytes.

Regards,
Ants Aasma

[1]: https://github.com/geofflangdale/simdcsv/

#12Kyotaro Horiguchi
horikyota.ntt@gmail.com
In reply to: Amit Kapila (#10)
Re: Parallel copy

At Mon, 17 Feb 2020 16:49:22 +0530, Amit Kapila <amit.kapila16@gmail.com> wrote in

On Sun, Feb 16, 2020 at 12:21 PM Andrew Dunstan
<andrew.dunstan@2ndquadrant.com> wrote:

On 2/15/20 7:32 AM, Amit Kapila wrote:

On Sat, Feb 15, 2020 at 4:08 PM Alastair Turner <minion@decodable.me> wrot> > So why not just forbid parallel copy in CSV

mode, at least for now? I guess it depends on the actual use case. If we
expect to be parallel loading humungous CSVs then that won't fly.

I am not sure about this part. However, I guess we should at the very
least have some extendable solution that can deal with csv, otherwise,
we might end up re-designing everything if someday we want to deal
with CSV. One naive idea is that in csv mode, we can set up the
things slightly differently like the worker, won't start processing
the chunk unless the previous chunk is completely parsed. So each
worker would first parse and tokenize the entire chunk and then start
writing it. So, this will make the reading/parsing part serialized,
but writes can still be parallel. Now, I don't know if it is a good
idea to process in a different way for csv mode.

In an extreme case, if we didn't see a QUOTE in a chunk, we cannot
know the chunk is in a quoted section or not, until all the past
chunks are parsed. After all we are forced to parse fully
sequentially as far as we allow QUOTE.

On the other hand, if we allowed "COPY t FROM f WITH (FORMAT CSV,
QUOTE '')" in order to signal that there's no quoted section in the
file then all chunks would be fully concurrently parsable.

regards.

--
Kyotaro Horiguchi
NTT Open Source Software Center

#13Thomas Munro
thomas.munro@gmail.com
In reply to: Ants Aasma (#11)
Re: Parallel copy

On Tue, Feb 18, 2020 at 4:04 AM Ants Aasma <ants@cybertec.at> wrote:

On Sat, 15 Feb 2020 at 14:32, Amit Kapila <amit.kapila16@gmail.com> wrote:

Good point and I agree with you that having a single process would
avoid any such stuff. However, I will think some more on it and if
you/anyone else gets some idea on how to deal with this in a
multi-worker system (where we can allow each worker to read and
process the chunk) then feel free to share your thoughts.

I think having a single process handle splitting the input into tuples makes
most sense. It's possible to parse csv at multiple GB/s rates [1], finding
tuple boundaries is a subset of that task.

Yeah, this is compelling. Even though it has to read the file
serially, the real gains from parallel COPY should come from doing the
real work in parallel: data-type parsing, tuple forming, WHERE clause
filtering, partition routing, buffer management, insertion and
associated triggers, FKs and index maintenance.

The reason I used the other approach for the file_fdw patch is that I
was trying to make it look as much as possible like parallel
sequential scan and not create an extra worker, because I didn't feel
like an FDW should be allowed to do that (what if executor nodes all
over the query tree created worker processes willy-nilly?). Obviously
it doesn't work correctly for embedded newlines, and even if you
decree that multi-line values aren't allowed in parallel COPY, the
stuff about tuples crossing chunk boundaries is still a bit unpleasant
(whether solved by double reading as I showed, or a bunch of tap
dancing in shared memory) and creates overheads.

My first thought for a design would be to have two shared memory ring buffers,
one for data and one for tuple start positions. Reader process reads the CSV
data into the main buffer, finds tuple start locations in there and writes
those to the secondary buffer.

Worker processes claim a chunk of tuple positions from the secondary buffer and
update their "keep this data around" position with the first position. Then
proceed to parse and insert the tuples, updating their position until they find
the end of the last tuple in the chunk.

+1. That sort of two-queue scheme is exactly how I sketched out a
multi-consumer queue for a hypothetical Parallel Scatter node. It
probably gets a bit trickier when the payload has to be broken up into
fragments to wrap around the "data" buffer N times.

#14Ants Aasma
ants@cybertec.at
In reply to: Thomas Munro (#13)
Re: Parallel copy

On Tue, 18 Feb 2020 at 04:40, Thomas Munro <thomas.munro@gmail.com> wrote:

+1. That sort of two-queue scheme is exactly how I sketched out a
multi-consumer queue for a hypothetical Parallel Scatter node. It
probably gets a bit trickier when the payload has to be broken up into
fragments to wrap around the "data" buffer N times.

At least for copy it should be easy enough - it already has to handle reading
data block by block. If worker updates its position while doing so the reader
can wrap around the data buffer.

There will be no parallelism while one worker is buffering up a line larger
than the data buffer, but that doesn't seem like a major issue. Once the line is
buffered and begins inserting next worker can start buffering the next tuple.

Regards,
Ants Aasma

#15Amit Kapila
amit.kapila16@gmail.com
In reply to: Ants Aasma (#11)
Re: Parallel copy

On Mon, Feb 17, 2020 at 8:34 PM Ants Aasma <ants@cybertec.at> wrote:

On Sat, 15 Feb 2020 at 14:32, Amit Kapila <amit.kapila16@gmail.com> wrote:

Good point and I agree with you that having a single process would
avoid any such stuff. However, I will think some more on it and if
you/anyone else gets some idea on how to deal with this in a
multi-worker system (where we can allow each worker to read and
process the chunk) then feel free to share your thoughts.

I think having a single process handle splitting the input into tuples makes
most sense. It's possible to parse csv at multiple GB/s rates [1], finding
tuple boundaries is a subset of that task.

My first thought for a design would be to have two shared memory ring buffers,
one for data and one for tuple start positions. Reader process reads the CSV
data into the main buffer, finds tuple start locations in there and writes
those to the secondary buffer.

Worker processes claim a chunk of tuple positions from the secondary buffer and
update their "keep this data around" position with the first position. Then
proceed to parse and insert the tuples, updating their position until they find
the end of the last tuple in the chunk.

This is something similar to what I had also in mind for this idea. I
had thought of handing over complete chunk (64K or whatever we
decide). The one thing that slightly bothers me is that we will add
some additional overhead of copying to and from shared memory which
was earlier from local process memory. And, the tokenization (finding
line boundaries) would be serial. I think that tokenization should be
a small part of the overall work we do during the copy operation, but
will do some measurements to ascertain the same.

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#16Amit Kapila
amit.kapila16@gmail.com
In reply to: Kyotaro Horiguchi (#12)
Re: Parallel copy

On Tue, Feb 18, 2020 at 7:28 AM Kyotaro Horiguchi
<horikyota.ntt@gmail.com> wrote:

At Mon, 17 Feb 2020 16:49:22 +0530, Amit Kapila <amit.kapila16@gmail.com> wrote in

On Sun, Feb 16, 2020 at 12:21 PM Andrew Dunstan
<andrew.dunstan@2ndquadrant.com> wrote:

On 2/15/20 7:32 AM, Amit Kapila wrote:

On Sat, Feb 15, 2020 at 4:08 PM Alastair Turner <minion@decodable.me> wrot> > So why not just forbid parallel copy in CSV

mode, at least for now? I guess it depends on the actual use case. If we
expect to be parallel loading humungous CSVs then that won't fly.

I am not sure about this part. However, I guess we should at the very
least have some extendable solution that can deal with csv, otherwise,
we might end up re-designing everything if someday we want to deal
with CSV. One naive idea is that in csv mode, we can set up the
things slightly differently like the worker, won't start processing
the chunk unless the previous chunk is completely parsed. So each
worker would first parse and tokenize the entire chunk and then start
writing it. So, this will make the reading/parsing part serialized,
but writes can still be parallel. Now, I don't know if it is a good
idea to process in a different way for csv mode.

In an extreme case, if we didn't see a QUOTE in a chunk, we cannot
know the chunk is in a quoted section or not, until all the past
chunks are parsed. After all we are forced to parse fully
sequentially as far as we allow QUOTE.

Right, I think the benefits of this as compared to single reader idea
would be (a) we can save accessing shared memory for the most part of
the chunk (b) for non-csv mode, even the tokenization (finding line
boundaries) would also be parallel. OTOH, doing processing
differently for csv and non-csv mode might not be good.

On the other hand, if we allowed "COPY t FROM f WITH (FORMAT CSV,
QUOTE '')" in order to signal that there's no quoted section in the
file then all chunks would be fully concurrently parsable.

Yeah, if we can provide such an option, we can probably make parallel
csv processing equivalent to non-csv. However, users might not like
this as I think in some cases it won't be easier for them to tell
whether the file has quoted fields or not. I am not very sure of this
point.

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#17Kyotaro Horiguchi
horikyota.ntt@gmail.com
In reply to: Amit Kapila (#16)
Re: Parallel copy

At Tue, 18 Feb 2020 15:59:36 +0530, Amit Kapila <amit.kapila16@gmail.com> wrote in

On Tue, Feb 18, 2020 at 7:28 AM Kyotaro Horiguchi
<horikyota.ntt@gmail.com> wrote:

In an extreme case, if we didn't see a QUOTE in a chunk, we cannot
know the chunk is in a quoted section or not, until all the past
chunks are parsed. After all we are forced to parse fully
sequentially as far as we allow QUOTE.

Right, I think the benefits of this as compared to single reader idea
would be (a) we can save accessing shared memory for the most part of
the chunk (b) for non-csv mode, even the tokenization (finding line
boundaries) would also be parallel. OTOH, doing processing
differently for csv and non-csv mode might not be good.

Agreed. So I think it's a good point of compromize.

On the other hand, if we allowed "COPY t FROM f WITH (FORMAT CSV,
QUOTE '')" in order to signal that there's no quoted section in the
file then all chunks would be fully concurrently parsable.

Yeah, if we can provide such an option, we can probably make parallel
csv processing equivalent to non-csv. However, users might not like
this as I think in some cases it won't be easier for them to tell
whether the file has quoted fields or not. I am not very sure of this
point.

I'm not sure how large portion of the usage contains quoted sections,
so I'm not sure how it is useful..

regards.

--
Kyotaro Horiguchi
NTT Open Source Software Center

#18Ants Aasma
ants@cybertec.at
In reply to: Amit Kapila (#15)
1 attachment(s)
Re: Parallel copy

On Tue, 18 Feb 2020 at 12:20, Amit Kapila <amit.kapila16@gmail.com> wrote:

This is something similar to what I had also in mind for this idea. I
had thought of handing over complete chunk (64K or whatever we
decide). The one thing that slightly bothers me is that we will add
some additional overhead of copying to and from shared memory which
was earlier from local process memory. And, the tokenization (finding
line boundaries) would be serial. I think that tokenization should be
a small part of the overall work we do during the copy operation, but
will do some measurements to ascertain the same.

I don't think any extra copying is needed. The reader can directly
fread()/pq_copymsgbytes() into shared memory, and the workers can run
CopyReadLineText() inner loop directly off of the buffer in shared memory.

For serial performance of tokenization into lines, I really think a SIMD
based approach will be fast enough for quite some time. I hacked up the code in
the simdcsv project to only tokenize on line endings and it was able to
tokenize a CSV file with short lines at 8+ GB/s. There are going to be many
other bottlenecks before this one starts limiting. Patch attached if you'd
like to try that out.

Regards,
Ants Aasma

Attachments:

simdcsv-find-only-lineendings.difftext/x-patch; charset=US-ASCII; name=simdcsv-find-only-lineendings.diffDownload
diff --git a/src/main.cpp b/src/main.cpp
index 9d33a85..2cf775c 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -185,7 +185,6 @@ bool find_indexes(const uint8_t * buf, size_t len, ParsedCSV & pcsv) {
 #endif
         simd_input in = fill_input(buf+internal_idx);
         uint64_t quote_mask = find_quote_mask(in, prev_iter_inside_quote);
-        uint64_t sep = cmp_mask_against_input(in, ',');
 #ifdef CRLF
         uint64_t cr = cmp_mask_against_input(in, 0x0d);
         uint64_t cr_adjusted = (cr << 1) | prev_iter_cr_end;
@@ -195,7 +194,7 @@ bool find_indexes(const uint8_t * buf, size_t len, ParsedCSV & pcsv) {
 #else
         uint64_t end = cmp_mask_against_input(in, 0x0a);
 #endif
-        fields[b] = (end | sep) & ~quote_mask;
+        fields[b] = (end) & ~quote_mask;
       }
       for(size_t b = 0; b < SIMDCSV_BUFFERSIZE; b++){
         size_t internal_idx = 64 * b + idx;
@@ -211,7 +210,6 @@ bool find_indexes(const uint8_t * buf, size_t len, ParsedCSV & pcsv) {
 #endif
       simd_input in = fill_input(buf+idx);
       uint64_t quote_mask = find_quote_mask(in, prev_iter_inside_quote);
-      uint64_t sep = cmp_mask_against_input(in, ',');
 #ifdef CRLF
       uint64_t cr = cmp_mask_against_input(in, 0x0d);
       uint64_t cr_adjusted = (cr << 1) | prev_iter_cr_end;
@@ -226,7 +224,7 @@ bool find_indexes(const uint8_t * buf, size_t len, ParsedCSV & pcsv) {
     // then outside the quotes with LF so it's OK to "and off"
     // the quoted bits here. Some other quote convention would
     // need to be thought about carefully
-      uint64_t field_sep = (end | sep) & ~quote_mask;
+      uint64_t field_sep = (end) & ~quote_mask;
       flatten_bits(base_ptr, base, idx, field_sep);
   }
 #undef SIMDCSV_BUFFERSIZE
#19Amit Kapila
amit.kapila16@gmail.com
In reply to: Ants Aasma (#18)
Re: Parallel copy

On Tue, Feb 18, 2020 at 5:59 PM Ants Aasma <ants@cybertec.at> wrote:

On Tue, 18 Feb 2020 at 12:20, Amit Kapila <amit.kapila16@gmail.com> wrote:

This is something similar to what I had also in mind for this idea. I
had thought of handing over complete chunk (64K or whatever we
decide). The one thing that slightly bothers me is that we will add
some additional overhead of copying to and from shared memory which
was earlier from local process memory. And, the tokenization (finding
line boundaries) would be serial. I think that tokenization should be
a small part of the overall work we do during the copy operation, but
will do some measurements to ascertain the same.

I don't think any extra copying is needed.

I am talking about access to shared memory instead of the process
local memory. I understand that an extra copy won't be required.

The reader can directly
fread()/pq_copymsgbytes() into shared memory, and the workers can run
CopyReadLineText() inner loop directly off of the buffer in shared memory.

I am slightly confused here. AFAIU, the for(;;) loop in
CopyReadLineText is about finding the line endings which we thought
that the reader process will do.

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#20Mike Blackwell
mike.blackwell@rrd.com
In reply to: Andrew Dunstan (#9)
Re: Parallel copy

On Sun, Feb 16, 2020 at 12:51 AM Andrew Dunstan <
andrew.dunstan@2ndquadrant.com> wrote:

IIRC, in_quote only matters here in CSV mode (because CSV fields can
have embedded newlines). So why not just forbid parallel copy in CSV
mode, at least for now? I guess it depends on the actual use case. If we
expect to be parallel loading humungous CSVs then that won't fly.

Loading large CSV files is pretty common here. I hope this can be
supported.

MIKE BLACKWELL

* <Mike.Blackwell@rrd.com>*

Show quoted text
#21Ants Aasma
ants@cybertec.at
In reply to: Amit Kapila (#19)
Re: Parallel copy

On Tue, 18 Feb 2020 at 15:21, Amit Kapila <amit.kapila16@gmail.com> wrote:

On Tue, Feb 18, 2020 at 5:59 PM Ants Aasma <ants@cybertec.at> wrote:

On Tue, 18 Feb 2020 at 12:20, Amit Kapila <amit.kapila16@gmail.com> wrote:

This is something similar to what I had also in mind for this idea. I
had thought of handing over complete chunk (64K or whatever we
decide). The one thing that slightly bothers me is that we will add
some additional overhead of copying to and from shared memory which
was earlier from local process memory. And, the tokenization (finding
line boundaries) would be serial. I think that tokenization should be
a small part of the overall work we do during the copy operation, but
will do some measurements to ascertain the same.

I don't think any extra copying is needed.

I am talking about access to shared memory instead of the process
local memory. I understand that an extra copy won't be required.

The reader can directly
fread()/pq_copymsgbytes() into shared memory, and the workers can run
CopyReadLineText() inner loop directly off of the buffer in shared memory.

I am slightly confused here. AFAIU, the for(;;) loop in
CopyReadLineText is about finding the line endings which we thought
that the reader process will do.

Indeed, I somehow misread the code while scanning over it. So CopyReadLineText
currently copies data from cstate->raw_buf to the StringInfo in
cstate->line_buf. In parallel mode it would copy it from the shared data buffer
to local line_buf until it hits the line end found by the data reader. The
amount of copying done is still exactly the same as it is now.

Regards,
Ants Aasma

#22David Fetter
david@fetter.org
In reply to: Amit Kapila (#19)
Re: Parallel copy

On Tue, Feb 18, 2020 at 06:51:29PM +0530, Amit Kapila wrote:

On Tue, Feb 18, 2020 at 5:59 PM Ants Aasma <ants@cybertec.at> wrote:

On Tue, 18 Feb 2020 at 12:20, Amit Kapila <amit.kapila16@gmail.com> wrote:

This is something similar to what I had also in mind for this idea. I
had thought of handing over complete chunk (64K or whatever we
decide). The one thing that slightly bothers me is that we will add
some additional overhead of copying to and from shared memory which
was earlier from local process memory. And, the tokenization (finding
line boundaries) would be serial. I think that tokenization should be
a small part of the overall work we do during the copy operation, but
will do some measurements to ascertain the same.

I don't think any extra copying is needed.

I am talking about access to shared memory instead of the process
local memory. I understand that an extra copy won't be required.

Isn't accessing shared memory from different pieces of execution what
threads were designed to do?

Best,
David.
--
David Fetter <david(at)fetter(dot)org> http://fetter.org/
Phone: +1 415 235 3778

Remember to vote!
Consider donating to Postgres: http://www.postgresql.org/about/donate

#23Amit Kapila
amit.kapila16@gmail.com
In reply to: David Fetter (#22)
Re: Parallel copy

On Tue, Feb 18, 2020 at 8:41 PM David Fetter <david@fetter.org> wrote:

On Tue, Feb 18, 2020 at 06:51:29PM +0530, Amit Kapila wrote:

On Tue, Feb 18, 2020 at 5:59 PM Ants Aasma <ants@cybertec.at> wrote:

On Tue, 18 Feb 2020 at 12:20, Amit Kapila <amit.kapila16@gmail.com> wrote:

This is something similar to what I had also in mind for this idea. I
had thought of handing over complete chunk (64K or whatever we
decide). The one thing that slightly bothers me is that we will add
some additional overhead of copying to and from shared memory which
was earlier from local process memory. And, the tokenization (finding
line boundaries) would be serial. I think that tokenization should be
a small part of the overall work we do during the copy operation, but
will do some measurements to ascertain the same.

I don't think any extra copying is needed.

I am talking about access to shared memory instead of the process
local memory. I understand that an extra copy won't be required.

Isn't accessing shared memory from different pieces of execution what
threads were designed to do?

Sorry, but I don't understand what you mean by the above? We are
going to use background workers (which are processes) for parallel
workers. In general, it might not make a big difference in accessing
shared memory as compared to local memory especially because the cost
of other stuff in the copy is relatively higher. But still, it is a
point to consider.

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#24Amit Kapila
amit.kapila16@gmail.com
In reply to: Ants Aasma (#21)
Re: Parallel copy

On Tue, Feb 18, 2020 at 8:08 PM Ants Aasma <ants@cybertec.at> wrote:

On Tue, 18 Feb 2020 at 15:21, Amit Kapila <amit.kapila16@gmail.com> wrote:

On Tue, Feb 18, 2020 at 5:59 PM Ants Aasma <ants@cybertec.at> wrote:

On Tue, 18 Feb 2020 at 12:20, Amit Kapila <amit.kapila16@gmail.com> wrote:

This is something similar to what I had also in mind for this idea. I
had thought of handing over complete chunk (64K or whatever we
decide). The one thing that slightly bothers me is that we will add
some additional overhead of copying to and from shared memory which
was earlier from local process memory. And, the tokenization (finding
line boundaries) would be serial. I think that tokenization should be
a small part of the overall work we do during the copy operation, but
will do some measurements to ascertain the same.

I don't think any extra copying is needed.

I am talking about access to shared memory instead of the process
local memory. I understand that an extra copy won't be required.

The reader can directly
fread()/pq_copymsgbytes() into shared memory, and the workers can run
CopyReadLineText() inner loop directly off of the buffer in shared memory.

I am slightly confused here. AFAIU, the for(;;) loop in
CopyReadLineText is about finding the line endings which we thought
that the reader process will do.

Indeed, I somehow misread the code while scanning over it. So CopyReadLineText
currently copies data from cstate->raw_buf to the StringInfo in
cstate->line_buf. In parallel mode it would copy it from the shared data buffer
to local line_buf until it hits the line end found by the data reader. The
amount of copying done is still exactly the same as it is now.

Yeah, on a broader level it will be something like that, but actual
details might vary during implementation. BTW, have you given any
thoughts on one other approach I have shared above [1]/messages/by-id/CAA4eK1LyAyPCtBk4rkwomeT6=yTse5qWws-7i9EFwnUFZhvu5w@mail.gmail.com? We might not
go with that idea, but it is better to discuss different ideas and
evaluate their pros and cons.

[1]: /messages/by-id/CAA4eK1LyAyPCtBk4rkwomeT6=yTse5qWws-7i9EFwnUFZhvu5w@mail.gmail.com

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#25Amit Kapila
amit.kapila16@gmail.com
In reply to: Mike Blackwell (#20)
Re: Parallel copy

On Tue, Feb 18, 2020 at 7:51 PM Mike Blackwell <mike.blackwell@rrd.com>
wrote:

On Sun, Feb 16, 2020 at 12:51 AM Andrew Dunstan <
andrew.dunstan@2ndquadrant.com> wrote:

IIRC, in_quote only matters here in CSV mode (because CSV fields can
have embedded newlines). So why not just forbid parallel copy in CSV
mode, at least for now? I guess it depends on the actual use case. If we
expect to be parallel loading humungous CSVs then that won't fly.

Loading large CSV files is pretty common here. I hope this can be
supported.

Thank you for your inputs. It is important and valuable.

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#26Ants Aasma
ants@cybertec.at
In reply to: Amit Kapila (#24)
Re: Parallel copy

On Wed, 19 Feb 2020 at 06:22, Amit Kapila <amit.kapila16@gmail.com> wrote:

On Tue, Feb 18, 2020 at 8:08 PM Ants Aasma <ants@cybertec.at> wrote:

On Tue, 18 Feb 2020 at 15:21, Amit Kapila <amit.kapila16@gmail.com> wrote:

On Tue, Feb 18, 2020 at 5:59 PM Ants Aasma <ants@cybertec.at> wrote:

On Tue, 18 Feb 2020 at 12:20, Amit Kapila <amit.kapila16@gmail.com> wrote:

This is something similar to what I had also in mind for this idea. I
had thought of handing over complete chunk (64K or whatever we
decide). The one thing that slightly bothers me is that we will add
some additional overhead of copying to and from shared memory which
was earlier from local process memory. And, the tokenization (finding
line boundaries) would be serial. I think that tokenization should be
a small part of the overall work we do during the copy operation, but
will do some measurements to ascertain the same.

I don't think any extra copying is needed.

I am talking about access to shared memory instead of the process
local memory. I understand that an extra copy won't be required.

The reader can directly
fread()/pq_copymsgbytes() into shared memory, and the workers can run
CopyReadLineText() inner loop directly off of the buffer in shared memory.

I am slightly confused here. AFAIU, the for(;;) loop in
CopyReadLineText is about finding the line endings which we thought
that the reader process will do.

Indeed, I somehow misread the code while scanning over it. So CopyReadLineText
currently copies data from cstate->raw_buf to the StringInfo in
cstate->line_buf. In parallel mode it would copy it from the shared data buffer
to local line_buf until it hits the line end found by the data reader. The
amount of copying done is still exactly the same as it is now.

Yeah, on a broader level it will be something like that, but actual
details might vary during implementation. BTW, have you given any
thoughts on one other approach I have shared above [1]? We might not
go with that idea, but it is better to discuss different ideas and
evaluate their pros and cons.

[1] - /messages/by-id/CAA4eK1LyAyPCtBk4rkwomeT6=yTse5qWws-7i9EFwnUFZhvu5w@mail.gmail.com

It seems to be that at least for the general CSV case the tokenization to
tuples is an inherently serial task. Adding thread synchronization to that path
for coordinating between multiple workers is only going to make it slower. It
may be possible to enforce limitations on the input (e.g. no quotes allowed) or
do some speculative tokenization (e.g. if we encounter quote before newline
assume the chunk started in a quoted section) to make it possible to do the
tokenization in parallel. But given that the simpler and more featured approach
of handling it in a single reader process looks to be fast enough, I don't see
the point. I rather think that the next big step would be to overlap reading
input and tokenization, hopefully by utilizing Andres's work on asyncio.

Regards,
Ants Aasma

#27Tomas Vondra
tomas.vondra@2ndquadrant.com
In reply to: Ants Aasma (#26)
Re: Parallel copy

On Wed, Feb 19, 2020 at 11:02:15AM +0200, Ants Aasma wrote:

On Wed, 19 Feb 2020 at 06:22, Amit Kapila <amit.kapila16@gmail.com> wrote:

On Tue, Feb 18, 2020 at 8:08 PM Ants Aasma <ants@cybertec.at> wrote:

On Tue, 18 Feb 2020 at 15:21, Amit Kapila <amit.kapila16@gmail.com> wrote:

On Tue, Feb 18, 2020 at 5:59 PM Ants Aasma <ants@cybertec.at> wrote:

On Tue, 18 Feb 2020 at 12:20, Amit Kapila <amit.kapila16@gmail.com> wrote:

This is something similar to what I had also in mind for this idea. I
had thought of handing over complete chunk (64K or whatever we
decide). The one thing that slightly bothers me is that we will add
some additional overhead of copying to and from shared memory which
was earlier from local process memory. And, the tokenization (finding
line boundaries) would be serial. I think that tokenization should be
a small part of the overall work we do during the copy operation, but
will do some measurements to ascertain the same.

I don't think any extra copying is needed.

I am talking about access to shared memory instead of the process
local memory. I understand that an extra copy won't be required.

The reader can directly
fread()/pq_copymsgbytes() into shared memory, and the workers can run
CopyReadLineText() inner loop directly off of the buffer in shared memory.

I am slightly confused here. AFAIU, the for(;;) loop in
CopyReadLineText is about finding the line endings which we thought
that the reader process will do.

Indeed, I somehow misread the code while scanning over it. So CopyReadLineText
currently copies data from cstate->raw_buf to the StringInfo in
cstate->line_buf. In parallel mode it would copy it from the shared data buffer
to local line_buf until it hits the line end found by the data reader. The
amount of copying done is still exactly the same as it is now.

Yeah, on a broader level it will be something like that, but actual
details might vary during implementation. BTW, have you given any
thoughts on one other approach I have shared above [1]? We might not
go with that idea, but it is better to discuss different ideas and
evaluate their pros and cons.

[1] - /messages/by-id/CAA4eK1LyAyPCtBk4rkwomeT6=yTse5qWws-7i9EFwnUFZhvu5w@mail.gmail.com

It seems to be that at least for the general CSV case the tokenization to
tuples is an inherently serial task. Adding thread synchronization to that path
for coordinating between multiple workers is only going to make it slower. It
may be possible to enforce limitations on the input (e.g. no quotes allowed) or
do some speculative tokenization (e.g. if we encounter quote before newline
assume the chunk started in a quoted section) to make it possible to do the
tokenization in parallel. But given that the simpler and more featured approach
of handling it in a single reader process looks to be fast enough, I don't see
the point. I rather think that the next big step would be to overlap reading
input and tokenization, hopefully by utilizing Andres's work on asyncio.

I generally agree with the impression that parsing CSV is tricky and
unlikely to benefit from parallelism in general. There may be cases with
restrictions making it easier (e.g. restrictions on the format) but that
might be a bit too complex to start with.

For example, I had an idea to parallelise the planning by splitting it
into two phases:

1) indexing

Splits the CSV file into equally-sized chunks, make each worker to just
scan through it's chunk and store positions of delimiters, quotes,
newlines etc. This is probably the most expensive part of the parsing
(essentially go char by char), and we'd speed it up linearly.

2) merge

Combine the information from (1) in a single process, and actually parse
the CSV data - we would not have to inspect each character, because we'd
know positions of interesting chars, so this should be fast. We might
have to recheck some stuff (e.g. escaping) but it should still be much
faster.

But yes, this may be a bit complex and I'm not sure it's worth it.

The one piece of information I'm missing here is at least a very rough
quantification of the individual steps of CSV processing - for example
if parsing takes only 10% of the time, it's pretty pointless to start by
parallelising this part and we should focus on the rest. If it's 50% it
might be a different story. Has anyone done any measurements?

regards

--
Tomas Vondra http://www.2ndQuadrant.com
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

#28Amit Kapila
amit.kapila16@gmail.com
In reply to: Tomas Vondra (#27)
Re: Parallel copy

On Wed, Feb 19, 2020 at 4:08 PM Tomas Vondra
<tomas.vondra@2ndquadrant.com> wrote:

The one piece of information I'm missing here is at least a very rough
quantification of the individual steps of CSV processing - for example
if parsing takes only 10% of the time, it's pretty pointless to start by
parallelising this part and we should focus on the rest. If it's 50% it
might be a different story.

Right, this is important information to know.

Has anyone done any measurements?

Not yet, but planning to work on it.

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#29David Fetter
david@fetter.org
In reply to: Amit Kapila (#1)
Re: Parallel copy

On Fri, Feb 14, 2020 at 01:41:54PM +0530, Amit Kapila wrote:

This work is to parallelize the copy command and in particular "Copy
<table_name> from 'filename' Where <condition>;" command.

Apropos of the initial parsing issue generally, there's an interesting
approach taken here: https://github.com/robertdavidgraham/wc2

Best,
David.
--
David Fetter <david(at)fetter(dot)org> http://fetter.org/
Phone: +1 415 235 3778

Remember to vote!
Consider donating to Postgres: http://www.postgresql.org/about/donate

#30Amit Kapila
amit.kapila16@gmail.com
In reply to: David Fetter (#29)
Re: Parallel copy

On Thu, Feb 20, 2020 at 5:12 AM David Fetter <david@fetter.org> wrote:

On Fri, Feb 14, 2020 at 01:41:54PM +0530, Amit Kapila wrote:

This work is to parallelize the copy command and in particular "Copy
<table_name> from 'filename' Where <condition>;" command.

Apropos of the initial parsing issue generally, there's an interesting
approach taken here: https://github.com/robertdavidgraham/wc2

Thanks for sharing. I might be missing something, but I can't figure
out how this can help here. Does this in some way help to allow
multiple workers to read and tokenize the chunks?

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#31Tomas Vondra
tomas.vondra@2ndquadrant.com
In reply to: Amit Kapila (#30)
Re: Parallel copy

On Thu, Feb 20, 2020 at 04:11:39PM +0530, Amit Kapila wrote:

On Thu, Feb 20, 2020 at 5:12 AM David Fetter <david@fetter.org> wrote:

On Fri, Feb 14, 2020 at 01:41:54PM +0530, Amit Kapila wrote:

This work is to parallelize the copy command and in particular "Copy
<table_name> from 'filename' Where <condition>;" command.

Apropos of the initial parsing issue generally, there's an interesting
approach taken here: https://github.com/robertdavidgraham/wc2

Thanks for sharing. I might be missing something, but I can't figure
out how this can help here. Does this in some way help to allow
multiple workers to read and tokenize the chunks?

I think the wc2 is showing that maybe instead of parallelizing the
parsing, we might instead try using a different tokenizer/parser and
make the implementation more efficient instead of just throwing more
CPUs on it.

I don't know if our code is similar to what wc does, maytbe parsing
csv is more complicated than what wc does.

regards

--
Tomas Vondra http://www.2ndQuadrant.com
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

#32David Fetter
david@fetter.org
In reply to: Tomas Vondra (#31)
Re: Parallel copy

On Thu, Feb 20, 2020 at 02:36:02PM +0100, Tomas Vondra wrote:

On Thu, Feb 20, 2020 at 04:11:39PM +0530, Amit Kapila wrote:

On Thu, Feb 20, 2020 at 5:12 AM David Fetter <david@fetter.org> wrote:

On Fri, Feb 14, 2020 at 01:41:54PM +0530, Amit Kapila wrote:

This work is to parallelize the copy command and in particular "Copy
<table_name> from 'filename' Where <condition>;" command.

Apropos of the initial parsing issue generally, there's an interesting
approach taken here: https://github.com/robertdavidgraham/wc2

Thanks for sharing. I might be missing something, but I can't figure
out how this can help here. Does this in some way help to allow
multiple workers to read and tokenize the chunks?

I think the wc2 is showing that maybe instead of parallelizing the
parsing, we might instead try using a different tokenizer/parser and
make the implementation more efficient instead of just throwing more
CPUs on it.

That was what I had in mind.

I don't know if our code is similar to what wc does, maytbe parsing
csv is more complicated than what wc does.

CSV parsing differs from wc in that there are more states in the state
machine, but I don't see anything fundamentally different.

Best,
David.
--
David Fetter <david(at)fetter(dot)org> http://fetter.org/
Phone: +1 415 235 3778

Remember to vote!
Consider donating to Postgres: http://www.postgresql.org/about/donate

#33Ants Aasma
ants@cybertec.at
In reply to: David Fetter (#32)
1 attachment(s)
Re: Parallel copy

On Thu, 20 Feb 2020 at 18:43, David Fetter <david@fetter.org> wrote:>

On Thu, Feb 20, 2020 at 02:36:02PM +0100, Tomas Vondra wrote:

I think the wc2 is showing that maybe instead of parallelizing the
parsing, we might instead try using a different tokenizer/parser and
make the implementation more efficient instead of just throwing more
CPUs on it.

That was what I had in mind.

I don't know if our code is similar to what wc does, maytbe parsing
csv is more complicated than what wc does.

CSV parsing differs from wc in that there are more states in the state
machine, but I don't see anything fundamentally different.

The trouble with a state machine based approach is that the state
transitions form a dependency chain, which means that at best the
processing rate will be 4-5 cycles per byte (L1 latency to fetch the
next state).

I whipped together a quick prototype that uses SIMD and bitmap
manipulations to do the equivalent of CopyReadLineText() in csv mode
including quotes and escape handling, this runs at 0.25-0.5 cycles per
byte.

Regards,
Ants Aasma

Attachments:

simdcopy.ctext/x-csrc; charset=US-ASCII; name=simdcopy.cDownload
#34Tomas Vondra
tomas.vondra@2ndquadrant.com
In reply to: Ants Aasma (#33)
Re: Parallel copy

On Fri, Feb 21, 2020 at 02:54:31PM +0200, Ants Aasma wrote:

On Thu, 20 Feb 2020 at 18:43, David Fetter <david@fetter.org> wrote:>

On Thu, Feb 20, 2020 at 02:36:02PM +0100, Tomas Vondra wrote:

I think the wc2 is showing that maybe instead of parallelizing the
parsing, we might instead try using a different tokenizer/parser and
make the implementation more efficient instead of just throwing more
CPUs on it.

That was what I had in mind.

I don't know if our code is similar to what wc does, maytbe parsing
csv is more complicated than what wc does.

CSV parsing differs from wc in that there are more states in the state
machine, but I don't see anything fundamentally different.

The trouble with a state machine based approach is that the state
transitions form a dependency chain, which means that at best the
processing rate will be 4-5 cycles per byte (L1 latency to fetch the
next state).

I whipped together a quick prototype that uses SIMD and bitmap
manipulations to do the equivalent of CopyReadLineText() in csv mode
including quotes and escape handling, this runs at 0.25-0.5 cycles per
byte.

Interesting. How does that compare to what we currently have?

regards

--
Tomas Vondra http://www.2ndQuadrant.com
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

#35Robert Haas
robertmhaas@gmail.com
In reply to: Amit Kapila (#19)
Re: Parallel copy

On Tue, Feb 18, 2020 at 6:51 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

I am talking about access to shared memory instead of the process
local memory. I understand that an extra copy won't be required.

You make it sound like there is some performance penalty for accessing
shared memory, but I don't think that's true. It's true that
*contended* access to shared memory can be slower, because if multiple
processes are trying to access the same memory, and especially if
multiple processes are trying to write the same memory, then the cache
lines have to be shared and that has a cost. However, I don't think
that would create any noticeable effect in this case. First, there's
presumably only one writer process. Second, you wouldn't normally have
multiple readers working on the same part of the data at the same
time.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#36Andres Freund
andres@anarazel.de
In reply to: Tomas Vondra (#27)
Re: Parallel copy

Hi,

On 2020-02-19 11:38:45 +0100, Tomas Vondra wrote:

I generally agree with the impression that parsing CSV is tricky and
unlikely to benefit from parallelism in general. There may be cases with
restrictions making it easier (e.g. restrictions on the format) but that
might be a bit too complex to start with.

For example, I had an idea to parallelise the planning by splitting it
into two phases:

FWIW, I think we ought to rewrite our COPY parsers before we go for
complex schemes. They're way slower than a decent green-field
CSV/... parser.

The one piece of information I'm missing here is at least a very rough
quantification of the individual steps of CSV processing - for example
if parsing takes only 10% of the time, it's pretty pointless to start by
parallelising this part and we should focus on the rest. If it's 50% it
might be a different story. Has anyone done any measurements?

Not recently, but I'm pretty sure that I've observed CSV parsing to be
way more than 10%.

Greetings,

Andres Freund

#37Tomas Vondra
tomas.vondra@2ndquadrant.com
In reply to: Andres Freund (#36)
Re: Parallel copy

On Sun, Feb 23, 2020 at 05:09:51PM -0800, Andres Freund wrote:

Hi,

On 2020-02-19 11:38:45 +0100, Tomas Vondra wrote:

I generally agree with the impression that parsing CSV is tricky and
unlikely to benefit from parallelism in general. There may be cases with
restrictions making it easier (e.g. restrictions on the format) but that
might be a bit too complex to start with.

For example, I had an idea to parallelise the planning by splitting it
into two phases:

FWIW, I think we ought to rewrite our COPY parsers before we go for
complex schemes. They're way slower than a decent green-field
CSV/... parser.

Yep, that's quite possible.

The one piece of information I'm missing here is at least a very rough
quantification of the individual steps of CSV processing - for example
if parsing takes only 10% of the time, it's pretty pointless to start by
parallelising this part and we should focus on the rest. If it's 50% it
might be a different story. Has anyone done any measurements?

Not recently, but I'm pretty sure that I've observed CSV parsing to be
way more than 10%.

Perhaps. I guess it'll depend on the CSV file (number of fields, ...),
so I still think we need to do some measurements first. I'm willing to
do that, but (a) I doubt I'll have time for that until after 2020-03,
and (b) it'd be good to agree on some set of typical CSV files.

regards

--
Tomas Vondra http://www.2ndQuadrant.com
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

#38Amit Kapila
amit.kapila16@gmail.com
In reply to: Tomas Vondra (#37)
Re: Parallel copy

On Tue, Feb 25, 2020 at 9:30 PM Tomas Vondra
<tomas.vondra@2ndquadrant.com> wrote:

On Sun, Feb 23, 2020 at 05:09:51PM -0800, Andres Freund wrote:

Hi,

The one piece of information I'm missing here is at least a very rough
quantification of the individual steps of CSV processing - for example
if parsing takes only 10% of the time, it's pretty pointless to start by
parallelising this part and we should focus on the rest. If it's 50% it
might be a different story. Has anyone done any measurements?

Not recently, but I'm pretty sure that I've observed CSV parsing to be
way more than 10%.

Perhaps. I guess it'll depend on the CSV file (number of fields, ...),
so I still think we need to do some measurements first.

Agreed.

I'm willing to
do that, but (a) I doubt I'll have time for that until after 2020-03,
and (b) it'd be good to agree on some set of typical CSV files.

Right, I don't know what is the best way to define that. I can think
of the below tests.

1. A table with 10 columns (with datatypes as integers, date, text).
It has one index (unique/primary). Load with 1 million rows (basically
the data should be probably 5-10 GB).
2. A table with 10 columns (with datatypes as integers, date, text).
It has three indexes, one index can be (unique/primary). Load with 1
million rows (basically the data should be probably 5-10 GB).
3. A table with 10 columns (with datatypes as integers, date, text).
It has three indexes, one index can be (unique/primary). It has before
and after trigeers. Load with 1 million rows (basically the data
should be probably 5-10 GB).
4. A table with 10 columns (with datatypes as integers, date, text).
It has five or six indexes, one index can be (unique/primary). Load
with 1 million rows (basically the data should be probably 5-10 GB).

Among all these tests, we can check how much time did we spend in
reading, parsing the csv files vs. rest of execution?

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#39Alastair Turner
minion@decodable.me
In reply to: Amit Kapila (#38)
Re: Parallel copy

On Wed, 26 Feb 2020 at 10:54, Amit Kapila <amit.kapila16@gmail.com> wrote:

On Tue, Feb 25, 2020 at 9:30 PM Tomas Vondra
<tomas.vondra@2ndquadrant.com> wrote:

...

Perhaps. I guess it'll depend on the CSV file (number of fields, ...),
so I still think we need to do some measurements first.

Agreed.

I'm willing to
do that, but (a) I doubt I'll have time for that until after 2020-03,
and (b) it'd be good to agree on some set of typical CSV files.

Right, I don't know what is the best way to define that. I can think
of the below tests.

1. A table with 10 columns (with datatypes as integers, date, text).
It has one index (unique/primary). Load with 1 million rows (basically
the data should be probably 5-10 GB).
2. A table with 10 columns (with datatypes as integers, date, text).
It has three indexes, one index can be (unique/primary). Load with 1
million rows (basically the data should be probably 5-10 GB).
3. A table with 10 columns (with datatypes as integers, date, text).
It has three indexes, one index can be (unique/primary). It has before
and after trigeers. Load with 1 million rows (basically the data
should be probably 5-10 GB).
4. A table with 10 columns (with datatypes as integers, date, text).
It has five or six indexes, one index can be (unique/primary). Load
with 1 million rows (basically the data should be probably 5-10 GB).

Among all these tests, we can check how much time did we spend in
reading, parsing the csv files vs. rest of execution?

That's a good set of tests of what happens after the parse. Two
simpler test runs may provide useful baselines - no
constraints/indexes with all columns varchar and no
constraints/indexes with columns correctly typed.

For testing the impact of various parts of the parse process, my idea would be:
- A base dataset with 10 columns including int, date and text. One
text field quoted and containing both delimiters and line terminators
- A derivative to measure just line parsing - strip the quotes around
the text field and quote the whole row as one text field
- A derivative to measure the impact of quoted fields - clean up the
text field so it doesn't require quoting
- A derivative to measure the impact of row length - run ten rows
together to make 100 column rows, but only a tenth as many rows

If that sounds reasonable, I'll try to knock up a generator.

--
Alastair

#40Ants Aasma
ants@cybertec.at
In reply to: Tomas Vondra (#37)
Re: Parallel copy

On Tue, 25 Feb 2020 at 18:00, Tomas Vondra <tomas.vondra@2ndquadrant.com> wrote:

Perhaps. I guess it'll depend on the CSV file (number of fields, ...),
so I still think we need to do some measurements first. I'm willing to
do that, but (a) I doubt I'll have time for that until after 2020-03,
and (b) it'd be good to agree on some set of typical CSV files.

I agree that getting a nice varied dataset would be nice. Including
things like narrow integer only tables, strings with newlines and
escapes in them, extremely wide rows.

I tried to capture a quick profile just to see what it looks like.
Grabbed a random open data set from the web, about 800MB of narrow
rows CSV [1]https://www3.stats.govt.nz/2018census/Age-sex-by-ethnic-group-grouped-total-responses-census-usually-resident-population-counts-2006-2013-2018-Censuses-RC-TA-SA2-DHB.zip.

Script:
CREATE TABLE census (year int,age int,ethnic int,sex int,area text,count text);
COPY census FROM '.../Data8277.csv' WITH (FORMAT 'csv', HEADER true);

Profile:
# Samples: 59K of event 'cycles:u'
# Event count (approx.): 57644269486
#
# Overhead Command Shared Object Symbol
# ........ ........ ..................
.......................................
#
18.24% postgres postgres [.] CopyReadLine
9.23% postgres postgres [.] NextCopyFrom
8.87% postgres postgres [.] NextCopyFromRawFields
5.82% postgres postgres [.] pg_verify_mbstr_len
5.45% postgres postgres [.] pg_strtoint32
4.16% postgres postgres [.] heap_fill_tuple
4.03% postgres postgres [.] heap_compute_data_size
3.83% postgres postgres [.] CopyFrom
3.78% postgres postgres [.] AllocSetAlloc
3.53% postgres postgres [.] heap_form_tuple
2.96% postgres postgres [.] InputFunctionCall
2.89% postgres libc-2.30.so [.] __memmove_avx_unaligned_erms
1.82% postgres libc-2.30.so [.] __strlen_avx2
1.72% postgres postgres [.] AllocSetReset
1.72% postgres postgres [.] RelationPutHeapTuple
1.47% postgres postgres [.] heap_prepare_insert
1.31% postgres postgres [.] heap_multi_insert
1.25% postgres postgres [.] textin
1.24% postgres postgres [.] int4in
1.05% postgres postgres [.] tts_buffer_heap_clear
0.85% postgres postgres [.] pg_any_to_server
0.80% postgres postgres [.] pg_comp_crc32c_sse42
0.77% postgres postgres [.] cstring_to_text_with_len
0.69% postgres postgres [.] AllocSetFree
0.60% postgres postgres [.] appendBinaryStringInfo
0.55% postgres postgres [.] tts_buffer_heap_materialize.part.0
0.54% postgres postgres [.] palloc
0.54% postgres libc-2.30.so [.] __memmove_avx_unaligned
0.51% postgres postgres [.] palloc0
0.51% postgres postgres [.] pg_encoding_max_length
0.48% postgres postgres [.] enlargeStringInfo
0.47% postgres postgres [.] ExecStoreVirtualTuple
0.45% postgres postgres [.] PageAddItemExtended

So that confirms that the parsing is a huge chunk of overhead with
current splitting into lines being the largest portion. Amdahl's law
says that splitting into tuples needs to be made fast before
parallelizing makes any sense.

Regards,
Ants Aasma

[1]: https://www3.stats.govt.nz/2018census/Age-sex-by-ethnic-group-grouped-total-responses-census-usually-resident-population-counts-2006-2013-2018-Censuses-RC-TA-SA2-DHB.zip

#41Dilip Kumar
dilipbalaut@gmail.com
In reply to: Ants Aasma (#40)
Re: Parallel copy

On Wed, Feb 26, 2020 at 8:47 PM Ants Aasma <ants@cybertec.at> wrote:

On Tue, 25 Feb 2020 at 18:00, Tomas Vondra <tomas.vondra@2ndquadrant.com> wrote:

Perhaps. I guess it'll depend on the CSV file (number of fields, ...),
so I still think we need to do some measurements first. I'm willing to
do that, but (a) I doubt I'll have time for that until after 2020-03,
and (b) it'd be good to agree on some set of typical CSV files.

I agree that getting a nice varied dataset would be nice. Including
things like narrow integer only tables, strings with newlines and
escapes in them, extremely wide rows.

I tried to capture a quick profile just to see what it looks like.
Grabbed a random open data set from the web, about 800MB of narrow
rows CSV [1].

Script:
CREATE TABLE census (year int,age int,ethnic int,sex int,area text,count text);
COPY census FROM '.../Data8277.csv' WITH (FORMAT 'csv', HEADER true);

Profile:
# Samples: 59K of event 'cycles:u'
# Event count (approx.): 57644269486
#
# Overhead Command Shared Object Symbol
# ........ ........ ..................
.......................................
#
18.24% postgres postgres [.] CopyReadLine
9.23% postgres postgres [.] NextCopyFrom
8.87% postgres postgres [.] NextCopyFromRawFields
5.82% postgres postgres [.] pg_verify_mbstr_len
5.45% postgres postgres [.] pg_strtoint32
4.16% postgres postgres [.] heap_fill_tuple
4.03% postgres postgres [.] heap_compute_data_size
3.83% postgres postgres [.] CopyFrom
3.78% postgres postgres [.] AllocSetAlloc
3.53% postgres postgres [.] heap_form_tuple
2.96% postgres postgres [.] InputFunctionCall
2.89% postgres libc-2.30.so [.] __memmove_avx_unaligned_erms
1.82% postgres libc-2.30.so [.] __strlen_avx2
1.72% postgres postgres [.] AllocSetReset
1.72% postgres postgres [.] RelationPutHeapTuple
1.47% postgres postgres [.] heap_prepare_insert
1.31% postgres postgres [.] heap_multi_insert
1.25% postgres postgres [.] textin
1.24% postgres postgres [.] int4in
1.05% postgres postgres [.] tts_buffer_heap_clear
0.85% postgres postgres [.] pg_any_to_server
0.80% postgres postgres [.] pg_comp_crc32c_sse42
0.77% postgres postgres [.] cstring_to_text_with_len
0.69% postgres postgres [.] AllocSetFree
0.60% postgres postgres [.] appendBinaryStringInfo
0.55% postgres postgres [.] tts_buffer_heap_materialize.part.0
0.54% postgres postgres [.] palloc
0.54% postgres libc-2.30.so [.] __memmove_avx_unaligned
0.51% postgres postgres [.] palloc0
0.51% postgres postgres [.] pg_encoding_max_length
0.48% postgres postgres [.] enlargeStringInfo
0.47% postgres postgres [.] ExecStoreVirtualTuple
0.45% postgres postgres [.] PageAddItemExtended

So that confirms that the parsing is a huge chunk of overhead with
current splitting into lines being the largest portion. Amdahl's law
says that splitting into tuples needs to be made fast before
parallelizing makes any sense.

I have ran very simple case on table with 2 indexes and I can see a
lot of time is spent in index insertion. I agree that there is a good
amount of time spent in tokanizing but it is not very huge compared to
index insertion.

I have expanded the time spent in the CopyFrom function from my perf
report and pasted here. We can see that a lot of time is spent in
ExecInsertIndexTuples(77%). I agree that we need to further evaluate
that out of which how much is I/O vs CPU operations. But, the point I
want to make is that it's not true for all the cases that parsing is
taking maximum amout of time.

   - 99.50% CopyFrom
      - 82.90% CopyMultiInsertInfoFlush
         - 82.85% CopyMultiInsertBufferFlush
            + 77.68% ExecInsertIndexTuples
            + 3.74% table_multi_insert
            + 0.89% ExecClearTuple
      - 12.54% NextCopyFrom
         - 7.70% NextCopyFromRawFields
            - 5.72% CopyReadLine
                 3.96% CopyReadLineText
               + 1.49% pg_any_to_server
              1.86% CopyReadAttributesCSV
         + 3.68% InputFunctionCall
      + 2.11% ExecMaterializeSlot
      + 0.94% MemoryContextReset

My test:
-- Prepare:
CREATE TABLE t (a int, b int, c varchar);
insert into t select i,i, 'aaaaaaaaaaaaaaaaaaaaaaaa' from
generate_series(1,10000000) as i;
copy t to '/home/dilipkumar/a.csv' WITH (FORMAT 'csv', HEADER true);
truncate table t;
create index idx on t(a);
create index idx1 on t(c);

-- Test CopyFrom and measure with perf:
copy t from '/home/dilipkumar/a.csv' WITH (FORMAT 'csv', HEADER true);

--
Regards,
Dilip Kumar
EnterpriseDB: http://www.enterprisedb.com

#42vignesh C
vignesh21@gmail.com
In reply to: Amit Kapila (#38)
Re: Parallel copy

On Wed, Feb 26, 2020 at 4:24 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Tue, Feb 25, 2020 at 9:30 PM Tomas Vondra
<tomas.vondra@2ndquadrant.com> wrote:

On Sun, Feb 23, 2020 at 05:09:51PM -0800, Andres Freund wrote:

Hi,

The one piece of information I'm missing here is at least a very

rough

quantification of the individual steps of CSV processing - for

example

if parsing takes only 10% of the time, it's pretty pointless to

start by

parallelising this part and we should focus on the rest. If it's 50%

it

might be a different story. Has anyone done any measurements?

Not recently, but I'm pretty sure that I've observed CSV parsing to be
way more than 10%.

Perhaps. I guess it'll depend on the CSV file (number of fields, ...),
so I still think we need to do some measurements first.

Agreed.

I'm willing to
do that, but (a) I doubt I'll have time for that until after 2020-03,
and (b) it'd be good to agree on some set of typical CSV files.

Right, I don't know what is the best way to define that. I can think
of the below tests.

1. A table with 10 columns (with datatypes as integers, date, text).
It has one index (unique/primary). Load with 1 million rows (basically
the data should be probably 5-10 GB).
2. A table with 10 columns (with datatypes as integers, date, text).
It has three indexes, one index can be (unique/primary). Load with 1
million rows (basically the data should be probably 5-10 GB).
3. A table with 10 columns (with datatypes as integers, date, text).
It has three indexes, one index can be (unique/primary). It has before
and after trigeers. Load with 1 million rows (basically the data
should be probably 5-10 GB).
4. A table with 10 columns (with datatypes as integers, date, text).
It has five or six indexes, one index can be (unique/primary). Load
with 1 million rows (basically the data should be probably 5-10 GB).

I have tried to capture the execution time taken for 3 scenarios which I
felt could give a fair idea:
Test1 (Table with 3 indexes and 1 trigger)
Test2 (Table with 2 indexes)
Test3 (Table without indexes/triggers)

I have captured the following details:
File Read time - time taken to read the file from CopyGetData function.
Read line Time - time taken to read line from NextCopyFrom function(read
time & tokenise time excluded)
Tokenize Time - time taken to tokenize the contents from
NextCopyFromRawFields function.
Data Execution Time - remaining execution time from the total time

The execution breakdown for the tests are given below:
Test/ Time(In Seconds) Total Time File Read Time Read line /Buffer
Read Time Tokenize
Time Data Execution Time
Test1 1693.369 0.256 34.173 5.578 1653.362
Test2 736.096 0.288 39.762 6.525 689.521
Test3 112.06 0.266 39.189 6.433 66.172
Steps for the scenarios:
Test1(Table with 3 indexes and 1 trigger):
CREATE TABLE census2 (year int,age int,ethnic int,sex int,area text,count
text);
CREATE TABLE census3(year int,age int,ethnic int,sex int,area text,count
text);

CREATE INDEX idx1_census2 on census2(year);
CREATE INDEX idx2_census2 on census2(age);
CREATE INDEX idx2_census2 on census2(ethnic);

CREATE or REPLACE FUNCTION census2_afterinsert()
RETURNS TRIGGER
AS $$
BEGIN
INSERT INTO census3 SELECT * FROM census2 limit 1;
RETURN NEW;
END;
$$
LANGUAGE plpgsql;

CREATE TRIGGER census2_trigger AFTER INSERT ON census2 FOR EACH ROW
EXECUTE PROCEDURE census2_afterinsert();
COPY census2 FROM 'Data8277.csv' WITH (FORMAT 'csv', HEADER true);

Test2 (Table with 2 indexes):
CREATE TABLE census1 (year int,age int,ethnic int,sex int,area text,count
text);
CREATE INDEX idx1_census1 on census1(year);
CREATE INDEX idx2_census1 on census1(age);
COPY census1 FROM 'Data8277.csv' WITH (FORMAT 'csv', HEADER true);

Test3 (Table without indexes/triggers):
CREATE TABLE census (year int,age int,ethnic int,sex int,area text,count
text);
COPY census FROM 'Data8277.csv' WITH (FORMAT 'csv', HEADER true);

Note: The Data8277.csv used was the same data that Ants aasma had used.

From the above result we could infer that Read line will have to be done
sequentially. Read line time takes about 2.01%, 5.40% and 34.97%of the
total time. I felt we will be able to parallelise the remaining phases of
the copy. The performance improvement will vary based on the
scenario(indexes/triggers), it will be proportionate to the number of
indexes and triggers. Read line can also be parallelised in txt format(non
csv). I feel parallelising copy could give significant improvement in quite
some scenarios.

Further I'm planning to see how the execution will be for toast table. I'm
also planning to do test on RAM disk where I will configure the data on RAM
disk, so that we can further eliminate the I/O cost.

Thoughts?

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

#43vignesh C
vignesh21@gmail.com
In reply to: Ants Aasma (#40)
Re: Parallel copy

On Wed, Feb 26, 2020 at 8:47 PM Ants Aasma <ants@cybertec.at> wrote:

On Tue, 25 Feb 2020 at 18:00, Tomas Vondra <tomas.vondra@2ndquadrant.com>

wrote:

Perhaps. I guess it'll depend on the CSV file (number of fields, ...),
so I still think we need to do some measurements first. I'm willing to
do that, but (a) I doubt I'll have time for that until after 2020-03,
and (b) it'd be good to agree on some set of typical CSV files.

I agree that getting a nice varied dataset would be nice. Including
things like narrow integer only tables, strings with newlines and
escapes in them, extremely wide rows.

I tried to capture a quick profile just to see what it looks like.
Grabbed a random open data set from the web, about 800MB of narrow
rows CSV [1].

Script:
CREATE TABLE census (year int,age int,ethnic int,sex int,area text,count

text);

COPY census FROM '.../Data8277.csv' WITH (FORMAT 'csv', HEADER true);

Profile:
# Samples: 59K of event 'cycles:u'
# Event count (approx.): 57644269486
#
# Overhead Command Shared Object Symbol
# ........ ........ ..................
.......................................
#
18.24% postgres postgres [.] CopyReadLine
9.23% postgres postgres [.] NextCopyFrom
8.87% postgres postgres [.] NextCopyFromRawFields
5.82% postgres postgres [.] pg_verify_mbstr_len
5.45% postgres postgres [.] pg_strtoint32
4.16% postgres postgres [.] heap_fill_tuple
4.03% postgres postgres [.] heap_compute_data_size
3.83% postgres postgres [.] CopyFrom
3.78% postgres postgres [.] AllocSetAlloc
3.53% postgres postgres [.] heap_form_tuple
2.96% postgres postgres [.] InputFunctionCall
2.89% postgres libc-2.30.so [.] __memmove_avx_unaligned_erms
1.82% postgres libc-2.30.so [.] __strlen_avx2
1.72% postgres postgres [.] AllocSetReset
1.72% postgres postgres [.] RelationPutHeapTuple
1.47% postgres postgres [.] heap_prepare_insert
1.31% postgres postgres [.] heap_multi_insert
1.25% postgres postgres [.] textin
1.24% postgres postgres [.] int4in
1.05% postgres postgres [.] tts_buffer_heap_clear
0.85% postgres postgres [.] pg_any_to_server
0.80% postgres postgres [.] pg_comp_crc32c_sse42
0.77% postgres postgres [.] cstring_to_text_with_len
0.69% postgres postgres [.] AllocSetFree
0.60% postgres postgres [.] appendBinaryStringInfo
0.55% postgres postgres [.]

tts_buffer_heap_materialize.part.0

0.54% postgres postgres [.] palloc
0.54% postgres libc-2.30.so [.] __memmove_avx_unaligned
0.51% postgres postgres [.] palloc0
0.51% postgres postgres [.] pg_encoding_max_length
0.48% postgres postgres [.] enlargeStringInfo
0.47% postgres postgres [.] ExecStoreVirtualTuple
0.45% postgres postgres [.] PageAddItemExtended

So that confirms that the parsing is a huge chunk of overhead with
current splitting into lines being the largest portion. Amdahl's law
says that splitting into tuples needs to be made fast before
parallelizing makes any sense.

I had taken perf report with the same test data that you had used, I was
getting the following results:
.....
+   99.61%     0.00%  postgres  postgres            [.] PortalRun
+   99.61%     0.00%  postgres  postgres            [.] PortalRunMulti
+   99.61%     0.00%  postgres  postgres            [.] PortalRunUtility
+   99.61%     0.00%  postgres  postgres            [.] ProcessUtility
+   99.61%     0.00%  postgres  postgres            [.]
standard_ProcessUtility
+   99.61%     0.00%  postgres  postgres            [.] DoCopy
+   99.30%     0.94%  postgres  postgres            [.] CopyFrom
+   51.61%     7.76%  postgres  postgres            [.] NextCopyFrom
+   23.66%     0.01%  postgres  postgres            [.]
CopyMultiInsertInfoFlush
+   23.61%     0.28%  postgres  postgres            [.]
CopyMultiInsertBufferFlush
+   21.99%     1.02%  postgres  postgres            [.]
NextCopyFromRawFields

*+ 19.79% 0.01% postgres postgres [.]
table_multi_insert+ 19.32% 3.00% postgres postgres [.]
heap_multi_insert*+ 18.27% 2.44% postgres postgres [.]
InputFunctionCall

*+   15.19%     0.89%  postgres  postgres            [.] CopyReadLine*+
13.05%     0.18%  postgres  postgres            [.] ExecMaterializeSlot
+   13.00%     0.55%  postgres  postgres            [.]
tts_buffer_heap_materialize
+   12.31%     1.77%  postgres  postgres            [.] heap_form_tuple
+   10.43%     0.45%  postgres  postgres            [.] int4in
+   10.18%     8.92%  postgres  postgres            [.] CopyReadLineText
......

In my results I observed execution table_multi_insert was nearly 20%. Also
I felt like once we have made few tuples from CopyReadLine, the parallel
workers should be able to start consuming the data and process the data. We
need not wait for the complete tokenisation to be finished. Once few tuples
are tokenised parallel workers should start consuming the data parallelly
and tokenisation should happen simultaneously. In this way once the copy is
done parallelly total execution time should be CopyReadLine Time + delta
processing time.

Thoughts?

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

#44vignesh C
vignesh21@gmail.com
In reply to: vignesh C (#43)
1 attachment(s)
Re: Parallel copy

I have got the execution breakdown for few scenarios with normal disk and
RAM disk.

*Execution breakup in Normal disk:*
Test/ Time(In Seconds)
Total TIme File Read Time copyreadline Time
Remaining
Execution Time Read line percentage
Test1(3 index + 1 trigger) 2099.017 0.311 10.256 2088.45 0.4886096682
Test2(2 index) 657.994 0.303 10.171 647.52 1.545758776
Test3(no index, no trigger) 112.41 0.296 10.996 101.118 9.782047861
Test4(toast) 360.028 1.43 46.556 312.042 12.93121646

*Execution breakup in RAM disk:*
Test/ Time(In Seconds)
Total TIme File Read Time copyreadline Time
Remaining
Execution Time Read line percentage
Test1(3 index + 1 trigger) 1571.558 0.259 6.986 1564.313 0.4445270235
Test2(2 index) 369.942 0.263 6.848 362.831 1.851100983
Test3(no index, no trigger) 54.077 0.239 6.805 47.033 12.58390813
Test4(toast) 96.323 0.918 26.603 68.802 27.61853348

Steps for the scenarios:
*Test1(Table with 3 indexes and 1 trigger):*

*CREATE TABLE census2 (year int,age int,ethnic int,sex int,area text,count
text);CREATE TABLE census3(year int,age int,ethnic int,sex int,area
text,count text);CREATE INDEX idx1_census2 on census2(year);CREATE INDEX
idx2_census2 on census2(age);CREATE INDEX idx3_census2 on
census2(ethnic);CREATE or REPLACE FUNCTION census2_afterinsert()RETURNS
TRIGGERAS $$BEGIN INSERT INTO census3 SELECT * FROM census2 limit 1;
RETURN NEW;END;$$LANGUAGE plpgsql;CREATE TRIGGER census2_trigger AFTER
INSERT ON census2 FOR EACH ROW EXECUTE PROCEDURE
census2_afterinsert();COPY census2 FROM 'Data8277.csv' WITH (FORMAT 'csv',
HEADER true);*

*Test2 (Table with 2 indexes):*

*CREATE TABLE census1 (year int,age int,ethnic int,sex int,area text,count
text);CREATE INDEX idx1_census1 on census1(year);CREATE INDEX idx2_census1
on census1(age);COPY census1 FROM 'Data8277.csv' WITH (FORMAT 'csv', HEADER
true);*

*Test3 (Table without indexes/triggers):*

*CREATE TABLE census (year int,age int,ethnic int,sex int,area text,count
text);COPY census FROM 'Data8277.csv' WITH (FORMAT 'csv', HEADER true);*

*Random open data set from the web, about 800MB of narrow rows CSV [1] was
used in the above tests, the same which Ants Aasma had used.*

*Test4 (Toast table):*

*CREATE TABLE indtoasttest(descr text, cnt int DEFAULT 0, f1 text, f2
text);alter table indtoasttest alter column f1 set storage external;alter
table indtoasttest alter column f2 set storage external;inserted 262144
recordscopy indtoasttest to
'/mnt/magnetic/vignesh.c/postgres/toast_data3.csv' WITH (FORMAT 'csv',
HEADER true);CREATE TABLE indtoasttest1(descr text, cnt int DEFAULT 0, f1
text, f2 text);alter table indtoasttest1 alter column f1 set storage
external;alter table indtoasttest1 alter column f2 set storage
external;copy indtoasttest1 from
'/mnt/magnetic/vignesh.c/postgres/toast_data3.csv' WITH (FORMAT 'csv',
HEADER true);*

We could infer that Read line Time cannot be parallelized, this is mainly
because if the data has quote present we will not be able to differentiate
if it is part of previous record or it is part of current record. The rest
of the execution time can be parallelized. Read line Time takes about 0.5%,
1.5%, 9.8% & 12.9% of the total time. We could parallelize the remaining
phases of the copy. The performance improvement will vary based on the
scenario(indexes/triggers), it will be proportionate to the number of
indexes and triggers. Read line can also be parallelized in txt format(non
csv). We feel parallelize copy could give significant improvement in many
scenarios.

Attached patch for reference which was used to capture the execution time
breakup.

Thoughts?

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

On Tue, Mar 3, 2020 at 11:44 AM vignesh C <vignesh21@gmail.com> wrote:

Show quoted text

On Wed, Feb 26, 2020 at 8:47 PM Ants Aasma <ants@cybertec.at> wrote:

On Tue, 25 Feb 2020 at 18:00, Tomas Vondra <tomas.vondra@2ndquadrant.com>

wrote:

Perhaps. I guess it'll depend on the CSV file (number of fields, ...),
so I still think we need to do some measurements first. I'm willing to
do that, but (a) I doubt I'll have time for that until after 2020-03,
and (b) it'd be good to agree on some set of typical CSV files.

I agree that getting a nice varied dataset would be nice. Including
things like narrow integer only tables, strings with newlines and
escapes in them, extremely wide rows.

I tried to capture a quick profile just to see what it looks like.
Grabbed a random open data set from the web, about 800MB of narrow
rows CSV [1].

Script:
CREATE TABLE census (year int,age int,ethnic int,sex int,area text,count

text);

COPY census FROM '.../Data8277.csv' WITH (FORMAT 'csv', HEADER true);

Profile:
# Samples: 59K of event 'cycles:u'
# Event count (approx.): 57644269486
#
# Overhead Command Shared Object Symbol
# ........ ........ ..................
.......................................
#
18.24% postgres postgres [.] CopyReadLine
9.23% postgres postgres [.] NextCopyFrom
8.87% postgres postgres [.] NextCopyFromRawFields
5.82% postgres postgres [.] pg_verify_mbstr_len
5.45% postgres postgres [.] pg_strtoint32
4.16% postgres postgres [.] heap_fill_tuple
4.03% postgres postgres [.] heap_compute_data_size
3.83% postgres postgres [.] CopyFrom
3.78% postgres postgres [.] AllocSetAlloc
3.53% postgres postgres [.] heap_form_tuple
2.96% postgres postgres [.] InputFunctionCall
2.89% postgres libc-2.30.so [.]

__memmove_avx_unaligned_erms

1.82% postgres libc-2.30.so [.] __strlen_avx2
1.72% postgres postgres [.] AllocSetReset
1.72% postgres postgres [.] RelationPutHeapTuple
1.47% postgres postgres [.] heap_prepare_insert
1.31% postgres postgres [.] heap_multi_insert
1.25% postgres postgres [.] textin
1.24% postgres postgres [.] int4in
1.05% postgres postgres [.] tts_buffer_heap_clear
0.85% postgres postgres [.] pg_any_to_server
0.80% postgres postgres [.] pg_comp_crc32c_sse42
0.77% postgres postgres [.] cstring_to_text_with_len
0.69% postgres postgres [.] AllocSetFree
0.60% postgres postgres [.] appendBinaryStringInfo
0.55% postgres postgres [.]

tts_buffer_heap_materialize.part.0

0.54% postgres postgres [.] palloc
0.54% postgres libc-2.30.so [.] __memmove_avx_unaligned
0.51% postgres postgres [.] palloc0
0.51% postgres postgres [.] pg_encoding_max_length
0.48% postgres postgres [.] enlargeStringInfo
0.47% postgres postgres [.] ExecStoreVirtualTuple
0.45% postgres postgres [.] PageAddItemExtended

So that confirms that the parsing is a huge chunk of overhead with
current splitting into lines being the largest portion. Amdahl's law
says that splitting into tuples needs to be made fast before
parallelizing makes any sense.

I had taken perf report with the same test data that you had used, I was
getting the following results:
.....
+   99.61%     0.00%  postgres  postgres            [.] PortalRun
+   99.61%     0.00%  postgres  postgres            [.] PortalRunMulti
+   99.61%     0.00%  postgres  postgres            [.] PortalRunUtility
+   99.61%     0.00%  postgres  postgres            [.] ProcessUtility
+   99.61%     0.00%  postgres  postgres            [.]
standard_ProcessUtility
+   99.61%     0.00%  postgres  postgres            [.] DoCopy
+   99.30%     0.94%  postgres  postgres            [.] CopyFrom
+   51.61%     7.76%  postgres  postgres            [.] NextCopyFrom
+   23.66%     0.01%  postgres  postgres            [.]
CopyMultiInsertInfoFlush
+   23.61%     0.28%  postgres  postgres            [.]
CopyMultiInsertBufferFlush
+   21.99%     1.02%  postgres  postgres            [.]
NextCopyFromRawFields

*+ 19.79% 0.01% postgres postgres [.]
table_multi_insert+ 19.32% 3.00% postgres postgres [.]
heap_multi_insert*+ 18.27% 2.44% postgres postgres [.]
InputFunctionCall

*+   15.19%     0.89%  postgres  postgres            [.] CopyReadLine*+
13.05%     0.18%  postgres  postgres            [.] ExecMaterializeSlot
+   13.00%     0.55%  postgres  postgres            [.]
tts_buffer_heap_materialize
+   12.31%     1.77%  postgres  postgres            [.] heap_form_tuple
+   10.43%     0.45%  postgres  postgres            [.] int4in
+   10.18%     8.92%  postgres  postgres            [.] CopyReadLineText
......

In my results I observed execution table_multi_insert was nearly 20%. Also
I felt like once we have made few tuples from CopyReadLine, the parallel
workers should be able to start consuming the data and process the data. We
need not wait for the complete tokenisation to be finished. Once few tuples
are tokenised parallel workers should start consuming the data parallelly
and tokenisation should happen simultaneously. In this way once the copy is
done parallelly total execution time should be CopyReadLine Time + delta
processing time.

Thoughts?

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

Attachments:

copy_execution_time_v2.patchtext/x-patch; charset=US-ASCII; name=copy_execution_time_v2.patchDownload
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index e79ede4..ea0cc6e 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -61,6 +61,8 @@
 #define ISOCTAL(c) (((c) >= '0') && ((c) <= '7'))
 #define OCTVALUE(c) ((c) - '0')
 
+double copyreadlineTime, readTime, totalTime;
+
 /*
  * Represents the different source/dest cases we need to worry about at
  * the bottom level
@@ -610,10 +612,12 @@ static int
 CopyGetData(CopyState cstate, void *databuf, int minread, int maxread)
 {
 	int			bytesread = 0;
-
+	struct timespec before, after;
 	switch (cstate->copy_dest)
 	{
 		case COPY_FILE:
+			INSTR_TIME_SET_CURRENT(before);
+
 			bytesread = fread(databuf, 1, maxread, cstate->copy_file);
 			if (ferror(cstate->copy_file))
 				ereport(ERROR,
@@ -621,6 +625,10 @@ CopyGetData(CopyState cstate, void *databuf, int minread, int maxread)
 						 errmsg("could not read from COPY file: %m")));
 			if (bytesread == 0)
 				cstate->reached_eof = true;
+
+			INSTR_TIME_SET_CURRENT(after);
+			INSTR_TIME_SUBTRACT(after, before);
+			readTime += INSTR_TIME_GET_MILLISEC(after);
 			break;
 		case COPY_OLD_FE:
 
@@ -1059,8 +1067,15 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 
 	if (is_from)
 	{
+		struct timespec before, after;
+		INSTR_TIME_SET_CURRENT(before);
 		Assert(rel);
 
+		/* Reset the variables before every copy operation */
+		readTime = 0;
+		copyreadlineTime = 0;
+		totalTime = 0;
+
 		/* check read-only transaction and parallel mode */
 		if (XactReadOnly && !rel->rd_islocaltemp)
 			PreventCommandIfReadOnly("COPY FROM");
@@ -1070,6 +1085,22 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 		cstate->whereClause = whereClause;
 		*processed = CopyFrom(cstate);	/* copy from file to database */
 		EndCopyFrom(cstate);
+
+		INSTR_TIME_SET_CURRENT(after);
+		INSTR_TIME_SUBTRACT(after, before);
+		totalTime += INSTR_TIME_GET_MILLISEC(after);
+
+		elog(LOG, "Total file read time for copying operation : %.3f ms\n",
+				readTime);
+
+		/* Read time is included in copyreadlinetime*/
+		elog(LOG, "Total copyreadline time for copying operation: %.3f ms\n",
+				copyreadlineTime - readTime);
+
+		elog(LOG, "Remaining execution time for copying operation: %.3f ms\n",
+				totalTime - copyreadlineTime);
+		elog(LOG, "Total time for copying: %.3f ms\n", totalTime);
+
 	}
 	else
 	{
@@ -3890,12 +3921,14 @@ static bool
 CopyReadLine(CopyState cstate)
 {
 	bool		result;
+	struct timespec before, after;
 
 	resetStringInfo(&cstate->line_buf);
 	cstate->line_buf_valid = true;
 
 	/* Mark that encoding conversion hasn't occurred yet */
 	cstate->line_buf_converted = false;
+	INSTR_TIME_SET_CURRENT(before);
 
 	/* Parse data and transfer into line_buf */
 	result = CopyReadLineText(cstate);
@@ -3949,6 +3982,10 @@ CopyReadLine(CopyState cstate)
 		}
 	}
 
+	INSTR_TIME_SET_CURRENT(after);
+	INSTR_TIME_SUBTRACT(after, before);
+	copyreadlineTime += INSTR_TIME_GET_MILLISEC(after);
+
 	/* Done reading the line.  Convert it to server encoding. */
 	if (cstate->need_transcoding)
 	{
#45vignesh C
vignesh21@gmail.com
In reply to: vignesh C (#44)
Re: Parallel copy

On Thu, Mar 12, 2020 at 6:39 PM vignesh C <vignesh21@gmail.com> wrote:

Existing parallel copy code flow. Copy supports copy operation from
csv, txt & bin format file. For processing csv & text format, it will
read 64kb chunk or lesser size if in case the file has lesser size
contents in the input file. Server will then read one tuple of data
and do the processing of the tuple. If the above tuple that is
generated was less than 64kb data, then the server will try to
generate another tuple for processing from the remaining unprocessed
data. If it is not able to generate one tuple from the unprocessed
data it will do a further 64kb data read or lesser remaining size that
is present in the file and send the tuple for processing. This process
is repeated till the complete file is processed. For processing bin
format file the flow is slightly different. Server will read the
number of columns that are present. Then read the column size data and
then read the actual column contents, repeat this for all the columns.
Server will then process the tuple that is generated. This process is
repeated for all the remaining tuples in the bin file. The tuple
processing flow is the same in all the formats. Currently all the
operations happen sequentially. This project will help in
parallelizing the copy operation.

I'm planning to do the POC of parallel copy with the below design:
Proposed Syntax:
COPY table_name FROM ‘copy_file' WITH (FORMAT ‘format’, PARALLEL ‘workers’);
Users can specify the number of workers that must be used for copying
the data in parallel. Here ‘workers’ is the number of workers that
must be used for parallel copy operation apart from the leader. Leader
is responsible for reading the data from the input file and generating
the work for the workers. Leader will start a transaction and share
this transaction with the workers. All workers will be using the same
transaction to insert the records. Leader will create a circular queue
and share it across the workers. The circular queue will be present in
DSM. Leader will be using a fixed size queue to share the contents
between the leader and the workers. Currently we will have 100
elements present in the queue. This will be created before the workers
are started and shared with the workers. The data structures that are
required by the parallel workers will be initialized by the leader,
the size required in dsm will be calculated and the necessary keys
will be loaded in the DSM. The specified number of workers will then
be launched. Leader will read the table data from the file and copy
the contents to the queue element by element. Each element in the
queue will have 64K size DSA. This DSA will be used to store tuple
contents from the file. The leader will try to copy as much content as
possible within one 64K DSA queue element. We intend to store at least
one tuple in each queue element. There are some cases where the 64K
space may not be enough to store a single tuple. Mostly in cases where
the table has toast data present and the single tuple can be more than
64K size. In these scenarios we will extend the DSA space accordingly.
We cannot change the size of the dsm once the workers are launched.
Whereas in case of DSA we can free the dsa pointer and reallocate the
dsa pointer based on the memory size required. This is the very reason
for choosing DSA over DSM for storing the data that must be inserted
into the relation. Leader will keep on loading the data into the queue
till the queue becomes full. Leader will transform his role into a
worker either when the Queue is full or the Complete file is
processed. Once the queue is full, the leader will switch its role to
become a worker, then the leader will continue to act as worker till
25% of the elements in the queue is consumed by all the workers. Once
there is at least 25% space available in the queue leader who was
working as a worker will switch its role back to become the leader
again. The above process of filling the queue will be continued by the
leader until the whole file is processed. Leader will wait until the
respective workers finish processing the queue elements. The copy from
functionality is also being used during initdb operations where the
copy is intended to be performed in single mode or the user can still
continue running in non-parallel mode. In case of non parallel mode,
memory allocation will happen using palloc instead of DSM/DSA and most
of the flow will be the same in both parallel and non parallel cases.

We had a couple of options for the way in which queue elements can be stored.
Option 1: Each element (DSA chunk) will contain tuples such that each
tuple will be preceded by the length of the tuple. So the tuples will
be arranged like (Length of tuple-1, tuple-1), (Length of tuple-2,
tuple-2), .... Or Option 2: Each element (DSA chunk) will contain only
tuples (tuple-1), (tuple-2), ..... And we will have a second
ring-buffer which contains a start-offset or length of each tuple. The
old design used to generate one tuple of data and process tuple by
tuple. In the new design, the server will generate multiple tuples of
data per queue element. The worker will then process data tuple by
tuple. As we are processing the data tuple by tuple, I felt both of
the options are almost the same. However Design1 was chosen over
Design 2 as we can save up on some space that was required by another
variable in each element of the queue.

The parallel workers will read the tuples from the queue and do the
following operations, all of these operations: a) where clause
handling, b) convert tuple to columns, c) add default null values for
the missing columns that are not present in that record, d) find the
partition if it is partitioned table, e) before row insert Triggers,
constraints f) insertion of the data. Rest of the flow is the same as
the existing code.

Enhancements after POC is done:
Initially we plan to use the number of workers based on the worker
count user has specified, Later we will do some experiments and think
of an approach to choose workers automatically after processing sample
contents from the file.
Initially we plan to use 100 elements in the queue, Later we will
experiment to find the right size for the queue once the basic patch
is ready.
Initially we plan to generate the transaction from the leader and
share it across to the workers. Later we will change this in such a
way that the first process that will do an insert operation will
generate the transaction and share it with the rest of them.

Thoughts?

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

#46Ants Aasma
ants@cybertec.at
In reply to: vignesh C (#45)
Re: Parallel copy

On Tue, 7 Apr 2020 at 08:24, vignesh C <vignesh21@gmail.com> wrote:

Leader will create a circular queue
and share it across the workers. The circular queue will be present in
DSM. Leader will be using a fixed size queue to share the contents
between the leader and the workers. Currently we will have 100
elements present in the queue. This will be created before the workers
are started and shared with the workers. The data structures that are
required by the parallel workers will be initialized by the leader,
the size required in dsm will be calculated and the necessary keys
will be loaded in the DSM. The specified number of workers will then
be launched. Leader will read the table data from the file and copy
the contents to the queue element by element. Each element in the
queue will have 64K size DSA. This DSA will be used to store tuple
contents from the file. The leader will try to copy as much content as
possible within one 64K DSA queue element. We intend to store at least
one tuple in each queue element. There are some cases where the 64K
space may not be enough to store a single tuple. Mostly in cases where
the table has toast data present and the single tuple can be more than
64K size. In these scenarios we will extend the DSA space accordingly.
We cannot change the size of the dsm once the workers are launched.
Whereas in case of DSA we can free the dsa pointer and reallocate the
dsa pointer based on the memory size required. This is the very reason
for choosing DSA over DSM for storing the data that must be inserted
into the relation.

I think the element based approach and requirement that all tuples fit
into the queue makes things unnecessarily complex. The approach I
detailed earlier allows for tuples to be bigger than the buffer. In
that case a worker will claim the long tuple from the ring queue of
tuple start positions, and starts copying it into its local line_buf.
This can wrap around the buffer multiple times until the next start
position shows up. At that point this worker can proceed with
inserting the tuple and the next worker will claim the next tuple.

This way nothing needs to be resized, there is no risk of a file with
huge tuples running the system out of memory because each element will
be reallocated to be huge and the number of elements is not something
that has to be tuned.

We had a couple of options for the way in which queue elements can be stored.
Option 1: Each element (DSA chunk) will contain tuples such that each
tuple will be preceded by the length of the tuple. So the tuples will
be arranged like (Length of tuple-1, tuple-1), (Length of tuple-2,
tuple-2), .... Or Option 2: Each element (DSA chunk) will contain only
tuples (tuple-1), (tuple-2), ..... And we will have a second
ring-buffer which contains a start-offset or length of each tuple. The
old design used to generate one tuple of data and process tuple by
tuple. In the new design, the server will generate multiple tuples of
data per queue element. The worker will then process data tuple by
tuple. As we are processing the data tuple by tuple, I felt both of
the options are almost the same. However Design1 was chosen over
Design 2 as we can save up on some space that was required by another
variable in each element of the queue.

With option 1 it's not possible to read input data into shared memory
and there needs to be an extra memcpy in the time critical sequential
flow of the leader. With option 2 data could be read directly into the
shared memory buffer. With future async io support, reading and
looking for tuple boundaries could be performed concurrently.

Regards,
Ants Aasma
Cybertec

#47Amit Kapila
amit.kapila16@gmail.com
In reply to: Ants Aasma (#46)
Re: Parallel copy

On Tue, Apr 7, 2020 at 7:08 PM Ants Aasma <ants@cybertec.at> wrote:

On Tue, 7 Apr 2020 at 08:24, vignesh C <vignesh21@gmail.com> wrote:

Leader will create a circular queue
and share it across the workers. The circular queue will be present in
DSM. Leader will be using a fixed size queue to share the contents
between the leader and the workers. Currently we will have 100
elements present in the queue. This will be created before the workers
are started and shared with the workers. The data structures that are
required by the parallel workers will be initialized by the leader,
the size required in dsm will be calculated and the necessary keys
will be loaded in the DSM. The specified number of workers will then
be launched. Leader will read the table data from the file and copy
the contents to the queue element by element. Each element in the
queue will have 64K size DSA. This DSA will be used to store tuple
contents from the file. The leader will try to copy as much content as
possible within one 64K DSA queue element. We intend to store at least
one tuple in each queue element. There are some cases where the 64K
space may not be enough to store a single tuple. Mostly in cases where
the table has toast data present and the single tuple can be more than
64K size. In these scenarios we will extend the DSA space accordingly.
We cannot change the size of the dsm once the workers are launched.
Whereas in case of DSA we can free the dsa pointer and reallocate the
dsa pointer based on the memory size required. This is the very reason
for choosing DSA over DSM for storing the data that must be inserted
into the relation.

I think the element based approach and requirement that all tuples fit
into the queue makes things unnecessarily complex. The approach I
detailed earlier allows for tuples to be bigger than the buffer. In
that case a worker will claim the long tuple from the ring queue of
tuple start positions, and starts copying it into its local line_buf.
This can wrap around the buffer multiple times until the next start
position shows up. At that point this worker can proceed with
inserting the tuple and the next worker will claim the next tuple.

IIUC, with the fixed size buffer, the parallelism might hit a bit
because till the worker copies the data from shared buffer to local
buffer the reader process won't be able to continue. I think there
will be somewhat more leader-worker coordination is required with the
fixed buffer size. However, as you pointed out, we can't allow it to
increase it to max_size possible for all tuples as that might require
a lot of memory. One idea could be that we allow it for first any
such tuple and then if any other element/chunk in the queue required
more memory than the default 64KB, then we will always fallback to use
the memory we have allocated for first chunk. This will allow us to
not use more memory except for one tuple and won't hit parallelism
much as in many cases not all tuples will be so large.

I think in the proposed approach queue element is nothing but a way to
divide the work among workers based on size rather than based on
number of tuples. Say if we try to divide the work among workers
based on start offsets, it can be more tricky. Because it could lead
to either a lot of contentention if we choose say one offset
per-worker (basically copy the data for one tuple, process it and then
pick next tuple) or probably unequal division of work because some can
be smaller and others can be bigger. I guess division based on size
would be a better idea. OTOH, I see the advantage of your approach as
well and I will think more on it.

We had a couple of options for the way in which queue elements can be stored.
Option 1: Each element (DSA chunk) will contain tuples such that each
tuple will be preceded by the length of the tuple. So the tuples will
be arranged like (Length of tuple-1, tuple-1), (Length of tuple-2,
tuple-2), .... Or Option 2: Each element (DSA chunk) will contain only
tuples (tuple-1), (tuple-2), ..... And we will have a second
ring-buffer which contains a start-offset or length of each tuple. The
old design used to generate one tuple of data and process tuple by
tuple. In the new design, the server will generate multiple tuples of
data per queue element. The worker will then process data tuple by
tuple. As we are processing the data tuple by tuple, I felt both of
the options are almost the same. However Design1 was chosen over
Design 2 as we can save up on some space that was required by another
variable in each element of the queue.

With option 1 it's not possible to read input data into shared memory
and there needs to be an extra memcpy in the time critical sequential
flow of the leader. With option 2 data could be read directly into the
shared memory buffer. With future async io support, reading and
looking for tuple boundaries could be performed concurrently.

Yeah, option-2 sounds better.

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#48Robert Haas
robertmhaas@gmail.com
In reply to: Ants Aasma (#46)
Re: Parallel copy

On Tue, Apr 7, 2020 at 9:38 AM Ants Aasma <ants@cybertec.at> wrote:

I think the element based approach and requirement that all tuples fit
into the queue makes things unnecessarily complex. The approach I
detailed earlier allows for tuples to be bigger than the buffer. In
that case a worker will claim the long tuple from the ring queue of
tuple start positions, and starts copying it into its local line_buf.
This can wrap around the buffer multiple times until the next start
position shows up. At that point this worker can proceed with
inserting the tuple and the next worker will claim the next tuple.

This way nothing needs to be resized, there is no risk of a file with
huge tuples running the system out of memory because each element will
be reallocated to be huge and the number of elements is not something
that has to be tuned.

+1. This seems like the right way to do it.

We had a couple of options for the way in which queue elements can be stored.
Option 1: Each element (DSA chunk) will contain tuples such that each
tuple will be preceded by the length of the tuple. So the tuples will
be arranged like (Length of tuple-1, tuple-1), (Length of tuple-2,
tuple-2), .... Or Option 2: Each element (DSA chunk) will contain only
tuples (tuple-1), (tuple-2), ..... And we will have a second
ring-buffer which contains a start-offset or length of each tuple. The
old design used to generate one tuple of data and process tuple by
tuple. In the new design, the server will generate multiple tuples of
data per queue element. The worker will then process data tuple by
tuple. As we are processing the data tuple by tuple, I felt both of
the options are almost the same. However Design1 was chosen over
Design 2 as we can save up on some space that was required by another
variable in each element of the queue.

With option 1 it's not possible to read input data into shared memory
and there needs to be an extra memcpy in the time critical sequential
flow of the leader. With option 2 data could be read directly into the
shared memory buffer. With future async io support, reading and
looking for tuple boundaries could be performed concurrently.

But option 2 still seems significantly worse than your proposal above, right?

I really think we don't want a single worker in charge of finding
tuple boundaries for everybody. That adds a lot of unnecessary
inter-process communication and synchronization. Each process should
just get the next tuple starting after where the last one ended, and
then advance the end pointer so that the next process can do the same
thing. Vignesh's proposal involves having a leader process that has to
switch roles - he picks an arbitrary 25% threshold - and if it doesn't
switch roles at the right time, performance will be impacted. If the
leader doesn't get scheduled in time to refill the queue before it
runs completely empty, workers will have to wait. Ants's scheme avoids
that risk: whoever needs the next tuple reads the next line. There's
no need to ever wait for the leader because there is no leader.

I think it's worth enumerating some of the other ways that a project
in this area can fail to achieve good speedups, so that we can try to
avoid those that are avoidable and be aware of the others:

- If we're unable to supply data to the COPY process as fast as the
workers could load it, then speed will be limited at that point. We
know reading the file from disk is pretty fast compared to what a
single process can do. I'm not sure we've tested what happens with a
network socket. It will depend on the network speed some, but it might
be useful to know how many MB/s we can pump through over a UNIX
socket.

- The portion of the time that is used to split the lines is not
easily parallelizable. That seems to be a fairly small percentage for
a reasonably wide table, but it looks significant (13-18%) for a
narrow table. Such cases will gain less performance and be limited to
a smaller number of workers. I think we also need to be careful about
files whose lines are longer than the size of the buffer. If we're not
careful, we could get a significant performance drop-off in such
cases. We should make sure to pick an algorithm that seems like it
will handle such cases without serious regressions and check that a
file composed entirely of such long lines is handled reasonably
efficiently.

- There could be index contention. Let's suppose that we can read data
super fast and break it up into lines super fast. Maybe the file we're
reading is fully RAM-cached and the lines are long. Now all of the
backends are inserting into the indexes at the same time, and they
might be trying to insert into the same pages. If so, lock contention
could become a factor that hinders performance.

- There could also be similar contention on the heap. Say the tuples
are narrow, and many backends are trying to insert tuples into the
same heap page at the same time. This would lead to many lock/unlock
cycles. This could be avoided if the backends avoid targeting the same
heap pages, but I'm not sure there's any reason to expect that they
would do so unless we make some special provision for it.

- These problems could also arise with respect to TOAST table
insertions, either on the TOAST table itself or on its index. This
would only happen if the table contains a lot of toastable values, but
that could be the case: imagine a table with a bunch of columns each
of which contains a long string that isn't very compressible.

- What else? I bet the above list is not comprehensive.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#49Ants Aasma
ants@cybertec.at
In reply to: Robert Haas (#48)
Re: Parallel copy

On Wed, 8 Apr 2020 at 22:30, Robert Haas <robertmhaas@gmail.com> wrote:

- If we're unable to supply data to the COPY process as fast as the
workers could load it, then speed will be limited at that point. We
know reading the file from disk is pretty fast compared to what a
single process can do. I'm not sure we've tested what happens with a
network socket. It will depend on the network speed some, but it might
be useful to know how many MB/s we can pump through over a UNIX
socket.

This raises a good point. If at some point we want to minimize the
amount of memory copies then we might want to allow for RDMA to
directly write incoming network traffic into a distributing ring
buffer, which would include the protocol level headers. But at this
point we are so far off from network reception becoming a bottleneck I
don't think it's worth holding anything up for not allowing for zero
copy transfers.

- The portion of the time that is used to split the lines is not
easily parallelizable. That seems to be a fairly small percentage for
a reasonably wide table, but it looks significant (13-18%) for a
narrow table. Such cases will gain less performance and be limited to
a smaller number of workers. I think we also need to be careful about
files whose lines are longer than the size of the buffer. If we're not
careful, we could get a significant performance drop-off in such
cases. We should make sure to pick an algorithm that seems like it
will handle such cases without serious regressions and check that a
file composed entirely of such long lines is handled reasonably
efficiently.

I don't have a proof, but my gut feel tells me that it's fundamentally
impossible to ingest csv without a serial line-ending/comment
tokenization pass. The current line splitting algorithm is terrible.
I'm currently working with some scientific data where on ingestion
CopyReadLineText() is about 25% on profiles. I prototyped a
replacement that can do ~8GB/s on narrow rows, more on wider ones.

For rows that are consistently wider than the input buffer I think
parallelism will still give a win - the serial phase is just memcpy
through a ringbuffer, after which a worker goes away to perform the
actual insert, letting the next worker read the data. The memcpy is
already happening today, CopyReadLineText() copies the input buffer
into a StringInfo, so the only extra work is synchronization between
leader and worker.

- There could be index contention. Let's suppose that we can read data
super fast and break it up into lines super fast. Maybe the file we're
reading is fully RAM-cached and the lines are long. Now all of the
backends are inserting into the indexes at the same time, and they
might be trying to insert into the same pages. If so, lock contention
could become a factor that hinders performance.

Different data distribution strategies can have an effect on that.
Dealing out input data in larger or smaller chunks will have a
considerable effect on contention, btree page splits and all kinds of
things. I think the common theme would be a push to increase chunk
size to reduce contention..

- There could also be similar contention on the heap. Say the tuples
are narrow, and many backends are trying to insert tuples into the
same heap page at the same time. This would lead to many lock/unlock
cycles. This could be avoided if the backends avoid targeting the same
heap pages, but I'm not sure there's any reason to expect that they
would do so unless we make some special provision for it.

I thought there already was a provision for that. Am I mis-remembering?

- What else? I bet the above list is not comprehensive.

I think parallel copy patch needs to concentrate on splitting input
data to workers. After that any performance issues would be basically
the same as a normal parallel insert workload. There may well be
bottlenecks there, but those could be tackled independently.

Regards,
Ants Aasma
Cybertec

#50Amit Kapila
amit.kapila16@gmail.com
In reply to: Robert Haas (#48)
Re: Parallel copy

On Thu, Apr 9, 2020 at 1:00 AM Robert Haas <robertmhaas@gmail.com> wrote:

On Tue, Apr 7, 2020 at 9:38 AM Ants Aasma <ants@cybertec.at> wrote:

With option 1 it's not possible to read input data into shared memory
and there needs to be an extra memcpy in the time critical sequential
flow of the leader. With option 2 data could be read directly into the
shared memory buffer. With future async io support, reading and
looking for tuple boundaries could be performed concurrently.

But option 2 still seems significantly worse than your proposal above, right?

I really think we don't want a single worker in charge of finding
tuple boundaries for everybody. That adds a lot of unnecessary
inter-process communication and synchronization. Each process should
just get the next tuple starting after where the last one ended, and
then advance the end pointer so that the next process can do the same
thing. Vignesh's proposal involves having a leader process that has to
switch roles - he picks an arbitrary 25% threshold - and if it doesn't
switch roles at the right time, performance will be impacted. If the
leader doesn't get scheduled in time to refill the queue before it
runs completely empty, workers will have to wait. Ants's scheme avoids
that risk: whoever needs the next tuple reads the next line. There's
no need to ever wait for the leader because there is no leader.

Hmm, I think in his scheme also there is a single reader process. See
the email above [1] where he described how it should work. I think
the difference is in the division of work. AFAIU, in Ants scheme, the
worker needs to pick the work from tuple_offset queue whereas in
Vignesh's scheme it will be based on the size (each worker will get
probably 64KB of work). I think in his scheme the main thing to find
out is how many tuple offsets to be assigned to each worker in one-go
so that we don't unnecessarily add contention for finding the work
unit. I think we need to find the right balance between size and
number of tuples. I am trying to consider size here because larger
sized tuples will probably require more time as we need to allocate
more space for them and also probably requires more processing time.
One way to achieve that could be each worker will try to claim 500
tuples (or some other threshold number) but if their size is greater
than 64K (or some other threshold size) then the worker will try with
lesser number of tuples (such that the size of the chunk of tuples is
less than a threshold size.).

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#51Amit Kapila
amit.kapila16@gmail.com
In reply to: Amit Kapila (#50)
Re: Parallel copy

On Thu, Apr 9, 2020 at 4:20 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Thu, Apr 9, 2020 at 1:00 AM Robert Haas <robertmhaas@gmail.com> wrote:

On Tue, Apr 7, 2020 at 9:38 AM Ants Aasma <ants@cybertec.at> wrote:

With option 1 it's not possible to read input data into shared memory
and there needs to be an extra memcpy in the time critical sequential
flow of the leader. With option 2 data could be read directly into the
shared memory buffer. With future async io support, reading and
looking for tuple boundaries could be performed concurrently.

But option 2 still seems significantly worse than your proposal above, right?

I really think we don't want a single worker in charge of finding
tuple boundaries for everybody. That adds a lot of unnecessary
inter-process communication and synchronization. Each process should
just get the next tuple starting after where the last one ended, and
then advance the end pointer so that the next process can do the same
thing. Vignesh's proposal involves having a leader process that has to
switch roles - he picks an arbitrary 25% threshold - and if it doesn't
switch roles at the right time, performance will be impacted. If the
leader doesn't get scheduled in time to refill the queue before it
runs completely empty, workers will have to wait. Ants's scheme avoids
that risk: whoever needs the next tuple reads the next line. There's
no need to ever wait for the leader because there is no leader.

Hmm, I think in his scheme also there is a single reader process. See
the email above [1] where he described how it should work.

oops, I forgot to specify the link to the email. See
/messages/by-id/CANwKhkO87A8gApobOz_o6c9P5auuEG1W2iCz0D5CfOeGgAnk3g@mail.gmail.com

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#52Amit Kapila
amit.kapila16@gmail.com
In reply to: Ants Aasma (#49)
Re: Parallel copy

On Thu, Apr 9, 2020 at 3:55 AM Ants Aasma <ants@cybertec.at> wrote:

On Wed, 8 Apr 2020 at 22:30, Robert Haas <robertmhaas@gmail.com> wrote:

- The portion of the time that is used to split the lines is not
easily parallelizable. That seems to be a fairly small percentage for
a reasonably wide table, but it looks significant (13-18%) for a
narrow table. Such cases will gain less performance and be limited to
a smaller number of workers. I think we also need to be careful about
files whose lines are longer than the size of the buffer. If we're not
careful, we could get a significant performance drop-off in such
cases. We should make sure to pick an algorithm that seems like it
will handle such cases without serious regressions and check that a
file composed entirely of such long lines is handled reasonably
efficiently.

I don't have a proof, but my gut feel tells me that it's fundamentally
impossible to ingest csv without a serial line-ending/comment
tokenization pass.

I think even if we try to do it via multiple workers it might not be
better. In such a scheme, every worker needs to update the end
boundaries and the next worker to keep a check if the previous has
updated the end pointer. I think this can add a significant
synchronization effort for cases where tuples are of 100 or so bytes
which will be a common case.

The current line splitting algorithm is terrible.
I'm currently working with some scientific data where on ingestion
CopyReadLineText() is about 25% on profiles. I prototyped a
replacement that can do ~8GB/s on narrow rows, more on wider ones.

Good to hear. I think that will be a good project on its own and that
might give a boost to parallel copy as with that we can further reduce
the non-parallelizable work unit.

For rows that are consistently wider than the input buffer I think
parallelism will still give a win - the serial phase is just memcpy
through a ringbuffer, after which a worker goes away to perform the
actual insert, letting the next worker read the data. The memcpy is
already happening today, CopyReadLineText() copies the input buffer
into a StringInfo, so the only extra work is synchronization between
leader and worker.

- There could also be similar contention on the heap. Say the tuples
are narrow, and many backends are trying to insert tuples into the
same heap page at the same time. This would lead to many lock/unlock
cycles. This could be avoided if the backends avoid targeting the same
heap pages, but I'm not sure there's any reason to expect that they
would do so unless we make some special provision for it.

I thought there already was a provision for that. Am I mis-remembering?

The copy uses heap_multi_insert to insert batch of tuples and I think
each batch should ideally use a different page mostly it will be a new
page. So, not sure if this will be a problem or a problem of a level
for which we need to do some special handling. But if this turns out
to be a problem, we definetly need some better way to deal with it.

- What else? I bet the above list is not comprehensive.

I think parallel copy patch needs to concentrate on splitting input
data to workers. After that any performance issues would be basically
the same as a normal parallel insert workload. There may well be
bottlenecks there, but those could be tackled independently.

I agree.

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#53Dilip Kumar
dilipbalaut@gmail.com
In reply to: Robert Haas (#48)
Re: Parallel copy

On Thu, Apr 9, 2020 at 1:00 AM Robert Haas <robertmhaas@gmail.com> wrote:

On Tue, Apr 7, 2020 at 9:38 AM Ants Aasma <ants@cybertec.at> wrote:

I think the element based approach and requirement that all tuples fit
into the queue makes things unnecessarily complex. The approach I
detailed earlier allows for tuples to be bigger than the buffer. In
that case a worker will claim the long tuple from the ring queue of
tuple start positions, and starts copying it into its local line_buf.
This can wrap around the buffer multiple times until the next start
position shows up. At that point this worker can proceed with
inserting the tuple and the next worker will claim the next tuple.

This way nothing needs to be resized, there is no risk of a file with
huge tuples running the system out of memory because each element will
be reallocated to be huge and the number of elements is not something
that has to be tuned.

+1. This seems like the right way to do it.

We had a couple of options for the way in which queue elements can be stored.
Option 1: Each element (DSA chunk) will contain tuples such that each
tuple will be preceded by the length of the tuple. So the tuples will
be arranged like (Length of tuple-1, tuple-1), (Length of tuple-2,
tuple-2), .... Or Option 2: Each element (DSA chunk) will contain only
tuples (tuple-1), (tuple-2), ..... And we will have a second
ring-buffer which contains a start-offset or length of each tuple. The
old design used to generate one tuple of data and process tuple by
tuple. In the new design, the server will generate multiple tuples of
data per queue element. The worker will then process data tuple by
tuple. As we are processing the data tuple by tuple, I felt both of
the options are almost the same. However Design1 was chosen over
Design 2 as we can save up on some space that was required by another
variable in each element of the queue.

With option 1 it's not possible to read input data into shared memory
and there needs to be an extra memcpy in the time critical sequential
flow of the leader. With option 2 data could be read directly into the
shared memory buffer. With future async io support, reading and
looking for tuple boundaries could be performed concurrently.

But option 2 still seems significantly worse than your proposal above, right?

I really think we don't want a single worker in charge of finding
tuple boundaries for everybody. That adds a lot of unnecessary
inter-process communication and synchronization. Each process should
just get the next tuple starting after where the last one ended, and
then advance the end pointer so that the next process can do the same
thing. Vignesh's proposal involves having a leader process that has to
switch roles - he picks an arbitrary 25% threshold - and if it doesn't
switch roles at the right time, performance will be impacted. If the
leader doesn't get scheduled in time to refill the queue before it
runs completely empty, workers will have to wait. Ants's scheme avoids
that risk: whoever needs the next tuple reads the next line. There's
no need to ever wait for the leader because there is no leader.

I agree that if the leader switches the role, then it is possible that
sometimes the leader might not produce the work before the queue is
empty. OTOH, the problem with the approach you are suggesting is that
the work will be generated on-demand, i.e. there is no specific
process who is generating the data while workers are busy inserting
the data. So IMHO, if we have a specific leader process then there
will always be work available for all the workers. I agree that we
need to find the correct point when the leader will work as a worker.
One idea could be that when the queue is full and there is no space to
push more work to queue then the leader himself processes that work.

--
Regards,
Dilip Kumar
EnterpriseDB: http://www.enterprisedb.com

#54Robert Haas
robertmhaas@gmail.com
In reply to: Dilip Kumar (#53)
Re: Parallel copy

On Thu, Apr 9, 2020 at 7:49 AM Dilip Kumar <dilipbalaut@gmail.com> wrote:

I agree that if the leader switches the role, then it is possible that
sometimes the leader might not produce the work before the queue is
empty. OTOH, the problem with the approach you are suggesting is that
the work will be generated on-demand, i.e. there is no specific
process who is generating the data while workers are busy inserting
the data.

I think you have a point. The way I think things could go wrong if we
don't have a leader is if it tends to happen that everyone wants new
work at the same time. In that case, everyone will wait at once,
whereas if there is a designated process that aggressively queues up
work, we could perhaps avoid that. Note that you really have to have
the case where everyone wants new work at the exact same moment,
because otherwise they just all take turns finding work for
themselves, and everything is fine, because nobody's waiting for
anybody else to do any work, so everyone is always making forward
progress.

Now on the other hand, if we do have a leader, and for some reason
it's slow in responding, everyone will have to wait. That could happen
either because the leader also has other responsibilities, like
reading data or helping with the main work when the queue is full, or
just because the system is really busy and the leader doesn't get
scheduled on-CPU for a while. I am inclined to think that's likely to
be a more serious problem.

The thing is, the problem of everyone needing new work at the same
time can't really keep on repeating. Say that everyone finishes
processing their first chunk at the same time. Now everyone needs a
second chunk, and in a leaderless system, they must take turns getting
it. So they will go in some order. The ones who go later will
presumably also finish later, so the end times for the second and
following chunks will be scattered. You shouldn't get repeated
pile-ups with everyone finishing at the same time, because each time
it happens, it will force a little bit of waiting that will spread
things out. If they clump up again, that will happen again, but it
shouldn't happen every time.

But in the case where there is a leader, I don't think there's any
similar protection. Suppose we go with the design Vignesh proposes
where the leader switches to processing chunks when the queue is more
than 75% full. If the leader has a "hiccup" where it gets swapped out
or is busy with processing a chunk for a longer-than-normal time, all
of the other processes have to wait for it. Now we can probably tune
this to some degree by adjusting the queue size and fullness
thresholds, but the optimal values for those parameters might be quite
different on different systems, depending on load, I/O performance,
CPU architecture, etc. If there's a system or configuration where the
leader tends not to respond fast enough, it will probably just keep
happening, because nothing in the algorithm will tend to shake it out
of that bad pattern.

I'm not 100% certain that my analysis here is right, so it will be
interesting to hear from other people. However, as a general rule, I
think we want to minimize the amount of work that can only be done by
one process (the leader) and maximize the amount that can be done by
any process with whichever one is available taking on the job. In the
case of COPY FROM STDIN, the reads from the network socket can only be
done by the one process connected to it. In the case of COPY from a
file, even that could be rotated around, if all processes open the
file individually and seek to the appropriate offset.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#55Andres Freund
andres@anarazel.de
In reply to: Amit Kapila (#52)
Re: Parallel copy

Hi,

On April 9, 2020 4:01:43 AM PDT, Amit Kapila <amit.kapila16@gmail.com> wrote:

On Thu, Apr 9, 2020 at 3:55 AM Ants Aasma <ants@cybertec.at> wrote:

On Wed, 8 Apr 2020 at 22:30, Robert Haas <robertmhaas@gmail.com>

wrote:

- The portion of the time that is used to split the lines is not
easily parallelizable. That seems to be a fairly small percentage

for

a reasonably wide table, but it looks significant (13-18%) for a
narrow table. Such cases will gain less performance and be limited

to

a smaller number of workers. I think we also need to be careful

about

files whose lines are longer than the size of the buffer. If we're

not

careful, we could get a significant performance drop-off in such
cases. We should make sure to pick an algorithm that seems like it
will handle such cases without serious regressions and check that a
file composed entirely of such long lines is handled reasonably
efficiently.

I don't have a proof, but my gut feel tells me that it's

fundamentally

impossible to ingest csv without a serial line-ending/comment
tokenization pass.

I can't quite see a way either. But even if it were, I have a hard time seeing parallelizing that path as the right thing.

I think even if we try to do it via multiple workers it might not be
better. In such a scheme, every worker needs to update the end
boundaries and the next worker to keep a check if the previous has
updated the end pointer. I think this can add a significant
synchronization effort for cases where tuples are of 100 or so bytes
which will be a common case.

It seems like it'd also have terrible caching and instruction level parallelism behavior. By constantly switching the process that analyzes boundaries, the current data will have to be brought into l1/register, rather than staying there.

I'm fairly certain that we do *not* want to distribute input data between processes on a single tuple basis. Probably not even below a few hundred kb. If there's any sort of natural clustering in the loaded data - extremely common, think timestamps - splitting on a granular basis will make indexing much more expensive. And have a lot more contention.

The current line splitting algorithm is terrible.
I'm currently working with some scientific data where on ingestion
CopyReadLineText() is about 25% on profiles. I prototyped a
replacement that can do ~8GB/s on narrow rows, more on wider ones.

We should really replace the entire copy parsing code. It's terrible.

Andres
--
Sent from my Android device with K-9 Mail. Please excuse my brevity.

#56Robert Haas
robertmhaas@gmail.com
In reply to: Andres Freund (#55)
Re: Parallel copy

On Thu, Apr 9, 2020 at 2:55 PM Andres Freund <andres@anarazel.de> wrote:

I'm fairly certain that we do *not* want to distribute input data between processes on a single tuple basis. Probably not even below a few hundred kb. If there's any sort of natural clustering in the loaded data - extremely common, think timestamps - splitting on a granular basis will make indexing much more expensive. And have a lot more contention.

That's a fair point. I think the solution ought to be that once any
process starts finding line endings, it continues until it's grabbed
at least a certain amount of data for itself. Then it stops and lets
some other process grab a chunk of data.

Or are you are arguing that there should be only one process that's
allowed to find line endings for the entire duration of the load?

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#57Andres Freund
andres@anarazel.de
In reply to: Robert Haas (#56)
Re: Parallel copy

Hi,

On April 9, 2020 12:29:09 PM PDT, Robert Haas <robertmhaas@gmail.com> wrote:

On Thu, Apr 9, 2020 at 2:55 PM Andres Freund <andres@anarazel.de>
wrote:

I'm fairly certain that we do *not* want to distribute input data

between processes on a single tuple basis. Probably not even below a
few hundred kb. If there's any sort of natural clustering in the loaded
data - extremely common, think timestamps - splitting on a granular
basis will make indexing much more expensive. And have a lot more
contention.

That's a fair point. I think the solution ought to be that once any
process starts finding line endings, it continues until it's grabbed
at least a certain amount of data for itself. Then it stops and lets
some other process grab a chunk of data.

Or are you are arguing that there should be only one process that's
allowed to find line endings for the entire duration of the load?

I've not yet read the whole thread. So I'm probably restating ideas.

Imo, yes, there should be only one process doing the chunking. For ilp, cache efficiency, but also because the leader is the only process with access to the network socket. It should load input data into one large buffer that's shared across processes. There should be a separate ringbuffer with tuple/partial tuple (for huge tuples) offsets. Worker processes should grab large chunks of offsets from the offset ringbuffer. If the ringbuffer is not full, the worker chunks should be reduced in size.

Given that everything stalls if the leader doesn't accept further input data, as well as when there are no available splitted chunks, it doesn't seem like a good idea to have the leader do other work.

I don't think optimizing/targeting copy from local files, where multiple processes could read, is useful. COPY STDIN is the only thing that practically matters.

Andres

--
Sent from my Android device with K-9 Mail. Please excuse my brevity.

#58Robert Haas
robertmhaas@gmail.com
In reply to: Andres Freund (#57)
Re: Parallel copy

On Thu, Apr 9, 2020 at 4:00 PM Andres Freund <andres@anarazel.de> wrote:

I've not yet read the whole thread. So I'm probably restating ideas.

Yeah, but that's OK.

Imo, yes, there should be only one process doing the chunking. For ilp, cache efficiency, but also because the leader is the only process with access to the network socket. It should load input data into one large buffer that's shared across processes. There should be a separate ringbuffer with tuple/partial tuple (for huge tuples) offsets. Worker processes should grab large chunks of offsets from the offset ringbuffer. If the ringbuffer is not full, the worker chunks should be reduced in size.

My concern here is that it's going to be hard to avoid processes going
idle. If the leader does nothing at all once the ring buffer is full,
it's wasting time that it could spend processing a chunk. But if it
picks up a chunk, then it might not get around to refilling the buffer
before other processes are idle with no work to do.

Still, it might be the case that having the process that is reading
the data also find the line endings is so fast that it makes no sense
to split those two tasks. After all, whoever just read the data must
have it in cache, and that helps a lot.

Given that everything stalls if the leader doesn't accept further input data, as well as when there are no available splitted chunks, it doesn't seem like a good idea to have the leader do other work.

I don't think optimizing/targeting copy from local files, where multiple processes could read, is useful. COPY STDIN is the only thing that practically matters.

Yeah, I think Amit has been thinking primarily in terms of COPY from
files, and I've been encouraging him to at least consider the STDIN
case. But I think you're right, and COPY FROM STDIN should be the
design center for this feature.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#59Andres Freund
andres@anarazel.de
In reply to: Robert Haas (#58)
Re: Parallel copy

Hi,

On 2020-04-10 07:40:06 -0400, Robert Haas wrote:

On Thu, Apr 9, 2020 at 4:00 PM Andres Freund <andres@anarazel.de> wrote:

Imo, yes, there should be only one process doing the chunking. For ilp, cache efficiency, but also because the leader is the only process with access to the network socket. It should load input data into one large buffer that's shared across processes. There should be a separate ringbuffer with tuple/partial tuple (for huge tuples) offsets. Worker processes should grab large chunks of offsets from the offset ringbuffer. If the ringbuffer is not full, the worker chunks should be reduced in size.

My concern here is that it's going to be hard to avoid processes going
idle. If the leader does nothing at all once the ring buffer is full,
it's wasting time that it could spend processing a chunk. But if it
picks up a chunk, then it might not get around to refilling the buffer
before other processes are idle with no work to do.

An idle process doesn't cost much. Processes that use CPU inefficiently
however...

Still, it might be the case that having the process that is reading
the data also find the line endings is so fast that it makes no sense
to split those two tasks. After all, whoever just read the data must
have it in cache, and that helps a lot.

Yea. And if it's not fast enough to split lines, then we have a problem
regardless of which process does the splitting.

Greetings,

Andres Freund

#60Robert Haas
robertmhaas@gmail.com
In reply to: Andres Freund (#59)
Re: Parallel copy

On Fri, Apr 10, 2020 at 2:26 PM Andres Freund <andres@anarazel.de> wrote:

Still, it might be the case that having the process that is reading
the data also find the line endings is so fast that it makes no sense
to split those two tasks. After all, whoever just read the data must
have it in cache, and that helps a lot.

Yea. And if it's not fast enough to split lines, then we have a problem
regardless of which process does the splitting.

Still, if the reader does the splitting, then you don't need as much
IPC, right? The shared memory data structure is just a ring of bytes,
and whoever reads from it is responsible for the rest.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#61Andres Freund
andres@anarazel.de
In reply to: Robert Haas (#60)
Re: Parallel copy

Hi,

On 2020-04-13 14:13:46 -0400, Robert Haas wrote:

On Fri, Apr 10, 2020 at 2:26 PM Andres Freund <andres@anarazel.de> wrote:

Still, it might be the case that having the process that is reading
the data also find the line endings is so fast that it makes no sense
to split those two tasks. After all, whoever just read the data must
have it in cache, and that helps a lot.

Yea. And if it's not fast enough to split lines, then we have a problem
regardless of which process does the splitting.

Still, if the reader does the splitting, then you don't need as much
IPC, right? The shared memory data structure is just a ring of bytes,
and whoever reads from it is responsible for the rest.

I don't think so. If only one process does the splitting, the
exclusively locked section is just popping off a bunch of offsets of the
ring. And that could fairly easily be done with atomic ops (since what
we need is basically a single producer multiple consumer queue, which
can be done lock free fairly easily ). Whereas in the case of each
process doing the splitting, the exclusively locked part is splitting
along lines - which takes considerably longer than just popping off a
few offsets.

Greetings,

Andres Freund

#62Robert Haas
robertmhaas@gmail.com
In reply to: Andres Freund (#61)
Re: Parallel copy

On Mon, Apr 13, 2020 at 4:16 PM Andres Freund <andres@anarazel.de> wrote:

I don't think so. If only one process does the splitting, the
exclusively locked section is just popping off a bunch of offsets of the
ring. And that could fairly easily be done with atomic ops (since what
we need is basically a single producer multiple consumer queue, which
can be done lock free fairly easily ). Whereas in the case of each
process doing the splitting, the exclusively locked part is splitting
along lines - which takes considerably longer than just popping off a
few offsets.

Hmm, that does seem believable.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#63Kuntal Ghosh
kuntalghosh.2007@gmail.com
In reply to: Robert Haas (#62)
Re: Parallel copy

Hello,

I was going through some literatures on parsing CSV files in a fully
parallelized way and found (from [1]https://www.microsoft.com/en-us/research/uploads/prod/2019/04/chunker-sigmod19.pdf) an interesting approach
implemented in the open-source project ParaText[2]ParaText. https://github.com/wiseio/paratext.. The algorithm
follows a two-phase approach: the first pass identifies the adjusted
chunks in parallel by exploiting the simplicity of CSV formats and the
second phase processes complete records within each adjusted chunk by
one of the available workers. Here is the sketch:

1. Each worker scans a distinct fixed sized chunk of the CSV file and
collects the following three stats from the chunk:
a) number of quotes
b) position of the first new line after even number of quotes
c) position of the first new line after odd number of quotes
2. Once stats from all the chunks are collected, the leader identifies
the adjusted chunk boundaries by iterating over the stats linearly:
- For the k-th chunk, the leader adds the number of quotes in k-1 chunks.
- If the number is even, then the k-th chunk does not start in the
middle of a quoted field, and the first newline after an even number
of quotes (the second collected information) is the first record
delimiter in this chunk.
- Otherwise, if the number is odd, the first newline after an odd
number of quotes (the third collected information) is the first record
delimiter.
- The end position of the adjusted chunk is obtained based on the
starting position of the next adjusted chunk.
3. Once the boundaries of the chunks are determined (forming adjusted
chunks), individual worker may take up one adjusted chunk and process
the tuples independently.

Although this approach parses the CSV in parallel, it requires two
scan on the CSV file. So, given a system with spinning hard-disk and
small RAM, as per my understanding, the algorithm will perform very
poorly. But, if we use this algorithm to parse a CSV file on a
multi-core system with a large RAM, the performance might be improved
significantly [1]https://www.microsoft.com/en-us/research/uploads/prod/2019/04/chunker-sigmod19.pdf.

Hence, I was trying to think whether we can leverage this idea for
implementing parallel COPY in PG. We can design an algorithm similar
to parallel hash-join where the workers pass through different phases.
1. Phase 1 - Read fixed size chunks in parallel, store the chunks and
the small stats about each chunk in the shared memory. If the shared
memory is full, go to phase 2.
2. Phase 2 - Allow a single worker to process the stats and decide the
actual chunk boundaries so that no tuple spans across two different
chunks. Go to phase 3.
3. Phase 3 - Each worker picks one adjusted chunk, parse and process
tuples from the same. Once done with one chunk, it picks the next one
and so on.
4. If there are still some unread contents, go back to phase 1.

We can probably use separate workers for phase 1 and phase 3 so that
they can work concurrently.

Advantages:
1. Each worker spends some significant time in each phase. Gets
benefit of the instruction cache - at least in phase 1.
2. It also has the same advantage of parallel hash join - fast workers
get to work more.
3. We can extend this solution for reading data from STDIN. Of course,
the phase 1 and phase 2 must be performed by the leader process who
can read from the socket.

Disadvantages:
1. Surely doesn't work if we don't have enough shared memory.
2. Probably, this approach is just impractical for PG due to certain
limitations.

Thoughts?

[1]: https://www.microsoft.com/en-us/research/uploads/prod/2019/04/chunker-sigmod19.pdf
[2]: ParaText. https://github.com/wiseio/paratext.

--
Thanks & Regards,
Kuntal Ghosh
EnterpriseDB: http://www.enterprisedb.com

#64Ants Aasma
ants@cybertec.at
In reply to: Kuntal Ghosh (#63)
Re: Parallel copy

On Tue, 14 Apr 2020 at 22:40, Kuntal Ghosh <kuntalghosh.2007@gmail.com> wrote:

1. Each worker scans a distinct fixed sized chunk of the CSV file and
collects the following three stats from the chunk:
a) number of quotes
b) position of the first new line after even number of quotes
c) position of the first new line after odd number of quotes
2. Once stats from all the chunks are collected, the leader identifies
the adjusted chunk boundaries by iterating over the stats linearly:
- For the k-th chunk, the leader adds the number of quotes in k-1 chunks.
- If the number is even, then the k-th chunk does not start in the
middle of a quoted field, and the first newline after an even number
of quotes (the second collected information) is the first record
delimiter in this chunk.
- Otherwise, if the number is odd, the first newline after an odd
number of quotes (the third collected information) is the first record
delimiter.
- The end position of the adjusted chunk is obtained based on the
starting position of the next adjusted chunk.

The trouble is that, at least with current coding, the number of
quotes in a chunk can depend on whether the chunk started in a quote
or not. That's because escape characters only count inside quotes. See
for example the following csv:

foo,\"bar
baz",\"xyz"

This currently parses as one line and the number of parsed quotes
doesn't change if you add a quote in front.

But the general approach of doing the tokenization in parallel and
then a serial pass over the tokenization would still work. The quote
counting and new line finding just has to be done for both starting in
quote and not starting in quote case.

Using phases doesn't look like the correct approach - the tokenization
can be prepared just in time for the serial pass and processing the
chunk can proceed immediately after. This could all be done by having
the data in a single ringbuffer with a processing pipeline where one
process does the reading, then workers grab tokenization chunks as
they become available, then one process handles determining the chunk
boundaries, after which the chunks are processed.

But I still don't think this is something to worry about for the first
version. Just a better line splitting algorithm should go a looong way
in feeding a large number of workers, even when inserting to an
unindexed unlogged table. If we get the SIMD line splitting in, it
will be enough to overwhelm most I/O subsystems available today.

Regards,
Ants Aasma

#65Ants Aasma
ants@cybertec.at
In reply to: Andres Freund (#61)
Re: Parallel copy

On Mon, 13 Apr 2020 at 23:16, Andres Freund <andres@anarazel.de> wrote:

Still, if the reader does the splitting, then you don't need as much
IPC, right? The shared memory data structure is just a ring of bytes,
and whoever reads from it is responsible for the rest.

I don't think so. If only one process does the splitting, the
exclusively locked section is just popping off a bunch of offsets of the
ring. And that could fairly easily be done with atomic ops (since what
we need is basically a single producer multiple consumer queue, which
can be done lock free fairly easily ). Whereas in the case of each
process doing the splitting, the exclusively locked part is splitting
along lines - which takes considerably longer than just popping off a
few offsets.

I see the benefit of having one process responsible for splitting as
being able to run ahead of the workers to queue up work when many of
them need new data at the same time. I don't think the locking
benefits of a ring are important in this case. At current rather
conservative chunk sizes we are looking at ~100k chunks per second at
best, normal locking should be perfectly adequate. And chunk size can
easily be increased. I see the main value in it being simple.

But there is a point that having a layer of indirection instead of a
linear buffer allows for some workers to fall behind. Either because
the kernel scheduled them out for a time slice, or they need to do I/O
or because inserting some tuple hit an unique conflict and needs to
wait for a tx to complete or abort to resolve. With a ring buffer
reading has to wait on the slowest worker reading its chunk. Having
workers copy the data to a local buffer as the first step would reduce
the probability of hitting any issues. But still, at GB/s rates,
hiding a 10ms timeslice of delay would need 10's of megabytes of
buffer.

FWIW. I think just increasing the buffer is good enough - the CPUs
processing this workload are likely to have tens to hundreds of
megabytes of cache on board.

#66Amit Kapila
amit.kapila16@gmail.com
In reply to: Kuntal Ghosh (#63)
Re: Parallel copy

On Wed, Apr 15, 2020 at 1:10 AM Kuntal Ghosh <kuntalghosh.2007@gmail.com> wrote:

Hence, I was trying to think whether we can leverage this idea for
implementing parallel COPY in PG. We can design an algorithm similar
to parallel hash-join where the workers pass through different phases.
1. Phase 1 - Read fixed size chunks in parallel, store the chunks and
the small stats about each chunk in the shared memory. If the shared
memory is full, go to phase 2.
2. Phase 2 - Allow a single worker to process the stats and decide the
actual chunk boundaries so that no tuple spans across two different
chunks. Go to phase 3.

3. Phase 3 - Each worker picks one adjusted chunk, parse and process
tuples from the same. Once done with one chunk, it picks the next one
and so on.

4. If there are still some unread contents, go back to phase 1.

We can probably use separate workers for phase 1 and phase 3 so that
they can work concurrently.

Advantages:
1. Each worker spends some significant time in each phase. Gets
benefit of the instruction cache - at least in phase 1.
2. It also has the same advantage of parallel hash join - fast workers
get to work more.
3. We can extend this solution for reading data from STDIN. Of course,
the phase 1 and phase 2 must be performed by the leader process who
can read from the socket.

Disadvantages:
1. Surely doesn't work if we don't have enough shared memory.
2. Probably, this approach is just impractical for PG due to certain
limitations.

As I understand this, it needs to parse the lines twice (second time
in phase-3) and till the first two phases are over, we can't start the
tuple processing work which is done in phase-3. So even if the
tokenization is done a bit faster but we will lose some on processing
the tuples which might not be an overall win and in fact, it can be
worse as compared to the single reader approach being discussed.
Now, if the work done in tokenization is a major (or significant)
portion of the copy then thinking of such a technique might be useful
but that is not the case as seen in the data shared above (the
tokenize time is very less as compared to data processing time) in
this email.

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#67Robert Haas
robertmhaas@gmail.com
In reply to: Amit Kapila (#66)
Re: Parallel copy

On Wed, Apr 15, 2020 at 7:15 AM Amit Kapila <amit.kapila16@gmail.com> wrote:

As I understand this, it needs to parse the lines twice (second time
in phase-3) and till the first two phases are over, we can't start the
tuple processing work which is done in phase-3. So even if the
tokenization is done a bit faster but we will lose some on processing
the tuples which might not be an overall win and in fact, it can be
worse as compared to the single reader approach being discussed.
Now, if the work done in tokenization is a major (or significant)
portion of the copy then thinking of such a technique might be useful
but that is not the case as seen in the data shared above (the
tokenize time is very less as compared to data processing time) in
this email.

It seems to me that a good first step here might be to forget about
parallelism for a minute and just write a patch to make the line
splitting as fast as possible.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#68Kuntal Ghosh
kuntalghosh.2007@gmail.com
In reply to: Ants Aasma (#64)
Re: Parallel copy

On Wed, Apr 15, 2020 at 2:15 PM Ants Aasma <ants@cybertec.at> wrote:

On Tue, 14 Apr 2020 at 22:40, Kuntal Ghosh <kuntalghosh.2007@gmail.com> wrote:

1. Each worker scans a distinct fixed sized chunk of the CSV file and
collects the following three stats from the chunk:
a) number of quotes
b) position of the first new line after even number of quotes
c) position of the first new line after odd number of quotes
2. Once stats from all the chunks are collected, the leader identifies
the adjusted chunk boundaries by iterating over the stats linearly:
- For the k-th chunk, the leader adds the number of quotes in k-1 chunks.
- If the number is even, then the k-th chunk does not start in the
middle of a quoted field, and the first newline after an even number
of quotes (the second collected information) is the first record
delimiter in this chunk.
- Otherwise, if the number is odd, the first newline after an odd
number of quotes (the third collected information) is the first record
delimiter.
- The end position of the adjusted chunk is obtained based on the
starting position of the next adjusted chunk.

The trouble is that, at least with current coding, the number of
quotes in a chunk can depend on whether the chunk started in a quote
or not. That's because escape characters only count inside quotes. See
for example the following csv:

foo,\"bar
baz",\"xyz"

This currently parses as one line and the number of parsed quotes
doesn't change if you add a quote in front.

But the general approach of doing the tokenization in parallel and
then a serial pass over the tokenization would still work. The quote
counting and new line finding just has to be done for both starting in
quote and not starting in quote case.

Yeah, right.

Using phases doesn't look like the correct approach - the tokenization
can be prepared just in time for the serial pass and processing the
chunk can proceed immediately after. This could all be done by having
the data in a single ringbuffer with a processing pipeline where one
process does the reading, then workers grab tokenization chunks as
they become available, then one process handles determining the chunk
boundaries, after which the chunks are processed.

I was thinking from this point of view - the sooner we introduce
parallelism in the process, the greater the benefits. Probably there
isn't any way to avoid a single-pass over the data (phase - 2 in the
above case) to tokenise the chunks. So yeah, if the reading and
tokenisation phase doesn't take much time, parallelising the same will
just be an overkill. As pointed by Andres and you, using a lock-free
circular buffer implementation sounds the way to go forward. AFAIK,
FIFO circular queue with CAS-based implementation suffers from two
problems - 1. (as pointed by you) slow workers may block producers. 2.
Since it doesn't partition the queue among the workers, does not
achieve good locality and cache-friendliness, limits their scalability
on NUMA systems.

But I still don't think this is something to worry about for the first
version. Just a better line splitting algorithm should go a looong way
in feeding a large number of workers, even when inserting to an
unindexed unlogged table. If we get the SIMD line splitting in, it
will be enough to overwhelm most I/O subsystems available today.

Yeah. Parsing text is a great use case for data parallelism which can
be achieved by SIMD instructions. Consider processing 8-bit ASCII
characters in 512-bit SIMD word. A lot of code and complexity from
CopyReadLineText will surely go away. And further (I'm not sure in
this point), if we can use the schema of the table, perhaps JIT can
generate machine code to efficient read of fields based on their
types.

--
Thanks & Regards,
Kuntal Ghosh
EnterpriseDB: http://www.enterprisedb.com

#69Andres Freund
andres@anarazel.de
In reply to: Robert Haas (#67)
Re: Parallel copy

On 2020-04-15 10:12:14 -0400, Robert Haas wrote:

On Wed, Apr 15, 2020 at 7:15 AM Amit Kapila <amit.kapila16@gmail.com> wrote:

As I understand this, it needs to parse the lines twice (second time
in phase-3) and till the first two phases are over, we can't start the
tuple processing work which is done in phase-3. So even if the
tokenization is done a bit faster but we will lose some on processing
the tuples which might not be an overall win and in fact, it can be
worse as compared to the single reader approach being discussed.
Now, if the work done in tokenization is a major (or significant)
portion of the copy then thinking of such a technique might be useful
but that is not the case as seen in the data shared above (the
tokenize time is very less as compared to data processing time) in
this email.

It seems to me that a good first step here might be to forget about
parallelism for a minute and just write a patch to make the line
splitting as fast as possible.

+1

Compared to all the rest of the efforts during COPY a fast "split rows"
implementation should not be a bottleneck anymore.

#70Andres Freund
andres@anarazel.de
In reply to: Kuntal Ghosh (#68)
Re: Parallel copy

Hi,

On 2020-04-15 20:36:39 +0530, Kuntal Ghosh wrote:

I was thinking from this point of view - the sooner we introduce
parallelism in the process, the greater the benefits.

I don't really agree. Sure, that's true from a theoretical perspective,
but the incremental gains may be very small, and the cost in complexity
very high. If we can get single threaded splitting of rows to be >4GB/s,
which should very well be attainable, the rest of the COPY work is going
to dominate the time. We shouldn't add complexity to parallelize more
of the line splitting, caring too much about scalable datastructures,
etc when the bottleneck after some straightforward optimization is
usually still in the parallelized part.

I'd expect that for now we'd likely hit scalability issues in other
parts of the system first (e.g. extension locks, buffer mapping).

Greetings,

Andres Freund

#71Andres Freund
andres@anarazel.de
In reply to: Ants Aasma (#65)
Re: Parallel copy

Hi,

On 2020-04-15 12:05:47 +0300, Ants Aasma wrote:

I see the benefit of having one process responsible for splitting as
being able to run ahead of the workers to queue up work when many of
them need new data at the same time.

Yea, I agree.

I don't think the locking benefits of a ring are important in this
case. At current rather conservative chunk sizes we are looking at
~100k chunks per second at best, normal locking should be perfectly
adequate. And chunk size can easily be increased. I see the main value
in it being simple.

I think the locking benefits of not needing to hold a lock *while*
splitting (as we'd need in some proposal floated earlier) is likely to
already be beneficial. I don't think we need to worry about lock
scalability protecting the queue of already split data, for now.

I don't think we really want to have a much larger chunk size,
btw. Makes it more likely for data to workers to take an uneven amount
of time.

But there is a point that having a layer of indirection instead of a
linear buffer allows for some workers to fall behind.

Yea. It'd probably make sense to read the input data into an array of
evenly sized blocks, and have the datastructure (still think a
ringbuffer makes sense) of split boundaries point into those entries. If
we don't require the input blocks to be in-order in that array, we can
reuse blocks therein that are fully processed, even if "earlier" data in
the input has not yet been fully processed.

With a ring buffer reading has to wait on the slowest worker reading
its chunk.

To be clear, I was only thinking of using a ringbuffer to indicate split
boundaries. And that workers would just pop entries from it before they
actually process the data (stored outside of the ringbuffer). Since the
split boundaries will always be read in order by workers, and the
entries will be tiny, there's no need to avoid copying out entries.

So basically what I was thinking we *eventually* may want (I'd forgo some
of this initially) is something like:

struct InputBlock
{
uint32 unprocessed_chunk_parts;
uint32 following_block;
char data[INPUT_BLOCK_SIZE]
};

// array of input data, with > 2*nworkers entries
InputBlock *input_blocks;

struct ChunkedInputBoundary
{
uint32 firstblock;
uint32 startoff;
};

struct ChunkedInputBoundaries
{
uint32 read_pos;
uint32 write_end;
ChunkedInputBoundary ring[RINGSIZE];
};

Where the leader would read data into InputBlocks with
unprocessed_chunk_parts == 0. Then it'd split the read input data into
chunks (presumably with chunk size << input block size), putting
identified chunks into ChunkedInputBoundaries. For each
ChunkedInputBoundary it'd increment the unprocessed_chunk_parts of each
InputBlock containing parts of the chunk. For chunks across >1
InputBlocks each InputBlock's following_block would be set accordingly.

Workers would just pop an entry from the ringbuffer (making that entry
reusable), and process the chunk. The underlying data would not be
copied out of the InputBlocks, but obviously readers would need to take
care to handle InputBlock boundaries. Whenever a chunk is fully read, or
when crossing a InputBlock boundary, the InputBlock's
unprocessed_chunk_parts would be decremented.

Recycling of InputBlocks could probably just be an occasional linear
search for buffers with unprocessed_chunk_parts == 0.

Something roughly like this should not be too complicated to
implement. Unless extremely unluckly (very wide input data spanning many
InputBlocks) a straggling reader would not prevent global progress, it'd
just prevent reuse of the InputBlocks with data for its chunk (normally
that'd be two InputBlocks, not more).

Having workers copy the data to a local buffer as the first
step would reduce the probability of hitting any issues. But still, at
GB/s rates, hiding a 10ms timeslice of delay would need 10's of
megabytes of buffer.

Yea. Given the likelihood of blocking on resources (reading in index
data, writing out dirty buffers for reclaim, row locks for uniqueness
checks, extension locks, ...), as well as non uniform per-row costs
(partial indexes, index splits, ...) I think we ought to try to cope
well with that. IMO/IME it'll be common to see stalls that are much
longer than 10ms for processes that do COPY, even when the system is not
overloaded.

FWIW. I think just increasing the buffer is good enough - the CPUs
processing this workload are likely to have tens to hundreds of
megabytes of cache on board.

It'll not necessarily be a cache shared between leader / workers though,
and some of the cache-cache transfers will be more expensive even within
a socket (between core complexes for AMD, multi chip processors for
Intel).

Greetings,

Andres Freund

#72Kuntal Ghosh
kuntalghosh.2007@gmail.com
In reply to: Andres Freund (#70)
Re: Parallel copy

On Wed, Apr 15, 2020 at 10:45 PM Andres Freund <andres@anarazel.de> wrote:

Hi,

On 2020-04-15 20:36:39 +0530, Kuntal Ghosh wrote:

I was thinking from this point of view - the sooner we introduce
parallelism in the process, the greater the benefits.

I don't really agree. Sure, that's true from a theoretical perspective,
but the incremental gains may be very small, and the cost in complexity
very high. If we can get single threaded splitting of rows to be >4GB/s,
which should very well be attainable, the rest of the COPY work is going
to dominate the time. We shouldn't add complexity to parallelize more
of the line splitting, caring too much about scalable datastructures,
etc when the bottleneck after some straightforward optimization is
usually still in the parallelized part.

I'd expect that for now we'd likely hit scalability issues in other
parts of the system first (e.g. extension locks, buffer mapping).

Got your point. In this particular case, a single producer is fast
enough (or probably we can make it fast enough) to generate enough
chunks for multiple consumers so that they don't stay idle and wait
for work.

--
Thanks & Regards,
Kuntal Ghosh
EnterpriseDB: http://www.enterprisedb.com

#73Amit Kapila
amit.kapila16@gmail.com
In reply to: Andres Freund (#71)
Re: Parallel copy

On Wed, Apr 15, 2020 at 11:49 PM Andres Freund <andres@anarazel.de> wrote:

To be clear, I was only thinking of using a ringbuffer to indicate split
boundaries. And that workers would just pop entries from it before they
actually process the data (stored outside of the ringbuffer). Since the
split boundaries will always be read in order by workers, and the
entries will be tiny, there's no need to avoid copying out entries.

I think the binary mode processing will be slightly different because
unlike text and csv format, the data is stored in Length, Value format
for each column and there are no line markers. I don't think there
will be a big difference but still, we need to somewhere keep the
information what is the format of data in ring buffers. Basically, we
can copy the data in Length, Value format and once the writers know
about the format, they will parse the data in the appropriate format.
We currently also have a different way of parsing the binary format,
see NextCopyFrom. I think we need to be careful about avoiding
duplicate work as much as possible.

Apart from this, we have analyzed the other cases as mentioned below
where we need to decide whether we can allow parallelism for the copy
command.
Case-1:
Do we want to enable parallelism for a copy when transition tables are
involved? Basically, during the copy, we do capture tuples in
transition tables for certain cases like when after statement trigger
accesses the same relation on which we have a trigger. See the
example below [1]create or replace function dump_insert() returns trigger language plpgsql as $$ begin raise notice 'trigger = %, new table = %', TG_NAME, (select string_agg(new_table::text, ', ' order by a) from new_table); return null; end; $$;. We decide this in function
MakeTransitionCaptureState. For such cases, we collect minimal tuples
in the tuple store after processing them so that later after statement
triggers can access them. Now, if we want to enable parallelism for
such cases, we instead need to store and access tuples from shared
tuple store (sharedtuplestore.c/sharedtuplestore.h). However, it
doesn't have the facility to store tuples in-memory, so we always need
to store and access from a file which could be costly unless we also
have an additional way to store minimal tuples in shared memory till
work_memory and then in shared tuple store. It is possible to do all
this or part of this work to enable parallel copy for such cases but I
am not sure if it is worth it. We can decide to not enable parallelism
for such cases and later allow if we see demand for the same and it
will also help us to not introduce additional work/complexity in the
first version of the patch.

Case-2:
The Single Insertion mode (CIM_SINGLE) is performed in various
scenarios and whether we can allow parallelism for those depends on
case to case basis which is discussed below:
a. When there are BEFORE/INSTEAD OF triggers on the table. We don't
allow multi-inserts in such cases because such triggers might query
the table we're inserting into and act differently if the tuples that
have already been processed and prepared for insertion are not there.
Now, if we allow parallelism with such triggers the behavior would
depend on if the parallel worker has already inserted or not that
particular row. I guess such functions should ideally be marked as
parallel-unsafe. So, in short in this case whether to allow
parallelism or not depends upon the parallel-safety marking of this
function.
b. For partitioned tables, we can't support multi-inserts when there
are any statement-level insert triggers. This is because as of now,
we expect that any before row insert and statement-level insert
triggers are on the same relation. Now, there is no harm in allowing
parallelism for such cases but it depends upon if we have the
infrastructure (basically allow tuples to be collected in shared tuple
store) to support statement-level insert triggers.
c. For inserts into foreign tables. We can't allow the parallelism in
this case because each worker needs to establish the FDW connection
and operate in a separate transaction. Now unless we have a
capability to provide a two-phase commit protocol for "Transactions
involving multiple postgres foreign servers" (which is being discussed
in a separate thread [2]/messages/by-id/20191206.173215.1818665441859410805.horikyota.ntt@gmail.com), we can't allow this.
d. If there are volatile default expressions or the where clause
contains a volatile expression. Here, we can check if the expression
is parallel-safe, then we can allow parallelism.

Case-3:
In copy command, for performing foreign key checks, we take KEY SHARE
lock on primary key table rows which inturn will increment the command
counter and updates the snapshot. Now, as we share the snapshots at
the beginning of the command, we can't allow it to be changed later.
So, unless we do something special for it, I think we can't allow
parallelism in such cases.

I couldn't think of many problems if we allow parallelism in such
cases. One inconsistency, if we allow FK checks via workers, would be
that at the end of COPY the value of command_counter will not be what
we expect as we wouldn't have accounted for that from workers. Now,
if COPY is being done in a transaction it will not assign the correct
values to the next commands. Also, for executing deferred triggers,
we use transaction snapshot, so if anything is changed in snapshot via
parallel workers, ideally it should have synced the changed snapshot
in the worker.

Now, the other concern could be that different workers can try to
acquire KEY SHARE lock on the same tuples which they will be able to
acquire due to group locking or otherwise but I don't see any problem
with it.

I am not sure if it above leads to any user-visible problem but I
might be missing something here. I think if we can think of any real
problems we can try to design a better solution to address those.

Case-4:
For Deferred Triggers, it seems we record CTIDs of tuples (via
ExecARInsertTriggers->AfterTriggerSaveEvent) and then execute deferred
triggers at transaction end using AfterTriggerFireDeferred or at end
of the statement. The challenge to allow parallelism for such cases
is we need to capture the CTID events in shared memory. For that, we
either need to invent a new infrastructure for event capturing in
shared memory which will be a huge task on its own. The other idea is
to get CTIDs via shared memory and then add those to event queues via
leader but I think in that case we need to ensure the order of CTIDs
(basically it should be in the same order in which we have processed
them).

[1]: create or replace function dump_insert() returns trigger language plpgsql as $$ begin raise notice 'trigger = %, new table = %', TG_NAME, (select string_agg(new_table::text, ', ' order by a) from new_table); return null; end; $$;
create or replace function dump_insert() returns trigger language plpgsql as
$$
begin
raise notice 'trigger = %, new table = %',
TG_NAME,
(select string_agg(new_table::text, ', ' order by a)
from new_table);
return null;
end;
$$;

create table test (a int);
create trigger trg1_test after insert on test referencing new table
as new_table for each statement execute procedure dump_insert();
copy test (a) from stdin;
1
2
3
\.

[2]: /messages/by-id/20191206.173215.1818665441859410805.horikyota.ntt@gmail.com

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#74Robert Haas
robertmhaas@gmail.com
In reply to: Amit Kapila (#73)
Re: Parallel copy

I wonder why you're still looking at this instead of looking at just
speeding up the current code, especially the line splitting, per
previous discussion. And then coming back to study this issue more
after that's done.

On Mon, May 11, 2020 at 8:12 AM Amit Kapila <amit.kapila16@gmail.com> wrote:

Apart from this, we have analyzed the other cases as mentioned below
where we need to decide whether we can allow parallelism for the copy
command.
Case-1:
Do we want to enable parallelism for a copy when transition tables are
involved?

I think it would be OK not to support this.

Case-2:
a. When there are BEFORE/INSTEAD OF triggers on the table.
b. For partitioned tables, we can't support multi-inserts when there
are any statement-level insert triggers.
c. For inserts into foreign tables.
d. If there are volatile default expressions or the where clause
contains a volatile expression. Here, we can check if the expression
is parallel-safe, then we can allow parallelism.

This all sounds fine.

Case-3:
In copy command, for performing foreign key checks, we take KEY SHARE
lock on primary key table rows which inturn will increment the command
counter and updates the snapshot. Now, as we share the snapshots at
the beginning of the command, we can't allow it to be changed later.
So, unless we do something special for it, I think we can't allow
parallelism in such cases.

This sounds like much more of a problem to me; it'd be a significant
restriction that would kick in routine cases where the user isn't
doing anything particularly exciting. The command counter presumably
only needs to be updated once per command, so maybe we could do that
before we start parallelism. However, I think we would need to have
some kind of dynamic memory structure to which new combo CIDs can be
added by any member of the group, and then discovered by other members
of the group later. At the end of the parallel operation, the leader
must discover any combo CIDs added by others to that table before
destroying it, even if it has no immediate use for the information. We
can't allow a situation where the group members have inconsistent
notions of which combo CIDs exist or what their mappings are, and if
KEY SHARE locks are being taken, new combo CIDs could be created.

Case-4:
For Deferred Triggers, it seems we record CTIDs of tuples (via
ExecARInsertTriggers->AfterTriggerSaveEvent) and then execute deferred
triggers at transaction end using AfterTriggerFireDeferred or at end
of the statement.

I think this could be left for the future.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#75Amit Kapila
amit.kapila16@gmail.com
In reply to: Robert Haas (#74)
Re: Parallel copy

On Mon, May 11, 2020 at 11:52 PM Robert Haas <robertmhaas@gmail.com> wrote:

I wonder why you're still looking at this instead of looking at just
speeding up the current code, especially the line splitting,

Because the line splitting is just 1-2% of overall work in common
cases. See the data shared by Vignesh for various workloads [1]/messages/by-id/CALDaNm3r8cPsk0Vo_-6AXipTrVwd0o9U2S0nCmRdku1Dn-Tpqg@mail.gmail.com. The
time it takes is in range of 0.5-12% approximately and for cases like
a table with few indexes, it is not more than 1-2%.

[1]: /messages/by-id/CALDaNm3r8cPsk0Vo_-6AXipTrVwd0o9U2S0nCmRdku1Dn-Tpqg@mail.gmail.com

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#76Amit Kapila
amit.kapila16@gmail.com
In reply to: Robert Haas (#74)
Re: Parallel copy

On Mon, May 11, 2020 at 11:52 PM Robert Haas <robertmhaas@gmail.com> wrote:

Case-3:
In copy command, for performing foreign key checks, we take KEY SHARE
lock on primary key table rows which inturn will increment the command
counter and updates the snapshot. Now, as we share the snapshots at
the beginning of the command, we can't allow it to be changed later.
So, unless we do something special for it, I think we can't allow
parallelism in such cases.

This sounds like much more of a problem to me; it'd be a significant
restriction that would kick in routine cases where the user isn't
doing anything particularly exciting. The command counter presumably
only needs to be updated once per command, so maybe we could do that
before we start parallelism. However, I think we would need to have
some kind of dynamic memory structure to which new combo CIDs can be
added by any member of the group, and then discovered by other members
of the group later. At the end of the parallel operation, the leader
must discover any combo CIDs added by others to that table before
destroying it, even if it has no immediate use for the information. We
can't allow a situation where the group members have inconsistent
notions of which combo CIDs exist or what their mappings are, and if
KEY SHARE locks are being taken, new combo CIDs could be created.

AFAIU, we don't generate combo CIDs for this case. See below code in
heap_lock_tuple():

/*
* Store transaction information of xact locking the tuple.
*
* Note: Cmax is meaningless in this context, so don't set it; this avoids
* possibly generating a useless combo CID. Moreover, if we're locking a
* previously updated tuple, it's important to preserve the Cmax.
*
* Also reset the HOT UPDATE bit, but only if there's no update; otherwise
* we would break the HOT chain.
*/
tuple->t_data->t_infomask &= ~HEAP_XMAX_BITS;
tuple->t_data->t_infomask2 &= ~HEAP_KEYS_UPDATED;
tuple->t_data->t_infomask |= new_infomask;
tuple->t_data->t_infomask2 |= new_infomask2;

I don't understand why we need to do something special for combo CIDs
if they are not generated during this operation?

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#77Robert Haas
robertmhaas@gmail.com
In reply to: Amit Kapila (#76)
Re: Parallel copy

On Tue, May 12, 2020 at 1:01 AM Amit Kapila <amit.kapila16@gmail.com> wrote:

I don't understand why we need to do something special for combo CIDs
if they are not generated during this operation?

Hmm. Well I guess if they're not being generated then we don't need to
do anything about them, but I still think we should try to work around
having to disable parallelism for a table which is referenced by
foreign keys.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#78Amit Kapila
amit.kapila16@gmail.com
In reply to: Robert Haas (#77)
Re: Parallel copy

On Thu, May 14, 2020 at 12:39 AM Robert Haas <robertmhaas@gmail.com> wrote:

On Tue, May 12, 2020 at 1:01 AM Amit Kapila <amit.kapila16@gmail.com> wrote:

I don't understand why we need to do something special for combo CIDs
if they are not generated during this operation?

Hmm. Well I guess if they're not being generated then we don't need to
do anything about them, but I still think we should try to work around
having to disable parallelism for a table which is referenced by
foreign keys.

Okay, just to be clear, we want to allow parallelism for a table that
has foreign keys. Basically, a parallel copy should work while
loading data into tables having FK references.

To support that, we need to consider a few things.
a. Currently, we increment the command counter each time we take a key
share lock on a tuple during trigger execution. I am really not sure
if this is required during Copy command execution or we can just
increment it once for the copy. If we need to increment the command
counter just once for copy command then for the parallel copy we can
ensure that we do it just once at the end of the parallel copy but if
not then we might need some special handling.

b. Another point is that after inserting rows we record CTIDs of the
tuples in the event queue and then once all tuples are processed we
call FK trigger for each CTID. Now, with parallelism, the FK checks
will be processed once the worker processed one chunk. I don't see
any problem with it but still, this will be a bit different from what
we do in serial case. Do you see any problem with this?

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#79Dilip Kumar
dilipbalaut@gmail.com
In reply to: Amit Kapila (#78)
Re: Parallel copy

On Thu, May 14, 2020 at 11:48 AM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Thu, May 14, 2020 at 12:39 AM Robert Haas <robertmhaas@gmail.com> wrote:

On Tue, May 12, 2020 at 1:01 AM Amit Kapila <amit.kapila16@gmail.com> wrote:

I don't understand why we need to do something special for combo CIDs
if they are not generated during this operation?

Hmm. Well I guess if they're not being generated then we don't need to
do anything about them, but I still think we should try to work around
having to disable parallelism for a table which is referenced by
foreign keys.

Okay, just to be clear, we want to allow parallelism for a table that
has foreign keys. Basically, a parallel copy should work while
loading data into tables having FK references.

To support that, we need to consider a few things.
a. Currently, we increment the command counter each time we take a key
share lock on a tuple during trigger execution. I am really not sure
if this is required during Copy command execution or we can just
increment it once for the copy. If we need to increment the command
counter just once for copy command then for the parallel copy we can
ensure that we do it just once at the end of the parallel copy but if
not then we might need some special handling.

b. Another point is that after inserting rows we record CTIDs of the
tuples in the event queue and then once all tuples are processed we
call FK trigger for each CTID. Now, with parallelism, the FK checks
will be processed once the worker processed one chunk. I don't see
any problem with it but still, this will be a bit different from what
we do in serial case. Do you see any problem with this?

IMHO, it should not be a problem because without parallelism also we
trigger the foreign key check when we detect EOF and end of data from
STDIN. And, with parallel workers also the worker will assume that it
has complete all the work and it can go for the foreign key check is
only after the leader receives EOF and end of data from STDIN.

The only difference is that each worker is not waiting for all the
data (from all workers) to get inserted before checking the
constraint. Moreover, we are not supporting external triggers with
the parallel copy, otherwise, we might have to worry that those
triggers could do something on the primary table before we check the
constraint. I am not sure if there are any other factors that I am
missing.

--
Regards,
Dilip Kumar
EnterpriseDB: http://www.enterprisedb.com

#80Robert Haas
robertmhaas@gmail.com
In reply to: Amit Kapila (#78)
Re: Parallel copy

On Thu, May 14, 2020 at 2:18 AM Amit Kapila <amit.kapila16@gmail.com> wrote:

To support that, we need to consider a few things.
a. Currently, we increment the command counter each time we take a key
share lock on a tuple during trigger execution. I am really not sure
if this is required during Copy command execution or we can just
increment it once for the copy. If we need to increment the command
counter just once for copy command then for the parallel copy we can
ensure that we do it just once at the end of the parallel copy but if
not then we might need some special handling.

My sense is that it would be a lot more sensible to do it at the
*beginning* of the parallel operation. Once we do it once, we
shouldn't ever do it again; that's how it works now. Deferring it
until later seems much more likely to break things.

b. Another point is that after inserting rows we record CTIDs of the
tuples in the event queue and then once all tuples are processed we
call FK trigger for each CTID. Now, with parallelism, the FK checks
will be processed once the worker processed one chunk. I don't see
any problem with it but still, this will be a bit different from what
we do in serial case. Do you see any problem with this?

I think there could be some problems here. For instance, suppose that
there are two entries for different workers for the same CTID. If the
leader were trying to do all the work, they'd be handled
consecutively. If they were from completely unrelated processes,
locking would serialize them. But group locking won't, so there you
have an issue, I think. Also, it's not ideal from a work-distribution
perspective: one worker could finish early and be unable to help the
others.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#81Amit Kapila
amit.kapila16@gmail.com
In reply to: Robert Haas (#80)
Re: Parallel copy

On Fri, May 15, 2020 at 1:51 AM Robert Haas <robertmhaas@gmail.com> wrote:

On Thu, May 14, 2020 at 2:18 AM Amit Kapila <amit.kapila16@gmail.com> wrote:

To support that, we need to consider a few things.
a. Currently, we increment the command counter each time we take a key
share lock on a tuple during trigger execution. I am really not sure
if this is required during Copy command execution or we can just
increment it once for the copy. If we need to increment the command
counter just once for copy command then for the parallel copy we can
ensure that we do it just once at the end of the parallel copy but if
not then we might need some special handling.

My sense is that it would be a lot more sensible to do it at the
*beginning* of the parallel operation. Once we do it once, we
shouldn't ever do it again; that's how it works now. Deferring it
until later seems much more likely to break things.

AFAIU, we always increment the command counter after executing the
command. Why do we want to do it differently here?

b. Another point is that after inserting rows we record CTIDs of the
tuples in the event queue and then once all tuples are processed we
call FK trigger for each CTID. Now, with parallelism, the FK checks
will be processed once the worker processed one chunk. I don't see
any problem with it but still, this will be a bit different from what
we do in serial case. Do you see any problem with this?

I think there could be some problems here. For instance, suppose that
there are two entries for different workers for the same CTID.

First, let me clarify the CTID I have used in my email are for the
table in which insertion is happening which means FK table. So, in
such a case, we can't have the same CTIDs queued for different
workers. Basically, we use CTID to fetch the row from FK table later
and form a query to lock (in KEY SHARE mode) the corresponding tuple
in PK table. Now, it is possible that two different workers try to
lock the same row of PK table. I am not clear what problem group
locking can have in this case because these are non-conflicting locks.
Can you please elaborate a bit more?

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#82Robert Haas
robertmhaas@gmail.com
In reply to: Amit Kapila (#81)
Re: Parallel copy

On Fri, May 15, 2020 at 12:19 AM Amit Kapila <amit.kapila16@gmail.com> wrote:

My sense is that it would be a lot more sensible to do it at the
*beginning* of the parallel operation. Once we do it once, we
shouldn't ever do it again; that's how it works now. Deferring it
until later seems much more likely to break things.

AFAIU, we always increment the command counter after executing the
command. Why do we want to do it differently here?

Hmm, now I'm starting to think that I'm confused about what is under
discussion here. Which CommandCounterIncrement() are we talking about
here?

First, let me clarify the CTID I have used in my email are for the
table in which insertion is happening which means FK table. So, in
such a case, we can't have the same CTIDs queued for different
workers. Basically, we use CTID to fetch the row from FK table later
and form a query to lock (in KEY SHARE mode) the corresponding tuple
in PK table. Now, it is possible that two different workers try to
lock the same row of PK table. I am not clear what problem group
locking can have in this case because these are non-conflicting locks.
Can you please elaborate a bit more?

I'm concerned about two workers trying to take the same lock at the
same time. If that's prevented by the buffer locking then I think it's
OK, but if it's prevented by a heavyweight lock then it's not going to
work in this case.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#83Amit Kapila
amit.kapila16@gmail.com
In reply to: Robert Haas (#82)
Re: Parallel copy

On Fri, May 15, 2020 at 6:49 PM Robert Haas <robertmhaas@gmail.com> wrote:

On Fri, May 15, 2020 at 12:19 AM Amit Kapila <amit.kapila16@gmail.com> wrote:

My sense is that it would be a lot more sensible to do it at the
*beginning* of the parallel operation. Once we do it once, we
shouldn't ever do it again; that's how it works now. Deferring it
until later seems much more likely to break things.

AFAIU, we always increment the command counter after executing the
command. Why do we want to do it differently here?

Hmm, now I'm starting to think that I'm confused about what is under
discussion here. Which CommandCounterIncrement() are we talking about
here?

The one we do after executing a non-readonly command. Let me try to
explain by example:

CREATE TABLE tab_fk_referenced_chk(refindex INTEGER PRIMARY KEY,
height real, weight real);
insert into tab_fk_referenced_chk values( 1, 1.1, 100);
CREATE TABLE tab_fk_referencing_chk(index INTEGER REFERENCES
tab_fk_referenced_chk(refindex), height real, weight real);

COPY tab_fk_referencing_chk(index,height,weight) FROM stdin WITH(
DELIMITER ',');
1,1.1,100
1,2.1,200
1,3.1,300
\.

In the above case, even though we are executing a single command from
the user perspective, but the currentCommandId will be four after the
command. One increment will be for the copy command and the other
three increments are for locking tuple in PK table
(tab_fk_referenced_chk) for three tuples in FK table
(tab_fk_referencing_chk). Now, for parallel workers, it is
(theoretically) possible that the three tuples are processed by three
different workers which don't get synced as of now. The question was
do we see any kind of problem with this and if so can we just sync it
up at the end of parallelism.

First, let me clarify the CTID I have used in my email are for the
table in which insertion is happening which means FK table. So, in
such a case, we can't have the same CTIDs queued for different
workers. Basically, we use CTID to fetch the row from FK table later
and form a query to lock (in KEY SHARE mode) the corresponding tuple
in PK table. Now, it is possible that two different workers try to
lock the same row of PK table. I am not clear what problem group
locking can have in this case because these are non-conflicting locks.
Can you please elaborate a bit more?

I'm concerned about two workers trying to take the same lock at the
same time. If that's prevented by the buffer locking then I think it's
OK, but if it's prevented by a heavyweight lock then it's not going to
work in this case.

We do take buffer lock in exclusive mode before trying to acquire KEY
SHARE lock on the tuple, so the two workers shouldn't try to acquire
at the same time. I think you are trying to see if in any case, two
workers try to acquire heavyweight lock like tuple lock or something
like that to perform the operation then it will create a problem
because due to group locking it will allow such an operation where it
should not have been. But I don't think anything of that sort is
feasible in COPY operation and if it is then we probably need to
carefully block it or find some solution for it.

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#84vignesh C
vignesh21@gmail.com
In reply to: Amit Kapila (#83)
2 attachment(s)
Re: Parallel copy

Hi.

We have made a patch on the lines that were discussed in the previous
mails. We could achieve up to 9.87X performance improvement. The
improvement varies from case to case.

Workers/
Exec time (seconds) copy from file,
2 indexes on integer columns
1 index on text column copy from stdin,
2 indexes on integer columns
1 index on text column copy from file, 1 gist index on text column copy
from file,
3 indexes on integer columns copy from stdin, 3 indexes on integer columns
0 1162.772(1X) 1176.035(1X) 827.669(1X) 216.171(1X) 217.376(1X)
1 1110.288(1.05X) 1120.556(1.05X) 747.384(1.11X) 174.242(1.24X)
163.492(1.33X)
2 635.249(1.83X) 668.18(1.76X) 435.673(1.9X) 133.829(1.61X) 126.516(1.72X)
4 336.835(3.45X) 346.768(3.39X) 236.406(3.5X) 105.767(2.04X) 107.382(2.02X)
8 188.577(6.17X) 194.491(6.04X) 148.962(5.56X) 100.708(2.15X) 107.72(2.01X)
16 126.819(9.17X) 146.402(8.03X) 119.923(6.9X) 97.996(2.2X) 106.531(2.04X)
20 *117.845(9.87X)* 149.203(7.88X) 138.741(5.96X) 97.94(2.21X) 107.5(2.02)
30 127.554(9.11X) 161.218(7.29X) 172.443(4.8X) 98.232(2.2X) 108.778(1.99X)

Posting the initial patch to get the feedback.

Design of the Parallel Copy: The backend, to which the "COPY FROM" query is
submitted acts as leader with the responsibility of reading data from the
file/stdin, launching at most n number of workers as specified with
PARALLEL 'n' option in the "COPY FROM" query. The leader populates the
common data required for the workers execution in the DSM and shares it
with the workers. The leader then executes before statement triggers if
there exists any. Leader populates DSM chunks which includes the start
offset and chunk size, while populating the chunks it reads as many blocks
as required into the DSM data blocks from the file. Each block is of 64K
size. The leader parses the data to identify a chunk, the existing logic
from CopyReadLineText which identifies the chunks with some changes was
used for this. Leader checks if a free chunk is available to copy the
information, if there is no free chunk it waits till the required chunk is
freed up by the worker and then copies the identified chunks information
(offset & chunk size) into the DSM chunks. This process is repeated till
the complete file is processed. Simultaneously, the workers cache the
chunks(50) locally into the local memory and release the chunks to the
leader for further populating. Each worker processes the chunk that it
cached and inserts it into the table. The leader waits till all the chunks
populated are processed by the workers and exits.

We would like to include support of parallel copy for referential integrity
constraints and parallelizing copy from binary format files in the future.
The above mentioned tests were run with CSV format, file size of 5.1GB & 10
million records in the table. The postgres configuration and system
configuration used is attached in config.txt.
Myself and one of my colleagues Bharath have developed this patch. We would
like to thank Amit, Dilip, Robert, Andres, Ants, Kuntal, Alastair, Tomas,
David, Thomas, Andrew & Kyotaro for their thoughts/discussions/suggestions.

Thoughts?

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

On Mon, May 18, 2020 at 10:18 AM Amit Kapila <amit.kapila16@gmail.com>
wrote:

Show quoted text

On Fri, May 15, 2020 at 6:49 PM Robert Haas <robertmhaas@gmail.com> wrote:

On Fri, May 15, 2020 at 12:19 AM Amit Kapila <amit.kapila16@gmail.com>

wrote:

My sense is that it would be a lot more sensible to do it at the
*beginning* of the parallel operation. Once we do it once, we
shouldn't ever do it again; that's how it works now. Deferring it
until later seems much more likely to break things.

AFAIU, we always increment the command counter after executing the
command. Why do we want to do it differently here?

Hmm, now I'm starting to think that I'm confused about what is under
discussion here. Which CommandCounterIncrement() are we talking about
here?

The one we do after executing a non-readonly command. Let me try to
explain by example:

CREATE TABLE tab_fk_referenced_chk(refindex INTEGER PRIMARY KEY,
height real, weight real);
insert into tab_fk_referenced_chk values( 1, 1.1, 100);
CREATE TABLE tab_fk_referencing_chk(index INTEGER REFERENCES
tab_fk_referenced_chk(refindex), height real, weight real);

COPY tab_fk_referencing_chk(index,height,weight) FROM stdin WITH(
DELIMITER ',');
1,1.1,100
1,2.1,200
1,3.1,300
\.

In the above case, even though we are executing a single command from
the user perspective, but the currentCommandId will be four after the
command. One increment will be for the copy command and the other
three increments are for locking tuple in PK table
(tab_fk_referenced_chk) for three tuples in FK table
(tab_fk_referencing_chk). Now, for parallel workers, it is
(theoretically) possible that the three tuples are processed by three
different workers which don't get synced as of now. The question was
do we see any kind of problem with this and if so can we just sync it
up at the end of parallelism.

First, let me clarify the CTID I have used in my email are for the
table in which insertion is happening which means FK table. So, in
such a case, we can't have the same CTIDs queued for different
workers. Basically, we use CTID to fetch the row from FK table later
and form a query to lock (in KEY SHARE mode) the corresponding tuple
in PK table. Now, it is possible that two different workers try to
lock the same row of PK table. I am not clear what problem group
locking can have in this case because these are non-conflicting locks.
Can you please elaborate a bit more?

I'm concerned about two workers trying to take the same lock at the
same time. If that's prevented by the buffer locking then I think it's
OK, but if it's prevented by a heavyweight lock then it's not going to
work in this case.

We do take buffer lock in exclusive mode before trying to acquire KEY
SHARE lock on the tuple, so the two workers shouldn't try to acquire
at the same time. I think you are trying to see if in any case, two
workers try to acquire heavyweight lock like tuple lock or something
like that to perform the operation then it will create a problem
because due to group locking it will allow such an operation where it
should not have been. But I don't think anything of that sort is
feasible in COPY operation and if it is then we probably need to
carefully block it or find some solution for it.

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

Attachments:

config.txttext/plain; charset=US-ASCII; name=config.txtDownload
0001-Support-parallel-copy.patchapplication/x-patch; name=0001-Support-parallel-copy.patchDownload
From 4a1febf53529c4ea29312660c7a7b633f829c342 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>, Bharath Rupireddy <bharath.rupireddyforpostgres@gmail.com>
Date: Wed, 3 Jun 2020 09:29:58 +0530
Subject: [PATCH] Allow copy from command to process data from file/STDIN 
 contents to a table in parallel.

This feature allows the copy from to leverage multiple CPUs in order to copy
data from file/STDIN to a table. This adds a PARALLEL option to COPY FROM
command where the user can specify the number of workers that can be used
to perform the COPY FROM command. Specifying zero as number of workers will
disable parallelism.
---
 doc/src/sgml/ref/copy.sgml                  |   16 +
 src/backend/access/heap/heapam.c            |   13 -
 src/backend/access/transam/parallel.c       |    4 +
 src/backend/access/transam/xact.c           |   13 +
 src/backend/commands/copy.c                 | 2729 ++++++++++++++++++++++-----
 src/backend/optimizer/util/clauses.c        |    2 +-
 src/backend/replication/logical/tablesync.c |    2 +-
 src/include/access/xact.h                   |    1 +
 src/include/commands/copy.h                 |    4 +
 src/tools/pgindent/typedefs.list            |   10 +
 10 files changed, 2329 insertions(+), 465 deletions(-)

diff --git a/doc/src/sgml/ref/copy.sgml b/doc/src/sgml/ref/copy.sgml
index 18189ab..95d349d 100644
--- a/doc/src/sgml/ref/copy.sgml
+++ b/doc/src/sgml/ref/copy.sgml
@@ -37,6 +37,7 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
     DELIMITER '<replaceable class="parameter">delimiter_character</replaceable>'
     NULL '<replaceable class="parameter">null_string</replaceable>'
     HEADER [ <replaceable class="parameter">boolean</replaceable> ]
+    PARALLEL <replaceable class="parameter">integer</replaceable>
     QUOTE '<replaceable class="parameter">quote_character</replaceable>'
     ESCAPE '<replaceable class="parameter">escape_character</replaceable>'
     FORCE_QUOTE { ( <replaceable class="parameter">column_name</replaceable> [, ...] ) | * }
@@ -275,6 +276,21 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
    </varlistentry>
 
    <varlistentry>
+    <term><literal>PARALLEL</literal></term>
+    <listitem>
+     <para>
+      Perform <command>COPY FROM</command> in parallel using <replaceable
+      class="parameter"> integer</replaceable> background workers.  Please
+      note that it is not guaranteed that the number of parallel workers
+      specified in <replaceable class="parameter">integer</replaceable> will
+      be used during execution.  It is possible for a copy to run with fewer
+      workers than specified, or even with no workers at all.  This option is
+      allowed only in <command>COPY FROM</command>.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><literal>QUOTE</literal></term>
     <listitem>
      <para>
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 94eb37d..6991b9f 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2012,19 +2012,6 @@ static HeapTuple
 heap_prepare_insert(Relation relation, HeapTuple tup, TransactionId xid,
 					CommandId cid, int options)
 {
-	/*
-	 * Parallel operations are required to be strictly read-only in a parallel
-	 * worker.  Parallel inserts are not safe even in the leader in the
-	 * general case, because group locking means that heavyweight locks for
-	 * relation extension or GIN page locks will not conflict between members
-	 * of a lock group, but we don't prohibit that case here because there are
-	 * useful special cases that we can safely allow, such as CREATE TABLE AS.
-	 */
-	if (IsParallelWorker())
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_TRANSACTION_STATE),
-				 errmsg("cannot insert tuples in a parallel worker")));
-
 	tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
 	tup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK);
 	tup->t_data->t_infomask |= HEAP_XMAX_INVALID;
diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index 14a8690..09e7a19 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -25,6 +25,7 @@
 #include "catalog/pg_enum.h"
 #include "catalog/storage.h"
 #include "commands/async.h"
+#include "commands/copy.h"
 #include "executor/execParallel.h"
 #include "libpq/libpq.h"
 #include "libpq/pqformat.h"
@@ -145,6 +146,9 @@ static const struct
 	},
 	{
 		"parallel_vacuum_main", parallel_vacuum_main
+	},
+	{
+		"ParallelCopyMain", ParallelCopyMain
 	}
 };
 
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index cd30b62..d43902c 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -502,6 +502,19 @@ GetCurrentFullTransactionIdIfAny(void)
 }
 
 /*
+ *	AssignFullTransactionIdForWorker
+ *
+ * For parallel copy, all the workers must use the same transaction id.
+ */
+void AssignFullTransactionIdForWorker(FullTransactionId fullTransactionId)
+{
+	TransactionState s = CurrentTransactionState;
+
+	Assert((IsInParallelMode() || IsParallelWorker()));
+	s->fullTransactionId = fullTransactionId;
+}
+
+/*
  *	MarkCurrentTransactionIdLoggedIfAny
  *
  * Remember that the current xid - if it is assigned - now has been wal logged.
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 6d53dc4..2a49255 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -26,6 +26,7 @@
 #include "access/xlog.h"
 #include "catalog/dependency.h"
 #include "catalog/pg_authid.h"
+#include "catalog/pg_proc_d.h"
 #include "catalog/pg_type.h"
 #include "commands/copy.h"
 #include "commands/defrem.h"
@@ -40,11 +41,13 @@
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
+#include "optimizer/clauses.h"
 #include "optimizer/optimizer.h"
 #include "parser/parse_coerce.h"
 #include "parser/parse_collate.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_relation.h"
+#include "pgstat.h"
 #include "port/pg_bswap.h"
 #include "rewrite/rewriteHandler.h"
 #include "storage/fd.h"
@@ -96,6 +99,154 @@ typedef enum CopyInsertMethod
 } CopyInsertMethod;
 
 /*
+ * State of the chunk.
+ */
+typedef enum ChunkState
+{
+	CHUNK_INIT,					/* initial state of chunk */
+	CHUNK_LEADER_POPULATING,	/* leader processing chunk */
+	CHUNK_LEADER_POPULATED,		/* leader completed populating chunk */
+	CHUNK_WORKER_PROCESSING,	/* worker processing chunk */
+	CHUNK_WORKER_PROCESSED		/* worker completed processing chunk */
+}ChunkState;
+
+#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+
+#define DATA_BLOCK_SIZE RAW_BUF_SIZE
+#define RINGSIZE (10 * 1000)
+#define MAX_BLOCKS_COUNT 1000
+#define WORKER_CHUNK_COUNT 50	/* should be mod of RINGSIZE */
+
+#define	IsParallelCopy()		(cstate->is_parallel)
+#define IsLeader()				(cstate->pcdata->is_leader)
+#define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
+
+/*
+ * Copy data block information.
+ */
+typedef struct CopyDataBlock
+{
+	/* The number of unprocessed chunks in the current block. */
+	pg_atomic_uint32 unprocessed_chunk_parts;
+
+	/*
+	 * If the current chunk data is continued into another block,
+	 * following_block will have the position where the remaining data need to
+	 * be read.
+	 */
+	uint32	following_block;
+
+	/*
+	 * This flag will be set, when the leader finds out this block can be read
+	 * safely by the worker. This helps the worker to start processing the chunk
+	 * early where the chunk will be spread across many blocks and the worker
+	 * need not wait for the complete chunk to be processed.
+	 */
+	bool   curr_blk_completed;
+	char   data[DATA_BLOCK_SIZE + 1]; /* data read from file */
+}CopyDataBlock;
+
+/*
+ * Individual Chunk information.
+ */
+typedef struct ChunkBoundary
+{
+	/* Position of the first block in data_blocks array. */
+	uint32				first_block;
+	uint32				start_offset;   /* start offset of the chunk */
+
+	/*
+	 * Size of the current chunk -1 means chunk is yet to be filled completely,
+	 * 0 means empty chunk, >0 means chunk filled with chunk size data.
+	 */
+	pg_atomic_uint32	chunk_size;
+	pg_atomic_uint32	chunk_state;	/* chunk state */
+	uint64				cur_lineno;		/* line number for error messages */
+}ChunkBoundary;
+
+/*
+ * Array of the chunk.
+ */
+typedef struct ChunkBoundaries
+{
+	/* Position for the leader to populate a chunk. */
+	uint32			leader_pos;
+
+	/* Data read from the file/stdin by the leader process. */
+	ChunkBoundary	ring[RINGSIZE];
+}ChunkBoundaries;
+
+/*
+ * Shared information among parallel copy workers. This will be allocated in the
+ * DSM segment.
+ */
+typedef struct ShmCopyInfo
+{
+	bool					is_read_in_progress; /* file read status */
+
+	/*
+	 * Actual Chunks inserted by worker (some records will be filtered based on
+	 * where condition).
+	 */
+	pg_atomic_uint64		processed;
+	pg_atomic_uint64		total_worker_processed; /* total processed records by the workers */
+	uint64					populated; /* Chunks populated by leader */
+	uint32					cur_block_pos; /* current data block */
+	CopyDataBlock			data_blocks[MAX_BLOCKS_COUNT]; /* data block array */
+	FullTransactionId		full_transaction_id; /* xid for copy from statement */
+	CommandId				mycid;	/* command id */
+	ChunkBoundaries			chunk_boundaries; /* chunk array */
+} ShmCopyInfo;
+
+/*
+ * This structure maintains the state of the buffer information.
+ */
+typedef struct CopyBufferState
+{
+	char		    *copy_raw_buf;
+	int				 raw_buf_ptr;	/* current offset */
+	int				 copy_buf_len;	/* total size available */
+
+	/* For parallel copy */
+	CopyDataBlock   *data_blk_ptr;
+	CopyDataBlock	*curr_data_blk_ptr;
+	uint32			 chunk_size;
+	bool		 	 block_switched;
+}CopyBufferState;
+
+/*
+ * Parallel copy line buffer information.
+ */
+typedef struct ParallelCopyLineBuf
+{
+	StringInfoData		line_buf;
+	uint64				cur_lineno;	/* line number for error messages */
+}ParallelCopyLineBuf;
+
+/*
+ * Parallel copy data information.
+ */
+typedef struct ParallelCopyData
+{
+	Oid					relid;				/* relation id of the table */
+	ShmCopyInfo		   *pcshared_info;		/* common info in shared memory */
+	bool				is_leader;
+
+	/* chunk position which worker is processing */
+	uint32				worker_processed_pos;
+
+	/*
+	 * Local line_buf array, workers will copy it here and release the chunks
+	 * for the leader to continue.
+	 */
+	ParallelCopyLineBuf	worker_line_buf[WORKER_CHUNK_COUNT];
+	uint32				worker_line_buf_count; /* Number of lines */
+
+	/* Current position in worker_line_buf */
+	uint32				worker_line_buf_pos;
+}ParallelCopyData;
+
+/*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
  * even though some fields are used in only some cases.
@@ -219,12 +370,61 @@ typedef struct CopyStateData
 	 * converts it.  Note: we guarantee that there is a \0 at
 	 * raw_buf[raw_buf_len].
 	 */
-#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
+	int			nworkers;
+	bool		is_parallel;
+	ParallelCopyData *pcdata;
 } CopyStateData;
 
+/*
+ * Common information that need to be copied to shared memory.
+ */
+typedef struct CopyWorkerCommonData
+{
+	/* low-level state data */
+	CopyDest            copy_dest;		/* type of copy source/destination */
+	int                 file_encoding;	/* file or remote side's character encoding */
+	bool                need_transcoding;	/* file encoding diff from server? */
+	bool                encoding_embeds_ascii;	/* ASCII can be non-first byte? */
+
+	/* parameters from the COPY command */
+	bool                csv_mode;		/* Comma Separated Value format? */
+	bool                header_line;	/* CSV header line? */
+	int                 null_print_len; /* length of same */
+	bool                force_quote_all;	/* FORCE_QUOTE *? */
+	bool                convert_selectively;	/* do selective binary conversion? */
+
+	/* Working state for COPY FROM */
+	AttrNumber          num_defaults;
+	Oid                 relid;
+}CopyWorkerCommonData;
+
+/* List information */
+typedef struct ListInfo
+{
+	int	count;		/* count of attributes */
+
+	/* string info in the form info followed by info1, info2... infon  */
+	char    info[1];
+} ListInfo;
+
+/*
+ * List of internal parallel copy function pointers.
+ */
+static const struct
+{
+	char *fn_name;
+	copy_data_source_cb fn_addr;
+}			InternalParallelCopyFuncPtrs[] =
+
+{
+	{
+		"copy_read_data", copy_read_data
+	},
+};
+
 /* DestReceiver for COPY (query) TO */
 typedef struct
 {
@@ -254,6 +454,23 @@ typedef struct
 /* Trim the list of buffers back down to this number after flushing */
 #define MAX_PARTITION_BUFFERS	32
 
+/* DSM keys for parallel copy.  */
+#define PARALLEL_COPY_KEY_SHARED_INFO		    1
+#define PARALLEL_COPY_KEY_CSTATE				2
+#define PARALLEL_COPY_KEY_NULL_PRINT			3
+#define PARALLEL_COPY_KEY_NULL_PRINT_CLIENT		4
+#define PARALLEL_COPY_KEY_DELIM					5
+#define PARALLEL_COPY_KEY_QUOTE					6
+#define PARALLEL_COPY_KEY_ESCAPE				7
+#define PARALLEL_COPY_KEY_ATTNAME_LIST			8
+#define PARALLEL_COPY_KEY_FORCE_QUOTE_LIST  	9
+#define PARALLEL_COPY_KEY_NOT_NULL_LIST		   10
+#define PARALLEL_COPY_KEY_NULL_LIST			   11
+#define PARALLEL_COPY_KEY_CONVERT_LIST		   12
+#define PARALLEL_COPY_KEY_DATASOURCE_CB		   13
+#define PARALLEL_COPY_KEY_WHERE_CLAUSE_STR     14
+#define PARALLEL_COPY_KEY_RANGE_TABLE		   15
+
 /* Stores multi-insert data related to a single relation in CopyFrom. */
 typedef struct CopyMultiInsertBuffer
 {
@@ -295,104 +512,1484 @@ typedef struct CopyMultiInsertInfo
  */
 
 /*
- * This keeps the character read at the top of the loop in the buffer
- * even if there is more than one read-ahead.
+ * This keeps the character read at the top of the loop in the buffer
+ * even if there is more than one read-ahead.
+ */
+#define IF_NEED_REFILL_AND_NOT_EOF_CONTINUE(extralen) \
+if (1) \
+{ \
+	if (copy_buff_state.raw_buf_ptr + (extralen) >= copy_buff_state.copy_buf_len && !hit_eof) \
+	{ \
+		if (IsParallelCopy()) \
+		{ \
+			copy_buff_state.chunk_size = prev_chunk_size; /* update previous chunk size */ \
+			if (copy_buff_state.block_switched) \
+			{ \
+				pg_atomic_sub_fetch_u32(&copy_buff_state.data_blk_ptr->unprocessed_chunk_parts, 1); \
+				copy_buff_state.copy_buf_len = prev_copy_buf_len; \
+			} \
+		} \
+		copy_buff_state.raw_buf_ptr = prev_raw_ptr; /* undo fetch */ \
+		need_data = true; \
+		continue; \
+	} \
+} else ((void) 0)
+
+/* This consumes the remainder of the buffer and breaks */
+#define IF_NEED_REFILL_AND_EOF_BREAK(extralen) \
+if (1) \
+{ \
+	if (copy_buff_state.raw_buf_ptr + (extralen) >= copy_buff_state.copy_buf_len && hit_eof) \
+	{ \
+		if (extralen) \
+			copy_buff_state.raw_buf_ptr = copy_buff_state.copy_buf_len; /* consume the partial character */ \
+		/* backslash just before EOF, treat as data char */ \
+		result = true; \
+		break; \
+	} \
+} else ((void) 0)
+
+/*
+ * Transfer any approved data to line_buf; must do this to be sure
+ * there is some room in raw_buf.
+ */
+#define REFILL_LINEBUF \
+if (1) \
+{ \
+	if (copy_buff_state.raw_buf_ptr > cstate->raw_buf_index && !IsParallelCopy()) \
+		appendBinaryStringInfo(&cstate->line_buf, \
+						 cstate->raw_buf + cstate->raw_buf_index, \
+						   copy_buff_state.raw_buf_ptr - cstate->raw_buf_index); \
+	cstate->raw_buf_index = copy_buff_state.raw_buf_ptr; \
+} else ((void) 0)
+
+/* Undo any read-ahead and jump out of the block. */
+#define NO_END_OF_COPY_GOTO \
+if (1) \
+{ \
+	if (!IsParallelCopy()) \
+		copy_buff_state.raw_buf_ptr = prev_raw_ptr + 1; \
+	else \
+	{ \
+		copy_buff_state.chunk_size = prev_chunk_size + 1; \
+		if (copy_buff_state.block_switched) \
+		{ \
+			pg_atomic_sub_fetch_u32(&copy_buff_state.data_blk_ptr->unprocessed_chunk_parts, 1); \
+			cstate->raw_buf = copy_buff_state.data_blk_ptr->data; \
+			copy_buff_state.copy_buf_len = prev_copy_buf_len; \
+		} \
+		copy_buff_state.raw_buf_ptr = (prev_raw_ptr + 1) % DATA_BLOCK_SIZE; \
+	} \
+	goto not_end_of_copy; \
+} else ((void) 0)
+
+/*
+ * SEEK_COPY_BUFF_POS - Seek the buffer and set the buffer state information.
+ */
+#define SEEK_COPY_BUFF_POS(cstate, add_size, copy_buff_state) \
+{ \
+	if (IsParallelCopy()) \
+	{ \
+		copy_buff_state.chunk_size += add_size; \
+		if (copy_buff_state.raw_buf_ptr + add_size >= DATA_BLOCK_SIZE) \
+		{ \
+			/* Increment the unprocessed chunks for the block which we are working */ \
+			if (copy_buff_state.copy_raw_buf == copy_buff_state.data_blk_ptr->data) \
+				pg_atomic_add_fetch_u32(&copy_buff_state.data_blk_ptr->unprocessed_chunk_parts, 1); \
+			else \
+				pg_atomic_add_fetch_u32(&copy_buff_state.curr_data_blk_ptr->unprocessed_chunk_parts, 1); \
+			cstate->raw_buf = copy_buff_state.curr_data_blk_ptr->data; \
+			copy_buff_state.copy_buf_len -= DATA_BLOCK_SIZE; \
+			copy_buff_state.raw_buf_ptr = 0; \
+			copy_buff_state.block_switched = true; \
+		} \
+		else \
+			copy_buff_state.raw_buf_ptr += add_size; \
+	} \
+	else \
+		copy_buff_state.raw_buf_ptr += add_size; \
+}
+
+/*
+ * BEGIN_READ_LINE - Initializes the buff state for read line.
+ */
+#define BEGIN_READ_LINE(cstate, chunk_first_block) \
+{ \
+	copy_buff_state.copy_raw_buf = cstate->raw_buf; \
+	copy_buff_state.raw_buf_ptr = cstate->raw_buf_index; \
+	copy_buff_state.copy_buf_len = cstate->raw_buf_len; \
+	/* \
+	 * There is some data that was read earlier, which need to be \
+	 * processed. \
+	 */ \
+	if (IsParallelCopy()) \
+	{ \
+		copy_buff_state.chunk_size = 0; \
+		if ((copy_buff_state.copy_buf_len - copy_buff_state.raw_buf_ptr) > 0) \
+		{ \
+			ShmCopyInfo	*pcshared_info = cstate->pcdata->pcshared_info; \
+			uint32 cur_block_pos = pcshared_info->cur_block_pos; \
+			chunk_first_block = pcshared_info->cur_block_pos; \
+			copy_buff_state.data_blk_ptr = &pcshared_info->data_blocks[cur_block_pos]; \
+			copy_buff_state.curr_data_blk_ptr = copy_buff_state.data_blk_ptr; \
+		} \
+	} \
+}
+
+/*
+ * SET_RAWBUF_FOR_LOAD - Set raw_buf to the shared memory where the file data must
+ * be read.
+ */
+#define SET_RAWBUF_FOR_LOAD() \
+{ \
+	ShmCopyInfo	*pcshared_info = cstate->pcdata->pcshared_info; \
+	uint32 cur_block_pos; \
+	/* \
+	 * Mark the previous block as completed, worker can start copying this data. \
+	 */ \
+	if (copy_buff_state.data_blk_ptr != copy_buff_state.curr_data_blk_ptr && \
+		copy_buff_state.data_blk_ptr->curr_blk_completed == false) \
+		copy_buff_state.data_blk_ptr->curr_blk_completed = true; \
+	\
+	copy_buff_state.data_blk_ptr = copy_buff_state.curr_data_blk_ptr; \
+	cur_block_pos = WaitGetFreeCopyBlock(pcshared_info); \
+	copy_buff_state.curr_data_blk_ptr = &pcshared_info->data_blocks[cur_block_pos]; \
+	\
+	if (!copy_buff_state.data_blk_ptr) \
+	{ \
+		copy_buff_state.data_blk_ptr = copy_buff_state.curr_data_blk_ptr; \
+		chunk_first_block = cur_block_pos; \
+	} \
+	else if (need_data == false) \
+		copy_buff_state.data_blk_ptr->following_block = cur_block_pos; \
+	\
+	cstate->raw_buf = copy_buff_state.curr_data_blk_ptr->data; \
+	copy_buff_state.copy_raw_buf = cstate->raw_buf; \
+}
+
+/*
+ * END_CHUNK_PARALLEL_COPY - Update the chunk information in shared memory.
+ */
+#define END_CHUNK_PARALLEL_COPY() \
+{ \
+	if (!IsHeaderLine()) \
+	{ \
+		ShmCopyInfo *pcshared_info = cstate->pcdata->pcshared_info; \
+		ChunkBoundaries *chunkBoundaryPtr = &pcshared_info->chunk_boundaries; \
+		if (copy_buff_state.chunk_size) \
+		{ \
+			ChunkBoundary *chunkInfo = &chunkBoundaryPtr->ring[chunk_pos]; \
+			/* \
+			 * If raw_buf_ptr is zero, unprocessed_chunk_parts would have been \
+			 * incremented in SEEK_COPY_BUFF_POS. This will happen if the whole \
+			 * chunk finishes at the end of the current block. If the \
+			 * new_line_size > raw_buf_ptr, then the new block has only new line \
+			 * char content. The unprocessed count should not be increased in \
+			 * this case. \
+			 */ \
+			if (copy_buff_state.raw_buf_ptr != 0 && \
+				copy_buff_state.raw_buf_ptr > new_line_size) \
+				pg_atomic_add_fetch_u32(&copy_buff_state.curr_data_blk_ptr->unprocessed_chunk_parts, 1); \
+			\
+			/* Update chunk size. */ \
+			pg_atomic_write_u32(&chunkInfo->chunk_size, copy_buff_state.chunk_size); \
+			pg_atomic_write_u32(&chunkInfo->chunk_state, CHUNK_LEADER_POPULATED); \
+			elog(DEBUG1, "[Leader] After adding - chunk position:%d, chunk_size:%d", \
+						chunk_pos, copy_buff_state.chunk_size); \
+			pcshared_info->populated++; \
+		} \
+		else if (new_line_size) \
+		{ \
+			/* \
+			 * This means only new line char, empty record should be \
+			 * inserted. \
+			 */ \
+			ChunkBoundary *chunkInfo; \
+			chunk_pos = UpdateBlockInChunkInfo(cstate, -1, -1, 0, \
+											   CHUNK_LEADER_POPULATED); \
+			chunkInfo = &chunkBoundaryPtr->ring[chunk_pos]; \
+			elog(DEBUG1, "[Leader] Added empty chunk with offset:%d, chunk position:%d, chunk size:%d", \
+						 chunkInfo->start_offset, chunk_pos, \
+						 pg_atomic_read_u32(&chunkInfo->chunk_size)); \
+			pcshared_info->populated++; \
+		} \
+	}\
+	\
+	/*\
+	 * All of the read data is processed, reset index & len. In the\
+	 * subsequent read, we will get a new block and copy data in to the\
+	 * new block.\
+	 */\
+	if (copy_buff_state.raw_buf_ptr == copy_buff_state.copy_buf_len)\
+	{\
+		cstate->raw_buf_index = 0;\
+		cstate->raw_buf_len = 0;\
+	}\
+	else\
+		cstate->raw_buf_len = copy_buff_state.copy_buf_len;\
+}
+
+/*
+ * CONVERT_TO_SERVER_ENCODING - convert contents to server encoding.
+ */
+#define CONVERT_TO_SERVER_ENCODING(cstate) \
+{ \
+	/* Done reading the line.  Convert it to server encoding. */ \
+	if (cstate->need_transcoding && \
+		(!IsParallelCopy() || \
+		 (IsParallelCopy() && !IsLeader()))) \
+	{ \
+		char	   *cvt; \
+		cvt = pg_any_to_server(cstate->line_buf.data, \
+							   cstate->line_buf.len, \
+							   cstate->file_encoding); \
+		if (cvt != cstate->line_buf.data) \
+		{ \
+			/* transfer converted data back to line_buf */ \
+			resetStringInfo(&cstate->line_buf); \
+			appendBinaryStringInfo(&cstate->line_buf, cvt, strlen(cvt)); \
+			pfree(cvt); \
+		} \
+	} \
+	/* Now it's safe to use the buffer in error messages */ \
+	cstate->line_buf_converted = true; \
+}
+
+/*
+ * CLEAR_EOL_CHUNK_NON_PARALLEL - Clear EOL from the copied data.
+ */
+#define CLEAR_EOL_CHUNK_NON_PARALLEL(cstate) \
+{ \
+	/* \
+	 * If we didn't hit EOF, then we must have transferred the EOL marker \
+	 * to line_buf along with the data.  Get rid of it. \
+	 */ \
+   switch (cstate->eol_type) \
+   { \
+	   case EOL_NL: \
+		   Assert(cstate->line_buf.len >= 1); \
+		   Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n'); \
+		   cstate->line_buf.len--; \
+		   cstate->line_buf.data[cstate->line_buf.len] = '\0'; \
+		   break; \
+	   case EOL_CR: \
+		   Assert(cstate->line_buf.len >= 1); \
+		   Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\r'); \
+		   cstate->line_buf.len--; \
+		   cstate->line_buf.data[cstate->line_buf.len] = '\0'; \
+		   break; \
+	   case EOL_CRNL: \
+		   Assert(cstate->line_buf.len >= 2); \
+		   Assert(cstate->line_buf.data[cstate->line_buf.len - 2] == '\r'); \
+		   Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n'); \
+		   cstate->line_buf.len -= 2; \
+		   cstate->line_buf.data[cstate->line_buf.len] = '\0'; \
+		   break; \
+	   case EOL_UNKNOWN: \
+		   /* shouldn't get here */ \
+		   Assert(false); \
+		   break; \
+   } \
+}
+
+/*
+ * CLEAR_EOL_LINE - Wrapper for clearing EOL.
+ */
+#define CLEAR_EOL_LINE() \
+{ \
+	if (!result && !IsHeaderLine()) \
+	{ \
+		if (IsParallelCopy()) \
+			new_line_size = ClearEOLFromParallelChunk(cstate, &copy_buff_state); \
+		else \
+			CLEAR_EOL_CHUNK_NON_PARALLEL(cstate) \
+	} \
+}
+
+/*
+ * COPY_WAIT_TO_PROCESS - Wait before continuing to process.
+ */
+#define COPY_WAIT_TO_PROCESS() \
+{ \
+	CHECK_FOR_INTERRUPTS(); \
+	(void) WaitLatch(MyLatch, \
+					 WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH, \
+					 1L, WAIT_EVENT_PG_SLEEP); \
+	ResetLatch(MyLatch); \
+}
+
+/*
+ * INCREMENTPROCESSED - Increment the lines processed.
+ */
+#define INCREMENTPROCESSED(processed) \
+{ \
+	if (!IsParallelCopy()) \
+		processed++; \
+	else \
+		pg_atomic_add_fetch_u64(&cstate->pcdata->pcshared_info->processed, 1); \
+}
+
+/*
+ * GETPROCESSED - Get the lines processed.
+ */
+#define GETPROCESSED(processed) \
+if (!IsParallelCopy()) \
+	return processed; \
+else \
+	return pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
+
+static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
+
+/* non-export function prototypes */
+static CopyState BeginCopy(ParseState *pstate, bool is_from, Relation rel,
+						   RawStmt *raw_query, Oid queryRelId, List *attnamelist,
+						   List *options);
+static void EndCopy(CopyState cstate);
+static void ClosePipeToProgram(CopyState cstate);
+static CopyState BeginCopyTo(ParseState *pstate, Relation rel, RawStmt *query,
+							 Oid queryRelId, const char *filename, bool is_program,
+							 List *attnamelist, List *options);
+static void EndCopyTo(CopyState cstate);
+static uint64 DoCopyTo(CopyState cstate);
+static uint64 CopyTo(CopyState cstate);
+static void CopyOneRowTo(CopyState cstate, TupleTableSlot *slot);
+static bool CopyReadLine(CopyState cstate);
+static bool CopyReadLineText(CopyState cstate);
+static int	CopyReadAttributesText(CopyState cstate);
+static int	CopyReadAttributesCSV(CopyState cstate);
+static Datum CopyReadBinaryAttribute(CopyState cstate,
+									 int column_no, FmgrInfo *flinfo,
+									 Oid typioparam, int32 typmod,
+									 bool *isnull);
+static void CopyAttributeOutText(CopyState cstate, char *string);
+static void CopyAttributeOutCSV(CopyState cstate, char *string,
+								bool use_quote, bool single_attr);
+static List *CopyGetAttnums(TupleDesc tupDesc, Relation rel,
+							List *attnamelist);
+static char *limit_printout_length(const char *str);
+
+/* Low-level communications functions */
+static void SendCopyBegin(CopyState cstate);
+static void ReceiveCopyBegin(CopyState cstate);
+static void SendCopyEnd(CopyState cstate);
+static void CopySendData(CopyState cstate, const void *databuf, int datasize);
+static void CopySendString(CopyState cstate, const char *str);
+static void CopySendChar(CopyState cstate, char c);
+static void CopySendEndOfRow(CopyState cstate);
+static int	CopyGetData(CopyState cstate, void *databuf,
+						int minread, int maxread);
+static void CopySendInt32(CopyState cstate, int32 val);
+static bool CopyGetInt32(CopyState cstate, int32 *val);
+static void CopySendInt16(CopyState cstate, int16 val);
+static bool CopyGetInt16(CopyState cstate, int16 *val);
+
+static ParallelContext *BeginParallelCopy(int nworkers, CopyState cstate,
+										  List *attlist, Oid relid);
+static pg_attribute_always_inline void EndParallelCopy(ParallelContext *pcxt);
+static void ExecBeforeStmtTrigger(CopyState cstate);
+static pg_attribute_always_inline bool IsTriggerFunctionParallelSafe(TriggerDesc *trigdesc);
+static pg_attribute_always_inline bool IsParallelCopyAllowed(CopyState cstate);
+static void CheckCopyFromValidity(CopyState cstate);
+static pg_attribute_always_inline bool CheckExprParallelSafety(CopyState cstate);
+extern void ParallelCopyMain(dsm_segment *seg, shm_toc *toc);
+static void ParallelCopyLeader(CopyState cstate);
+static void ParallelWorkerInitialization(CopyWorkerCommonData *shared_cstate,
+										 CopyState cstate, List *attnamelist);
+static bool CacheChunkInfo(CopyState cstate, uint32 buff_count);
+static void PopulateAttributes(CopyState cstate, TupleDesc	tup_desc,
+							   List *attnamelist);
+static void PopulateCatalogInformation(CopyState cstate);
+static pg_attribute_always_inline uint32 GetChunkPosition(CopyState cstate);
+
+static pg_attribute_always_inline copy_data_source_cb LookupParallelCopyFnPtr(const char *funcname);
+static pg_attribute_always_inline char* LookupParallelCopyFnStr(copy_data_source_cb fn_addr);
+
+/*
+ * CopyCommonInfoForWorker - Copy shared_cstate using cstate information.
+ */
+static pg_attribute_always_inline void
+CopyCommonInfoForWorker(CopyState cstate, CopyWorkerCommonData *shared_cstate)
+{
+	shared_cstate->copy_dest = cstate->copy_dest;
+	shared_cstate->file_encoding = cstate->file_encoding;
+	shared_cstate->need_transcoding = cstate->need_transcoding;
+	shared_cstate->encoding_embeds_ascii = cstate->encoding_embeds_ascii;
+	shared_cstate->csv_mode = cstate->csv_mode;
+	shared_cstate->header_line = cstate->header_line;
+	shared_cstate->null_print_len = cstate->null_print_len;
+	shared_cstate->force_quote_all = cstate->force_quote_all;
+	shared_cstate->convert_selectively = cstate->convert_selectively;
+	shared_cstate->num_defaults = cstate->num_defaults;
+	shared_cstate->relid = cstate->pcdata->relid;
+}
+
+/*
+ * RetrieveSharedString - Retrieve the string from shared memory.
+ */
+static void
+RetrieveSharedString(shm_toc *toc, int sharedkey, char **copystr)
+{
+	char *shared_str_val = (char *)shm_toc_lookup(toc, sharedkey, true);
+	if (shared_str_val)
+		*copystr = pstrdup(shared_str_val);
+}
+
+/*
+ * RetrieveSharedList - Retrieve the list from shared memory.
+ */
+static void
+RetrieveSharedList(shm_toc *toc, int sharedkey, List **copylist)
+{
+	ListInfo *listinformation = (ListInfo *)shm_toc_lookup(toc, sharedkey,
+														   true);
+	if (listinformation)
+	{
+		int	length  = 0;
+		int count;
+
+		for (count = 0; count < listinformation->count; count++)
+		{
+			char *attname = (char *)(listinformation->info + length);
+			length += strlen(attname) + 1;
+			*copylist = lappend(*copylist, makeString(attname));
+		}
+	}
+}
+
+/*
+ * CopyListSharedMemory - Copy the list into shared memory.
+ */
+static void
+CopyListSharedMemory(List *inputlist, Size memsize, ListInfo *sharedlistinfo)
+{
+	ListCell   *l;
+	int			length  = 0;
+
+	MemSet(sharedlistinfo, 0, memsize);
+	foreach(l, inputlist)
+	{
+		char	   *name = strVal(lfirst(l));
+		memcpy((char *)(sharedlistinfo->info + length), name, strlen(name));
+		sharedlistinfo->count++;
+		length += strlen(name) + 1;
+	}
+}
+
+/*
+ * ComputeListSize - compute the list size.
+ */
+static int
+ComputeListSize(List *inputlist)
+{
+	int est_size = sizeof(int);
+	if (inputlist != NIL)
+	{
+		ListCell   *l;
+		foreach(l, inputlist)
+			est_size += strlen(strVal(lfirst(l))) + 1;
+	}
+
+	return est_size;
+}
+
+/*
+ * EstimateChunkKeysStr - Estimate the size required in shared memory for the
+ * input string.
+ */
+static void
+EstimateChunkKeysStr(ParallelContext *pcxt, char *inputstr)
+{
+	if (inputstr)
+	{
+		shm_toc_estimate_chunk(&pcxt->estimator, strlen(inputstr) + 1);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+}
+
+/*
+ * EstimateChunkKeysList - Estimate the size required in shared memory for the
+ * input list.
+ */
+static void
+EstimateChunkKeysList(ParallelContext *pcxt, List *inputlist,
+		Size *est_list_size)
+{
+	if (inputlist != NIL)
+	{
+		*est_list_size = ComputeListSize(inputlist);
+		shm_toc_estimate_chunk(&pcxt->estimator, *est_list_size);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+}
+
+/*
+ * InsertStringShm - Insert a string into shared memory.
+ */
+static void
+InsertStringShm(ParallelContext *pcxt, int key, char *inputstr)
+{
+	if (inputstr)
+	{
+		char *shmptr = (char *)shm_toc_allocate(pcxt->toc,
+												strlen(inputstr) + 1);
+		strcpy(shmptr, inputstr);
+		shm_toc_insert(pcxt->toc, key, shmptr);
+	}
+}
+
+/*
+ * InsertListShm - Insert a list into shared memory.
+ */
+static void
+InsertListShm(ParallelContext *pcxt, int key, List *inputlist,
+			  Size est_list_size)
+{
+	if (inputlist != NIL)
+	{
+		ListInfo *sharedlistinfo = (ListInfo *)shm_toc_allocate(pcxt->toc,
+																est_list_size);
+		CopyListSharedMemory(inputlist, est_list_size, sharedlistinfo);
+		shm_toc_insert(pcxt->toc, key, sharedlistinfo);
+	}
+}
+
+/*
+ * IsTriggerFunctionParallelSafe - Check if the trigger function is parallel
+ * safe for the triggers. Return false if any one of the trigger has parallel
+ * unsafe function.
+ */
+static pg_attribute_always_inline bool
+IsTriggerFunctionParallelSafe(TriggerDesc *trigdesc)
+{
+	int	i;
+	for (i = 0; i < trigdesc->numtriggers; i++)
+	{
+		Trigger    *trigger = &trigdesc->triggers[i];
+		int 		trigtype = RI_TRIGGER_NONE;
+
+		if (func_parallel(trigger->tgfoid) != PROPARALLEL_SAFE)
+			return false;
+
+		/* If the trigger is parallel safe, also look for RI_TRIGGER. */
+		trigtype = RI_FKey_trigger_type(trigger->tgfoid);
+		if (trigtype == RI_TRIGGER_PK || trigtype == RI_TRIGGER_FK)
+			return false;
+	}
+
+	return true;
+}
+
+/*
+ * CheckExprParallelSafety - determine parallel safety of volatile expressions
+ * in default clause of column definition or in where clause and return true if
+ * they are parallel safe.
+ */
+static pg_attribute_always_inline bool
+CheckExprParallelSafety(CopyState cstate)
+{
+	if (contain_volatile_functions(cstate->whereClause))
+	{
+		if (!is_parallel_safe(NULL, (Node *)cstate->whereClause))
+			return false;
+	}
+
+	if (cstate->volatile_defexprs && cstate->defexprs != NULL &&
+		cstate->num_defaults != 0)
+	{
+		int     i;
+		for (i = 0; i < cstate->num_defaults; i++)
+		{
+			if (!is_parallel_safe(NULL, (Node *) cstate->defexprs[i]->expr))
+				return false;
+		}
+	}
+
+	return true;
+}
+
+/*
+ * FindInsertMethod - determine insert mode single, multi, or multi conditional.
+ */
+static pg_attribute_always_inline CopyInsertMethod
+FindInsertMethod(CopyState cstate)
+{
+	if (cstate->rel->trigdesc != NULL &&
+		(cstate->rel->trigdesc->trig_insert_before_row ||
+		 cstate->rel->trigdesc->trig_insert_instead_row))
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
+			cstate->rel->trigdesc != NULL &&
+			cstate->rel->trigdesc->trig_insert_new_table)
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+		return CIM_MULTI_CONDITIONAL;
+
+	return CIM_MULTI;
+}
+
+/*
+ * IsParallelCopyAllowed - check for the cases where parallel copy is not
+ * applicable.
+ */
+static pg_attribute_always_inline bool
+IsParallelCopyAllowed(CopyState cstate)
+{
+	/* Parallel copy not allowed for freeze & binary option. */
+	if (cstate->freeze || cstate->binary)
+		return false;
+
+	/* Check if copy is into foreign table. */
+	if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+		return false;
+
+	/* Check if copy is into a temporary table. */
+	if (RELATION_IS_LOCAL(cstate->rel) || RELATION_IS_OTHER_TEMP(cstate->rel))
+		return false;
+
+	/* Check if trigger function is parallel safe. */
+	if (cstate->rel->trigdesc != NULL &&
+			!IsTriggerFunctionParallelSafe(cstate->rel->trigdesc))
+		return false;
+
+	/*
+	 * Check if there is after statement or instead of trigger or transition
+	 * table triggers.
+	 */
+	if (cstate->rel->trigdesc != NULL &&
+		(cstate->rel->trigdesc->trig_insert_after_statement ||
+		 cstate->rel->trigdesc->trig_insert_instead_row ||
+		 cstate->rel->trigdesc->trig_insert_new_table))
+		return false;
+
+	/* Check if the volatile expressions are parallel safe, if present any. */
+	if (!CheckExprParallelSafety(cstate))
+		return false;
+
+	/* Check if the insertion mode is single. */
+	if (FindInsertMethod(cstate) == CIM_SINGLE)
+		return false;
+
+	return true;
+}
+
+/*
+ * BeginParallelCopy - start parallel copy tasks.
+ *
+ * Get the number of workers required to perform the parallel copy. The data
+ * structures that are required by the parallel workers will be initialized, the
+ * size required in DSM will be calculated and the necessary keys will be loaded
+ * in the DSM. The specified number of workers will then be launched.
+ *
+ */
+static ParallelContext*
+BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
+{
+	ParallelContext *pcxt;
+	ShmCopyInfo *shared_info_ptr;
+	CopyWorkerCommonData *shared_cstate;
+	FullTransactionId full_transaction_id;
+	Size est_shared_info;
+	Size est_cstateshared;
+	Size est_att_list_size;
+	Size est_quote_list_size;
+	Size est_notnull_list_size;
+	Size est_null_list_size;
+	Size est_convert_list_size;
+	Size est_datasource_cb_size;
+	int  count = 0;
+	char *whereClauseStr = NULL;
+	char *rangeTableStr = NULL;
+	int  parallel_workers = 0;
+	ParallelCopyData *pcdata;
+
+	CheckCopyFromValidity(cstate);
+
+	parallel_workers = Min(nworkers, max_worker_processes);
+
+	/* Can't perform copy in parallel */
+	if (parallel_workers <= 0)
+		return NULL;
+
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	cstate->pcdata = pcdata;
+
+	/*
+	 * User chosen parallel copy. Determine if the parallel copy is actually
+	 * allowed. If not, go with the non-parallel mode.
+	 */
+	if (!IsParallelCopyAllowed(cstate))
+		return NULL;
+
+	full_transaction_id = GetCurrentFullTransactionId();
+
+	EnterParallelMode();
+	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
+								 parallel_workers);
+	Assert(pcxt->nworkers > 0);
+
+	/*
+	 * Estimate size for shared information for PARALLEL_COPY_KEY_SHARED_INFO
+	 */
+	est_shared_info = sizeof(ShmCopyInfo);
+	shm_toc_estimate_chunk(&pcxt->estimator, est_shared_info);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_CSTATE */
+	est_cstateshared = 	MAXALIGN(sizeof(CopyWorkerCommonData));
+	shm_toc_estimate_chunk(&pcxt->estimator, est_cstateshared);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	EstimateChunkKeysStr(pcxt, cstate->null_print);
+	EstimateChunkKeysStr(pcxt, cstate->null_print_client);
+	EstimateChunkKeysStr(pcxt, cstate->delim);
+	EstimateChunkKeysStr(pcxt, cstate->quote);
+	EstimateChunkKeysStr(pcxt, cstate->escape);
+
+	if (cstate->whereClause != NULL)
+	{
+		whereClauseStr = nodeToString(cstate->whereClause);
+		EstimateChunkKeysStr(pcxt, whereClauseStr);
+	}
+
+	if (cstate->range_table != NULL)
+	{
+		rangeTableStr = nodeToString(cstate->range_table);
+		EstimateChunkKeysStr(pcxt, rangeTableStr);
+	}
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_XID. */
+	shm_toc_estimate_chunk(&pcxt->estimator, sizeof(FullTransactionId));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_ATTNAME_LIST.
+	 */
+	EstimateChunkKeysList(pcxt, attnamelist, &est_att_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_FORCE_QUOTE_LIST.
+	 */
+	EstimateChunkKeysList(pcxt, cstate->force_quote, &est_quote_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_NOT_NULL_LIST.
+	 */
+	EstimateChunkKeysList(pcxt, cstate->force_notnull,
+							 &est_notnull_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_NULL_LIST.
+	 */
+	EstimateChunkKeysList(pcxt, cstate->force_null, &est_null_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_CONVERT_LIST.
+	 */
+	EstimateChunkKeysList(pcxt, cstate->convert_select,
+							 &est_convert_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_DATASOURCE_CB.
+	 */
+	if (cstate->data_source_cb)
+	{
+		char *functionname = LookupParallelCopyFnStr(cstate->data_source_cb);
+		est_datasource_cb_size = strlen(functionname) + 1;
+		shm_toc_estimate_chunk(&pcxt->estimator, est_datasource_cb_size);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+
+	InitializeParallelDSM(pcxt);
+
+	/* If no DSM segment was available, back out (do serial copy) */
+	if (pcxt->seg == NULL)
+	{
+		EndParallelCopy(pcxt);
+		return NULL;
+	}
+
+	/* Allocate shared memory for PARALLEL_COPY_KEY_SHARED_INFO */
+	shared_info_ptr = (ShmCopyInfo *) shm_toc_allocate(pcxt->toc,
+													   est_shared_info);
+	MemSet(shared_info_ptr, 0, est_shared_info);
+	shared_info_ptr->is_read_in_progress = true;
+	shared_info_ptr->cur_block_pos = -1;
+	shared_info_ptr->full_transaction_id = full_transaction_id;
+	shared_info_ptr->mycid = GetCurrentCommandId(true);
+	for (count = 0; count < RINGSIZE; count++)
+	{
+		ChunkBoundary *chunkInfo = &shared_info_ptr->chunk_boundaries.ring[count];
+		pg_atomic_init_u32(&(chunkInfo->chunk_size), -1);
+	}
+
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_SHARED_INFO, shared_info_ptr);
+	pcdata->pcshared_info = shared_info_ptr;
+	pcdata->relid = relid;
+
+	/* Store shared build state, for which we reserved space. */
+	shared_cstate = (CopyWorkerCommonData *)shm_toc_allocate(pcxt->toc,
+															est_cstateshared);
+
+	/* copy cstate variables. */
+	CopyCommonInfoForWorker(cstate, shared_cstate);
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_CSTATE, shared_cstate);
+
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_NULL_PRINT, cstate->null_print);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_NULL_PRINT_CLIENT,
+					  cstate->null_print_client);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_DELIM, cstate->delim);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_QUOTE, cstate->quote);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_ESCAPE, cstate->escape);
+
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_ATTNAME_LIST,
+					attnamelist, est_att_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_FORCE_QUOTE_LIST,
+					cstate->force_quote, est_quote_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_NOT_NULL_LIST,
+					cstate->force_notnull, est_notnull_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_NULL_LIST, cstate->force_null,
+					est_null_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_CONVERT_LIST,
+					cstate->convert_select, est_convert_list_size);
+
+	if (cstate->data_source_cb)
+	{
+		char *functionname = LookupParallelCopyFnStr(cstate->data_source_cb);
+		char *data_source_cb = (char *) shm_toc_allocate(pcxt->toc,
+														 est_datasource_cb_size);
+		strcpy(data_source_cb, functionname);
+		shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_DATASOURCE_CB,
+					   data_source_cb);
+	}
+
+	if (cstate->whereClause)
+		InsertStringShm(pcxt, PARALLEL_COPY_KEY_WHERE_CLAUSE_STR,
+						whereClauseStr);
+
+	if(cstate->range_table)
+		InsertStringShm(pcxt, PARALLEL_COPY_KEY_RANGE_TABLE, rangeTableStr);
+
+	LaunchParallelWorkers(pcxt);
+	if (pcxt->nworkers_launched == 0)
+	{
+		EndParallelCopy(pcxt);
+		return NULL;
+	}
+
+	/*
+	 * Caller needs to wait for all launched workers when we return.  Make sure
+	 * that the failure-to-start case will not hang forever.
+	 */
+	WaitForParallelWorkersToAttach(pcxt);
+
+	pcdata->is_leader = true;
+	cstate->is_parallel = true;
+	return pcxt;
+}
+
+/*
+ * EndParallelCopy - end the parallel copy tasks.
+ */
+static pg_attribute_always_inline void
+EndParallelCopy(ParallelContext *pcxt)
+{
+	Assert(!IsParallelWorker());
+
+	DestroyParallelContext(pcxt);
+	ExitParallelMode();
+}
+
+/*
+ * ParallelWorkerInitialization - Initialize parallel worker.
+ */
+static void
+ParallelWorkerInitialization(CopyWorkerCommonData *shared_cstate,
+		CopyState cstate, List *attnamelist)
+{
+	uint32		count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	cstate->copy_dest = shared_cstate->copy_dest;
+	cstate->file_encoding = shared_cstate->file_encoding;
+	cstate->need_transcoding = shared_cstate->need_transcoding;
+	cstate->encoding_embeds_ascii = shared_cstate->encoding_embeds_ascii;
+	cstate->csv_mode = shared_cstate->csv_mode;
+	cstate->header_line = shared_cstate->header_line;
+	cstate->null_print_len = shared_cstate->null_print_len;
+	cstate->force_quote_all = shared_cstate->force_quote_all;
+	cstate->convert_selectively = shared_cstate->convert_selectively;
+	cstate->num_defaults = shared_cstate->num_defaults;
+	pcdata->relid = shared_cstate->relid;
+
+	PopulateAttributes(cstate, tup_desc, attnamelist);
+
+	/* Initialize state variables. */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/* Set up variables to avoid per-attribute overhead. */
+	initStringInfo(&cstate->attribute_buf);
+
+	initStringInfo(&cstate->line_buf);
+	for (count = 0; count < WORKER_CHUNK_COUNT;count++)
+		initStringInfo(&pcdata->worker_line_buf[count].line_buf);
+
+	cstate->line_buf_converted = false;
+	cstate->raw_buf = NULL;
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+
+	PopulateCatalogInformation(cstate);
+
+	/* Create workspace for CopyReadAttributes results. */
+	if (!cstate->binary)
+	{
+		AttrNumber	attr_count = list_length(cstate->attnumlist);
+
+		cstate->max_fields = attr_count;
+		cstate->raw_fields = (char **)palloc(attr_count * sizeof(char *));
+	}
+}
+
+/*
+ * CacheChunkInfo - Cache the chunk information to local memory.
+ */
+static bool
+CacheChunkInfo(CopyState cstate, uint32 buff_count)
+{
+	ShmCopyInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	uint32			write_pos;
+	CopyDataBlock *data_blk_ptr;
+	ChunkBoundary *chunkInfo;
+	uint32 offset;
+	int dataSize;
+	int copiedSize = 0;
+
+	resetStringInfo(&pcdata->worker_line_buf[buff_count].line_buf);
+	write_pos = GetChunkPosition(cstate);
+	if (-1 == write_pos)
+		return true;
+
+	/* Get the current chunk information. */
+	chunkInfo = &pcshared_info->chunk_boundaries.ring[write_pos];
+	if (pg_atomic_read_u32(&chunkInfo->chunk_size) == 0)
+		goto empty_data_chunk_update;
+
+	/* Get the block information. */
+	data_blk_ptr = &pcshared_info->data_blocks[chunkInfo->first_block];
+
+	/* Get the offset information from where the data must be copied. */
+	offset = chunkInfo->start_offset;
+	pcdata->worker_line_buf[buff_count].cur_lineno = chunkInfo->cur_lineno;
+
+	elog(DEBUG1, "[Worker] Processing - chunk position:%d, block:%d, unprocessed chunks:%d, offset:%d, chunk size:%d",
+				 write_pos, chunkInfo->first_block,
+				 pg_atomic_read_u32(&data_blk_ptr->unprocessed_chunk_parts),
+				 offset, pg_atomic_read_u32(&chunkInfo->chunk_size));
+
+	for (;;)
+	{
+		/*
+		 * There is a possibility that the above loop has come out because
+		 * data_blk_ptr->curr_blk_completed is set, but dataSize read might
+		 * be an old value, if data_blk_ptr->curr_blk_completed and the chunk is
+		 * completed, chunk_size will be set. Read the chunk_size again to be
+		 * sure if it is complete or partial block.
+		 */
+		dataSize = pg_atomic_read_u32(&chunkInfo->chunk_size);
+		if (dataSize)
+		{
+			int remainingSize = dataSize - copiedSize;
+			if (!remainingSize)
+				break;
+
+			/* Whole chunk is in current block. */
+			if (remainingSize + offset < DATA_BLOCK_SIZE)
+			{
+				appendBinaryStringInfo(&pcdata->worker_line_buf[buff_count].line_buf, &data_blk_ptr->data[offset],
+									   remainingSize);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_chunk_parts, 1);
+				break;
+			}
+			else
+			{
+				/* Chunk is spread across the blocks. */
+				int chunkInCurrentBlock =  DATA_BLOCK_SIZE - offset;
+				appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+										 &data_blk_ptr->data[offset],
+										 chunkInCurrentBlock);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_chunk_parts, 1);
+				copiedSize += chunkInCurrentBlock;
+				while (copiedSize < dataSize)
+				{
+					CopyDataBlock *currBlkPtr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+
+					/*
+					 * If complete data is present in current block use
+					 * dataSize - copiedSize, or copy the whole block from
+					 * current block.
+					 */
+					int currentBlockCopySize = Min(dataSize - copiedSize, DATA_BLOCK_SIZE);
+					appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+											 &currBlkPtr->data[0],
+											 currentBlockCopySize);
+					pg_atomic_sub_fetch_u32(&currBlkPtr->unprocessed_chunk_parts, 1);
+					copiedSize += currentBlockCopySize;
+					data_blk_ptr = currBlkPtr;
+				}
+
+				break;
+			}
+		}
+		else
+		{
+			/* Copy this complete block from the current offset. */
+			int chunkInCurrentBlock =  DATA_BLOCK_SIZE - offset;
+			appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+									 &data_blk_ptr->data[offset],
+									 chunkInCurrentBlock);
+			pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_chunk_parts, 1);
+			copiedSize += chunkInCurrentBlock;
+
+			/*
+			 * Reset the offset. For the first copy, copy from the offset. For
+			 * the subsequent copy the complete block.
+			 */
+			offset = 0;
+
+			/* Set data_blk_ptr to the following block. */
+			data_blk_ptr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+		}
+
+		for (;;)
+		{
+			/* Get the size of this chunk */
+			dataSize = pg_atomic_read_u32(&chunkInfo->chunk_size);
+
+			/*
+			 * If the data is present in current block chunkInfo.chunk_size
+			 * will be updated. If the data is spread across the blocks either
+			 * of chunkInfo.chunk_size or data_blk_ptr->curr_blk_completed can
+			 * be updated. chunkInfo.chunk_size will be updated if the complete
+			 * read is finished. data_blk_ptr->curr_blk_completed will be
+			 * updated if processing of current block is finished and data
+			 * processing is not finished.
+			 */
+			if (data_blk_ptr->curr_blk_completed || (dataSize != -1))
+				break;
+
+			COPY_WAIT_TO_PROCESS()
+		}
+	}
+
+empty_data_chunk_update:
+	elog(DEBUG1, "[Worker] Completed processing chunk:%d", write_pos);
+	pg_atomic_write_u32(&chunkInfo->chunk_state, CHUNK_WORKER_PROCESSED);
+	pg_atomic_write_u32(&chunkInfo->chunk_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+	return false;
+}
+
+/*
+ * GetWorkerChunk - Returns a chunk for worker to process.
+ */
+static bool
+GetWorkerChunk(CopyState cstate)
+{
+	uint32 buff_count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+
+	/*
+	 * Copy the chunk data to line_buf and release the chunk position so that the
+	 * worker can continue loading data.
+	 */
+	if (pcdata->worker_line_buf_pos < pcdata->worker_line_buf_count)
+		goto return_chunk;
+
+	pcdata->worker_line_buf_pos = 0;
+	pcdata->worker_line_buf_count = 0;
+
+	for (buff_count = 0; buff_count < WORKER_CHUNK_COUNT; buff_count++)
+	{
+		bool result = CacheChunkInfo(cstate, buff_count);
+		if (result)
+			break;
+
+		pcdata->worker_line_buf_count++;
+	}
+
+	if (pcdata->worker_line_buf_count)
+		goto return_chunk;
+	else
+		resetStringInfo(&cstate->line_buf);
+
+	return true;
+
+return_chunk:
+	cstate->line_buf = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].line_buf;
+	cstate->cur_lineno = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].cur_lineno;
+	cstate->line_buf_valid = true;
+
+	/* Mark that encoding conversion hasn't occurred yet. */
+	cstate->line_buf_converted = false;
+	CONVERT_TO_SERVER_ENCODING(cstate)
+	pcdata->worker_line_buf_pos++;
+	return false;
+}
+
+/*
+ * ParallelCopyMain - parallel copy worker's code.
+ *
+ * Where clause handling, convert tuple to columns, add default null values for
+ * the missing columns that are not present in that record. Find the partition
+ * if it is partitioned table, invoke before row insert Triggers, handle
+ * constraints and insert the tuples.
+ */
+void
+ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
+{
+	CopyState cstate;
+	ParallelCopyData *pcdata;
+	ShmCopyInfo *pcshared_info;
+	CopyWorkerCommonData *shared_cstate;
+	Relation	rel = NULL;
+	MemoryContext oldcontext;
+	List *attlist = NIL;
+	char *data_source_cb;
+	char *whereClauseStr = NULL;
+	char *rangeTableStr = NULL;
+
+	/* Allocate workspace and zero all fields. */
+	cstate = (CopyStateData *) palloc0(sizeof(CopyStateData));
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	cstate->pcdata = pcdata;
+	pcdata->is_leader = false;
+	pcdata->worker_processed_pos = -1;
+	cstate->is_parallel = true;
+
+	/*
+	 * We allocate everything used by a cstate in a new memory context. This
+	 * avoids memory leaks during repeated use of COPY in a query.
+	 */
+	cstate->copycontext = AllocSetContextCreate(CurrentMemoryContext,
+												"COPY",
+												ALLOCSET_DEFAULT_SIZES);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	pcshared_info = (ShmCopyInfo *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_SHARED_INFO,
+														false);
+
+	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
+
+	pcdata->pcshared_info = pcshared_info;
+	AssignFullTransactionIdForWorker(pcshared_info->full_transaction_id);
+
+	shared_cstate = (CopyWorkerCommonData *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE,
+														   false);
+
+	cstate->null_print = (char *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_NULL_PRINT,
+												true);
+	cstate->null_print_client = (char *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_NULL_PRINT_CLIENT,
+													   true);
+
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_DELIM, &cstate->delim);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_QUOTE, &cstate->quote);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_ESCAPE, &cstate->escape);
+
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_ATTNAME_LIST, &attlist);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_FORCE_QUOTE_LIST, &cstate->force_quote);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_NOT_NULL_LIST, &cstate->force_notnull);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_NULL_LIST, &cstate->force_null);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_CONVERT_LIST, &cstate->convert_select);
+	data_source_cb = (char *)shm_toc_lookup(toc,
+											PARALLEL_COPY_KEY_DATASOURCE_CB,
+											true);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_WHERE_CLAUSE_STR, &whereClauseStr);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_RANGE_TABLE, &rangeTableStr);
+
+	if (data_source_cb)
+		cstate->data_source_cb = LookupParallelCopyFnPtr(data_source_cb);
+
+	if (whereClauseStr)
+	{
+		Node *whereClauseCnvrtdFrmStr = (Node *) stringToNode(whereClauseStr);
+		cstate->whereClause = whereClauseCnvrtdFrmStr;
+	}
+
+	if (rangeTableStr)
+	{
+		List *rangeTableCnvrtdFrmStr = (List *) stringToNode(rangeTableStr);
+		cstate->range_table = rangeTableCnvrtdFrmStr;
+	}
+
+	/* Open and lock the relation, using the appropriate lock type. */
+	rel = table_open(shared_cstate->relid, RowExclusiveLock);
+	cstate->rel = rel;
+	ParallelWorkerInitialization(shared_cstate, cstate, attlist);
+
+	CopyFrom(cstate);
+
+	if (rel != NULL)
+		table_close(rel, RowExclusiveLock);
+
+	MemoryContextSwitchTo(oldcontext);
+	return;
+}
+
+/*
+ * UpdateBlockInChunkInfo - Update the chunk information.
+ */
+static pg_attribute_always_inline int
+UpdateBlockInChunkInfo(CopyState cstate, uint32 blk_pos,
+					   uint32 offset, uint32 chunk_size, uint32 chunk_state)
+{
+	ShmCopyInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ChunkBoundaries *chunkBoundaryPtr = &pcshared_info->chunk_boundaries;
+	ChunkBoundary *chunkInfo;
+	int chunk_pos = chunkBoundaryPtr->leader_pos;
+
+	/* Update the chunk information for the worker to pick and process. */
+	chunkInfo = &chunkBoundaryPtr->ring[chunk_pos];
+	while (pg_atomic_read_u32(&chunkInfo->chunk_size) != -1)
+		COPY_WAIT_TO_PROCESS()
+
+	chunkInfo->first_block = blk_pos;
+	chunkInfo->start_offset = offset;
+	chunkInfo->cur_lineno = cstate->cur_lineno;
+	pg_atomic_write_u32(&chunkInfo->chunk_size, chunk_size);
+	pg_atomic_write_u32(&chunkInfo->chunk_state, chunk_state);
+	chunkBoundaryPtr->leader_pos = (chunkBoundaryPtr->leader_pos + 1) % RINGSIZE;
+
+	return chunk_pos;
+}
+
+/*
+ * ParallelCopyLeader - parallel copy leader's functionality.
+ *
+ * Leader will populate the shared queue and share it across the workers. Leader
+ * will read the table data from the file and copy the contents to block. Leader
+ * will then read the input contents and identify the data based on line beaks.
+ * This information is called chunk. The chunk will be populate in
+ * ChunkBoundary. Workers will then pick up this information and insert
+ * in to table. Leader will do this till it completes processing the file.
+ * Leader executes the before statement if before statement trigger is present.
+ * Leader read the data from input file. Leader then loads data to data blocks
+ * as and when required block by block. Leader traverses through the data block
+ * to identify one chunk. It gets a free chunk to copy the information, if there
+ * is no free chunk it will wait till there is one free chunk.
+ * Server copies  the identified chunks information into chunks. This process is
+ * repeated till the complete file is processed.
+ * Leader will wait till all the chunks populated are processed by the workers
+ * and exits.
+ */
+static void
+ParallelCopyLeader(CopyState cstate)
+{
+	ShmCopyInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
+
+	/* Execute the before statement triggers from the leader */
+	ExecBeforeStmtTrigger(cstate);
+
+	/* On input just throw the header line away. */
+	if (cstate->cur_lineno == 0 && cstate->header_line)
+	{
+		cstate->cur_lineno++;
+		if (CopyReadLine(cstate))
+		{
+			pcshared_info->is_read_in_progress = false;
+			return;			/* done */
+		}
+	}
+
+	for (;;)
+	{
+		bool done;
+		cstate->cur_lineno++;
+
+		/* Actually read the line into memory here. */
+		done = CopyReadLine(cstate);
+
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			break;
+	}
+
+	pcshared_info->is_read_in_progress = false;
+	cstate->cur_lineno = 0;
+}
+
+/*
+ * GetChunkPosition - return the chunk position that worker should process.
+ */
+static uint32
+GetChunkPosition(CopyState cstate)
+{
+	ParallelCopyData *pcdata = cstate->pcdata;
+	ShmCopyInfo *pcshared_info = pcdata->pcshared_info;
+	uint32  previous_pos = pcdata->worker_processed_pos;
+	uint32 write_pos = (previous_pos == -1) ? 0 : (previous_pos + 1) % RINGSIZE;
+	for (;;)
+	{
+		int		dataSize;
+		bool	is_read_in_progress = pcshared_info->is_read_in_progress;
+		ChunkBoundary *chunkInfo;
+		CopyDataBlock *data_blk_ptr;
+		ChunkState chunk_state = CHUNK_LEADER_POPULATED;
+		ChunkState curr_chunk_state;
+		CHECK_FOR_INTERRUPTS();
+
+		/* File read completed & no elements to process. */
+		if (!is_read_in_progress &&
+			(pcshared_info->populated ==
+			 pg_atomic_read_u64(&pcshared_info->total_worker_processed)))
+		{
+			write_pos = -1;
+			break;
+		}
+
+		/* Get the current chunk information. */
+		chunkInfo = &pcshared_info->chunk_boundaries.ring[write_pos];
+		curr_chunk_state = pg_atomic_read_u32(&chunkInfo->chunk_state);
+		if ((write_pos % WORKER_CHUNK_COUNT == 0) &&
+			(curr_chunk_state == CHUNK_WORKER_PROCESSED ||
+			 curr_chunk_state == CHUNK_WORKER_PROCESSING))
+		{
+			pcdata->worker_processed_pos = write_pos;
+			write_pos = (write_pos + WORKER_CHUNK_COUNT) %  RINGSIZE;
+			continue;
+		}
+
+		/* Get the size of this chunk. */
+		dataSize = pg_atomic_read_u32(&chunkInfo->chunk_size);
+
+		if (dataSize != 0) /* If not an empty chunk. */
+		{
+			/* Get the block information. */
+			data_blk_ptr = &pcshared_info->data_blocks[chunkInfo->first_block];
+
+			if (!data_blk_ptr->curr_blk_completed && (dataSize == -1))
+			{
+				/* Wait till the current chunk or block is added. */
+				COPY_WAIT_TO_PROCESS()
+				continue;
+			}
+		}
+
+		/* Make sure that no worker has consumed this element. */
+		if (pg_atomic_compare_exchange_u32(&chunkInfo->chunk_state,
+										   &chunk_state, CHUNK_WORKER_PROCESSING))
+			break;
+	}
+
+	pcdata->worker_processed_pos = write_pos;
+	return write_pos;
+}
+
+/*
+ * GetFreeCopyBlock - Get a free block for data to be copied.
+ */
+static pg_attribute_always_inline uint32
+GetFreeCopyBlock(ShmCopyInfo *pcshared_info)
+{
+	int count = 0;
+	uint32 last_free_block = pcshared_info->cur_block_pos;
+	uint32 block_pos = (last_free_block != -1) ? ((last_free_block + 1) % MAX_BLOCKS_COUNT): 0;
+
+	/* Get a new block for copying data. */
+	while (count < MAX_BLOCKS_COUNT)
+	{
+		CopyDataBlock *inputBlk = &pcshared_info->data_blocks[block_pos];
+		uint32 unprocessed_chunk_parts = pg_atomic_read_u32(&inputBlk->unprocessed_chunk_parts);
+		if (unprocessed_chunk_parts == 0)
+		{
+			inputBlk->curr_blk_completed = false;
+			pcshared_info->cur_block_pos = block_pos;
+			return block_pos;
+		}
+
+		block_pos = (block_pos + 1) % MAX_BLOCKS_COUNT;
+		count++;
+	}
+
+	return -1;
+}
+
+/*
+ * WaitGetFreeCopyBlock - If there are no blocks available, wait and get a block
+ * for copying data.
  */
-#define IF_NEED_REFILL_AND_NOT_EOF_CONTINUE(extralen) \
-if (1) \
-{ \
-	if (raw_buf_ptr + (extralen) >= copy_buf_len && !hit_eof) \
-	{ \
-		raw_buf_ptr = prev_raw_ptr; /* undo fetch */ \
-		need_data = true; \
-		continue; \
-	} \
-} else ((void) 0)
+static uint32
+WaitGetFreeCopyBlock(ShmCopyInfo *pcshared_info)
+{
+	uint32 new_free_pos = -1;
+	for (;;)
+	{
+		new_free_pos = GetFreeCopyBlock(pcshared_info);
+		if (new_free_pos != -1)	/* We have got one block, break now. */
+			break;
 
-/* This consumes the remainder of the buffer and breaks */
-#define IF_NEED_REFILL_AND_EOF_BREAK(extralen) \
-if (1) \
-{ \
-	if (raw_buf_ptr + (extralen) >= copy_buf_len && hit_eof) \
-	{ \
-		if (extralen) \
-			raw_buf_ptr = copy_buf_len; /* consume the partial character */ \
-		/* backslash just before EOF, treat as data char */ \
-		result = true; \
-		break; \
-	} \
-} else ((void) 0)
+		COPY_WAIT_TO_PROCESS()
+	}
+
+	return new_free_pos;
+}
 
 /*
- * Transfer any approved data to line_buf; must do this to be sure
- * there is some room in raw_buf.
+ * LookupParallelCopyFnPtr - Look up parallel copy function pointer.
  */
-#define REFILL_LINEBUF \
-if (1) \
-{ \
-	if (raw_buf_ptr > cstate->raw_buf_index) \
-	{ \
-		appendBinaryStringInfo(&cstate->line_buf, \
-							 cstate->raw_buf + cstate->raw_buf_index, \
-							   raw_buf_ptr - cstate->raw_buf_index); \
-		cstate->raw_buf_index = raw_buf_ptr; \
-	} \
-} else ((void) 0)
-
-/* Undo any read-ahead and jump out of the block. */
-#define NO_END_OF_COPY_GOTO \
-if (1) \
-{ \
-	raw_buf_ptr = prev_raw_ptr + 1; \
-	goto not_end_of_copy; \
-} else ((void) 0)
+static pg_attribute_always_inline copy_data_source_cb
+LookupParallelCopyFnPtr(const char *funcname)
+{
+	int			i;
 
-static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
+	for (i = 0; i < lengthof(InternalParallelCopyFuncPtrs); i++)
+	{
+		if (strcmp(InternalParallelCopyFuncPtrs[i].fn_name, funcname) == 0)
+			return InternalParallelCopyFuncPtrs[i].fn_addr;
+	}
 
+	/* We can only reach this by programming error. */
+	elog(ERROR, "internal function \"%s\" not found", funcname);
+}
 
-/* non-export function prototypes */
-static CopyState BeginCopy(ParseState *pstate, bool is_from, Relation rel,
-						   RawStmt *raw_query, Oid queryRelId, List *attnamelist,
-						   List *options);
-static void EndCopy(CopyState cstate);
-static void ClosePipeToProgram(CopyState cstate);
-static CopyState BeginCopyTo(ParseState *pstate, Relation rel, RawStmt *query,
-							 Oid queryRelId, const char *filename, bool is_program,
-							 List *attnamelist, List *options);
-static void EndCopyTo(CopyState cstate);
-static uint64 DoCopyTo(CopyState cstate);
-static uint64 CopyTo(CopyState cstate);
-static void CopyOneRowTo(CopyState cstate, TupleTableSlot *slot);
-static bool CopyReadLine(CopyState cstate);
-static bool CopyReadLineText(CopyState cstate);
-static int	CopyReadAttributesText(CopyState cstate);
-static int	CopyReadAttributesCSV(CopyState cstate);
-static Datum CopyReadBinaryAttribute(CopyState cstate,
-									 int column_no, FmgrInfo *flinfo,
-									 Oid typioparam, int32 typmod,
-									 bool *isnull);
-static void CopyAttributeOutText(CopyState cstate, char *string);
-static void CopyAttributeOutCSV(CopyState cstate, char *string,
-								bool use_quote, bool single_attr);
-static List *CopyGetAttnums(TupleDesc tupDesc, Relation rel,
-							List *attnamelist);
-static char *limit_printout_length(const char *str);
+/*
+ * LookupParallelCopyFnStr - Lookup function string from a function pointer.
+ */
+static pg_attribute_always_inline char*
+LookupParallelCopyFnStr(copy_data_source_cb fn_addr)
+{
+	int			i;
 
-/* Low-level communications functions */
-static void SendCopyBegin(CopyState cstate);
-static void ReceiveCopyBegin(CopyState cstate);
-static void SendCopyEnd(CopyState cstate);
-static void CopySendData(CopyState cstate, const void *databuf, int datasize);
-static void CopySendString(CopyState cstate, const char *str);
-static void CopySendChar(CopyState cstate, char c);
-static void CopySendEndOfRow(CopyState cstate);
-static int	CopyGetData(CopyState cstate, void *databuf,
-						int minread, int maxread);
-static void CopySendInt32(CopyState cstate, int32 val);
-static bool CopyGetInt32(CopyState cstate, int32 *val);
-static void CopySendInt16(CopyState cstate, int16 val);
-static bool CopyGetInt16(CopyState cstate, int16 *val);
+	for (i = 0; i < lengthof(InternalParallelCopyFuncPtrs); i++)
+	{
+		if (InternalParallelCopyFuncPtrs[i].fn_addr == fn_addr)
+			return InternalParallelCopyFuncPtrs[i].fn_name;
+	}
 
+	/* We can only reach this by programming error. */
+	elog(ERROR, "internal function pointer not found");
+}
 
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
@@ -611,7 +2208,6 @@ static int
 CopyGetData(CopyState cstate, void *databuf, int minread, int maxread)
 {
 	int			bytesread = 0;
-
 	switch (cstate->copy_dest)
 	{
 		case COPY_FILE:
@@ -790,17 +2386,17 @@ CopyGetInt16(CopyState cstate, int16 *val)
  * bufferload boundary.
  */
 static bool
-CopyLoadRawBuf(CopyState cstate)
+CopyLoadRawBuf(CopyState cstate, int raw_buf_len, int *raw_buf_index)
 {
 	int			nbytes;
 	int			inbytes;
 
-	if (cstate->raw_buf_index < cstate->raw_buf_len)
+	if (!IsParallelCopy() && *raw_buf_index < raw_buf_len)
 	{
-		/* Copy down the unprocessed data */
-		nbytes = cstate->raw_buf_len - cstate->raw_buf_index;
-		memmove(cstate->raw_buf, cstate->raw_buf + cstate->raw_buf_index,
-				nbytes);
+		/* Copy down the unprocessed data. */
+		nbytes = raw_buf_len - *raw_buf_index;
+		memmove(cstate->raw_buf, cstate->raw_buf + *raw_buf_index,
+					nbytes);
 	}
 	else
 		nbytes = 0;				/* no data need be saved */
@@ -809,12 +2405,16 @@ CopyLoadRawBuf(CopyState cstate)
 						  1, RAW_BUF_SIZE - nbytes);
 	nbytes += inbytes;
 	cstate->raw_buf[nbytes] = '\0';
-	cstate->raw_buf_index = 0;
+	if (!IsParallelCopy())
+	{
+		cstate->raw_buf_index = 0;
+		*raw_buf_index = 0;
+	}
 	cstate->raw_buf_len = nbytes;
+
 	return (inbytes > 0);
 }
 
-
 /*
  *	 DoCopy executes the SQL COPY statement
  *
@@ -1060,6 +2660,7 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 
 	if (is_from)
 	{
+		ParallelContext *pcxt = NULL;
 		Assert(rel);
 
 		/* check read-only transaction and parallel mode */
@@ -1069,7 +2670,24 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 		cstate = BeginCopyFrom(pstate, rel, stmt->filename, stmt->is_program,
 							   NULL, stmt->attlist, stmt->options);
 		cstate->whereClause = whereClause;
-		*processed = CopyFrom(cstate);	/* copy from file to database */
+		cstate->is_parallel = false;
+
+		if (cstate->nworkers > 0)
+			pcxt = BeginParallelCopy(cstate->nworkers, cstate, stmt->attlist,
+									 relid);
+
+		if (pcxt)
+		{
+			ParallelCopyLeader(cstate);
+
+			/* Wait for all copy workers to finish */
+			WaitForParallelWorkersToFinish(pcxt);
+			*processed = pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
+			EndParallelCopy(pcxt);
+		}
+		else
+			*processed = CopyFrom(cstate); /* copy from file to database */
+
 		EndCopyFrom(cstate);
 	}
 	else
@@ -1118,6 +2736,7 @@ ProcessCopyOptions(ParseState *pstate,
 	cstate->is_copy_from = is_from;
 
 	cstate->file_encoding = -1;
+	cstate->nworkers = -1;
 
 	/* Extract options from the statement node tree */
 	foreach(option, options)
@@ -1286,6 +2905,26 @@ ProcessCopyOptions(ParseState *pstate,
 								defel->defname),
 						 parser_errposition(pstate, defel->location)));
 		}
+		else if (strcmp(defel->defname, "parallel") == 0)
+		{
+			if (!cstate->is_copy_from)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("parallel option supported only for copy from"),
+						 parser_errposition(pstate, defel->location)));
+			if (cstate->nworkers >= 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options"),
+						 parser_errposition(pstate, defel->location)));
+			cstate->nworkers = atoi(defGetString(defel));
+			if (cstate->nworkers < 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("argument to option \"%s\" must be a non-negative integer",
+								defel->defname),
+						 parser_errposition(pstate, defel->location)));
+		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_SYNTAX_ERROR),
@@ -1377,67 +3016,194 @@ ProcessCopyOptions(ParseState *pstate,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 				 errmsg("COPY quote must be a single one-byte character")));
 
-	if (cstate->csv_mode && cstate->delim[0] == cstate->quote[0])
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-				 errmsg("COPY delimiter and quote must be different")));
+	if (cstate->csv_mode && cstate->delim[0] == cstate->quote[0])
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				 errmsg("COPY delimiter and quote must be different")));
+
+	/* Check escape */
+	if (!cstate->csv_mode && cstate->escape != NULL)
+		ereport(ERROR,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("COPY escape available only in CSV mode")));
+
+	if (cstate->csv_mode && strlen(cstate->escape) != 1)
+		ereport(ERROR,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("COPY escape must be a single one-byte character")));
+
+	/* Check force_quote */
+	if (!cstate->csv_mode && (cstate->force_quote || cstate->force_quote_all))
+		ereport(ERROR,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("COPY force quote available only in CSV mode")));
+	if ((cstate->force_quote || cstate->force_quote_all) && is_from)
+		ereport(ERROR,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("COPY force quote only available using COPY TO")));
+
+	/* Check force_notnull */
+	if (!cstate->csv_mode && cstate->force_notnull != NIL)
+		ereport(ERROR,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("COPY force not null available only in CSV mode")));
+	if (cstate->force_notnull != NIL && !is_from)
+		ereport(ERROR,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("COPY force not null only available using COPY FROM")));
+
+	/* Check force_null */
+	if (!cstate->csv_mode && cstate->force_null != NIL)
+		ereport(ERROR,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("COPY force null available only in CSV mode")));
+
+	if (cstate->force_null != NIL && !is_from)
+		ereport(ERROR,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("COPY force null only available using COPY FROM")));
+
+	/* Don't allow the delimiter to appear in the null string. */
+	if (strchr(cstate->null_print, cstate->delim[0]) != NULL)
+		ereport(ERROR,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("COPY delimiter must not appear in the NULL specification")));
+
+	/* Don't allow the CSV quote char to appear in the null string. */
+	if (cstate->csv_mode &&
+		strchr(cstate->null_print, cstate->quote[0]) != NULL)
+		ereport(ERROR,
+				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				 errmsg("CSV quote character must not appear in the NULL specification")));
+}
+
+/*
+ * PopulateAttributes - Populate the attributes.
+ */
+void PopulateAttributes(CopyState cstate, TupleDesc	tupDesc, List *attnamelist)
+{
+	int			num_phys_attrs;
+
+	/* Generate or convert list of attributes to process */
+	cstate->attnumlist = CopyGetAttnums(tupDesc, cstate->rel, attnamelist);
+
+	num_phys_attrs = tupDesc->natts;
+
+	/* Convert FORCE_QUOTE name list to per-column flags, check validity */
+	cstate->force_quote_flags = (bool *) palloc0(num_phys_attrs * sizeof(bool));
+	if (cstate->force_quote_all)
+	{
+		int			i;
+
+		for (i = 0; i < num_phys_attrs; i++)
+			cstate->force_quote_flags[i] = true;
+	}
+	else if (cstate->force_quote)
+	{
+		List	   *attnums;
+		ListCell   *cur;
+
+		attnums = CopyGetAttnums(tupDesc, cstate->rel, cstate->force_quote);
+
+		foreach(cur, attnums)
+		{
+			int			attnum = lfirst_int(cur);
+			Form_pg_attribute attr = TupleDescAttr(tupDesc, attnum - 1);
+
+			if (!list_member_int(cstate->attnumlist, attnum))
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
+						 errmsg("FORCE_QUOTE column \"%s\" not referenced by COPY",
+								NameStr(attr->attname))));
+			cstate->force_quote_flags[attnum - 1] = true;
+		}
+	}
+
+	/* Convert FORCE_NOT_NULL name list to per-column flags, check validity */
+	cstate->force_notnull_flags = (bool *) palloc0(num_phys_attrs * sizeof(bool));
+	if (cstate->force_notnull)
+	{
+		List	   *attnums;
+		ListCell   *cur;
+
+		attnums = CopyGetAttnums(tupDesc, cstate->rel, cstate->force_notnull);
+
+		foreach(cur, attnums)
+		{
+			int			attnum = lfirst_int(cur);
+			Form_pg_attribute attr = TupleDescAttr(tupDesc, attnum - 1);
+
+			if (!list_member_int(cstate->attnumlist, attnum))
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
+						 errmsg("FORCE_NOT_NULL column \"%s\" not referenced by COPY",
+								NameStr(attr->attname))));
+			cstate->force_notnull_flags[attnum - 1] = true;
+		}
+	}
+
+	/* Convert FORCE_NULL name list to per-column flags, check validity */
+	cstate->force_null_flags = (bool *) palloc0(num_phys_attrs * sizeof(bool));
+	if (cstate->force_null)
+	{
+		List	   *attnums;
+		ListCell   *cur;
+
+		attnums = CopyGetAttnums(tupDesc, cstate->rel, cstate->force_null);
 
-	/* Check escape */
-	if (!cstate->csv_mode && cstate->escape != NULL)
-		ereport(ERROR,
-				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-				 errmsg("COPY escape available only in CSV mode")));
+		foreach(cur, attnums)
+		{
+			int			attnum = lfirst_int(cur);
+			Form_pg_attribute attr = TupleDescAttr(tupDesc, attnum - 1);
 
-	if (cstate->csv_mode && strlen(cstate->escape) != 1)
-		ereport(ERROR,
-				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-				 errmsg("COPY escape must be a single one-byte character")));
+			if (!list_member_int(cstate->attnumlist, attnum))
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
+						 errmsg("FORCE_NULL column \"%s\" not referenced by COPY",
+								NameStr(attr->attname))));
+			cstate->force_null_flags[attnum - 1] = true;
+		}
+	}
 
-	/* Check force_quote */
-	if (!cstate->csv_mode && (cstate->force_quote || cstate->force_quote_all))
-		ereport(ERROR,
-				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-				 errmsg("COPY force quote available only in CSV mode")));
-	if ((cstate->force_quote || cstate->force_quote_all) && is_from)
-		ereport(ERROR,
-				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-				 errmsg("COPY force quote only available using COPY TO")));
+	/* Convert convert_selectively name list to per-column flags */
+	if (cstate->convert_selectively)
+	{
+		List	   *attnums;
+		ListCell   *cur;
 
-	/* Check force_notnull */
-	if (!cstate->csv_mode && cstate->force_notnull != NIL)
-		ereport(ERROR,
-				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-				 errmsg("COPY force not null available only in CSV mode")));
-	if (cstate->force_notnull != NIL && !is_from)
-		ereport(ERROR,
-				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-				 errmsg("COPY force not null only available using COPY FROM")));
+		cstate->convert_select_flags = (bool *) palloc0(num_phys_attrs * sizeof(bool));
 
-	/* Check force_null */
-	if (!cstate->csv_mode && cstate->force_null != NIL)
-		ereport(ERROR,
-				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-				 errmsg("COPY force null available only in CSV mode")));
+		attnums = CopyGetAttnums(tupDesc, cstate->rel, cstate->convert_select);
 
-	if (cstate->force_null != NIL && !is_from)
-		ereport(ERROR,
-				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-				 errmsg("COPY force null only available using COPY FROM")));
+		foreach(cur, attnums)
+		{
+			int			attnum = lfirst_int(cur);
+			Form_pg_attribute attr = TupleDescAttr(tupDesc, attnum - 1);
 
-	/* Don't allow the delimiter to appear in the null string. */
-	if (strchr(cstate->null_print, cstate->delim[0]) != NULL)
-		ereport(ERROR,
-				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-				 errmsg("COPY delimiter must not appear in the NULL specification")));
+			if (!list_member_int(cstate->attnumlist, attnum))
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
+						 errmsg_internal("selected column \"%s\" not referenced by COPY",
+										 NameStr(attr->attname))));
+			cstate->convert_select_flags[attnum - 1] = true;
+		}
+	}
 
-	/* Don't allow the CSV quote char to appear in the null string. */
-	if (cstate->csv_mode &&
-		strchr(cstate->null_print, cstate->quote[0]) != NULL)
-		ereport(ERROR,
-				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-				 errmsg("CSV quote character must not appear in the NULL specification")));
-}
+	/* Use client encoding when ENCODING option is not specified. */
+	if (cstate->file_encoding < 0)
+		cstate->file_encoding = pg_get_client_encoding();
 
+	/*
+	 * Set up encoding conversion info.  Even if the file and server encodings
+	 * are the same, we must apply pg_any_to_server() to validate data in
+	 * multibyte encodings.
+	 */
+	cstate->need_transcoding =
+		(cstate->file_encoding != GetDatabaseEncoding() ||
+		 pg_database_encoding_max_length() > 1);
+	/* See Multibyte encoding comment above */
+	cstate->encoding_embeds_ascii = PG_ENCODING_IS_CLIENT_ONLY(cstate->file_encoding);
+}
 /*
  * Common setup routines used by BeginCopyFrom and BeginCopyTo.
  *
@@ -1464,7 +3230,6 @@ BeginCopy(ParseState *pstate,
 {
 	CopyState	cstate;
 	TupleDesc	tupDesc;
-	int			num_phys_attrs;
 	MemoryContext oldcontext;
 
 	/* Allocate workspace and zero all fields */
@@ -1630,126 +3395,7 @@ BeginCopy(ParseState *pstate,
 		tupDesc = cstate->queryDesc->tupDesc;
 	}
 
-	/* Generate or convert list of attributes to process */
-	cstate->attnumlist = CopyGetAttnums(tupDesc, cstate->rel, attnamelist);
-
-	num_phys_attrs = tupDesc->natts;
-
-	/* Convert FORCE_QUOTE name list to per-column flags, check validity */
-	cstate->force_quote_flags = (bool *) palloc0(num_phys_attrs * sizeof(bool));
-	if (cstate->force_quote_all)
-	{
-		int			i;
-
-		for (i = 0; i < num_phys_attrs; i++)
-			cstate->force_quote_flags[i] = true;
-	}
-	else if (cstate->force_quote)
-	{
-		List	   *attnums;
-		ListCell   *cur;
-
-		attnums = CopyGetAttnums(tupDesc, cstate->rel, cstate->force_quote);
-
-		foreach(cur, attnums)
-		{
-			int			attnum = lfirst_int(cur);
-			Form_pg_attribute attr = TupleDescAttr(tupDesc, attnum - 1);
-
-			if (!list_member_int(cstate->attnumlist, attnum))
-				ereport(ERROR,
-						(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
-						 errmsg("FORCE_QUOTE column \"%s\" not referenced by COPY",
-								NameStr(attr->attname))));
-			cstate->force_quote_flags[attnum - 1] = true;
-		}
-	}
-
-	/* Convert FORCE_NOT_NULL name list to per-column flags, check validity */
-	cstate->force_notnull_flags = (bool *) palloc0(num_phys_attrs * sizeof(bool));
-	if (cstate->force_notnull)
-	{
-		List	   *attnums;
-		ListCell   *cur;
-
-		attnums = CopyGetAttnums(tupDesc, cstate->rel, cstate->force_notnull);
-
-		foreach(cur, attnums)
-		{
-			int			attnum = lfirst_int(cur);
-			Form_pg_attribute attr = TupleDescAttr(tupDesc, attnum - 1);
-
-			if (!list_member_int(cstate->attnumlist, attnum))
-				ereport(ERROR,
-						(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
-						 errmsg("FORCE_NOT_NULL column \"%s\" not referenced by COPY",
-								NameStr(attr->attname))));
-			cstate->force_notnull_flags[attnum - 1] = true;
-		}
-	}
-
-	/* Convert FORCE_NULL name list to per-column flags, check validity */
-	cstate->force_null_flags = (bool *) palloc0(num_phys_attrs * sizeof(bool));
-	if (cstate->force_null)
-	{
-		List	   *attnums;
-		ListCell   *cur;
-
-		attnums = CopyGetAttnums(tupDesc, cstate->rel, cstate->force_null);
-
-		foreach(cur, attnums)
-		{
-			int			attnum = lfirst_int(cur);
-			Form_pg_attribute attr = TupleDescAttr(tupDesc, attnum - 1);
-
-			if (!list_member_int(cstate->attnumlist, attnum))
-				ereport(ERROR,
-						(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
-						 errmsg("FORCE_NULL column \"%s\" not referenced by COPY",
-								NameStr(attr->attname))));
-			cstate->force_null_flags[attnum - 1] = true;
-		}
-	}
-
-	/* Convert convert_selectively name list to per-column flags */
-	if (cstate->convert_selectively)
-	{
-		List	   *attnums;
-		ListCell   *cur;
-
-		cstate->convert_select_flags = (bool *) palloc0(num_phys_attrs * sizeof(bool));
-
-		attnums = CopyGetAttnums(tupDesc, cstate->rel, cstate->convert_select);
-
-		foreach(cur, attnums)
-		{
-			int			attnum = lfirst_int(cur);
-			Form_pg_attribute attr = TupleDescAttr(tupDesc, attnum - 1);
-
-			if (!list_member_int(cstate->attnumlist, attnum))
-				ereport(ERROR,
-						(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
-						 errmsg_internal("selected column \"%s\" not referenced by COPY",
-										 NameStr(attr->attname))));
-			cstate->convert_select_flags[attnum - 1] = true;
-		}
-	}
-
-	/* Use client encoding when ENCODING option is not specified. */
-	if (cstate->file_encoding < 0)
-		cstate->file_encoding = pg_get_client_encoding();
-
-	/*
-	 * Set up encoding conversion info.  Even if the file and server encodings
-	 * are the same, we must apply pg_any_to_server() to validate data in
-	 * multibyte encodings.
-	 */
-	cstate->need_transcoding =
-		(cstate->file_encoding != GetDatabaseEncoding() ||
-		 pg_database_encoding_max_length() > 1);
-	/* See Multibyte encoding comment above */
-	cstate->encoding_embeds_ascii = PG_ENCODING_IS_CLIENT_ONLY(cstate->file_encoding);
-
+	PopulateAttributes(cstate, tupDesc, attnamelist);
 	cstate->copy_dest = COPY_FILE;	/* default */
 
 	MemoryContextSwitchTo(oldcontext);
@@ -2638,41 +4284,67 @@ CopyMultiInsertInfoStore(CopyMultiInsertInfo *miinfo, ResultRelInfo *rri,
 	/* Store the line number so we can properly report any errors later */
 	buffer->linenos[buffer->nused] = lineno;
 
-	/* Record this slot as being used */
-	buffer->nused++;
+	/* Record this slot as being used */
+	buffer->nused++;
+
+	/* Update how many tuples are stored and their size */
+	miinfo->bufferedTuples++;
+	miinfo->bufferedBytes += tuplen;
+}
+
+/*
+ * ExecBeforeStmtTrigger - Execute the before statement trigger, this will be
+ * executed for parallel copy by the leader process.
+ */
+static void
+ExecBeforeStmtTrigger(CopyState cstate)
+{
+	EState	   *estate = CreateExecutorState();
+	ResultRelInfo *resultRelInfo;
+
+	Assert(IsLeader());
+
+	/*
+	 * We need a ResultRelInfo so we can use the regular executor's
+	 * index-entry-making machinery.  (There used to be a huge amount of code
+	 * here that basically duplicated execUtils.c ...)
+	 */
+	resultRelInfo = makeNode(ResultRelInfo);
+	InitResultRelInfo(resultRelInfo,
+					  cstate->rel,
+					  1,		/* must match rel's position in range_table */
+					  NULL,
+					  0);
+
+	/* Verify the named relation is a valid target for INSERT */
+	CheckValidResultRel(resultRelInfo, CMD_INSERT);
+
+	estate->es_result_relations = resultRelInfo;
+	estate->es_num_result_relations = 1;
+	estate->es_result_relation_info = resultRelInfo;
+
+	ExecInitRangeTable(estate, cstate->range_table);
+
+	/*
+	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
+	 * should do this for COPY, since it's not really an "INSERT" statement as
+	 * such. However, executing these triggers maintains consistency with the
+	 * EACH ROW triggers that we already fire on COPY.
+	 */
+	ExecBSInsertTriggers(estate, resultRelInfo);
+
+	/* Close any trigger target relations */
+	ExecCleanUpTriggerState(estate);
 
-	/* Update how many tuples are stored and their size */
-	miinfo->bufferedTuples++;
-	miinfo->bufferedBytes += tuplen;
+	FreeExecutorState(estate);
 }
 
 /*
- * Copy FROM file to relation.
+ * Check if the relation specified in copy from is valid.
  */
-uint64
-CopyFrom(CopyState cstate)
+static void
+CheckCopyFromValidity(CopyState cstate)
 {
-	ResultRelInfo *resultRelInfo;
-	ResultRelInfo *target_resultRelInfo;
-	ResultRelInfo *prevResultRelInfo = NULL;
-	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
-	ModifyTableState *mtstate;
-	ExprContext *econtext;
-	TupleTableSlot *singleslot = NULL;
-	MemoryContext oldcontext = CurrentMemoryContext;
-
-	PartitionTupleRouting *proute = NULL;
-	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
-	int			ti_options = 0; /* start with default options for insert */
-	BulkInsertState bistate = NULL;
-	CopyInsertMethod insertMethod;
-	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
-	uint64		processed = 0;
-	bool		has_before_insert_row_trig;
-	bool		has_instead_insert_row_trig;
-	bool		leafpart_use_multi_insert = false;
-
 	Assert(cstate->rel);
 
 	/*
@@ -2708,6 +4380,44 @@ CopyFrom(CopyState cstate)
 					 errmsg("cannot copy to non-table relation \"%s\"",
 							RelationGetRelationName(cstate->rel))));
 	}
+}
+
+/*
+ * Copy FROM file to relation.
+ */
+uint64
+CopyFrom(CopyState cstate)
+{
+	ResultRelInfo *resultRelInfo;
+	ResultRelInfo *target_resultRelInfo;
+	ResultRelInfo *prevResultRelInfo = NULL;
+	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
+	ModifyTableState *mtstate;
+	ExprContext *econtext;
+	TupleTableSlot *singleslot = NULL;
+	MemoryContext oldcontext = CurrentMemoryContext;
+
+	PartitionTupleRouting *proute = NULL;
+	ErrorContextCallback errcallback;
+	CommandId	mycid = IsParallelCopy() ? cstate->pcdata->pcshared_info->mycid :
+										   GetCurrentCommandId(true);
+	int			ti_options = 0; /* start with default options for insert */
+	BulkInsertState bistate = NULL;
+	CopyInsertMethod insertMethod;
+	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
+	uint64		processed = 0;
+	bool		has_before_insert_row_trig;
+	bool		has_instead_insert_row_trig;
+	bool		leafpart_use_multi_insert = false;
+
+	/*
+	 * Perform this check if it is not parallel copy. In case of parallel
+	 * copy, this check is done by the leader, so that if any invalid case
+	 * exist the copy from command will error out from the leader itself,
+	 * avoiding launching workers, just to throw error.
+	 */
+	if (!IsParallelCopy())
+		CheckCopyFromValidity(cstate);
 
 	/*
 	 * If the target file is new-in-transaction, we assume that checking FSM
@@ -2934,13 +4644,16 @@ CopyFrom(CopyState cstate)
 	has_instead_insert_row_trig = (resultRelInfo->ri_TrigDesc &&
 								   resultRelInfo->ri_TrigDesc->trig_insert_instead_row);
 
-	/*
-	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
-	 * should do this for COPY, since it's not really an "INSERT" statement as
-	 * such. However, executing these triggers maintains consistency with the
-	 * EACH ROW triggers that we already fire on COPY.
-	 */
-	ExecBSInsertTriggers(estate, resultRelInfo);
+	if (!IsParallelCopy())
+	{
+		/*
+		 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
+		 * should do this for COPY, since it's not really an "INSERT" statement as
+		 * such. However, executing these triggers maintains consistency with the
+		 * EACH ROW triggers that we already fire on COPY.
+		 */
+		ExecBSInsertTriggers(estate, resultRelInfo);
+	}
 
 	econtext = GetPerTupleExprContext(estate);
 
@@ -3262,7 +4975,7 @@ CopyFrom(CopyState cstate)
 			 * or FDW; this is the same definition used by nodeModifyTable.c
 			 * for counting tuples inserted by an INSERT command.
 			 */
-			processed++;
+			INCREMENTPROCESSED(processed)
 		}
 	}
 
@@ -3317,30 +5030,14 @@ CopyFrom(CopyState cstate)
 
 	FreeExecutorState(estate);
 
-	return processed;
+	GETPROCESSED(processed)
 }
 
 /*
- * Setup to read tuples from a file for COPY FROM.
- *
- * 'rel': Used as a template for the tuples
- * 'filename': Name of server-local file to read
- * 'attnamelist': List of char *, columns to include. NIL selects all cols.
- * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
- *
- * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ * PopulateCatalogInformation - populate the catalog information.
  */
-CopyState
-BeginCopyFrom(ParseState *pstate,
-			  Relation rel,
-			  const char *filename,
-			  bool is_program,
-			  copy_data_source_cb data_source_cb,
-			  List *attnamelist,
-			  List *options)
+void PopulateCatalogInformation(CopyState cstate)
 {
-	CopyState	cstate;
-	bool		pipe = (filename == NULL);
 	TupleDesc	tupDesc;
 	AttrNumber	num_phys_attrs,
 				num_defaults;
@@ -3350,31 +5047,8 @@ BeginCopyFrom(ParseState *pstate,
 	Oid			in_func_oid;
 	int		   *defmap;
 	ExprState **defexprs;
-	MemoryContext oldcontext;
 	bool		volatile_defexprs;
 
-	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
-	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
-
-	/* Initialize state variables */
-	cstate->reached_eof = false;
-	cstate->eol_type = EOL_UNKNOWN;
-	cstate->cur_relname = RelationGetRelationName(cstate->rel);
-	cstate->cur_lineno = 0;
-	cstate->cur_attname = NULL;
-	cstate->cur_attval = NULL;
-
-	/* Set up variables to avoid per-attribute overhead. */
-	initStringInfo(&cstate->attribute_buf);
-	initStringInfo(&cstate->line_buf);
-	cstate->line_buf_converted = false;
-	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
-	cstate->raw_buf_index = cstate->raw_buf_len = 0;
-
-	/* Assign range table, we'll need it in CopyFrom. */
-	if (pstate)
-		cstate->range_table = pstate->p_rtable;
-
 	tupDesc = RelationGetDescr(cstate->rel);
 	num_phys_attrs = tupDesc->natts;
 	num_defaults = 0;
@@ -3452,6 +5126,55 @@ BeginCopyFrom(ParseState *pstate,
 	cstate->defexprs = defexprs;
 	cstate->volatile_defexprs = volatile_defexprs;
 	cstate->num_defaults = num_defaults;
+}
+
+/*
+ * Setup to read tuples from a file for COPY FROM.
+ *
+ * 'rel': Used as a template for the tuples
+ * 'filename': Name of server-local file to read
+ * 'attnamelist': List of char *, columns to include. NIL selects all cols.
+ * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
+ *
+ * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ */
+CopyState
+BeginCopyFrom(ParseState *pstate,
+			  Relation rel,
+			  const char *filename,
+			  bool is_program,
+			  copy_data_source_cb data_source_cb,
+			  List *attnamelist,
+			  List *options)
+{
+	CopyState	cstate;
+	bool		pipe = (filename == NULL);
+	MemoryContext oldcontext;
+
+	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist,
+					   options);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	/* Initialize state variables */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/* Set up variables to avoid per-attribute overhead. */
+	initStringInfo(&cstate->attribute_buf);
+	initStringInfo(&cstate->line_buf);
+	cstate->line_buf_converted = false;
+	cstate->raw_buf = (IsParallelCopy()) ? NULL : (char *) palloc(RAW_BUF_SIZE + 1);
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+
+	/* Assign range table, we'll need it in CopyFrom. */
+	if (pstate)
+		cstate->range_table = pstate->p_rtable;
+
+	PopulateCatalogInformation(cstate);
 	cstate->is_program = is_program;
 
 	if (data_source_cb)
@@ -3588,26 +5311,35 @@ NextCopyFromRawFields(CopyState cstate, char ***fields, int *nfields)
 	/* only available for text or csv input */
 	Assert(!cstate->binary);
 
-	/* on input just throw the header line away */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (IsParallelCopy())
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
-			return false;		/* done */
+		done = GetWorkerChunk(cstate);
+		if (done && cstate->line_buf.len == 0)
+			return false;
 	}
+	else
+	{
+		/* on input just throw the header line away */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
+		{
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+				return false;		/* done */
+		}
 
-	cstate->cur_lineno++;
+		cstate->cur_lineno++;
 
-	/* Actually read the line into memory here */
-	done = CopyReadLine(cstate);
+		/* Actually read the line into memory here */
+		done = CopyReadLine(cstate);
 
-	/*
-	 * EOF at start of line means we're done.  If we see EOF after some
-	 * characters, we act as though it was newline followed by EOF, ie,
-	 * process the line and then exit loop on next iteration.
-	 */
-	if (done && cstate->line_buf.len == 0)
-		return false;
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			return false;
+	}
 
 	/* Parse the line into de-escaped field values */
 	if (cstate->csv_mode)
@@ -3828,6 +5560,61 @@ EndCopyFrom(CopyState cstate)
 }
 
 /*
+ * ClearEOLFromParallelChunk - Clear EOL from the copied data.
+ */
+static int
+ClearEOLFromParallelChunk(CopyState cstate, CopyBufferState	*copy_buff_state)
+{
+	/* raw_buf_ptr will be pointing to the next char that need to be read. */
+	int cur_pos = (copy_buff_state->raw_buf_ptr == 0) ? RAW_BUF_SIZE - 1: copy_buff_state->raw_buf_ptr - 1;
+	CopyDataBlock *data_blk_ptr = copy_buff_state->data_blk_ptr;
+	CopyDataBlock *curr_data_blk_ptr = copy_buff_state->curr_data_blk_ptr;
+	int new_line_size = 0;
+	PG_USED_FOR_ASSERTS_ONLY char ch;
+
+	/*
+	 * If we didn't hit EOF, then we must have transferred the EOL marker
+	 * to line_buf along with the data.  Get rid of it.
+	 */
+   switch (cstate->eol_type)
+   {
+	   case EOL_NL:
+		   Assert(copy_buff_state->chunk_size >= 1);
+		   Assert(curr_data_blk_ptr->data[cur_pos] == '\n');
+		   copy_buff_state->chunk_size -= 1;
+		   curr_data_blk_ptr->data[cur_pos] = '\0';
+		   new_line_size = 1;
+		   break;
+	   case EOL_CR:
+		   Assert(copy_buff_state->chunk_size >= 1);
+		   Assert(curr_data_blk_ptr->data[cur_pos] == '\r');
+		   copy_buff_state->chunk_size -= 1;
+		   curr_data_blk_ptr->data[cur_pos] = '\0';
+		   new_line_size = 1;
+		   break;
+	   case EOL_CRNL:
+		   Assert(copy_buff_state->chunk_size >= 2);
+
+		   if (cur_pos >= 1)
+			   ch = curr_data_blk_ptr->data[cur_pos - 1];
+		   else
+			   ch = data_blk_ptr->data[RAW_BUF_SIZE - 1];
+		   Assert(ch == '\r');
+		   Assert(curr_data_blk_ptr->data[cur_pos] == '\n');
+		   copy_buff_state->chunk_size -= 2;
+		   curr_data_blk_ptr->data[cur_pos] = '\0';
+		   new_line_size = 2;
+		   break;
+	   case EOL_UNKNOWN:
+		   /* shouldn't get here */
+		   Assert(false);
+		   break;
+   }
+
+   return new_line_size;
+}
+
+/*
  * Read the next input line and stash it in line_buf, with conversion to
  * server encoding.
  *
@@ -3839,7 +5626,6 @@ static bool
 CopyReadLine(CopyState cstate)
 {
 	bool		result;
-
 	resetStringInfo(&cstate->line_buf);
 	cstate->line_buf_valid = true;
 
@@ -3858,66 +5644,40 @@ CopyReadLine(CopyState cstate)
 		 */
 		if (cstate->copy_dest == COPY_NEW_FE)
 		{
+			bool bIsFirst = true;
 			do
 			{
-				cstate->raw_buf_index = cstate->raw_buf_len;
-			} while (CopyLoadRawBuf(cstate));
-		}
-	}
-	else
-	{
-		/*
-		 * If we didn't hit EOF, then we must have transferred the EOL marker
-		 * to line_buf along with the data.  Get rid of it.
-		 */
-		switch (cstate->eol_type)
-		{
-			case EOL_NL:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CR:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\r');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CRNL:
-				Assert(cstate->line_buf.len >= 2);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 2] == '\r');
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len -= 2;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_UNKNOWN:
-				/* shouldn't get here */
-				Assert(false);
-				break;
-		}
-	}
-
-	/* Done reading the line.  Convert it to server encoding. */
-	if (cstate->need_transcoding)
-	{
-		char	   *cvt;
+				if (!IsParallelCopy())
+					cstate->raw_buf_index = cstate->raw_buf_len;
+				else
+				{
+					if (cstate->raw_buf_index == RAW_BUF_SIZE)
+					{
+						/* Get a new block if it is the first time */
+						if (bIsFirst)
+						{
+							ShmCopyInfo *pcshared_info = cstate->pcdata->pcshared_info;
+							uint32 block_pos = WaitGetFreeCopyBlock(pcshared_info);
+							cstate->raw_buf = pcshared_info->data_blocks[block_pos].data;
+							cstate->raw_buf_index = cstate->raw_buf_len = 0;
+							bIsFirst = false;
+						}
+						else
+						{
+							/*
+							 * From the subsequent time, reset the index and
+							 * re-use the same block.
+							 */
+							cstate->raw_buf_index = cstate->raw_buf_len = 0;
+						}
+					}
+				}
 
-		cvt = pg_any_to_server(cstate->line_buf.data,
-							   cstate->line_buf.len,
-							   cstate->file_encoding);
-		if (cvt != cstate->line_buf.data)
-		{
-			/* transfer converted data back to line_buf */
-			resetStringInfo(&cstate->line_buf);
-			appendBinaryStringInfo(&cstate->line_buf, cvt, strlen(cvt));
-			pfree(cvt);
+			} while (CopyLoadRawBuf(cstate, cstate->raw_buf_len, &cstate->raw_buf_index));
 		}
 	}
 
-	/* Now it's safe to use the buffer in error messages */
-	cstate->line_buf_converted = true;
-
+	CONVERT_TO_SERVER_ENCODING(cstate)
 	return result;
 }
 
@@ -3927,9 +5687,6 @@ CopyReadLine(CopyState cstate)
 static bool
 CopyReadLineText(CopyState cstate)
 {
-	char	   *copy_raw_buf;
-	int			raw_buf_ptr;
-	int			copy_buf_len;
 	bool		need_data = false;
 	bool		hit_eof = false;
 	bool		result = false;
@@ -3942,6 +5699,11 @@ CopyReadLineText(CopyState cstate)
 	char		quotec = '\0';
 	char		escapec = '\0';
 
+	int			chunk_pos = 0;
+	uint32		chunk_first_block = 0;
+	uint32		new_line_size = 0;
+	CopyBufferState copy_buff_state = {0};
+
 	if (cstate->csv_mode)
 	{
 		quotec = cstate->quote[0];
@@ -3974,14 +5736,13 @@ CopyReadLineText(CopyState cstate)
 	 * For a little extra speed within the loop, we copy raw_buf and
 	 * raw_buf_len into local variables.
 	 */
-	copy_raw_buf = cstate->raw_buf;
-	raw_buf_ptr = cstate->raw_buf_index;
-	copy_buf_len = cstate->raw_buf_len;
-
+	BEGIN_READ_LINE(cstate, chunk_first_block)
 	for (;;)
 	{
 		int			prev_raw_ptr;
 		char		c;
+		uint32		prev_chunk_size = copy_buff_state.chunk_size;
+		int			prev_copy_buf_len = copy_buff_state.copy_buf_len;
 
 		/*
 		 * Load more data if needed.  Ideally we would just force four bytes
@@ -3993,35 +5754,70 @@ CopyReadLineText(CopyState cstate)
 		 * cstate->copy_dest != COPY_OLD_FE, but it hardly seems worth it,
 		 * considering the size of the buffer.
 		 */
-		if (raw_buf_ptr >= copy_buf_len || need_data)
+		if (copy_buff_state.raw_buf_ptr >= copy_buff_state.copy_buf_len ||
+			need_data)
 		{
+			uint32 remaining_data;
 			REFILL_LINEBUF;
 
+			/* In parallel mode, read as much data as possible to a new block */
+			if (IsParallelCopy())
+				SET_RAWBUF_FOR_LOAD()
+
+			remaining_data = copy_buff_state.copy_buf_len - copy_buff_state.raw_buf_ptr;
+
 			/*
 			 * Try to read some more data.  This will certainly reset
 			 * raw_buf_index to zero, and raw_buf_ptr must go with it.
 			 */
-			if (!CopyLoadRawBuf(cstate))
+			if (!CopyLoadRawBuf(cstate, copy_buff_state.copy_buf_len,
+								&copy_buff_state.raw_buf_ptr))
 				hit_eof = true;
-			raw_buf_ptr = 0;
-			copy_buf_len = cstate->raw_buf_len;
+
+			remaining_data += cstate->raw_buf_len;
 
 			/*
-			 * If we are completely out of data, break out of the loop,
-			 * reporting EOF.
+			 * If all the data of previous block is not consumed, set raw_buf back to
+			 * previous block.
 			 */
-			if (copy_buf_len <= 0)
+			if (IsParallelCopy() && need_data &&
+				(copy_buff_state.curr_data_blk_ptr != copy_buff_state.data_blk_ptr))
+			{
+				copy_buff_state.copy_buf_len += cstate->raw_buf_len;
+				cstate->raw_buf = copy_buff_state.data_blk_ptr->data;
+			}
+			else
+				copy_buff_state.copy_buf_len = cstate->raw_buf_len;
+
+			need_data = false;
+			if (remaining_data <= 0)
 			{
+				/*
+				 * If we are completely out of data, break out of the loop,
+				 * reporting EOF.
+				 */
 				result = true;
 				break;
 			}
-			need_data = false;
 		}
 
-		/* OK to fetch a character */
-		prev_raw_ptr = raw_buf_ptr;
-		c = copy_raw_buf[raw_buf_ptr++];
+		/*
+		 * Store the current information, we might have to reset if we find that
+		 * enough data is not present while reading. If enough data is not
+		 * present, we will reset using the current information and load more
+		 * data.
+		 */
+		prev_raw_ptr = copy_buff_state.raw_buf_ptr;
+		if (IsParallelCopy())
+		{
+			prev_copy_buf_len = copy_buff_state.copy_buf_len;
+			prev_chunk_size = copy_buff_state.chunk_size;
+			copy_buff_state.block_switched = false;
+		}
 
+		/* OK to fetch a character */
+		c = copy_buff_state.copy_raw_buf[copy_buff_state.raw_buf_ptr];
+		SEEK_COPY_BUFF_POS(cstate, 1, copy_buff_state)
 		if (cstate->csv_mode)
 		{
 			/*
@@ -4079,11 +5875,10 @@ CopyReadLineText(CopyState cstate)
 				IF_NEED_REFILL_AND_NOT_EOF_CONTINUE(0);
 
 				/* get next char */
-				c = copy_raw_buf[raw_buf_ptr];
-
+				c = copy_buff_state.copy_raw_buf[copy_buff_state.raw_buf_ptr];
 				if (c == '\n')
 				{
-					raw_buf_ptr++;	/* eat newline */
+					SEEK_COPY_BUFF_POS(cstate, 1, copy_buff_state)	/* eat newline */
 					cstate->eol_type = EOL_CRNL;	/* in case not set yet */
 				}
 				else
@@ -4153,11 +5948,11 @@ CopyReadLineText(CopyState cstate)
 			 * through and continue processing for file encoding.
 			 * -----
 			 */
-			c2 = copy_raw_buf[raw_buf_ptr];
+			c2 = copy_buff_state.copy_raw_buf[copy_buff_state.raw_buf_ptr];
 
 			if (c2 == '.')
 			{
-				raw_buf_ptr++;	/* consume the '.' */
+				SEEK_COPY_BUFF_POS(cstate, 1, copy_buff_state)	/* consume the '.' */
 
 				/*
 				 * Note: if we loop back for more data here, it does not
@@ -4169,7 +5964,8 @@ CopyReadLineText(CopyState cstate)
 					/* Get the next character */
 					IF_NEED_REFILL_AND_NOT_EOF_CONTINUE(0);
 					/* if hit_eof, c2 will become '\0' */
-					c2 = copy_raw_buf[raw_buf_ptr++];
+					c2 = copy_buff_state.copy_raw_buf[copy_buff_state.raw_buf_ptr];
+					SEEK_COPY_BUFF_POS(cstate, 1, copy_buff_state)
 
 					if (c2 == '\n')
 					{
@@ -4194,7 +5990,8 @@ CopyReadLineText(CopyState cstate)
 				/* Get the next character */
 				IF_NEED_REFILL_AND_NOT_EOF_CONTINUE(0);
 				/* if hit_eof, c2 will become '\0' */
-				c2 = copy_raw_buf[raw_buf_ptr++];
+				c2 = copy_buff_state.copy_raw_buf[copy_buff_state.raw_buf_ptr];
+				SEEK_COPY_BUFF_POS(cstate, 1, copy_buff_state)
 
 				if (c2 != '\r' && c2 != '\n')
 				{
@@ -4220,14 +6017,21 @@ CopyReadLineText(CopyState cstate)
 				 * discard the data and the \. sequence.
 				 */
 				if (prev_raw_ptr > cstate->raw_buf_index)
-					appendBinaryStringInfo(&cstate->line_buf,
+				{
+					if (!IsParallelCopy())
+						appendBinaryStringInfo(&cstate->line_buf,
 										   cstate->raw_buf + cstate->raw_buf_index,
 										   prev_raw_ptr - cstate->raw_buf_index);
-				cstate->raw_buf_index = raw_buf_ptr;
+					else
+						copy_buff_state.chunk_size = prev_chunk_size;
+				}
+
+				cstate->raw_buf_index = copy_buff_state.raw_buf_ptr;
 				result = true;	/* report EOF */
 				break;
 			}
 			else if (!cstate->csv_mode)
+			{
 
 				/*
 				 * If we are here, it means we found a backslash followed by
@@ -4240,7 +6044,8 @@ CopyReadLineText(CopyState cstate)
 				 * character after the backslash just like a normal character,
 				 * so we don't increment in those cases.
 				 */
-				raw_buf_ptr++;
+				SEEK_COPY_BUFF_POS(cstate, 1, copy_buff_state)
+			}
 		}
 
 		/*
@@ -4272,8 +6077,27 @@ not_end_of_copy:
 
 			IF_NEED_REFILL_AND_NOT_EOF_CONTINUE(mblen - 1);
 			IF_NEED_REFILL_AND_EOF_BREAK(mblen - 1);
-			raw_buf_ptr += mblen - 1;
+			SEEK_COPY_BUFF_POS(cstate, mblen - 1, copy_buff_state)
+		}
+
+		/*
+		 * Skip the header line. Update the chunk here, this cannot be done at
+		 * the beginning, as there is a possibility that file contains empty
+		 * lines.
+		 */
+		if (IsParallelCopy() && first_char_in_line && !IsHeaderLine())
+		{
+			ShmCopyInfo	*pcshared_info = cstate->pcdata->pcshared_info;
+			ChunkBoundary *chunkInfo;
+			chunk_pos = UpdateBlockInChunkInfo(cstate,
+											   chunk_first_block,
+											   cstate->raw_buf_index, -1,
+											   CHUNK_LEADER_POPULATING);
+			chunkInfo = &pcshared_info->chunk_boundaries.ring[chunk_pos];
+			elog(DEBUG1, "[Leader] Adding - block:%d, offset:%d, chunk position:%d",
+						 chunk_first_block,	chunkInfo->start_offset, chunk_pos);
 		}
+
 		first_char_in_line = false;
 	}							/* end of outer loop */
 
@@ -4281,6 +6105,11 @@ not_end_of_copy:
 	 * Transfer any still-uncopied data to line_buf.
 	 */
 	REFILL_LINEBUF;
+	CLEAR_EOL_LINE()
+
+	/* Skip the header line */
+	if (IsParallelCopy())
+		END_CHUNK_PARALLEL_COPY()
 
 	return result;
 }
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 0c6fe01..3faadb8 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -865,7 +865,7 @@ is_parallel_safe(PlannerInfo *root, Node *node)
 	 * planning, because those are parallel-restricted and there might be one
 	 * in this expression.  But otherwise we don't need to look.
 	 */
-	if (root->glob->maxParallelHazard == PROPARALLEL_SAFE &&
+	if (root != NULL && root->glob->maxParallelHazard == PROPARALLEL_SAFE &&
 		root->glob->paramExecTypes == NIL)
 		return true;
 	/* Else use max_parallel_hazard's search logic, but stop on RESTRICTED */
diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c
index c27d970..b3787c1 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -557,7 +557,7 @@ make_copy_attnamelist(LogicalRepRelMapEntry *rel)
  * Data source callback for the COPY FROM, which reads from the remote
  * connection and passes the data back to our local COPY.
  */
-static int
+int
 copy_read_data(void *outbuf, int minread, int maxread)
 {
 	int			bytesread = 0;
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index 7ee04ba..6933ade 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -381,6 +381,7 @@ extern FullTransactionId GetTopFullTransactionId(void);
 extern FullTransactionId GetTopFullTransactionIdIfAny(void);
 extern FullTransactionId GetCurrentFullTransactionId(void);
 extern FullTransactionId GetCurrentFullTransactionIdIfAny(void);
+extern void AssignFullTransactionIdForWorker(FullTransactionId fullTransactionId);
 extern void MarkCurrentTransactionIdLoggedIfAny(void);
 extern bool SubTransactionIsActive(SubTransactionId subxid);
 extern CommandId GetCurrentCommandId(bool used);
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index c639833..5dc95ac 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -14,6 +14,7 @@
 #ifndef COPY_H
 #define COPY_H
 
+#include "access/parallel.h"
 #include "nodes/execnodes.h"
 #include "nodes/parsenodes.h"
 #include "parser/parse_node.h"
@@ -41,4 +42,7 @@ extern uint64 CopyFrom(CopyState cstate);
 
 extern DestReceiver *CreateCopyDestReceiver(void);
 
+extern void ParallelCopyMain(dsm_segment *seg, shm_toc *toc);
+
+extern int copy_read_data(void *outbuf, int minread, int maxread);
 #endif							/* COPY_H */
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 05c5e9c..ad5fbd0 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -337,6 +337,9 @@ CheckpointStatsData
 CheckpointerRequest
 CheckpointerShmemStruct
 Chromosome
+ChunkBoundaries
+ChunkBoundary
+ChunkState
 CkptSortItem
 CkptTsStatus
 ClientAuthentication_hook_type
@@ -419,6 +422,8 @@ ConvProcInfo
 ConversionLocation
 ConvertRowtypeExpr
 CookedConstraint
+CopyBufferState
+CopyDataBlock
 CopyDest
 CopyInsertMethod
 CopyMultiInsertBuffer
@@ -426,6 +431,7 @@ CopyMultiInsertInfo
 CopyState
 CopyStateData
 CopyStmt
+CopyWorkerCommonData
 Cost
 CostSelector
 Counters
@@ -1278,6 +1284,7 @@ LimitStateCond
 List
 ListCell
 ListDictionary
+ListInfo
 ListParsedLex
 ListenAction
 ListenActionKind
@@ -1699,6 +1706,8 @@ ParallelBitmapHeapState
 ParallelBlockTableScanDesc
 ParallelCompletionPtr
 ParallelContext
+ParallelCopyData
+ParallelCopyLineBuf
 ParallelExecutorInfo
 ParallelHashGrowth
 ParallelHashJoinBatch
@@ -2264,6 +2273,7 @@ Sharedsort
 ShellTypeInfo
 ShippableCacheEntry
 ShippableCacheKey
+ShmCopyInfo
 ShmemIndexEnt
 ShutdownForeignScan_function
 ShutdownInformation
-- 
1.8.3.1

#85Robert Haas
robertmhaas@gmail.com
In reply to: Amit Kapila (#83)
Re: Parallel copy

On Mon, May 18, 2020 at 12:48 AM Amit Kapila <amit.kapila16@gmail.com> wrote:

In the above case, even though we are executing a single command from
the user perspective, but the currentCommandId will be four after the
command. One increment will be for the copy command and the other
three increments are for locking tuple in PK table
(tab_fk_referenced_chk) for three tuples in FK table
(tab_fk_referencing_chk). Now, for parallel workers, it is
(theoretically) possible that the three tuples are processed by three
different workers which don't get synced as of now. The question was
do we see any kind of problem with this and if so can we just sync it
up at the end of parallelism.

I strongly disagree with the idea of "just sync(ing) it up at the end
of parallelism". That seems like a completely unprincipled approach to
the problem. Either the command counter increment is important or it's
not. If it's not important, maybe we can arrange to skip it in the
first place. If it is important, then it's probably not OK for each
backend to be doing it separately.

--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#86Andres Freund
andres@anarazel.de
In reply to: Robert Haas (#85)
Re: Parallel copy

Hi,

On 2020-06-03 12:13:14 -0400, Robert Haas wrote:

On Mon, May 18, 2020 at 12:48 AM Amit Kapila <amit.kapila16@gmail.com> wrote:

In the above case, even though we are executing a single command from
the user perspective, but the currentCommandId will be four after the
command. One increment will be for the copy command and the other
three increments are for locking tuple in PK table
(tab_fk_referenced_chk) for three tuples in FK table
(tab_fk_referencing_chk). Now, for parallel workers, it is
(theoretically) possible that the three tuples are processed by three
different workers which don't get synced as of now. The question was
do we see any kind of problem with this and if so can we just sync it
up at the end of parallelism.

I strongly disagree with the idea of "just sync(ing) it up at the end
of parallelism". That seems like a completely unprincipled approach to
the problem. Either the command counter increment is important or it's
not. If it's not important, maybe we can arrange to skip it in the
first place. If it is important, then it's probably not OK for each
backend to be doing it separately.

That scares me too. These command counter increments definitely aren't
unnecessary in the general case.

Even in the example you share above, aren't we potentially going to
actually lock rows multiple times from within the same transaction,
instead of once? If the command counter increments from within
ri_trigger.c aren't visible to other parallel workers/leader, we'll not
correctly understand that a locked row is invisible to heap_lock_tuple,
because we're not using a new enough snapshot (by dint of not having a
new enough cid).

I've not dug through everything that'd potentially cause, but it seems
pretty clearly a no-go from here.

Greetings,

Andres Freund

#87Andres Freund
andres@anarazel.de
In reply to: vignesh C (#84)
Re: Parallel copy

Hi,

On 2020-06-03 15:53:24 +0530, vignesh C wrote:

Workers/
Exec time (seconds) copy from file,
2 indexes on integer columns
1 index on text column copy from stdin,
2 indexes on integer columns
1 index on text column copy from file, 1 gist index on text column copy
from file,
3 indexes on integer columns copy from stdin, 3 indexes on integer columns
0 1162.772(1X) 1176.035(1X) 827.669(1X) 216.171(1X) 217.376(1X)
1 1110.288(1.05X) 1120.556(1.05X) 747.384(1.11X) 174.242(1.24X) 163.492(1.33X)
2 635.249(1.83X) 668.18(1.76X) 435.673(1.9X) 133.829(1.61X) 126.516(1.72X)
4 336.835(3.45X) 346.768(3.39X) 236.406(3.5X) 105.767(2.04X) 107.382(2.02X)
8 188.577(6.17X) 194.491(6.04X) 148.962(5.56X) 100.708(2.15X) 107.72(2.01X)
16 126.819(9.17X) 146.402(8.03X) 119.923(6.9X) 97.996(2.2X) 106.531(2.04X)
20 *117.845(9.87X)* 149.203(7.88X) 138.741(5.96X) 97.94(2.21X) 107.5(2.02)
30 127.554(9.11X) 161.218(7.29X) 172.443(4.8X) 98.232(2.2X) 108.778(1.99X)

Hm. you don't explicitly mention that in your design, but given how
small the benefits going from 0-1 workers is, I assume the leader
doesn't do any "chunk processing" on its own?

Design of the Parallel Copy: The backend, to which the "COPY FROM" query is
submitted acts as leader with the responsibility of reading data from the
file/stdin, launching at most n number of workers as specified with
PARALLEL 'n' option in the "COPY FROM" query. The leader populates the
common data required for the workers execution in the DSM and shares it
with the workers. The leader then executes before statement triggers if
there exists any. Leader populates DSM chunks which includes the start
offset and chunk size, while populating the chunks it reads as many blocks
as required into the DSM data blocks from the file. Each block is of 64K
size. The leader parses the data to identify a chunk, the existing logic
from CopyReadLineText which identifies the chunks with some changes was
used for this. Leader checks if a free chunk is available to copy the
information, if there is no free chunk it waits till the required chunk is
freed up by the worker and then copies the identified chunks information
(offset & chunk size) into the DSM chunks. This process is repeated till
the complete file is processed. Simultaneously, the workers cache the
chunks(50) locally into the local memory and release the chunks to the
leader for further populating. Each worker processes the chunk that it
cached and inserts it into the table. The leader waits till all the chunks
populated are processed by the workers and exits.

Why do we need the local copy of 50 chunks? Copying memory around is far
from free. I don't see why it'd be better to add per-process caching,
rather than making the DSM bigger? I can see some benefit in marking
multiple chunks as being processed with one lock acquisition, but I
don't think adding a memory copy is a good idea.

This patch *desperately* needs to be split up. It imo is close to
unreviewable, due to a large amount of changes that just move code
around without other functional changes being mixed in with the actual
new stuff.

/*
+ * State of the chunk.
+ */
+typedef enum ChunkState
+{
+	CHUNK_INIT,					/* initial state of chunk */
+	CHUNK_LEADER_POPULATING,	/* leader processing chunk */
+	CHUNK_LEADER_POPULATED,		/* leader completed populating chunk */
+	CHUNK_WORKER_PROCESSING,	/* worker processing chunk */
+	CHUNK_WORKER_PROCESSED		/* worker completed processing chunk */
+}ChunkState;
+
+#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+
+#define DATA_BLOCK_SIZE RAW_BUF_SIZE
+#define RINGSIZE (10 * 1000)
+#define MAX_BLOCKS_COUNT 1000
+#define WORKER_CHUNK_COUNT 50	/* should be mod of RINGSIZE */
+
+#define	IsParallelCopy()		(cstate->is_parallel)
+#define IsLeader()				(cstate->pcdata->is_leader)
+#define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
+
+/*
+ * Copy data block information.
+ */
+typedef struct CopyDataBlock
+{
+	/* The number of unprocessed chunks in the current block. */
+	pg_atomic_uint32 unprocessed_chunk_parts;
+
+	/*
+	 * If the current chunk data is continued into another block,
+	 * following_block will have the position where the remaining data need to
+	 * be read.
+	 */
+	uint32	following_block;
+
+	/*
+	 * This flag will be set, when the leader finds out this block can be read
+	 * safely by the worker. This helps the worker to start processing the chunk
+	 * early where the chunk will be spread across many blocks and the worker
+	 * need not wait for the complete chunk to be processed.
+	 */
+	bool   curr_blk_completed;
+	char   data[DATA_BLOCK_SIZE + 1]; /* data read from file */
+}CopyDataBlock;

What's the + 1 here about?

+/*
+ * Parallel copy line buffer information.
+ */
+typedef struct ParallelCopyLineBuf
+{
+	StringInfoData		line_buf;
+	uint64				cur_lineno;	/* line number for error messages */
+}ParallelCopyLineBuf;

Why do we need separate infrastructure for this? We shouldn't duplicate
infrastructure unnecessarily.

+/*
+ * Common information that need to be copied to shared memory.
+ */
+typedef struct CopyWorkerCommonData
+{

Why is parallel specific stuff here suddenly not named ParallelCopy*
anymore? If you introduce a naming like that it imo should be used
consistently.

+	/* low-level state data */
+	CopyDest            copy_dest;		/* type of copy source/destination */
+	int                 file_encoding;	/* file or remote side's character encoding */
+	bool                need_transcoding;	/* file encoding diff from server? */
+	bool                encoding_embeds_ascii;	/* ASCII can be non-first byte? */
+
+	/* parameters from the COPY command */
+	bool                csv_mode;		/* Comma Separated Value format? */
+	bool                header_line;	/* CSV header line? */
+	int                 null_print_len; /* length of same */
+	bool                force_quote_all;	/* FORCE_QUOTE *? */
+	bool                convert_selectively;	/* do selective binary conversion? */
+
+	/* Working state for COPY FROM */
+	AttrNumber          num_defaults;
+	Oid                 relid;
+}CopyWorkerCommonData;

But I actually think we shouldn't have this information in two different
structs. This should exist once, independent of using parallel /
non-parallel copy.

+/* List information */
+typedef struct ListInfo
+{
+	int	count;		/* count of attributes */
+
+	/* string info in the form info followed by info1, info2... infon  */
+	char    info[1];
+} ListInfo;

Based on these comments I have no idea what this could be for.

/*
- * This keeps the character read at the top of the loop in the buffer
- * even if there is more than one read-ahead.
+ * This keeps the character read at the top of the loop in the buffer
+ * even if there is more than one read-ahead.
+ */
+#define IF_NEED_REFILL_AND_NOT_EOF_CONTINUE(extralen) \
+if (1) \
+{ \
+	if (copy_buff_state.raw_buf_ptr + (extralen) >= copy_buff_state.copy_buf_len && !hit_eof) \
+	{ \
+		if (IsParallelCopy()) \
+		{ \
+			copy_buff_state.chunk_size = prev_chunk_size; /* update previous chunk size */ \
+			if (copy_buff_state.block_switched) \
+			{ \
+				pg_atomic_sub_fetch_u32(&copy_buff_state.data_blk_ptr->unprocessed_chunk_parts, 1); \
+				copy_buff_state.copy_buf_len = prev_copy_buf_len; \
+			} \
+		} \
+		copy_buff_state.raw_buf_ptr = prev_raw_ptr; /* undo fetch */ \
+		need_data = true; \
+		continue; \
+	} \
+} else ((void) 0)

I think it's an absolutely clear no-go to add new branches to
these. They're *really* hot already, and this is going to sprinkle a
significant amount of new instructions over a lot of places.

+/*
+ * SET_RAWBUF_FOR_LOAD - Set raw_buf to the shared memory where the file data must
+ * be read.
+ */
+#define SET_RAWBUF_FOR_LOAD() \
+{ \
+	ShmCopyInfo	*pcshared_info = cstate->pcdata->pcshared_info; \
+	uint32 cur_block_pos; \
+	/* \
+	 * Mark the previous block as completed, worker can start copying this data. \
+	 */ \
+	if (copy_buff_state.data_blk_ptr != copy_buff_state.curr_data_blk_ptr && \
+		copy_buff_state.data_blk_ptr->curr_blk_completed == false) \
+		copy_buff_state.data_blk_ptr->curr_blk_completed = true; \
+	\
+	copy_buff_state.data_blk_ptr = copy_buff_state.curr_data_blk_ptr; \
+	cur_block_pos = WaitGetFreeCopyBlock(pcshared_info); \
+	copy_buff_state.curr_data_blk_ptr = &pcshared_info->data_blocks[cur_block_pos]; \
+	\
+	if (!copy_buff_state.data_blk_ptr) \
+	{ \
+		copy_buff_state.data_blk_ptr = copy_buff_state.curr_data_blk_ptr; \
+		chunk_first_block = cur_block_pos; \
+	} \
+	else if (need_data == false) \
+		copy_buff_state.data_blk_ptr->following_block = cur_block_pos; \
+	\
+	cstate->raw_buf = copy_buff_state.curr_data_blk_ptr->data; \
+	copy_buff_state.copy_raw_buf = cstate->raw_buf; \
+}
+
+/*
+ * END_CHUNK_PARALLEL_COPY - Update the chunk information in shared memory.
+ */
+#define END_CHUNK_PARALLEL_COPY() \
+{ \
+	if (!IsHeaderLine()) \
+	{ \
+		ShmCopyInfo *pcshared_info = cstate->pcdata->pcshared_info; \
+		ChunkBoundaries *chunkBoundaryPtr = &pcshared_info->chunk_boundaries; \
+		if (copy_buff_state.chunk_size) \
+		{ \
+			ChunkBoundary *chunkInfo = &chunkBoundaryPtr->ring[chunk_pos]; \
+			/* \
+			 * If raw_buf_ptr is zero, unprocessed_chunk_parts would have been \
+			 * incremented in SEEK_COPY_BUFF_POS. This will happen if the whole \
+			 * chunk finishes at the end of the current block. If the \
+			 * new_line_size > raw_buf_ptr, then the new block has only new line \
+			 * char content. The unprocessed count should not be increased in \
+			 * this case. \
+			 */ \
+			if (copy_buff_state.raw_buf_ptr != 0 && \
+				copy_buff_state.raw_buf_ptr > new_line_size) \
+				pg_atomic_add_fetch_u32(&copy_buff_state.curr_data_blk_ptr->unprocessed_chunk_parts, 1); \
+			\
+			/* Update chunk size. */ \
+			pg_atomic_write_u32(&chunkInfo->chunk_size, copy_buff_state.chunk_size); \
+			pg_atomic_write_u32(&chunkInfo->chunk_state, CHUNK_LEADER_POPULATED); \
+			elog(DEBUG1, "[Leader] After adding - chunk position:%d, chunk_size:%d", \
+						chunk_pos, copy_buff_state.chunk_size); \
+			pcshared_info->populated++; \
+		} \
+		else if (new_line_size) \
+		{ \
+			/* \
+			 * This means only new line char, empty record should be \
+			 * inserted. \
+			 */ \
+			ChunkBoundary *chunkInfo; \
+			chunk_pos = UpdateBlockInChunkInfo(cstate, -1, -1, 0, \
+											   CHUNK_LEADER_POPULATED); \
+			chunkInfo = &chunkBoundaryPtr->ring[chunk_pos]; \
+			elog(DEBUG1, "[Leader] Added empty chunk with offset:%d, chunk position:%d, chunk size:%d", \
+						 chunkInfo->start_offset, chunk_pos, \
+						 pg_atomic_read_u32(&chunkInfo->chunk_size)); \
+			pcshared_info->populated++; \
+		} \
+	}\
+	\
+	/*\
+	 * All of the read data is processed, reset index & len. In the\
+	 * subsequent read, we will get a new block and copy data in to the\
+	 * new block.\
+	 */\
+	if (copy_buff_state.raw_buf_ptr == copy_buff_state.copy_buf_len)\
+	{\
+		cstate->raw_buf_index = 0;\
+		cstate->raw_buf_len = 0;\
+	}\
+	else\
+		cstate->raw_buf_len = copy_buff_state.copy_buf_len;\
+}

Why are these macros? They are way way way above a length where that
makes any sort of sense.

Greetings,

Andres Freund

#88Amit Kapila
amit.kapila16@gmail.com
In reply to: Andres Freund (#86)
Re: Parallel copy

On Thu, Jun 4, 2020 at 12:09 AM Andres Freund <andres@anarazel.de> wrote:

Hi,

On 2020-06-03 12:13:14 -0400, Robert Haas wrote:

On Mon, May 18, 2020 at 12:48 AM Amit Kapila <amit.kapila16@gmail.com> wrote:

In the above case, even though we are executing a single command from
the user perspective, but the currentCommandId will be four after the
command. One increment will be for the copy command and the other
three increments are for locking tuple in PK table
(tab_fk_referenced_chk) for three tuples in FK table
(tab_fk_referencing_chk). Now, for parallel workers, it is
(theoretically) possible that the three tuples are processed by three
different workers which don't get synced as of now. The question was
do we see any kind of problem with this and if so can we just sync it
up at the end of parallelism.

I strongly disagree with the idea of "just sync(ing) it up at the end
of parallelism". That seems like a completely unprincipled approach to
the problem. Either the command counter increment is important or it's
not. If it's not important, maybe we can arrange to skip it in the
first place. If it is important, then it's probably not OK for each
backend to be doing it separately.

That scares me too. These command counter increments definitely aren't
unnecessary in the general case.

Yeah, this is what we want to understand? Can you explain how they
are useful here? AFAIU, heap_lock_tuple doesn't use commandid while
storing the transaction information of xact while locking the tuple.

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#89Andres Freund
andres@anarazel.de
In reply to: Amit Kapila (#88)
Re: Parallel copy

Hi,

On 2020-06-04 08:10:07 +0530, Amit Kapila wrote:

On Thu, Jun 4, 2020 at 12:09 AM Andres Freund <andres@anarazel.de> wrote:

I strongly disagree with the idea of "just sync(ing) it up at the end
of parallelism". That seems like a completely unprincipled approach to
the problem. Either the command counter increment is important or it's
not. If it's not important, maybe we can arrange to skip it in the
first place. If it is important, then it's probably not OK for each
backend to be doing it separately.

That scares me too. These command counter increments definitely aren't
unnecessary in the general case.

Yeah, this is what we want to understand? Can you explain how they
are useful here? AFAIU, heap_lock_tuple doesn't use commandid while
storing the transaction information of xact while locking the tuple.

But the HeapTupleSatisfiesUpdate() call does use it?

And even if that weren't an issue, I don't see how it's defensible to
just randomly break the the commandid coherency for parallel copy.

Greetings,

Andres Freund

#90Amit Kapila
amit.kapila16@gmail.com
In reply to: Andres Freund (#89)
Re: Parallel copy

On Thu, Jun 4, 2020 at 9:10 AM Andres Freund <andres@anarazel.de> wrote:

Hi,

On 2020-06-04 08:10:07 +0530, Amit Kapila wrote:

On Thu, Jun 4, 2020 at 12:09 AM Andres Freund <andres@anarazel.de> wrote:

I strongly disagree with the idea of "just sync(ing) it up at the end
of parallelism". That seems like a completely unprincipled approach to
the problem. Either the command counter increment is important or it's
not. If it's not important, maybe we can arrange to skip it in the
first place. If it is important, then it's probably not OK for each
backend to be doing it separately.

That scares me too. These command counter increments definitely aren't
unnecessary in the general case.

Yeah, this is what we want to understand? Can you explain how they
are useful here? AFAIU, heap_lock_tuple doesn't use commandid while
storing the transaction information of xact while locking the tuple.

But the HeapTupleSatisfiesUpdate() call does use it?

It won't use 'cid' for lockers or multi-lockers case (AFAICS, there
are special case handling for lockers/multi-lockers). I think it is
used for updates/deletes.

And even if that weren't an issue, I don't see how it's defensible to
just randomly break the the commandid coherency for parallel copy.

At this stage, we are evelauating whether there is any need to
increment command counter for foreign key checks or is it just
happening because we are using using some common code to execute
"Select ... For Key Share" statetement during these checks.

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#91vignesh C
vignesh21@gmail.com
In reply to: Andres Freund (#87)
4 attachment(s)
Re: Parallel copy

On Thu, Jun 4, 2020 at 12:44 AM Andres Freund <andres@anarazel.de> wrote

Hm. you don't explicitly mention that in your design, but given how
small the benefits going from 0-1 workers is, I assume the leader
doesn't do any "chunk processing" on its own?

Yes you are right, the leader does not do any processing, Leader's
work is mainly to populate the shared memory with the offset
information for each record.

Design of the Parallel Copy: The backend, to which the "COPY FROM" query is
submitted acts as leader with the responsibility of reading data from the
file/stdin, launching at most n number of workers as specified with
PARALLEL 'n' option in the "COPY FROM" query. The leader populates the
common data required for the workers execution in the DSM and shares it
with the workers. The leader then executes before statement triggers if
there exists any. Leader populates DSM chunks which includes the start
offset and chunk size, while populating the chunks it reads as many blocks
as required into the DSM data blocks from the file. Each block is of 64K
size. The leader parses the data to identify a chunk, the existing logic
from CopyReadLineText which identifies the chunks with some changes was
used for this. Leader checks if a free chunk is available to copy the
information, if there is no free chunk it waits till the required chunk is
freed up by the worker and then copies the identified chunks information
(offset & chunk size) into the DSM chunks. This process is repeated till
the complete file is processed. Simultaneously, the workers cache the
chunks(50) locally into the local memory and release the chunks to the
leader for further populating. Each worker processes the chunk that it
cached and inserts it into the table. The leader waits till all the chunks
populated are processed by the workers and exits.

Why do we need the local copy of 50 chunks? Copying memory around is far
from free. I don't see why it'd be better to add per-process caching,
rather than making the DSM bigger? I can see some benefit in marking
multiple chunks as being processed with one lock acquisition, but I
don't think adding a memory copy is a good idea.

We had run performance with csv data file, 5.1GB, 10million tuples, 2
indexes on integer columns, results for the same are given below. We
noticed in some cases the performance is better if we copy the 50
records locally and release the shared memory. We will get better
benefits as the workers increase. Thoughts?
------------------------------------------------------------------------------------------------
Workers | Exec time (With local copying | Exec time (Without copying,
| 50 records & release the | processing record by record)
| shared memory) |
------------------------------------------------------------------------------------------------
0 | 1162.772(1X) | 1152.684(1X)
2 | 635.249(1.83X) | 647.894(1.78X)
4 | 336.835(3.45X) | 335.534(3.43X)
8 | 188.577(6.17 X) | 189.461(6.08X)
16 | 126.819(9.17X) | 142.730(8.07X)
20 | 117.845(9.87X) | 146.533(7.87X)
30 | 127.554(9.11X) | 160.307(7.19X)

This patch *desperately* needs to be split up. It imo is close to
unreviewable, due to a large amount of changes that just move code
around without other functional changes being mixed in with the actual
new stuff.

I have split the patch, the new split patches are attached.

/*
+ * State of the chunk.
+ */
+typedef enum ChunkState
+{
+     CHUNK_INIT,                                     /* initial state of chunk */
+     CHUNK_LEADER_POPULATING,        /* leader processing chunk */
+     CHUNK_LEADER_POPULATED,         /* leader completed populating chunk */
+     CHUNK_WORKER_PROCESSING,        /* worker processing chunk */
+     CHUNK_WORKER_PROCESSED          /* worker completed processing chunk */
+}ChunkState;
+
+#define RAW_BUF_SIZE 65536           /* we palloc RAW_BUF_SIZE+1 bytes */
+
+#define DATA_BLOCK_SIZE RAW_BUF_SIZE
+#define RINGSIZE (10 * 1000)
+#define MAX_BLOCKS_COUNT 1000
+#define WORKER_CHUNK_COUNT 50        /* should be mod of RINGSIZE */
+
+#define      IsParallelCopy()                (cstate->is_parallel)
+#define IsLeader()                           (cstate->pcdata->is_leader)
+#define IsHeaderLine()                       (cstate->header_line && cstate->cur_lineno == 1)
+
+/*
+ * Copy data block information.
+ */
+typedef struct CopyDataBlock
+{
+     /* The number of unprocessed chunks in the current block. */
+     pg_atomic_uint32 unprocessed_chunk_parts;
+
+     /*
+      * If the current chunk data is continued into another block,
+      * following_block will have the position where the remaining data need to
+      * be read.
+      */
+     uint32  following_block;
+
+     /*
+      * This flag will be set, when the leader finds out this block can be read
+      * safely by the worker. This helps the worker to start processing the chunk
+      * early where the chunk will be spread across many blocks and the worker
+      * need not wait for the complete chunk to be processed.
+      */
+     bool   curr_blk_completed;
+     char   data[DATA_BLOCK_SIZE + 1]; /* data read from file */
+}CopyDataBlock;

What's the + 1 here about?

Fixed this, removed +1. That is not needed.

+/*
+ * Parallel copy line buffer information.
+ */
+typedef struct ParallelCopyLineBuf
+{
+     StringInfoData          line_buf;
+     uint64                          cur_lineno;     /* line number for error messages */
+}ParallelCopyLineBuf;

Why do we need separate infrastructure for this? We shouldn't duplicate
infrastructure unnecessarily.

This was required for copying the multiple records locally and
releasing the shared memory. I have not changed this, will decide on
this based on the decision taken for one of the previous comments.

+/*
+ * Common information that need to be copied to shared memory.
+ */
+typedef struct CopyWorkerCommonData
+{

Why is parallel specific stuff here suddenly not named ParallelCopy*
anymore? If you introduce a naming like that it imo should be used
consistently.

Fixed, changed to maintain ParallelCopy in all structs.

+     /* low-level state data */
+     CopyDest            copy_dest;          /* type of copy source/destination */
+     int                 file_encoding;      /* file or remote side's character encoding */
+     bool                need_transcoding;   /* file encoding diff from server? */
+     bool                encoding_embeds_ascii;      /* ASCII can be non-first byte? */
+
+     /* parameters from the COPY command */
+     bool                csv_mode;           /* Comma Separated Value format? */
+     bool                header_line;        /* CSV header line? */
+     int                 null_print_len; /* length of same */
+     bool                force_quote_all;    /* FORCE_QUOTE *? */
+     bool                convert_selectively;        /* do selective binary conversion? */
+
+     /* Working state for COPY FROM */
+     AttrNumber          num_defaults;
+     Oid                 relid;
+}CopyWorkerCommonData;

But I actually think we shouldn't have this information in two different
structs. This should exist once, independent of using parallel /
non-parallel copy.

This structure helps in storing the common data from CopyStateData
that are required by the workers. This information will then be
allocated and stored into the DSM for the worker to retrieve and copy
it to CopyStateData.

+/* List information */
+typedef struct ListInfo
+{
+     int     count;          /* count of attributes */
+
+     /* string info in the form info followed by info1, info2... infon  */
+     char    info[1];
+} ListInfo;

Based on these comments I have no idea what this could be for.

Have added better comments for this. The following is added: This
structure will help in converting a List data type into the below
structure format with the count having the number of elements in the
list and the info having the List elements appended contiguously. This
converted structure will be allocated in shared memory and stored in
DSM for the worker to retrieve and later convert it back to List data
type.

/*
- * This keeps the character read at the top of the loop in the buffer
- * even if there is more than one read-ahead.
+ * This keeps the character read at the top of the loop in the buffer
+ * even if there is more than one read-ahead.
+ */
+#define IF_NEED_REFILL_AND_NOT_EOF_CONTINUE(extralen) \
+if (1) \
+{ \
+     if (copy_buff_state.raw_buf_ptr + (extralen) >= copy_buff_state.copy_buf_len && !hit_eof) \
+     { \
+             if (IsParallelCopy()) \
+             { \
+                     copy_buff_state.chunk_size = prev_chunk_size; /* update previous chunk size */ \
+                     if (copy_buff_state.block_switched) \
+                     { \
+                             pg_atomic_sub_fetch_u32(&copy_buff_state.data_blk_ptr->unprocessed_chunk_parts, 1); \
+                             copy_buff_state.copy_buf_len = prev_copy_buf_len; \
+                     } \
+             } \
+             copy_buff_state.raw_buf_ptr = prev_raw_ptr; /* undo fetch */ \
+             need_data = true; \
+             continue; \
+     } \
+} else ((void) 0)

I think it's an absolutely clear no-go to add new branches to
these. They're *really* hot already, and this is going to sprinkle a
significant amount of new instructions over a lot of places.

Fixed, removed this.

+/*
+ * SET_RAWBUF_FOR_LOAD - Set raw_buf to the shared memory where the file data must
+ * be read.
+ */
+#define SET_RAWBUF_FOR_LOAD() \
+{ \
+     ShmCopyInfo     *pcshared_info = cstate->pcdata->pcshared_info; \
+     uint32 cur_block_pos; \
+     /* \
+      * Mark the previous block as completed, worker can start copying this data. \
+      */ \
+     if (copy_buff_state.data_blk_ptr != copy_buff_state.curr_data_blk_ptr && \
+             copy_buff_state.data_blk_ptr->curr_blk_completed == false) \
+             copy_buff_state.data_blk_ptr->curr_blk_completed = true; \
+     \
+     copy_buff_state.data_blk_ptr = copy_buff_state.curr_data_blk_ptr; \
+     cur_block_pos = WaitGetFreeCopyBlock(pcshared_info); \
+     copy_buff_state.curr_data_blk_ptr = &pcshared_info->data_blocks[cur_block_pos]; \
+     \
+     if (!copy_buff_state.data_blk_ptr) \
+     { \
+             copy_buff_state.data_blk_ptr = copy_buff_state.curr_data_blk_ptr; \
+             chunk_first_block = cur_block_pos; \
+     } \
+     else if (need_data == false) \
+             copy_buff_state.data_blk_ptr->following_block = cur_block_pos; \
+     \
+     cstate->raw_buf = copy_buff_state.curr_data_blk_ptr->data; \
+     copy_buff_state.copy_raw_buf = cstate->raw_buf; \
+}
+
+/*
+ * END_CHUNK_PARALLEL_COPY - Update the chunk information in shared memory.
+ */
+#define END_CHUNK_PARALLEL_COPY() \
+{ \
+     if (!IsHeaderLine()) \
+     { \
+             ShmCopyInfo *pcshared_info = cstate->pcdata->pcshared_info; \
+             ChunkBoundaries *chunkBoundaryPtr = &pcshared_info->chunk_boundaries; \
+             if (copy_buff_state.chunk_size) \
+             { \
+                     ChunkBoundary *chunkInfo = &chunkBoundaryPtr->ring[chunk_pos]; \
+                     /* \
+                      * If raw_buf_ptr is zero, unprocessed_chunk_parts would have been \
+                      * incremented in SEEK_COPY_BUFF_POS. This will happen if the whole \
+                      * chunk finishes at the end of the current block. If the \
+                      * new_line_size > raw_buf_ptr, then the new block has only new line \
+                      * char content. The unprocessed count should not be increased in \
+                      * this case. \
+                      */ \
+                     if (copy_buff_state.raw_buf_ptr != 0 && \
+                             copy_buff_state.raw_buf_ptr > new_line_size) \
+                             pg_atomic_add_fetch_u32(&copy_buff_state.curr_data_blk_ptr->unprocessed_chunk_parts, 1); \
+                     \
+                     /* Update chunk size. */ \
+                     pg_atomic_write_u32(&chunkInfo->chunk_size, copy_buff_state.chunk_size); \
+                     pg_atomic_write_u32(&chunkInfo->chunk_state, CHUNK_LEADER_POPULATED); \
+                     elog(DEBUG1, "[Leader] After adding - chunk position:%d, chunk_size:%d", \
+                                             chunk_pos, copy_buff_state.chunk_size); \
+                     pcshared_info->populated++; \
+             } \
+             else if (new_line_size) \
+             { \
+                     /* \
+                      * This means only new line char, empty record should be \
+                      * inserted. \
+                      */ \
+                     ChunkBoundary *chunkInfo; \
+                     chunk_pos = UpdateBlockInChunkInfo(cstate, -1, -1, 0, \
+                                                                                        CHUNK_LEADER_POPULATED); \
+                     chunkInfo = &chunkBoundaryPtr->ring[chunk_pos]; \
+                     elog(DEBUG1, "[Leader] Added empty chunk with offset:%d, chunk position:%d, chunk size:%d", \
+                                              chunkInfo->start_offset, chunk_pos, \
+                                              pg_atomic_read_u32(&chunkInfo->chunk_size)); \
+                     pcshared_info->populated++; \
+             } \
+     }\
+     \
+     /*\
+      * All of the read data is processed, reset index & len. In the\
+      * subsequent read, we will get a new block and copy data in to the\
+      * new block.\
+      */\
+     if (copy_buff_state.raw_buf_ptr == copy_buff_state.copy_buf_len)\
+     {\
+             cstate->raw_buf_index = 0;\
+             cstate->raw_buf_len = 0;\
+     }\
+     else\
+             cstate->raw_buf_len = copy_buff_state.copy_buf_len;\
+}

Why are these macros? They are way way way above a length where that
makes any sort of sense.

Converted these macros to functions.

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

Attachments:

0001-Copy-code-readjustment-to-support-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=0001-Copy-code-readjustment-to-support-parallel-copy.patchDownload
From 97204eb6abafe891a654b34ff84cf9812e6c1fef Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 10 Jun 2020 06:07:17 +0530
Subject: [PATCH 1/4] Copy code readjustment to support parallel copy.

This patch has the copy code slightly readjusted so that the common code is
separated to functions/macros, these functions/macros will be used by the
workers in the parallel copy code of the upcoming patches. EOL removal is moved
from CopyReadLine to CopyReadLineText, this change was required because in case
of parallel copy the chunk identification and chunk updation is done in
CopyReadLineText, before chunk information is updated in shared memory the new
line characters should be removed.
---
 src/backend/commands/copy.c | 320 ++++++++++++++++++++++++++------------------
 1 file changed, 191 insertions(+), 129 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 6d53dc4..eaf0f78 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -95,6 +95,9 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
+#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+#define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
+
 /*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
@@ -219,7 +222,6 @@ typedef struct CopyStateData
 	 * converts it.  Note: we guarantee that there is a \0 at
 	 * raw_buf[raw_buf_len].
 	 */
-#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
@@ -347,6 +349,88 @@ if (1) \
 	goto not_end_of_copy; \
 } else ((void) 0)
 
+/*
+ * CONVERT_TO_SERVER_ENCODING - convert contents to server encoding.
+ */
+#define CONVERT_TO_SERVER_ENCODING(cstate) \
+{ \
+	/* Done reading the line.  Convert it to server encoding. */ \
+	if (cstate->need_transcoding) \
+	{ \
+		char	   *cvt; \
+		cvt = pg_any_to_server(cstate->line_buf.data, \
+							   cstate->line_buf.len, \
+							   cstate->file_encoding); \
+		if (cvt != cstate->line_buf.data) \
+		{ \
+			/* transfer converted data back to line_buf */ \
+			resetStringInfo(&cstate->line_buf); \
+			appendBinaryStringInfo(&cstate->line_buf, cvt, strlen(cvt)); \
+			pfree(cvt); \
+		} \
+	} \
+	/* Now it's safe to use the buffer in error messages */ \
+	cstate->line_buf_converted = true; \
+}
+
+/*
+ * CLEAR_EOL_FROM_COPIED_DATA - Clear EOL from the copied data.
+ */
+#define CLEAR_EOL_FROM_COPIED_DATA(copy_line_data, copy_line_pos, copy_line_size) \
+{ \
+	/* \
+	 * If we didn't hit EOF, then we must have transferred the EOL marker \
+	 * to line_buf along with the data.  Get rid of it. \
+	 */ \
+   switch (cstate->eol_type) \
+   { \
+	   case EOL_NL: \
+		   Assert(copy_line_size >= 1); \
+		   Assert(copy_line_data[copy_line_pos - 1] == '\n'); \
+		   copy_line_data[copy_line_pos - 1] = '\0'; \
+		   copy_line_size--; \
+		   break; \
+	   case EOL_CR: \
+		   Assert(copy_line_size >= 1); \
+		   Assert(copy_line_data[copy_line_pos - 1] == '\r'); \
+		   copy_line_data[copy_line_pos - 1] = '\0'; \
+		   copy_line_size--; \
+		   break; \
+	   case EOL_CRNL: \
+		   Assert(copy_line_size >= 2); \
+		   Assert(copy_line_data[copy_line_pos - 2] == '\r'); \
+		   Assert(copy_line_data[copy_line_pos - 1] == '\n'); \
+		   copy_line_data[copy_line_pos - 2] = '\0'; \
+		   copy_line_size -= 2; \
+		   break; \
+	   case EOL_UNKNOWN: \
+		   /* shouldn't get here */ \
+		   Assert(false); \
+		   break; \
+   } \
+}
+
+/*
+ * CLEAR_EOL_LINE - Wrapper for clearing EOL.
+ */
+#define CLEAR_EOL_LINE() \
+if (!result && !IsHeaderLine()) \
+	CLEAR_EOL_FROM_COPIED_DATA(cstate->line_buf.data, \
+								cstate->line_buf.len, \
+								cstate->line_buf.len) \
+
+/*
+ * INCREMENTPROCESSED - Increment the lines processed.
+ */
+#define INCREMENTPROCESSED(processed)  \
+processed++;
+
+/*
+ * GETPROCESSED - Get the lines processed.
+ */
+#define GETPROCESSED(processed) \
+return processed;
+
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
 
@@ -393,6 +477,8 @@ static bool CopyGetInt32(CopyState cstate, int32 *val);
 static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 
+static void PopulateAttributes(CopyState cstate, TupleDesc	tup_desc,
+							   List *attnamelist);
 
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
@@ -1464,7 +1550,6 @@ BeginCopy(ParseState *pstate,
 {
 	CopyState	cstate;
 	TupleDesc	tupDesc;
-	int			num_phys_attrs;
 	MemoryContext oldcontext;
 
 	/* Allocate workspace and zero all fields */
@@ -1630,6 +1715,22 @@ BeginCopy(ParseState *pstate,
 		tupDesc = cstate->queryDesc->tupDesc;
 	}
 
+	PopulateAttributes(cstate, tupDesc, attnamelist);
+	cstate->copy_dest = COPY_FILE;	/* default */
+
+	MemoryContextSwitchTo(oldcontext);
+
+	return cstate;
+}
+
+/*
+ * PopulateAttributes - Populate the attributes.
+ */
+static void
+PopulateAttributes(CopyState cstate, TupleDesc	tupDesc, List *attnamelist)
+{
+	int			num_phys_attrs;
+
 	/* Generate or convert list of attributes to process */
 	cstate->attnumlist = CopyGetAttnums(tupDesc, cstate->rel, attnamelist);
 
@@ -1749,12 +1850,6 @@ BeginCopy(ParseState *pstate,
 		 pg_database_encoding_max_length() > 1);
 	/* See Multibyte encoding comment above */
 	cstate->encoding_embeds_ascii = PG_ENCODING_IS_CLIENT_ONLY(cstate->file_encoding);
-
-	cstate->copy_dest = COPY_FILE;	/* default */
-
-	MemoryContextSwitchTo(oldcontext);
-
-	return cstate;
 }
 
 /*
@@ -2647,32 +2742,11 @@ CopyMultiInsertInfoStore(CopyMultiInsertInfo *miinfo, ResultRelInfo *rri,
 }
 
 /*
- * Copy FROM file to relation.
+ * Check if the relation specified in copy from is valid.
  */
-uint64
-CopyFrom(CopyState cstate)
+static void
+CheckCopyFromValidity(CopyState cstate)
 {
-	ResultRelInfo *resultRelInfo;
-	ResultRelInfo *target_resultRelInfo;
-	ResultRelInfo *prevResultRelInfo = NULL;
-	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
-	ModifyTableState *mtstate;
-	ExprContext *econtext;
-	TupleTableSlot *singleslot = NULL;
-	MemoryContext oldcontext = CurrentMemoryContext;
-
-	PartitionTupleRouting *proute = NULL;
-	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
-	int			ti_options = 0; /* start with default options for insert */
-	BulkInsertState bistate = NULL;
-	CopyInsertMethod insertMethod;
-	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
-	uint64		processed = 0;
-	bool		has_before_insert_row_trig;
-	bool		has_instead_insert_row_trig;
-	bool		leafpart_use_multi_insert = false;
-
 	Assert(cstate->rel);
 
 	/*
@@ -2708,6 +2782,36 @@ CopyFrom(CopyState cstate)
 					 errmsg("cannot copy to non-table relation \"%s\"",
 							RelationGetRelationName(cstate->rel))));
 	}
+}
+
+/*
+ * Copy FROM file to relation.
+ */
+uint64
+CopyFrom(CopyState cstate)
+{
+	ResultRelInfo *resultRelInfo;
+	ResultRelInfo *target_resultRelInfo;
+	ResultRelInfo *prevResultRelInfo = NULL;
+	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
+	ModifyTableState *mtstate;
+	ExprContext *econtext;
+	TupleTableSlot *singleslot = NULL;
+	MemoryContext oldcontext = CurrentMemoryContext;
+
+	PartitionTupleRouting *proute = NULL;
+	ErrorContextCallback errcallback;
+	CommandId	mycid = GetCurrentCommandId(true);
+	int			ti_options = 0; /* start with default options for insert */
+	BulkInsertState bistate = NULL;
+	CopyInsertMethod insertMethod;
+	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
+	uint64		processed = 0;
+	bool		has_before_insert_row_trig;
+	bool		has_instead_insert_row_trig;
+	bool		leafpart_use_multi_insert = false;
+
+	CheckCopyFromValidity(cstate);
 
 	/*
 	 * If the target file is new-in-transaction, we assume that checking FSM
@@ -3262,7 +3366,7 @@ CopyFrom(CopyState cstate)
 			 * or FDW; this is the same definition used by nodeModifyTable.c
 			 * for counting tuples inserted by an INSERT command.
 			 */
-			processed++;
+			INCREMENTPROCESSED(processed)
 		}
 	}
 
@@ -3317,30 +3421,15 @@ CopyFrom(CopyState cstate)
 
 	FreeExecutorState(estate);
 
-	return processed;
+	GETPROCESSED(processed)
 }
 
 /*
- * Setup to read tuples from a file for COPY FROM.
- *
- * 'rel': Used as a template for the tuples
- * 'filename': Name of server-local file to read
- * 'attnamelist': List of char *, columns to include. NIL selects all cols.
- * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
- *
- * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ * PopulateCatalogInformation - populate the catalog information.
  */
-CopyState
-BeginCopyFrom(ParseState *pstate,
-			  Relation rel,
-			  const char *filename,
-			  bool is_program,
-			  copy_data_source_cb data_source_cb,
-			  List *attnamelist,
-			  List *options)
+static void
+PopulateCatalogInformation(CopyState cstate)
 {
-	CopyState	cstate;
-	bool		pipe = (filename == NULL);
 	TupleDesc	tupDesc;
 	AttrNumber	num_phys_attrs,
 				num_defaults;
@@ -3350,31 +3439,8 @@ BeginCopyFrom(ParseState *pstate,
 	Oid			in_func_oid;
 	int		   *defmap;
 	ExprState **defexprs;
-	MemoryContext oldcontext;
 	bool		volatile_defexprs;
 
-	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
-	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
-
-	/* Initialize state variables */
-	cstate->reached_eof = false;
-	cstate->eol_type = EOL_UNKNOWN;
-	cstate->cur_relname = RelationGetRelationName(cstate->rel);
-	cstate->cur_lineno = 0;
-	cstate->cur_attname = NULL;
-	cstate->cur_attval = NULL;
-
-	/* Set up variables to avoid per-attribute overhead. */
-	initStringInfo(&cstate->attribute_buf);
-	initStringInfo(&cstate->line_buf);
-	cstate->line_buf_converted = false;
-	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
-	cstate->raw_buf_index = cstate->raw_buf_len = 0;
-
-	/* Assign range table, we'll need it in CopyFrom. */
-	if (pstate)
-		cstate->range_table = pstate->p_rtable;
-
 	tupDesc = RelationGetDescr(cstate->rel);
 	num_phys_attrs = tupDesc->natts;
 	num_defaults = 0;
@@ -3452,6 +3518,54 @@ BeginCopyFrom(ParseState *pstate,
 	cstate->defexprs = defexprs;
 	cstate->volatile_defexprs = volatile_defexprs;
 	cstate->num_defaults = num_defaults;
+}
+
+/*
+ * Setup to read tuples from a file for COPY FROM.
+ *
+ * 'rel': Used as a template for the tuples
+ * 'filename': Name of server-local file to read
+ * 'attnamelist': List of char *, columns to include. NIL selects all cols.
+ * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
+ *
+ * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ */
+CopyState
+BeginCopyFrom(ParseState *pstate,
+			  Relation rel,
+			  const char *filename,
+			  bool is_program,
+			  copy_data_source_cb data_source_cb,
+			  List *attnamelist,
+			  List *options)
+{
+	CopyState	cstate;
+	bool		pipe = (filename == NULL);
+	MemoryContext oldcontext;
+
+	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	/* Initialize state variables */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/* Set up variables to avoid per-attribute overhead. */
+	initStringInfo(&cstate->attribute_buf);
+	initStringInfo(&cstate->line_buf);
+	cstate->line_buf_converted = false;
+	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+
+	/* Assign range table, we'll need it in CopyFrom. */
+	if (pstate)
+		cstate->range_table = pstate->p_rtable;
+
+	PopulateCatalogInformation(cstate);
 	cstate->is_program = is_program;
 
 	if (data_source_cb)
@@ -3839,7 +3953,6 @@ static bool
 CopyReadLine(CopyState cstate)
 {
 	bool		result;
-
 	resetStringInfo(&cstate->line_buf);
 	cstate->line_buf_valid = true;
 
@@ -3864,60 +3977,8 @@ CopyReadLine(CopyState cstate)
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
-	else
-	{
-		/*
-		 * If we didn't hit EOF, then we must have transferred the EOL marker
-		 * to line_buf along with the data.  Get rid of it.
-		 */
-		switch (cstate->eol_type)
-		{
-			case EOL_NL:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CR:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\r');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CRNL:
-				Assert(cstate->line_buf.len >= 2);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 2] == '\r');
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len -= 2;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_UNKNOWN:
-				/* shouldn't get here */
-				Assert(false);
-				break;
-		}
-	}
-
-	/* Done reading the line.  Convert it to server encoding. */
-	if (cstate->need_transcoding)
-	{
-		char	   *cvt;
-
-		cvt = pg_any_to_server(cstate->line_buf.data,
-							   cstate->line_buf.len,
-							   cstate->file_encoding);
-		if (cvt != cstate->line_buf.data)
-		{
-			/* transfer converted data back to line_buf */
-			resetStringInfo(&cstate->line_buf);
-			appendBinaryStringInfo(&cstate->line_buf, cvt, strlen(cvt));
-			pfree(cvt);
-		}
-	}
-
-	/* Now it's safe to use the buffer in error messages */
-	cstate->line_buf_converted = true;
 
+	CONVERT_TO_SERVER_ENCODING(cstate)
 	return result;
 }
 
@@ -4281,6 +4342,7 @@ not_end_of_copy:
 	 * Transfer any still-uncopied data to line_buf.
 	 */
 	REFILL_LINEBUF;
+	CLEAR_EOL_LINE()
 
 	return result;
 }
-- 
1.8.3.1

0003-Allow-copy-from-command-to-process-data-from-file-ST.patchtext/x-patch; charset=US-ASCII; name=0003-Allow-copy-from-command-to-process-data-from-file-ST.patchDownload
From 4ff785c888e93a8dd33d4e48cb4f804e204cb739 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 10 Jun 2020 07:18:33 +0530
Subject: [PATCH 3/4] Allow copy from command to process data from file/STDIN
 contents to a table in parallel.

This feature allows the copy from to leverage multiple CPUs in order to copy
data from file/STDIN to a table. This adds a PARALLEL option to COPY FROM
command where the user can specify the number of workers that can be used
to perform the COPY FROM command. Specifying zero as number of workers will
disable parallelism.
The backend, to which the "COPY FROM" query is submitted acts as leader with
the responsibility of reading data from the file/stdin, launching at most n
number of workers as specified with PARALLEL 'n' option in the "COPY FROM"
query. The leader populates the common data required for the workers execution
in the DSM and shares it with the workers. The leader then executes before
statement triggers if there exists any. Leader populates DSM chunks which
includes the start offset and chunk size, while populating the chunks it reads
as many blocks as required into the DSM data blocks from the file. Each block
is of 64K size. The leader parses the data to identify a chunk, the existing
logic from CopyReadLineText which identifies the chunks with some changes was
used for this. Leader checks if a free chunk is available to copy the
information, if there is no free chunk it waits till the required chunk is
freed up by the worker and then copies the identified chunks information
(offset & chunk size) into the DSM chunks. This process is repeated till the
complete file is processed. Simultaneously, the workers cache the chunks(50)
locally into the local memory and release the chunks to the leader for further
populating. Each worker processes the chunk that it cached and inserts it into
the table. The leader does not participate in the insertion of data, leaders
only responsibility will be to identify the chunks as fast as possible for the
workers to do the actual copy operation. The leader waits till all the chunks
populated are processed by the workers and exits.
---
 src/backend/access/heap/heapam.c     |  13 -
 src/backend/access/transam/xact.c    |  13 +
 src/backend/commands/copy.c          | 875 +++++++++++++++++++++++++++++++++--
 src/backend/optimizer/util/clauses.c |   2 +-
 src/include/access/xact.h            |   1 +
 src/tools/pgindent/typedefs.list     |   1 +
 6 files changed, 853 insertions(+), 52 deletions(-)

diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 94eb37d..6991b9f 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2012,19 +2012,6 @@ static HeapTuple
 heap_prepare_insert(Relation relation, HeapTuple tup, TransactionId xid,
 					CommandId cid, int options)
 {
-	/*
-	 * Parallel operations are required to be strictly read-only in a parallel
-	 * worker.  Parallel inserts are not safe even in the leader in the
-	 * general case, because group locking means that heavyweight locks for
-	 * relation extension or GIN page locks will not conflict between members
-	 * of a lock group, but we don't prohibit that case here because there are
-	 * useful special cases that we can safely allow, such as CREATE TABLE AS.
-	 */
-	if (IsParallelWorker())
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_TRANSACTION_STATE),
-				 errmsg("cannot insert tuples in a parallel worker")));
-
 	tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
 	tup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK);
 	tup->t_data->t_infomask |= HEAP_XMAX_INVALID;
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index cd30b62..d43902c 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -502,6 +502,19 @@ GetCurrentFullTransactionIdIfAny(void)
 }
 
 /*
+ *	AssignFullTransactionIdForWorker
+ *
+ * For parallel copy, all the workers must use the same transaction id.
+ */
+void AssignFullTransactionIdForWorker(FullTransactionId fullTransactionId)
+{
+	TransactionState s = CurrentTransactionState;
+
+	Assert((IsInParallelMode() || IsParallelWorker()));
+	s->fullTransactionId = fullTransactionId;
+}
+
+/*
  *	MarkCurrentTransactionIdLoggedIfAny
  *
  * Remember that the current xid - if it is assigned - now has been wal logged.
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index d930644..b1e2e71 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -26,6 +26,7 @@
 #include "access/xlog.h"
 #include "catalog/dependency.h"
 #include "catalog/pg_authid.h"
+#include "catalog/pg_proc_d.h"
 #include "catalog/pg_type.h"
 #include "commands/copy.h"
 #include "commands/defrem.h"
@@ -40,11 +41,13 @@
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
+#include "optimizer/clauses.h"
 #include "optimizer/optimizer.h"
 #include "parser/parse_coerce.h"
 #include "parser/parse_collate.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_relation.h"
+#include "pgstat.h"
 #include "port/pg_bswap.h"
 #include "rewrite/rewriteHandler.h"
 #include "storage/fd.h"
@@ -95,6 +98,18 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
+/*
+ * State of the chunk.
+ */
+typedef enum ParallelCopyChunkState
+{
+	CHUNK_INIT,					/* initial state of chunk */
+	CHUNK_LEADER_POPULATING,	/* leader processing chunk */
+	CHUNK_LEADER_POPULATED,		/* leader completed populating chunk */
+	CHUNK_WORKER_PROCESSING,	/* worker processing chunk */
+	CHUNK_WORKER_PROCESSED		/* worker completed processing chunk */
+}ParallelCopyChunkState;
+
 #define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
 
 #define DATA_BLOCK_SIZE RAW_BUF_SIZE
@@ -527,9 +542,13 @@ if (1) \
 { \
 	if (raw_buf_ptr > cstate->raw_buf_index) \
 	{ \
-		appendBinaryStringInfo(&cstate->line_buf, \
-							 cstate->raw_buf + cstate->raw_buf_index, \
-							   raw_buf_ptr - cstate->raw_buf_index); \
+		if (!IsParallelCopy()) \
+			appendBinaryStringInfo(&cstate->line_buf, \
+								   cstate->raw_buf + cstate->raw_buf_index, \
+								   raw_buf_ptr - cstate->raw_buf_index); \
+		else \
+			chunk_size +=  raw_buf_ptr - cstate->raw_buf_index; \
+		\
 		cstate->raw_buf_index = raw_buf_ptr; \
 	} \
 } else ((void) 0)
@@ -542,13 +561,40 @@ if (1) \
 	goto not_end_of_copy; \
 } else ((void) 0)
 
+/* Begin parallel copy Macros */
+#define SET_NEWLINE_SIZE() \
+{ \
+	if (cstate->eol_type == EOL_NL || cstate->eol_type == EOL_CR) \
+		new_line_size = 1; \
+	else if (cstate->eol_type == EOL_CRNL) \
+		new_line_size = 2; \
+	else \
+		new_line_size = 0; \
+}
+
+/*
+ * COPY_WAIT_TO_PROCESS - Wait before continuing to process.
+ */
+#define COPY_WAIT_TO_PROCESS() \
+{ \
+	CHECK_FOR_INTERRUPTS(); \
+	(void) WaitLatch(MyLatch, \
+					 WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH, \
+					 1L, WAIT_EVENT_PG_SLEEP); \
+	ResetLatch(MyLatch); \
+}
+
+/* End parallel copy Macros */
+
 /*
  * CONVERT_TO_SERVER_ENCODING - convert contents to server encoding.
  */
 #define CONVERT_TO_SERVER_ENCODING(cstate) \
 { \
 	/* Done reading the line.  Convert it to server encoding. */ \
-	if (cstate->need_transcoding) \
+	if (cstate->need_transcoding && \
+		(!IsParallelCopy() || \
+		 (IsParallelCopy() && !IsLeader()))) \
 	{ \
 		char	   *cvt; \
 		cvt = pg_any_to_server(cstate->line_buf.data, \
@@ -607,22 +653,38 @@ if (1) \
  * CLEAR_EOL_LINE - Wrapper for clearing EOL.
  */
 #define CLEAR_EOL_LINE() \
-if (!result && !IsHeaderLine()) \
-	CLEAR_EOL_FROM_COPIED_DATA(cstate->line_buf.data, \
-								cstate->line_buf.len, \
-								cstate->line_buf.len) \
+{ \
+	if (!result && !IsHeaderLine()) \
+	{ \
+		if (IsParallelCopy()) \
+			CLEAR_EOL_FROM_COPIED_DATA(cstate->raw_buf, \
+									   raw_buf_ptr, chunk_size) \
+		else \
+			CLEAR_EOL_FROM_COPIED_DATA(cstate->line_buf.data, \
+									   cstate->line_buf.len, \
+									   cstate->line_buf.len) \
+	} \
+}
 
 /*
  * INCREMENTPROCESSED - Increment the lines processed.
  */
-#define INCREMENTPROCESSED(processed)  \
-processed++;
+#define INCREMENTPROCESSED(processed) \
+{ \
+	if (!IsParallelCopy()) \
+		processed++; \
+	else \
+		pg_atomic_add_fetch_u64(&cstate->pcdata->pcshared_info->processed, 1); \
+}
 
 /*
  * GETPROCESSED - Get the lines processed.
  */
 #define GETPROCESSED(processed) \
-return processed;
+if (!IsParallelCopy()) \
+	return processed; \
+else \
+	return pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
 
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
@@ -671,8 +733,12 @@ static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 
 static pg_attribute_always_inline void EndParallelCopy(ParallelContext *pcxt);
+static void ExecBeforeStmtTrigger(CopyState cstate);
+static void CheckCopyFromValidity(CopyState cstate);
 static void PopulateAttributes(CopyState cstate, TupleDesc	tup_desc,
 							   List *attnamelist);
+static void PopulateCatalogInformation(CopyState cstate);
+static pg_attribute_always_inline uint32 GetChunkPosition(CopyState cstate);
 static pg_attribute_always_inline copy_data_source_cb LookupParallelCopyFnPtr(const char *funcname);
 static pg_attribute_always_inline char* LookupParallelCopyFnStr(copy_data_source_cb fn_addr);
 
@@ -826,6 +892,130 @@ InsertListShm(ParallelContext *pcxt, int key, List *inputlist,
 }
 
 /*
+ * IsTriggerFunctionParallelSafe - Check if the trigger function is parallel
+ * safe for the triggers. Return false if any one of the trigger has parallel
+ * unsafe function.
+ */
+static pg_attribute_always_inline bool
+IsTriggerFunctionParallelSafe(TriggerDesc *trigdesc)
+{
+	int	i;
+	for (i = 0; i < trigdesc->numtriggers; i++)
+	{
+		Trigger    *trigger = &trigdesc->triggers[i];
+		int 		trigtype = RI_TRIGGER_NONE;
+
+		if (func_parallel(trigger->tgfoid) != PROPARALLEL_SAFE)
+			return false;
+
+		/* If the trigger is parallel safe, also look for RI_TRIGGER. */
+		trigtype = RI_FKey_trigger_type(trigger->tgfoid);
+		if (trigtype == RI_TRIGGER_PK || trigtype == RI_TRIGGER_FK)
+			return false;
+	}
+
+	return true;
+}
+
+/*
+ * CheckExprParallelSafety - determine parallel safety of volatile expressions
+ * in default clause of column definition or in where clause and return true if
+ * they are parallel safe.
+ */
+static pg_attribute_always_inline bool
+CheckExprParallelSafety(CopyState cstate)
+{
+	if (contain_volatile_functions(cstate->whereClause))
+	{
+		if (!is_parallel_safe(NULL, (Node *)cstate->whereClause))
+			return false;
+	}
+
+	if (cstate->volatile_defexprs && cstate->defexprs != NULL &&
+		cstate->num_defaults != 0)
+	{
+		int     i;
+		for (i = 0; i < cstate->num_defaults; i++)
+		{
+			if (!is_parallel_safe(NULL, (Node *) cstate->defexprs[i]->expr))
+				return false;
+		}
+	}
+
+	return true;
+}
+
+/*
+ * FindInsertMethod - determine insert mode single, multi, or multi conditional.
+ */
+static pg_attribute_always_inline CopyInsertMethod
+FindInsertMethod(CopyState cstate)
+{
+	if (cstate->rel->trigdesc != NULL &&
+		(cstate->rel->trigdesc->trig_insert_before_row ||
+		 cstate->rel->trigdesc->trig_insert_instead_row))
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
+			cstate->rel->trigdesc != NULL &&
+			cstate->rel->trigdesc->trig_insert_new_table)
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+		return CIM_MULTI_CONDITIONAL;
+
+	return CIM_MULTI;
+}
+
+/*
+ * IsParallelCopyAllowed - check for the cases where parallel copy is not
+ * applicable.
+ */
+static pg_attribute_always_inline bool
+IsParallelCopyAllowed(CopyState cstate)
+{
+	/* Parallel copy not allowed for freeze & binary option. */
+	if (cstate->freeze || cstate->binary)
+		return false;
+
+	/* Check if copy is into foreign table. */
+	if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+		return false;
+
+	/* Check if copy is into a temporary table. */
+	if (RELATION_IS_LOCAL(cstate->rel) || RELATION_IS_OTHER_TEMP(cstate->rel))
+		return false;
+
+	/* Check if trigger function is parallel safe. */
+	if (cstate->rel->trigdesc != NULL &&
+			!IsTriggerFunctionParallelSafe(cstate->rel->trigdesc))
+		return false;
+
+	/*
+	 * Check if there is after statement or instead of trigger or transition
+	 * table triggers.
+	 */
+	if (cstate->rel->trigdesc != NULL &&
+		(cstate->rel->trigdesc->trig_insert_after_statement ||
+		 cstate->rel->trigdesc->trig_insert_instead_row ||
+		 cstate->rel->trigdesc->trig_insert_new_table))
+		return false;
+
+	/* Check if the volatile expressions are parallel safe, if present any. */
+	if (!CheckExprParallelSafety(cstate))
+		return false;
+
+	/* Check if the insertion mode is single. */
+	if (FindInsertMethod(cstate) == CIM_SINGLE)
+		return false;
+
+	return true;
+}
+
+/*
  * BeginParallelCopy - start parallel copy tasks.
  *
  * Get the number of workers required to perform the parallel copy. The data
@@ -855,6 +1045,8 @@ BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
 	int  parallel_workers = 0;
 	ParallelCopyData *pcdata;
 
+	CheckCopyFromValidity(cstate);
+
 	parallel_workers = Min(nworkers, max_worker_processes);
 
 	/* Can't perform copy in parallel */
@@ -864,6 +1056,15 @@ BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
 	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
 	cstate->pcdata = pcdata;
 
+	/*
+	 * User chosen parallel copy. Determine if the parallel copy is actually
+	 * allowed. If not, go with the non-parallel mode.
+	 */
+	if (!IsParallelCopyAllowed(cstate))
+		return NULL;
+
+	full_transaction_id = GetCurrentFullTransactionId();
+
 	EnterParallelMode();
 	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
 								 parallel_workers);
@@ -1090,7 +1291,211 @@ ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
 	cstate->line_buf_converted = false;
 	cstate->raw_buf = NULL;
 	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+
+	PopulateCatalogInformation(cstate);
+
+	/* Create workspace for CopyReadAttributes results. */
+	if (!cstate->binary)
+	{
+		AttrNumber	attr_count = list_length(cstate->attnumlist);
+
+		cstate->max_fields = attr_count;
+		cstate->raw_fields = (char **)palloc(attr_count * sizeof(char *));
+	}
 }
+
+/*
+ * CacheChunkInfo - Cache the chunk information to local memory.
+ */
+static bool
+CacheChunkInfo(CopyState cstate, uint32 buff_count)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	uint32			write_pos;
+	ParallelCopyDataBlock *data_blk_ptr;
+	ParallelCopyChunkBoundary *chunkInfo;
+	uint32 offset;
+	int dataSize;
+	int copiedSize = 0;
+
+	resetStringInfo(&pcdata->worker_line_buf[buff_count].line_buf);
+	write_pos = GetChunkPosition(cstate);
+	if (-1 == write_pos)
+		return true;
+
+	/* Get the current chunk information. */
+	chunkInfo = &pcshared_info->chunk_boundaries.ring[write_pos];
+	if (pg_atomic_read_u32(&chunkInfo->chunk_size) == 0)
+		goto empty_data_chunk_update;
+
+	/* Get the block information. */
+	data_blk_ptr = &pcshared_info->data_blocks[chunkInfo->first_block];
+
+	/* Get the offset information from where the data must be copied. */
+	offset = chunkInfo->start_offset;
+	pcdata->worker_line_buf[buff_count].cur_lineno = chunkInfo->cur_lineno;
+
+	elog(DEBUG1, "[Worker] Processing - chunk position:%d, block:%d, unprocessed chunks:%d, offset:%d, chunk size:%d",
+				 write_pos, chunkInfo->first_block,
+				 pg_atomic_read_u32(&data_blk_ptr->unprocessed_chunk_parts),
+				 offset, pg_atomic_read_u32(&chunkInfo->chunk_size));
+
+	for (;;)
+	{
+		uint8 skip_bytes = data_blk_ptr->skip_bytes;
+		/*
+		 * There is a possibility that the above loop has come out because
+		 * data_blk_ptr->curr_blk_completed is set, but dataSize read might
+		 * be an old value, if data_blk_ptr->curr_blk_completed and the chunk is
+		 * completed, chunk_size will be set. Read the chunk_size again to be
+		 * sure if it is complete or partial block.
+		 */
+		dataSize = pg_atomic_read_u32(&chunkInfo->chunk_size);
+		if (dataSize)
+		{
+			int remainingSize = dataSize - copiedSize;
+			if (!remainingSize)
+				break;
+
+			/* Whole chunk is in current block. */
+			if (remainingSize + offset + skip_bytes < DATA_BLOCK_SIZE)
+			{
+				appendBinaryStringInfo(&pcdata->worker_line_buf[buff_count].line_buf,
+									   &data_blk_ptr->data[offset],
+									   remainingSize);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_chunk_parts,
+										1);
+				break;
+			}
+			else
+			{
+				/* Chunk is spread across the blocks. */
+				uint32 chunkInCurrentBlock =  (DATA_BLOCK_SIZE - skip_bytes) - offset;
+				appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+										 &data_blk_ptr->data[offset],
+										 chunkInCurrentBlock);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_chunk_parts, 1);
+				copiedSize += chunkInCurrentBlock;
+				while (copiedSize < dataSize)
+				{
+					uint32 currentBlockCopySize;
+					ParallelCopyDataBlock *currBlkPtr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+					skip_bytes = currBlkPtr->skip_bytes;
+
+					/*
+					 * If complete data is present in current block use
+					 * dataSize - copiedSize, or copy the whole block from
+					 * current block.
+					 */
+					currentBlockCopySize = Min(dataSize - copiedSize, DATA_BLOCK_SIZE - skip_bytes);
+					appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+											 &currBlkPtr->data[0],
+											 currentBlockCopySize);
+					pg_atomic_sub_fetch_u32(&currBlkPtr->unprocessed_chunk_parts, 1);
+					copiedSize += currentBlockCopySize;
+					data_blk_ptr = currBlkPtr;
+				}
+
+				break;
+			}
+		}
+		else
+		{
+			/* Copy this complete block from the current offset. */
+			uint32 chunkInCurrentBlock =  (DATA_BLOCK_SIZE - skip_bytes) - offset;
+			appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+									 &data_blk_ptr->data[offset],
+									 chunkInCurrentBlock);
+			pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_chunk_parts, 1);
+			copiedSize += chunkInCurrentBlock;
+
+			/*
+			 * Reset the offset. For the first copy, copy from the offset. For
+			 * the subsequent copy the complete block.
+			 */
+			offset = 0;
+
+			/* Set data_blk_ptr to the following block. */
+			data_blk_ptr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+		}
+
+		for (;;)
+		{
+			/* Get the size of this chunk */
+			dataSize = pg_atomic_read_u32(&chunkInfo->chunk_size);
+
+			/*
+			 * If the data is present in current block chunkInfo.chunk_size
+			 * will be updated. If the data is spread across the blocks either
+			 * of chunkInfo.chunk_size or data_blk_ptr->curr_blk_completed can
+			 * be updated. chunkInfo.chunk_size will be updated if the complete
+			 * read is finished. data_blk_ptr->curr_blk_completed will be
+			 * updated if processing of current block is finished and data
+			 * processing is not finished.
+			 */
+			if (data_blk_ptr->curr_blk_completed || (dataSize != -1))
+				break;
+
+			COPY_WAIT_TO_PROCESS()
+		}
+	}
+
+empty_data_chunk_update:
+	elog(DEBUG1, "[Worker] Completed processing chunk:%d", write_pos);
+	pg_atomic_write_u32(&chunkInfo->chunk_state, CHUNK_WORKER_PROCESSED);
+	pg_atomic_write_u32(&chunkInfo->chunk_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+	return false;
+}
+
+/*
+ * GetWorkerChunk - Returns a chunk for worker to process.
+ */
+static bool
+GetWorkerChunk(CopyState cstate)
+{
+	uint32 buff_count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+
+	/*
+	 * Copy the chunk data to line_buf and release the chunk position so that the
+	 * worker can continue loading data.
+	 */
+	if (pcdata->worker_line_buf_pos < pcdata->worker_line_buf_count)
+		goto return_chunk;
+
+	pcdata->worker_line_buf_pos = 0;
+	pcdata->worker_line_buf_count = 0;
+
+	for (buff_count = 0; buff_count < WORKER_CHUNK_COUNT; buff_count++)
+	{
+		bool result = CacheChunkInfo(cstate, buff_count);
+		if (result)
+			break;
+
+		pcdata->worker_line_buf_count++;
+	}
+
+	if (pcdata->worker_line_buf_count)
+		goto return_chunk;
+	else
+		resetStringInfo(&cstate->line_buf);
+
+	return true;
+
+return_chunk:
+	cstate->line_buf = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].line_buf;
+	cstate->cur_lineno = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].cur_lineno;
+	cstate->line_buf_valid = true;
+
+	/* Mark that encoding conversion hasn't occurred yet. */
+	cstate->line_buf_converted = false;
+	CONVERT_TO_SERVER_ENCODING(cstate)
+	pcdata->worker_line_buf_pos++;
+	return false;
+}
+
 /*
  * ParallelCopyMain - parallel copy worker's code.
  *
@@ -1136,6 +1541,7 @@ ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
 	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
 
 	pcdata->pcshared_info = pcshared_info;
+	AssignFullTransactionIdForWorker(pcshared_info->full_transaction_id);
 
 	shared_cstate = (ParallelCopyCommonKeyData *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE,
 														   false);
@@ -1188,6 +1594,34 @@ ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
 	MemoryContextSwitchTo(oldcontext);
 	return;
 }
+
+/*
+ * UpdateBlockInChunkInfo - Update the chunk information.
+ */
+static pg_attribute_always_inline int
+UpdateBlockInChunkInfo(CopyState cstate, uint32 blk_pos,
+					   uint32 offset, uint32 chunk_size, uint32 chunk_state)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyChunkBoundaries *chunkBoundaryPtr = &pcshared_info->chunk_boundaries;
+	ParallelCopyChunkBoundary *chunkInfo;
+	int chunk_pos = chunkBoundaryPtr->leader_pos;
+
+	/* Update the chunk information for the worker to pick and process. */
+	chunkInfo = &chunkBoundaryPtr->ring[chunk_pos];
+	while (pg_atomic_read_u32(&chunkInfo->chunk_size) != -1)
+		COPY_WAIT_TO_PROCESS()
+
+	chunkInfo->first_block = blk_pos;
+	chunkInfo->start_offset = offset;
+	chunkInfo->cur_lineno = cstate->cur_lineno;
+	pg_atomic_write_u32(&chunkInfo->chunk_size, chunk_size);
+	pg_atomic_write_u32(&chunkInfo->chunk_state, chunk_state);
+	chunkBoundaryPtr->leader_pos = (chunkBoundaryPtr->leader_pos + 1) % RINGSIZE;
+
+	return chunk_pos;
+}
+
 /*
  * ParallelCopyLeader - parallel copy leader's functionality.
  *
@@ -1213,9 +1647,158 @@ ParallelCopyLeader(CopyState cstate)
 	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
 	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
 
+	/* Execute the before statement triggers from the leader */
+	ExecBeforeStmtTrigger(cstate);
+
+	/* On input just throw the header line away. */
+	if (cstate->cur_lineno == 0 && cstate->header_line)
+	{
+		cstate->cur_lineno++;
+		if (CopyReadLine(cstate))
+		{
+			pcshared_info->is_read_in_progress = false;
+			return;			/* done */
+		}
+	}
+
+	for (;;)
+	{
+		bool done;
+		cstate->cur_lineno++;
+
+		/* Actually read the line into memory here. */
+		done = CopyReadLine(cstate);
+
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			break;
+	}
+
 	pcshared_info->is_read_in_progress = false;
 	cstate->cur_lineno = 0;
 }
+
+/*
+ * GetChunkPosition - return the chunk position that worker should process.
+ */
+static uint32
+GetChunkPosition(CopyState cstate)
+{
+	ParallelCopyData *pcdata = cstate->pcdata;
+	ParallelCopyShmInfo *pcshared_info = pcdata->pcshared_info;
+	uint32  previous_pos = pcdata->worker_processed_pos;
+	uint32 write_pos = (previous_pos == -1) ? 0 : (previous_pos + 1) % RINGSIZE;
+	for (;;)
+	{
+		int		dataSize;
+		bool	is_read_in_progress = pcshared_info->is_read_in_progress;
+		ParallelCopyChunkBoundary *chunkInfo;
+		ParallelCopyDataBlock *data_blk_ptr;
+		ParallelCopyChunkState chunk_state = CHUNK_LEADER_POPULATED;
+		ParallelCopyChunkState curr_chunk_state;
+		CHECK_FOR_INTERRUPTS();
+
+		/* File read completed & no elements to process. */
+		if (!is_read_in_progress &&
+			(pcshared_info->populated ==
+			 pg_atomic_read_u64(&pcshared_info->total_worker_processed)))
+		{
+			write_pos = -1;
+			break;
+		}
+
+		/* Get the current chunk information. */
+		chunkInfo = &pcshared_info->chunk_boundaries.ring[write_pos];
+		curr_chunk_state = pg_atomic_read_u32(&chunkInfo->chunk_state);
+		if ((write_pos % WORKER_CHUNK_COUNT == 0) &&
+			(curr_chunk_state == CHUNK_WORKER_PROCESSED ||
+			 curr_chunk_state == CHUNK_WORKER_PROCESSING))
+		{
+			pcdata->worker_processed_pos = write_pos;
+			write_pos = (write_pos + WORKER_CHUNK_COUNT) %  RINGSIZE;
+			continue;
+		}
+
+		/* Get the size of this chunk. */
+		dataSize = pg_atomic_read_u32(&chunkInfo->chunk_size);
+
+		if (dataSize != 0) /* If not an empty chunk. */
+		{
+			/* Get the block information. */
+			data_blk_ptr = &pcshared_info->data_blocks[chunkInfo->first_block];
+
+			if (!data_blk_ptr->curr_blk_completed && (dataSize == -1))
+			{
+				/* Wait till the current chunk or block is added. */
+				COPY_WAIT_TO_PROCESS()
+				continue;
+			}
+		}
+
+		/* Make sure that no worker has consumed this element. */
+		if (pg_atomic_compare_exchange_u32(&chunkInfo->chunk_state,
+										   &chunk_state, CHUNK_WORKER_PROCESSING))
+			break;
+	}
+
+	pcdata->worker_processed_pos = write_pos;
+	return write_pos;
+}
+
+/*
+ * GetFreeCopyBlock - Get a free block for data to be copied.
+ */
+static pg_attribute_always_inline uint32
+GetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	int count = 0;
+	uint32 last_free_block = pcshared_info->cur_block_pos;
+	uint32 block_pos = (last_free_block != -1) ? ((last_free_block + 1) % MAX_BLOCKS_COUNT): 0;
+
+	/* Get a new block for copying data. */
+	while (count < MAX_BLOCKS_COUNT)
+	{
+		ParallelCopyDataBlock *dataBlkPtr = &pcshared_info->data_blocks[block_pos];
+		uint32 unprocessed_chunk_parts = pg_atomic_read_u32(&dataBlkPtr->unprocessed_chunk_parts);
+		if (unprocessed_chunk_parts == 0)
+		{
+			dataBlkPtr->curr_blk_completed = false;
+			dataBlkPtr->skip_bytes = 0;
+			pcshared_info->cur_block_pos = block_pos;
+			return block_pos;
+		}
+
+		block_pos = (block_pos + 1) % MAX_BLOCKS_COUNT;
+		count++;
+	}
+
+	return -1;
+}
+
+/*
+ * WaitGetFreeCopyBlock - If there are no blocks available, wait and get a block
+ * for copying data.
+ */
+static uint32
+WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	uint32 new_free_pos = -1;
+	for (;;)
+	{
+		new_free_pos = GetFreeCopyBlock(pcshared_info);
+		if (new_free_pos != -1)	/* We have got one block, break now. */
+			break;
+
+		COPY_WAIT_TO_PROCESS()
+	}
+
+	return new_free_pos;
+}
+
 /*
  * LookupParallelCopyFnPtr - Look up parallel copy function pointer.
  */
@@ -1251,6 +1834,146 @@ LookupParallelCopyFnStr(copy_data_source_cb fn_addr)
 	/* We can only reach this by programming error. */
 	elog(ERROR, "internal function pointer not found");
 }
+
+/*
+ * SetRawBufForLoad - Set raw_buf to the shared memory where the file data must
+ * be read.
+ */
+static void
+SetRawBufForLoad(CopyState cstate, uint32 chunk_size, uint32 copy_buf_len,
+				 uint32 raw_buf_ptr, char **copy_raw_buf)
+{
+	ParallelCopyShmInfo	*pcshared_info;
+	uint32 cur_block_pos;
+	uint32 next_block_pos;
+	ParallelCopyDataBlock	*cur_data_blk_ptr = NULL;
+	ParallelCopyDataBlock	*next_data_blk_ptr = NULL;
+
+	if (!IsParallelCopy())
+		return;
+
+	pcshared_info = cstate->pcdata->pcshared_info;
+	cur_block_pos = pcshared_info->cur_block_pos;
+	cur_data_blk_ptr = (cstate->raw_buf) ? &pcshared_info->data_blocks[cur_block_pos] : NULL;
+	next_block_pos = WaitGetFreeCopyBlock(pcshared_info);
+	next_data_blk_ptr = &pcshared_info->data_blocks[next_block_pos];
+
+	/* set raw_buf to the data block in shared memory */
+	cstate->raw_buf = next_data_blk_ptr->data;
+	*copy_raw_buf = cstate->raw_buf;
+	if (cur_data_blk_ptr && chunk_size)
+	{
+		/*
+		 * Mark the previous block as completed, worker can start copying this
+		 * data.
+		 */
+		cur_data_blk_ptr->following_block = next_block_pos;
+		pg_atomic_add_fetch_u32(&cur_data_blk_ptr->unprocessed_chunk_parts, 1);
+		cur_data_blk_ptr->skip_bytes = copy_buf_len - raw_buf_ptr;
+		cur_data_blk_ptr->curr_blk_completed = true;
+	}
+}
+
+/*
+ * EndChunkParallelCopy - Update the chunk information in shared memory.
+ */
+static void
+EndChunkParallelCopy(CopyState cstate, uint32 chunk_pos, uint32 chunk_size,
+					 uint32 raw_buf_ptr)
+{
+	uint8 new_line_size;
+	if (!IsParallelCopy())
+		return;
+
+	if (!IsHeaderLine())
+	{
+		ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+		ParallelCopyChunkBoundaries *chunkBoundaryPtr = &pcshared_info->chunk_boundaries;
+		SET_NEWLINE_SIZE()
+		if (chunk_size)
+		{
+			ParallelCopyChunkBoundary *chunkInfo = &chunkBoundaryPtr->ring[chunk_pos];
+			/*
+			 * If the new_line_size > raw_buf_ptr, then the new block has only
+			 * new line char content. The unprocessed count should not be
+			 * increased in this case.
+			 */
+			if (raw_buf_ptr > new_line_size)
+			{
+				uint32 cur_block_pos = pcshared_info->cur_block_pos;
+				ParallelCopyDataBlock *curr_data_blk_ptr = &pcshared_info->data_blocks[cur_block_pos];
+				pg_atomic_add_fetch_u32(&curr_data_blk_ptr->unprocessed_chunk_parts, 1);
+			}
+
+			/* Update chunk size. */
+			pg_atomic_write_u32(&chunkInfo->chunk_size, chunk_size);
+			pg_atomic_write_u32(&chunkInfo->chunk_state, CHUNK_LEADER_POPULATED);
+			elog(DEBUG1, "[Leader] After adding - chunk position:%d, chunk_size:%d",
+						 chunk_pos, chunk_size);
+			pcshared_info->populated++;
+		}
+		else if (new_line_size)
+		{
+			/* This means only new line char, empty record should be inserted.*/
+			ParallelCopyChunkBoundary *chunkInfo;
+			chunk_pos = UpdateBlockInChunkInfo(cstate, -1, -1, 0,
+											   CHUNK_LEADER_POPULATED);
+			chunkInfo = &chunkBoundaryPtr->ring[chunk_pos];
+			elog(DEBUG1, "[Leader] Added empty chunk with offset:%d, chunk position:%d, chunk size:%d",
+						 chunkInfo->start_offset, chunk_pos,
+						 pg_atomic_read_u32(&chunkInfo->chunk_size));
+			pcshared_info->populated++;
+		}
+	}
+}
+
+/*
+ * ExecBeforeStmtTrigger - Execute the before statement trigger, this will be
+ * executed for parallel copy by the leader process.
+ */
+static void
+ExecBeforeStmtTrigger(CopyState cstate)
+{
+	EState	   *estate = CreateExecutorState();
+	ResultRelInfo *resultRelInfo;
+
+	Assert(IsLeader());
+
+	/*
+	 * We need a ResultRelInfo so we can use the regular executor's
+	 * index-entry-making machinery.  (There used to be a huge amount of code
+	 * here that basically duplicated execUtils.c ...)
+	 */
+	resultRelInfo = makeNode(ResultRelInfo);
+	InitResultRelInfo(resultRelInfo,
+					  cstate->rel,
+					  1,		/* must match rel's position in range_table */
+					  NULL,
+					  0);
+
+	/* Verify the named relation is a valid target for INSERT */
+	CheckValidResultRel(resultRelInfo, CMD_INSERT);
+
+	estate->es_result_relations = resultRelInfo;
+	estate->es_num_result_relations = 1;
+	estate->es_result_relation_info = resultRelInfo;
+
+	ExecInitRangeTable(estate, cstate->range_table);
+
+	/*
+	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
+	 * should do this for COPY, since it's not really an "INSERT" statement as
+	 * such. However, executing these triggers maintains consistency with the
+	 * EACH ROW triggers that we already fire on COPY.
+	 */
+	ExecBSInsertTriggers(estate, resultRelInfo);
+
+	/* Close any trigger target relations */
+	ExecCleanUpTriggerState(estate);
+
+	FreeExecutorState(estate);
+}
+
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
  * in past protocol redesigns.
@@ -3611,7 +4334,8 @@ CopyFrom(CopyState cstate)
 
 	PartitionTupleRouting *proute = NULL;
 	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
+	CommandId	mycid = IsParallelCopy() ? cstate->pcdata->pcshared_info->mycid :
+										   GetCurrentCommandId(true);
 	int			ti_options = 0; /* start with default options for insert */
 	BulkInsertState bistate = NULL;
 	CopyInsertMethod insertMethod;
@@ -3621,7 +4345,14 @@ CopyFrom(CopyState cstate)
 	bool		has_instead_insert_row_trig;
 	bool		leafpart_use_multi_insert = false;
 
-	CheckCopyFromValidity(cstate);
+	/*
+	 * Perform this check if it is not parallel copy. In case of parallel
+	 * copy, this check is done by the leader, so that if any invalid case
+	 * exist the copy from command will error out from the leader itself,
+	 * avoiding launching workers, just to throw error.
+	 */
+	if (!IsParallelCopy())
+		CheckCopyFromValidity(cstate);
 
 	/*
 	 * If the target file is new-in-transaction, we assume that checking FSM
@@ -3848,13 +4579,16 @@ CopyFrom(CopyState cstate)
 	has_instead_insert_row_trig = (resultRelInfo->ri_TrigDesc &&
 								   resultRelInfo->ri_TrigDesc->trig_insert_instead_row);
 
-	/*
-	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
-	 * should do this for COPY, since it's not really an "INSERT" statement as
-	 * such. However, executing these triggers maintains consistency with the
-	 * EACH ROW triggers that we already fire on COPY.
-	 */
-	ExecBSInsertTriggers(estate, resultRelInfo);
+	if (!IsParallelCopy())
+	{
+		/*
+		 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
+		 * should do this for COPY, since it's not really an "INSERT" statement as
+		 * such. However, executing these triggers maintains consistency with the
+		 * EACH ROW triggers that we already fire on COPY.
+		 */
+		ExecBSInsertTriggers(estate, resultRelInfo);
+	}
 
 	econtext = GetPerTupleExprContext(estate);
 
@@ -4368,7 +5102,7 @@ BeginCopyFrom(ParseState *pstate,
 	initStringInfo(&cstate->attribute_buf);
 	initStringInfo(&cstate->line_buf);
 	cstate->line_buf_converted = false;
-	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+	cstate->raw_buf = (IsParallelCopy()) ? NULL : (char *) palloc(RAW_BUF_SIZE + 1);
 	cstate->raw_buf_index = cstate->raw_buf_len = 0;
 
 	/* Assign range table, we'll need it in CopyFrom. */
@@ -4512,26 +5246,35 @@ NextCopyFromRawFields(CopyState cstate, char ***fields, int *nfields)
 	/* only available for text or csv input */
 	Assert(!cstate->binary);
 
-	/* on input just throw the header line away */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (IsParallelCopy())
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
-			return false;		/* done */
+		done = GetWorkerChunk(cstate);
+		if (done && cstate->line_buf.len == 0)
+			return false;
 	}
+	else
+	{
+		/* on input just throw the header line away */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
+		{
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+				return false;		/* done */
+		}
 
-	cstate->cur_lineno++;
+		cstate->cur_lineno++;
 
-	/* Actually read the line into memory here */
-	done = CopyReadLine(cstate);
+		/* Actually read the line into memory here */
+		done = CopyReadLine(cstate);
 
-	/*
-	 * EOF at start of line means we're done.  If we see EOF after some
-	 * characters, we act as though it was newline followed by EOF, ie,
-	 * process the line and then exit loop on next iteration.
-	 */
-	if (done && cstate->line_buf.len == 0)
-		return false;
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			return false;
+	}
 
 	/* Parse the line into de-escaped field values */
 	if (cstate->csv_mode)
@@ -4781,9 +5524,31 @@ CopyReadLine(CopyState cstate)
 		 */
 		if (cstate->copy_dest == COPY_NEW_FE)
 		{
+			bool bIsFirst = true;
 			do
 			{
-				cstate->raw_buf_index = cstate->raw_buf_len;
+				if (!IsParallelCopy())
+					cstate->raw_buf_index = cstate->raw_buf_len;
+				else
+				{
+					if (cstate->raw_buf_index == RAW_BUF_SIZE)
+					{
+						/* Get a new block if it is the first time, From the
+						 * subsequent time, reset the index and re-use the same
+						 * block.
+						 */
+						if (bIsFirst)
+						{
+							ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+							uint32 block_pos = WaitGetFreeCopyBlock(pcshared_info);
+							cstate->raw_buf = pcshared_info->data_blocks[block_pos].data;
+							bIsFirst = false;
+						}
+
+						cstate->raw_buf_index = cstate->raw_buf_len = 0;
+					}
+				}
+
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
@@ -4813,6 +5578,11 @@ CopyReadLineText(CopyState cstate)
 	char		quotec = '\0';
 	char		escapec = '\0';
 
+	/* For parallel copy */
+	uint32			 chunk_size = 0;
+	int				 chunk_pos = 0;
+
+	cstate->eol_type = EOL_UNKNOWN;
 	if (cstate->csv_mode)
 	{
 		quotec = cstate->quote[0];
@@ -4867,6 +5637,8 @@ CopyReadLineText(CopyState cstate)
 		if (raw_buf_ptr >= copy_buf_len || need_data)
 		{
 			REFILL_LINEBUF;
+			SetRawBufForLoad(cstate, chunk_size, copy_buf_len, raw_buf_ptr,
+							 &copy_raw_buf);
 
 			/*
 			 * Try to read some more data.  This will certainly reset
@@ -5091,9 +5863,15 @@ CopyReadLineText(CopyState cstate)
 				 * discard the data and the \. sequence.
 				 */
 				if (prev_raw_ptr > cstate->raw_buf_index)
-					appendBinaryStringInfo(&cstate->line_buf,
+				{
+					if (!IsParallelCopy())
+						appendBinaryStringInfo(&cstate->line_buf,
 										   cstate->raw_buf + cstate->raw_buf_index,
 										   prev_raw_ptr - cstate->raw_buf_index);
+					else
+						chunk_size += prev_raw_ptr - cstate->raw_buf_index;
+				}
+
 				cstate->raw_buf_index = raw_buf_ptr;
 				result = true;	/* report EOF */
 				break;
@@ -5145,6 +5923,26 @@ not_end_of_copy:
 			IF_NEED_REFILL_AND_EOF_BREAK(mblen - 1);
 			raw_buf_ptr += mblen - 1;
 		}
+
+		/*
+		 * Skip the header line. Update the chunk here, this cannot be done at
+		 * the beginning, as there is a possibility that file contains empty
+		 * lines.
+		 */
+		if (IsParallelCopy() && first_char_in_line && !IsHeaderLine())
+		{
+			ParallelCopyShmInfo	*pcshared_info = cstate->pcdata->pcshared_info;
+			ParallelCopyChunkBoundary *chunkInfo;
+			uint32			 chunk_first_block = pcshared_info->cur_block_pos;
+			chunk_pos = UpdateBlockInChunkInfo(cstate,
+											   chunk_first_block,
+											   cstate->raw_buf_index, -1,
+											   CHUNK_LEADER_POPULATING);
+			chunkInfo = &pcshared_info->chunk_boundaries.ring[chunk_pos];
+			elog(DEBUG1, "[Leader] Adding - block:%d, offset:%d, chunk position:%d",
+						 chunk_first_block,	chunkInfo->start_offset, chunk_pos);
+		}
+
 		first_char_in_line = false;
 	}							/* end of outer loop */
 
@@ -5153,6 +5951,7 @@ not_end_of_copy:
 	 */
 	REFILL_LINEBUF;
 	CLEAR_EOL_LINE()
+	EndChunkParallelCopy(cstate, chunk_pos, chunk_size, raw_buf_ptr);
 
 	return result;
 }
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 0c6fe01..3faadb8 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -865,7 +865,7 @@ is_parallel_safe(PlannerInfo *root, Node *node)
 	 * planning, because those are parallel-restricted and there might be one
 	 * in this expression.  But otherwise we don't need to look.
 	 */
-	if (root->glob->maxParallelHazard == PROPARALLEL_SAFE &&
+	if (root != NULL && root->glob->maxParallelHazard == PROPARALLEL_SAFE &&
 		root->glob->paramExecTypes == NIL)
 		return true;
 	/* Else use max_parallel_hazard's search logic, but stop on RESTRICTED */
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index 88025b1..f8bdcc3 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -381,6 +381,7 @@ extern FullTransactionId GetTopFullTransactionId(void);
 extern FullTransactionId GetTopFullTransactionIdIfAny(void);
 extern FullTransactionId GetCurrentFullTransactionId(void);
 extern FullTransactionId GetCurrentFullTransactionIdIfAny(void);
+extern void AssignFullTransactionIdForWorker(FullTransactionId fullTransactionId);
 extern void MarkCurrentTransactionIdLoggedIfAny(void);
 extern bool SubTransactionIsActive(SubTransactionId subxid);
 extern CommandId GetCurrentCommandId(bool used);
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 3373894..30eb49d 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1700,6 +1700,7 @@ ParallelCompletionPtr
 ParallelContext
 ParallelCopyChunkBoundaries
 ParallelCopyChunkBoundary
+ParallelCopyChunkState
 ParallelCopyCommonKeyData
 ParallelCopyData
 ParallelCopyDataBlock
-- 
1.8.3.1

0002-Framework-for-leader-worker-in-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=0002-Framework-for-leader-worker-in-parallel-copy.patchDownload
From 8a4d7943545a16d980ae06dcc9f25b6a6b0b5a92 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 10 Jun 2020 06:53:04 +0530
Subject: [PATCH 2/4] Framework for leader/worker in parallel copy.

This patch has the framework for data structures in parallel copy, leader
initialization, worker initialization, shared memory updation, starting workers,
wait for workers and workers exiting.
---
 src/backend/access/transam/parallel.c       |   4 +
 src/backend/commands/copy.c                 | 812 +++++++++++++++++++++++++++-
 src/backend/replication/logical/tablesync.c |   2 +-
 src/include/commands/copy.h                 |   4 +
 src/tools/pgindent/typedefs.list            |   8 +
 5 files changed, 828 insertions(+), 2 deletions(-)

diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index 14a8690..09e7a19 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -25,6 +25,7 @@
 #include "catalog/pg_enum.h"
 #include "catalog/storage.h"
 #include "commands/async.h"
+#include "commands/copy.h"
 #include "executor/execParallel.h"
 #include "libpq/libpq.h"
 #include "libpq/pqformat.h"
@@ -145,6 +146,9 @@ static const struct
 	},
 	{
 		"parallel_vacuum_main", parallel_vacuum_main
+	},
+	{
+		"ParallelCopyMain", ParallelCopyMain
 	}
 };
 
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index eaf0f78..d930644 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -96,9 +96,127 @@ typedef enum CopyInsertMethod
 } CopyInsertMethod;
 
 #define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+
+#define DATA_BLOCK_SIZE RAW_BUF_SIZE
+#define RINGSIZE (10 * 1000)
+#define MAX_BLOCKS_COUNT 1000
+#define WORKER_CHUNK_COUNT 50	/* should be mod of RINGSIZE */
+
+#define	IsParallelCopy()		(cstate->is_parallel)
+#define IsLeader()				(cstate->pcdata->is_leader)
 #define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
 
 /*
+ * Copy data block information.
+ */
+typedef struct ParallelCopyDataBlock
+{
+	/* The number of unprocessed chunks in the current block. */
+	pg_atomic_uint32 unprocessed_chunk_parts;
+
+	/*
+	 * If the current chunk data is continued into another block,
+	 * following_block will have the position where the remaining data need to
+	 * be read.
+	 */
+	uint32	following_block;
+
+	/*
+	 * This flag will be set, when the leader finds out this block can be read
+	 * safely by the worker. This helps the worker to start processing the chunk
+	 * early where the chunk will be spread across many blocks and the worker
+	 * need not wait for the complete chunk to be processed.
+	 */
+	bool   curr_blk_completed;
+	char   data[DATA_BLOCK_SIZE]; /* data read from file */
+	uint8  skip_bytes;
+}ParallelCopyDataBlock;
+
+/*
+ * Individual Chunk information.
+ */
+typedef struct ParallelCopyChunkBoundary
+{
+	/* Position of the first block in data_blocks array. */
+	uint32				first_block;
+	uint32				start_offset;   /* start offset of the chunk */
+
+	/*
+	 * Size of the current chunk -1 means chunk is yet to be filled completely,
+	 * 0 means empty chunk, >0 means chunk filled with chunk size data.
+	 */
+	pg_atomic_uint32	chunk_size;
+	pg_atomic_uint32	chunk_state;	/* chunk state */
+	uint64				cur_lineno;		/* line number for error messages */
+}ParallelCopyChunkBoundary;
+
+/*
+ * Array of the chunk.
+ */
+typedef struct ParallelCopyChunkBoundaries
+{
+	/* Position for the leader to populate a chunk. */
+	uint32			leader_pos;
+
+	/* Data read from the file/stdin by the leader process. */
+	ParallelCopyChunkBoundary	ring[RINGSIZE];
+}ParallelCopyChunkBoundaries;
+
+/*
+ * Shared information among parallel copy workers. This will be allocated in the
+ * DSM segment.
+ */
+typedef struct ParallelCopyShmInfo
+{
+	bool					is_read_in_progress; /* file read status */
+
+	/*
+	 * Actual Chunks inserted by worker (some records will be filtered based on
+	 * where condition).
+	 */
+	pg_atomic_uint64		processed;
+	pg_atomic_uint64		total_worker_processed; /* total processed records by the workers */
+	uint64					populated; /* Chunks populated by leader */
+	uint32					cur_block_pos; /* current data block */
+	ParallelCopyDataBlock			data_blocks[MAX_BLOCKS_COUNT]; /* data block array */
+	FullTransactionId		full_transaction_id; /* xid for copy from statement */
+	CommandId				mycid;	/* command id */
+	ParallelCopyChunkBoundaries			chunk_boundaries; /* chunk array */
+} ParallelCopyShmInfo;
+
+/*
+ * Parallel copy line buffer information.
+ */
+typedef struct ParallelCopyLineBuf
+{
+	StringInfoData		line_buf;
+	uint64				cur_lineno;	/* line number for error messages */
+}ParallelCopyLineBuf;
+
+/*
+ * Parallel copy data information.
+ */
+typedef struct ParallelCopyData
+{
+	Oid					relid;				/* relation id of the table */
+	ParallelCopyShmInfo	*pcshared_info;		/* common info in shared memory */
+	bool				is_leader;
+
+	/* chunk position which worker is processing */
+	uint32				worker_processed_pos;
+
+	/*
+	 * Local line_buf array, workers will copy it here and release the chunks
+	 * for the leader to continue.
+	 */
+	ParallelCopyLineBuf	worker_line_buf[WORKER_CHUNK_COUNT];
+	uint32				worker_line_buf_count; /* Number of lines */
+
+	/* Current position in worker_line_buf */
+	uint32				worker_line_buf_pos;
+}ParallelCopyData;
+
+/*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
  * even though some fields are used in only some cases.
@@ -225,8 +343,66 @@ typedef struct CopyStateData
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
+	int			nworkers;
+	bool		is_parallel;
+	ParallelCopyData *pcdata;
 } CopyStateData;
 
+/*
+ * This structure helps in storing the common data from CopyStateData that are
+ * required by the workers. This information will then be allocated and stored
+ * into the DSM for the worker to retrieve and copy it to CopyStateData.
+ */
+typedef struct ParallelCopyCommonKeyData
+{
+	/* low-level state data */
+	CopyDest            copy_dest;		/* type of copy source/destination */
+	int                 file_encoding;	/* file or remote side's character encoding */
+	bool                need_transcoding;	/* file encoding diff from server? */
+	bool                encoding_embeds_ascii;	/* ASCII can be non-first byte? */
+
+	/* parameters from the COPY command */
+	bool                csv_mode;		/* Comma Separated Value format? */
+	bool                header_line;	/* CSV header line? */
+	int                 null_print_len; /* length of same */
+	bool                force_quote_all;	/* FORCE_QUOTE *? */
+	bool                convert_selectively;	/* do selective binary conversion? */
+
+	/* Working state for COPY FROM */
+	AttrNumber          num_defaults;
+	Oid                 relid;
+}ParallelCopyCommonKeyData;
+
+/*
+ * This structure will help in converting a List data type into the below
+ * structure format with the count having the number of elements in the list and
+ * the info having the List elements appended contigously. This converted
+ * structure will be allocated in shared memory and stored in DSM for the worker
+ * to retrieve and later convert it back to List data type.
+ */
+typedef struct ParallelCopyKeyListInfo
+{
+	int	count;		/* count of attributes */
+
+	/* string info in the form info followed by info1, info2... infon  */
+	char    info[1];
+} ParallelCopyKeyListInfo;
+
+/*
+ * List of internal parallel copy function pointers.
+ */
+static const struct
+{
+	char *fn_name;
+	copy_data_source_cb fn_addr;
+}			InternalParallelCopyFuncPtrs[] =
+
+{
+	{
+		"copy_read_data", copy_read_data
+	},
+};
+
 /* DestReceiver for COPY (query) TO */
 typedef struct
 {
@@ -256,6 +432,23 @@ typedef struct
 /* Trim the list of buffers back down to this number after flushing */
 #define MAX_PARTITION_BUFFERS	32
 
+/* DSM keys for parallel copy.  */
+#define PARALLEL_COPY_KEY_SHARED_INFO		    1
+#define PARALLEL_COPY_KEY_CSTATE				2
+#define PARALLEL_COPY_KEY_NULL_PRINT			3
+#define PARALLEL_COPY_KEY_NULL_PRINT_CLIENT		4
+#define PARALLEL_COPY_KEY_DELIM					5
+#define PARALLEL_COPY_KEY_QUOTE					6
+#define PARALLEL_COPY_KEY_ESCAPE				7
+#define PARALLEL_COPY_KEY_ATTNAME_LIST			8
+#define PARALLEL_COPY_KEY_FORCE_QUOTE_LIST  	9
+#define PARALLEL_COPY_KEY_NOT_NULL_LIST		   10
+#define PARALLEL_COPY_KEY_NULL_LIST			   11
+#define PARALLEL_COPY_KEY_CONVERT_LIST		   12
+#define PARALLEL_COPY_KEY_DATASOURCE_CB		   13
+#define PARALLEL_COPY_KEY_WHERE_CLAUSE_STR     14
+#define PARALLEL_COPY_KEY_RANGE_TABLE		   15
+
 /* Stores multi-insert data related to a single relation in CopyFrom. */
 typedef struct CopyMultiInsertBuffer
 {
@@ -477,10 +670,588 @@ static bool CopyGetInt32(CopyState cstate, int32 *val);
 static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 
+static pg_attribute_always_inline void EndParallelCopy(ParallelContext *pcxt);
 static void PopulateAttributes(CopyState cstate, TupleDesc	tup_desc,
 							   List *attnamelist);
+static pg_attribute_always_inline copy_data_source_cb LookupParallelCopyFnPtr(const char *funcname);
+static pg_attribute_always_inline char* LookupParallelCopyFnStr(copy_data_source_cb fn_addr);
 
 /*
+ * CopyCommonInfoForWorker - Copy shared_cstate using cstate information.
+ */
+static pg_attribute_always_inline void
+CopyCommonInfoForWorker(CopyState cstate, ParallelCopyCommonKeyData *shared_cstate)
+{
+	shared_cstate->copy_dest = cstate->copy_dest;
+	shared_cstate->file_encoding = cstate->file_encoding;
+	shared_cstate->need_transcoding = cstate->need_transcoding;
+	shared_cstate->encoding_embeds_ascii = cstate->encoding_embeds_ascii;
+	shared_cstate->csv_mode = cstate->csv_mode;
+	shared_cstate->header_line = cstate->header_line;
+	shared_cstate->null_print_len = cstate->null_print_len;
+	shared_cstate->force_quote_all = cstate->force_quote_all;
+	shared_cstate->convert_selectively = cstate->convert_selectively;
+	shared_cstate->num_defaults = cstate->num_defaults;
+	shared_cstate->relid = cstate->pcdata->relid;
+}
+
+/*
+ * RetrieveSharedString - Retrieve the string from shared memory.
+ */
+static void
+RetrieveSharedString(shm_toc *toc, int sharedkey, char **copystr)
+{
+	char *shared_str_val = (char *)shm_toc_lookup(toc, sharedkey, true);
+	if (shared_str_val)
+		*copystr = pstrdup(shared_str_val);
+}
+
+/*
+ * RetrieveSharedList - Retrieve the list from shared memory.
+ */
+static void
+RetrieveSharedList(shm_toc *toc, int sharedkey, List **copylist)
+{
+	ParallelCopyKeyListInfo *listinformation = (ParallelCopyKeyListInfo *)shm_toc_lookup(toc, sharedkey,
+														   true);
+	if (listinformation)
+	{
+		int	length  = 0;
+		int count;
+
+		for (count = 0; count < listinformation->count; count++)
+		{
+			char *attname = (char *)(listinformation->info + length);
+			length += strlen(attname) + 1;
+			*copylist = lappend(*copylist, makeString(attname));
+		}
+	}
+}
+
+/*
+ * CopyListSharedMemory - Copy the list into shared memory.
+ */
+static void
+CopyListSharedMemory(List *inputlist, Size memsize, ParallelCopyKeyListInfo *sharedlistinfo)
+{
+	ListCell   *l;
+	int			length  = 0;
+
+	MemSet(sharedlistinfo, 0, memsize);
+	foreach(l, inputlist)
+	{
+		char	   *name = strVal(lfirst(l));
+		memcpy((char *)(sharedlistinfo->info + length), name, strlen(name));
+		sharedlistinfo->count++;
+		length += strlen(name) + 1;
+	}
+}
+
+/*
+ * ComputeListSize - compute the list size.
+ */
+static int
+ComputeListSize(List *inputlist)
+{
+	int est_size = sizeof(int);
+	if (inputlist != NIL)
+	{
+		ListCell   *l;
+		foreach(l, inputlist)
+			est_size += strlen(strVal(lfirst(l))) + 1;
+	}
+
+	return est_size;
+}
+
+/*
+ * EstimateChunkKeysStr - Estimate the size required in shared memory for the
+ * input string.
+ */
+static void
+EstimateChunkKeysStr(ParallelContext *pcxt, char *inputstr)
+{
+	if (inputstr)
+	{
+		shm_toc_estimate_chunk(&pcxt->estimator, strlen(inputstr) + 1);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+}
+
+/*
+ * EstimateChunkKeysList - Estimate the size required in shared memory for the
+ * input list.
+ */
+static void
+EstimateChunkKeysList(ParallelContext *pcxt, List *inputlist,
+		Size *est_list_size)
+{
+	if (inputlist != NIL)
+	{
+		*est_list_size = ComputeListSize(inputlist);
+		shm_toc_estimate_chunk(&pcxt->estimator, *est_list_size);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+}
+
+/*
+ * InsertStringShm - Insert a string into shared memory.
+ */
+static void
+InsertStringShm(ParallelContext *pcxt, int key, char *inputstr)
+{
+	if (inputstr)
+	{
+		char *shmptr = (char *)shm_toc_allocate(pcxt->toc,
+												strlen(inputstr) + 1);
+		strcpy(shmptr, inputstr);
+		shm_toc_insert(pcxt->toc, key, shmptr);
+	}
+}
+
+/*
+ * InsertListShm - Insert a list into shared memory.
+ */
+static void
+InsertListShm(ParallelContext *pcxt, int key, List *inputlist,
+			  Size est_list_size)
+{
+	if (inputlist != NIL)
+	{
+		ParallelCopyKeyListInfo *sharedlistinfo = (ParallelCopyKeyListInfo *)shm_toc_allocate(pcxt->toc,
+																est_list_size);
+		CopyListSharedMemory(inputlist, est_list_size, sharedlistinfo);
+		shm_toc_insert(pcxt->toc, key, sharedlistinfo);
+	}
+}
+
+/*
+ * BeginParallelCopy - start parallel copy tasks.
+ *
+ * Get the number of workers required to perform the parallel copy. The data
+ * structures that are required by the parallel workers will be initialized, the
+ * size required in DSM will be calculated and the necessary keys will be loaded
+ * in the DSM. The specified number of workers will then be launched.
+ *
+ */
+static ParallelContext*
+BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
+{
+	ParallelContext *pcxt;
+	ParallelCopyShmInfo *shared_info_ptr;
+	ParallelCopyCommonKeyData *shared_cstate;
+	FullTransactionId full_transaction_id;
+	Size est_shared_info;
+	Size est_cstateshared;
+	Size est_att_list_size;
+	Size est_quote_list_size;
+	Size est_notnull_list_size;
+	Size est_null_list_size;
+	Size est_convert_list_size;
+	Size est_datasource_cb_size;
+	int  count = 0;
+	char *whereClauseStr = NULL;
+	char *rangeTableStr = NULL;
+	int  parallel_workers = 0;
+	ParallelCopyData *pcdata;
+
+	parallel_workers = Min(nworkers, max_worker_processes);
+
+	/* Can't perform copy in parallel */
+	if (parallel_workers <= 0)
+		return NULL;
+
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	cstate->pcdata = pcdata;
+
+	EnterParallelMode();
+	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
+								 parallel_workers);
+	Assert(pcxt->nworkers > 0);
+
+	/*
+	 * Estimate size for shared information for PARALLEL_COPY_KEY_SHARED_INFO
+	 */
+	est_shared_info = sizeof(ParallelCopyShmInfo);
+	shm_toc_estimate_chunk(&pcxt->estimator, est_shared_info);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_CSTATE */
+	est_cstateshared = 	MAXALIGN(sizeof(ParallelCopyCommonKeyData));
+	shm_toc_estimate_chunk(&pcxt->estimator, est_cstateshared);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	EstimateChunkKeysStr(pcxt, cstate->null_print);
+	EstimateChunkKeysStr(pcxt, cstate->null_print_client);
+	EstimateChunkKeysStr(pcxt, cstate->delim);
+	EstimateChunkKeysStr(pcxt, cstate->quote);
+	EstimateChunkKeysStr(pcxt, cstate->escape);
+
+	if (cstate->whereClause != NULL)
+	{
+		whereClauseStr = nodeToString(cstate->whereClause);
+		EstimateChunkKeysStr(pcxt, whereClauseStr);
+	}
+
+	if (cstate->range_table != NULL)
+	{
+		rangeTableStr = nodeToString(cstate->range_table);
+		EstimateChunkKeysStr(pcxt, rangeTableStr);
+	}
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_XID. */
+	shm_toc_estimate_chunk(&pcxt->estimator, sizeof(FullTransactionId));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_ATTNAME_LIST.
+	 */
+	EstimateChunkKeysList(pcxt, attnamelist, &est_att_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_FORCE_QUOTE_LIST.
+	 */
+	EstimateChunkKeysList(pcxt, cstate->force_quote, &est_quote_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_NOT_NULL_LIST.
+	 */
+	EstimateChunkKeysList(pcxt, cstate->force_notnull,
+							 &est_notnull_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_NULL_LIST.
+	 */
+	EstimateChunkKeysList(pcxt, cstate->force_null, &est_null_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_CONVERT_LIST.
+	 */
+	EstimateChunkKeysList(pcxt, cstate->convert_select,
+							 &est_convert_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_DATASOURCE_CB.
+	 */
+	if (cstate->data_source_cb)
+	{
+		char *functionname = LookupParallelCopyFnStr(cstate->data_source_cb);
+		est_datasource_cb_size = strlen(functionname) + 1;
+		shm_toc_estimate_chunk(&pcxt->estimator, est_datasource_cb_size);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+
+	InitializeParallelDSM(pcxt);
+
+	/* If no DSM segment was available, back out (do serial copy) */
+	if (pcxt->seg == NULL)
+	{
+		EndParallelCopy(pcxt);
+		return NULL;
+	}
+
+	/* Allocate shared memory for PARALLEL_COPY_KEY_SHARED_INFO */
+	shared_info_ptr = (ParallelCopyShmInfo *) shm_toc_allocate(pcxt->toc,
+													   est_shared_info);
+	MemSet(shared_info_ptr, 0, est_shared_info);
+	shared_info_ptr->is_read_in_progress = true;
+	shared_info_ptr->cur_block_pos = -1;
+	shared_info_ptr->full_transaction_id = full_transaction_id;
+	shared_info_ptr->mycid = GetCurrentCommandId(true);
+	for (count = 0; count < RINGSIZE; count++)
+	{
+		ParallelCopyChunkBoundary *chunkInfo = &shared_info_ptr->chunk_boundaries.ring[count];
+		pg_atomic_init_u32(&(chunkInfo->chunk_size), -1);
+	}
+
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_SHARED_INFO, shared_info_ptr);
+	pcdata->pcshared_info = shared_info_ptr;
+	pcdata->relid = relid;
+
+	/* Store shared build state, for which we reserved space. */
+	shared_cstate = (ParallelCopyCommonKeyData *)shm_toc_allocate(pcxt->toc,
+															est_cstateshared);
+
+	/* copy cstate variables. */
+	CopyCommonInfoForWorker(cstate, shared_cstate);
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_CSTATE, shared_cstate);
+
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_NULL_PRINT, cstate->null_print);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_NULL_PRINT_CLIENT,
+					  cstate->null_print_client);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_DELIM, cstate->delim);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_QUOTE, cstate->quote);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_ESCAPE, cstate->escape);
+
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_ATTNAME_LIST,
+					attnamelist, est_att_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_FORCE_QUOTE_LIST,
+					cstate->force_quote, est_quote_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_NOT_NULL_LIST,
+					cstate->force_notnull, est_notnull_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_NULL_LIST, cstate->force_null,
+					est_null_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_CONVERT_LIST,
+					cstate->convert_select, est_convert_list_size);
+
+	if (cstate->data_source_cb)
+	{
+		char *functionname = LookupParallelCopyFnStr(cstate->data_source_cb);
+		char *data_source_cb = (char *) shm_toc_allocate(pcxt->toc,
+														 est_datasource_cb_size);
+		strcpy(data_source_cb, functionname);
+		shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_DATASOURCE_CB,
+					   data_source_cb);
+	}
+
+	if (cstate->whereClause)
+		InsertStringShm(pcxt, PARALLEL_COPY_KEY_WHERE_CLAUSE_STR,
+						whereClauseStr);
+
+	if(cstate->range_table)
+		InsertStringShm(pcxt, PARALLEL_COPY_KEY_RANGE_TABLE, rangeTableStr);
+
+	LaunchParallelWorkers(pcxt);
+	if (pcxt->nworkers_launched == 0)
+	{
+		EndParallelCopy(pcxt);
+		return NULL;
+	}
+
+	/*
+	 * Caller needs to wait for all launched workers when we return.  Make sure
+	 * that the failure-to-start case will not hang forever.
+	 */
+	WaitForParallelWorkersToAttach(pcxt);
+
+	pcdata->is_leader = true;
+	cstate->is_parallel = true;
+	return pcxt;
+}
+
+/*
+ * EndParallelCopy - end the parallel copy tasks.
+ */
+static pg_attribute_always_inline void
+EndParallelCopy(ParallelContext *pcxt)
+{
+	Assert(!IsParallelWorker());
+
+	DestroyParallelContext(pcxt);
+	ExitParallelMode();
+}
+
+/*
+ * ParallelWorkerInitialization - Initialize parallel worker.
+ */
+static void
+ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
+		CopyState cstate, List *attnamelist)
+{
+	uint32		count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	cstate->copy_dest = shared_cstate->copy_dest;
+	cstate->file_encoding = shared_cstate->file_encoding;
+	cstate->need_transcoding = shared_cstate->need_transcoding;
+	cstate->encoding_embeds_ascii = shared_cstate->encoding_embeds_ascii;
+	cstate->csv_mode = shared_cstate->csv_mode;
+	cstate->header_line = shared_cstate->header_line;
+	cstate->null_print_len = shared_cstate->null_print_len;
+	cstate->force_quote_all = shared_cstate->force_quote_all;
+	cstate->convert_selectively = shared_cstate->convert_selectively;
+	cstate->num_defaults = shared_cstate->num_defaults;
+	pcdata->relid = shared_cstate->relid;
+
+	PopulateAttributes(cstate, tup_desc, attnamelist);
+
+	/* Initialize state variables. */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/* Set up variables to avoid per-attribute overhead. */
+	initStringInfo(&cstate->attribute_buf);
+
+	initStringInfo(&cstate->line_buf);
+	for (count = 0; count < WORKER_CHUNK_COUNT;count++)
+		initStringInfo(&pcdata->worker_line_buf[count].line_buf);
+
+	cstate->line_buf_converted = false;
+	cstate->raw_buf = NULL;
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+}
+/*
+ * ParallelCopyMain - parallel copy worker's code.
+ *
+ * Where clause handling, convert tuple to columns, add default null values for
+ * the missing columns that are not present in that record. Find the partition
+ * if it is partitioned table, invoke before row insert Triggers, handle
+ * constraints and insert the tuples.
+ */
+void
+ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
+{
+	CopyState cstate;
+	ParallelCopyData *pcdata;
+	ParallelCopyShmInfo *pcshared_info;
+	ParallelCopyCommonKeyData *shared_cstate;
+	Relation	rel = NULL;
+	MemoryContext oldcontext;
+	List *attlist = NIL;
+	char *data_source_cb;
+	char *whereClauseStr = NULL;
+	char *rangeTableStr = NULL;
+
+	/* Allocate workspace and zero all fields. */
+	cstate = (CopyStateData *) palloc0(sizeof(CopyStateData));
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	cstate->pcdata = pcdata;
+	pcdata->is_leader = false;
+	pcdata->worker_processed_pos = -1;
+	cstate->is_parallel = true;
+
+	/*
+	 * We allocate everything used by a cstate in a new memory context. This
+	 * avoids memory leaks during repeated use of COPY in a query.
+	 */
+	cstate->copycontext = AllocSetContextCreate(CurrentMemoryContext,
+												"COPY",
+												ALLOCSET_DEFAULT_SIZES);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	pcshared_info = (ParallelCopyShmInfo *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_SHARED_INFO,
+														false);
+
+	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
+
+	pcdata->pcshared_info = pcshared_info;
+
+	shared_cstate = (ParallelCopyCommonKeyData *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE,
+														   false);
+
+	cstate->null_print = (char *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_NULL_PRINT,
+												true);
+	cstate->null_print_client = (char *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_NULL_PRINT_CLIENT,
+													   true);
+
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_DELIM, &cstate->delim);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_QUOTE, &cstate->quote);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_ESCAPE, &cstate->escape);
+
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_ATTNAME_LIST, &attlist);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_FORCE_QUOTE_LIST, &cstate->force_quote);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_NOT_NULL_LIST, &cstate->force_notnull);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_NULL_LIST, &cstate->force_null);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_CONVERT_LIST, &cstate->convert_select);
+	data_source_cb = (char *)shm_toc_lookup(toc,
+											PARALLEL_COPY_KEY_DATASOURCE_CB,
+											true);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_WHERE_CLAUSE_STR, &whereClauseStr);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_RANGE_TABLE, &rangeTableStr);
+
+	if (data_source_cb)
+		cstate->data_source_cb = LookupParallelCopyFnPtr(data_source_cb);
+
+	if (whereClauseStr)
+	{
+		Node *whereClauseCnvrtdFrmStr = (Node *) stringToNode(whereClauseStr);
+		cstate->whereClause = whereClauseCnvrtdFrmStr;
+	}
+
+	if (rangeTableStr)
+	{
+		List *rangeTableCnvrtdFrmStr = (List *) stringToNode(rangeTableStr);
+		cstate->range_table = rangeTableCnvrtdFrmStr;
+	}
+
+	/* Open and lock the relation, using the appropriate lock type. */
+	rel = table_open(shared_cstate->relid, RowExclusiveLock);
+	cstate->rel = rel;
+	ParallelWorkerInitialization(shared_cstate, cstate, attlist);
+
+	CopyFrom(cstate);
+
+	if (rel != NULL)
+		table_close(rel, RowExclusiveLock);
+
+	MemoryContextSwitchTo(oldcontext);
+	return;
+}
+/*
+ * ParallelCopyLeader - parallel copy leader's functionality.
+ *
+ * Leader will populate the shared queue and share it across the workers. Leader
+ * will read the table data from the file and copy the contents to block. Leader
+ * will then read the input contents and identify the data based on line beaks.
+ * This information is called chunk. The chunk will be populate in
+ * ParallelCopyChunkBoundary. Workers will then pick up this information and insert
+ * in to table. Leader will do this till it completes processing the file.
+ * Leader executes the before statement if before statement trigger is present.
+ * Leader read the data from input file. Leader then loads data to data blocks
+ * as and when required block by block. Leader traverses through the data block
+ * to identify one chunk. It gets a free chunk to copy the information, if there
+ * is no free chunk it will wait till there is one free chunk.
+ * Server copies  the identified chunks information into chunks. This process is
+ * repeated till the complete file is processed.
+ * Leader will wait till all the chunks populated are processed by the workers
+ * and exits.
+ */
+static void
+ParallelCopyLeader(CopyState cstate)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
+
+	pcshared_info->is_read_in_progress = false;
+	cstate->cur_lineno = 0;
+}
+/*
+ * LookupParallelCopyFnPtr - Look up parallel copy function pointer.
+ */
+static pg_attribute_always_inline copy_data_source_cb
+LookupParallelCopyFnPtr(const char *funcname)
+{
+	int			i;
+
+	for (i = 0; i < lengthof(InternalParallelCopyFuncPtrs); i++)
+	{
+		if (strcmp(InternalParallelCopyFuncPtrs[i].fn_name, funcname) == 0)
+			return InternalParallelCopyFuncPtrs[i].fn_addr;
+	}
+
+	/* We can only reach this by programming error. */
+	elog(ERROR, "internal function \"%s\" not found", funcname);
+}
+
+/*
+ * LookupParallelCopyFnStr - Lookup function string from a function pointer.
+ */
+static pg_attribute_always_inline char*
+LookupParallelCopyFnStr(copy_data_source_cb fn_addr)
+{
+	int			i;
+
+	for (i = 0; i < lengthof(InternalParallelCopyFuncPtrs); i++)
+	{
+		if (InternalParallelCopyFuncPtrs[i].fn_addr == fn_addr)
+			return InternalParallelCopyFuncPtrs[i].fn_name;
+	}
+
+	/* We can only reach this by programming error. */
+	elog(ERROR, "internal function pointer not found");
+}
+/*
  * Send copy start/stop messages for frontend copies.  These have changed
  * in past protocol redesigns.
  */
@@ -1146,6 +1917,7 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 
 	if (is_from)
 	{
+		ParallelContext *pcxt = NULL;
 		Assert(rel);
 
 		/* check read-only transaction and parallel mode */
@@ -1155,7 +1927,24 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 		cstate = BeginCopyFrom(pstate, rel, stmt->filename, stmt->is_program,
 							   NULL, stmt->attlist, stmt->options);
 		cstate->whereClause = whereClause;
-		*processed = CopyFrom(cstate);	/* copy from file to database */
+		cstate->is_parallel = false;
+
+		if (cstate->nworkers > 0)
+			pcxt = BeginParallelCopy(cstate->nworkers, cstate, stmt->attlist,
+									 relid);
+
+		if (pcxt)
+		{
+			ParallelCopyLeader(cstate);
+
+			/* Wait for all copy workers to finish */
+			WaitForParallelWorkersToFinish(pcxt);
+			*processed = pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
+			EndParallelCopy(pcxt);
+		}
+		else
+			*processed = CopyFrom(cstate); /* copy from file to database */
+
 		EndCopyFrom(cstate);
 	}
 	else
@@ -1204,6 +1993,7 @@ ProcessCopyOptions(ParseState *pstate,
 	cstate->is_copy_from = is_from;
 
 	cstate->file_encoding = -1;
+	cstate->nworkers = -1;
 
 	/* Extract options from the statement node tree */
 	foreach(option, options)
@@ -1372,6 +2162,26 @@ ProcessCopyOptions(ParseState *pstate,
 								defel->defname),
 						 parser_errposition(pstate, defel->location)));
 		}
+		else if (strcmp(defel->defname, "parallel") == 0)
+		{
+			if (!cstate->is_copy_from)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("parallel option supported only for copy from"),
+						 parser_errposition(pstate, defel->location)));
+			if (cstate->nworkers >= 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options"),
+						 parser_errposition(pstate, defel->location)));
+			cstate->nworkers = atoi(defGetString(defel));
+			if (cstate->nworkers < 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("argument to option \"%s\" must be a non-negative integer",
+								defel->defname),
+						 parser_errposition(pstate, defel->location)));
+		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_SYNTAX_ERROR),
diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c
index c27d970..b3787c1 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -557,7 +557,7 @@ make_copy_attnamelist(LogicalRepRelMapEntry *rel)
  * Data source callback for the COPY FROM, which reads from the remote
  * connection and passes the data back to our local COPY.
  */
-static int
+int
 copy_read_data(void *outbuf, int minread, int maxread)
 {
 	int			bytesread = 0;
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index c639833..5dc95ac 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -14,6 +14,7 @@
 #ifndef COPY_H
 #define COPY_H
 
+#include "access/parallel.h"
 #include "nodes/execnodes.h"
 #include "nodes/parsenodes.h"
 #include "parser/parse_node.h"
@@ -41,4 +42,7 @@ extern uint64 CopyFrom(CopyState cstate);
 
 extern DestReceiver *CreateCopyDestReceiver(void);
 
+extern void ParallelCopyMain(dsm_segment *seg, shm_toc *toc);
+
+extern int copy_read_data(void *outbuf, int minread, int maxread);
 #endif							/* COPY_H */
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index c65a552..3373894 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1698,6 +1698,14 @@ ParallelBitmapHeapState
 ParallelBlockTableScanDesc
 ParallelCompletionPtr
 ParallelContext
+ParallelCopyChunkBoundaries
+ParallelCopyChunkBoundary
+ParallelCopyCommonKeyData
+ParallelCopyData
+ParallelCopyDataBlock
+ParallelCopyKeyListInfo
+ParallelCopyLineBuf
+ParallelCopyShmInfo
 ParallelExecutorInfo
 ParallelHashGrowth
 ParallelHashJoinBatch
-- 
1.8.3.1

0004-Documentation-for-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=0004-Documentation-for-parallel-copy.patchDownload
From a45985a66ead7f31e6f885b8406da14f261d7021 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 10 Jun 2020 07:21:10 +0530
Subject: [PATCH 4/4] Documentation for parallel copy.

This patch has the documentation changes for parallel copy.
---
 doc/src/sgml/ref/copy.sgml | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/doc/src/sgml/ref/copy.sgml b/doc/src/sgml/ref/copy.sgml
index 18189ab..95d349d 100644
--- a/doc/src/sgml/ref/copy.sgml
+++ b/doc/src/sgml/ref/copy.sgml
@@ -37,6 +37,7 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
     DELIMITER '<replaceable class="parameter">delimiter_character</replaceable>'
     NULL '<replaceable class="parameter">null_string</replaceable>'
     HEADER [ <replaceable class="parameter">boolean</replaceable> ]
+    PARALLEL <replaceable class="parameter">integer</replaceable>
     QUOTE '<replaceable class="parameter">quote_character</replaceable>'
     ESCAPE '<replaceable class="parameter">escape_character</replaceable>'
     FORCE_QUOTE { ( <replaceable class="parameter">column_name</replaceable> [, ...] ) | * }
@@ -275,6 +276,21 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
    </varlistentry>
 
    <varlistentry>
+    <term><literal>PARALLEL</literal></term>
+    <listitem>
+     <para>
+      Perform <command>COPY FROM</command> in parallel using <replaceable
+      class="parameter"> integer</replaceable> background workers.  Please
+      note that it is not guaranteed that the number of parallel workers
+      specified in <replaceable class="parameter">integer</replaceable> will
+      be used during execution.  It is possible for a copy to run with fewer
+      workers than specified, or even with no workers at all.  This option is
+      allowed only in <command>COPY FROM</command>.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><literal>QUOTE</literal></term>
     <listitem>
      <para>
-- 
1.8.3.1

#92Ashutosh Sharma
ashu.coek88@gmail.com
In reply to: vignesh C (#91)
Re: Parallel copy

Hi All,

I've spent little bit of time going through the project discussion that has
happened in this email thread and to start with I have few questions which
I would like to put here:

Q1) Are we also planning to read the input data in parallel or is it only
about performing the multi-insert operation in parallel? AFAIU, the data
reading part will be done by the leader process alone so no parallelism is
involved there.

Q2) How are we going to deal with the partitioned tables? I mean will there
be some worker process dedicated for each partition or how is it? Further,
the challenge that I see incase of partitioned tables is that we would have
a single input file containing data to be inserted into multiple tables
(aka partitions) unlike the normal case where all the tuples in the input
file would belong to the same table.

Q3) Incase of toast tables, there is a possibility of having a single tuple
in the input file which could be of a very big size (probably in GB)
eventually resulting in a bigger file size. So, in this case, how are we
going to decide the number of worker processes to be launched. I mean,
although the file size is big, but the number of tuples to be processed is
just one or few of them, so, can we decide the number of the worker
processes to be launched based on the file size?

Q4) Who is going to process constraints (preferably the deferred
constraint) that is supposed to be executed at the COMMIT time? I mean is
it the leader process or the worker process or in such cases we won't be
choosing the parallelism at all?

Q5) Do we have any risk of table bloating when the data is loaded in
parallel. I am just asking this because incase of parallelism there would
be multiple processes performing bulk insert into a table. There is a
chance that the table file might get extended even if there is some space
into the file being written into, but that space is locked by some other
worker process and hence that might result in a creation of a new block for
that table. Sorry, if I am missing something here.

Please note that I haven't gone through all the emails in this thread so
there is a possibility that I might have repeated the question that has
already been raised and answered here. If that is the case, I am sorry for
that, but it would be very helpful if someone could point out that thread
so that I can go through it. Thank you.

--
With Regards,
Ashutosh Sharma
EnterpriseDB:http://www.enterprisedb.com

On Fri, Jun 12, 2020 at 11:01 AM vignesh C <vignesh21@gmail.com> wrote:

Show quoted text

On Thu, Jun 4, 2020 at 12:44 AM Andres Freund <andres@anarazel.de> wrote

Hm. you don't explicitly mention that in your design, but given how
small the benefits going from 0-1 workers is, I assume the leader
doesn't do any "chunk processing" on its own?

Yes you are right, the leader does not do any processing, Leader's
work is mainly to populate the shared memory with the offset
information for each record.

Design of the Parallel Copy: The backend, to which the "COPY FROM"

query is

submitted acts as leader with the responsibility of reading data from

the

file/stdin, launching at most n number of workers as specified with
PARALLEL 'n' option in the "COPY FROM" query. The leader populates the
common data required for the workers execution in the DSM and shares it
with the workers. The leader then executes before statement triggers if
there exists any. Leader populates DSM chunks which includes the start
offset and chunk size, while populating the chunks it reads as many

blocks

as required into the DSM data blocks from the file. Each block is of

64K

size. The leader parses the data to identify a chunk, the existing

logic

from CopyReadLineText which identifies the chunks with some changes was
used for this. Leader checks if a free chunk is available to copy the
information, if there is no free chunk it waits till the required

chunk is

freed up by the worker and then copies the identified chunks

information

(offset & chunk size) into the DSM chunks. This process is repeated

till

the complete file is processed. Simultaneously, the workers cache the
chunks(50) locally into the local memory and release the chunks to the
leader for further populating. Each worker processes the chunk that it
cached and inserts it into the table. The leader waits till all the

chunks

populated are processed by the workers and exits.

Why do we need the local copy of 50 chunks? Copying memory around is far
from free. I don't see why it'd be better to add per-process caching,
rather than making the DSM bigger? I can see some benefit in marking
multiple chunks as being processed with one lock acquisition, but I
don't think adding a memory copy is a good idea.

We had run performance with csv data file, 5.1GB, 10million tuples, 2
indexes on integer columns, results for the same are given below. We
noticed in some cases the performance is better if we copy the 50
records locally and release the shared memory. We will get better
benefits as the workers increase. Thoughts?

------------------------------------------------------------------------------------------------
Workers | Exec time (With local copying | Exec time (Without copying,
| 50 records & release the | processing record by
record)
| shared memory) |

------------------------------------------------------------------------------------------------
0 | 1162.772(1X) | 1152.684(1X)
2 | 635.249(1.83X) | 647.894(1.78X)
4 | 336.835(3.45X) | 335.534(3.43X)
8 | 188.577(6.17 X) | 189.461(6.08X)
16 | 126.819(9.17X) | 142.730(8.07X)
20 | 117.845(9.87X) | 146.533(7.87X)
30 | 127.554(9.11X) | 160.307(7.19X)

This patch *desperately* needs to be split up. It imo is close to
unreviewable, due to a large amount of changes that just move code
around without other functional changes being mixed in with the actual
new stuff.

I have split the patch, the new split patches are attached.

/*
+ * State of the chunk.
+ */
+typedef enum ChunkState
+{
+     CHUNK_INIT,                                     /* initial state

of chunk */

+     CHUNK_LEADER_POPULATING,        /* leader processing chunk */
+     CHUNK_LEADER_POPULATED,         /* leader completed populating

chunk */

+     CHUNK_WORKER_PROCESSING,        /* worker processing chunk */
+     CHUNK_WORKER_PROCESSED          /* worker completed processing

chunk */

+}ChunkState;
+
+#define RAW_BUF_SIZE 65536           /* we palloc RAW_BUF_SIZE+1

bytes */

+
+#define DATA_BLOCK_SIZE RAW_BUF_SIZE
+#define RINGSIZE (10 * 1000)
+#define MAX_BLOCKS_COUNT 1000
+#define WORKER_CHUNK_COUNT 50        /* should be mod of RINGSIZE */
+
+#define      IsParallelCopy()                (cstate->is_parallel)
+#define IsLeader()

(cstate->pcdata->is_leader)

+#define IsHeaderLine() (cstate->header_line &&

cstate->cur_lineno == 1)

+
+/*
+ * Copy data block information.
+ */
+typedef struct CopyDataBlock
+{
+     /* The number of unprocessed chunks in the current block. */
+     pg_atomic_uint32 unprocessed_chunk_parts;
+
+     /*
+      * If the current chunk data is continued into another block,
+      * following_block will have the position where the remaining

data need to

+      * be read.
+      */
+     uint32  following_block;
+
+     /*
+      * This flag will be set, when the leader finds out this block

can be read

+ * safely by the worker. This helps the worker to start

processing the chunk

+ * early where the chunk will be spread across many blocks and

the worker

+      * need not wait for the complete chunk to be processed.
+      */
+     bool   curr_blk_completed;
+     char   data[DATA_BLOCK_SIZE + 1]; /* data read from file */
+}CopyDataBlock;

What's the + 1 here about?

Fixed this, removed +1. That is not needed.

+/*
+ * Parallel copy line buffer information.
+ */
+typedef struct ParallelCopyLineBuf
+{
+     StringInfoData          line_buf;
+     uint64                          cur_lineno;     /* line number

for error messages */

+}ParallelCopyLineBuf;

Why do we need separate infrastructure for this? We shouldn't duplicate
infrastructure unnecessarily.

This was required for copying the multiple records locally and
releasing the shared memory. I have not changed this, will decide on
this based on the decision taken for one of the previous comments.

+/*
+ * Common information that need to be copied to shared memory.
+ */
+typedef struct CopyWorkerCommonData
+{

Why is parallel specific stuff here suddenly not named ParallelCopy*
anymore? If you introduce a naming like that it imo should be used
consistently.

Fixed, changed to maintain ParallelCopy in all structs.

+     /* low-level state data */
+     CopyDest            copy_dest;          /* type of copy

source/destination */

+ int file_encoding; /* file or remote side's

character encoding */

+ bool need_transcoding; /* file encoding diff

from server? */

+ bool encoding_embeds_ascii; /* ASCII can be

non-first byte? */

+
+     /* parameters from the COPY command */
+     bool                csv_mode;           /* Comma Separated Value

format? */

+     bool                header_line;        /* CSV header line? */
+     int                 null_print_len; /* length of same */
+     bool                force_quote_all;    /* FORCE_QUOTE *? */
+     bool                convert_selectively;        /* do selective

binary conversion? */

+
+     /* Working state for COPY FROM */
+     AttrNumber          num_defaults;
+     Oid                 relid;
+}CopyWorkerCommonData;

But I actually think we shouldn't have this information in two different
structs. This should exist once, independent of using parallel /
non-parallel copy.

This structure helps in storing the common data from CopyStateData
that are required by the workers. This information will then be
allocated and stored into the DSM for the worker to retrieve and copy
it to CopyStateData.

+/* List information */
+typedef struct ListInfo
+{
+     int     count;          /* count of attributes */
+
+     /* string info in the form info followed by info1, info2...

infon */

+ char info[1];
+} ListInfo;

Based on these comments I have no idea what this could be for.

Have added better comments for this. The following is added: This
structure will help in converting a List data type into the below
structure format with the count having the number of elements in the
list and the info having the List elements appended contiguously. This
converted structure will be allocated in shared memory and stored in
DSM for the worker to retrieve and later convert it back to List data
type.

/*
- * This keeps the character read at the top of the loop in the buffer
- * even if there is more than one read-ahead.
+ * This keeps the character read at the top of the loop in the buffer
+ * even if there is more than one read-ahead.
+ */
+#define IF_NEED_REFILL_AND_NOT_EOF_CONTINUE(extralen) \
+if (1) \
+{ \
+     if (copy_buff_state.raw_buf_ptr + (extralen) >=

copy_buff_state.copy_buf_len && !hit_eof) \

+     { \
+             if (IsParallelCopy()) \
+             { \
+                     copy_buff_state.chunk_size = prev_chunk_size; /*

update previous chunk size */ \

+                     if (copy_buff_state.block_switched) \
+                     { \
+

pg_atomic_sub_fetch_u32(&copy_buff_state.data_blk_ptr->unprocessed_chunk_parts,
1); \

+ copy_buff_state.copy_buf_len =

prev_copy_buf_len; \

+                     } \
+             } \
+             copy_buff_state.raw_buf_ptr = prev_raw_ptr; /* undo

fetch */ \

+             need_data = true; \
+             continue; \
+     } \
+} else ((void) 0)

I think it's an absolutely clear no-go to add new branches to
these. They're *really* hot already, and this is going to sprinkle a
significant amount of new instructions over a lot of places.

Fixed, removed this.

+/*
+ * SET_RAWBUF_FOR_LOAD - Set raw_buf to the shared memory where the

file data must

+ * be read.
+ */
+#define SET_RAWBUF_FOR_LOAD() \
+{ \
+     ShmCopyInfo     *pcshared_info = cstate->pcdata->pcshared_info; \
+     uint32 cur_block_pos; \
+     /* \
+      * Mark the previous block as completed, worker can start

copying this data. \

+      */ \
+     if (copy_buff_state.data_blk_ptr !=

copy_buff_state.curr_data_blk_ptr && \

+ copy_buff_state.data_blk_ptr->curr_blk_completed ==

false) \

+ copy_buff_state.data_blk_ptr->curr_blk_completed = true;

\

+ \
+ copy_buff_state.data_blk_ptr =

copy_buff_state.curr_data_blk_ptr; \

+     cur_block_pos = WaitGetFreeCopyBlock(pcshared_info); \
+     copy_buff_state.curr_data_blk_ptr =

&pcshared_info->data_blocks[cur_block_pos]; \

+     \
+     if (!copy_buff_state.data_blk_ptr) \
+     { \
+             copy_buff_state.data_blk_ptr =

copy_buff_state.curr_data_blk_ptr; \

+             chunk_first_block = cur_block_pos; \
+     } \
+     else if (need_data == false) \
+             copy_buff_state.data_blk_ptr->following_block =

cur_block_pos; \

+     \
+     cstate->raw_buf = copy_buff_state.curr_data_blk_ptr->data; \
+     copy_buff_state.copy_raw_buf = cstate->raw_buf; \
+}
+
+/*
+ * END_CHUNK_PARALLEL_COPY - Update the chunk information in shared

memory.

+ */
+#define END_CHUNK_PARALLEL_COPY() \
+{ \
+     if (!IsHeaderLine()) \
+     { \
+             ShmCopyInfo *pcshared_info =

cstate->pcdata->pcshared_info; \

+ ChunkBoundaries *chunkBoundaryPtr =

&pcshared_info->chunk_boundaries; \

+             if (copy_buff_state.chunk_size) \
+             { \
+                     ChunkBoundary *chunkInfo =

&chunkBoundaryPtr->ring[chunk_pos]; \

+                     /* \
+                      * If raw_buf_ptr is zero,

unprocessed_chunk_parts would have been \

+ * incremented in SEEK_COPY_BUFF_POS. This will

happen if the whole \

+ * chunk finishes at the end of the current

block. If the \

+ * new_line_size > raw_buf_ptr, then the new

block has only new line \

+ * char content. The unprocessed count should

not be increased in \

+                      * this case. \
+                      */ \
+                     if (copy_buff_state.raw_buf_ptr != 0 && \
+                             copy_buff_state.raw_buf_ptr >

new_line_size) \

+

pg_atomic_add_fetch_u32(&copy_buff_state.curr_data_blk_ptr->unprocessed_chunk_parts,
1); \

+                     \
+                     /* Update chunk size. */ \
+                     pg_atomic_write_u32(&chunkInfo->chunk_size,

copy_buff_state.chunk_size); \

+ pg_atomic_write_u32(&chunkInfo->chunk_state,

CHUNK_LEADER_POPULATED); \

+ elog(DEBUG1, "[Leader] After adding - chunk

position:%d, chunk_size:%d", \

+ chunk_pos,

copy_buff_state.chunk_size); \

+                     pcshared_info->populated++; \
+             } \
+             else if (new_line_size) \
+             { \
+                     /* \
+                      * This means only new line char, empty record

should be \

+                      * inserted. \
+                      */ \
+                     ChunkBoundary *chunkInfo; \
+                     chunk_pos = UpdateBlockInChunkInfo(cstate, -1,

-1, 0, \

+

CHUNK_LEADER_POPULATED); \

+                     chunkInfo = &chunkBoundaryPtr->ring[chunk_pos]; \
+                     elog(DEBUG1, "[Leader] Added empty chunk with

offset:%d, chunk position:%d, chunk size:%d", \

+

chunkInfo->start_offset, chunk_pos, \

+

pg_atomic_read_u32(&chunkInfo->chunk_size)); \

+                     pcshared_info->populated++; \
+             } \
+     }\
+     \
+     /*\
+      * All of the read data is processed, reset index & len. In the\
+      * subsequent read, we will get a new block and copy data in to

the\

+      * new block.\
+      */\
+     if (copy_buff_state.raw_buf_ptr == copy_buff_state.copy_buf_len)\
+     {\
+             cstate->raw_buf_index = 0;\
+             cstate->raw_buf_len = 0;\
+     }\
+     else\
+             cstate->raw_buf_len = copy_buff_state.copy_buf_len;\
+}

Why are these macros? They are way way way above a length where that
makes any sort of sense.

Converted these macros to functions.

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

#93Amit Kapila
amit.kapila16@gmail.com
In reply to: Ashutosh Sharma (#92)
Re: Parallel copy

On Fri, Jun 12, 2020 at 4:57 PM Ashutosh Sharma <ashu.coek88@gmail.com> wrote:

Hi All,

I've spent little bit of time going through the project discussion that has happened in this email thread and to start with I have few questions which I would like to put here:

Q1) Are we also planning to read the input data in parallel or is it only about performing the multi-insert operation in parallel? AFAIU, the data reading part will be done by the leader process alone so no parallelism is involved there.

Yes, your understanding is correct.

Q2) How are we going to deal with the partitioned tables?

I haven't studied the patch but my understanding is that we will
support parallel copy for partitioned tables with a few restrictions
as explained in my earlier email [1]/messages/by-id/CAA4eK1+ANNEaMJCCXm4naweP5PLY6LhJMvGo_V7-Pnfbh6GsOA@mail.gmail.com. See, Case-2 (b) in the email.

I mean will there be some worker process dedicated for each partition or how is it?

No, it the split is just based on the input, otherwise each worker
should insert as we would have done without any workers.

Q3) Incase of toast tables, there is a possibility of having a single tuple in the input file which could be of a very big size (probably in GB) eventually resulting in a bigger file size. So, in this case, how are we going to decide the number of worker processes to be launched. I mean, although the file size is big, but the number of tuples to be processed is just one or few of them, so, can we decide the number of the worker processes to be launched based on the file size?

Yeah, such situations would be tricky, so we should have an option for
user to specify the number of workers.

Q4) Who is going to process constraints (preferably the deferred constraint) that is supposed to be executed at the COMMIT time? I mean is it the leader process or the worker process or in such cases we won't be choosing the parallelism at all?

In the first version, we won't do parallelism for this. Again, see
one of my earlier email [1]/messages/by-id/CAA4eK1+ANNEaMJCCXm4naweP5PLY6LhJMvGo_V7-Pnfbh6GsOA@mail.gmail.com where I have explained this and other
cases where we won't be supporting parallel copy.

Q5) Do we have any risk of table bloating when the data is loaded in parallel. I am just asking this because incase of parallelism there would be multiple processes performing bulk insert into a table. There is a chance that the table file might get extended even if there is some space into the file being written into, but that space is locked by some other worker process and hence that might result in a creation of a new block for that table. Sorry, if I am missing something here.

Hmm, each worker will operate at page level, after first insertion,
the same worker will try to insert in the same page in which it has
inserted last, so there shouldn't be such a problem.

Please note that I haven't gone through all the emails in this thread so there is a possibility that I might have repeated the question that has already been raised and answered here. If that is the case, I am sorry for that, but it would be very helpful if someone could point out that thread so that I can go through it. Thank you.

No problem, I understand sometimes it is difficult to go through each
and every email especially when the discussion is long. Anyway,
thanks for showing the interest in the patch.

[1]: /messages/by-id/CAA4eK1+ANNEaMJCCXm4naweP5PLY6LhJMvGo_V7-Pnfbh6GsOA@mail.gmail.com

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#94Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Amit Kapila (#93)
2 attachment(s)
Re: Parallel copy

Hi,

Attached is the patch supporting parallel copy for binary format files.

The performance improvement achieved with different workers is as shown
below. Dataset used has 10million tuples and is of 5.3GB size.

parallel workers test case 1(exec time in sec): copy from binary file, 2
indexes on integer columns and 1 index on text column test case 2(exec time
in sec): copy from binary file, 1 gist index on text column test case
3(exec time in sec): copy from binary file, 3 indexes on integer columns
0 1106.899(1X) 772.758(1X) 171.338(1X)
1 1094.165(1.01X) 757.365(1.02X) 163.018(1.05X)
2 618.397(1.79X) 428.304(1.8X) 117.508(1.46X)
4 320.511(3.45X) 231.938(3.33X) 80.297(2.13X)
8 172.462(6.42X) 150.212(5.14X) *71.518(2.39X)*
16 110.460(10.02X) *124.929(6.18X)* 91.308(1.88X)
20 *98.470(11.24X)* 137.313(5.63X) 95.289(1.79X)
30 109.229(10.13X) 173.54(4.45X) 95.799(1.78X)

Design followed for developing this patch:

Leader reads data from the file into the DSM data blocks each of 64K size.
It also identifies each tuple data block id, start offset, end offset,
tuple size and updates this information in the ring data structure. Workers
parallely read the tuple information from the ring data structure, the
actual tuple data from the data blocks and parallely insert the tuples into
the table.

Please note that this patch can be applied on the series of patches that
were posted previously[1]/messages/by-id/CALDaNm3uyHpD9sKoFtB0EnMO8DLuD6H9pReFm=tm=9ccEWuUVQ@mail.gmail.com for parallel copy for csv/text files.
The correct order to apply all the patches is -
0001-Copy-code-readjustment-to-support-parallel-copy.patch
</messages/by-id/attachment/111463/0001-Copy-code-readjustment-to-support-parallel-copy.patch&gt;
0002-Framework-for-leader-worker-in-parallel-copy.patch
</messages/by-id/attachment/111465/0002-Framework-for-leader-worker-in-parallel-copy.patch&gt;
0003-Allow-copy-from-command-to-process-data-from-file-ST.patch
</messages/by-id/attachment/111464/0003-Allow-copy-from-command-to-process-data-from-file-ST.patch&gt;
0004-Documentation-for-parallel-copy.patch
</messages/by-id/attachment/111466/0004-Documentation-for-parallel-copy.patch&gt;
and
0005-Parallel-Copy-For-Binary-Format-Files.patch

The above tests were run with the configuration attached config.txt, which
is the same used for performance tests of csv/text files posted earlier in
this mail chain.

Request the community to take this patch up for review along with the
parallel copy for csv/text file patches and provide feedback.

[1]: /messages/by-id/CALDaNm3uyHpD9sKoFtB0EnMO8DLuD6H9pReFm=tm=9ccEWuUVQ@mail.gmail.com
/messages/by-id/CALDaNm3uyHpD9sKoFtB0EnMO8DLuD6H9pReFm=tm=9ccEWuUVQ@mail.gmail.com

With Regards,
Bharath Rupireddy.
EnterpriseDB: http://www.enterprisedb.com

Attachments:

config.txttext/plain; charset=UTF-8; name=config.txtDownload
0005-Parallel-Copy-For-Binary-Format-Files.patchapplication/octet-stream; name=0005-Parallel-Copy-For-Binary-Format-Files.patchDownload
From 5f3f9c365e5ba75a293f9685247a1a6c19762c51 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddy@enterprisedb.com>
Date: Mon, 15 Jun 2020 15:41:06 +0530
Subject: [PATCH v3] Parallel Copy For Binary Format Files

Leader reads data from the file into the DSM data blocks each of 64K size.
It also identifies each tuple data block id, start offset, end offset,
tuple size and updates this information in the ring data structure.
Workers parallely read the tuple information from the ring data structure,
the actual tuple data from the data blocks and parallely insert the tuples
into the table.
---
 src/backend/commands/copy.c | 667 ++++++++++++++++++++++++++++++++----
 1 file changed, 599 insertions(+), 68 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index b1e2e71a7c..5b9508d27b 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -231,6 +231,16 @@ typedef struct ParallelCopyData
 	uint32				worker_line_buf_pos;
 }ParallelCopyData;
 
+/*
+ * Tuple boundary information used for parallel copy
+ * for binary format files.
+ */
+typedef struct ParallelCopyTupleInfo
+{
+	uint32 offset;
+	uint32 block_id;
+}ParallelCopyTupleInfo;
+
 /*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
@@ -361,6 +371,16 @@ typedef struct CopyStateData
 	int			nworkers;
 	bool		is_parallel;
 	ParallelCopyData *pcdata;
+
+	/*
+	 * Parallel copy for binary formatted files
+	 */
+	ParallelCopyDataBlock *curr_data_block;
+	ParallelCopyDataBlock *prev_data_block;
+	uint32				   curr_data_offset;
+	uint32				   curr_block_pos;
+	ParallelCopyTupleInfo  curr_tuple_start_info;
+	ParallelCopyTupleInfo  curr_tuple_end_info;
 } CopyStateData;
 
 /*
@@ -386,6 +406,7 @@ typedef struct ParallelCopyCommonKeyData
 	/* Working state for COPY FROM */
 	AttrNumber          num_defaults;
 	Oid                 relid;
+	bool 				binary;
 }ParallelCopyCommonKeyData;
 
 /*
@@ -741,6 +762,14 @@ static void PopulateCatalogInformation(CopyState cstate);
 static pg_attribute_always_inline uint32 GetChunkPosition(CopyState cstate);
 static pg_attribute_always_inline copy_data_source_cb LookupParallelCopyFnPtr(const char *funcname);
 static pg_attribute_always_inline char* LookupParallelCopyFnStr(copy_data_source_cb fn_addr);
+static uint32 WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info);
+static pg_attribute_always_inline bool CopyReadBinaryTupleLeader(CopyState cstate);
+static pg_attribute_always_inline void CopyReadBinaryAttributeLeader(CopyState cstate,
+										FmgrInfo *flinfo, Oid typioparam, int32 typmod,
+										uint32 *new_block_pos);
+static pg_attribute_always_inline bool CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls);
+static pg_attribute_always_inline Datum CopyReadBinaryAttributeWorker(CopyState cstate, int column_no,
+										 FmgrInfo *flinfo, Oid typioparam, int32 typmod, bool *isnull);
 
 /*
  * CopyCommonInfoForWorker - Copy shared_cstate using cstate information.
@@ -759,6 +788,7 @@ CopyCommonInfoForWorker(CopyState cstate, ParallelCopyCommonKeyData *shared_csta
 	shared_cstate->convert_selectively = cstate->convert_selectively;
 	shared_cstate->num_defaults = cstate->num_defaults;
 	shared_cstate->relid = cstate->pcdata->relid;
+	shared_cstate->binary = cstate->binary;
 }
 
 /*
@@ -977,8 +1007,8 @@ FindInsertMethod(CopyState cstate)
 static pg_attribute_always_inline bool
 IsParallelCopyAllowed(CopyState cstate)
 {
-	/* Parallel copy not allowed for freeze & binary option. */
-	if (cstate->freeze || cstate->binary)
+	/* Parallel copy not allowed for freeze. */
+	if (cstate->freeze)
 		return false;
 
 	/* Check if copy is into foreign table. */
@@ -1270,6 +1300,7 @@ ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
 	cstate->convert_selectively = shared_cstate->convert_selectively;
 	cstate->num_defaults = shared_cstate->num_defaults;
 	pcdata->relid = shared_cstate->relid;
+	cstate->binary = shared_cstate->binary;
 
 	PopulateAttributes(cstate, tup_desc, attnamelist);
 
@@ -1302,6 +1333,15 @@ ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
 		cstate->max_fields = attr_count;
 		cstate->raw_fields = (char **)palloc(attr_count * sizeof(char *));
 	}
+
+	cstate->curr_data_block = NULL;
+	cstate->prev_data_block = NULL;
+	cstate->curr_data_offset = 0;
+	cstate->curr_block_pos = 0;
+	cstate->curr_tuple_start_info.block_id = -1;
+	cstate->curr_tuple_start_info.offset = -1;
+	cstate->curr_tuple_end_info.block_id = -1;
+	cstate->curr_tuple_end_info.offset = -1;
 }
 
 /*
@@ -1650,38 +1690,515 @@ ParallelCopyLeader(CopyState cstate)
 	/* Execute the before statement triggers from the leader */
 	ExecBeforeStmtTrigger(cstate);
 
-	/* On input just throw the header line away. */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (!cstate->binary)
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
+		/* On input just throw the header line away. */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
 		{
-			pcshared_info->is_read_in_progress = false;
-			return;			/* done */
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+			{
+				pcshared_info->is_read_in_progress = false;
+				return;			/* done */
+			}
 		}
-	}
 
-	for (;;)
+		for (;;)
+		{
+			bool done;
+			cstate->cur_lineno++;
+
+			/* Actually read the line into memory here. */
+			done = CopyReadLine(cstate);
+
+			/*
+			* EOF at start of line means we're done.  If we see EOF after some
+			* characters, we act as though it was newline followed by EOF, ie,
+			* process the line and then exit loop on next iteration.
+			*/
+			if (done && cstate->line_buf.len == 0)
+				break;
+		}
+	}
+	else
 	{
-		bool done;
-		cstate->cur_lineno++;
+		cstate->curr_data_block = NULL;
+		cstate->prev_data_block = NULL;
+		cstate->curr_data_offset = 0;
+		cstate->curr_block_pos = 0;
+		cstate->curr_tuple_start_info.block_id = -1;
+		cstate->curr_tuple_start_info.offset = -1;
+		cstate->curr_tuple_end_info.block_id = -1;
+		cstate->curr_tuple_end_info.offset = -1;
+		pcshared_info->populated = 0;
+		cstate->cur_lineno = 0;
 
-		/* Actually read the line into memory here. */
-		done = CopyReadLine(cstate);
+		for (;;)
+		{
+			bool eof = false;
+			cstate->cur_lineno++;
 
-		/*
-		 * EOF at start of line means we're done.  If we see EOF after some
-		 * characters, we act as though it was newline followed by EOF, ie,
-		 * process the line and then exit loop on next iteration.
-		 */
-		if (done && cstate->line_buf.len == 0)
-			break;
+			eof = CopyReadBinaryTupleLeader(cstate);
+
+			if (eof)
+				break;
+		}
 	}
 
 	pcshared_info->is_read_in_progress = false;
 	cstate->cur_lineno = 0;
 }
 
+/*
+ * CopyReadBinaryTupleLeader - leader reads data from binary formatted file
+ * to data blocks and identies tuple boundaries/offsets so that workers
+ * can work on the data blocks data.
+ */
+static pg_attribute_always_inline bool
+CopyReadBinaryTupleLeader(CopyState cstate)
+{
+	int readbytes = 0;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	uint32 block_pos;
+	int16		fld_count;
+	AttrNumber	attr_count = list_length(cstate->attnumlist);
+	ListCell   *cur;
+	FmgrInfo   *in_functions = cstate->in_functions;
+	Oid		   *typioparams = cstate->typioparams;
+	TupleDesc	tupDesc = RelationGetDescr(cstate->rel);
+	uint32      new_block_pos;
+	uint32      chunk_size;
+
+	if (cstate->curr_data_block == NULL)
+	{
+		block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+		cstate->curr_block_pos = block_pos;
+
+		cstate->curr_data_block = &pcshared_info->data_blocks[block_pos];
+
+		cstate->curr_data_offset = 0;
+
+		readbytes = CopyGetData(cstate, &cstate->curr_data_block->data, 1, DATA_BLOCK_SIZE);
+
+		elog(DEBUG1, "LEADER - bytes read from file %d", readbytes);
+
+		if (cstate->reached_eof)
+			return true;
+	}
+
+	if (cstate->curr_data_offset + sizeof(fld_count) >= (DATA_BLOCK_SIZE - 1))
+	{
+		ParallelCopyDataBlock *data_block = NULL;
+		uint8 movebytes = 0;
+
+		block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+		movebytes = DATA_BLOCK_SIZE - cstate->curr_data_offset;
+
+		cstate->curr_data_block->skip_bytes = movebytes;
+
+		data_block = &pcshared_info->data_blocks[block_pos];
+
+		if (movebytes > 0)
+			memmove(&data_block->data[0], &cstate->curr_data_block->data[cstate->curr_data_offset],
+			 movebytes);
+
+		elog(DEBUG1, "LEADER - field count is spread across data blocks - moved %d bytes from current block %u to %u block",
+			movebytes, cstate->curr_block_pos, block_pos);
+
+		readbytes = CopyGetData(cstate, &data_block->data[movebytes], 1, (DATA_BLOCK_SIZE - movebytes));
+
+		elog(DEBUG1, "LEADER - bytes read from file after field count is moved to next data block %d", readbytes);
+
+		if (cstate->reached_eof)
+			ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("unexpected EOF in COPY data")));
+
+		cstate->curr_data_block = data_block;
+		cstate->curr_data_offset = 0;
+		cstate->curr_block_pos = block_pos;
+	}
+
+	memcpy(&fld_count, &cstate->curr_data_block->data[cstate->curr_data_offset], sizeof(fld_count));
+
+	fld_count = (int16) pg_ntoh16(fld_count);
+
+	if (fld_count == -1)
+	{
+		/*
+			* Received EOF marker.  In a V3-protocol copy, wait for the
+			* protocol-level EOF, and complain if it doesn't come
+			* immediately.  This ensures that we correctly handle CopyFail,
+			* if client chooses to send that now.
+			*
+			* Note that we MUST NOT try to read more data in an old-protocol
+			* copy, since there is no protocol-level EOF marker then.  We
+			* could go either way for copy from file, but choose to throw
+			* error if there's data after the EOF marker, for consistency
+			* with the new-protocol case.
+			*/
+		char		dummy;
+
+		if (cstate->copy_dest != COPY_OLD_FE &&
+			CopyGetData(cstate, &dummy, 1, 1) > 0)
+			ereport(ERROR,
+					(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+						errmsg("received copy data after EOF marker")));
+		return true;
+	}
+
+	if (fld_count != attr_count)
+		ereport(ERROR,
+			(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+			errmsg("row field count is %d, expected %d",
+			(int) fld_count, attr_count)));
+
+	cstate->curr_tuple_start_info.block_id = cstate->curr_block_pos;
+	cstate->curr_tuple_start_info.offset =  cstate->curr_data_offset;
+	cstate->curr_data_offset = cstate->curr_data_offset + sizeof(fld_count);
+	new_block_pos = cstate->curr_block_pos;
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			attnum = lfirst_int(cur);
+		int			m = attnum - 1;
+		Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+
+		CopyReadBinaryAttributeLeader(cstate,
+									&in_functions[m],
+									typioparams[m],
+									att->atttypmod,
+									&new_block_pos);
+	}
+
+	cstate->curr_tuple_end_info.block_id = new_block_pos;
+	cstate->curr_tuple_end_info.offset =  cstate->curr_data_offset-1;;
+
+	if (cstate->curr_tuple_start_info.block_id == cstate->curr_tuple_end_info.block_id)
+	{
+		elog(DEBUG1,"LEADER - tuple lies in a single data block");
+
+		chunk_size = cstate->curr_tuple_end_info.offset - cstate->curr_tuple_start_info.offset + 1;
+		pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[cstate->curr_tuple_start_info.block_id].unprocessed_chunk_parts, 1);
+	}
+	else
+	{
+		uint32 following_block_id = pcshared_info->data_blocks[cstate->curr_tuple_start_info.block_id].following_block;
+
+		elog(DEBUG1,"LEADER - tuple is spread across data blocks");
+
+		chunk_size = DATA_BLOCK_SIZE - cstate->curr_tuple_start_info.offset-
+			pcshared_info->data_blocks[cstate->curr_tuple_start_info.block_id].skip_bytes;
+
+		pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[cstate->curr_tuple_start_info.block_id].unprocessed_chunk_parts, 1);
+
+		while (following_block_id != cstate->curr_tuple_end_info.block_id)
+		{
+			chunk_size = chunk_size + DATA_BLOCK_SIZE - pcshared_info->data_blocks[following_block_id].skip_bytes;
+
+			pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[following_block_id].unprocessed_chunk_parts, 1);
+
+			following_block_id = pcshared_info->data_blocks[following_block_id].following_block;
+
+			if (following_block_id == -1)
+				break;
+		}
+
+		if (following_block_id != -1)
+			pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[following_block_id].unprocessed_chunk_parts, 1);
+
+		chunk_size = chunk_size + cstate->curr_tuple_end_info.offset + 1;
+	}
+
+	if (chunk_size > 0)
+	{
+		int chunk_pos = UpdateBlockInChunkInfo(cstate,
+											cstate->curr_tuple_start_info.block_id,
+											cstate->curr_tuple_start_info.offset,
+											chunk_size,
+											CHUNK_LEADER_POPULATED);
+
+		pcshared_info->populated++;
+
+		elog(DEBUG1, "LEADER - adding - block:%u, offset:%u, chunk size:%u chunk position:%d",
+						 cstate->curr_tuple_start_info.block_id,
+						 cstate->curr_tuple_start_info.offset,
+						 chunk_size, chunk_pos);
+	}
+
+	cstate->curr_tuple_start_info.block_id = -1;
+	cstate->curr_tuple_start_info.offset = -1;
+	cstate->curr_tuple_end_info.block_id = -1;
+	cstate->curr_tuple_end_info.offset = -1;
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryAttributeLeader - leader identifies boundaries/offsets
+ * for each attribute/column, it moves on to next data block if the
+ * attribute/column is spread across data blocks.
+ */
+static pg_attribute_always_inline void
+CopyReadBinaryAttributeLeader(CopyState cstate, FmgrInfo *flinfo,
+	Oid typioparam, int32 typmod, uint32 *new_block_pos)
+{
+	int32		fld_size;
+	int readbytes;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	uint32 block_pos;
+
+	if ((cstate->curr_data_offset + sizeof(fld_size)) >= (DATA_BLOCK_SIZE - 1))
+	{
+		ParallelCopyDataBlock *data_block = NULL;
+		uint8 movebytes = DATA_BLOCK_SIZE - cstate->curr_data_offset;
+
+		block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+		cstate->curr_data_block->skip_bytes = movebytes;
+
+		data_block = &pcshared_info->data_blocks[block_pos];
+
+		if (movebytes > 0)
+			memmove(&data_block->data[0], &cstate->curr_data_block->data[cstate->curr_data_offset], movebytes);
+
+		elog(DEBUG1, "LEADER - field size is spread across data blocks - moved %d bytes from current block %u to %u block",
+			movebytes, cstate->curr_block_pos, block_pos);
+
+		readbytes = CopyGetData(cstate, &data_block->data[movebytes], 1, DATA_BLOCK_SIZE-movebytes);
+
+		elog(DEBUG1, "LEADER - bytes read from file after field size is moved to next data block %d", readbytes);
+
+		if (cstate->reached_eof)
+			ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("unexpected EOF in COPY data")));
+
+		cstate->prev_data_block = cstate->curr_data_block;
+		cstate->prev_data_block->following_block = block_pos;
+		cstate->curr_data_block = data_block;
+		cstate->curr_block_pos = block_pos;
+
+		if (cstate->prev_data_block->curr_blk_completed  == false)
+			cstate->prev_data_block->curr_blk_completed = true;
+
+		cstate->curr_data_offset = 0;
+		*new_block_pos = block_pos;
+	}
+
+	memcpy(&fld_size, &cstate->curr_data_block->data[cstate->curr_data_offset], sizeof(fld_size));
+
+	cstate->curr_data_offset = cstate->curr_data_offset + sizeof(fld_size);
+
+	fld_size = (int32) pg_ntoh32(fld_size);
+
+	if (fld_size == 0)
+		ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("unexpected EOF in COPY data")));
+
+	if (fld_size < -1)
+		ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("invalid field size")));
+
+	if ((DATA_BLOCK_SIZE-cstate->curr_data_offset) >= fld_size)
+	{
+		cstate->curr_data_offset = cstate->curr_data_offset + fld_size;
+	}
+	else
+	{
+		ParallelCopyDataBlock *data_block = NULL;
+
+		block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+		data_block = &pcshared_info->data_blocks[block_pos];
+
+		readbytes = CopyGetData(cstate, &data_block->data[0], 1, DATA_BLOCK_SIZE);
+
+		elog(DEBUG1, "LEADER - bytes read from file after detecting that tuple is spread across data blocks %d", readbytes);
+
+		if (cstate->reached_eof)
+			ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("unexpected EOF in COPY data")));
+
+
+		cstate->prev_data_block = cstate->curr_data_block;
+		cstate->prev_data_block->following_block = block_pos;
+
+		if (cstate->prev_data_block->curr_blk_completed  == false)
+			cstate->prev_data_block->curr_blk_completed = true;
+
+		cstate->curr_data_block = data_block;
+		cstate->curr_data_offset = fld_size - (DATA_BLOCK_SIZE - cstate->curr_data_offset);
+		cstate->curr_block_pos = block_pos;
+		*new_block_pos = block_pos;
+	}
+}
+
+/*
+ * CopyReadBinaryTupleWorker - each worker reads data from data blocks after
+ * getting leader-identified tuple offsets from ring data structure.
+ */
+static pg_attribute_always_inline bool
+CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls)
+{
+	uint32 chunk_pos;
+	ParallelCopyChunkBoundary *chunk_info;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	int16		fld_count;
+	AttrNumber	attr_count = list_length(cstate->attnumlist);
+	ListCell   *cur;
+	FmgrInfo   *in_functions = cstate->in_functions;
+	Oid		   *typioparams = cstate->typioparams;
+	TupleDesc	tupDesc = RelationGetDescr(cstate->rel);
+	int			i;
+
+	chunk_pos = GetChunkPosition(cstate);
+
+	if (chunk_pos == -1)
+		return true;
+
+	chunk_info = &pcshared_info->chunk_boundaries.ring[chunk_pos];
+	cstate->curr_data_block = &pcshared_info->data_blocks[chunk_info->first_block];
+	cstate->curr_data_offset = chunk_info->start_offset;
+
+	if (cstate->curr_data_offset + sizeof(fld_count) >= (DATA_BLOCK_SIZE - 1))
+	{
+		/*the case where field count spread across datablocks should never occur.
+		  as the leader would have moved it to next block*/
+		elog(DEBUG1, "WORKER - field count spread across datablocks should never occur");
+	}
+
+	memcpy(&fld_count, &cstate->curr_data_block->data[cstate->curr_data_offset], sizeof(fld_count));
+	fld_count = (int16) pg_ntoh16(fld_count);
+
+	if (fld_count == -1)
+	{
+		return true;
+	}
+
+	if (fld_count != attr_count)
+		ereport(ERROR,
+			(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+			errmsg("row field count is %d, expected %d",
+			(int) fld_count, attr_count)));
+
+	cstate->curr_data_offset = cstate->curr_data_offset + sizeof(fld_count);
+	i = 0;
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			attnum = lfirst_int(cur);
+		int			m = attnum - 1;
+		Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+		cstate->cur_attname = NameStr(att->attname);
+
+		i++;
+		values[m] = CopyReadBinaryAttributeWorker(cstate,
+											i,
+											&in_functions[m],
+											typioparams[m],
+											att->atttypmod,
+											&nulls[m]);
+		cstate->cur_attname = NULL;
+	}
+
+	pg_atomic_sub_fetch_u32(&cstate->curr_data_block->unprocessed_chunk_parts, 1);
+	chunk_info->start_offset = -1;
+	pg_atomic_write_u32(&chunk_info->chunk_state, CHUNK_WORKER_PROCESSED);
+	pg_atomic_write_u32(&chunk_info->chunk_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryAttributeWorker - leader identifies boundaries/offsets
+ * for each attribute/column, it moves on to next data block if the
+ * attribute/column is spread across data blocks.
+ */
+static pg_attribute_always_inline Datum
+CopyReadBinaryAttributeWorker(CopyState cstate, int column_no,
+		FmgrInfo *flinfo, Oid typioparam, int32 typmod, bool *isnull)
+{
+	int32		fld_size;
+	Datum		result;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+	if ((cstate->curr_data_offset + sizeof(fld_size)) >= (DATA_BLOCK_SIZE - 1))
+	{
+		ParallelCopyDataBlock *prev_data_block = cstate->curr_data_block;
+
+		elog(DEBUG1, "WORKER - field size is spread across data blocks");
+
+		cstate->curr_data_block = &pcshared_info->data_blocks[cstate->curr_data_block->following_block];
+		pg_atomic_sub_fetch_u32(&prev_data_block->unprocessed_chunk_parts, 1);
+		cstate->curr_data_offset = 0;
+	}
+
+	memcpy(&fld_size, &cstate->curr_data_block->data[cstate->curr_data_offset], sizeof(fld_size));
+	fld_size = (int32) pg_ntoh32(fld_size);
+
+	if (fld_size == 0)
+		ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("unexpected EOF in COPY data")));
+
+	if (fld_size < -1)
+		ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("invalid field size")));
+
+	cstate->curr_data_offset = cstate->curr_data_offset + sizeof(fld_size);
+
+	/* reset attribute_buf to empty, and load raw data in it */
+	resetStringInfo(&cstate->attribute_buf);
+
+	enlargeStringInfo(&cstate->attribute_buf, fld_size);
+
+	if ((DATA_BLOCK_SIZE-cstate->curr_data_offset) >= fld_size)
+	{
+		elog(DEBUG1, "WORKER - tuple lies in single data block");
+
+		memcpy(&cstate->attribute_buf.data[0],&cstate->curr_data_block->data[cstate->curr_data_offset], fld_size);
+		cstate->curr_data_offset = cstate->curr_data_offset + fld_size;
+	}
+	else
+	{
+		ParallelCopyDataBlock *prev_data_block = cstate->curr_data_block;
+
+		elog(DEBUG1, "WORKER - tuple is spread across data blocks");
+
+		memcpy(&cstate->attribute_buf.data[0], &cstate->curr_data_block->data[cstate->curr_data_offset],
+				(DATA_BLOCK_SIZE - cstate->curr_data_offset));
+		cstate->curr_data_block = &pcshared_info->data_blocks[cstate->curr_data_block->following_block];
+		pg_atomic_sub_fetch_u32(&prev_data_block->unprocessed_chunk_parts, 1);
+		memcpy(&cstate->attribute_buf.data[DATA_BLOCK_SIZE - cstate->curr_data_offset],
+			&cstate->curr_data_block->data[0], (fld_size - (DATA_BLOCK_SIZE - cstate->curr_data_offset)));
+		cstate->curr_data_offset = fld_size - (DATA_BLOCK_SIZE - cstate->curr_data_offset);
+	}
+
+	cstate->attribute_buf.len = fld_size;
+	cstate->attribute_buf.data[fld_size] = '\0';
+
+	/* Call the column type's binary input converter */
+	result = ReceiveFunctionCall(flinfo, &cstate->attribute_buf,
+								 typioparam, typmod);
+
+	/* Trouble if it didn't eat the whole buffer */
+	if (cstate->attribute_buf.cursor != cstate->attribute_buf.len)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+				 errmsg("incorrect binary data format")));
+
+	*isnull = false;
+	return result;
+}
+
 /*
  * GetChunkPosition - return the chunk position that worker should process.
  */
@@ -5402,63 +5919,77 @@ NextCopyFrom(CopyState cstate, ExprContext *econtext,
 	else
 	{
 		/* binary */
-		int16		fld_count;
-		ListCell   *cur;
+		if (!IsParallelCopy())
+		{
+			int16		fld_count;
+			ListCell   *cur;
 
-		cstate->cur_lineno++;
+			cstate->cur_lineno++;
 
-		if (!CopyGetInt16(cstate, &fld_count))
-		{
-			/* EOF detected (end of file, or protocol-level EOF) */
-			return false;
-		}
+			if (!CopyGetInt16(cstate, &fld_count))
+			{
+				/* EOF detected (end of file, or protocol-level EOF) */
+				return false;
+			}
 
-		if (fld_count == -1)
-		{
-			/*
-			 * Received EOF marker.  In a V3-protocol copy, wait for the
-			 * protocol-level EOF, and complain if it doesn't come
-			 * immediately.  This ensures that we correctly handle CopyFail,
-			 * if client chooses to send that now.
-			 *
-			 * Note that we MUST NOT try to read more data in an old-protocol
-			 * copy, since there is no protocol-level EOF marker then.  We
-			 * could go either way for copy from file, but choose to throw
-			 * error if there's data after the EOF marker, for consistency
-			 * with the new-protocol case.
-			 */
-			char		dummy;
+			if (fld_count == -1)
+			{
+				/*
+				* Received EOF marker.  In a V3-protocol copy, wait for the
+				* protocol-level EOF, and complain if it doesn't come
+				* immediately.  This ensures that we correctly handle CopyFail,
+				* if client chooses to send that now.
+				*
+				* Note that we MUST NOT try to read more data in an old-protocol
+				* copy, since there is no protocol-level EOF marker then.  We
+				* could go either way for copy from file, but choose to throw
+				* error if there's data after the EOF marker, for consistency
+				* with the new-protocol case.
+				*/
+				char		dummy;
+
+				if (cstate->copy_dest != COPY_OLD_FE &&
+					CopyGetData(cstate, &dummy, 1, 1) > 0)
+					ereport(ERROR,
+							(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+							errmsg("received copy data after EOF marker")));
+				return false;
+			}
 
-			if (cstate->copy_dest != COPY_OLD_FE &&
-				CopyGetData(cstate, &dummy, 1, 1) > 0)
+			if (fld_count != attr_count)
 				ereport(ERROR,
 						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-						 errmsg("received copy data after EOF marker")));
-			return false;
+						errmsg("row field count is %d, expected %d",
+								(int) fld_count, attr_count)));
+
+			i = 0;
+			foreach(cur, cstate->attnumlist)
+			{
+				int			attnum = lfirst_int(cur);
+				int			m = attnum - 1;
+				Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+
+				cstate->cur_attname = NameStr(att->attname);
+				i++;
+				values[m] = CopyReadBinaryAttribute(cstate,
+													i,
+													&in_functions[m],
+													typioparams[m],
+													att->atttypmod,
+													&nulls[m]);
+				cstate->cur_attname = NULL;
+			}
 		}
+		else
+		{
+			bool eof = false;
 
-		if (fld_count != attr_count)
-			ereport(ERROR,
-					(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-					 errmsg("row field count is %d, expected %d",
-							(int) fld_count, attr_count)));
+			cstate->cur_lineno++;
 
-		i = 0;
-		foreach(cur, cstate->attnumlist)
-		{
-			int			attnum = lfirst_int(cur);
-			int			m = attnum - 1;
-			Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+			eof = CopyReadBinaryTupleWorker(cstate, values, nulls);
 
-			cstate->cur_attname = NameStr(att->attname);
-			i++;
-			values[m] = CopyReadBinaryAttribute(cstate,
-												i,
-												&in_functions[m],
-												typioparams[m],
-												att->atttypmod,
-												&nulls[m]);
-			cstate->cur_attname = NULL;
+			if (eof)
+				return false;
 		}
 	}
 
-- 
2.25.1

#95Ashutosh Sharma
ashu.coek88@gmail.com
In reply to: Amit Kapila (#93)
Re: Parallel copy

Thanks Amit for the clarifications. Regarding partitioned table, one of the
question was - if we are loading data into a partitioned table using COPY
command, then the input file would contain tuples for different tables
(partitions) unlike the normal table case where all the tuples in the input
file would belong to the same table. So, in such a case, how are we going
to accumulate tuples into the DSM? I mean will the leader process check
which tuple needs to be routed to which partition and accordingly
accumulate them into the DSM. For e.g. let's say in the input data file we
have 10 tuples where the 1st tuple belongs to partition1, 2nd belongs to
partition2 and likewise. So, in such cases, will the leader process
accumulate all the tuples belonging to partition1 into one DSM and tuples
belonging to partition2 into some other DSM and assign them to the worker
process or we have taken some other approach to handle this scenario?

Further, I haven't got much time to look into the links that you have
shared in your previous response. Will have a look into those and will also
slowly start looking into the patches as and when I get some time. Thank
you.

--
With Regards,
Ashutosh Sharma
EnterpriseDB:http://www.enterprisedb.com

On Sat, Jun 13, 2020 at 9:42 AM Amit Kapila <amit.kapila16@gmail.com> wrote:

Show quoted text

On Fri, Jun 12, 2020 at 4:57 PM Ashutosh Sharma <ashu.coek88@gmail.com>
wrote:

Hi All,

I've spent little bit of time going through the project discussion that

has happened in this email thread and to start with I have few questions
which I would like to put here:

Q1) Are we also planning to read the input data in parallel or is it

only about performing the multi-insert operation in parallel? AFAIU, the
data reading part will be done by the leader process alone so no
parallelism is involved there.

Yes, your understanding is correct.

Q2) How are we going to deal with the partitioned tables?

I haven't studied the patch but my understanding is that we will
support parallel copy for partitioned tables with a few restrictions
as explained in my earlier email [1]. See, Case-2 (b) in the email.

I mean will there be some worker process dedicated for each partition or

how is it?

No, it the split is just based on the input, otherwise each worker
should insert as we would have done without any workers.

Q3) Incase of toast tables, there is a possibility of having a single

tuple in the input file which could be of a very big size (probably in GB)
eventually resulting in a bigger file size. So, in this case, how are we
going to decide the number of worker processes to be launched. I mean,
although the file size is big, but the number of tuples to be processed is
just one or few of them, so, can we decide the number of the worker
processes to be launched based on the file size?

Yeah, such situations would be tricky, so we should have an option for
user to specify the number of workers.

Q4) Who is going to process constraints (preferably the deferred

constraint) that is supposed to be executed at the COMMIT time? I mean is
it the leader process or the worker process or in such cases we won't be
choosing the parallelism at all?

In the first version, we won't do parallelism for this. Again, see
one of my earlier email [1] where I have explained this and other
cases where we won't be supporting parallel copy.

Q5) Do we have any risk of table bloating when the data is loaded in

parallel. I am just asking this because incase of parallelism there would
be multiple processes performing bulk insert into a table. There is a
chance that the table file might get extended even if there is some space
into the file being written into, but that space is locked by some other
worker process and hence that might result in a creation of a new block for
that table. Sorry, if I am missing something here.

Hmm, each worker will operate at page level, after first insertion,
the same worker will try to insert in the same page in which it has
inserted last, so there shouldn't be such a problem.

Please note that I haven't gone through all the emails in this thread so

there is a possibility that I might have repeated the question that has
already been raised and answered here. If that is the case, I am sorry for
that, but it would be very helpful if someone could point out that thread
so that I can go through it. Thank you.

No problem, I understand sometimes it is difficult to go through each
and every email especially when the discussion is long. Anyway,
thanks for showing the interest in the patch.

[1] -
/messages/by-id/CAA4eK1+ANNEaMJCCXm4naweP5PLY6LhJMvGo_V7-Pnfbh6GsOA@mail.gmail.com

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#96Amit Kapila
amit.kapila16@gmail.com
In reply to: Ashutosh Sharma (#95)
Re: Parallel copy

On Mon, Jun 15, 2020 at 7:41 PM Ashutosh Sharma <ashu.coek88@gmail.com> wrote:

Thanks Amit for the clarifications. Regarding partitioned table, one of the question was - if we are loading data into a partitioned table using COPY command, then the input file would contain tuples for different tables (partitions) unlike the normal table case where all the tuples in the input file would belong to the same table. So, in such a case, how are we going to accumulate tuples into the DSM? I mean will the leader process check which tuple needs to be routed to which partition and accordingly accumulate them into the DSM. For e.g. let's say in the input data file we have 10 tuples where the 1st tuple belongs to partition1, 2nd belongs to partition2 and likewise. So, in such cases, will the leader process accumulate all the tuples belonging to partition1 into one DSM and tuples belonging to partition2 into some other DSM and assign them to the worker process or we have taken some other approach to handle this scenario?

No, all the tuples (for all partitions) will be accumulated in a
single DSM and the workers/leader will route the tuple to an
appropriate partition.

Further, I haven't got much time to look into the links that you have shared in your previous response. Will have a look into those and will also slowly start looking into the patches as and when I get some time. Thank you.

Yeah, it will be good if you go through all the emails once because
most of the decisions (and design) in the patch is supposed to be
based on the discussion in this thread.

Note - Please don't top post, try to give inline replies.

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#97vignesh C
vignesh21@gmail.com
In reply to: Amit Kapila (#96)
6 attachment(s)
Re: Parallel copy

Hi,

I have included tests for parallel copy feature & few bugs that were
identified during testing have been fixed. Attached patches for the
same.
Thoughts?

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

Show quoted text

On Tue, Jun 16, 2020 at 3:21 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Mon, Jun 15, 2020 at 7:41 PM Ashutosh Sharma <ashu.coek88@gmail.com> wrote:

Thanks Amit for the clarifications. Regarding partitioned table, one of the question was - if we are loading data into a partitioned table using COPY command, then the input file would contain tuples for different tables (partitions) unlike the normal table case where all the tuples in the input file would belong to the same table. So, in such a case, how are we going to accumulate tuples into the DSM? I mean will the leader process check which tuple needs to be routed to which partition and accordingly accumulate them into the DSM. For e.g. let's say in the input data file we have 10 tuples where the 1st tuple belongs to partition1, 2nd belongs to partition2 and likewise. So, in such cases, will the leader process accumulate all the tuples belonging to partition1 into one DSM and tuples belonging to partition2 into some other DSM and assign them to the worker process or we have taken some other approach to handle this scenario?

No, all the tuples (for all partitions) will be accumulated in a
single DSM and the workers/leader will route the tuple to an
appropriate partition.

Further, I haven't got much time to look into the links that you have shared in your previous response. Will have a look into those and will also slowly start looking into the patches as and when I get some time. Thank you.

Yeah, it will be good if you go through all the emails once because
most of the decisions (and design) in the patch is supposed to be
based on the discussion in this thread.

Note - Please don't top post, try to give inline replies.

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

Attachments:

0002-Framework-for-leader-worker-in-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=0002-Framework-for-leader-worker-in-parallel-copy.patchDownload
From df3439e3292ff04a471274a3e5f385c7773e1916 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>,Bharath <bharath.rupireddyforpostgres@gmail.com>
Date: Wed, 17 Jun 2020 07:23:14 +0530
Subject: [PATCH 2/6] Framework for leader/worker in parallel copy.

This patch has the framework for data structures in parallel copy, leader
initialization, worker initialization, shared memory updation, starting workers,
wait for workers and workers exiting.
---
 src/backend/access/transam/parallel.c       |   4 +
 src/backend/commands/copy.c                 | 831 +++++++++++++++++++++++++++-
 src/backend/replication/logical/tablesync.c |   2 +-
 src/include/commands/copy.h                 |   4 +
 src/tools/pgindent/typedefs.list            |   8 +
 5 files changed, 847 insertions(+), 2 deletions(-)

diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index 14a8690..09e7a19 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -25,6 +25,7 @@
 #include "catalog/pg_enum.h"
 #include "catalog/storage.h"
 #include "commands/async.h"
+#include "commands/copy.h"
 #include "executor/execParallel.h"
 #include "libpq/libpq.h"
 #include "libpq/pqformat.h"
@@ -145,6 +146,9 @@ static const struct
 	},
 	{
 		"parallel_vacuum_main", parallel_vacuum_main
+	},
+	{
+		"ParallelCopyMain", ParallelCopyMain
 	}
 };
 
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index f2310ab..9977aa6 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -96,9 +96,138 @@ typedef enum CopyInsertMethod
 } CopyInsertMethod;
 
 #define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+
+#define DATA_BLOCK_SIZE RAW_BUF_SIZE
+#define RINGSIZE (10 * 1000)
+#define MAX_BLOCKS_COUNT 1000
+#define WORKER_CHUNK_COUNT 50	/* should be mod of RINGSIZE */
+
+#define	IsParallelCopy()		(cstate->is_parallel)
+#define IsLeader()				(cstate->pcdata->is_leader)
 #define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
 
 /*
+ * Copy data block information.
+ */
+typedef struct ParallelCopyDataBlock
+{
+	/* The number of unprocessed lines in the current block. */
+	pg_atomic_uint32 unprocessed_line_parts;
+
+	/*
+	 * If the current line data is continued into another block, following_block
+	 * will have the position where the remaining data need to be read.
+	 */
+	uint32	following_block;
+
+	/*
+	 * This flag will be set, when the leader finds out this block can be read
+	 * safely by the worker. This helps the worker to start processing the line
+	 * early where the line will be spread across many blocks and the worker
+	 * need not wait for the complete line to be processed.
+	 */
+	bool   curr_blk_completed;
+	char   data[DATA_BLOCK_SIZE]; /* data read from file */
+	uint8  skip_bytes;
+}ParallelCopyDataBlock;
+
+/*
+ * Individual line information.
+ * ParallelCopyLineBoundary is common data structure between leader & worker,
+ * this is protected by the following sequence in the leader & worker.
+ * Leader should operate in the following order:
+ * 1) update first_block, start_offset & cur_lineno in any order.
+ * 2) update line_size.
+ * 3) update line_state.
+ * Worker should operate in the following order:
+ * 1) read line_size.
+ * 2) only one worker should choose one line for processing, this is handled by
+ *    using pg_atomic_compare_exchange_u32, worker will change the sate to
+ *    LINE_WORKER_PROCESSING only if line_state is LINE_LEADER_POPULATED.
+ * 3) read first_block, start_offset & cur_lineno in any order.
+ */
+typedef struct ParallelCopyLineBoundary
+{
+	/* Position of the first block in data_blocks array. */
+	uint32				first_block;
+	uint32				start_offset;   /* start offset of the line */
+
+	/*
+	 * Size of the current line -1 means line is yet to be filled completely,
+	 * 0 means empty line, >0 means line filled with line size data.
+	 */
+	pg_atomic_uint32	line_size;
+	pg_atomic_uint32	line_state;		/* line state */
+	uint64				cur_lineno;		/* line number for error messages */
+}ParallelCopyLineBoundary;
+
+/*
+ * Circular queue used to store the line information.
+ */
+typedef struct ParallelCopyLineBoundaries
+{
+	/* Position for the leader to populate a line. */
+	uint32			leader_pos;
+
+	/* Data read from the file/stdin by the leader process. */
+	ParallelCopyLineBoundary	ring[RINGSIZE];
+}ParallelCopyLineBoundaries;
+
+/*
+ * Shared information among parallel copy workers. This will be allocated in the
+ * DSM segment.
+ */
+typedef struct ParallelCopyShmInfo
+{
+	bool					is_read_in_progress; /* file read status */
+
+	/*
+	 * Actual lines inserted by worker (some records will be filtered based on
+	 * where condition).
+	 */
+	pg_atomic_uint64			processed;
+	pg_atomic_uint64			total_worker_processed; /* total processed records by the workers */
+	uint64						populated; /* lines populated by leader */
+	uint32						cur_block_pos; /* current data block */
+	ParallelCopyDataBlock		data_blocks[MAX_BLOCKS_COUNT]; /* data block array */
+	FullTransactionId			full_transaction_id; /* xid for copy from statement */
+	CommandId					mycid;	/* command id */
+	ParallelCopyLineBoundaries	line_boundaries; /* line array */
+} ParallelCopyShmInfo;
+
+/*
+ * Parallel copy line buffer information.
+ */
+typedef struct ParallelCopyLineBuf
+{
+	StringInfoData		line_buf;
+	uint64				cur_lineno;	/* line number for error messages */
+}ParallelCopyLineBuf;
+
+/*
+ * Parallel copy data information.
+ */
+typedef struct ParallelCopyData
+{
+	Oid					relid;				/* relation id of the table */
+	ParallelCopyShmInfo	*pcshared_info;		/* common info in shared memory */
+	bool				is_leader;
+
+	/* line position which worker is processing */
+	uint32				worker_processed_pos;
+
+	/*
+	 * Local line_buf array, workers will copy it here and release the lines
+	 * for the leader to continue.
+	 */
+	ParallelCopyLineBuf	worker_line_buf[WORKER_CHUNK_COUNT];
+	uint32				worker_line_buf_count; /* Number of lines */
+
+	/* Current position in worker_line_buf */
+	uint32				worker_line_buf_pos;
+}ParallelCopyData;
+
+/*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
  * even though some fields are used in only some cases.
@@ -225,8 +354,66 @@ typedef struct CopyStateData
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
+	int			nworkers;
+	bool		is_parallel;
+	ParallelCopyData *pcdata;
 } CopyStateData;
 
+/*
+ * This structure helps in storing the common data from CopyStateData that are
+ * required by the workers. This information will then be allocated and stored
+ * into the DSM for the worker to retrieve and copy it to CopyStateData.
+ */
+typedef struct ParallelCopyCommonKeyData
+{
+	/* low-level state data */
+	CopyDest            copy_dest;		/* type of copy source/destination */
+	int                 file_encoding;	/* file or remote side's character encoding */
+	bool                need_transcoding;	/* file encoding diff from server? */
+	bool                encoding_embeds_ascii;	/* ASCII can be non-first byte? */
+
+	/* parameters from the COPY command */
+	bool                csv_mode;		/* Comma Separated Value format? */
+	bool                header_line;	/* CSV header line? */
+	int                 null_print_len; /* length of same */
+	bool                force_quote_all;	/* FORCE_QUOTE *? */
+	bool                convert_selectively;	/* do selective binary conversion? */
+
+	/* Working state for COPY FROM */
+	AttrNumber          num_defaults;
+	Oid                 relid;
+}ParallelCopyCommonKeyData;
+
+/*
+ * This structure will help in converting a List data type into the below
+ * structure format with the count having the number of elements in the list and
+ * the info having the List elements appended contigously. This converted
+ * structure will be allocated in shared memory and stored in DSM for the worker
+ * to retrieve and later convert it back to List data type.
+ */
+typedef struct ParallelCopyKeyListInfo
+{
+	int	count;		/* count of attributes */
+
+	/* string info in the form info followed by info1, info2... infon  */
+	char    info[1];
+} ParallelCopyKeyListInfo;
+
+/*
+ * List of internal parallel copy function pointers.
+ */
+static const struct
+{
+	char *fn_name;
+	copy_data_source_cb fn_addr;
+}			InternalParallelCopyFuncPtrs[] =
+
+{
+	{
+		"copy_read_data", copy_read_data
+	},
+};
+
 /* DestReceiver for COPY (query) TO */
 typedef struct
 {
@@ -256,6 +443,23 @@ typedef struct
 /* Trim the list of buffers back down to this number after flushing */
 #define MAX_PARTITION_BUFFERS	32
 
+/* DSM keys for parallel copy.  */
+#define PARALLEL_COPY_KEY_SHARED_INFO		    1
+#define PARALLEL_COPY_KEY_CSTATE				2
+#define PARALLEL_COPY_KEY_NULL_PRINT			3
+#define PARALLEL_COPY_KEY_NULL_PRINT_CLIENT		4
+#define PARALLEL_COPY_KEY_DELIM					5
+#define PARALLEL_COPY_KEY_QUOTE					6
+#define PARALLEL_COPY_KEY_ESCAPE				7
+#define PARALLEL_COPY_KEY_ATTNAME_LIST			8
+#define PARALLEL_COPY_KEY_FORCE_QUOTE_LIST  	9
+#define PARALLEL_COPY_KEY_NOT_NULL_LIST		   10
+#define PARALLEL_COPY_KEY_NULL_LIST			   11
+#define PARALLEL_COPY_KEY_CONVERT_LIST		   12
+#define PARALLEL_COPY_KEY_DATASOURCE_CB		   13
+#define PARALLEL_COPY_KEY_WHERE_CLAUSE_STR     14
+#define PARALLEL_COPY_KEY_RANGE_TABLE		   15
+
 /* Stores multi-insert data related to a single relation in CopyFrom. */
 typedef struct CopyMultiInsertBuffer
 {
@@ -477,10 +681,596 @@ static bool CopyGetInt32(CopyState cstate, int32 *val);
 static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 
+static pg_attribute_always_inline void EndParallelCopy(ParallelContext *pcxt);
 static void PopulateAttributes(CopyState cstate, TupleDesc	tup_desc,
 							   List *attnamelist);
+static pg_attribute_always_inline copy_data_source_cb LookupParallelCopyFnPtr(const char *funcname);
+static pg_attribute_always_inline char* LookupParallelCopyFnStr(copy_data_source_cb fn_addr);
 
 /*
+ * CopyCommonInfoForWorker - Copy shared_cstate using cstate information.
+ */
+static pg_attribute_always_inline void
+CopyCommonInfoForWorker(CopyState cstate, ParallelCopyCommonKeyData *shared_cstate)
+{
+	shared_cstate->copy_dest = cstate->copy_dest;
+	shared_cstate->file_encoding = cstate->file_encoding;
+	shared_cstate->need_transcoding = cstate->need_transcoding;
+	shared_cstate->encoding_embeds_ascii = cstate->encoding_embeds_ascii;
+	shared_cstate->csv_mode = cstate->csv_mode;
+	shared_cstate->header_line = cstate->header_line;
+	shared_cstate->null_print_len = cstate->null_print_len;
+	shared_cstate->force_quote_all = cstate->force_quote_all;
+	shared_cstate->convert_selectively = cstate->convert_selectively;
+	shared_cstate->num_defaults = cstate->num_defaults;
+	shared_cstate->relid = cstate->pcdata->relid;
+}
+
+/*
+ * RetrieveSharedString - Retrieve the string from shared memory.
+ */
+static void
+RetrieveSharedString(shm_toc *toc, int sharedkey, char **copystr)
+{
+	char *shared_str_val = (char *)shm_toc_lookup(toc, sharedkey, true);
+	if (shared_str_val)
+		*copystr = pstrdup(shared_str_val);
+}
+
+/*
+ * RetrieveSharedList - Retrieve the list from shared memory.
+ */
+static void
+RetrieveSharedList(shm_toc *toc, int sharedkey, List **copylist)
+{
+	ParallelCopyKeyListInfo *listinformation = (ParallelCopyKeyListInfo *)shm_toc_lookup(toc, sharedkey,
+														   true);
+	if (listinformation)
+	{
+		int	length  = 0;
+		int count;
+
+		for (count = 0; count < listinformation->count; count++)
+		{
+			char *attname = (char *)(listinformation->info + length);
+			length += strlen(attname) + 1;
+			*copylist = lappend(*copylist, makeString(attname));
+		}
+	}
+}
+
+/*
+ * CopyListSharedMemory - Copy the list into shared memory.
+ */
+static void
+CopyListSharedMemory(List *inputlist, Size memsize, ParallelCopyKeyListInfo *sharedlistinfo)
+{
+	ListCell   *l;
+	int			length  = 0;
+
+	MemSet(sharedlistinfo, 0, memsize);
+	foreach(l, inputlist)
+	{
+		char	   *name = strVal(lfirst(l));
+		memcpy((char *)(sharedlistinfo->info + length), name, strlen(name));
+		sharedlistinfo->count++;
+		length += strlen(name) + 1;
+	}
+}
+
+/*
+ * ComputeListSize - compute the list size.
+ */
+static int
+ComputeListSize(List *inputlist)
+{
+	int est_size = sizeof(int);
+	if (inputlist != NIL)
+	{
+		ListCell   *l;
+		foreach(l, inputlist)
+			est_size += strlen(strVal(lfirst(l))) + 1;
+	}
+
+	return est_size;
+}
+
+/*
+ * EstimateLineKeysStr - Estimate the size required in shared memory for the
+ * input string.
+ */
+static void
+EstimateLineKeysStr(ParallelContext *pcxt, char *inputstr)
+{
+	if (inputstr)
+	{
+		shm_toc_estimate_chunk(&pcxt->estimator, strlen(inputstr) + 1);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+}
+
+/*
+ * EstimateLineKeysList - Estimate the size required in shared memory for the
+ * input list.
+ */
+static void
+EstimateLineKeysList(ParallelContext *pcxt, List *inputlist,
+		Size *est_list_size)
+{
+	if (inputlist != NIL)
+	{
+		*est_list_size = ComputeListSize(inputlist);
+		shm_toc_estimate_chunk(&pcxt->estimator, *est_list_size);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+}
+
+/*
+ * InsertStringShm - Insert a string into shared memory.
+ */
+static void
+InsertStringShm(ParallelContext *pcxt, int key, char *inputstr)
+{
+	if (inputstr)
+	{
+		char *shmptr = (char *)shm_toc_allocate(pcxt->toc,
+												strlen(inputstr) + 1);
+		strcpy(shmptr, inputstr);
+		shm_toc_insert(pcxt->toc, key, shmptr);
+	}
+}
+
+/*
+ * InsertListShm - Insert a list into shared memory.
+ */
+static void
+InsertListShm(ParallelContext *pcxt, int key, List *inputlist,
+			  Size est_list_size)
+{
+	if (inputlist != NIL)
+	{
+		ParallelCopyKeyListInfo *sharedlistinfo = (ParallelCopyKeyListInfo *)shm_toc_allocate(pcxt->toc,
+																est_list_size);
+		CopyListSharedMemory(inputlist, est_list_size, sharedlistinfo);
+		shm_toc_insert(pcxt->toc, key, sharedlistinfo);
+	}
+}
+
+/*
+ * BeginParallelCopy - start parallel copy tasks.
+ *
+ * Get the number of workers required to perform the parallel copy. The data
+ * structures that are required by the parallel workers will be initialized, the
+ * size required in DSM will be calculated and the necessary keys will be loaded
+ * in the DSM. The specified number of workers will then be launched.
+ *
+ */
+static ParallelContext*
+BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
+{
+	ParallelContext *pcxt;
+	ParallelCopyShmInfo *shared_info_ptr;
+	ParallelCopyCommonKeyData *shared_cstate;
+	FullTransactionId full_transaction_id;
+	Size est_shared_info;
+	Size est_cstateshared;
+	Size est_att_list_size;
+	Size est_quote_list_size;
+	Size est_notnull_list_size;
+	Size est_null_list_size;
+	Size est_convert_list_size;
+	Size est_datasource_cb_size;
+	int  count = 0;
+	char *whereClauseStr = NULL;
+	char *rangeTableStr = NULL;
+	int  parallel_workers = 0;
+	ParallelCopyData *pcdata;
+
+	parallel_workers = Min(nworkers, max_worker_processes);
+
+	/* Can't perform copy in parallel */
+	if (parallel_workers <= 0)
+	{
+		elog(WARNING,
+			 "No workers available, copy will be run in non-parallel mode");
+		return NULL;
+	}
+
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	cstate->pcdata = pcdata;
+
+	EnterParallelMode();
+	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
+								 parallel_workers);
+	Assert(pcxt->nworkers > 0);
+
+	/*
+	 * Estimate size for shared information for PARALLEL_COPY_KEY_SHARED_INFO
+	 */
+	est_shared_info = sizeof(ParallelCopyShmInfo);
+	shm_toc_estimate_chunk(&pcxt->estimator, est_shared_info);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_CSTATE */
+	est_cstateshared = 	MAXALIGN(sizeof(ParallelCopyCommonKeyData));
+	shm_toc_estimate_chunk(&pcxt->estimator, est_cstateshared);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	EstimateLineKeysStr(pcxt, cstate->null_print);
+	EstimateLineKeysStr(pcxt, cstate->null_print_client);
+	EstimateLineKeysStr(pcxt, cstate->delim);
+	EstimateLineKeysStr(pcxt, cstate->quote);
+	EstimateLineKeysStr(pcxt, cstate->escape);
+
+	if (cstate->whereClause != NULL)
+	{
+		whereClauseStr = nodeToString(cstate->whereClause);
+		EstimateLineKeysStr(pcxt, whereClauseStr);
+	}
+
+	if (cstate->range_table != NULL)
+	{
+		rangeTableStr = nodeToString(cstate->range_table);
+		EstimateLineKeysStr(pcxt, rangeTableStr);
+	}
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_XID. */
+	shm_toc_estimate_chunk(&pcxt->estimator, sizeof(FullTransactionId));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_ATTNAME_LIST.
+	 */
+	EstimateLineKeysList(pcxt, attnamelist, &est_att_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_FORCE_QUOTE_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->force_quote, &est_quote_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_NOT_NULL_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->force_notnull,
+							 &est_notnull_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_NULL_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->force_null, &est_null_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_CONVERT_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->convert_select,
+							 &est_convert_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_DATASOURCE_CB.
+	 */
+	if (cstate->data_source_cb)
+	{
+		char *functionname = LookupParallelCopyFnStr(cstate->data_source_cb);
+		est_datasource_cb_size = strlen(functionname) + 1;
+		shm_toc_estimate_chunk(&pcxt->estimator, est_datasource_cb_size);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+
+	InitializeParallelDSM(pcxt);
+
+	/* If no DSM segment was available, back out (do serial copy) */
+	if (pcxt->seg == NULL)
+	{
+		EndParallelCopy(pcxt);
+		elog(WARNING,
+			 "DSM segments not available, copy will be run in non-parallel mode");
+		return NULL;
+	}
+
+	/* Allocate shared memory for PARALLEL_COPY_KEY_SHARED_INFO */
+	shared_info_ptr = (ParallelCopyShmInfo *) shm_toc_allocate(pcxt->toc,
+													   est_shared_info);
+	MemSet(shared_info_ptr, 0, est_shared_info);
+	shared_info_ptr->is_read_in_progress = true;
+	shared_info_ptr->cur_block_pos = -1;
+	shared_info_ptr->full_transaction_id = full_transaction_id;
+	shared_info_ptr->mycid = GetCurrentCommandId(true);
+	for (count = 0; count < RINGSIZE; count++)
+	{
+		ParallelCopyLineBoundary *lineInfo = &shared_info_ptr->line_boundaries.ring[count];
+		pg_atomic_init_u32(&(lineInfo->line_size), -1);
+	}
+
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_SHARED_INFO, shared_info_ptr);
+	pcdata->pcshared_info = shared_info_ptr;
+	pcdata->relid = relid;
+
+	/* Store shared build state, for which we reserved space. */
+	shared_cstate = (ParallelCopyCommonKeyData *)shm_toc_allocate(pcxt->toc,
+															est_cstateshared);
+
+	/* copy cstate variables. */
+	CopyCommonInfoForWorker(cstate, shared_cstate);
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_CSTATE, shared_cstate);
+
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_NULL_PRINT, cstate->null_print);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_NULL_PRINT_CLIENT,
+					  cstate->null_print_client);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_DELIM, cstate->delim);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_QUOTE, cstate->quote);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_ESCAPE, cstate->escape);
+
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_ATTNAME_LIST,
+					attnamelist, est_att_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_FORCE_QUOTE_LIST,
+					cstate->force_quote, est_quote_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_NOT_NULL_LIST,
+					cstate->force_notnull, est_notnull_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_NULL_LIST, cstate->force_null,
+					est_null_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_CONVERT_LIST,
+					cstate->convert_select, est_convert_list_size);
+
+	if (cstate->data_source_cb)
+	{
+		char *functionname = LookupParallelCopyFnStr(cstate->data_source_cb);
+		char *data_source_cb = (char *) shm_toc_allocate(pcxt->toc,
+														 est_datasource_cb_size);
+		strcpy(data_source_cb, functionname);
+		shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_DATASOURCE_CB,
+					   data_source_cb);
+	}
+
+	if (cstate->whereClause)
+		InsertStringShm(pcxt, PARALLEL_COPY_KEY_WHERE_CLAUSE_STR,
+						whereClauseStr);
+
+	if(cstate->range_table)
+		InsertStringShm(pcxt, PARALLEL_COPY_KEY_RANGE_TABLE, rangeTableStr);
+
+	LaunchParallelWorkers(pcxt);
+	if (pcxt->nworkers_launched == 0)
+	{
+		EndParallelCopy(pcxt);
+		elog(WARNING,
+			 "No workers available, copy will be run in non-parallel mode");
+		return NULL;
+	}
+
+	/*
+	 * Caller needs to wait for all launched workers when we return.  Make sure
+	 * that the failure-to-start case will not hang forever.
+	 */
+	WaitForParallelWorkersToAttach(pcxt);
+
+	pcdata->is_leader = true;
+	cstate->is_parallel = true;
+	return pcxt;
+}
+
+/*
+ * EndParallelCopy - end the parallel copy tasks.
+ */
+static pg_attribute_always_inline void
+EndParallelCopy(ParallelContext *pcxt)
+{
+	Assert(!IsParallelWorker());
+
+	DestroyParallelContext(pcxt);
+	ExitParallelMode();
+}
+
+/*
+ * ParallelWorkerInitialization - Initialize parallel worker.
+ */
+static void
+ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
+		CopyState cstate, List *attnamelist)
+{
+	uint32		count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	cstate->copy_dest = shared_cstate->copy_dest;
+	cstate->file_encoding = shared_cstate->file_encoding;
+	cstate->need_transcoding = shared_cstate->need_transcoding;
+	cstate->encoding_embeds_ascii = shared_cstate->encoding_embeds_ascii;
+	cstate->csv_mode = shared_cstate->csv_mode;
+	cstate->header_line = shared_cstate->header_line;
+	cstate->null_print_len = shared_cstate->null_print_len;
+	cstate->force_quote_all = shared_cstate->force_quote_all;
+	cstate->convert_selectively = shared_cstate->convert_selectively;
+	cstate->num_defaults = shared_cstate->num_defaults;
+	pcdata->relid = shared_cstate->relid;
+
+	PopulateAttributes(cstate, tup_desc, attnamelist);
+
+	/* Initialize state variables. */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/* Set up variables to avoid per-attribute overhead. */
+	initStringInfo(&cstate->attribute_buf);
+
+	initStringInfo(&cstate->line_buf);
+	for (count = 0; count < WORKER_CHUNK_COUNT;count++)
+		initStringInfo(&pcdata->worker_line_buf[count].line_buf);
+
+	cstate->line_buf_converted = false;
+	cstate->raw_buf = NULL;
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+}
+/*
+ * ParallelCopyMain - parallel copy worker's code.
+ *
+ * Where clause handling, convert tuple to columns, add default null values for
+ * the missing columns that are not present in that record. Find the partition
+ * if it is partitioned table, invoke before row insert Triggers, handle
+ * constraints and insert the tuples.
+ */
+void
+ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
+{
+	CopyState cstate;
+	ParallelCopyData *pcdata;
+	ParallelCopyShmInfo *pcshared_info;
+	ParallelCopyCommonKeyData *shared_cstate;
+	Relation	rel = NULL;
+	MemoryContext oldcontext;
+	List *attlist = NIL;
+	char *data_source_cb;
+	char *whereClauseStr = NULL;
+	char *rangeTableStr = NULL;
+
+	/* Allocate workspace and zero all fields. */
+	cstate = (CopyStateData *) palloc0(sizeof(CopyStateData));
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	cstate->pcdata = pcdata;
+	pcdata->is_leader = false;
+	pcdata->worker_processed_pos = -1;
+	cstate->is_parallel = true;
+
+	/*
+	 * We allocate everything used by a cstate in a new memory context. This
+	 * avoids memory leaks during repeated use of COPY in a query.
+	 */
+	cstate->copycontext = AllocSetContextCreate(CurrentMemoryContext,
+												"COPY",
+												ALLOCSET_DEFAULT_SIZES);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	pcshared_info = (ParallelCopyShmInfo *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_SHARED_INFO,
+														false);
+
+	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
+
+	pcdata->pcshared_info = pcshared_info;
+
+	shared_cstate = (ParallelCopyCommonKeyData *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE,
+														   false);
+
+	cstate->null_print = (char *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_NULL_PRINT,
+												true);
+	cstate->null_print_client = (char *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_NULL_PRINT_CLIENT,
+													   true);
+
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_DELIM, &cstate->delim);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_QUOTE, &cstate->quote);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_ESCAPE, &cstate->escape);
+
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_ATTNAME_LIST, &attlist);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_FORCE_QUOTE_LIST, &cstate->force_quote);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_NOT_NULL_LIST, &cstate->force_notnull);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_NULL_LIST, &cstate->force_null);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_CONVERT_LIST, &cstate->convert_select);
+	data_source_cb = (char *)shm_toc_lookup(toc,
+											PARALLEL_COPY_KEY_DATASOURCE_CB,
+											true);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_WHERE_CLAUSE_STR, &whereClauseStr);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_RANGE_TABLE, &rangeTableStr);
+
+	if (data_source_cb)
+		cstate->data_source_cb = LookupParallelCopyFnPtr(data_source_cb);
+
+	if (whereClauseStr)
+	{
+		Node *whereClauseCnvrtdFrmStr = (Node *) stringToNode(whereClauseStr);
+		cstate->whereClause = whereClauseCnvrtdFrmStr;
+	}
+
+	if (rangeTableStr)
+	{
+		List *rangeTableCnvrtdFrmStr = (List *) stringToNode(rangeTableStr);
+		cstate->range_table = rangeTableCnvrtdFrmStr;
+	}
+
+	/* Open and lock the relation, using the appropriate lock type. */
+	rel = table_open(shared_cstate->relid, RowExclusiveLock);
+	cstate->rel = rel;
+	ParallelWorkerInitialization(shared_cstate, cstate, attlist);
+
+	CopyFrom(cstate);
+
+	if (rel != NULL)
+		table_close(rel, RowExclusiveLock);
+
+	MemoryContextSwitchTo(oldcontext);
+	return;
+}
+/*
+ * ParallelCopyLeader - parallel copy leader's functionality.
+ *
+ * Leader will populate the shared memory and share it across the workers.
+ * Leader will read the table data from the file and copy the contents to block.
+ * Leader will then read the input contents and identify the data based on line
+ * beaks. This information is called line. The line will be populate in
+ * ParallelCopyLineBoundary. Workers will then pick up this information and
+ * insert in to table. Leader will do this till it completes processing the
+ * file. Leader executes the before statement if before statement trigger is
+ * present. Leader read the data from input file. Leader then loads data to data
+ * blocks as and when required block by block. Leader traverses through the data
+ * block to identify one line. It gets a free line to copy the information, if
+ * there is no free line it will wait till there is one free line.
+ * Server copies  the identified lines information into lines. This process is
+ * repeated till the complete file is processed.
+ * Leader will wait till all the lines populated are processed by the workers
+ * and exits.
+ */
+static void
+ParallelCopyLeader(CopyState cstate)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
+
+	pcshared_info->is_read_in_progress = false;
+	cstate->cur_lineno = 0;
+}
+/*
+ * LookupParallelCopyFnPtr - Look up parallel copy function pointer.
+ */
+static pg_attribute_always_inline copy_data_source_cb
+LookupParallelCopyFnPtr(const char *funcname)
+{
+	int			i;
+
+	for (i = 0; i < lengthof(InternalParallelCopyFuncPtrs); i++)
+	{
+		if (strcmp(InternalParallelCopyFuncPtrs[i].fn_name, funcname) == 0)
+			return InternalParallelCopyFuncPtrs[i].fn_addr;
+	}
+
+	/* We can only reach this by programming error. */
+	elog(ERROR, "internal function \"%s\" not found", funcname);
+}
+
+/*
+ * LookupParallelCopyFnStr - Lookup function string from a function pointer.
+ */
+static pg_attribute_always_inline char*
+LookupParallelCopyFnStr(copy_data_source_cb fn_addr)
+{
+	int			i;
+
+	for (i = 0; i < lengthof(InternalParallelCopyFuncPtrs); i++)
+	{
+		if (InternalParallelCopyFuncPtrs[i].fn_addr == fn_addr)
+			return InternalParallelCopyFuncPtrs[i].fn_name;
+	}
+
+	/* We can only reach this by programming error. */
+	elog(ERROR, "internal function pointer not found");
+}
+/*
  * Send copy start/stop messages for frontend copies.  These have changed
  * in past protocol redesigns.
  */
@@ -1150,6 +1940,7 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 
 	if (is_from)
 	{
+		ParallelContext *pcxt = NULL;
 		Assert(rel);
 
 		/* check read-only transaction and parallel mode */
@@ -1159,7 +1950,24 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 		cstate = BeginCopyFrom(pstate, rel, stmt->filename, stmt->is_program,
 							   NULL, stmt->attlist, stmt->options);
 		cstate->whereClause = whereClause;
-		*processed = CopyFrom(cstate);	/* copy from file to database */
+		cstate->is_parallel = false;
+
+		if (cstate->nworkers > 0)
+			pcxt = BeginParallelCopy(cstate->nworkers, cstate, stmt->attlist,
+									 relid);
+
+		if (pcxt)
+		{
+			ParallelCopyLeader(cstate);
+
+			/* Wait for all copy workers to finish */
+			WaitForParallelWorkersToFinish(pcxt);
+			*processed = pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
+			EndParallelCopy(pcxt);
+		}
+		else
+			*processed = CopyFrom(cstate); /* copy from file to database */
+
 		EndCopyFrom(cstate);
 	}
 	else
@@ -1208,6 +2016,7 @@ ProcessCopyOptions(ParseState *pstate,
 	cstate->is_copy_from = is_from;
 
 	cstate->file_encoding = -1;
+	cstate->nworkers = -1;
 
 	/* Extract options from the statement node tree */
 	foreach(option, options)
@@ -1376,6 +2185,26 @@ ProcessCopyOptions(ParseState *pstate,
 								defel->defname),
 						 parser_errposition(pstate, defel->location)));
 		}
+		else if (strcmp(defel->defname, "parallel") == 0)
+		{
+			if (!cstate->is_copy_from)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("parallel option supported only for copy from"),
+						 parser_errposition(pstate, defel->location)));
+			if (cstate->nworkers >= 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options"),
+						 parser_errposition(pstate, defel->location)));
+			cstate->nworkers = atoi(defGetString(defel));
+			if (cstate->nworkers <= 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("argument to option \"%s\" must be a positive integer greater than zero",
+								defel->defname),
+						 parser_errposition(pstate, defel->location)));
+		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_SYNTAX_ERROR),
diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c
index c27d970..b3787c1 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -557,7 +557,7 @@ make_copy_attnamelist(LogicalRepRelMapEntry *rel)
  * Data source callback for the COPY FROM, which reads from the remote
  * connection and passes the data back to our local COPY.
  */
-static int
+int
 copy_read_data(void *outbuf, int minread, int maxread)
 {
 	int			bytesread = 0;
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index c639833..5dc95ac 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -14,6 +14,7 @@
 #ifndef COPY_H
 #define COPY_H
 
+#include "access/parallel.h"
 #include "nodes/execnodes.h"
 #include "nodes/parsenodes.h"
 #include "parser/parse_node.h"
@@ -41,4 +42,7 @@ extern uint64 CopyFrom(CopyState cstate);
 
 extern DestReceiver *CreateCopyDestReceiver(void);
 
+extern void ParallelCopyMain(dsm_segment *seg, shm_toc *toc);
+
+extern int copy_read_data(void *outbuf, int minread, int maxread);
 #endif							/* COPY_H */
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index c65a552..8a79794 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1698,6 +1698,14 @@ ParallelBitmapHeapState
 ParallelBlockTableScanDesc
 ParallelCompletionPtr
 ParallelContext
+ParallelCopyLineBoundaries
+ParallelCopyLineBoundary
+ParallelCopyCommonKeyData
+ParallelCopyData
+ParallelCopyDataBlock
+ParallelCopyKeyListInfo
+ParallelCopyLineBuf
+ParallelCopyShmInfo
 ParallelExecutorInfo
 ParallelHashGrowth
 ParallelHashJoinBatch
-- 
1.8.3.1

0003-Allow-copy-from-command-to-process-data-from-file-ST.patchtext/x-patch; charset=US-ASCII; name=0003-Allow-copy-from-command-to-process-data-from-file-ST.patchDownload
From 1f0b6d47ffe5ef7d1c08edbfb62c527e122494ab Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>, Bharath <bharath.rupireddyforpostgres@gmail.com>
Date: Wed, 17 Jun 2020 07:31:30 +0530
Subject: [PATCH 3/6] Allow copy from command to process data from file/STDIN 
 contents to a table in parallel.

This feature allows the copy from to leverage multiple CPUs in order to copy
data from file/STDIN to a table. This adds a PARALLEL option to COPY FROM
command where the user can specify the number of workers that can be used
to perform the COPY FROM command. Specifying zero as number of workers will
disable parallelism.
The backend, to which the "COPY FROM" query is submitted acts as leader with
the responsibility of reading data from the file/stdin, launching at most n
number of workers as specified with PARALLEL 'n' option in the "COPY FROM"
query. The leader populates the common data required for the workers execution
in the DSM and shares it with the workers. The leader then executes before
statement triggers if there exists any. Leader populates DSM lines which
includes the start offset and line size, while populating the lines it reads
as many blocks as required into the DSM data blocks from the file. Each block
is of 64K size. The leader parses the data to identify a line, the existing
logic from CopyReadLineText which identifies the lines with some changes was
used for this. Leader checks if a free line is available to copy the
information, if there is no free line it waits till the required line is
freed up by the worker and then copies the identified lines information
(offset & line size) into the DSM lines. This process is repeated till the
complete file is processed. Simultaneously, the workers cache the lines(50)
locally into the local memory and release the lines to the leader for further
populating. Each worker processes the lines that it cached and inserts it into
the table. The leader does not participate in the insertion of data, leaders
only responsibility will be to identify the lines as fast as possible for the
workers to do the actual copy operation. The leader waits till all the lines
populated are processed by the workers and exits.
---
 src/backend/access/heap/heapam.c  |  13 -
 src/backend/access/transam/xact.c |  13 +
 src/backend/commands/copy.c       | 896 ++++++++++++++++++++++++++++++++++++--
 src/include/access/xact.h         |   1 +
 src/tools/pgindent/typedefs.list  |   1 +
 5 files changed, 873 insertions(+), 51 deletions(-)

diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 537913d..28f3a98 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2012,19 +2012,6 @@ static HeapTuple
 heap_prepare_insert(Relation relation, HeapTuple tup, TransactionId xid,
 					CommandId cid, int options)
 {
-	/*
-	 * Parallel operations are required to be strictly read-only in a parallel
-	 * worker.  Parallel inserts are not safe even in the leader in the
-	 * general case, because group locking means that heavyweight locks for
-	 * relation extension or GIN page locks will not conflict between members
-	 * of a lock group, but we don't prohibit that case here because there are
-	 * useful special cases that we can safely allow, such as CREATE TABLE AS.
-	 */
-	if (IsParallelWorker())
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_TRANSACTION_STATE),
-				 errmsg("cannot insert tuples in a parallel worker")));
-
 	tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
 	tup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK);
 	tup->t_data->t_infomask |= HEAP_XMAX_INVALID;
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index cd30b62..d43902c 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -502,6 +502,19 @@ GetCurrentFullTransactionIdIfAny(void)
 }
 
 /*
+ *	AssignFullTransactionIdForWorker
+ *
+ * For parallel copy, all the workers must use the same transaction id.
+ */
+void AssignFullTransactionIdForWorker(FullTransactionId fullTransactionId)
+{
+	TransactionState s = CurrentTransactionState;
+
+	Assert((IsInParallelMode() || IsParallelWorker()));
+	s->fullTransactionId = fullTransactionId;
+}
+
+/*
  *	MarkCurrentTransactionIdLoggedIfAny
  *
  * Remember that the current xid - if it is assigned - now has been wal logged.
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 9977aa6..f19e991 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -26,6 +26,7 @@
 #include "access/xlog.h"
 #include "catalog/dependency.h"
 #include "catalog/pg_authid.h"
+#include "catalog/pg_proc_d.h"
 #include "catalog/pg_type.h"
 #include "commands/copy.h"
 #include "commands/defrem.h"
@@ -40,11 +41,13 @@
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
+#include "optimizer/clauses.h"
 #include "optimizer/optimizer.h"
 #include "parser/parse_coerce.h"
 #include "parser/parse_collate.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_relation.h"
+#include "pgstat.h"
 #include "port/pg_bswap.h"
 #include "rewrite/rewriteHandler.h"
 #include "storage/fd.h"
@@ -95,6 +98,18 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
+/*
+ * State of the line.
+ */
+typedef enum ParallelCopyLineState
+{
+	LINE_INIT,					/* initial state of line */
+	LINE_LEADER_POPULATING,		/* leader processing line */
+	LINE_LEADER_POPULATED,		/* leader completed populating line */
+	LINE_WORKER_PROCESSING,		/* worker processing line */
+	LINE_WORKER_PROCESSED		/* worker completed processing line */
+}ParallelCopyLineState;
+
 #define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
 
 #define DATA_BLOCK_SIZE RAW_BUF_SIZE
@@ -538,9 +553,13 @@ if (1) \
 { \
 	if (raw_buf_ptr > cstate->raw_buf_index) \
 	{ \
-		appendBinaryStringInfo(&cstate->line_buf, \
-							 cstate->raw_buf + cstate->raw_buf_index, \
-							   raw_buf_ptr - cstate->raw_buf_index); \
+		if (!IsParallelCopy()) \
+			appendBinaryStringInfo(&cstate->line_buf, \
+								   cstate->raw_buf + cstate->raw_buf_index, \
+								   raw_buf_ptr - cstate->raw_buf_index); \
+		else \
+			line_size +=  raw_buf_ptr - cstate->raw_buf_index; \
+		\
 		cstate->raw_buf_index = raw_buf_ptr; \
 	} \
 } else ((void) 0)
@@ -553,13 +572,40 @@ if (1) \
 	goto not_end_of_copy; \
 } else ((void) 0)
 
+/* Begin parallel copy Macros */
+#define SET_NEWLINE_SIZE() \
+{ \
+	if (cstate->eol_type == EOL_NL || cstate->eol_type == EOL_CR) \
+		new_line_size = 1; \
+	else if (cstate->eol_type == EOL_CRNL) \
+		new_line_size = 2; \
+	else \
+		new_line_size = 0; \
+}
+
+/*
+ * COPY_WAIT_TO_PROCESS - Wait before continuing to process.
+ */
+#define COPY_WAIT_TO_PROCESS() \
+{ \
+	CHECK_FOR_INTERRUPTS(); \
+	(void) WaitLatch(MyLatch, \
+					 WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH, \
+					 1L, WAIT_EVENT_PG_SLEEP); \
+	ResetLatch(MyLatch); \
+}
+
+/* End parallel copy Macros */
+
 /*
  * CONVERT_TO_SERVER_ENCODING - convert contents to server encoding.
  */
 #define CONVERT_TO_SERVER_ENCODING(cstate) \
 { \
 	/* Done reading the line.  Convert it to server encoding. */ \
-	if (cstate->need_transcoding) \
+	if (cstate->need_transcoding && \
+		(!IsParallelCopy() || \
+		 (IsParallelCopy() && !IsLeader()))) \
 	{ \
 		char	   *cvt; \
 		cvt = pg_any_to_server(cstate->line_buf.data, \
@@ -618,22 +664,38 @@ if (1) \
  * CLEAR_EOL_LINE - Wrapper for clearing EOL.
  */
 #define CLEAR_EOL_LINE() \
-if (!result && !IsHeaderLine()) \
-	CLEAR_EOL_FROM_COPIED_DATA(cstate->line_buf.data, \
-								cstate->line_buf.len, \
-								cstate->line_buf.len) \
+{ \
+	if (!result && !IsHeaderLine()) \
+	{ \
+		if (IsParallelCopy()) \
+			CLEAR_EOL_FROM_COPIED_DATA(cstate->raw_buf, \
+									   raw_buf_ptr, line_size) \
+		else \
+			CLEAR_EOL_FROM_COPIED_DATA(cstate->line_buf.data, \
+									   cstate->line_buf.len, \
+									   cstate->line_buf.len) \
+	} \
+}
 
 /*
  * INCREMENTPROCESSED - Increment the lines processed.
  */
-#define INCREMENTPROCESSED(processed)  \
-processed++;
+#define INCREMENTPROCESSED(processed) \
+{ \
+	if (!IsParallelCopy()) \
+		processed++; \
+	else \
+		pg_atomic_add_fetch_u64(&cstate->pcdata->pcshared_info->processed, 1); \
+}
 
 /*
  * GETPROCESSED - Get the lines processed.
  */
 #define GETPROCESSED(processed) \
-return processed;
+if (!IsParallelCopy()) \
+	return processed; \
+else \
+	return pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
 
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
@@ -682,8 +744,12 @@ static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 
 static pg_attribute_always_inline void EndParallelCopy(ParallelContext *pcxt);
+static void ExecBeforeStmtTrigger(CopyState cstate);
+static void CheckCopyFromValidity(CopyState cstate);
 static void PopulateAttributes(CopyState cstate, TupleDesc	tup_desc,
 							   List *attnamelist);
+static void PopulateCatalogInformation(CopyState cstate);
+static pg_attribute_always_inline uint32 GetLinePosition(CopyState cstate);
 static pg_attribute_always_inline copy_data_source_cb LookupParallelCopyFnPtr(const char *funcname);
 static pg_attribute_always_inline char* LookupParallelCopyFnStr(copy_data_source_cb fn_addr);
 
@@ -837,6 +903,137 @@ InsertListShm(ParallelContext *pcxt, int key, List *inputlist,
 }
 
 /*
+ * IsTriggerFunctionParallelSafe - Check if the trigger function is parallel
+ * safe for the triggers. Return false if any one of the trigger has parallel
+ * unsafe function.
+ */
+static pg_attribute_always_inline bool
+IsTriggerFunctionParallelSafe(TriggerDesc *trigdesc)
+{
+	int	i;
+	for (i = 0; i < trigdesc->numtriggers; i++)
+	{
+		Trigger    *trigger = &trigdesc->triggers[i];
+		int 		trigtype = RI_TRIGGER_NONE;
+
+		if (func_parallel(trigger->tgfoid) != PROPARALLEL_SAFE)
+			return false;
+
+		/* If the trigger is parallel safe, also look for RI_TRIGGER. */
+		trigtype = RI_FKey_trigger_type(trigger->tgfoid);
+		if (trigtype == RI_TRIGGER_PK || trigtype == RI_TRIGGER_FK)
+			return false;
+	}
+
+	return true;
+}
+
+/*
+ * CheckExprParallelSafety - determine parallel safety of volatile expressions
+ * in default clause of column definition or in where clause and return true if
+ * they are parallel safe.
+ */
+static pg_attribute_always_inline bool
+CheckExprParallelSafety(CopyState cstate)
+{
+	if (contain_volatile_functions(cstate->whereClause))
+	{
+		if (max_parallel_hazard((Query *)cstate->whereClause) != PROPARALLEL_SAFE)
+			return false;
+	}
+
+	/*
+	 * Check if any of the column has volatile default expression. if yes, and
+	 * they are not parallel safe, then parallelism is not allowed. For
+	 * instance, if there are any serial/bigserial columns for which nextval()
+	 * default expression which is parallel unsafe is associated, parallelism
+	 * should not be allowed. In non paralllel copy volatile functions are not
+	 * checked for nextval().
+	 */
+	if (cstate->defexprs != NULL && cstate->num_defaults != 0)
+	{
+		int     i;
+		for (i = 0; i < cstate->num_defaults; i++)
+		{
+			bool volatile_expr = contain_volatile_functions((Node *)cstate->defexprs[i]->expr);
+			if (volatile_expr &&
+				(max_parallel_hazard((Query *)cstate->defexprs[i]->expr)) !=
+				 PROPARALLEL_SAFE)
+				return false;
+		}
+	}
+
+	return true;
+}
+
+/*
+ * FindInsertMethod - determine insert mode single, multi, or multi conditional.
+ */
+static pg_attribute_always_inline CopyInsertMethod
+FindInsertMethod(CopyState cstate)
+{
+	if (cstate->rel->trigdesc != NULL &&
+		(cstate->rel->trigdesc->trig_insert_before_row ||
+		 cstate->rel->trigdesc->trig_insert_instead_row))
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
+			cstate->rel->trigdesc != NULL &&
+			cstate->rel->trigdesc->trig_insert_new_table)
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+		return CIM_MULTI_CONDITIONAL;
+
+	return CIM_MULTI;
+}
+
+/*
+ * IsParallelCopyAllowed - check for the cases where parallel copy is not
+ * applicable.
+ */
+static pg_attribute_always_inline bool
+IsParallelCopyAllowed(CopyState cstate)
+{
+	/* Parallel copy not allowed for frontend (2.0 protocol) & binary option. */
+	if ((cstate->copy_dest == COPY_OLD_FE) || cstate->binary)
+		return false;
+
+	/* Check if copy is into foreign table or temporary table. */
+	if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
+		RelationUsesLocalBuffers(cstate->rel))
+		return false;
+
+	/* Check if trigger function is parallel safe. */
+	if (cstate->rel->trigdesc != NULL &&
+		!IsTriggerFunctionParallelSafe(cstate->rel->trigdesc))
+		return false;
+
+	/*
+	 * Check if there is after statement or instead of trigger or transition
+	 * table triggers.
+	 */
+	if (cstate->rel->trigdesc != NULL &&
+		(cstate->rel->trigdesc->trig_insert_after_statement ||
+		 cstate->rel->trigdesc->trig_insert_instead_row ||
+		 cstate->rel->trigdesc->trig_insert_new_table))
+		return false;
+
+	/* Check if the volatile expressions are parallel safe, if present any. */
+	if (!CheckExprParallelSafety(cstate))
+		return false;
+
+	/* Check if the insertion mode is single. */
+	if (FindInsertMethod(cstate) == CIM_SINGLE)
+		return false;
+
+	return true;
+}
+
+/*
  * BeginParallelCopy - start parallel copy tasks.
  *
  * Get the number of workers required to perform the parallel copy. The data
@@ -866,6 +1063,8 @@ BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
 	int  parallel_workers = 0;
 	ParallelCopyData *pcdata;
 
+	CheckCopyFromValidity(cstate);
+
 	parallel_workers = Min(nworkers, max_worker_processes);
 
 	/* Can't perform copy in parallel */
@@ -879,6 +1078,19 @@ BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
 	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
 	cstate->pcdata = pcdata;
 
+	/*
+	 * User chosen parallel copy. Determine if the parallel copy is actually
+	 * allowed. If not, go with the non-parallel mode.
+	 */
+	if (!IsParallelCopyAllowed(cstate))
+	{
+		elog(WARNING,
+			 "Parallel copy not supported for specified table, copy will be run in non-parallel mode");
+		return NULL;
+	}
+
+	full_transaction_id = GetCurrentFullTransactionId();
+
 	EnterParallelMode();
 	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
 								 parallel_workers);
@@ -1109,7 +1321,211 @@ ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
 	cstate->line_buf_converted = false;
 	cstate->raw_buf = NULL;
 	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+
+	PopulateCatalogInformation(cstate);
+
+	/* Create workspace for CopyReadAttributes results. */
+	if (!cstate->binary)
+	{
+		AttrNumber	attr_count = list_length(cstate->attnumlist);
+
+		cstate->max_fields = attr_count;
+		cstate->raw_fields = (char **)palloc(attr_count * sizeof(char *));
+	}
+}
+
+/*
+ * CacheLineInfo - Cache the line information to local memory.
+ */
+static bool
+CacheLineInfo(CopyState cstate, uint32 buff_count)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	uint32			write_pos;
+	ParallelCopyDataBlock *data_blk_ptr;
+	ParallelCopyLineBoundary *lineInfo;
+	uint32 offset;
+	int dataSize;
+	int copiedSize = 0;
+
+	resetStringInfo(&pcdata->worker_line_buf[buff_count].line_buf);
+	write_pos = GetLinePosition(cstate);
+	if (-1 == write_pos)
+		return true;
+
+	/* Get the current line information. */
+	lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+	if (pg_atomic_read_u32(&lineInfo->line_size) == 0)
+		goto empty_data_line_update;
+
+	/* Get the block information. */
+	data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+	/* Get the offset information from where the data must be copied. */
+	offset = lineInfo->start_offset;
+	pcdata->worker_line_buf[buff_count].cur_lineno = lineInfo->cur_lineno;
+
+	elog(DEBUG1, "[Worker] Processing - line position:%d, block:%d, unprocessed lines:%d, offset:%d, line size:%d",
+				 write_pos, lineInfo->first_block,
+				 pg_atomic_read_u32(&data_blk_ptr->unprocessed_line_parts),
+				 offset, pg_atomic_read_u32(&lineInfo->line_size));
+
+	for (;;)
+	{
+		uint8 skip_bytes = data_blk_ptr->skip_bytes;
+		/*
+		 * There is a possibility that the above loop has come out because
+		 * data_blk_ptr->curr_blk_completed is set, but dataSize read might
+		 * be an old value, if data_blk_ptr->curr_blk_completed and the line is
+		 * completed, line_size will be set. Read the line_size again to be
+		 * sure if it is complete or partial block.
+		 */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+		if (dataSize)
+		{
+			int remainingSize = dataSize - copiedSize;
+			if (!remainingSize)
+				break;
+
+			/* Whole line is in current block. */
+			if (remainingSize + offset + skip_bytes < DATA_BLOCK_SIZE)
+			{
+				appendBinaryStringInfo(&pcdata->worker_line_buf[buff_count].line_buf,
+									   &data_blk_ptr->data[offset],
+									   remainingSize);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts,
+										1);
+				break;
+			}
+			else
+			{
+				/* Line is spread across the blocks. */
+				uint32 lineInCurrentBlock =  (DATA_BLOCK_SIZE - skip_bytes) - offset;
+				appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+										 &data_blk_ptr->data[offset],
+										 lineInCurrentBlock);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+				copiedSize += lineInCurrentBlock;
+				while (copiedSize < dataSize)
+				{
+					uint32 currentBlockCopySize;
+					ParallelCopyDataBlock *currBlkPtr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+					skip_bytes = currBlkPtr->skip_bytes;
+
+					/*
+					 * If complete data is present in current block use
+					 * dataSize - copiedSize, or copy the whole block from
+					 * current block.
+					 */
+					currentBlockCopySize = Min(dataSize - copiedSize, DATA_BLOCK_SIZE - skip_bytes);
+					appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+											 &currBlkPtr->data[0],
+											 currentBlockCopySize);
+					pg_atomic_sub_fetch_u32(&currBlkPtr->unprocessed_line_parts, 1);
+					copiedSize += currentBlockCopySize;
+					data_blk_ptr = currBlkPtr;
+				}
+
+				break;
+			}
+		}
+		else
+		{
+			/* Copy this complete block from the current offset. */
+			uint32 lineInCurrentBlock =  (DATA_BLOCK_SIZE - skip_bytes) - offset;
+			appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+									 &data_blk_ptr->data[offset],
+									 lineInCurrentBlock);
+			pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+			copiedSize += lineInCurrentBlock;
+
+			/*
+			 * Reset the offset. For the first copy, copy from the offset. For
+			 * the subsequent copy the complete block.
+			 */
+			offset = 0;
+
+			/* Set data_blk_ptr to the following block. */
+			data_blk_ptr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+		}
+
+		for (;;)
+		{
+			/* Get the size of this line */
+			dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+			/*
+			 * If the data is present in current block lineInfo.line_size
+			 * will be updated. If the data is spread across the blocks either
+			 * of lineInfo.line_size or data_blk_ptr->curr_blk_completed can
+			 * be updated. lineInfo.line_size will be updated if the complete
+			 * read is finished. data_blk_ptr->curr_blk_completed will be
+			 * updated if processing of current block is finished and data
+			 * processing is not finished.
+			 */
+			if (data_blk_ptr->curr_blk_completed || (dataSize != -1))
+				break;
+
+			COPY_WAIT_TO_PROCESS()
+		}
+	}
+
+empty_data_line_update:
+	elog(DEBUG1, "[Worker] Completed processing line:%d", write_pos);
+	pg_atomic_write_u32(&lineInfo->line_state, LINE_WORKER_PROCESSED);
+	pg_atomic_write_u32(&lineInfo->line_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+	return false;
+}
+
+/*
+ * GetWorkerLine - Returns a line for worker to process.
+ */
+static bool
+GetWorkerLine(CopyState cstate)
+{
+	uint32 buff_count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+
+	/*
+	 * Copy the line data to line_buf and release the line position so that the
+	 * worker can continue loading data.
+	 */
+	if (pcdata->worker_line_buf_pos < pcdata->worker_line_buf_count)
+		goto return_line;
+
+	pcdata->worker_line_buf_pos = 0;
+	pcdata->worker_line_buf_count = 0;
+
+	for (buff_count = 0; buff_count < WORKER_CHUNK_COUNT; buff_count++)
+	{
+		bool result = CacheLineInfo(cstate, buff_count);
+		if (result)
+			break;
+
+		pcdata->worker_line_buf_count++;
+	}
+
+	if (pcdata->worker_line_buf_count)
+		goto return_line;
+	else
+		resetStringInfo(&cstate->line_buf);
+
+	return true;
+
+return_line:
+	cstate->line_buf = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].line_buf;
+	cstate->cur_lineno = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].cur_lineno;
+	cstate->line_buf_valid = true;
+
+	/* Mark that encoding conversion hasn't occurred yet. */
+	cstate->line_buf_converted = false;
+	CONVERT_TO_SERVER_ENCODING(cstate)
+	pcdata->worker_line_buf_pos++;
+	return false;
 }
+
 /*
  * ParallelCopyMain - parallel copy worker's code.
  *
@@ -1155,6 +1571,7 @@ ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
 	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
 
 	pcdata->pcshared_info = pcshared_info;
+	AssignFullTransactionIdForWorker(pcshared_info->full_transaction_id);
 
 	shared_cstate = (ParallelCopyCommonKeyData *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE,
 														   false);
@@ -1207,6 +1624,34 @@ ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
 	MemoryContextSwitchTo(oldcontext);
 	return;
 }
+
+/*
+ * UpdateBlockInLineInfo - Update the line information.
+ */
+static pg_attribute_always_inline int
+UpdateBlockInLineInfo(CopyState cstate, uint32 blk_pos,
+					   uint32 offset, uint32 line_size, uint32 line_state)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyLineBoundaries *lineBoundaryPtr = &pcshared_info->line_boundaries;
+	ParallelCopyLineBoundary *lineInfo;
+	int line_pos = lineBoundaryPtr->leader_pos;
+
+	/* Update the line information for the worker to pick and process. */
+	lineInfo = &lineBoundaryPtr->ring[line_pos];
+	while (pg_atomic_read_u32(&lineInfo->line_size) != -1)
+		COPY_WAIT_TO_PROCESS()
+
+	lineInfo->first_block = blk_pos;
+	lineInfo->start_offset = offset;
+	lineInfo->cur_lineno = cstate->cur_lineno;
+	pg_atomic_write_u32(&lineInfo->line_size, line_size);
+	pg_atomic_write_u32(&lineInfo->line_state, line_state);
+	lineBoundaryPtr->leader_pos = (lineBoundaryPtr->leader_pos + 1) % RINGSIZE;
+
+	return line_pos;
+}
+
 /*
  * ParallelCopyLeader - parallel copy leader's functionality.
  *
@@ -1232,9 +1677,158 @@ ParallelCopyLeader(CopyState cstate)
 	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
 	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
 
+	/* Execute the before statement triggers from the leader */
+	ExecBeforeStmtTrigger(cstate);
+
+	/* On input just throw the header line away. */
+	if (cstate->cur_lineno == 0 && cstate->header_line)
+	{
+		cstate->cur_lineno++;
+		if (CopyReadLine(cstate))
+		{
+			pcshared_info->is_read_in_progress = false;
+			return;			/* done */
+		}
+	}
+
+	for (;;)
+	{
+		bool done;
+		cstate->cur_lineno++;
+
+		/* Actually read the line into memory here. */
+		done = CopyReadLine(cstate);
+
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			break;
+	}
+
 	pcshared_info->is_read_in_progress = false;
 	cstate->cur_lineno = 0;
 }
+
+/*
+ * GetLinePosition - return the line position that worker should process.
+ */
+static uint32
+GetLinePosition(CopyState cstate)
+{
+	ParallelCopyData *pcdata = cstate->pcdata;
+	ParallelCopyShmInfo *pcshared_info = pcdata->pcshared_info;
+	uint32  previous_pos = pcdata->worker_processed_pos;
+	uint32 write_pos = (previous_pos == -1) ? 0 : (previous_pos + 1) % RINGSIZE;
+	for (;;)
+	{
+		int		dataSize;
+		bool	is_read_in_progress = pcshared_info->is_read_in_progress;
+		ParallelCopyLineBoundary *lineInfo;
+		ParallelCopyDataBlock *data_blk_ptr;
+		ParallelCopyLineState line_state = LINE_LEADER_POPULATED;
+		ParallelCopyLineState curr_line_state;
+		CHECK_FOR_INTERRUPTS();
+
+		/* File read completed & no elements to process. */
+		if (!is_read_in_progress &&
+			(pcshared_info->populated ==
+			 pg_atomic_read_u64(&pcshared_info->total_worker_processed)))
+		{
+			write_pos = -1;
+			break;
+		}
+
+		/* Get the current line information. */
+		lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+		curr_line_state = pg_atomic_read_u32(&lineInfo->line_state);
+		if ((write_pos % WORKER_CHUNK_COUNT == 0) &&
+			(curr_line_state == LINE_WORKER_PROCESSED ||
+			 curr_line_state == LINE_WORKER_PROCESSING))
+		{
+			pcdata->worker_processed_pos = write_pos;
+			write_pos = (write_pos + WORKER_CHUNK_COUNT) %  RINGSIZE;
+			continue;
+		}
+
+		/* Get the size of this line. */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+		if (dataSize != 0) /* If not an empty line. */
+		{
+			/* Get the block information. */
+			data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+			if (!data_blk_ptr->curr_blk_completed && (dataSize == -1))
+			{
+				/* Wait till the current line or block is added. */
+				COPY_WAIT_TO_PROCESS()
+				continue;
+			}
+		}
+
+		/* Make sure that no worker has consumed this element. */
+		if (pg_atomic_compare_exchange_u32(&lineInfo->line_state,
+										   &line_state, LINE_WORKER_PROCESSING))
+			break;
+	}
+
+	pcdata->worker_processed_pos = write_pos;
+	return write_pos;
+}
+
+/*
+ * GetFreeCopyBlock - Get a free block for data to be copied.
+ */
+static pg_attribute_always_inline uint32
+GetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	int count = 0;
+	uint32 last_free_block = pcshared_info->cur_block_pos;
+	uint32 block_pos = (last_free_block != -1) ? ((last_free_block + 1) % MAX_BLOCKS_COUNT): 0;
+
+	/* Get a new block for copying data. */
+	while (count < MAX_BLOCKS_COUNT)
+	{
+		ParallelCopyDataBlock *dataBlkPtr = &pcshared_info->data_blocks[block_pos];
+		uint32 unprocessed_line_parts = pg_atomic_read_u32(&dataBlkPtr->unprocessed_line_parts);
+		if (unprocessed_line_parts == 0)
+		{
+			dataBlkPtr->curr_blk_completed = false;
+			dataBlkPtr->skip_bytes = 0;
+			pcshared_info->cur_block_pos = block_pos;
+			return block_pos;
+		}
+
+		block_pos = (block_pos + 1) % MAX_BLOCKS_COUNT;
+		count++;
+	}
+
+	return -1;
+}
+
+/*
+ * WaitGetFreeCopyBlock - If there are no blocks available, wait and get a block
+ * for copying data.
+ */
+static uint32
+WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	uint32 new_free_pos = -1;
+	for (;;)
+	{
+		new_free_pos = GetFreeCopyBlock(pcshared_info);
+		if (new_free_pos != -1)	/* We have got one block, break now. */
+			break;
+
+		COPY_WAIT_TO_PROCESS()
+	}
+
+	return new_free_pos;
+}
+
 /*
  * LookupParallelCopyFnPtr - Look up parallel copy function pointer.
  */
@@ -1270,6 +1864,146 @@ LookupParallelCopyFnStr(copy_data_source_cb fn_addr)
 	/* We can only reach this by programming error. */
 	elog(ERROR, "internal function pointer not found");
 }
+
+/*
+ * SetRawBufForLoad - Set raw_buf to the shared memory where the file data must
+ * be read.
+ */
+static void
+SetRawBufForLoad(CopyState cstate, uint32 line_size, uint32 copy_buf_len,
+				 uint32 raw_buf_ptr, char **copy_raw_buf)
+{
+	ParallelCopyShmInfo	*pcshared_info;
+	uint32 cur_block_pos;
+	uint32 next_block_pos;
+	ParallelCopyDataBlock	*cur_data_blk_ptr = NULL;
+	ParallelCopyDataBlock	*next_data_blk_ptr = NULL;
+
+	if (!IsParallelCopy())
+		return;
+
+	pcshared_info = cstate->pcdata->pcshared_info;
+	cur_block_pos = pcshared_info->cur_block_pos;
+	cur_data_blk_ptr = (cstate->raw_buf) ? &pcshared_info->data_blocks[cur_block_pos] : NULL;
+	next_block_pos = WaitGetFreeCopyBlock(pcshared_info);
+	next_data_blk_ptr = &pcshared_info->data_blocks[next_block_pos];
+
+	/* set raw_buf to the data block in shared memory */
+	cstate->raw_buf = next_data_blk_ptr->data;
+	*copy_raw_buf = cstate->raw_buf;
+	if (cur_data_blk_ptr && line_size)
+	{
+		/*
+		 * Mark the previous block as completed, worker can start copying this
+		 * data.
+		 */
+		cur_data_blk_ptr->following_block = next_block_pos;
+		pg_atomic_add_fetch_u32(&cur_data_blk_ptr->unprocessed_line_parts, 1);
+		cur_data_blk_ptr->skip_bytes = copy_buf_len - raw_buf_ptr;
+		cur_data_blk_ptr->curr_blk_completed = true;
+	}
+}
+
+/*
+ * EndLineParallelCopy - Update the line information in shared memory.
+ */
+static void
+EndLineParallelCopy(CopyState cstate, uint32 line_pos, uint32 line_size,
+					 uint32 raw_buf_ptr)
+{
+	uint8 new_line_size;
+	if (!IsParallelCopy())
+		return;
+
+	if (!IsHeaderLine())
+	{
+		ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+		ParallelCopyLineBoundaries *lineBoundaryPtr = &pcshared_info->line_boundaries;
+		SET_NEWLINE_SIZE()
+		if (line_size)
+		{
+			ParallelCopyLineBoundary *lineInfo = &lineBoundaryPtr->ring[line_pos];
+			/*
+			 * If the new_line_size > raw_buf_ptr, then the new block has only
+			 * new line char content. The unprocessed count should not be
+			 * increased in this case.
+			 */
+			if (raw_buf_ptr > new_line_size)
+			{
+				uint32 cur_block_pos = pcshared_info->cur_block_pos;
+				ParallelCopyDataBlock *curr_data_blk_ptr = &pcshared_info->data_blocks[cur_block_pos];
+				pg_atomic_add_fetch_u32(&curr_data_blk_ptr->unprocessed_line_parts, 1);
+			}
+
+			/* Update line size. */
+			pg_atomic_write_u32(&lineInfo->line_size, line_size);
+			pg_atomic_write_u32(&lineInfo->line_state, LINE_LEADER_POPULATED);
+			elog(DEBUG1, "[Leader] After adding - line position:%d, line_size:%d",
+						 line_pos, line_size);
+			pcshared_info->populated++;
+		}
+		else if (new_line_size)
+		{
+			/* This means only new line char, empty record should be inserted.*/
+			ParallelCopyLineBoundary *lineInfo;
+			line_pos = UpdateBlockInLineInfo(cstate, -1, -1, 0,
+											   LINE_LEADER_POPULATED);
+			lineInfo = &lineBoundaryPtr->ring[line_pos];
+			elog(DEBUG1, "[Leader] Added empty line with offset:%d, line position:%d, line size:%d",
+						 lineInfo->start_offset, line_pos,
+						 pg_atomic_read_u32(&lineInfo->line_size));
+			pcshared_info->populated++;
+		}
+	}
+}
+
+/*
+ * ExecBeforeStmtTrigger - Execute the before statement trigger, this will be
+ * executed for parallel copy by the leader process.
+ */
+static void
+ExecBeforeStmtTrigger(CopyState cstate)
+{
+	EState	   *estate = CreateExecutorState();
+	ResultRelInfo *resultRelInfo;
+
+	Assert(IsLeader());
+
+	/*
+	 * We need a ResultRelInfo so we can use the regular executor's
+	 * index-entry-making machinery.  (There used to be a huge amount of code
+	 * here that basically duplicated execUtils.c ...)
+	 */
+	resultRelInfo = makeNode(ResultRelInfo);
+	InitResultRelInfo(resultRelInfo,
+					  cstate->rel,
+					  1,		/* must match rel's position in range_table */
+					  NULL,
+					  0);
+
+	/* Verify the named relation is a valid target for INSERT */
+	CheckValidResultRel(resultRelInfo, CMD_INSERT);
+
+	estate->es_result_relations = resultRelInfo;
+	estate->es_num_result_relations = 1;
+	estate->es_result_relation_info = resultRelInfo;
+
+	ExecInitRangeTable(estate, cstate->range_table);
+
+	/*
+	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
+	 * should do this for COPY, since it's not really an "INSERT" statement as
+	 * such. However, executing these triggers maintains consistency with the
+	 * EACH ROW triggers that we already fire on COPY.
+	 */
+	ExecBSInsertTriggers(estate, resultRelInfo);
+
+	/* Close any trigger target relations */
+	ExecCleanUpTriggerState(estate);
+
+	FreeExecutorState(estate);
+}
+
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
  * in past protocol redesigns.
@@ -3673,7 +4407,8 @@ CopyFrom(CopyState cstate)
 
 	PartitionTupleRouting *proute = NULL;
 	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
+	CommandId	mycid = IsParallelCopy() ? cstate->pcdata->pcshared_info->mycid :
+										   GetCurrentCommandId(true);
 	int			ti_options = 0; /* start with default options for insert */
 	BulkInsertState bistate = NULL;
 	CopyInsertMethod insertMethod;
@@ -3683,7 +4418,14 @@ CopyFrom(CopyState cstate)
 	bool		has_instead_insert_row_trig;
 	bool		leafpart_use_multi_insert = false;
 
-	CheckCopyFromValidity(cstate);
+	/*
+	 * Perform this check if it is not parallel copy. In case of parallel
+	 * copy, this check is done by the leader, so that if any invalid case
+	 * exist the copy from command will error out from the leader itself,
+	 * avoiding launching workers, just to throw error.
+	 */
+	if (!IsParallelCopy())
+		CheckCopyFromValidity(cstate);
 
 	/*
 	 * If the target file is new-in-transaction, we assume that checking FSM
@@ -3872,13 +4614,16 @@ CopyFrom(CopyState cstate)
 	has_instead_insert_row_trig = (resultRelInfo->ri_TrigDesc &&
 								   resultRelInfo->ri_TrigDesc->trig_insert_instead_row);
 
-	/*
-	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
-	 * should do this for COPY, since it's not really an "INSERT" statement as
-	 * such. However, executing these triggers maintains consistency with the
-	 * EACH ROW triggers that we already fire on COPY.
-	 */
-	ExecBSInsertTriggers(estate, resultRelInfo);
+	if (!IsParallelCopy())
+	{
+		/*
+		 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
+		 * should do this for COPY, since it's not really an "INSERT" statement as
+		 * such. However, executing these triggers maintains consistency with the
+		 * EACH ROW triggers that we already fire on COPY.
+		 */
+		ExecBSInsertTriggers(estate, resultRelInfo);
+	}
 
 	econtext = GetPerTupleExprContext(estate);
 
@@ -3978,6 +4723,16 @@ CopyFrom(CopyState cstate)
 					!has_instead_insert_row_trig &&
 					resultRelInfo->ri_FdwRoutine == NULL;
 
+				/*
+				 * If the table has any partitions that are either foreign or
+				 * has BEFORE/INSTEAD OF triggers, we can't perform copy
+				 * operations with parallel workers.
+				 */
+				if (!leafpart_use_multi_insert && IsParallelWorker())
+					ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							errmsg("cannot perform PARALLEL COPY if partition has BEFORE/INSTEAD OF triggers, or if the partition is foreign partition"),
+							errhint("Try COPY without PARALLEL option")));
+
 				/* Set the multi-insert buffer to use for this partition. */
 				if (leafpart_use_multi_insert)
 				{
@@ -4392,7 +5147,7 @@ BeginCopyFrom(ParseState *pstate,
 	initStringInfo(&cstate->attribute_buf);
 	initStringInfo(&cstate->line_buf);
 	cstate->line_buf_converted = false;
-	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+	cstate->raw_buf = (IsParallelCopy()) ? NULL : (char *) palloc(RAW_BUF_SIZE + 1);
 	cstate->raw_buf_index = cstate->raw_buf_len = 0;
 
 	/* Assign range table, we'll need it in CopyFrom. */
@@ -4536,26 +5291,35 @@ NextCopyFromRawFields(CopyState cstate, char ***fields, int *nfields)
 	/* only available for text or csv input */
 	Assert(!cstate->binary);
 
-	/* on input just throw the header line away */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (IsParallelCopy())
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
-			return false;		/* done */
+		done = GetWorkerLine(cstate);
+		if (done && cstate->line_buf.len == 0)
+			return false;
 	}
+	else
+	{
+		/* on input just throw the header line away */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
+		{
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+				return false;		/* done */
+		}
 
-	cstate->cur_lineno++;
+		cstate->cur_lineno++;
 
-	/* Actually read the line into memory here */
-	done = CopyReadLine(cstate);
+		/* Actually read the line into memory here */
+		done = CopyReadLine(cstate);
 
-	/*
-	 * EOF at start of line means we're done.  If we see EOF after some
-	 * characters, we act as though it was newline followed by EOF, ie,
-	 * process the line and then exit loop on next iteration.
-	 */
-	if (done && cstate->line_buf.len == 0)
-		return false;
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			return false;
+	}
 
 	/* Parse the line into de-escaped field values */
 	if (cstate->csv_mode)
@@ -4805,9 +5569,31 @@ CopyReadLine(CopyState cstate)
 		 */
 		if (cstate->copy_dest == COPY_NEW_FE)
 		{
+			bool bIsFirst = true;
 			do
 			{
-				cstate->raw_buf_index = cstate->raw_buf_len;
+				if (!IsParallelCopy())
+					cstate->raw_buf_index = cstate->raw_buf_len;
+				else
+				{
+					if (cstate->raw_buf_index == RAW_BUF_SIZE)
+					{
+						/* Get a new block if it is the first time, From the
+						 * subsequent time, reset the index and re-use the same
+						 * block.
+						 */
+						if (bIsFirst)
+						{
+							ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+							uint32 block_pos = WaitGetFreeCopyBlock(pcshared_info);
+							cstate->raw_buf = pcshared_info->data_blocks[block_pos].data;
+							bIsFirst = false;
+						}
+
+						cstate->raw_buf_index = cstate->raw_buf_len = 0;
+					}
+				}
+
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
@@ -4837,6 +5623,11 @@ CopyReadLineText(CopyState cstate)
 	char		quotec = '\0';
 	char		escapec = '\0';
 
+	/* For parallel copy */
+	uint32			 line_size = 0;
+	int				 line_pos = 0;
+
+	cstate->eol_type = EOL_UNKNOWN;
 	if (cstate->csv_mode)
 	{
 		quotec = cstate->quote[0];
@@ -4891,6 +5682,8 @@ CopyReadLineText(CopyState cstate)
 		if (raw_buf_ptr >= copy_buf_len || need_data)
 		{
 			REFILL_LINEBUF;
+			SetRawBufForLoad(cstate, line_size, copy_buf_len, raw_buf_ptr,
+							 &copy_raw_buf);
 
 			/*
 			 * Try to read some more data.  This will certainly reset
@@ -5115,9 +5908,15 @@ CopyReadLineText(CopyState cstate)
 				 * discard the data and the \. sequence.
 				 */
 				if (prev_raw_ptr > cstate->raw_buf_index)
-					appendBinaryStringInfo(&cstate->line_buf,
+				{
+					if (!IsParallelCopy())
+						appendBinaryStringInfo(&cstate->line_buf,
 										   cstate->raw_buf + cstate->raw_buf_index,
 										   prev_raw_ptr - cstate->raw_buf_index);
+					else
+						line_size += prev_raw_ptr - cstate->raw_buf_index;
+				}
+
 				cstate->raw_buf_index = raw_buf_ptr;
 				result = true;	/* report EOF */
 				break;
@@ -5169,6 +5968,26 @@ not_end_of_copy:
 			IF_NEED_REFILL_AND_EOF_BREAK(mblen - 1);
 			raw_buf_ptr += mblen - 1;
 		}
+
+		/*
+		 * Skip the header line. Update the line here, this cannot be done at
+		 * the beginning, as there is a possibility that file contains empty
+		 * lines.
+		 */
+		if (IsParallelCopy() && first_char_in_line && !IsHeaderLine())
+		{
+			ParallelCopyShmInfo	*pcshared_info = cstate->pcdata->pcshared_info;
+			ParallelCopyLineBoundary *lineInfo;
+			uint32			 line_first_block = pcshared_info->cur_block_pos;
+			line_pos = UpdateBlockInLineInfo(cstate,
+											   line_first_block,
+											   cstate->raw_buf_index, -1,
+											   LINE_LEADER_POPULATING);
+			lineInfo = &pcshared_info->line_boundaries.ring[line_pos];
+			elog(DEBUG1, "[Leader] Adding - block:%d, offset:%d, line position:%d",
+						 line_first_block,	lineInfo->start_offset, line_pos);
+		}
+
 		first_char_in_line = false;
 	}							/* end of outer loop */
 
@@ -5177,6 +5996,7 @@ not_end_of_copy:
 	 */
 	REFILL_LINEBUF;
 	CLEAR_EOL_LINE()
+	EndLineParallelCopy(cstate, line_pos, line_size, raw_buf_ptr);
 
 	return result;
 }
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index 88025b1..f8bdcc3 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -381,6 +381,7 @@ extern FullTransactionId GetTopFullTransactionId(void);
 extern FullTransactionId GetTopFullTransactionIdIfAny(void);
 extern FullTransactionId GetCurrentFullTransactionId(void);
 extern FullTransactionId GetCurrentFullTransactionIdIfAny(void);
+extern void AssignFullTransactionIdForWorker(FullTransactionId fullTransactionId);
 extern void MarkCurrentTransactionIdLoggedIfAny(void);
 extern bool SubTransactionIsActive(SubTransactionId subxid);
 extern CommandId GetCurrentCommandId(bool used);
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 8a79794..86b5c62 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1700,6 +1700,7 @@ ParallelCompletionPtr
 ParallelContext
 ParallelCopyLineBoundaries
 ParallelCopyLineBoundary
+ParallelCopyLineState
 ParallelCopyCommonKeyData
 ParallelCopyData
 ParallelCopyDataBlock
-- 
1.8.3.1

0006-Parallel-Copy-For-Binary-Format-Files.patchtext/x-patch; charset=US-ASCII; name=0006-Parallel-Copy-For-Binary-Format-Files.patchDownload
From 770204d2eb526a975b832ddae63abaddf181cde5 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddy@enterprisedb.com>, Vignesh C <vignesh21@gmail.com>
Date: Wed, 17 Jun 2020 08:00:31 +0530
Subject: [PATCH 6/6] Parallel Copy For Binary Format Files

Leader reads data from the file into the DSM data blocks each of 64K size.
It also identifies each tuple data block id, start offset, end offset,
tuple size and updates this information in the ring data structure.
Workers parallely read the tuple information from the ring data structure,
the actual tuple data from the data blocks and parallely insert the tuples
into the table.
---
 src/backend/commands/copy.c | 669 +++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 600 insertions(+), 69 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index f19e991..093b836 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -243,6 +243,16 @@ typedef struct ParallelCopyData
 }ParallelCopyData;
 
 /*
+ * Tuple boundary information used for parallel copy
+ * for binary format files.
+ */
+typedef struct ParallelCopyTupleInfo
+{
+	uint32 offset;
+	uint32 block_id;
+}ParallelCopyTupleInfo;
+
+/*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
  * even though some fields are used in only some cases.
@@ -372,6 +382,16 @@ typedef struct CopyStateData
 	int			nworkers;
 	bool		is_parallel;
 	ParallelCopyData *pcdata;
+
+	/*
+	 * Parallel copy for binary formatted files
+	 */
+	ParallelCopyDataBlock *curr_data_block;
+	ParallelCopyDataBlock *prev_data_block;
+	uint32				   curr_data_offset;
+	uint32				   curr_block_pos;
+	ParallelCopyTupleInfo  curr_tuple_start_info;
+	ParallelCopyTupleInfo  curr_tuple_end_info;
 } CopyStateData;
 
 /*
@@ -397,6 +417,7 @@ typedef struct ParallelCopyCommonKeyData
 	/* Working state for COPY FROM */
 	AttrNumber          num_defaults;
 	Oid                 relid;
+	bool 				binary;
 }ParallelCopyCommonKeyData;
 
 /*
@@ -752,6 +773,14 @@ static void PopulateCatalogInformation(CopyState cstate);
 static pg_attribute_always_inline uint32 GetLinePosition(CopyState cstate);
 static pg_attribute_always_inline copy_data_source_cb LookupParallelCopyFnPtr(const char *funcname);
 static pg_attribute_always_inline char* LookupParallelCopyFnStr(copy_data_source_cb fn_addr);
+static uint32 WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info);
+static pg_attribute_always_inline bool CopyReadBinaryTupleLeader(CopyState cstate);
+static pg_attribute_always_inline void CopyReadBinaryAttributeLeader(CopyState cstate,
+										FmgrInfo *flinfo, Oid typioparam, int32 typmod,
+										uint32 *new_block_pos);
+static pg_attribute_always_inline bool CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls);
+static pg_attribute_always_inline Datum CopyReadBinaryAttributeWorker(CopyState cstate, int column_no,
+										 FmgrInfo *flinfo, Oid typioparam, int32 typmod, bool *isnull);
 
 /*
  * CopyCommonInfoForWorker - Copy shared_cstate using cstate information.
@@ -770,6 +799,7 @@ CopyCommonInfoForWorker(CopyState cstate, ParallelCopyCommonKeyData *shared_csta
 	shared_cstate->convert_selectively = cstate->convert_selectively;
 	shared_cstate->num_defaults = cstate->num_defaults;
 	shared_cstate->relid = cstate->pcdata->relid;
+	shared_cstate->binary = cstate->binary;
 }
 
 /*
@@ -998,8 +1028,8 @@ FindInsertMethod(CopyState cstate)
 static pg_attribute_always_inline bool
 IsParallelCopyAllowed(CopyState cstate)
 {
-	/* Parallel copy not allowed for frontend (2.0 protocol) & binary option. */
-	if ((cstate->copy_dest == COPY_OLD_FE) || cstate->binary)
+	/* Parallel copy not allowed for frontend (2.0 protocol). */
+	if (cstate->copy_dest == COPY_OLD_FE)
 		return false;
 
 	/* Check if copy is into foreign table or temporary table. */
@@ -1300,6 +1330,7 @@ ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
 	cstate->convert_selectively = shared_cstate->convert_selectively;
 	cstate->num_defaults = shared_cstate->num_defaults;
 	pcdata->relid = shared_cstate->relid;
+	cstate->binary = shared_cstate->binary;
 
 	PopulateAttributes(cstate, tup_desc, attnamelist);
 
@@ -1315,7 +1346,7 @@ ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
 	initStringInfo(&cstate->attribute_buf);
 
 	initStringInfo(&cstate->line_buf);
-	for (count = 0; count < WORKER_CHUNK_COUNT;count++)
+	for (count = 0; count < WORKER_CHUNK_COUNT; count++)
 		initStringInfo(&pcdata->worker_line_buf[count].line_buf);
 
 	cstate->line_buf_converted = false;
@@ -1332,6 +1363,15 @@ ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
 		cstate->max_fields = attr_count;
 		cstate->raw_fields = (char **)palloc(attr_count * sizeof(char *));
 	}
+
+	cstate->curr_data_block = NULL;
+	cstate->prev_data_block = NULL;
+	cstate->curr_data_offset = 0;
+	cstate->curr_block_pos = 0;
+	cstate->curr_tuple_start_info.block_id = -1;
+	cstate->curr_tuple_start_info.offset = -1;
+	cstate->curr_tuple_end_info.block_id = -1;
+	cstate->curr_tuple_end_info.offset = -1;
 }
 
 /*
@@ -1680,32 +1720,59 @@ ParallelCopyLeader(CopyState cstate)
 	/* Execute the before statement triggers from the leader */
 	ExecBeforeStmtTrigger(cstate);
 
-	/* On input just throw the header line away. */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (!cstate->binary)
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
+		/* On input just throw the header line away. */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
 		{
-			pcshared_info->is_read_in_progress = false;
-			return;			/* done */
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+			{
+				pcshared_info->is_read_in_progress = false;
+				return;			/* done */
+			}
 		}
-	}
 
-	for (;;)
+		for (;;)
+		{
+			bool done;
+			cstate->cur_lineno++;
+
+			/* Actually read the line into memory here. */
+			done = CopyReadLine(cstate);
+
+			/*
+			* EOF at start of line means we're done.  If we see EOF after some
+			* characters, we act as though it was newline followed by EOF, ie,
+			* process the line and then exit loop on next iteration.
+			*/
+			if (done && cstate->line_buf.len == 0)
+				break;
+		}
+	}
+	else
 	{
-		bool done;
-		cstate->cur_lineno++;
+		cstate->curr_data_block = NULL;
+		cstate->prev_data_block = NULL;
+		cstate->curr_data_offset = 0;
+		cstate->curr_block_pos = 0;
+		cstate->curr_tuple_start_info.block_id = -1;
+		cstate->curr_tuple_start_info.offset = -1;
+		cstate->curr_tuple_end_info.block_id = -1;
+		cstate->curr_tuple_end_info.offset = -1;
+		pcshared_info->populated = 0;
+		cstate->cur_lineno = 0;
 
-		/* Actually read the line into memory here. */
-		done = CopyReadLine(cstate);
+		for (;;)
+		{
+			bool eof = false;
+			cstate->cur_lineno++;
 
-		/*
-		 * EOF at start of line means we're done.  If we see EOF after some
-		 * characters, we act as though it was newline followed by EOF, ie,
-		 * process the line and then exit loop on next iteration.
-		 */
-		if (done && cstate->line_buf.len == 0)
-			break;
+			eof = CopyReadBinaryTupleLeader(cstate);
+
+			if (eof)
+				break;
+		}
 	}
 
 	pcshared_info->is_read_in_progress = false;
@@ -1713,6 +1780,456 @@ ParallelCopyLeader(CopyState cstate)
 }
 
 /*
+ * CopyReadBinaryTupleLeader - leader reads data from binary formatted file
+ * to data blocks and identies tuple boundaries/offsets so that workers
+ * can work on the data blocks data.
+ */
+static pg_attribute_always_inline bool
+CopyReadBinaryTupleLeader(CopyState cstate)
+{
+	int readbytes = 0;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	uint32 block_pos;
+	int16		fld_count;
+	AttrNumber	attr_count = list_length(cstate->attnumlist);
+	ListCell   *cur;
+	FmgrInfo   *in_functions = cstate->in_functions;
+	Oid		   *typioparams = cstate->typioparams;
+	TupleDesc	tupDesc = RelationGetDescr(cstate->rel);
+	uint32      new_block_pos;
+	uint32      line_size;
+
+	if (cstate->curr_data_block == NULL)
+	{
+		block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+		cstate->curr_block_pos = block_pos;
+
+		cstate->curr_data_block = &pcshared_info->data_blocks[block_pos];
+
+		cstate->curr_data_offset = 0;
+
+		readbytes = CopyGetData(cstate, &cstate->curr_data_block->data, 1, DATA_BLOCK_SIZE);
+
+		elog(DEBUG1, "LEADER - bytes read from file %d", readbytes);
+
+		if (cstate->reached_eof)
+			return true;
+	}
+
+	if (cstate->curr_data_offset + sizeof(fld_count) >= (DATA_BLOCK_SIZE - 1))
+	{
+		ParallelCopyDataBlock *data_block = NULL;
+		uint8 movebytes = 0;
+
+		block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+		movebytes = DATA_BLOCK_SIZE - cstate->curr_data_offset;
+
+		cstate->curr_data_block->skip_bytes = movebytes;
+
+		data_block = &pcshared_info->data_blocks[block_pos];
+
+		if (movebytes > 0)
+			memmove(&data_block->data[0], &cstate->curr_data_block->data[cstate->curr_data_offset],
+			 movebytes);
+
+		elog(DEBUG1, "LEADER - field count is spread across data blocks - moved %d bytes from current block %u to %u block",
+			movebytes, cstate->curr_block_pos, block_pos);
+
+		readbytes = CopyGetData(cstate, &data_block->data[movebytes], 1, (DATA_BLOCK_SIZE - movebytes));
+
+		elog(DEBUG1, "LEADER - bytes read from file after field count is moved to next data block %d", readbytes);
+
+		if (cstate->reached_eof)
+			ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("unexpected EOF in COPY data")));
+
+		cstate->curr_data_block = data_block;
+		cstate->curr_data_offset = 0;
+		cstate->curr_block_pos = block_pos;
+	}
+
+	memcpy(&fld_count, &cstate->curr_data_block->data[cstate->curr_data_offset], sizeof(fld_count));
+
+	fld_count = (int16) pg_ntoh16(fld_count);
+
+	if (fld_count == -1)
+	{
+		/*
+			* Received EOF marker.  In a V3-protocol copy, wait for the
+			* protocol-level EOF, and complain if it doesn't come
+			* immediately.  This ensures that we correctly handle CopyFail,
+			* if client chooses to send that now.
+			*
+			* Note that we MUST NOT try to read more data in an old-protocol
+			* copy, since there is no protocol-level EOF marker then.  We
+			* could go either way for copy from file, but choose to throw
+			* error if there's data after the EOF marker, for consistency
+			* with the new-protocol case.
+			*/
+		char		dummy;
+
+		if (cstate->copy_dest != COPY_OLD_FE &&
+			CopyGetData(cstate, &dummy, 1, 1) > 0)
+			ereport(ERROR,
+					(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+						errmsg("received copy data after EOF marker")));
+		return true;
+	}
+
+	if (fld_count != attr_count)
+		ereport(ERROR,
+			(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+			errmsg("row field count is %d, expected %d",
+			(int) fld_count, attr_count)));
+
+	cstate->curr_tuple_start_info.block_id = cstate->curr_block_pos;
+	cstate->curr_tuple_start_info.offset =  cstate->curr_data_offset;
+	cstate->curr_data_offset = cstate->curr_data_offset + sizeof(fld_count);
+	new_block_pos = cstate->curr_block_pos;
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			attnum = lfirst_int(cur);
+		int			m = attnum - 1;
+		Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+
+		CopyReadBinaryAttributeLeader(cstate,
+									&in_functions[m],
+									typioparams[m],
+									att->atttypmod,
+									&new_block_pos);
+	}
+
+	cstate->curr_tuple_end_info.block_id = new_block_pos;
+	cstate->curr_tuple_end_info.offset =  cstate->curr_data_offset-1;;
+
+	if (cstate->curr_tuple_start_info.block_id == cstate->curr_tuple_end_info.block_id)
+	{
+		elog(DEBUG1,"LEADER - tuple lies in a single data block");
+
+		line_size = cstate->curr_tuple_end_info.offset - cstate->curr_tuple_start_info.offset + 1;
+		pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[cstate->curr_tuple_start_info.block_id].unprocessed_line_parts, 1);
+	}
+	else
+	{
+		uint32 following_block_id = pcshared_info->data_blocks[cstate->curr_tuple_start_info.block_id].following_block;
+
+		elog(DEBUG1,"LEADER - tuple is spread across data blocks");
+
+		line_size = DATA_BLOCK_SIZE - cstate->curr_tuple_start_info.offset -
+			pcshared_info->data_blocks[cstate->curr_tuple_start_info.block_id].skip_bytes;
+
+		pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[cstate->curr_tuple_start_info.block_id].unprocessed_line_parts, 1);
+
+		while (following_block_id != cstate->curr_tuple_end_info.block_id)
+		{
+			line_size = line_size + DATA_BLOCK_SIZE - pcshared_info->data_blocks[following_block_id].skip_bytes;
+
+			pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[following_block_id].unprocessed_line_parts, 1);
+
+			following_block_id = pcshared_info->data_blocks[following_block_id].following_block;
+
+			if (following_block_id == -1)
+				break;
+		}
+
+		if (following_block_id != -1)
+			pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[following_block_id].unprocessed_line_parts, 1);
+
+		line_size = line_size + cstate->curr_tuple_end_info.offset + 1;
+	}
+
+	if (line_size > 0)
+	{
+		int line_pos = UpdateBlockInLineInfo(cstate,
+											cstate->curr_tuple_start_info.block_id,
+											cstate->curr_tuple_start_info.offset,
+											line_size,
+											LINE_LEADER_POPULATED);
+
+		pcshared_info->populated++;
+
+		elog(DEBUG1, "LEADER - adding - block:%u, offset:%u, line size:%u line position:%d",
+						 cstate->curr_tuple_start_info.block_id,
+						 cstate->curr_tuple_start_info.offset,
+						 line_size, line_pos);
+	}
+
+	cstate->curr_tuple_start_info.block_id = -1;
+	cstate->curr_tuple_start_info.offset = -1;
+	cstate->curr_tuple_end_info.block_id = -1;
+	cstate->curr_tuple_end_info.offset = -1;
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryAttributeLeader - leader identifies boundaries/offsets
+ * for each attribute/column, it moves on to next data block if the
+ * attribute/column is spread across data blocks.
+ */
+static pg_attribute_always_inline void
+CopyReadBinaryAttributeLeader(CopyState cstate, FmgrInfo *flinfo,
+	Oid typioparam, int32 typmod, uint32 *new_block_pos)
+{
+	int32		fld_size;
+	int readbytes;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	uint32 block_pos;
+
+	if ((cstate->curr_data_offset + sizeof(fld_size)) >= (DATA_BLOCK_SIZE - 1))
+	{
+		ParallelCopyDataBlock *data_block = NULL;
+		uint8 movebytes = DATA_BLOCK_SIZE - cstate->curr_data_offset;
+
+		block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+		cstate->curr_data_block->skip_bytes = movebytes;
+
+		data_block = &pcshared_info->data_blocks[block_pos];
+
+		if (movebytes > 0)
+			memmove(&data_block->data[0], &cstate->curr_data_block->data[cstate->curr_data_offset], movebytes);
+
+		elog(DEBUG1, "LEADER - field size is spread across data blocks - moved %d bytes from current block %u to %u block",
+			movebytes, cstate->curr_block_pos, block_pos);
+
+		readbytes = CopyGetData(cstate, &data_block->data[movebytes], 1, DATA_BLOCK_SIZE-movebytes);
+
+		elog(DEBUG1, "LEADER - bytes read from file after field size is moved to next data block %d", readbytes);
+
+		if (cstate->reached_eof)
+			ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("unexpected EOF in COPY data")));
+
+		cstate->prev_data_block = cstate->curr_data_block;
+		cstate->prev_data_block->following_block = block_pos;
+		cstate->curr_data_block = data_block;
+		cstate->curr_block_pos = block_pos;
+
+		if (cstate->prev_data_block->curr_blk_completed  == false)
+			cstate->prev_data_block->curr_blk_completed = true;
+
+		cstate->curr_data_offset = 0;
+		*new_block_pos = block_pos;
+	}
+
+	memcpy(&fld_size, &cstate->curr_data_block->data[cstate->curr_data_offset], sizeof(fld_size));
+
+	cstate->curr_data_offset = cstate->curr_data_offset + sizeof(fld_size);
+
+	fld_size = (int32) pg_ntoh32(fld_size);
+
+	if (fld_size == 0)
+		ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("unexpected EOF in COPY data")));
+
+	if (fld_size < -1)
+		ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("invalid field size")));
+
+	if ((DATA_BLOCK_SIZE-cstate->curr_data_offset) >= fld_size)
+	{
+		cstate->curr_data_offset = cstate->curr_data_offset + fld_size;
+	}
+	else
+	{
+		ParallelCopyDataBlock *data_block = NULL;
+
+		block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+		data_block = &pcshared_info->data_blocks[block_pos];
+
+		readbytes = CopyGetData(cstate, &data_block->data[0], 1, DATA_BLOCK_SIZE);
+
+		elog(DEBUG1, "LEADER - bytes read from file after detecting that tuple is spread across data blocks %d", readbytes);
+
+		if (cstate->reached_eof)
+			ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("unexpected EOF in COPY data")));
+
+
+		cstate->prev_data_block = cstate->curr_data_block;
+		cstate->prev_data_block->following_block = block_pos;
+
+		if (cstate->prev_data_block->curr_blk_completed  == false)
+			cstate->prev_data_block->curr_blk_completed = true;
+
+		cstate->curr_data_block = data_block;
+		cstate->curr_data_offset = fld_size - (DATA_BLOCK_SIZE - cstate->curr_data_offset);
+		cstate->curr_block_pos = block_pos;
+		*new_block_pos = block_pos;
+	}
+}
+
+/*
+ * CopyReadBinaryTupleWorker - each worker reads data from data blocks after
+ * getting leader-identified tuple offsets from ring data structure.
+ */
+static pg_attribute_always_inline bool
+CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls)
+{
+	uint32 line_pos;
+	ParallelCopyLineBoundary *line_info;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	int16		fld_count;
+	AttrNumber	attr_count = list_length(cstate->attnumlist);
+	ListCell   *cur;
+	FmgrInfo   *in_functions = cstate->in_functions;
+	Oid		   *typioparams = cstate->typioparams;
+	TupleDesc	tupDesc = RelationGetDescr(cstate->rel);
+	int			i;
+
+	line_pos = GetLinePosition(cstate);
+
+	if (line_pos == -1)
+		return true;
+
+	line_info = &pcshared_info->line_boundaries.ring[line_pos];
+	cstate->curr_data_block = &pcshared_info->data_blocks[line_info->first_block];
+	cstate->curr_data_offset = line_info->start_offset;
+
+	if (cstate->curr_data_offset + sizeof(fld_count) >= (DATA_BLOCK_SIZE - 1))
+	{
+		/*the case where field count spread across datablocks should never occur.
+		  as the leader would have moved it to next block*/
+		elog(DEBUG1, "WORKER - field count spread across datablocks should never occur");
+	}
+
+	memcpy(&fld_count, &cstate->curr_data_block->data[cstate->curr_data_offset], sizeof(fld_count));
+	fld_count = (int16) pg_ntoh16(fld_count);
+
+	if (fld_count == -1)
+	{
+		return true;
+	}
+
+	if (fld_count != attr_count)
+		ereport(ERROR,
+			(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+			errmsg("row field count is %d, expected %d",
+			(int) fld_count, attr_count)));
+
+	cstate->curr_data_offset = cstate->curr_data_offset + sizeof(fld_count);
+	i = 0;
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			attnum = lfirst_int(cur);
+		int			m = attnum - 1;
+		Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+		cstate->cur_attname = NameStr(att->attname);
+
+		i++;
+		values[m] = CopyReadBinaryAttributeWorker(cstate,
+											i,
+											&in_functions[m],
+											typioparams[m],
+											att->atttypmod,
+											&nulls[m]);
+		cstate->cur_attname = NULL;
+	}
+
+	pg_atomic_sub_fetch_u32(&cstate->curr_data_block->unprocessed_line_parts, 1);
+	line_info->start_offset = -1;
+	pg_atomic_write_u32(&line_info->line_state, LINE_WORKER_PROCESSED);
+	pg_atomic_write_u32(&line_info->line_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryAttributeWorker - leader identifies boundaries/offsets
+ * for each attribute/column, it moves on to next data block if the
+ * attribute/column is spread across data blocks.
+ */
+static pg_attribute_always_inline Datum
+CopyReadBinaryAttributeWorker(CopyState cstate, int column_no,
+		FmgrInfo *flinfo, Oid typioparam, int32 typmod, bool *isnull)
+{
+	int32		fld_size;
+	Datum		result;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+	if ((cstate->curr_data_offset + sizeof(fld_size)) >= (DATA_BLOCK_SIZE - 1))
+	{
+		ParallelCopyDataBlock *prev_data_block = cstate->curr_data_block;
+
+		elog(DEBUG1, "WORKER - field size is spread across data blocks");
+
+		cstate->curr_data_block = &pcshared_info->data_blocks[cstate->curr_data_block->following_block];
+		pg_atomic_sub_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+		cstate->curr_data_offset = 0;
+	}
+
+	memcpy(&fld_size, &cstate->curr_data_block->data[cstate->curr_data_offset], sizeof(fld_size));
+	fld_size = (int32) pg_ntoh32(fld_size);
+
+	if (fld_size == 0)
+		ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("unexpected EOF in COPY data")));
+
+	if (fld_size < -1)
+		ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("invalid field size")));
+
+	cstate->curr_data_offset = cstate->curr_data_offset + sizeof(fld_size);
+
+	/* reset attribute_buf to empty, and load raw data in it */
+	resetStringInfo(&cstate->attribute_buf);
+
+	enlargeStringInfo(&cstate->attribute_buf, fld_size);
+
+	if ((DATA_BLOCK_SIZE-cstate->curr_data_offset) >= fld_size)
+	{
+		elog(DEBUG1, "WORKER - tuple lies in single data block");
+
+		memcpy(&cstate->attribute_buf.data[0],&cstate->curr_data_block->data[cstate->curr_data_offset], fld_size);
+		cstate->curr_data_offset = cstate->curr_data_offset + fld_size;
+	}
+	else
+	{
+		ParallelCopyDataBlock *prev_data_block = cstate->curr_data_block;
+
+		elog(DEBUG1, "WORKER - tuple is spread across data blocks");
+
+		memcpy(&cstate->attribute_buf.data[0], &cstate->curr_data_block->data[cstate->curr_data_offset],
+				(DATA_BLOCK_SIZE - cstate->curr_data_offset));
+		cstate->curr_data_block = &pcshared_info->data_blocks[cstate->curr_data_block->following_block];
+		pg_atomic_sub_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+		memcpy(&cstate->attribute_buf.data[DATA_BLOCK_SIZE - cstate->curr_data_offset],
+			&cstate->curr_data_block->data[0], (fld_size - (DATA_BLOCK_SIZE - cstate->curr_data_offset)));
+		cstate->curr_data_offset = fld_size - (DATA_BLOCK_SIZE - cstate->curr_data_offset);
+	}
+
+	cstate->attribute_buf.len = fld_size;
+	cstate->attribute_buf.data[fld_size] = '\0';
+
+	/* Call the column type's binary input converter */
+	result = ReceiveFunctionCall(flinfo, &cstate->attribute_buf,
+								 typioparam, typmod);
+
+	/* Trouble if it didn't eat the whole buffer */
+	if (cstate->attribute_buf.cursor != cstate->attribute_buf.len)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+				 errmsg("incorrect binary data format")));
+
+	*isnull = false;
+	return result;
+}
+
+/*
  * GetLinePosition - return the line position that worker should process.
  */
 static uint32
@@ -5447,63 +5964,77 @@ NextCopyFrom(CopyState cstate, ExprContext *econtext,
 	else
 	{
 		/* binary */
-		int16		fld_count;
-		ListCell   *cur;
+		if (!IsParallelCopy())
+		{
+			int16		fld_count;
+			ListCell   *cur;
 
-		cstate->cur_lineno++;
+			cstate->cur_lineno++;
 
-		if (!CopyGetInt16(cstate, &fld_count))
-		{
-			/* EOF detected (end of file, or protocol-level EOF) */
-			return false;
-		}
+			if (!CopyGetInt16(cstate, &fld_count))
+			{
+				/* EOF detected (end of file, or protocol-level EOF) */
+				return false;
+			}
 
-		if (fld_count == -1)
-		{
-			/*
-			 * Received EOF marker.  In a V3-protocol copy, wait for the
-			 * protocol-level EOF, and complain if it doesn't come
-			 * immediately.  This ensures that we correctly handle CopyFail,
-			 * if client chooses to send that now.
-			 *
-			 * Note that we MUST NOT try to read more data in an old-protocol
-			 * copy, since there is no protocol-level EOF marker then.  We
-			 * could go either way for copy from file, but choose to throw
-			 * error if there's data after the EOF marker, for consistency
-			 * with the new-protocol case.
-			 */
-			char		dummy;
+			if (fld_count == -1)
+			{
+				/*
+				* Received EOF marker.  In a V3-protocol copy, wait for the
+				* protocol-level EOF, and complain if it doesn't come
+				* immediately.  This ensures that we correctly handle CopyFail,
+				* if client chooses to send that now.
+				*
+				* Note that we MUST NOT try to read more data in an old-protocol
+				* copy, since there is no protocol-level EOF marker then.  We
+				* could go either way for copy from file, but choose to throw
+				* error if there's data after the EOF marker, for consistency
+				* with the new-protocol case.
+				*/
+				char		dummy;
+
+				if (cstate->copy_dest != COPY_OLD_FE &&
+					CopyGetData(cstate, &dummy, 1, 1) > 0)
+					ereport(ERROR,
+							(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+							errmsg("received copy data after EOF marker")));
+				return false;
+			}
 
-			if (cstate->copy_dest != COPY_OLD_FE &&
-				CopyGetData(cstate, &dummy, 1, 1) > 0)
+			if (fld_count != attr_count)
 				ereport(ERROR,
 						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-						 errmsg("received copy data after EOF marker")));
-			return false;
+						errmsg("row field count is %d, expected %d",
+								(int) fld_count, attr_count)));
+
+			i = 0;
+			foreach(cur, cstate->attnumlist)
+			{
+				int			attnum = lfirst_int(cur);
+				int			m = attnum - 1;
+				Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+
+				cstate->cur_attname = NameStr(att->attname);
+				i++;
+				values[m] = CopyReadBinaryAttribute(cstate,
+													i,
+													&in_functions[m],
+													typioparams[m],
+													att->atttypmod,
+													&nulls[m]);
+				cstate->cur_attname = NULL;
+			}
 		}
+		else
+		{
+			bool eof = false;
 
-		if (fld_count != attr_count)
-			ereport(ERROR,
-					(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-					 errmsg("row field count is %d, expected %d",
-							(int) fld_count, attr_count)));
+			cstate->cur_lineno++;
 
-		i = 0;
-		foreach(cur, cstate->attnumlist)
-		{
-			int			attnum = lfirst_int(cur);
-			int			m = attnum - 1;
-			Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+			eof = CopyReadBinaryTupleWorker(cstate, values, nulls);
 
-			cstate->cur_attname = NameStr(att->attname);
-			i++;
-			values[m] = CopyReadBinaryAttribute(cstate,
-												i,
-												&in_functions[m],
-												typioparams[m],
-												att->atttypmod,
-												&nulls[m]);
-			cstate->cur_attname = NULL;
+			if (eof)
+				return false;
 		}
 	}
 
-- 
1.8.3.1

0005-Tests-for-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=0005-Tests-for-parallel-copy.patchDownload
From d06328623b7ecb051bfa23b2e54a439eed7f073f Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 17 Jun 2020 07:37:26 +0530
Subject: [PATCH 5/6] Tests for parallel copy.

This patch has the tests for parallel copy.
---
 src/test/regress/expected/copy2.out | 210 +++++++++++++++++++++++++++++++++++-
 src/test/regress/input/copy.source  |  12 +++
 src/test/regress/output/copy.source |  12 +++
 src/test/regress/sql/copy2.sql      | 208 ++++++++++++++++++++++++++++++++++-
 4 files changed, 434 insertions(+), 8 deletions(-)

diff --git a/src/test/regress/expected/copy2.out b/src/test/regress/expected/copy2.out
index e40287d..a088f72 100644
--- a/src/test/regress/expected/copy2.out
+++ b/src/test/regress/expected/copy2.out
@@ -254,18 +254,32 @@ It is "perfect".|
 "It is ""perfect"".","	"
 "",
 --test that we read consecutive LFs properly
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 COPY testnl FROM stdin CSV;
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL '2');
+SELECT * FROM testnl;
+ a |          b           | c 
+---+----------------------+---
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+(2 rows)
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 COPY testeoc FROM stdin CSV;
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL '2');
 COPY testeoc TO stdout CSV;
 a\.
 \.b
 c\.d
 "\."
 -- test handling of nonstandard null marker that violates escaping rules
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 COPY testnull TO stdout WITH NULL AS E'\\0';
 1	\\0
@@ -280,6 +294,15 @@ SELECT * FROM testnull;
     | 
 (4 rows)
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 2);
+SELECT * FROM testnull;
+ a  | b  
+----+----
+ 42 | \0
+    | 
+(2 rows)
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -349,6 +372,34 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 2);
+SELECT * FROM vistest;
+ a  
+----
+ a2
+ b
+(2 rows)
+
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 2);
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+COMMIT;
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 SELECT * FROM vistest;
  a 
@@ -409,7 +460,7 @@ SELECT * FROM vistest;
 (2 rows)
 
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -420,6 +471,8 @@ CREATE TEMP TABLE forcetest (
 -- should succeed with no effect ("b" remains an empty string, "c" remains NULL)
 BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 2);
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
  b |  c   
@@ -430,6 +483,8 @@ SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
 BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 2);
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
  c |  d   
@@ -486,6 +541,31 @@ select * from check_con_tbl;
    
 (2 rows)
 
+\d+ check_con_tbl
+                               Table "public.check_con_tbl"
+ Column |  Type   | Collation | Nullable | Default | Storage | Stats target | Description 
+--------+---------+-----------+----------+---------+---------+--------------+-------------
+ f1     | integer |           |          |         | plain   |              | 
+Check constraints:
+    "check_con_tbl_check" CHECK (check_con_function(check_con_tbl.*))
+
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 2);
+NOTICE:  input = {"f1":1}
+NOTICE:  input = {"f1":null}
+copy check_con_tbl from stdin with (parallel 2);
+NOTICE:  input = {"f1":0}
+ERROR:  new row for relation "check_con_tbl" violates check constraint "check_con_tbl_check"
+DETAIL:  Failing row contains (0).
+CONTEXT:  COPY check_con_tbl, line 1: "0"
+parallel worker
+select * from check_con_tbl;
+ f1 
+----
+  1
+   
+(2 rows)
+
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
 CREATE ROLE regress_rls_copy_user_colperms;
@@ -600,8 +680,130 @@ SELECT * FROM instead_of_insert_tbl;
 (2 rows)
 
 COMMIT;
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+COPY test_parallel_copy (a, b, c, d, e) from stdin with (PARALLEL '2');
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '2');
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '2');
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '2', FORMAT 'csv', HEADER);
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0');
+ERROR:  argument to option "parallel" must be a positive integer greater than zero
+LINE 1: COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0'...
+                                                        ^
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri from stdin with (FORMAT csv, DELIMITER ',', PARALLEL '2');
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', parallel '2') WHERE height > random() * 65;
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', parallel '2');
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- temporary table copy: should peform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+COPY temp_test (a) from stdin with (PARALLEL '2');
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) from stdin with (PARALLEL '2');
+ERROR:  column "xyz" of relation "test_parallel_copy" does not exist
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) from stdin with (PARALLEL '2');
+ERROR:  column "d" specified more than once
+-- missing data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL '2');
+ERROR:  invalid input syntax for type integer: ""
+CONTEXT:  COPY test_parallel_copy, line 0, column a: ""
+parallel worker
+COPY test_parallel_copy from stdin with (PARALLEL '2');
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2000	230	23	23"
+parallel worker
+COPY test_parallel_copy from stdin with (PARALLEL '2');
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2001	231	\N	\N"
+parallel worker
+-- extra data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL '2');
+ERROR:  extra data after last expected column
+CONTEXT:  COPY test_parallel_copy, line 1: "2002	232	40	50	60	70	80"
+parallel worker
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) from stdin with (delimiter ',', null 'x', PARALLEL '2') ;
+COPY test_parallel_copy from stdin WITH (DELIMITER ';', NULL '', PARALLEL '2');
+COPY test_parallel_copy from stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL '2');
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a = 50004;
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a > 60003;
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE f > 60003;
+ERROR:  column "f" does not exist
+LINE 1: ...arallel_copy from stdin WITH (PARALLEL '2') WHERE f > 60003;
+                                                             ^
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a = max(x.b);
+ERROR:  missing FROM-clause entry for table "x"
+LINE 1: ...llel_copy from stdin WITH (PARALLEL '2') WHERE a = max(x.b);
+                                                                  ^
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a IN (SELECT 1 FROM x);
+ERROR:  cannot use subquery in COPY FROM WHERE condition
+LINE 1: ...allel_copy from stdin WITH (PARALLEL '2') WHERE a IN (SELECT...
+                                                             ^
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a IN (generate_series(1,5));
+ERROR:  set-returning functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...l_copy from stdin WITH (PARALLEL '2') WHERE a IN (generate_s...
+                                                             ^
+COPY test_parallel_copy from stdin WITH(PARALLEL '2') WHERE a = row_number() over(b);
+ERROR:  window functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...llel_copy from stdin WITH(PARALLEL '2') WHERE a = row_number...
+                                                             ^
+-- check results of copy in
+SELECT * FROM test_parallel_copy;
+   a   | b  |     c      |    d    |    e    
+-------+----+------------+---------+---------
+     1 | 11 | test_c1    | test_d1 | test_e1
+     2 | 12 | test_c2    | test_d2 | test_e2
+       |  3 | stuff      | test_d3 | 
+       |  4 | stuff      | test_d4 | 
+       |  5 | stuff      | test_d5 | 
+       |    | 45         | 80      | 90
+       |    | x          | \x      | \x
+       |    | ,          | \,      | \
+  3000 |    | c          |         | 
+  4000 |    | C          |         | 
+  4001 |  1 | empty      |         | 
+  4002 |  2 | null       |         | 
+  4003 |  3 | Backslash  | \       | \
+  4004 |  4 | BackslashX | \X      | \X
+  4005 |  5 | N          | N       | N
+  4006 |  6 | BackslashN | \N      | \N
+  4007 |  7 | XX         | XX      | XX
+  4008 |  8 | Delimiter  | :       | :
+ 50004 | 25 | 35         | 45      | 55
+ 60004 | 25 | 35         | 45      | 55
+ 60005 | 26 | 36         | 46      | 56
+(21 rows)
+
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
 DROP TABLE x, y;
diff --git a/src/test/regress/input/copy.source b/src/test/regress/input/copy.source
index a1d529a..159c058 100644
--- a/src/test/regress/input/copy.source
+++ b/src/test/regress/input/copy.source
@@ -15,6 +15,13 @@ DELETE FROM onek;
 
 COPY onek FROM '@abs_builddir@/results/onek.data';
 
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+
+SELECT COUNT(*) FROM tenk1;
+
+TRUNCATE tenk1;
+
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
@@ -159,6 +166,11 @@ truncate parted_copytest;
 
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
 
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
+
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/output/copy.source b/src/test/regress/output/copy.source
index 938d355..c3003fe 100644
--- a/src/test/regress/output/copy.source
+++ b/src/test/regress/output/copy.source
@@ -9,6 +9,15 @@ COPY onek FROM '@abs_srcdir@/data/onek.data';
 COPY onek TO '@abs_builddir@/results/onek.data';
 DELETE FROM onek;
 COPY onek FROM '@abs_builddir@/results/onek.data';
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+SELECT COUNT(*) FROM tenk1;
+ count 
+-------
+ 10000
+(1 row)
+
+TRUNCATE tenk1;
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
 COPY person FROM '@abs_srcdir@/data/person.data';
@@ -113,6 +122,9 @@ insert into parted_copytest select x,1,'One' from generate_series(1011,1020) x;
 copy (select * from parted_copytest order by a) to '@abs_builddir@/results/parted_copytest.csv';
 truncate parted_copytest;
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/sql/copy2.sql b/src/test/regress/sql/copy2.sql
index 902f4fa..13104f4 100644
--- a/src/test/regress/sql/copy2.sql
+++ b/src/test/regress/sql/copy2.sql
@@ -157,7 +157,7 @@ COPY y TO stdout (FORMAT CSV, FORCE_QUOTE *);
 
 --test that we read consecutive LFs properly
 
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 
 COPY testnl FROM stdin CSV;
 1,"a field with two LFs
@@ -165,8 +165,16 @@ COPY testnl FROM stdin CSV;
 inside",2
 \.
 
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL '2');
+1,"a field with two LFs
+
+inside",2
+\.
+
+SELECT * FROM testnl;
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 
 COPY testeoc FROM stdin CSV;
 a\.
@@ -175,11 +183,19 @@ c\.d
 "\."
 \.
 
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL '2');
+a\.
+\.b
+c\.d
+"\."
+\.
+
 COPY testeoc TO stdout CSV;
 
 -- test handling of nonstandard null marker that violates escaping rules
 
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 
 COPY testnull TO stdout WITH NULL AS E'\\0';
@@ -191,6 +207,14 @@ COPY testnull FROM stdin WITH NULL AS E'\\0';
 
 SELECT * FROM testnull;
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 2);
+42	\\0
+\0	\0
+\.
+
+SELECT * FROM testnull;
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -235,6 +259,23 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 2);
+a2
+b
+\.
+SELECT * FROM vistest;
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 2);
+d2
+e
+\.
+SELECT * FROM vistest;
+COMMIT;
+SELECT * FROM vistest;
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 x
 y
@@ -284,7 +325,7 @@ SELECT * FROM vistest;
 COMMIT;
 SELECT * FROM vistest;
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -297,6 +338,10 @@ BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
 1,,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 2);
+1,,""
+\.
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
@@ -304,6 +349,10 @@ BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
 2,'a',,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 2);
+2,'a',,""
+\.
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
 -- should fail with not-null constraint violation
@@ -339,6 +388,16 @@ copy check_con_tbl from stdin;
 0
 \.
 select * from check_con_tbl;
+\d+ check_con_tbl
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 2);
+1
+\N
+\.
+copy check_con_tbl from stdin with (parallel 2);
+0
+\.
+select * from check_con_tbl;
 
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
@@ -440,8 +499,149 @@ test1
 SELECT * FROM instead_of_insert_tbl;
 COMMIT;
 
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+
+COPY test_parallel_copy (a, b, c, d, e) from stdin with (PARALLEL '2');
+1	11	test_c1	test_d1	test_e1
+2	12	test_c2	test_d2	test_e2
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '2');
+3	test_d3
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '2');
+4	test_d4
+5	test_d5
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '2', FORMAT 'csv', HEADER);
+b	d
+\.
+
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0');
+
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri from stdin with (FORMAT csv, DELIMITER ',', PARALLEL '2');
+10
+\.
+
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', parallel '2') WHERE height > random() * 65;
+60,60,60
+\.
+
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', parallel '2');
+60
+\.
+
+-- temporary table copy: should peform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+
+COPY temp_test (a) from stdin with (PARALLEL '2');
+10
+\.
+
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) from stdin with (PARALLEL '2');
+
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) from stdin with (PARALLEL '2');
+
+-- missing data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL '2');
+
+\.
+COPY test_parallel_copy from stdin with (PARALLEL '2');
+2000	230	23	23
+\.
+COPY test_parallel_copy from stdin with (PARALLEL '2');
+2001	231	\N	\N
+\.
+
+-- extra data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL '2');
+2002	232	40	50	60	70	80
+\.
+
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) from stdin with (delimiter ',', null 'x', PARALLEL '2') ;
+x,45,80,90
+x,\x,\\x,\\\x
+x,\,,\\\,,\\
+\.
+
+COPY test_parallel_copy from stdin WITH (DELIMITER ';', NULL '', PARALLEL '2');
+3000;;c;;
+\.
+
+COPY test_parallel_copy from stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL '2');
+4000:\X:C:\X:\X
+4001:1:empty::
+4002:2:null:\X:\X
+4003:3:Backslash:\\:\\
+4004:4:BackslashX:\\X:\\X
+4005:5:N:\N:\N
+4006:6:BackslashN:\\N:\\N
+4007:7:XX:\XX:\XX
+4008:8:Delimiter:\::\:
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a = 50004;
+50003	24	34	44	54
+50004	25	35	45 	55
+50005	26	36	46	56
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a > 60003;
+60001	22	32	42	52
+60002	23	33	43	53
+60003	24	34	44	54
+60004	25	35	45	55
+60005	26	36	46	56
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE f > 60003;
+
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a = max(x.b);
+
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a IN (SELECT 1 FROM x);
+
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a IN (generate_series(1,5));
+
+COPY test_parallel_copy from stdin WITH(PARALLEL '2') WHERE a = row_number() over(b);
+
+-- check results of copy in
+SELECT * FROM test_parallel_copy;
+
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
 DROP TABLE x, y;
-- 
1.8.3.1

0004-Documentation-for-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=0004-Documentation-for-parallel-copy.patchDownload
From 59fc88e4ce32d955e874d6ea83d1976e7b148b9e Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 17 Jun 2020 07:34:56 +0530
Subject: [PATCH 4/6] Documentation for parallel copy.

This patch has the documentation changes for parallel copy.
---
 doc/src/sgml/ref/copy.sgml | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/doc/src/sgml/ref/copy.sgml b/doc/src/sgml/ref/copy.sgml
index 18189ab..95d349d 100644
--- a/doc/src/sgml/ref/copy.sgml
+++ b/doc/src/sgml/ref/copy.sgml
@@ -37,6 +37,7 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
     DELIMITER '<replaceable class="parameter">delimiter_character</replaceable>'
     NULL '<replaceable class="parameter">null_string</replaceable>'
     HEADER [ <replaceable class="parameter">boolean</replaceable> ]
+    PARALLEL <replaceable class="parameter">integer</replaceable>
     QUOTE '<replaceable class="parameter">quote_character</replaceable>'
     ESCAPE '<replaceable class="parameter">escape_character</replaceable>'
     FORCE_QUOTE { ( <replaceable class="parameter">column_name</replaceable> [, ...] ) | * }
@@ -275,6 +276,21 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
    </varlistentry>
 
    <varlistentry>
+    <term><literal>PARALLEL</literal></term>
+    <listitem>
+     <para>
+      Perform <command>COPY FROM</command> in parallel using <replaceable
+      class="parameter"> integer</replaceable> background workers.  Please
+      note that it is not guaranteed that the number of parallel workers
+      specified in <replaceable class="parameter">integer</replaceable> will
+      be used during execution.  It is possible for a copy to run with fewer
+      workers than specified, or even with no workers at all.  This option is
+      allowed only in <command>COPY FROM</command>.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><literal>QUOTE</literal></term>
     <listitem>
      <para>
-- 
1.8.3.1

0001-Copy-code-readjustment-to-support-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=0001-Copy-code-readjustment-to-support-parallel-copy.patchDownload
From c7b9bb834716b1ba83f641dbb4932a592a9310fc Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 17 Jun 2020 07:13:53 +0530
Subject: [PATCH 1/6] Copy code readjustment to support parallel copy.

This patch has the copy code slightly readjusted so that the common code is
separated to functions/macros, these functions/macros will be used by the
workers in the parallel copy code of the upcoming patches. EOL removal is moved
from CopyReadLine to CopyReadLineText, this change was required because in case
of parallel copy the chunk identification and chunk updation is done in
CopyReadLineText, before chunk information is updated in shared memory the new
line characters should be removed.
---
 src/backend/commands/copy.c | 371 ++++++++++++++++++++++++++------------------
 1 file changed, 219 insertions(+), 152 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 6d53dc4..f2310ab 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -95,6 +95,9 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
+#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+#define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
+
 /*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
@@ -219,7 +222,6 @@ typedef struct CopyStateData
 	 * converts it.  Note: we guarantee that there is a \0 at
 	 * raw_buf[raw_buf_len].
 	 */
-#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
@@ -347,6 +349,88 @@ if (1) \
 	goto not_end_of_copy; \
 } else ((void) 0)
 
+/*
+ * CONVERT_TO_SERVER_ENCODING - convert contents to server encoding.
+ */
+#define CONVERT_TO_SERVER_ENCODING(cstate) \
+{ \
+	/* Done reading the line.  Convert it to server encoding. */ \
+	if (cstate->need_transcoding) \
+	{ \
+		char	   *cvt; \
+		cvt = pg_any_to_server(cstate->line_buf.data, \
+							   cstate->line_buf.len, \
+							   cstate->file_encoding); \
+		if (cvt != cstate->line_buf.data) \
+		{ \
+			/* transfer converted data back to line_buf */ \
+			resetStringInfo(&cstate->line_buf); \
+			appendBinaryStringInfo(&cstate->line_buf, cvt, strlen(cvt)); \
+			pfree(cvt); \
+		} \
+	} \
+	/* Now it's safe to use the buffer in error messages */ \
+	cstate->line_buf_converted = true; \
+}
+
+/*
+ * CLEAR_EOL_FROM_COPIED_DATA - Clear EOL from the copied data.
+ */
+#define CLEAR_EOL_FROM_COPIED_DATA(copy_line_data, copy_line_pos, copy_line_size) \
+{ \
+	/* \
+	 * If we didn't hit EOF, then we must have transferred the EOL marker \
+	 * to line_buf along with the data.  Get rid of it. \
+	 */ \
+   switch (cstate->eol_type) \
+   { \
+	   case EOL_NL: \
+		   Assert(copy_line_size >= 1); \
+		   Assert(copy_line_data[copy_line_pos - 1] == '\n'); \
+		   copy_line_data[copy_line_pos - 1] = '\0'; \
+		   copy_line_size--; \
+		   break; \
+	   case EOL_CR: \
+		   Assert(copy_line_size >= 1); \
+		   Assert(copy_line_data[copy_line_pos - 1] == '\r'); \
+		   copy_line_data[copy_line_pos - 1] = '\0'; \
+		   copy_line_size--; \
+		   break; \
+	   case EOL_CRNL: \
+		   Assert(copy_line_size >= 2); \
+		   Assert(copy_line_data[copy_line_pos - 2] == '\r'); \
+		   Assert(copy_line_data[copy_line_pos - 1] == '\n'); \
+		   copy_line_data[copy_line_pos - 2] = '\0'; \
+		   copy_line_size -= 2; \
+		   break; \
+	   case EOL_UNKNOWN: \
+		   /* shouldn't get here */ \
+		   Assert(false); \
+		   break; \
+   } \
+}
+
+/*
+ * CLEAR_EOL_LINE - Wrapper for clearing EOL.
+ */
+#define CLEAR_EOL_LINE() \
+if (!result && !IsHeaderLine()) \
+	CLEAR_EOL_FROM_COPIED_DATA(cstate->line_buf.data, \
+								cstate->line_buf.len, \
+								cstate->line_buf.len) \
+
+/*
+ * INCREMENTPROCESSED - Increment the lines processed.
+ */
+#define INCREMENTPROCESSED(processed)  \
+processed++;
+
+/*
+ * GETPROCESSED - Get the lines processed.
+ */
+#define GETPROCESSED(processed) \
+return processed;
+
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
 
@@ -393,6 +477,8 @@ static bool CopyGetInt32(CopyState cstate, int32 *val);
 static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 
+static void PopulateAttributes(CopyState cstate, TupleDesc	tup_desc,
+							   List *attnamelist);
 
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
@@ -794,6 +880,7 @@ CopyLoadRawBuf(CopyState cstate)
 {
 	int			nbytes;
 	int			inbytes;
+	int         minread = 1;
 
 	if (cstate->raw_buf_index < cstate->raw_buf_len)
 	{
@@ -805,8 +892,11 @@ CopyLoadRawBuf(CopyState cstate)
 	else
 		nbytes = 0;				/* no data need be saved */
 
+	if (cstate->copy_dest == COPY_NEW_FE)
+		minread = RAW_BUF_SIZE - nbytes;
+
 	inbytes = CopyGetData(cstate, cstate->raw_buf + nbytes,
-						  1, RAW_BUF_SIZE - nbytes);
+						  minread, RAW_BUF_SIZE - nbytes);
 	nbytes += inbytes;
 	cstate->raw_buf[nbytes] = '\0';
 	cstate->raw_buf_index = 0;
@@ -1464,7 +1554,6 @@ BeginCopy(ParseState *pstate,
 {
 	CopyState	cstate;
 	TupleDesc	tupDesc;
-	int			num_phys_attrs;
 	MemoryContext oldcontext;
 
 	/* Allocate workspace and zero all fields */
@@ -1630,6 +1719,22 @@ BeginCopy(ParseState *pstate,
 		tupDesc = cstate->queryDesc->tupDesc;
 	}
 
+	PopulateAttributes(cstate, tupDesc, attnamelist);
+	cstate->copy_dest = COPY_FILE;	/* default */
+
+	MemoryContextSwitchTo(oldcontext);
+
+	return cstate;
+}
+
+/*
+ * PopulateAttributes - Populate the attributes.
+ */
+static void
+PopulateAttributes(CopyState cstate, TupleDesc	tupDesc, List *attnamelist)
+{
+	int			num_phys_attrs;
+
 	/* Generate or convert list of attributes to process */
 	cstate->attnumlist = CopyGetAttnums(tupDesc, cstate->rel, attnamelist);
 
@@ -1749,12 +1854,6 @@ BeginCopy(ParseState *pstate,
 		 pg_database_encoding_max_length() > 1);
 	/* See Multibyte encoding comment above */
 	cstate->encoding_embeds_ascii = PG_ENCODING_IS_CLIENT_ONLY(cstate->file_encoding);
-
-	cstate->copy_dest = COPY_FILE;	/* default */
-
-	MemoryContextSwitchTo(oldcontext);
-
-	return cstate;
 }
 
 /*
@@ -2647,32 +2746,11 @@ CopyMultiInsertInfoStore(CopyMultiInsertInfo *miinfo, ResultRelInfo *rri,
 }
 
 /*
- * Copy FROM file to relation.
+ * Check if the relation specified in copy from is valid.
  */
-uint64
-CopyFrom(CopyState cstate)
+static void
+CheckCopyFromValidity(CopyState cstate)
 {
-	ResultRelInfo *resultRelInfo;
-	ResultRelInfo *target_resultRelInfo;
-	ResultRelInfo *prevResultRelInfo = NULL;
-	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
-	ModifyTableState *mtstate;
-	ExprContext *econtext;
-	TupleTableSlot *singleslot = NULL;
-	MemoryContext oldcontext = CurrentMemoryContext;
-
-	PartitionTupleRouting *proute = NULL;
-	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
-	int			ti_options = 0; /* start with default options for insert */
-	BulkInsertState bistate = NULL;
-	CopyInsertMethod insertMethod;
-	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
-	uint64		processed = 0;
-	bool		has_before_insert_row_trig;
-	bool		has_instead_insert_row_trig;
-	bool		leafpart_use_multi_insert = false;
-
 	Assert(cstate->rel);
 
 	/*
@@ -2709,27 +2787,6 @@ CopyFrom(CopyState cstate)
 							RelationGetRelationName(cstate->rel))));
 	}
 
-	/*
-	 * If the target file is new-in-transaction, we assume that checking FSM
-	 * for free space is a waste of time.  This could possibly be wrong, but
-	 * it's unlikely.
-	 */
-	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
-		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
-		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
-		ti_options |= TABLE_INSERT_SKIP_FSM;
-
-	/*
-	 * Optimize if new relfilenode was created in this subxact or one of its
-	 * committed children and we won't see those rows later as part of an
-	 * earlier scan or command. The subxact test ensures that if this subxact
-	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
-	 * that the stronger test of exactly which subtransaction created it is
-	 * crucial for correctness of this optimization. The test for an earlier
-	 * scan or command tolerates false negatives. FREEZE causes other sessions
-	 * to see rows they would not see under MVCC, and a false negative merely
-	 * spreads that anomaly to the current session.
-	 */
 	if (cstate->freeze)
 	{
 		/*
@@ -2767,9 +2824,61 @@ CopyFrom(CopyState cstate)
 			ereport(ERROR,
 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 					 errmsg("cannot perform COPY FREEZE because the table was not created or truncated in the current subtransaction")));
+	}
+}
+
+/*
+ * Copy FROM file to relation.
+ */
+uint64
+CopyFrom(CopyState cstate)
+{
+	ResultRelInfo *resultRelInfo;
+	ResultRelInfo *target_resultRelInfo;
+	ResultRelInfo *prevResultRelInfo = NULL;
+	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
+	ModifyTableState *mtstate;
+	ExprContext *econtext;
+	TupleTableSlot *singleslot = NULL;
+	MemoryContext oldcontext = CurrentMemoryContext;
+
+	PartitionTupleRouting *proute = NULL;
+	ErrorContextCallback errcallback;
+	CommandId	mycid = GetCurrentCommandId(true);
+	int			ti_options = 0; /* start with default options for insert */
+	BulkInsertState bistate = NULL;
+	CopyInsertMethod insertMethod;
+	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
+	uint64		processed = 0;
+	bool		has_before_insert_row_trig;
+	bool		has_instead_insert_row_trig;
+	bool		leafpart_use_multi_insert = false;
+
+	CheckCopyFromValidity(cstate);
+
+	/*
+	 * If the target file is new-in-transaction, we assume that checking FSM
+	 * for free space is a waste of time.  This could possibly be wrong, but
+	 * it's unlikely.
+	 */
+	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
+		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
+		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
+		ti_options |= TABLE_INSERT_SKIP_FSM;
 
+	/*
+	 * Optimize if new relfilenode was created in this subxact or one of its
+	 * committed children and we won't see those rows later as part of an
+	 * earlier scan or command. The subxact test ensures that if this subxact
+	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
+	 * that the stronger test of exactly which subtransaction created it is
+	 * crucial for correctness of this optimization. The test for an earlier
+	 * scan or command tolerates false negatives. FREEZE causes other sessions
+	 * to see rows they would not see under MVCC, and a false negative merely
+	 * spreads that anomaly to the current session.
+	 */
+	if (cstate->freeze)
 		ti_options |= TABLE_INSERT_FROZEN;
-	}
 
 	/*
 	 * We need a ResultRelInfo so we can use the regular executor's
@@ -3262,7 +3371,7 @@ CopyFrom(CopyState cstate)
 			 * or FDW; this is the same definition used by nodeModifyTable.c
 			 * for counting tuples inserted by an INSERT command.
 			 */
-			processed++;
+			INCREMENTPROCESSED(processed)
 		}
 	}
 
@@ -3317,30 +3426,15 @@ CopyFrom(CopyState cstate)
 
 	FreeExecutorState(estate);
 
-	return processed;
+	GETPROCESSED(processed)
 }
 
 /*
- * Setup to read tuples from a file for COPY FROM.
- *
- * 'rel': Used as a template for the tuples
- * 'filename': Name of server-local file to read
- * 'attnamelist': List of char *, columns to include. NIL selects all cols.
- * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
- *
- * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ * PopulateCatalogInformation - populate the catalog information.
  */
-CopyState
-BeginCopyFrom(ParseState *pstate,
-			  Relation rel,
-			  const char *filename,
-			  bool is_program,
-			  copy_data_source_cb data_source_cb,
-			  List *attnamelist,
-			  List *options)
+static void
+PopulateCatalogInformation(CopyState cstate)
 {
-	CopyState	cstate;
-	bool		pipe = (filename == NULL);
 	TupleDesc	tupDesc;
 	AttrNumber	num_phys_attrs,
 				num_defaults;
@@ -3350,31 +3444,8 @@ BeginCopyFrom(ParseState *pstate,
 	Oid			in_func_oid;
 	int		   *defmap;
 	ExprState **defexprs;
-	MemoryContext oldcontext;
 	bool		volatile_defexprs;
 
-	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
-	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
-
-	/* Initialize state variables */
-	cstate->reached_eof = false;
-	cstate->eol_type = EOL_UNKNOWN;
-	cstate->cur_relname = RelationGetRelationName(cstate->rel);
-	cstate->cur_lineno = 0;
-	cstate->cur_attname = NULL;
-	cstate->cur_attval = NULL;
-
-	/* Set up variables to avoid per-attribute overhead. */
-	initStringInfo(&cstate->attribute_buf);
-	initStringInfo(&cstate->line_buf);
-	cstate->line_buf_converted = false;
-	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
-	cstate->raw_buf_index = cstate->raw_buf_len = 0;
-
-	/* Assign range table, we'll need it in CopyFrom. */
-	if (pstate)
-		cstate->range_table = pstate->p_rtable;
-
 	tupDesc = RelationGetDescr(cstate->rel);
 	num_phys_attrs = tupDesc->natts;
 	num_defaults = 0;
@@ -3452,6 +3523,54 @@ BeginCopyFrom(ParseState *pstate,
 	cstate->defexprs = defexprs;
 	cstate->volatile_defexprs = volatile_defexprs;
 	cstate->num_defaults = num_defaults;
+}
+
+/*
+ * Setup to read tuples from a file for COPY FROM.
+ *
+ * 'rel': Used as a template for the tuples
+ * 'filename': Name of server-local file to read
+ * 'attnamelist': List of char *, columns to include. NIL selects all cols.
+ * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
+ *
+ * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ */
+CopyState
+BeginCopyFrom(ParseState *pstate,
+			  Relation rel,
+			  const char *filename,
+			  bool is_program,
+			  copy_data_source_cb data_source_cb,
+			  List *attnamelist,
+			  List *options)
+{
+	CopyState	cstate;
+	bool		pipe = (filename == NULL);
+	MemoryContext oldcontext;
+
+	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	/* Initialize state variables */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/* Set up variables to avoid per-attribute overhead. */
+	initStringInfo(&cstate->attribute_buf);
+	initStringInfo(&cstate->line_buf);
+	cstate->line_buf_converted = false;
+	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+
+	/* Assign range table, we'll need it in CopyFrom. */
+	if (pstate)
+		cstate->range_table = pstate->p_rtable;
+
+	PopulateCatalogInformation(cstate);
 	cstate->is_program = is_program;
 
 	if (data_source_cb)
@@ -3839,7 +3958,6 @@ static bool
 CopyReadLine(CopyState cstate)
 {
 	bool		result;
-
 	resetStringInfo(&cstate->line_buf);
 	cstate->line_buf_valid = true;
 
@@ -3864,60 +3982,8 @@ CopyReadLine(CopyState cstate)
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
-	else
-	{
-		/*
-		 * If we didn't hit EOF, then we must have transferred the EOL marker
-		 * to line_buf along with the data.  Get rid of it.
-		 */
-		switch (cstate->eol_type)
-		{
-			case EOL_NL:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CR:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\r');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CRNL:
-				Assert(cstate->line_buf.len >= 2);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 2] == '\r');
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len -= 2;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_UNKNOWN:
-				/* shouldn't get here */
-				Assert(false);
-				break;
-		}
-	}
-
-	/* Done reading the line.  Convert it to server encoding. */
-	if (cstate->need_transcoding)
-	{
-		char	   *cvt;
-
-		cvt = pg_any_to_server(cstate->line_buf.data,
-							   cstate->line_buf.len,
-							   cstate->file_encoding);
-		if (cvt != cstate->line_buf.data)
-		{
-			/* transfer converted data back to line_buf */
-			resetStringInfo(&cstate->line_buf);
-			appendBinaryStringInfo(&cstate->line_buf, cvt, strlen(cvt));
-			pfree(cvt);
-		}
-	}
-
-	/* Now it's safe to use the buffer in error messages */
-	cstate->line_buf_converted = true;
 
+	CONVERT_TO_SERVER_ENCODING(cstate)
 	return result;
 }
 
@@ -4281,6 +4347,7 @@ not_end_of_copy:
 	 * Transfer any still-uncopied data to line_buf.
 	 */
 	REFILL_LINEBUF;
+	CLEAR_EOL_LINE()
 
 	return result;
 }
-- 
1.8.3.1

#98vignesh C
vignesh21@gmail.com
In reply to: Bharath Rupireddy (#94)
Re: Parallel copy

On Mon, Jun 15, 2020 at 4:39 PM Bharath Rupireddy
<bharath.rupireddyforpostgres@gmail.com> wrote:

The above tests were run with the configuration attached config.txt, which is the same used for performance tests of csv/text files posted earlier in this mail chain.

Request the community to take this patch up for review along with the parallel copy for csv/text file patches and provide feedback.

I had reviewed the patch, few comments:
+
+       /*
+        * Parallel copy for binary formatted files
+        */
+       ParallelCopyDataBlock *curr_data_block;
+       ParallelCopyDataBlock *prev_data_block;
+       uint32                             curr_data_offset;
+       uint32                             curr_block_pos;
+       ParallelCopyTupleInfo  curr_tuple_start_info;
+       ParallelCopyTupleInfo  curr_tuple_end_info;
 } CopyStateData;

The new members added should be present in ParallelCopyData

+       if (cstate->curr_tuple_start_info.block_id ==
cstate->curr_tuple_end_info.block_id)
+       {
+               elog(DEBUG1,"LEADER - tuple lies in a single data block");
+
+               line_size = cstate->curr_tuple_end_info.offset -
cstate->curr_tuple_start_info.offset + 1;
+
pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[cstate->curr_tuple_start_info.block_id].unprocessed_line_parts,
1);
+       }
+       else
+       {
+               uint32 following_block_id =
pcshared_info->data_blocks[cstate->curr_tuple_start_info.block_id].following_block;
+
+               elog(DEBUG1,"LEADER - tuple is spread across data blocks");
+
+               line_size = DATA_BLOCK_SIZE -
cstate->curr_tuple_start_info.offset -
+
pcshared_info->data_blocks[cstate->curr_tuple_start_info.block_id].skip_bytes;
+
+
pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[cstate->curr_tuple_start_info.block_id].unprocessed_line_parts,
1);
+
+               while (following_block_id !=
cstate->curr_tuple_end_info.block_id)
+               {
+                       line_size = line_size + DATA_BLOCK_SIZE -
pcshared_info->data_blocks[following_block_id].skip_bytes;
+
+
pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[following_block_id].unprocessed_line_parts,
1);
+
+                       following_block_id =
pcshared_info->data_blocks[following_block_id].following_block;
+
+                       if (following_block_id == -1)
+                               break;
+               }
+
+               if (following_block_id != -1)
+
pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[following_block_id].unprocessed_line_parts,
1);
+
+               line_size = line_size + cstate->curr_tuple_end_info.offset + 1;
+       }

line_size can be set as and when we process the tuple from
CopyReadBinaryTupleLeader and this can be set at the end. That way the
above code can be removed.

+
+       /*
+        * Parallel copy for binary formatted files
+        */
+       ParallelCopyDataBlock *curr_data_block;
+       ParallelCopyDataBlock *prev_data_block;
+       uint32                             curr_data_offset;
+       uint32                             curr_block_pos;
+       ParallelCopyTupleInfo  curr_tuple_start_info;
+       ParallelCopyTupleInfo  curr_tuple_end_info;
 } CopyStateData;

curr_block_pos variable is present in ParallelCopyShmInfo, we could
use it and remove from here.
curr_data_offset, similar variable raw_buf_index is present in
CopyStateData, we could use it and remove from here.

+ if (cstate->curr_data_offset + sizeof(fld_count) >= (DATA_BLOCK_SIZE - 1))
+ {
+ ParallelCopyDataBlock *data_block = NULL;
+ uint8 movebytes = 0;
+
+ block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+ movebytes = DATA_BLOCK_SIZE - cstate->curr_data_offset;
+
+ cstate->curr_data_block->skip_bytes = movebytes;
+
+ data_block = &pcshared_info->data_blocks[block_pos];
+
+ if (movebytes > 0)
+ memmove(&data_block->data[0],
&cstate->curr_data_block->data[cstate->curr_data_offset],
+ movebytes);
+
+ elog(DEBUG1, "LEADER - field count is spread across data blocks -
moved %d bytes from current block %u to %u block",
+ movebytes, cstate->curr_block_pos, block_pos);
+
+ readbytes = CopyGetData(cstate, &data_block->data[movebytes], 1,
(DATA_BLOCK_SIZE - movebytes));
+
+ elog(DEBUG1, "LEADER - bytes read from file after field count is
moved to next data block %d", readbytes);
+
+ if (cstate->reached_eof)
+ ereport(ERROR,
+ (errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+ errmsg("unexpected EOF in COPY data")));
+
+ cstate->curr_data_block = data_block;
+ cstate->curr_data_offset = 0;
+ cstate->curr_block_pos = block_pos;
+ }

This code is duplicate in CopyReadBinaryTupleLeader &
CopyReadBinaryAttributeLeader. We could make a function and re-use.

+/*
+ * CopyReadBinaryAttributeWorker - leader identifies boundaries/offsets
+ * for each attribute/column, it moves on to next data block if the
+ * attribute/column is spread across data blocks.
+ */
+static pg_attribute_always_inline Datum
+CopyReadBinaryAttributeWorker(CopyState cstate, int column_no,
+               FmgrInfo *flinfo, Oid typioparam, int32 typmod, bool *isnull)
+{
+       int32           fld_size;
+       Datum           result;

column_no is not used, it can be removed

+       if (fld_count == -1)
+       {
+               /*
+                       * Received EOF marker.  In a V3-protocol copy,
wait for the
+                       * protocol-level EOF, and complain if it doesn't come
+                       * immediately.  This ensures that we correctly
handle CopyFail,
+                       * if client chooses to send that now.
+                       *
+                       * Note that we MUST NOT try to read more data
in an old-protocol
+                       * copy, since there is no protocol-level EOF
marker then.  We
+                       * could go either way for copy from file, but
choose to throw
+                       * error if there's data after the EOF marker,
for consistency
+                       * with the new-protocol case.
+                       */
+               char            dummy;
+
+               if (cstate->copy_dest != COPY_OLD_FE &&
+                       CopyGetData(cstate, &dummy, 1, 1) > 0)
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+                                               errmsg("received copy
data after EOF marker")));
+               return true;
+       }
+
+       if (fld_count != attr_count)
+               ereport(ERROR,
+                       (errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+                       errmsg("row field count is %d, expected %d",
+                       (int) fld_count, attr_count)));
+
+       cstate->curr_tuple_start_info.block_id = cstate->curr_block_pos;
+       cstate->curr_tuple_start_info.offset =  cstate->curr_data_offset;
+       cstate->curr_data_offset = cstate->curr_data_offset + sizeof(fld_count);
+       new_block_pos = cstate->curr_block_pos;
+
+       foreach(cur, cstate->attnumlist)
+       {
+               int                     attnum = lfirst_int(cur);
+               int                     m = attnum - 1;
+               Form_pg_attribute att = TupleDescAttr(tupDesc, m);

The above code is present in NextCopyFrom & CopyReadBinaryTupleLeader,
check if we can make a common function or we could use NextCopyFrom as
it is.

+       memcpy(&fld_count,
&cstate->curr_data_block->data[cstate->curr_data_offset],
sizeof(fld_count));
+       fld_count = (int16) pg_ntoh16(fld_count);
+
+       if (fld_count == -1)
+       {
+               return true;
+       }

Should this be an assert in CopyReadBinaryTupleWorker function as this
check is already done in the leader.

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

#99Ashutosh Sharma
ashu.coek88@gmail.com
In reply to: vignesh C (#91)
Re: Parallel copy

Hi,

I just got some time to review the first patch in the list i.e.
0001-Copy-code-readjustment-to-support-parallel-copy.patch. As the patch
name suggests, it is just trying to reshuffle the existing code for COPY
command here and there. There is no extra changes added in the patch as
such, but still I do have some review comments, please have a look:

1) Can you please add some comments atop the new function
PopulateAttributes() describing its functionality in detail. Further, this
new function contains the code from BeginCopy() to set attribute level
options used with COPY FROM such as FORCE_QUOTE, FORCE_NOT_NULL, FORCE_NULL
etc. in cstate and along with that it also copies the code from BeginCopy()
to set other infos such as client encoding type, encoding conversion etc.
Hence, I think it would be good to give it some better name, basically
something that matches with what actually it is doing.

2) Again, the name for the new function CheckCopyFromValidity() doesn't
look good to me. From the function name it appears as if it does the sanity
check of the entire COPY FROM command, but actually it is just doing the
sanity check for the target relation specified with COPY FROM. So, probably
something like CheckTargetRelValidity would look more sensible, I think?
TBH, I am not good at naming the functions so you can always ignore my
suggestions about function and variable names :)

3) Any reason for not making CheckCopyFromValidity as a macro instead of a
new function. It is just doing the sanity check for the target relation.

4) Earlier in CopyReadLine() function while trying to clear the EOL marker
from cstate->line_buf.data (copied data), we were not checking if the line
read by CopyReadLineText() function is a header line or not, but I can see
that your patch checks that before clearing the EOL marker. Any reason for
this extra check?

5) I noticed the below spurious line removal in the patch.

@@ -3839,7 +3953,6 @@ static bool
CopyReadLine(CopyState cstate)
{
bool result;
-

Please note that I haven't got a chance to look into other patches as of
now. I will do that whenever possible. Thank you.

--
With Regards,
Ashutosh Sharma
EnterpriseDB:http://www.enterprisedb.com

On Fri, Jun 12, 2020 at 11:01 AM vignesh C <vignesh21@gmail.com> wrote:

Show quoted text

On Thu, Jun 4, 2020 at 12:44 AM Andres Freund <andres@anarazel.de> wrote

Hm. you don't explicitly mention that in your design, but given how
small the benefits going from 0-1 workers is, I assume the leader
doesn't do any "chunk processing" on its own?

Yes you are right, the leader does not do any processing, Leader's
work is mainly to populate the shared memory with the offset
information for each record.

Design of the Parallel Copy: The backend, to which the "COPY FROM"

query is

submitted acts as leader with the responsibility of reading data from

the

file/stdin, launching at most n number of workers as specified with
PARALLEL 'n' option in the "COPY FROM" query. The leader populates the
common data required for the workers execution in the DSM and shares it
with the workers. The leader then executes before statement triggers if
there exists any. Leader populates DSM chunks which includes the start
offset and chunk size, while populating the chunks it reads as many

blocks

as required into the DSM data blocks from the file. Each block is of

64K

size. The leader parses the data to identify a chunk, the existing

logic

from CopyReadLineText which identifies the chunks with some changes was
used for this. Leader checks if a free chunk is available to copy the
information, if there is no free chunk it waits till the required

chunk is

freed up by the worker and then copies the identified chunks

information

(offset & chunk size) into the DSM chunks. This process is repeated

till

the complete file is processed. Simultaneously, the workers cache the
chunks(50) locally into the local memory and release the chunks to the
leader for further populating. Each worker processes the chunk that it
cached and inserts it into the table. The leader waits till all the

chunks

populated are processed by the workers and exits.

Why do we need the local copy of 50 chunks? Copying memory around is far
from free. I don't see why it'd be better to add per-process caching,
rather than making the DSM bigger? I can see some benefit in marking
multiple chunks as being processed with one lock acquisition, but I
don't think adding a memory copy is a good idea.

We had run performance with csv data file, 5.1GB, 10million tuples, 2
indexes on integer columns, results for the same are given below. We
noticed in some cases the performance is better if we copy the 50
records locally and release the shared memory. We will get better
benefits as the workers increase. Thoughts?

------------------------------------------------------------------------------------------------
Workers | Exec time (With local copying | Exec time (Without copying,
| 50 records & release the | processing record by
record)
| shared memory) |

------------------------------------------------------------------------------------------------
0 | 1162.772(1X) | 1152.684(1X)
2 | 635.249(1.83X) | 647.894(1.78X)
4 | 336.835(3.45X) | 335.534(3.43X)
8 | 188.577(6.17 X) | 189.461(6.08X)
16 | 126.819(9.17X) | 142.730(8.07X)
20 | 117.845(9.87X) | 146.533(7.87X)
30 | 127.554(9.11X) | 160.307(7.19X)

This patch *desperately* needs to be split up. It imo is close to
unreviewable, due to a large amount of changes that just move code
around without other functional changes being mixed in with the actual
new stuff.

I have split the patch, the new split patches are attached.

/*
+ * State of the chunk.
+ */
+typedef enum ChunkState
+{
+     CHUNK_INIT,                                     /* initial state

of chunk */

+     CHUNK_LEADER_POPULATING,        /* leader processing chunk */
+     CHUNK_LEADER_POPULATED,         /* leader completed populating

chunk */

+     CHUNK_WORKER_PROCESSING,        /* worker processing chunk */
+     CHUNK_WORKER_PROCESSED          /* worker completed processing

chunk */

+}ChunkState;
+
+#define RAW_BUF_SIZE 65536           /* we palloc RAW_BUF_SIZE+1

bytes */

+
+#define DATA_BLOCK_SIZE RAW_BUF_SIZE
+#define RINGSIZE (10 * 1000)
+#define MAX_BLOCKS_COUNT 1000
+#define WORKER_CHUNK_COUNT 50        /* should be mod of RINGSIZE */
+
+#define      IsParallelCopy()                (cstate->is_parallel)
+#define IsLeader()

(cstate->pcdata->is_leader)

+#define IsHeaderLine() (cstate->header_line &&

cstate->cur_lineno == 1)

+
+/*
+ * Copy data block information.
+ */
+typedef struct CopyDataBlock
+{
+     /* The number of unprocessed chunks in the current block. */
+     pg_atomic_uint32 unprocessed_chunk_parts;
+
+     /*
+      * If the current chunk data is continued into another block,
+      * following_block will have the position where the remaining

data need to

+      * be read.
+      */
+     uint32  following_block;
+
+     /*
+      * This flag will be set, when the leader finds out this block

can be read

+ * safely by the worker. This helps the worker to start

processing the chunk

+ * early where the chunk will be spread across many blocks and

the worker

+      * need not wait for the complete chunk to be processed.
+      */
+     bool   curr_blk_completed;
+     char   data[DATA_BLOCK_SIZE + 1]; /* data read from file */
+}CopyDataBlock;

What's the + 1 here about?

Fixed this, removed +1. That is not needed.

+/*
+ * Parallel copy line buffer information.
+ */
+typedef struct ParallelCopyLineBuf
+{
+     StringInfoData          line_buf;
+     uint64                          cur_lineno;     /* line number

for error messages */

+}ParallelCopyLineBuf;

Why do we need separate infrastructure for this? We shouldn't duplicate
infrastructure unnecessarily.

This was required for copying the multiple records locally and
releasing the shared memory. I have not changed this, will decide on
this based on the decision taken for one of the previous comments.

+/*
+ * Common information that need to be copied to shared memory.
+ */
+typedef struct CopyWorkerCommonData
+{

Why is parallel specific stuff here suddenly not named ParallelCopy*
anymore? If you introduce a naming like that it imo should be used
consistently.

Fixed, changed to maintain ParallelCopy in all structs.

+     /* low-level state data */
+     CopyDest            copy_dest;          /* type of copy

source/destination */

+ int file_encoding; /* file or remote side's

character encoding */

+ bool need_transcoding; /* file encoding diff

from server? */

+ bool encoding_embeds_ascii; /* ASCII can be

non-first byte? */

+
+     /* parameters from the COPY command */
+     bool                csv_mode;           /* Comma Separated Value

format? */

+     bool                header_line;        /* CSV header line? */
+     int                 null_print_len; /* length of same */
+     bool                force_quote_all;    /* FORCE_QUOTE *? */
+     bool                convert_selectively;        /* do selective

binary conversion? */

+
+     /* Working state for COPY FROM */
+     AttrNumber          num_defaults;
+     Oid                 relid;
+}CopyWorkerCommonData;

But I actually think we shouldn't have this information in two different
structs. This should exist once, independent of using parallel /
non-parallel copy.

This structure helps in storing the common data from CopyStateData
that are required by the workers. This information will then be
allocated and stored into the DSM for the worker to retrieve and copy
it to CopyStateData.

+/* List information */
+typedef struct ListInfo
+{
+     int     count;          /* count of attributes */
+
+     /* string info in the form info followed by info1, info2...

infon */

+ char info[1];
+} ListInfo;

Based on these comments I have no idea what this could be for.

Have added better comments for this. The following is added: This
structure will help in converting a List data type into the below
structure format with the count having the number of elements in the
list and the info having the List elements appended contiguously. This
converted structure will be allocated in shared memory and stored in
DSM for the worker to retrieve and later convert it back to List data
type.

/*
- * This keeps the character read at the top of the loop in the buffer
- * even if there is more than one read-ahead.
+ * This keeps the character read at the top of the loop in the buffer
+ * even if there is more than one read-ahead.
+ */
+#define IF_NEED_REFILL_AND_NOT_EOF_CONTINUE(extralen) \
+if (1) \
+{ \
+     if (copy_buff_state.raw_buf_ptr + (extralen) >=

copy_buff_state.copy_buf_len && !hit_eof) \

+     { \
+             if (IsParallelCopy()) \
+             { \
+                     copy_buff_state.chunk_size = prev_chunk_size; /*

update previous chunk size */ \

+                     if (copy_buff_state.block_switched) \
+                     { \
+

pg_atomic_sub_fetch_u32(&copy_buff_state.data_blk_ptr->unprocessed_chunk_parts,
1); \

+ copy_buff_state.copy_buf_len =

prev_copy_buf_len; \

+                     } \
+             } \
+             copy_buff_state.raw_buf_ptr = prev_raw_ptr; /* undo

fetch */ \

+             need_data = true; \
+             continue; \
+     } \
+} else ((void) 0)

I think it's an absolutely clear no-go to add new branches to
these. They're *really* hot already, and this is going to sprinkle a
significant amount of new instructions over a lot of places.

Fixed, removed this.

+/*
+ * SET_RAWBUF_FOR_LOAD - Set raw_buf to the shared memory where the

file data must

+ * be read.
+ */
+#define SET_RAWBUF_FOR_LOAD() \
+{ \
+     ShmCopyInfo     *pcshared_info = cstate->pcdata->pcshared_info; \
+     uint32 cur_block_pos; \
+     /* \
+      * Mark the previous block as completed, worker can start

copying this data. \

+      */ \
+     if (copy_buff_state.data_blk_ptr !=

copy_buff_state.curr_data_blk_ptr && \

+ copy_buff_state.data_blk_ptr->curr_blk_completed ==

false) \

+ copy_buff_state.data_blk_ptr->curr_blk_completed = true;

\

+ \
+ copy_buff_state.data_blk_ptr =

copy_buff_state.curr_data_blk_ptr; \

+     cur_block_pos = WaitGetFreeCopyBlock(pcshared_info); \
+     copy_buff_state.curr_data_blk_ptr =

&pcshared_info->data_blocks[cur_block_pos]; \

+     \
+     if (!copy_buff_state.data_blk_ptr) \
+     { \
+             copy_buff_state.data_blk_ptr =

copy_buff_state.curr_data_blk_ptr; \

+             chunk_first_block = cur_block_pos; \
+     } \
+     else if (need_data == false) \
+             copy_buff_state.data_blk_ptr->following_block =

cur_block_pos; \

+     \
+     cstate->raw_buf = copy_buff_state.curr_data_blk_ptr->data; \
+     copy_buff_state.copy_raw_buf = cstate->raw_buf; \
+}
+
+/*
+ * END_CHUNK_PARALLEL_COPY - Update the chunk information in shared

memory.

+ */
+#define END_CHUNK_PARALLEL_COPY() \
+{ \
+     if (!IsHeaderLine()) \
+     { \
+             ShmCopyInfo *pcshared_info =

cstate->pcdata->pcshared_info; \

+ ChunkBoundaries *chunkBoundaryPtr =

&pcshared_info->chunk_boundaries; \

+             if (copy_buff_state.chunk_size) \
+             { \
+                     ChunkBoundary *chunkInfo =

&chunkBoundaryPtr->ring[chunk_pos]; \

+                     /* \
+                      * If raw_buf_ptr is zero,

unprocessed_chunk_parts would have been \

+ * incremented in SEEK_COPY_BUFF_POS. This will

happen if the whole \

+ * chunk finishes at the end of the current

block. If the \

+ * new_line_size > raw_buf_ptr, then the new

block has only new line \

+ * char content. The unprocessed count should

not be increased in \

+                      * this case. \
+                      */ \
+                     if (copy_buff_state.raw_buf_ptr != 0 && \
+                             copy_buff_state.raw_buf_ptr >

new_line_size) \

+

pg_atomic_add_fetch_u32(&copy_buff_state.curr_data_blk_ptr->unprocessed_chunk_parts,
1); \

+                     \
+                     /* Update chunk size. */ \
+                     pg_atomic_write_u32(&chunkInfo->chunk_size,

copy_buff_state.chunk_size); \

+ pg_atomic_write_u32(&chunkInfo->chunk_state,

CHUNK_LEADER_POPULATED); \

+ elog(DEBUG1, "[Leader] After adding - chunk

position:%d, chunk_size:%d", \

+ chunk_pos,

copy_buff_state.chunk_size); \

+                     pcshared_info->populated++; \
+             } \
+             else if (new_line_size) \
+             { \
+                     /* \
+                      * This means only new line char, empty record

should be \

+                      * inserted. \
+                      */ \
+                     ChunkBoundary *chunkInfo; \
+                     chunk_pos = UpdateBlockInChunkInfo(cstate, -1,

-1, 0, \

+

CHUNK_LEADER_POPULATED); \

+                     chunkInfo = &chunkBoundaryPtr->ring[chunk_pos]; \
+                     elog(DEBUG1, "[Leader] Added empty chunk with

offset:%d, chunk position:%d, chunk size:%d", \

+

chunkInfo->start_offset, chunk_pos, \

+

pg_atomic_read_u32(&chunkInfo->chunk_size)); \

+                     pcshared_info->populated++; \
+             } \
+     }\
+     \
+     /*\
+      * All of the read data is processed, reset index & len. In the\
+      * subsequent read, we will get a new block and copy data in to

the\

+      * new block.\
+      */\
+     if (copy_buff_state.raw_buf_ptr == copy_buff_state.copy_buf_len)\
+     {\
+             cstate->raw_buf_index = 0;\
+             cstate->raw_buf_len = 0;\
+     }\
+     else\
+             cstate->raw_buf_len = copy_buff_state.copy_buf_len;\
+}

Why are these macros? They are way way way above a length where that
makes any sort of sense.

Converted these macros to functions.

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

#100vignesh C
vignesh21@gmail.com
In reply to: Ashutosh Sharma (#99)
1 attachment(s)
Re: Parallel copy

Thanks Ashutosh For your review, my comments are inline.
On Fri, Jun 19, 2020 at 5:41 PM Ashutosh Sharma <ashu.coek88@gmail.com> wrote:

Hi,

I just got some time to review the first patch in the list i.e. 0001-Copy-code-readjustment-to-support-parallel-copy.patch. As the patch name suggests, it is just trying to reshuffle the existing code for COPY command here and there. There is no extra changes added in the patch as such, but still I do have some review comments, please have a look:

1) Can you please add some comments atop the new function PopulateAttributes() describing its functionality in detail. Further, this new function contains the code from BeginCopy() to set attribute level options used with COPY FROM such as FORCE_QUOTE, FORCE_NOT_NULL, FORCE_NULL etc. in cstate and along with that it also copies the code from BeginCopy() to set other infos such as client encoding type, encoding conversion etc. Hence, I think it would be good to give it some better name, basically something that matches with what actually it is doing.

There is no new code added in this function, some part of code from
BeginCopy was made in to a new function as this part of code will also
be required for the parallel copy workers before the workers start the
actual copy operation. This code was made into a function to avoid
duplication. Changed the function name to PopulateGlobalsForCopyFrom &
added few comments.

2) Again, the name for the new function CheckCopyFromValidity() doesn't look good to me. From the function name it appears as if it does the sanity check of the entire COPY FROM command, but actually it is just doing the sanity check for the target relation specified with COPY FROM. So, probably something like CheckTargetRelValidity would look more sensible, I think? TBH, I am not good at naming the functions so you can always ignore my suggestions about function and variable names :)

Changed as suggested.

3) Any reason for not making CheckCopyFromValidity as a macro instead of a new function. It is just doing the sanity check for the target relation.

I felt there is reasonable number of lines in the function & it is not
in performance intensive path, so I preferred function over macro.
Your thoughts?

4) Earlier in CopyReadLine() function while trying to clear the EOL marker from cstate->line_buf.data (copied data), we were not checking if the line read by CopyReadLineText() function is a header line or not, but I can see that your patch checks that before clearing the EOL marker. Any reason for this extra check?

If you see the caller of CopyReadLine, i.e. NextCopyFromRawFields does
nothing for the header line, server basically calls CopyReadLine
again, it is a kind of small optimization. Anyway server is not going
to do anything with header line, I felt no need to clear EOL marker
for header lines.
/* on input just throw the header line away */
if (cstate->cur_lineno == 0 && cstate->header_line)
{
cstate->cur_lineno++;
if (CopyReadLine(cstate))
return false; /* done */
}

cstate->cur_lineno++;

/* Actually read the line into memory here */
done = CopyReadLine(cstate);
I think no need to make a fix for this. Your thoughts?

5) I noticed the below spurious line removal in the patch.

@@ -3839,7 +3953,6 @@ static bool
CopyReadLine(CopyState cstate)
{
bool result;
-

Fixed.
I have attached the patch for the same with the fixes.
Thoughts?

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

Attachments:

0001-Copy-code-readjustment-to-support-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=0001-Copy-code-readjustment-to-support-parallel-copy.patchDownload
From 4455d3e067bda56316bb292e5d010bdf40254fec Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Tue, 23 Jun 2020 06:49:22 +0530
Subject: [PATCH 1/6] Copy code readjustment to support parallel copy.

This patch has the copy code slightly readjusted so that the common code is
separated to functions/macros, these functions/macros will be used by the
workers in the parallel copy code of the upcoming patches. EOL removal is moved
from CopyReadLine to CopyReadLineText, this change was required because in case
of parallel copy the record identification and record updation is done in
CopyReadLineText, before record information is updated in shared memory the new
line characters should be removed.
---
 src/backend/commands/copy.c | 372 ++++++++++++++++++++++++++------------------
 1 file changed, 221 insertions(+), 151 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 6b1fd6d..65a504f 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -95,6 +95,9 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
+#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+#define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
+
 /*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
@@ -219,7 +222,6 @@ typedef struct CopyStateData
 	 * converts it.  Note: we guarantee that there is a \0 at
 	 * raw_buf[raw_buf_len].
 	 */
-#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
@@ -347,6 +349,88 @@ if (1) \
 	goto not_end_of_copy; \
 } else ((void) 0)
 
+/*
+ * CONVERT_TO_SERVER_ENCODING - convert contents to server encoding.
+ */
+#define CONVERT_TO_SERVER_ENCODING(cstate) \
+{ \
+	/* Done reading the line.  Convert it to server encoding. */ \
+	if (cstate->need_transcoding) \
+	{ \
+		char	   *cvt; \
+		cvt = pg_any_to_server(cstate->line_buf.data, \
+							   cstate->line_buf.len, \
+							   cstate->file_encoding); \
+		if (cvt != cstate->line_buf.data) \
+		{ \
+			/* transfer converted data back to line_buf */ \
+			resetStringInfo(&cstate->line_buf); \
+			appendBinaryStringInfo(&cstate->line_buf, cvt, strlen(cvt)); \
+			pfree(cvt); \
+		} \
+	} \
+	/* Now it's safe to use the buffer in error messages */ \
+	cstate->line_buf_converted = true; \
+}
+
+/*
+ * CLEAR_EOL_FROM_COPIED_DATA - Clear EOL from the copied data.
+ */
+#define CLEAR_EOL_FROM_COPIED_DATA(copy_line_data, copy_line_pos, copy_line_size) \
+{ \
+	/* \
+	 * If we didn't hit EOF, then we must have transferred the EOL marker \
+	 * to line_buf along with the data.  Get rid of it. \
+	 */ \
+   switch (cstate->eol_type) \
+   { \
+	   case EOL_NL: \
+		   Assert(copy_line_size >= 1); \
+		   Assert(copy_line_data[copy_line_pos - 1] == '\n'); \
+		   copy_line_data[copy_line_pos - 1] = '\0'; \
+		   copy_line_size--; \
+		   break; \
+	   case EOL_CR: \
+		   Assert(copy_line_size >= 1); \
+		   Assert(copy_line_data[copy_line_pos - 1] == '\r'); \
+		   copy_line_data[copy_line_pos - 1] = '\0'; \
+		   copy_line_size--; \
+		   break; \
+	   case EOL_CRNL: \
+		   Assert(copy_line_size >= 2); \
+		   Assert(copy_line_data[copy_line_pos - 2] == '\r'); \
+		   Assert(copy_line_data[copy_line_pos - 1] == '\n'); \
+		   copy_line_data[copy_line_pos - 2] = '\0'; \
+		   copy_line_size -= 2; \
+		   break; \
+	   case EOL_UNKNOWN: \
+		   /* shouldn't get here */ \
+		   Assert(false); \
+		   break; \
+   } \
+}
+
+/*
+ * CLEAR_EOL_LINE - Wrapper for clearing EOL.
+ */
+#define CLEAR_EOL_LINE() \
+if (!result && !IsHeaderLine()) \
+	CLEAR_EOL_FROM_COPIED_DATA(cstate->line_buf.data, \
+								cstate->line_buf.len, \
+								cstate->line_buf.len) \
+
+/*
+ * INCREMENTPROCESSED - Increment the lines processed.
+ */
+#define INCREMENTPROCESSED(processed)  \
+processed++;
+
+/*
+ * GETPROCESSED - Get the lines processed.
+ */
+#define GETPROCESSED(processed) \
+return processed;
+
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
 
@@ -392,6 +476,8 @@ static bool CopyGetInt32(CopyState cstate, int32 *val);
 static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 
+static void PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tup_desc,
+							   List *attnamelist);
 
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
@@ -793,6 +879,7 @@ CopyLoadRawBuf(CopyState cstate)
 {
 	int			nbytes;
 	int			inbytes;
+	int         minread = 1;
 
 	if (cstate->raw_buf_index < cstate->raw_buf_len)
 	{
@@ -804,8 +891,11 @@ CopyLoadRawBuf(CopyState cstate)
 	else
 		nbytes = 0;				/* no data need be saved */
 
+	if (cstate->copy_dest == COPY_NEW_FE)
+		minread = RAW_BUF_SIZE - nbytes;
+
 	inbytes = CopyGetData(cstate, cstate->raw_buf + nbytes,
-						  1, RAW_BUF_SIZE - nbytes);
+						  minread, RAW_BUF_SIZE - nbytes);
 	nbytes += inbytes;
 	cstate->raw_buf[nbytes] = '\0';
 	cstate->raw_buf_index = 0;
@@ -1463,7 +1553,6 @@ BeginCopy(ParseState *pstate,
 {
 	CopyState	cstate;
 	TupleDesc	tupDesc;
-	int			num_phys_attrs;
 	MemoryContext oldcontext;
 
 	/* Allocate workspace and zero all fields */
@@ -1629,6 +1718,24 @@ BeginCopy(ParseState *pstate,
 		tupDesc = cstate->queryDesc->tupDesc;
 	}
 
+	PopulateGlobalsForCopyFrom(cstate, tupDesc, attnamelist);
+	cstate->copy_dest = COPY_FILE;	/* default */
+
+	MemoryContextSwitchTo(oldcontext);
+
+	return cstate;
+}
+
+/*
+ * PopulateGlobalsForCopyFrom - Populates the common variables required for copy
+ * from operation. This is a helper function for BeginCopy function.
+ */
+static void
+PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tupDesc,
+							List *attnamelist)
+{
+	int			num_phys_attrs;
+
 	/* Generate or convert list of attributes to process */
 	cstate->attnumlist = CopyGetAttnums(tupDesc, cstate->rel, attnamelist);
 
@@ -1748,12 +1855,6 @@ BeginCopy(ParseState *pstate,
 		 pg_database_encoding_max_length() > 1);
 	/* See Multibyte encoding comment above */
 	cstate->encoding_embeds_ascii = PG_ENCODING_IS_CLIENT_ONLY(cstate->file_encoding);
-
-	cstate->copy_dest = COPY_FILE;	/* default */
-
-	MemoryContextSwitchTo(oldcontext);
-
-	return cstate;
 }
 
 /*
@@ -2646,32 +2747,11 @@ CopyMultiInsertInfoStore(CopyMultiInsertInfo *miinfo, ResultRelInfo *rri,
 }
 
 /*
- * Copy FROM file to relation.
+ * Check if the relation specified in copy from is valid.
  */
-uint64
-CopyFrom(CopyState cstate)
+static void
+CheckTargetRelValidity(CopyState cstate)
 {
-	ResultRelInfo *resultRelInfo;
-	ResultRelInfo *target_resultRelInfo;
-	ResultRelInfo *prevResultRelInfo = NULL;
-	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
-	ModifyTableState *mtstate;
-	ExprContext *econtext;
-	TupleTableSlot *singleslot = NULL;
-	MemoryContext oldcontext = CurrentMemoryContext;
-
-	PartitionTupleRouting *proute = NULL;
-	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
-	int			ti_options = 0; /* start with default options for insert */
-	BulkInsertState bistate = NULL;
-	CopyInsertMethod insertMethod;
-	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
-	uint64		processed = 0;
-	bool		has_before_insert_row_trig;
-	bool		has_instead_insert_row_trig;
-	bool		leafpart_use_multi_insert = false;
-
 	Assert(cstate->rel);
 
 	/*
@@ -2708,27 +2788,6 @@ CopyFrom(CopyState cstate)
 							RelationGetRelationName(cstate->rel))));
 	}
 
-	/*
-	 * If the target file is new-in-transaction, we assume that checking FSM
-	 * for free space is a waste of time.  This could possibly be wrong, but
-	 * it's unlikely.
-	 */
-	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
-		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
-		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
-		ti_options |= TABLE_INSERT_SKIP_FSM;
-
-	/*
-	 * Optimize if new relfilenode was created in this subxact or one of its
-	 * committed children and we won't see those rows later as part of an
-	 * earlier scan or command. The subxact test ensures that if this subxact
-	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
-	 * that the stronger test of exactly which subtransaction created it is
-	 * crucial for correctness of this optimization. The test for an earlier
-	 * scan or command tolerates false negatives. FREEZE causes other sessions
-	 * to see rows they would not see under MVCC, and a false negative merely
-	 * spreads that anomaly to the current session.
-	 */
 	if (cstate->freeze)
 	{
 		/*
@@ -2766,9 +2825,61 @@ CopyFrom(CopyState cstate)
 			ereport(ERROR,
 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 					 errmsg("cannot perform COPY FREEZE because the table was not created or truncated in the current subtransaction")));
+	}
+}
+
+/*
+ * Copy FROM file to relation.
+ */
+uint64
+CopyFrom(CopyState cstate)
+{
+	ResultRelInfo *resultRelInfo;
+	ResultRelInfo *target_resultRelInfo;
+	ResultRelInfo *prevResultRelInfo = NULL;
+	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
+	ModifyTableState *mtstate;
+	ExprContext *econtext;
+	TupleTableSlot *singleslot = NULL;
+	MemoryContext oldcontext = CurrentMemoryContext;
+
+	PartitionTupleRouting *proute = NULL;
+	ErrorContextCallback errcallback;
+	CommandId	mycid = GetCurrentCommandId(true);
+	int			ti_options = 0; /* start with default options for insert */
+	BulkInsertState bistate = NULL;
+	CopyInsertMethod insertMethod;
+	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
+	uint64		processed = 0;
+	bool		has_before_insert_row_trig;
+	bool		has_instead_insert_row_trig;
+	bool		leafpart_use_multi_insert = false;
+
+	CheckTargetRelValidity(cstate);
 
+	/*
+	 * If the target file is new-in-transaction, we assume that checking FSM
+	 * for free space is a waste of time.  This could possibly be wrong, but
+	 * it's unlikely.
+	 */
+	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
+		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
+		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
+		ti_options |= TABLE_INSERT_SKIP_FSM;
+
+	/*
+	 * Optimize if new relfilenode was created in this subxact or one of its
+	 * committed children and we won't see those rows later as part of an
+	 * earlier scan or command. The subxact test ensures that if this subxact
+	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
+	 * that the stronger test of exactly which subtransaction created it is
+	 * crucial for correctness of this optimization. The test for an earlier
+	 * scan or command tolerates false negatives. FREEZE causes other sessions
+	 * to see rows they would not see under MVCC, and a false negative merely
+	 * spreads that anomaly to the current session.
+	 */
+	if (cstate->freeze)
 		ti_options |= TABLE_INSERT_FROZEN;
-	}
 
 	/*
 	 * We need a ResultRelInfo so we can use the regular executor's
@@ -3261,7 +3372,7 @@ CopyFrom(CopyState cstate)
 			 * or FDW; this is the same definition used by nodeModifyTable.c
 			 * for counting tuples inserted by an INSERT command.
 			 */
-			processed++;
+			INCREMENTPROCESSED(processed)
 		}
 	}
 
@@ -3316,30 +3427,15 @@ CopyFrom(CopyState cstate)
 
 	FreeExecutorState(estate);
 
-	return processed;
+	GETPROCESSED(processed)
 }
 
 /*
- * Setup to read tuples from a file for COPY FROM.
- *
- * 'rel': Used as a template for the tuples
- * 'filename': Name of server-local file to read
- * 'attnamelist': List of char *, columns to include. NIL selects all cols.
- * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
- *
- * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ * PopulateCatalogInformation - populate the catalog information.
  */
-CopyState
-BeginCopyFrom(ParseState *pstate,
-			  Relation rel,
-			  const char *filename,
-			  bool is_program,
-			  copy_data_source_cb data_source_cb,
-			  List *attnamelist,
-			  List *options)
+static void
+PopulateCatalogInformation(CopyState cstate)
 {
-	CopyState	cstate;
-	bool		pipe = (filename == NULL);
 	TupleDesc	tupDesc;
 	AttrNumber	num_phys_attrs,
 				num_defaults;
@@ -3349,31 +3445,8 @@ BeginCopyFrom(ParseState *pstate,
 	Oid			in_func_oid;
 	int		   *defmap;
 	ExprState **defexprs;
-	MemoryContext oldcontext;
 	bool		volatile_defexprs;
 
-	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
-	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
-
-	/* Initialize state variables */
-	cstate->reached_eof = false;
-	cstate->eol_type = EOL_UNKNOWN;
-	cstate->cur_relname = RelationGetRelationName(cstate->rel);
-	cstate->cur_lineno = 0;
-	cstate->cur_attname = NULL;
-	cstate->cur_attval = NULL;
-
-	/* Set up variables to avoid per-attribute overhead. */
-	initStringInfo(&cstate->attribute_buf);
-	initStringInfo(&cstate->line_buf);
-	cstate->line_buf_converted = false;
-	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
-	cstate->raw_buf_index = cstate->raw_buf_len = 0;
-
-	/* Assign range table, we'll need it in CopyFrom. */
-	if (pstate)
-		cstate->range_table = pstate->p_rtable;
-
 	tupDesc = RelationGetDescr(cstate->rel);
 	num_phys_attrs = tupDesc->natts;
 	num_defaults = 0;
@@ -3451,6 +3524,54 @@ BeginCopyFrom(ParseState *pstate,
 	cstate->defexprs = defexprs;
 	cstate->volatile_defexprs = volatile_defexprs;
 	cstate->num_defaults = num_defaults;
+}
+
+/*
+ * Setup to read tuples from a file for COPY FROM.
+ *
+ * 'rel': Used as a template for the tuples
+ * 'filename': Name of server-local file to read
+ * 'attnamelist': List of char *, columns to include. NIL selects all cols.
+ * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
+ *
+ * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ */
+CopyState
+BeginCopyFrom(ParseState *pstate,
+			  Relation rel,
+			  const char *filename,
+			  bool is_program,
+			  copy_data_source_cb data_source_cb,
+			  List *attnamelist,
+			  List *options)
+{
+	CopyState	cstate;
+	bool		pipe = (filename == NULL);
+	MemoryContext oldcontext;
+
+	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	/* Initialize state variables */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/* Set up variables to avoid per-attribute overhead. */
+	initStringInfo(&cstate->attribute_buf);
+	initStringInfo(&cstate->line_buf);
+	cstate->line_buf_converted = false;
+	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+
+	/* Assign range table, we'll need it in CopyFrom. */
+	if (pstate)
+		cstate->range_table = pstate->p_rtable;
+
+	PopulateCatalogInformation(cstate);
 	cstate->is_program = is_program;
 
 	if (data_source_cb)
@@ -3860,60 +3981,8 @@ CopyReadLine(CopyState cstate)
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
-	else
-	{
-		/*
-		 * If we didn't hit EOF, then we must have transferred the EOL marker
-		 * to line_buf along with the data.  Get rid of it.
-		 */
-		switch (cstate->eol_type)
-		{
-			case EOL_NL:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CR:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\r');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CRNL:
-				Assert(cstate->line_buf.len >= 2);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 2] == '\r');
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len -= 2;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_UNKNOWN:
-				/* shouldn't get here */
-				Assert(false);
-				break;
-		}
-	}
-
-	/* Done reading the line.  Convert it to server encoding. */
-	if (cstate->need_transcoding)
-	{
-		char	   *cvt;
-
-		cvt = pg_any_to_server(cstate->line_buf.data,
-							   cstate->line_buf.len,
-							   cstate->file_encoding);
-		if (cvt != cstate->line_buf.data)
-		{
-			/* transfer converted data back to line_buf */
-			resetStringInfo(&cstate->line_buf);
-			appendBinaryStringInfo(&cstate->line_buf, cvt, strlen(cvt));
-			pfree(cvt);
-		}
-	}
-
-	/* Now it's safe to use the buffer in error messages */
-	cstate->line_buf_converted = true;
 
+	CONVERT_TO_SERVER_ENCODING(cstate)
 	return result;
 }
 
@@ -4277,6 +4346,7 @@ not_end_of_copy:
 	 * Transfer any still-uncopied data to line_buf.
 	 */
 	REFILL_LINEBUF;
+	CLEAR_EOL_LINE()
 
 	return result;
 }
-- 
1.8.3.1

#101vignesh C
vignesh21@gmail.com
In reply to: vignesh C (#100)
6 attachment(s)
Re: Parallel copy

On Tue, Jun 23, 2020 at 8:07 AM vignesh C <vignesh21@gmail.com> wrote:

I have attached the patch for the same with the fixes.

The patches were not applying on the head, attached the patches that can be
applied on head.
I have added a commitfest entry[1]https://commitfest.postgresql.org/28/2610/ for this feature.

[1]: https://commitfest.postgresql.org/28/2610/

On Tue, Jun 23, 2020 at 8:07 AM vignesh C <vignesh21@gmail.com> wrote:

Show quoted text

Thanks Ashutosh For your review, my comments are inline.
On Fri, Jun 19, 2020 at 5:41 PM Ashutosh Sharma <ashu.coek88@gmail.com>
wrote:

Hi,

I just got some time to review the first patch in the list i.e.

0001-Copy-code-readjustment-to-support-parallel-copy.patch. As the patch
name suggests, it is just trying to reshuffle the existing code for COPY
command here and there. There is no extra changes added in the patch as
such, but still I do have some review comments, please have a look:

1) Can you please add some comments atop the new function

PopulateAttributes() describing its functionality in detail. Further, this
new function contains the code from BeginCopy() to set attribute level
options used with COPY FROM such as FORCE_QUOTE, FORCE_NOT_NULL, FORCE_NULL
etc. in cstate and along with that it also copies the code from BeginCopy()
to set other infos such as client encoding type, encoding conversion etc.
Hence, I think it would be good to give it some better name, basically
something that matches with what actually it is doing.

There is no new code added in this function, some part of code from
BeginCopy was made in to a new function as this part of code will also
be required for the parallel copy workers before the workers start the
actual copy operation. This code was made into a function to avoid
duplication. Changed the function name to PopulateGlobalsForCopyFrom &
added few comments.

2) Again, the name for the new function CheckCopyFromValidity() doesn't

look good to me. From the function name it appears as if it does the sanity
check of the entire COPY FROM command, but actually it is just doing the
sanity check for the target relation specified with COPY FROM. So, probably
something like CheckTargetRelValidity would look more sensible, I think?
TBH, I am not good at naming the functions so you can always ignore my
suggestions about function and variable names :)

Changed as suggested.

3) Any reason for not making CheckCopyFromValidity as a macro instead of

a new function. It is just doing the sanity check for the target relation.

I felt there is reasonable number of lines in the function & it is not
in performance intensive path, so I preferred function over macro.
Your thoughts?

4) Earlier in CopyReadLine() function while trying to clear the EOL

marker from cstate->line_buf.data (copied data), we were not checking if
the line read by CopyReadLineText() function is a header line or not, but I
can see that your patch checks that before clearing the EOL marker. Any
reason for this extra check?

If you see the caller of CopyReadLine, i.e. NextCopyFromRawFields does
nothing for the header line, server basically calls CopyReadLine
again, it is a kind of small optimization. Anyway server is not going
to do anything with header line, I felt no need to clear EOL marker
for header lines.
/* on input just throw the header line away */
if (cstate->cur_lineno == 0 && cstate->header_line)
{
cstate->cur_lineno++;
if (CopyReadLine(cstate))
return false; /* done */
}

cstate->cur_lineno++;

/* Actually read the line into memory here */
done = CopyReadLine(cstate);
I think no need to make a fix for this. Your thoughts?

5) I noticed the below spurious line removal in the patch.

@@ -3839,7 +3953,6 @@ static bool
CopyReadLine(CopyState cstate)
{
bool result;
-

Fixed.
I have attached the patch for the same with the fixes.
Thoughts?

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

Attachments:

0001-Copy-code-readjustment-to-support-parallel-copy.patchapplication/x-patch; name=0001-Copy-code-readjustment-to-support-parallel-copy.patchDownload
From 4455d3e067bda56316bb292e5d010bdf40254fec Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Tue, 23 Jun 2020 06:49:22 +0530
Subject: [PATCH 1/6] Copy code readjustment to support parallel copy.

This patch has the copy code slightly readjusted so that the common code is
separated to functions/macros, these functions/macros will be used by the
workers in the parallel copy code of the upcoming patches. EOL removal is moved
from CopyReadLine to CopyReadLineText, this change was required because in case
of parallel copy the record identification and record updation is done in
CopyReadLineText, before record information is updated in shared memory the new
line characters should be removed.
---
 src/backend/commands/copy.c | 372 ++++++++++++++++++++++++++------------------
 1 file changed, 221 insertions(+), 151 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 6b1fd6d..65a504f 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -95,6 +95,9 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
+#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+#define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
+
 /*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
@@ -219,7 +222,6 @@ typedef struct CopyStateData
 	 * converts it.  Note: we guarantee that there is a \0 at
 	 * raw_buf[raw_buf_len].
 	 */
-#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
@@ -347,6 +349,88 @@ if (1) \
 	goto not_end_of_copy; \
 } else ((void) 0)
 
+/*
+ * CONVERT_TO_SERVER_ENCODING - convert contents to server encoding.
+ */
+#define CONVERT_TO_SERVER_ENCODING(cstate) \
+{ \
+	/* Done reading the line.  Convert it to server encoding. */ \
+	if (cstate->need_transcoding) \
+	{ \
+		char	   *cvt; \
+		cvt = pg_any_to_server(cstate->line_buf.data, \
+							   cstate->line_buf.len, \
+							   cstate->file_encoding); \
+		if (cvt != cstate->line_buf.data) \
+		{ \
+			/* transfer converted data back to line_buf */ \
+			resetStringInfo(&cstate->line_buf); \
+			appendBinaryStringInfo(&cstate->line_buf, cvt, strlen(cvt)); \
+			pfree(cvt); \
+		} \
+	} \
+	/* Now it's safe to use the buffer in error messages */ \
+	cstate->line_buf_converted = true; \
+}
+
+/*
+ * CLEAR_EOL_FROM_COPIED_DATA - Clear EOL from the copied data.
+ */
+#define CLEAR_EOL_FROM_COPIED_DATA(copy_line_data, copy_line_pos, copy_line_size) \
+{ \
+	/* \
+	 * If we didn't hit EOF, then we must have transferred the EOL marker \
+	 * to line_buf along with the data.  Get rid of it. \
+	 */ \
+   switch (cstate->eol_type) \
+   { \
+	   case EOL_NL: \
+		   Assert(copy_line_size >= 1); \
+		   Assert(copy_line_data[copy_line_pos - 1] == '\n'); \
+		   copy_line_data[copy_line_pos - 1] = '\0'; \
+		   copy_line_size--; \
+		   break; \
+	   case EOL_CR: \
+		   Assert(copy_line_size >= 1); \
+		   Assert(copy_line_data[copy_line_pos - 1] == '\r'); \
+		   copy_line_data[copy_line_pos - 1] = '\0'; \
+		   copy_line_size--; \
+		   break; \
+	   case EOL_CRNL: \
+		   Assert(copy_line_size >= 2); \
+		   Assert(copy_line_data[copy_line_pos - 2] == '\r'); \
+		   Assert(copy_line_data[copy_line_pos - 1] == '\n'); \
+		   copy_line_data[copy_line_pos - 2] = '\0'; \
+		   copy_line_size -= 2; \
+		   break; \
+	   case EOL_UNKNOWN: \
+		   /* shouldn't get here */ \
+		   Assert(false); \
+		   break; \
+   } \
+}
+
+/*
+ * CLEAR_EOL_LINE - Wrapper for clearing EOL.
+ */
+#define CLEAR_EOL_LINE() \
+if (!result && !IsHeaderLine()) \
+	CLEAR_EOL_FROM_COPIED_DATA(cstate->line_buf.data, \
+								cstate->line_buf.len, \
+								cstate->line_buf.len) \
+
+/*
+ * INCREMENTPROCESSED - Increment the lines processed.
+ */
+#define INCREMENTPROCESSED(processed)  \
+processed++;
+
+/*
+ * GETPROCESSED - Get the lines processed.
+ */
+#define GETPROCESSED(processed) \
+return processed;
+
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
 
@@ -392,6 +476,8 @@ static bool CopyGetInt32(CopyState cstate, int32 *val);
 static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 
+static void PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tup_desc,
+							   List *attnamelist);
 
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
@@ -793,6 +879,7 @@ CopyLoadRawBuf(CopyState cstate)
 {
 	int			nbytes;
 	int			inbytes;
+	int         minread = 1;
 
 	if (cstate->raw_buf_index < cstate->raw_buf_len)
 	{
@@ -804,8 +891,11 @@ CopyLoadRawBuf(CopyState cstate)
 	else
 		nbytes = 0;				/* no data need be saved */
 
+	if (cstate->copy_dest == COPY_NEW_FE)
+		minread = RAW_BUF_SIZE - nbytes;
+
 	inbytes = CopyGetData(cstate, cstate->raw_buf + nbytes,
-						  1, RAW_BUF_SIZE - nbytes);
+						  minread, RAW_BUF_SIZE - nbytes);
 	nbytes += inbytes;
 	cstate->raw_buf[nbytes] = '\0';
 	cstate->raw_buf_index = 0;
@@ -1463,7 +1553,6 @@ BeginCopy(ParseState *pstate,
 {
 	CopyState	cstate;
 	TupleDesc	tupDesc;
-	int			num_phys_attrs;
 	MemoryContext oldcontext;
 
 	/* Allocate workspace and zero all fields */
@@ -1629,6 +1718,24 @@ BeginCopy(ParseState *pstate,
 		tupDesc = cstate->queryDesc->tupDesc;
 	}
 
+	PopulateGlobalsForCopyFrom(cstate, tupDesc, attnamelist);
+	cstate->copy_dest = COPY_FILE;	/* default */
+
+	MemoryContextSwitchTo(oldcontext);
+
+	return cstate;
+}
+
+/*
+ * PopulateGlobalsForCopyFrom - Populates the common variables required for copy
+ * from operation. This is a helper function for BeginCopy function.
+ */
+static void
+PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tupDesc,
+							List *attnamelist)
+{
+	int			num_phys_attrs;
+
 	/* Generate or convert list of attributes to process */
 	cstate->attnumlist = CopyGetAttnums(tupDesc, cstate->rel, attnamelist);
 
@@ -1748,12 +1855,6 @@ BeginCopy(ParseState *pstate,
 		 pg_database_encoding_max_length() > 1);
 	/* See Multibyte encoding comment above */
 	cstate->encoding_embeds_ascii = PG_ENCODING_IS_CLIENT_ONLY(cstate->file_encoding);
-
-	cstate->copy_dest = COPY_FILE;	/* default */
-
-	MemoryContextSwitchTo(oldcontext);
-
-	return cstate;
 }
 
 /*
@@ -2646,32 +2747,11 @@ CopyMultiInsertInfoStore(CopyMultiInsertInfo *miinfo, ResultRelInfo *rri,
 }
 
 /*
- * Copy FROM file to relation.
+ * Check if the relation specified in copy from is valid.
  */
-uint64
-CopyFrom(CopyState cstate)
+static void
+CheckTargetRelValidity(CopyState cstate)
 {
-	ResultRelInfo *resultRelInfo;
-	ResultRelInfo *target_resultRelInfo;
-	ResultRelInfo *prevResultRelInfo = NULL;
-	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
-	ModifyTableState *mtstate;
-	ExprContext *econtext;
-	TupleTableSlot *singleslot = NULL;
-	MemoryContext oldcontext = CurrentMemoryContext;
-
-	PartitionTupleRouting *proute = NULL;
-	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
-	int			ti_options = 0; /* start with default options for insert */
-	BulkInsertState bistate = NULL;
-	CopyInsertMethod insertMethod;
-	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
-	uint64		processed = 0;
-	bool		has_before_insert_row_trig;
-	bool		has_instead_insert_row_trig;
-	bool		leafpart_use_multi_insert = false;
-
 	Assert(cstate->rel);
 
 	/*
@@ -2708,27 +2788,6 @@ CopyFrom(CopyState cstate)
 							RelationGetRelationName(cstate->rel))));
 	}
 
-	/*
-	 * If the target file is new-in-transaction, we assume that checking FSM
-	 * for free space is a waste of time.  This could possibly be wrong, but
-	 * it's unlikely.
-	 */
-	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
-		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
-		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
-		ti_options |= TABLE_INSERT_SKIP_FSM;
-
-	/*
-	 * Optimize if new relfilenode was created in this subxact or one of its
-	 * committed children and we won't see those rows later as part of an
-	 * earlier scan or command. The subxact test ensures that if this subxact
-	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
-	 * that the stronger test of exactly which subtransaction created it is
-	 * crucial for correctness of this optimization. The test for an earlier
-	 * scan or command tolerates false negatives. FREEZE causes other sessions
-	 * to see rows they would not see under MVCC, and a false negative merely
-	 * spreads that anomaly to the current session.
-	 */
 	if (cstate->freeze)
 	{
 		/*
@@ -2766,9 +2825,61 @@ CopyFrom(CopyState cstate)
 			ereport(ERROR,
 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 					 errmsg("cannot perform COPY FREEZE because the table was not created or truncated in the current subtransaction")));
+	}
+}
+
+/*
+ * Copy FROM file to relation.
+ */
+uint64
+CopyFrom(CopyState cstate)
+{
+	ResultRelInfo *resultRelInfo;
+	ResultRelInfo *target_resultRelInfo;
+	ResultRelInfo *prevResultRelInfo = NULL;
+	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
+	ModifyTableState *mtstate;
+	ExprContext *econtext;
+	TupleTableSlot *singleslot = NULL;
+	MemoryContext oldcontext = CurrentMemoryContext;
+
+	PartitionTupleRouting *proute = NULL;
+	ErrorContextCallback errcallback;
+	CommandId	mycid = GetCurrentCommandId(true);
+	int			ti_options = 0; /* start with default options for insert */
+	BulkInsertState bistate = NULL;
+	CopyInsertMethod insertMethod;
+	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
+	uint64		processed = 0;
+	bool		has_before_insert_row_trig;
+	bool		has_instead_insert_row_trig;
+	bool		leafpart_use_multi_insert = false;
+
+	CheckTargetRelValidity(cstate);
 
+	/*
+	 * If the target file is new-in-transaction, we assume that checking FSM
+	 * for free space is a waste of time.  This could possibly be wrong, but
+	 * it's unlikely.
+	 */
+	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
+		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
+		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
+		ti_options |= TABLE_INSERT_SKIP_FSM;
+
+	/*
+	 * Optimize if new relfilenode was created in this subxact or one of its
+	 * committed children and we won't see those rows later as part of an
+	 * earlier scan or command. The subxact test ensures that if this subxact
+	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
+	 * that the stronger test of exactly which subtransaction created it is
+	 * crucial for correctness of this optimization. The test for an earlier
+	 * scan or command tolerates false negatives. FREEZE causes other sessions
+	 * to see rows they would not see under MVCC, and a false negative merely
+	 * spreads that anomaly to the current session.
+	 */
+	if (cstate->freeze)
 		ti_options |= TABLE_INSERT_FROZEN;
-	}
 
 	/*
 	 * We need a ResultRelInfo so we can use the regular executor's
@@ -3261,7 +3372,7 @@ CopyFrom(CopyState cstate)
 			 * or FDW; this is the same definition used by nodeModifyTable.c
 			 * for counting tuples inserted by an INSERT command.
 			 */
-			processed++;
+			INCREMENTPROCESSED(processed)
 		}
 	}
 
@@ -3316,30 +3427,15 @@ CopyFrom(CopyState cstate)
 
 	FreeExecutorState(estate);
 
-	return processed;
+	GETPROCESSED(processed)
 }
 
 /*
- * Setup to read tuples from a file for COPY FROM.
- *
- * 'rel': Used as a template for the tuples
- * 'filename': Name of server-local file to read
- * 'attnamelist': List of char *, columns to include. NIL selects all cols.
- * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
- *
- * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ * PopulateCatalogInformation - populate the catalog information.
  */
-CopyState
-BeginCopyFrom(ParseState *pstate,
-			  Relation rel,
-			  const char *filename,
-			  bool is_program,
-			  copy_data_source_cb data_source_cb,
-			  List *attnamelist,
-			  List *options)
+static void
+PopulateCatalogInformation(CopyState cstate)
 {
-	CopyState	cstate;
-	bool		pipe = (filename == NULL);
 	TupleDesc	tupDesc;
 	AttrNumber	num_phys_attrs,
 				num_defaults;
@@ -3349,31 +3445,8 @@ BeginCopyFrom(ParseState *pstate,
 	Oid			in_func_oid;
 	int		   *defmap;
 	ExprState **defexprs;
-	MemoryContext oldcontext;
 	bool		volatile_defexprs;
 
-	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
-	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
-
-	/* Initialize state variables */
-	cstate->reached_eof = false;
-	cstate->eol_type = EOL_UNKNOWN;
-	cstate->cur_relname = RelationGetRelationName(cstate->rel);
-	cstate->cur_lineno = 0;
-	cstate->cur_attname = NULL;
-	cstate->cur_attval = NULL;
-
-	/* Set up variables to avoid per-attribute overhead. */
-	initStringInfo(&cstate->attribute_buf);
-	initStringInfo(&cstate->line_buf);
-	cstate->line_buf_converted = false;
-	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
-	cstate->raw_buf_index = cstate->raw_buf_len = 0;
-
-	/* Assign range table, we'll need it in CopyFrom. */
-	if (pstate)
-		cstate->range_table = pstate->p_rtable;
-
 	tupDesc = RelationGetDescr(cstate->rel);
 	num_phys_attrs = tupDesc->natts;
 	num_defaults = 0;
@@ -3451,6 +3524,54 @@ BeginCopyFrom(ParseState *pstate,
 	cstate->defexprs = defexprs;
 	cstate->volatile_defexprs = volatile_defexprs;
 	cstate->num_defaults = num_defaults;
+}
+
+/*
+ * Setup to read tuples from a file for COPY FROM.
+ *
+ * 'rel': Used as a template for the tuples
+ * 'filename': Name of server-local file to read
+ * 'attnamelist': List of char *, columns to include. NIL selects all cols.
+ * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
+ *
+ * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ */
+CopyState
+BeginCopyFrom(ParseState *pstate,
+			  Relation rel,
+			  const char *filename,
+			  bool is_program,
+			  copy_data_source_cb data_source_cb,
+			  List *attnamelist,
+			  List *options)
+{
+	CopyState	cstate;
+	bool		pipe = (filename == NULL);
+	MemoryContext oldcontext;
+
+	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	/* Initialize state variables */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/* Set up variables to avoid per-attribute overhead. */
+	initStringInfo(&cstate->attribute_buf);
+	initStringInfo(&cstate->line_buf);
+	cstate->line_buf_converted = false;
+	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+
+	/* Assign range table, we'll need it in CopyFrom. */
+	if (pstate)
+		cstate->range_table = pstate->p_rtable;
+
+	PopulateCatalogInformation(cstate);
 	cstate->is_program = is_program;
 
 	if (data_source_cb)
@@ -3860,60 +3981,8 @@ CopyReadLine(CopyState cstate)
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
-	else
-	{
-		/*
-		 * If we didn't hit EOF, then we must have transferred the EOL marker
-		 * to line_buf along with the data.  Get rid of it.
-		 */
-		switch (cstate->eol_type)
-		{
-			case EOL_NL:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CR:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\r');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CRNL:
-				Assert(cstate->line_buf.len >= 2);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 2] == '\r');
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len -= 2;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_UNKNOWN:
-				/* shouldn't get here */
-				Assert(false);
-				break;
-		}
-	}
-
-	/* Done reading the line.  Convert it to server encoding. */
-	if (cstate->need_transcoding)
-	{
-		char	   *cvt;
-
-		cvt = pg_any_to_server(cstate->line_buf.data,
-							   cstate->line_buf.len,
-							   cstate->file_encoding);
-		if (cvt != cstate->line_buf.data)
-		{
-			/* transfer converted data back to line_buf */
-			resetStringInfo(&cstate->line_buf);
-			appendBinaryStringInfo(&cstate->line_buf, cvt, strlen(cvt));
-			pfree(cvt);
-		}
-	}
-
-	/* Now it's safe to use the buffer in error messages */
-	cstate->line_buf_converted = true;
 
+	CONVERT_TO_SERVER_ENCODING(cstate)
 	return result;
 }
 
@@ -4277,6 +4346,7 @@ not_end_of_copy:
 	 * Transfer any still-uncopied data to line_buf.
 	 */
 	REFILL_LINEBUF;
+	CLEAR_EOL_LINE()
 
 	return result;
 }
-- 
1.8.3.1

0004-Documentation-for-parallel-copy.patchapplication/x-patch; name=0004-Documentation-for-parallel-copy.patchDownload
From f06311aab275234125ed5b2c1a5c4740db55df3f Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 17 Jun 2020 07:34:56 +0530
Subject: [PATCH 4/6] Documentation for parallel copy.

This patch has the documentation changes for parallel copy.
---
 doc/src/sgml/ref/copy.sgml | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/doc/src/sgml/ref/copy.sgml b/doc/src/sgml/ref/copy.sgml
index 18189ab..95d349d 100644
--- a/doc/src/sgml/ref/copy.sgml
+++ b/doc/src/sgml/ref/copy.sgml
@@ -37,6 +37,7 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
     DELIMITER '<replaceable class="parameter">delimiter_character</replaceable>'
     NULL '<replaceable class="parameter">null_string</replaceable>'
     HEADER [ <replaceable class="parameter">boolean</replaceable> ]
+    PARALLEL <replaceable class="parameter">integer</replaceable>
     QUOTE '<replaceable class="parameter">quote_character</replaceable>'
     ESCAPE '<replaceable class="parameter">escape_character</replaceable>'
     FORCE_QUOTE { ( <replaceable class="parameter">column_name</replaceable> [, ...] ) | * }
@@ -275,6 +276,21 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
    </varlistentry>
 
    <varlistentry>
+    <term><literal>PARALLEL</literal></term>
+    <listitem>
+     <para>
+      Perform <command>COPY FROM</command> in parallel using <replaceable
+      class="parameter"> integer</replaceable> background workers.  Please
+      note that it is not guaranteed that the number of parallel workers
+      specified in <replaceable class="parameter">integer</replaceable> will
+      be used during execution.  It is possible for a copy to run with fewer
+      workers than specified, or even with no workers at all.  This option is
+      allowed only in <command>COPY FROM</command>.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><literal>QUOTE</literal></term>
     <listitem>
      <para>
-- 
1.8.3.1

0003-Allow-copy-from-command-to-process-data-from-file-ST.patchapplication/x-patch; name=0003-Allow-copy-from-command-to-process-data-from-file-ST.patchDownload
From efc6dcb1ad7285c4e7486cd152c5908a48a7544d Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>, Bharath <bharath.rupireddyforpostgres@gmail.com>
Date: Tue, 23 Jun 2020 07:15:43 +0530
Subject: [PATCH 3/6] Allow copy from command to process data from file/STDIN
 contents to a table in parallel.

This feature allows the copy from to leverage multiple CPUs in order to copy
data from file/STDIN to a table. This adds a PARALLEL option to COPY FROM
command where the user can specify the number of workers that can be used
to perform the COPY FROM command. Specifying zero as number of workers will
disable parallelism.
The backend, to which the "COPY FROM" query is submitted acts as leader with
the responsibility of reading data from the file/stdin, launching at most n
number of workers as specified with PARALLEL 'n' option in the "COPY FROM"
query. The leader populates the common data required for the workers execution
in the DSM and shares it with the workers. The leader then executes before
statement triggers if there exists any. Leader populates DSM lines which
includes the start offset and line size, while populating the lines it reads
as many blocks as required into the DSM data blocks from the file. Each block
is of 64K size. The leader parses the data to identify a line, the existing
logic from CopyReadLineText which identifies the lines with some changes was
used for this. Leader checks if a free line is available to copy the
information, if there is no free line it waits till the required line is
freed up by the worker and then copies the identified lines information
(offset & line size) into the DSM lines. This process is repeated till the
complete file is processed. Simultaneously, the workers cache the lines(50)
locally into the local memory and release the lines to the leader for further
populating. Each worker processes the lines that it cached and inserts it into
the table. The leader does not participate in the insertion of data, leaders
only responsibility will be to identify the lines as fast as possible for the
workers to do the actual copy operation. The leader waits till all the lines
populated are processed by the workers and exits.
---
 src/backend/access/heap/heapam.c  |  13 -
 src/backend/access/transam/xact.c |  13 +
 src/backend/commands/copy.c       | 896 ++++++++++++++++++++++++++++++++++++--
 src/include/access/xact.h         |   1 +
 src/tools/pgindent/typedefs.list  |   1 +
 5 files changed, 873 insertions(+), 51 deletions(-)

diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 537913d..28f3a98 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2012,19 +2012,6 @@ static HeapTuple
 heap_prepare_insert(Relation relation, HeapTuple tup, TransactionId xid,
 					CommandId cid, int options)
 {
-	/*
-	 * Parallel operations are required to be strictly read-only in a parallel
-	 * worker.  Parallel inserts are not safe even in the leader in the
-	 * general case, because group locking means that heavyweight locks for
-	 * relation extension or GIN page locks will not conflict between members
-	 * of a lock group, but we don't prohibit that case here because there are
-	 * useful special cases that we can safely allow, such as CREATE TABLE AS.
-	 */
-	if (IsParallelWorker())
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_TRANSACTION_STATE),
-				 errmsg("cannot insert tuples in a parallel worker")));
-
 	tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
 	tup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK);
 	tup->t_data->t_infomask |= HEAP_XMAX_INVALID;
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 905dc7d..66f7236 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -502,6 +502,19 @@ GetCurrentFullTransactionIdIfAny(void)
 }
 
 /*
+ *	AssignFullTransactionIdForWorker
+ *
+ * For parallel copy, all the workers must use the same transaction id.
+ */
+void AssignFullTransactionIdForWorker(FullTransactionId fullTransactionId)
+{
+	TransactionState s = CurrentTransactionState;
+
+	Assert((IsInParallelMode() || IsParallelWorker()));
+	s->fullTransactionId = fullTransactionId;
+}
+
+/*
  *	MarkCurrentTransactionIdLoggedIfAny
  *
  * Remember that the current xid - if it is assigned - now has been wal logged.
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 34c657c..e8a89a4 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -26,6 +26,7 @@
 #include "access/xlog.h"
 #include "catalog/dependency.h"
 #include "catalog/pg_authid.h"
+#include "catalog/pg_proc_d.h"
 #include "catalog/pg_type.h"
 #include "commands/copy.h"
 #include "commands/defrem.h"
@@ -40,11 +41,13 @@
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
+#include "optimizer/clauses.h"
 #include "optimizer/optimizer.h"
 #include "parser/parse_coerce.h"
 #include "parser/parse_collate.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_relation.h"
+#include "pgstat.h"
 #include "port/pg_bswap.h"
 #include "rewrite/rewriteHandler.h"
 #include "storage/fd.h"
@@ -95,6 +98,18 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
+/*
+ * State of the line.
+ */
+typedef enum ParallelCopyLineState
+{
+	LINE_INIT,					/* initial state of line */
+	LINE_LEADER_POPULATING,		/* leader processing line */
+	LINE_LEADER_POPULATED,		/* leader completed populating line */
+	LINE_WORKER_PROCESSING,		/* worker processing line */
+	LINE_WORKER_PROCESSED		/* worker completed processing line */
+}ParallelCopyLineState;
+
 #define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
 
 #define DATA_BLOCK_SIZE RAW_BUF_SIZE
@@ -538,9 +553,13 @@ if (1) \
 { \
 	if (raw_buf_ptr > cstate->raw_buf_index) \
 	{ \
-		appendBinaryStringInfo(&cstate->line_buf, \
-							 cstate->raw_buf + cstate->raw_buf_index, \
-							   raw_buf_ptr - cstate->raw_buf_index); \
+		if (!IsParallelCopy()) \
+			appendBinaryStringInfo(&cstate->line_buf, \
+								   cstate->raw_buf + cstate->raw_buf_index, \
+								   raw_buf_ptr - cstate->raw_buf_index); \
+		else \
+			line_size +=  raw_buf_ptr - cstate->raw_buf_index; \
+		\
 		cstate->raw_buf_index = raw_buf_ptr; \
 	} \
 } else ((void) 0)
@@ -553,13 +572,40 @@ if (1) \
 	goto not_end_of_copy; \
 } else ((void) 0)
 
+/* Begin parallel copy Macros */
+#define SET_NEWLINE_SIZE() \
+{ \
+	if (cstate->eol_type == EOL_NL || cstate->eol_type == EOL_CR) \
+		new_line_size = 1; \
+	else if (cstate->eol_type == EOL_CRNL) \
+		new_line_size = 2; \
+	else \
+		new_line_size = 0; \
+}
+
+/*
+ * COPY_WAIT_TO_PROCESS - Wait before continuing to process.
+ */
+#define COPY_WAIT_TO_PROCESS() \
+{ \
+	CHECK_FOR_INTERRUPTS(); \
+	(void) WaitLatch(MyLatch, \
+					 WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH, \
+					 1L, WAIT_EVENT_PG_SLEEP); \
+	ResetLatch(MyLatch); \
+}
+
+/* End parallel copy Macros */
+
 /*
  * CONVERT_TO_SERVER_ENCODING - convert contents to server encoding.
  */
 #define CONVERT_TO_SERVER_ENCODING(cstate) \
 { \
 	/* Done reading the line.  Convert it to server encoding. */ \
-	if (cstate->need_transcoding) \
+	if (cstate->need_transcoding && \
+		(!IsParallelCopy() || \
+		 (IsParallelCopy() && !IsLeader()))) \
 	{ \
 		char	   *cvt; \
 		cvt = pg_any_to_server(cstate->line_buf.data, \
@@ -618,22 +664,38 @@ if (1) \
  * CLEAR_EOL_LINE - Wrapper for clearing EOL.
  */
 #define CLEAR_EOL_LINE() \
-if (!result && !IsHeaderLine()) \
-	CLEAR_EOL_FROM_COPIED_DATA(cstate->line_buf.data, \
-								cstate->line_buf.len, \
-								cstate->line_buf.len) \
+{ \
+	if (!result && !IsHeaderLine()) \
+	{ \
+		if (IsParallelCopy()) \
+			CLEAR_EOL_FROM_COPIED_DATA(cstate->raw_buf, \
+									   raw_buf_ptr, line_size) \
+		else \
+			CLEAR_EOL_FROM_COPIED_DATA(cstate->line_buf.data, \
+									   cstate->line_buf.len, \
+									   cstate->line_buf.len) \
+	} \
+}
 
 /*
  * INCREMENTPROCESSED - Increment the lines processed.
  */
-#define INCREMENTPROCESSED(processed)  \
-processed++;
+#define INCREMENTPROCESSED(processed) \
+{ \
+	if (!IsParallelCopy()) \
+		processed++; \
+	else \
+		pg_atomic_add_fetch_u64(&cstate->pcdata->pcshared_info->processed, 1); \
+}
 
 /*
  * GETPROCESSED - Get the lines processed.
  */
 #define GETPROCESSED(processed) \
-return processed;
+if (!IsParallelCopy()) \
+	return processed; \
+else \
+	return pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
 
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
@@ -681,8 +743,12 @@ static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 
 static pg_attribute_always_inline void EndParallelCopy(ParallelContext *pcxt);
+static void ExecBeforeStmtTrigger(CopyState cstate);
+static void CheckTargetRelValidity(CopyState cstate);
 static void PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tup_desc,
 							   List *attnamelist);
+static void PopulateCatalogInformation(CopyState cstate);
+static pg_attribute_always_inline uint32 GetLinePosition(CopyState cstate);
 static pg_attribute_always_inline copy_data_source_cb LookupParallelCopyFnPtr(const char *funcname);
 static pg_attribute_always_inline char* LookupParallelCopyFnStr(copy_data_source_cb fn_addr);
 
@@ -836,6 +902,137 @@ InsertListShm(ParallelContext *pcxt, int key, List *inputlist,
 }
 
 /*
+ * IsTriggerFunctionParallelSafe - Check if the trigger function is parallel
+ * safe for the triggers. Return false if any one of the trigger has parallel
+ * unsafe function.
+ */
+static pg_attribute_always_inline bool
+IsTriggerFunctionParallelSafe(TriggerDesc *trigdesc)
+{
+	int	i;
+	for (i = 0; i < trigdesc->numtriggers; i++)
+	{
+		Trigger    *trigger = &trigdesc->triggers[i];
+		int 		trigtype = RI_TRIGGER_NONE;
+
+		if (func_parallel(trigger->tgfoid) != PROPARALLEL_SAFE)
+			return false;
+
+		/* If the trigger is parallel safe, also look for RI_TRIGGER. */
+		trigtype = RI_FKey_trigger_type(trigger->tgfoid);
+		if (trigtype == RI_TRIGGER_PK || trigtype == RI_TRIGGER_FK)
+			return false;
+	}
+
+	return true;
+}
+
+/*
+ * CheckExprParallelSafety - determine parallel safety of volatile expressions
+ * in default clause of column definition or in where clause and return true if
+ * they are parallel safe.
+ */
+static pg_attribute_always_inline bool
+CheckExprParallelSafety(CopyState cstate)
+{
+	if (contain_volatile_functions(cstate->whereClause))
+	{
+		if (max_parallel_hazard((Query *)cstate->whereClause) != PROPARALLEL_SAFE)
+			return false;
+	}
+
+	/*
+	 * Check if any of the column has volatile default expression. if yes, and
+	 * they are not parallel safe, then parallelism is not allowed. For
+	 * instance, if there are any serial/bigserial columns for which nextval()
+	 * default expression which is parallel unsafe is associated, parallelism
+	 * should not be allowed. In non paralllel copy volatile functions are not
+	 * checked for nextval().
+	 */
+	if (cstate->defexprs != NULL && cstate->num_defaults != 0)
+	{
+		int     i;
+		for (i = 0; i < cstate->num_defaults; i++)
+		{
+			bool volatile_expr = contain_volatile_functions((Node *)cstate->defexprs[i]->expr);
+			if (volatile_expr &&
+				(max_parallel_hazard((Query *)cstate->defexprs[i]->expr)) !=
+				 PROPARALLEL_SAFE)
+				return false;
+		}
+	}
+
+	return true;
+}
+
+/*
+ * FindInsertMethod - determine insert mode single, multi, or multi conditional.
+ */
+static pg_attribute_always_inline CopyInsertMethod
+FindInsertMethod(CopyState cstate)
+{
+	if (cstate->rel->trigdesc != NULL &&
+		(cstate->rel->trigdesc->trig_insert_before_row ||
+		 cstate->rel->trigdesc->trig_insert_instead_row))
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
+			cstate->rel->trigdesc != NULL &&
+			cstate->rel->trigdesc->trig_insert_new_table)
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+		return CIM_MULTI_CONDITIONAL;
+
+	return CIM_MULTI;
+}
+
+/*
+ * IsParallelCopyAllowed - check for the cases where parallel copy is not
+ * applicable.
+ */
+static pg_attribute_always_inline bool
+IsParallelCopyAllowed(CopyState cstate)
+{
+	/* Parallel copy not allowed for frontend (2.0 protocol) & binary option. */
+	if ((cstate->copy_dest == COPY_OLD_FE) || cstate->binary)
+		return false;
+
+	/* Check if copy is into foreign table or temporary table. */
+	if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
+		RelationUsesLocalBuffers(cstate->rel))
+		return false;
+
+	/* Check if trigger function is parallel safe. */
+	if (cstate->rel->trigdesc != NULL &&
+		!IsTriggerFunctionParallelSafe(cstate->rel->trigdesc))
+		return false;
+
+	/*
+	 * Check if there is after statement or instead of trigger or transition
+	 * table triggers.
+	 */
+	if (cstate->rel->trigdesc != NULL &&
+		(cstate->rel->trigdesc->trig_insert_after_statement ||
+		 cstate->rel->trigdesc->trig_insert_instead_row ||
+		 cstate->rel->trigdesc->trig_insert_new_table))
+		return false;
+
+	/* Check if the volatile expressions are parallel safe, if present any. */
+	if (!CheckExprParallelSafety(cstate))
+		return false;
+
+	/* Check if the insertion mode is single. */
+	if (FindInsertMethod(cstate) == CIM_SINGLE)
+		return false;
+
+	return true;
+}
+
+/*
  * BeginParallelCopy - start parallel copy tasks.
  *
  * Get the number of workers required to perform the parallel copy. The data
@@ -865,6 +1062,8 @@ BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
 	int  parallel_workers = 0;
 	ParallelCopyData *pcdata;
 
+	CheckTargetRelValidity(cstate);
+
 	parallel_workers = Min(nworkers, max_worker_processes);
 
 	/* Can't perform copy in parallel */
@@ -878,6 +1077,19 @@ BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
 	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
 	cstate->pcdata = pcdata;
 
+	/*
+	 * User chosen parallel copy. Determine if the parallel copy is actually
+	 * allowed. If not, go with the non-parallel mode.
+	 */
+	if (!IsParallelCopyAllowed(cstate))
+	{
+		elog(WARNING,
+			 "Parallel copy not supported for specified table, copy will be run in non-parallel mode");
+		return NULL;
+	}
+
+	full_transaction_id = GetCurrentFullTransactionId();
+
 	EnterParallelMode();
 	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
 								 parallel_workers);
@@ -1108,7 +1320,211 @@ ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
 	cstate->line_buf_converted = false;
 	cstate->raw_buf = NULL;
 	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+
+	PopulateCatalogInformation(cstate);
+
+	/* Create workspace for CopyReadAttributes results. */
+	if (!cstate->binary)
+	{
+		AttrNumber	attr_count = list_length(cstate->attnumlist);
+
+		cstate->max_fields = attr_count;
+		cstate->raw_fields = (char **)palloc(attr_count * sizeof(char *));
+	}
+}
+
+/*
+ * CacheLineInfo - Cache the line information to local memory.
+ */
+static bool
+CacheLineInfo(CopyState cstate, uint32 buff_count)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	uint32			write_pos;
+	ParallelCopyDataBlock *data_blk_ptr;
+	ParallelCopyLineBoundary *lineInfo;
+	uint32 offset;
+	int dataSize;
+	int copiedSize = 0;
+
+	resetStringInfo(&pcdata->worker_line_buf[buff_count].line_buf);
+	write_pos = GetLinePosition(cstate);
+	if (-1 == write_pos)
+		return true;
+
+	/* Get the current line information. */
+	lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+	if (pg_atomic_read_u32(&lineInfo->line_size) == 0)
+		goto empty_data_line_update;
+
+	/* Get the block information. */
+	data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+	/* Get the offset information from where the data must be copied. */
+	offset = lineInfo->start_offset;
+	pcdata->worker_line_buf[buff_count].cur_lineno = lineInfo->cur_lineno;
+
+	elog(DEBUG1, "[Worker] Processing - line position:%d, block:%d, unprocessed lines:%d, offset:%d, line size:%d",
+				 write_pos, lineInfo->first_block,
+				 pg_atomic_read_u32(&data_blk_ptr->unprocessed_line_parts),
+				 offset, pg_atomic_read_u32(&lineInfo->line_size));
+
+	for (;;)
+	{
+		uint8 skip_bytes = data_blk_ptr->skip_bytes;
+		/*
+		 * There is a possibility that the above loop has come out because
+		 * data_blk_ptr->curr_blk_completed is set, but dataSize read might
+		 * be an old value, if data_blk_ptr->curr_blk_completed and the line is
+		 * completed, line_size will be set. Read the line_size again to be
+		 * sure if it is complete or partial block.
+		 */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+		if (dataSize)
+		{
+			int remainingSize = dataSize - copiedSize;
+			if (!remainingSize)
+				break;
+
+			/* Whole line is in current block. */
+			if (remainingSize + offset + skip_bytes < DATA_BLOCK_SIZE)
+			{
+				appendBinaryStringInfo(&pcdata->worker_line_buf[buff_count].line_buf,
+									   &data_blk_ptr->data[offset],
+									   remainingSize);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts,
+										1);
+				break;
+			}
+			else
+			{
+				/* Line is spread across the blocks. */
+				uint32 lineInCurrentBlock =  (DATA_BLOCK_SIZE - skip_bytes) - offset;
+				appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+										 &data_blk_ptr->data[offset],
+										 lineInCurrentBlock);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+				copiedSize += lineInCurrentBlock;
+				while (copiedSize < dataSize)
+				{
+					uint32 currentBlockCopySize;
+					ParallelCopyDataBlock *currBlkPtr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+					skip_bytes = currBlkPtr->skip_bytes;
+
+					/*
+					 * If complete data is present in current block use
+					 * dataSize - copiedSize, or copy the whole block from
+					 * current block.
+					 */
+					currentBlockCopySize = Min(dataSize - copiedSize, DATA_BLOCK_SIZE - skip_bytes);
+					appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+											 &currBlkPtr->data[0],
+											 currentBlockCopySize);
+					pg_atomic_sub_fetch_u32(&currBlkPtr->unprocessed_line_parts, 1);
+					copiedSize += currentBlockCopySize;
+					data_blk_ptr = currBlkPtr;
+				}
+
+				break;
+			}
+		}
+		else
+		{
+			/* Copy this complete block from the current offset. */
+			uint32 lineInCurrentBlock =  (DATA_BLOCK_SIZE - skip_bytes) - offset;
+			appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+									 &data_blk_ptr->data[offset],
+									 lineInCurrentBlock);
+			pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+			copiedSize += lineInCurrentBlock;
+
+			/*
+			 * Reset the offset. For the first copy, copy from the offset. For
+			 * the subsequent copy the complete block.
+			 */
+			offset = 0;
+
+			/* Set data_blk_ptr to the following block. */
+			data_blk_ptr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+		}
+
+		for (;;)
+		{
+			/* Get the size of this line */
+			dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+			/*
+			 * If the data is present in current block lineInfo.line_size
+			 * will be updated. If the data is spread across the blocks either
+			 * of lineInfo.line_size or data_blk_ptr->curr_blk_completed can
+			 * be updated. lineInfo.line_size will be updated if the complete
+			 * read is finished. data_blk_ptr->curr_blk_completed will be
+			 * updated if processing of current block is finished and data
+			 * processing is not finished.
+			 */
+			if (data_blk_ptr->curr_blk_completed || (dataSize != -1))
+				break;
+
+			COPY_WAIT_TO_PROCESS()
+		}
+	}
+
+empty_data_line_update:
+	elog(DEBUG1, "[Worker] Completed processing line:%d", write_pos);
+	pg_atomic_write_u32(&lineInfo->line_state, LINE_WORKER_PROCESSED);
+	pg_atomic_write_u32(&lineInfo->line_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+	return false;
+}
+
+/*
+ * GetWorkerLine - Returns a line for worker to process.
+ */
+static bool
+GetWorkerLine(CopyState cstate)
+{
+	uint32 buff_count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+
+	/*
+	 * Copy the line data to line_buf and release the line position so that the
+	 * worker can continue loading data.
+	 */
+	if (pcdata->worker_line_buf_pos < pcdata->worker_line_buf_count)
+		goto return_line;
+
+	pcdata->worker_line_buf_pos = 0;
+	pcdata->worker_line_buf_count = 0;
+
+	for (buff_count = 0; buff_count < WORKER_CHUNK_COUNT; buff_count++)
+	{
+		bool result = CacheLineInfo(cstate, buff_count);
+		if (result)
+			break;
+
+		pcdata->worker_line_buf_count++;
+	}
+
+	if (pcdata->worker_line_buf_count)
+		goto return_line;
+	else
+		resetStringInfo(&cstate->line_buf);
+
+	return true;
+
+return_line:
+	cstate->line_buf = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].line_buf;
+	cstate->cur_lineno = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].cur_lineno;
+	cstate->line_buf_valid = true;
+
+	/* Mark that encoding conversion hasn't occurred yet. */
+	cstate->line_buf_converted = false;
+	CONVERT_TO_SERVER_ENCODING(cstate)
+	pcdata->worker_line_buf_pos++;
+	return false;
 }
+
 /*
  * ParallelCopyMain - parallel copy worker's code.
  *
@@ -1154,6 +1570,7 @@ ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
 	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
 
 	pcdata->pcshared_info = pcshared_info;
+	AssignFullTransactionIdForWorker(pcshared_info->full_transaction_id);
 
 	shared_cstate = (ParallelCopyCommonKeyData *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE,
 														   false);
@@ -1206,6 +1623,34 @@ ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
 	MemoryContextSwitchTo(oldcontext);
 	return;
 }
+
+/*
+ * UpdateBlockInLineInfo - Update the line information.
+ */
+static pg_attribute_always_inline int
+UpdateBlockInLineInfo(CopyState cstate, uint32 blk_pos,
+					   uint32 offset, uint32 line_size, uint32 line_state)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyLineBoundaries *lineBoundaryPtr = &pcshared_info->line_boundaries;
+	ParallelCopyLineBoundary *lineInfo;
+	int line_pos = lineBoundaryPtr->leader_pos;
+
+	/* Update the line information for the worker to pick and process. */
+	lineInfo = &lineBoundaryPtr->ring[line_pos];
+	while (pg_atomic_read_u32(&lineInfo->line_size) != -1)
+		COPY_WAIT_TO_PROCESS()
+
+	lineInfo->first_block = blk_pos;
+	lineInfo->start_offset = offset;
+	lineInfo->cur_lineno = cstate->cur_lineno;
+	pg_atomic_write_u32(&lineInfo->line_size, line_size);
+	pg_atomic_write_u32(&lineInfo->line_state, line_state);
+	lineBoundaryPtr->leader_pos = (lineBoundaryPtr->leader_pos + 1) % RINGSIZE;
+
+	return line_pos;
+}
+
 /*
  * ParallelCopyLeader - parallel copy leader's functionality.
  *
@@ -1231,9 +1676,158 @@ ParallelCopyLeader(CopyState cstate)
 	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
 	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
 
+	/* Execute the before statement triggers from the leader */
+	ExecBeforeStmtTrigger(cstate);
+
+	/* On input just throw the header line away. */
+	if (cstate->cur_lineno == 0 && cstate->header_line)
+	{
+		cstate->cur_lineno++;
+		if (CopyReadLine(cstate))
+		{
+			pcshared_info->is_read_in_progress = false;
+			return;			/* done */
+		}
+	}
+
+	for (;;)
+	{
+		bool done;
+		cstate->cur_lineno++;
+
+		/* Actually read the line into memory here. */
+		done = CopyReadLine(cstate);
+
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			break;
+	}
+
 	pcshared_info->is_read_in_progress = false;
 	cstate->cur_lineno = 0;
 }
+
+/*
+ * GetLinePosition - return the line position that worker should process.
+ */
+static uint32
+GetLinePosition(CopyState cstate)
+{
+	ParallelCopyData *pcdata = cstate->pcdata;
+	ParallelCopyShmInfo *pcshared_info = pcdata->pcshared_info;
+	uint32  previous_pos = pcdata->worker_processed_pos;
+	uint32 write_pos = (previous_pos == -1) ? 0 : (previous_pos + 1) % RINGSIZE;
+	for (;;)
+	{
+		int		dataSize;
+		bool	is_read_in_progress = pcshared_info->is_read_in_progress;
+		ParallelCopyLineBoundary *lineInfo;
+		ParallelCopyDataBlock *data_blk_ptr;
+		ParallelCopyLineState line_state = LINE_LEADER_POPULATED;
+		ParallelCopyLineState curr_line_state;
+		CHECK_FOR_INTERRUPTS();
+
+		/* File read completed & no elements to process. */
+		if (!is_read_in_progress &&
+			(pcshared_info->populated ==
+			 pg_atomic_read_u64(&pcshared_info->total_worker_processed)))
+		{
+			write_pos = -1;
+			break;
+		}
+
+		/* Get the current line information. */
+		lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+		curr_line_state = pg_atomic_read_u32(&lineInfo->line_state);
+		if ((write_pos % WORKER_CHUNK_COUNT == 0) &&
+			(curr_line_state == LINE_WORKER_PROCESSED ||
+			 curr_line_state == LINE_WORKER_PROCESSING))
+		{
+			pcdata->worker_processed_pos = write_pos;
+			write_pos = (write_pos + WORKER_CHUNK_COUNT) %  RINGSIZE;
+			continue;
+		}
+
+		/* Get the size of this line. */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+		if (dataSize != 0) /* If not an empty line. */
+		{
+			/* Get the block information. */
+			data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+			if (!data_blk_ptr->curr_blk_completed && (dataSize == -1))
+			{
+				/* Wait till the current line or block is added. */
+				COPY_WAIT_TO_PROCESS()
+				continue;
+			}
+		}
+
+		/* Make sure that no worker has consumed this element. */
+		if (pg_atomic_compare_exchange_u32(&lineInfo->line_state,
+										   &line_state, LINE_WORKER_PROCESSING))
+			break;
+	}
+
+	pcdata->worker_processed_pos = write_pos;
+	return write_pos;
+}
+
+/*
+ * GetFreeCopyBlock - Get a free block for data to be copied.
+ */
+static pg_attribute_always_inline uint32
+GetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	int count = 0;
+	uint32 last_free_block = pcshared_info->cur_block_pos;
+	uint32 block_pos = (last_free_block != -1) ? ((last_free_block + 1) % MAX_BLOCKS_COUNT): 0;
+
+	/* Get a new block for copying data. */
+	while (count < MAX_BLOCKS_COUNT)
+	{
+		ParallelCopyDataBlock *dataBlkPtr = &pcshared_info->data_blocks[block_pos];
+		uint32 unprocessed_line_parts = pg_atomic_read_u32(&dataBlkPtr->unprocessed_line_parts);
+		if (unprocessed_line_parts == 0)
+		{
+			dataBlkPtr->curr_blk_completed = false;
+			dataBlkPtr->skip_bytes = 0;
+			pcshared_info->cur_block_pos = block_pos;
+			return block_pos;
+		}
+
+		block_pos = (block_pos + 1) % MAX_BLOCKS_COUNT;
+		count++;
+	}
+
+	return -1;
+}
+
+/*
+ * WaitGetFreeCopyBlock - If there are no blocks available, wait and get a block
+ * for copying data.
+ */
+static uint32
+WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	uint32 new_free_pos = -1;
+	for (;;)
+	{
+		new_free_pos = GetFreeCopyBlock(pcshared_info);
+		if (new_free_pos != -1)	/* We have got one block, break now. */
+			break;
+
+		COPY_WAIT_TO_PROCESS()
+	}
+
+	return new_free_pos;
+}
+
 /*
  * LookupParallelCopyFnPtr - Look up parallel copy function pointer.
  */
@@ -1269,6 +1863,146 @@ LookupParallelCopyFnStr(copy_data_source_cb fn_addr)
 	/* We can only reach this by programming error. */
 	elog(ERROR, "internal function pointer not found");
 }
+
+/*
+ * SetRawBufForLoad - Set raw_buf to the shared memory where the file data must
+ * be read.
+ */
+static void
+SetRawBufForLoad(CopyState cstate, uint32 line_size, uint32 copy_buf_len,
+				 uint32 raw_buf_ptr, char **copy_raw_buf)
+{
+	ParallelCopyShmInfo	*pcshared_info;
+	uint32 cur_block_pos;
+	uint32 next_block_pos;
+	ParallelCopyDataBlock	*cur_data_blk_ptr = NULL;
+	ParallelCopyDataBlock	*next_data_blk_ptr = NULL;
+
+	if (!IsParallelCopy())
+		return;
+
+	pcshared_info = cstate->pcdata->pcshared_info;
+	cur_block_pos = pcshared_info->cur_block_pos;
+	cur_data_blk_ptr = (cstate->raw_buf) ? &pcshared_info->data_blocks[cur_block_pos] : NULL;
+	next_block_pos = WaitGetFreeCopyBlock(pcshared_info);
+	next_data_blk_ptr = &pcshared_info->data_blocks[next_block_pos];
+
+	/* set raw_buf to the data block in shared memory */
+	cstate->raw_buf = next_data_blk_ptr->data;
+	*copy_raw_buf = cstate->raw_buf;
+	if (cur_data_blk_ptr && line_size)
+	{
+		/*
+		 * Mark the previous block as completed, worker can start copying this
+		 * data.
+		 */
+		cur_data_blk_ptr->following_block = next_block_pos;
+		pg_atomic_add_fetch_u32(&cur_data_blk_ptr->unprocessed_line_parts, 1);
+		cur_data_blk_ptr->skip_bytes = copy_buf_len - raw_buf_ptr;
+		cur_data_blk_ptr->curr_blk_completed = true;
+	}
+}
+
+/*
+ * EndLineParallelCopy - Update the line information in shared memory.
+ */
+static void
+EndLineParallelCopy(CopyState cstate, uint32 line_pos, uint32 line_size,
+					 uint32 raw_buf_ptr)
+{
+	uint8 new_line_size;
+	if (!IsParallelCopy())
+		return;
+
+	if (!IsHeaderLine())
+	{
+		ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+		ParallelCopyLineBoundaries *lineBoundaryPtr = &pcshared_info->line_boundaries;
+		SET_NEWLINE_SIZE()
+		if (line_size)
+		{
+			ParallelCopyLineBoundary *lineInfo = &lineBoundaryPtr->ring[line_pos];
+			/*
+			 * If the new_line_size > raw_buf_ptr, then the new block has only
+			 * new line char content. The unprocessed count should not be
+			 * increased in this case.
+			 */
+			if (raw_buf_ptr > new_line_size)
+			{
+				uint32 cur_block_pos = pcshared_info->cur_block_pos;
+				ParallelCopyDataBlock *curr_data_blk_ptr = &pcshared_info->data_blocks[cur_block_pos];
+				pg_atomic_add_fetch_u32(&curr_data_blk_ptr->unprocessed_line_parts, 1);
+			}
+
+			/* Update line size. */
+			pg_atomic_write_u32(&lineInfo->line_size, line_size);
+			pg_atomic_write_u32(&lineInfo->line_state, LINE_LEADER_POPULATED);
+			elog(DEBUG1, "[Leader] After adding - line position:%d, line_size:%d",
+						 line_pos, line_size);
+			pcshared_info->populated++;
+		}
+		else if (new_line_size)
+		{
+			/* This means only new line char, empty record should be inserted.*/
+			ParallelCopyLineBoundary *lineInfo;
+			line_pos = UpdateBlockInLineInfo(cstate, -1, -1, 0,
+											   LINE_LEADER_POPULATED);
+			lineInfo = &lineBoundaryPtr->ring[line_pos];
+			elog(DEBUG1, "[Leader] Added empty line with offset:%d, line position:%d, line size:%d",
+						 lineInfo->start_offset, line_pos,
+						 pg_atomic_read_u32(&lineInfo->line_size));
+			pcshared_info->populated++;
+		}
+	}
+}
+
+/*
+ * ExecBeforeStmtTrigger - Execute the before statement trigger, this will be
+ * executed for parallel copy by the leader process.
+ */
+static void
+ExecBeforeStmtTrigger(CopyState cstate)
+{
+	EState	   *estate = CreateExecutorState();
+	ResultRelInfo *resultRelInfo;
+
+	Assert(IsLeader());
+
+	/*
+	 * We need a ResultRelInfo so we can use the regular executor's
+	 * index-entry-making machinery.  (There used to be a huge amount of code
+	 * here that basically duplicated execUtils.c ...)
+	 */
+	resultRelInfo = makeNode(ResultRelInfo);
+	InitResultRelInfo(resultRelInfo,
+					  cstate->rel,
+					  1,		/* must match rel's position in range_table */
+					  NULL,
+					  0);
+
+	/* Verify the named relation is a valid target for INSERT */
+	CheckValidResultRel(resultRelInfo, CMD_INSERT);
+
+	estate->es_result_relations = resultRelInfo;
+	estate->es_num_result_relations = 1;
+	estate->es_result_relation_info = resultRelInfo;
+
+	ExecInitRangeTable(estate, cstate->range_table);
+
+	/*
+	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
+	 * should do this for COPY, since it's not really an "INSERT" statement as
+	 * such. However, executing these triggers maintains consistency with the
+	 * EACH ROW triggers that we already fire on COPY.
+	 */
+	ExecBSInsertTriggers(estate, resultRelInfo);
+
+	/* Close any trigger target relations */
+	ExecCleanUpTriggerState(estate);
+
+	FreeExecutorState(estate);
+}
+
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
  * in past protocol redesigns.
@@ -3675,7 +4409,8 @@ CopyFrom(CopyState cstate)
 
 	PartitionTupleRouting *proute = NULL;
 	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
+	CommandId	mycid = IsParallelCopy() ? cstate->pcdata->pcshared_info->mycid :
+										   GetCurrentCommandId(true);
 	int			ti_options = 0; /* start with default options for insert */
 	BulkInsertState bistate = NULL;
 	CopyInsertMethod insertMethod;
@@ -3685,7 +4420,14 @@ CopyFrom(CopyState cstate)
 	bool		has_instead_insert_row_trig;
 	bool		leafpart_use_multi_insert = false;
 
-	CheckTargetRelValidity(cstate);
+	/*
+	 * Perform this check if it is not parallel copy. In case of parallel
+	 * copy, this check is done by the leader, so that if any invalid case
+	 * exist the copy from command will error out from the leader itself,
+	 * avoiding launching workers, just to throw error.
+	 */
+	if (!IsParallelCopy())
+		CheckTargetRelValidity(cstate);
 
 	/*
 	 * If the target file is new-in-transaction, we assume that checking FSM
@@ -3874,13 +4616,16 @@ CopyFrom(CopyState cstate)
 	has_instead_insert_row_trig = (resultRelInfo->ri_TrigDesc &&
 								   resultRelInfo->ri_TrigDesc->trig_insert_instead_row);
 
-	/*
-	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
-	 * should do this for COPY, since it's not really an "INSERT" statement as
-	 * such. However, executing these triggers maintains consistency with the
-	 * EACH ROW triggers that we already fire on COPY.
-	 */
-	ExecBSInsertTriggers(estate, resultRelInfo);
+	if (!IsParallelCopy())
+	{
+		/*
+		 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
+		 * should do this for COPY, since it's not really an "INSERT" statement as
+		 * such. However, executing these triggers maintains consistency with the
+		 * EACH ROW triggers that we already fire on COPY.
+		 */
+		ExecBSInsertTriggers(estate, resultRelInfo);
+	}
 
 	econtext = GetPerTupleExprContext(estate);
 
@@ -3980,6 +4725,16 @@ CopyFrom(CopyState cstate)
 					!has_instead_insert_row_trig &&
 					resultRelInfo->ri_FdwRoutine == NULL;
 
+				/*
+				 * If the table has any partitions that are either foreign or
+				 * has BEFORE/INSTEAD OF triggers, we can't perform copy
+				 * operations with parallel workers.
+				 */
+				if (!leafpart_use_multi_insert && IsParallelWorker())
+					ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							errmsg("cannot perform PARALLEL COPY if partition has BEFORE/INSTEAD OF triggers, or if the partition is foreign partition"),
+							errhint("Try COPY without PARALLEL option")));
+
 				/* Set the multi-insert buffer to use for this partition. */
 				if (leafpart_use_multi_insert)
 				{
@@ -4394,7 +5149,7 @@ BeginCopyFrom(ParseState *pstate,
 	initStringInfo(&cstate->attribute_buf);
 	initStringInfo(&cstate->line_buf);
 	cstate->line_buf_converted = false;
-	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+	cstate->raw_buf = (IsParallelCopy()) ? NULL : (char *) palloc(RAW_BUF_SIZE + 1);
 	cstate->raw_buf_index = cstate->raw_buf_len = 0;
 
 	/* Assign range table, we'll need it in CopyFrom. */
@@ -4538,26 +5293,35 @@ NextCopyFromRawFields(CopyState cstate, char ***fields, int *nfields)
 	/* only available for text or csv input */
 	Assert(!cstate->binary);
 
-	/* on input just throw the header line away */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (IsParallelCopy())
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
-			return false;		/* done */
+		done = GetWorkerLine(cstate);
+		if (done && cstate->line_buf.len == 0)
+			return false;
 	}
+	else
+	{
+		/* on input just throw the header line away */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
+		{
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+				return false;		/* done */
+		}
 
-	cstate->cur_lineno++;
+		cstate->cur_lineno++;
 
-	/* Actually read the line into memory here */
-	done = CopyReadLine(cstate);
+		/* Actually read the line into memory here */
+		done = CopyReadLine(cstate);
 
-	/*
-	 * EOF at start of line means we're done.  If we see EOF after some
-	 * characters, we act as though it was newline followed by EOF, ie,
-	 * process the line and then exit loop on next iteration.
-	 */
-	if (done && cstate->line_buf.len == 0)
-		return false;
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			return false;
+	}
 
 	/* Parse the line into de-escaped field values */
 	if (cstate->csv_mode)
@@ -4805,9 +5569,31 @@ CopyReadLine(CopyState cstate)
 		 */
 		if (cstate->copy_dest == COPY_NEW_FE)
 		{
+			bool bIsFirst = true;
 			do
 			{
-				cstate->raw_buf_index = cstate->raw_buf_len;
+				if (!IsParallelCopy())
+					cstate->raw_buf_index = cstate->raw_buf_len;
+				else
+				{
+					if (cstate->raw_buf_index == RAW_BUF_SIZE)
+					{
+						/* Get a new block if it is the first time, From the
+						 * subsequent time, reset the index and re-use the same
+						 * block.
+						 */
+						if (bIsFirst)
+						{
+							ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+							uint32 block_pos = WaitGetFreeCopyBlock(pcshared_info);
+							cstate->raw_buf = pcshared_info->data_blocks[block_pos].data;
+							bIsFirst = false;
+						}
+
+						cstate->raw_buf_index = cstate->raw_buf_len = 0;
+					}
+				}
+
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
@@ -4837,6 +5623,11 @@ CopyReadLineText(CopyState cstate)
 	char		quotec = '\0';
 	char		escapec = '\0';
 
+	/* For parallel copy */
+	uint32			 line_size = 0;
+	int				 line_pos = 0;
+
+	cstate->eol_type = EOL_UNKNOWN;
 	if (cstate->csv_mode)
 	{
 		quotec = cstate->quote[0];
@@ -4891,6 +5682,8 @@ CopyReadLineText(CopyState cstate)
 		if (raw_buf_ptr >= copy_buf_len || need_data)
 		{
 			REFILL_LINEBUF;
+			SetRawBufForLoad(cstate, line_size, copy_buf_len, raw_buf_ptr,
+							 &copy_raw_buf);
 
 			/*
 			 * Try to read some more data.  This will certainly reset
@@ -5115,9 +5908,15 @@ CopyReadLineText(CopyState cstate)
 				 * discard the data and the \. sequence.
 				 */
 				if (prev_raw_ptr > cstate->raw_buf_index)
-					appendBinaryStringInfo(&cstate->line_buf,
+				{
+					if (!IsParallelCopy())
+						appendBinaryStringInfo(&cstate->line_buf,
 										   cstate->raw_buf + cstate->raw_buf_index,
 										   prev_raw_ptr - cstate->raw_buf_index);
+					else
+						line_size += prev_raw_ptr - cstate->raw_buf_index;
+				}
+
 				cstate->raw_buf_index = raw_buf_ptr;
 				result = true;	/* report EOF */
 				break;
@@ -5169,6 +5968,26 @@ not_end_of_copy:
 			IF_NEED_REFILL_AND_EOF_BREAK(mblen - 1);
 			raw_buf_ptr += mblen - 1;
 		}
+
+		/*
+		 * Skip the header line. Update the line here, this cannot be done at
+		 * the beginning, as there is a possibility that file contains empty
+		 * lines.
+		 */
+		if (IsParallelCopy() && first_char_in_line && !IsHeaderLine())
+		{
+			ParallelCopyShmInfo	*pcshared_info = cstate->pcdata->pcshared_info;
+			ParallelCopyLineBoundary *lineInfo;
+			uint32			 line_first_block = pcshared_info->cur_block_pos;
+			line_pos = UpdateBlockInLineInfo(cstate,
+											   line_first_block,
+											   cstate->raw_buf_index, -1,
+											   LINE_LEADER_POPULATING);
+			lineInfo = &pcshared_info->line_boundaries.ring[line_pos];
+			elog(DEBUG1, "[Leader] Adding - block:%d, offset:%d, line position:%d",
+						 line_first_block,	lineInfo->start_offset, line_pos);
+		}
+
 		first_char_in_line = false;
 	}							/* end of outer loop */
 
@@ -5177,6 +5996,7 @@ not_end_of_copy:
 	 */
 	REFILL_LINEBUF;
 	CLEAR_EOL_LINE()
+	EndLineParallelCopy(cstate, line_pos, line_size, raw_buf_ptr);
 
 	return result;
 }
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index db19187..584b7ee 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -381,6 +381,7 @@ extern FullTransactionId GetTopFullTransactionId(void);
 extern FullTransactionId GetTopFullTransactionIdIfAny(void);
 extern FullTransactionId GetCurrentFullTransactionId(void);
 extern FullTransactionId GetCurrentFullTransactionIdIfAny(void);
+extern void AssignFullTransactionIdForWorker(FullTransactionId fullTransactionId);
 extern void MarkCurrentTransactionIdLoggedIfAny(void);
 extern bool SubTransactionIsActive(SubTransactionId subxid);
 extern CommandId GetCurrentCommandId(bool used);
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 8a79794..86b5c62 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1700,6 +1700,7 @@ ParallelCompletionPtr
 ParallelContext
 ParallelCopyLineBoundaries
 ParallelCopyLineBoundary
+ParallelCopyLineState
 ParallelCopyCommonKeyData
 ParallelCopyData
 ParallelCopyDataBlock
-- 
1.8.3.1

0002-Framework-for-leader-worker-in-parallel-copy.patchapplication/x-patch; name=0002-Framework-for-leader-worker-in-parallel-copy.patchDownload
From 447a954eed01432c170ad94e3ffffa30112f53aa Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>,Bharath <bharath.rupireddyforpostgres@gmail.com>
Date: Tue, 23 Jun 2020 07:04:46 +0530
Subject: [PATCH 2/6] Framework for leader/worker in parallel copy.

This patch has the framework for data structures in parallel copy, leader
initialization, worker initialization, shared memory updation, starting workers,
wait for workers and workers exiting.
---
 src/backend/access/transam/parallel.c       |   4 +
 src/backend/commands/copy.c                 | 838 +++++++++++++++++++++++++++-
 src/backend/replication/logical/tablesync.c |   2 +-
 src/include/commands/copy.h                 |   4 +
 src/tools/pgindent/typedefs.list            |   8 +
 5 files changed, 851 insertions(+), 5 deletions(-)

diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index 14a8690..09e7a19 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -25,6 +25,7 @@
 #include "catalog/pg_enum.h"
 #include "catalog/storage.h"
 #include "commands/async.h"
+#include "commands/copy.h"
 #include "executor/execParallel.h"
 #include "libpq/libpq.h"
 #include "libpq/pqformat.h"
@@ -145,6 +146,9 @@ static const struct
 	},
 	{
 		"parallel_vacuum_main", parallel_vacuum_main
+	},
+	{
+		"ParallelCopyMain", ParallelCopyMain
 	}
 };
 
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 65a504f..34c657c 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -96,9 +96,138 @@ typedef enum CopyInsertMethod
 } CopyInsertMethod;
 
 #define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+
+#define DATA_BLOCK_SIZE RAW_BUF_SIZE
+#define RINGSIZE (10 * 1000)
+#define MAX_BLOCKS_COUNT 1000
+#define WORKER_CHUNK_COUNT 50	/* should be mod of RINGSIZE */
+
+#define	IsParallelCopy()		(cstate->is_parallel)
+#define IsLeader()				(cstate->pcdata->is_leader)
 #define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
 
 /*
+ * Copy data block information.
+ */
+typedef struct ParallelCopyDataBlock
+{
+	/* The number of unprocessed lines in the current block. */
+	pg_atomic_uint32 unprocessed_line_parts;
+
+	/*
+	 * If the current line data is continued into another block, following_block
+	 * will have the position where the remaining data need to be read.
+	 */
+	uint32	following_block;
+
+	/*
+	 * This flag will be set, when the leader finds out this block can be read
+	 * safely by the worker. This helps the worker to start processing the line
+	 * early where the line will be spread across many blocks and the worker
+	 * need not wait for the complete line to be processed.
+	 */
+	bool   curr_blk_completed;
+	char   data[DATA_BLOCK_SIZE]; /* data read from file */
+	uint8  skip_bytes;
+}ParallelCopyDataBlock;
+
+/*
+ * Individual line information.
+ * ParallelCopyLineBoundary is common data structure between leader & worker,
+ * this is protected by the following sequence in the leader & worker.
+ * Leader should operate in the following order:
+ * 1) update first_block, start_offset & cur_lineno in any order.
+ * 2) update line_size.
+ * 3) update line_state.
+ * Worker should operate in the following order:
+ * 1) read line_size.
+ * 2) only one worker should choose one line for processing, this is handled by
+ *    using pg_atomic_compare_exchange_u32, worker will change the sate to
+ *    LINE_WORKER_PROCESSING only if line_state is LINE_LEADER_POPULATED.
+ * 3) read first_block, start_offset & cur_lineno in any order.
+ */
+typedef struct ParallelCopyLineBoundary
+{
+	/* Position of the first block in data_blocks array. */
+	uint32				first_block;
+	uint32				start_offset;   /* start offset of the line */
+
+	/*
+	 * Size of the current line -1 means line is yet to be filled completely,
+	 * 0 means empty line, >0 means line filled with line size data.
+	 */
+	pg_atomic_uint32	line_size;
+	pg_atomic_uint32	line_state;		/* line state */
+	uint64				cur_lineno;		/* line number for error messages */
+}ParallelCopyLineBoundary;
+
+/*
+ * Circular queue used to store the line information.
+ */
+typedef struct ParallelCopyLineBoundaries
+{
+	/* Position for the leader to populate a line. */
+	uint32			leader_pos;
+
+	/* Data read from the file/stdin by the leader process. */
+	ParallelCopyLineBoundary	ring[RINGSIZE];
+}ParallelCopyLineBoundaries;
+
+/*
+ * Shared information among parallel copy workers. This will be allocated in the
+ * DSM segment.
+ */
+typedef struct ParallelCopyShmInfo
+{
+	bool					is_read_in_progress; /* file read status */
+
+	/*
+	 * Actual lines inserted by worker (some records will be filtered based on
+	 * where condition).
+	 */
+	pg_atomic_uint64			processed;
+	pg_atomic_uint64			total_worker_processed; /* total processed records by the workers */
+	uint64						populated; /* lines populated by leader */
+	uint32						cur_block_pos; /* current data block */
+	ParallelCopyDataBlock		data_blocks[MAX_BLOCKS_COUNT]; /* data block array */
+	FullTransactionId			full_transaction_id; /* xid for copy from statement */
+	CommandId					mycid;	/* command id */
+	ParallelCopyLineBoundaries	line_boundaries; /* line array */
+} ParallelCopyShmInfo;
+
+/*
+ * Parallel copy line buffer information.
+ */
+typedef struct ParallelCopyLineBuf
+{
+	StringInfoData		line_buf;
+	uint64				cur_lineno;	/* line number for error messages */
+}ParallelCopyLineBuf;
+
+/*
+ * Parallel copy data information.
+ */
+typedef struct ParallelCopyData
+{
+	Oid					relid;				/* relation id of the table */
+	ParallelCopyShmInfo	*pcshared_info;		/* common info in shared memory */
+	bool				is_leader;
+
+	/* line position which worker is processing */
+	uint32				worker_processed_pos;
+
+	/*
+	 * Local line_buf array, workers will copy it here and release the lines
+	 * for the leader to continue.
+	 */
+	ParallelCopyLineBuf	worker_line_buf[WORKER_CHUNK_COUNT];
+	uint32				worker_line_buf_count; /* Number of lines */
+
+	/* Current position in worker_line_buf */
+	uint32				worker_line_buf_pos;
+}ParallelCopyData;
+
+/*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
  * even though some fields are used in only some cases.
@@ -225,8 +354,66 @@ typedef struct CopyStateData
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
+	int			nworkers;
+	bool		is_parallel;
+	ParallelCopyData *pcdata;
 } CopyStateData;
 
+/*
+ * This structure helps in storing the common data from CopyStateData that are
+ * required by the workers. This information will then be allocated and stored
+ * into the DSM for the worker to retrieve and copy it to CopyStateData.
+ */
+typedef struct ParallelCopyCommonKeyData
+{
+	/* low-level state data */
+	CopyDest            copy_dest;		/* type of copy source/destination */
+	int                 file_encoding;	/* file or remote side's character encoding */
+	bool                need_transcoding;	/* file encoding diff from server? */
+	bool                encoding_embeds_ascii;	/* ASCII can be non-first byte? */
+
+	/* parameters from the COPY command */
+	bool                csv_mode;		/* Comma Separated Value format? */
+	bool                header_line;	/* CSV header line? */
+	int                 null_print_len; /* length of same */
+	bool                force_quote_all;	/* FORCE_QUOTE *? */
+	bool                convert_selectively;	/* do selective binary conversion? */
+
+	/* Working state for COPY FROM */
+	AttrNumber          num_defaults;
+	Oid                 relid;
+}ParallelCopyCommonKeyData;
+
+/*
+ * This structure will help in converting a List data type into the below
+ * structure format with the count having the number of elements in the list and
+ * the info having the List elements appended contigously. This converted
+ * structure will be allocated in shared memory and stored in DSM for the worker
+ * to retrieve and later convert it back to List data type.
+ */
+typedef struct ParallelCopyKeyListInfo
+{
+	int	count;		/* count of attributes */
+
+	/* string info in the form info followed by info1, info2... infon  */
+	char    info[1];
+} ParallelCopyKeyListInfo;
+
+/*
+ * List of internal parallel copy function pointers.
+ */
+static const struct
+{
+	char *fn_name;
+	copy_data_source_cb fn_addr;
+}			InternalParallelCopyFuncPtrs[] =
+
+{
+	{
+		"copy_read_data", copy_read_data
+	},
+};
+
 /* DestReceiver for COPY (query) TO */
 typedef struct
 {
@@ -256,6 +443,23 @@ typedef struct
 /* Trim the list of buffers back down to this number after flushing */
 #define MAX_PARTITION_BUFFERS	32
 
+/* DSM keys for parallel copy.  */
+#define PARALLEL_COPY_KEY_SHARED_INFO		    1
+#define PARALLEL_COPY_KEY_CSTATE				2
+#define PARALLEL_COPY_KEY_NULL_PRINT			3
+#define PARALLEL_COPY_KEY_NULL_PRINT_CLIENT		4
+#define PARALLEL_COPY_KEY_DELIM					5
+#define PARALLEL_COPY_KEY_QUOTE					6
+#define PARALLEL_COPY_KEY_ESCAPE				7
+#define PARALLEL_COPY_KEY_ATTNAME_LIST			8
+#define PARALLEL_COPY_KEY_FORCE_QUOTE_LIST  	9
+#define PARALLEL_COPY_KEY_NOT_NULL_LIST		   10
+#define PARALLEL_COPY_KEY_NULL_LIST			   11
+#define PARALLEL_COPY_KEY_CONVERT_LIST		   12
+#define PARALLEL_COPY_KEY_DATASOURCE_CB		   13
+#define PARALLEL_COPY_KEY_WHERE_CLAUSE_STR     14
+#define PARALLEL_COPY_KEY_RANGE_TABLE		   15
+
 /* Stores multi-insert data related to a single relation in CopyFrom. */
 typedef struct CopyMultiInsertBuffer
 {
@@ -476,10 +680,596 @@ static bool CopyGetInt32(CopyState cstate, int32 *val);
 static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 
+static pg_attribute_always_inline void EndParallelCopy(ParallelContext *pcxt);
 static void PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tup_desc,
 							   List *attnamelist);
+static pg_attribute_always_inline copy_data_source_cb LookupParallelCopyFnPtr(const char *funcname);
+static pg_attribute_always_inline char* LookupParallelCopyFnStr(copy_data_source_cb fn_addr);
 
 /*
+ * CopyCommonInfoForWorker - Copy shared_cstate using cstate information.
+ */
+static pg_attribute_always_inline void
+CopyCommonInfoForWorker(CopyState cstate, ParallelCopyCommonKeyData *shared_cstate)
+{
+	shared_cstate->copy_dest = cstate->copy_dest;
+	shared_cstate->file_encoding = cstate->file_encoding;
+	shared_cstate->need_transcoding = cstate->need_transcoding;
+	shared_cstate->encoding_embeds_ascii = cstate->encoding_embeds_ascii;
+	shared_cstate->csv_mode = cstate->csv_mode;
+	shared_cstate->header_line = cstate->header_line;
+	shared_cstate->null_print_len = cstate->null_print_len;
+	shared_cstate->force_quote_all = cstate->force_quote_all;
+	shared_cstate->convert_selectively = cstate->convert_selectively;
+	shared_cstate->num_defaults = cstate->num_defaults;
+	shared_cstate->relid = cstate->pcdata->relid;
+}
+
+/*
+ * RetrieveSharedString - Retrieve the string from shared memory.
+ */
+static void
+RetrieveSharedString(shm_toc *toc, int sharedkey, char **copystr)
+{
+	char *shared_str_val = (char *)shm_toc_lookup(toc, sharedkey, true);
+	if (shared_str_val)
+		*copystr = pstrdup(shared_str_val);
+}
+
+/*
+ * RetrieveSharedList - Retrieve the list from shared memory.
+ */
+static void
+RetrieveSharedList(shm_toc *toc, int sharedkey, List **copylist)
+{
+	ParallelCopyKeyListInfo *listinformation = (ParallelCopyKeyListInfo *)shm_toc_lookup(toc, sharedkey,
+														   true);
+	if (listinformation)
+	{
+		int	length  = 0;
+		int count;
+
+		for (count = 0; count < listinformation->count; count++)
+		{
+			char *attname = (char *)(listinformation->info + length);
+			length += strlen(attname) + 1;
+			*copylist = lappend(*copylist, makeString(attname));
+		}
+	}
+}
+
+/*
+ * CopyListSharedMemory - Copy the list into shared memory.
+ */
+static void
+CopyListSharedMemory(List *inputlist, Size memsize, ParallelCopyKeyListInfo *sharedlistinfo)
+{
+	ListCell   *l;
+	int			length  = 0;
+
+	MemSet(sharedlistinfo, 0, memsize);
+	foreach(l, inputlist)
+	{
+		char	   *name = strVal(lfirst(l));
+		memcpy((char *)(sharedlistinfo->info + length), name, strlen(name));
+		sharedlistinfo->count++;
+		length += strlen(name) + 1;
+	}
+}
+
+/*
+ * ComputeListSize - compute the list size.
+ */
+static int
+ComputeListSize(List *inputlist)
+{
+	int est_size = sizeof(int);
+	if (inputlist != NIL)
+	{
+		ListCell   *l;
+		foreach(l, inputlist)
+			est_size += strlen(strVal(lfirst(l))) + 1;
+	}
+
+	return est_size;
+}
+
+/*
+ * EstimateLineKeysStr - Estimate the size required in shared memory for the
+ * input string.
+ */
+static void
+EstimateLineKeysStr(ParallelContext *pcxt, char *inputstr)
+{
+	if (inputstr)
+	{
+		shm_toc_estimate_chunk(&pcxt->estimator, strlen(inputstr) + 1);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+}
+
+/*
+ * EstimateLineKeysList - Estimate the size required in shared memory for the
+ * input list.
+ */
+static void
+EstimateLineKeysList(ParallelContext *pcxt, List *inputlist,
+		Size *est_list_size)
+{
+	if (inputlist != NIL)
+	{
+		*est_list_size = ComputeListSize(inputlist);
+		shm_toc_estimate_chunk(&pcxt->estimator, *est_list_size);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+}
+
+/*
+ * InsertStringShm - Insert a string into shared memory.
+ */
+static void
+InsertStringShm(ParallelContext *pcxt, int key, char *inputstr)
+{
+	if (inputstr)
+	{
+		char *shmptr = (char *)shm_toc_allocate(pcxt->toc,
+												strlen(inputstr) + 1);
+		strcpy(shmptr, inputstr);
+		shm_toc_insert(pcxt->toc, key, shmptr);
+	}
+}
+
+/*
+ * InsertListShm - Insert a list into shared memory.
+ */
+static void
+InsertListShm(ParallelContext *pcxt, int key, List *inputlist,
+			  Size est_list_size)
+{
+	if (inputlist != NIL)
+	{
+		ParallelCopyKeyListInfo *sharedlistinfo = (ParallelCopyKeyListInfo *)shm_toc_allocate(pcxt->toc,
+																est_list_size);
+		CopyListSharedMemory(inputlist, est_list_size, sharedlistinfo);
+		shm_toc_insert(pcxt->toc, key, sharedlistinfo);
+	}
+}
+
+/*
+ * BeginParallelCopy - start parallel copy tasks.
+ *
+ * Get the number of workers required to perform the parallel copy. The data
+ * structures that are required by the parallel workers will be initialized, the
+ * size required in DSM will be calculated and the necessary keys will be loaded
+ * in the DSM. The specified number of workers will then be launched.
+ *
+ */
+static ParallelContext*
+BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
+{
+	ParallelContext *pcxt;
+	ParallelCopyShmInfo *shared_info_ptr;
+	ParallelCopyCommonKeyData *shared_cstate;
+	FullTransactionId full_transaction_id;
+	Size est_shared_info;
+	Size est_cstateshared;
+	Size est_att_list_size;
+	Size est_quote_list_size;
+	Size est_notnull_list_size;
+	Size est_null_list_size;
+	Size est_convert_list_size;
+	Size est_datasource_cb_size;
+	int  count = 0;
+	char *whereClauseStr = NULL;
+	char *rangeTableStr = NULL;
+	int  parallel_workers = 0;
+	ParallelCopyData *pcdata;
+
+	parallel_workers = Min(nworkers, max_worker_processes);
+
+	/* Can't perform copy in parallel */
+	if (parallel_workers <= 0)
+	{
+		elog(WARNING,
+			 "No workers available, copy will be run in non-parallel mode");
+		return NULL;
+	}
+
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	cstate->pcdata = pcdata;
+
+	EnterParallelMode();
+	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
+								 parallel_workers);
+	Assert(pcxt->nworkers > 0);
+
+	/*
+	 * Estimate size for shared information for PARALLEL_COPY_KEY_SHARED_INFO
+	 */
+	est_shared_info = sizeof(ParallelCopyShmInfo);
+	shm_toc_estimate_chunk(&pcxt->estimator, est_shared_info);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_CSTATE */
+	est_cstateshared = 	MAXALIGN(sizeof(ParallelCopyCommonKeyData));
+	shm_toc_estimate_chunk(&pcxt->estimator, est_cstateshared);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	EstimateLineKeysStr(pcxt, cstate->null_print);
+	EstimateLineKeysStr(pcxt, cstate->null_print_client);
+	EstimateLineKeysStr(pcxt, cstate->delim);
+	EstimateLineKeysStr(pcxt, cstate->quote);
+	EstimateLineKeysStr(pcxt, cstate->escape);
+
+	if (cstate->whereClause != NULL)
+	{
+		whereClauseStr = nodeToString(cstate->whereClause);
+		EstimateLineKeysStr(pcxt, whereClauseStr);
+	}
+
+	if (cstate->range_table != NULL)
+	{
+		rangeTableStr = nodeToString(cstate->range_table);
+		EstimateLineKeysStr(pcxt, rangeTableStr);
+	}
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_XID. */
+	shm_toc_estimate_chunk(&pcxt->estimator, sizeof(FullTransactionId));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_ATTNAME_LIST.
+	 */
+	EstimateLineKeysList(pcxt, attnamelist, &est_att_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_FORCE_QUOTE_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->force_quote, &est_quote_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_NOT_NULL_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->force_notnull,
+							 &est_notnull_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_NULL_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->force_null, &est_null_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_CONVERT_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->convert_select,
+							 &est_convert_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_DATASOURCE_CB.
+	 */
+	if (cstate->data_source_cb)
+	{
+		char *functionname = LookupParallelCopyFnStr(cstate->data_source_cb);
+		est_datasource_cb_size = strlen(functionname) + 1;
+		shm_toc_estimate_chunk(&pcxt->estimator, est_datasource_cb_size);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+
+	InitializeParallelDSM(pcxt);
+
+	/* If no DSM segment was available, back out (do serial copy) */
+	if (pcxt->seg == NULL)
+	{
+		EndParallelCopy(pcxt);
+		elog(WARNING,
+			 "DSM segments not available, copy will be run in non-parallel mode");
+		return NULL;
+	}
+
+	/* Allocate shared memory for PARALLEL_COPY_KEY_SHARED_INFO */
+	shared_info_ptr = (ParallelCopyShmInfo *) shm_toc_allocate(pcxt->toc,
+													   est_shared_info);
+	MemSet(shared_info_ptr, 0, est_shared_info);
+	shared_info_ptr->is_read_in_progress = true;
+	shared_info_ptr->cur_block_pos = -1;
+	shared_info_ptr->full_transaction_id = full_transaction_id;
+	shared_info_ptr->mycid = GetCurrentCommandId(true);
+	for (count = 0; count < RINGSIZE; count++)
+	{
+		ParallelCopyLineBoundary *lineInfo = &shared_info_ptr->line_boundaries.ring[count];
+		pg_atomic_init_u32(&(lineInfo->line_size), -1);
+	}
+
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_SHARED_INFO, shared_info_ptr);
+	pcdata->pcshared_info = shared_info_ptr;
+	pcdata->relid = relid;
+
+	/* Store shared build state, for which we reserved space. */
+	shared_cstate = (ParallelCopyCommonKeyData *)shm_toc_allocate(pcxt->toc,
+															est_cstateshared);
+
+	/* copy cstate variables. */
+	CopyCommonInfoForWorker(cstate, shared_cstate);
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_CSTATE, shared_cstate);
+
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_NULL_PRINT, cstate->null_print);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_NULL_PRINT_CLIENT,
+					  cstate->null_print_client);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_DELIM, cstate->delim);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_QUOTE, cstate->quote);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_ESCAPE, cstate->escape);
+
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_ATTNAME_LIST,
+					attnamelist, est_att_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_FORCE_QUOTE_LIST,
+					cstate->force_quote, est_quote_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_NOT_NULL_LIST,
+					cstate->force_notnull, est_notnull_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_NULL_LIST, cstate->force_null,
+					est_null_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_CONVERT_LIST,
+					cstate->convert_select, est_convert_list_size);
+
+	if (cstate->data_source_cb)
+	{
+		char *functionname = LookupParallelCopyFnStr(cstate->data_source_cb);
+		char *data_source_cb = (char *) shm_toc_allocate(pcxt->toc,
+														 est_datasource_cb_size);
+		strcpy(data_source_cb, functionname);
+		shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_DATASOURCE_CB,
+					   data_source_cb);
+	}
+
+	if (cstate->whereClause)
+		InsertStringShm(pcxt, PARALLEL_COPY_KEY_WHERE_CLAUSE_STR,
+						whereClauseStr);
+
+	if(cstate->range_table)
+		InsertStringShm(pcxt, PARALLEL_COPY_KEY_RANGE_TABLE, rangeTableStr);
+
+	LaunchParallelWorkers(pcxt);
+	if (pcxt->nworkers_launched == 0)
+	{
+		EndParallelCopy(pcxt);
+		elog(WARNING,
+			 "No workers available, copy will be run in non-parallel mode");
+		return NULL;
+	}
+
+	/*
+	 * Caller needs to wait for all launched workers when we return.  Make sure
+	 * that the failure-to-start case will not hang forever.
+	 */
+	WaitForParallelWorkersToAttach(pcxt);
+
+	pcdata->is_leader = true;
+	cstate->is_parallel = true;
+	return pcxt;
+}
+
+/*
+ * EndParallelCopy - end the parallel copy tasks.
+ */
+static pg_attribute_always_inline void
+EndParallelCopy(ParallelContext *pcxt)
+{
+	Assert(!IsParallelWorker());
+
+	DestroyParallelContext(pcxt);
+	ExitParallelMode();
+}
+
+/*
+ * ParallelWorkerInitialization - Initialize parallel worker.
+ */
+static void
+ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
+		CopyState cstate, List *attnamelist)
+{
+	uint32		count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	cstate->copy_dest = shared_cstate->copy_dest;
+	cstate->file_encoding = shared_cstate->file_encoding;
+	cstate->need_transcoding = shared_cstate->need_transcoding;
+	cstate->encoding_embeds_ascii = shared_cstate->encoding_embeds_ascii;
+	cstate->csv_mode = shared_cstate->csv_mode;
+	cstate->header_line = shared_cstate->header_line;
+	cstate->null_print_len = shared_cstate->null_print_len;
+	cstate->force_quote_all = shared_cstate->force_quote_all;
+	cstate->convert_selectively = shared_cstate->convert_selectively;
+	cstate->num_defaults = shared_cstate->num_defaults;
+	pcdata->relid = shared_cstate->relid;
+
+	PopulateGlobalsForCopyFrom(cstate, tup_desc, attnamelist);
+
+	/* Initialize state variables. */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/* Set up variables to avoid per-attribute overhead. */
+	initStringInfo(&cstate->attribute_buf);
+
+	initStringInfo(&cstate->line_buf);
+	for (count = 0; count < WORKER_CHUNK_COUNT;count++)
+		initStringInfo(&pcdata->worker_line_buf[count].line_buf);
+
+	cstate->line_buf_converted = false;
+	cstate->raw_buf = NULL;
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+}
+/*
+ * ParallelCopyMain - parallel copy worker's code.
+ *
+ * Where clause handling, convert tuple to columns, add default null values for
+ * the missing columns that are not present in that record. Find the partition
+ * if it is partitioned table, invoke before row insert Triggers, handle
+ * constraints and insert the tuples.
+ */
+void
+ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
+{
+	CopyState cstate;
+	ParallelCopyData *pcdata;
+	ParallelCopyShmInfo *pcshared_info;
+	ParallelCopyCommonKeyData *shared_cstate;
+	Relation	rel = NULL;
+	MemoryContext oldcontext;
+	List *attlist = NIL;
+	char *data_source_cb;
+	char *whereClauseStr = NULL;
+	char *rangeTableStr = NULL;
+
+	/* Allocate workspace and zero all fields. */
+	cstate = (CopyStateData *) palloc0(sizeof(CopyStateData));
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	cstate->pcdata = pcdata;
+	pcdata->is_leader = false;
+	pcdata->worker_processed_pos = -1;
+	cstate->is_parallel = true;
+
+	/*
+	 * We allocate everything used by a cstate in a new memory context. This
+	 * avoids memory leaks during repeated use of COPY in a query.
+	 */
+	cstate->copycontext = AllocSetContextCreate(CurrentMemoryContext,
+												"COPY",
+												ALLOCSET_DEFAULT_SIZES);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	pcshared_info = (ParallelCopyShmInfo *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_SHARED_INFO,
+														false);
+
+	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
+
+	pcdata->pcshared_info = pcshared_info;
+
+	shared_cstate = (ParallelCopyCommonKeyData *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE,
+														   false);
+
+	cstate->null_print = (char *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_NULL_PRINT,
+												true);
+	cstate->null_print_client = (char *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_NULL_PRINT_CLIENT,
+													   true);
+
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_DELIM, &cstate->delim);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_QUOTE, &cstate->quote);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_ESCAPE, &cstate->escape);
+
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_ATTNAME_LIST, &attlist);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_FORCE_QUOTE_LIST, &cstate->force_quote);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_NOT_NULL_LIST, &cstate->force_notnull);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_NULL_LIST, &cstate->force_null);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_CONVERT_LIST, &cstate->convert_select);
+	data_source_cb = (char *)shm_toc_lookup(toc,
+											PARALLEL_COPY_KEY_DATASOURCE_CB,
+											true);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_WHERE_CLAUSE_STR, &whereClauseStr);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_RANGE_TABLE, &rangeTableStr);
+
+	if (data_source_cb)
+		cstate->data_source_cb = LookupParallelCopyFnPtr(data_source_cb);
+
+	if (whereClauseStr)
+	{
+		Node *whereClauseCnvrtdFrmStr = (Node *) stringToNode(whereClauseStr);
+		cstate->whereClause = whereClauseCnvrtdFrmStr;
+	}
+
+	if (rangeTableStr)
+	{
+		List *rangeTableCnvrtdFrmStr = (List *) stringToNode(rangeTableStr);
+		cstate->range_table = rangeTableCnvrtdFrmStr;
+	}
+
+	/* Open and lock the relation, using the appropriate lock type. */
+	rel = table_open(shared_cstate->relid, RowExclusiveLock);
+	cstate->rel = rel;
+	ParallelWorkerInitialization(shared_cstate, cstate, attlist);
+
+	CopyFrom(cstate);
+
+	if (rel != NULL)
+		table_close(rel, RowExclusiveLock);
+
+	MemoryContextSwitchTo(oldcontext);
+	return;
+}
+/*
+ * ParallelCopyLeader - parallel copy leader's functionality.
+ *
+ * Leader will populate the shared memory and share it across the workers.
+ * Leader will read the table data from the file and copy the contents to block.
+ * Leader will then read the input contents and identify the data based on line
+ * beaks. This information is called line. The line will be populate in
+ * ParallelCopyLineBoundary. Workers will then pick up this information and
+ * insert in to table. Leader will do this till it completes processing the
+ * file. Leader executes the before statement if before statement trigger is
+ * present. Leader read the data from input file. Leader then loads data to data
+ * blocks as and when required block by block. Leader traverses through the data
+ * block to identify one line. It gets a free line to copy the information, if
+ * there is no free line it will wait till there is one free line.
+ * Server copies  the identified lines information into lines. This process is
+ * repeated till the complete file is processed.
+ * Leader will wait till all the lines populated are processed by the workers
+ * and exits.
+ */
+static void
+ParallelCopyLeader(CopyState cstate)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
+
+	pcshared_info->is_read_in_progress = false;
+	cstate->cur_lineno = 0;
+}
+/*
+ * LookupParallelCopyFnPtr - Look up parallel copy function pointer.
+ */
+static pg_attribute_always_inline copy_data_source_cb
+LookupParallelCopyFnPtr(const char *funcname)
+{
+	int			i;
+
+	for (i = 0; i < lengthof(InternalParallelCopyFuncPtrs); i++)
+	{
+		if (strcmp(InternalParallelCopyFuncPtrs[i].fn_name, funcname) == 0)
+			return InternalParallelCopyFuncPtrs[i].fn_addr;
+	}
+
+	/* We can only reach this by programming error. */
+	elog(ERROR, "internal function \"%s\" not found", funcname);
+}
+
+/*
+ * LookupParallelCopyFnStr - Lookup function string from a function pointer.
+ */
+static pg_attribute_always_inline char*
+LookupParallelCopyFnStr(copy_data_source_cb fn_addr)
+{
+	int			i;
+
+	for (i = 0; i < lengthof(InternalParallelCopyFuncPtrs); i++)
+	{
+		if (InternalParallelCopyFuncPtrs[i].fn_addr == fn_addr)
+			return InternalParallelCopyFuncPtrs[i].fn_name;
+	}
+
+	/* We can only reach this by programming error. */
+	elog(ERROR, "internal function pointer not found");
+}
+/*
  * Send copy start/stop messages for frontend copies.  These have changed
  * in past protocol redesigns.
  */
@@ -1149,6 +1939,7 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 
 	if (is_from)
 	{
+		ParallelContext *pcxt = NULL;
 		Assert(rel);
 
 		/* check read-only transaction and parallel mode */
@@ -1158,7 +1949,24 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 		cstate = BeginCopyFrom(pstate, rel, stmt->filename, stmt->is_program,
 							   NULL, stmt->attlist, stmt->options);
 		cstate->whereClause = whereClause;
-		*processed = CopyFrom(cstate);	/* copy from file to database */
+		cstate->is_parallel = false;
+
+		if (cstate->nworkers > 0)
+			pcxt = BeginParallelCopy(cstate->nworkers, cstate, stmt->attlist,
+									 relid);
+
+		if (pcxt)
+		{
+			ParallelCopyLeader(cstate);
+
+			/* Wait for all copy workers to finish */
+			WaitForParallelWorkersToFinish(pcxt);
+			*processed = pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
+			EndParallelCopy(pcxt);
+		}
+		else
+			*processed = CopyFrom(cstate); /* copy from file to database */
+
 		EndCopyFrom(cstate);
 	}
 	else
@@ -1207,6 +2015,7 @@ ProcessCopyOptions(ParseState *pstate,
 	cstate->is_copy_from = is_from;
 
 	cstate->file_encoding = -1;
+	cstate->nworkers = -1;
 
 	/* Extract options from the statement node tree */
 	foreach(option, options)
@@ -1375,6 +2184,26 @@ ProcessCopyOptions(ParseState *pstate,
 								defel->defname),
 						 parser_errposition(pstate, defel->location)));
 		}
+		else if (strcmp(defel->defname, "parallel") == 0)
+		{
+			if (!cstate->is_copy_from)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("parallel option supported only for copy from"),
+						 parser_errposition(pstate, defel->location)));
+			if (cstate->nworkers >= 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options"),
+						 parser_errposition(pstate, defel->location)));
+			cstate->nworkers = atoi(defGetString(defel));
+			if (cstate->nworkers <= 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("argument to option \"%s\" must be a positive integer greater than zero",
+								defel->defname),
+						 parser_errposition(pstate, defel->location)));
+		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_SYNTAX_ERROR),
@@ -1727,12 +2556,13 @@ BeginCopy(ParseState *pstate,
 }
 
 /*
- * PopulateGlobalsForCopyFrom - Populates the common variables required for copy
- * from operation. This is a helper function for BeginCopy function.
+ * PopulateCatalogInformation - Populates the common variables required for copy
+ * from operation. This is a helper function for BeginCopy &
+ * ParallelWorkerInitialization function.
  */
 static void
 PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tupDesc,
-							List *attnamelist)
+						   List *attnamelist)
 {
 	int			num_phys_attrs;
 
diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c
index c27d970..b3787c1 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -557,7 +557,7 @@ make_copy_attnamelist(LogicalRepRelMapEntry *rel)
  * Data source callback for the COPY FROM, which reads from the remote
  * connection and passes the data back to our local COPY.
  */
-static int
+int
 copy_read_data(void *outbuf, int minread, int maxread)
 {
 	int			bytesread = 0;
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index c639833..5dc95ac 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -14,6 +14,7 @@
 #ifndef COPY_H
 #define COPY_H
 
+#include "access/parallel.h"
 #include "nodes/execnodes.h"
 #include "nodes/parsenodes.h"
 #include "parser/parse_node.h"
@@ -41,4 +42,7 @@ extern uint64 CopyFrom(CopyState cstate);
 
 extern DestReceiver *CreateCopyDestReceiver(void);
 
+extern void ParallelCopyMain(dsm_segment *seg, shm_toc *toc);
+
+extern int copy_read_data(void *outbuf, int minread, int maxread);
 #endif							/* COPY_H */
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index c65a552..8a79794 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1698,6 +1698,14 @@ ParallelBitmapHeapState
 ParallelBlockTableScanDesc
 ParallelCompletionPtr
 ParallelContext
+ParallelCopyLineBoundaries
+ParallelCopyLineBoundary
+ParallelCopyCommonKeyData
+ParallelCopyData
+ParallelCopyDataBlock
+ParallelCopyKeyListInfo
+ParallelCopyLineBuf
+ParallelCopyShmInfo
 ParallelExecutorInfo
 ParallelHashGrowth
 ParallelHashJoinBatch
-- 
1.8.3.1

0005-Tests-for-parallel-copy.patchapplication/x-patch; name=0005-Tests-for-parallel-copy.patchDownload
From 740f39b8a87eb74e74182ed2cc5e8c18bd2ce367 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 17 Jun 2020 07:37:26 +0530
Subject: [PATCH 5/6] Tests for parallel copy.

This patch has the tests for parallel copy.
---
 src/test/regress/expected/copy2.out | 210 +++++++++++++++++++++++++++++++++++-
 src/test/regress/input/copy.source  |  12 +++
 src/test/regress/output/copy.source |  12 +++
 src/test/regress/sql/copy2.sql      | 208 ++++++++++++++++++++++++++++++++++-
 4 files changed, 434 insertions(+), 8 deletions(-)

diff --git a/src/test/regress/expected/copy2.out b/src/test/regress/expected/copy2.out
index e40287d..a088f72 100644
--- a/src/test/regress/expected/copy2.out
+++ b/src/test/regress/expected/copy2.out
@@ -254,18 +254,32 @@ It is "perfect".|
 "It is ""perfect"".","	"
 "",
 --test that we read consecutive LFs properly
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 COPY testnl FROM stdin CSV;
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL '2');
+SELECT * FROM testnl;
+ a |          b           | c 
+---+----------------------+---
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+(2 rows)
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 COPY testeoc FROM stdin CSV;
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL '2');
 COPY testeoc TO stdout CSV;
 a\.
 \.b
 c\.d
 "\."
 -- test handling of nonstandard null marker that violates escaping rules
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 COPY testnull TO stdout WITH NULL AS E'\\0';
 1	\\0
@@ -280,6 +294,15 @@ SELECT * FROM testnull;
     | 
 (4 rows)
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 2);
+SELECT * FROM testnull;
+ a  | b  
+----+----
+ 42 | \0
+    | 
+(2 rows)
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -349,6 +372,34 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 2);
+SELECT * FROM vistest;
+ a  
+----
+ a2
+ b
+(2 rows)
+
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 2);
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+COMMIT;
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 SELECT * FROM vistest;
  a 
@@ -409,7 +460,7 @@ SELECT * FROM vistest;
 (2 rows)
 
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -420,6 +471,8 @@ CREATE TEMP TABLE forcetest (
 -- should succeed with no effect ("b" remains an empty string, "c" remains NULL)
 BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 2);
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
  b |  c   
@@ -430,6 +483,8 @@ SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
 BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 2);
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
  c |  d   
@@ -486,6 +541,31 @@ select * from check_con_tbl;
    
 (2 rows)
 
+\d+ check_con_tbl
+                               Table "public.check_con_tbl"
+ Column |  Type   | Collation | Nullable | Default | Storage | Stats target | Description 
+--------+---------+-----------+----------+---------+---------+--------------+-------------
+ f1     | integer |           |          |         | plain   |              | 
+Check constraints:
+    "check_con_tbl_check" CHECK (check_con_function(check_con_tbl.*))
+
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 2);
+NOTICE:  input = {"f1":1}
+NOTICE:  input = {"f1":null}
+copy check_con_tbl from stdin with (parallel 2);
+NOTICE:  input = {"f1":0}
+ERROR:  new row for relation "check_con_tbl" violates check constraint "check_con_tbl_check"
+DETAIL:  Failing row contains (0).
+CONTEXT:  COPY check_con_tbl, line 1: "0"
+parallel worker
+select * from check_con_tbl;
+ f1 
+----
+  1
+   
+(2 rows)
+
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
 CREATE ROLE regress_rls_copy_user_colperms;
@@ -600,8 +680,130 @@ SELECT * FROM instead_of_insert_tbl;
 (2 rows)
 
 COMMIT;
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+COPY test_parallel_copy (a, b, c, d, e) from stdin with (PARALLEL '2');
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '2');
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '2');
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '2', FORMAT 'csv', HEADER);
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0');
+ERROR:  argument to option "parallel" must be a positive integer greater than zero
+LINE 1: COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0'...
+                                                        ^
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri from stdin with (FORMAT csv, DELIMITER ',', PARALLEL '2');
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', parallel '2') WHERE height > random() * 65;
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', parallel '2');
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- temporary table copy: should peform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+COPY temp_test (a) from stdin with (PARALLEL '2');
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) from stdin with (PARALLEL '2');
+ERROR:  column "xyz" of relation "test_parallel_copy" does not exist
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) from stdin with (PARALLEL '2');
+ERROR:  column "d" specified more than once
+-- missing data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL '2');
+ERROR:  invalid input syntax for type integer: ""
+CONTEXT:  COPY test_parallel_copy, line 0, column a: ""
+parallel worker
+COPY test_parallel_copy from stdin with (PARALLEL '2');
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2000	230	23	23"
+parallel worker
+COPY test_parallel_copy from stdin with (PARALLEL '2');
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2001	231	\N	\N"
+parallel worker
+-- extra data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL '2');
+ERROR:  extra data after last expected column
+CONTEXT:  COPY test_parallel_copy, line 1: "2002	232	40	50	60	70	80"
+parallel worker
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) from stdin with (delimiter ',', null 'x', PARALLEL '2') ;
+COPY test_parallel_copy from stdin WITH (DELIMITER ';', NULL '', PARALLEL '2');
+COPY test_parallel_copy from stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL '2');
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a = 50004;
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a > 60003;
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE f > 60003;
+ERROR:  column "f" does not exist
+LINE 1: ...arallel_copy from stdin WITH (PARALLEL '2') WHERE f > 60003;
+                                                             ^
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a = max(x.b);
+ERROR:  missing FROM-clause entry for table "x"
+LINE 1: ...llel_copy from stdin WITH (PARALLEL '2') WHERE a = max(x.b);
+                                                                  ^
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a IN (SELECT 1 FROM x);
+ERROR:  cannot use subquery in COPY FROM WHERE condition
+LINE 1: ...allel_copy from stdin WITH (PARALLEL '2') WHERE a IN (SELECT...
+                                                             ^
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a IN (generate_series(1,5));
+ERROR:  set-returning functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...l_copy from stdin WITH (PARALLEL '2') WHERE a IN (generate_s...
+                                                             ^
+COPY test_parallel_copy from stdin WITH(PARALLEL '2') WHERE a = row_number() over(b);
+ERROR:  window functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...llel_copy from stdin WITH(PARALLEL '2') WHERE a = row_number...
+                                                             ^
+-- check results of copy in
+SELECT * FROM test_parallel_copy;
+   a   | b  |     c      |    d    |    e    
+-------+----+------------+---------+---------
+     1 | 11 | test_c1    | test_d1 | test_e1
+     2 | 12 | test_c2    | test_d2 | test_e2
+       |  3 | stuff      | test_d3 | 
+       |  4 | stuff      | test_d4 | 
+       |  5 | stuff      | test_d5 | 
+       |    | 45         | 80      | 90
+       |    | x          | \x      | \x
+       |    | ,          | \,      | \
+  3000 |    | c          |         | 
+  4000 |    | C          |         | 
+  4001 |  1 | empty      |         | 
+  4002 |  2 | null       |         | 
+  4003 |  3 | Backslash  | \       | \
+  4004 |  4 | BackslashX | \X      | \X
+  4005 |  5 | N          | N       | N
+  4006 |  6 | BackslashN | \N      | \N
+  4007 |  7 | XX         | XX      | XX
+  4008 |  8 | Delimiter  | :       | :
+ 50004 | 25 | 35         | 45      | 55
+ 60004 | 25 | 35         | 45      | 55
+ 60005 | 26 | 36         | 46      | 56
+(21 rows)
+
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
 DROP TABLE x, y;
diff --git a/src/test/regress/input/copy.source b/src/test/regress/input/copy.source
index a1d529a..159c058 100644
--- a/src/test/regress/input/copy.source
+++ b/src/test/regress/input/copy.source
@@ -15,6 +15,13 @@ DELETE FROM onek;
 
 COPY onek FROM '@abs_builddir@/results/onek.data';
 
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+
+SELECT COUNT(*) FROM tenk1;
+
+TRUNCATE tenk1;
+
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
@@ -159,6 +166,11 @@ truncate parted_copytest;
 
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
 
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
+
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/output/copy.source b/src/test/regress/output/copy.source
index 938d355..c3003fe 100644
--- a/src/test/regress/output/copy.source
+++ b/src/test/regress/output/copy.source
@@ -9,6 +9,15 @@ COPY onek FROM '@abs_srcdir@/data/onek.data';
 COPY onek TO '@abs_builddir@/results/onek.data';
 DELETE FROM onek;
 COPY onek FROM '@abs_builddir@/results/onek.data';
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+SELECT COUNT(*) FROM tenk1;
+ count 
+-------
+ 10000
+(1 row)
+
+TRUNCATE tenk1;
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
 COPY person FROM '@abs_srcdir@/data/person.data';
@@ -113,6 +122,9 @@ insert into parted_copytest select x,1,'One' from generate_series(1011,1020) x;
 copy (select * from parted_copytest order by a) to '@abs_builddir@/results/parted_copytest.csv';
 truncate parted_copytest;
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/sql/copy2.sql b/src/test/regress/sql/copy2.sql
index 902f4fa..13104f4 100644
--- a/src/test/regress/sql/copy2.sql
+++ b/src/test/regress/sql/copy2.sql
@@ -157,7 +157,7 @@ COPY y TO stdout (FORMAT CSV, FORCE_QUOTE *);
 
 --test that we read consecutive LFs properly
 
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 
 COPY testnl FROM stdin CSV;
 1,"a field with two LFs
@@ -165,8 +165,16 @@ COPY testnl FROM stdin CSV;
 inside",2
 \.
 
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL '2');
+1,"a field with two LFs
+
+inside",2
+\.
+
+SELECT * FROM testnl;
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 
 COPY testeoc FROM stdin CSV;
 a\.
@@ -175,11 +183,19 @@ c\.d
 "\."
 \.
 
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL '2');
+a\.
+\.b
+c\.d
+"\."
+\.
+
 COPY testeoc TO stdout CSV;
 
 -- test handling of nonstandard null marker that violates escaping rules
 
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 
 COPY testnull TO stdout WITH NULL AS E'\\0';
@@ -191,6 +207,14 @@ COPY testnull FROM stdin WITH NULL AS E'\\0';
 
 SELECT * FROM testnull;
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 2);
+42	\\0
+\0	\0
+\.
+
+SELECT * FROM testnull;
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -235,6 +259,23 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 2);
+a2
+b
+\.
+SELECT * FROM vistest;
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 2);
+d2
+e
+\.
+SELECT * FROM vistest;
+COMMIT;
+SELECT * FROM vistest;
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 x
 y
@@ -284,7 +325,7 @@ SELECT * FROM vistest;
 COMMIT;
 SELECT * FROM vistest;
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -297,6 +338,10 @@ BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
 1,,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 2);
+1,,""
+\.
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
@@ -304,6 +349,10 @@ BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
 2,'a',,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 2);
+2,'a',,""
+\.
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
 -- should fail with not-null constraint violation
@@ -339,6 +388,16 @@ copy check_con_tbl from stdin;
 0
 \.
 select * from check_con_tbl;
+\d+ check_con_tbl
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 2);
+1
+\N
+\.
+copy check_con_tbl from stdin with (parallel 2);
+0
+\.
+select * from check_con_tbl;
 
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
@@ -440,8 +499,149 @@ test1
 SELECT * FROM instead_of_insert_tbl;
 COMMIT;
 
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+
+COPY test_parallel_copy (a, b, c, d, e) from stdin with (PARALLEL '2');
+1	11	test_c1	test_d1	test_e1
+2	12	test_c2	test_d2	test_e2
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '2');
+3	test_d3
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '2');
+4	test_d4
+5	test_d5
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '2', FORMAT 'csv', HEADER);
+b	d
+\.
+
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0');
+
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri from stdin with (FORMAT csv, DELIMITER ',', PARALLEL '2');
+10
+\.
+
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', parallel '2') WHERE height > random() * 65;
+60,60,60
+\.
+
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', parallel '2');
+60
+\.
+
+-- temporary table copy: should peform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+
+COPY temp_test (a) from stdin with (PARALLEL '2');
+10
+\.
+
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) from stdin with (PARALLEL '2');
+
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) from stdin with (PARALLEL '2');
+
+-- missing data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL '2');
+
+\.
+COPY test_parallel_copy from stdin with (PARALLEL '2');
+2000	230	23	23
+\.
+COPY test_parallel_copy from stdin with (PARALLEL '2');
+2001	231	\N	\N
+\.
+
+-- extra data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL '2');
+2002	232	40	50	60	70	80
+\.
+
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) from stdin with (delimiter ',', null 'x', PARALLEL '2') ;
+x,45,80,90
+x,\x,\\x,\\\x
+x,\,,\\\,,\\
+\.
+
+COPY test_parallel_copy from stdin WITH (DELIMITER ';', NULL '', PARALLEL '2');
+3000;;c;;
+\.
+
+COPY test_parallel_copy from stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL '2');
+4000:\X:C:\X:\X
+4001:1:empty::
+4002:2:null:\X:\X
+4003:3:Backslash:\\:\\
+4004:4:BackslashX:\\X:\\X
+4005:5:N:\N:\N
+4006:6:BackslashN:\\N:\\N
+4007:7:XX:\XX:\XX
+4008:8:Delimiter:\::\:
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a = 50004;
+50003	24	34	44	54
+50004	25	35	45 	55
+50005	26	36	46	56
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a > 60003;
+60001	22	32	42	52
+60002	23	33	43	53
+60003	24	34	44	54
+60004	25	35	45	55
+60005	26	36	46	56
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE f > 60003;
+
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a = max(x.b);
+
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a IN (SELECT 1 FROM x);
+
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a IN (generate_series(1,5));
+
+COPY test_parallel_copy from stdin WITH(PARALLEL '2') WHERE a = row_number() over(b);
+
+-- check results of copy in
+SELECT * FROM test_parallel_copy;
+
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
 DROP TABLE x, y;
-- 
1.8.3.1

0006-Parallel-Copy-For-Binary-Format-Files.patchapplication/x-patch; name=0006-Parallel-Copy-For-Binary-Format-Files.patchDownload
From 14cf6fcfaa9b49c8e8ab9e503e549d40f1eebafc Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddy@enterprisedb.com>, Vignesh C <vignesh21@gmail.com>
Date: Tue, 23 Jun 2020 07:25:14 +0530
Subject: [PATCH 6/6] Parallel Copy For Binary Format Files

Leader reads data from the file into the DSM data blocks each of 64K size.
It also identifies each tuple data block id, start offset, end offset,
tuple size and updates this information in the ring data structure.
Workers parallely read the tuple information from the ring data structure,
the actual tuple data from the data blocks and parallely insert the tuples
into the table.
---
 src/backend/commands/copy.c | 663 +++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 597 insertions(+), 66 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index e8a89a4..e22292c 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -243,6 +243,16 @@ typedef struct ParallelCopyData
 }ParallelCopyData;
 
 /*
+ * Tuple boundary information used for parallel copy
+ * for binary format files.
+ */
+typedef struct ParallelCopyTupleInfo
+{
+	uint32 offset;
+	uint32 block_id;
+}ParallelCopyTupleInfo;
+
+/*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
  * even though some fields are used in only some cases.
@@ -372,6 +382,16 @@ typedef struct CopyStateData
 	int			nworkers;
 	bool		is_parallel;
 	ParallelCopyData *pcdata;
+
+	/*
+	 * Parallel copy for binary formatted files
+	 */
+	ParallelCopyDataBlock *curr_data_block;
+	ParallelCopyDataBlock *prev_data_block;
+	uint32				   curr_data_offset;
+	uint32				   curr_block_pos;
+	ParallelCopyTupleInfo  curr_tuple_start_info;
+	ParallelCopyTupleInfo  curr_tuple_end_info;
 } CopyStateData;
 
 /*
@@ -397,6 +417,7 @@ typedef struct ParallelCopyCommonKeyData
 	/* Working state for COPY FROM */
 	AttrNumber          num_defaults;
 	Oid                 relid;
+	bool 				binary;
 }ParallelCopyCommonKeyData;
 
 /*
@@ -751,6 +772,14 @@ static void PopulateCatalogInformation(CopyState cstate);
 static pg_attribute_always_inline uint32 GetLinePosition(CopyState cstate);
 static pg_attribute_always_inline copy_data_source_cb LookupParallelCopyFnPtr(const char *funcname);
 static pg_attribute_always_inline char* LookupParallelCopyFnStr(copy_data_source_cb fn_addr);
+static uint32 WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info);
+static pg_attribute_always_inline bool CopyReadBinaryTupleLeader(CopyState cstate);
+static pg_attribute_always_inline void CopyReadBinaryAttributeLeader(CopyState cstate,
+										FmgrInfo *flinfo, Oid typioparam, int32 typmod,
+										uint32 *new_block_pos);
+static pg_attribute_always_inline bool CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls);
+static pg_attribute_always_inline Datum CopyReadBinaryAttributeWorker(CopyState cstate, int column_no,
+										 FmgrInfo *flinfo, Oid typioparam, int32 typmod, bool *isnull);
 
 /*
  * CopyCommonInfoForWorker - Copy shared_cstate using cstate information.
@@ -769,6 +798,7 @@ CopyCommonInfoForWorker(CopyState cstate, ParallelCopyCommonKeyData *shared_csta
 	shared_cstate->convert_selectively = cstate->convert_selectively;
 	shared_cstate->num_defaults = cstate->num_defaults;
 	shared_cstate->relid = cstate->pcdata->relid;
+	shared_cstate->binary = cstate->binary;
 }
 
 /*
@@ -997,8 +1027,8 @@ FindInsertMethod(CopyState cstate)
 static pg_attribute_always_inline bool
 IsParallelCopyAllowed(CopyState cstate)
 {
-	/* Parallel copy not allowed for frontend (2.0 protocol) & binary option. */
-	if ((cstate->copy_dest == COPY_OLD_FE) || cstate->binary)
+	/* Parallel copy not allowed for frontend (2.0 protocol). */
+	if (cstate->copy_dest == COPY_OLD_FE)
 		return false;
 
 	/* Check if copy is into foreign table or temporary table. */
@@ -1299,6 +1329,7 @@ ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
 	cstate->convert_selectively = shared_cstate->convert_selectively;
 	cstate->num_defaults = shared_cstate->num_defaults;
 	pcdata->relid = shared_cstate->relid;
+	cstate->binary = shared_cstate->binary;
 
 	PopulateGlobalsForCopyFrom(cstate, tup_desc, attnamelist);
 
@@ -1314,7 +1345,7 @@ ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
 	initStringInfo(&cstate->attribute_buf);
 
 	initStringInfo(&cstate->line_buf);
-	for (count = 0; count < WORKER_CHUNK_COUNT;count++)
+	for (count = 0; count < WORKER_CHUNK_COUNT; count++)
 		initStringInfo(&pcdata->worker_line_buf[count].line_buf);
 
 	cstate->line_buf_converted = false;
@@ -1331,6 +1362,15 @@ ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
 		cstate->max_fields = attr_count;
 		cstate->raw_fields = (char **)palloc(attr_count * sizeof(char *));
 	}
+
+	cstate->curr_data_block = NULL;
+	cstate->prev_data_block = NULL;
+	cstate->curr_data_offset = 0;
+	cstate->curr_block_pos = 0;
+	cstate->curr_tuple_start_info.block_id = -1;
+	cstate->curr_tuple_start_info.offset = -1;
+	cstate->curr_tuple_end_info.block_id = -1;
+	cstate->curr_tuple_end_info.offset = -1;
 }
 
 /*
@@ -1679,32 +1719,59 @@ ParallelCopyLeader(CopyState cstate)
 	/* Execute the before statement triggers from the leader */
 	ExecBeforeStmtTrigger(cstate);
 
-	/* On input just throw the header line away. */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (!cstate->binary)
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
+		/* On input just throw the header line away. */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
 		{
-			pcshared_info->is_read_in_progress = false;
-			return;			/* done */
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+			{
+				pcshared_info->is_read_in_progress = false;
+				return;			/* done */
+			}
 		}
-	}
 
-	for (;;)
+		for (;;)
+		{
+			bool done;
+			cstate->cur_lineno++;
+
+			/* Actually read the line into memory here. */
+			done = CopyReadLine(cstate);
+
+			/*
+			* EOF at start of line means we're done.  If we see EOF after some
+			* characters, we act as though it was newline followed by EOF, ie,
+			* process the line and then exit loop on next iteration.
+			*/
+			if (done && cstate->line_buf.len == 0)
+				break;
+		}
+	}
+	else
 	{
-		bool done;
-		cstate->cur_lineno++;
+		cstate->curr_data_block = NULL;
+		cstate->prev_data_block = NULL;
+		cstate->curr_data_offset = 0;
+		cstate->curr_block_pos = 0;
+		cstate->curr_tuple_start_info.block_id = -1;
+		cstate->curr_tuple_start_info.offset = -1;
+		cstate->curr_tuple_end_info.block_id = -1;
+		cstate->curr_tuple_end_info.offset = -1;
+		pcshared_info->populated = 0;
+		cstate->cur_lineno = 0;
 
-		/* Actually read the line into memory here. */
-		done = CopyReadLine(cstate);
+		for (;;)
+		{
+			bool eof = false;
+			cstate->cur_lineno++;
 
-		/*
-		 * EOF at start of line means we're done.  If we see EOF after some
-		 * characters, we act as though it was newline followed by EOF, ie,
-		 * process the line and then exit loop on next iteration.
-		 */
-		if (done && cstate->line_buf.len == 0)
-			break;
+			eof = CopyReadBinaryTupleLeader(cstate);
+
+			if (eof)
+				break;
+		}
 	}
 
 	pcshared_info->is_read_in_progress = false;
@@ -1712,6 +1779,456 @@ ParallelCopyLeader(CopyState cstate)
 }
 
 /*
+ * CopyReadBinaryTupleLeader - leader reads data from binary formatted file
+ * to data blocks and identies tuple boundaries/offsets so that workers
+ * can work on the data blocks data.
+ */
+static pg_attribute_always_inline bool
+CopyReadBinaryTupleLeader(CopyState cstate)
+{
+	int readbytes = 0;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	uint32 block_pos;
+	int16		fld_count;
+	AttrNumber	attr_count = list_length(cstate->attnumlist);
+	ListCell   *cur;
+	FmgrInfo   *in_functions = cstate->in_functions;
+	Oid		   *typioparams = cstate->typioparams;
+	TupleDesc	tupDesc = RelationGetDescr(cstate->rel);
+	uint32      new_block_pos;
+	uint32      line_size;
+
+	if (cstate->curr_data_block == NULL)
+	{
+		block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+		cstate->curr_block_pos = block_pos;
+
+		cstate->curr_data_block = &pcshared_info->data_blocks[block_pos];
+
+		cstate->curr_data_offset = 0;
+
+		readbytes = CopyGetData(cstate, &cstate->curr_data_block->data, 1, DATA_BLOCK_SIZE);
+
+		elog(DEBUG1, "LEADER - bytes read from file %d", readbytes);
+
+		if (cstate->reached_eof)
+			return true;
+	}
+
+	if (cstate->curr_data_offset + sizeof(fld_count) >= (DATA_BLOCK_SIZE - 1))
+	{
+		ParallelCopyDataBlock *data_block = NULL;
+		uint8 movebytes = 0;
+
+		block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+		movebytes = DATA_BLOCK_SIZE - cstate->curr_data_offset;
+
+		cstate->curr_data_block->skip_bytes = movebytes;
+
+		data_block = &pcshared_info->data_blocks[block_pos];
+
+		if (movebytes > 0)
+			memmove(&data_block->data[0], &cstate->curr_data_block->data[cstate->curr_data_offset],
+			 movebytes);
+
+		elog(DEBUG1, "LEADER - field count is spread across data blocks - moved %d bytes from current block %u to %u block",
+			movebytes, cstate->curr_block_pos, block_pos);
+
+		readbytes = CopyGetData(cstate, &data_block->data[movebytes], 1, (DATA_BLOCK_SIZE - movebytes));
+
+		elog(DEBUG1, "LEADER - bytes read from file after field count is moved to next data block %d", readbytes);
+
+		if (cstate->reached_eof)
+			ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("unexpected EOF in COPY data")));
+
+		cstate->curr_data_block = data_block;
+		cstate->curr_data_offset = 0;
+		cstate->curr_block_pos = block_pos;
+	}
+
+	memcpy(&fld_count, &cstate->curr_data_block->data[cstate->curr_data_offset], sizeof(fld_count));
+
+	fld_count = (int16) pg_ntoh16(fld_count);
+
+	if (fld_count == -1)
+	{
+		/*
+			* Received EOF marker.  In a V3-protocol copy, wait for the
+			* protocol-level EOF, and complain if it doesn't come
+			* immediately.  This ensures that we correctly handle CopyFail,
+			* if client chooses to send that now.
+			*
+			* Note that we MUST NOT try to read more data in an old-protocol
+			* copy, since there is no protocol-level EOF marker then.  We
+			* could go either way for copy from file, but choose to throw
+			* error if there's data after the EOF marker, for consistency
+			* with the new-protocol case.
+			*/
+		char		dummy;
+
+		if (cstate->copy_dest != COPY_OLD_FE &&
+			CopyGetData(cstate, &dummy, 1, 1) > 0)
+			ereport(ERROR,
+					(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+						errmsg("received copy data after EOF marker")));
+		return true;
+	}
+
+	if (fld_count != attr_count)
+		ereport(ERROR,
+			(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+			errmsg("row field count is %d, expected %d",
+			(int) fld_count, attr_count)));
+
+	cstate->curr_tuple_start_info.block_id = cstate->curr_block_pos;
+	cstate->curr_tuple_start_info.offset =  cstate->curr_data_offset;
+	cstate->curr_data_offset = cstate->curr_data_offset + sizeof(fld_count);
+	new_block_pos = cstate->curr_block_pos;
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			attnum = lfirst_int(cur);
+		int			m = attnum - 1;
+		Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+
+		CopyReadBinaryAttributeLeader(cstate,
+									&in_functions[m],
+									typioparams[m],
+									att->atttypmod,
+									&new_block_pos);
+	}
+
+	cstate->curr_tuple_end_info.block_id = new_block_pos;
+	cstate->curr_tuple_end_info.offset =  cstate->curr_data_offset-1;;
+
+	if (cstate->curr_tuple_start_info.block_id == cstate->curr_tuple_end_info.block_id)
+	{
+		elog(DEBUG1,"LEADER - tuple lies in a single data block");
+
+		line_size = cstate->curr_tuple_end_info.offset - cstate->curr_tuple_start_info.offset + 1;
+		pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[cstate->curr_tuple_start_info.block_id].unprocessed_line_parts, 1);
+	}
+	else
+	{
+		uint32 following_block_id = pcshared_info->data_blocks[cstate->curr_tuple_start_info.block_id].following_block;
+
+		elog(DEBUG1,"LEADER - tuple is spread across data blocks");
+
+		line_size = DATA_BLOCK_SIZE - cstate->curr_tuple_start_info.offset -
+			pcshared_info->data_blocks[cstate->curr_tuple_start_info.block_id].skip_bytes;
+
+		pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[cstate->curr_tuple_start_info.block_id].unprocessed_line_parts, 1);
+
+		while (following_block_id != cstate->curr_tuple_end_info.block_id)
+		{
+			line_size = line_size + DATA_BLOCK_SIZE - pcshared_info->data_blocks[following_block_id].skip_bytes;
+
+			pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[following_block_id].unprocessed_line_parts, 1);
+
+			following_block_id = pcshared_info->data_blocks[following_block_id].following_block;
+
+			if (following_block_id == -1)
+				break;
+		}
+
+		if (following_block_id != -1)
+			pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[following_block_id].unprocessed_line_parts, 1);
+
+		line_size = line_size + cstate->curr_tuple_end_info.offset + 1;
+	}
+
+	if (line_size > 0)
+	{
+		int line_pos = UpdateBlockInLineInfo(cstate,
+											cstate->curr_tuple_start_info.block_id,
+											cstate->curr_tuple_start_info.offset,
+											line_size,
+											LINE_LEADER_POPULATED);
+
+		pcshared_info->populated++;
+
+		elog(DEBUG1, "LEADER - adding - block:%u, offset:%u, line size:%u line position:%d",
+						 cstate->curr_tuple_start_info.block_id,
+						 cstate->curr_tuple_start_info.offset,
+						 line_size, line_pos);
+	}
+
+	cstate->curr_tuple_start_info.block_id = -1;
+	cstate->curr_tuple_start_info.offset = -1;
+	cstate->curr_tuple_end_info.block_id = -1;
+	cstate->curr_tuple_end_info.offset = -1;
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryAttributeLeader - leader identifies boundaries/offsets
+ * for each attribute/column, it moves on to next data block if the
+ * attribute/column is spread across data blocks.
+ */
+static pg_attribute_always_inline void
+CopyReadBinaryAttributeLeader(CopyState cstate, FmgrInfo *flinfo,
+	Oid typioparam, int32 typmod, uint32 *new_block_pos)
+{
+	int32		fld_size;
+	int readbytes;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	uint32 block_pos;
+
+	if ((cstate->curr_data_offset + sizeof(fld_size)) >= (DATA_BLOCK_SIZE - 1))
+	{
+		ParallelCopyDataBlock *data_block = NULL;
+		uint8 movebytes = DATA_BLOCK_SIZE - cstate->curr_data_offset;
+
+		block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+		cstate->curr_data_block->skip_bytes = movebytes;
+
+		data_block = &pcshared_info->data_blocks[block_pos];
+
+		if (movebytes > 0)
+			memmove(&data_block->data[0], &cstate->curr_data_block->data[cstate->curr_data_offset], movebytes);
+
+		elog(DEBUG1, "LEADER - field size is spread across data blocks - moved %d bytes from current block %u to %u block",
+			movebytes, cstate->curr_block_pos, block_pos);
+
+		readbytes = CopyGetData(cstate, &data_block->data[movebytes], 1, DATA_BLOCK_SIZE-movebytes);
+
+		elog(DEBUG1, "LEADER - bytes read from file after field size is moved to next data block %d", readbytes);
+
+		if (cstate->reached_eof)
+			ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("unexpected EOF in COPY data")));
+
+		cstate->prev_data_block = cstate->curr_data_block;
+		cstate->prev_data_block->following_block = block_pos;
+		cstate->curr_data_block = data_block;
+		cstate->curr_block_pos = block_pos;
+
+		if (cstate->prev_data_block->curr_blk_completed  == false)
+			cstate->prev_data_block->curr_blk_completed = true;
+
+		cstate->curr_data_offset = 0;
+		*new_block_pos = block_pos;
+	}
+
+	memcpy(&fld_size, &cstate->curr_data_block->data[cstate->curr_data_offset], sizeof(fld_size));
+
+	cstate->curr_data_offset = cstate->curr_data_offset + sizeof(fld_size);
+
+	fld_size = (int32) pg_ntoh32(fld_size);
+
+	if (fld_size == 0)
+		ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("unexpected EOF in COPY data")));
+
+	if (fld_size < -1)
+		ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("invalid field size")));
+
+	if ((DATA_BLOCK_SIZE-cstate->curr_data_offset) >= fld_size)
+	{
+		cstate->curr_data_offset = cstate->curr_data_offset + fld_size;
+	}
+	else
+	{
+		ParallelCopyDataBlock *data_block = NULL;
+
+		block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+		data_block = &pcshared_info->data_blocks[block_pos];
+
+		readbytes = CopyGetData(cstate, &data_block->data[0], 1, DATA_BLOCK_SIZE);
+
+		elog(DEBUG1, "LEADER - bytes read from file after detecting that tuple is spread across data blocks %d", readbytes);
+
+		if (cstate->reached_eof)
+			ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("unexpected EOF in COPY data")));
+
+
+		cstate->prev_data_block = cstate->curr_data_block;
+		cstate->prev_data_block->following_block = block_pos;
+
+		if (cstate->prev_data_block->curr_blk_completed  == false)
+			cstate->prev_data_block->curr_blk_completed = true;
+
+		cstate->curr_data_block = data_block;
+		cstate->curr_data_offset = fld_size - (DATA_BLOCK_SIZE - cstate->curr_data_offset);
+		cstate->curr_block_pos = block_pos;
+		*new_block_pos = block_pos;
+	}
+}
+
+/*
+ * CopyReadBinaryTupleWorker - each worker reads data from data blocks after
+ * getting leader-identified tuple offsets from ring data structure.
+ */
+static pg_attribute_always_inline bool
+CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls)
+{
+	uint32 line_pos;
+	ParallelCopyLineBoundary *line_info;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	int16		fld_count;
+	AttrNumber	attr_count = list_length(cstate->attnumlist);
+	ListCell   *cur;
+	FmgrInfo   *in_functions = cstate->in_functions;
+	Oid		   *typioparams = cstate->typioparams;
+	TupleDesc	tupDesc = RelationGetDescr(cstate->rel);
+	int			i;
+
+	line_pos = GetLinePosition(cstate);
+
+	if (line_pos == -1)
+		return true;
+
+	line_info = &pcshared_info->line_boundaries.ring[line_pos];
+	cstate->curr_data_block = &pcshared_info->data_blocks[line_info->first_block];
+	cstate->curr_data_offset = line_info->start_offset;
+
+	if (cstate->curr_data_offset + sizeof(fld_count) >= (DATA_BLOCK_SIZE - 1))
+	{
+		/*the case where field count spread across datablocks should never occur.
+		  as the leader would have moved it to next block*/
+		elog(DEBUG1, "WORKER - field count spread across datablocks should never occur");
+	}
+
+	memcpy(&fld_count, &cstate->curr_data_block->data[cstate->curr_data_offset], sizeof(fld_count));
+	fld_count = (int16) pg_ntoh16(fld_count);
+
+	if (fld_count == -1)
+	{
+		return true;
+	}
+
+	if (fld_count != attr_count)
+		ereport(ERROR,
+			(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+			errmsg("row field count is %d, expected %d",
+			(int) fld_count, attr_count)));
+
+	cstate->curr_data_offset = cstate->curr_data_offset + sizeof(fld_count);
+	i = 0;
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			attnum = lfirst_int(cur);
+		int			m = attnum - 1;
+		Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+		cstate->cur_attname = NameStr(att->attname);
+
+		i++;
+		values[m] = CopyReadBinaryAttributeWorker(cstate,
+											i,
+											&in_functions[m],
+											typioparams[m],
+											att->atttypmod,
+											&nulls[m]);
+		cstate->cur_attname = NULL;
+	}
+
+	pg_atomic_sub_fetch_u32(&cstate->curr_data_block->unprocessed_line_parts, 1);
+	line_info->start_offset = -1;
+	pg_atomic_write_u32(&line_info->line_state, LINE_WORKER_PROCESSED);
+	pg_atomic_write_u32(&line_info->line_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryAttributeWorker - leader identifies boundaries/offsets
+ * for each attribute/column, it moves on to next data block if the
+ * attribute/column is spread across data blocks.
+ */
+static pg_attribute_always_inline Datum
+CopyReadBinaryAttributeWorker(CopyState cstate, int column_no,
+		FmgrInfo *flinfo, Oid typioparam, int32 typmod, bool *isnull)
+{
+	int32		fld_size;
+	Datum		result;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+	if ((cstate->curr_data_offset + sizeof(fld_size)) >= (DATA_BLOCK_SIZE - 1))
+	{
+		ParallelCopyDataBlock *prev_data_block = cstate->curr_data_block;
+
+		elog(DEBUG1, "WORKER - field size is spread across data blocks");
+
+		cstate->curr_data_block = &pcshared_info->data_blocks[cstate->curr_data_block->following_block];
+		pg_atomic_sub_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+		cstate->curr_data_offset = 0;
+	}
+
+	memcpy(&fld_size, &cstate->curr_data_block->data[cstate->curr_data_offset], sizeof(fld_size));
+	fld_size = (int32) pg_ntoh32(fld_size);
+
+	if (fld_size == 0)
+		ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("unexpected EOF in COPY data")));
+
+	if (fld_size < -1)
+		ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("invalid field size")));
+
+	cstate->curr_data_offset = cstate->curr_data_offset + sizeof(fld_size);
+
+	/* reset attribute_buf to empty, and load raw data in it */
+	resetStringInfo(&cstate->attribute_buf);
+
+	enlargeStringInfo(&cstate->attribute_buf, fld_size);
+
+	if ((DATA_BLOCK_SIZE-cstate->curr_data_offset) >= fld_size)
+	{
+		elog(DEBUG1, "WORKER - tuple lies in single data block");
+
+		memcpy(&cstate->attribute_buf.data[0],&cstate->curr_data_block->data[cstate->curr_data_offset], fld_size);
+		cstate->curr_data_offset = cstate->curr_data_offset + fld_size;
+	}
+	else
+	{
+		ParallelCopyDataBlock *prev_data_block = cstate->curr_data_block;
+
+		elog(DEBUG1, "WORKER - tuple is spread across data blocks");
+
+		memcpy(&cstate->attribute_buf.data[0], &cstate->curr_data_block->data[cstate->curr_data_offset],
+				(DATA_BLOCK_SIZE - cstate->curr_data_offset));
+		cstate->curr_data_block = &pcshared_info->data_blocks[cstate->curr_data_block->following_block];
+		pg_atomic_sub_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+		memcpy(&cstate->attribute_buf.data[DATA_BLOCK_SIZE - cstate->curr_data_offset],
+			&cstate->curr_data_block->data[0], (fld_size - (DATA_BLOCK_SIZE - cstate->curr_data_offset)));
+		cstate->curr_data_offset = fld_size - (DATA_BLOCK_SIZE - cstate->curr_data_offset);
+	}
+
+	cstate->attribute_buf.len = fld_size;
+	cstate->attribute_buf.data[fld_size] = '\0';
+
+	/* Call the column type's binary input converter */
+	result = ReceiveFunctionCall(flinfo, &cstate->attribute_buf,
+								 typioparam, typmod);
+
+	/* Trouble if it didn't eat the whole buffer */
+	if (cstate->attribute_buf.cursor != cstate->attribute_buf.len)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+				 errmsg("incorrect binary data format")));
+
+	*isnull = false;
+	return result;
+}
+
+/*
  * GetLinePosition - return the line position that worker should process.
  */
 static uint32
@@ -5449,60 +5966,74 @@ NextCopyFrom(CopyState cstate, ExprContext *econtext,
 	else
 	{
 		/* binary */
-		int16		fld_count;
-		ListCell   *cur;
+		if (!IsParallelCopy())
+		{
+			int16		fld_count;
+			ListCell   *cur;
 
-		cstate->cur_lineno++;
+			cstate->cur_lineno++;
 
-		if (!CopyGetInt16(cstate, &fld_count))
-		{
-			/* EOF detected (end of file, or protocol-level EOF) */
-			return false;
-		}
+			if (!CopyGetInt16(cstate, &fld_count))
+			{
+				/* EOF detected (end of file, or protocol-level EOF) */
+				return false;
+			}
 
-		if (fld_count == -1)
-		{
-			/*
-			 * Received EOF marker.  In a V3-protocol copy, wait for the
-			 * protocol-level EOF, and complain if it doesn't come
-			 * immediately.  This ensures that we correctly handle CopyFail,
-			 * if client chooses to send that now.
-			 *
-			 * Note that we MUST NOT try to read more data in an old-protocol
-			 * copy, since there is no protocol-level EOF marker then.  We
-			 * could go either way for copy from file, but choose to throw
-			 * error if there's data after the EOF marker, for consistency
-			 * with the new-protocol case.
-			 */
-			char		dummy;
+			if (fld_count == -1)
+			{
+				/*
+				* Received EOF marker.  In a V3-protocol copy, wait for the
+				* protocol-level EOF, and complain if it doesn't come
+				* immediately.  This ensures that we correctly handle CopyFail,
+				* if client chooses to send that now.
+				*
+				* Note that we MUST NOT try to read more data in an old-protocol
+				* copy, since there is no protocol-level EOF marker then.  We
+				* could go either way for copy from file, but choose to throw
+				* error if there's data after the EOF marker, for consistency
+				* with the new-protocol case.
+				*/
+				char		dummy;
+
+				if (cstate->copy_dest != COPY_OLD_FE &&
+					CopyGetData(cstate, &dummy, 1, 1) > 0)
+					ereport(ERROR,
+							(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+							errmsg("received copy data after EOF marker")));
+				return false;
+			}
 
-			if (cstate->copy_dest != COPY_OLD_FE &&
-				CopyGetData(cstate, &dummy, 1, 1) > 0)
+			if (fld_count != attr_count)
 				ereport(ERROR,
 						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-						 errmsg("received copy data after EOF marker")));
-			return false;
+						errmsg("row field count is %d, expected %d",
+								(int) fld_count, attr_count)));
+
+			foreach(cur, cstate->attnumlist)
+			{
+				int			attnum = lfirst_int(cur);
+				int			m = attnum - 1;
+				Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+
+				cstate->cur_attname = NameStr(att->attname);
+				values[m] = CopyReadBinaryAttribute(cstate,
+													&in_functions[m],
+													typioparams[m],
+													att->atttypmod,
+													&nulls[m]);
+				cstate->cur_attname = NULL;
+			}
 		}
+		else
+		{
+			bool eof = false;
 
-		if (fld_count != attr_count)
-			ereport(ERROR,
-					(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-					 errmsg("row field count is %d, expected %d",
-							(int) fld_count, attr_count)));
+			cstate->cur_lineno++;
 
-		foreach(cur, cstate->attnumlist)
-		{
-			int			attnum = lfirst_int(cur);
-			int			m = attnum - 1;
-			Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+			eof = CopyReadBinaryTupleWorker(cstate, values, nulls);
 
-			cstate->cur_attname = NameStr(att->attname);
-			values[m] = CopyReadBinaryAttribute(cstate,
-												&in_functions[m],
-												typioparams[m],
-												att->atttypmod,
-												&nulls[m]);
-			cstate->cur_attname = NULL;
+			if (eof)
+				return false;
 		}
 	}
 
-- 
1.8.3.1

#102Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: vignesh C (#98)
6 attachment(s)
Re: Parallel copy

Hi,

Thanks Vignesh for reviewing parallel copy for binary format files
patch. I tried to address the comments in the attached patch
(0006-Parallel-Copy-For-Binary-Format-Files.patch).

On Thu, Jun 18, 2020 at 6:42 PM vignesh C <vignesh21@gmail.com> wrote:

On Mon, Jun 15, 2020 at 4:39 PM Bharath Rupireddy
<bharath.rupireddyforpostgres@gmail.com> wrote:

The above tests were run with the configuration attached config.txt, which is the same used for performance tests of csv/text files posted earlier in this mail chain.

Request the community to take this patch up for review along with the parallel copy for csv/text file patches and provide feedback.

I had reviewed the patch, few comments:

The new members added should be present in ParallelCopyData

Added to ParallelCopyData.

line_size can be set as and when we process the tuple from
CopyReadBinaryTupleLeader and this can be set at the end. That way the
above code can be removed.

curr_tuple_start_info and curr_tuple_end_info variables are now local
variables to CopyReadBinaryTupleLeader and the line size calculation
code is moved to CopyReadBinaryAttributeLeader.

curr_block_pos variable is present in ParallelCopyShmInfo, we could
use it and remove from here.
curr_data_offset, similar variable raw_buf_index is present in
CopyStateData, we could use it and remove from here.

Yes, making use of them now.

This code is duplicate in CopyReadBinaryTupleLeader &
CopyReadBinaryAttributeLeader. We could make a function and re-use.

Added a new function AdjustFieldInfo.

column_no is not used, it can be removed

Removed.

The above code is present in NextCopyFrom & CopyReadBinaryTupleLeader,
check if we can make a common function or we could use NextCopyFrom as
it is.

Added a macro CHECK_FIELD_COUNT.

+       if (fld_count == -1)
+       {
+               return true;
+       }

Should this be an assert in CopyReadBinaryTupleWorker function as this
check is already done in the leader.

This check in leader signifies the end of the file. For the workers,
the eof is when GetLinePosition() returns -1.
line_pos = GetLinePosition(cstate);
if (line_pos == -1)
return true;
In case the if (fld_count == -1) is encountered in the worker, workers
should just return true from CopyReadBinaryTupleWorker marking eof.
Having this as an assert doesn't serve the purpose I feel.

Along with the review comments addressed
patch(0006-Parallel-Copy-For-Binary-Format-Files.patch) also attaching
all other latest series of patches(0001 to 0005) from [1]/messages/by-id/CALDaNm0H3N9gK7CMheoaXkO99g=uAPA93nSZXu0xDarPyPY6sg@mail.gmail.com, the order
of applying patches is from 0001 to 0006.

[1]: /messages/by-id/CALDaNm0H3N9gK7CMheoaXkO99g=uAPA93nSZXu0xDarPyPY6sg@mail.gmail.com

With Regards,
Bharath Rupireddy.
EnterpriseDB: http://www.enterprisedb.com

Attachments:

0006-Parallel-Copy-For-Binary-Format-Files.patchapplication/octet-stream; name=0006-Parallel-Copy-For-Binary-Format-Files.patchDownload
From be5da9036b223be38d0df4617781eb02634ecdac Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddy@enterprisedb.com>
Date: Wed, 24 Jun 2020 13:12:55 +0530
Subject: [PATCH 6/6] Parallel Copy For Binary Format Files

Leader reads data from the file into the DSM data blocks each of 64K size.
It also identifies each tuple data block id, start offset, end offset,
tuple size and updates this information in the ring data structure.
Workers parallely read the tuple information from the ring data structure,
the actual tuple data from the data blocks and parallely insert the tuples
into the table.
---
 src/backend/commands/copy.c | 642 ++++++++++++++++++++++++++++++++----
 1 file changed, 572 insertions(+), 70 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index e8a89a40a0..e1f03241e8 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -219,6 +219,16 @@ typedef struct ParallelCopyLineBuf
 	uint64				cur_lineno;	/* line number for error messages */
 }ParallelCopyLineBuf;
 
+/*
+ * Tuple boundary information used for parallel copy
+ * for binary format files.
+ */
+typedef struct ParallelCopyTupleInfo
+{
+	uint32 offset;
+	uint32 block_id;
+}ParallelCopyTupleInfo;
+
 /*
  * Parallel copy data information.
  */
@@ -240,6 +250,11 @@ typedef struct ParallelCopyData
 
 	/* Current position in worker_line_buf */
 	uint32				worker_line_buf_pos;
+
+	/*
+	 * For binary formatted files
+	 */
+	ParallelCopyDataBlock *curr_data_block;
 }ParallelCopyData;
 
 /*
@@ -397,6 +412,7 @@ typedef struct ParallelCopyCommonKeyData
 	/* Working state for COPY FROM */
 	AttrNumber          num_defaults;
 	Oid                 relid;
+	bool 				binary;
 }ParallelCopyCommonKeyData;
 
 /*
@@ -697,6 +713,51 @@ if (!IsParallelCopy()) \
 else \
 	return pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
 
+/*
+ * CHECK_FIELD_COUNT - Handles the error cases for field count
+ * for binary format files.
+ */
+#define CHECK_FIELD_COUNT \
+{\
+	if (fld_count == -1) \
+	{ \
+		if (IsParallelCopy() && \
+			!IsLeader()) \
+			return true; \
+		else \
+		{ \
+			/* \
+			* Received EOF marker.  In a V3-protocol copy, wait for the \
+			* protocol-level EOF, and complain if it doesn't come \
+			* immediately.  This ensures that we correctly handle CopyFail, \
+			* if client chooses to send that now. \
+			* \
+			* Note that we MUST NOT try to read more data in an old-protocol \
+			* copy, since there is no protocol-level EOF marker then.  We \
+			* could go either way for copy from file, but choose to throw \
+			* error if there's data after the EOF marker, for consistency \
+			* with the new-protocol case. \
+			*/ \
+			char		dummy; \
+			if (cstate->copy_dest != COPY_OLD_FE && \
+				CopyGetData(cstate, &dummy, 1, 1) > 0) \
+				ereport(ERROR, \
+						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+						errmsg("received copy data after EOF marker"))); \
+			if (IsParallelCopy() && \
+				IsLeader()) \
+				return true; \
+			else \
+				return false; \
+		} \
+	} \
+	if (fld_count != cstate->max_fields) \
+		ereport(ERROR, \
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+				errmsg("row field count is %d, expected %d", \
+				(int) fld_count, cstate->max_fields))); \
+}
+
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
 
@@ -751,6 +812,16 @@ static void PopulateCatalogInformation(CopyState cstate);
 static pg_attribute_always_inline uint32 GetLinePosition(CopyState cstate);
 static pg_attribute_always_inline copy_data_source_cb LookupParallelCopyFnPtr(const char *funcname);
 static pg_attribute_always_inline char* LookupParallelCopyFnStr(copy_data_source_cb fn_addr);
+static uint32 WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info);
+static pg_attribute_always_inline bool CopyReadBinaryTupleLeader(CopyState cstate);
+static pg_attribute_always_inline void CopyReadBinaryAttributeLeader(CopyState cstate,
+										FmgrInfo *flinfo, Oid typioparam, int32 typmod,
+										uint32 *new_block_pos, int m, ParallelCopyTupleInfo *tuple_start_info_ptr,
+										ParallelCopyTupleInfo *tuple_end_info_ptr, uint32 *line_size);
+static pg_attribute_always_inline bool CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls);
+static pg_attribute_always_inline Datum CopyReadBinaryAttributeWorker(CopyState cstate, FmgrInfo *flinfo,
+										  Oid typioparam, int32 typmod, bool *isnull);
+static void AdjustFieldInfo(CopyState cstate, uint8 mode);
 
 /*
  * CopyCommonInfoForWorker - Copy shared_cstate using cstate information.
@@ -769,6 +840,7 @@ CopyCommonInfoForWorker(CopyState cstate, ParallelCopyCommonKeyData *shared_csta
 	shared_cstate->convert_selectively = cstate->convert_selectively;
 	shared_cstate->num_defaults = cstate->num_defaults;
 	shared_cstate->relid = cstate->pcdata->relid;
+	shared_cstate->binary = cstate->binary;
 }
 
 /*
@@ -997,8 +1069,8 @@ FindInsertMethod(CopyState cstate)
 static pg_attribute_always_inline bool
 IsParallelCopyAllowed(CopyState cstate)
 {
-	/* Parallel copy not allowed for frontend (2.0 protocol) & binary option. */
-	if ((cstate->copy_dest == COPY_OLD_FE) || cstate->binary)
+	/* Parallel copy not allowed for frontend (2.0 protocol). */
+	if (cstate->copy_dest == COPY_OLD_FE)
 		return false;
 
 	/* Check if copy is into foreign table or temporary table. */
@@ -1299,6 +1371,7 @@ ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
 	cstate->convert_selectively = shared_cstate->convert_selectively;
 	cstate->num_defaults = shared_cstate->num_defaults;
 	pcdata->relid = shared_cstate->relid;
+	cstate->binary = shared_cstate->binary;
 
 	PopulateGlobalsForCopyFrom(cstate, tup_desc, attnamelist);
 
@@ -1314,7 +1387,7 @@ ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
 	initStringInfo(&cstate->attribute_buf);
 
 	initStringInfo(&cstate->line_buf);
-	for (count = 0; count < WORKER_CHUNK_COUNT;count++)
+	for (count = 0; count < WORKER_CHUNK_COUNT; count++)
 		initStringInfo(&pcdata->worker_line_buf[count].line_buf);
 
 	cstate->line_buf_converted = false;
@@ -1679,32 +1752,55 @@ ParallelCopyLeader(CopyState cstate)
 	/* Execute the before statement triggers from the leader */
 	ExecBeforeStmtTrigger(cstate);
 
-	/* On input just throw the header line away. */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (!cstate->binary)
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
+		/* On input just throw the header line away. */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
 		{
-			pcshared_info->is_read_in_progress = false;
-			return;			/* done */
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+			{
+				pcshared_info->is_read_in_progress = false;
+				return;			/* done */
+			}
 		}
-	}
 
-	for (;;)
+		for (;;)
+		{
+			bool done;
+			cstate->cur_lineno++;
+
+			/* Actually read the line into memory here. */
+			done = CopyReadLine(cstate);
+
+			/*
+			* EOF at start of line means we're done.  If we see EOF after some
+			* characters, we act as though it was newline followed by EOF, ie,
+			* process the line and then exit loop on next iteration.
+			*/
+			if (done && cstate->line_buf.len == 0)
+				break;
+		}
+	}
+	else
 	{
-		bool done;
-		cstate->cur_lineno++;
+		/* binary format */
+		cstate->pcdata->curr_data_block = NULL;
+		cstate->raw_buf_index = 0;
+		pcshared_info->populated = 0;
+		cstate->cur_lineno = 0;
+		cstate->max_fields = list_length(cstate->attnumlist);
 
-		/* Actually read the line into memory here. */
-		done = CopyReadLine(cstate);
+		for (;;)
+		{
+			bool eof = false;
+			cstate->cur_lineno++;
 
-		/*
-		 * EOF at start of line means we're done.  If we see EOF after some
-		 * characters, we act as though it was newline followed by EOF, ie,
-		 * process the line and then exit loop on next iteration.
-		 */
-		if (done && cstate->line_buf.len == 0)
-			break;
+			eof = CopyReadBinaryTupleLeader(cstate);
+
+			if (eof)
+				break;
+		}
 	}
 
 	pcshared_info->is_read_in_progress = false;
@@ -1712,7 +1808,425 @@ ParallelCopyLeader(CopyState cstate)
 }
 
 /*
- * GetLinePosition - return the line position that worker should process.
+ * AdjustFieldInfo - gets a new block, updates the
+ * current offset, calculates the skip bytes.
+ * Works in two modes, 1 for field count
+ * 2 for field size
+ */
+static void
+AdjustFieldInfo(CopyState cstate, uint8 mode)
+{
+	ParallelCopyDataBlock *data_block = NULL;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	uint8 movebytes = 0;
+	uint32 block_pos;
+	uint32 prev_block_pos;
+	int readbytes = 0;
+
+	prev_block_pos = pcshared_info->cur_block_pos;
+
+	block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+	movebytes = DATA_BLOCK_SIZE - cstate->raw_buf_index;
+
+	cstate->pcdata->curr_data_block->skip_bytes = movebytes;
+
+	data_block = &pcshared_info->data_blocks[block_pos];
+
+	if (movebytes > 0)
+		memmove(&data_block->data[0], &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index],
+			movebytes);
+
+	elog(DEBUG1, "LEADER - field info is spread across data blocks - moved %d bytes from current block %u to %u block",
+		movebytes, prev_block_pos, block_pos);
+
+	readbytes = CopyGetData(cstate, &data_block->data[movebytes], 1, (DATA_BLOCK_SIZE - movebytes));
+
+	elog(DEBUG1, "LEADER - bytes read from file after field info is moved to next data block %d", readbytes);
+
+	if (cstate->reached_eof)
+		ereport(ERROR,
+			(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				errmsg("unexpected EOF in COPY data")));
+
+	if (mode == 1)
+	{
+		cstate->pcdata->curr_data_block = data_block;
+		cstate->raw_buf_index = 0;
+	}
+	else if(mode == 2)
+	{
+		ParallelCopyDataBlock *prev_data_block = NULL;
+		prev_data_block = cstate->pcdata->curr_data_block;
+		prev_data_block->following_block = block_pos;
+		cstate->pcdata->curr_data_block = data_block;
+
+		if (prev_data_block->curr_blk_completed  == false)
+			prev_data_block->curr_blk_completed = true;
+
+		cstate->raw_buf_index = 0;
+	}
+}
+
+/*
+ * CopyReadBinaryTupleLeader - leader reads data from binary formatted file
+ * to data blocks and identies tuple boundaries/offsets so that workers
+ * can work on the data blocks data.
+ */
+static pg_attribute_always_inline bool
+CopyReadBinaryTupleLeader(CopyState cstate)
+{
+	int readbytes = 0;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	uint32 block_pos;
+	int16		fld_count;
+	ListCell   *cur;
+	FmgrInfo   *in_functions = cstate->in_functions;
+	Oid		   *typioparams = cstate->typioparams;
+	TupleDesc	tupDesc = RelationGetDescr(cstate->rel);
+	uint32      new_block_pos;
+	uint32      line_size = -1;
+	ParallelCopyTupleInfo curr_tuple_start_info;
+	ParallelCopyTupleInfo curr_tuple_end_info;
+
+	curr_tuple_start_info.block_id = -1;
+	curr_tuple_start_info.offset = -1;
+	curr_tuple_end_info.block_id = -1;
+	curr_tuple_end_info.offset = -1;
+
+	if (cstate->pcdata->curr_data_block == NULL)
+	{
+		block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+		cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[block_pos];
+
+		cstate->raw_buf_index = 0;
+
+		readbytes = CopyGetData(cstate, &cstate->pcdata->curr_data_block->data, 1, DATA_BLOCK_SIZE);
+
+		elog(DEBUG1, "LEADER - bytes read from file %d", readbytes);
+
+		if (cstate->reached_eof)
+			return true;
+	}
+
+	if (cstate->raw_buf_index + sizeof(fld_count) >= (DATA_BLOCK_SIZE - 1))
+		AdjustFieldInfo(cstate, 1);
+
+	memcpy(&fld_count, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_count));
+
+	fld_count = (int16) pg_ntoh16(fld_count);
+
+	CHECK_FIELD_COUNT;
+
+	cstate->raw_buf_index = cstate->raw_buf_index + sizeof(fld_count);
+	new_block_pos = pcshared_info->cur_block_pos;
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			attnum = lfirst_int(cur);
+		int			m = attnum - 1;
+		Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+
+		CopyReadBinaryAttributeLeader(cstate,
+									&in_functions[m],
+									typioparams[m],
+									att->atttypmod,
+									&new_block_pos,
+									m,
+									&curr_tuple_start_info,
+									&curr_tuple_end_info,
+									&line_size);
+	}
+
+	if (line_size > 0)
+	{
+		int line_pos = UpdateBlockInLineInfo(cstate,
+											curr_tuple_start_info.block_id,
+											curr_tuple_start_info.offset,
+											line_size,
+											LINE_LEADER_POPULATED);
+
+		pcshared_info->populated++;
+
+		elog(DEBUG1, "LEADER - adding - block:%u, offset:%u, line size:%u line position:%d",
+						 curr_tuple_start_info.block_id,
+						 curr_tuple_start_info.offset,
+						 line_size, line_pos);
+	}
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryAttributeLeader - leader identifies boundaries/offsets
+ * for each attribute/column, it moves on to next data block if the
+ * attribute/column is spread across data blocks.
+ */
+static pg_attribute_always_inline void
+CopyReadBinaryAttributeLeader(CopyState cstate, FmgrInfo *flinfo,
+	Oid typioparam, int32 typmod, uint32 *new_block_pos,
+	int m, ParallelCopyTupleInfo *tuple_start_info_ptr,
+	ParallelCopyTupleInfo *tuple_end_info_ptr, uint32 *line_size)
+{
+	int32		fld_size;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+	if (m == 0)
+	{
+		tuple_start_info_ptr->block_id = pcshared_info->cur_block_pos;
+		/* raw_buf_index would have moved away size of field count bytes
+		   in the caller, so move back to store the tuple start offset.
+		*/
+		tuple_start_info_ptr->offset =  cstate->raw_buf_index - sizeof(int16);
+	}
+
+	if ((cstate->raw_buf_index + sizeof(fld_size)) >= (DATA_BLOCK_SIZE - 1))
+	{
+		AdjustFieldInfo(cstate, 2);
+		*new_block_pos = pcshared_info->cur_block_pos;
+	}
+
+	memcpy(&fld_size, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_size));
+
+	cstate->raw_buf_index = cstate->raw_buf_index + sizeof(fld_size);
+
+	fld_size = (int32) pg_ntoh32(fld_size);
+
+	if (fld_size == 0)
+		ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("unexpected EOF in COPY data")));
+
+	if (fld_size < -1)
+		ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("invalid field size")));
+
+	if ((DATA_BLOCK_SIZE-cstate->raw_buf_index) >= fld_size)
+	{
+		cstate->raw_buf_index = cstate->raw_buf_index + fld_size;
+	}
+	else
+	{
+		ParallelCopyDataBlock *data_block = NULL;
+		ParallelCopyDataBlock *prev_data_block = NULL;
+		uint32 block_pos;
+		int readbytes;
+
+		block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+		data_block = &pcshared_info->data_blocks[block_pos];
+
+		readbytes = CopyGetData(cstate, &data_block->data[0], 1, DATA_BLOCK_SIZE);
+
+		elog(DEBUG1, "LEADER - bytes read from file after detecting that tuple is spread across data blocks %d", readbytes);
+
+		if (cstate->reached_eof)
+			ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("unexpected EOF in COPY data")));
+
+		prev_data_block = cstate->pcdata->curr_data_block;
+		prev_data_block->following_block = block_pos;
+
+		if (prev_data_block->curr_blk_completed  == false)
+			prev_data_block->curr_blk_completed = true;
+
+		cstate->pcdata->curr_data_block = data_block;
+		cstate->raw_buf_index = fld_size - (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+		*new_block_pos = block_pos;
+	}
+
+	if (m == cstate->max_fields - 1)
+	{
+		tuple_end_info_ptr->block_id = *new_block_pos;
+		tuple_end_info_ptr->offset =  cstate->raw_buf_index - 1;
+
+		if (tuple_start_info_ptr->block_id == tuple_end_info_ptr->block_id)
+		{
+			elog(DEBUG1,"LEADER - tuple lies in a single data block");
+
+			*line_size = tuple_end_info_ptr->offset - tuple_start_info_ptr->offset + 1;
+			pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[tuple_start_info_ptr->block_id].unprocessed_line_parts, 1);
+		}
+		else
+		{
+			uint32 following_block_id = pcshared_info->data_blocks[tuple_start_info_ptr->block_id].following_block;
+
+			elog(DEBUG1,"LEADER - tuple is spread across data blocks");
+
+			*line_size = DATA_BLOCK_SIZE - tuple_start_info_ptr->offset -
+				pcshared_info->data_blocks[tuple_start_info_ptr->block_id].skip_bytes;
+
+			pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[tuple_start_info_ptr->block_id].unprocessed_line_parts, 1);
+
+			while (following_block_id != tuple_end_info_ptr->block_id)
+			{
+				*line_size = *line_size + DATA_BLOCK_SIZE - pcshared_info->data_blocks[following_block_id].skip_bytes;
+
+				pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[following_block_id].unprocessed_line_parts, 1);
+
+				following_block_id = pcshared_info->data_blocks[following_block_id].following_block;
+
+				if (following_block_id == -1)
+					break;
+			}
+
+			if (following_block_id != -1)
+				pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[following_block_id].unprocessed_line_parts, 1);
+
+			*line_size = *line_size + tuple_end_info_ptr->offset + 1;
+		}
+	}
+}
+
+/*
+ * CopyReadBinaryTupleWorker - each worker reads data from data blocks after
+ * getting leader-identified tuple offsets from ring data structure.
+ */
+static pg_attribute_always_inline bool
+CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls)
+{
+	uint32 line_pos;
+	ParallelCopyLineBoundary *line_info;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	int16		fld_count;
+	ListCell   *cur;
+	FmgrInfo   *in_functions = cstate->in_functions;
+	Oid		   *typioparams = cstate->typioparams;
+	TupleDesc	tupDesc = RelationGetDescr(cstate->rel);
+
+	line_pos = GetLinePosition(cstate);
+
+	if (line_pos == -1)
+		return true;
+
+	line_info = &pcshared_info->line_boundaries.ring[line_pos];
+	cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[line_info->first_block];
+	cstate->raw_buf_index = line_info->start_offset;
+
+	if (cstate->raw_buf_index + sizeof(fld_count) >= (DATA_BLOCK_SIZE - 1))
+		/*the case where field count spread across datablocks should never occur.
+		  as the leader would have moved it to next block*/
+		elog(DEBUG1, "WORKER - field count spread across datablocks should never occur");
+
+	memcpy(&fld_count, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_count));
+	fld_count = (int16) pg_ntoh16(fld_count);
+
+	CHECK_FIELD_COUNT;
+
+	cstate->raw_buf_index = cstate->raw_buf_index + sizeof(fld_count);
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			attnum = lfirst_int(cur);
+		int			m = attnum - 1;
+		Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+		cstate->cur_attname = NameStr(att->attname);
+
+		values[m] = CopyReadBinaryAttributeWorker(cstate,
+											&in_functions[m],
+											typioparams[m],
+											att->atttypmod,
+											&nulls[m]);
+		cstate->cur_attname = NULL;
+	}
+
+	pg_atomic_sub_fetch_u32(&cstate->pcdata->curr_data_block->unprocessed_line_parts, 1);
+	line_info->start_offset = -1;
+	pg_atomic_write_u32(&line_info->line_state, LINE_WORKER_PROCESSED);
+	pg_atomic_write_u32(&line_info->line_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryAttributeWorker - leader identifies boundaries/offsets
+ * for each attribute/column, it moves on to next data block if the
+ * attribute/column is spread across data blocks.
+ */
+static pg_attribute_always_inline Datum
+CopyReadBinaryAttributeWorker(CopyState cstate, FmgrInfo *flinfo,
+		Oid typioparam, int32 typmod, bool *isnull)
+{
+	int32		fld_size;
+	Datum		result;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+	if ((cstate->raw_buf_index + sizeof(fld_size)) >= (DATA_BLOCK_SIZE - 1))
+	{
+		ParallelCopyDataBlock *prev_data_block = cstate->pcdata->curr_data_block;
+
+		elog(DEBUG1, "WORKER - field size is spread across data blocks");
+
+		cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[cstate->pcdata->curr_data_block->following_block];
+		pg_atomic_sub_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+		cstate->raw_buf_index = 0;
+	}
+
+	memcpy(&fld_size, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_size));
+	fld_size = (int32) pg_ntoh32(fld_size);
+
+	if (fld_size == 0)
+		ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("unexpected EOF in COPY data")));
+
+	if (fld_size < -1)
+		ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("invalid field size")));
+
+	cstate->raw_buf_index = cstate->raw_buf_index + sizeof(fld_size);
+
+	/* reset attribute_buf to empty, and load raw data in it */
+	resetStringInfo(&cstate->attribute_buf);
+
+	enlargeStringInfo(&cstate->attribute_buf, fld_size);
+
+	if ((DATA_BLOCK_SIZE - cstate->raw_buf_index) >= fld_size)
+	{
+		elog(DEBUG1, "WORKER - tuple lies in single data block");
+
+		memcpy(&cstate->attribute_buf.data[0],&cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], fld_size);
+		cstate->raw_buf_index = cstate->raw_buf_index + fld_size;
+	}
+	else
+	{
+		ParallelCopyDataBlock *prev_data_block = cstate->pcdata->curr_data_block;
+
+		elog(DEBUG1, "WORKER - tuple is spread across data blocks");
+
+		memcpy(&cstate->attribute_buf.data[0], &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index],
+				(DATA_BLOCK_SIZE - cstate->raw_buf_index));
+		cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[cstate->pcdata->curr_data_block->following_block];
+		pg_atomic_sub_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+		memcpy(&cstate->attribute_buf.data[DATA_BLOCK_SIZE - cstate->raw_buf_index],
+			&cstate->pcdata->curr_data_block->data[0], (fld_size - (DATA_BLOCK_SIZE - cstate->raw_buf_index)));
+		cstate->raw_buf_index = fld_size - (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+	}
+
+	cstate->attribute_buf.len = fld_size;
+	cstate->attribute_buf.data[fld_size] = '\0';
+
+	/* Call the column type's binary input converter */
+	result = ReceiveFunctionCall(flinfo, &cstate->attribute_buf,
+								 typioparam, typmod);
+
+	/* Trouble if it didn't eat the whole buffer */
+	if (cstate->attribute_buf.cursor != cstate->attribute_buf.len)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+				 errmsg("incorrect binary data format")));
+
+	*isnull = false;
+	return result;
+}
+
+/*
+ * GetLinePosition - return the line position that worker should pcdata->process.
  */
 static uint32
 GetLinePosition(CopyState cstate)
@@ -1797,6 +2311,7 @@ GetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
 		{
 			dataBlkPtr->curr_blk_completed = false;
 			dataBlkPtr->skip_bytes = 0;
+			dataBlkPtr->following_block = -1;
 			pcshared_info->cur_block_pos = block_pos;
 			return block_pos;
 		}
@@ -5449,60 +5964,47 @@ NextCopyFrom(CopyState cstate, ExprContext *econtext,
 	else
 	{
 		/* binary */
-		int16		fld_count;
-		ListCell   *cur;
-
-		cstate->cur_lineno++;
-
-		if (!CopyGetInt16(cstate, &fld_count))
+		if (!IsParallelCopy())
 		{
-			/* EOF detected (end of file, or protocol-level EOF) */
-			return false;
-		}
+			int16		fld_count;
+			ListCell   *cur;
 
-		if (fld_count == -1)
-		{
-			/*
-			 * Received EOF marker.  In a V3-protocol copy, wait for the
-			 * protocol-level EOF, and complain if it doesn't come
-			 * immediately.  This ensures that we correctly handle CopyFail,
-			 * if client chooses to send that now.
-			 *
-			 * Note that we MUST NOT try to read more data in an old-protocol
-			 * copy, since there is no protocol-level EOF marker then.  We
-			 * could go either way for copy from file, but choose to throw
-			 * error if there's data after the EOF marker, for consistency
-			 * with the new-protocol case.
-			 */
-			char		dummy;
+			cstate->cur_lineno++;
+			cstate->max_fields = list_length(cstate->attnumlist);
 
-			if (cstate->copy_dest != COPY_OLD_FE &&
-				CopyGetData(cstate, &dummy, 1, 1) > 0)
-				ereport(ERROR,
-						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-						 errmsg("received copy data after EOF marker")));
-			return false;
-		}
+			if (!CopyGetInt16(cstate, &fld_count))
+			{
+				/* EOF detected (end of file, or protocol-level EOF) */
+				return false;
+			}
 
-		if (fld_count != attr_count)
-			ereport(ERROR,
-					(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-					 errmsg("row field count is %d, expected %d",
-							(int) fld_count, attr_count)));
+			CHECK_FIELD_COUNT;
 
-		foreach(cur, cstate->attnumlist)
+			foreach(cur, cstate->attnumlist)
+			{
+				int			attnum = lfirst_int(cur);
+				int			m = attnum - 1;
+				Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+
+				cstate->cur_attname = NameStr(att->attname);
+				values[m] = CopyReadBinaryAttribute(cstate,
+													&in_functions[m],
+													typioparams[m],
+													att->atttypmod,
+													&nulls[m]);
+				cstate->cur_attname = NULL;
+			}
+		}
+		else
 		{
-			int			attnum = lfirst_int(cur);
-			int			m = attnum - 1;
-			Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+			bool eof = false;
+			cstate->cur_lineno++;
+			cstate->max_fields = list_length(cstate->attnumlist);
 
-			cstate->cur_attname = NameStr(att->attname);
-			values[m] = CopyReadBinaryAttribute(cstate,
-												&in_functions[m],
-												typioparams[m],
-												att->atttypmod,
-												&nulls[m]);
-			cstate->cur_attname = NULL;
+			eof = CopyReadBinaryTupleWorker(cstate, values, nulls);
+
+			if (eof)
+				return false;
 		}
 	}
 
-- 
2.25.1

0001-Copy-code-readjustment-to-support-parallel-copy.patchapplication/octet-stream; name=0001-Copy-code-readjustment-to-support-parallel-copy.patchDownload
From 4455d3e067bda56316bb292e5d010bdf40254fec Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Tue, 23 Jun 2020 06:49:22 +0530
Subject: [PATCH 1/6] Copy code readjustment to support parallel copy.

This patch has the copy code slightly readjusted so that the common code is
separated to functions/macros, these functions/macros will be used by the
workers in the parallel copy code of the upcoming patches. EOL removal is moved
from CopyReadLine to CopyReadLineText, this change was required because in case
of parallel copy the record identification and record updation is done in
CopyReadLineText, before record information is updated in shared memory the new
line characters should be removed.
---
 src/backend/commands/copy.c | 372 ++++++++++++++++++++++++++------------------
 1 file changed, 221 insertions(+), 151 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 6b1fd6d..65a504f 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -95,6 +95,9 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
+#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+#define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
+
 /*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
@@ -219,7 +222,6 @@ typedef struct CopyStateData
 	 * converts it.  Note: we guarantee that there is a \0 at
 	 * raw_buf[raw_buf_len].
 	 */
-#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
@@ -347,6 +349,88 @@ if (1) \
 	goto not_end_of_copy; \
 } else ((void) 0)
 
+/*
+ * CONVERT_TO_SERVER_ENCODING - convert contents to server encoding.
+ */
+#define CONVERT_TO_SERVER_ENCODING(cstate) \
+{ \
+	/* Done reading the line.  Convert it to server encoding. */ \
+	if (cstate->need_transcoding) \
+	{ \
+		char	   *cvt; \
+		cvt = pg_any_to_server(cstate->line_buf.data, \
+							   cstate->line_buf.len, \
+							   cstate->file_encoding); \
+		if (cvt != cstate->line_buf.data) \
+		{ \
+			/* transfer converted data back to line_buf */ \
+			resetStringInfo(&cstate->line_buf); \
+			appendBinaryStringInfo(&cstate->line_buf, cvt, strlen(cvt)); \
+			pfree(cvt); \
+		} \
+	} \
+	/* Now it's safe to use the buffer in error messages */ \
+	cstate->line_buf_converted = true; \
+}
+
+/*
+ * CLEAR_EOL_FROM_COPIED_DATA - Clear EOL from the copied data.
+ */
+#define CLEAR_EOL_FROM_COPIED_DATA(copy_line_data, copy_line_pos, copy_line_size) \
+{ \
+	/* \
+	 * If we didn't hit EOF, then we must have transferred the EOL marker \
+	 * to line_buf along with the data.  Get rid of it. \
+	 */ \
+   switch (cstate->eol_type) \
+   { \
+	   case EOL_NL: \
+		   Assert(copy_line_size >= 1); \
+		   Assert(copy_line_data[copy_line_pos - 1] == '\n'); \
+		   copy_line_data[copy_line_pos - 1] = '\0'; \
+		   copy_line_size--; \
+		   break; \
+	   case EOL_CR: \
+		   Assert(copy_line_size >= 1); \
+		   Assert(copy_line_data[copy_line_pos - 1] == '\r'); \
+		   copy_line_data[copy_line_pos - 1] = '\0'; \
+		   copy_line_size--; \
+		   break; \
+	   case EOL_CRNL: \
+		   Assert(copy_line_size >= 2); \
+		   Assert(copy_line_data[copy_line_pos - 2] == '\r'); \
+		   Assert(copy_line_data[copy_line_pos - 1] == '\n'); \
+		   copy_line_data[copy_line_pos - 2] = '\0'; \
+		   copy_line_size -= 2; \
+		   break; \
+	   case EOL_UNKNOWN: \
+		   /* shouldn't get here */ \
+		   Assert(false); \
+		   break; \
+   } \
+}
+
+/*
+ * CLEAR_EOL_LINE - Wrapper for clearing EOL.
+ */
+#define CLEAR_EOL_LINE() \
+if (!result && !IsHeaderLine()) \
+	CLEAR_EOL_FROM_COPIED_DATA(cstate->line_buf.data, \
+								cstate->line_buf.len, \
+								cstate->line_buf.len) \
+
+/*
+ * INCREMENTPROCESSED - Increment the lines processed.
+ */
+#define INCREMENTPROCESSED(processed)  \
+processed++;
+
+/*
+ * GETPROCESSED - Get the lines processed.
+ */
+#define GETPROCESSED(processed) \
+return processed;
+
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
 
@@ -392,6 +476,8 @@ static bool CopyGetInt32(CopyState cstate, int32 *val);
 static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 
+static void PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tup_desc,
+							   List *attnamelist);
 
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
@@ -793,6 +879,7 @@ CopyLoadRawBuf(CopyState cstate)
 {
 	int			nbytes;
 	int			inbytes;
+	int         minread = 1;
 
 	if (cstate->raw_buf_index < cstate->raw_buf_len)
 	{
@@ -804,8 +891,11 @@ CopyLoadRawBuf(CopyState cstate)
 	else
 		nbytes = 0;				/* no data need be saved */
 
+	if (cstate->copy_dest == COPY_NEW_FE)
+		minread = RAW_BUF_SIZE - nbytes;
+
 	inbytes = CopyGetData(cstate, cstate->raw_buf + nbytes,
-						  1, RAW_BUF_SIZE - nbytes);
+						  minread, RAW_BUF_SIZE - nbytes);
 	nbytes += inbytes;
 	cstate->raw_buf[nbytes] = '\0';
 	cstate->raw_buf_index = 0;
@@ -1463,7 +1553,6 @@ BeginCopy(ParseState *pstate,
 {
 	CopyState	cstate;
 	TupleDesc	tupDesc;
-	int			num_phys_attrs;
 	MemoryContext oldcontext;
 
 	/* Allocate workspace and zero all fields */
@@ -1629,6 +1718,24 @@ BeginCopy(ParseState *pstate,
 		tupDesc = cstate->queryDesc->tupDesc;
 	}
 
+	PopulateGlobalsForCopyFrom(cstate, tupDesc, attnamelist);
+	cstate->copy_dest = COPY_FILE;	/* default */
+
+	MemoryContextSwitchTo(oldcontext);
+
+	return cstate;
+}
+
+/*
+ * PopulateGlobalsForCopyFrom - Populates the common variables required for copy
+ * from operation. This is a helper function for BeginCopy function.
+ */
+static void
+PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tupDesc,
+							List *attnamelist)
+{
+	int			num_phys_attrs;
+
 	/* Generate or convert list of attributes to process */
 	cstate->attnumlist = CopyGetAttnums(tupDesc, cstate->rel, attnamelist);
 
@@ -1748,12 +1855,6 @@ BeginCopy(ParseState *pstate,
 		 pg_database_encoding_max_length() > 1);
 	/* See Multibyte encoding comment above */
 	cstate->encoding_embeds_ascii = PG_ENCODING_IS_CLIENT_ONLY(cstate->file_encoding);
-
-	cstate->copy_dest = COPY_FILE;	/* default */
-
-	MemoryContextSwitchTo(oldcontext);
-
-	return cstate;
 }
 
 /*
@@ -2646,32 +2747,11 @@ CopyMultiInsertInfoStore(CopyMultiInsertInfo *miinfo, ResultRelInfo *rri,
 }
 
 /*
- * Copy FROM file to relation.
+ * Check if the relation specified in copy from is valid.
  */
-uint64
-CopyFrom(CopyState cstate)
+static void
+CheckTargetRelValidity(CopyState cstate)
 {
-	ResultRelInfo *resultRelInfo;
-	ResultRelInfo *target_resultRelInfo;
-	ResultRelInfo *prevResultRelInfo = NULL;
-	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
-	ModifyTableState *mtstate;
-	ExprContext *econtext;
-	TupleTableSlot *singleslot = NULL;
-	MemoryContext oldcontext = CurrentMemoryContext;
-
-	PartitionTupleRouting *proute = NULL;
-	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
-	int			ti_options = 0; /* start with default options for insert */
-	BulkInsertState bistate = NULL;
-	CopyInsertMethod insertMethod;
-	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
-	uint64		processed = 0;
-	bool		has_before_insert_row_trig;
-	bool		has_instead_insert_row_trig;
-	bool		leafpart_use_multi_insert = false;
-
 	Assert(cstate->rel);
 
 	/*
@@ -2708,27 +2788,6 @@ CopyFrom(CopyState cstate)
 							RelationGetRelationName(cstate->rel))));
 	}
 
-	/*
-	 * If the target file is new-in-transaction, we assume that checking FSM
-	 * for free space is a waste of time.  This could possibly be wrong, but
-	 * it's unlikely.
-	 */
-	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
-		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
-		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
-		ti_options |= TABLE_INSERT_SKIP_FSM;
-
-	/*
-	 * Optimize if new relfilenode was created in this subxact or one of its
-	 * committed children and we won't see those rows later as part of an
-	 * earlier scan or command. The subxact test ensures that if this subxact
-	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
-	 * that the stronger test of exactly which subtransaction created it is
-	 * crucial for correctness of this optimization. The test for an earlier
-	 * scan or command tolerates false negatives. FREEZE causes other sessions
-	 * to see rows they would not see under MVCC, and a false negative merely
-	 * spreads that anomaly to the current session.
-	 */
 	if (cstate->freeze)
 	{
 		/*
@@ -2766,9 +2825,61 @@ CopyFrom(CopyState cstate)
 			ereport(ERROR,
 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 					 errmsg("cannot perform COPY FREEZE because the table was not created or truncated in the current subtransaction")));
+	}
+}
+
+/*
+ * Copy FROM file to relation.
+ */
+uint64
+CopyFrom(CopyState cstate)
+{
+	ResultRelInfo *resultRelInfo;
+	ResultRelInfo *target_resultRelInfo;
+	ResultRelInfo *prevResultRelInfo = NULL;
+	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
+	ModifyTableState *mtstate;
+	ExprContext *econtext;
+	TupleTableSlot *singleslot = NULL;
+	MemoryContext oldcontext = CurrentMemoryContext;
+
+	PartitionTupleRouting *proute = NULL;
+	ErrorContextCallback errcallback;
+	CommandId	mycid = GetCurrentCommandId(true);
+	int			ti_options = 0; /* start with default options for insert */
+	BulkInsertState bistate = NULL;
+	CopyInsertMethod insertMethod;
+	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
+	uint64		processed = 0;
+	bool		has_before_insert_row_trig;
+	bool		has_instead_insert_row_trig;
+	bool		leafpart_use_multi_insert = false;
+
+	CheckTargetRelValidity(cstate);
 
+	/*
+	 * If the target file is new-in-transaction, we assume that checking FSM
+	 * for free space is a waste of time.  This could possibly be wrong, but
+	 * it's unlikely.
+	 */
+	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
+		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
+		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
+		ti_options |= TABLE_INSERT_SKIP_FSM;
+
+	/*
+	 * Optimize if new relfilenode was created in this subxact or one of its
+	 * committed children and we won't see those rows later as part of an
+	 * earlier scan or command. The subxact test ensures that if this subxact
+	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
+	 * that the stronger test of exactly which subtransaction created it is
+	 * crucial for correctness of this optimization. The test for an earlier
+	 * scan or command tolerates false negatives. FREEZE causes other sessions
+	 * to see rows they would not see under MVCC, and a false negative merely
+	 * spreads that anomaly to the current session.
+	 */
+	if (cstate->freeze)
 		ti_options |= TABLE_INSERT_FROZEN;
-	}
 
 	/*
 	 * We need a ResultRelInfo so we can use the regular executor's
@@ -3261,7 +3372,7 @@ CopyFrom(CopyState cstate)
 			 * or FDW; this is the same definition used by nodeModifyTable.c
 			 * for counting tuples inserted by an INSERT command.
 			 */
-			processed++;
+			INCREMENTPROCESSED(processed)
 		}
 	}
 
@@ -3316,30 +3427,15 @@ CopyFrom(CopyState cstate)
 
 	FreeExecutorState(estate);
 
-	return processed;
+	GETPROCESSED(processed)
 }
 
 /*
- * Setup to read tuples from a file for COPY FROM.
- *
- * 'rel': Used as a template for the tuples
- * 'filename': Name of server-local file to read
- * 'attnamelist': List of char *, columns to include. NIL selects all cols.
- * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
- *
- * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ * PopulateCatalogInformation - populate the catalog information.
  */
-CopyState
-BeginCopyFrom(ParseState *pstate,
-			  Relation rel,
-			  const char *filename,
-			  bool is_program,
-			  copy_data_source_cb data_source_cb,
-			  List *attnamelist,
-			  List *options)
+static void
+PopulateCatalogInformation(CopyState cstate)
 {
-	CopyState	cstate;
-	bool		pipe = (filename == NULL);
 	TupleDesc	tupDesc;
 	AttrNumber	num_phys_attrs,
 				num_defaults;
@@ -3349,31 +3445,8 @@ BeginCopyFrom(ParseState *pstate,
 	Oid			in_func_oid;
 	int		   *defmap;
 	ExprState **defexprs;
-	MemoryContext oldcontext;
 	bool		volatile_defexprs;
 
-	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
-	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
-
-	/* Initialize state variables */
-	cstate->reached_eof = false;
-	cstate->eol_type = EOL_UNKNOWN;
-	cstate->cur_relname = RelationGetRelationName(cstate->rel);
-	cstate->cur_lineno = 0;
-	cstate->cur_attname = NULL;
-	cstate->cur_attval = NULL;
-
-	/* Set up variables to avoid per-attribute overhead. */
-	initStringInfo(&cstate->attribute_buf);
-	initStringInfo(&cstate->line_buf);
-	cstate->line_buf_converted = false;
-	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
-	cstate->raw_buf_index = cstate->raw_buf_len = 0;
-
-	/* Assign range table, we'll need it in CopyFrom. */
-	if (pstate)
-		cstate->range_table = pstate->p_rtable;
-
 	tupDesc = RelationGetDescr(cstate->rel);
 	num_phys_attrs = tupDesc->natts;
 	num_defaults = 0;
@@ -3451,6 +3524,54 @@ BeginCopyFrom(ParseState *pstate,
 	cstate->defexprs = defexprs;
 	cstate->volatile_defexprs = volatile_defexprs;
 	cstate->num_defaults = num_defaults;
+}
+
+/*
+ * Setup to read tuples from a file for COPY FROM.
+ *
+ * 'rel': Used as a template for the tuples
+ * 'filename': Name of server-local file to read
+ * 'attnamelist': List of char *, columns to include. NIL selects all cols.
+ * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
+ *
+ * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ */
+CopyState
+BeginCopyFrom(ParseState *pstate,
+			  Relation rel,
+			  const char *filename,
+			  bool is_program,
+			  copy_data_source_cb data_source_cb,
+			  List *attnamelist,
+			  List *options)
+{
+	CopyState	cstate;
+	bool		pipe = (filename == NULL);
+	MemoryContext oldcontext;
+
+	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	/* Initialize state variables */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/* Set up variables to avoid per-attribute overhead. */
+	initStringInfo(&cstate->attribute_buf);
+	initStringInfo(&cstate->line_buf);
+	cstate->line_buf_converted = false;
+	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+
+	/* Assign range table, we'll need it in CopyFrom. */
+	if (pstate)
+		cstate->range_table = pstate->p_rtable;
+
+	PopulateCatalogInformation(cstate);
 	cstate->is_program = is_program;
 
 	if (data_source_cb)
@@ -3860,60 +3981,8 @@ CopyReadLine(CopyState cstate)
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
-	else
-	{
-		/*
-		 * If we didn't hit EOF, then we must have transferred the EOL marker
-		 * to line_buf along with the data.  Get rid of it.
-		 */
-		switch (cstate->eol_type)
-		{
-			case EOL_NL:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CR:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\r');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CRNL:
-				Assert(cstate->line_buf.len >= 2);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 2] == '\r');
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len -= 2;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_UNKNOWN:
-				/* shouldn't get here */
-				Assert(false);
-				break;
-		}
-	}
-
-	/* Done reading the line.  Convert it to server encoding. */
-	if (cstate->need_transcoding)
-	{
-		char	   *cvt;
-
-		cvt = pg_any_to_server(cstate->line_buf.data,
-							   cstate->line_buf.len,
-							   cstate->file_encoding);
-		if (cvt != cstate->line_buf.data)
-		{
-			/* transfer converted data back to line_buf */
-			resetStringInfo(&cstate->line_buf);
-			appendBinaryStringInfo(&cstate->line_buf, cvt, strlen(cvt));
-			pfree(cvt);
-		}
-	}
-
-	/* Now it's safe to use the buffer in error messages */
-	cstate->line_buf_converted = true;
 
+	CONVERT_TO_SERVER_ENCODING(cstate)
 	return result;
 }
 
@@ -4277,6 +4346,7 @@ not_end_of_copy:
 	 * Transfer any still-uncopied data to line_buf.
 	 */
 	REFILL_LINEBUF;
+	CLEAR_EOL_LINE()
 
 	return result;
 }
-- 
1.8.3.1

0002-Framework-for-leader-worker-in-parallel-copy.patchapplication/octet-stream; name=0002-Framework-for-leader-worker-in-parallel-copy.patchDownload
From 447a954eed01432c170ad94e3ffffa30112f53aa Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>,Bharath <bharath.rupireddyforpostgres@gmail.com>
Date: Tue, 23 Jun 2020 07:04:46 +0530
Subject: [PATCH 2/6] Framework for leader/worker in parallel copy.

This patch has the framework for data structures in parallel copy, leader
initialization, worker initialization, shared memory updation, starting workers,
wait for workers and workers exiting.
---
 src/backend/access/transam/parallel.c       |   4 +
 src/backend/commands/copy.c                 | 838 +++++++++++++++++++++++++++-
 src/backend/replication/logical/tablesync.c |   2 +-
 src/include/commands/copy.h                 |   4 +
 src/tools/pgindent/typedefs.list            |   8 +
 5 files changed, 851 insertions(+), 5 deletions(-)

diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index 14a8690..09e7a19 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -25,6 +25,7 @@
 #include "catalog/pg_enum.h"
 #include "catalog/storage.h"
 #include "commands/async.h"
+#include "commands/copy.h"
 #include "executor/execParallel.h"
 #include "libpq/libpq.h"
 #include "libpq/pqformat.h"
@@ -145,6 +146,9 @@ static const struct
 	},
 	{
 		"parallel_vacuum_main", parallel_vacuum_main
+	},
+	{
+		"ParallelCopyMain", ParallelCopyMain
 	}
 };
 
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 65a504f..34c657c 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -96,9 +96,138 @@ typedef enum CopyInsertMethod
 } CopyInsertMethod;
 
 #define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+
+#define DATA_BLOCK_SIZE RAW_BUF_SIZE
+#define RINGSIZE (10 * 1000)
+#define MAX_BLOCKS_COUNT 1000
+#define WORKER_CHUNK_COUNT 50	/* should be mod of RINGSIZE */
+
+#define	IsParallelCopy()		(cstate->is_parallel)
+#define IsLeader()				(cstate->pcdata->is_leader)
 #define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
 
 /*
+ * Copy data block information.
+ */
+typedef struct ParallelCopyDataBlock
+{
+	/* The number of unprocessed lines in the current block. */
+	pg_atomic_uint32 unprocessed_line_parts;
+
+	/*
+	 * If the current line data is continued into another block, following_block
+	 * will have the position where the remaining data need to be read.
+	 */
+	uint32	following_block;
+
+	/*
+	 * This flag will be set, when the leader finds out this block can be read
+	 * safely by the worker. This helps the worker to start processing the line
+	 * early where the line will be spread across many blocks and the worker
+	 * need not wait for the complete line to be processed.
+	 */
+	bool   curr_blk_completed;
+	char   data[DATA_BLOCK_SIZE]; /* data read from file */
+	uint8  skip_bytes;
+}ParallelCopyDataBlock;
+
+/*
+ * Individual line information.
+ * ParallelCopyLineBoundary is common data structure between leader & worker,
+ * this is protected by the following sequence in the leader & worker.
+ * Leader should operate in the following order:
+ * 1) update first_block, start_offset & cur_lineno in any order.
+ * 2) update line_size.
+ * 3) update line_state.
+ * Worker should operate in the following order:
+ * 1) read line_size.
+ * 2) only one worker should choose one line for processing, this is handled by
+ *    using pg_atomic_compare_exchange_u32, worker will change the sate to
+ *    LINE_WORKER_PROCESSING only if line_state is LINE_LEADER_POPULATED.
+ * 3) read first_block, start_offset & cur_lineno in any order.
+ */
+typedef struct ParallelCopyLineBoundary
+{
+	/* Position of the first block in data_blocks array. */
+	uint32				first_block;
+	uint32				start_offset;   /* start offset of the line */
+
+	/*
+	 * Size of the current line -1 means line is yet to be filled completely,
+	 * 0 means empty line, >0 means line filled with line size data.
+	 */
+	pg_atomic_uint32	line_size;
+	pg_atomic_uint32	line_state;		/* line state */
+	uint64				cur_lineno;		/* line number for error messages */
+}ParallelCopyLineBoundary;
+
+/*
+ * Circular queue used to store the line information.
+ */
+typedef struct ParallelCopyLineBoundaries
+{
+	/* Position for the leader to populate a line. */
+	uint32			leader_pos;
+
+	/* Data read from the file/stdin by the leader process. */
+	ParallelCopyLineBoundary	ring[RINGSIZE];
+}ParallelCopyLineBoundaries;
+
+/*
+ * Shared information among parallel copy workers. This will be allocated in the
+ * DSM segment.
+ */
+typedef struct ParallelCopyShmInfo
+{
+	bool					is_read_in_progress; /* file read status */
+
+	/*
+	 * Actual lines inserted by worker (some records will be filtered based on
+	 * where condition).
+	 */
+	pg_atomic_uint64			processed;
+	pg_atomic_uint64			total_worker_processed; /* total processed records by the workers */
+	uint64						populated; /* lines populated by leader */
+	uint32						cur_block_pos; /* current data block */
+	ParallelCopyDataBlock		data_blocks[MAX_BLOCKS_COUNT]; /* data block array */
+	FullTransactionId			full_transaction_id; /* xid for copy from statement */
+	CommandId					mycid;	/* command id */
+	ParallelCopyLineBoundaries	line_boundaries; /* line array */
+} ParallelCopyShmInfo;
+
+/*
+ * Parallel copy line buffer information.
+ */
+typedef struct ParallelCopyLineBuf
+{
+	StringInfoData		line_buf;
+	uint64				cur_lineno;	/* line number for error messages */
+}ParallelCopyLineBuf;
+
+/*
+ * Parallel copy data information.
+ */
+typedef struct ParallelCopyData
+{
+	Oid					relid;				/* relation id of the table */
+	ParallelCopyShmInfo	*pcshared_info;		/* common info in shared memory */
+	bool				is_leader;
+
+	/* line position which worker is processing */
+	uint32				worker_processed_pos;
+
+	/*
+	 * Local line_buf array, workers will copy it here and release the lines
+	 * for the leader to continue.
+	 */
+	ParallelCopyLineBuf	worker_line_buf[WORKER_CHUNK_COUNT];
+	uint32				worker_line_buf_count; /* Number of lines */
+
+	/* Current position in worker_line_buf */
+	uint32				worker_line_buf_pos;
+}ParallelCopyData;
+
+/*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
  * even though some fields are used in only some cases.
@@ -225,8 +354,66 @@ typedef struct CopyStateData
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
+	int			nworkers;
+	bool		is_parallel;
+	ParallelCopyData *pcdata;
 } CopyStateData;
 
+/*
+ * This structure helps in storing the common data from CopyStateData that are
+ * required by the workers. This information will then be allocated and stored
+ * into the DSM for the worker to retrieve and copy it to CopyStateData.
+ */
+typedef struct ParallelCopyCommonKeyData
+{
+	/* low-level state data */
+	CopyDest            copy_dest;		/* type of copy source/destination */
+	int                 file_encoding;	/* file or remote side's character encoding */
+	bool                need_transcoding;	/* file encoding diff from server? */
+	bool                encoding_embeds_ascii;	/* ASCII can be non-first byte? */
+
+	/* parameters from the COPY command */
+	bool                csv_mode;		/* Comma Separated Value format? */
+	bool                header_line;	/* CSV header line? */
+	int                 null_print_len; /* length of same */
+	bool                force_quote_all;	/* FORCE_QUOTE *? */
+	bool                convert_selectively;	/* do selective binary conversion? */
+
+	/* Working state for COPY FROM */
+	AttrNumber          num_defaults;
+	Oid                 relid;
+}ParallelCopyCommonKeyData;
+
+/*
+ * This structure will help in converting a List data type into the below
+ * structure format with the count having the number of elements in the list and
+ * the info having the List elements appended contigously. This converted
+ * structure will be allocated in shared memory and stored in DSM for the worker
+ * to retrieve and later convert it back to List data type.
+ */
+typedef struct ParallelCopyKeyListInfo
+{
+	int	count;		/* count of attributes */
+
+	/* string info in the form info followed by info1, info2... infon  */
+	char    info[1];
+} ParallelCopyKeyListInfo;
+
+/*
+ * List of internal parallel copy function pointers.
+ */
+static const struct
+{
+	char *fn_name;
+	copy_data_source_cb fn_addr;
+}			InternalParallelCopyFuncPtrs[] =
+
+{
+	{
+		"copy_read_data", copy_read_data
+	},
+};
+
 /* DestReceiver for COPY (query) TO */
 typedef struct
 {
@@ -256,6 +443,23 @@ typedef struct
 /* Trim the list of buffers back down to this number after flushing */
 #define MAX_PARTITION_BUFFERS	32
 
+/* DSM keys for parallel copy.  */
+#define PARALLEL_COPY_KEY_SHARED_INFO		    1
+#define PARALLEL_COPY_KEY_CSTATE				2
+#define PARALLEL_COPY_KEY_NULL_PRINT			3
+#define PARALLEL_COPY_KEY_NULL_PRINT_CLIENT		4
+#define PARALLEL_COPY_KEY_DELIM					5
+#define PARALLEL_COPY_KEY_QUOTE					6
+#define PARALLEL_COPY_KEY_ESCAPE				7
+#define PARALLEL_COPY_KEY_ATTNAME_LIST			8
+#define PARALLEL_COPY_KEY_FORCE_QUOTE_LIST  	9
+#define PARALLEL_COPY_KEY_NOT_NULL_LIST		   10
+#define PARALLEL_COPY_KEY_NULL_LIST			   11
+#define PARALLEL_COPY_KEY_CONVERT_LIST		   12
+#define PARALLEL_COPY_KEY_DATASOURCE_CB		   13
+#define PARALLEL_COPY_KEY_WHERE_CLAUSE_STR     14
+#define PARALLEL_COPY_KEY_RANGE_TABLE		   15
+
 /* Stores multi-insert data related to a single relation in CopyFrom. */
 typedef struct CopyMultiInsertBuffer
 {
@@ -476,10 +680,596 @@ static bool CopyGetInt32(CopyState cstate, int32 *val);
 static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 
+static pg_attribute_always_inline void EndParallelCopy(ParallelContext *pcxt);
 static void PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tup_desc,
 							   List *attnamelist);
+static pg_attribute_always_inline copy_data_source_cb LookupParallelCopyFnPtr(const char *funcname);
+static pg_attribute_always_inline char* LookupParallelCopyFnStr(copy_data_source_cb fn_addr);
 
 /*
+ * CopyCommonInfoForWorker - Copy shared_cstate using cstate information.
+ */
+static pg_attribute_always_inline void
+CopyCommonInfoForWorker(CopyState cstate, ParallelCopyCommonKeyData *shared_cstate)
+{
+	shared_cstate->copy_dest = cstate->copy_dest;
+	shared_cstate->file_encoding = cstate->file_encoding;
+	shared_cstate->need_transcoding = cstate->need_transcoding;
+	shared_cstate->encoding_embeds_ascii = cstate->encoding_embeds_ascii;
+	shared_cstate->csv_mode = cstate->csv_mode;
+	shared_cstate->header_line = cstate->header_line;
+	shared_cstate->null_print_len = cstate->null_print_len;
+	shared_cstate->force_quote_all = cstate->force_quote_all;
+	shared_cstate->convert_selectively = cstate->convert_selectively;
+	shared_cstate->num_defaults = cstate->num_defaults;
+	shared_cstate->relid = cstate->pcdata->relid;
+}
+
+/*
+ * RetrieveSharedString - Retrieve the string from shared memory.
+ */
+static void
+RetrieveSharedString(shm_toc *toc, int sharedkey, char **copystr)
+{
+	char *shared_str_val = (char *)shm_toc_lookup(toc, sharedkey, true);
+	if (shared_str_val)
+		*copystr = pstrdup(shared_str_val);
+}
+
+/*
+ * RetrieveSharedList - Retrieve the list from shared memory.
+ */
+static void
+RetrieveSharedList(shm_toc *toc, int sharedkey, List **copylist)
+{
+	ParallelCopyKeyListInfo *listinformation = (ParallelCopyKeyListInfo *)shm_toc_lookup(toc, sharedkey,
+														   true);
+	if (listinformation)
+	{
+		int	length  = 0;
+		int count;
+
+		for (count = 0; count < listinformation->count; count++)
+		{
+			char *attname = (char *)(listinformation->info + length);
+			length += strlen(attname) + 1;
+			*copylist = lappend(*copylist, makeString(attname));
+		}
+	}
+}
+
+/*
+ * CopyListSharedMemory - Copy the list into shared memory.
+ */
+static void
+CopyListSharedMemory(List *inputlist, Size memsize, ParallelCopyKeyListInfo *sharedlistinfo)
+{
+	ListCell   *l;
+	int			length  = 0;
+
+	MemSet(sharedlistinfo, 0, memsize);
+	foreach(l, inputlist)
+	{
+		char	   *name = strVal(lfirst(l));
+		memcpy((char *)(sharedlistinfo->info + length), name, strlen(name));
+		sharedlistinfo->count++;
+		length += strlen(name) + 1;
+	}
+}
+
+/*
+ * ComputeListSize - compute the list size.
+ */
+static int
+ComputeListSize(List *inputlist)
+{
+	int est_size = sizeof(int);
+	if (inputlist != NIL)
+	{
+		ListCell   *l;
+		foreach(l, inputlist)
+			est_size += strlen(strVal(lfirst(l))) + 1;
+	}
+
+	return est_size;
+}
+
+/*
+ * EstimateLineKeysStr - Estimate the size required in shared memory for the
+ * input string.
+ */
+static void
+EstimateLineKeysStr(ParallelContext *pcxt, char *inputstr)
+{
+	if (inputstr)
+	{
+		shm_toc_estimate_chunk(&pcxt->estimator, strlen(inputstr) + 1);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+}
+
+/*
+ * EstimateLineKeysList - Estimate the size required in shared memory for the
+ * input list.
+ */
+static void
+EstimateLineKeysList(ParallelContext *pcxt, List *inputlist,
+		Size *est_list_size)
+{
+	if (inputlist != NIL)
+	{
+		*est_list_size = ComputeListSize(inputlist);
+		shm_toc_estimate_chunk(&pcxt->estimator, *est_list_size);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+}
+
+/*
+ * InsertStringShm - Insert a string into shared memory.
+ */
+static void
+InsertStringShm(ParallelContext *pcxt, int key, char *inputstr)
+{
+	if (inputstr)
+	{
+		char *shmptr = (char *)shm_toc_allocate(pcxt->toc,
+												strlen(inputstr) + 1);
+		strcpy(shmptr, inputstr);
+		shm_toc_insert(pcxt->toc, key, shmptr);
+	}
+}
+
+/*
+ * InsertListShm - Insert a list into shared memory.
+ */
+static void
+InsertListShm(ParallelContext *pcxt, int key, List *inputlist,
+			  Size est_list_size)
+{
+	if (inputlist != NIL)
+	{
+		ParallelCopyKeyListInfo *sharedlistinfo = (ParallelCopyKeyListInfo *)shm_toc_allocate(pcxt->toc,
+																est_list_size);
+		CopyListSharedMemory(inputlist, est_list_size, sharedlistinfo);
+		shm_toc_insert(pcxt->toc, key, sharedlistinfo);
+	}
+}
+
+/*
+ * BeginParallelCopy - start parallel copy tasks.
+ *
+ * Get the number of workers required to perform the parallel copy. The data
+ * structures that are required by the parallel workers will be initialized, the
+ * size required in DSM will be calculated and the necessary keys will be loaded
+ * in the DSM. The specified number of workers will then be launched.
+ *
+ */
+static ParallelContext*
+BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
+{
+	ParallelContext *pcxt;
+	ParallelCopyShmInfo *shared_info_ptr;
+	ParallelCopyCommonKeyData *shared_cstate;
+	FullTransactionId full_transaction_id;
+	Size est_shared_info;
+	Size est_cstateshared;
+	Size est_att_list_size;
+	Size est_quote_list_size;
+	Size est_notnull_list_size;
+	Size est_null_list_size;
+	Size est_convert_list_size;
+	Size est_datasource_cb_size;
+	int  count = 0;
+	char *whereClauseStr = NULL;
+	char *rangeTableStr = NULL;
+	int  parallel_workers = 0;
+	ParallelCopyData *pcdata;
+
+	parallel_workers = Min(nworkers, max_worker_processes);
+
+	/* Can't perform copy in parallel */
+	if (parallel_workers <= 0)
+	{
+		elog(WARNING,
+			 "No workers available, copy will be run in non-parallel mode");
+		return NULL;
+	}
+
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	cstate->pcdata = pcdata;
+
+	EnterParallelMode();
+	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
+								 parallel_workers);
+	Assert(pcxt->nworkers > 0);
+
+	/*
+	 * Estimate size for shared information for PARALLEL_COPY_KEY_SHARED_INFO
+	 */
+	est_shared_info = sizeof(ParallelCopyShmInfo);
+	shm_toc_estimate_chunk(&pcxt->estimator, est_shared_info);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_CSTATE */
+	est_cstateshared = 	MAXALIGN(sizeof(ParallelCopyCommonKeyData));
+	shm_toc_estimate_chunk(&pcxt->estimator, est_cstateshared);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	EstimateLineKeysStr(pcxt, cstate->null_print);
+	EstimateLineKeysStr(pcxt, cstate->null_print_client);
+	EstimateLineKeysStr(pcxt, cstate->delim);
+	EstimateLineKeysStr(pcxt, cstate->quote);
+	EstimateLineKeysStr(pcxt, cstate->escape);
+
+	if (cstate->whereClause != NULL)
+	{
+		whereClauseStr = nodeToString(cstate->whereClause);
+		EstimateLineKeysStr(pcxt, whereClauseStr);
+	}
+
+	if (cstate->range_table != NULL)
+	{
+		rangeTableStr = nodeToString(cstate->range_table);
+		EstimateLineKeysStr(pcxt, rangeTableStr);
+	}
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_XID. */
+	shm_toc_estimate_chunk(&pcxt->estimator, sizeof(FullTransactionId));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_ATTNAME_LIST.
+	 */
+	EstimateLineKeysList(pcxt, attnamelist, &est_att_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_FORCE_QUOTE_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->force_quote, &est_quote_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_NOT_NULL_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->force_notnull,
+							 &est_notnull_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_NULL_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->force_null, &est_null_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_CONVERT_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->convert_select,
+							 &est_convert_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_DATASOURCE_CB.
+	 */
+	if (cstate->data_source_cb)
+	{
+		char *functionname = LookupParallelCopyFnStr(cstate->data_source_cb);
+		est_datasource_cb_size = strlen(functionname) + 1;
+		shm_toc_estimate_chunk(&pcxt->estimator, est_datasource_cb_size);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+
+	InitializeParallelDSM(pcxt);
+
+	/* If no DSM segment was available, back out (do serial copy) */
+	if (pcxt->seg == NULL)
+	{
+		EndParallelCopy(pcxt);
+		elog(WARNING,
+			 "DSM segments not available, copy will be run in non-parallel mode");
+		return NULL;
+	}
+
+	/* Allocate shared memory for PARALLEL_COPY_KEY_SHARED_INFO */
+	shared_info_ptr = (ParallelCopyShmInfo *) shm_toc_allocate(pcxt->toc,
+													   est_shared_info);
+	MemSet(shared_info_ptr, 0, est_shared_info);
+	shared_info_ptr->is_read_in_progress = true;
+	shared_info_ptr->cur_block_pos = -1;
+	shared_info_ptr->full_transaction_id = full_transaction_id;
+	shared_info_ptr->mycid = GetCurrentCommandId(true);
+	for (count = 0; count < RINGSIZE; count++)
+	{
+		ParallelCopyLineBoundary *lineInfo = &shared_info_ptr->line_boundaries.ring[count];
+		pg_atomic_init_u32(&(lineInfo->line_size), -1);
+	}
+
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_SHARED_INFO, shared_info_ptr);
+	pcdata->pcshared_info = shared_info_ptr;
+	pcdata->relid = relid;
+
+	/* Store shared build state, for which we reserved space. */
+	shared_cstate = (ParallelCopyCommonKeyData *)shm_toc_allocate(pcxt->toc,
+															est_cstateshared);
+
+	/* copy cstate variables. */
+	CopyCommonInfoForWorker(cstate, shared_cstate);
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_CSTATE, shared_cstate);
+
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_NULL_PRINT, cstate->null_print);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_NULL_PRINT_CLIENT,
+					  cstate->null_print_client);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_DELIM, cstate->delim);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_QUOTE, cstate->quote);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_ESCAPE, cstate->escape);
+
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_ATTNAME_LIST,
+					attnamelist, est_att_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_FORCE_QUOTE_LIST,
+					cstate->force_quote, est_quote_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_NOT_NULL_LIST,
+					cstate->force_notnull, est_notnull_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_NULL_LIST, cstate->force_null,
+					est_null_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_CONVERT_LIST,
+					cstate->convert_select, est_convert_list_size);
+
+	if (cstate->data_source_cb)
+	{
+		char *functionname = LookupParallelCopyFnStr(cstate->data_source_cb);
+		char *data_source_cb = (char *) shm_toc_allocate(pcxt->toc,
+														 est_datasource_cb_size);
+		strcpy(data_source_cb, functionname);
+		shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_DATASOURCE_CB,
+					   data_source_cb);
+	}
+
+	if (cstate->whereClause)
+		InsertStringShm(pcxt, PARALLEL_COPY_KEY_WHERE_CLAUSE_STR,
+						whereClauseStr);
+
+	if(cstate->range_table)
+		InsertStringShm(pcxt, PARALLEL_COPY_KEY_RANGE_TABLE, rangeTableStr);
+
+	LaunchParallelWorkers(pcxt);
+	if (pcxt->nworkers_launched == 0)
+	{
+		EndParallelCopy(pcxt);
+		elog(WARNING,
+			 "No workers available, copy will be run in non-parallel mode");
+		return NULL;
+	}
+
+	/*
+	 * Caller needs to wait for all launched workers when we return.  Make sure
+	 * that the failure-to-start case will not hang forever.
+	 */
+	WaitForParallelWorkersToAttach(pcxt);
+
+	pcdata->is_leader = true;
+	cstate->is_parallel = true;
+	return pcxt;
+}
+
+/*
+ * EndParallelCopy - end the parallel copy tasks.
+ */
+static pg_attribute_always_inline void
+EndParallelCopy(ParallelContext *pcxt)
+{
+	Assert(!IsParallelWorker());
+
+	DestroyParallelContext(pcxt);
+	ExitParallelMode();
+}
+
+/*
+ * ParallelWorkerInitialization - Initialize parallel worker.
+ */
+static void
+ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
+		CopyState cstate, List *attnamelist)
+{
+	uint32		count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	cstate->copy_dest = shared_cstate->copy_dest;
+	cstate->file_encoding = shared_cstate->file_encoding;
+	cstate->need_transcoding = shared_cstate->need_transcoding;
+	cstate->encoding_embeds_ascii = shared_cstate->encoding_embeds_ascii;
+	cstate->csv_mode = shared_cstate->csv_mode;
+	cstate->header_line = shared_cstate->header_line;
+	cstate->null_print_len = shared_cstate->null_print_len;
+	cstate->force_quote_all = shared_cstate->force_quote_all;
+	cstate->convert_selectively = shared_cstate->convert_selectively;
+	cstate->num_defaults = shared_cstate->num_defaults;
+	pcdata->relid = shared_cstate->relid;
+
+	PopulateGlobalsForCopyFrom(cstate, tup_desc, attnamelist);
+
+	/* Initialize state variables. */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/* Set up variables to avoid per-attribute overhead. */
+	initStringInfo(&cstate->attribute_buf);
+
+	initStringInfo(&cstate->line_buf);
+	for (count = 0; count < WORKER_CHUNK_COUNT;count++)
+		initStringInfo(&pcdata->worker_line_buf[count].line_buf);
+
+	cstate->line_buf_converted = false;
+	cstate->raw_buf = NULL;
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+}
+/*
+ * ParallelCopyMain - parallel copy worker's code.
+ *
+ * Where clause handling, convert tuple to columns, add default null values for
+ * the missing columns that are not present in that record. Find the partition
+ * if it is partitioned table, invoke before row insert Triggers, handle
+ * constraints and insert the tuples.
+ */
+void
+ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
+{
+	CopyState cstate;
+	ParallelCopyData *pcdata;
+	ParallelCopyShmInfo *pcshared_info;
+	ParallelCopyCommonKeyData *shared_cstate;
+	Relation	rel = NULL;
+	MemoryContext oldcontext;
+	List *attlist = NIL;
+	char *data_source_cb;
+	char *whereClauseStr = NULL;
+	char *rangeTableStr = NULL;
+
+	/* Allocate workspace and zero all fields. */
+	cstate = (CopyStateData *) palloc0(sizeof(CopyStateData));
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	cstate->pcdata = pcdata;
+	pcdata->is_leader = false;
+	pcdata->worker_processed_pos = -1;
+	cstate->is_parallel = true;
+
+	/*
+	 * We allocate everything used by a cstate in a new memory context. This
+	 * avoids memory leaks during repeated use of COPY in a query.
+	 */
+	cstate->copycontext = AllocSetContextCreate(CurrentMemoryContext,
+												"COPY",
+												ALLOCSET_DEFAULT_SIZES);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	pcshared_info = (ParallelCopyShmInfo *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_SHARED_INFO,
+														false);
+
+	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
+
+	pcdata->pcshared_info = pcshared_info;
+
+	shared_cstate = (ParallelCopyCommonKeyData *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE,
+														   false);
+
+	cstate->null_print = (char *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_NULL_PRINT,
+												true);
+	cstate->null_print_client = (char *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_NULL_PRINT_CLIENT,
+													   true);
+
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_DELIM, &cstate->delim);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_QUOTE, &cstate->quote);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_ESCAPE, &cstate->escape);
+
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_ATTNAME_LIST, &attlist);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_FORCE_QUOTE_LIST, &cstate->force_quote);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_NOT_NULL_LIST, &cstate->force_notnull);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_NULL_LIST, &cstate->force_null);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_CONVERT_LIST, &cstate->convert_select);
+	data_source_cb = (char *)shm_toc_lookup(toc,
+											PARALLEL_COPY_KEY_DATASOURCE_CB,
+											true);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_WHERE_CLAUSE_STR, &whereClauseStr);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_RANGE_TABLE, &rangeTableStr);
+
+	if (data_source_cb)
+		cstate->data_source_cb = LookupParallelCopyFnPtr(data_source_cb);
+
+	if (whereClauseStr)
+	{
+		Node *whereClauseCnvrtdFrmStr = (Node *) stringToNode(whereClauseStr);
+		cstate->whereClause = whereClauseCnvrtdFrmStr;
+	}
+
+	if (rangeTableStr)
+	{
+		List *rangeTableCnvrtdFrmStr = (List *) stringToNode(rangeTableStr);
+		cstate->range_table = rangeTableCnvrtdFrmStr;
+	}
+
+	/* Open and lock the relation, using the appropriate lock type. */
+	rel = table_open(shared_cstate->relid, RowExclusiveLock);
+	cstate->rel = rel;
+	ParallelWorkerInitialization(shared_cstate, cstate, attlist);
+
+	CopyFrom(cstate);
+
+	if (rel != NULL)
+		table_close(rel, RowExclusiveLock);
+
+	MemoryContextSwitchTo(oldcontext);
+	return;
+}
+/*
+ * ParallelCopyLeader - parallel copy leader's functionality.
+ *
+ * Leader will populate the shared memory and share it across the workers.
+ * Leader will read the table data from the file and copy the contents to block.
+ * Leader will then read the input contents and identify the data based on line
+ * beaks. This information is called line. The line will be populate in
+ * ParallelCopyLineBoundary. Workers will then pick up this information and
+ * insert in to table. Leader will do this till it completes processing the
+ * file. Leader executes the before statement if before statement trigger is
+ * present. Leader read the data from input file. Leader then loads data to data
+ * blocks as and when required block by block. Leader traverses through the data
+ * block to identify one line. It gets a free line to copy the information, if
+ * there is no free line it will wait till there is one free line.
+ * Server copies  the identified lines information into lines. This process is
+ * repeated till the complete file is processed.
+ * Leader will wait till all the lines populated are processed by the workers
+ * and exits.
+ */
+static void
+ParallelCopyLeader(CopyState cstate)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
+
+	pcshared_info->is_read_in_progress = false;
+	cstate->cur_lineno = 0;
+}
+/*
+ * LookupParallelCopyFnPtr - Look up parallel copy function pointer.
+ */
+static pg_attribute_always_inline copy_data_source_cb
+LookupParallelCopyFnPtr(const char *funcname)
+{
+	int			i;
+
+	for (i = 0; i < lengthof(InternalParallelCopyFuncPtrs); i++)
+	{
+		if (strcmp(InternalParallelCopyFuncPtrs[i].fn_name, funcname) == 0)
+			return InternalParallelCopyFuncPtrs[i].fn_addr;
+	}
+
+	/* We can only reach this by programming error. */
+	elog(ERROR, "internal function \"%s\" not found", funcname);
+}
+
+/*
+ * LookupParallelCopyFnStr - Lookup function string from a function pointer.
+ */
+static pg_attribute_always_inline char*
+LookupParallelCopyFnStr(copy_data_source_cb fn_addr)
+{
+	int			i;
+
+	for (i = 0; i < lengthof(InternalParallelCopyFuncPtrs); i++)
+	{
+		if (InternalParallelCopyFuncPtrs[i].fn_addr == fn_addr)
+			return InternalParallelCopyFuncPtrs[i].fn_name;
+	}
+
+	/* We can only reach this by programming error. */
+	elog(ERROR, "internal function pointer not found");
+}
+/*
  * Send copy start/stop messages for frontend copies.  These have changed
  * in past protocol redesigns.
  */
@@ -1149,6 +1939,7 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 
 	if (is_from)
 	{
+		ParallelContext *pcxt = NULL;
 		Assert(rel);
 
 		/* check read-only transaction and parallel mode */
@@ -1158,7 +1949,24 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 		cstate = BeginCopyFrom(pstate, rel, stmt->filename, stmt->is_program,
 							   NULL, stmt->attlist, stmt->options);
 		cstate->whereClause = whereClause;
-		*processed = CopyFrom(cstate);	/* copy from file to database */
+		cstate->is_parallel = false;
+
+		if (cstate->nworkers > 0)
+			pcxt = BeginParallelCopy(cstate->nworkers, cstate, stmt->attlist,
+									 relid);
+
+		if (pcxt)
+		{
+			ParallelCopyLeader(cstate);
+
+			/* Wait for all copy workers to finish */
+			WaitForParallelWorkersToFinish(pcxt);
+			*processed = pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
+			EndParallelCopy(pcxt);
+		}
+		else
+			*processed = CopyFrom(cstate); /* copy from file to database */
+
 		EndCopyFrom(cstate);
 	}
 	else
@@ -1207,6 +2015,7 @@ ProcessCopyOptions(ParseState *pstate,
 	cstate->is_copy_from = is_from;
 
 	cstate->file_encoding = -1;
+	cstate->nworkers = -1;
 
 	/* Extract options from the statement node tree */
 	foreach(option, options)
@@ -1375,6 +2184,26 @@ ProcessCopyOptions(ParseState *pstate,
 								defel->defname),
 						 parser_errposition(pstate, defel->location)));
 		}
+		else if (strcmp(defel->defname, "parallel") == 0)
+		{
+			if (!cstate->is_copy_from)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("parallel option supported only for copy from"),
+						 parser_errposition(pstate, defel->location)));
+			if (cstate->nworkers >= 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options"),
+						 parser_errposition(pstate, defel->location)));
+			cstate->nworkers = atoi(defGetString(defel));
+			if (cstate->nworkers <= 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("argument to option \"%s\" must be a positive integer greater than zero",
+								defel->defname),
+						 parser_errposition(pstate, defel->location)));
+		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_SYNTAX_ERROR),
@@ -1727,12 +2556,13 @@ BeginCopy(ParseState *pstate,
 }
 
 /*
- * PopulateGlobalsForCopyFrom - Populates the common variables required for copy
- * from operation. This is a helper function for BeginCopy function.
+ * PopulateCatalogInformation - Populates the common variables required for copy
+ * from operation. This is a helper function for BeginCopy &
+ * ParallelWorkerInitialization function.
  */
 static void
 PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tupDesc,
-							List *attnamelist)
+						   List *attnamelist)
 {
 	int			num_phys_attrs;
 
diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c
index c27d970..b3787c1 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -557,7 +557,7 @@ make_copy_attnamelist(LogicalRepRelMapEntry *rel)
  * Data source callback for the COPY FROM, which reads from the remote
  * connection and passes the data back to our local COPY.
  */
-static int
+int
 copy_read_data(void *outbuf, int minread, int maxread)
 {
 	int			bytesread = 0;
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index c639833..5dc95ac 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -14,6 +14,7 @@
 #ifndef COPY_H
 #define COPY_H
 
+#include "access/parallel.h"
 #include "nodes/execnodes.h"
 #include "nodes/parsenodes.h"
 #include "parser/parse_node.h"
@@ -41,4 +42,7 @@ extern uint64 CopyFrom(CopyState cstate);
 
 extern DestReceiver *CreateCopyDestReceiver(void);
 
+extern void ParallelCopyMain(dsm_segment *seg, shm_toc *toc);
+
+extern int copy_read_data(void *outbuf, int minread, int maxread);
 #endif							/* COPY_H */
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index c65a552..8a79794 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1698,6 +1698,14 @@ ParallelBitmapHeapState
 ParallelBlockTableScanDesc
 ParallelCompletionPtr
 ParallelContext
+ParallelCopyLineBoundaries
+ParallelCopyLineBoundary
+ParallelCopyCommonKeyData
+ParallelCopyData
+ParallelCopyDataBlock
+ParallelCopyKeyListInfo
+ParallelCopyLineBuf
+ParallelCopyShmInfo
 ParallelExecutorInfo
 ParallelHashGrowth
 ParallelHashJoinBatch
-- 
1.8.3.1

0003-Allow-copy-from-command-to-process-data-from-file-ST.patchapplication/octet-stream; name=0003-Allow-copy-from-command-to-process-data-from-file-ST.patchDownload
From efc6dcb1ad7285c4e7486cd152c5908a48a7544d Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>, Bharath <bharath.rupireddyforpostgres@gmail.com>
Date: Tue, 23 Jun 2020 07:15:43 +0530
Subject: [PATCH 3/6] Allow copy from command to process data from file/STDIN
 contents to a table in parallel.

This feature allows the copy from to leverage multiple CPUs in order to copy
data from file/STDIN to a table. This adds a PARALLEL option to COPY FROM
command where the user can specify the number of workers that can be used
to perform the COPY FROM command. Specifying zero as number of workers will
disable parallelism.
The backend, to which the "COPY FROM" query is submitted acts as leader with
the responsibility of reading data from the file/stdin, launching at most n
number of workers as specified with PARALLEL 'n' option in the "COPY FROM"
query. The leader populates the common data required for the workers execution
in the DSM and shares it with the workers. The leader then executes before
statement triggers if there exists any. Leader populates DSM lines which
includes the start offset and line size, while populating the lines it reads
as many blocks as required into the DSM data blocks from the file. Each block
is of 64K size. The leader parses the data to identify a line, the existing
logic from CopyReadLineText which identifies the lines with some changes was
used for this. Leader checks if a free line is available to copy the
information, if there is no free line it waits till the required line is
freed up by the worker and then copies the identified lines information
(offset & line size) into the DSM lines. This process is repeated till the
complete file is processed. Simultaneously, the workers cache the lines(50)
locally into the local memory and release the lines to the leader for further
populating. Each worker processes the lines that it cached and inserts it into
the table. The leader does not participate in the insertion of data, leaders
only responsibility will be to identify the lines as fast as possible for the
workers to do the actual copy operation. The leader waits till all the lines
populated are processed by the workers and exits.
---
 src/backend/access/heap/heapam.c  |  13 -
 src/backend/access/transam/xact.c |  13 +
 src/backend/commands/copy.c       | 896 ++++++++++++++++++++++++++++++++++++--
 src/include/access/xact.h         |   1 +
 src/tools/pgindent/typedefs.list  |   1 +
 5 files changed, 873 insertions(+), 51 deletions(-)

diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 537913d..28f3a98 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2012,19 +2012,6 @@ static HeapTuple
 heap_prepare_insert(Relation relation, HeapTuple tup, TransactionId xid,
 					CommandId cid, int options)
 {
-	/*
-	 * Parallel operations are required to be strictly read-only in a parallel
-	 * worker.  Parallel inserts are not safe even in the leader in the
-	 * general case, because group locking means that heavyweight locks for
-	 * relation extension or GIN page locks will not conflict between members
-	 * of a lock group, but we don't prohibit that case here because there are
-	 * useful special cases that we can safely allow, such as CREATE TABLE AS.
-	 */
-	if (IsParallelWorker())
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_TRANSACTION_STATE),
-				 errmsg("cannot insert tuples in a parallel worker")));
-
 	tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
 	tup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK);
 	tup->t_data->t_infomask |= HEAP_XMAX_INVALID;
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 905dc7d..66f7236 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -502,6 +502,19 @@ GetCurrentFullTransactionIdIfAny(void)
 }
 
 /*
+ *	AssignFullTransactionIdForWorker
+ *
+ * For parallel copy, all the workers must use the same transaction id.
+ */
+void AssignFullTransactionIdForWorker(FullTransactionId fullTransactionId)
+{
+	TransactionState s = CurrentTransactionState;
+
+	Assert((IsInParallelMode() || IsParallelWorker()));
+	s->fullTransactionId = fullTransactionId;
+}
+
+/*
  *	MarkCurrentTransactionIdLoggedIfAny
  *
  * Remember that the current xid - if it is assigned - now has been wal logged.
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 34c657c..e8a89a4 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -26,6 +26,7 @@
 #include "access/xlog.h"
 #include "catalog/dependency.h"
 #include "catalog/pg_authid.h"
+#include "catalog/pg_proc_d.h"
 #include "catalog/pg_type.h"
 #include "commands/copy.h"
 #include "commands/defrem.h"
@@ -40,11 +41,13 @@
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
+#include "optimizer/clauses.h"
 #include "optimizer/optimizer.h"
 #include "parser/parse_coerce.h"
 #include "parser/parse_collate.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_relation.h"
+#include "pgstat.h"
 #include "port/pg_bswap.h"
 #include "rewrite/rewriteHandler.h"
 #include "storage/fd.h"
@@ -95,6 +98,18 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
+/*
+ * State of the line.
+ */
+typedef enum ParallelCopyLineState
+{
+	LINE_INIT,					/* initial state of line */
+	LINE_LEADER_POPULATING,		/* leader processing line */
+	LINE_LEADER_POPULATED,		/* leader completed populating line */
+	LINE_WORKER_PROCESSING,		/* worker processing line */
+	LINE_WORKER_PROCESSED		/* worker completed processing line */
+}ParallelCopyLineState;
+
 #define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
 
 #define DATA_BLOCK_SIZE RAW_BUF_SIZE
@@ -538,9 +553,13 @@ if (1) \
 { \
 	if (raw_buf_ptr > cstate->raw_buf_index) \
 	{ \
-		appendBinaryStringInfo(&cstate->line_buf, \
-							 cstate->raw_buf + cstate->raw_buf_index, \
-							   raw_buf_ptr - cstate->raw_buf_index); \
+		if (!IsParallelCopy()) \
+			appendBinaryStringInfo(&cstate->line_buf, \
+								   cstate->raw_buf + cstate->raw_buf_index, \
+								   raw_buf_ptr - cstate->raw_buf_index); \
+		else \
+			line_size +=  raw_buf_ptr - cstate->raw_buf_index; \
+		\
 		cstate->raw_buf_index = raw_buf_ptr; \
 	} \
 } else ((void) 0)
@@ -553,13 +572,40 @@ if (1) \
 	goto not_end_of_copy; \
 } else ((void) 0)
 
+/* Begin parallel copy Macros */
+#define SET_NEWLINE_SIZE() \
+{ \
+	if (cstate->eol_type == EOL_NL || cstate->eol_type == EOL_CR) \
+		new_line_size = 1; \
+	else if (cstate->eol_type == EOL_CRNL) \
+		new_line_size = 2; \
+	else \
+		new_line_size = 0; \
+}
+
+/*
+ * COPY_WAIT_TO_PROCESS - Wait before continuing to process.
+ */
+#define COPY_WAIT_TO_PROCESS() \
+{ \
+	CHECK_FOR_INTERRUPTS(); \
+	(void) WaitLatch(MyLatch, \
+					 WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH, \
+					 1L, WAIT_EVENT_PG_SLEEP); \
+	ResetLatch(MyLatch); \
+}
+
+/* End parallel copy Macros */
+
 /*
  * CONVERT_TO_SERVER_ENCODING - convert contents to server encoding.
  */
 #define CONVERT_TO_SERVER_ENCODING(cstate) \
 { \
 	/* Done reading the line.  Convert it to server encoding. */ \
-	if (cstate->need_transcoding) \
+	if (cstate->need_transcoding && \
+		(!IsParallelCopy() || \
+		 (IsParallelCopy() && !IsLeader()))) \
 	{ \
 		char	   *cvt; \
 		cvt = pg_any_to_server(cstate->line_buf.data, \
@@ -618,22 +664,38 @@ if (1) \
  * CLEAR_EOL_LINE - Wrapper for clearing EOL.
  */
 #define CLEAR_EOL_LINE() \
-if (!result && !IsHeaderLine()) \
-	CLEAR_EOL_FROM_COPIED_DATA(cstate->line_buf.data, \
-								cstate->line_buf.len, \
-								cstate->line_buf.len) \
+{ \
+	if (!result && !IsHeaderLine()) \
+	{ \
+		if (IsParallelCopy()) \
+			CLEAR_EOL_FROM_COPIED_DATA(cstate->raw_buf, \
+									   raw_buf_ptr, line_size) \
+		else \
+			CLEAR_EOL_FROM_COPIED_DATA(cstate->line_buf.data, \
+									   cstate->line_buf.len, \
+									   cstate->line_buf.len) \
+	} \
+}
 
 /*
  * INCREMENTPROCESSED - Increment the lines processed.
  */
-#define INCREMENTPROCESSED(processed)  \
-processed++;
+#define INCREMENTPROCESSED(processed) \
+{ \
+	if (!IsParallelCopy()) \
+		processed++; \
+	else \
+		pg_atomic_add_fetch_u64(&cstate->pcdata->pcshared_info->processed, 1); \
+}
 
 /*
  * GETPROCESSED - Get the lines processed.
  */
 #define GETPROCESSED(processed) \
-return processed;
+if (!IsParallelCopy()) \
+	return processed; \
+else \
+	return pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
 
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
@@ -681,8 +743,12 @@ static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 
 static pg_attribute_always_inline void EndParallelCopy(ParallelContext *pcxt);
+static void ExecBeforeStmtTrigger(CopyState cstate);
+static void CheckTargetRelValidity(CopyState cstate);
 static void PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tup_desc,
 							   List *attnamelist);
+static void PopulateCatalogInformation(CopyState cstate);
+static pg_attribute_always_inline uint32 GetLinePosition(CopyState cstate);
 static pg_attribute_always_inline copy_data_source_cb LookupParallelCopyFnPtr(const char *funcname);
 static pg_attribute_always_inline char* LookupParallelCopyFnStr(copy_data_source_cb fn_addr);
 
@@ -836,6 +902,137 @@ InsertListShm(ParallelContext *pcxt, int key, List *inputlist,
 }
 
 /*
+ * IsTriggerFunctionParallelSafe - Check if the trigger function is parallel
+ * safe for the triggers. Return false if any one of the trigger has parallel
+ * unsafe function.
+ */
+static pg_attribute_always_inline bool
+IsTriggerFunctionParallelSafe(TriggerDesc *trigdesc)
+{
+	int	i;
+	for (i = 0; i < trigdesc->numtriggers; i++)
+	{
+		Trigger    *trigger = &trigdesc->triggers[i];
+		int 		trigtype = RI_TRIGGER_NONE;
+
+		if (func_parallel(trigger->tgfoid) != PROPARALLEL_SAFE)
+			return false;
+
+		/* If the trigger is parallel safe, also look for RI_TRIGGER. */
+		trigtype = RI_FKey_trigger_type(trigger->tgfoid);
+		if (trigtype == RI_TRIGGER_PK || trigtype == RI_TRIGGER_FK)
+			return false;
+	}
+
+	return true;
+}
+
+/*
+ * CheckExprParallelSafety - determine parallel safety of volatile expressions
+ * in default clause of column definition or in where clause and return true if
+ * they are parallel safe.
+ */
+static pg_attribute_always_inline bool
+CheckExprParallelSafety(CopyState cstate)
+{
+	if (contain_volatile_functions(cstate->whereClause))
+	{
+		if (max_parallel_hazard((Query *)cstate->whereClause) != PROPARALLEL_SAFE)
+			return false;
+	}
+
+	/*
+	 * Check if any of the column has volatile default expression. if yes, and
+	 * they are not parallel safe, then parallelism is not allowed. For
+	 * instance, if there are any serial/bigserial columns for which nextval()
+	 * default expression which is parallel unsafe is associated, parallelism
+	 * should not be allowed. In non paralllel copy volatile functions are not
+	 * checked for nextval().
+	 */
+	if (cstate->defexprs != NULL && cstate->num_defaults != 0)
+	{
+		int     i;
+		for (i = 0; i < cstate->num_defaults; i++)
+		{
+			bool volatile_expr = contain_volatile_functions((Node *)cstate->defexprs[i]->expr);
+			if (volatile_expr &&
+				(max_parallel_hazard((Query *)cstate->defexprs[i]->expr)) !=
+				 PROPARALLEL_SAFE)
+				return false;
+		}
+	}
+
+	return true;
+}
+
+/*
+ * FindInsertMethod - determine insert mode single, multi, or multi conditional.
+ */
+static pg_attribute_always_inline CopyInsertMethod
+FindInsertMethod(CopyState cstate)
+{
+	if (cstate->rel->trigdesc != NULL &&
+		(cstate->rel->trigdesc->trig_insert_before_row ||
+		 cstate->rel->trigdesc->trig_insert_instead_row))
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
+			cstate->rel->trigdesc != NULL &&
+			cstate->rel->trigdesc->trig_insert_new_table)
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+		return CIM_MULTI_CONDITIONAL;
+
+	return CIM_MULTI;
+}
+
+/*
+ * IsParallelCopyAllowed - check for the cases where parallel copy is not
+ * applicable.
+ */
+static pg_attribute_always_inline bool
+IsParallelCopyAllowed(CopyState cstate)
+{
+	/* Parallel copy not allowed for frontend (2.0 protocol) & binary option. */
+	if ((cstate->copy_dest == COPY_OLD_FE) || cstate->binary)
+		return false;
+
+	/* Check if copy is into foreign table or temporary table. */
+	if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
+		RelationUsesLocalBuffers(cstate->rel))
+		return false;
+
+	/* Check if trigger function is parallel safe. */
+	if (cstate->rel->trigdesc != NULL &&
+		!IsTriggerFunctionParallelSafe(cstate->rel->trigdesc))
+		return false;
+
+	/*
+	 * Check if there is after statement or instead of trigger or transition
+	 * table triggers.
+	 */
+	if (cstate->rel->trigdesc != NULL &&
+		(cstate->rel->trigdesc->trig_insert_after_statement ||
+		 cstate->rel->trigdesc->trig_insert_instead_row ||
+		 cstate->rel->trigdesc->trig_insert_new_table))
+		return false;
+
+	/* Check if the volatile expressions are parallel safe, if present any. */
+	if (!CheckExprParallelSafety(cstate))
+		return false;
+
+	/* Check if the insertion mode is single. */
+	if (FindInsertMethod(cstate) == CIM_SINGLE)
+		return false;
+
+	return true;
+}
+
+/*
  * BeginParallelCopy - start parallel copy tasks.
  *
  * Get the number of workers required to perform the parallel copy. The data
@@ -865,6 +1062,8 @@ BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
 	int  parallel_workers = 0;
 	ParallelCopyData *pcdata;
 
+	CheckTargetRelValidity(cstate);
+
 	parallel_workers = Min(nworkers, max_worker_processes);
 
 	/* Can't perform copy in parallel */
@@ -878,6 +1077,19 @@ BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
 	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
 	cstate->pcdata = pcdata;
 
+	/*
+	 * User chosen parallel copy. Determine if the parallel copy is actually
+	 * allowed. If not, go with the non-parallel mode.
+	 */
+	if (!IsParallelCopyAllowed(cstate))
+	{
+		elog(WARNING,
+			 "Parallel copy not supported for specified table, copy will be run in non-parallel mode");
+		return NULL;
+	}
+
+	full_transaction_id = GetCurrentFullTransactionId();
+
 	EnterParallelMode();
 	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
 								 parallel_workers);
@@ -1108,7 +1320,211 @@ ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
 	cstate->line_buf_converted = false;
 	cstate->raw_buf = NULL;
 	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+
+	PopulateCatalogInformation(cstate);
+
+	/* Create workspace for CopyReadAttributes results. */
+	if (!cstate->binary)
+	{
+		AttrNumber	attr_count = list_length(cstate->attnumlist);
+
+		cstate->max_fields = attr_count;
+		cstate->raw_fields = (char **)palloc(attr_count * sizeof(char *));
+	}
+}
+
+/*
+ * CacheLineInfo - Cache the line information to local memory.
+ */
+static bool
+CacheLineInfo(CopyState cstate, uint32 buff_count)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	uint32			write_pos;
+	ParallelCopyDataBlock *data_blk_ptr;
+	ParallelCopyLineBoundary *lineInfo;
+	uint32 offset;
+	int dataSize;
+	int copiedSize = 0;
+
+	resetStringInfo(&pcdata->worker_line_buf[buff_count].line_buf);
+	write_pos = GetLinePosition(cstate);
+	if (-1 == write_pos)
+		return true;
+
+	/* Get the current line information. */
+	lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+	if (pg_atomic_read_u32(&lineInfo->line_size) == 0)
+		goto empty_data_line_update;
+
+	/* Get the block information. */
+	data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+	/* Get the offset information from where the data must be copied. */
+	offset = lineInfo->start_offset;
+	pcdata->worker_line_buf[buff_count].cur_lineno = lineInfo->cur_lineno;
+
+	elog(DEBUG1, "[Worker] Processing - line position:%d, block:%d, unprocessed lines:%d, offset:%d, line size:%d",
+				 write_pos, lineInfo->first_block,
+				 pg_atomic_read_u32(&data_blk_ptr->unprocessed_line_parts),
+				 offset, pg_atomic_read_u32(&lineInfo->line_size));
+
+	for (;;)
+	{
+		uint8 skip_bytes = data_blk_ptr->skip_bytes;
+		/*
+		 * There is a possibility that the above loop has come out because
+		 * data_blk_ptr->curr_blk_completed is set, but dataSize read might
+		 * be an old value, if data_blk_ptr->curr_blk_completed and the line is
+		 * completed, line_size will be set. Read the line_size again to be
+		 * sure if it is complete or partial block.
+		 */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+		if (dataSize)
+		{
+			int remainingSize = dataSize - copiedSize;
+			if (!remainingSize)
+				break;
+
+			/* Whole line is in current block. */
+			if (remainingSize + offset + skip_bytes < DATA_BLOCK_SIZE)
+			{
+				appendBinaryStringInfo(&pcdata->worker_line_buf[buff_count].line_buf,
+									   &data_blk_ptr->data[offset],
+									   remainingSize);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts,
+										1);
+				break;
+			}
+			else
+			{
+				/* Line is spread across the blocks. */
+				uint32 lineInCurrentBlock =  (DATA_BLOCK_SIZE - skip_bytes) - offset;
+				appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+										 &data_blk_ptr->data[offset],
+										 lineInCurrentBlock);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+				copiedSize += lineInCurrentBlock;
+				while (copiedSize < dataSize)
+				{
+					uint32 currentBlockCopySize;
+					ParallelCopyDataBlock *currBlkPtr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+					skip_bytes = currBlkPtr->skip_bytes;
+
+					/*
+					 * If complete data is present in current block use
+					 * dataSize - copiedSize, or copy the whole block from
+					 * current block.
+					 */
+					currentBlockCopySize = Min(dataSize - copiedSize, DATA_BLOCK_SIZE - skip_bytes);
+					appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+											 &currBlkPtr->data[0],
+											 currentBlockCopySize);
+					pg_atomic_sub_fetch_u32(&currBlkPtr->unprocessed_line_parts, 1);
+					copiedSize += currentBlockCopySize;
+					data_blk_ptr = currBlkPtr;
+				}
+
+				break;
+			}
+		}
+		else
+		{
+			/* Copy this complete block from the current offset. */
+			uint32 lineInCurrentBlock =  (DATA_BLOCK_SIZE - skip_bytes) - offset;
+			appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+									 &data_blk_ptr->data[offset],
+									 lineInCurrentBlock);
+			pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+			copiedSize += lineInCurrentBlock;
+
+			/*
+			 * Reset the offset. For the first copy, copy from the offset. For
+			 * the subsequent copy the complete block.
+			 */
+			offset = 0;
+
+			/* Set data_blk_ptr to the following block. */
+			data_blk_ptr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+		}
+
+		for (;;)
+		{
+			/* Get the size of this line */
+			dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+			/*
+			 * If the data is present in current block lineInfo.line_size
+			 * will be updated. If the data is spread across the blocks either
+			 * of lineInfo.line_size or data_blk_ptr->curr_blk_completed can
+			 * be updated. lineInfo.line_size will be updated if the complete
+			 * read is finished. data_blk_ptr->curr_blk_completed will be
+			 * updated if processing of current block is finished and data
+			 * processing is not finished.
+			 */
+			if (data_blk_ptr->curr_blk_completed || (dataSize != -1))
+				break;
+
+			COPY_WAIT_TO_PROCESS()
+		}
+	}
+
+empty_data_line_update:
+	elog(DEBUG1, "[Worker] Completed processing line:%d", write_pos);
+	pg_atomic_write_u32(&lineInfo->line_state, LINE_WORKER_PROCESSED);
+	pg_atomic_write_u32(&lineInfo->line_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+	return false;
+}
+
+/*
+ * GetWorkerLine - Returns a line for worker to process.
+ */
+static bool
+GetWorkerLine(CopyState cstate)
+{
+	uint32 buff_count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+
+	/*
+	 * Copy the line data to line_buf and release the line position so that the
+	 * worker can continue loading data.
+	 */
+	if (pcdata->worker_line_buf_pos < pcdata->worker_line_buf_count)
+		goto return_line;
+
+	pcdata->worker_line_buf_pos = 0;
+	pcdata->worker_line_buf_count = 0;
+
+	for (buff_count = 0; buff_count < WORKER_CHUNK_COUNT; buff_count++)
+	{
+		bool result = CacheLineInfo(cstate, buff_count);
+		if (result)
+			break;
+
+		pcdata->worker_line_buf_count++;
+	}
+
+	if (pcdata->worker_line_buf_count)
+		goto return_line;
+	else
+		resetStringInfo(&cstate->line_buf);
+
+	return true;
+
+return_line:
+	cstate->line_buf = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].line_buf;
+	cstate->cur_lineno = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].cur_lineno;
+	cstate->line_buf_valid = true;
+
+	/* Mark that encoding conversion hasn't occurred yet. */
+	cstate->line_buf_converted = false;
+	CONVERT_TO_SERVER_ENCODING(cstate)
+	pcdata->worker_line_buf_pos++;
+	return false;
 }
+
 /*
  * ParallelCopyMain - parallel copy worker's code.
  *
@@ -1154,6 +1570,7 @@ ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
 	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
 
 	pcdata->pcshared_info = pcshared_info;
+	AssignFullTransactionIdForWorker(pcshared_info->full_transaction_id);
 
 	shared_cstate = (ParallelCopyCommonKeyData *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE,
 														   false);
@@ -1206,6 +1623,34 @@ ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
 	MemoryContextSwitchTo(oldcontext);
 	return;
 }
+
+/*
+ * UpdateBlockInLineInfo - Update the line information.
+ */
+static pg_attribute_always_inline int
+UpdateBlockInLineInfo(CopyState cstate, uint32 blk_pos,
+					   uint32 offset, uint32 line_size, uint32 line_state)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyLineBoundaries *lineBoundaryPtr = &pcshared_info->line_boundaries;
+	ParallelCopyLineBoundary *lineInfo;
+	int line_pos = lineBoundaryPtr->leader_pos;
+
+	/* Update the line information for the worker to pick and process. */
+	lineInfo = &lineBoundaryPtr->ring[line_pos];
+	while (pg_atomic_read_u32(&lineInfo->line_size) != -1)
+		COPY_WAIT_TO_PROCESS()
+
+	lineInfo->first_block = blk_pos;
+	lineInfo->start_offset = offset;
+	lineInfo->cur_lineno = cstate->cur_lineno;
+	pg_atomic_write_u32(&lineInfo->line_size, line_size);
+	pg_atomic_write_u32(&lineInfo->line_state, line_state);
+	lineBoundaryPtr->leader_pos = (lineBoundaryPtr->leader_pos + 1) % RINGSIZE;
+
+	return line_pos;
+}
+
 /*
  * ParallelCopyLeader - parallel copy leader's functionality.
  *
@@ -1231,9 +1676,158 @@ ParallelCopyLeader(CopyState cstate)
 	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
 	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
 
+	/* Execute the before statement triggers from the leader */
+	ExecBeforeStmtTrigger(cstate);
+
+	/* On input just throw the header line away. */
+	if (cstate->cur_lineno == 0 && cstate->header_line)
+	{
+		cstate->cur_lineno++;
+		if (CopyReadLine(cstate))
+		{
+			pcshared_info->is_read_in_progress = false;
+			return;			/* done */
+		}
+	}
+
+	for (;;)
+	{
+		bool done;
+		cstate->cur_lineno++;
+
+		/* Actually read the line into memory here. */
+		done = CopyReadLine(cstate);
+
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			break;
+	}
+
 	pcshared_info->is_read_in_progress = false;
 	cstate->cur_lineno = 0;
 }
+
+/*
+ * GetLinePosition - return the line position that worker should process.
+ */
+static uint32
+GetLinePosition(CopyState cstate)
+{
+	ParallelCopyData *pcdata = cstate->pcdata;
+	ParallelCopyShmInfo *pcshared_info = pcdata->pcshared_info;
+	uint32  previous_pos = pcdata->worker_processed_pos;
+	uint32 write_pos = (previous_pos == -1) ? 0 : (previous_pos + 1) % RINGSIZE;
+	for (;;)
+	{
+		int		dataSize;
+		bool	is_read_in_progress = pcshared_info->is_read_in_progress;
+		ParallelCopyLineBoundary *lineInfo;
+		ParallelCopyDataBlock *data_blk_ptr;
+		ParallelCopyLineState line_state = LINE_LEADER_POPULATED;
+		ParallelCopyLineState curr_line_state;
+		CHECK_FOR_INTERRUPTS();
+
+		/* File read completed & no elements to process. */
+		if (!is_read_in_progress &&
+			(pcshared_info->populated ==
+			 pg_atomic_read_u64(&pcshared_info->total_worker_processed)))
+		{
+			write_pos = -1;
+			break;
+		}
+
+		/* Get the current line information. */
+		lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+		curr_line_state = pg_atomic_read_u32(&lineInfo->line_state);
+		if ((write_pos % WORKER_CHUNK_COUNT == 0) &&
+			(curr_line_state == LINE_WORKER_PROCESSED ||
+			 curr_line_state == LINE_WORKER_PROCESSING))
+		{
+			pcdata->worker_processed_pos = write_pos;
+			write_pos = (write_pos + WORKER_CHUNK_COUNT) %  RINGSIZE;
+			continue;
+		}
+
+		/* Get the size of this line. */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+		if (dataSize != 0) /* If not an empty line. */
+		{
+			/* Get the block information. */
+			data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+			if (!data_blk_ptr->curr_blk_completed && (dataSize == -1))
+			{
+				/* Wait till the current line or block is added. */
+				COPY_WAIT_TO_PROCESS()
+				continue;
+			}
+		}
+
+		/* Make sure that no worker has consumed this element. */
+		if (pg_atomic_compare_exchange_u32(&lineInfo->line_state,
+										   &line_state, LINE_WORKER_PROCESSING))
+			break;
+	}
+
+	pcdata->worker_processed_pos = write_pos;
+	return write_pos;
+}
+
+/*
+ * GetFreeCopyBlock - Get a free block for data to be copied.
+ */
+static pg_attribute_always_inline uint32
+GetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	int count = 0;
+	uint32 last_free_block = pcshared_info->cur_block_pos;
+	uint32 block_pos = (last_free_block != -1) ? ((last_free_block + 1) % MAX_BLOCKS_COUNT): 0;
+
+	/* Get a new block for copying data. */
+	while (count < MAX_BLOCKS_COUNT)
+	{
+		ParallelCopyDataBlock *dataBlkPtr = &pcshared_info->data_blocks[block_pos];
+		uint32 unprocessed_line_parts = pg_atomic_read_u32(&dataBlkPtr->unprocessed_line_parts);
+		if (unprocessed_line_parts == 0)
+		{
+			dataBlkPtr->curr_blk_completed = false;
+			dataBlkPtr->skip_bytes = 0;
+			pcshared_info->cur_block_pos = block_pos;
+			return block_pos;
+		}
+
+		block_pos = (block_pos + 1) % MAX_BLOCKS_COUNT;
+		count++;
+	}
+
+	return -1;
+}
+
+/*
+ * WaitGetFreeCopyBlock - If there are no blocks available, wait and get a block
+ * for copying data.
+ */
+static uint32
+WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	uint32 new_free_pos = -1;
+	for (;;)
+	{
+		new_free_pos = GetFreeCopyBlock(pcshared_info);
+		if (new_free_pos != -1)	/* We have got one block, break now. */
+			break;
+
+		COPY_WAIT_TO_PROCESS()
+	}
+
+	return new_free_pos;
+}
+
 /*
  * LookupParallelCopyFnPtr - Look up parallel copy function pointer.
  */
@@ -1269,6 +1863,146 @@ LookupParallelCopyFnStr(copy_data_source_cb fn_addr)
 	/* We can only reach this by programming error. */
 	elog(ERROR, "internal function pointer not found");
 }
+
+/*
+ * SetRawBufForLoad - Set raw_buf to the shared memory where the file data must
+ * be read.
+ */
+static void
+SetRawBufForLoad(CopyState cstate, uint32 line_size, uint32 copy_buf_len,
+				 uint32 raw_buf_ptr, char **copy_raw_buf)
+{
+	ParallelCopyShmInfo	*pcshared_info;
+	uint32 cur_block_pos;
+	uint32 next_block_pos;
+	ParallelCopyDataBlock	*cur_data_blk_ptr = NULL;
+	ParallelCopyDataBlock	*next_data_blk_ptr = NULL;
+
+	if (!IsParallelCopy())
+		return;
+
+	pcshared_info = cstate->pcdata->pcshared_info;
+	cur_block_pos = pcshared_info->cur_block_pos;
+	cur_data_blk_ptr = (cstate->raw_buf) ? &pcshared_info->data_blocks[cur_block_pos] : NULL;
+	next_block_pos = WaitGetFreeCopyBlock(pcshared_info);
+	next_data_blk_ptr = &pcshared_info->data_blocks[next_block_pos];
+
+	/* set raw_buf to the data block in shared memory */
+	cstate->raw_buf = next_data_blk_ptr->data;
+	*copy_raw_buf = cstate->raw_buf;
+	if (cur_data_blk_ptr && line_size)
+	{
+		/*
+		 * Mark the previous block as completed, worker can start copying this
+		 * data.
+		 */
+		cur_data_blk_ptr->following_block = next_block_pos;
+		pg_atomic_add_fetch_u32(&cur_data_blk_ptr->unprocessed_line_parts, 1);
+		cur_data_blk_ptr->skip_bytes = copy_buf_len - raw_buf_ptr;
+		cur_data_blk_ptr->curr_blk_completed = true;
+	}
+}
+
+/*
+ * EndLineParallelCopy - Update the line information in shared memory.
+ */
+static void
+EndLineParallelCopy(CopyState cstate, uint32 line_pos, uint32 line_size,
+					 uint32 raw_buf_ptr)
+{
+	uint8 new_line_size;
+	if (!IsParallelCopy())
+		return;
+
+	if (!IsHeaderLine())
+	{
+		ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+		ParallelCopyLineBoundaries *lineBoundaryPtr = &pcshared_info->line_boundaries;
+		SET_NEWLINE_SIZE()
+		if (line_size)
+		{
+			ParallelCopyLineBoundary *lineInfo = &lineBoundaryPtr->ring[line_pos];
+			/*
+			 * If the new_line_size > raw_buf_ptr, then the new block has only
+			 * new line char content. The unprocessed count should not be
+			 * increased in this case.
+			 */
+			if (raw_buf_ptr > new_line_size)
+			{
+				uint32 cur_block_pos = pcshared_info->cur_block_pos;
+				ParallelCopyDataBlock *curr_data_blk_ptr = &pcshared_info->data_blocks[cur_block_pos];
+				pg_atomic_add_fetch_u32(&curr_data_blk_ptr->unprocessed_line_parts, 1);
+			}
+
+			/* Update line size. */
+			pg_atomic_write_u32(&lineInfo->line_size, line_size);
+			pg_atomic_write_u32(&lineInfo->line_state, LINE_LEADER_POPULATED);
+			elog(DEBUG1, "[Leader] After adding - line position:%d, line_size:%d",
+						 line_pos, line_size);
+			pcshared_info->populated++;
+		}
+		else if (new_line_size)
+		{
+			/* This means only new line char, empty record should be inserted.*/
+			ParallelCopyLineBoundary *lineInfo;
+			line_pos = UpdateBlockInLineInfo(cstate, -1, -1, 0,
+											   LINE_LEADER_POPULATED);
+			lineInfo = &lineBoundaryPtr->ring[line_pos];
+			elog(DEBUG1, "[Leader] Added empty line with offset:%d, line position:%d, line size:%d",
+						 lineInfo->start_offset, line_pos,
+						 pg_atomic_read_u32(&lineInfo->line_size));
+			pcshared_info->populated++;
+		}
+	}
+}
+
+/*
+ * ExecBeforeStmtTrigger - Execute the before statement trigger, this will be
+ * executed for parallel copy by the leader process.
+ */
+static void
+ExecBeforeStmtTrigger(CopyState cstate)
+{
+	EState	   *estate = CreateExecutorState();
+	ResultRelInfo *resultRelInfo;
+
+	Assert(IsLeader());
+
+	/*
+	 * We need a ResultRelInfo so we can use the regular executor's
+	 * index-entry-making machinery.  (There used to be a huge amount of code
+	 * here that basically duplicated execUtils.c ...)
+	 */
+	resultRelInfo = makeNode(ResultRelInfo);
+	InitResultRelInfo(resultRelInfo,
+					  cstate->rel,
+					  1,		/* must match rel's position in range_table */
+					  NULL,
+					  0);
+
+	/* Verify the named relation is a valid target for INSERT */
+	CheckValidResultRel(resultRelInfo, CMD_INSERT);
+
+	estate->es_result_relations = resultRelInfo;
+	estate->es_num_result_relations = 1;
+	estate->es_result_relation_info = resultRelInfo;
+
+	ExecInitRangeTable(estate, cstate->range_table);
+
+	/*
+	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
+	 * should do this for COPY, since it's not really an "INSERT" statement as
+	 * such. However, executing these triggers maintains consistency with the
+	 * EACH ROW triggers that we already fire on COPY.
+	 */
+	ExecBSInsertTriggers(estate, resultRelInfo);
+
+	/* Close any trigger target relations */
+	ExecCleanUpTriggerState(estate);
+
+	FreeExecutorState(estate);
+}
+
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
  * in past protocol redesigns.
@@ -3675,7 +4409,8 @@ CopyFrom(CopyState cstate)
 
 	PartitionTupleRouting *proute = NULL;
 	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
+	CommandId	mycid = IsParallelCopy() ? cstate->pcdata->pcshared_info->mycid :
+										   GetCurrentCommandId(true);
 	int			ti_options = 0; /* start with default options for insert */
 	BulkInsertState bistate = NULL;
 	CopyInsertMethod insertMethod;
@@ -3685,7 +4420,14 @@ CopyFrom(CopyState cstate)
 	bool		has_instead_insert_row_trig;
 	bool		leafpart_use_multi_insert = false;
 
-	CheckTargetRelValidity(cstate);
+	/*
+	 * Perform this check if it is not parallel copy. In case of parallel
+	 * copy, this check is done by the leader, so that if any invalid case
+	 * exist the copy from command will error out from the leader itself,
+	 * avoiding launching workers, just to throw error.
+	 */
+	if (!IsParallelCopy())
+		CheckTargetRelValidity(cstate);
 
 	/*
 	 * If the target file is new-in-transaction, we assume that checking FSM
@@ -3874,13 +4616,16 @@ CopyFrom(CopyState cstate)
 	has_instead_insert_row_trig = (resultRelInfo->ri_TrigDesc &&
 								   resultRelInfo->ri_TrigDesc->trig_insert_instead_row);
 
-	/*
-	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
-	 * should do this for COPY, since it's not really an "INSERT" statement as
-	 * such. However, executing these triggers maintains consistency with the
-	 * EACH ROW triggers that we already fire on COPY.
-	 */
-	ExecBSInsertTriggers(estate, resultRelInfo);
+	if (!IsParallelCopy())
+	{
+		/*
+		 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
+		 * should do this for COPY, since it's not really an "INSERT" statement as
+		 * such. However, executing these triggers maintains consistency with the
+		 * EACH ROW triggers that we already fire on COPY.
+		 */
+		ExecBSInsertTriggers(estate, resultRelInfo);
+	}
 
 	econtext = GetPerTupleExprContext(estate);
 
@@ -3980,6 +4725,16 @@ CopyFrom(CopyState cstate)
 					!has_instead_insert_row_trig &&
 					resultRelInfo->ri_FdwRoutine == NULL;
 
+				/*
+				 * If the table has any partitions that are either foreign or
+				 * has BEFORE/INSTEAD OF triggers, we can't perform copy
+				 * operations with parallel workers.
+				 */
+				if (!leafpart_use_multi_insert && IsParallelWorker())
+					ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							errmsg("cannot perform PARALLEL COPY if partition has BEFORE/INSTEAD OF triggers, or if the partition is foreign partition"),
+							errhint("Try COPY without PARALLEL option")));
+
 				/* Set the multi-insert buffer to use for this partition. */
 				if (leafpart_use_multi_insert)
 				{
@@ -4394,7 +5149,7 @@ BeginCopyFrom(ParseState *pstate,
 	initStringInfo(&cstate->attribute_buf);
 	initStringInfo(&cstate->line_buf);
 	cstate->line_buf_converted = false;
-	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+	cstate->raw_buf = (IsParallelCopy()) ? NULL : (char *) palloc(RAW_BUF_SIZE + 1);
 	cstate->raw_buf_index = cstate->raw_buf_len = 0;
 
 	/* Assign range table, we'll need it in CopyFrom. */
@@ -4538,26 +5293,35 @@ NextCopyFromRawFields(CopyState cstate, char ***fields, int *nfields)
 	/* only available for text or csv input */
 	Assert(!cstate->binary);
 
-	/* on input just throw the header line away */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (IsParallelCopy())
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
-			return false;		/* done */
+		done = GetWorkerLine(cstate);
+		if (done && cstate->line_buf.len == 0)
+			return false;
 	}
+	else
+	{
+		/* on input just throw the header line away */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
+		{
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+				return false;		/* done */
+		}
 
-	cstate->cur_lineno++;
+		cstate->cur_lineno++;
 
-	/* Actually read the line into memory here */
-	done = CopyReadLine(cstate);
+		/* Actually read the line into memory here */
+		done = CopyReadLine(cstate);
 
-	/*
-	 * EOF at start of line means we're done.  If we see EOF after some
-	 * characters, we act as though it was newline followed by EOF, ie,
-	 * process the line and then exit loop on next iteration.
-	 */
-	if (done && cstate->line_buf.len == 0)
-		return false;
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			return false;
+	}
 
 	/* Parse the line into de-escaped field values */
 	if (cstate->csv_mode)
@@ -4805,9 +5569,31 @@ CopyReadLine(CopyState cstate)
 		 */
 		if (cstate->copy_dest == COPY_NEW_FE)
 		{
+			bool bIsFirst = true;
 			do
 			{
-				cstate->raw_buf_index = cstate->raw_buf_len;
+				if (!IsParallelCopy())
+					cstate->raw_buf_index = cstate->raw_buf_len;
+				else
+				{
+					if (cstate->raw_buf_index == RAW_BUF_SIZE)
+					{
+						/* Get a new block if it is the first time, From the
+						 * subsequent time, reset the index and re-use the same
+						 * block.
+						 */
+						if (bIsFirst)
+						{
+							ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+							uint32 block_pos = WaitGetFreeCopyBlock(pcshared_info);
+							cstate->raw_buf = pcshared_info->data_blocks[block_pos].data;
+							bIsFirst = false;
+						}
+
+						cstate->raw_buf_index = cstate->raw_buf_len = 0;
+					}
+				}
+
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
@@ -4837,6 +5623,11 @@ CopyReadLineText(CopyState cstate)
 	char		quotec = '\0';
 	char		escapec = '\0';
 
+	/* For parallel copy */
+	uint32			 line_size = 0;
+	int				 line_pos = 0;
+
+	cstate->eol_type = EOL_UNKNOWN;
 	if (cstate->csv_mode)
 	{
 		quotec = cstate->quote[0];
@@ -4891,6 +5682,8 @@ CopyReadLineText(CopyState cstate)
 		if (raw_buf_ptr >= copy_buf_len || need_data)
 		{
 			REFILL_LINEBUF;
+			SetRawBufForLoad(cstate, line_size, copy_buf_len, raw_buf_ptr,
+							 &copy_raw_buf);
 
 			/*
 			 * Try to read some more data.  This will certainly reset
@@ -5115,9 +5908,15 @@ CopyReadLineText(CopyState cstate)
 				 * discard the data and the \. sequence.
 				 */
 				if (prev_raw_ptr > cstate->raw_buf_index)
-					appendBinaryStringInfo(&cstate->line_buf,
+				{
+					if (!IsParallelCopy())
+						appendBinaryStringInfo(&cstate->line_buf,
 										   cstate->raw_buf + cstate->raw_buf_index,
 										   prev_raw_ptr - cstate->raw_buf_index);
+					else
+						line_size += prev_raw_ptr - cstate->raw_buf_index;
+				}
+
 				cstate->raw_buf_index = raw_buf_ptr;
 				result = true;	/* report EOF */
 				break;
@@ -5169,6 +5968,26 @@ not_end_of_copy:
 			IF_NEED_REFILL_AND_EOF_BREAK(mblen - 1);
 			raw_buf_ptr += mblen - 1;
 		}
+
+		/*
+		 * Skip the header line. Update the line here, this cannot be done at
+		 * the beginning, as there is a possibility that file contains empty
+		 * lines.
+		 */
+		if (IsParallelCopy() && first_char_in_line && !IsHeaderLine())
+		{
+			ParallelCopyShmInfo	*pcshared_info = cstate->pcdata->pcshared_info;
+			ParallelCopyLineBoundary *lineInfo;
+			uint32			 line_first_block = pcshared_info->cur_block_pos;
+			line_pos = UpdateBlockInLineInfo(cstate,
+											   line_first_block,
+											   cstate->raw_buf_index, -1,
+											   LINE_LEADER_POPULATING);
+			lineInfo = &pcshared_info->line_boundaries.ring[line_pos];
+			elog(DEBUG1, "[Leader] Adding - block:%d, offset:%d, line position:%d",
+						 line_first_block,	lineInfo->start_offset, line_pos);
+		}
+
 		first_char_in_line = false;
 	}							/* end of outer loop */
 
@@ -5177,6 +5996,7 @@ not_end_of_copy:
 	 */
 	REFILL_LINEBUF;
 	CLEAR_EOL_LINE()
+	EndLineParallelCopy(cstate, line_pos, line_size, raw_buf_ptr);
 
 	return result;
 }
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index db19187..584b7ee 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -381,6 +381,7 @@ extern FullTransactionId GetTopFullTransactionId(void);
 extern FullTransactionId GetTopFullTransactionIdIfAny(void);
 extern FullTransactionId GetCurrentFullTransactionId(void);
 extern FullTransactionId GetCurrentFullTransactionIdIfAny(void);
+extern void AssignFullTransactionIdForWorker(FullTransactionId fullTransactionId);
 extern void MarkCurrentTransactionIdLoggedIfAny(void);
 extern bool SubTransactionIsActive(SubTransactionId subxid);
 extern CommandId GetCurrentCommandId(bool used);
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 8a79794..86b5c62 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1700,6 +1700,7 @@ ParallelCompletionPtr
 ParallelContext
 ParallelCopyLineBoundaries
 ParallelCopyLineBoundary
+ParallelCopyLineState
 ParallelCopyCommonKeyData
 ParallelCopyData
 ParallelCopyDataBlock
-- 
1.8.3.1

0004-Documentation-for-parallel-copy.patchapplication/octet-stream; name=0004-Documentation-for-parallel-copy.patchDownload
From f06311aab275234125ed5b2c1a5c4740db55df3f Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 17 Jun 2020 07:34:56 +0530
Subject: [PATCH 4/6] Documentation for parallel copy.

This patch has the documentation changes for parallel copy.
---
 doc/src/sgml/ref/copy.sgml | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/doc/src/sgml/ref/copy.sgml b/doc/src/sgml/ref/copy.sgml
index 18189ab..95d349d 100644
--- a/doc/src/sgml/ref/copy.sgml
+++ b/doc/src/sgml/ref/copy.sgml
@@ -37,6 +37,7 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
     DELIMITER '<replaceable class="parameter">delimiter_character</replaceable>'
     NULL '<replaceable class="parameter">null_string</replaceable>'
     HEADER [ <replaceable class="parameter">boolean</replaceable> ]
+    PARALLEL <replaceable class="parameter">integer</replaceable>
     QUOTE '<replaceable class="parameter">quote_character</replaceable>'
     ESCAPE '<replaceable class="parameter">escape_character</replaceable>'
     FORCE_QUOTE { ( <replaceable class="parameter">column_name</replaceable> [, ...] ) | * }
@@ -275,6 +276,21 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
    </varlistentry>
 
    <varlistentry>
+    <term><literal>PARALLEL</literal></term>
+    <listitem>
+     <para>
+      Perform <command>COPY FROM</command> in parallel using <replaceable
+      class="parameter"> integer</replaceable> background workers.  Please
+      note that it is not guaranteed that the number of parallel workers
+      specified in <replaceable class="parameter">integer</replaceable> will
+      be used during execution.  It is possible for a copy to run with fewer
+      workers than specified, or even with no workers at all.  This option is
+      allowed only in <command>COPY FROM</command>.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><literal>QUOTE</literal></term>
     <listitem>
      <para>
-- 
1.8.3.1

0005-Tests-for-parallel-copy.patchapplication/octet-stream; name=0005-Tests-for-parallel-copy.patchDownload
From 740f39b8a87eb74e74182ed2cc5e8c18bd2ce367 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 17 Jun 2020 07:37:26 +0530
Subject: [PATCH 5/6] Tests for parallel copy.

This patch has the tests for parallel copy.
---
 src/test/regress/expected/copy2.out | 210 +++++++++++++++++++++++++++++++++++-
 src/test/regress/input/copy.source  |  12 +++
 src/test/regress/output/copy.source |  12 +++
 src/test/regress/sql/copy2.sql      | 208 ++++++++++++++++++++++++++++++++++-
 4 files changed, 434 insertions(+), 8 deletions(-)

diff --git a/src/test/regress/expected/copy2.out b/src/test/regress/expected/copy2.out
index e40287d..a088f72 100644
--- a/src/test/regress/expected/copy2.out
+++ b/src/test/regress/expected/copy2.out
@@ -254,18 +254,32 @@ It is "perfect".|
 "It is ""perfect"".","	"
 "",
 --test that we read consecutive LFs properly
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 COPY testnl FROM stdin CSV;
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL '2');
+SELECT * FROM testnl;
+ a |          b           | c 
+---+----------------------+---
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+(2 rows)
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 COPY testeoc FROM stdin CSV;
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL '2');
 COPY testeoc TO stdout CSV;
 a\.
 \.b
 c\.d
 "\."
 -- test handling of nonstandard null marker that violates escaping rules
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 COPY testnull TO stdout WITH NULL AS E'\\0';
 1	\\0
@@ -280,6 +294,15 @@ SELECT * FROM testnull;
     | 
 (4 rows)
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 2);
+SELECT * FROM testnull;
+ a  | b  
+----+----
+ 42 | \0
+    | 
+(2 rows)
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -349,6 +372,34 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 2);
+SELECT * FROM vistest;
+ a  
+----
+ a2
+ b
+(2 rows)
+
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 2);
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+COMMIT;
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 SELECT * FROM vistest;
  a 
@@ -409,7 +460,7 @@ SELECT * FROM vistest;
 (2 rows)
 
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -420,6 +471,8 @@ CREATE TEMP TABLE forcetest (
 -- should succeed with no effect ("b" remains an empty string, "c" remains NULL)
 BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 2);
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
  b |  c   
@@ -430,6 +483,8 @@ SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
 BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 2);
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
  c |  d   
@@ -486,6 +541,31 @@ select * from check_con_tbl;
    
 (2 rows)
 
+\d+ check_con_tbl
+                               Table "public.check_con_tbl"
+ Column |  Type   | Collation | Nullable | Default | Storage | Stats target | Description 
+--------+---------+-----------+----------+---------+---------+--------------+-------------
+ f1     | integer |           |          |         | plain   |              | 
+Check constraints:
+    "check_con_tbl_check" CHECK (check_con_function(check_con_tbl.*))
+
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 2);
+NOTICE:  input = {"f1":1}
+NOTICE:  input = {"f1":null}
+copy check_con_tbl from stdin with (parallel 2);
+NOTICE:  input = {"f1":0}
+ERROR:  new row for relation "check_con_tbl" violates check constraint "check_con_tbl_check"
+DETAIL:  Failing row contains (0).
+CONTEXT:  COPY check_con_tbl, line 1: "0"
+parallel worker
+select * from check_con_tbl;
+ f1 
+----
+  1
+   
+(2 rows)
+
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
 CREATE ROLE regress_rls_copy_user_colperms;
@@ -600,8 +680,130 @@ SELECT * FROM instead_of_insert_tbl;
 (2 rows)
 
 COMMIT;
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+COPY test_parallel_copy (a, b, c, d, e) from stdin with (PARALLEL '2');
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '2');
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '2');
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '2', FORMAT 'csv', HEADER);
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0');
+ERROR:  argument to option "parallel" must be a positive integer greater than zero
+LINE 1: COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0'...
+                                                        ^
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri from stdin with (FORMAT csv, DELIMITER ',', PARALLEL '2');
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', parallel '2') WHERE height > random() * 65;
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', parallel '2');
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- temporary table copy: should peform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+COPY temp_test (a) from stdin with (PARALLEL '2');
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) from stdin with (PARALLEL '2');
+ERROR:  column "xyz" of relation "test_parallel_copy" does not exist
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) from stdin with (PARALLEL '2');
+ERROR:  column "d" specified more than once
+-- missing data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL '2');
+ERROR:  invalid input syntax for type integer: ""
+CONTEXT:  COPY test_parallel_copy, line 0, column a: ""
+parallel worker
+COPY test_parallel_copy from stdin with (PARALLEL '2');
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2000	230	23	23"
+parallel worker
+COPY test_parallel_copy from stdin with (PARALLEL '2');
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2001	231	\N	\N"
+parallel worker
+-- extra data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL '2');
+ERROR:  extra data after last expected column
+CONTEXT:  COPY test_parallel_copy, line 1: "2002	232	40	50	60	70	80"
+parallel worker
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) from stdin with (delimiter ',', null 'x', PARALLEL '2') ;
+COPY test_parallel_copy from stdin WITH (DELIMITER ';', NULL '', PARALLEL '2');
+COPY test_parallel_copy from stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL '2');
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a = 50004;
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a > 60003;
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE f > 60003;
+ERROR:  column "f" does not exist
+LINE 1: ...arallel_copy from stdin WITH (PARALLEL '2') WHERE f > 60003;
+                                                             ^
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a = max(x.b);
+ERROR:  missing FROM-clause entry for table "x"
+LINE 1: ...llel_copy from stdin WITH (PARALLEL '2') WHERE a = max(x.b);
+                                                                  ^
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a IN (SELECT 1 FROM x);
+ERROR:  cannot use subquery in COPY FROM WHERE condition
+LINE 1: ...allel_copy from stdin WITH (PARALLEL '2') WHERE a IN (SELECT...
+                                                             ^
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a IN (generate_series(1,5));
+ERROR:  set-returning functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...l_copy from stdin WITH (PARALLEL '2') WHERE a IN (generate_s...
+                                                             ^
+COPY test_parallel_copy from stdin WITH(PARALLEL '2') WHERE a = row_number() over(b);
+ERROR:  window functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...llel_copy from stdin WITH(PARALLEL '2') WHERE a = row_number...
+                                                             ^
+-- check results of copy in
+SELECT * FROM test_parallel_copy;
+   a   | b  |     c      |    d    |    e    
+-------+----+------------+---------+---------
+     1 | 11 | test_c1    | test_d1 | test_e1
+     2 | 12 | test_c2    | test_d2 | test_e2
+       |  3 | stuff      | test_d3 | 
+       |  4 | stuff      | test_d4 | 
+       |  5 | stuff      | test_d5 | 
+       |    | 45         | 80      | 90
+       |    | x          | \x      | \x
+       |    | ,          | \,      | \
+  3000 |    | c          |         | 
+  4000 |    | C          |         | 
+  4001 |  1 | empty      |         | 
+  4002 |  2 | null       |         | 
+  4003 |  3 | Backslash  | \       | \
+  4004 |  4 | BackslashX | \X      | \X
+  4005 |  5 | N          | N       | N
+  4006 |  6 | BackslashN | \N      | \N
+  4007 |  7 | XX         | XX      | XX
+  4008 |  8 | Delimiter  | :       | :
+ 50004 | 25 | 35         | 45      | 55
+ 60004 | 25 | 35         | 45      | 55
+ 60005 | 26 | 36         | 46      | 56
+(21 rows)
+
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
 DROP TABLE x, y;
diff --git a/src/test/regress/input/copy.source b/src/test/regress/input/copy.source
index a1d529a..159c058 100644
--- a/src/test/regress/input/copy.source
+++ b/src/test/regress/input/copy.source
@@ -15,6 +15,13 @@ DELETE FROM onek;
 
 COPY onek FROM '@abs_builddir@/results/onek.data';
 
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+
+SELECT COUNT(*) FROM tenk1;
+
+TRUNCATE tenk1;
+
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
@@ -159,6 +166,11 @@ truncate parted_copytest;
 
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
 
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
+
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/output/copy.source b/src/test/regress/output/copy.source
index 938d355..c3003fe 100644
--- a/src/test/regress/output/copy.source
+++ b/src/test/regress/output/copy.source
@@ -9,6 +9,15 @@ COPY onek FROM '@abs_srcdir@/data/onek.data';
 COPY onek TO '@abs_builddir@/results/onek.data';
 DELETE FROM onek;
 COPY onek FROM '@abs_builddir@/results/onek.data';
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+SELECT COUNT(*) FROM tenk1;
+ count 
+-------
+ 10000
+(1 row)
+
+TRUNCATE tenk1;
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
 COPY person FROM '@abs_srcdir@/data/person.data';
@@ -113,6 +122,9 @@ insert into parted_copytest select x,1,'One' from generate_series(1011,1020) x;
 copy (select * from parted_copytest order by a) to '@abs_builddir@/results/parted_copytest.csv';
 truncate parted_copytest;
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/sql/copy2.sql b/src/test/regress/sql/copy2.sql
index 902f4fa..13104f4 100644
--- a/src/test/regress/sql/copy2.sql
+++ b/src/test/regress/sql/copy2.sql
@@ -157,7 +157,7 @@ COPY y TO stdout (FORMAT CSV, FORCE_QUOTE *);
 
 --test that we read consecutive LFs properly
 
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 
 COPY testnl FROM stdin CSV;
 1,"a field with two LFs
@@ -165,8 +165,16 @@ COPY testnl FROM stdin CSV;
 inside",2
 \.
 
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL '2');
+1,"a field with two LFs
+
+inside",2
+\.
+
+SELECT * FROM testnl;
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 
 COPY testeoc FROM stdin CSV;
 a\.
@@ -175,11 +183,19 @@ c\.d
 "\."
 \.
 
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL '2');
+a\.
+\.b
+c\.d
+"\."
+\.
+
 COPY testeoc TO stdout CSV;
 
 -- test handling of nonstandard null marker that violates escaping rules
 
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 
 COPY testnull TO stdout WITH NULL AS E'\\0';
@@ -191,6 +207,14 @@ COPY testnull FROM stdin WITH NULL AS E'\\0';
 
 SELECT * FROM testnull;
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 2);
+42	\\0
+\0	\0
+\.
+
+SELECT * FROM testnull;
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -235,6 +259,23 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 2);
+a2
+b
+\.
+SELECT * FROM vistest;
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 2);
+d2
+e
+\.
+SELECT * FROM vistest;
+COMMIT;
+SELECT * FROM vistest;
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 x
 y
@@ -284,7 +325,7 @@ SELECT * FROM vistest;
 COMMIT;
 SELECT * FROM vistest;
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -297,6 +338,10 @@ BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
 1,,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 2);
+1,,""
+\.
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
@@ -304,6 +349,10 @@ BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
 2,'a',,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 2);
+2,'a',,""
+\.
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
 -- should fail with not-null constraint violation
@@ -339,6 +388,16 @@ copy check_con_tbl from stdin;
 0
 \.
 select * from check_con_tbl;
+\d+ check_con_tbl
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 2);
+1
+\N
+\.
+copy check_con_tbl from stdin with (parallel 2);
+0
+\.
+select * from check_con_tbl;
 
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
@@ -440,8 +499,149 @@ test1
 SELECT * FROM instead_of_insert_tbl;
 COMMIT;
 
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+
+COPY test_parallel_copy (a, b, c, d, e) from stdin with (PARALLEL '2');
+1	11	test_c1	test_d1	test_e1
+2	12	test_c2	test_d2	test_e2
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '2');
+3	test_d3
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '2');
+4	test_d4
+5	test_d5
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '2', FORMAT 'csv', HEADER);
+b	d
+\.
+
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0');
+
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri from stdin with (FORMAT csv, DELIMITER ',', PARALLEL '2');
+10
+\.
+
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', parallel '2') WHERE height > random() * 65;
+60,60,60
+\.
+
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', parallel '2');
+60
+\.
+
+-- temporary table copy: should peform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+
+COPY temp_test (a) from stdin with (PARALLEL '2');
+10
+\.
+
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) from stdin with (PARALLEL '2');
+
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) from stdin with (PARALLEL '2');
+
+-- missing data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL '2');
+
+\.
+COPY test_parallel_copy from stdin with (PARALLEL '2');
+2000	230	23	23
+\.
+COPY test_parallel_copy from stdin with (PARALLEL '2');
+2001	231	\N	\N
+\.
+
+-- extra data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL '2');
+2002	232	40	50	60	70	80
+\.
+
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) from stdin with (delimiter ',', null 'x', PARALLEL '2') ;
+x,45,80,90
+x,\x,\\x,\\\x
+x,\,,\\\,,\\
+\.
+
+COPY test_parallel_copy from stdin WITH (DELIMITER ';', NULL '', PARALLEL '2');
+3000;;c;;
+\.
+
+COPY test_parallel_copy from stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL '2');
+4000:\X:C:\X:\X
+4001:1:empty::
+4002:2:null:\X:\X
+4003:3:Backslash:\\:\\
+4004:4:BackslashX:\\X:\\X
+4005:5:N:\N:\N
+4006:6:BackslashN:\\N:\\N
+4007:7:XX:\XX:\XX
+4008:8:Delimiter:\::\:
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a = 50004;
+50003	24	34	44	54
+50004	25	35	45 	55
+50005	26	36	46	56
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a > 60003;
+60001	22	32	42	52
+60002	23	33	43	53
+60003	24	34	44	54
+60004	25	35	45	55
+60005	26	36	46	56
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE f > 60003;
+
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a = max(x.b);
+
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a IN (SELECT 1 FROM x);
+
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a IN (generate_series(1,5));
+
+COPY test_parallel_copy from stdin WITH(PARALLEL '2') WHERE a = row_number() over(b);
+
+-- check results of copy in
+SELECT * FROM test_parallel_copy;
+
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
 DROP TABLE x, y;
-- 
1.8.3.1

#103Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: vignesh C (#101)
Re: Parallel copy

Hi,

It looks like the parsing of newly introduced "PARALLEL" option for
COPY FROM command has an issue(in the
0002-Framework-for-leader-worker-in-parallel-copy.patch),
Mentioning ....PARALLEL '4ar2eteid'); would pass with 4 workers since
atoi() is being used for converting string to integer which just
returns 4, ignoring other strings.

I used strtol(), added error checks and introduced the error "
improper use of argument to option "parallel"" for the above cases.

parallel '4ar2eteid');
ERROR: improper use of argument to option "parallel"
LINE 5: parallel '1\');

Along with the updated patch
0002-Framework-for-leader-worker-in-parallel-copy.patch, also
attaching all the latest patches from [1]/messages/by-id/CALj2ACW94icER3WrWapon7JkcX8j0TGRue5ycWMTEvgA3X7fOg@mail.gmail.com.

[1]: /messages/by-id/CALj2ACW94icER3WrWapon7JkcX8j0TGRue5ycWMTEvgA3X7fOg@mail.gmail.com

With Regards,
Bharath Rupireddy.
EnterpriseDB: http://www.enterprisedb.com

Show quoted text

On Tue, Jun 23, 2020 at 12:22 PM vignesh C <vignesh21@gmail.com> wrote:

On Tue, Jun 23, 2020 at 8:07 AM vignesh C <vignesh21@gmail.com> wrote:

I have attached the patch for the same with the fixes.

The patches were not applying on the head, attached the patches that can be applied on head.
I have added a commitfest entry[1] for this feature.

[1] - https://commitfest.postgresql.org/28/2610/

On Tue, Jun 23, 2020 at 8:07 AM vignesh C <vignesh21@gmail.com> wrote:

Thanks Ashutosh For your review, my comments are inline.
On Fri, Jun 19, 2020 at 5:41 PM Ashutosh Sharma <ashu.coek88@gmail.com> wrote:

Hi,

I just got some time to review the first patch in the list i.e. 0001-Copy-code-readjustment-to-support-parallel-copy.patch. As the patch name suggests, it is just trying to reshuffle the existing code for COPY command here and there. There is no extra changes added in the patch as such, but still I do have some review comments, please have a look:

1) Can you please add some comments atop the new function PopulateAttributes() describing its functionality in detail. Further, this new function contains the code from BeginCopy() to set attribute level options used with COPY FROM such as FORCE_QUOTE, FORCE_NOT_NULL, FORCE_NULL etc. in cstate and along with that it also copies the code from BeginCopy() to set other infos such as client encoding type, encoding conversion etc. Hence, I think it would be good to give it some better name, basically something that matches with what actually it is doing.

There is no new code added in this function, some part of code from
BeginCopy was made in to a new function as this part of code will also
be required for the parallel copy workers before the workers start the
actual copy operation. This code was made into a function to avoid
duplication. Changed the function name to PopulateGlobalsForCopyFrom &
added few comments.

2) Again, the name for the new function CheckCopyFromValidity() doesn't look good to me. From the function name it appears as if it does the sanity check of the entire COPY FROM command, but actually it is just doing the sanity check for the target relation specified with COPY FROM. So, probably something like CheckTargetRelValidity would look more sensible, I think? TBH, I am not good at naming the functions so you can always ignore my suggestions about function and variable names :)

Changed as suggested.

3) Any reason for not making CheckCopyFromValidity as a macro instead of a new function. It is just doing the sanity check for the target relation.

I felt there is reasonable number of lines in the function & it is not
in performance intensive path, so I preferred function over macro.
Your thoughts?

4) Earlier in CopyReadLine() function while trying to clear the EOL marker from cstate->line_buf.data (copied data), we were not checking if the line read by CopyReadLineText() function is a header line or not, but I can see that your patch checks that before clearing the EOL marker. Any reason for this extra check?

If you see the caller of CopyReadLine, i.e. NextCopyFromRawFields does
nothing for the header line, server basically calls CopyReadLine
again, it is a kind of small optimization. Anyway server is not going
to do anything with header line, I felt no need to clear EOL marker
for header lines.
/* on input just throw the header line away */
if (cstate->cur_lineno == 0 && cstate->header_line)
{
cstate->cur_lineno++;
if (CopyReadLine(cstate))
return false; /* done */
}

cstate->cur_lineno++;

/* Actually read the line into memory here */
done = CopyReadLine(cstate);
I think no need to make a fix for this. Your thoughts?

5) I noticed the below spurious line removal in the patch.

@@ -3839,7 +3953,6 @@ static bool
CopyReadLine(CopyState cstate)
{
bool result;
-

Fixed.
I have attached the patch for the same with the fixes.
Thoughts?

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

#104Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Bharath Rupireddy (#103)
6 attachment(s)
Re: Parallel copy

On Wed, Jun 24, 2020 at 2:16 PM Bharath Rupireddy
<bharath.rupireddyforpostgres@gmail.com> wrote:

Hi,

It looks like the parsing of newly introduced "PARALLEL" option for
COPY FROM command has an issue(in the
0002-Framework-for-leader-worker-in-parallel-copy.patch),
Mentioning ....PARALLEL '4ar2eteid'); would pass with 4 workers since
atoi() is being used for converting string to integer which just
returns 4, ignoring other strings.

I used strtol(), added error checks and introduced the error "
improper use of argument to option "parallel"" for the above cases.

parallel '4ar2eteid');
ERROR: improper use of argument to option "parallel"
LINE 5: parallel '1\');

Along with the updated patch
0002-Framework-for-leader-worker-in-parallel-copy.patch, also
attaching all the latest patches from [1].

[1] - /messages/by-id/CALj2ACW94icER3WrWapon7JkcX8j0TGRue5ycWMTEvgA3X7fOg@mail.gmail.com

I'm sorry, I forgot to attach the patches. Here are the latest series
of patches.

With Regards,
Bharath Rupireddy.
EnterpriseDB: http://www.enterprisedb.com

Attachments:

0001-Copy-code-readjustment-to-support-parallel-copy.patchapplication/octet-stream; name=0001-Copy-code-readjustment-to-support-parallel-copy.patchDownload
From 4455d3e067bda56316bb292e5d010bdf40254fec Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Tue, 23 Jun 2020 06:49:22 +0530
Subject: [PATCH 1/6] Copy code readjustment to support parallel copy.

This patch has the copy code slightly readjusted so that the common code is
separated to functions/macros, these functions/macros will be used by the
workers in the parallel copy code of the upcoming patches. EOL removal is moved
from CopyReadLine to CopyReadLineText, this change was required because in case
of parallel copy the record identification and record updation is done in
CopyReadLineText, before record information is updated in shared memory the new
line characters should be removed.
---
 src/backend/commands/copy.c | 372 ++++++++++++++++++++++++++------------------
 1 file changed, 221 insertions(+), 151 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 6b1fd6d..65a504f 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -95,6 +95,9 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
+#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+#define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
+
 /*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
@@ -219,7 +222,6 @@ typedef struct CopyStateData
 	 * converts it.  Note: we guarantee that there is a \0 at
 	 * raw_buf[raw_buf_len].
 	 */
-#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
@@ -347,6 +349,88 @@ if (1) \
 	goto not_end_of_copy; \
 } else ((void) 0)
 
+/*
+ * CONVERT_TO_SERVER_ENCODING - convert contents to server encoding.
+ */
+#define CONVERT_TO_SERVER_ENCODING(cstate) \
+{ \
+	/* Done reading the line.  Convert it to server encoding. */ \
+	if (cstate->need_transcoding) \
+	{ \
+		char	   *cvt; \
+		cvt = pg_any_to_server(cstate->line_buf.data, \
+							   cstate->line_buf.len, \
+							   cstate->file_encoding); \
+		if (cvt != cstate->line_buf.data) \
+		{ \
+			/* transfer converted data back to line_buf */ \
+			resetStringInfo(&cstate->line_buf); \
+			appendBinaryStringInfo(&cstate->line_buf, cvt, strlen(cvt)); \
+			pfree(cvt); \
+		} \
+	} \
+	/* Now it's safe to use the buffer in error messages */ \
+	cstate->line_buf_converted = true; \
+}
+
+/*
+ * CLEAR_EOL_FROM_COPIED_DATA - Clear EOL from the copied data.
+ */
+#define CLEAR_EOL_FROM_COPIED_DATA(copy_line_data, copy_line_pos, copy_line_size) \
+{ \
+	/* \
+	 * If we didn't hit EOF, then we must have transferred the EOL marker \
+	 * to line_buf along with the data.  Get rid of it. \
+	 */ \
+   switch (cstate->eol_type) \
+   { \
+	   case EOL_NL: \
+		   Assert(copy_line_size >= 1); \
+		   Assert(copy_line_data[copy_line_pos - 1] == '\n'); \
+		   copy_line_data[copy_line_pos - 1] = '\0'; \
+		   copy_line_size--; \
+		   break; \
+	   case EOL_CR: \
+		   Assert(copy_line_size >= 1); \
+		   Assert(copy_line_data[copy_line_pos - 1] == '\r'); \
+		   copy_line_data[copy_line_pos - 1] = '\0'; \
+		   copy_line_size--; \
+		   break; \
+	   case EOL_CRNL: \
+		   Assert(copy_line_size >= 2); \
+		   Assert(copy_line_data[copy_line_pos - 2] == '\r'); \
+		   Assert(copy_line_data[copy_line_pos - 1] == '\n'); \
+		   copy_line_data[copy_line_pos - 2] = '\0'; \
+		   copy_line_size -= 2; \
+		   break; \
+	   case EOL_UNKNOWN: \
+		   /* shouldn't get here */ \
+		   Assert(false); \
+		   break; \
+   } \
+}
+
+/*
+ * CLEAR_EOL_LINE - Wrapper for clearing EOL.
+ */
+#define CLEAR_EOL_LINE() \
+if (!result && !IsHeaderLine()) \
+	CLEAR_EOL_FROM_COPIED_DATA(cstate->line_buf.data, \
+								cstate->line_buf.len, \
+								cstate->line_buf.len) \
+
+/*
+ * INCREMENTPROCESSED - Increment the lines processed.
+ */
+#define INCREMENTPROCESSED(processed)  \
+processed++;
+
+/*
+ * GETPROCESSED - Get the lines processed.
+ */
+#define GETPROCESSED(processed) \
+return processed;
+
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
 
@@ -392,6 +476,8 @@ static bool CopyGetInt32(CopyState cstate, int32 *val);
 static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 
+static void PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tup_desc,
+							   List *attnamelist);
 
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
@@ -793,6 +879,7 @@ CopyLoadRawBuf(CopyState cstate)
 {
 	int			nbytes;
 	int			inbytes;
+	int         minread = 1;
 
 	if (cstate->raw_buf_index < cstate->raw_buf_len)
 	{
@@ -804,8 +891,11 @@ CopyLoadRawBuf(CopyState cstate)
 	else
 		nbytes = 0;				/* no data need be saved */
 
+	if (cstate->copy_dest == COPY_NEW_FE)
+		minread = RAW_BUF_SIZE - nbytes;
+
 	inbytes = CopyGetData(cstate, cstate->raw_buf + nbytes,
-						  1, RAW_BUF_SIZE - nbytes);
+						  minread, RAW_BUF_SIZE - nbytes);
 	nbytes += inbytes;
 	cstate->raw_buf[nbytes] = '\0';
 	cstate->raw_buf_index = 0;
@@ -1463,7 +1553,6 @@ BeginCopy(ParseState *pstate,
 {
 	CopyState	cstate;
 	TupleDesc	tupDesc;
-	int			num_phys_attrs;
 	MemoryContext oldcontext;
 
 	/* Allocate workspace and zero all fields */
@@ -1629,6 +1718,24 @@ BeginCopy(ParseState *pstate,
 		tupDesc = cstate->queryDesc->tupDesc;
 	}
 
+	PopulateGlobalsForCopyFrom(cstate, tupDesc, attnamelist);
+	cstate->copy_dest = COPY_FILE;	/* default */
+
+	MemoryContextSwitchTo(oldcontext);
+
+	return cstate;
+}
+
+/*
+ * PopulateGlobalsForCopyFrom - Populates the common variables required for copy
+ * from operation. This is a helper function for BeginCopy function.
+ */
+static void
+PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tupDesc,
+							List *attnamelist)
+{
+	int			num_phys_attrs;
+
 	/* Generate or convert list of attributes to process */
 	cstate->attnumlist = CopyGetAttnums(tupDesc, cstate->rel, attnamelist);
 
@@ -1748,12 +1855,6 @@ BeginCopy(ParseState *pstate,
 		 pg_database_encoding_max_length() > 1);
 	/* See Multibyte encoding comment above */
 	cstate->encoding_embeds_ascii = PG_ENCODING_IS_CLIENT_ONLY(cstate->file_encoding);
-
-	cstate->copy_dest = COPY_FILE;	/* default */
-
-	MemoryContextSwitchTo(oldcontext);
-
-	return cstate;
 }
 
 /*
@@ -2646,32 +2747,11 @@ CopyMultiInsertInfoStore(CopyMultiInsertInfo *miinfo, ResultRelInfo *rri,
 }
 
 /*
- * Copy FROM file to relation.
+ * Check if the relation specified in copy from is valid.
  */
-uint64
-CopyFrom(CopyState cstate)
+static void
+CheckTargetRelValidity(CopyState cstate)
 {
-	ResultRelInfo *resultRelInfo;
-	ResultRelInfo *target_resultRelInfo;
-	ResultRelInfo *prevResultRelInfo = NULL;
-	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
-	ModifyTableState *mtstate;
-	ExprContext *econtext;
-	TupleTableSlot *singleslot = NULL;
-	MemoryContext oldcontext = CurrentMemoryContext;
-
-	PartitionTupleRouting *proute = NULL;
-	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
-	int			ti_options = 0; /* start with default options for insert */
-	BulkInsertState bistate = NULL;
-	CopyInsertMethod insertMethod;
-	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
-	uint64		processed = 0;
-	bool		has_before_insert_row_trig;
-	bool		has_instead_insert_row_trig;
-	bool		leafpart_use_multi_insert = false;
-
 	Assert(cstate->rel);
 
 	/*
@@ -2708,27 +2788,6 @@ CopyFrom(CopyState cstate)
 							RelationGetRelationName(cstate->rel))));
 	}
 
-	/*
-	 * If the target file is new-in-transaction, we assume that checking FSM
-	 * for free space is a waste of time.  This could possibly be wrong, but
-	 * it's unlikely.
-	 */
-	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
-		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
-		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
-		ti_options |= TABLE_INSERT_SKIP_FSM;
-
-	/*
-	 * Optimize if new relfilenode was created in this subxact or one of its
-	 * committed children and we won't see those rows later as part of an
-	 * earlier scan or command. The subxact test ensures that if this subxact
-	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
-	 * that the stronger test of exactly which subtransaction created it is
-	 * crucial for correctness of this optimization. The test for an earlier
-	 * scan or command tolerates false negatives. FREEZE causes other sessions
-	 * to see rows they would not see under MVCC, and a false negative merely
-	 * spreads that anomaly to the current session.
-	 */
 	if (cstate->freeze)
 	{
 		/*
@@ -2766,9 +2825,61 @@ CopyFrom(CopyState cstate)
 			ereport(ERROR,
 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 					 errmsg("cannot perform COPY FREEZE because the table was not created or truncated in the current subtransaction")));
+	}
+}
+
+/*
+ * Copy FROM file to relation.
+ */
+uint64
+CopyFrom(CopyState cstate)
+{
+	ResultRelInfo *resultRelInfo;
+	ResultRelInfo *target_resultRelInfo;
+	ResultRelInfo *prevResultRelInfo = NULL;
+	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
+	ModifyTableState *mtstate;
+	ExprContext *econtext;
+	TupleTableSlot *singleslot = NULL;
+	MemoryContext oldcontext = CurrentMemoryContext;
+
+	PartitionTupleRouting *proute = NULL;
+	ErrorContextCallback errcallback;
+	CommandId	mycid = GetCurrentCommandId(true);
+	int			ti_options = 0; /* start with default options for insert */
+	BulkInsertState bistate = NULL;
+	CopyInsertMethod insertMethod;
+	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
+	uint64		processed = 0;
+	bool		has_before_insert_row_trig;
+	bool		has_instead_insert_row_trig;
+	bool		leafpart_use_multi_insert = false;
+
+	CheckTargetRelValidity(cstate);
 
+	/*
+	 * If the target file is new-in-transaction, we assume that checking FSM
+	 * for free space is a waste of time.  This could possibly be wrong, but
+	 * it's unlikely.
+	 */
+	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
+		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
+		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
+		ti_options |= TABLE_INSERT_SKIP_FSM;
+
+	/*
+	 * Optimize if new relfilenode was created in this subxact or one of its
+	 * committed children and we won't see those rows later as part of an
+	 * earlier scan or command. The subxact test ensures that if this subxact
+	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
+	 * that the stronger test of exactly which subtransaction created it is
+	 * crucial for correctness of this optimization. The test for an earlier
+	 * scan or command tolerates false negatives. FREEZE causes other sessions
+	 * to see rows they would not see under MVCC, and a false negative merely
+	 * spreads that anomaly to the current session.
+	 */
+	if (cstate->freeze)
 		ti_options |= TABLE_INSERT_FROZEN;
-	}
 
 	/*
 	 * We need a ResultRelInfo so we can use the regular executor's
@@ -3261,7 +3372,7 @@ CopyFrom(CopyState cstate)
 			 * or FDW; this is the same definition used by nodeModifyTable.c
 			 * for counting tuples inserted by an INSERT command.
 			 */
-			processed++;
+			INCREMENTPROCESSED(processed)
 		}
 	}
 
@@ -3316,30 +3427,15 @@ CopyFrom(CopyState cstate)
 
 	FreeExecutorState(estate);
 
-	return processed;
+	GETPROCESSED(processed)
 }
 
 /*
- * Setup to read tuples from a file for COPY FROM.
- *
- * 'rel': Used as a template for the tuples
- * 'filename': Name of server-local file to read
- * 'attnamelist': List of char *, columns to include. NIL selects all cols.
- * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
- *
- * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ * PopulateCatalogInformation - populate the catalog information.
  */
-CopyState
-BeginCopyFrom(ParseState *pstate,
-			  Relation rel,
-			  const char *filename,
-			  bool is_program,
-			  copy_data_source_cb data_source_cb,
-			  List *attnamelist,
-			  List *options)
+static void
+PopulateCatalogInformation(CopyState cstate)
 {
-	CopyState	cstate;
-	bool		pipe = (filename == NULL);
 	TupleDesc	tupDesc;
 	AttrNumber	num_phys_attrs,
 				num_defaults;
@@ -3349,31 +3445,8 @@ BeginCopyFrom(ParseState *pstate,
 	Oid			in_func_oid;
 	int		   *defmap;
 	ExprState **defexprs;
-	MemoryContext oldcontext;
 	bool		volatile_defexprs;
 
-	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
-	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
-
-	/* Initialize state variables */
-	cstate->reached_eof = false;
-	cstate->eol_type = EOL_UNKNOWN;
-	cstate->cur_relname = RelationGetRelationName(cstate->rel);
-	cstate->cur_lineno = 0;
-	cstate->cur_attname = NULL;
-	cstate->cur_attval = NULL;
-
-	/* Set up variables to avoid per-attribute overhead. */
-	initStringInfo(&cstate->attribute_buf);
-	initStringInfo(&cstate->line_buf);
-	cstate->line_buf_converted = false;
-	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
-	cstate->raw_buf_index = cstate->raw_buf_len = 0;
-
-	/* Assign range table, we'll need it in CopyFrom. */
-	if (pstate)
-		cstate->range_table = pstate->p_rtable;
-
 	tupDesc = RelationGetDescr(cstate->rel);
 	num_phys_attrs = tupDesc->natts;
 	num_defaults = 0;
@@ -3451,6 +3524,54 @@ BeginCopyFrom(ParseState *pstate,
 	cstate->defexprs = defexprs;
 	cstate->volatile_defexprs = volatile_defexprs;
 	cstate->num_defaults = num_defaults;
+}
+
+/*
+ * Setup to read tuples from a file for COPY FROM.
+ *
+ * 'rel': Used as a template for the tuples
+ * 'filename': Name of server-local file to read
+ * 'attnamelist': List of char *, columns to include. NIL selects all cols.
+ * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
+ *
+ * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ */
+CopyState
+BeginCopyFrom(ParseState *pstate,
+			  Relation rel,
+			  const char *filename,
+			  bool is_program,
+			  copy_data_source_cb data_source_cb,
+			  List *attnamelist,
+			  List *options)
+{
+	CopyState	cstate;
+	bool		pipe = (filename == NULL);
+	MemoryContext oldcontext;
+
+	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	/* Initialize state variables */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/* Set up variables to avoid per-attribute overhead. */
+	initStringInfo(&cstate->attribute_buf);
+	initStringInfo(&cstate->line_buf);
+	cstate->line_buf_converted = false;
+	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+
+	/* Assign range table, we'll need it in CopyFrom. */
+	if (pstate)
+		cstate->range_table = pstate->p_rtable;
+
+	PopulateCatalogInformation(cstate);
 	cstate->is_program = is_program;
 
 	if (data_source_cb)
@@ -3860,60 +3981,8 @@ CopyReadLine(CopyState cstate)
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
-	else
-	{
-		/*
-		 * If we didn't hit EOF, then we must have transferred the EOL marker
-		 * to line_buf along with the data.  Get rid of it.
-		 */
-		switch (cstate->eol_type)
-		{
-			case EOL_NL:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CR:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\r');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CRNL:
-				Assert(cstate->line_buf.len >= 2);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 2] == '\r');
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len -= 2;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_UNKNOWN:
-				/* shouldn't get here */
-				Assert(false);
-				break;
-		}
-	}
-
-	/* Done reading the line.  Convert it to server encoding. */
-	if (cstate->need_transcoding)
-	{
-		char	   *cvt;
-
-		cvt = pg_any_to_server(cstate->line_buf.data,
-							   cstate->line_buf.len,
-							   cstate->file_encoding);
-		if (cvt != cstate->line_buf.data)
-		{
-			/* transfer converted data back to line_buf */
-			resetStringInfo(&cstate->line_buf);
-			appendBinaryStringInfo(&cstate->line_buf, cvt, strlen(cvt));
-			pfree(cvt);
-		}
-	}
-
-	/* Now it's safe to use the buffer in error messages */
-	cstate->line_buf_converted = true;
 
+	CONVERT_TO_SERVER_ENCODING(cstate)
 	return result;
 }
 
@@ -4277,6 +4346,7 @@ not_end_of_copy:
 	 * Transfer any still-uncopied data to line_buf.
 	 */
 	REFILL_LINEBUF;
+	CLEAR_EOL_LINE()
 
 	return result;
 }
-- 
1.8.3.1

0002-Framework-for-leader-worker-in-parallel-copy.patchapplication/octet-stream; name=0002-Framework-for-leader-worker-in-parallel-copy.patchDownload
From d8e1447263289fe2ad5ed40f620ab00b5f0bd407 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddy@enterprisedb.com>
Date: Wed, 24 Jun 2020 13:51:56 +0530
Subject: [PATCH 2/6] Framework for leader/worker in parallel copy

This patch has the framework for data structures in parallel copy, leader
initialization, worker initialization, shared memory updation, starting workers,
wait for workers and workers exiting.
---
 src/backend/access/transam/parallel.c       |   4 +
 src/backend/commands/copy.c                 | 865 +++++++++++++++++++-
 src/backend/replication/logical/tablesync.c |   2 +-
 src/include/commands/copy.h                 |   4 +
 src/tools/pgindent/typedefs.list            |   8 +
 5 files changed, 878 insertions(+), 5 deletions(-)

diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index 14a8690019..09e7a191d3 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -25,6 +25,7 @@
 #include "catalog/pg_enum.h"
 #include "catalog/storage.h"
 #include "commands/async.h"
+#include "commands/copy.h"
 #include "executor/execParallel.h"
 #include "libpq/libpq.h"
 #include "libpq/pqformat.h"
@@ -145,6 +146,9 @@ static const struct
 	},
 	{
 		"parallel_vacuum_main", parallel_vacuum_main
+	},
+	{
+		"ParallelCopyMain", ParallelCopyMain
 	}
 };
 
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 65a504fe96..c906655d0b 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -96,8 +96,137 @@ typedef enum CopyInsertMethod
 } CopyInsertMethod;
 
 #define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+
+#define DATA_BLOCK_SIZE RAW_BUF_SIZE
+#define RINGSIZE (10 * 1000)
+#define MAX_BLOCKS_COUNT 1000
+#define WORKER_CHUNK_COUNT 50	/* should be mod of RINGSIZE */
+
+#define	IsParallelCopy()		(cstate->is_parallel)
+#define IsLeader()				(cstate->pcdata->is_leader)
 #define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
 
+/*
+ * Copy data block information.
+ */
+typedef struct ParallelCopyDataBlock
+{
+	/* The number of unprocessed lines in the current block. */
+	pg_atomic_uint32 unprocessed_line_parts;
+
+	/*
+	 * If the current line data is continued into another block, following_block
+	 * will have the position where the remaining data need to be read.
+	 */
+	uint32	following_block;
+
+	/*
+	 * This flag will be set, when the leader finds out this block can be read
+	 * safely by the worker. This helps the worker to start processing the line
+	 * early where the line will be spread across many blocks and the worker
+	 * need not wait for the complete line to be processed.
+	 */
+	bool   curr_blk_completed;
+	char   data[DATA_BLOCK_SIZE]; /* data read from file */
+	uint8  skip_bytes;
+}ParallelCopyDataBlock;
+
+/*
+ * Individual line information.
+ * ParallelCopyLineBoundary is common data structure between leader & worker,
+ * this is protected by the following sequence in the leader & worker.
+ * Leader should operate in the following order:
+ * 1) update first_block, start_offset & cur_lineno in any order.
+ * 2) update line_size.
+ * 3) update line_state.
+ * Worker should operate in the following order:
+ * 1) read line_size.
+ * 2) only one worker should choose one line for processing, this is handled by
+ *    using pg_atomic_compare_exchange_u32, worker will change the sate to
+ *    LINE_WORKER_PROCESSING only if line_state is LINE_LEADER_POPULATED.
+ * 3) read first_block, start_offset & cur_lineno in any order.
+ */
+typedef struct ParallelCopyLineBoundary
+{
+	/* Position of the first block in data_blocks array. */
+	uint32				first_block;
+	uint32				start_offset;   /* start offset of the line */
+
+	/*
+	 * Size of the current line -1 means line is yet to be filled completely,
+	 * 0 means empty line, >0 means line filled with line size data.
+	 */
+	pg_atomic_uint32	line_size;
+	pg_atomic_uint32	line_state;		/* line state */
+	uint64				cur_lineno;		/* line number for error messages */
+}ParallelCopyLineBoundary;
+
+/*
+ * Circular queue used to store the line information.
+ */
+typedef struct ParallelCopyLineBoundaries
+{
+	/* Position for the leader to populate a line. */
+	uint32			leader_pos;
+
+	/* Data read from the file/stdin by the leader process. */
+	ParallelCopyLineBoundary	ring[RINGSIZE];
+}ParallelCopyLineBoundaries;
+
+/*
+ * Shared information among parallel copy workers. This will be allocated in the
+ * DSM segment.
+ */
+typedef struct ParallelCopyShmInfo
+{
+	bool					is_read_in_progress; /* file read status */
+
+	/*
+	 * Actual lines inserted by worker (some records will be filtered based on
+	 * where condition).
+	 */
+	pg_atomic_uint64			processed;
+	pg_atomic_uint64			total_worker_processed; /* total processed records by the workers */
+	uint64						populated; /* lines populated by leader */
+	uint32						cur_block_pos; /* current data block */
+	ParallelCopyDataBlock		data_blocks[MAX_BLOCKS_COUNT]; /* data block array */
+	FullTransactionId			full_transaction_id; /* xid for copy from statement */
+	CommandId					mycid;	/* command id */
+	ParallelCopyLineBoundaries	line_boundaries; /* line array */
+} ParallelCopyShmInfo;
+
+/*
+ * Parallel copy line buffer information.
+ */
+typedef struct ParallelCopyLineBuf
+{
+	StringInfoData		line_buf;
+	uint64				cur_lineno;	/* line number for error messages */
+}ParallelCopyLineBuf;
+
+/*
+ * Parallel copy data information.
+ */
+typedef struct ParallelCopyData
+{
+	Oid					relid;				/* relation id of the table */
+	ParallelCopyShmInfo	*pcshared_info;		/* common info in shared memory */
+	bool				is_leader;
+
+	/* line position which worker is processing */
+	uint32				worker_processed_pos;
+
+	/*
+	 * Local line_buf array, workers will copy it here and release the lines
+	 * for the leader to continue.
+	 */
+	ParallelCopyLineBuf	worker_line_buf[WORKER_CHUNK_COUNT];
+	uint32				worker_line_buf_count; /* Number of lines */
+
+	/* Current position in worker_line_buf */
+	uint32				worker_line_buf_pos;
+}ParallelCopyData;
+
 /*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
@@ -225,8 +354,66 @@ typedef struct CopyStateData
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
+	int			nworkers;
+	bool		is_parallel;
+	ParallelCopyData *pcdata;
 } CopyStateData;
 
+/*
+ * This structure helps in storing the common data from CopyStateData that are
+ * required by the workers. This information will then be allocated and stored
+ * into the DSM for the worker to retrieve and copy it to CopyStateData.
+ */
+typedef struct ParallelCopyCommonKeyData
+{
+	/* low-level state data */
+	CopyDest            copy_dest;		/* type of copy source/destination */
+	int                 file_encoding;	/* file or remote side's character encoding */
+	bool                need_transcoding;	/* file encoding diff from server? */
+	bool                encoding_embeds_ascii;	/* ASCII can be non-first byte? */
+
+	/* parameters from the COPY command */
+	bool                csv_mode;		/* Comma Separated Value format? */
+	bool                header_line;	/* CSV header line? */
+	int                 null_print_len; /* length of same */
+	bool                force_quote_all;	/* FORCE_QUOTE *? */
+	bool                convert_selectively;	/* do selective binary conversion? */
+
+	/* Working state for COPY FROM */
+	AttrNumber          num_defaults;
+	Oid                 relid;
+}ParallelCopyCommonKeyData;
+
+/*
+ * This structure will help in converting a List data type into the below
+ * structure format with the count having the number of elements in the list and
+ * the info having the List elements appended contigously. This converted
+ * structure will be allocated in shared memory and stored in DSM for the worker
+ * to retrieve and later convert it back to List data type.
+ */
+typedef struct ParallelCopyKeyListInfo
+{
+	int	count;		/* count of attributes */
+
+	/* string info in the form info followed by info1, info2... infon  */
+	char    info[1];
+} ParallelCopyKeyListInfo;
+
+/*
+ * List of internal parallel copy function pointers.
+ */
+static const struct
+{
+	char *fn_name;
+	copy_data_source_cb fn_addr;
+}			InternalParallelCopyFuncPtrs[] =
+
+{
+	{
+		"copy_read_data", copy_read_data
+	},
+};
+
 /* DestReceiver for COPY (query) TO */
 typedef struct
 {
@@ -256,6 +443,23 @@ typedef struct
 /* Trim the list of buffers back down to this number after flushing */
 #define MAX_PARTITION_BUFFERS	32
 
+/* DSM keys for parallel copy.  */
+#define PARALLEL_COPY_KEY_SHARED_INFO		    1
+#define PARALLEL_COPY_KEY_CSTATE				2
+#define PARALLEL_COPY_KEY_NULL_PRINT			3
+#define PARALLEL_COPY_KEY_NULL_PRINT_CLIENT		4
+#define PARALLEL_COPY_KEY_DELIM					5
+#define PARALLEL_COPY_KEY_QUOTE					6
+#define PARALLEL_COPY_KEY_ESCAPE				7
+#define PARALLEL_COPY_KEY_ATTNAME_LIST			8
+#define PARALLEL_COPY_KEY_FORCE_QUOTE_LIST  	9
+#define PARALLEL_COPY_KEY_NOT_NULL_LIST		   10
+#define PARALLEL_COPY_KEY_NULL_LIST			   11
+#define PARALLEL_COPY_KEY_CONVERT_LIST		   12
+#define PARALLEL_COPY_KEY_DATASOURCE_CB		   13
+#define PARALLEL_COPY_KEY_WHERE_CLAUSE_STR     14
+#define PARALLEL_COPY_KEY_RANGE_TABLE		   15
+
 /* Stores multi-insert data related to a single relation in CopyFrom. */
 typedef struct CopyMultiInsertBuffer
 {
@@ -476,9 +680,595 @@ static bool CopyGetInt32(CopyState cstate, int32 *val);
 static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 
+static pg_attribute_always_inline void EndParallelCopy(ParallelContext *pcxt);
 static void PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tup_desc,
 							   List *attnamelist);
+static pg_attribute_always_inline copy_data_source_cb LookupParallelCopyFnPtr(const char *funcname);
+static pg_attribute_always_inline char* LookupParallelCopyFnStr(copy_data_source_cb fn_addr);
+
+/*
+ * CopyCommonInfoForWorker - Copy shared_cstate using cstate information.
+ */
+static pg_attribute_always_inline void
+CopyCommonInfoForWorker(CopyState cstate, ParallelCopyCommonKeyData *shared_cstate)
+{
+	shared_cstate->copy_dest = cstate->copy_dest;
+	shared_cstate->file_encoding = cstate->file_encoding;
+	shared_cstate->need_transcoding = cstate->need_transcoding;
+	shared_cstate->encoding_embeds_ascii = cstate->encoding_embeds_ascii;
+	shared_cstate->csv_mode = cstate->csv_mode;
+	shared_cstate->header_line = cstate->header_line;
+	shared_cstate->null_print_len = cstate->null_print_len;
+	shared_cstate->force_quote_all = cstate->force_quote_all;
+	shared_cstate->convert_selectively = cstate->convert_selectively;
+	shared_cstate->num_defaults = cstate->num_defaults;
+	shared_cstate->relid = cstate->pcdata->relid;
+}
+
+/*
+ * RetrieveSharedString - Retrieve the string from shared memory.
+ */
+static void
+RetrieveSharedString(shm_toc *toc, int sharedkey, char **copystr)
+{
+	char *shared_str_val = (char *)shm_toc_lookup(toc, sharedkey, true);
+	if (shared_str_val)
+		*copystr = pstrdup(shared_str_val);
+}
+
+/*
+ * RetrieveSharedList - Retrieve the list from shared memory.
+ */
+static void
+RetrieveSharedList(shm_toc *toc, int sharedkey, List **copylist)
+{
+	ParallelCopyKeyListInfo *listinformation = (ParallelCopyKeyListInfo *)shm_toc_lookup(toc, sharedkey,
+														   true);
+	if (listinformation)
+	{
+		int	length  = 0;
+		int count;
+
+		for (count = 0; count < listinformation->count; count++)
+		{
+			char *attname = (char *)(listinformation->info + length);
+			length += strlen(attname) + 1;
+			*copylist = lappend(*copylist, makeString(attname));
+		}
+	}
+}
+
+/*
+ * CopyListSharedMemory - Copy the list into shared memory.
+ */
+static void
+CopyListSharedMemory(List *inputlist, Size memsize, ParallelCopyKeyListInfo *sharedlistinfo)
+{
+	ListCell   *l;
+	int			length  = 0;
+
+	MemSet(sharedlistinfo, 0, memsize);
+	foreach(l, inputlist)
+	{
+		char	   *name = strVal(lfirst(l));
+		memcpy((char *)(sharedlistinfo->info + length), name, strlen(name));
+		sharedlistinfo->count++;
+		length += strlen(name) + 1;
+	}
+}
+
+/*
+ * ComputeListSize - compute the list size.
+ */
+static int
+ComputeListSize(List *inputlist)
+{
+	int est_size = sizeof(int);
+	if (inputlist != NIL)
+	{
+		ListCell   *l;
+		foreach(l, inputlist)
+			est_size += strlen(strVal(lfirst(l))) + 1;
+	}
+
+	return est_size;
+}
+
+/*
+ * EstimateLineKeysStr - Estimate the size required in shared memory for the
+ * input string.
+ */
+static void
+EstimateLineKeysStr(ParallelContext *pcxt, char *inputstr)
+{
+	if (inputstr)
+	{
+		shm_toc_estimate_chunk(&pcxt->estimator, strlen(inputstr) + 1);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+}
+
+/*
+ * EstimateLineKeysList - Estimate the size required in shared memory for the
+ * input list.
+ */
+static void
+EstimateLineKeysList(ParallelContext *pcxt, List *inputlist,
+		Size *est_list_size)
+{
+	if (inputlist != NIL)
+	{
+		*est_list_size = ComputeListSize(inputlist);
+		shm_toc_estimate_chunk(&pcxt->estimator, *est_list_size);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+}
 
+/*
+ * InsertStringShm - Insert a string into shared memory.
+ */
+static void
+InsertStringShm(ParallelContext *pcxt, int key, char *inputstr)
+{
+	if (inputstr)
+	{
+		char *shmptr = (char *)shm_toc_allocate(pcxt->toc,
+												strlen(inputstr) + 1);
+		strcpy(shmptr, inputstr);
+		shm_toc_insert(pcxt->toc, key, shmptr);
+	}
+}
+
+/*
+ * InsertListShm - Insert a list into shared memory.
+ */
+static void
+InsertListShm(ParallelContext *pcxt, int key, List *inputlist,
+			  Size est_list_size)
+{
+	if (inputlist != NIL)
+	{
+		ParallelCopyKeyListInfo *sharedlistinfo = (ParallelCopyKeyListInfo *)shm_toc_allocate(pcxt->toc,
+																est_list_size);
+		CopyListSharedMemory(inputlist, est_list_size, sharedlistinfo);
+		shm_toc_insert(pcxt->toc, key, sharedlistinfo);
+	}
+}
+
+/*
+ * BeginParallelCopy - start parallel copy tasks.
+ *
+ * Get the number of workers required to perform the parallel copy. The data
+ * structures that are required by the parallel workers will be initialized, the
+ * size required in DSM will be calculated and the necessary keys will be loaded
+ * in the DSM. The specified number of workers will then be launched.
+ *
+ */
+static ParallelContext*
+BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
+{
+	ParallelContext *pcxt;
+	ParallelCopyShmInfo *shared_info_ptr;
+	ParallelCopyCommonKeyData *shared_cstate;
+	FullTransactionId full_transaction_id;
+	Size est_shared_info;
+	Size est_cstateshared;
+	Size est_att_list_size;
+	Size est_quote_list_size;
+	Size est_notnull_list_size;
+	Size est_null_list_size;
+	Size est_convert_list_size;
+	Size est_datasource_cb_size;
+	int  count = 0;
+	char *whereClauseStr = NULL;
+	char *rangeTableStr = NULL;
+	int  parallel_workers = 0;
+	ParallelCopyData *pcdata;
+
+	parallel_workers = Min(nworkers, max_worker_processes);
+
+	/* Can't perform copy in parallel */
+	if (parallel_workers <= 0)
+	{
+		elog(WARNING,
+			 "No workers available, copy will be run in non-parallel mode");
+		return NULL;
+	}
+
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	cstate->pcdata = pcdata;
+
+	EnterParallelMode();
+	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
+								 parallel_workers);
+	Assert(pcxt->nworkers > 0);
+
+	/*
+	 * Estimate size for shared information for PARALLEL_COPY_KEY_SHARED_INFO
+	 */
+	est_shared_info = sizeof(ParallelCopyShmInfo);
+	shm_toc_estimate_chunk(&pcxt->estimator, est_shared_info);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_CSTATE */
+	est_cstateshared = 	MAXALIGN(sizeof(ParallelCopyCommonKeyData));
+	shm_toc_estimate_chunk(&pcxt->estimator, est_cstateshared);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	EstimateLineKeysStr(pcxt, cstate->null_print);
+	EstimateLineKeysStr(pcxt, cstate->null_print_client);
+	EstimateLineKeysStr(pcxt, cstate->delim);
+	EstimateLineKeysStr(pcxt, cstate->quote);
+	EstimateLineKeysStr(pcxt, cstate->escape);
+
+	if (cstate->whereClause != NULL)
+	{
+		whereClauseStr = nodeToString(cstate->whereClause);
+		EstimateLineKeysStr(pcxt, whereClauseStr);
+	}
+
+	if (cstate->range_table != NULL)
+	{
+		rangeTableStr = nodeToString(cstate->range_table);
+		EstimateLineKeysStr(pcxt, rangeTableStr);
+	}
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_XID. */
+	shm_toc_estimate_chunk(&pcxt->estimator, sizeof(FullTransactionId));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_ATTNAME_LIST.
+	 */
+	EstimateLineKeysList(pcxt, attnamelist, &est_att_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_FORCE_QUOTE_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->force_quote, &est_quote_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_NOT_NULL_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->force_notnull,
+							 &est_notnull_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_NULL_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->force_null, &est_null_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_CONVERT_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->convert_select,
+							 &est_convert_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_DATASOURCE_CB.
+	 */
+	if (cstate->data_source_cb)
+	{
+		char *functionname = LookupParallelCopyFnStr(cstate->data_source_cb);
+		est_datasource_cb_size = strlen(functionname) + 1;
+		shm_toc_estimate_chunk(&pcxt->estimator, est_datasource_cb_size);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+
+	InitializeParallelDSM(pcxt);
+
+	/* If no DSM segment was available, back out (do serial copy) */
+	if (pcxt->seg == NULL)
+	{
+		EndParallelCopy(pcxt);
+		elog(WARNING,
+			 "DSM segments not available, copy will be run in non-parallel mode");
+		return NULL;
+	}
+
+	/* Allocate shared memory for PARALLEL_COPY_KEY_SHARED_INFO */
+	shared_info_ptr = (ParallelCopyShmInfo *) shm_toc_allocate(pcxt->toc,
+													   est_shared_info);
+	MemSet(shared_info_ptr, 0, est_shared_info);
+	shared_info_ptr->is_read_in_progress = true;
+	shared_info_ptr->cur_block_pos = -1;
+	shared_info_ptr->full_transaction_id = full_transaction_id;
+	shared_info_ptr->mycid = GetCurrentCommandId(true);
+	for (count = 0; count < RINGSIZE; count++)
+	{
+		ParallelCopyLineBoundary *lineInfo = &shared_info_ptr->line_boundaries.ring[count];
+		pg_atomic_init_u32(&(lineInfo->line_size), -1);
+	}
+
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_SHARED_INFO, shared_info_ptr);
+	pcdata->pcshared_info = shared_info_ptr;
+	pcdata->relid = relid;
+
+	/* Store shared build state, for which we reserved space. */
+	shared_cstate = (ParallelCopyCommonKeyData *)shm_toc_allocate(pcxt->toc,
+															est_cstateshared);
+
+	/* copy cstate variables. */
+	CopyCommonInfoForWorker(cstate, shared_cstate);
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_CSTATE, shared_cstate);
+
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_NULL_PRINT, cstate->null_print);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_NULL_PRINT_CLIENT,
+					  cstate->null_print_client);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_DELIM, cstate->delim);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_QUOTE, cstate->quote);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_ESCAPE, cstate->escape);
+
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_ATTNAME_LIST,
+					attnamelist, est_att_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_FORCE_QUOTE_LIST,
+					cstate->force_quote, est_quote_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_NOT_NULL_LIST,
+					cstate->force_notnull, est_notnull_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_NULL_LIST, cstate->force_null,
+					est_null_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_CONVERT_LIST,
+					cstate->convert_select, est_convert_list_size);
+
+	if (cstate->data_source_cb)
+	{
+		char *functionname = LookupParallelCopyFnStr(cstate->data_source_cb);
+		char *data_source_cb = (char *) shm_toc_allocate(pcxt->toc,
+														 est_datasource_cb_size);
+		strcpy(data_source_cb, functionname);
+		shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_DATASOURCE_CB,
+					   data_source_cb);
+	}
+
+	if (cstate->whereClause)
+		InsertStringShm(pcxt, PARALLEL_COPY_KEY_WHERE_CLAUSE_STR,
+						whereClauseStr);
+
+	if(cstate->range_table)
+		InsertStringShm(pcxt, PARALLEL_COPY_KEY_RANGE_TABLE, rangeTableStr);
+
+	LaunchParallelWorkers(pcxt);
+	if (pcxt->nworkers_launched == 0)
+	{
+		EndParallelCopy(pcxt);
+		elog(WARNING,
+			 "No workers available, copy will be run in non-parallel mode");
+		return NULL;
+	}
+
+	/*
+	 * Caller needs to wait for all launched workers when we return.  Make sure
+	 * that the failure-to-start case will not hang forever.
+	 */
+	WaitForParallelWorkersToAttach(pcxt);
+
+	pcdata->is_leader = true;
+	cstate->is_parallel = true;
+	return pcxt;
+}
+
+/*
+ * EndParallelCopy - end the parallel copy tasks.
+ */
+static pg_attribute_always_inline void
+EndParallelCopy(ParallelContext *pcxt)
+{
+	Assert(!IsParallelWorker());
+
+	DestroyParallelContext(pcxt);
+	ExitParallelMode();
+}
+
+/*
+ * ParallelWorkerInitialization - Initialize parallel worker.
+ */
+static void
+ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
+		CopyState cstate, List *attnamelist)
+{
+	uint32		count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	cstate->copy_dest = shared_cstate->copy_dest;
+	cstate->file_encoding = shared_cstate->file_encoding;
+	cstate->need_transcoding = shared_cstate->need_transcoding;
+	cstate->encoding_embeds_ascii = shared_cstate->encoding_embeds_ascii;
+	cstate->csv_mode = shared_cstate->csv_mode;
+	cstate->header_line = shared_cstate->header_line;
+	cstate->null_print_len = shared_cstate->null_print_len;
+	cstate->force_quote_all = shared_cstate->force_quote_all;
+	cstate->convert_selectively = shared_cstate->convert_selectively;
+	cstate->num_defaults = shared_cstate->num_defaults;
+	pcdata->relid = shared_cstate->relid;
+
+	PopulateGlobalsForCopyFrom(cstate, tup_desc, attnamelist);
+
+	/* Initialize state variables. */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/* Set up variables to avoid per-attribute overhead. */
+	initStringInfo(&cstate->attribute_buf);
+
+	initStringInfo(&cstate->line_buf);
+	for (count = 0; count < WORKER_CHUNK_COUNT;count++)
+		initStringInfo(&pcdata->worker_line_buf[count].line_buf);
+
+	cstate->line_buf_converted = false;
+	cstate->raw_buf = NULL;
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+}
+/*
+ * ParallelCopyMain - parallel copy worker's code.
+ *
+ * Where clause handling, convert tuple to columns, add default null values for
+ * the missing columns that are not present in that record. Find the partition
+ * if it is partitioned table, invoke before row insert Triggers, handle
+ * constraints and insert the tuples.
+ */
+void
+ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
+{
+	CopyState cstate;
+	ParallelCopyData *pcdata;
+	ParallelCopyShmInfo *pcshared_info;
+	ParallelCopyCommonKeyData *shared_cstate;
+	Relation	rel = NULL;
+	MemoryContext oldcontext;
+	List *attlist = NIL;
+	char *data_source_cb;
+	char *whereClauseStr = NULL;
+	char *rangeTableStr = NULL;
+
+	/* Allocate workspace and zero all fields. */
+	cstate = (CopyStateData *) palloc0(sizeof(CopyStateData));
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	cstate->pcdata = pcdata;
+	pcdata->is_leader = false;
+	pcdata->worker_processed_pos = -1;
+	cstate->is_parallel = true;
+
+	/*
+	 * We allocate everything used by a cstate in a new memory context. This
+	 * avoids memory leaks during repeated use of COPY in a query.
+	 */
+	cstate->copycontext = AllocSetContextCreate(CurrentMemoryContext,
+												"COPY",
+												ALLOCSET_DEFAULT_SIZES);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	pcshared_info = (ParallelCopyShmInfo *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_SHARED_INFO,
+														false);
+
+	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
+
+	pcdata->pcshared_info = pcshared_info;
+
+	shared_cstate = (ParallelCopyCommonKeyData *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE,
+														   false);
+
+	cstate->null_print = (char *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_NULL_PRINT,
+												true);
+	cstate->null_print_client = (char *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_NULL_PRINT_CLIENT,
+													   true);
+
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_DELIM, &cstate->delim);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_QUOTE, &cstate->quote);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_ESCAPE, &cstate->escape);
+
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_ATTNAME_LIST, &attlist);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_FORCE_QUOTE_LIST, &cstate->force_quote);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_NOT_NULL_LIST, &cstate->force_notnull);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_NULL_LIST, &cstate->force_null);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_CONVERT_LIST, &cstate->convert_select);
+	data_source_cb = (char *)shm_toc_lookup(toc,
+											PARALLEL_COPY_KEY_DATASOURCE_CB,
+											true);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_WHERE_CLAUSE_STR, &whereClauseStr);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_RANGE_TABLE, &rangeTableStr);
+
+	if (data_source_cb)
+		cstate->data_source_cb = LookupParallelCopyFnPtr(data_source_cb);
+
+	if (whereClauseStr)
+	{
+		Node *whereClauseCnvrtdFrmStr = (Node *) stringToNode(whereClauseStr);
+		cstate->whereClause = whereClauseCnvrtdFrmStr;
+	}
+
+	if (rangeTableStr)
+	{
+		List *rangeTableCnvrtdFrmStr = (List *) stringToNode(rangeTableStr);
+		cstate->range_table = rangeTableCnvrtdFrmStr;
+	}
+
+	/* Open and lock the relation, using the appropriate lock type. */
+	rel = table_open(shared_cstate->relid, RowExclusiveLock);
+	cstate->rel = rel;
+	ParallelWorkerInitialization(shared_cstate, cstate, attlist);
+
+	CopyFrom(cstate);
+
+	if (rel != NULL)
+		table_close(rel, RowExclusiveLock);
+
+	MemoryContextSwitchTo(oldcontext);
+	return;
+}
+/*
+ * ParallelCopyLeader - parallel copy leader's functionality.
+ *
+ * Leader will populate the shared memory and share it across the workers.
+ * Leader will read the table data from the file and copy the contents to block.
+ * Leader will then read the input contents and identify the data based on line
+ * beaks. This information is called line. The line will be populate in
+ * ParallelCopyLineBoundary. Workers will then pick up this information and
+ * insert in to table. Leader will do this till it completes processing the
+ * file. Leader executes the before statement if before statement trigger is
+ * present. Leader read the data from input file. Leader then loads data to data
+ * blocks as and when required block by block. Leader traverses through the data
+ * block to identify one line. It gets a free line to copy the information, if
+ * there is no free line it will wait till there is one free line.
+ * Server copies  the identified lines information into lines. This process is
+ * repeated till the complete file is processed.
+ * Leader will wait till all the lines populated are processed by the workers
+ * and exits.
+ */
+static void
+ParallelCopyLeader(CopyState cstate)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
+
+	pcshared_info->is_read_in_progress = false;
+	cstate->cur_lineno = 0;
+}
+/*
+ * LookupParallelCopyFnPtr - Look up parallel copy function pointer.
+ */
+static pg_attribute_always_inline copy_data_source_cb
+LookupParallelCopyFnPtr(const char *funcname)
+{
+	int			i;
+
+	for (i = 0; i < lengthof(InternalParallelCopyFuncPtrs); i++)
+	{
+		if (strcmp(InternalParallelCopyFuncPtrs[i].fn_name, funcname) == 0)
+			return InternalParallelCopyFuncPtrs[i].fn_addr;
+	}
+
+	/* We can only reach this by programming error. */
+	elog(ERROR, "internal function \"%s\" not found", funcname);
+}
+
+/*
+ * LookupParallelCopyFnStr - Lookup function string from a function pointer.
+ */
+static pg_attribute_always_inline char*
+LookupParallelCopyFnStr(copy_data_source_cb fn_addr)
+{
+	int			i;
+
+	for (i = 0; i < lengthof(InternalParallelCopyFuncPtrs); i++)
+	{
+		if (InternalParallelCopyFuncPtrs[i].fn_addr == fn_addr)
+			return InternalParallelCopyFuncPtrs[i].fn_name;
+	}
+
+	/* We can only reach this by programming error. */
+	elog(ERROR, "internal function pointer not found");
+}
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
  * in past protocol redesigns.
@@ -1149,6 +1939,7 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 
 	if (is_from)
 	{
+		ParallelContext *pcxt = NULL;
 		Assert(rel);
 
 		/* check read-only transaction and parallel mode */
@@ -1158,7 +1949,24 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 		cstate = BeginCopyFrom(pstate, rel, stmt->filename, stmt->is_program,
 							   NULL, stmt->attlist, stmt->options);
 		cstate->whereClause = whereClause;
-		*processed = CopyFrom(cstate);	/* copy from file to database */
+		cstate->is_parallel = false;
+
+		if (cstate->nworkers > 0)
+			pcxt = BeginParallelCopy(cstate->nworkers, cstate, stmt->attlist,
+									 relid);
+
+		if (pcxt)
+		{
+			ParallelCopyLeader(cstate);
+
+			/* Wait for all copy workers to finish */
+			WaitForParallelWorkersToFinish(pcxt);
+			*processed = pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
+			EndParallelCopy(pcxt);
+		}
+		else
+			*processed = CopyFrom(cstate); /* copy from file to database */
+
 		EndCopyFrom(cstate);
 	}
 	else
@@ -1207,6 +2015,7 @@ ProcessCopyOptions(ParseState *pstate,
 	cstate->is_copy_from = is_from;
 
 	cstate->file_encoding = -1;
+	cstate->nworkers = -1;
 
 	/* Extract options from the statement node tree */
 	foreach(option, options)
@@ -1375,6 +2184,53 @@ ProcessCopyOptions(ParseState *pstate,
 								defel->defname),
 						 parser_errposition(pstate, defel->location)));
 		}
+		else if (strcmp(defel->defname, "parallel") == 0)
+		{
+			char *endptr, *str;
+			long val;
+
+			if (!cstate->is_copy_from)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("parallel option supported only for copy from"),
+						 parser_errposition(pstate, defel->location)));
+			if (cstate->nworkers >= 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options"),
+						 parser_errposition(pstate, defel->location)));
+
+			str = defGetString(defel);
+
+			errno = 0; /* To distinguish success/failure after call */
+			val = strtol(str, &endptr, 10);
+
+			/* Check for various possible errors */
+			if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
+				|| (errno != 0 && val == 0) ||
+				*endptr)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("improper use of argument to option \"%s\"",
+								defel->defname),
+						 parser_errposition(pstate, defel->location)));
+
+			if (endptr == str)
+			   ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("no digits were found in argument to option \"%s\"",
+								defel->defname),
+						 parser_errposition(pstate, defel->location)));
+
+			cstate->nworkers = (int) val;
+
+			if (cstate->nworkers <= 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("argument to option \"%s\" must be a positive integer greater than zero",
+								defel->defname),
+						 parser_errposition(pstate, defel->location)));
+		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_SYNTAX_ERROR),
@@ -1727,12 +2583,13 @@ BeginCopy(ParseState *pstate,
 }
 
 /*
- * PopulateGlobalsForCopyFrom - Populates the common variables required for copy
- * from operation. This is a helper function for BeginCopy function.
+ * PopulateCatalogInformation - Populates the common variables required for copy
+ * from operation. This is a helper function for BeginCopy &
+ * ParallelWorkerInitialization function.
  */
 static void
 PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tupDesc,
-							List *attnamelist)
+						   List *attnamelist)
 {
 	int			num_phys_attrs;
 
diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c
index c27d970589..b3787c1c7f 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -557,7 +557,7 @@ make_copy_attnamelist(LogicalRepRelMapEntry *rel)
  * Data source callback for the COPY FROM, which reads from the remote
  * connection and passes the data back to our local COPY.
  */
-static int
+int
 copy_read_data(void *outbuf, int minread, int maxread)
 {
 	int			bytesread = 0;
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index c639833565..5dc95ac3f5 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -14,6 +14,7 @@
 #ifndef COPY_H
 #define COPY_H
 
+#include "access/parallel.h"
 #include "nodes/execnodes.h"
 #include "nodes/parsenodes.h"
 #include "parser/parse_node.h"
@@ -41,4 +42,7 @@ extern uint64 CopyFrom(CopyState cstate);
 
 extern DestReceiver *CreateCopyDestReceiver(void);
 
+extern void ParallelCopyMain(dsm_segment *seg, shm_toc *toc);
+
+extern int copy_read_data(void *outbuf, int minread, int maxread);
 #endif							/* COPY_H */
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index c65a55257d..8a7979412b 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1698,6 +1698,14 @@ ParallelBitmapHeapState
 ParallelBlockTableScanDesc
 ParallelCompletionPtr
 ParallelContext
+ParallelCopyLineBoundaries
+ParallelCopyLineBoundary
+ParallelCopyCommonKeyData
+ParallelCopyData
+ParallelCopyDataBlock
+ParallelCopyKeyListInfo
+ParallelCopyLineBuf
+ParallelCopyShmInfo
 ParallelExecutorInfo
 ParallelHashGrowth
 ParallelHashJoinBatch
-- 
2.25.1

0003-Allow-copy-from-command-to-process-data-from-file-ST.patchapplication/octet-stream; name=0003-Allow-copy-from-command-to-process-data-from-file-ST.patchDownload
From efc6dcb1ad7285c4e7486cd152c5908a48a7544d Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>, Bharath <bharath.rupireddyforpostgres@gmail.com>
Date: Tue, 23 Jun 2020 07:15:43 +0530
Subject: [PATCH 3/6] Allow copy from command to process data from file/STDIN
 contents to a table in parallel.

This feature allows the copy from to leverage multiple CPUs in order to copy
data from file/STDIN to a table. This adds a PARALLEL option to COPY FROM
command where the user can specify the number of workers that can be used
to perform the COPY FROM command. Specifying zero as number of workers will
disable parallelism.
The backend, to which the "COPY FROM" query is submitted acts as leader with
the responsibility of reading data from the file/stdin, launching at most n
number of workers as specified with PARALLEL 'n' option in the "COPY FROM"
query. The leader populates the common data required for the workers execution
in the DSM and shares it with the workers. The leader then executes before
statement triggers if there exists any. Leader populates DSM lines which
includes the start offset and line size, while populating the lines it reads
as many blocks as required into the DSM data blocks from the file. Each block
is of 64K size. The leader parses the data to identify a line, the existing
logic from CopyReadLineText which identifies the lines with some changes was
used for this. Leader checks if a free line is available to copy the
information, if there is no free line it waits till the required line is
freed up by the worker and then copies the identified lines information
(offset & line size) into the DSM lines. This process is repeated till the
complete file is processed. Simultaneously, the workers cache the lines(50)
locally into the local memory and release the lines to the leader for further
populating. Each worker processes the lines that it cached and inserts it into
the table. The leader does not participate in the insertion of data, leaders
only responsibility will be to identify the lines as fast as possible for the
workers to do the actual copy operation. The leader waits till all the lines
populated are processed by the workers and exits.
---
 src/backend/access/heap/heapam.c  |  13 -
 src/backend/access/transam/xact.c |  13 +
 src/backend/commands/copy.c       | 896 ++++++++++++++++++++++++++++++++++++--
 src/include/access/xact.h         |   1 +
 src/tools/pgindent/typedefs.list  |   1 +
 5 files changed, 873 insertions(+), 51 deletions(-)

diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 537913d..28f3a98 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2012,19 +2012,6 @@ static HeapTuple
 heap_prepare_insert(Relation relation, HeapTuple tup, TransactionId xid,
 					CommandId cid, int options)
 {
-	/*
-	 * Parallel operations are required to be strictly read-only in a parallel
-	 * worker.  Parallel inserts are not safe even in the leader in the
-	 * general case, because group locking means that heavyweight locks for
-	 * relation extension or GIN page locks will not conflict between members
-	 * of a lock group, but we don't prohibit that case here because there are
-	 * useful special cases that we can safely allow, such as CREATE TABLE AS.
-	 */
-	if (IsParallelWorker())
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_TRANSACTION_STATE),
-				 errmsg("cannot insert tuples in a parallel worker")));
-
 	tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
 	tup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK);
 	tup->t_data->t_infomask |= HEAP_XMAX_INVALID;
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 905dc7d..66f7236 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -502,6 +502,19 @@ GetCurrentFullTransactionIdIfAny(void)
 }
 
 /*
+ *	AssignFullTransactionIdForWorker
+ *
+ * For parallel copy, all the workers must use the same transaction id.
+ */
+void AssignFullTransactionIdForWorker(FullTransactionId fullTransactionId)
+{
+	TransactionState s = CurrentTransactionState;
+
+	Assert((IsInParallelMode() || IsParallelWorker()));
+	s->fullTransactionId = fullTransactionId;
+}
+
+/*
  *	MarkCurrentTransactionIdLoggedIfAny
  *
  * Remember that the current xid - if it is assigned - now has been wal logged.
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 34c657c..e8a89a4 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -26,6 +26,7 @@
 #include "access/xlog.h"
 #include "catalog/dependency.h"
 #include "catalog/pg_authid.h"
+#include "catalog/pg_proc_d.h"
 #include "catalog/pg_type.h"
 #include "commands/copy.h"
 #include "commands/defrem.h"
@@ -40,11 +41,13 @@
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
+#include "optimizer/clauses.h"
 #include "optimizer/optimizer.h"
 #include "parser/parse_coerce.h"
 #include "parser/parse_collate.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_relation.h"
+#include "pgstat.h"
 #include "port/pg_bswap.h"
 #include "rewrite/rewriteHandler.h"
 #include "storage/fd.h"
@@ -95,6 +98,18 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
+/*
+ * State of the line.
+ */
+typedef enum ParallelCopyLineState
+{
+	LINE_INIT,					/* initial state of line */
+	LINE_LEADER_POPULATING,		/* leader processing line */
+	LINE_LEADER_POPULATED,		/* leader completed populating line */
+	LINE_WORKER_PROCESSING,		/* worker processing line */
+	LINE_WORKER_PROCESSED		/* worker completed processing line */
+}ParallelCopyLineState;
+
 #define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
 
 #define DATA_BLOCK_SIZE RAW_BUF_SIZE
@@ -538,9 +553,13 @@ if (1) \
 { \
 	if (raw_buf_ptr > cstate->raw_buf_index) \
 	{ \
-		appendBinaryStringInfo(&cstate->line_buf, \
-							 cstate->raw_buf + cstate->raw_buf_index, \
-							   raw_buf_ptr - cstate->raw_buf_index); \
+		if (!IsParallelCopy()) \
+			appendBinaryStringInfo(&cstate->line_buf, \
+								   cstate->raw_buf + cstate->raw_buf_index, \
+								   raw_buf_ptr - cstate->raw_buf_index); \
+		else \
+			line_size +=  raw_buf_ptr - cstate->raw_buf_index; \
+		\
 		cstate->raw_buf_index = raw_buf_ptr; \
 	} \
 } else ((void) 0)
@@ -553,13 +572,40 @@ if (1) \
 	goto not_end_of_copy; \
 } else ((void) 0)
 
+/* Begin parallel copy Macros */
+#define SET_NEWLINE_SIZE() \
+{ \
+	if (cstate->eol_type == EOL_NL || cstate->eol_type == EOL_CR) \
+		new_line_size = 1; \
+	else if (cstate->eol_type == EOL_CRNL) \
+		new_line_size = 2; \
+	else \
+		new_line_size = 0; \
+}
+
+/*
+ * COPY_WAIT_TO_PROCESS - Wait before continuing to process.
+ */
+#define COPY_WAIT_TO_PROCESS() \
+{ \
+	CHECK_FOR_INTERRUPTS(); \
+	(void) WaitLatch(MyLatch, \
+					 WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH, \
+					 1L, WAIT_EVENT_PG_SLEEP); \
+	ResetLatch(MyLatch); \
+}
+
+/* End parallel copy Macros */
+
 /*
  * CONVERT_TO_SERVER_ENCODING - convert contents to server encoding.
  */
 #define CONVERT_TO_SERVER_ENCODING(cstate) \
 { \
 	/* Done reading the line.  Convert it to server encoding. */ \
-	if (cstate->need_transcoding) \
+	if (cstate->need_transcoding && \
+		(!IsParallelCopy() || \
+		 (IsParallelCopy() && !IsLeader()))) \
 	{ \
 		char	   *cvt; \
 		cvt = pg_any_to_server(cstate->line_buf.data, \
@@ -618,22 +664,38 @@ if (1) \
  * CLEAR_EOL_LINE - Wrapper for clearing EOL.
  */
 #define CLEAR_EOL_LINE() \
-if (!result && !IsHeaderLine()) \
-	CLEAR_EOL_FROM_COPIED_DATA(cstate->line_buf.data, \
-								cstate->line_buf.len, \
-								cstate->line_buf.len) \
+{ \
+	if (!result && !IsHeaderLine()) \
+	{ \
+		if (IsParallelCopy()) \
+			CLEAR_EOL_FROM_COPIED_DATA(cstate->raw_buf, \
+									   raw_buf_ptr, line_size) \
+		else \
+			CLEAR_EOL_FROM_COPIED_DATA(cstate->line_buf.data, \
+									   cstate->line_buf.len, \
+									   cstate->line_buf.len) \
+	} \
+}
 
 /*
  * INCREMENTPROCESSED - Increment the lines processed.
  */
-#define INCREMENTPROCESSED(processed)  \
-processed++;
+#define INCREMENTPROCESSED(processed) \
+{ \
+	if (!IsParallelCopy()) \
+		processed++; \
+	else \
+		pg_atomic_add_fetch_u64(&cstate->pcdata->pcshared_info->processed, 1); \
+}
 
 /*
  * GETPROCESSED - Get the lines processed.
  */
 #define GETPROCESSED(processed) \
-return processed;
+if (!IsParallelCopy()) \
+	return processed; \
+else \
+	return pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
 
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
@@ -681,8 +743,12 @@ static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 
 static pg_attribute_always_inline void EndParallelCopy(ParallelContext *pcxt);
+static void ExecBeforeStmtTrigger(CopyState cstate);
+static void CheckTargetRelValidity(CopyState cstate);
 static void PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tup_desc,
 							   List *attnamelist);
+static void PopulateCatalogInformation(CopyState cstate);
+static pg_attribute_always_inline uint32 GetLinePosition(CopyState cstate);
 static pg_attribute_always_inline copy_data_source_cb LookupParallelCopyFnPtr(const char *funcname);
 static pg_attribute_always_inline char* LookupParallelCopyFnStr(copy_data_source_cb fn_addr);
 
@@ -836,6 +902,137 @@ InsertListShm(ParallelContext *pcxt, int key, List *inputlist,
 }
 
 /*
+ * IsTriggerFunctionParallelSafe - Check if the trigger function is parallel
+ * safe for the triggers. Return false if any one of the trigger has parallel
+ * unsafe function.
+ */
+static pg_attribute_always_inline bool
+IsTriggerFunctionParallelSafe(TriggerDesc *trigdesc)
+{
+	int	i;
+	for (i = 0; i < trigdesc->numtriggers; i++)
+	{
+		Trigger    *trigger = &trigdesc->triggers[i];
+		int 		trigtype = RI_TRIGGER_NONE;
+
+		if (func_parallel(trigger->tgfoid) != PROPARALLEL_SAFE)
+			return false;
+
+		/* If the trigger is parallel safe, also look for RI_TRIGGER. */
+		trigtype = RI_FKey_trigger_type(trigger->tgfoid);
+		if (trigtype == RI_TRIGGER_PK || trigtype == RI_TRIGGER_FK)
+			return false;
+	}
+
+	return true;
+}
+
+/*
+ * CheckExprParallelSafety - determine parallel safety of volatile expressions
+ * in default clause of column definition or in where clause and return true if
+ * they are parallel safe.
+ */
+static pg_attribute_always_inline bool
+CheckExprParallelSafety(CopyState cstate)
+{
+	if (contain_volatile_functions(cstate->whereClause))
+	{
+		if (max_parallel_hazard((Query *)cstate->whereClause) != PROPARALLEL_SAFE)
+			return false;
+	}
+
+	/*
+	 * Check if any of the column has volatile default expression. if yes, and
+	 * they are not parallel safe, then parallelism is not allowed. For
+	 * instance, if there are any serial/bigserial columns for which nextval()
+	 * default expression which is parallel unsafe is associated, parallelism
+	 * should not be allowed. In non paralllel copy volatile functions are not
+	 * checked for nextval().
+	 */
+	if (cstate->defexprs != NULL && cstate->num_defaults != 0)
+	{
+		int     i;
+		for (i = 0; i < cstate->num_defaults; i++)
+		{
+			bool volatile_expr = contain_volatile_functions((Node *)cstate->defexprs[i]->expr);
+			if (volatile_expr &&
+				(max_parallel_hazard((Query *)cstate->defexprs[i]->expr)) !=
+				 PROPARALLEL_SAFE)
+				return false;
+		}
+	}
+
+	return true;
+}
+
+/*
+ * FindInsertMethod - determine insert mode single, multi, or multi conditional.
+ */
+static pg_attribute_always_inline CopyInsertMethod
+FindInsertMethod(CopyState cstate)
+{
+	if (cstate->rel->trigdesc != NULL &&
+		(cstate->rel->trigdesc->trig_insert_before_row ||
+		 cstate->rel->trigdesc->trig_insert_instead_row))
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
+			cstate->rel->trigdesc != NULL &&
+			cstate->rel->trigdesc->trig_insert_new_table)
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+		return CIM_MULTI_CONDITIONAL;
+
+	return CIM_MULTI;
+}
+
+/*
+ * IsParallelCopyAllowed - check for the cases where parallel copy is not
+ * applicable.
+ */
+static pg_attribute_always_inline bool
+IsParallelCopyAllowed(CopyState cstate)
+{
+	/* Parallel copy not allowed for frontend (2.0 protocol) & binary option. */
+	if ((cstate->copy_dest == COPY_OLD_FE) || cstate->binary)
+		return false;
+
+	/* Check if copy is into foreign table or temporary table. */
+	if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
+		RelationUsesLocalBuffers(cstate->rel))
+		return false;
+
+	/* Check if trigger function is parallel safe. */
+	if (cstate->rel->trigdesc != NULL &&
+		!IsTriggerFunctionParallelSafe(cstate->rel->trigdesc))
+		return false;
+
+	/*
+	 * Check if there is after statement or instead of trigger or transition
+	 * table triggers.
+	 */
+	if (cstate->rel->trigdesc != NULL &&
+		(cstate->rel->trigdesc->trig_insert_after_statement ||
+		 cstate->rel->trigdesc->trig_insert_instead_row ||
+		 cstate->rel->trigdesc->trig_insert_new_table))
+		return false;
+
+	/* Check if the volatile expressions are parallel safe, if present any. */
+	if (!CheckExprParallelSafety(cstate))
+		return false;
+
+	/* Check if the insertion mode is single. */
+	if (FindInsertMethod(cstate) == CIM_SINGLE)
+		return false;
+
+	return true;
+}
+
+/*
  * BeginParallelCopy - start parallel copy tasks.
  *
  * Get the number of workers required to perform the parallel copy. The data
@@ -865,6 +1062,8 @@ BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
 	int  parallel_workers = 0;
 	ParallelCopyData *pcdata;
 
+	CheckTargetRelValidity(cstate);
+
 	parallel_workers = Min(nworkers, max_worker_processes);
 
 	/* Can't perform copy in parallel */
@@ -878,6 +1077,19 @@ BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
 	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
 	cstate->pcdata = pcdata;
 
+	/*
+	 * User chosen parallel copy. Determine if the parallel copy is actually
+	 * allowed. If not, go with the non-parallel mode.
+	 */
+	if (!IsParallelCopyAllowed(cstate))
+	{
+		elog(WARNING,
+			 "Parallel copy not supported for specified table, copy will be run in non-parallel mode");
+		return NULL;
+	}
+
+	full_transaction_id = GetCurrentFullTransactionId();
+
 	EnterParallelMode();
 	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
 								 parallel_workers);
@@ -1108,7 +1320,211 @@ ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
 	cstate->line_buf_converted = false;
 	cstate->raw_buf = NULL;
 	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+
+	PopulateCatalogInformation(cstate);
+
+	/* Create workspace for CopyReadAttributes results. */
+	if (!cstate->binary)
+	{
+		AttrNumber	attr_count = list_length(cstate->attnumlist);
+
+		cstate->max_fields = attr_count;
+		cstate->raw_fields = (char **)palloc(attr_count * sizeof(char *));
+	}
+}
+
+/*
+ * CacheLineInfo - Cache the line information to local memory.
+ */
+static bool
+CacheLineInfo(CopyState cstate, uint32 buff_count)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	uint32			write_pos;
+	ParallelCopyDataBlock *data_blk_ptr;
+	ParallelCopyLineBoundary *lineInfo;
+	uint32 offset;
+	int dataSize;
+	int copiedSize = 0;
+
+	resetStringInfo(&pcdata->worker_line_buf[buff_count].line_buf);
+	write_pos = GetLinePosition(cstate);
+	if (-1 == write_pos)
+		return true;
+
+	/* Get the current line information. */
+	lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+	if (pg_atomic_read_u32(&lineInfo->line_size) == 0)
+		goto empty_data_line_update;
+
+	/* Get the block information. */
+	data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+	/* Get the offset information from where the data must be copied. */
+	offset = lineInfo->start_offset;
+	pcdata->worker_line_buf[buff_count].cur_lineno = lineInfo->cur_lineno;
+
+	elog(DEBUG1, "[Worker] Processing - line position:%d, block:%d, unprocessed lines:%d, offset:%d, line size:%d",
+				 write_pos, lineInfo->first_block,
+				 pg_atomic_read_u32(&data_blk_ptr->unprocessed_line_parts),
+				 offset, pg_atomic_read_u32(&lineInfo->line_size));
+
+	for (;;)
+	{
+		uint8 skip_bytes = data_blk_ptr->skip_bytes;
+		/*
+		 * There is a possibility that the above loop has come out because
+		 * data_blk_ptr->curr_blk_completed is set, but dataSize read might
+		 * be an old value, if data_blk_ptr->curr_blk_completed and the line is
+		 * completed, line_size will be set. Read the line_size again to be
+		 * sure if it is complete or partial block.
+		 */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+		if (dataSize)
+		{
+			int remainingSize = dataSize - copiedSize;
+			if (!remainingSize)
+				break;
+
+			/* Whole line is in current block. */
+			if (remainingSize + offset + skip_bytes < DATA_BLOCK_SIZE)
+			{
+				appendBinaryStringInfo(&pcdata->worker_line_buf[buff_count].line_buf,
+									   &data_blk_ptr->data[offset],
+									   remainingSize);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts,
+										1);
+				break;
+			}
+			else
+			{
+				/* Line is spread across the blocks. */
+				uint32 lineInCurrentBlock =  (DATA_BLOCK_SIZE - skip_bytes) - offset;
+				appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+										 &data_blk_ptr->data[offset],
+										 lineInCurrentBlock);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+				copiedSize += lineInCurrentBlock;
+				while (copiedSize < dataSize)
+				{
+					uint32 currentBlockCopySize;
+					ParallelCopyDataBlock *currBlkPtr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+					skip_bytes = currBlkPtr->skip_bytes;
+
+					/*
+					 * If complete data is present in current block use
+					 * dataSize - copiedSize, or copy the whole block from
+					 * current block.
+					 */
+					currentBlockCopySize = Min(dataSize - copiedSize, DATA_BLOCK_SIZE - skip_bytes);
+					appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+											 &currBlkPtr->data[0],
+											 currentBlockCopySize);
+					pg_atomic_sub_fetch_u32(&currBlkPtr->unprocessed_line_parts, 1);
+					copiedSize += currentBlockCopySize;
+					data_blk_ptr = currBlkPtr;
+				}
+
+				break;
+			}
+		}
+		else
+		{
+			/* Copy this complete block from the current offset. */
+			uint32 lineInCurrentBlock =  (DATA_BLOCK_SIZE - skip_bytes) - offset;
+			appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+									 &data_blk_ptr->data[offset],
+									 lineInCurrentBlock);
+			pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+			copiedSize += lineInCurrentBlock;
+
+			/*
+			 * Reset the offset. For the first copy, copy from the offset. For
+			 * the subsequent copy the complete block.
+			 */
+			offset = 0;
+
+			/* Set data_blk_ptr to the following block. */
+			data_blk_ptr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+		}
+
+		for (;;)
+		{
+			/* Get the size of this line */
+			dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+			/*
+			 * If the data is present in current block lineInfo.line_size
+			 * will be updated. If the data is spread across the blocks either
+			 * of lineInfo.line_size or data_blk_ptr->curr_blk_completed can
+			 * be updated. lineInfo.line_size will be updated if the complete
+			 * read is finished. data_blk_ptr->curr_blk_completed will be
+			 * updated if processing of current block is finished and data
+			 * processing is not finished.
+			 */
+			if (data_blk_ptr->curr_blk_completed || (dataSize != -1))
+				break;
+
+			COPY_WAIT_TO_PROCESS()
+		}
+	}
+
+empty_data_line_update:
+	elog(DEBUG1, "[Worker] Completed processing line:%d", write_pos);
+	pg_atomic_write_u32(&lineInfo->line_state, LINE_WORKER_PROCESSED);
+	pg_atomic_write_u32(&lineInfo->line_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+	return false;
+}
+
+/*
+ * GetWorkerLine - Returns a line for worker to process.
+ */
+static bool
+GetWorkerLine(CopyState cstate)
+{
+	uint32 buff_count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+
+	/*
+	 * Copy the line data to line_buf and release the line position so that the
+	 * worker can continue loading data.
+	 */
+	if (pcdata->worker_line_buf_pos < pcdata->worker_line_buf_count)
+		goto return_line;
+
+	pcdata->worker_line_buf_pos = 0;
+	pcdata->worker_line_buf_count = 0;
+
+	for (buff_count = 0; buff_count < WORKER_CHUNK_COUNT; buff_count++)
+	{
+		bool result = CacheLineInfo(cstate, buff_count);
+		if (result)
+			break;
+
+		pcdata->worker_line_buf_count++;
+	}
+
+	if (pcdata->worker_line_buf_count)
+		goto return_line;
+	else
+		resetStringInfo(&cstate->line_buf);
+
+	return true;
+
+return_line:
+	cstate->line_buf = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].line_buf;
+	cstate->cur_lineno = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].cur_lineno;
+	cstate->line_buf_valid = true;
+
+	/* Mark that encoding conversion hasn't occurred yet. */
+	cstate->line_buf_converted = false;
+	CONVERT_TO_SERVER_ENCODING(cstate)
+	pcdata->worker_line_buf_pos++;
+	return false;
 }
+
 /*
  * ParallelCopyMain - parallel copy worker's code.
  *
@@ -1154,6 +1570,7 @@ ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
 	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
 
 	pcdata->pcshared_info = pcshared_info;
+	AssignFullTransactionIdForWorker(pcshared_info->full_transaction_id);
 
 	shared_cstate = (ParallelCopyCommonKeyData *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE,
 														   false);
@@ -1206,6 +1623,34 @@ ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
 	MemoryContextSwitchTo(oldcontext);
 	return;
 }
+
+/*
+ * UpdateBlockInLineInfo - Update the line information.
+ */
+static pg_attribute_always_inline int
+UpdateBlockInLineInfo(CopyState cstate, uint32 blk_pos,
+					   uint32 offset, uint32 line_size, uint32 line_state)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyLineBoundaries *lineBoundaryPtr = &pcshared_info->line_boundaries;
+	ParallelCopyLineBoundary *lineInfo;
+	int line_pos = lineBoundaryPtr->leader_pos;
+
+	/* Update the line information for the worker to pick and process. */
+	lineInfo = &lineBoundaryPtr->ring[line_pos];
+	while (pg_atomic_read_u32(&lineInfo->line_size) != -1)
+		COPY_WAIT_TO_PROCESS()
+
+	lineInfo->first_block = blk_pos;
+	lineInfo->start_offset = offset;
+	lineInfo->cur_lineno = cstate->cur_lineno;
+	pg_atomic_write_u32(&lineInfo->line_size, line_size);
+	pg_atomic_write_u32(&lineInfo->line_state, line_state);
+	lineBoundaryPtr->leader_pos = (lineBoundaryPtr->leader_pos + 1) % RINGSIZE;
+
+	return line_pos;
+}
+
 /*
  * ParallelCopyLeader - parallel copy leader's functionality.
  *
@@ -1231,9 +1676,158 @@ ParallelCopyLeader(CopyState cstate)
 	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
 	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
 
+	/* Execute the before statement triggers from the leader */
+	ExecBeforeStmtTrigger(cstate);
+
+	/* On input just throw the header line away. */
+	if (cstate->cur_lineno == 0 && cstate->header_line)
+	{
+		cstate->cur_lineno++;
+		if (CopyReadLine(cstate))
+		{
+			pcshared_info->is_read_in_progress = false;
+			return;			/* done */
+		}
+	}
+
+	for (;;)
+	{
+		bool done;
+		cstate->cur_lineno++;
+
+		/* Actually read the line into memory here. */
+		done = CopyReadLine(cstate);
+
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			break;
+	}
+
 	pcshared_info->is_read_in_progress = false;
 	cstate->cur_lineno = 0;
 }
+
+/*
+ * GetLinePosition - return the line position that worker should process.
+ */
+static uint32
+GetLinePosition(CopyState cstate)
+{
+	ParallelCopyData *pcdata = cstate->pcdata;
+	ParallelCopyShmInfo *pcshared_info = pcdata->pcshared_info;
+	uint32  previous_pos = pcdata->worker_processed_pos;
+	uint32 write_pos = (previous_pos == -1) ? 0 : (previous_pos + 1) % RINGSIZE;
+	for (;;)
+	{
+		int		dataSize;
+		bool	is_read_in_progress = pcshared_info->is_read_in_progress;
+		ParallelCopyLineBoundary *lineInfo;
+		ParallelCopyDataBlock *data_blk_ptr;
+		ParallelCopyLineState line_state = LINE_LEADER_POPULATED;
+		ParallelCopyLineState curr_line_state;
+		CHECK_FOR_INTERRUPTS();
+
+		/* File read completed & no elements to process. */
+		if (!is_read_in_progress &&
+			(pcshared_info->populated ==
+			 pg_atomic_read_u64(&pcshared_info->total_worker_processed)))
+		{
+			write_pos = -1;
+			break;
+		}
+
+		/* Get the current line information. */
+		lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+		curr_line_state = pg_atomic_read_u32(&lineInfo->line_state);
+		if ((write_pos % WORKER_CHUNK_COUNT == 0) &&
+			(curr_line_state == LINE_WORKER_PROCESSED ||
+			 curr_line_state == LINE_WORKER_PROCESSING))
+		{
+			pcdata->worker_processed_pos = write_pos;
+			write_pos = (write_pos + WORKER_CHUNK_COUNT) %  RINGSIZE;
+			continue;
+		}
+
+		/* Get the size of this line. */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+		if (dataSize != 0) /* If not an empty line. */
+		{
+			/* Get the block information. */
+			data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+			if (!data_blk_ptr->curr_blk_completed && (dataSize == -1))
+			{
+				/* Wait till the current line or block is added. */
+				COPY_WAIT_TO_PROCESS()
+				continue;
+			}
+		}
+
+		/* Make sure that no worker has consumed this element. */
+		if (pg_atomic_compare_exchange_u32(&lineInfo->line_state,
+										   &line_state, LINE_WORKER_PROCESSING))
+			break;
+	}
+
+	pcdata->worker_processed_pos = write_pos;
+	return write_pos;
+}
+
+/*
+ * GetFreeCopyBlock - Get a free block for data to be copied.
+ */
+static pg_attribute_always_inline uint32
+GetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	int count = 0;
+	uint32 last_free_block = pcshared_info->cur_block_pos;
+	uint32 block_pos = (last_free_block != -1) ? ((last_free_block + 1) % MAX_BLOCKS_COUNT): 0;
+
+	/* Get a new block for copying data. */
+	while (count < MAX_BLOCKS_COUNT)
+	{
+		ParallelCopyDataBlock *dataBlkPtr = &pcshared_info->data_blocks[block_pos];
+		uint32 unprocessed_line_parts = pg_atomic_read_u32(&dataBlkPtr->unprocessed_line_parts);
+		if (unprocessed_line_parts == 0)
+		{
+			dataBlkPtr->curr_blk_completed = false;
+			dataBlkPtr->skip_bytes = 0;
+			pcshared_info->cur_block_pos = block_pos;
+			return block_pos;
+		}
+
+		block_pos = (block_pos + 1) % MAX_BLOCKS_COUNT;
+		count++;
+	}
+
+	return -1;
+}
+
+/*
+ * WaitGetFreeCopyBlock - If there are no blocks available, wait and get a block
+ * for copying data.
+ */
+static uint32
+WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	uint32 new_free_pos = -1;
+	for (;;)
+	{
+		new_free_pos = GetFreeCopyBlock(pcshared_info);
+		if (new_free_pos != -1)	/* We have got one block, break now. */
+			break;
+
+		COPY_WAIT_TO_PROCESS()
+	}
+
+	return new_free_pos;
+}
+
 /*
  * LookupParallelCopyFnPtr - Look up parallel copy function pointer.
  */
@@ -1269,6 +1863,146 @@ LookupParallelCopyFnStr(copy_data_source_cb fn_addr)
 	/* We can only reach this by programming error. */
 	elog(ERROR, "internal function pointer not found");
 }
+
+/*
+ * SetRawBufForLoad - Set raw_buf to the shared memory where the file data must
+ * be read.
+ */
+static void
+SetRawBufForLoad(CopyState cstate, uint32 line_size, uint32 copy_buf_len,
+				 uint32 raw_buf_ptr, char **copy_raw_buf)
+{
+	ParallelCopyShmInfo	*pcshared_info;
+	uint32 cur_block_pos;
+	uint32 next_block_pos;
+	ParallelCopyDataBlock	*cur_data_blk_ptr = NULL;
+	ParallelCopyDataBlock	*next_data_blk_ptr = NULL;
+
+	if (!IsParallelCopy())
+		return;
+
+	pcshared_info = cstate->pcdata->pcshared_info;
+	cur_block_pos = pcshared_info->cur_block_pos;
+	cur_data_blk_ptr = (cstate->raw_buf) ? &pcshared_info->data_blocks[cur_block_pos] : NULL;
+	next_block_pos = WaitGetFreeCopyBlock(pcshared_info);
+	next_data_blk_ptr = &pcshared_info->data_blocks[next_block_pos];
+
+	/* set raw_buf to the data block in shared memory */
+	cstate->raw_buf = next_data_blk_ptr->data;
+	*copy_raw_buf = cstate->raw_buf;
+	if (cur_data_blk_ptr && line_size)
+	{
+		/*
+		 * Mark the previous block as completed, worker can start copying this
+		 * data.
+		 */
+		cur_data_blk_ptr->following_block = next_block_pos;
+		pg_atomic_add_fetch_u32(&cur_data_blk_ptr->unprocessed_line_parts, 1);
+		cur_data_blk_ptr->skip_bytes = copy_buf_len - raw_buf_ptr;
+		cur_data_blk_ptr->curr_blk_completed = true;
+	}
+}
+
+/*
+ * EndLineParallelCopy - Update the line information in shared memory.
+ */
+static void
+EndLineParallelCopy(CopyState cstate, uint32 line_pos, uint32 line_size,
+					 uint32 raw_buf_ptr)
+{
+	uint8 new_line_size;
+	if (!IsParallelCopy())
+		return;
+
+	if (!IsHeaderLine())
+	{
+		ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+		ParallelCopyLineBoundaries *lineBoundaryPtr = &pcshared_info->line_boundaries;
+		SET_NEWLINE_SIZE()
+		if (line_size)
+		{
+			ParallelCopyLineBoundary *lineInfo = &lineBoundaryPtr->ring[line_pos];
+			/*
+			 * If the new_line_size > raw_buf_ptr, then the new block has only
+			 * new line char content. The unprocessed count should not be
+			 * increased in this case.
+			 */
+			if (raw_buf_ptr > new_line_size)
+			{
+				uint32 cur_block_pos = pcshared_info->cur_block_pos;
+				ParallelCopyDataBlock *curr_data_blk_ptr = &pcshared_info->data_blocks[cur_block_pos];
+				pg_atomic_add_fetch_u32(&curr_data_blk_ptr->unprocessed_line_parts, 1);
+			}
+
+			/* Update line size. */
+			pg_atomic_write_u32(&lineInfo->line_size, line_size);
+			pg_atomic_write_u32(&lineInfo->line_state, LINE_LEADER_POPULATED);
+			elog(DEBUG1, "[Leader] After adding - line position:%d, line_size:%d",
+						 line_pos, line_size);
+			pcshared_info->populated++;
+		}
+		else if (new_line_size)
+		{
+			/* This means only new line char, empty record should be inserted.*/
+			ParallelCopyLineBoundary *lineInfo;
+			line_pos = UpdateBlockInLineInfo(cstate, -1, -1, 0,
+											   LINE_LEADER_POPULATED);
+			lineInfo = &lineBoundaryPtr->ring[line_pos];
+			elog(DEBUG1, "[Leader] Added empty line with offset:%d, line position:%d, line size:%d",
+						 lineInfo->start_offset, line_pos,
+						 pg_atomic_read_u32(&lineInfo->line_size));
+			pcshared_info->populated++;
+		}
+	}
+}
+
+/*
+ * ExecBeforeStmtTrigger - Execute the before statement trigger, this will be
+ * executed for parallel copy by the leader process.
+ */
+static void
+ExecBeforeStmtTrigger(CopyState cstate)
+{
+	EState	   *estate = CreateExecutorState();
+	ResultRelInfo *resultRelInfo;
+
+	Assert(IsLeader());
+
+	/*
+	 * We need a ResultRelInfo so we can use the regular executor's
+	 * index-entry-making machinery.  (There used to be a huge amount of code
+	 * here that basically duplicated execUtils.c ...)
+	 */
+	resultRelInfo = makeNode(ResultRelInfo);
+	InitResultRelInfo(resultRelInfo,
+					  cstate->rel,
+					  1,		/* must match rel's position in range_table */
+					  NULL,
+					  0);
+
+	/* Verify the named relation is a valid target for INSERT */
+	CheckValidResultRel(resultRelInfo, CMD_INSERT);
+
+	estate->es_result_relations = resultRelInfo;
+	estate->es_num_result_relations = 1;
+	estate->es_result_relation_info = resultRelInfo;
+
+	ExecInitRangeTable(estate, cstate->range_table);
+
+	/*
+	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
+	 * should do this for COPY, since it's not really an "INSERT" statement as
+	 * such. However, executing these triggers maintains consistency with the
+	 * EACH ROW triggers that we already fire on COPY.
+	 */
+	ExecBSInsertTriggers(estate, resultRelInfo);
+
+	/* Close any trigger target relations */
+	ExecCleanUpTriggerState(estate);
+
+	FreeExecutorState(estate);
+}
+
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
  * in past protocol redesigns.
@@ -3675,7 +4409,8 @@ CopyFrom(CopyState cstate)
 
 	PartitionTupleRouting *proute = NULL;
 	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
+	CommandId	mycid = IsParallelCopy() ? cstate->pcdata->pcshared_info->mycid :
+										   GetCurrentCommandId(true);
 	int			ti_options = 0; /* start with default options for insert */
 	BulkInsertState bistate = NULL;
 	CopyInsertMethod insertMethod;
@@ -3685,7 +4420,14 @@ CopyFrom(CopyState cstate)
 	bool		has_instead_insert_row_trig;
 	bool		leafpart_use_multi_insert = false;
 
-	CheckTargetRelValidity(cstate);
+	/*
+	 * Perform this check if it is not parallel copy. In case of parallel
+	 * copy, this check is done by the leader, so that if any invalid case
+	 * exist the copy from command will error out from the leader itself,
+	 * avoiding launching workers, just to throw error.
+	 */
+	if (!IsParallelCopy())
+		CheckTargetRelValidity(cstate);
 
 	/*
 	 * If the target file is new-in-transaction, we assume that checking FSM
@@ -3874,13 +4616,16 @@ CopyFrom(CopyState cstate)
 	has_instead_insert_row_trig = (resultRelInfo->ri_TrigDesc &&
 								   resultRelInfo->ri_TrigDesc->trig_insert_instead_row);
 
-	/*
-	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
-	 * should do this for COPY, since it's not really an "INSERT" statement as
-	 * such. However, executing these triggers maintains consistency with the
-	 * EACH ROW triggers that we already fire on COPY.
-	 */
-	ExecBSInsertTriggers(estate, resultRelInfo);
+	if (!IsParallelCopy())
+	{
+		/*
+		 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
+		 * should do this for COPY, since it's not really an "INSERT" statement as
+		 * such. However, executing these triggers maintains consistency with the
+		 * EACH ROW triggers that we already fire on COPY.
+		 */
+		ExecBSInsertTriggers(estate, resultRelInfo);
+	}
 
 	econtext = GetPerTupleExprContext(estate);
 
@@ -3980,6 +4725,16 @@ CopyFrom(CopyState cstate)
 					!has_instead_insert_row_trig &&
 					resultRelInfo->ri_FdwRoutine == NULL;
 
+				/*
+				 * If the table has any partitions that are either foreign or
+				 * has BEFORE/INSTEAD OF triggers, we can't perform copy
+				 * operations with parallel workers.
+				 */
+				if (!leafpart_use_multi_insert && IsParallelWorker())
+					ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							errmsg("cannot perform PARALLEL COPY if partition has BEFORE/INSTEAD OF triggers, or if the partition is foreign partition"),
+							errhint("Try COPY without PARALLEL option")));
+
 				/* Set the multi-insert buffer to use for this partition. */
 				if (leafpart_use_multi_insert)
 				{
@@ -4394,7 +5149,7 @@ BeginCopyFrom(ParseState *pstate,
 	initStringInfo(&cstate->attribute_buf);
 	initStringInfo(&cstate->line_buf);
 	cstate->line_buf_converted = false;
-	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+	cstate->raw_buf = (IsParallelCopy()) ? NULL : (char *) palloc(RAW_BUF_SIZE + 1);
 	cstate->raw_buf_index = cstate->raw_buf_len = 0;
 
 	/* Assign range table, we'll need it in CopyFrom. */
@@ -4538,26 +5293,35 @@ NextCopyFromRawFields(CopyState cstate, char ***fields, int *nfields)
 	/* only available for text or csv input */
 	Assert(!cstate->binary);
 
-	/* on input just throw the header line away */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (IsParallelCopy())
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
-			return false;		/* done */
+		done = GetWorkerLine(cstate);
+		if (done && cstate->line_buf.len == 0)
+			return false;
 	}
+	else
+	{
+		/* on input just throw the header line away */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
+		{
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+				return false;		/* done */
+		}
 
-	cstate->cur_lineno++;
+		cstate->cur_lineno++;
 
-	/* Actually read the line into memory here */
-	done = CopyReadLine(cstate);
+		/* Actually read the line into memory here */
+		done = CopyReadLine(cstate);
 
-	/*
-	 * EOF at start of line means we're done.  If we see EOF after some
-	 * characters, we act as though it was newline followed by EOF, ie,
-	 * process the line and then exit loop on next iteration.
-	 */
-	if (done && cstate->line_buf.len == 0)
-		return false;
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			return false;
+	}
 
 	/* Parse the line into de-escaped field values */
 	if (cstate->csv_mode)
@@ -4805,9 +5569,31 @@ CopyReadLine(CopyState cstate)
 		 */
 		if (cstate->copy_dest == COPY_NEW_FE)
 		{
+			bool bIsFirst = true;
 			do
 			{
-				cstate->raw_buf_index = cstate->raw_buf_len;
+				if (!IsParallelCopy())
+					cstate->raw_buf_index = cstate->raw_buf_len;
+				else
+				{
+					if (cstate->raw_buf_index == RAW_BUF_SIZE)
+					{
+						/* Get a new block if it is the first time, From the
+						 * subsequent time, reset the index and re-use the same
+						 * block.
+						 */
+						if (bIsFirst)
+						{
+							ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+							uint32 block_pos = WaitGetFreeCopyBlock(pcshared_info);
+							cstate->raw_buf = pcshared_info->data_blocks[block_pos].data;
+							bIsFirst = false;
+						}
+
+						cstate->raw_buf_index = cstate->raw_buf_len = 0;
+					}
+				}
+
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
@@ -4837,6 +5623,11 @@ CopyReadLineText(CopyState cstate)
 	char		quotec = '\0';
 	char		escapec = '\0';
 
+	/* For parallel copy */
+	uint32			 line_size = 0;
+	int				 line_pos = 0;
+
+	cstate->eol_type = EOL_UNKNOWN;
 	if (cstate->csv_mode)
 	{
 		quotec = cstate->quote[0];
@@ -4891,6 +5682,8 @@ CopyReadLineText(CopyState cstate)
 		if (raw_buf_ptr >= copy_buf_len || need_data)
 		{
 			REFILL_LINEBUF;
+			SetRawBufForLoad(cstate, line_size, copy_buf_len, raw_buf_ptr,
+							 &copy_raw_buf);
 
 			/*
 			 * Try to read some more data.  This will certainly reset
@@ -5115,9 +5908,15 @@ CopyReadLineText(CopyState cstate)
 				 * discard the data and the \. sequence.
 				 */
 				if (prev_raw_ptr > cstate->raw_buf_index)
-					appendBinaryStringInfo(&cstate->line_buf,
+				{
+					if (!IsParallelCopy())
+						appendBinaryStringInfo(&cstate->line_buf,
 										   cstate->raw_buf + cstate->raw_buf_index,
 										   prev_raw_ptr - cstate->raw_buf_index);
+					else
+						line_size += prev_raw_ptr - cstate->raw_buf_index;
+				}
+
 				cstate->raw_buf_index = raw_buf_ptr;
 				result = true;	/* report EOF */
 				break;
@@ -5169,6 +5968,26 @@ not_end_of_copy:
 			IF_NEED_REFILL_AND_EOF_BREAK(mblen - 1);
 			raw_buf_ptr += mblen - 1;
 		}
+
+		/*
+		 * Skip the header line. Update the line here, this cannot be done at
+		 * the beginning, as there is a possibility that file contains empty
+		 * lines.
+		 */
+		if (IsParallelCopy() && first_char_in_line && !IsHeaderLine())
+		{
+			ParallelCopyShmInfo	*pcshared_info = cstate->pcdata->pcshared_info;
+			ParallelCopyLineBoundary *lineInfo;
+			uint32			 line_first_block = pcshared_info->cur_block_pos;
+			line_pos = UpdateBlockInLineInfo(cstate,
+											   line_first_block,
+											   cstate->raw_buf_index, -1,
+											   LINE_LEADER_POPULATING);
+			lineInfo = &pcshared_info->line_boundaries.ring[line_pos];
+			elog(DEBUG1, "[Leader] Adding - block:%d, offset:%d, line position:%d",
+						 line_first_block,	lineInfo->start_offset, line_pos);
+		}
+
 		first_char_in_line = false;
 	}							/* end of outer loop */
 
@@ -5177,6 +5996,7 @@ not_end_of_copy:
 	 */
 	REFILL_LINEBUF;
 	CLEAR_EOL_LINE()
+	EndLineParallelCopy(cstate, line_pos, line_size, raw_buf_ptr);
 
 	return result;
 }
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index db19187..584b7ee 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -381,6 +381,7 @@ extern FullTransactionId GetTopFullTransactionId(void);
 extern FullTransactionId GetTopFullTransactionIdIfAny(void);
 extern FullTransactionId GetCurrentFullTransactionId(void);
 extern FullTransactionId GetCurrentFullTransactionIdIfAny(void);
+extern void AssignFullTransactionIdForWorker(FullTransactionId fullTransactionId);
 extern void MarkCurrentTransactionIdLoggedIfAny(void);
 extern bool SubTransactionIsActive(SubTransactionId subxid);
 extern CommandId GetCurrentCommandId(bool used);
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 8a79794..86b5c62 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1700,6 +1700,7 @@ ParallelCompletionPtr
 ParallelContext
 ParallelCopyLineBoundaries
 ParallelCopyLineBoundary
+ParallelCopyLineState
 ParallelCopyCommonKeyData
 ParallelCopyData
 ParallelCopyDataBlock
-- 
1.8.3.1

0004-Documentation-for-parallel-copy.patchapplication/octet-stream; name=0004-Documentation-for-parallel-copy.patchDownload
From f06311aab275234125ed5b2c1a5c4740db55df3f Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 17 Jun 2020 07:34:56 +0530
Subject: [PATCH 4/6] Documentation for parallel copy.

This patch has the documentation changes for parallel copy.
---
 doc/src/sgml/ref/copy.sgml | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/doc/src/sgml/ref/copy.sgml b/doc/src/sgml/ref/copy.sgml
index 18189ab..95d349d 100644
--- a/doc/src/sgml/ref/copy.sgml
+++ b/doc/src/sgml/ref/copy.sgml
@@ -37,6 +37,7 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
     DELIMITER '<replaceable class="parameter">delimiter_character</replaceable>'
     NULL '<replaceable class="parameter">null_string</replaceable>'
     HEADER [ <replaceable class="parameter">boolean</replaceable> ]
+    PARALLEL <replaceable class="parameter">integer</replaceable>
     QUOTE '<replaceable class="parameter">quote_character</replaceable>'
     ESCAPE '<replaceable class="parameter">escape_character</replaceable>'
     FORCE_QUOTE { ( <replaceable class="parameter">column_name</replaceable> [, ...] ) | * }
@@ -275,6 +276,21 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
    </varlistentry>
 
    <varlistentry>
+    <term><literal>PARALLEL</literal></term>
+    <listitem>
+     <para>
+      Perform <command>COPY FROM</command> in parallel using <replaceable
+      class="parameter"> integer</replaceable> background workers.  Please
+      note that it is not guaranteed that the number of parallel workers
+      specified in <replaceable class="parameter">integer</replaceable> will
+      be used during execution.  It is possible for a copy to run with fewer
+      workers than specified, or even with no workers at all.  This option is
+      allowed only in <command>COPY FROM</command>.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><literal>QUOTE</literal></term>
     <listitem>
      <para>
-- 
1.8.3.1

0005-Tests-for-parallel-copy.patchapplication/octet-stream; name=0005-Tests-for-parallel-copy.patchDownload
From 740f39b8a87eb74e74182ed2cc5e8c18bd2ce367 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 17 Jun 2020 07:37:26 +0530
Subject: [PATCH 5/6] Tests for parallel copy.

This patch has the tests for parallel copy.
---
 src/test/regress/expected/copy2.out | 210 +++++++++++++++++++++++++++++++++++-
 src/test/regress/input/copy.source  |  12 +++
 src/test/regress/output/copy.source |  12 +++
 src/test/regress/sql/copy2.sql      | 208 ++++++++++++++++++++++++++++++++++-
 4 files changed, 434 insertions(+), 8 deletions(-)

diff --git a/src/test/regress/expected/copy2.out b/src/test/regress/expected/copy2.out
index e40287d..a088f72 100644
--- a/src/test/regress/expected/copy2.out
+++ b/src/test/regress/expected/copy2.out
@@ -254,18 +254,32 @@ It is "perfect".|
 "It is ""perfect"".","	"
 "",
 --test that we read consecutive LFs properly
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 COPY testnl FROM stdin CSV;
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL '2');
+SELECT * FROM testnl;
+ a |          b           | c 
+---+----------------------+---
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+(2 rows)
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 COPY testeoc FROM stdin CSV;
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL '2');
 COPY testeoc TO stdout CSV;
 a\.
 \.b
 c\.d
 "\."
 -- test handling of nonstandard null marker that violates escaping rules
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 COPY testnull TO stdout WITH NULL AS E'\\0';
 1	\\0
@@ -280,6 +294,15 @@ SELECT * FROM testnull;
     | 
 (4 rows)
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 2);
+SELECT * FROM testnull;
+ a  | b  
+----+----
+ 42 | \0
+    | 
+(2 rows)
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -349,6 +372,34 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 2);
+SELECT * FROM vistest;
+ a  
+----
+ a2
+ b
+(2 rows)
+
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 2);
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+COMMIT;
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 SELECT * FROM vistest;
  a 
@@ -409,7 +460,7 @@ SELECT * FROM vistest;
 (2 rows)
 
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -420,6 +471,8 @@ CREATE TEMP TABLE forcetest (
 -- should succeed with no effect ("b" remains an empty string, "c" remains NULL)
 BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 2);
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
  b |  c   
@@ -430,6 +483,8 @@ SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
 BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 2);
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
  c |  d   
@@ -486,6 +541,31 @@ select * from check_con_tbl;
    
 (2 rows)
 
+\d+ check_con_tbl
+                               Table "public.check_con_tbl"
+ Column |  Type   | Collation | Nullable | Default | Storage | Stats target | Description 
+--------+---------+-----------+----------+---------+---------+--------------+-------------
+ f1     | integer |           |          |         | plain   |              | 
+Check constraints:
+    "check_con_tbl_check" CHECK (check_con_function(check_con_tbl.*))
+
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 2);
+NOTICE:  input = {"f1":1}
+NOTICE:  input = {"f1":null}
+copy check_con_tbl from stdin with (parallel 2);
+NOTICE:  input = {"f1":0}
+ERROR:  new row for relation "check_con_tbl" violates check constraint "check_con_tbl_check"
+DETAIL:  Failing row contains (0).
+CONTEXT:  COPY check_con_tbl, line 1: "0"
+parallel worker
+select * from check_con_tbl;
+ f1 
+----
+  1
+   
+(2 rows)
+
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
 CREATE ROLE regress_rls_copy_user_colperms;
@@ -600,8 +680,130 @@ SELECT * FROM instead_of_insert_tbl;
 (2 rows)
 
 COMMIT;
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+COPY test_parallel_copy (a, b, c, d, e) from stdin with (PARALLEL '2');
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '2');
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '2');
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '2', FORMAT 'csv', HEADER);
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0');
+ERROR:  argument to option "parallel" must be a positive integer greater than zero
+LINE 1: COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0'...
+                                                        ^
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri from stdin with (FORMAT csv, DELIMITER ',', PARALLEL '2');
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', parallel '2') WHERE height > random() * 65;
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', parallel '2');
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- temporary table copy: should peform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+COPY temp_test (a) from stdin with (PARALLEL '2');
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) from stdin with (PARALLEL '2');
+ERROR:  column "xyz" of relation "test_parallel_copy" does not exist
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) from stdin with (PARALLEL '2');
+ERROR:  column "d" specified more than once
+-- missing data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL '2');
+ERROR:  invalid input syntax for type integer: ""
+CONTEXT:  COPY test_parallel_copy, line 0, column a: ""
+parallel worker
+COPY test_parallel_copy from stdin with (PARALLEL '2');
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2000	230	23	23"
+parallel worker
+COPY test_parallel_copy from stdin with (PARALLEL '2');
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2001	231	\N	\N"
+parallel worker
+-- extra data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL '2');
+ERROR:  extra data after last expected column
+CONTEXT:  COPY test_parallel_copy, line 1: "2002	232	40	50	60	70	80"
+parallel worker
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) from stdin with (delimiter ',', null 'x', PARALLEL '2') ;
+COPY test_parallel_copy from stdin WITH (DELIMITER ';', NULL '', PARALLEL '2');
+COPY test_parallel_copy from stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL '2');
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a = 50004;
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a > 60003;
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE f > 60003;
+ERROR:  column "f" does not exist
+LINE 1: ...arallel_copy from stdin WITH (PARALLEL '2') WHERE f > 60003;
+                                                             ^
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a = max(x.b);
+ERROR:  missing FROM-clause entry for table "x"
+LINE 1: ...llel_copy from stdin WITH (PARALLEL '2') WHERE a = max(x.b);
+                                                                  ^
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a IN (SELECT 1 FROM x);
+ERROR:  cannot use subquery in COPY FROM WHERE condition
+LINE 1: ...allel_copy from stdin WITH (PARALLEL '2') WHERE a IN (SELECT...
+                                                             ^
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a IN (generate_series(1,5));
+ERROR:  set-returning functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...l_copy from stdin WITH (PARALLEL '2') WHERE a IN (generate_s...
+                                                             ^
+COPY test_parallel_copy from stdin WITH(PARALLEL '2') WHERE a = row_number() over(b);
+ERROR:  window functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...llel_copy from stdin WITH(PARALLEL '2') WHERE a = row_number...
+                                                             ^
+-- check results of copy in
+SELECT * FROM test_parallel_copy;
+   a   | b  |     c      |    d    |    e    
+-------+----+------------+---------+---------
+     1 | 11 | test_c1    | test_d1 | test_e1
+     2 | 12 | test_c2    | test_d2 | test_e2
+       |  3 | stuff      | test_d3 | 
+       |  4 | stuff      | test_d4 | 
+       |  5 | stuff      | test_d5 | 
+       |    | 45         | 80      | 90
+       |    | x          | \x      | \x
+       |    | ,          | \,      | \
+  3000 |    | c          |         | 
+  4000 |    | C          |         | 
+  4001 |  1 | empty      |         | 
+  4002 |  2 | null       |         | 
+  4003 |  3 | Backslash  | \       | \
+  4004 |  4 | BackslashX | \X      | \X
+  4005 |  5 | N          | N       | N
+  4006 |  6 | BackslashN | \N      | \N
+  4007 |  7 | XX         | XX      | XX
+  4008 |  8 | Delimiter  | :       | :
+ 50004 | 25 | 35         | 45      | 55
+ 60004 | 25 | 35         | 45      | 55
+ 60005 | 26 | 36         | 46      | 56
+(21 rows)
+
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
 DROP TABLE x, y;
diff --git a/src/test/regress/input/copy.source b/src/test/regress/input/copy.source
index a1d529a..159c058 100644
--- a/src/test/regress/input/copy.source
+++ b/src/test/regress/input/copy.source
@@ -15,6 +15,13 @@ DELETE FROM onek;
 
 COPY onek FROM '@abs_builddir@/results/onek.data';
 
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+
+SELECT COUNT(*) FROM tenk1;
+
+TRUNCATE tenk1;
+
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
@@ -159,6 +166,11 @@ truncate parted_copytest;
 
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
 
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
+
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/output/copy.source b/src/test/regress/output/copy.source
index 938d355..c3003fe 100644
--- a/src/test/regress/output/copy.source
+++ b/src/test/regress/output/copy.source
@@ -9,6 +9,15 @@ COPY onek FROM '@abs_srcdir@/data/onek.data';
 COPY onek TO '@abs_builddir@/results/onek.data';
 DELETE FROM onek;
 COPY onek FROM '@abs_builddir@/results/onek.data';
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+SELECT COUNT(*) FROM tenk1;
+ count 
+-------
+ 10000
+(1 row)
+
+TRUNCATE tenk1;
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
 COPY person FROM '@abs_srcdir@/data/person.data';
@@ -113,6 +122,9 @@ insert into parted_copytest select x,1,'One' from generate_series(1011,1020) x;
 copy (select * from parted_copytest order by a) to '@abs_builddir@/results/parted_copytest.csv';
 truncate parted_copytest;
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/sql/copy2.sql b/src/test/regress/sql/copy2.sql
index 902f4fa..13104f4 100644
--- a/src/test/regress/sql/copy2.sql
+++ b/src/test/regress/sql/copy2.sql
@@ -157,7 +157,7 @@ COPY y TO stdout (FORMAT CSV, FORCE_QUOTE *);
 
 --test that we read consecutive LFs properly
 
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 
 COPY testnl FROM stdin CSV;
 1,"a field with two LFs
@@ -165,8 +165,16 @@ COPY testnl FROM stdin CSV;
 inside",2
 \.
 
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL '2');
+1,"a field with two LFs
+
+inside",2
+\.
+
+SELECT * FROM testnl;
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 
 COPY testeoc FROM stdin CSV;
 a\.
@@ -175,11 +183,19 @@ c\.d
 "\."
 \.
 
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL '2');
+a\.
+\.b
+c\.d
+"\."
+\.
+
 COPY testeoc TO stdout CSV;
 
 -- test handling of nonstandard null marker that violates escaping rules
 
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 
 COPY testnull TO stdout WITH NULL AS E'\\0';
@@ -191,6 +207,14 @@ COPY testnull FROM stdin WITH NULL AS E'\\0';
 
 SELECT * FROM testnull;
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 2);
+42	\\0
+\0	\0
+\.
+
+SELECT * FROM testnull;
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -235,6 +259,23 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 2);
+a2
+b
+\.
+SELECT * FROM vistest;
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 2);
+d2
+e
+\.
+SELECT * FROM vistest;
+COMMIT;
+SELECT * FROM vistest;
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 x
 y
@@ -284,7 +325,7 @@ SELECT * FROM vistest;
 COMMIT;
 SELECT * FROM vistest;
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -297,6 +338,10 @@ BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
 1,,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 2);
+1,,""
+\.
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
@@ -304,6 +349,10 @@ BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
 2,'a',,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 2);
+2,'a',,""
+\.
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
 -- should fail with not-null constraint violation
@@ -339,6 +388,16 @@ copy check_con_tbl from stdin;
 0
 \.
 select * from check_con_tbl;
+\d+ check_con_tbl
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 2);
+1
+\N
+\.
+copy check_con_tbl from stdin with (parallel 2);
+0
+\.
+select * from check_con_tbl;
 
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
@@ -440,8 +499,149 @@ test1
 SELECT * FROM instead_of_insert_tbl;
 COMMIT;
 
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+
+COPY test_parallel_copy (a, b, c, d, e) from stdin with (PARALLEL '2');
+1	11	test_c1	test_d1	test_e1
+2	12	test_c2	test_d2	test_e2
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '2');
+3	test_d3
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '2');
+4	test_d4
+5	test_d5
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '2', FORMAT 'csv', HEADER);
+b	d
+\.
+
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0');
+
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri from stdin with (FORMAT csv, DELIMITER ',', PARALLEL '2');
+10
+\.
+
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', parallel '2') WHERE height > random() * 65;
+60,60,60
+\.
+
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', parallel '2');
+60
+\.
+
+-- temporary table copy: should peform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+
+COPY temp_test (a) from stdin with (PARALLEL '2');
+10
+\.
+
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) from stdin with (PARALLEL '2');
+
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) from stdin with (PARALLEL '2');
+
+-- missing data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL '2');
+
+\.
+COPY test_parallel_copy from stdin with (PARALLEL '2');
+2000	230	23	23
+\.
+COPY test_parallel_copy from stdin with (PARALLEL '2');
+2001	231	\N	\N
+\.
+
+-- extra data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL '2');
+2002	232	40	50	60	70	80
+\.
+
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) from stdin with (delimiter ',', null 'x', PARALLEL '2') ;
+x,45,80,90
+x,\x,\\x,\\\x
+x,\,,\\\,,\\
+\.
+
+COPY test_parallel_copy from stdin WITH (DELIMITER ';', NULL '', PARALLEL '2');
+3000;;c;;
+\.
+
+COPY test_parallel_copy from stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL '2');
+4000:\X:C:\X:\X
+4001:1:empty::
+4002:2:null:\X:\X
+4003:3:Backslash:\\:\\
+4004:4:BackslashX:\\X:\\X
+4005:5:N:\N:\N
+4006:6:BackslashN:\\N:\\N
+4007:7:XX:\XX:\XX
+4008:8:Delimiter:\::\:
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a = 50004;
+50003	24	34	44	54
+50004	25	35	45 	55
+50005	26	36	46	56
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a > 60003;
+60001	22	32	42	52
+60002	23	33	43	53
+60003	24	34	44	54
+60004	25	35	45	55
+60005	26	36	46	56
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE f > 60003;
+
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a = max(x.b);
+
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a IN (SELECT 1 FROM x);
+
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a IN (generate_series(1,5));
+
+COPY test_parallel_copy from stdin WITH(PARALLEL '2') WHERE a = row_number() over(b);
+
+-- check results of copy in
+SELECT * FROM test_parallel_copy;
+
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
 DROP TABLE x, y;
-- 
1.8.3.1

0006-Parallel-Copy-For-Binary-Format-Files.patchapplication/octet-stream; name=0006-Parallel-Copy-For-Binary-Format-Files.patchDownload
From be5da9036b223be38d0df4617781eb02634ecdac Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddy@enterprisedb.com>
Date: Wed, 24 Jun 2020 13:12:55 +0530
Subject: [PATCH 6/6] Parallel Copy For Binary Format Files

Leader reads data from the file into the DSM data blocks each of 64K size.
It also identifies each tuple data block id, start offset, end offset,
tuple size and updates this information in the ring data structure.
Workers parallely read the tuple information from the ring data structure,
the actual tuple data from the data blocks and parallely insert the tuples
into the table.
---
 src/backend/commands/copy.c | 642 ++++++++++++++++++++++++++++++++----
 1 file changed, 572 insertions(+), 70 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index e8a89a40a0..e1f03241e8 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -219,6 +219,16 @@ typedef struct ParallelCopyLineBuf
 	uint64				cur_lineno;	/* line number for error messages */
 }ParallelCopyLineBuf;
 
+/*
+ * Tuple boundary information used for parallel copy
+ * for binary format files.
+ */
+typedef struct ParallelCopyTupleInfo
+{
+	uint32 offset;
+	uint32 block_id;
+}ParallelCopyTupleInfo;
+
 /*
  * Parallel copy data information.
  */
@@ -240,6 +250,11 @@ typedef struct ParallelCopyData
 
 	/* Current position in worker_line_buf */
 	uint32				worker_line_buf_pos;
+
+	/*
+	 * For binary formatted files
+	 */
+	ParallelCopyDataBlock *curr_data_block;
 }ParallelCopyData;
 
 /*
@@ -397,6 +412,7 @@ typedef struct ParallelCopyCommonKeyData
 	/* Working state for COPY FROM */
 	AttrNumber          num_defaults;
 	Oid                 relid;
+	bool 				binary;
 }ParallelCopyCommonKeyData;
 
 /*
@@ -697,6 +713,51 @@ if (!IsParallelCopy()) \
 else \
 	return pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
 
+/*
+ * CHECK_FIELD_COUNT - Handles the error cases for field count
+ * for binary format files.
+ */
+#define CHECK_FIELD_COUNT \
+{\
+	if (fld_count == -1) \
+	{ \
+		if (IsParallelCopy() && \
+			!IsLeader()) \
+			return true; \
+		else \
+		{ \
+			/* \
+			* Received EOF marker.  In a V3-protocol copy, wait for the \
+			* protocol-level EOF, and complain if it doesn't come \
+			* immediately.  This ensures that we correctly handle CopyFail, \
+			* if client chooses to send that now. \
+			* \
+			* Note that we MUST NOT try to read more data in an old-protocol \
+			* copy, since there is no protocol-level EOF marker then.  We \
+			* could go either way for copy from file, but choose to throw \
+			* error if there's data after the EOF marker, for consistency \
+			* with the new-protocol case. \
+			*/ \
+			char		dummy; \
+			if (cstate->copy_dest != COPY_OLD_FE && \
+				CopyGetData(cstate, &dummy, 1, 1) > 0) \
+				ereport(ERROR, \
+						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+						errmsg("received copy data after EOF marker"))); \
+			if (IsParallelCopy() && \
+				IsLeader()) \
+				return true; \
+			else \
+				return false; \
+		} \
+	} \
+	if (fld_count != cstate->max_fields) \
+		ereport(ERROR, \
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+				errmsg("row field count is %d, expected %d", \
+				(int) fld_count, cstate->max_fields))); \
+}
+
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
 
@@ -751,6 +812,16 @@ static void PopulateCatalogInformation(CopyState cstate);
 static pg_attribute_always_inline uint32 GetLinePosition(CopyState cstate);
 static pg_attribute_always_inline copy_data_source_cb LookupParallelCopyFnPtr(const char *funcname);
 static pg_attribute_always_inline char* LookupParallelCopyFnStr(copy_data_source_cb fn_addr);
+static uint32 WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info);
+static pg_attribute_always_inline bool CopyReadBinaryTupleLeader(CopyState cstate);
+static pg_attribute_always_inline void CopyReadBinaryAttributeLeader(CopyState cstate,
+										FmgrInfo *flinfo, Oid typioparam, int32 typmod,
+										uint32 *new_block_pos, int m, ParallelCopyTupleInfo *tuple_start_info_ptr,
+										ParallelCopyTupleInfo *tuple_end_info_ptr, uint32 *line_size);
+static pg_attribute_always_inline bool CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls);
+static pg_attribute_always_inline Datum CopyReadBinaryAttributeWorker(CopyState cstate, FmgrInfo *flinfo,
+										  Oid typioparam, int32 typmod, bool *isnull);
+static void AdjustFieldInfo(CopyState cstate, uint8 mode);
 
 /*
  * CopyCommonInfoForWorker - Copy shared_cstate using cstate information.
@@ -769,6 +840,7 @@ CopyCommonInfoForWorker(CopyState cstate, ParallelCopyCommonKeyData *shared_csta
 	shared_cstate->convert_selectively = cstate->convert_selectively;
 	shared_cstate->num_defaults = cstate->num_defaults;
 	shared_cstate->relid = cstate->pcdata->relid;
+	shared_cstate->binary = cstate->binary;
 }
 
 /*
@@ -997,8 +1069,8 @@ FindInsertMethod(CopyState cstate)
 static pg_attribute_always_inline bool
 IsParallelCopyAllowed(CopyState cstate)
 {
-	/* Parallel copy not allowed for frontend (2.0 protocol) & binary option. */
-	if ((cstate->copy_dest == COPY_OLD_FE) || cstate->binary)
+	/* Parallel copy not allowed for frontend (2.0 protocol). */
+	if (cstate->copy_dest == COPY_OLD_FE)
 		return false;
 
 	/* Check if copy is into foreign table or temporary table. */
@@ -1299,6 +1371,7 @@ ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
 	cstate->convert_selectively = shared_cstate->convert_selectively;
 	cstate->num_defaults = shared_cstate->num_defaults;
 	pcdata->relid = shared_cstate->relid;
+	cstate->binary = shared_cstate->binary;
 
 	PopulateGlobalsForCopyFrom(cstate, tup_desc, attnamelist);
 
@@ -1314,7 +1387,7 @@ ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
 	initStringInfo(&cstate->attribute_buf);
 
 	initStringInfo(&cstate->line_buf);
-	for (count = 0; count < WORKER_CHUNK_COUNT;count++)
+	for (count = 0; count < WORKER_CHUNK_COUNT; count++)
 		initStringInfo(&pcdata->worker_line_buf[count].line_buf);
 
 	cstate->line_buf_converted = false;
@@ -1679,32 +1752,55 @@ ParallelCopyLeader(CopyState cstate)
 	/* Execute the before statement triggers from the leader */
 	ExecBeforeStmtTrigger(cstate);
 
-	/* On input just throw the header line away. */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (!cstate->binary)
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
+		/* On input just throw the header line away. */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
 		{
-			pcshared_info->is_read_in_progress = false;
-			return;			/* done */
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+			{
+				pcshared_info->is_read_in_progress = false;
+				return;			/* done */
+			}
 		}
-	}
 
-	for (;;)
+		for (;;)
+		{
+			bool done;
+			cstate->cur_lineno++;
+
+			/* Actually read the line into memory here. */
+			done = CopyReadLine(cstate);
+
+			/*
+			* EOF at start of line means we're done.  If we see EOF after some
+			* characters, we act as though it was newline followed by EOF, ie,
+			* process the line and then exit loop on next iteration.
+			*/
+			if (done && cstate->line_buf.len == 0)
+				break;
+		}
+	}
+	else
 	{
-		bool done;
-		cstate->cur_lineno++;
+		/* binary format */
+		cstate->pcdata->curr_data_block = NULL;
+		cstate->raw_buf_index = 0;
+		pcshared_info->populated = 0;
+		cstate->cur_lineno = 0;
+		cstate->max_fields = list_length(cstate->attnumlist);
 
-		/* Actually read the line into memory here. */
-		done = CopyReadLine(cstate);
+		for (;;)
+		{
+			bool eof = false;
+			cstate->cur_lineno++;
 
-		/*
-		 * EOF at start of line means we're done.  If we see EOF after some
-		 * characters, we act as though it was newline followed by EOF, ie,
-		 * process the line and then exit loop on next iteration.
-		 */
-		if (done && cstate->line_buf.len == 0)
-			break;
+			eof = CopyReadBinaryTupleLeader(cstate);
+
+			if (eof)
+				break;
+		}
 	}
 
 	pcshared_info->is_read_in_progress = false;
@@ -1712,7 +1808,425 @@ ParallelCopyLeader(CopyState cstate)
 }
 
 /*
- * GetLinePosition - return the line position that worker should process.
+ * AdjustFieldInfo - gets a new block, updates the
+ * current offset, calculates the skip bytes.
+ * Works in two modes, 1 for field count
+ * 2 for field size
+ */
+static void
+AdjustFieldInfo(CopyState cstate, uint8 mode)
+{
+	ParallelCopyDataBlock *data_block = NULL;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	uint8 movebytes = 0;
+	uint32 block_pos;
+	uint32 prev_block_pos;
+	int readbytes = 0;
+
+	prev_block_pos = pcshared_info->cur_block_pos;
+
+	block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+	movebytes = DATA_BLOCK_SIZE - cstate->raw_buf_index;
+
+	cstate->pcdata->curr_data_block->skip_bytes = movebytes;
+
+	data_block = &pcshared_info->data_blocks[block_pos];
+
+	if (movebytes > 0)
+		memmove(&data_block->data[0], &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index],
+			movebytes);
+
+	elog(DEBUG1, "LEADER - field info is spread across data blocks - moved %d bytes from current block %u to %u block",
+		movebytes, prev_block_pos, block_pos);
+
+	readbytes = CopyGetData(cstate, &data_block->data[movebytes], 1, (DATA_BLOCK_SIZE - movebytes));
+
+	elog(DEBUG1, "LEADER - bytes read from file after field info is moved to next data block %d", readbytes);
+
+	if (cstate->reached_eof)
+		ereport(ERROR,
+			(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				errmsg("unexpected EOF in COPY data")));
+
+	if (mode == 1)
+	{
+		cstate->pcdata->curr_data_block = data_block;
+		cstate->raw_buf_index = 0;
+	}
+	else if(mode == 2)
+	{
+		ParallelCopyDataBlock *prev_data_block = NULL;
+		prev_data_block = cstate->pcdata->curr_data_block;
+		prev_data_block->following_block = block_pos;
+		cstate->pcdata->curr_data_block = data_block;
+
+		if (prev_data_block->curr_blk_completed  == false)
+			prev_data_block->curr_blk_completed = true;
+
+		cstate->raw_buf_index = 0;
+	}
+}
+
+/*
+ * CopyReadBinaryTupleLeader - leader reads data from binary formatted file
+ * to data blocks and identies tuple boundaries/offsets so that workers
+ * can work on the data blocks data.
+ */
+static pg_attribute_always_inline bool
+CopyReadBinaryTupleLeader(CopyState cstate)
+{
+	int readbytes = 0;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	uint32 block_pos;
+	int16		fld_count;
+	ListCell   *cur;
+	FmgrInfo   *in_functions = cstate->in_functions;
+	Oid		   *typioparams = cstate->typioparams;
+	TupleDesc	tupDesc = RelationGetDescr(cstate->rel);
+	uint32      new_block_pos;
+	uint32      line_size = -1;
+	ParallelCopyTupleInfo curr_tuple_start_info;
+	ParallelCopyTupleInfo curr_tuple_end_info;
+
+	curr_tuple_start_info.block_id = -1;
+	curr_tuple_start_info.offset = -1;
+	curr_tuple_end_info.block_id = -1;
+	curr_tuple_end_info.offset = -1;
+
+	if (cstate->pcdata->curr_data_block == NULL)
+	{
+		block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+		cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[block_pos];
+
+		cstate->raw_buf_index = 0;
+
+		readbytes = CopyGetData(cstate, &cstate->pcdata->curr_data_block->data, 1, DATA_BLOCK_SIZE);
+
+		elog(DEBUG1, "LEADER - bytes read from file %d", readbytes);
+
+		if (cstate->reached_eof)
+			return true;
+	}
+
+	if (cstate->raw_buf_index + sizeof(fld_count) >= (DATA_BLOCK_SIZE - 1))
+		AdjustFieldInfo(cstate, 1);
+
+	memcpy(&fld_count, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_count));
+
+	fld_count = (int16) pg_ntoh16(fld_count);
+
+	CHECK_FIELD_COUNT;
+
+	cstate->raw_buf_index = cstate->raw_buf_index + sizeof(fld_count);
+	new_block_pos = pcshared_info->cur_block_pos;
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			attnum = lfirst_int(cur);
+		int			m = attnum - 1;
+		Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+
+		CopyReadBinaryAttributeLeader(cstate,
+									&in_functions[m],
+									typioparams[m],
+									att->atttypmod,
+									&new_block_pos,
+									m,
+									&curr_tuple_start_info,
+									&curr_tuple_end_info,
+									&line_size);
+	}
+
+	if (line_size > 0)
+	{
+		int line_pos = UpdateBlockInLineInfo(cstate,
+											curr_tuple_start_info.block_id,
+											curr_tuple_start_info.offset,
+											line_size,
+											LINE_LEADER_POPULATED);
+
+		pcshared_info->populated++;
+
+		elog(DEBUG1, "LEADER - adding - block:%u, offset:%u, line size:%u line position:%d",
+						 curr_tuple_start_info.block_id,
+						 curr_tuple_start_info.offset,
+						 line_size, line_pos);
+	}
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryAttributeLeader - leader identifies boundaries/offsets
+ * for each attribute/column, it moves on to next data block if the
+ * attribute/column is spread across data blocks.
+ */
+static pg_attribute_always_inline void
+CopyReadBinaryAttributeLeader(CopyState cstate, FmgrInfo *flinfo,
+	Oid typioparam, int32 typmod, uint32 *new_block_pos,
+	int m, ParallelCopyTupleInfo *tuple_start_info_ptr,
+	ParallelCopyTupleInfo *tuple_end_info_ptr, uint32 *line_size)
+{
+	int32		fld_size;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+	if (m == 0)
+	{
+		tuple_start_info_ptr->block_id = pcshared_info->cur_block_pos;
+		/* raw_buf_index would have moved away size of field count bytes
+		   in the caller, so move back to store the tuple start offset.
+		*/
+		tuple_start_info_ptr->offset =  cstate->raw_buf_index - sizeof(int16);
+	}
+
+	if ((cstate->raw_buf_index + sizeof(fld_size)) >= (DATA_BLOCK_SIZE - 1))
+	{
+		AdjustFieldInfo(cstate, 2);
+		*new_block_pos = pcshared_info->cur_block_pos;
+	}
+
+	memcpy(&fld_size, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_size));
+
+	cstate->raw_buf_index = cstate->raw_buf_index + sizeof(fld_size);
+
+	fld_size = (int32) pg_ntoh32(fld_size);
+
+	if (fld_size == 0)
+		ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("unexpected EOF in COPY data")));
+
+	if (fld_size < -1)
+		ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("invalid field size")));
+
+	if ((DATA_BLOCK_SIZE-cstate->raw_buf_index) >= fld_size)
+	{
+		cstate->raw_buf_index = cstate->raw_buf_index + fld_size;
+	}
+	else
+	{
+		ParallelCopyDataBlock *data_block = NULL;
+		ParallelCopyDataBlock *prev_data_block = NULL;
+		uint32 block_pos;
+		int readbytes;
+
+		block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+		data_block = &pcshared_info->data_blocks[block_pos];
+
+		readbytes = CopyGetData(cstate, &data_block->data[0], 1, DATA_BLOCK_SIZE);
+
+		elog(DEBUG1, "LEADER - bytes read from file after detecting that tuple is spread across data blocks %d", readbytes);
+
+		if (cstate->reached_eof)
+			ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("unexpected EOF in COPY data")));
+
+		prev_data_block = cstate->pcdata->curr_data_block;
+		prev_data_block->following_block = block_pos;
+
+		if (prev_data_block->curr_blk_completed  == false)
+			prev_data_block->curr_blk_completed = true;
+
+		cstate->pcdata->curr_data_block = data_block;
+		cstate->raw_buf_index = fld_size - (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+		*new_block_pos = block_pos;
+	}
+
+	if (m == cstate->max_fields - 1)
+	{
+		tuple_end_info_ptr->block_id = *new_block_pos;
+		tuple_end_info_ptr->offset =  cstate->raw_buf_index - 1;
+
+		if (tuple_start_info_ptr->block_id == tuple_end_info_ptr->block_id)
+		{
+			elog(DEBUG1,"LEADER - tuple lies in a single data block");
+
+			*line_size = tuple_end_info_ptr->offset - tuple_start_info_ptr->offset + 1;
+			pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[tuple_start_info_ptr->block_id].unprocessed_line_parts, 1);
+		}
+		else
+		{
+			uint32 following_block_id = pcshared_info->data_blocks[tuple_start_info_ptr->block_id].following_block;
+
+			elog(DEBUG1,"LEADER - tuple is spread across data blocks");
+
+			*line_size = DATA_BLOCK_SIZE - tuple_start_info_ptr->offset -
+				pcshared_info->data_blocks[tuple_start_info_ptr->block_id].skip_bytes;
+
+			pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[tuple_start_info_ptr->block_id].unprocessed_line_parts, 1);
+
+			while (following_block_id != tuple_end_info_ptr->block_id)
+			{
+				*line_size = *line_size + DATA_BLOCK_SIZE - pcshared_info->data_blocks[following_block_id].skip_bytes;
+
+				pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[following_block_id].unprocessed_line_parts, 1);
+
+				following_block_id = pcshared_info->data_blocks[following_block_id].following_block;
+
+				if (following_block_id == -1)
+					break;
+			}
+
+			if (following_block_id != -1)
+				pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[following_block_id].unprocessed_line_parts, 1);
+
+			*line_size = *line_size + tuple_end_info_ptr->offset + 1;
+		}
+	}
+}
+
+/*
+ * CopyReadBinaryTupleWorker - each worker reads data from data blocks after
+ * getting leader-identified tuple offsets from ring data structure.
+ */
+static pg_attribute_always_inline bool
+CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls)
+{
+	uint32 line_pos;
+	ParallelCopyLineBoundary *line_info;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	int16		fld_count;
+	ListCell   *cur;
+	FmgrInfo   *in_functions = cstate->in_functions;
+	Oid		   *typioparams = cstate->typioparams;
+	TupleDesc	tupDesc = RelationGetDescr(cstate->rel);
+
+	line_pos = GetLinePosition(cstate);
+
+	if (line_pos == -1)
+		return true;
+
+	line_info = &pcshared_info->line_boundaries.ring[line_pos];
+	cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[line_info->first_block];
+	cstate->raw_buf_index = line_info->start_offset;
+
+	if (cstate->raw_buf_index + sizeof(fld_count) >= (DATA_BLOCK_SIZE - 1))
+		/*the case where field count spread across datablocks should never occur.
+		  as the leader would have moved it to next block*/
+		elog(DEBUG1, "WORKER - field count spread across datablocks should never occur");
+
+	memcpy(&fld_count, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_count));
+	fld_count = (int16) pg_ntoh16(fld_count);
+
+	CHECK_FIELD_COUNT;
+
+	cstate->raw_buf_index = cstate->raw_buf_index + sizeof(fld_count);
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			attnum = lfirst_int(cur);
+		int			m = attnum - 1;
+		Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+		cstate->cur_attname = NameStr(att->attname);
+
+		values[m] = CopyReadBinaryAttributeWorker(cstate,
+											&in_functions[m],
+											typioparams[m],
+											att->atttypmod,
+											&nulls[m]);
+		cstate->cur_attname = NULL;
+	}
+
+	pg_atomic_sub_fetch_u32(&cstate->pcdata->curr_data_block->unprocessed_line_parts, 1);
+	line_info->start_offset = -1;
+	pg_atomic_write_u32(&line_info->line_state, LINE_WORKER_PROCESSED);
+	pg_atomic_write_u32(&line_info->line_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryAttributeWorker - leader identifies boundaries/offsets
+ * for each attribute/column, it moves on to next data block if the
+ * attribute/column is spread across data blocks.
+ */
+static pg_attribute_always_inline Datum
+CopyReadBinaryAttributeWorker(CopyState cstate, FmgrInfo *flinfo,
+		Oid typioparam, int32 typmod, bool *isnull)
+{
+	int32		fld_size;
+	Datum		result;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+	if ((cstate->raw_buf_index + sizeof(fld_size)) >= (DATA_BLOCK_SIZE - 1))
+	{
+		ParallelCopyDataBlock *prev_data_block = cstate->pcdata->curr_data_block;
+
+		elog(DEBUG1, "WORKER - field size is spread across data blocks");
+
+		cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[cstate->pcdata->curr_data_block->following_block];
+		pg_atomic_sub_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+		cstate->raw_buf_index = 0;
+	}
+
+	memcpy(&fld_size, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_size));
+	fld_size = (int32) pg_ntoh32(fld_size);
+
+	if (fld_size == 0)
+		ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("unexpected EOF in COPY data")));
+
+	if (fld_size < -1)
+		ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("invalid field size")));
+
+	cstate->raw_buf_index = cstate->raw_buf_index + sizeof(fld_size);
+
+	/* reset attribute_buf to empty, and load raw data in it */
+	resetStringInfo(&cstate->attribute_buf);
+
+	enlargeStringInfo(&cstate->attribute_buf, fld_size);
+
+	if ((DATA_BLOCK_SIZE - cstate->raw_buf_index) >= fld_size)
+	{
+		elog(DEBUG1, "WORKER - tuple lies in single data block");
+
+		memcpy(&cstate->attribute_buf.data[0],&cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], fld_size);
+		cstate->raw_buf_index = cstate->raw_buf_index + fld_size;
+	}
+	else
+	{
+		ParallelCopyDataBlock *prev_data_block = cstate->pcdata->curr_data_block;
+
+		elog(DEBUG1, "WORKER - tuple is spread across data blocks");
+
+		memcpy(&cstate->attribute_buf.data[0], &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index],
+				(DATA_BLOCK_SIZE - cstate->raw_buf_index));
+		cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[cstate->pcdata->curr_data_block->following_block];
+		pg_atomic_sub_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+		memcpy(&cstate->attribute_buf.data[DATA_BLOCK_SIZE - cstate->raw_buf_index],
+			&cstate->pcdata->curr_data_block->data[0], (fld_size - (DATA_BLOCK_SIZE - cstate->raw_buf_index)));
+		cstate->raw_buf_index = fld_size - (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+	}
+
+	cstate->attribute_buf.len = fld_size;
+	cstate->attribute_buf.data[fld_size] = '\0';
+
+	/* Call the column type's binary input converter */
+	result = ReceiveFunctionCall(flinfo, &cstate->attribute_buf,
+								 typioparam, typmod);
+
+	/* Trouble if it didn't eat the whole buffer */
+	if (cstate->attribute_buf.cursor != cstate->attribute_buf.len)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+				 errmsg("incorrect binary data format")));
+
+	*isnull = false;
+	return result;
+}
+
+/*
+ * GetLinePosition - return the line position that worker should pcdata->process.
  */
 static uint32
 GetLinePosition(CopyState cstate)
@@ -1797,6 +2311,7 @@ GetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
 		{
 			dataBlkPtr->curr_blk_completed = false;
 			dataBlkPtr->skip_bytes = 0;
+			dataBlkPtr->following_block = -1;
 			pcshared_info->cur_block_pos = block_pos;
 			return block_pos;
 		}
@@ -5449,60 +5964,47 @@ NextCopyFrom(CopyState cstate, ExprContext *econtext,
 	else
 	{
 		/* binary */
-		int16		fld_count;
-		ListCell   *cur;
-
-		cstate->cur_lineno++;
-
-		if (!CopyGetInt16(cstate, &fld_count))
+		if (!IsParallelCopy())
 		{
-			/* EOF detected (end of file, or protocol-level EOF) */
-			return false;
-		}
+			int16		fld_count;
+			ListCell   *cur;
 
-		if (fld_count == -1)
-		{
-			/*
-			 * Received EOF marker.  In a V3-protocol copy, wait for the
-			 * protocol-level EOF, and complain if it doesn't come
-			 * immediately.  This ensures that we correctly handle CopyFail,
-			 * if client chooses to send that now.
-			 *
-			 * Note that we MUST NOT try to read more data in an old-protocol
-			 * copy, since there is no protocol-level EOF marker then.  We
-			 * could go either way for copy from file, but choose to throw
-			 * error if there's data after the EOF marker, for consistency
-			 * with the new-protocol case.
-			 */
-			char		dummy;
+			cstate->cur_lineno++;
+			cstate->max_fields = list_length(cstate->attnumlist);
 
-			if (cstate->copy_dest != COPY_OLD_FE &&
-				CopyGetData(cstate, &dummy, 1, 1) > 0)
-				ereport(ERROR,
-						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-						 errmsg("received copy data after EOF marker")));
-			return false;
-		}
+			if (!CopyGetInt16(cstate, &fld_count))
+			{
+				/* EOF detected (end of file, or protocol-level EOF) */
+				return false;
+			}
 
-		if (fld_count != attr_count)
-			ereport(ERROR,
-					(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-					 errmsg("row field count is %d, expected %d",
-							(int) fld_count, attr_count)));
+			CHECK_FIELD_COUNT;
 
-		foreach(cur, cstate->attnumlist)
+			foreach(cur, cstate->attnumlist)
+			{
+				int			attnum = lfirst_int(cur);
+				int			m = attnum - 1;
+				Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+
+				cstate->cur_attname = NameStr(att->attname);
+				values[m] = CopyReadBinaryAttribute(cstate,
+													&in_functions[m],
+													typioparams[m],
+													att->atttypmod,
+													&nulls[m]);
+				cstate->cur_attname = NULL;
+			}
+		}
+		else
 		{
-			int			attnum = lfirst_int(cur);
-			int			m = attnum - 1;
-			Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+			bool eof = false;
+			cstate->cur_lineno++;
+			cstate->max_fields = list_length(cstate->attnumlist);
 
-			cstate->cur_attname = NameStr(att->attname);
-			values[m] = CopyReadBinaryAttribute(cstate,
-												&in_functions[m],
-												typioparams[m],
-												att->atttypmod,
-												&nulls[m]);
-			cstate->cur_attname = NULL;
+			eof = CopyReadBinaryTupleWorker(cstate, values, nulls);
+
+			if (eof)
+				return false;
 		}
 	}
 
-- 
2.25.1

#105Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Bharath Rupireddy (#104)
6 attachment(s)
Re: Parallel copy

Hi,

0006 patch has some code clean up and issue fixes found during internal testing.

Attaching the latest patches herewith.

The order of applying the patches remains the same i.e. from 0001 to 0006.

With Regards,
Bharath Rupireddy.
EnterpriseDB: http://www.enterprisedb.com

Attachments:

0001-Copy-code-readjustment-to-support-parallel-copy.patchapplication/octet-stream; name=0001-Copy-code-readjustment-to-support-parallel-copy.patchDownload
From 4455d3e067bda56316bb292e5d010bdf40254fec Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Tue, 23 Jun 2020 06:49:22 +0530
Subject: [PATCH 1/6] Copy code readjustment to support parallel copy.

This patch has the copy code slightly readjusted so that the common code is
separated to functions/macros, these functions/macros will be used by the
workers in the parallel copy code of the upcoming patches. EOL removal is moved
from CopyReadLine to CopyReadLineText, this change was required because in case
of parallel copy the record identification and record updation is done in
CopyReadLineText, before record information is updated in shared memory the new
line characters should be removed.
---
 src/backend/commands/copy.c | 372 ++++++++++++++++++++++++++------------------
 1 file changed, 221 insertions(+), 151 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 6b1fd6d..65a504f 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -95,6 +95,9 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
+#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+#define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
+
 /*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
@@ -219,7 +222,6 @@ typedef struct CopyStateData
 	 * converts it.  Note: we guarantee that there is a \0 at
 	 * raw_buf[raw_buf_len].
 	 */
-#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
@@ -347,6 +349,88 @@ if (1) \
 	goto not_end_of_copy; \
 } else ((void) 0)
 
+/*
+ * CONVERT_TO_SERVER_ENCODING - convert contents to server encoding.
+ */
+#define CONVERT_TO_SERVER_ENCODING(cstate) \
+{ \
+	/* Done reading the line.  Convert it to server encoding. */ \
+	if (cstate->need_transcoding) \
+	{ \
+		char	   *cvt; \
+		cvt = pg_any_to_server(cstate->line_buf.data, \
+							   cstate->line_buf.len, \
+							   cstate->file_encoding); \
+		if (cvt != cstate->line_buf.data) \
+		{ \
+			/* transfer converted data back to line_buf */ \
+			resetStringInfo(&cstate->line_buf); \
+			appendBinaryStringInfo(&cstate->line_buf, cvt, strlen(cvt)); \
+			pfree(cvt); \
+		} \
+	} \
+	/* Now it's safe to use the buffer in error messages */ \
+	cstate->line_buf_converted = true; \
+}
+
+/*
+ * CLEAR_EOL_FROM_COPIED_DATA - Clear EOL from the copied data.
+ */
+#define CLEAR_EOL_FROM_COPIED_DATA(copy_line_data, copy_line_pos, copy_line_size) \
+{ \
+	/* \
+	 * If we didn't hit EOF, then we must have transferred the EOL marker \
+	 * to line_buf along with the data.  Get rid of it. \
+	 */ \
+   switch (cstate->eol_type) \
+   { \
+	   case EOL_NL: \
+		   Assert(copy_line_size >= 1); \
+		   Assert(copy_line_data[copy_line_pos - 1] == '\n'); \
+		   copy_line_data[copy_line_pos - 1] = '\0'; \
+		   copy_line_size--; \
+		   break; \
+	   case EOL_CR: \
+		   Assert(copy_line_size >= 1); \
+		   Assert(copy_line_data[copy_line_pos - 1] == '\r'); \
+		   copy_line_data[copy_line_pos - 1] = '\0'; \
+		   copy_line_size--; \
+		   break; \
+	   case EOL_CRNL: \
+		   Assert(copy_line_size >= 2); \
+		   Assert(copy_line_data[copy_line_pos - 2] == '\r'); \
+		   Assert(copy_line_data[copy_line_pos - 1] == '\n'); \
+		   copy_line_data[copy_line_pos - 2] = '\0'; \
+		   copy_line_size -= 2; \
+		   break; \
+	   case EOL_UNKNOWN: \
+		   /* shouldn't get here */ \
+		   Assert(false); \
+		   break; \
+   } \
+}
+
+/*
+ * CLEAR_EOL_LINE - Wrapper for clearing EOL.
+ */
+#define CLEAR_EOL_LINE() \
+if (!result && !IsHeaderLine()) \
+	CLEAR_EOL_FROM_COPIED_DATA(cstate->line_buf.data, \
+								cstate->line_buf.len, \
+								cstate->line_buf.len) \
+
+/*
+ * INCREMENTPROCESSED - Increment the lines processed.
+ */
+#define INCREMENTPROCESSED(processed)  \
+processed++;
+
+/*
+ * GETPROCESSED - Get the lines processed.
+ */
+#define GETPROCESSED(processed) \
+return processed;
+
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
 
@@ -392,6 +476,8 @@ static bool CopyGetInt32(CopyState cstate, int32 *val);
 static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 
+static void PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tup_desc,
+							   List *attnamelist);
 
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
@@ -793,6 +879,7 @@ CopyLoadRawBuf(CopyState cstate)
 {
 	int			nbytes;
 	int			inbytes;
+	int         minread = 1;
 
 	if (cstate->raw_buf_index < cstate->raw_buf_len)
 	{
@@ -804,8 +891,11 @@ CopyLoadRawBuf(CopyState cstate)
 	else
 		nbytes = 0;				/* no data need be saved */
 
+	if (cstate->copy_dest == COPY_NEW_FE)
+		minread = RAW_BUF_SIZE - nbytes;
+
 	inbytes = CopyGetData(cstate, cstate->raw_buf + nbytes,
-						  1, RAW_BUF_SIZE - nbytes);
+						  minread, RAW_BUF_SIZE - nbytes);
 	nbytes += inbytes;
 	cstate->raw_buf[nbytes] = '\0';
 	cstate->raw_buf_index = 0;
@@ -1463,7 +1553,6 @@ BeginCopy(ParseState *pstate,
 {
 	CopyState	cstate;
 	TupleDesc	tupDesc;
-	int			num_phys_attrs;
 	MemoryContext oldcontext;
 
 	/* Allocate workspace and zero all fields */
@@ -1629,6 +1718,24 @@ BeginCopy(ParseState *pstate,
 		tupDesc = cstate->queryDesc->tupDesc;
 	}
 
+	PopulateGlobalsForCopyFrom(cstate, tupDesc, attnamelist);
+	cstate->copy_dest = COPY_FILE;	/* default */
+
+	MemoryContextSwitchTo(oldcontext);
+
+	return cstate;
+}
+
+/*
+ * PopulateGlobalsForCopyFrom - Populates the common variables required for copy
+ * from operation. This is a helper function for BeginCopy function.
+ */
+static void
+PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tupDesc,
+							List *attnamelist)
+{
+	int			num_phys_attrs;
+
 	/* Generate or convert list of attributes to process */
 	cstate->attnumlist = CopyGetAttnums(tupDesc, cstate->rel, attnamelist);
 
@@ -1748,12 +1855,6 @@ BeginCopy(ParseState *pstate,
 		 pg_database_encoding_max_length() > 1);
 	/* See Multibyte encoding comment above */
 	cstate->encoding_embeds_ascii = PG_ENCODING_IS_CLIENT_ONLY(cstate->file_encoding);
-
-	cstate->copy_dest = COPY_FILE;	/* default */
-
-	MemoryContextSwitchTo(oldcontext);
-
-	return cstate;
 }
 
 /*
@@ -2646,32 +2747,11 @@ CopyMultiInsertInfoStore(CopyMultiInsertInfo *miinfo, ResultRelInfo *rri,
 }
 
 /*
- * Copy FROM file to relation.
+ * Check if the relation specified in copy from is valid.
  */
-uint64
-CopyFrom(CopyState cstate)
+static void
+CheckTargetRelValidity(CopyState cstate)
 {
-	ResultRelInfo *resultRelInfo;
-	ResultRelInfo *target_resultRelInfo;
-	ResultRelInfo *prevResultRelInfo = NULL;
-	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
-	ModifyTableState *mtstate;
-	ExprContext *econtext;
-	TupleTableSlot *singleslot = NULL;
-	MemoryContext oldcontext = CurrentMemoryContext;
-
-	PartitionTupleRouting *proute = NULL;
-	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
-	int			ti_options = 0; /* start with default options for insert */
-	BulkInsertState bistate = NULL;
-	CopyInsertMethod insertMethod;
-	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
-	uint64		processed = 0;
-	bool		has_before_insert_row_trig;
-	bool		has_instead_insert_row_trig;
-	bool		leafpart_use_multi_insert = false;
-
 	Assert(cstate->rel);
 
 	/*
@@ -2708,27 +2788,6 @@ CopyFrom(CopyState cstate)
 							RelationGetRelationName(cstate->rel))));
 	}
 
-	/*
-	 * If the target file is new-in-transaction, we assume that checking FSM
-	 * for free space is a waste of time.  This could possibly be wrong, but
-	 * it's unlikely.
-	 */
-	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
-		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
-		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
-		ti_options |= TABLE_INSERT_SKIP_FSM;
-
-	/*
-	 * Optimize if new relfilenode was created in this subxact or one of its
-	 * committed children and we won't see those rows later as part of an
-	 * earlier scan or command. The subxact test ensures that if this subxact
-	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
-	 * that the stronger test of exactly which subtransaction created it is
-	 * crucial for correctness of this optimization. The test for an earlier
-	 * scan or command tolerates false negatives. FREEZE causes other sessions
-	 * to see rows they would not see under MVCC, and a false negative merely
-	 * spreads that anomaly to the current session.
-	 */
 	if (cstate->freeze)
 	{
 		/*
@@ -2766,9 +2825,61 @@ CopyFrom(CopyState cstate)
 			ereport(ERROR,
 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 					 errmsg("cannot perform COPY FREEZE because the table was not created or truncated in the current subtransaction")));
+	}
+}
+
+/*
+ * Copy FROM file to relation.
+ */
+uint64
+CopyFrom(CopyState cstate)
+{
+	ResultRelInfo *resultRelInfo;
+	ResultRelInfo *target_resultRelInfo;
+	ResultRelInfo *prevResultRelInfo = NULL;
+	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
+	ModifyTableState *mtstate;
+	ExprContext *econtext;
+	TupleTableSlot *singleslot = NULL;
+	MemoryContext oldcontext = CurrentMemoryContext;
+
+	PartitionTupleRouting *proute = NULL;
+	ErrorContextCallback errcallback;
+	CommandId	mycid = GetCurrentCommandId(true);
+	int			ti_options = 0; /* start with default options for insert */
+	BulkInsertState bistate = NULL;
+	CopyInsertMethod insertMethod;
+	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
+	uint64		processed = 0;
+	bool		has_before_insert_row_trig;
+	bool		has_instead_insert_row_trig;
+	bool		leafpart_use_multi_insert = false;
+
+	CheckTargetRelValidity(cstate);
 
+	/*
+	 * If the target file is new-in-transaction, we assume that checking FSM
+	 * for free space is a waste of time.  This could possibly be wrong, but
+	 * it's unlikely.
+	 */
+	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
+		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
+		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
+		ti_options |= TABLE_INSERT_SKIP_FSM;
+
+	/*
+	 * Optimize if new relfilenode was created in this subxact or one of its
+	 * committed children and we won't see those rows later as part of an
+	 * earlier scan or command. The subxact test ensures that if this subxact
+	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
+	 * that the stronger test of exactly which subtransaction created it is
+	 * crucial for correctness of this optimization. The test for an earlier
+	 * scan or command tolerates false negatives. FREEZE causes other sessions
+	 * to see rows they would not see under MVCC, and a false negative merely
+	 * spreads that anomaly to the current session.
+	 */
+	if (cstate->freeze)
 		ti_options |= TABLE_INSERT_FROZEN;
-	}
 
 	/*
 	 * We need a ResultRelInfo so we can use the regular executor's
@@ -3261,7 +3372,7 @@ CopyFrom(CopyState cstate)
 			 * or FDW; this is the same definition used by nodeModifyTable.c
 			 * for counting tuples inserted by an INSERT command.
 			 */
-			processed++;
+			INCREMENTPROCESSED(processed)
 		}
 	}
 
@@ -3316,30 +3427,15 @@ CopyFrom(CopyState cstate)
 
 	FreeExecutorState(estate);
 
-	return processed;
+	GETPROCESSED(processed)
 }
 
 /*
- * Setup to read tuples from a file for COPY FROM.
- *
- * 'rel': Used as a template for the tuples
- * 'filename': Name of server-local file to read
- * 'attnamelist': List of char *, columns to include. NIL selects all cols.
- * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
- *
- * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ * PopulateCatalogInformation - populate the catalog information.
  */
-CopyState
-BeginCopyFrom(ParseState *pstate,
-			  Relation rel,
-			  const char *filename,
-			  bool is_program,
-			  copy_data_source_cb data_source_cb,
-			  List *attnamelist,
-			  List *options)
+static void
+PopulateCatalogInformation(CopyState cstate)
 {
-	CopyState	cstate;
-	bool		pipe = (filename == NULL);
 	TupleDesc	tupDesc;
 	AttrNumber	num_phys_attrs,
 				num_defaults;
@@ -3349,31 +3445,8 @@ BeginCopyFrom(ParseState *pstate,
 	Oid			in_func_oid;
 	int		   *defmap;
 	ExprState **defexprs;
-	MemoryContext oldcontext;
 	bool		volatile_defexprs;
 
-	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
-	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
-
-	/* Initialize state variables */
-	cstate->reached_eof = false;
-	cstate->eol_type = EOL_UNKNOWN;
-	cstate->cur_relname = RelationGetRelationName(cstate->rel);
-	cstate->cur_lineno = 0;
-	cstate->cur_attname = NULL;
-	cstate->cur_attval = NULL;
-
-	/* Set up variables to avoid per-attribute overhead. */
-	initStringInfo(&cstate->attribute_buf);
-	initStringInfo(&cstate->line_buf);
-	cstate->line_buf_converted = false;
-	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
-	cstate->raw_buf_index = cstate->raw_buf_len = 0;
-
-	/* Assign range table, we'll need it in CopyFrom. */
-	if (pstate)
-		cstate->range_table = pstate->p_rtable;
-
 	tupDesc = RelationGetDescr(cstate->rel);
 	num_phys_attrs = tupDesc->natts;
 	num_defaults = 0;
@@ -3451,6 +3524,54 @@ BeginCopyFrom(ParseState *pstate,
 	cstate->defexprs = defexprs;
 	cstate->volatile_defexprs = volatile_defexprs;
 	cstate->num_defaults = num_defaults;
+}
+
+/*
+ * Setup to read tuples from a file for COPY FROM.
+ *
+ * 'rel': Used as a template for the tuples
+ * 'filename': Name of server-local file to read
+ * 'attnamelist': List of char *, columns to include. NIL selects all cols.
+ * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
+ *
+ * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ */
+CopyState
+BeginCopyFrom(ParseState *pstate,
+			  Relation rel,
+			  const char *filename,
+			  bool is_program,
+			  copy_data_source_cb data_source_cb,
+			  List *attnamelist,
+			  List *options)
+{
+	CopyState	cstate;
+	bool		pipe = (filename == NULL);
+	MemoryContext oldcontext;
+
+	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	/* Initialize state variables */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/* Set up variables to avoid per-attribute overhead. */
+	initStringInfo(&cstate->attribute_buf);
+	initStringInfo(&cstate->line_buf);
+	cstate->line_buf_converted = false;
+	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+
+	/* Assign range table, we'll need it in CopyFrom. */
+	if (pstate)
+		cstate->range_table = pstate->p_rtable;
+
+	PopulateCatalogInformation(cstate);
 	cstate->is_program = is_program;
 
 	if (data_source_cb)
@@ -3860,60 +3981,8 @@ CopyReadLine(CopyState cstate)
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
-	else
-	{
-		/*
-		 * If we didn't hit EOF, then we must have transferred the EOL marker
-		 * to line_buf along with the data.  Get rid of it.
-		 */
-		switch (cstate->eol_type)
-		{
-			case EOL_NL:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CR:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\r');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CRNL:
-				Assert(cstate->line_buf.len >= 2);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 2] == '\r');
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len -= 2;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_UNKNOWN:
-				/* shouldn't get here */
-				Assert(false);
-				break;
-		}
-	}
-
-	/* Done reading the line.  Convert it to server encoding. */
-	if (cstate->need_transcoding)
-	{
-		char	   *cvt;
-
-		cvt = pg_any_to_server(cstate->line_buf.data,
-							   cstate->line_buf.len,
-							   cstate->file_encoding);
-		if (cvt != cstate->line_buf.data)
-		{
-			/* transfer converted data back to line_buf */
-			resetStringInfo(&cstate->line_buf);
-			appendBinaryStringInfo(&cstate->line_buf, cvt, strlen(cvt));
-			pfree(cvt);
-		}
-	}
-
-	/* Now it's safe to use the buffer in error messages */
-	cstate->line_buf_converted = true;
 
+	CONVERT_TO_SERVER_ENCODING(cstate)
 	return result;
 }
 
@@ -4277,6 +4346,7 @@ not_end_of_copy:
 	 * Transfer any still-uncopied data to line_buf.
 	 */
 	REFILL_LINEBUF;
+	CLEAR_EOL_LINE()
 
 	return result;
 }
-- 
1.8.3.1

0002-Framework-for-leader-worker-in-parallel-copy.patchapplication/octet-stream; name=0002-Framework-for-leader-worker-in-parallel-copy.patchDownload
From d8e1447263289fe2ad5ed40f620ab00b5f0bd407 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddy@enterprisedb.com>
Date: Wed, 24 Jun 2020 13:51:56 +0530
Subject: [PATCH 2/6] Framework for leader/worker in parallel copy

This patch has the framework for data structures in parallel copy, leader
initialization, worker initialization, shared memory updation, starting workers,
wait for workers and workers exiting.
---
 src/backend/access/transam/parallel.c       |   4 +
 src/backend/commands/copy.c                 | 865 +++++++++++++++++++-
 src/backend/replication/logical/tablesync.c |   2 +-
 src/include/commands/copy.h                 |   4 +
 src/tools/pgindent/typedefs.list            |   8 +
 5 files changed, 878 insertions(+), 5 deletions(-)

diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index 14a8690019..09e7a191d3 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -25,6 +25,7 @@
 #include "catalog/pg_enum.h"
 #include "catalog/storage.h"
 #include "commands/async.h"
+#include "commands/copy.h"
 #include "executor/execParallel.h"
 #include "libpq/libpq.h"
 #include "libpq/pqformat.h"
@@ -145,6 +146,9 @@ static const struct
 	},
 	{
 		"parallel_vacuum_main", parallel_vacuum_main
+	},
+	{
+		"ParallelCopyMain", ParallelCopyMain
 	}
 };
 
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 65a504fe96..c906655d0b 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -96,8 +96,137 @@ typedef enum CopyInsertMethod
 } CopyInsertMethod;
 
 #define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+
+#define DATA_BLOCK_SIZE RAW_BUF_SIZE
+#define RINGSIZE (10 * 1000)
+#define MAX_BLOCKS_COUNT 1000
+#define WORKER_CHUNK_COUNT 50	/* should be mod of RINGSIZE */
+
+#define	IsParallelCopy()		(cstate->is_parallel)
+#define IsLeader()				(cstate->pcdata->is_leader)
 #define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
 
+/*
+ * Copy data block information.
+ */
+typedef struct ParallelCopyDataBlock
+{
+	/* The number of unprocessed lines in the current block. */
+	pg_atomic_uint32 unprocessed_line_parts;
+
+	/*
+	 * If the current line data is continued into another block, following_block
+	 * will have the position where the remaining data need to be read.
+	 */
+	uint32	following_block;
+
+	/*
+	 * This flag will be set, when the leader finds out this block can be read
+	 * safely by the worker. This helps the worker to start processing the line
+	 * early where the line will be spread across many blocks and the worker
+	 * need not wait for the complete line to be processed.
+	 */
+	bool   curr_blk_completed;
+	char   data[DATA_BLOCK_SIZE]; /* data read from file */
+	uint8  skip_bytes;
+}ParallelCopyDataBlock;
+
+/*
+ * Individual line information.
+ * ParallelCopyLineBoundary is common data structure between leader & worker,
+ * this is protected by the following sequence in the leader & worker.
+ * Leader should operate in the following order:
+ * 1) update first_block, start_offset & cur_lineno in any order.
+ * 2) update line_size.
+ * 3) update line_state.
+ * Worker should operate in the following order:
+ * 1) read line_size.
+ * 2) only one worker should choose one line for processing, this is handled by
+ *    using pg_atomic_compare_exchange_u32, worker will change the sate to
+ *    LINE_WORKER_PROCESSING only if line_state is LINE_LEADER_POPULATED.
+ * 3) read first_block, start_offset & cur_lineno in any order.
+ */
+typedef struct ParallelCopyLineBoundary
+{
+	/* Position of the first block in data_blocks array. */
+	uint32				first_block;
+	uint32				start_offset;   /* start offset of the line */
+
+	/*
+	 * Size of the current line -1 means line is yet to be filled completely,
+	 * 0 means empty line, >0 means line filled with line size data.
+	 */
+	pg_atomic_uint32	line_size;
+	pg_atomic_uint32	line_state;		/* line state */
+	uint64				cur_lineno;		/* line number for error messages */
+}ParallelCopyLineBoundary;
+
+/*
+ * Circular queue used to store the line information.
+ */
+typedef struct ParallelCopyLineBoundaries
+{
+	/* Position for the leader to populate a line. */
+	uint32			leader_pos;
+
+	/* Data read from the file/stdin by the leader process. */
+	ParallelCopyLineBoundary	ring[RINGSIZE];
+}ParallelCopyLineBoundaries;
+
+/*
+ * Shared information among parallel copy workers. This will be allocated in the
+ * DSM segment.
+ */
+typedef struct ParallelCopyShmInfo
+{
+	bool					is_read_in_progress; /* file read status */
+
+	/*
+	 * Actual lines inserted by worker (some records will be filtered based on
+	 * where condition).
+	 */
+	pg_atomic_uint64			processed;
+	pg_atomic_uint64			total_worker_processed; /* total processed records by the workers */
+	uint64						populated; /* lines populated by leader */
+	uint32						cur_block_pos; /* current data block */
+	ParallelCopyDataBlock		data_blocks[MAX_BLOCKS_COUNT]; /* data block array */
+	FullTransactionId			full_transaction_id; /* xid for copy from statement */
+	CommandId					mycid;	/* command id */
+	ParallelCopyLineBoundaries	line_boundaries; /* line array */
+} ParallelCopyShmInfo;
+
+/*
+ * Parallel copy line buffer information.
+ */
+typedef struct ParallelCopyLineBuf
+{
+	StringInfoData		line_buf;
+	uint64				cur_lineno;	/* line number for error messages */
+}ParallelCopyLineBuf;
+
+/*
+ * Parallel copy data information.
+ */
+typedef struct ParallelCopyData
+{
+	Oid					relid;				/* relation id of the table */
+	ParallelCopyShmInfo	*pcshared_info;		/* common info in shared memory */
+	bool				is_leader;
+
+	/* line position which worker is processing */
+	uint32				worker_processed_pos;
+
+	/*
+	 * Local line_buf array, workers will copy it here and release the lines
+	 * for the leader to continue.
+	 */
+	ParallelCopyLineBuf	worker_line_buf[WORKER_CHUNK_COUNT];
+	uint32				worker_line_buf_count; /* Number of lines */
+
+	/* Current position in worker_line_buf */
+	uint32				worker_line_buf_pos;
+}ParallelCopyData;
+
 /*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
@@ -225,8 +354,66 @@ typedef struct CopyStateData
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
+	int			nworkers;
+	bool		is_parallel;
+	ParallelCopyData *pcdata;
 } CopyStateData;
 
+/*
+ * This structure helps in storing the common data from CopyStateData that are
+ * required by the workers. This information will then be allocated and stored
+ * into the DSM for the worker to retrieve and copy it to CopyStateData.
+ */
+typedef struct ParallelCopyCommonKeyData
+{
+	/* low-level state data */
+	CopyDest            copy_dest;		/* type of copy source/destination */
+	int                 file_encoding;	/* file or remote side's character encoding */
+	bool                need_transcoding;	/* file encoding diff from server? */
+	bool                encoding_embeds_ascii;	/* ASCII can be non-first byte? */
+
+	/* parameters from the COPY command */
+	bool                csv_mode;		/* Comma Separated Value format? */
+	bool                header_line;	/* CSV header line? */
+	int                 null_print_len; /* length of same */
+	bool                force_quote_all;	/* FORCE_QUOTE *? */
+	bool                convert_selectively;	/* do selective binary conversion? */
+
+	/* Working state for COPY FROM */
+	AttrNumber          num_defaults;
+	Oid                 relid;
+}ParallelCopyCommonKeyData;
+
+/*
+ * This structure will help in converting a List data type into the below
+ * structure format with the count having the number of elements in the list and
+ * the info having the List elements appended contigously. This converted
+ * structure will be allocated in shared memory and stored in DSM for the worker
+ * to retrieve and later convert it back to List data type.
+ */
+typedef struct ParallelCopyKeyListInfo
+{
+	int	count;		/* count of attributes */
+
+	/* string info in the form info followed by info1, info2... infon  */
+	char    info[1];
+} ParallelCopyKeyListInfo;
+
+/*
+ * List of internal parallel copy function pointers.
+ */
+static const struct
+{
+	char *fn_name;
+	copy_data_source_cb fn_addr;
+}			InternalParallelCopyFuncPtrs[] =
+
+{
+	{
+		"copy_read_data", copy_read_data
+	},
+};
+
 /* DestReceiver for COPY (query) TO */
 typedef struct
 {
@@ -256,6 +443,23 @@ typedef struct
 /* Trim the list of buffers back down to this number after flushing */
 #define MAX_PARTITION_BUFFERS	32
 
+/* DSM keys for parallel copy.  */
+#define PARALLEL_COPY_KEY_SHARED_INFO		    1
+#define PARALLEL_COPY_KEY_CSTATE				2
+#define PARALLEL_COPY_KEY_NULL_PRINT			3
+#define PARALLEL_COPY_KEY_NULL_PRINT_CLIENT		4
+#define PARALLEL_COPY_KEY_DELIM					5
+#define PARALLEL_COPY_KEY_QUOTE					6
+#define PARALLEL_COPY_KEY_ESCAPE				7
+#define PARALLEL_COPY_KEY_ATTNAME_LIST			8
+#define PARALLEL_COPY_KEY_FORCE_QUOTE_LIST  	9
+#define PARALLEL_COPY_KEY_NOT_NULL_LIST		   10
+#define PARALLEL_COPY_KEY_NULL_LIST			   11
+#define PARALLEL_COPY_KEY_CONVERT_LIST		   12
+#define PARALLEL_COPY_KEY_DATASOURCE_CB		   13
+#define PARALLEL_COPY_KEY_WHERE_CLAUSE_STR     14
+#define PARALLEL_COPY_KEY_RANGE_TABLE		   15
+
 /* Stores multi-insert data related to a single relation in CopyFrom. */
 typedef struct CopyMultiInsertBuffer
 {
@@ -476,9 +680,595 @@ static bool CopyGetInt32(CopyState cstate, int32 *val);
 static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 
+static pg_attribute_always_inline void EndParallelCopy(ParallelContext *pcxt);
 static void PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tup_desc,
 							   List *attnamelist);
+static pg_attribute_always_inline copy_data_source_cb LookupParallelCopyFnPtr(const char *funcname);
+static pg_attribute_always_inline char* LookupParallelCopyFnStr(copy_data_source_cb fn_addr);
+
+/*
+ * CopyCommonInfoForWorker - Copy shared_cstate using cstate information.
+ */
+static pg_attribute_always_inline void
+CopyCommonInfoForWorker(CopyState cstate, ParallelCopyCommonKeyData *shared_cstate)
+{
+	shared_cstate->copy_dest = cstate->copy_dest;
+	shared_cstate->file_encoding = cstate->file_encoding;
+	shared_cstate->need_transcoding = cstate->need_transcoding;
+	shared_cstate->encoding_embeds_ascii = cstate->encoding_embeds_ascii;
+	shared_cstate->csv_mode = cstate->csv_mode;
+	shared_cstate->header_line = cstate->header_line;
+	shared_cstate->null_print_len = cstate->null_print_len;
+	shared_cstate->force_quote_all = cstate->force_quote_all;
+	shared_cstate->convert_selectively = cstate->convert_selectively;
+	shared_cstate->num_defaults = cstate->num_defaults;
+	shared_cstate->relid = cstate->pcdata->relid;
+}
+
+/*
+ * RetrieveSharedString - Retrieve the string from shared memory.
+ */
+static void
+RetrieveSharedString(shm_toc *toc, int sharedkey, char **copystr)
+{
+	char *shared_str_val = (char *)shm_toc_lookup(toc, sharedkey, true);
+	if (shared_str_val)
+		*copystr = pstrdup(shared_str_val);
+}
+
+/*
+ * RetrieveSharedList - Retrieve the list from shared memory.
+ */
+static void
+RetrieveSharedList(shm_toc *toc, int sharedkey, List **copylist)
+{
+	ParallelCopyKeyListInfo *listinformation = (ParallelCopyKeyListInfo *)shm_toc_lookup(toc, sharedkey,
+														   true);
+	if (listinformation)
+	{
+		int	length  = 0;
+		int count;
+
+		for (count = 0; count < listinformation->count; count++)
+		{
+			char *attname = (char *)(listinformation->info + length);
+			length += strlen(attname) + 1;
+			*copylist = lappend(*copylist, makeString(attname));
+		}
+	}
+}
+
+/*
+ * CopyListSharedMemory - Copy the list into shared memory.
+ */
+static void
+CopyListSharedMemory(List *inputlist, Size memsize, ParallelCopyKeyListInfo *sharedlistinfo)
+{
+	ListCell   *l;
+	int			length  = 0;
+
+	MemSet(sharedlistinfo, 0, memsize);
+	foreach(l, inputlist)
+	{
+		char	   *name = strVal(lfirst(l));
+		memcpy((char *)(sharedlistinfo->info + length), name, strlen(name));
+		sharedlistinfo->count++;
+		length += strlen(name) + 1;
+	}
+}
+
+/*
+ * ComputeListSize - compute the list size.
+ */
+static int
+ComputeListSize(List *inputlist)
+{
+	int est_size = sizeof(int);
+	if (inputlist != NIL)
+	{
+		ListCell   *l;
+		foreach(l, inputlist)
+			est_size += strlen(strVal(lfirst(l))) + 1;
+	}
+
+	return est_size;
+}
+
+/*
+ * EstimateLineKeysStr - Estimate the size required in shared memory for the
+ * input string.
+ */
+static void
+EstimateLineKeysStr(ParallelContext *pcxt, char *inputstr)
+{
+	if (inputstr)
+	{
+		shm_toc_estimate_chunk(&pcxt->estimator, strlen(inputstr) + 1);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+}
+
+/*
+ * EstimateLineKeysList - Estimate the size required in shared memory for the
+ * input list.
+ */
+static void
+EstimateLineKeysList(ParallelContext *pcxt, List *inputlist,
+		Size *est_list_size)
+{
+	if (inputlist != NIL)
+	{
+		*est_list_size = ComputeListSize(inputlist);
+		shm_toc_estimate_chunk(&pcxt->estimator, *est_list_size);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+}
 
+/*
+ * InsertStringShm - Insert a string into shared memory.
+ */
+static void
+InsertStringShm(ParallelContext *pcxt, int key, char *inputstr)
+{
+	if (inputstr)
+	{
+		char *shmptr = (char *)shm_toc_allocate(pcxt->toc,
+												strlen(inputstr) + 1);
+		strcpy(shmptr, inputstr);
+		shm_toc_insert(pcxt->toc, key, shmptr);
+	}
+}
+
+/*
+ * InsertListShm - Insert a list into shared memory.
+ */
+static void
+InsertListShm(ParallelContext *pcxt, int key, List *inputlist,
+			  Size est_list_size)
+{
+	if (inputlist != NIL)
+	{
+		ParallelCopyKeyListInfo *sharedlistinfo = (ParallelCopyKeyListInfo *)shm_toc_allocate(pcxt->toc,
+																est_list_size);
+		CopyListSharedMemory(inputlist, est_list_size, sharedlistinfo);
+		shm_toc_insert(pcxt->toc, key, sharedlistinfo);
+	}
+}
+
+/*
+ * BeginParallelCopy - start parallel copy tasks.
+ *
+ * Get the number of workers required to perform the parallel copy. The data
+ * structures that are required by the parallel workers will be initialized, the
+ * size required in DSM will be calculated and the necessary keys will be loaded
+ * in the DSM. The specified number of workers will then be launched.
+ *
+ */
+static ParallelContext*
+BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
+{
+	ParallelContext *pcxt;
+	ParallelCopyShmInfo *shared_info_ptr;
+	ParallelCopyCommonKeyData *shared_cstate;
+	FullTransactionId full_transaction_id;
+	Size est_shared_info;
+	Size est_cstateshared;
+	Size est_att_list_size;
+	Size est_quote_list_size;
+	Size est_notnull_list_size;
+	Size est_null_list_size;
+	Size est_convert_list_size;
+	Size est_datasource_cb_size;
+	int  count = 0;
+	char *whereClauseStr = NULL;
+	char *rangeTableStr = NULL;
+	int  parallel_workers = 0;
+	ParallelCopyData *pcdata;
+
+	parallel_workers = Min(nworkers, max_worker_processes);
+
+	/* Can't perform copy in parallel */
+	if (parallel_workers <= 0)
+	{
+		elog(WARNING,
+			 "No workers available, copy will be run in non-parallel mode");
+		return NULL;
+	}
+
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	cstate->pcdata = pcdata;
+
+	EnterParallelMode();
+	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
+								 parallel_workers);
+	Assert(pcxt->nworkers > 0);
+
+	/*
+	 * Estimate size for shared information for PARALLEL_COPY_KEY_SHARED_INFO
+	 */
+	est_shared_info = sizeof(ParallelCopyShmInfo);
+	shm_toc_estimate_chunk(&pcxt->estimator, est_shared_info);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_CSTATE */
+	est_cstateshared = 	MAXALIGN(sizeof(ParallelCopyCommonKeyData));
+	shm_toc_estimate_chunk(&pcxt->estimator, est_cstateshared);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	EstimateLineKeysStr(pcxt, cstate->null_print);
+	EstimateLineKeysStr(pcxt, cstate->null_print_client);
+	EstimateLineKeysStr(pcxt, cstate->delim);
+	EstimateLineKeysStr(pcxt, cstate->quote);
+	EstimateLineKeysStr(pcxt, cstate->escape);
+
+	if (cstate->whereClause != NULL)
+	{
+		whereClauseStr = nodeToString(cstate->whereClause);
+		EstimateLineKeysStr(pcxt, whereClauseStr);
+	}
+
+	if (cstate->range_table != NULL)
+	{
+		rangeTableStr = nodeToString(cstate->range_table);
+		EstimateLineKeysStr(pcxt, rangeTableStr);
+	}
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_XID. */
+	shm_toc_estimate_chunk(&pcxt->estimator, sizeof(FullTransactionId));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_ATTNAME_LIST.
+	 */
+	EstimateLineKeysList(pcxt, attnamelist, &est_att_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_FORCE_QUOTE_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->force_quote, &est_quote_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_NOT_NULL_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->force_notnull,
+							 &est_notnull_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_NULL_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->force_null, &est_null_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_CONVERT_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->convert_select,
+							 &est_convert_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_DATASOURCE_CB.
+	 */
+	if (cstate->data_source_cb)
+	{
+		char *functionname = LookupParallelCopyFnStr(cstate->data_source_cb);
+		est_datasource_cb_size = strlen(functionname) + 1;
+		shm_toc_estimate_chunk(&pcxt->estimator, est_datasource_cb_size);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+
+	InitializeParallelDSM(pcxt);
+
+	/* If no DSM segment was available, back out (do serial copy) */
+	if (pcxt->seg == NULL)
+	{
+		EndParallelCopy(pcxt);
+		elog(WARNING,
+			 "DSM segments not available, copy will be run in non-parallel mode");
+		return NULL;
+	}
+
+	/* Allocate shared memory for PARALLEL_COPY_KEY_SHARED_INFO */
+	shared_info_ptr = (ParallelCopyShmInfo *) shm_toc_allocate(pcxt->toc,
+													   est_shared_info);
+	MemSet(shared_info_ptr, 0, est_shared_info);
+	shared_info_ptr->is_read_in_progress = true;
+	shared_info_ptr->cur_block_pos = -1;
+	shared_info_ptr->full_transaction_id = full_transaction_id;
+	shared_info_ptr->mycid = GetCurrentCommandId(true);
+	for (count = 0; count < RINGSIZE; count++)
+	{
+		ParallelCopyLineBoundary *lineInfo = &shared_info_ptr->line_boundaries.ring[count];
+		pg_atomic_init_u32(&(lineInfo->line_size), -1);
+	}
+
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_SHARED_INFO, shared_info_ptr);
+	pcdata->pcshared_info = shared_info_ptr;
+	pcdata->relid = relid;
+
+	/* Store shared build state, for which we reserved space. */
+	shared_cstate = (ParallelCopyCommonKeyData *)shm_toc_allocate(pcxt->toc,
+															est_cstateshared);
+
+	/* copy cstate variables. */
+	CopyCommonInfoForWorker(cstate, shared_cstate);
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_CSTATE, shared_cstate);
+
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_NULL_PRINT, cstate->null_print);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_NULL_PRINT_CLIENT,
+					  cstate->null_print_client);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_DELIM, cstate->delim);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_QUOTE, cstate->quote);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_ESCAPE, cstate->escape);
+
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_ATTNAME_LIST,
+					attnamelist, est_att_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_FORCE_QUOTE_LIST,
+					cstate->force_quote, est_quote_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_NOT_NULL_LIST,
+					cstate->force_notnull, est_notnull_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_NULL_LIST, cstate->force_null,
+					est_null_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_CONVERT_LIST,
+					cstate->convert_select, est_convert_list_size);
+
+	if (cstate->data_source_cb)
+	{
+		char *functionname = LookupParallelCopyFnStr(cstate->data_source_cb);
+		char *data_source_cb = (char *) shm_toc_allocate(pcxt->toc,
+														 est_datasource_cb_size);
+		strcpy(data_source_cb, functionname);
+		shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_DATASOURCE_CB,
+					   data_source_cb);
+	}
+
+	if (cstate->whereClause)
+		InsertStringShm(pcxt, PARALLEL_COPY_KEY_WHERE_CLAUSE_STR,
+						whereClauseStr);
+
+	if(cstate->range_table)
+		InsertStringShm(pcxt, PARALLEL_COPY_KEY_RANGE_TABLE, rangeTableStr);
+
+	LaunchParallelWorkers(pcxt);
+	if (pcxt->nworkers_launched == 0)
+	{
+		EndParallelCopy(pcxt);
+		elog(WARNING,
+			 "No workers available, copy will be run in non-parallel mode");
+		return NULL;
+	}
+
+	/*
+	 * Caller needs to wait for all launched workers when we return.  Make sure
+	 * that the failure-to-start case will not hang forever.
+	 */
+	WaitForParallelWorkersToAttach(pcxt);
+
+	pcdata->is_leader = true;
+	cstate->is_parallel = true;
+	return pcxt;
+}
+
+/*
+ * EndParallelCopy - end the parallel copy tasks.
+ */
+static pg_attribute_always_inline void
+EndParallelCopy(ParallelContext *pcxt)
+{
+	Assert(!IsParallelWorker());
+
+	DestroyParallelContext(pcxt);
+	ExitParallelMode();
+}
+
+/*
+ * ParallelWorkerInitialization - Initialize parallel worker.
+ */
+static void
+ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
+		CopyState cstate, List *attnamelist)
+{
+	uint32		count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	cstate->copy_dest = shared_cstate->copy_dest;
+	cstate->file_encoding = shared_cstate->file_encoding;
+	cstate->need_transcoding = shared_cstate->need_transcoding;
+	cstate->encoding_embeds_ascii = shared_cstate->encoding_embeds_ascii;
+	cstate->csv_mode = shared_cstate->csv_mode;
+	cstate->header_line = shared_cstate->header_line;
+	cstate->null_print_len = shared_cstate->null_print_len;
+	cstate->force_quote_all = shared_cstate->force_quote_all;
+	cstate->convert_selectively = shared_cstate->convert_selectively;
+	cstate->num_defaults = shared_cstate->num_defaults;
+	pcdata->relid = shared_cstate->relid;
+
+	PopulateGlobalsForCopyFrom(cstate, tup_desc, attnamelist);
+
+	/* Initialize state variables. */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/* Set up variables to avoid per-attribute overhead. */
+	initStringInfo(&cstate->attribute_buf);
+
+	initStringInfo(&cstate->line_buf);
+	for (count = 0; count < WORKER_CHUNK_COUNT;count++)
+		initStringInfo(&pcdata->worker_line_buf[count].line_buf);
+
+	cstate->line_buf_converted = false;
+	cstate->raw_buf = NULL;
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+}
+/*
+ * ParallelCopyMain - parallel copy worker's code.
+ *
+ * Where clause handling, convert tuple to columns, add default null values for
+ * the missing columns that are not present in that record. Find the partition
+ * if it is partitioned table, invoke before row insert Triggers, handle
+ * constraints and insert the tuples.
+ */
+void
+ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
+{
+	CopyState cstate;
+	ParallelCopyData *pcdata;
+	ParallelCopyShmInfo *pcshared_info;
+	ParallelCopyCommonKeyData *shared_cstate;
+	Relation	rel = NULL;
+	MemoryContext oldcontext;
+	List *attlist = NIL;
+	char *data_source_cb;
+	char *whereClauseStr = NULL;
+	char *rangeTableStr = NULL;
+
+	/* Allocate workspace and zero all fields. */
+	cstate = (CopyStateData *) palloc0(sizeof(CopyStateData));
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	cstate->pcdata = pcdata;
+	pcdata->is_leader = false;
+	pcdata->worker_processed_pos = -1;
+	cstate->is_parallel = true;
+
+	/*
+	 * We allocate everything used by a cstate in a new memory context. This
+	 * avoids memory leaks during repeated use of COPY in a query.
+	 */
+	cstate->copycontext = AllocSetContextCreate(CurrentMemoryContext,
+												"COPY",
+												ALLOCSET_DEFAULT_SIZES);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	pcshared_info = (ParallelCopyShmInfo *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_SHARED_INFO,
+														false);
+
+	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
+
+	pcdata->pcshared_info = pcshared_info;
+
+	shared_cstate = (ParallelCopyCommonKeyData *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE,
+														   false);
+
+	cstate->null_print = (char *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_NULL_PRINT,
+												true);
+	cstate->null_print_client = (char *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_NULL_PRINT_CLIENT,
+													   true);
+
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_DELIM, &cstate->delim);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_QUOTE, &cstate->quote);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_ESCAPE, &cstate->escape);
+
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_ATTNAME_LIST, &attlist);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_FORCE_QUOTE_LIST, &cstate->force_quote);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_NOT_NULL_LIST, &cstate->force_notnull);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_NULL_LIST, &cstate->force_null);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_CONVERT_LIST, &cstate->convert_select);
+	data_source_cb = (char *)shm_toc_lookup(toc,
+											PARALLEL_COPY_KEY_DATASOURCE_CB,
+											true);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_WHERE_CLAUSE_STR, &whereClauseStr);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_RANGE_TABLE, &rangeTableStr);
+
+	if (data_source_cb)
+		cstate->data_source_cb = LookupParallelCopyFnPtr(data_source_cb);
+
+	if (whereClauseStr)
+	{
+		Node *whereClauseCnvrtdFrmStr = (Node *) stringToNode(whereClauseStr);
+		cstate->whereClause = whereClauseCnvrtdFrmStr;
+	}
+
+	if (rangeTableStr)
+	{
+		List *rangeTableCnvrtdFrmStr = (List *) stringToNode(rangeTableStr);
+		cstate->range_table = rangeTableCnvrtdFrmStr;
+	}
+
+	/* Open and lock the relation, using the appropriate lock type. */
+	rel = table_open(shared_cstate->relid, RowExclusiveLock);
+	cstate->rel = rel;
+	ParallelWorkerInitialization(shared_cstate, cstate, attlist);
+
+	CopyFrom(cstate);
+
+	if (rel != NULL)
+		table_close(rel, RowExclusiveLock);
+
+	MemoryContextSwitchTo(oldcontext);
+	return;
+}
+/*
+ * ParallelCopyLeader - parallel copy leader's functionality.
+ *
+ * Leader will populate the shared memory and share it across the workers.
+ * Leader will read the table data from the file and copy the contents to block.
+ * Leader will then read the input contents and identify the data based on line
+ * beaks. This information is called line. The line will be populate in
+ * ParallelCopyLineBoundary. Workers will then pick up this information and
+ * insert in to table. Leader will do this till it completes processing the
+ * file. Leader executes the before statement if before statement trigger is
+ * present. Leader read the data from input file. Leader then loads data to data
+ * blocks as and when required block by block. Leader traverses through the data
+ * block to identify one line. It gets a free line to copy the information, if
+ * there is no free line it will wait till there is one free line.
+ * Server copies  the identified lines information into lines. This process is
+ * repeated till the complete file is processed.
+ * Leader will wait till all the lines populated are processed by the workers
+ * and exits.
+ */
+static void
+ParallelCopyLeader(CopyState cstate)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
+
+	pcshared_info->is_read_in_progress = false;
+	cstate->cur_lineno = 0;
+}
+/*
+ * LookupParallelCopyFnPtr - Look up parallel copy function pointer.
+ */
+static pg_attribute_always_inline copy_data_source_cb
+LookupParallelCopyFnPtr(const char *funcname)
+{
+	int			i;
+
+	for (i = 0; i < lengthof(InternalParallelCopyFuncPtrs); i++)
+	{
+		if (strcmp(InternalParallelCopyFuncPtrs[i].fn_name, funcname) == 0)
+			return InternalParallelCopyFuncPtrs[i].fn_addr;
+	}
+
+	/* We can only reach this by programming error. */
+	elog(ERROR, "internal function \"%s\" not found", funcname);
+}
+
+/*
+ * LookupParallelCopyFnStr - Lookup function string from a function pointer.
+ */
+static pg_attribute_always_inline char*
+LookupParallelCopyFnStr(copy_data_source_cb fn_addr)
+{
+	int			i;
+
+	for (i = 0; i < lengthof(InternalParallelCopyFuncPtrs); i++)
+	{
+		if (InternalParallelCopyFuncPtrs[i].fn_addr == fn_addr)
+			return InternalParallelCopyFuncPtrs[i].fn_name;
+	}
+
+	/* We can only reach this by programming error. */
+	elog(ERROR, "internal function pointer not found");
+}
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
  * in past protocol redesigns.
@@ -1149,6 +1939,7 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 
 	if (is_from)
 	{
+		ParallelContext *pcxt = NULL;
 		Assert(rel);
 
 		/* check read-only transaction and parallel mode */
@@ -1158,7 +1949,24 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 		cstate = BeginCopyFrom(pstate, rel, stmt->filename, stmt->is_program,
 							   NULL, stmt->attlist, stmt->options);
 		cstate->whereClause = whereClause;
-		*processed = CopyFrom(cstate);	/* copy from file to database */
+		cstate->is_parallel = false;
+
+		if (cstate->nworkers > 0)
+			pcxt = BeginParallelCopy(cstate->nworkers, cstate, stmt->attlist,
+									 relid);
+
+		if (pcxt)
+		{
+			ParallelCopyLeader(cstate);
+
+			/* Wait for all copy workers to finish */
+			WaitForParallelWorkersToFinish(pcxt);
+			*processed = pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
+			EndParallelCopy(pcxt);
+		}
+		else
+			*processed = CopyFrom(cstate); /* copy from file to database */
+
 		EndCopyFrom(cstate);
 	}
 	else
@@ -1207,6 +2015,7 @@ ProcessCopyOptions(ParseState *pstate,
 	cstate->is_copy_from = is_from;
 
 	cstate->file_encoding = -1;
+	cstate->nworkers = -1;
 
 	/* Extract options from the statement node tree */
 	foreach(option, options)
@@ -1375,6 +2184,53 @@ ProcessCopyOptions(ParseState *pstate,
 								defel->defname),
 						 parser_errposition(pstate, defel->location)));
 		}
+		else if (strcmp(defel->defname, "parallel") == 0)
+		{
+			char *endptr, *str;
+			long val;
+
+			if (!cstate->is_copy_from)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("parallel option supported only for copy from"),
+						 parser_errposition(pstate, defel->location)));
+			if (cstate->nworkers >= 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options"),
+						 parser_errposition(pstate, defel->location)));
+
+			str = defGetString(defel);
+
+			errno = 0; /* To distinguish success/failure after call */
+			val = strtol(str, &endptr, 10);
+
+			/* Check for various possible errors */
+			if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
+				|| (errno != 0 && val == 0) ||
+				*endptr)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("improper use of argument to option \"%s\"",
+								defel->defname),
+						 parser_errposition(pstate, defel->location)));
+
+			if (endptr == str)
+			   ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("no digits were found in argument to option \"%s\"",
+								defel->defname),
+						 parser_errposition(pstate, defel->location)));
+
+			cstate->nworkers = (int) val;
+
+			if (cstate->nworkers <= 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("argument to option \"%s\" must be a positive integer greater than zero",
+								defel->defname),
+						 parser_errposition(pstate, defel->location)));
+		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_SYNTAX_ERROR),
@@ -1727,12 +2583,13 @@ BeginCopy(ParseState *pstate,
 }
 
 /*
- * PopulateGlobalsForCopyFrom - Populates the common variables required for copy
- * from operation. This is a helper function for BeginCopy function.
+ * PopulateCatalogInformation - Populates the common variables required for copy
+ * from operation. This is a helper function for BeginCopy &
+ * ParallelWorkerInitialization function.
  */
 static void
 PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tupDesc,
-							List *attnamelist)
+						   List *attnamelist)
 {
 	int			num_phys_attrs;
 
diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c
index c27d970589..b3787c1c7f 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -557,7 +557,7 @@ make_copy_attnamelist(LogicalRepRelMapEntry *rel)
  * Data source callback for the COPY FROM, which reads from the remote
  * connection and passes the data back to our local COPY.
  */
-static int
+int
 copy_read_data(void *outbuf, int minread, int maxread)
 {
 	int			bytesread = 0;
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index c639833565..5dc95ac3f5 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -14,6 +14,7 @@
 #ifndef COPY_H
 #define COPY_H
 
+#include "access/parallel.h"
 #include "nodes/execnodes.h"
 #include "nodes/parsenodes.h"
 #include "parser/parse_node.h"
@@ -41,4 +42,7 @@ extern uint64 CopyFrom(CopyState cstate);
 
 extern DestReceiver *CreateCopyDestReceiver(void);
 
+extern void ParallelCopyMain(dsm_segment *seg, shm_toc *toc);
+
+extern int copy_read_data(void *outbuf, int minread, int maxread);
 #endif							/* COPY_H */
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index c65a55257d..8a7979412b 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1698,6 +1698,14 @@ ParallelBitmapHeapState
 ParallelBlockTableScanDesc
 ParallelCompletionPtr
 ParallelContext
+ParallelCopyLineBoundaries
+ParallelCopyLineBoundary
+ParallelCopyCommonKeyData
+ParallelCopyData
+ParallelCopyDataBlock
+ParallelCopyKeyListInfo
+ParallelCopyLineBuf
+ParallelCopyShmInfo
 ParallelExecutorInfo
 ParallelHashGrowth
 ParallelHashJoinBatch
-- 
2.25.1

0003-Allow-copy-from-command-to-process-data-from-file-ST.patchapplication/octet-stream; name=0003-Allow-copy-from-command-to-process-data-from-file-ST.patchDownload
From efc6dcb1ad7285c4e7486cd152c5908a48a7544d Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>, Bharath <bharath.rupireddyforpostgres@gmail.com>
Date: Tue, 23 Jun 2020 07:15:43 +0530
Subject: [PATCH 3/6] Allow copy from command to process data from file/STDIN
 contents to a table in parallel.

This feature allows the copy from to leverage multiple CPUs in order to copy
data from file/STDIN to a table. This adds a PARALLEL option to COPY FROM
command where the user can specify the number of workers that can be used
to perform the COPY FROM command. Specifying zero as number of workers will
disable parallelism.
The backend, to which the "COPY FROM" query is submitted acts as leader with
the responsibility of reading data from the file/stdin, launching at most n
number of workers as specified with PARALLEL 'n' option in the "COPY FROM"
query. The leader populates the common data required for the workers execution
in the DSM and shares it with the workers. The leader then executes before
statement triggers if there exists any. Leader populates DSM lines which
includes the start offset and line size, while populating the lines it reads
as many blocks as required into the DSM data blocks from the file. Each block
is of 64K size. The leader parses the data to identify a line, the existing
logic from CopyReadLineText which identifies the lines with some changes was
used for this. Leader checks if a free line is available to copy the
information, if there is no free line it waits till the required line is
freed up by the worker and then copies the identified lines information
(offset & line size) into the DSM lines. This process is repeated till the
complete file is processed. Simultaneously, the workers cache the lines(50)
locally into the local memory and release the lines to the leader for further
populating. Each worker processes the lines that it cached and inserts it into
the table. The leader does not participate in the insertion of data, leaders
only responsibility will be to identify the lines as fast as possible for the
workers to do the actual copy operation. The leader waits till all the lines
populated are processed by the workers and exits.
---
 src/backend/access/heap/heapam.c  |  13 -
 src/backend/access/transam/xact.c |  13 +
 src/backend/commands/copy.c       | 896 ++++++++++++++++++++++++++++++++++++--
 src/include/access/xact.h         |   1 +
 src/tools/pgindent/typedefs.list  |   1 +
 5 files changed, 873 insertions(+), 51 deletions(-)

diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 537913d..28f3a98 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2012,19 +2012,6 @@ static HeapTuple
 heap_prepare_insert(Relation relation, HeapTuple tup, TransactionId xid,
 					CommandId cid, int options)
 {
-	/*
-	 * Parallel operations are required to be strictly read-only in a parallel
-	 * worker.  Parallel inserts are not safe even in the leader in the
-	 * general case, because group locking means that heavyweight locks for
-	 * relation extension or GIN page locks will not conflict between members
-	 * of a lock group, but we don't prohibit that case here because there are
-	 * useful special cases that we can safely allow, such as CREATE TABLE AS.
-	 */
-	if (IsParallelWorker())
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_TRANSACTION_STATE),
-				 errmsg("cannot insert tuples in a parallel worker")));
-
 	tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
 	tup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK);
 	tup->t_data->t_infomask |= HEAP_XMAX_INVALID;
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 905dc7d..66f7236 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -502,6 +502,19 @@ GetCurrentFullTransactionIdIfAny(void)
 }
 
 /*
+ *	AssignFullTransactionIdForWorker
+ *
+ * For parallel copy, all the workers must use the same transaction id.
+ */
+void AssignFullTransactionIdForWorker(FullTransactionId fullTransactionId)
+{
+	TransactionState s = CurrentTransactionState;
+
+	Assert((IsInParallelMode() || IsParallelWorker()));
+	s->fullTransactionId = fullTransactionId;
+}
+
+/*
  *	MarkCurrentTransactionIdLoggedIfAny
  *
  * Remember that the current xid - if it is assigned - now has been wal logged.
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 34c657c..e8a89a4 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -26,6 +26,7 @@
 #include "access/xlog.h"
 #include "catalog/dependency.h"
 #include "catalog/pg_authid.h"
+#include "catalog/pg_proc_d.h"
 #include "catalog/pg_type.h"
 #include "commands/copy.h"
 #include "commands/defrem.h"
@@ -40,11 +41,13 @@
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
+#include "optimizer/clauses.h"
 #include "optimizer/optimizer.h"
 #include "parser/parse_coerce.h"
 #include "parser/parse_collate.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_relation.h"
+#include "pgstat.h"
 #include "port/pg_bswap.h"
 #include "rewrite/rewriteHandler.h"
 #include "storage/fd.h"
@@ -95,6 +98,18 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
+/*
+ * State of the line.
+ */
+typedef enum ParallelCopyLineState
+{
+	LINE_INIT,					/* initial state of line */
+	LINE_LEADER_POPULATING,		/* leader processing line */
+	LINE_LEADER_POPULATED,		/* leader completed populating line */
+	LINE_WORKER_PROCESSING,		/* worker processing line */
+	LINE_WORKER_PROCESSED		/* worker completed processing line */
+}ParallelCopyLineState;
+
 #define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
 
 #define DATA_BLOCK_SIZE RAW_BUF_SIZE
@@ -538,9 +553,13 @@ if (1) \
 { \
 	if (raw_buf_ptr > cstate->raw_buf_index) \
 	{ \
-		appendBinaryStringInfo(&cstate->line_buf, \
-							 cstate->raw_buf + cstate->raw_buf_index, \
-							   raw_buf_ptr - cstate->raw_buf_index); \
+		if (!IsParallelCopy()) \
+			appendBinaryStringInfo(&cstate->line_buf, \
+								   cstate->raw_buf + cstate->raw_buf_index, \
+								   raw_buf_ptr - cstate->raw_buf_index); \
+		else \
+			line_size +=  raw_buf_ptr - cstate->raw_buf_index; \
+		\
 		cstate->raw_buf_index = raw_buf_ptr; \
 	} \
 } else ((void) 0)
@@ -553,13 +572,40 @@ if (1) \
 	goto not_end_of_copy; \
 } else ((void) 0)
 
+/* Begin parallel copy Macros */
+#define SET_NEWLINE_SIZE() \
+{ \
+	if (cstate->eol_type == EOL_NL || cstate->eol_type == EOL_CR) \
+		new_line_size = 1; \
+	else if (cstate->eol_type == EOL_CRNL) \
+		new_line_size = 2; \
+	else \
+		new_line_size = 0; \
+}
+
+/*
+ * COPY_WAIT_TO_PROCESS - Wait before continuing to process.
+ */
+#define COPY_WAIT_TO_PROCESS() \
+{ \
+	CHECK_FOR_INTERRUPTS(); \
+	(void) WaitLatch(MyLatch, \
+					 WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH, \
+					 1L, WAIT_EVENT_PG_SLEEP); \
+	ResetLatch(MyLatch); \
+}
+
+/* End parallel copy Macros */
+
 /*
  * CONVERT_TO_SERVER_ENCODING - convert contents to server encoding.
  */
 #define CONVERT_TO_SERVER_ENCODING(cstate) \
 { \
 	/* Done reading the line.  Convert it to server encoding. */ \
-	if (cstate->need_transcoding) \
+	if (cstate->need_transcoding && \
+		(!IsParallelCopy() || \
+		 (IsParallelCopy() && !IsLeader()))) \
 	{ \
 		char	   *cvt; \
 		cvt = pg_any_to_server(cstate->line_buf.data, \
@@ -618,22 +664,38 @@ if (1) \
  * CLEAR_EOL_LINE - Wrapper for clearing EOL.
  */
 #define CLEAR_EOL_LINE() \
-if (!result && !IsHeaderLine()) \
-	CLEAR_EOL_FROM_COPIED_DATA(cstate->line_buf.data, \
-								cstate->line_buf.len, \
-								cstate->line_buf.len) \
+{ \
+	if (!result && !IsHeaderLine()) \
+	{ \
+		if (IsParallelCopy()) \
+			CLEAR_EOL_FROM_COPIED_DATA(cstate->raw_buf, \
+									   raw_buf_ptr, line_size) \
+		else \
+			CLEAR_EOL_FROM_COPIED_DATA(cstate->line_buf.data, \
+									   cstate->line_buf.len, \
+									   cstate->line_buf.len) \
+	} \
+}
 
 /*
  * INCREMENTPROCESSED - Increment the lines processed.
  */
-#define INCREMENTPROCESSED(processed)  \
-processed++;
+#define INCREMENTPROCESSED(processed) \
+{ \
+	if (!IsParallelCopy()) \
+		processed++; \
+	else \
+		pg_atomic_add_fetch_u64(&cstate->pcdata->pcshared_info->processed, 1); \
+}
 
 /*
  * GETPROCESSED - Get the lines processed.
  */
 #define GETPROCESSED(processed) \
-return processed;
+if (!IsParallelCopy()) \
+	return processed; \
+else \
+	return pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
 
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
@@ -681,8 +743,12 @@ static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 
 static pg_attribute_always_inline void EndParallelCopy(ParallelContext *pcxt);
+static void ExecBeforeStmtTrigger(CopyState cstate);
+static void CheckTargetRelValidity(CopyState cstate);
 static void PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tup_desc,
 							   List *attnamelist);
+static void PopulateCatalogInformation(CopyState cstate);
+static pg_attribute_always_inline uint32 GetLinePosition(CopyState cstate);
 static pg_attribute_always_inline copy_data_source_cb LookupParallelCopyFnPtr(const char *funcname);
 static pg_attribute_always_inline char* LookupParallelCopyFnStr(copy_data_source_cb fn_addr);
 
@@ -836,6 +902,137 @@ InsertListShm(ParallelContext *pcxt, int key, List *inputlist,
 }
 
 /*
+ * IsTriggerFunctionParallelSafe - Check if the trigger function is parallel
+ * safe for the triggers. Return false if any one of the trigger has parallel
+ * unsafe function.
+ */
+static pg_attribute_always_inline bool
+IsTriggerFunctionParallelSafe(TriggerDesc *trigdesc)
+{
+	int	i;
+	for (i = 0; i < trigdesc->numtriggers; i++)
+	{
+		Trigger    *trigger = &trigdesc->triggers[i];
+		int 		trigtype = RI_TRIGGER_NONE;
+
+		if (func_parallel(trigger->tgfoid) != PROPARALLEL_SAFE)
+			return false;
+
+		/* If the trigger is parallel safe, also look for RI_TRIGGER. */
+		trigtype = RI_FKey_trigger_type(trigger->tgfoid);
+		if (trigtype == RI_TRIGGER_PK || trigtype == RI_TRIGGER_FK)
+			return false;
+	}
+
+	return true;
+}
+
+/*
+ * CheckExprParallelSafety - determine parallel safety of volatile expressions
+ * in default clause of column definition or in where clause and return true if
+ * they are parallel safe.
+ */
+static pg_attribute_always_inline bool
+CheckExprParallelSafety(CopyState cstate)
+{
+	if (contain_volatile_functions(cstate->whereClause))
+	{
+		if (max_parallel_hazard((Query *)cstate->whereClause) != PROPARALLEL_SAFE)
+			return false;
+	}
+
+	/*
+	 * Check if any of the column has volatile default expression. if yes, and
+	 * they are not parallel safe, then parallelism is not allowed. For
+	 * instance, if there are any serial/bigserial columns for which nextval()
+	 * default expression which is parallel unsafe is associated, parallelism
+	 * should not be allowed. In non paralllel copy volatile functions are not
+	 * checked for nextval().
+	 */
+	if (cstate->defexprs != NULL && cstate->num_defaults != 0)
+	{
+		int     i;
+		for (i = 0; i < cstate->num_defaults; i++)
+		{
+			bool volatile_expr = contain_volatile_functions((Node *)cstate->defexprs[i]->expr);
+			if (volatile_expr &&
+				(max_parallel_hazard((Query *)cstate->defexprs[i]->expr)) !=
+				 PROPARALLEL_SAFE)
+				return false;
+		}
+	}
+
+	return true;
+}
+
+/*
+ * FindInsertMethod - determine insert mode single, multi, or multi conditional.
+ */
+static pg_attribute_always_inline CopyInsertMethod
+FindInsertMethod(CopyState cstate)
+{
+	if (cstate->rel->trigdesc != NULL &&
+		(cstate->rel->trigdesc->trig_insert_before_row ||
+		 cstate->rel->trigdesc->trig_insert_instead_row))
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
+			cstate->rel->trigdesc != NULL &&
+			cstate->rel->trigdesc->trig_insert_new_table)
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+		return CIM_MULTI_CONDITIONAL;
+
+	return CIM_MULTI;
+}
+
+/*
+ * IsParallelCopyAllowed - check for the cases where parallel copy is not
+ * applicable.
+ */
+static pg_attribute_always_inline bool
+IsParallelCopyAllowed(CopyState cstate)
+{
+	/* Parallel copy not allowed for frontend (2.0 protocol) & binary option. */
+	if ((cstate->copy_dest == COPY_OLD_FE) || cstate->binary)
+		return false;
+
+	/* Check if copy is into foreign table or temporary table. */
+	if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
+		RelationUsesLocalBuffers(cstate->rel))
+		return false;
+
+	/* Check if trigger function is parallel safe. */
+	if (cstate->rel->trigdesc != NULL &&
+		!IsTriggerFunctionParallelSafe(cstate->rel->trigdesc))
+		return false;
+
+	/*
+	 * Check if there is after statement or instead of trigger or transition
+	 * table triggers.
+	 */
+	if (cstate->rel->trigdesc != NULL &&
+		(cstate->rel->trigdesc->trig_insert_after_statement ||
+		 cstate->rel->trigdesc->trig_insert_instead_row ||
+		 cstate->rel->trigdesc->trig_insert_new_table))
+		return false;
+
+	/* Check if the volatile expressions are parallel safe, if present any. */
+	if (!CheckExprParallelSafety(cstate))
+		return false;
+
+	/* Check if the insertion mode is single. */
+	if (FindInsertMethod(cstate) == CIM_SINGLE)
+		return false;
+
+	return true;
+}
+
+/*
  * BeginParallelCopy - start parallel copy tasks.
  *
  * Get the number of workers required to perform the parallel copy. The data
@@ -865,6 +1062,8 @@ BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
 	int  parallel_workers = 0;
 	ParallelCopyData *pcdata;
 
+	CheckTargetRelValidity(cstate);
+
 	parallel_workers = Min(nworkers, max_worker_processes);
 
 	/* Can't perform copy in parallel */
@@ -878,6 +1077,19 @@ BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
 	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
 	cstate->pcdata = pcdata;
 
+	/*
+	 * User chosen parallel copy. Determine if the parallel copy is actually
+	 * allowed. If not, go with the non-parallel mode.
+	 */
+	if (!IsParallelCopyAllowed(cstate))
+	{
+		elog(WARNING,
+			 "Parallel copy not supported for specified table, copy will be run in non-parallel mode");
+		return NULL;
+	}
+
+	full_transaction_id = GetCurrentFullTransactionId();
+
 	EnterParallelMode();
 	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
 								 parallel_workers);
@@ -1108,7 +1320,211 @@ ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
 	cstate->line_buf_converted = false;
 	cstate->raw_buf = NULL;
 	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+
+	PopulateCatalogInformation(cstate);
+
+	/* Create workspace for CopyReadAttributes results. */
+	if (!cstate->binary)
+	{
+		AttrNumber	attr_count = list_length(cstate->attnumlist);
+
+		cstate->max_fields = attr_count;
+		cstate->raw_fields = (char **)palloc(attr_count * sizeof(char *));
+	}
+}
+
+/*
+ * CacheLineInfo - Cache the line information to local memory.
+ */
+static bool
+CacheLineInfo(CopyState cstate, uint32 buff_count)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	uint32			write_pos;
+	ParallelCopyDataBlock *data_blk_ptr;
+	ParallelCopyLineBoundary *lineInfo;
+	uint32 offset;
+	int dataSize;
+	int copiedSize = 0;
+
+	resetStringInfo(&pcdata->worker_line_buf[buff_count].line_buf);
+	write_pos = GetLinePosition(cstate);
+	if (-1 == write_pos)
+		return true;
+
+	/* Get the current line information. */
+	lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+	if (pg_atomic_read_u32(&lineInfo->line_size) == 0)
+		goto empty_data_line_update;
+
+	/* Get the block information. */
+	data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+	/* Get the offset information from where the data must be copied. */
+	offset = lineInfo->start_offset;
+	pcdata->worker_line_buf[buff_count].cur_lineno = lineInfo->cur_lineno;
+
+	elog(DEBUG1, "[Worker] Processing - line position:%d, block:%d, unprocessed lines:%d, offset:%d, line size:%d",
+				 write_pos, lineInfo->first_block,
+				 pg_atomic_read_u32(&data_blk_ptr->unprocessed_line_parts),
+				 offset, pg_atomic_read_u32(&lineInfo->line_size));
+
+	for (;;)
+	{
+		uint8 skip_bytes = data_blk_ptr->skip_bytes;
+		/*
+		 * There is a possibility that the above loop has come out because
+		 * data_blk_ptr->curr_blk_completed is set, but dataSize read might
+		 * be an old value, if data_blk_ptr->curr_blk_completed and the line is
+		 * completed, line_size will be set. Read the line_size again to be
+		 * sure if it is complete or partial block.
+		 */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+		if (dataSize)
+		{
+			int remainingSize = dataSize - copiedSize;
+			if (!remainingSize)
+				break;
+
+			/* Whole line is in current block. */
+			if (remainingSize + offset + skip_bytes < DATA_BLOCK_SIZE)
+			{
+				appendBinaryStringInfo(&pcdata->worker_line_buf[buff_count].line_buf,
+									   &data_blk_ptr->data[offset],
+									   remainingSize);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts,
+										1);
+				break;
+			}
+			else
+			{
+				/* Line is spread across the blocks. */
+				uint32 lineInCurrentBlock =  (DATA_BLOCK_SIZE - skip_bytes) - offset;
+				appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+										 &data_blk_ptr->data[offset],
+										 lineInCurrentBlock);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+				copiedSize += lineInCurrentBlock;
+				while (copiedSize < dataSize)
+				{
+					uint32 currentBlockCopySize;
+					ParallelCopyDataBlock *currBlkPtr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+					skip_bytes = currBlkPtr->skip_bytes;
+
+					/*
+					 * If complete data is present in current block use
+					 * dataSize - copiedSize, or copy the whole block from
+					 * current block.
+					 */
+					currentBlockCopySize = Min(dataSize - copiedSize, DATA_BLOCK_SIZE - skip_bytes);
+					appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+											 &currBlkPtr->data[0],
+											 currentBlockCopySize);
+					pg_atomic_sub_fetch_u32(&currBlkPtr->unprocessed_line_parts, 1);
+					copiedSize += currentBlockCopySize;
+					data_blk_ptr = currBlkPtr;
+				}
+
+				break;
+			}
+		}
+		else
+		{
+			/* Copy this complete block from the current offset. */
+			uint32 lineInCurrentBlock =  (DATA_BLOCK_SIZE - skip_bytes) - offset;
+			appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+									 &data_blk_ptr->data[offset],
+									 lineInCurrentBlock);
+			pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+			copiedSize += lineInCurrentBlock;
+
+			/*
+			 * Reset the offset. For the first copy, copy from the offset. For
+			 * the subsequent copy the complete block.
+			 */
+			offset = 0;
+
+			/* Set data_blk_ptr to the following block. */
+			data_blk_ptr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+		}
+
+		for (;;)
+		{
+			/* Get the size of this line */
+			dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+			/*
+			 * If the data is present in current block lineInfo.line_size
+			 * will be updated. If the data is spread across the blocks either
+			 * of lineInfo.line_size or data_blk_ptr->curr_blk_completed can
+			 * be updated. lineInfo.line_size will be updated if the complete
+			 * read is finished. data_blk_ptr->curr_blk_completed will be
+			 * updated if processing of current block is finished and data
+			 * processing is not finished.
+			 */
+			if (data_blk_ptr->curr_blk_completed || (dataSize != -1))
+				break;
+
+			COPY_WAIT_TO_PROCESS()
+		}
+	}
+
+empty_data_line_update:
+	elog(DEBUG1, "[Worker] Completed processing line:%d", write_pos);
+	pg_atomic_write_u32(&lineInfo->line_state, LINE_WORKER_PROCESSED);
+	pg_atomic_write_u32(&lineInfo->line_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+	return false;
+}
+
+/*
+ * GetWorkerLine - Returns a line for worker to process.
+ */
+static bool
+GetWorkerLine(CopyState cstate)
+{
+	uint32 buff_count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+
+	/*
+	 * Copy the line data to line_buf and release the line position so that the
+	 * worker can continue loading data.
+	 */
+	if (pcdata->worker_line_buf_pos < pcdata->worker_line_buf_count)
+		goto return_line;
+
+	pcdata->worker_line_buf_pos = 0;
+	pcdata->worker_line_buf_count = 0;
+
+	for (buff_count = 0; buff_count < WORKER_CHUNK_COUNT; buff_count++)
+	{
+		bool result = CacheLineInfo(cstate, buff_count);
+		if (result)
+			break;
+
+		pcdata->worker_line_buf_count++;
+	}
+
+	if (pcdata->worker_line_buf_count)
+		goto return_line;
+	else
+		resetStringInfo(&cstate->line_buf);
+
+	return true;
+
+return_line:
+	cstate->line_buf = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].line_buf;
+	cstate->cur_lineno = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].cur_lineno;
+	cstate->line_buf_valid = true;
+
+	/* Mark that encoding conversion hasn't occurred yet. */
+	cstate->line_buf_converted = false;
+	CONVERT_TO_SERVER_ENCODING(cstate)
+	pcdata->worker_line_buf_pos++;
+	return false;
 }
+
 /*
  * ParallelCopyMain - parallel copy worker's code.
  *
@@ -1154,6 +1570,7 @@ ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
 	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
 
 	pcdata->pcshared_info = pcshared_info;
+	AssignFullTransactionIdForWorker(pcshared_info->full_transaction_id);
 
 	shared_cstate = (ParallelCopyCommonKeyData *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE,
 														   false);
@@ -1206,6 +1623,34 @@ ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
 	MemoryContextSwitchTo(oldcontext);
 	return;
 }
+
+/*
+ * UpdateBlockInLineInfo - Update the line information.
+ */
+static pg_attribute_always_inline int
+UpdateBlockInLineInfo(CopyState cstate, uint32 blk_pos,
+					   uint32 offset, uint32 line_size, uint32 line_state)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyLineBoundaries *lineBoundaryPtr = &pcshared_info->line_boundaries;
+	ParallelCopyLineBoundary *lineInfo;
+	int line_pos = lineBoundaryPtr->leader_pos;
+
+	/* Update the line information for the worker to pick and process. */
+	lineInfo = &lineBoundaryPtr->ring[line_pos];
+	while (pg_atomic_read_u32(&lineInfo->line_size) != -1)
+		COPY_WAIT_TO_PROCESS()
+
+	lineInfo->first_block = blk_pos;
+	lineInfo->start_offset = offset;
+	lineInfo->cur_lineno = cstate->cur_lineno;
+	pg_atomic_write_u32(&lineInfo->line_size, line_size);
+	pg_atomic_write_u32(&lineInfo->line_state, line_state);
+	lineBoundaryPtr->leader_pos = (lineBoundaryPtr->leader_pos + 1) % RINGSIZE;
+
+	return line_pos;
+}
+
 /*
  * ParallelCopyLeader - parallel copy leader's functionality.
  *
@@ -1231,9 +1676,158 @@ ParallelCopyLeader(CopyState cstate)
 	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
 	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
 
+	/* Execute the before statement triggers from the leader */
+	ExecBeforeStmtTrigger(cstate);
+
+	/* On input just throw the header line away. */
+	if (cstate->cur_lineno == 0 && cstate->header_line)
+	{
+		cstate->cur_lineno++;
+		if (CopyReadLine(cstate))
+		{
+			pcshared_info->is_read_in_progress = false;
+			return;			/* done */
+		}
+	}
+
+	for (;;)
+	{
+		bool done;
+		cstate->cur_lineno++;
+
+		/* Actually read the line into memory here. */
+		done = CopyReadLine(cstate);
+
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			break;
+	}
+
 	pcshared_info->is_read_in_progress = false;
 	cstate->cur_lineno = 0;
 }
+
+/*
+ * GetLinePosition - return the line position that worker should process.
+ */
+static uint32
+GetLinePosition(CopyState cstate)
+{
+	ParallelCopyData *pcdata = cstate->pcdata;
+	ParallelCopyShmInfo *pcshared_info = pcdata->pcshared_info;
+	uint32  previous_pos = pcdata->worker_processed_pos;
+	uint32 write_pos = (previous_pos == -1) ? 0 : (previous_pos + 1) % RINGSIZE;
+	for (;;)
+	{
+		int		dataSize;
+		bool	is_read_in_progress = pcshared_info->is_read_in_progress;
+		ParallelCopyLineBoundary *lineInfo;
+		ParallelCopyDataBlock *data_blk_ptr;
+		ParallelCopyLineState line_state = LINE_LEADER_POPULATED;
+		ParallelCopyLineState curr_line_state;
+		CHECK_FOR_INTERRUPTS();
+
+		/* File read completed & no elements to process. */
+		if (!is_read_in_progress &&
+			(pcshared_info->populated ==
+			 pg_atomic_read_u64(&pcshared_info->total_worker_processed)))
+		{
+			write_pos = -1;
+			break;
+		}
+
+		/* Get the current line information. */
+		lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+		curr_line_state = pg_atomic_read_u32(&lineInfo->line_state);
+		if ((write_pos % WORKER_CHUNK_COUNT == 0) &&
+			(curr_line_state == LINE_WORKER_PROCESSED ||
+			 curr_line_state == LINE_WORKER_PROCESSING))
+		{
+			pcdata->worker_processed_pos = write_pos;
+			write_pos = (write_pos + WORKER_CHUNK_COUNT) %  RINGSIZE;
+			continue;
+		}
+
+		/* Get the size of this line. */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+		if (dataSize != 0) /* If not an empty line. */
+		{
+			/* Get the block information. */
+			data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+			if (!data_blk_ptr->curr_blk_completed && (dataSize == -1))
+			{
+				/* Wait till the current line or block is added. */
+				COPY_WAIT_TO_PROCESS()
+				continue;
+			}
+		}
+
+		/* Make sure that no worker has consumed this element. */
+		if (pg_atomic_compare_exchange_u32(&lineInfo->line_state,
+										   &line_state, LINE_WORKER_PROCESSING))
+			break;
+	}
+
+	pcdata->worker_processed_pos = write_pos;
+	return write_pos;
+}
+
+/*
+ * GetFreeCopyBlock - Get a free block for data to be copied.
+ */
+static pg_attribute_always_inline uint32
+GetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	int count = 0;
+	uint32 last_free_block = pcshared_info->cur_block_pos;
+	uint32 block_pos = (last_free_block != -1) ? ((last_free_block + 1) % MAX_BLOCKS_COUNT): 0;
+
+	/* Get a new block for copying data. */
+	while (count < MAX_BLOCKS_COUNT)
+	{
+		ParallelCopyDataBlock *dataBlkPtr = &pcshared_info->data_blocks[block_pos];
+		uint32 unprocessed_line_parts = pg_atomic_read_u32(&dataBlkPtr->unprocessed_line_parts);
+		if (unprocessed_line_parts == 0)
+		{
+			dataBlkPtr->curr_blk_completed = false;
+			dataBlkPtr->skip_bytes = 0;
+			pcshared_info->cur_block_pos = block_pos;
+			return block_pos;
+		}
+
+		block_pos = (block_pos + 1) % MAX_BLOCKS_COUNT;
+		count++;
+	}
+
+	return -1;
+}
+
+/*
+ * WaitGetFreeCopyBlock - If there are no blocks available, wait and get a block
+ * for copying data.
+ */
+static uint32
+WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	uint32 new_free_pos = -1;
+	for (;;)
+	{
+		new_free_pos = GetFreeCopyBlock(pcshared_info);
+		if (new_free_pos != -1)	/* We have got one block, break now. */
+			break;
+
+		COPY_WAIT_TO_PROCESS()
+	}
+
+	return new_free_pos;
+}
+
 /*
  * LookupParallelCopyFnPtr - Look up parallel copy function pointer.
  */
@@ -1269,6 +1863,146 @@ LookupParallelCopyFnStr(copy_data_source_cb fn_addr)
 	/* We can only reach this by programming error. */
 	elog(ERROR, "internal function pointer not found");
 }
+
+/*
+ * SetRawBufForLoad - Set raw_buf to the shared memory where the file data must
+ * be read.
+ */
+static void
+SetRawBufForLoad(CopyState cstate, uint32 line_size, uint32 copy_buf_len,
+				 uint32 raw_buf_ptr, char **copy_raw_buf)
+{
+	ParallelCopyShmInfo	*pcshared_info;
+	uint32 cur_block_pos;
+	uint32 next_block_pos;
+	ParallelCopyDataBlock	*cur_data_blk_ptr = NULL;
+	ParallelCopyDataBlock	*next_data_blk_ptr = NULL;
+
+	if (!IsParallelCopy())
+		return;
+
+	pcshared_info = cstate->pcdata->pcshared_info;
+	cur_block_pos = pcshared_info->cur_block_pos;
+	cur_data_blk_ptr = (cstate->raw_buf) ? &pcshared_info->data_blocks[cur_block_pos] : NULL;
+	next_block_pos = WaitGetFreeCopyBlock(pcshared_info);
+	next_data_blk_ptr = &pcshared_info->data_blocks[next_block_pos];
+
+	/* set raw_buf to the data block in shared memory */
+	cstate->raw_buf = next_data_blk_ptr->data;
+	*copy_raw_buf = cstate->raw_buf;
+	if (cur_data_blk_ptr && line_size)
+	{
+		/*
+		 * Mark the previous block as completed, worker can start copying this
+		 * data.
+		 */
+		cur_data_blk_ptr->following_block = next_block_pos;
+		pg_atomic_add_fetch_u32(&cur_data_blk_ptr->unprocessed_line_parts, 1);
+		cur_data_blk_ptr->skip_bytes = copy_buf_len - raw_buf_ptr;
+		cur_data_blk_ptr->curr_blk_completed = true;
+	}
+}
+
+/*
+ * EndLineParallelCopy - Update the line information in shared memory.
+ */
+static void
+EndLineParallelCopy(CopyState cstate, uint32 line_pos, uint32 line_size,
+					 uint32 raw_buf_ptr)
+{
+	uint8 new_line_size;
+	if (!IsParallelCopy())
+		return;
+
+	if (!IsHeaderLine())
+	{
+		ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+		ParallelCopyLineBoundaries *lineBoundaryPtr = &pcshared_info->line_boundaries;
+		SET_NEWLINE_SIZE()
+		if (line_size)
+		{
+			ParallelCopyLineBoundary *lineInfo = &lineBoundaryPtr->ring[line_pos];
+			/*
+			 * If the new_line_size > raw_buf_ptr, then the new block has only
+			 * new line char content. The unprocessed count should not be
+			 * increased in this case.
+			 */
+			if (raw_buf_ptr > new_line_size)
+			{
+				uint32 cur_block_pos = pcshared_info->cur_block_pos;
+				ParallelCopyDataBlock *curr_data_blk_ptr = &pcshared_info->data_blocks[cur_block_pos];
+				pg_atomic_add_fetch_u32(&curr_data_blk_ptr->unprocessed_line_parts, 1);
+			}
+
+			/* Update line size. */
+			pg_atomic_write_u32(&lineInfo->line_size, line_size);
+			pg_atomic_write_u32(&lineInfo->line_state, LINE_LEADER_POPULATED);
+			elog(DEBUG1, "[Leader] After adding - line position:%d, line_size:%d",
+						 line_pos, line_size);
+			pcshared_info->populated++;
+		}
+		else if (new_line_size)
+		{
+			/* This means only new line char, empty record should be inserted.*/
+			ParallelCopyLineBoundary *lineInfo;
+			line_pos = UpdateBlockInLineInfo(cstate, -1, -1, 0,
+											   LINE_LEADER_POPULATED);
+			lineInfo = &lineBoundaryPtr->ring[line_pos];
+			elog(DEBUG1, "[Leader] Added empty line with offset:%d, line position:%d, line size:%d",
+						 lineInfo->start_offset, line_pos,
+						 pg_atomic_read_u32(&lineInfo->line_size));
+			pcshared_info->populated++;
+		}
+	}
+}
+
+/*
+ * ExecBeforeStmtTrigger - Execute the before statement trigger, this will be
+ * executed for parallel copy by the leader process.
+ */
+static void
+ExecBeforeStmtTrigger(CopyState cstate)
+{
+	EState	   *estate = CreateExecutorState();
+	ResultRelInfo *resultRelInfo;
+
+	Assert(IsLeader());
+
+	/*
+	 * We need a ResultRelInfo so we can use the regular executor's
+	 * index-entry-making machinery.  (There used to be a huge amount of code
+	 * here that basically duplicated execUtils.c ...)
+	 */
+	resultRelInfo = makeNode(ResultRelInfo);
+	InitResultRelInfo(resultRelInfo,
+					  cstate->rel,
+					  1,		/* must match rel's position in range_table */
+					  NULL,
+					  0);
+
+	/* Verify the named relation is a valid target for INSERT */
+	CheckValidResultRel(resultRelInfo, CMD_INSERT);
+
+	estate->es_result_relations = resultRelInfo;
+	estate->es_num_result_relations = 1;
+	estate->es_result_relation_info = resultRelInfo;
+
+	ExecInitRangeTable(estate, cstate->range_table);
+
+	/*
+	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
+	 * should do this for COPY, since it's not really an "INSERT" statement as
+	 * such. However, executing these triggers maintains consistency with the
+	 * EACH ROW triggers that we already fire on COPY.
+	 */
+	ExecBSInsertTriggers(estate, resultRelInfo);
+
+	/* Close any trigger target relations */
+	ExecCleanUpTriggerState(estate);
+
+	FreeExecutorState(estate);
+}
+
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
  * in past protocol redesigns.
@@ -3675,7 +4409,8 @@ CopyFrom(CopyState cstate)
 
 	PartitionTupleRouting *proute = NULL;
 	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
+	CommandId	mycid = IsParallelCopy() ? cstate->pcdata->pcshared_info->mycid :
+										   GetCurrentCommandId(true);
 	int			ti_options = 0; /* start with default options for insert */
 	BulkInsertState bistate = NULL;
 	CopyInsertMethod insertMethod;
@@ -3685,7 +4420,14 @@ CopyFrom(CopyState cstate)
 	bool		has_instead_insert_row_trig;
 	bool		leafpart_use_multi_insert = false;
 
-	CheckTargetRelValidity(cstate);
+	/*
+	 * Perform this check if it is not parallel copy. In case of parallel
+	 * copy, this check is done by the leader, so that if any invalid case
+	 * exist the copy from command will error out from the leader itself,
+	 * avoiding launching workers, just to throw error.
+	 */
+	if (!IsParallelCopy())
+		CheckTargetRelValidity(cstate);
 
 	/*
 	 * If the target file is new-in-transaction, we assume that checking FSM
@@ -3874,13 +4616,16 @@ CopyFrom(CopyState cstate)
 	has_instead_insert_row_trig = (resultRelInfo->ri_TrigDesc &&
 								   resultRelInfo->ri_TrigDesc->trig_insert_instead_row);
 
-	/*
-	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
-	 * should do this for COPY, since it's not really an "INSERT" statement as
-	 * such. However, executing these triggers maintains consistency with the
-	 * EACH ROW triggers that we already fire on COPY.
-	 */
-	ExecBSInsertTriggers(estate, resultRelInfo);
+	if (!IsParallelCopy())
+	{
+		/*
+		 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
+		 * should do this for COPY, since it's not really an "INSERT" statement as
+		 * such. However, executing these triggers maintains consistency with the
+		 * EACH ROW triggers that we already fire on COPY.
+		 */
+		ExecBSInsertTriggers(estate, resultRelInfo);
+	}
 
 	econtext = GetPerTupleExprContext(estate);
 
@@ -3980,6 +4725,16 @@ CopyFrom(CopyState cstate)
 					!has_instead_insert_row_trig &&
 					resultRelInfo->ri_FdwRoutine == NULL;
 
+				/*
+				 * If the table has any partitions that are either foreign or
+				 * has BEFORE/INSTEAD OF triggers, we can't perform copy
+				 * operations with parallel workers.
+				 */
+				if (!leafpart_use_multi_insert && IsParallelWorker())
+					ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							errmsg("cannot perform PARALLEL COPY if partition has BEFORE/INSTEAD OF triggers, or if the partition is foreign partition"),
+							errhint("Try COPY without PARALLEL option")));
+
 				/* Set the multi-insert buffer to use for this partition. */
 				if (leafpart_use_multi_insert)
 				{
@@ -4394,7 +5149,7 @@ BeginCopyFrom(ParseState *pstate,
 	initStringInfo(&cstate->attribute_buf);
 	initStringInfo(&cstate->line_buf);
 	cstate->line_buf_converted = false;
-	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+	cstate->raw_buf = (IsParallelCopy()) ? NULL : (char *) palloc(RAW_BUF_SIZE + 1);
 	cstate->raw_buf_index = cstate->raw_buf_len = 0;
 
 	/* Assign range table, we'll need it in CopyFrom. */
@@ -4538,26 +5293,35 @@ NextCopyFromRawFields(CopyState cstate, char ***fields, int *nfields)
 	/* only available for text or csv input */
 	Assert(!cstate->binary);
 
-	/* on input just throw the header line away */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (IsParallelCopy())
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
-			return false;		/* done */
+		done = GetWorkerLine(cstate);
+		if (done && cstate->line_buf.len == 0)
+			return false;
 	}
+	else
+	{
+		/* on input just throw the header line away */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
+		{
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+				return false;		/* done */
+		}
 
-	cstate->cur_lineno++;
+		cstate->cur_lineno++;
 
-	/* Actually read the line into memory here */
-	done = CopyReadLine(cstate);
+		/* Actually read the line into memory here */
+		done = CopyReadLine(cstate);
 
-	/*
-	 * EOF at start of line means we're done.  If we see EOF after some
-	 * characters, we act as though it was newline followed by EOF, ie,
-	 * process the line and then exit loop on next iteration.
-	 */
-	if (done && cstate->line_buf.len == 0)
-		return false;
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			return false;
+	}
 
 	/* Parse the line into de-escaped field values */
 	if (cstate->csv_mode)
@@ -4805,9 +5569,31 @@ CopyReadLine(CopyState cstate)
 		 */
 		if (cstate->copy_dest == COPY_NEW_FE)
 		{
+			bool bIsFirst = true;
 			do
 			{
-				cstate->raw_buf_index = cstate->raw_buf_len;
+				if (!IsParallelCopy())
+					cstate->raw_buf_index = cstate->raw_buf_len;
+				else
+				{
+					if (cstate->raw_buf_index == RAW_BUF_SIZE)
+					{
+						/* Get a new block if it is the first time, From the
+						 * subsequent time, reset the index and re-use the same
+						 * block.
+						 */
+						if (bIsFirst)
+						{
+							ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+							uint32 block_pos = WaitGetFreeCopyBlock(pcshared_info);
+							cstate->raw_buf = pcshared_info->data_blocks[block_pos].data;
+							bIsFirst = false;
+						}
+
+						cstate->raw_buf_index = cstate->raw_buf_len = 0;
+					}
+				}
+
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
@@ -4837,6 +5623,11 @@ CopyReadLineText(CopyState cstate)
 	char		quotec = '\0';
 	char		escapec = '\0';
 
+	/* For parallel copy */
+	uint32			 line_size = 0;
+	int				 line_pos = 0;
+
+	cstate->eol_type = EOL_UNKNOWN;
 	if (cstate->csv_mode)
 	{
 		quotec = cstate->quote[0];
@@ -4891,6 +5682,8 @@ CopyReadLineText(CopyState cstate)
 		if (raw_buf_ptr >= copy_buf_len || need_data)
 		{
 			REFILL_LINEBUF;
+			SetRawBufForLoad(cstate, line_size, copy_buf_len, raw_buf_ptr,
+							 &copy_raw_buf);
 
 			/*
 			 * Try to read some more data.  This will certainly reset
@@ -5115,9 +5908,15 @@ CopyReadLineText(CopyState cstate)
 				 * discard the data and the \. sequence.
 				 */
 				if (prev_raw_ptr > cstate->raw_buf_index)
-					appendBinaryStringInfo(&cstate->line_buf,
+				{
+					if (!IsParallelCopy())
+						appendBinaryStringInfo(&cstate->line_buf,
 										   cstate->raw_buf + cstate->raw_buf_index,
 										   prev_raw_ptr - cstate->raw_buf_index);
+					else
+						line_size += prev_raw_ptr - cstate->raw_buf_index;
+				}
+
 				cstate->raw_buf_index = raw_buf_ptr;
 				result = true;	/* report EOF */
 				break;
@@ -5169,6 +5968,26 @@ not_end_of_copy:
 			IF_NEED_REFILL_AND_EOF_BREAK(mblen - 1);
 			raw_buf_ptr += mblen - 1;
 		}
+
+		/*
+		 * Skip the header line. Update the line here, this cannot be done at
+		 * the beginning, as there is a possibility that file contains empty
+		 * lines.
+		 */
+		if (IsParallelCopy() && first_char_in_line && !IsHeaderLine())
+		{
+			ParallelCopyShmInfo	*pcshared_info = cstate->pcdata->pcshared_info;
+			ParallelCopyLineBoundary *lineInfo;
+			uint32			 line_first_block = pcshared_info->cur_block_pos;
+			line_pos = UpdateBlockInLineInfo(cstate,
+											   line_first_block,
+											   cstate->raw_buf_index, -1,
+											   LINE_LEADER_POPULATING);
+			lineInfo = &pcshared_info->line_boundaries.ring[line_pos];
+			elog(DEBUG1, "[Leader] Adding - block:%d, offset:%d, line position:%d",
+						 line_first_block,	lineInfo->start_offset, line_pos);
+		}
+
 		first_char_in_line = false;
 	}							/* end of outer loop */
 
@@ -5177,6 +5996,7 @@ not_end_of_copy:
 	 */
 	REFILL_LINEBUF;
 	CLEAR_EOL_LINE()
+	EndLineParallelCopy(cstate, line_pos, line_size, raw_buf_ptr);
 
 	return result;
 }
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index db19187..584b7ee 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -381,6 +381,7 @@ extern FullTransactionId GetTopFullTransactionId(void);
 extern FullTransactionId GetTopFullTransactionIdIfAny(void);
 extern FullTransactionId GetCurrentFullTransactionId(void);
 extern FullTransactionId GetCurrentFullTransactionIdIfAny(void);
+extern void AssignFullTransactionIdForWorker(FullTransactionId fullTransactionId);
 extern void MarkCurrentTransactionIdLoggedIfAny(void);
 extern bool SubTransactionIsActive(SubTransactionId subxid);
 extern CommandId GetCurrentCommandId(bool used);
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 8a79794..86b5c62 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1700,6 +1700,7 @@ ParallelCompletionPtr
 ParallelContext
 ParallelCopyLineBoundaries
 ParallelCopyLineBoundary
+ParallelCopyLineState
 ParallelCopyCommonKeyData
 ParallelCopyData
 ParallelCopyDataBlock
-- 
1.8.3.1

0004-Documentation-for-parallel-copy.patchapplication/octet-stream; name=0004-Documentation-for-parallel-copy.patchDownload
From f06311aab275234125ed5b2c1a5c4740db55df3f Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 17 Jun 2020 07:34:56 +0530
Subject: [PATCH 4/6] Documentation for parallel copy.

This patch has the documentation changes for parallel copy.
---
 doc/src/sgml/ref/copy.sgml | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/doc/src/sgml/ref/copy.sgml b/doc/src/sgml/ref/copy.sgml
index 18189ab..95d349d 100644
--- a/doc/src/sgml/ref/copy.sgml
+++ b/doc/src/sgml/ref/copy.sgml
@@ -37,6 +37,7 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
     DELIMITER '<replaceable class="parameter">delimiter_character</replaceable>'
     NULL '<replaceable class="parameter">null_string</replaceable>'
     HEADER [ <replaceable class="parameter">boolean</replaceable> ]
+    PARALLEL <replaceable class="parameter">integer</replaceable>
     QUOTE '<replaceable class="parameter">quote_character</replaceable>'
     ESCAPE '<replaceable class="parameter">escape_character</replaceable>'
     FORCE_QUOTE { ( <replaceable class="parameter">column_name</replaceable> [, ...] ) | * }
@@ -275,6 +276,21 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
    </varlistentry>
 
    <varlistentry>
+    <term><literal>PARALLEL</literal></term>
+    <listitem>
+     <para>
+      Perform <command>COPY FROM</command> in parallel using <replaceable
+      class="parameter"> integer</replaceable> background workers.  Please
+      note that it is not guaranteed that the number of parallel workers
+      specified in <replaceable class="parameter">integer</replaceable> will
+      be used during execution.  It is possible for a copy to run with fewer
+      workers than specified, or even with no workers at all.  This option is
+      allowed only in <command>COPY FROM</command>.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><literal>QUOTE</literal></term>
     <listitem>
      <para>
-- 
1.8.3.1

0005-Tests-for-parallel-copy.patchapplication/octet-stream; name=0005-Tests-for-parallel-copy.patchDownload
From 740f39b8a87eb74e74182ed2cc5e8c18bd2ce367 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 17 Jun 2020 07:37:26 +0530
Subject: [PATCH 5/6] Tests for parallel copy.

This patch has the tests for parallel copy.
---
 src/test/regress/expected/copy2.out | 210 +++++++++++++++++++++++++++++++++++-
 src/test/regress/input/copy.source  |  12 +++
 src/test/regress/output/copy.source |  12 +++
 src/test/regress/sql/copy2.sql      | 208 ++++++++++++++++++++++++++++++++++-
 4 files changed, 434 insertions(+), 8 deletions(-)

diff --git a/src/test/regress/expected/copy2.out b/src/test/regress/expected/copy2.out
index e40287d..a088f72 100644
--- a/src/test/regress/expected/copy2.out
+++ b/src/test/regress/expected/copy2.out
@@ -254,18 +254,32 @@ It is "perfect".|
 "It is ""perfect"".","	"
 "",
 --test that we read consecutive LFs properly
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 COPY testnl FROM stdin CSV;
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL '2');
+SELECT * FROM testnl;
+ a |          b           | c 
+---+----------------------+---
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+(2 rows)
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 COPY testeoc FROM stdin CSV;
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL '2');
 COPY testeoc TO stdout CSV;
 a\.
 \.b
 c\.d
 "\."
 -- test handling of nonstandard null marker that violates escaping rules
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 COPY testnull TO stdout WITH NULL AS E'\\0';
 1	\\0
@@ -280,6 +294,15 @@ SELECT * FROM testnull;
     | 
 (4 rows)
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 2);
+SELECT * FROM testnull;
+ a  | b  
+----+----
+ 42 | \0
+    | 
+(2 rows)
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -349,6 +372,34 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 2);
+SELECT * FROM vistest;
+ a  
+----
+ a2
+ b
+(2 rows)
+
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 2);
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+COMMIT;
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 SELECT * FROM vistest;
  a 
@@ -409,7 +460,7 @@ SELECT * FROM vistest;
 (2 rows)
 
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -420,6 +471,8 @@ CREATE TEMP TABLE forcetest (
 -- should succeed with no effect ("b" remains an empty string, "c" remains NULL)
 BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 2);
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
  b |  c   
@@ -430,6 +483,8 @@ SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
 BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 2);
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
  c |  d   
@@ -486,6 +541,31 @@ select * from check_con_tbl;
    
 (2 rows)
 
+\d+ check_con_tbl
+                               Table "public.check_con_tbl"
+ Column |  Type   | Collation | Nullable | Default | Storage | Stats target | Description 
+--------+---------+-----------+----------+---------+---------+--------------+-------------
+ f1     | integer |           |          |         | plain   |              | 
+Check constraints:
+    "check_con_tbl_check" CHECK (check_con_function(check_con_tbl.*))
+
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 2);
+NOTICE:  input = {"f1":1}
+NOTICE:  input = {"f1":null}
+copy check_con_tbl from stdin with (parallel 2);
+NOTICE:  input = {"f1":0}
+ERROR:  new row for relation "check_con_tbl" violates check constraint "check_con_tbl_check"
+DETAIL:  Failing row contains (0).
+CONTEXT:  COPY check_con_tbl, line 1: "0"
+parallel worker
+select * from check_con_tbl;
+ f1 
+----
+  1
+   
+(2 rows)
+
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
 CREATE ROLE regress_rls_copy_user_colperms;
@@ -600,8 +680,130 @@ SELECT * FROM instead_of_insert_tbl;
 (2 rows)
 
 COMMIT;
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+COPY test_parallel_copy (a, b, c, d, e) from stdin with (PARALLEL '2');
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '2');
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '2');
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '2', FORMAT 'csv', HEADER);
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0');
+ERROR:  argument to option "parallel" must be a positive integer greater than zero
+LINE 1: COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0'...
+                                                        ^
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri from stdin with (FORMAT csv, DELIMITER ',', PARALLEL '2');
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', parallel '2') WHERE height > random() * 65;
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', parallel '2');
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- temporary table copy: should peform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+COPY temp_test (a) from stdin with (PARALLEL '2');
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) from stdin with (PARALLEL '2');
+ERROR:  column "xyz" of relation "test_parallel_copy" does not exist
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) from stdin with (PARALLEL '2');
+ERROR:  column "d" specified more than once
+-- missing data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL '2');
+ERROR:  invalid input syntax for type integer: ""
+CONTEXT:  COPY test_parallel_copy, line 0, column a: ""
+parallel worker
+COPY test_parallel_copy from stdin with (PARALLEL '2');
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2000	230	23	23"
+parallel worker
+COPY test_parallel_copy from stdin with (PARALLEL '2');
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2001	231	\N	\N"
+parallel worker
+-- extra data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL '2');
+ERROR:  extra data after last expected column
+CONTEXT:  COPY test_parallel_copy, line 1: "2002	232	40	50	60	70	80"
+parallel worker
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) from stdin with (delimiter ',', null 'x', PARALLEL '2') ;
+COPY test_parallel_copy from stdin WITH (DELIMITER ';', NULL '', PARALLEL '2');
+COPY test_parallel_copy from stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL '2');
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a = 50004;
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a > 60003;
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE f > 60003;
+ERROR:  column "f" does not exist
+LINE 1: ...arallel_copy from stdin WITH (PARALLEL '2') WHERE f > 60003;
+                                                             ^
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a = max(x.b);
+ERROR:  missing FROM-clause entry for table "x"
+LINE 1: ...llel_copy from stdin WITH (PARALLEL '2') WHERE a = max(x.b);
+                                                                  ^
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a IN (SELECT 1 FROM x);
+ERROR:  cannot use subquery in COPY FROM WHERE condition
+LINE 1: ...allel_copy from stdin WITH (PARALLEL '2') WHERE a IN (SELECT...
+                                                             ^
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a IN (generate_series(1,5));
+ERROR:  set-returning functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...l_copy from stdin WITH (PARALLEL '2') WHERE a IN (generate_s...
+                                                             ^
+COPY test_parallel_copy from stdin WITH(PARALLEL '2') WHERE a = row_number() over(b);
+ERROR:  window functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...llel_copy from stdin WITH(PARALLEL '2') WHERE a = row_number...
+                                                             ^
+-- check results of copy in
+SELECT * FROM test_parallel_copy;
+   a   | b  |     c      |    d    |    e    
+-------+----+------------+---------+---------
+     1 | 11 | test_c1    | test_d1 | test_e1
+     2 | 12 | test_c2    | test_d2 | test_e2
+       |  3 | stuff      | test_d3 | 
+       |  4 | stuff      | test_d4 | 
+       |  5 | stuff      | test_d5 | 
+       |    | 45         | 80      | 90
+       |    | x          | \x      | \x
+       |    | ,          | \,      | \
+  3000 |    | c          |         | 
+  4000 |    | C          |         | 
+  4001 |  1 | empty      |         | 
+  4002 |  2 | null       |         | 
+  4003 |  3 | Backslash  | \       | \
+  4004 |  4 | BackslashX | \X      | \X
+  4005 |  5 | N          | N       | N
+  4006 |  6 | BackslashN | \N      | \N
+  4007 |  7 | XX         | XX      | XX
+  4008 |  8 | Delimiter  | :       | :
+ 50004 | 25 | 35         | 45      | 55
+ 60004 | 25 | 35         | 45      | 55
+ 60005 | 26 | 36         | 46      | 56
+(21 rows)
+
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
 DROP TABLE x, y;
diff --git a/src/test/regress/input/copy.source b/src/test/regress/input/copy.source
index a1d529a..159c058 100644
--- a/src/test/regress/input/copy.source
+++ b/src/test/regress/input/copy.source
@@ -15,6 +15,13 @@ DELETE FROM onek;
 
 COPY onek FROM '@abs_builddir@/results/onek.data';
 
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+
+SELECT COUNT(*) FROM tenk1;
+
+TRUNCATE tenk1;
+
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
@@ -159,6 +166,11 @@ truncate parted_copytest;
 
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
 
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
+
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/output/copy.source b/src/test/regress/output/copy.source
index 938d355..c3003fe 100644
--- a/src/test/regress/output/copy.source
+++ b/src/test/regress/output/copy.source
@@ -9,6 +9,15 @@ COPY onek FROM '@abs_srcdir@/data/onek.data';
 COPY onek TO '@abs_builddir@/results/onek.data';
 DELETE FROM onek;
 COPY onek FROM '@abs_builddir@/results/onek.data';
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+SELECT COUNT(*) FROM tenk1;
+ count 
+-------
+ 10000
+(1 row)
+
+TRUNCATE tenk1;
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
 COPY person FROM '@abs_srcdir@/data/person.data';
@@ -113,6 +122,9 @@ insert into parted_copytest select x,1,'One' from generate_series(1011,1020) x;
 copy (select * from parted_copytest order by a) to '@abs_builddir@/results/parted_copytest.csv';
 truncate parted_copytest;
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/sql/copy2.sql b/src/test/regress/sql/copy2.sql
index 902f4fa..13104f4 100644
--- a/src/test/regress/sql/copy2.sql
+++ b/src/test/regress/sql/copy2.sql
@@ -157,7 +157,7 @@ COPY y TO stdout (FORMAT CSV, FORCE_QUOTE *);
 
 --test that we read consecutive LFs properly
 
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 
 COPY testnl FROM stdin CSV;
 1,"a field with two LFs
@@ -165,8 +165,16 @@ COPY testnl FROM stdin CSV;
 inside",2
 \.
 
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL '2');
+1,"a field with two LFs
+
+inside",2
+\.
+
+SELECT * FROM testnl;
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 
 COPY testeoc FROM stdin CSV;
 a\.
@@ -175,11 +183,19 @@ c\.d
 "\."
 \.
 
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL '2');
+a\.
+\.b
+c\.d
+"\."
+\.
+
 COPY testeoc TO stdout CSV;
 
 -- test handling of nonstandard null marker that violates escaping rules
 
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 
 COPY testnull TO stdout WITH NULL AS E'\\0';
@@ -191,6 +207,14 @@ COPY testnull FROM stdin WITH NULL AS E'\\0';
 
 SELECT * FROM testnull;
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 2);
+42	\\0
+\0	\0
+\.
+
+SELECT * FROM testnull;
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -235,6 +259,23 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 2);
+a2
+b
+\.
+SELECT * FROM vistest;
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 2);
+d2
+e
+\.
+SELECT * FROM vistest;
+COMMIT;
+SELECT * FROM vistest;
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 x
 y
@@ -284,7 +325,7 @@ SELECT * FROM vistest;
 COMMIT;
 SELECT * FROM vistest;
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -297,6 +338,10 @@ BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
 1,,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 2);
+1,,""
+\.
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
@@ -304,6 +349,10 @@ BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
 2,'a',,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 2);
+2,'a',,""
+\.
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
 -- should fail with not-null constraint violation
@@ -339,6 +388,16 @@ copy check_con_tbl from stdin;
 0
 \.
 select * from check_con_tbl;
+\d+ check_con_tbl
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 2);
+1
+\N
+\.
+copy check_con_tbl from stdin with (parallel 2);
+0
+\.
+select * from check_con_tbl;
 
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
@@ -440,8 +499,149 @@ test1
 SELECT * FROM instead_of_insert_tbl;
 COMMIT;
 
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+
+COPY test_parallel_copy (a, b, c, d, e) from stdin with (PARALLEL '2');
+1	11	test_c1	test_d1	test_e1
+2	12	test_c2	test_d2	test_e2
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '2');
+3	test_d3
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '2');
+4	test_d4
+5	test_d5
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '2', FORMAT 'csv', HEADER);
+b	d
+\.
+
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0');
+
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri from stdin with (FORMAT csv, DELIMITER ',', PARALLEL '2');
+10
+\.
+
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', parallel '2') WHERE height > random() * 65;
+60,60,60
+\.
+
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', parallel '2');
+60
+\.
+
+-- temporary table copy: should peform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+
+COPY temp_test (a) from stdin with (PARALLEL '2');
+10
+\.
+
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) from stdin with (PARALLEL '2');
+
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) from stdin with (PARALLEL '2');
+
+-- missing data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL '2');
+
+\.
+COPY test_parallel_copy from stdin with (PARALLEL '2');
+2000	230	23	23
+\.
+COPY test_parallel_copy from stdin with (PARALLEL '2');
+2001	231	\N	\N
+\.
+
+-- extra data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL '2');
+2002	232	40	50	60	70	80
+\.
+
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) from stdin with (delimiter ',', null 'x', PARALLEL '2') ;
+x,45,80,90
+x,\x,\\x,\\\x
+x,\,,\\\,,\\
+\.
+
+COPY test_parallel_copy from stdin WITH (DELIMITER ';', NULL '', PARALLEL '2');
+3000;;c;;
+\.
+
+COPY test_parallel_copy from stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL '2');
+4000:\X:C:\X:\X
+4001:1:empty::
+4002:2:null:\X:\X
+4003:3:Backslash:\\:\\
+4004:4:BackslashX:\\X:\\X
+4005:5:N:\N:\N
+4006:6:BackslashN:\\N:\\N
+4007:7:XX:\XX:\XX
+4008:8:Delimiter:\::\:
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a = 50004;
+50003	24	34	44	54
+50004	25	35	45 	55
+50005	26	36	46	56
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a > 60003;
+60001	22	32	42	52
+60002	23	33	43	53
+60003	24	34	44	54
+60004	25	35	45	55
+60005	26	36	46	56
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE f > 60003;
+
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a = max(x.b);
+
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a IN (SELECT 1 FROM x);
+
+COPY test_parallel_copy from stdin WITH (PARALLEL '2') WHERE a IN (generate_series(1,5));
+
+COPY test_parallel_copy from stdin WITH(PARALLEL '2') WHERE a = row_number() over(b);
+
+-- check results of copy in
+SELECT * FROM test_parallel_copy;
+
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
 DROP TABLE x, y;
-- 
1.8.3.1

0006-Parallel-Copy-For-Binary-Format-Files.patchapplication/octet-stream; name=0006-Parallel-Copy-For-Binary-Format-Files.patchDownload
From 19af24a893547e7cc87adf2384c462a9b2bea188 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddy@enterprisedb.com>
Date: Fri, 26 Jun 2020 11:43:48 +0530
Subject: [PATCH 6/6] Parallel Copy For Binary Format Files

Leader reads data from the file into the DSM data blocks each of 64K size.
It also identifies each tuple data block id, start offset, end offset,
tuple size and updates this information in the ring data structure.
Workers parallely read the tuple information from the ring data structure,
the actual tuple data from the data blocks and parallely insert the tuples
into the table.
---
 src/backend/commands/copy.c | 697 ++++++++++++++++++++++++++++++++----
 1 file changed, 627 insertions(+), 70 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 440ada868d..c4c8078fe1 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -219,6 +219,16 @@ typedef struct ParallelCopyLineBuf
 	uint64				cur_lineno;	/* line number for error messages */
 }ParallelCopyLineBuf;
 
+/*
+ * Tuple boundary information used for parallel copy
+ * for binary format files.
+ */
+typedef struct ParallelCopyTupleInfo
+{
+	uint32 offset;
+	uint32 block_id;
+}ParallelCopyTupleInfo;
+
 /*
  * Parallel copy data information.
  */
@@ -240,6 +250,11 @@ typedef struct ParallelCopyData
 
 	/* Current position in worker_line_buf */
 	uint32				worker_line_buf_pos;
+
+	/*
+	 * For binary formatted files
+	 */
+	ParallelCopyDataBlock *curr_data_block;
 }ParallelCopyData;
 
 /*
@@ -397,6 +412,7 @@ typedef struct ParallelCopyCommonKeyData
 	/* Working state for COPY FROM */
 	AttrNumber          num_defaults;
 	Oid                 relid;
+	bool 				binary;
 }ParallelCopyCommonKeyData;
 
 /*
@@ -697,6 +713,56 @@ if (!IsParallelCopy()) \
 else \
 	return pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
 
+/*
+ * CHECK_FIELD_COUNT - Handles the error cases for field count
+ * for binary format files.
+ */
+#define CHECK_FIELD_COUNT \
+{\
+	if (fld_count == -1) \
+	{ \
+		if (IsParallelCopy() && \
+			!IsLeader()) \
+			return true; \
+		else if (IsParallelCopy() && \
+			IsLeader()) \
+		{ \
+			if (cstate->pcdata->curr_data_block->data[cstate->raw_buf_index + sizeof(fld_count)] != 0) \
+				ereport(ERROR, \
+						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+						errmsg("received copy data after EOF marker"))); \
+			return true; \
+		} \
+		else \
+		{ \
+			/* \
+			* Received EOF marker.  In a V3-protocol copy, wait for the \
+			* protocol-level EOF, and complain if it doesn't come \
+			* immediately.  This ensures that we correctly handle CopyFail, \
+			* if client chooses to send that now. \
+			* \
+			* Note that we MUST NOT try to read more data in an old-protocol \
+			* copy, since there is no protocol-level EOF marker then.  We \
+			* could go either way for copy from file, but choose to throw \
+			* error if there's data after the EOF marker, for consistency \
+			* with the new-protocol case. \
+			*/ \
+			char		dummy; \
+			if (cstate->copy_dest != COPY_OLD_FE && \
+				CopyGetData(cstate, &dummy, 1, 1) > 0) \
+				ereport(ERROR, \
+						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+						errmsg("received copy data after EOF marker"))); \
+				return false; \
+		} \
+	} \
+	if (fld_count != cstate->max_fields) \
+		ereport(ERROR, \
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+				errmsg("row field count is %d, expected %d", \
+				(int) fld_count, cstate->max_fields))); \
+}
+
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
 
@@ -751,6 +817,16 @@ static void PopulateCatalogInformation(CopyState cstate);
 static pg_attribute_always_inline uint32 GetLinePosition(CopyState cstate);
 static pg_attribute_always_inline copy_data_source_cb LookupParallelCopyFnPtr(const char *funcname);
 static pg_attribute_always_inline char* LookupParallelCopyFnStr(copy_data_source_cb fn_addr);
+static uint32 WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info);
+static pg_attribute_always_inline bool CopyReadBinaryTupleLeader(CopyState cstate);
+static pg_attribute_always_inline void CopyReadBinaryAttributeLeader(CopyState cstate,
+										FmgrInfo *flinfo, Oid typioparam, int32 typmod,
+										uint32 *new_block_pos, int m, ParallelCopyTupleInfo *tuple_start_info_ptr,
+										ParallelCopyTupleInfo *tuple_end_info_ptr, uint32 *line_size);
+static pg_attribute_always_inline bool CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls);
+static pg_attribute_always_inline Datum CopyReadBinaryAttributeWorker(CopyState cstate, FmgrInfo *flinfo,
+										  Oid typioparam, int32 typmod, bool *isnull);
+static void AdjustFieldInfo(CopyState cstate, uint8 mode);
 
 /*
  * CopyCommonInfoForWorker - Copy shared_cstate using cstate information.
@@ -769,6 +845,7 @@ CopyCommonInfoForWorker(CopyState cstate, ParallelCopyCommonKeyData *shared_csta
 	shared_cstate->convert_selectively = cstate->convert_selectively;
 	shared_cstate->num_defaults = cstate->num_defaults;
 	shared_cstate->relid = cstate->pcdata->relid;
+	shared_cstate->binary = cstate->binary;
 }
 
 /*
@@ -997,8 +1074,8 @@ FindInsertMethod(CopyState cstate)
 static pg_attribute_always_inline bool
 IsParallelCopyAllowed(CopyState cstate)
 {
-	/* Parallel copy not allowed for frontend (2.0 protocol) & binary option. */
-	if ((cstate->copy_dest == COPY_OLD_FE) || cstate->binary)
+	/* Parallel copy not allowed for frontend (2.0 protocol). */
+	if (cstate->copy_dest == COPY_OLD_FE)
 		return false;
 
 	/* Check if copy is into foreign table or temporary table. */
@@ -1299,6 +1376,7 @@ ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
 	cstate->convert_selectively = shared_cstate->convert_selectively;
 	cstate->num_defaults = shared_cstate->num_defaults;
 	pcdata->relid = shared_cstate->relid;
+	cstate->binary = shared_cstate->binary;
 
 	PopulateGlobalsForCopyFrom(cstate, tup_desc, attnamelist);
 
@@ -1314,7 +1392,7 @@ ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
 	initStringInfo(&cstate->attribute_buf);
 
 	initStringInfo(&cstate->line_buf);
-	for (count = 0; count < WORKER_CHUNK_COUNT;count++)
+	for (count = 0; count < WORKER_CHUNK_COUNT; count++)
 		initStringInfo(&pcdata->worker_line_buf[count].line_buf);
 
 	cstate->line_buf_converted = false;
@@ -1679,32 +1757,66 @@ ParallelCopyLeader(CopyState cstate)
 	/* Execute the before statement triggers from the leader */
 	ExecBeforeStmtTrigger(cstate);
 
-	/* On input just throw the header line away. */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (!cstate->binary)
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
+		/* On input just throw the header line away. */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
 		{
-			pcshared_info->is_read_in_progress = false;
-			return;			/* done */
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+			{
+				pcshared_info->is_read_in_progress = false;
+				return;			/* done */
+			}
 		}
-	}
 
-	for (;;)
-	{
-		bool done;
-		cstate->cur_lineno++;
+		for (;;)
+		{
+			bool done;
+			cstate->cur_lineno++;
 
-		/* Actually read the line into memory here. */
-		done = CopyReadLine(cstate);
+			/* Actually read the line into memory here. */
+			done = CopyReadLine(cstate);
 
-		/*
-		 * EOF at start of line means we're done.  If we see EOF after some
-		 * characters, we act as though it was newline followed by EOF, ie,
-		 * process the line and then exit loop on next iteration.
+			/*
+			* EOF at start of line means we're done.  If we see EOF after some
+			* characters, we act as though it was newline followed by EOF, ie,
+			* process the line and then exit loop on next iteration.
+			*/
+			if (done && cstate->line_buf.len == 0)
+				break;
+		}
+	}
+	else
+	{
+		/* binary format */
+		/* for paralle copy leader, fill in the error
+		 * context inforation here, in case any failures
+		 * while determining tuple offsets, leader
+		 * would throw the errors with proper context.
 		 */
-		if (done && cstate->line_buf.len == 0)
-			break;
+		ErrorContextCallback errcallback;
+		errcallback.callback = CopyFromErrorCallback;
+		errcallback.arg = (void *) cstate;
+		errcallback.previous = error_context_stack;
+		error_context_stack = &errcallback;
+
+		cstate->pcdata->curr_data_block = NULL;
+		cstate->raw_buf_index = 0;
+		pcshared_info->populated = 0;
+		cstate->cur_lineno = 0;
+		cstate->max_fields = list_length(cstate->attnumlist);
+
+		for (;;)
+		{
+			bool eof = false;
+			cstate->cur_lineno++;
+
+			eof = CopyReadBinaryTupleLeader(cstate);
+
+			if (eof)
+				break;
+		}
 	}
 
 	pcshared_info->is_read_in_progress = false;
@@ -1712,7 +1824,463 @@ ParallelCopyLeader(CopyState cstate)
 }
 
 /*
- * GetLinePosition - return the line position that worker should process.
+ * AdjustFieldInfo - gets a new block, updates the
+ * current offset, calculates the skip bytes.
+ * Works in two modes, 1 for field count
+ * 2 for field size
+ */
+static void
+AdjustFieldInfo(CopyState cstate, uint8 mode)
+{
+	ParallelCopyDataBlock *data_block = NULL;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	uint8 movebytes = 0;
+	uint32 block_pos;
+	uint32 prev_block_pos;
+	int readbytes = 0;
+
+	prev_block_pos = pcshared_info->cur_block_pos;
+
+	block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+	movebytes = DATA_BLOCK_SIZE - cstate->raw_buf_index;
+
+	cstate->pcdata->curr_data_block->skip_bytes = movebytes;
+
+	data_block = &pcshared_info->data_blocks[block_pos];
+
+	if (movebytes > 0)
+		memmove(&data_block->data[0], &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index],
+			movebytes);
+
+	elog(DEBUG1, "LEADER - field info is spread across data blocks - moved %d bytes from current block %u to %u block",
+		movebytes, prev_block_pos, block_pos);
+
+	readbytes = CopyGetData(cstate, &data_block->data[movebytes], 1, (DATA_BLOCK_SIZE - movebytes));
+
+	elog(DEBUG1, "LEADER - bytes read from file after field info is moved to next data block %d", readbytes);
+
+	if (cstate->reached_eof)
+		ereport(ERROR,
+			(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				errmsg("unexpected EOF in COPY data")));
+
+	if (mode == 1)
+	{
+		cstate->pcdata->curr_data_block = data_block;
+		cstate->raw_buf_index = 0;
+	}
+	else if(mode == 2)
+	{
+		ParallelCopyDataBlock *prev_data_block = NULL;
+		prev_data_block = cstate->pcdata->curr_data_block;
+		prev_data_block->following_block = block_pos;
+		cstate->pcdata->curr_data_block = data_block;
+
+		if (prev_data_block->curr_blk_completed  == false)
+			prev_data_block->curr_blk_completed = true;
+
+		cstate->raw_buf_index = 0;
+	}
+}
+
+/*
+ * CopyReadBinaryTupleLeader - leader reads data from binary formatted file
+ * to data blocks and identies tuple boundaries/offsets so that workers
+ * can work on the data blocks data.
+ */
+static pg_attribute_always_inline bool
+CopyReadBinaryTupleLeader(CopyState cstate)
+{
+	int readbytes = 0;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	uint32 block_pos;
+	int16		fld_count;
+	ListCell   *cur;
+	FmgrInfo   *in_functions = cstate->in_functions;
+	Oid		   *typioparams = cstate->typioparams;
+	TupleDesc	tupDesc = RelationGetDescr(cstate->rel);
+	uint32      new_block_pos;
+	uint32      line_size = -1;
+	ParallelCopyTupleInfo curr_tuple_start_info;
+	ParallelCopyTupleInfo curr_tuple_end_info;
+
+	curr_tuple_start_info.block_id = -1;
+	curr_tuple_start_info.offset = -1;
+	curr_tuple_end_info.block_id = -1;
+	curr_tuple_end_info.offset = -1;
+
+	if (cstate->pcdata->curr_data_block == NULL)
+	{
+		block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+		cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[block_pos];
+
+		cstate->raw_buf_index = 0;
+
+		readbytes = CopyGetData(cstate, &cstate->pcdata->curr_data_block->data, 1, DATA_BLOCK_SIZE);
+
+		elog(DEBUG1, "LEADER - bytes read from file %d", readbytes);
+
+		if (cstate->reached_eof)
+			return true;
+	}
+
+	if (cstate->raw_buf_index + sizeof(fld_count) >= (DATA_BLOCK_SIZE - 1))
+		AdjustFieldInfo(cstate, 1);
+
+	memcpy(&fld_count, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_count));
+
+	fld_count = (int16) pg_ntoh16(fld_count);
+
+	CHECK_FIELD_COUNT;
+
+	cstate->raw_buf_index = cstate->raw_buf_index + sizeof(fld_count);
+	new_block_pos = pcshared_info->cur_block_pos;
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			attnum = lfirst_int(cur);
+		int			m = attnum - 1;
+		Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+		cstate->cur_attname = NameStr(att->attname);
+
+		CopyReadBinaryAttributeLeader(cstate,
+									&in_functions[m],
+									typioparams[m],
+									att->atttypmod,
+									&new_block_pos,
+									m,
+									&curr_tuple_start_info,
+									&curr_tuple_end_info,
+									&line_size);
+
+		cstate->cur_attname = NULL;
+	}
+
+	if (line_size > 0)
+	{
+		int line_pos = UpdateBlockInLineInfo(cstate,
+											curr_tuple_start_info.block_id,
+											curr_tuple_start_info.offset,
+											line_size,
+											LINE_LEADER_POPULATED);
+
+		pcshared_info->populated++;
+
+		elog(DEBUG1, "LEADER - adding - block:%u, offset:%u, line size:%u line position:%d",
+						 curr_tuple_start_info.block_id,
+						 curr_tuple_start_info.offset,
+						 line_size, line_pos);
+	}
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryAttributeLeader - leader identifies boundaries/offsets
+ * for each attribute/column, it moves on to next data block if the
+ * attribute/column is spread across data blocks.
+ */
+static pg_attribute_always_inline void
+CopyReadBinaryAttributeLeader(CopyState cstate, FmgrInfo *flinfo,
+	Oid typioparam, int32 typmod, uint32 *new_block_pos,
+	int m, ParallelCopyTupleInfo *tuple_start_info_ptr,
+	ParallelCopyTupleInfo *tuple_end_info_ptr, uint32 *line_size)
+{
+	int32		fld_size;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+	if (m == 0)
+	{
+		tuple_start_info_ptr->block_id = pcshared_info->cur_block_pos;
+		/* raw_buf_index would have moved away size of field count bytes
+		   in the caller, so move back to store the tuple start offset.
+		*/
+		tuple_start_info_ptr->offset =  cstate->raw_buf_index - sizeof(int16);
+	}
+
+	if ((cstate->raw_buf_index + sizeof(fld_size)) >= (DATA_BLOCK_SIZE - 1))
+	{
+		AdjustFieldInfo(cstate, 2);
+		*new_block_pos = pcshared_info->cur_block_pos;
+	}
+
+	memcpy(&fld_size, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_size));
+
+	cstate->raw_buf_index = cstate->raw_buf_index + sizeof(fld_size);
+
+	fld_size = (int32) pg_ntoh32(fld_size);
+
+	if (fld_size == 0)
+		ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("unexpected EOF in COPY data")));
+
+	if (fld_size < -1)
+		ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("invalid field size")));
+
+	if ((DATA_BLOCK_SIZE - cstate->raw_buf_index) >= fld_size)
+	{
+		cstate->raw_buf_index = cstate->raw_buf_index + fld_size;
+	}
+	else
+	{
+		ParallelCopyDataBlock *data_block = NULL;
+		ParallelCopyDataBlock *prev_data_block = NULL;
+		uint32 block_pos = *new_block_pos;
+		int readbytes;
+		int32 requiredblocks = 0;
+		int32 remainingbytesincurrdatablock = DATA_BLOCK_SIZE - cstate->raw_buf_index;
+		int i = 0;
+
+		/* field size can spread across multiple data blocks,
+		 * calculate the number of required data blocks and try to get
+		 * those many data blocks.
+		 */
+		requiredblocks = (int32)(fld_size - remainingbytesincurrdatablock)/(int32)DATA_BLOCK_SIZE;
+
+		if ((fld_size - remainingbytesincurrdatablock)%DATA_BLOCK_SIZE != 0)
+			requiredblocks++;
+
+		i = requiredblocks;
+
+		while(i > 0)
+		{
+			data_block = NULL;
+			prev_data_block = NULL;
+			readbytes = 0;
+
+			block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+			data_block = &pcshared_info->data_blocks[block_pos];
+
+			readbytes = CopyGetData(cstate, &data_block->data[0], 1, DATA_BLOCK_SIZE);
+
+			elog(DEBUG1, "LEADER - bytes read from file after detecting that tuple is spread across data blocks %d", readbytes);
+
+			/* eof here means that most probably,
+			 * the field size would have been corrupted.
+			 */
+			if (cstate->reached_eof)
+				ereport(ERROR,
+					(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+					errmsg("unexpected EOF in COPY data")));
+
+			prev_data_block = cstate->pcdata->curr_data_block;
+			prev_data_block->following_block = block_pos;
+
+			if (prev_data_block->curr_blk_completed  == false)
+				prev_data_block->curr_blk_completed = true;
+
+			cstate->pcdata->curr_data_block = data_block;
+
+			i--;
+		}
+
+		cstate->raw_buf_index = fld_size - (((requiredblocks - 1) * DATA_BLOCK_SIZE) +
+									remainingbytesincurrdatablock);
+
+		/* raw_buf_index should never cross data block size,
+		 * as the required number of data blocks would have
+		 * been obtained in the above while loop.
+		 */
+		Assert(cstate->raw_buf_index <= DATA_BLOCK_SIZE);
+
+		*new_block_pos = block_pos;
+	}
+
+	if (m == cstate->max_fields - 1)
+	{
+		tuple_end_info_ptr->block_id = *new_block_pos;
+		tuple_end_info_ptr->offset =  cstate->raw_buf_index - 1;
+
+		if (tuple_start_info_ptr->block_id == tuple_end_info_ptr->block_id)
+		{
+			elog(DEBUG1,"LEADER - tuple lies in a single data block");
+
+			*line_size = tuple_end_info_ptr->offset - tuple_start_info_ptr->offset + 1;
+			pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[tuple_start_info_ptr->block_id].unprocessed_line_parts, 1);
+		}
+		else
+		{
+			uint32 following_block_id = pcshared_info->data_blocks[tuple_start_info_ptr->block_id].following_block;
+
+			elog(DEBUG1,"LEADER - tuple is spread across data blocks");
+
+			*line_size = DATA_BLOCK_SIZE - tuple_start_info_ptr->offset -
+				pcshared_info->data_blocks[tuple_start_info_ptr->block_id].skip_bytes;
+
+			pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[tuple_start_info_ptr->block_id].unprocessed_line_parts, 1);
+
+			while (following_block_id != tuple_end_info_ptr->block_id)
+			{
+				*line_size = *line_size + DATA_BLOCK_SIZE - pcshared_info->data_blocks[following_block_id].skip_bytes;
+
+				pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[following_block_id].unprocessed_line_parts, 1);
+
+				following_block_id = pcshared_info->data_blocks[following_block_id].following_block;
+
+				if (following_block_id == -1)
+					break;
+			}
+
+			if (following_block_id != -1)
+				pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[following_block_id].unprocessed_line_parts, 1);
+
+			*line_size = *line_size + tuple_end_info_ptr->offset + 1;
+		}
+	}
+}
+
+/*
+ * CopyReadBinaryTupleWorker - each worker reads data from data blocks after
+ * getting leader-identified tuple offsets from ring data structure.
+ */
+static pg_attribute_always_inline bool
+CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls)
+{
+	uint32 line_pos;
+	ParallelCopyLineBoundary *line_info;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	int16		fld_count;
+	ListCell   *cur;
+	FmgrInfo   *in_functions = cstate->in_functions;
+	Oid		   *typioparams = cstate->typioparams;
+	TupleDesc	tupDesc = RelationGetDescr(cstate->rel);
+
+	line_pos = GetLinePosition(cstate);
+
+	if (line_pos == -1)
+		return true;
+
+	line_info = &pcshared_info->line_boundaries.ring[line_pos];
+	cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[line_info->first_block];
+	cstate->raw_buf_index = line_info->start_offset;
+
+	if (cstate->raw_buf_index + sizeof(fld_count) >= (DATA_BLOCK_SIZE - 1))
+		/*the case where field count spread across datablocks should never occur.
+		  as the leader would have moved it to next block*/
+		elog(DEBUG1, "WORKER - field count spread across datablocks should never occur");
+
+	memcpy(&fld_count, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_count));
+	fld_count = (int16) pg_ntoh16(fld_count);
+
+	CHECK_FIELD_COUNT;
+
+	cstate->raw_buf_index = cstate->raw_buf_index + sizeof(fld_count);
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			attnum = lfirst_int(cur);
+		int			m = attnum - 1;
+		Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+		cstate->cur_attname = NameStr(att->attname);
+
+		values[m] = CopyReadBinaryAttributeWorker(cstate,
+											&in_functions[m],
+											typioparams[m],
+											att->atttypmod,
+											&nulls[m]);
+		cstate->cur_attname = NULL;
+	}
+
+	pg_atomic_sub_fetch_u32(&cstate->pcdata->curr_data_block->unprocessed_line_parts, 1);
+	line_info->start_offset = -1;
+	pg_atomic_write_u32(&line_info->line_state, LINE_WORKER_PROCESSED);
+	pg_atomic_write_u32(&line_info->line_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryAttributeWorker - leader identifies boundaries/offsets
+ * for each attribute/column, it moves on to next data block if the
+ * attribute/column is spread across data blocks.
+ */
+static pg_attribute_always_inline Datum
+CopyReadBinaryAttributeWorker(CopyState cstate, FmgrInfo *flinfo,
+		Oid typioparam, int32 typmod, bool *isnull)
+{
+	int32		fld_size;
+	Datum		result;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+	if ((cstate->raw_buf_index + sizeof(fld_size)) >= (DATA_BLOCK_SIZE - 1))
+	{
+		ParallelCopyDataBlock *prev_data_block = cstate->pcdata->curr_data_block;
+
+		elog(DEBUG1, "WORKER - field size is spread across data blocks");
+
+		cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[cstate->pcdata->curr_data_block->following_block];
+		pg_atomic_sub_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+		cstate->raw_buf_index = 0;
+	}
+
+	memcpy(&fld_size, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_size));
+	fld_size = (int32) pg_ntoh32(fld_size);
+
+	if (fld_size == 0)
+		ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("unexpected EOF in COPY data")));
+
+	if (fld_size < -1)
+		ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("invalid field size")));
+
+	cstate->raw_buf_index = cstate->raw_buf_index + sizeof(fld_size);
+
+	/* reset attribute_buf to empty, and load raw data in it */
+	resetStringInfo(&cstate->attribute_buf);
+
+	enlargeStringInfo(&cstate->attribute_buf, fld_size);
+
+	if ((DATA_BLOCK_SIZE - cstate->raw_buf_index) >= fld_size)
+	{
+		elog(DEBUG1, "WORKER - tuple lies in single data block");
+
+		memcpy(&cstate->attribute_buf.data[0],&cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], fld_size);
+		cstate->raw_buf_index = cstate->raw_buf_index + fld_size;
+	}
+	else
+	{
+		ParallelCopyDataBlock *prev_data_block = cstate->pcdata->curr_data_block;
+
+		elog(DEBUG1, "WORKER - tuple is spread across data blocks");
+
+		memcpy(&cstate->attribute_buf.data[0], &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index],
+				(DATA_BLOCK_SIZE - cstate->raw_buf_index));
+		cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[cstate->pcdata->curr_data_block->following_block];
+		pg_atomic_sub_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+		memcpy(&cstate->attribute_buf.data[DATA_BLOCK_SIZE - cstate->raw_buf_index],
+			&cstate->pcdata->curr_data_block->data[0], (fld_size - (DATA_BLOCK_SIZE - cstate->raw_buf_index)));
+		cstate->raw_buf_index = fld_size - (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+	}
+
+	cstate->attribute_buf.len = fld_size;
+	cstate->attribute_buf.data[fld_size] = '\0';
+
+	/* Call the column type's binary input converter */
+	result = ReceiveFunctionCall(flinfo, &cstate->attribute_buf,
+								 typioparam, typmod);
+
+	/* Trouble if it didn't eat the whole buffer */
+	if (cstate->attribute_buf.cursor != cstate->attribute_buf.len)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+				 errmsg("incorrect binary data format")));
+
+	*isnull = false;
+	return result;
+}
+
+/*
+ * GetLinePosition - return the line position that worker should pcdata->process.
  */
 static uint32
 GetLinePosition(CopyState cstate)
@@ -1797,7 +2365,9 @@ GetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
 		{
 			dataBlkPtr->curr_blk_completed = false;
 			dataBlkPtr->skip_bytes = 0;
+			dataBlkPtr->following_block = -1;
 			pcshared_info->cur_block_pos = block_pos;
+			MemSet(&dataBlkPtr->data[0], 0, DATA_BLOCK_SIZE);
 			return block_pos;
 		}
 
@@ -5476,60 +6046,47 @@ NextCopyFrom(CopyState cstate, ExprContext *econtext,
 	else
 	{
 		/* binary */
-		int16		fld_count;
-		ListCell   *cur;
-
-		cstate->cur_lineno++;
-
-		if (!CopyGetInt16(cstate, &fld_count))
+		if (!IsParallelCopy())
 		{
-			/* EOF detected (end of file, or protocol-level EOF) */
-			return false;
-		}
+			int16		fld_count;
+			ListCell   *cur;
 
-		if (fld_count == -1)
-		{
-			/*
-			 * Received EOF marker.  In a V3-protocol copy, wait for the
-			 * protocol-level EOF, and complain if it doesn't come
-			 * immediately.  This ensures that we correctly handle CopyFail,
-			 * if client chooses to send that now.
-			 *
-			 * Note that we MUST NOT try to read more data in an old-protocol
-			 * copy, since there is no protocol-level EOF marker then.  We
-			 * could go either way for copy from file, but choose to throw
-			 * error if there's data after the EOF marker, for consistency
-			 * with the new-protocol case.
-			 */
-			char		dummy;
+			cstate->cur_lineno++;
+			cstate->max_fields = list_length(cstate->attnumlist);
 
-			if (cstate->copy_dest != COPY_OLD_FE &&
-				CopyGetData(cstate, &dummy, 1, 1) > 0)
-				ereport(ERROR,
-						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-						 errmsg("received copy data after EOF marker")));
-			return false;
-		}
+			if (!CopyGetInt16(cstate, &fld_count))
+			{
+				/* EOF detected (end of file, or protocol-level EOF) */
+				return false;
+			}
 
-		if (fld_count != attr_count)
-			ereport(ERROR,
-					(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-					 errmsg("row field count is %d, expected %d",
-							(int) fld_count, attr_count)));
+			CHECK_FIELD_COUNT;
 
-		foreach(cur, cstate->attnumlist)
+			foreach(cur, cstate->attnumlist)
+			{
+				int			attnum = lfirst_int(cur);
+				int			m = attnum - 1;
+				Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+
+				cstate->cur_attname = NameStr(att->attname);
+				values[m] = CopyReadBinaryAttribute(cstate,
+													&in_functions[m],
+													typioparams[m],
+													att->atttypmod,
+													&nulls[m]);
+				cstate->cur_attname = NULL;
+			}
+		}
+		else
 		{
-			int			attnum = lfirst_int(cur);
-			int			m = attnum - 1;
-			Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+			bool eof = false;
+			cstate->cur_lineno++;
+			cstate->max_fields = list_length(cstate->attnumlist);
 
-			cstate->cur_attname = NameStr(att->attname);
-			values[m] = CopyReadBinaryAttribute(cstate,
-												&in_functions[m],
-												typioparams[m],
-												att->atttypmod,
-												&nulls[m]);
-			cstate->cur_attname = NULL;
+			eof = CopyReadBinaryTupleWorker(cstate, values, nulls);
+
+			if (eof)
+				return false;
 		}
 	}
 
-- 
2.25.1

#106vignesh C
vignesh21@gmail.com
In reply to: Bharath Rupireddy (#105)
6 attachment(s)
Re: Parallel copy

Hi,

I have made few changes in 0003 & 0005 patch, there were a couple of
bugs in 0003 patch & some random test failures in 0005 patch.
Attached new patches which include the fixes for the same.
Thoughts?

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

On Fri, Jun 26, 2020 at 2:34 PM Bharath Rupireddy
<bharath.rupireddyforpostgres@gmail.com> wrote:

Show quoted text

Hi,

0006 patch has some code clean up and issue fixes found during internal testing.

Attaching the latest patches herewith.

The order of applying the patches remains the same i.e. from 0001 to 0006.

With Regards,
Bharath Rupireddy.
EnterpriseDB: http://www.enterprisedb.com

Attachments:

0001-Copy-code-readjustment-to-support-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=0001-Copy-code-readjustment-to-support-parallel-copy.patchDownload
From a6d82e18e41f5c5b9310699ccab4ce786984a8d6 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Tue, 23 Jun 2020 06:49:22 +0530
Subject: [PATCH 1/6] Copy code readjustment to support parallel copy.

This patch has the copy code slightly readjusted so that the common code is
separated to functions/macros, these functions/macros will be used by the
workers in the parallel copy code of the upcoming patches. EOL removal is moved
from CopyReadLine to CopyReadLineText, this change was required because in case
of parallel copy the record identification and record updation is done in
CopyReadLineText, before record information is updated in shared memory the new
line characters should be removed.
---
 src/backend/commands/copy.c | 372 ++++++++++++++++++++++++++------------------
 1 file changed, 221 insertions(+), 151 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 6b1fd6d..65a504f 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -95,6 +95,9 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
+#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+#define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
+
 /*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
@@ -219,7 +222,6 @@ typedef struct CopyStateData
 	 * converts it.  Note: we guarantee that there is a \0 at
 	 * raw_buf[raw_buf_len].
 	 */
-#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
@@ -347,6 +349,88 @@ if (1) \
 	goto not_end_of_copy; \
 } else ((void) 0)
 
+/*
+ * CONVERT_TO_SERVER_ENCODING - convert contents to server encoding.
+ */
+#define CONVERT_TO_SERVER_ENCODING(cstate) \
+{ \
+	/* Done reading the line.  Convert it to server encoding. */ \
+	if (cstate->need_transcoding) \
+	{ \
+		char	   *cvt; \
+		cvt = pg_any_to_server(cstate->line_buf.data, \
+							   cstate->line_buf.len, \
+							   cstate->file_encoding); \
+		if (cvt != cstate->line_buf.data) \
+		{ \
+			/* transfer converted data back to line_buf */ \
+			resetStringInfo(&cstate->line_buf); \
+			appendBinaryStringInfo(&cstate->line_buf, cvt, strlen(cvt)); \
+			pfree(cvt); \
+		} \
+	} \
+	/* Now it's safe to use the buffer in error messages */ \
+	cstate->line_buf_converted = true; \
+}
+
+/*
+ * CLEAR_EOL_FROM_COPIED_DATA - Clear EOL from the copied data.
+ */
+#define CLEAR_EOL_FROM_COPIED_DATA(copy_line_data, copy_line_pos, copy_line_size) \
+{ \
+	/* \
+	 * If we didn't hit EOF, then we must have transferred the EOL marker \
+	 * to line_buf along with the data.  Get rid of it. \
+	 */ \
+   switch (cstate->eol_type) \
+   { \
+	   case EOL_NL: \
+		   Assert(copy_line_size >= 1); \
+		   Assert(copy_line_data[copy_line_pos - 1] == '\n'); \
+		   copy_line_data[copy_line_pos - 1] = '\0'; \
+		   copy_line_size--; \
+		   break; \
+	   case EOL_CR: \
+		   Assert(copy_line_size >= 1); \
+		   Assert(copy_line_data[copy_line_pos - 1] == '\r'); \
+		   copy_line_data[copy_line_pos - 1] = '\0'; \
+		   copy_line_size--; \
+		   break; \
+	   case EOL_CRNL: \
+		   Assert(copy_line_size >= 2); \
+		   Assert(copy_line_data[copy_line_pos - 2] == '\r'); \
+		   Assert(copy_line_data[copy_line_pos - 1] == '\n'); \
+		   copy_line_data[copy_line_pos - 2] = '\0'; \
+		   copy_line_size -= 2; \
+		   break; \
+	   case EOL_UNKNOWN: \
+		   /* shouldn't get here */ \
+		   Assert(false); \
+		   break; \
+   } \
+}
+
+/*
+ * CLEAR_EOL_LINE - Wrapper for clearing EOL.
+ */
+#define CLEAR_EOL_LINE() \
+if (!result && !IsHeaderLine()) \
+	CLEAR_EOL_FROM_COPIED_DATA(cstate->line_buf.data, \
+								cstate->line_buf.len, \
+								cstate->line_buf.len) \
+
+/*
+ * INCREMENTPROCESSED - Increment the lines processed.
+ */
+#define INCREMENTPROCESSED(processed)  \
+processed++;
+
+/*
+ * GETPROCESSED - Get the lines processed.
+ */
+#define GETPROCESSED(processed) \
+return processed;
+
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
 
@@ -392,6 +476,8 @@ static bool CopyGetInt32(CopyState cstate, int32 *val);
 static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 
+static void PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tup_desc,
+							   List *attnamelist);
 
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
@@ -793,6 +879,7 @@ CopyLoadRawBuf(CopyState cstate)
 {
 	int			nbytes;
 	int			inbytes;
+	int         minread = 1;
 
 	if (cstate->raw_buf_index < cstate->raw_buf_len)
 	{
@@ -804,8 +891,11 @@ CopyLoadRawBuf(CopyState cstate)
 	else
 		nbytes = 0;				/* no data need be saved */
 
+	if (cstate->copy_dest == COPY_NEW_FE)
+		minread = RAW_BUF_SIZE - nbytes;
+
 	inbytes = CopyGetData(cstate, cstate->raw_buf + nbytes,
-						  1, RAW_BUF_SIZE - nbytes);
+						  minread, RAW_BUF_SIZE - nbytes);
 	nbytes += inbytes;
 	cstate->raw_buf[nbytes] = '\0';
 	cstate->raw_buf_index = 0;
@@ -1463,7 +1553,6 @@ BeginCopy(ParseState *pstate,
 {
 	CopyState	cstate;
 	TupleDesc	tupDesc;
-	int			num_phys_attrs;
 	MemoryContext oldcontext;
 
 	/* Allocate workspace and zero all fields */
@@ -1629,6 +1718,24 @@ BeginCopy(ParseState *pstate,
 		tupDesc = cstate->queryDesc->tupDesc;
 	}
 
+	PopulateGlobalsForCopyFrom(cstate, tupDesc, attnamelist);
+	cstate->copy_dest = COPY_FILE;	/* default */
+
+	MemoryContextSwitchTo(oldcontext);
+
+	return cstate;
+}
+
+/*
+ * PopulateGlobalsForCopyFrom - Populates the common variables required for copy
+ * from operation. This is a helper function for BeginCopy function.
+ */
+static void
+PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tupDesc,
+							List *attnamelist)
+{
+	int			num_phys_attrs;
+
 	/* Generate or convert list of attributes to process */
 	cstate->attnumlist = CopyGetAttnums(tupDesc, cstate->rel, attnamelist);
 
@@ -1748,12 +1855,6 @@ BeginCopy(ParseState *pstate,
 		 pg_database_encoding_max_length() > 1);
 	/* See Multibyte encoding comment above */
 	cstate->encoding_embeds_ascii = PG_ENCODING_IS_CLIENT_ONLY(cstate->file_encoding);
-
-	cstate->copy_dest = COPY_FILE;	/* default */
-
-	MemoryContextSwitchTo(oldcontext);
-
-	return cstate;
 }
 
 /*
@@ -2646,32 +2747,11 @@ CopyMultiInsertInfoStore(CopyMultiInsertInfo *miinfo, ResultRelInfo *rri,
 }
 
 /*
- * Copy FROM file to relation.
+ * Check if the relation specified in copy from is valid.
  */
-uint64
-CopyFrom(CopyState cstate)
+static void
+CheckTargetRelValidity(CopyState cstate)
 {
-	ResultRelInfo *resultRelInfo;
-	ResultRelInfo *target_resultRelInfo;
-	ResultRelInfo *prevResultRelInfo = NULL;
-	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
-	ModifyTableState *mtstate;
-	ExprContext *econtext;
-	TupleTableSlot *singleslot = NULL;
-	MemoryContext oldcontext = CurrentMemoryContext;
-
-	PartitionTupleRouting *proute = NULL;
-	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
-	int			ti_options = 0; /* start with default options for insert */
-	BulkInsertState bistate = NULL;
-	CopyInsertMethod insertMethod;
-	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
-	uint64		processed = 0;
-	bool		has_before_insert_row_trig;
-	bool		has_instead_insert_row_trig;
-	bool		leafpart_use_multi_insert = false;
-
 	Assert(cstate->rel);
 
 	/*
@@ -2708,27 +2788,6 @@ CopyFrom(CopyState cstate)
 							RelationGetRelationName(cstate->rel))));
 	}
 
-	/*
-	 * If the target file is new-in-transaction, we assume that checking FSM
-	 * for free space is a waste of time.  This could possibly be wrong, but
-	 * it's unlikely.
-	 */
-	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
-		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
-		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
-		ti_options |= TABLE_INSERT_SKIP_FSM;
-
-	/*
-	 * Optimize if new relfilenode was created in this subxact or one of its
-	 * committed children and we won't see those rows later as part of an
-	 * earlier scan or command. The subxact test ensures that if this subxact
-	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
-	 * that the stronger test of exactly which subtransaction created it is
-	 * crucial for correctness of this optimization. The test for an earlier
-	 * scan or command tolerates false negatives. FREEZE causes other sessions
-	 * to see rows they would not see under MVCC, and a false negative merely
-	 * spreads that anomaly to the current session.
-	 */
 	if (cstate->freeze)
 	{
 		/*
@@ -2766,9 +2825,61 @@ CopyFrom(CopyState cstate)
 			ereport(ERROR,
 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 					 errmsg("cannot perform COPY FREEZE because the table was not created or truncated in the current subtransaction")));
+	}
+}
+
+/*
+ * Copy FROM file to relation.
+ */
+uint64
+CopyFrom(CopyState cstate)
+{
+	ResultRelInfo *resultRelInfo;
+	ResultRelInfo *target_resultRelInfo;
+	ResultRelInfo *prevResultRelInfo = NULL;
+	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
+	ModifyTableState *mtstate;
+	ExprContext *econtext;
+	TupleTableSlot *singleslot = NULL;
+	MemoryContext oldcontext = CurrentMemoryContext;
+
+	PartitionTupleRouting *proute = NULL;
+	ErrorContextCallback errcallback;
+	CommandId	mycid = GetCurrentCommandId(true);
+	int			ti_options = 0; /* start with default options for insert */
+	BulkInsertState bistate = NULL;
+	CopyInsertMethod insertMethod;
+	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
+	uint64		processed = 0;
+	bool		has_before_insert_row_trig;
+	bool		has_instead_insert_row_trig;
+	bool		leafpart_use_multi_insert = false;
+
+	CheckTargetRelValidity(cstate);
 
+	/*
+	 * If the target file is new-in-transaction, we assume that checking FSM
+	 * for free space is a waste of time.  This could possibly be wrong, but
+	 * it's unlikely.
+	 */
+	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
+		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
+		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
+		ti_options |= TABLE_INSERT_SKIP_FSM;
+
+	/*
+	 * Optimize if new relfilenode was created in this subxact or one of its
+	 * committed children and we won't see those rows later as part of an
+	 * earlier scan or command. The subxact test ensures that if this subxact
+	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
+	 * that the stronger test of exactly which subtransaction created it is
+	 * crucial for correctness of this optimization. The test for an earlier
+	 * scan or command tolerates false negatives. FREEZE causes other sessions
+	 * to see rows they would not see under MVCC, and a false negative merely
+	 * spreads that anomaly to the current session.
+	 */
+	if (cstate->freeze)
 		ti_options |= TABLE_INSERT_FROZEN;
-	}
 
 	/*
 	 * We need a ResultRelInfo so we can use the regular executor's
@@ -3261,7 +3372,7 @@ CopyFrom(CopyState cstate)
 			 * or FDW; this is the same definition used by nodeModifyTable.c
 			 * for counting tuples inserted by an INSERT command.
 			 */
-			processed++;
+			INCREMENTPROCESSED(processed)
 		}
 	}
 
@@ -3316,30 +3427,15 @@ CopyFrom(CopyState cstate)
 
 	FreeExecutorState(estate);
 
-	return processed;
+	GETPROCESSED(processed)
 }
 
 /*
- * Setup to read tuples from a file for COPY FROM.
- *
- * 'rel': Used as a template for the tuples
- * 'filename': Name of server-local file to read
- * 'attnamelist': List of char *, columns to include. NIL selects all cols.
- * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
- *
- * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ * PopulateCatalogInformation - populate the catalog information.
  */
-CopyState
-BeginCopyFrom(ParseState *pstate,
-			  Relation rel,
-			  const char *filename,
-			  bool is_program,
-			  copy_data_source_cb data_source_cb,
-			  List *attnamelist,
-			  List *options)
+static void
+PopulateCatalogInformation(CopyState cstate)
 {
-	CopyState	cstate;
-	bool		pipe = (filename == NULL);
 	TupleDesc	tupDesc;
 	AttrNumber	num_phys_attrs,
 				num_defaults;
@@ -3349,31 +3445,8 @@ BeginCopyFrom(ParseState *pstate,
 	Oid			in_func_oid;
 	int		   *defmap;
 	ExprState **defexprs;
-	MemoryContext oldcontext;
 	bool		volatile_defexprs;
 
-	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
-	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
-
-	/* Initialize state variables */
-	cstate->reached_eof = false;
-	cstate->eol_type = EOL_UNKNOWN;
-	cstate->cur_relname = RelationGetRelationName(cstate->rel);
-	cstate->cur_lineno = 0;
-	cstate->cur_attname = NULL;
-	cstate->cur_attval = NULL;
-
-	/* Set up variables to avoid per-attribute overhead. */
-	initStringInfo(&cstate->attribute_buf);
-	initStringInfo(&cstate->line_buf);
-	cstate->line_buf_converted = false;
-	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
-	cstate->raw_buf_index = cstate->raw_buf_len = 0;
-
-	/* Assign range table, we'll need it in CopyFrom. */
-	if (pstate)
-		cstate->range_table = pstate->p_rtable;
-
 	tupDesc = RelationGetDescr(cstate->rel);
 	num_phys_attrs = tupDesc->natts;
 	num_defaults = 0;
@@ -3451,6 +3524,54 @@ BeginCopyFrom(ParseState *pstate,
 	cstate->defexprs = defexprs;
 	cstate->volatile_defexprs = volatile_defexprs;
 	cstate->num_defaults = num_defaults;
+}
+
+/*
+ * Setup to read tuples from a file for COPY FROM.
+ *
+ * 'rel': Used as a template for the tuples
+ * 'filename': Name of server-local file to read
+ * 'attnamelist': List of char *, columns to include. NIL selects all cols.
+ * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
+ *
+ * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ */
+CopyState
+BeginCopyFrom(ParseState *pstate,
+			  Relation rel,
+			  const char *filename,
+			  bool is_program,
+			  copy_data_source_cb data_source_cb,
+			  List *attnamelist,
+			  List *options)
+{
+	CopyState	cstate;
+	bool		pipe = (filename == NULL);
+	MemoryContext oldcontext;
+
+	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	/* Initialize state variables */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/* Set up variables to avoid per-attribute overhead. */
+	initStringInfo(&cstate->attribute_buf);
+	initStringInfo(&cstate->line_buf);
+	cstate->line_buf_converted = false;
+	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+
+	/* Assign range table, we'll need it in CopyFrom. */
+	if (pstate)
+		cstate->range_table = pstate->p_rtable;
+
+	PopulateCatalogInformation(cstate);
 	cstate->is_program = is_program;
 
 	if (data_source_cb)
@@ -3860,60 +3981,8 @@ CopyReadLine(CopyState cstate)
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
-	else
-	{
-		/*
-		 * If we didn't hit EOF, then we must have transferred the EOL marker
-		 * to line_buf along with the data.  Get rid of it.
-		 */
-		switch (cstate->eol_type)
-		{
-			case EOL_NL:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CR:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\r');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CRNL:
-				Assert(cstate->line_buf.len >= 2);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 2] == '\r');
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len -= 2;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_UNKNOWN:
-				/* shouldn't get here */
-				Assert(false);
-				break;
-		}
-	}
-
-	/* Done reading the line.  Convert it to server encoding. */
-	if (cstate->need_transcoding)
-	{
-		char	   *cvt;
-
-		cvt = pg_any_to_server(cstate->line_buf.data,
-							   cstate->line_buf.len,
-							   cstate->file_encoding);
-		if (cvt != cstate->line_buf.data)
-		{
-			/* transfer converted data back to line_buf */
-			resetStringInfo(&cstate->line_buf);
-			appendBinaryStringInfo(&cstate->line_buf, cvt, strlen(cvt));
-			pfree(cvt);
-		}
-	}
-
-	/* Now it's safe to use the buffer in error messages */
-	cstate->line_buf_converted = true;
 
+	CONVERT_TO_SERVER_ENCODING(cstate)
 	return result;
 }
 
@@ -4277,6 +4346,7 @@ not_end_of_copy:
 	 * Transfer any still-uncopied data to line_buf.
 	 */
 	REFILL_LINEBUF;
+	CLEAR_EOL_LINE()
 
 	return result;
 }
-- 
1.8.3.1

0002-Framework-for-leader-worker-in-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=0002-Framework-for-leader-worker-in-parallel-copy.patchDownload
From 3a2b807acb145ab0dbd12c9c3270da955e82a72c Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>, Bharath <bharath.rupireddyforpostgres@gmail.com>
Date: Wed, 24 Jun 2020 13:51:56 +0530
Subject: [PATCH 2/6] Framework for leader/worker in parallel copy

This patch has the framework for data structures in parallel copy, leader
initialization, worker initialization, shared memory updation, starting workers,
wait for workers and workers exiting.
---
 src/backend/access/transam/parallel.c       |   4 +
 src/backend/commands/copy.c                 | 865 +++++++++++++++++++++++++++-
 src/backend/replication/logical/tablesync.c |   2 +-
 src/include/commands/copy.h                 |   4 +
 src/tools/pgindent/typedefs.list            |   8 +
 5 files changed, 878 insertions(+), 5 deletions(-)

diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index 14a8690..09e7a19 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -25,6 +25,7 @@
 #include "catalog/pg_enum.h"
 #include "catalog/storage.h"
 #include "commands/async.h"
+#include "commands/copy.h"
 #include "executor/execParallel.h"
 #include "libpq/libpq.h"
 #include "libpq/pqformat.h"
@@ -145,6 +146,9 @@ static const struct
 	},
 	{
 		"parallel_vacuum_main", parallel_vacuum_main
+	},
+	{
+		"ParallelCopyMain", ParallelCopyMain
 	}
 };
 
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 65a504f..c906655 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -96,9 +96,138 @@ typedef enum CopyInsertMethod
 } CopyInsertMethod;
 
 #define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+
+#define DATA_BLOCK_SIZE RAW_BUF_SIZE
+#define RINGSIZE (10 * 1000)
+#define MAX_BLOCKS_COUNT 1000
+#define WORKER_CHUNK_COUNT 50	/* should be mod of RINGSIZE */
+
+#define	IsParallelCopy()		(cstate->is_parallel)
+#define IsLeader()				(cstate->pcdata->is_leader)
 #define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
 
 /*
+ * Copy data block information.
+ */
+typedef struct ParallelCopyDataBlock
+{
+	/* The number of unprocessed lines in the current block. */
+	pg_atomic_uint32 unprocessed_line_parts;
+
+	/*
+	 * If the current line data is continued into another block, following_block
+	 * will have the position where the remaining data need to be read.
+	 */
+	uint32	following_block;
+
+	/*
+	 * This flag will be set, when the leader finds out this block can be read
+	 * safely by the worker. This helps the worker to start processing the line
+	 * early where the line will be spread across many blocks and the worker
+	 * need not wait for the complete line to be processed.
+	 */
+	bool   curr_blk_completed;
+	char   data[DATA_BLOCK_SIZE]; /* data read from file */
+	uint8  skip_bytes;
+}ParallelCopyDataBlock;
+
+/*
+ * Individual line information.
+ * ParallelCopyLineBoundary is common data structure between leader & worker,
+ * this is protected by the following sequence in the leader & worker.
+ * Leader should operate in the following order:
+ * 1) update first_block, start_offset & cur_lineno in any order.
+ * 2) update line_size.
+ * 3) update line_state.
+ * Worker should operate in the following order:
+ * 1) read line_size.
+ * 2) only one worker should choose one line for processing, this is handled by
+ *    using pg_atomic_compare_exchange_u32, worker will change the sate to
+ *    LINE_WORKER_PROCESSING only if line_state is LINE_LEADER_POPULATED.
+ * 3) read first_block, start_offset & cur_lineno in any order.
+ */
+typedef struct ParallelCopyLineBoundary
+{
+	/* Position of the first block in data_blocks array. */
+	uint32				first_block;
+	uint32				start_offset;   /* start offset of the line */
+
+	/*
+	 * Size of the current line -1 means line is yet to be filled completely,
+	 * 0 means empty line, >0 means line filled with line size data.
+	 */
+	pg_atomic_uint32	line_size;
+	pg_atomic_uint32	line_state;		/* line state */
+	uint64				cur_lineno;		/* line number for error messages */
+}ParallelCopyLineBoundary;
+
+/*
+ * Circular queue used to store the line information.
+ */
+typedef struct ParallelCopyLineBoundaries
+{
+	/* Position for the leader to populate a line. */
+	uint32			leader_pos;
+
+	/* Data read from the file/stdin by the leader process. */
+	ParallelCopyLineBoundary	ring[RINGSIZE];
+}ParallelCopyLineBoundaries;
+
+/*
+ * Shared information among parallel copy workers. This will be allocated in the
+ * DSM segment.
+ */
+typedef struct ParallelCopyShmInfo
+{
+	bool					is_read_in_progress; /* file read status */
+
+	/*
+	 * Actual lines inserted by worker (some records will be filtered based on
+	 * where condition).
+	 */
+	pg_atomic_uint64			processed;
+	pg_atomic_uint64			total_worker_processed; /* total processed records by the workers */
+	uint64						populated; /* lines populated by leader */
+	uint32						cur_block_pos; /* current data block */
+	ParallelCopyDataBlock		data_blocks[MAX_BLOCKS_COUNT]; /* data block array */
+	FullTransactionId			full_transaction_id; /* xid for copy from statement */
+	CommandId					mycid;	/* command id */
+	ParallelCopyLineBoundaries	line_boundaries; /* line array */
+} ParallelCopyShmInfo;
+
+/*
+ * Parallel copy line buffer information.
+ */
+typedef struct ParallelCopyLineBuf
+{
+	StringInfoData		line_buf;
+	uint64				cur_lineno;	/* line number for error messages */
+}ParallelCopyLineBuf;
+
+/*
+ * Parallel copy data information.
+ */
+typedef struct ParallelCopyData
+{
+	Oid					relid;				/* relation id of the table */
+	ParallelCopyShmInfo	*pcshared_info;		/* common info in shared memory */
+	bool				is_leader;
+
+	/* line position which worker is processing */
+	uint32				worker_processed_pos;
+
+	/*
+	 * Local line_buf array, workers will copy it here and release the lines
+	 * for the leader to continue.
+	 */
+	ParallelCopyLineBuf	worker_line_buf[WORKER_CHUNK_COUNT];
+	uint32				worker_line_buf_count; /* Number of lines */
+
+	/* Current position in worker_line_buf */
+	uint32				worker_line_buf_pos;
+}ParallelCopyData;
+
+/*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
  * even though some fields are used in only some cases.
@@ -225,8 +354,66 @@ typedef struct CopyStateData
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
+	int			nworkers;
+	bool		is_parallel;
+	ParallelCopyData *pcdata;
 } CopyStateData;
 
+/*
+ * This structure helps in storing the common data from CopyStateData that are
+ * required by the workers. This information will then be allocated and stored
+ * into the DSM for the worker to retrieve and copy it to CopyStateData.
+ */
+typedef struct ParallelCopyCommonKeyData
+{
+	/* low-level state data */
+	CopyDest            copy_dest;		/* type of copy source/destination */
+	int                 file_encoding;	/* file or remote side's character encoding */
+	bool                need_transcoding;	/* file encoding diff from server? */
+	bool                encoding_embeds_ascii;	/* ASCII can be non-first byte? */
+
+	/* parameters from the COPY command */
+	bool                csv_mode;		/* Comma Separated Value format? */
+	bool                header_line;	/* CSV header line? */
+	int                 null_print_len; /* length of same */
+	bool                force_quote_all;	/* FORCE_QUOTE *? */
+	bool                convert_selectively;	/* do selective binary conversion? */
+
+	/* Working state for COPY FROM */
+	AttrNumber          num_defaults;
+	Oid                 relid;
+}ParallelCopyCommonKeyData;
+
+/*
+ * This structure will help in converting a List data type into the below
+ * structure format with the count having the number of elements in the list and
+ * the info having the List elements appended contigously. This converted
+ * structure will be allocated in shared memory and stored in DSM for the worker
+ * to retrieve and later convert it back to List data type.
+ */
+typedef struct ParallelCopyKeyListInfo
+{
+	int	count;		/* count of attributes */
+
+	/* string info in the form info followed by info1, info2... infon  */
+	char    info[1];
+} ParallelCopyKeyListInfo;
+
+/*
+ * List of internal parallel copy function pointers.
+ */
+static const struct
+{
+	char *fn_name;
+	copy_data_source_cb fn_addr;
+}			InternalParallelCopyFuncPtrs[] =
+
+{
+	{
+		"copy_read_data", copy_read_data
+	},
+};
+
 /* DestReceiver for COPY (query) TO */
 typedef struct
 {
@@ -256,6 +443,23 @@ typedef struct
 /* Trim the list of buffers back down to this number after flushing */
 #define MAX_PARTITION_BUFFERS	32
 
+/* DSM keys for parallel copy.  */
+#define PARALLEL_COPY_KEY_SHARED_INFO		    1
+#define PARALLEL_COPY_KEY_CSTATE				2
+#define PARALLEL_COPY_KEY_NULL_PRINT			3
+#define PARALLEL_COPY_KEY_NULL_PRINT_CLIENT		4
+#define PARALLEL_COPY_KEY_DELIM					5
+#define PARALLEL_COPY_KEY_QUOTE					6
+#define PARALLEL_COPY_KEY_ESCAPE				7
+#define PARALLEL_COPY_KEY_ATTNAME_LIST			8
+#define PARALLEL_COPY_KEY_FORCE_QUOTE_LIST  	9
+#define PARALLEL_COPY_KEY_NOT_NULL_LIST		   10
+#define PARALLEL_COPY_KEY_NULL_LIST			   11
+#define PARALLEL_COPY_KEY_CONVERT_LIST		   12
+#define PARALLEL_COPY_KEY_DATASOURCE_CB		   13
+#define PARALLEL_COPY_KEY_WHERE_CLAUSE_STR     14
+#define PARALLEL_COPY_KEY_RANGE_TABLE		   15
+
 /* Stores multi-insert data related to a single relation in CopyFrom. */
 typedef struct CopyMultiInsertBuffer
 {
@@ -476,10 +680,596 @@ static bool CopyGetInt32(CopyState cstate, int32 *val);
 static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 
+static pg_attribute_always_inline void EndParallelCopy(ParallelContext *pcxt);
 static void PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tup_desc,
 							   List *attnamelist);
+static pg_attribute_always_inline copy_data_source_cb LookupParallelCopyFnPtr(const char *funcname);
+static pg_attribute_always_inline char* LookupParallelCopyFnStr(copy_data_source_cb fn_addr);
+
+/*
+ * CopyCommonInfoForWorker - Copy shared_cstate using cstate information.
+ */
+static pg_attribute_always_inline void
+CopyCommonInfoForWorker(CopyState cstate, ParallelCopyCommonKeyData *shared_cstate)
+{
+	shared_cstate->copy_dest = cstate->copy_dest;
+	shared_cstate->file_encoding = cstate->file_encoding;
+	shared_cstate->need_transcoding = cstate->need_transcoding;
+	shared_cstate->encoding_embeds_ascii = cstate->encoding_embeds_ascii;
+	shared_cstate->csv_mode = cstate->csv_mode;
+	shared_cstate->header_line = cstate->header_line;
+	shared_cstate->null_print_len = cstate->null_print_len;
+	shared_cstate->force_quote_all = cstate->force_quote_all;
+	shared_cstate->convert_selectively = cstate->convert_selectively;
+	shared_cstate->num_defaults = cstate->num_defaults;
+	shared_cstate->relid = cstate->pcdata->relid;
+}
+
+/*
+ * RetrieveSharedString - Retrieve the string from shared memory.
+ */
+static void
+RetrieveSharedString(shm_toc *toc, int sharedkey, char **copystr)
+{
+	char *shared_str_val = (char *)shm_toc_lookup(toc, sharedkey, true);
+	if (shared_str_val)
+		*copystr = pstrdup(shared_str_val);
+}
+
+/*
+ * RetrieveSharedList - Retrieve the list from shared memory.
+ */
+static void
+RetrieveSharedList(shm_toc *toc, int sharedkey, List **copylist)
+{
+	ParallelCopyKeyListInfo *listinformation = (ParallelCopyKeyListInfo *)shm_toc_lookup(toc, sharedkey,
+														   true);
+	if (listinformation)
+	{
+		int	length  = 0;
+		int count;
+
+		for (count = 0; count < listinformation->count; count++)
+		{
+			char *attname = (char *)(listinformation->info + length);
+			length += strlen(attname) + 1;
+			*copylist = lappend(*copylist, makeString(attname));
+		}
+	}
+}
+
+/*
+ * CopyListSharedMemory - Copy the list into shared memory.
+ */
+static void
+CopyListSharedMemory(List *inputlist, Size memsize, ParallelCopyKeyListInfo *sharedlistinfo)
+{
+	ListCell   *l;
+	int			length  = 0;
+
+	MemSet(sharedlistinfo, 0, memsize);
+	foreach(l, inputlist)
+	{
+		char	   *name = strVal(lfirst(l));
+		memcpy((char *)(sharedlistinfo->info + length), name, strlen(name));
+		sharedlistinfo->count++;
+		length += strlen(name) + 1;
+	}
+}
+
+/*
+ * ComputeListSize - compute the list size.
+ */
+static int
+ComputeListSize(List *inputlist)
+{
+	int est_size = sizeof(int);
+	if (inputlist != NIL)
+	{
+		ListCell   *l;
+		foreach(l, inputlist)
+			est_size += strlen(strVal(lfirst(l))) + 1;
+	}
+
+	return est_size;
+}
+
+/*
+ * EstimateLineKeysStr - Estimate the size required in shared memory for the
+ * input string.
+ */
+static void
+EstimateLineKeysStr(ParallelContext *pcxt, char *inputstr)
+{
+	if (inputstr)
+	{
+		shm_toc_estimate_chunk(&pcxt->estimator, strlen(inputstr) + 1);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+}
+
+/*
+ * EstimateLineKeysList - Estimate the size required in shared memory for the
+ * input list.
+ */
+static void
+EstimateLineKeysList(ParallelContext *pcxt, List *inputlist,
+		Size *est_list_size)
+{
+	if (inputlist != NIL)
+	{
+		*est_list_size = ComputeListSize(inputlist);
+		shm_toc_estimate_chunk(&pcxt->estimator, *est_list_size);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+}
 
 /*
+ * InsertStringShm - Insert a string into shared memory.
+ */
+static void
+InsertStringShm(ParallelContext *pcxt, int key, char *inputstr)
+{
+	if (inputstr)
+	{
+		char *shmptr = (char *)shm_toc_allocate(pcxt->toc,
+												strlen(inputstr) + 1);
+		strcpy(shmptr, inputstr);
+		shm_toc_insert(pcxt->toc, key, shmptr);
+	}
+}
+
+/*
+ * InsertListShm - Insert a list into shared memory.
+ */
+static void
+InsertListShm(ParallelContext *pcxt, int key, List *inputlist,
+			  Size est_list_size)
+{
+	if (inputlist != NIL)
+	{
+		ParallelCopyKeyListInfo *sharedlistinfo = (ParallelCopyKeyListInfo *)shm_toc_allocate(pcxt->toc,
+																est_list_size);
+		CopyListSharedMemory(inputlist, est_list_size, sharedlistinfo);
+		shm_toc_insert(pcxt->toc, key, sharedlistinfo);
+	}
+}
+
+/*
+ * BeginParallelCopy - start parallel copy tasks.
+ *
+ * Get the number of workers required to perform the parallel copy. The data
+ * structures that are required by the parallel workers will be initialized, the
+ * size required in DSM will be calculated and the necessary keys will be loaded
+ * in the DSM. The specified number of workers will then be launched.
+ *
+ */
+static ParallelContext*
+BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
+{
+	ParallelContext *pcxt;
+	ParallelCopyShmInfo *shared_info_ptr;
+	ParallelCopyCommonKeyData *shared_cstate;
+	FullTransactionId full_transaction_id;
+	Size est_shared_info;
+	Size est_cstateshared;
+	Size est_att_list_size;
+	Size est_quote_list_size;
+	Size est_notnull_list_size;
+	Size est_null_list_size;
+	Size est_convert_list_size;
+	Size est_datasource_cb_size;
+	int  count = 0;
+	char *whereClauseStr = NULL;
+	char *rangeTableStr = NULL;
+	int  parallel_workers = 0;
+	ParallelCopyData *pcdata;
+
+	parallel_workers = Min(nworkers, max_worker_processes);
+
+	/* Can't perform copy in parallel */
+	if (parallel_workers <= 0)
+	{
+		elog(WARNING,
+			 "No workers available, copy will be run in non-parallel mode");
+		return NULL;
+	}
+
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	cstate->pcdata = pcdata;
+
+	EnterParallelMode();
+	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
+								 parallel_workers);
+	Assert(pcxt->nworkers > 0);
+
+	/*
+	 * Estimate size for shared information for PARALLEL_COPY_KEY_SHARED_INFO
+	 */
+	est_shared_info = sizeof(ParallelCopyShmInfo);
+	shm_toc_estimate_chunk(&pcxt->estimator, est_shared_info);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_CSTATE */
+	est_cstateshared = 	MAXALIGN(sizeof(ParallelCopyCommonKeyData));
+	shm_toc_estimate_chunk(&pcxt->estimator, est_cstateshared);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	EstimateLineKeysStr(pcxt, cstate->null_print);
+	EstimateLineKeysStr(pcxt, cstate->null_print_client);
+	EstimateLineKeysStr(pcxt, cstate->delim);
+	EstimateLineKeysStr(pcxt, cstate->quote);
+	EstimateLineKeysStr(pcxt, cstate->escape);
+
+	if (cstate->whereClause != NULL)
+	{
+		whereClauseStr = nodeToString(cstate->whereClause);
+		EstimateLineKeysStr(pcxt, whereClauseStr);
+	}
+
+	if (cstate->range_table != NULL)
+	{
+		rangeTableStr = nodeToString(cstate->range_table);
+		EstimateLineKeysStr(pcxt, rangeTableStr);
+	}
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_XID. */
+	shm_toc_estimate_chunk(&pcxt->estimator, sizeof(FullTransactionId));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_ATTNAME_LIST.
+	 */
+	EstimateLineKeysList(pcxt, attnamelist, &est_att_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_FORCE_QUOTE_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->force_quote, &est_quote_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_NOT_NULL_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->force_notnull,
+							 &est_notnull_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_NULL_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->force_null, &est_null_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_CONVERT_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->convert_select,
+							 &est_convert_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_DATASOURCE_CB.
+	 */
+	if (cstate->data_source_cb)
+	{
+		char *functionname = LookupParallelCopyFnStr(cstate->data_source_cb);
+		est_datasource_cb_size = strlen(functionname) + 1;
+		shm_toc_estimate_chunk(&pcxt->estimator, est_datasource_cb_size);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+
+	InitializeParallelDSM(pcxt);
+
+	/* If no DSM segment was available, back out (do serial copy) */
+	if (pcxt->seg == NULL)
+	{
+		EndParallelCopy(pcxt);
+		elog(WARNING,
+			 "DSM segments not available, copy will be run in non-parallel mode");
+		return NULL;
+	}
+
+	/* Allocate shared memory for PARALLEL_COPY_KEY_SHARED_INFO */
+	shared_info_ptr = (ParallelCopyShmInfo *) shm_toc_allocate(pcxt->toc,
+													   est_shared_info);
+	MemSet(shared_info_ptr, 0, est_shared_info);
+	shared_info_ptr->is_read_in_progress = true;
+	shared_info_ptr->cur_block_pos = -1;
+	shared_info_ptr->full_transaction_id = full_transaction_id;
+	shared_info_ptr->mycid = GetCurrentCommandId(true);
+	for (count = 0; count < RINGSIZE; count++)
+	{
+		ParallelCopyLineBoundary *lineInfo = &shared_info_ptr->line_boundaries.ring[count];
+		pg_atomic_init_u32(&(lineInfo->line_size), -1);
+	}
+
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_SHARED_INFO, shared_info_ptr);
+	pcdata->pcshared_info = shared_info_ptr;
+	pcdata->relid = relid;
+
+	/* Store shared build state, for which we reserved space. */
+	shared_cstate = (ParallelCopyCommonKeyData *)shm_toc_allocate(pcxt->toc,
+															est_cstateshared);
+
+	/* copy cstate variables. */
+	CopyCommonInfoForWorker(cstate, shared_cstate);
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_CSTATE, shared_cstate);
+
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_NULL_PRINT, cstate->null_print);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_NULL_PRINT_CLIENT,
+					  cstate->null_print_client);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_DELIM, cstate->delim);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_QUOTE, cstate->quote);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_ESCAPE, cstate->escape);
+
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_ATTNAME_LIST,
+					attnamelist, est_att_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_FORCE_QUOTE_LIST,
+					cstate->force_quote, est_quote_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_NOT_NULL_LIST,
+					cstate->force_notnull, est_notnull_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_NULL_LIST, cstate->force_null,
+					est_null_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_CONVERT_LIST,
+					cstate->convert_select, est_convert_list_size);
+
+	if (cstate->data_source_cb)
+	{
+		char *functionname = LookupParallelCopyFnStr(cstate->data_source_cb);
+		char *data_source_cb = (char *) shm_toc_allocate(pcxt->toc,
+														 est_datasource_cb_size);
+		strcpy(data_source_cb, functionname);
+		shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_DATASOURCE_CB,
+					   data_source_cb);
+	}
+
+	if (cstate->whereClause)
+		InsertStringShm(pcxt, PARALLEL_COPY_KEY_WHERE_CLAUSE_STR,
+						whereClauseStr);
+
+	if(cstate->range_table)
+		InsertStringShm(pcxt, PARALLEL_COPY_KEY_RANGE_TABLE, rangeTableStr);
+
+	LaunchParallelWorkers(pcxt);
+	if (pcxt->nworkers_launched == 0)
+	{
+		EndParallelCopy(pcxt);
+		elog(WARNING,
+			 "No workers available, copy will be run in non-parallel mode");
+		return NULL;
+	}
+
+	/*
+	 * Caller needs to wait for all launched workers when we return.  Make sure
+	 * that the failure-to-start case will not hang forever.
+	 */
+	WaitForParallelWorkersToAttach(pcxt);
+
+	pcdata->is_leader = true;
+	cstate->is_parallel = true;
+	return pcxt;
+}
+
+/*
+ * EndParallelCopy - end the parallel copy tasks.
+ */
+static pg_attribute_always_inline void
+EndParallelCopy(ParallelContext *pcxt)
+{
+	Assert(!IsParallelWorker());
+
+	DestroyParallelContext(pcxt);
+	ExitParallelMode();
+}
+
+/*
+ * ParallelWorkerInitialization - Initialize parallel worker.
+ */
+static void
+ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
+		CopyState cstate, List *attnamelist)
+{
+	uint32		count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	cstate->copy_dest = shared_cstate->copy_dest;
+	cstate->file_encoding = shared_cstate->file_encoding;
+	cstate->need_transcoding = shared_cstate->need_transcoding;
+	cstate->encoding_embeds_ascii = shared_cstate->encoding_embeds_ascii;
+	cstate->csv_mode = shared_cstate->csv_mode;
+	cstate->header_line = shared_cstate->header_line;
+	cstate->null_print_len = shared_cstate->null_print_len;
+	cstate->force_quote_all = shared_cstate->force_quote_all;
+	cstate->convert_selectively = shared_cstate->convert_selectively;
+	cstate->num_defaults = shared_cstate->num_defaults;
+	pcdata->relid = shared_cstate->relid;
+
+	PopulateGlobalsForCopyFrom(cstate, tup_desc, attnamelist);
+
+	/* Initialize state variables. */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/* Set up variables to avoid per-attribute overhead. */
+	initStringInfo(&cstate->attribute_buf);
+
+	initStringInfo(&cstate->line_buf);
+	for (count = 0; count < WORKER_CHUNK_COUNT;count++)
+		initStringInfo(&pcdata->worker_line_buf[count].line_buf);
+
+	cstate->line_buf_converted = false;
+	cstate->raw_buf = NULL;
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+}
+/*
+ * ParallelCopyMain - parallel copy worker's code.
+ *
+ * Where clause handling, convert tuple to columns, add default null values for
+ * the missing columns that are not present in that record. Find the partition
+ * if it is partitioned table, invoke before row insert Triggers, handle
+ * constraints and insert the tuples.
+ */
+void
+ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
+{
+	CopyState cstate;
+	ParallelCopyData *pcdata;
+	ParallelCopyShmInfo *pcshared_info;
+	ParallelCopyCommonKeyData *shared_cstate;
+	Relation	rel = NULL;
+	MemoryContext oldcontext;
+	List *attlist = NIL;
+	char *data_source_cb;
+	char *whereClauseStr = NULL;
+	char *rangeTableStr = NULL;
+
+	/* Allocate workspace and zero all fields. */
+	cstate = (CopyStateData *) palloc0(sizeof(CopyStateData));
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	cstate->pcdata = pcdata;
+	pcdata->is_leader = false;
+	pcdata->worker_processed_pos = -1;
+	cstate->is_parallel = true;
+
+	/*
+	 * We allocate everything used by a cstate in a new memory context. This
+	 * avoids memory leaks during repeated use of COPY in a query.
+	 */
+	cstate->copycontext = AllocSetContextCreate(CurrentMemoryContext,
+												"COPY",
+												ALLOCSET_DEFAULT_SIZES);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	pcshared_info = (ParallelCopyShmInfo *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_SHARED_INFO,
+														false);
+
+	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
+
+	pcdata->pcshared_info = pcshared_info;
+
+	shared_cstate = (ParallelCopyCommonKeyData *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE,
+														   false);
+
+	cstate->null_print = (char *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_NULL_PRINT,
+												true);
+	cstate->null_print_client = (char *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_NULL_PRINT_CLIENT,
+													   true);
+
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_DELIM, &cstate->delim);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_QUOTE, &cstate->quote);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_ESCAPE, &cstate->escape);
+
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_ATTNAME_LIST, &attlist);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_FORCE_QUOTE_LIST, &cstate->force_quote);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_NOT_NULL_LIST, &cstate->force_notnull);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_NULL_LIST, &cstate->force_null);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_CONVERT_LIST, &cstate->convert_select);
+	data_source_cb = (char *)shm_toc_lookup(toc,
+											PARALLEL_COPY_KEY_DATASOURCE_CB,
+											true);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_WHERE_CLAUSE_STR, &whereClauseStr);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_RANGE_TABLE, &rangeTableStr);
+
+	if (data_source_cb)
+		cstate->data_source_cb = LookupParallelCopyFnPtr(data_source_cb);
+
+	if (whereClauseStr)
+	{
+		Node *whereClauseCnvrtdFrmStr = (Node *) stringToNode(whereClauseStr);
+		cstate->whereClause = whereClauseCnvrtdFrmStr;
+	}
+
+	if (rangeTableStr)
+	{
+		List *rangeTableCnvrtdFrmStr = (List *) stringToNode(rangeTableStr);
+		cstate->range_table = rangeTableCnvrtdFrmStr;
+	}
+
+	/* Open and lock the relation, using the appropriate lock type. */
+	rel = table_open(shared_cstate->relid, RowExclusiveLock);
+	cstate->rel = rel;
+	ParallelWorkerInitialization(shared_cstate, cstate, attlist);
+
+	CopyFrom(cstate);
+
+	if (rel != NULL)
+		table_close(rel, RowExclusiveLock);
+
+	MemoryContextSwitchTo(oldcontext);
+	return;
+}
+/*
+ * ParallelCopyLeader - parallel copy leader's functionality.
+ *
+ * Leader will populate the shared memory and share it across the workers.
+ * Leader will read the table data from the file and copy the contents to block.
+ * Leader will then read the input contents and identify the data based on line
+ * beaks. This information is called line. The line will be populate in
+ * ParallelCopyLineBoundary. Workers will then pick up this information and
+ * insert in to table. Leader will do this till it completes processing the
+ * file. Leader executes the before statement if before statement trigger is
+ * present. Leader read the data from input file. Leader then loads data to data
+ * blocks as and when required block by block. Leader traverses through the data
+ * block to identify one line. It gets a free line to copy the information, if
+ * there is no free line it will wait till there is one free line.
+ * Server copies  the identified lines information into lines. This process is
+ * repeated till the complete file is processed.
+ * Leader will wait till all the lines populated are processed by the workers
+ * and exits.
+ */
+static void
+ParallelCopyLeader(CopyState cstate)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
+
+	pcshared_info->is_read_in_progress = false;
+	cstate->cur_lineno = 0;
+}
+/*
+ * LookupParallelCopyFnPtr - Look up parallel copy function pointer.
+ */
+static pg_attribute_always_inline copy_data_source_cb
+LookupParallelCopyFnPtr(const char *funcname)
+{
+	int			i;
+
+	for (i = 0; i < lengthof(InternalParallelCopyFuncPtrs); i++)
+	{
+		if (strcmp(InternalParallelCopyFuncPtrs[i].fn_name, funcname) == 0)
+			return InternalParallelCopyFuncPtrs[i].fn_addr;
+	}
+
+	/* We can only reach this by programming error. */
+	elog(ERROR, "internal function \"%s\" not found", funcname);
+}
+
+/*
+ * LookupParallelCopyFnStr - Lookup function string from a function pointer.
+ */
+static pg_attribute_always_inline char*
+LookupParallelCopyFnStr(copy_data_source_cb fn_addr)
+{
+	int			i;
+
+	for (i = 0; i < lengthof(InternalParallelCopyFuncPtrs); i++)
+	{
+		if (InternalParallelCopyFuncPtrs[i].fn_addr == fn_addr)
+			return InternalParallelCopyFuncPtrs[i].fn_name;
+	}
+
+	/* We can only reach this by programming error. */
+	elog(ERROR, "internal function pointer not found");
+}
+/*
  * Send copy start/stop messages for frontend copies.  These have changed
  * in past protocol redesigns.
  */
@@ -1149,6 +1939,7 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 
 	if (is_from)
 	{
+		ParallelContext *pcxt = NULL;
 		Assert(rel);
 
 		/* check read-only transaction and parallel mode */
@@ -1158,7 +1949,24 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 		cstate = BeginCopyFrom(pstate, rel, stmt->filename, stmt->is_program,
 							   NULL, stmt->attlist, stmt->options);
 		cstate->whereClause = whereClause;
-		*processed = CopyFrom(cstate);	/* copy from file to database */
+		cstate->is_parallel = false;
+
+		if (cstate->nworkers > 0)
+			pcxt = BeginParallelCopy(cstate->nworkers, cstate, stmt->attlist,
+									 relid);
+
+		if (pcxt)
+		{
+			ParallelCopyLeader(cstate);
+
+			/* Wait for all copy workers to finish */
+			WaitForParallelWorkersToFinish(pcxt);
+			*processed = pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
+			EndParallelCopy(pcxt);
+		}
+		else
+			*processed = CopyFrom(cstate); /* copy from file to database */
+
 		EndCopyFrom(cstate);
 	}
 	else
@@ -1207,6 +2015,7 @@ ProcessCopyOptions(ParseState *pstate,
 	cstate->is_copy_from = is_from;
 
 	cstate->file_encoding = -1;
+	cstate->nworkers = -1;
 
 	/* Extract options from the statement node tree */
 	foreach(option, options)
@@ -1375,6 +2184,53 @@ ProcessCopyOptions(ParseState *pstate,
 								defel->defname),
 						 parser_errposition(pstate, defel->location)));
 		}
+		else if (strcmp(defel->defname, "parallel") == 0)
+		{
+			char *endptr, *str;
+			long val;
+
+			if (!cstate->is_copy_from)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("parallel option supported only for copy from"),
+						 parser_errposition(pstate, defel->location)));
+			if (cstate->nworkers >= 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options"),
+						 parser_errposition(pstate, defel->location)));
+
+			str = defGetString(defel);
+
+			errno = 0; /* To distinguish success/failure after call */
+			val = strtol(str, &endptr, 10);
+
+			/* Check for various possible errors */
+			if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
+				|| (errno != 0 && val == 0) ||
+				*endptr)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("improper use of argument to option \"%s\"",
+								defel->defname),
+						 parser_errposition(pstate, defel->location)));
+
+			if (endptr == str)
+			   ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("no digits were found in argument to option \"%s\"",
+								defel->defname),
+						 parser_errposition(pstate, defel->location)));
+
+			cstate->nworkers = (int) val;
+
+			if (cstate->nworkers <= 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("argument to option \"%s\" must be a positive integer greater than zero",
+								defel->defname),
+						 parser_errposition(pstate, defel->location)));
+		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_SYNTAX_ERROR),
@@ -1727,12 +2583,13 @@ BeginCopy(ParseState *pstate,
 }
 
 /*
- * PopulateGlobalsForCopyFrom - Populates the common variables required for copy
- * from operation. This is a helper function for BeginCopy function.
+ * PopulateCatalogInformation - Populates the common variables required for copy
+ * from operation. This is a helper function for BeginCopy &
+ * ParallelWorkerInitialization function.
  */
 static void
 PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tupDesc,
-							List *attnamelist)
+						   List *attnamelist)
 {
 	int			num_phys_attrs;
 
diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c
index c27d970..b3787c1 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -557,7 +557,7 @@ make_copy_attnamelist(LogicalRepRelMapEntry *rel)
  * Data source callback for the COPY FROM, which reads from the remote
  * connection and passes the data back to our local COPY.
  */
-static int
+int
 copy_read_data(void *outbuf, int minread, int maxread)
 {
 	int			bytesread = 0;
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index c639833..5dc95ac 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -14,6 +14,7 @@
 #ifndef COPY_H
 #define COPY_H
 
+#include "access/parallel.h"
 #include "nodes/execnodes.h"
 #include "nodes/parsenodes.h"
 #include "parser/parse_node.h"
@@ -41,4 +42,7 @@ extern uint64 CopyFrom(CopyState cstate);
 
 extern DestReceiver *CreateCopyDestReceiver(void);
 
+extern void ParallelCopyMain(dsm_segment *seg, shm_toc *toc);
+
+extern int copy_read_data(void *outbuf, int minread, int maxread);
 #endif							/* COPY_H */
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index c65a552..8a79794 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1698,6 +1698,14 @@ ParallelBitmapHeapState
 ParallelBlockTableScanDesc
 ParallelCompletionPtr
 ParallelContext
+ParallelCopyLineBoundaries
+ParallelCopyLineBoundary
+ParallelCopyCommonKeyData
+ParallelCopyData
+ParallelCopyDataBlock
+ParallelCopyKeyListInfo
+ParallelCopyLineBuf
+ParallelCopyShmInfo
 ParallelExecutorInfo
 ParallelHashGrowth
 ParallelHashJoinBatch
-- 
1.8.3.1

0003-Allow-copy-from-command-to-process-data-from-file-ST.patchtext/x-patch; charset=US-ASCII; name=0003-Allow-copy-from-command-to-process-data-from-file-ST.patchDownload
From 0286eb202922101b488e5b7414fb2fe2ac302cc8 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>, Bharath <bharath.rupireddyforpostgres@gmail.com>
Date: Tue, 23 Jun 2020 07:15:43 +0530
Subject: [PATCH 3/6] Allow copy from command to process data from file/STDIN
 contents to a table in parallel.

This feature allows the copy from to leverage multiple CPUs in order to copy
data from file/STDIN to a table. This adds a PARALLEL option to COPY FROM
command where the user can specify the number of workers that can be used
to perform the COPY FROM command. Specifying zero as number of workers will
disable parallelism.
The backend, to which the "COPY FROM" query is submitted acts as leader with
the responsibility of reading data from the file/stdin, launching at most n
number of workers as specified with PARALLEL 'n' option in the "COPY FROM"
query. The leader populates the common data required for the workers execution
in the DSM and shares it with the workers. The leader then executes before
statement triggers if there exists any. Leader populates DSM lines which
includes the start offset and line size, while populating the lines it reads
as many blocks as required into the DSM data blocks from the file. Each block
is of 64K size. The leader parses the data to identify a line, the existing
logic from CopyReadLineText which identifies the lines with some changes was
used for this. Leader checks if a free line is available to copy the
information, if there is no free line it waits till the required line is
freed up by the worker and then copies the identified lines information
(offset & line size) into the DSM lines. This process is repeated till the
complete file is processed. Simultaneously, the workers cache the lines(50)
locally into the local memory and release the lines to the leader for further
populating. Each worker processes the lines that it cached and inserts it into
the table. The leader does not participate in the insertion of data, leaders
only responsibility will be to identify the lines as fast as possible for the
workers to do the actual copy operation. The leader waits till all the lines
populated are processed by the workers and exits.
---
 src/backend/access/common/toast_internals.c |  11 +-
 src/backend/access/heap/heapam.c            |  13 -
 src/backend/access/transam/xact.c           |  31 +
 src/backend/commands/copy.c                 | 900 ++++++++++++++++++++++++++--
 src/backend/libpq/pqmq.c                    |   3 +-
 src/include/access/xact.h                   |   2 +
 src/tools/pgindent/typedefs.list            |   1 +
 7 files changed, 908 insertions(+), 53 deletions(-)

diff --git a/src/backend/access/common/toast_internals.c b/src/backend/access/common/toast_internals.c
index 25a81e5..586d53d 100644
--- a/src/backend/access/common/toast_internals.c
+++ b/src/backend/access/common/toast_internals.c
@@ -17,6 +17,7 @@
 #include "access/genam.h"
 #include "access/heapam.h"
 #include "access/heaptoast.h"
+#include "access/parallel.h"
 #include "access/table.h"
 #include "access/toast_internals.h"
 #include "access/xact.h"
@@ -116,7 +117,15 @@ toast_save_datum(Relation rel, Datum value,
 	TupleDesc	toasttupDesc;
 	Datum		t_values[3];
 	bool		t_isnull[3];
-	CommandId	mycid = GetCurrentCommandId(true);
+
+	/*
+	 * Parallel copy can insert toast tuples, in case of parallel copy the
+	 * command would have been set already by calling AssignCommandIdForWorker.
+	 * For parallel copy call GetCurrentCommandId to get currentCommandId by
+	 * passing used as false, as this is taken care earlier.
+	 */
+	CommandId	mycid = IsParallelWorker() ? GetCurrentCommandId(false) :
+											 GetCurrentCommandId(true);
 	struct varlena *result;
 	struct varatt_external toast_pointer;
 	union
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 537913d..28f3a98 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2012,19 +2012,6 @@ static HeapTuple
 heap_prepare_insert(Relation relation, HeapTuple tup, TransactionId xid,
 					CommandId cid, int options)
 {
-	/*
-	 * Parallel operations are required to be strictly read-only in a parallel
-	 * worker.  Parallel inserts are not safe even in the leader in the
-	 * general case, because group locking means that heavyweight locks for
-	 * relation extension or GIN page locks will not conflict between members
-	 * of a lock group, but we don't prohibit that case here because there are
-	 * useful special cases that we can safely allow, such as CREATE TABLE AS.
-	 */
-	if (IsParallelWorker())
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_TRANSACTION_STATE),
-				 errmsg("cannot insert tuples in a parallel worker")));
-
 	tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
 	tup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK);
 	tup->t_data->t_infomask |= HEAP_XMAX_INVALID;
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 905dc7d..ed4009e 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -502,6 +502,37 @@ GetCurrentFullTransactionIdIfAny(void)
 }
 
 /*
+ *	AssignFullTransactionIdForWorker
+ *
+ * For parallel copy, transaction id of leader will be used by the workers.
+ */
+void
+AssignFullTransactionIdForWorker(FullTransactionId fullTransactionId)
+{
+	TransactionState s = CurrentTransactionState;
+
+	Assert((IsInParallelMode() || IsParallelWorker()));
+	s->fullTransactionId = fullTransactionId;
+}
+
+/*
+ *	AssignCommandIdForWorker
+ *
+ * For parallel copy, command id of leader will be used by the workers.
+ */
+void
+AssignCommandIdForWorker(CommandId commandId, bool used)
+{
+	Assert((IsInParallelMode() || IsParallelWorker()));
+
+	/* this is global to a transaction, not subtransaction-local */
+	if (used)
+		currentCommandIdUsed = true;
+
+	currentCommandId = commandId;
+}
+
+/*
  *	MarkCurrentTransactionIdLoggedIfAny
  *
  * Remember that the current xid - if it is assigned - now has been wal logged.
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index c906655..c7af30b 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -26,6 +26,7 @@
 #include "access/xlog.h"
 #include "catalog/dependency.h"
 #include "catalog/pg_authid.h"
+#include "catalog/pg_proc_d.h"
 #include "catalog/pg_type.h"
 #include "commands/copy.h"
 #include "commands/defrem.h"
@@ -40,11 +41,13 @@
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
+#include "optimizer/clauses.h"
 #include "optimizer/optimizer.h"
 #include "parser/parse_coerce.h"
 #include "parser/parse_collate.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_relation.h"
+#include "pgstat.h"
 #include "port/pg_bswap.h"
 #include "rewrite/rewriteHandler.h"
 #include "storage/fd.h"
@@ -95,6 +98,18 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
+/*
+ * State of the line.
+ */
+typedef enum ParallelCopyLineState
+{
+	LINE_INIT,					/* initial state of line */
+	LINE_LEADER_POPULATING,		/* leader processing line */
+	LINE_LEADER_POPULATED,		/* leader completed populating line */
+	LINE_WORKER_PROCESSING,		/* worker processing line */
+	LINE_WORKER_PROCESSED		/* worker completed processing line */
+}ParallelCopyLineState;
+
 #define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
 
 #define DATA_BLOCK_SIZE RAW_BUF_SIZE
@@ -538,9 +553,13 @@ if (1) \
 { \
 	if (raw_buf_ptr > cstate->raw_buf_index) \
 	{ \
-		appendBinaryStringInfo(&cstate->line_buf, \
-							 cstate->raw_buf + cstate->raw_buf_index, \
-							   raw_buf_ptr - cstate->raw_buf_index); \
+		if (!IsParallelCopy()) \
+			appendBinaryStringInfo(&cstate->line_buf, \
+								   cstate->raw_buf + cstate->raw_buf_index, \
+								   raw_buf_ptr - cstate->raw_buf_index); \
+		else \
+			line_size +=  raw_buf_ptr - cstate->raw_buf_index; \
+		\
 		cstate->raw_buf_index = raw_buf_ptr; \
 	} \
 } else ((void) 0)
@@ -553,13 +572,40 @@ if (1) \
 	goto not_end_of_copy; \
 } else ((void) 0)
 
+/* Begin parallel copy Macros */
+#define SET_NEWLINE_SIZE() \
+{ \
+	if (cstate->eol_type == EOL_NL || cstate->eol_type == EOL_CR) \
+		new_line_size = 1; \
+	else if (cstate->eol_type == EOL_CRNL) \
+		new_line_size = 2; \
+	else \
+		new_line_size = 0; \
+}
+
+/*
+ * COPY_WAIT_TO_PROCESS - Wait before continuing to process.
+ */
+#define COPY_WAIT_TO_PROCESS() \
+{ \
+	CHECK_FOR_INTERRUPTS(); \
+	(void) WaitLatch(MyLatch, \
+					 WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH, \
+					 1L, WAIT_EVENT_PG_SLEEP); \
+	ResetLatch(MyLatch); \
+}
+
+/* End parallel copy Macros */
+
 /*
  * CONVERT_TO_SERVER_ENCODING - convert contents to server encoding.
  */
 #define CONVERT_TO_SERVER_ENCODING(cstate) \
 { \
 	/* Done reading the line.  Convert it to server encoding. */ \
-	if (cstate->need_transcoding) \
+	if (cstate->need_transcoding && \
+		(!IsParallelCopy() || \
+		 (IsParallelCopy() && !IsLeader()))) \
 	{ \
 		char	   *cvt; \
 		cvt = pg_any_to_server(cstate->line_buf.data, \
@@ -618,22 +664,38 @@ if (1) \
  * CLEAR_EOL_LINE - Wrapper for clearing EOL.
  */
 #define CLEAR_EOL_LINE() \
-if (!result && !IsHeaderLine()) \
-	CLEAR_EOL_FROM_COPIED_DATA(cstate->line_buf.data, \
-								cstate->line_buf.len, \
-								cstate->line_buf.len) \
+{ \
+	if (!result && !IsHeaderLine()) \
+	{ \
+		if (IsParallelCopy()) \
+			CLEAR_EOL_FROM_COPIED_DATA(cstate->raw_buf, \
+									   raw_buf_ptr, line_size) \
+		else \
+			CLEAR_EOL_FROM_COPIED_DATA(cstate->line_buf.data, \
+									   cstate->line_buf.len, \
+									   cstate->line_buf.len) \
+	} \
+}
 
 /*
  * INCREMENTPROCESSED - Increment the lines processed.
  */
-#define INCREMENTPROCESSED(processed)  \
-processed++;
+#define INCREMENTPROCESSED(processed) \
+{ \
+	if (!IsParallelCopy()) \
+		processed++; \
+	else \
+		pg_atomic_add_fetch_u64(&cstate->pcdata->pcshared_info->processed, 1); \
+}
 
 /*
  * GETPROCESSED - Get the lines processed.
  */
 #define GETPROCESSED(processed) \
-return processed;
+if (!IsParallelCopy()) \
+	return processed; \
+else \
+	return pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
 
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
@@ -681,8 +743,12 @@ static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 
 static pg_attribute_always_inline void EndParallelCopy(ParallelContext *pcxt);
+static void ExecBeforeStmtTrigger(CopyState cstate);
+static void CheckTargetRelValidity(CopyState cstate);
 static void PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tup_desc,
 							   List *attnamelist);
+static void PopulateCatalogInformation(CopyState cstate);
+static pg_attribute_always_inline uint32 GetLinePosition(CopyState cstate);
 static pg_attribute_always_inline copy_data_source_cb LookupParallelCopyFnPtr(const char *funcname);
 static pg_attribute_always_inline char* LookupParallelCopyFnStr(copy_data_source_cb fn_addr);
 
@@ -836,6 +902,137 @@ InsertListShm(ParallelContext *pcxt, int key, List *inputlist,
 }
 
 /*
+ * IsTriggerFunctionParallelSafe - Check if the trigger function is parallel
+ * safe for the triggers. Return false if any one of the trigger has parallel
+ * unsafe function.
+ */
+static pg_attribute_always_inline bool
+IsTriggerFunctionParallelSafe(TriggerDesc *trigdesc)
+{
+	int	i;
+	for (i = 0; i < trigdesc->numtriggers; i++)
+	{
+		Trigger    *trigger = &trigdesc->triggers[i];
+		int 		trigtype = RI_TRIGGER_NONE;
+
+		if (func_parallel(trigger->tgfoid) != PROPARALLEL_SAFE)
+			return false;
+
+		/* If the trigger is parallel safe, also look for RI_TRIGGER. */
+		trigtype = RI_FKey_trigger_type(trigger->tgfoid);
+		if (trigtype == RI_TRIGGER_PK || trigtype == RI_TRIGGER_FK)
+			return false;
+	}
+
+	return true;
+}
+
+/*
+ * CheckExprParallelSafety - determine parallel safety of volatile expressions
+ * in default clause of column definition or in where clause and return true if
+ * they are parallel safe.
+ */
+static pg_attribute_always_inline bool
+CheckExprParallelSafety(CopyState cstate)
+{
+	if (contain_volatile_functions(cstate->whereClause))
+	{
+		if (max_parallel_hazard((Query *)cstate->whereClause) != PROPARALLEL_SAFE)
+			return false;
+	}
+
+	/*
+	 * Check if any of the column has volatile default expression. if yes, and
+	 * they are not parallel safe, then parallelism is not allowed. For
+	 * instance, if there are any serial/bigserial columns for which nextval()
+	 * default expression which is parallel unsafe is associated, parallelism
+	 * should not be allowed. In non parallel copy volatile functions are not
+	 * checked for nextval().
+	 */
+	if (cstate->defexprs != NULL && cstate->num_defaults != 0)
+	{
+		int     i;
+		for (i = 0; i < cstate->num_defaults; i++)
+		{
+			bool volatile_expr = contain_volatile_functions((Node *)cstate->defexprs[i]->expr);
+			if (volatile_expr &&
+				(max_parallel_hazard((Query *)cstate->defexprs[i]->expr)) !=
+				 PROPARALLEL_SAFE)
+				return false;
+		}
+	}
+
+	return true;
+}
+
+/*
+ * FindInsertMethod - determine insert mode single, multi, or multi conditional.
+ */
+static pg_attribute_always_inline CopyInsertMethod
+FindInsertMethod(CopyState cstate)
+{
+	if (cstate->rel->trigdesc != NULL &&
+		(cstate->rel->trigdesc->trig_insert_before_row ||
+		 cstate->rel->trigdesc->trig_insert_instead_row))
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
+			cstate->rel->trigdesc != NULL &&
+			cstate->rel->trigdesc->trig_insert_new_table)
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+		return CIM_MULTI_CONDITIONAL;
+
+	return CIM_MULTI;
+}
+
+/*
+ * IsParallelCopyAllowed - check for the cases where parallel copy is not
+ * applicable.
+ */
+static pg_attribute_always_inline bool
+IsParallelCopyAllowed(CopyState cstate)
+{
+	/* Parallel copy not allowed for frontend (2.0 protocol) & binary option. */
+	if ((cstate->copy_dest == COPY_OLD_FE) || cstate->binary)
+		return false;
+
+	/* Check if copy is into foreign table or temporary table. */
+	if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
+		RelationUsesLocalBuffers(cstate->rel))
+		return false;
+
+	/* Check if trigger function is parallel safe. */
+	if (cstate->rel->trigdesc != NULL &&
+		!IsTriggerFunctionParallelSafe(cstate->rel->trigdesc))
+		return false;
+
+	/*
+	 * Check if there is after statement or instead of trigger or transition
+	 * table triggers.
+	 */
+	if (cstate->rel->trigdesc != NULL &&
+		(cstate->rel->trigdesc->trig_insert_after_statement ||
+		 cstate->rel->trigdesc->trig_insert_instead_row ||
+		 cstate->rel->trigdesc->trig_insert_new_table))
+		return false;
+
+	/* Check if the volatile expressions are parallel safe, if present any. */
+	if (!CheckExprParallelSafety(cstate))
+		return false;
+
+	/* Check if the insertion mode is single. */
+	if (FindInsertMethod(cstate) == CIM_SINGLE)
+		return false;
+
+	return true;
+}
+
+/*
  * BeginParallelCopy - start parallel copy tasks.
  *
  * Get the number of workers required to perform the parallel copy. The data
@@ -865,6 +1062,8 @@ BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
 	int  parallel_workers = 0;
 	ParallelCopyData *pcdata;
 
+	CheckTargetRelValidity(cstate);
+
 	parallel_workers = Min(nworkers, max_worker_processes);
 
 	/* Can't perform copy in parallel */
@@ -878,6 +1077,19 @@ BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
 	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
 	cstate->pcdata = pcdata;
 
+	/*
+	 * User chosen parallel copy. Determine if the parallel copy is actually
+	 * allowed. If not, go with the non-parallel mode.
+	 */
+	if (!IsParallelCopyAllowed(cstate))
+	{
+		elog(WARNING,
+			 "Parallel copy not supported for specified table, copy will be run in non-parallel mode");
+		return NULL;
+	}
+
+	full_transaction_id = GetCurrentFullTransactionId();
+
 	EnterParallelMode();
 	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
 								 parallel_workers);
@@ -1108,7 +1320,211 @@ ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
 	cstate->line_buf_converted = false;
 	cstate->raw_buf = NULL;
 	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+
+	PopulateCatalogInformation(cstate);
+
+	/* Create workspace for CopyReadAttributes results. */
+	if (!cstate->binary)
+	{
+		AttrNumber	attr_count = list_length(cstate->attnumlist);
+
+		cstate->max_fields = attr_count;
+		cstate->raw_fields = (char **)palloc(attr_count * sizeof(char *));
+	}
+}
+
+/*
+ * CacheLineInfo - Cache the line information to local memory.
+ */
+static bool
+CacheLineInfo(CopyState cstate, uint32 buff_count)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	uint32			write_pos;
+	ParallelCopyDataBlock *data_blk_ptr;
+	ParallelCopyLineBoundary *lineInfo;
+	uint32 offset;
+	int dataSize;
+	int copiedSize = 0;
+
+	resetStringInfo(&pcdata->worker_line_buf[buff_count].line_buf);
+	write_pos = GetLinePosition(cstate);
+	if (-1 == write_pos)
+		return true;
+
+	/* Get the current line information. */
+	lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+	if (pg_atomic_read_u32(&lineInfo->line_size) == 0)
+		goto empty_data_line_update;
+
+	/* Get the block information. */
+	data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+	/* Get the offset information from where the data must be copied. */
+	offset = lineInfo->start_offset;
+	pcdata->worker_line_buf[buff_count].cur_lineno = lineInfo->cur_lineno;
+
+	elog(DEBUG1, "[Worker] Processing - line position:%d, block:%d, unprocessed lines:%d, offset:%d, line size:%d",
+				 write_pos, lineInfo->first_block,
+				 pg_atomic_read_u32(&data_blk_ptr->unprocessed_line_parts),
+				 offset, pg_atomic_read_u32(&lineInfo->line_size));
+
+	for (;;)
+	{
+		uint8 skip_bytes = data_blk_ptr->skip_bytes;
+		/*
+		 * There is a possibility that the above loop has come out because
+		 * data_blk_ptr->curr_blk_completed is set, but dataSize read might
+		 * be an old value, if data_blk_ptr->curr_blk_completed and the line is
+		 * completed, line_size will be set. Read the line_size again to be
+		 * sure if it is complete or partial block.
+		 */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+		if (dataSize)
+		{
+			int remainingSize = dataSize - copiedSize;
+			if (!remainingSize)
+				break;
+
+			/* Whole line is in current block. */
+			if (remainingSize + offset + skip_bytes < DATA_BLOCK_SIZE)
+			{
+				appendBinaryStringInfo(&pcdata->worker_line_buf[buff_count].line_buf,
+									   &data_blk_ptr->data[offset],
+									   remainingSize);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts,
+										1);
+				break;
+			}
+			else
+			{
+				/* Line is spread across the blocks. */
+				uint32 lineInCurrentBlock =  (DATA_BLOCK_SIZE - skip_bytes) - offset;
+				appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+										 &data_blk_ptr->data[offset],
+										 lineInCurrentBlock);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+				copiedSize += lineInCurrentBlock;
+				while (copiedSize < dataSize)
+				{
+					uint32 currentBlockCopySize;
+					ParallelCopyDataBlock *currBlkPtr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+					skip_bytes = currBlkPtr->skip_bytes;
+
+					/*
+					 * If complete data is present in current block use
+					 * dataSize - copiedSize, or copy the whole block from
+					 * current block.
+					 */
+					currentBlockCopySize = Min(dataSize - copiedSize, DATA_BLOCK_SIZE - skip_bytes);
+					appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+											 &currBlkPtr->data[0],
+											 currentBlockCopySize);
+					pg_atomic_sub_fetch_u32(&currBlkPtr->unprocessed_line_parts, 1);
+					copiedSize += currentBlockCopySize;
+					data_blk_ptr = currBlkPtr;
+				}
+
+				break;
+			}
+		}
+		else
+		{
+			/* Copy this complete block from the current offset. */
+			uint32 lineInCurrentBlock =  (DATA_BLOCK_SIZE - skip_bytes) - offset;
+			appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+									 &data_blk_ptr->data[offset],
+									 lineInCurrentBlock);
+			pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+			copiedSize += lineInCurrentBlock;
+
+			/*
+			 * Reset the offset. For the first copy, copy from the offset. For
+			 * the subsequent copy the complete block.
+			 */
+			offset = 0;
+
+			/* Set data_blk_ptr to the following block. */
+			data_blk_ptr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+		}
+
+		for (;;)
+		{
+			/* Get the size of this line */
+			dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+			/*
+			 * If the data is present in current block lineInfo.line_size
+			 * will be updated. If the data is spread across the blocks either
+			 * of lineInfo.line_size or data_blk_ptr->curr_blk_completed can
+			 * be updated. lineInfo.line_size will be updated if the complete
+			 * read is finished. data_blk_ptr->curr_blk_completed will be
+			 * updated if processing of current block is finished and data
+			 * processing is not finished.
+			 */
+			if (data_blk_ptr->curr_blk_completed || (dataSize != -1))
+				break;
+
+			COPY_WAIT_TO_PROCESS()
+		}
+	}
+
+empty_data_line_update:
+	elog(DEBUG1, "[Worker] Completed processing line:%d", write_pos);
+	pg_atomic_write_u32(&lineInfo->line_state, LINE_WORKER_PROCESSED);
+	pg_atomic_write_u32(&lineInfo->line_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+	return false;
+}
+
+/*
+ * GetWorkerLine - Returns a line for worker to process.
+ */
+static bool
+GetWorkerLine(CopyState cstate)
+{
+	uint32 buff_count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+
+	/*
+	 * Copy the line data to line_buf and release the line position so that the
+	 * worker can continue loading data.
+	 */
+	if (pcdata->worker_line_buf_pos < pcdata->worker_line_buf_count)
+		goto return_line;
+
+	pcdata->worker_line_buf_pos = 0;
+	pcdata->worker_line_buf_count = 0;
+
+	for (buff_count = 0; buff_count < WORKER_CHUNK_COUNT; buff_count++)
+	{
+		bool result = CacheLineInfo(cstate, buff_count);
+		if (result)
+			break;
+
+		pcdata->worker_line_buf_count++;
+	}
+
+	if (pcdata->worker_line_buf_count)
+		goto return_line;
+	else
+		resetStringInfo(&cstate->line_buf);
+
+	return true;
+
+return_line:
+	cstate->line_buf = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].line_buf;
+	cstate->cur_lineno = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].cur_lineno;
+	cstate->line_buf_valid = true;
+
+	/* Mark that encoding conversion hasn't occurred yet. */
+	cstate->line_buf_converted = false;
+	CONVERT_TO_SERVER_ENCODING(cstate)
+	pcdata->worker_line_buf_pos++;
+	return false;
 }
+
 /*
  * ParallelCopyMain - parallel copy worker's code.
  *
@@ -1154,6 +1570,8 @@ ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
 	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
 
 	pcdata->pcshared_info = pcshared_info;
+	AssignFullTransactionIdForWorker(pcshared_info->full_transaction_id);
+	AssignCommandIdForWorker(pcshared_info->mycid, true);
 
 	shared_cstate = (ParallelCopyCommonKeyData *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE,
 														   false);
@@ -1206,6 +1624,34 @@ ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
 	MemoryContextSwitchTo(oldcontext);
 	return;
 }
+
+/*
+ * UpdateBlockInLineInfo - Update the line information.
+ */
+static pg_attribute_always_inline int
+UpdateBlockInLineInfo(CopyState cstate, uint32 blk_pos,
+					   uint32 offset, uint32 line_size, uint32 line_state)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyLineBoundaries *lineBoundaryPtr = &pcshared_info->line_boundaries;
+	ParallelCopyLineBoundary *lineInfo;
+	int line_pos = lineBoundaryPtr->leader_pos;
+
+	/* Update the line information for the worker to pick and process. */
+	lineInfo = &lineBoundaryPtr->ring[line_pos];
+	while (pg_atomic_read_u32(&lineInfo->line_size) != -1)
+		COPY_WAIT_TO_PROCESS()
+
+	lineInfo->first_block = blk_pos;
+	lineInfo->start_offset = offset;
+	lineInfo->cur_lineno = cstate->cur_lineno;
+	pg_atomic_write_u32(&lineInfo->line_size, line_size);
+	pg_atomic_write_u32(&lineInfo->line_state, line_state);
+	lineBoundaryPtr->leader_pos = (lineBoundaryPtr->leader_pos + 1) % RINGSIZE;
+
+	return line_pos;
+}
+
 /*
  * ParallelCopyLeader - parallel copy leader's functionality.
  *
@@ -1231,9 +1677,161 @@ ParallelCopyLeader(CopyState cstate)
 	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
 	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
 
+	/* Execute the before statement triggers from the leader */
+	ExecBeforeStmtTrigger(cstate);
+
+	/* On input just throw the header line away. */
+	if (cstate->cur_lineno == 0 && cstate->header_line)
+	{
+		cstate->cur_lineno++;
+		if (CopyReadLine(cstate))
+		{
+			pcshared_info->is_read_in_progress = false;
+			return;			/* done */
+		}
+	}
+
+	for (;;)
+	{
+		bool done;
+		cstate->cur_lineno++;
+
+		/* Actually read the line into memory here. */
+		done = CopyReadLine(cstate);
+
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			break;
+	}
+
 	pcshared_info->is_read_in_progress = false;
 	cstate->cur_lineno = 0;
 }
+
+/*
+ * GetLinePosition - return the line position that worker should process.
+ */
+static uint32
+GetLinePosition(CopyState cstate)
+{
+	ParallelCopyData *pcdata = cstate->pcdata;
+	ParallelCopyShmInfo *pcshared_info = pcdata->pcshared_info;
+	uint32  previous_pos = pcdata->worker_processed_pos;
+	uint32 write_pos = (previous_pos == -1) ? 0 : (previous_pos + 1) % RINGSIZE;
+	for (;;)
+	{
+		int		dataSize;
+		bool	is_read_in_progress = pcshared_info->is_read_in_progress;
+		ParallelCopyLineBoundary *lineInfo;
+		ParallelCopyDataBlock *data_blk_ptr;
+		ParallelCopyLineState line_state = LINE_LEADER_POPULATED;
+		ParallelCopyLineState curr_line_state;
+		CHECK_FOR_INTERRUPTS();
+
+		/* File read completed & no elements to process. */
+		if (!is_read_in_progress &&
+			(pcshared_info->populated ==
+			 pg_atomic_read_u64(&pcshared_info->total_worker_processed)))
+		{
+			write_pos = -1;
+			break;
+		}
+
+		/* Get the current line information. */
+		lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+		curr_line_state = pg_atomic_read_u32(&lineInfo->line_state);
+		if ((write_pos % WORKER_CHUNK_COUNT == 0) &&
+			(curr_line_state == LINE_WORKER_PROCESSED ||
+			 curr_line_state == LINE_WORKER_PROCESSING))
+		{
+			pcdata->worker_processed_pos = write_pos;
+			write_pos = (write_pos + WORKER_CHUNK_COUNT) %  RINGSIZE;
+			continue;
+		}
+
+		/* Get the size of this line. */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+		if (dataSize != 0) /* If not an empty line. */
+		{
+			/* Get the block information. */
+			data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+			if (!data_blk_ptr->curr_blk_completed && (dataSize == -1))
+			{
+				/* Wait till the current line or block is added. */
+				COPY_WAIT_TO_PROCESS()
+				continue;
+			}
+		}
+
+		/* Make sure that no worker has consumed this element. */
+		if (pg_atomic_compare_exchange_u32(&lineInfo->line_state,
+										   &line_state, LINE_WORKER_PROCESSING))
+			break;
+	}
+
+	pcdata->worker_processed_pos = write_pos;
+	return write_pos;
+}
+
+/*
+ * GetFreeCopyBlock - Get a free block for data to be copied.
+ */
+static pg_attribute_always_inline uint32
+GetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	int count = 0;
+	uint32 last_free_block = pcshared_info->cur_block_pos;
+	uint32 block_pos = (last_free_block != -1) ? ((last_free_block + 1) % MAX_BLOCKS_COUNT): 0;
+
+	/*
+	 * Get a new block for copying data, don't check curent block, current
+	 * block will have some unprocessed data.
+	 */
+	while (count < (MAX_BLOCKS_COUNT - 1))
+	{
+		ParallelCopyDataBlock *dataBlkPtr = &pcshared_info->data_blocks[block_pos];
+		uint32 unprocessed_line_parts = pg_atomic_read_u32(&dataBlkPtr->unprocessed_line_parts);
+		if (unprocessed_line_parts == 0)
+		{
+			dataBlkPtr->curr_blk_completed = false;
+			dataBlkPtr->skip_bytes = 0;
+			pcshared_info->cur_block_pos = block_pos;
+			return block_pos;
+		}
+
+		block_pos = (block_pos + 1) % MAX_BLOCKS_COUNT;
+		count++;
+	}
+
+	return -1;
+}
+
+/*
+ * WaitGetFreeCopyBlock - If there are no blocks available, wait and get a block
+ * for copying data.
+ */
+static uint32
+WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	uint32 new_free_pos = -1;
+	for (;;)
+	{
+		new_free_pos = GetFreeCopyBlock(pcshared_info);
+		if (new_free_pos != -1)	/* We have got one block, break now. */
+			break;
+
+		COPY_WAIT_TO_PROCESS()
+	}
+
+	return new_free_pos;
+}
+
 /*
  * LookupParallelCopyFnPtr - Look up parallel copy function pointer.
  */
@@ -1269,6 +1867,146 @@ LookupParallelCopyFnStr(copy_data_source_cb fn_addr)
 	/* We can only reach this by programming error. */
 	elog(ERROR, "internal function pointer not found");
 }
+
+/*
+ * SetRawBufForLoad - Set raw_buf to the shared memory where the file data must
+ * be read.
+ */
+static void
+SetRawBufForLoad(CopyState cstate, uint32 line_size, uint32 copy_buf_len,
+				 uint32 raw_buf_ptr, char **copy_raw_buf)
+{
+	ParallelCopyShmInfo	*pcshared_info;
+	uint32 cur_block_pos;
+	uint32 next_block_pos;
+	ParallelCopyDataBlock	*cur_data_blk_ptr = NULL;
+	ParallelCopyDataBlock	*next_data_blk_ptr = NULL;
+
+	if (!IsParallelCopy())
+		return;
+
+	pcshared_info = cstate->pcdata->pcshared_info;
+	cur_block_pos = pcshared_info->cur_block_pos;
+	cur_data_blk_ptr = (cstate->raw_buf) ? &pcshared_info->data_blocks[cur_block_pos] : NULL;
+	next_block_pos = WaitGetFreeCopyBlock(pcshared_info);
+	next_data_blk_ptr = &pcshared_info->data_blocks[next_block_pos];
+
+	/* set raw_buf to the data block in shared memory */
+	cstate->raw_buf = next_data_blk_ptr->data;
+	*copy_raw_buf = cstate->raw_buf;
+	if (cur_data_blk_ptr && line_size)
+	{
+		/*
+		 * Mark the previous block as completed, worker can start copying this
+		 * data.
+		 */
+		cur_data_blk_ptr->following_block = next_block_pos;
+		pg_atomic_add_fetch_u32(&cur_data_blk_ptr->unprocessed_line_parts, 1);
+		cur_data_blk_ptr->skip_bytes = copy_buf_len - raw_buf_ptr;
+		cur_data_blk_ptr->curr_blk_completed = true;
+	}
+}
+
+/*
+ * EndLineParallelCopy - Update the line information in shared memory.
+ */
+static void
+EndLineParallelCopy(CopyState cstate, uint32 line_pos, uint32 line_size,
+					 uint32 raw_buf_ptr)
+{
+	uint8 new_line_size;
+	if (!IsParallelCopy())
+		return;
+
+	if (!IsHeaderLine())
+	{
+		ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+		ParallelCopyLineBoundaries *lineBoundaryPtr = &pcshared_info->line_boundaries;
+		SET_NEWLINE_SIZE()
+		if (line_size)
+		{
+			ParallelCopyLineBoundary *lineInfo = &lineBoundaryPtr->ring[line_pos];
+			/*
+			 * If the new_line_size > raw_buf_ptr, then the new block has only
+			 * new line char content. The unprocessed count should not be
+			 * increased in this case.
+			 */
+			if (raw_buf_ptr > new_line_size)
+			{
+				uint32 cur_block_pos = pcshared_info->cur_block_pos;
+				ParallelCopyDataBlock *curr_data_blk_ptr = &pcshared_info->data_blocks[cur_block_pos];
+				pg_atomic_add_fetch_u32(&curr_data_blk_ptr->unprocessed_line_parts, 1);
+			}
+
+			/* Update line size. */
+			pg_atomic_write_u32(&lineInfo->line_size, line_size);
+			pg_atomic_write_u32(&lineInfo->line_state, LINE_LEADER_POPULATED);
+			elog(DEBUG1, "[Leader] After adding - line position:%d, line_size:%d",
+						 line_pos, line_size);
+			pcshared_info->populated++;
+		}
+		else if (new_line_size)
+		{
+			/* This means only new line char, empty record should be inserted.*/
+			ParallelCopyLineBoundary *lineInfo;
+			line_pos = UpdateBlockInLineInfo(cstate, -1, -1, 0,
+											   LINE_LEADER_POPULATED);
+			lineInfo = &lineBoundaryPtr->ring[line_pos];
+			elog(DEBUG1, "[Leader] Added empty line with offset:%d, line position:%d, line size:%d",
+						 lineInfo->start_offset, line_pos,
+						 pg_atomic_read_u32(&lineInfo->line_size));
+			pcshared_info->populated++;
+		}
+	}
+}
+
+/*
+ * ExecBeforeStmtTrigger - Execute the before statement trigger, this will be
+ * executed for parallel copy by the leader process.
+ */
+static void
+ExecBeforeStmtTrigger(CopyState cstate)
+{
+	EState	   *estate = CreateExecutorState();
+	ResultRelInfo *resultRelInfo;
+
+	Assert(IsLeader());
+
+	/*
+	 * We need a ResultRelInfo so we can use the regular executor's
+	 * index-entry-making machinery.  (There used to be a huge amount of code
+	 * here that basically duplicated execUtils.c ...)
+	 */
+	resultRelInfo = makeNode(ResultRelInfo);
+	InitResultRelInfo(resultRelInfo,
+					  cstate->rel,
+					  1,		/* must match rel's position in range_table */
+					  NULL,
+					  0);
+
+	/* Verify the named relation is a valid target for INSERT */
+	CheckValidResultRel(resultRelInfo, CMD_INSERT);
+
+	estate->es_result_relations = resultRelInfo;
+	estate->es_num_result_relations = 1;
+	estate->es_result_relation_info = resultRelInfo;
+
+	ExecInitRangeTable(estate, cstate->range_table);
+
+	/*
+	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
+	 * should do this for COPY, since it's not really an "INSERT" statement as
+	 * such. However, executing these triggers maintains consistency with the
+	 * EACH ROW triggers that we already fire on COPY.
+	 */
+	ExecBSInsertTriggers(estate, resultRelInfo);
+
+	/* Close any trigger target relations */
+	ExecCleanUpTriggerState(estate);
+
+	FreeExecutorState(estate);
+}
+
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
  * in past protocol redesigns.
@@ -3702,7 +4440,8 @@ CopyFrom(CopyState cstate)
 
 	PartitionTupleRouting *proute = NULL;
 	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
+	CommandId	mycid = IsParallelCopy() ? GetCurrentCommandId(false) :
+										   GetCurrentCommandId(true);
 	int			ti_options = 0; /* start with default options for insert */
 	BulkInsertState bistate = NULL;
 	CopyInsertMethod insertMethod;
@@ -3712,7 +4451,14 @@ CopyFrom(CopyState cstate)
 	bool		has_instead_insert_row_trig;
 	bool		leafpart_use_multi_insert = false;
 
-	CheckTargetRelValidity(cstate);
+	/*
+	 * Perform this check if it is not parallel copy. In case of parallel
+	 * copy, this check is done by the leader, so that if any invalid case
+	 * exist the copy from command will error out from the leader itself,
+	 * avoiding launching workers, just to throw error.
+	 */
+	if (!IsParallelCopy())
+		CheckTargetRelValidity(cstate);
 
 	/*
 	 * If the target file is new-in-transaction, we assume that checking FSM
@@ -3901,13 +4647,16 @@ CopyFrom(CopyState cstate)
 	has_instead_insert_row_trig = (resultRelInfo->ri_TrigDesc &&
 								   resultRelInfo->ri_TrigDesc->trig_insert_instead_row);
 
-	/*
-	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
-	 * should do this for COPY, since it's not really an "INSERT" statement as
-	 * such. However, executing these triggers maintains consistency with the
-	 * EACH ROW triggers that we already fire on COPY.
-	 */
-	ExecBSInsertTriggers(estate, resultRelInfo);
+	if (!IsParallelCopy())
+	{
+		/*
+		 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
+		 * should do this for COPY, since it's not really an "INSERT" statement as
+		 * such. However, executing these triggers maintains consistency with the
+		 * EACH ROW triggers that we already fire on COPY.
+		 */
+		ExecBSInsertTriggers(estate, resultRelInfo);
+	}
 
 	econtext = GetPerTupleExprContext(estate);
 
@@ -4007,6 +4756,16 @@ CopyFrom(CopyState cstate)
 					!has_instead_insert_row_trig &&
 					resultRelInfo->ri_FdwRoutine == NULL;
 
+				/*
+				 * If the table has any partitions that are either foreign or
+				 * has BEFORE/INSTEAD OF triggers, we can't perform copy
+				 * operations with parallel workers.
+				 */
+				if (!leafpart_use_multi_insert && IsParallelWorker())
+					ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							errmsg("cannot perform PARALLEL COPY if partition has BEFORE/INSTEAD OF triggers, or if the partition is foreign partition"),
+							errhint("Try COPY without PARALLEL option")));
+
 				/* Set the multi-insert buffer to use for this partition. */
 				if (leafpart_use_multi_insert)
 				{
@@ -4421,7 +5180,7 @@ BeginCopyFrom(ParseState *pstate,
 	initStringInfo(&cstate->attribute_buf);
 	initStringInfo(&cstate->line_buf);
 	cstate->line_buf_converted = false;
-	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+	cstate->raw_buf = (IsParallelCopy()) ? NULL : (char *) palloc(RAW_BUF_SIZE + 1);
 	cstate->raw_buf_index = cstate->raw_buf_len = 0;
 
 	/* Assign range table, we'll need it in CopyFrom. */
@@ -4565,26 +5324,35 @@ NextCopyFromRawFields(CopyState cstate, char ***fields, int *nfields)
 	/* only available for text or csv input */
 	Assert(!cstate->binary);
 
-	/* on input just throw the header line away */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (IsParallelCopy())
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
-			return false;		/* done */
+		done = GetWorkerLine(cstate);
+		if (done && cstate->line_buf.len == 0)
+			return false;
 	}
+	else
+	{
+		/* on input just throw the header line away */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
+		{
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+				return false;		/* done */
+		}
 
-	cstate->cur_lineno++;
+		cstate->cur_lineno++;
 
-	/* Actually read the line into memory here */
-	done = CopyReadLine(cstate);
+		/* Actually read the line into memory here */
+		done = CopyReadLine(cstate);
 
-	/*
-	 * EOF at start of line means we're done.  If we see EOF after some
-	 * characters, we act as though it was newline followed by EOF, ie,
-	 * process the line and then exit loop on next iteration.
-	 */
-	if (done && cstate->line_buf.len == 0)
-		return false;
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			return false;
+	}
 
 	/* Parse the line into de-escaped field values */
 	if (cstate->csv_mode)
@@ -4832,9 +5600,31 @@ CopyReadLine(CopyState cstate)
 		 */
 		if (cstate->copy_dest == COPY_NEW_FE)
 		{
+			bool bIsFirst = true;
 			do
 			{
-				cstate->raw_buf_index = cstate->raw_buf_len;
+				if (!IsParallelCopy())
+					cstate->raw_buf_index = cstate->raw_buf_len;
+				else
+				{
+					if (cstate->raw_buf_index == RAW_BUF_SIZE)
+					{
+						/* Get a new block if it is the first time, From the
+						 * subsequent time, reset the index and re-use the same
+						 * block.
+						 */
+						if (bIsFirst)
+						{
+							ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+							uint32 block_pos = WaitGetFreeCopyBlock(pcshared_info);
+							cstate->raw_buf = pcshared_info->data_blocks[block_pos].data;
+							bIsFirst = false;
+						}
+
+						cstate->raw_buf_index = cstate->raw_buf_len = 0;
+					}
+				}
+
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
@@ -4864,6 +5654,11 @@ CopyReadLineText(CopyState cstate)
 	char		quotec = '\0';
 	char		escapec = '\0';
 
+	/* For parallel copy */
+	uint32			 line_size = 0;
+	int				 line_pos = 0;
+
+	cstate->eol_type = EOL_UNKNOWN;
 	if (cstate->csv_mode)
 	{
 		quotec = cstate->quote[0];
@@ -4918,6 +5713,8 @@ CopyReadLineText(CopyState cstate)
 		if (raw_buf_ptr >= copy_buf_len || need_data)
 		{
 			REFILL_LINEBUF;
+			SetRawBufForLoad(cstate, line_size, copy_buf_len, raw_buf_ptr,
+							 &copy_raw_buf);
 
 			/*
 			 * Try to read some more data.  This will certainly reset
@@ -5142,9 +5939,15 @@ CopyReadLineText(CopyState cstate)
 				 * discard the data and the \. sequence.
 				 */
 				if (prev_raw_ptr > cstate->raw_buf_index)
-					appendBinaryStringInfo(&cstate->line_buf,
+				{
+					if (!IsParallelCopy())
+						appendBinaryStringInfo(&cstate->line_buf,
 										   cstate->raw_buf + cstate->raw_buf_index,
 										   prev_raw_ptr - cstate->raw_buf_index);
+					else
+						line_size += prev_raw_ptr - cstate->raw_buf_index;
+				}
+
 				cstate->raw_buf_index = raw_buf_ptr;
 				result = true;	/* report EOF */
 				break;
@@ -5196,6 +5999,26 @@ not_end_of_copy:
 			IF_NEED_REFILL_AND_EOF_BREAK(mblen - 1);
 			raw_buf_ptr += mblen - 1;
 		}
+
+		/*
+		 * Skip the header line. Update the line here, this cannot be done at
+		 * the beginning, as there is a possibility that file contains empty
+		 * lines.
+		 */
+		if (IsParallelCopy() && first_char_in_line && !IsHeaderLine())
+		{
+			ParallelCopyShmInfo	*pcshared_info = cstate->pcdata->pcshared_info;
+			ParallelCopyLineBoundary *lineInfo;
+			uint32			 line_first_block = pcshared_info->cur_block_pos;
+			line_pos = UpdateBlockInLineInfo(cstate,
+											   line_first_block,
+											   cstate->raw_buf_index, -1,
+											   LINE_LEADER_POPULATING);
+			lineInfo = &pcshared_info->line_boundaries.ring[line_pos];
+			elog(DEBUG1, "[Leader] Adding - block:%d, offset:%d, line position:%d",
+						 line_first_block,	lineInfo->start_offset, line_pos);
+		}
+
 		first_char_in_line = false;
 	}							/* end of outer loop */
 
@@ -5204,6 +6027,7 @@ not_end_of_copy:
 	 */
 	REFILL_LINEBUF;
 	CLEAR_EOL_LINE()
+	EndLineParallelCopy(cstate, line_pos, line_size, raw_buf_ptr);
 
 	return result;
 }
diff --git a/src/backend/libpq/pqmq.c b/src/backend/libpq/pqmq.c
index 743d24c..21ef87f 100644
--- a/src/backend/libpq/pqmq.c
+++ b/src/backend/libpq/pqmq.c
@@ -168,7 +168,8 @@ mq_putmessage(char msgtype, const char *s, size_t len)
 		if (result != SHM_MQ_WOULD_BLOCK)
 			break;
 
-		(void) WaitLatch(MyLatch, WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
+		(void) WaitLatch(MyLatch,
+						 WL_TIMEOUT | WL_LATCH_SET | WL_EXIT_ON_PM_DEATH, 0,
 						 WAIT_EVENT_MQ_PUT_MESSAGE);
 		ResetLatch(MyLatch);
 		CHECK_FOR_INTERRUPTS();
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index db19187..20dafb7 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -381,6 +381,8 @@ extern FullTransactionId GetTopFullTransactionId(void);
 extern FullTransactionId GetTopFullTransactionIdIfAny(void);
 extern FullTransactionId GetCurrentFullTransactionId(void);
 extern FullTransactionId GetCurrentFullTransactionIdIfAny(void);
+extern void AssignFullTransactionIdForWorker(FullTransactionId fullTransactionId);
+extern void AssignCommandIdForWorker(CommandId commandId, bool used);
 extern void MarkCurrentTransactionIdLoggedIfAny(void);
 extern bool SubTransactionIsActive(SubTransactionId subxid);
 extern CommandId GetCurrentCommandId(bool used);
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 8a79794..86b5c62 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1700,6 +1700,7 @@ ParallelCompletionPtr
 ParallelContext
 ParallelCopyLineBoundaries
 ParallelCopyLineBoundary
+ParallelCopyLineState
 ParallelCopyCommonKeyData
 ParallelCopyData
 ParallelCopyDataBlock
-- 
1.8.3.1

0004-Documentation-for-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=0004-Documentation-for-parallel-copy.patchDownload
From 8db83cde4430300d40b926a02d8c3cb6e9847fa5 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 17 Jun 2020 07:34:56 +0530
Subject: [PATCH 4/6] Documentation for parallel copy.

This patch has the documentation changes for parallel copy.
---
 doc/src/sgml/ref/copy.sgml | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/doc/src/sgml/ref/copy.sgml b/doc/src/sgml/ref/copy.sgml
index 18189ab..95d349d 100644
--- a/doc/src/sgml/ref/copy.sgml
+++ b/doc/src/sgml/ref/copy.sgml
@@ -37,6 +37,7 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
     DELIMITER '<replaceable class="parameter">delimiter_character</replaceable>'
     NULL '<replaceable class="parameter">null_string</replaceable>'
     HEADER [ <replaceable class="parameter">boolean</replaceable> ]
+    PARALLEL <replaceable class="parameter">integer</replaceable>
     QUOTE '<replaceable class="parameter">quote_character</replaceable>'
     ESCAPE '<replaceable class="parameter">escape_character</replaceable>'
     FORCE_QUOTE { ( <replaceable class="parameter">column_name</replaceable> [, ...] ) | * }
@@ -275,6 +276,21 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
    </varlistentry>
 
    <varlistentry>
+    <term><literal>PARALLEL</literal></term>
+    <listitem>
+     <para>
+      Perform <command>COPY FROM</command> in parallel using <replaceable
+      class="parameter"> integer</replaceable> background workers.  Please
+      note that it is not guaranteed that the number of parallel workers
+      specified in <replaceable class="parameter">integer</replaceable> will
+      be used during execution.  It is possible for a copy to run with fewer
+      workers than specified, or even with no workers at all.  This option is
+      allowed only in <command>COPY FROM</command>.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><literal>QUOTE</literal></term>
     <listitem>
      <para>
-- 
1.8.3.1

0005-Tests-for-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=0005-Tests-for-parallel-copy.patchDownload
From 9eb6f57ba4e4bdf9f63eaab348c997fdfb7d0e98 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 17 Jun 2020 07:37:26 +0530
Subject: [PATCH 5/6] Tests for parallel copy.

This patch has the tests for parallel copy.
---
 src/test/regress/expected/copy2.out | 210 +++++++++++++++++++++++++++++++++++-
 src/test/regress/input/copy.source  |  12 +++
 src/test/regress/output/copy.source |  12 +++
 src/test/regress/sql/copy2.sql      | 208 ++++++++++++++++++++++++++++++++++-
 4 files changed, 434 insertions(+), 8 deletions(-)

diff --git a/src/test/regress/expected/copy2.out b/src/test/regress/expected/copy2.out
index e40287d..ef75148 100644
--- a/src/test/regress/expected/copy2.out
+++ b/src/test/regress/expected/copy2.out
@@ -254,18 +254,32 @@ It is "perfect".|
 "It is ""perfect"".","	"
 "",
 --test that we read consecutive LFs properly
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 COPY testnl FROM stdin CSV;
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+SELECT * FROM testnl;
+ a |          b           | c 
+---+----------------------+---
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+(2 rows)
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 COPY testeoc FROM stdin CSV;
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
 COPY testeoc TO stdout CSV;
 a\.
 \.b
 c\.d
 "\."
 -- test handling of nonstandard null marker that violates escaping rules
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 COPY testnull TO stdout WITH NULL AS E'\\0';
 1	\\0
@@ -280,6 +294,15 @@ SELECT * FROM testnull;
     | 
 (4 rows)
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 1);
+SELECT * FROM testnull;
+ a  | b  
+----+----
+ 42 | \0
+    | 
+(2 rows)
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -349,6 +372,34 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+SELECT * FROM vistest;
+ a  
+----
+ a2
+ b
+(2 rows)
+
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+COMMIT;
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 SELECT * FROM vistest;
  a 
@@ -409,7 +460,7 @@ SELECT * FROM vistest;
 (2 rows)
 
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -420,6 +471,8 @@ CREATE TEMP TABLE forcetest (
 -- should succeed with no effect ("b" remains an empty string, "c" remains NULL)
 BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 1);
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
  b |  c   
@@ -430,6 +483,8 @@ SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
 BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 1);
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
  c |  d   
@@ -486,6 +541,31 @@ select * from check_con_tbl;
    
 (2 rows)
 
+\d+ check_con_tbl
+                               Table "public.check_con_tbl"
+ Column |  Type   | Collation | Nullable | Default | Storage | Stats target | Description 
+--------+---------+-----------+----------+---------+---------+--------------+-------------
+ f1     | integer |           |          |         | plain   |              | 
+Check constraints:
+    "check_con_tbl_check" CHECK (check_con_function(check_con_tbl.*))
+
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 1);
+NOTICE:  input = {"f1":1}
+NOTICE:  input = {"f1":null}
+copy check_con_tbl from stdin with (parallel 1);
+NOTICE:  input = {"f1":0}
+ERROR:  new row for relation "check_con_tbl" violates check constraint "check_con_tbl_check"
+DETAIL:  Failing row contains (0).
+CONTEXT:  COPY check_con_tbl, line 1: "0"
+parallel worker
+select * from check_con_tbl;
+ f1 
+----
+  1
+   
+(2 rows)
+
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
 CREATE ROLE regress_rls_copy_user_colperms;
@@ -600,8 +680,130 @@ SELECT * FROM instead_of_insert_tbl;
 (2 rows)
 
 COMMIT;
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+COPY test_parallel_copy (a, b, c, d, e) from stdin with (PARALLEL 1);
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1, FORMAT 'csv', HEADER);
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0');
+ERROR:  argument to option "parallel" must be a positive integer greater than zero
+LINE 1: COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0'...
+                                                        ^
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri from stdin with (FORMAT csv, DELIMITER ',', PARALLEL 1);
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1) WHERE height > random() * 65;
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- temporary table copy: should peform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+COPY temp_test (a) from stdin with (PARALLEL 1);
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) from stdin with (PARALLEL 1);
+ERROR:  column "xyz" of relation "test_parallel_copy" does not exist
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) from stdin with (PARALLEL 1);
+ERROR:  column "d" specified more than once
+-- missing data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  invalid input syntax for type integer: ""
+CONTEXT:  COPY test_parallel_copy, line 0, column a: ""
+parallel worker
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2000	230	23	23"
+parallel worker
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2001	231	\N	\N"
+parallel worker
+-- extra data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  extra data after last expected column
+CONTEXT:  COPY test_parallel_copy, line 1: "2002	232	40	50	60	70	80"
+parallel worker
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) from stdin with (delimiter ',', null 'x', PARALLEL 1) ;
+COPY test_parallel_copy from stdin WITH (DELIMITER ';', NULL '', PARALLEL 1);
+COPY test_parallel_copy from stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL 1);
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = 50004;
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a > 60003;
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE f > 60003;
+ERROR:  column "f" does not exist
+LINE 1: ..._parallel_copy from stdin WITH (PARALLEL 1) WHERE f > 60003;
+                                                             ^
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+ERROR:  missing FROM-clause entry for table "x"
+LINE 1: ...rallel_copy from stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+                                                                  ^
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (SELECT 1 FROM x);
+ERROR:  cannot use subquery in COPY FROM WHERE condition
+LINE 1: ...arallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (SELECT...
+                                                             ^
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (generate_series(1,5));
+ERROR:  set-returning functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...lel_copy from stdin WITH (PARALLEL 1) WHERE a IN (generate_s...
+                                                             ^
+COPY test_parallel_copy from stdin WITH(PARALLEL 1) WHERE a = row_number() over(b);
+ERROR:  window functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...rallel_copy from stdin WITH(PARALLEL 1) WHERE a = row_number...
+                                                             ^
+-- check results of copy in
+SELECT * FROM test_parallel_copy;
+   a   | b  |     c      |    d    |    e    
+-------+----+------------+---------+---------
+     1 | 11 | test_c1    | test_d1 | test_e1
+     2 | 12 | test_c2    | test_d2 | test_e2
+       |  3 | stuff      | test_d3 | 
+       |  4 | stuff      | test_d4 | 
+       |  5 | stuff      | test_d5 | 
+       |    | 45         | 80      | 90
+       |    | x          | \x      | \x
+       |    | ,          | \,      | \
+  3000 |    | c          |         | 
+  4000 |    | C          |         | 
+  4001 |  1 | empty      |         | 
+  4002 |  2 | null       |         | 
+  4003 |  3 | Backslash  | \       | \
+  4004 |  4 | BackslashX | \X      | \X
+  4005 |  5 | N          | N       | N
+  4006 |  6 | BackslashN | \N      | \N
+  4007 |  7 | XX         | XX      | XX
+  4008 |  8 | Delimiter  | :       | :
+ 50004 | 25 | 35         | 45      | 55
+ 60004 | 25 | 35         | 45      | 55
+ 60005 | 26 | 36         | 46      | 56
+(21 rows)
+
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
 DROP TABLE x, y;
diff --git a/src/test/regress/input/copy.source b/src/test/regress/input/copy.source
index a1d529a..159c058 100644
--- a/src/test/regress/input/copy.source
+++ b/src/test/regress/input/copy.source
@@ -15,6 +15,13 @@ DELETE FROM onek;
 
 COPY onek FROM '@abs_builddir@/results/onek.data';
 
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+
+SELECT COUNT(*) FROM tenk1;
+
+TRUNCATE tenk1;
+
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
@@ -159,6 +166,11 @@ truncate parted_copytest;
 
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
 
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
+
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/output/copy.source b/src/test/regress/output/copy.source
index 938d355..c3003fe 100644
--- a/src/test/regress/output/copy.source
+++ b/src/test/regress/output/copy.source
@@ -9,6 +9,15 @@ COPY onek FROM '@abs_srcdir@/data/onek.data';
 COPY onek TO '@abs_builddir@/results/onek.data';
 DELETE FROM onek;
 COPY onek FROM '@abs_builddir@/results/onek.data';
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+SELECT COUNT(*) FROM tenk1;
+ count 
+-------
+ 10000
+(1 row)
+
+TRUNCATE tenk1;
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
 COPY person FROM '@abs_srcdir@/data/person.data';
@@ -113,6 +122,9 @@ insert into parted_copytest select x,1,'One' from generate_series(1011,1020) x;
 copy (select * from parted_copytest order by a) to '@abs_builddir@/results/parted_copytest.csv';
 truncate parted_copytest;
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/sql/copy2.sql b/src/test/regress/sql/copy2.sql
index 902f4fa..032cea9 100644
--- a/src/test/regress/sql/copy2.sql
+++ b/src/test/regress/sql/copy2.sql
@@ -157,7 +157,7 @@ COPY y TO stdout (FORMAT CSV, FORCE_QUOTE *);
 
 --test that we read consecutive LFs properly
 
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 
 COPY testnl FROM stdin CSV;
 1,"a field with two LFs
@@ -165,8 +165,16 @@ COPY testnl FROM stdin CSV;
 inside",2
 \.
 
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+1,"a field with two LFs
+
+inside",2
+\.
+
+SELECT * FROM testnl;
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 
 COPY testeoc FROM stdin CSV;
 a\.
@@ -175,11 +183,19 @@ c\.d
 "\."
 \.
 
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+a\.
+\.b
+c\.d
+"\."
+\.
+
 COPY testeoc TO stdout CSV;
 
 -- test handling of nonstandard null marker that violates escaping rules
 
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 
 COPY testnull TO stdout WITH NULL AS E'\\0';
@@ -191,6 +207,14 @@ COPY testnull FROM stdin WITH NULL AS E'\\0';
 
 SELECT * FROM testnull;
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 1);
+42	\\0
+\0	\0
+\.
+
+SELECT * FROM testnull;
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -235,6 +259,23 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+a2
+b
+\.
+SELECT * FROM vistest;
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+d2
+e
+\.
+SELECT * FROM vistest;
+COMMIT;
+SELECT * FROM vistest;
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 x
 y
@@ -284,7 +325,7 @@ SELECT * FROM vistest;
 COMMIT;
 SELECT * FROM vistest;
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -297,6 +338,10 @@ BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
 1,,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 1);
+1,,""
+\.
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
@@ -304,6 +349,10 @@ BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
 2,'a',,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 1);
+2,'a',,""
+\.
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
 -- should fail with not-null constraint violation
@@ -339,6 +388,16 @@ copy check_con_tbl from stdin;
 0
 \.
 select * from check_con_tbl;
+\d+ check_con_tbl
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 1);
+1
+\N
+\.
+copy check_con_tbl from stdin with (parallel 1);
+0
+\.
+select * from check_con_tbl;
 
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
@@ -440,8 +499,149 @@ test1
 SELECT * FROM instead_of_insert_tbl;
 COMMIT;
 
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+
+COPY test_parallel_copy (a, b, c, d, e) from stdin with (PARALLEL 1);
+1	11	test_c1	test_d1	test_e1
+2	12	test_c2	test_d2	test_e2
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+3	test_d3
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+4	test_d4
+5	test_d5
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1, FORMAT 'csv', HEADER);
+b	d
+\.
+
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0');
+
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri from stdin with (FORMAT csv, DELIMITER ',', PARALLEL 1);
+10
+\.
+
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1) WHERE height > random() * 65;
+60,60,60
+\.
+
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+60
+\.
+
+-- temporary table copy: should peform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+
+COPY temp_test (a) from stdin with (PARALLEL 1);
+10
+\.
+
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) from stdin with (PARALLEL 1);
+
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) from stdin with (PARALLEL 1);
+
+-- missing data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+
+\.
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+2000	230	23	23
+\.
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+2001	231	\N	\N
+\.
+
+-- extra data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+2002	232	40	50	60	70	80
+\.
+
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) from stdin with (delimiter ',', null 'x', PARALLEL 1) ;
+x,45,80,90
+x,\x,\\x,\\\x
+x,\,,\\\,,\\
+\.
+
+COPY test_parallel_copy from stdin WITH (DELIMITER ';', NULL '', PARALLEL 1);
+3000;;c;;
+\.
+
+COPY test_parallel_copy from stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL 1);
+4000:\X:C:\X:\X
+4001:1:empty::
+4002:2:null:\X:\X
+4003:3:Backslash:\\:\\
+4004:4:BackslashX:\\X:\\X
+4005:5:N:\N:\N
+4006:6:BackslashN:\\N:\\N
+4007:7:XX:\XX:\XX
+4008:8:Delimiter:\::\:
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = 50004;
+50003	24	34	44	54
+50004	25	35	45 	55
+50005	26	36	46	56
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a > 60003;
+60001	22	32	42	52
+60002	23	33	43	53
+60003	24	34	44	54
+60004	25	35	45	55
+60005	26	36	46	56
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE f > 60003;
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (SELECT 1 FROM x);
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (generate_series(1,5));
+
+COPY test_parallel_copy from stdin WITH(PARALLEL 1) WHERE a = row_number() over(b);
+
+-- check results of copy in
+SELECT * FROM test_parallel_copy;
+
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
 DROP TABLE x, y;
-- 
1.8.3.1

0006-Parallel-Copy-For-Binary-Format-Files.patchtext/x-patch; charset=US-ASCII; name=0006-Parallel-Copy-For-Binary-Format-Files.patchDownload
From 92156be05e28391d587a08cc11e318bcb8bab1ef Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddy@enterprisedb.com>
Date: Fri, 26 Jun 2020 11:43:48 +0530
Subject: [PATCH 6/6] Parallel Copy For Binary Format Files

Leader reads data from the file into the DSM data blocks each of 64K size.
It also identifies each tuple data block id, start offset, end offset,
tuple size and updates this information in the ring data structure.
Workers parallely read the tuple information from the ring data structure,
the actual tuple data from the data blocks and parallely insert the tuples
into the table.
---
 src/backend/commands/copy.c | 697 +++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 627 insertions(+), 70 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index c7af30b..f1d5539 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -220,6 +220,16 @@ typedef struct ParallelCopyLineBuf
 }ParallelCopyLineBuf;
 
 /*
+ * Tuple boundary information used for parallel copy
+ * for binary format files.
+ */
+typedef struct ParallelCopyTupleInfo
+{
+	uint32 offset;
+	uint32 block_id;
+}ParallelCopyTupleInfo;
+
+/*
  * Parallel copy data information.
  */
 typedef struct ParallelCopyData
@@ -240,6 +250,11 @@ typedef struct ParallelCopyData
 
 	/* Current position in worker_line_buf */
 	uint32				worker_line_buf_pos;
+
+	/*
+	 * For binary formatted files
+	 */
+	ParallelCopyDataBlock *curr_data_block;
 }ParallelCopyData;
 
 /*
@@ -397,6 +412,7 @@ typedef struct ParallelCopyCommonKeyData
 	/* Working state for COPY FROM */
 	AttrNumber          num_defaults;
 	Oid                 relid;
+	bool 				binary;
 }ParallelCopyCommonKeyData;
 
 /*
@@ -697,6 +713,56 @@ if (!IsParallelCopy()) \
 else \
 	return pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
 
+/*
+ * CHECK_FIELD_COUNT - Handles the error cases for field count
+ * for binary format files.
+ */
+#define CHECK_FIELD_COUNT \
+{\
+	if (fld_count == -1) \
+	{ \
+		if (IsParallelCopy() && \
+			!IsLeader()) \
+			return true; \
+		else if (IsParallelCopy() && \
+			IsLeader()) \
+		{ \
+			if (cstate->pcdata->curr_data_block->data[cstate->raw_buf_index + sizeof(fld_count)] != 0) \
+				ereport(ERROR, \
+						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+						errmsg("received copy data after EOF marker"))); \
+			return true; \
+		} \
+		else \
+		{ \
+			/* \
+			* Received EOF marker.  In a V3-protocol copy, wait for the \
+			* protocol-level EOF, and complain if it doesn't come \
+			* immediately.  This ensures that we correctly handle CopyFail, \
+			* if client chooses to send that now. \
+			* \
+			* Note that we MUST NOT try to read more data in an old-protocol \
+			* copy, since there is no protocol-level EOF marker then.  We \
+			* could go either way for copy from file, but choose to throw \
+			* error if there's data after the EOF marker, for consistency \
+			* with the new-protocol case. \
+			*/ \
+			char		dummy; \
+			if (cstate->copy_dest != COPY_OLD_FE && \
+				CopyGetData(cstate, &dummy, 1, 1) > 0) \
+				ereport(ERROR, \
+						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+						errmsg("received copy data after EOF marker"))); \
+				return false; \
+		} \
+	} \
+	if (fld_count != cstate->max_fields) \
+		ereport(ERROR, \
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+				errmsg("row field count is %d, expected %d", \
+				(int) fld_count, cstate->max_fields))); \
+}
+
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
 
@@ -751,6 +817,16 @@ static void PopulateCatalogInformation(CopyState cstate);
 static pg_attribute_always_inline uint32 GetLinePosition(CopyState cstate);
 static pg_attribute_always_inline copy_data_source_cb LookupParallelCopyFnPtr(const char *funcname);
 static pg_attribute_always_inline char* LookupParallelCopyFnStr(copy_data_source_cb fn_addr);
+static uint32 WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info);
+static pg_attribute_always_inline bool CopyReadBinaryTupleLeader(CopyState cstate);
+static pg_attribute_always_inline void CopyReadBinaryAttributeLeader(CopyState cstate,
+										FmgrInfo *flinfo, Oid typioparam, int32 typmod,
+										uint32 *new_block_pos, int m, ParallelCopyTupleInfo *tuple_start_info_ptr,
+										ParallelCopyTupleInfo *tuple_end_info_ptr, uint32 *line_size);
+static pg_attribute_always_inline bool CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls);
+static pg_attribute_always_inline Datum CopyReadBinaryAttributeWorker(CopyState cstate, FmgrInfo *flinfo,
+										  Oid typioparam, int32 typmod, bool *isnull);
+static void AdjustFieldInfo(CopyState cstate, uint8 mode);
 
 /*
  * CopyCommonInfoForWorker - Copy shared_cstate using cstate information.
@@ -769,6 +845,7 @@ CopyCommonInfoForWorker(CopyState cstate, ParallelCopyCommonKeyData *shared_csta
 	shared_cstate->convert_selectively = cstate->convert_selectively;
 	shared_cstate->num_defaults = cstate->num_defaults;
 	shared_cstate->relid = cstate->pcdata->relid;
+	shared_cstate->binary = cstate->binary;
 }
 
 /*
@@ -997,8 +1074,8 @@ FindInsertMethod(CopyState cstate)
 static pg_attribute_always_inline bool
 IsParallelCopyAllowed(CopyState cstate)
 {
-	/* Parallel copy not allowed for frontend (2.0 protocol) & binary option. */
-	if ((cstate->copy_dest == COPY_OLD_FE) || cstate->binary)
+	/* Parallel copy not allowed for frontend (2.0 protocol). */
+	if (cstate->copy_dest == COPY_OLD_FE)
 		return false;
 
 	/* Check if copy is into foreign table or temporary table. */
@@ -1299,6 +1376,7 @@ ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
 	cstate->convert_selectively = shared_cstate->convert_selectively;
 	cstate->num_defaults = shared_cstate->num_defaults;
 	pcdata->relid = shared_cstate->relid;
+	cstate->binary = shared_cstate->binary;
 
 	PopulateGlobalsForCopyFrom(cstate, tup_desc, attnamelist);
 
@@ -1314,7 +1392,7 @@ ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
 	initStringInfo(&cstate->attribute_buf);
 
 	initStringInfo(&cstate->line_buf);
-	for (count = 0; count < WORKER_CHUNK_COUNT;count++)
+	for (count = 0; count < WORKER_CHUNK_COUNT; count++)
 		initStringInfo(&pcdata->worker_line_buf[count].line_buf);
 
 	cstate->line_buf_converted = false;
@@ -1680,32 +1758,66 @@ ParallelCopyLeader(CopyState cstate)
 	/* Execute the before statement triggers from the leader */
 	ExecBeforeStmtTrigger(cstate);
 
-	/* On input just throw the header line away. */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (!cstate->binary)
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
+		/* On input just throw the header line away. */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
 		{
-			pcshared_info->is_read_in_progress = false;
-			return;			/* done */
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+			{
+				pcshared_info->is_read_in_progress = false;
+				return;			/* done */
+			}
 		}
-	}
 
-	for (;;)
-	{
-		bool done;
-		cstate->cur_lineno++;
+		for (;;)
+		{
+			bool done;
+			cstate->cur_lineno++;
 
-		/* Actually read the line into memory here. */
-		done = CopyReadLine(cstate);
+			/* Actually read the line into memory here. */
+			done = CopyReadLine(cstate);
 
-		/*
-		 * EOF at start of line means we're done.  If we see EOF after some
-		 * characters, we act as though it was newline followed by EOF, ie,
-		 * process the line and then exit loop on next iteration.
+			/*
+			* EOF at start of line means we're done.  If we see EOF after some
+			* characters, we act as though it was newline followed by EOF, ie,
+			* process the line and then exit loop on next iteration.
+			*/
+			if (done && cstate->line_buf.len == 0)
+				break;
+		}
+	}
+	else
+	{
+		/* binary format */
+		/* for paralle copy leader, fill in the error
+		 * context inforation here, in case any failures
+		 * while determining tuple offsets, leader
+		 * would throw the errors with proper context.
 		 */
-		if (done && cstate->line_buf.len == 0)
-			break;
+		ErrorContextCallback errcallback;
+		errcallback.callback = CopyFromErrorCallback;
+		errcallback.arg = (void *) cstate;
+		errcallback.previous = error_context_stack;
+		error_context_stack = &errcallback;
+
+		cstate->pcdata->curr_data_block = NULL;
+		cstate->raw_buf_index = 0;
+		pcshared_info->populated = 0;
+		cstate->cur_lineno = 0;
+		cstate->max_fields = list_length(cstate->attnumlist);
+
+		for (;;)
+		{
+			bool eof = false;
+			cstate->cur_lineno++;
+
+			eof = CopyReadBinaryTupleLeader(cstate);
+
+			if (eof)
+				break;
+		}
 	}
 
 	pcshared_info->is_read_in_progress = false;
@@ -1713,7 +1825,463 @@ ParallelCopyLeader(CopyState cstate)
 }
 
 /*
- * GetLinePosition - return the line position that worker should process.
+ * AdjustFieldInfo - gets a new block, updates the
+ * current offset, calculates the skip bytes.
+ * Works in two modes, 1 for field count
+ * 2 for field size
+ */
+static void
+AdjustFieldInfo(CopyState cstate, uint8 mode)
+{
+	ParallelCopyDataBlock *data_block = NULL;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	uint8 movebytes = 0;
+	uint32 block_pos;
+	uint32 prev_block_pos;
+	int readbytes = 0;
+
+	prev_block_pos = pcshared_info->cur_block_pos;
+
+	block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+	movebytes = DATA_BLOCK_SIZE - cstate->raw_buf_index;
+
+	cstate->pcdata->curr_data_block->skip_bytes = movebytes;
+
+	data_block = &pcshared_info->data_blocks[block_pos];
+
+	if (movebytes > 0)
+		memmove(&data_block->data[0], &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index],
+			movebytes);
+
+	elog(DEBUG1, "LEADER - field info is spread across data blocks - moved %d bytes from current block %u to %u block",
+		movebytes, prev_block_pos, block_pos);
+
+	readbytes = CopyGetData(cstate, &data_block->data[movebytes], 1, (DATA_BLOCK_SIZE - movebytes));
+
+	elog(DEBUG1, "LEADER - bytes read from file after field info is moved to next data block %d", readbytes);
+
+	if (cstate->reached_eof)
+		ereport(ERROR,
+			(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				errmsg("unexpected EOF in COPY data")));
+
+	if (mode == 1)
+	{
+		cstate->pcdata->curr_data_block = data_block;
+		cstate->raw_buf_index = 0;
+	}
+	else if(mode == 2)
+	{
+		ParallelCopyDataBlock *prev_data_block = NULL;
+		prev_data_block = cstate->pcdata->curr_data_block;
+		prev_data_block->following_block = block_pos;
+		cstate->pcdata->curr_data_block = data_block;
+
+		if (prev_data_block->curr_blk_completed  == false)
+			prev_data_block->curr_blk_completed = true;
+
+		cstate->raw_buf_index = 0;
+	}
+}
+
+/*
+ * CopyReadBinaryTupleLeader - leader reads data from binary formatted file
+ * to data blocks and identies tuple boundaries/offsets so that workers
+ * can work on the data blocks data.
+ */
+static pg_attribute_always_inline bool
+CopyReadBinaryTupleLeader(CopyState cstate)
+{
+	int readbytes = 0;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	uint32 block_pos;
+	int16		fld_count;
+	ListCell   *cur;
+	FmgrInfo   *in_functions = cstate->in_functions;
+	Oid		   *typioparams = cstate->typioparams;
+	TupleDesc	tupDesc = RelationGetDescr(cstate->rel);
+	uint32      new_block_pos;
+	uint32      line_size = -1;
+	ParallelCopyTupleInfo curr_tuple_start_info;
+	ParallelCopyTupleInfo curr_tuple_end_info;
+
+	curr_tuple_start_info.block_id = -1;
+	curr_tuple_start_info.offset = -1;
+	curr_tuple_end_info.block_id = -1;
+	curr_tuple_end_info.offset = -1;
+
+	if (cstate->pcdata->curr_data_block == NULL)
+	{
+		block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+		cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[block_pos];
+
+		cstate->raw_buf_index = 0;
+
+		readbytes = CopyGetData(cstate, &cstate->pcdata->curr_data_block->data, 1, DATA_BLOCK_SIZE);
+
+		elog(DEBUG1, "LEADER - bytes read from file %d", readbytes);
+
+		if (cstate->reached_eof)
+			return true;
+	}
+
+	if (cstate->raw_buf_index + sizeof(fld_count) >= (DATA_BLOCK_SIZE - 1))
+		AdjustFieldInfo(cstate, 1);
+
+	memcpy(&fld_count, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_count));
+
+	fld_count = (int16) pg_ntoh16(fld_count);
+
+	CHECK_FIELD_COUNT;
+
+	cstate->raw_buf_index = cstate->raw_buf_index + sizeof(fld_count);
+	new_block_pos = pcshared_info->cur_block_pos;
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			attnum = lfirst_int(cur);
+		int			m = attnum - 1;
+		Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+		cstate->cur_attname = NameStr(att->attname);
+
+		CopyReadBinaryAttributeLeader(cstate,
+									&in_functions[m],
+									typioparams[m],
+									att->atttypmod,
+									&new_block_pos,
+									m,
+									&curr_tuple_start_info,
+									&curr_tuple_end_info,
+									&line_size);
+
+		cstate->cur_attname = NULL;
+	}
+
+	if (line_size > 0)
+	{
+		int line_pos = UpdateBlockInLineInfo(cstate,
+											curr_tuple_start_info.block_id,
+											curr_tuple_start_info.offset,
+											line_size,
+											LINE_LEADER_POPULATED);
+
+		pcshared_info->populated++;
+
+		elog(DEBUG1, "LEADER - adding - block:%u, offset:%u, line size:%u line position:%d",
+						 curr_tuple_start_info.block_id,
+						 curr_tuple_start_info.offset,
+						 line_size, line_pos);
+	}
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryAttributeLeader - leader identifies boundaries/offsets
+ * for each attribute/column, it moves on to next data block if the
+ * attribute/column is spread across data blocks.
+ */
+static pg_attribute_always_inline void
+CopyReadBinaryAttributeLeader(CopyState cstate, FmgrInfo *flinfo,
+	Oid typioparam, int32 typmod, uint32 *new_block_pos,
+	int m, ParallelCopyTupleInfo *tuple_start_info_ptr,
+	ParallelCopyTupleInfo *tuple_end_info_ptr, uint32 *line_size)
+{
+	int32		fld_size;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+	if (m == 0)
+	{
+		tuple_start_info_ptr->block_id = pcshared_info->cur_block_pos;
+		/* raw_buf_index would have moved away size of field count bytes
+		   in the caller, so move back to store the tuple start offset.
+		*/
+		tuple_start_info_ptr->offset =  cstate->raw_buf_index - sizeof(int16);
+	}
+
+	if ((cstate->raw_buf_index + sizeof(fld_size)) >= (DATA_BLOCK_SIZE - 1))
+	{
+		AdjustFieldInfo(cstate, 2);
+		*new_block_pos = pcshared_info->cur_block_pos;
+	}
+
+	memcpy(&fld_size, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_size));
+
+	cstate->raw_buf_index = cstate->raw_buf_index + sizeof(fld_size);
+
+	fld_size = (int32) pg_ntoh32(fld_size);
+
+	if (fld_size == 0)
+		ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("unexpected EOF in COPY data")));
+
+	if (fld_size < -1)
+		ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("invalid field size")));
+
+	if ((DATA_BLOCK_SIZE - cstate->raw_buf_index) >= fld_size)
+	{
+		cstate->raw_buf_index = cstate->raw_buf_index + fld_size;
+	}
+	else
+	{
+		ParallelCopyDataBlock *data_block = NULL;
+		ParallelCopyDataBlock *prev_data_block = NULL;
+		uint32 block_pos = *new_block_pos;
+		int readbytes;
+		int32 requiredblocks = 0;
+		int32 remainingbytesincurrdatablock = DATA_BLOCK_SIZE - cstate->raw_buf_index;
+		int i = 0;
+
+		/* field size can spread across multiple data blocks,
+		 * calculate the number of required data blocks and try to get
+		 * those many data blocks.
+		 */
+		requiredblocks = (int32)(fld_size - remainingbytesincurrdatablock)/(int32)DATA_BLOCK_SIZE;
+
+		if ((fld_size - remainingbytesincurrdatablock)%DATA_BLOCK_SIZE != 0)
+			requiredblocks++;
+
+		i = requiredblocks;
+
+		while(i > 0)
+		{
+			data_block = NULL;
+			prev_data_block = NULL;
+			readbytes = 0;
+
+			block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+			data_block = &pcshared_info->data_blocks[block_pos];
+
+			readbytes = CopyGetData(cstate, &data_block->data[0], 1, DATA_BLOCK_SIZE);
+
+			elog(DEBUG1, "LEADER - bytes read from file after detecting that tuple is spread across data blocks %d", readbytes);
+
+			/* eof here means that most probably,
+			 * the field size would have been corrupted.
+			 */
+			if (cstate->reached_eof)
+				ereport(ERROR,
+					(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+					errmsg("unexpected EOF in COPY data")));
+
+			prev_data_block = cstate->pcdata->curr_data_block;
+			prev_data_block->following_block = block_pos;
+
+			if (prev_data_block->curr_blk_completed  == false)
+				prev_data_block->curr_blk_completed = true;
+
+			cstate->pcdata->curr_data_block = data_block;
+
+			i--;
+		}
+
+		cstate->raw_buf_index = fld_size - (((requiredblocks - 1) * DATA_BLOCK_SIZE) +
+									remainingbytesincurrdatablock);
+
+		/* raw_buf_index should never cross data block size,
+		 * as the required number of data blocks would have
+		 * been obtained in the above while loop.
+		 */
+		Assert(cstate->raw_buf_index <= DATA_BLOCK_SIZE);
+
+		*new_block_pos = block_pos;
+	}
+
+	if (m == cstate->max_fields - 1)
+	{
+		tuple_end_info_ptr->block_id = *new_block_pos;
+		tuple_end_info_ptr->offset =  cstate->raw_buf_index - 1;
+
+		if (tuple_start_info_ptr->block_id == tuple_end_info_ptr->block_id)
+		{
+			elog(DEBUG1,"LEADER - tuple lies in a single data block");
+
+			*line_size = tuple_end_info_ptr->offset - tuple_start_info_ptr->offset + 1;
+			pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[tuple_start_info_ptr->block_id].unprocessed_line_parts, 1);
+		}
+		else
+		{
+			uint32 following_block_id = pcshared_info->data_blocks[tuple_start_info_ptr->block_id].following_block;
+
+			elog(DEBUG1,"LEADER - tuple is spread across data blocks");
+
+			*line_size = DATA_BLOCK_SIZE - tuple_start_info_ptr->offset -
+				pcshared_info->data_blocks[tuple_start_info_ptr->block_id].skip_bytes;
+
+			pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[tuple_start_info_ptr->block_id].unprocessed_line_parts, 1);
+
+			while (following_block_id != tuple_end_info_ptr->block_id)
+			{
+				*line_size = *line_size + DATA_BLOCK_SIZE - pcshared_info->data_blocks[following_block_id].skip_bytes;
+
+				pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[following_block_id].unprocessed_line_parts, 1);
+
+				following_block_id = pcshared_info->data_blocks[following_block_id].following_block;
+
+				if (following_block_id == -1)
+					break;
+			}
+
+			if (following_block_id != -1)
+				pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[following_block_id].unprocessed_line_parts, 1);
+
+			*line_size = *line_size + tuple_end_info_ptr->offset + 1;
+		}
+	}
+}
+
+/*
+ * CopyReadBinaryTupleWorker - each worker reads data from data blocks after
+ * getting leader-identified tuple offsets from ring data structure.
+ */
+static pg_attribute_always_inline bool
+CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls)
+{
+	uint32 line_pos;
+	ParallelCopyLineBoundary *line_info;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	int16		fld_count;
+	ListCell   *cur;
+	FmgrInfo   *in_functions = cstate->in_functions;
+	Oid		   *typioparams = cstate->typioparams;
+	TupleDesc	tupDesc = RelationGetDescr(cstate->rel);
+
+	line_pos = GetLinePosition(cstate);
+
+	if (line_pos == -1)
+		return true;
+
+	line_info = &pcshared_info->line_boundaries.ring[line_pos];
+	cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[line_info->first_block];
+	cstate->raw_buf_index = line_info->start_offset;
+
+	if (cstate->raw_buf_index + sizeof(fld_count) >= (DATA_BLOCK_SIZE - 1))
+		/*the case where field count spread across datablocks should never occur.
+		  as the leader would have moved it to next block*/
+		elog(DEBUG1, "WORKER - field count spread across datablocks should never occur");
+
+	memcpy(&fld_count, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_count));
+	fld_count = (int16) pg_ntoh16(fld_count);
+
+	CHECK_FIELD_COUNT;
+
+	cstate->raw_buf_index = cstate->raw_buf_index + sizeof(fld_count);
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			attnum = lfirst_int(cur);
+		int			m = attnum - 1;
+		Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+		cstate->cur_attname = NameStr(att->attname);
+
+		values[m] = CopyReadBinaryAttributeWorker(cstate,
+											&in_functions[m],
+											typioparams[m],
+											att->atttypmod,
+											&nulls[m]);
+		cstate->cur_attname = NULL;
+	}
+
+	pg_atomic_sub_fetch_u32(&cstate->pcdata->curr_data_block->unprocessed_line_parts, 1);
+	line_info->start_offset = -1;
+	pg_atomic_write_u32(&line_info->line_state, LINE_WORKER_PROCESSED);
+	pg_atomic_write_u32(&line_info->line_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryAttributeWorker - leader identifies boundaries/offsets
+ * for each attribute/column, it moves on to next data block if the
+ * attribute/column is spread across data blocks.
+ */
+static pg_attribute_always_inline Datum
+CopyReadBinaryAttributeWorker(CopyState cstate, FmgrInfo *flinfo,
+		Oid typioparam, int32 typmod, bool *isnull)
+{
+	int32		fld_size;
+	Datum		result;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+	if ((cstate->raw_buf_index + sizeof(fld_size)) >= (DATA_BLOCK_SIZE - 1))
+	{
+		ParallelCopyDataBlock *prev_data_block = cstate->pcdata->curr_data_block;
+
+		elog(DEBUG1, "WORKER - field size is spread across data blocks");
+
+		cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[cstate->pcdata->curr_data_block->following_block];
+		pg_atomic_sub_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+		cstate->raw_buf_index = 0;
+	}
+
+	memcpy(&fld_size, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_size));
+	fld_size = (int32) pg_ntoh32(fld_size);
+
+	if (fld_size == 0)
+		ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("unexpected EOF in COPY data")));
+
+	if (fld_size < -1)
+		ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("invalid field size")));
+
+	cstate->raw_buf_index = cstate->raw_buf_index + sizeof(fld_size);
+
+	/* reset attribute_buf to empty, and load raw data in it */
+	resetStringInfo(&cstate->attribute_buf);
+
+	enlargeStringInfo(&cstate->attribute_buf, fld_size);
+
+	if ((DATA_BLOCK_SIZE - cstate->raw_buf_index) >= fld_size)
+	{
+		elog(DEBUG1, "WORKER - tuple lies in single data block");
+
+		memcpy(&cstate->attribute_buf.data[0],&cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], fld_size);
+		cstate->raw_buf_index = cstate->raw_buf_index + fld_size;
+	}
+	else
+	{
+		ParallelCopyDataBlock *prev_data_block = cstate->pcdata->curr_data_block;
+
+		elog(DEBUG1, "WORKER - tuple is spread across data blocks");
+
+		memcpy(&cstate->attribute_buf.data[0], &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index],
+				(DATA_BLOCK_SIZE - cstate->raw_buf_index));
+		cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[cstate->pcdata->curr_data_block->following_block];
+		pg_atomic_sub_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+		memcpy(&cstate->attribute_buf.data[DATA_BLOCK_SIZE - cstate->raw_buf_index],
+			&cstate->pcdata->curr_data_block->data[0], (fld_size - (DATA_BLOCK_SIZE - cstate->raw_buf_index)));
+		cstate->raw_buf_index = fld_size - (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+	}
+
+	cstate->attribute_buf.len = fld_size;
+	cstate->attribute_buf.data[fld_size] = '\0';
+
+	/* Call the column type's binary input converter */
+	result = ReceiveFunctionCall(flinfo, &cstate->attribute_buf,
+								 typioparam, typmod);
+
+	/* Trouble if it didn't eat the whole buffer */
+	if (cstate->attribute_buf.cursor != cstate->attribute_buf.len)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+				 errmsg("incorrect binary data format")));
+
+	*isnull = false;
+	return result;
+}
+
+/*
+ * GetLinePosition - return the line position that worker should pcdata->process.
  */
 static uint32
 GetLinePosition(CopyState cstate)
@@ -1801,7 +2369,9 @@ GetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
 		{
 			dataBlkPtr->curr_blk_completed = false;
 			dataBlkPtr->skip_bytes = 0;
+			dataBlkPtr->following_block = -1;
 			pcshared_info->cur_block_pos = block_pos;
+			MemSet(&dataBlkPtr->data[0], 0, DATA_BLOCK_SIZE);
 			return block_pos;
 		}
 
@@ -5480,60 +6050,47 @@ NextCopyFrom(CopyState cstate, ExprContext *econtext,
 	else
 	{
 		/* binary */
-		int16		fld_count;
-		ListCell   *cur;
-
-		cstate->cur_lineno++;
-
-		if (!CopyGetInt16(cstate, &fld_count))
+		if (!IsParallelCopy())
 		{
-			/* EOF detected (end of file, or protocol-level EOF) */
-			return false;
-		}
+			int16		fld_count;
+			ListCell   *cur;
 
-		if (fld_count == -1)
-		{
-			/*
-			 * Received EOF marker.  In a V3-protocol copy, wait for the
-			 * protocol-level EOF, and complain if it doesn't come
-			 * immediately.  This ensures that we correctly handle CopyFail,
-			 * if client chooses to send that now.
-			 *
-			 * Note that we MUST NOT try to read more data in an old-protocol
-			 * copy, since there is no protocol-level EOF marker then.  We
-			 * could go either way for copy from file, but choose to throw
-			 * error if there's data after the EOF marker, for consistency
-			 * with the new-protocol case.
-			 */
-			char		dummy;
+			cstate->cur_lineno++;
+			cstate->max_fields = list_length(cstate->attnumlist);
 
-			if (cstate->copy_dest != COPY_OLD_FE &&
-				CopyGetData(cstate, &dummy, 1, 1) > 0)
-				ereport(ERROR,
-						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-						 errmsg("received copy data after EOF marker")));
-			return false;
-		}
+			if (!CopyGetInt16(cstate, &fld_count))
+			{
+				/* EOF detected (end of file, or protocol-level EOF) */
+				return false;
+			}
 
-		if (fld_count != attr_count)
-			ereport(ERROR,
-					(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-					 errmsg("row field count is %d, expected %d",
-							(int) fld_count, attr_count)));
+			CHECK_FIELD_COUNT;
 
-		foreach(cur, cstate->attnumlist)
+			foreach(cur, cstate->attnumlist)
+			{
+				int			attnum = lfirst_int(cur);
+				int			m = attnum - 1;
+				Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+
+				cstate->cur_attname = NameStr(att->attname);
+				values[m] = CopyReadBinaryAttribute(cstate,
+													&in_functions[m],
+													typioparams[m],
+													att->atttypmod,
+													&nulls[m]);
+				cstate->cur_attname = NULL;
+			}
+		}
+		else
 		{
-			int			attnum = lfirst_int(cur);
-			int			m = attnum - 1;
-			Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+			bool eof = false;
+			cstate->cur_lineno++;
+			cstate->max_fields = list_length(cstate->attnumlist);
 
-			cstate->cur_attname = NameStr(att->attname);
-			values[m] = CopyReadBinaryAttribute(cstate,
-												&in_functions[m],
-												typioparams[m],
-												att->atttypmod,
-												&nulls[m]);
-			cstate->cur_attname = NULL;
+			eof = CopyReadBinaryTupleWorker(cstate, values, nulls);
+
+			if (eof)
+				return false;
 		}
 	}
 
-- 
1.8.3.1

#107vignesh C
vignesh21@gmail.com
In reply to: vignesh C (#106)
6 attachment(s)
Re: Parallel copy

On Wed, Jul 1, 2020 at 2:46 PM vignesh C <vignesh21@gmail.com> wrote:

Hi,

I have made few changes in 0003 & 0005 patch, there were a couple of
bugs in 0003 patch & some random test failures in 0005 patch.
Attached new patches which include the fixes for the same.

I have made changes in 0003 patch, to remove changes made in pqmq.c for
parallel worker error handling hang issue. This is being discussed in email
[1]: /messages/by-id/CALDaNm1d1hHPZUg3xU4XjtWBOLCrA+-2cJcLpw-cePZ=GgDVfA@mail.gmail.com
changes.

[1]: /messages/by-id/CALDaNm1d1hHPZUg3xU4XjtWBOLCrA+-2cJcLpw-cePZ=GgDVfA@mail.gmail.com
/messages/by-id/CALDaNm1d1hHPZUg3xU4XjtWBOLCrA+-2cJcLpw-cePZ=GgDVfA@mail.gmail.com

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

Attachments:

0001-Copy-code-readjustment-to-support-parallel-copy.patchapplication/x-patch; name=0001-Copy-code-readjustment-to-support-parallel-copy.patchDownload
From fe65142a5d461cf457ea87abdd62ab88feb62bea Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Tue, 23 Jun 2020 06:49:22 +0530
Subject: [PATCH 1/6] Copy code readjustment to support parallel copy.

This patch has the copy code slightly readjusted so that the common code is
separated to functions/macros, these functions/macros will be used by the
workers in the parallel copy code of the upcoming patches. EOL removal is moved
from CopyReadLine to CopyReadLineText, this change was required because in case
of parallel copy the record identification and record updation is done in
CopyReadLineText, before record information is updated in shared memory the new
line characters should be removed.
---
 src/backend/commands/copy.c | 372 ++++++++++++++++++++++++++------------------
 1 file changed, 221 insertions(+), 151 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 3e199bd..33ee891 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -95,6 +95,9 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
+#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+#define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
+
 /*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
@@ -219,7 +222,6 @@ typedef struct CopyStateData
 	 * converts it.  Note: we guarantee that there is a \0 at
 	 * raw_buf[raw_buf_len].
 	 */
-#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
@@ -347,6 +349,88 @@ if (1) \
 	goto not_end_of_copy; \
 } else ((void) 0)
 
+/*
+ * CONVERT_TO_SERVER_ENCODING - convert contents to server encoding.
+ */
+#define CONVERT_TO_SERVER_ENCODING(cstate) \
+{ \
+	/* Done reading the line.  Convert it to server encoding. */ \
+	if (cstate->need_transcoding) \
+	{ \
+		char	   *cvt; \
+		cvt = pg_any_to_server(cstate->line_buf.data, \
+							   cstate->line_buf.len, \
+							   cstate->file_encoding); \
+		if (cvt != cstate->line_buf.data) \
+		{ \
+			/* transfer converted data back to line_buf */ \
+			resetStringInfo(&cstate->line_buf); \
+			appendBinaryStringInfo(&cstate->line_buf, cvt, strlen(cvt)); \
+			pfree(cvt); \
+		} \
+	} \
+	/* Now it's safe to use the buffer in error messages */ \
+	cstate->line_buf_converted = true; \
+}
+
+/*
+ * CLEAR_EOL_FROM_COPIED_DATA - Clear EOL from the copied data.
+ */
+#define CLEAR_EOL_FROM_COPIED_DATA(copy_line_data, copy_line_pos, copy_line_size) \
+{ \
+	/* \
+	 * If we didn't hit EOF, then we must have transferred the EOL marker \
+	 * to line_buf along with the data.  Get rid of it. \
+	 */ \
+   switch (cstate->eol_type) \
+   { \
+	   case EOL_NL: \
+		   Assert(copy_line_size >= 1); \
+		   Assert(copy_line_data[copy_line_pos - 1] == '\n'); \
+		   copy_line_data[copy_line_pos - 1] = '\0'; \
+		   copy_line_size--; \
+		   break; \
+	   case EOL_CR: \
+		   Assert(copy_line_size >= 1); \
+		   Assert(copy_line_data[copy_line_pos - 1] == '\r'); \
+		   copy_line_data[copy_line_pos - 1] = '\0'; \
+		   copy_line_size--; \
+		   break; \
+	   case EOL_CRNL: \
+		   Assert(copy_line_size >= 2); \
+		   Assert(copy_line_data[copy_line_pos - 2] == '\r'); \
+		   Assert(copy_line_data[copy_line_pos - 1] == '\n'); \
+		   copy_line_data[copy_line_pos - 2] = '\0'; \
+		   copy_line_size -= 2; \
+		   break; \
+	   case EOL_UNKNOWN: \
+		   /* shouldn't get here */ \
+		   Assert(false); \
+		   break; \
+   } \
+}
+
+/*
+ * CLEAR_EOL_LINE - Wrapper for clearing EOL.
+ */
+#define CLEAR_EOL_LINE() \
+if (!result && !IsHeaderLine()) \
+	CLEAR_EOL_FROM_COPIED_DATA(cstate->line_buf.data, \
+								cstate->line_buf.len, \
+								cstate->line_buf.len) \
+
+/*
+ * INCREMENTPROCESSED - Increment the lines processed.
+ */
+#define INCREMENTPROCESSED(processed)  \
+processed++;
+
+/*
+ * GETPROCESSED - Get the lines processed.
+ */
+#define GETPROCESSED(processed) \
+return processed;
+
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
 
@@ -392,6 +476,8 @@ static bool CopyGetInt32(CopyState cstate, int32 *val);
 static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 
+static void PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tup_desc,
+							   List *attnamelist);
 
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
@@ -793,6 +879,7 @@ CopyLoadRawBuf(CopyState cstate)
 {
 	int			nbytes;
 	int			inbytes;
+	int         minread = 1;
 
 	if (cstate->raw_buf_index < cstate->raw_buf_len)
 	{
@@ -804,8 +891,11 @@ CopyLoadRawBuf(CopyState cstate)
 	else
 		nbytes = 0;				/* no data need be saved */
 
+	if (cstate->copy_dest == COPY_NEW_FE)
+		minread = RAW_BUF_SIZE - nbytes;
+
 	inbytes = CopyGetData(cstate, cstate->raw_buf + nbytes,
-						  1, RAW_BUF_SIZE - nbytes);
+						  minread, RAW_BUF_SIZE - nbytes);
 	nbytes += inbytes;
 	cstate->raw_buf[nbytes] = '\0';
 	cstate->raw_buf_index = 0;
@@ -1463,7 +1553,6 @@ BeginCopy(ParseState *pstate,
 {
 	CopyState	cstate;
 	TupleDesc	tupDesc;
-	int			num_phys_attrs;
 	MemoryContext oldcontext;
 
 	/* Allocate workspace and zero all fields */
@@ -1629,6 +1718,24 @@ BeginCopy(ParseState *pstate,
 		tupDesc = cstate->queryDesc->tupDesc;
 	}
 
+	PopulateGlobalsForCopyFrom(cstate, tupDesc, attnamelist);
+	cstate->copy_dest = COPY_FILE;	/* default */
+
+	MemoryContextSwitchTo(oldcontext);
+
+	return cstate;
+}
+
+/*
+ * PopulateGlobalsForCopyFrom - Populates the common variables required for copy
+ * from operation. This is a helper function for BeginCopy function.
+ */
+static void
+PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tupDesc,
+							List *attnamelist)
+{
+	int			num_phys_attrs;
+
 	/* Generate or convert list of attributes to process */
 	cstate->attnumlist = CopyGetAttnums(tupDesc, cstate->rel, attnamelist);
 
@@ -1748,12 +1855,6 @@ BeginCopy(ParseState *pstate,
 		 pg_database_encoding_max_length() > 1);
 	/* See Multibyte encoding comment above */
 	cstate->encoding_embeds_ascii = PG_ENCODING_IS_CLIENT_ONLY(cstate->file_encoding);
-
-	cstate->copy_dest = COPY_FILE;	/* default */
-
-	MemoryContextSwitchTo(oldcontext);
-
-	return cstate;
 }
 
 /*
@@ -2642,32 +2743,11 @@ CopyMultiInsertInfoStore(CopyMultiInsertInfo *miinfo, ResultRelInfo *rri,
 }
 
 /*
- * Copy FROM file to relation.
+ * Check if the relation specified in copy from is valid.
  */
-uint64
-CopyFrom(CopyState cstate)
+static void
+CheckTargetRelValidity(CopyState cstate)
 {
-	ResultRelInfo *resultRelInfo;
-	ResultRelInfo *target_resultRelInfo;
-	ResultRelInfo *prevResultRelInfo = NULL;
-	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
-	ModifyTableState *mtstate;
-	ExprContext *econtext;
-	TupleTableSlot *singleslot = NULL;
-	MemoryContext oldcontext = CurrentMemoryContext;
-
-	PartitionTupleRouting *proute = NULL;
-	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
-	int			ti_options = 0; /* start with default options for insert */
-	BulkInsertState bistate = NULL;
-	CopyInsertMethod insertMethod;
-	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
-	uint64		processed = 0;
-	bool		has_before_insert_row_trig;
-	bool		has_instead_insert_row_trig;
-	bool		leafpart_use_multi_insert = false;
-
 	Assert(cstate->rel);
 
 	/*
@@ -2704,27 +2784,6 @@ CopyFrom(CopyState cstate)
 							RelationGetRelationName(cstate->rel))));
 	}
 
-	/*
-	 * If the target file is new-in-transaction, we assume that checking FSM
-	 * for free space is a waste of time.  This could possibly be wrong, but
-	 * it's unlikely.
-	 */
-	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
-		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
-		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
-		ti_options |= TABLE_INSERT_SKIP_FSM;
-
-	/*
-	 * Optimize if new relfilenode was created in this subxact or one of its
-	 * committed children and we won't see those rows later as part of an
-	 * earlier scan or command. The subxact test ensures that if this subxact
-	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
-	 * that the stronger test of exactly which subtransaction created it is
-	 * crucial for correctness of this optimization. The test for an earlier
-	 * scan or command tolerates false negatives. FREEZE causes other sessions
-	 * to see rows they would not see under MVCC, and a false negative merely
-	 * spreads that anomaly to the current session.
-	 */
 	if (cstate->freeze)
 	{
 		/*
@@ -2762,9 +2821,61 @@ CopyFrom(CopyState cstate)
 			ereport(ERROR,
 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 					 errmsg("cannot perform COPY FREEZE because the table was not created or truncated in the current subtransaction")));
+	}
+}
+
+/*
+ * Copy FROM file to relation.
+ */
+uint64
+CopyFrom(CopyState cstate)
+{
+	ResultRelInfo *resultRelInfo;
+	ResultRelInfo *target_resultRelInfo;
+	ResultRelInfo *prevResultRelInfo = NULL;
+	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
+	ModifyTableState *mtstate;
+	ExprContext *econtext;
+	TupleTableSlot *singleslot = NULL;
+	MemoryContext oldcontext = CurrentMemoryContext;
+
+	PartitionTupleRouting *proute = NULL;
+	ErrorContextCallback errcallback;
+	CommandId	mycid = GetCurrentCommandId(true);
+	int			ti_options = 0; /* start with default options for insert */
+	BulkInsertState bistate = NULL;
+	CopyInsertMethod insertMethod;
+	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
+	uint64		processed = 0;
+	bool		has_before_insert_row_trig;
+	bool		has_instead_insert_row_trig;
+	bool		leafpart_use_multi_insert = false;
+
+	CheckTargetRelValidity(cstate);
 
+	/*
+	 * If the target file is new-in-transaction, we assume that checking FSM
+	 * for free space is a waste of time.  This could possibly be wrong, but
+	 * it's unlikely.
+	 */
+	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
+		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
+		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
+		ti_options |= TABLE_INSERT_SKIP_FSM;
+
+	/*
+	 * Optimize if new relfilenode was created in this subxact or one of its
+	 * committed children and we won't see those rows later as part of an
+	 * earlier scan or command. The subxact test ensures that if this subxact
+	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
+	 * that the stronger test of exactly which subtransaction created it is
+	 * crucial for correctness of this optimization. The test for an earlier
+	 * scan or command tolerates false negatives. FREEZE causes other sessions
+	 * to see rows they would not see under MVCC, and a false negative merely
+	 * spreads that anomaly to the current session.
+	 */
+	if (cstate->freeze)
 		ti_options |= TABLE_INSERT_FROZEN;
-	}
 
 	/*
 	 * We need a ResultRelInfo so we can use the regular executor's
@@ -3257,7 +3368,7 @@ CopyFrom(CopyState cstate)
 			 * or FDW; this is the same definition used by nodeModifyTable.c
 			 * for counting tuples inserted by an INSERT command.
 			 */
-			processed++;
+			INCREMENTPROCESSED(processed)
 		}
 	}
 
@@ -3312,30 +3423,15 @@ CopyFrom(CopyState cstate)
 
 	FreeExecutorState(estate);
 
-	return processed;
+	GETPROCESSED(processed)
 }
 
 /*
- * Setup to read tuples from a file for COPY FROM.
- *
- * 'rel': Used as a template for the tuples
- * 'filename': Name of server-local file to read
- * 'attnamelist': List of char *, columns to include. NIL selects all cols.
- * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
- *
- * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ * PopulateCatalogInformation - populate the catalog information.
  */
-CopyState
-BeginCopyFrom(ParseState *pstate,
-			  Relation rel,
-			  const char *filename,
-			  bool is_program,
-			  copy_data_source_cb data_source_cb,
-			  List *attnamelist,
-			  List *options)
+static void
+PopulateCatalogInformation(CopyState cstate)
 {
-	CopyState	cstate;
-	bool		pipe = (filename == NULL);
 	TupleDesc	tupDesc;
 	AttrNumber	num_phys_attrs,
 				num_defaults;
@@ -3345,31 +3441,8 @@ BeginCopyFrom(ParseState *pstate,
 	Oid			in_func_oid;
 	int		   *defmap;
 	ExprState **defexprs;
-	MemoryContext oldcontext;
 	bool		volatile_defexprs;
 
-	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
-	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
-
-	/* Initialize state variables */
-	cstate->reached_eof = false;
-	cstate->eol_type = EOL_UNKNOWN;
-	cstate->cur_relname = RelationGetRelationName(cstate->rel);
-	cstate->cur_lineno = 0;
-	cstate->cur_attname = NULL;
-	cstate->cur_attval = NULL;
-
-	/* Set up variables to avoid per-attribute overhead. */
-	initStringInfo(&cstate->attribute_buf);
-	initStringInfo(&cstate->line_buf);
-	cstate->line_buf_converted = false;
-	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
-	cstate->raw_buf_index = cstate->raw_buf_len = 0;
-
-	/* Assign range table, we'll need it in CopyFrom. */
-	if (pstate)
-		cstate->range_table = pstate->p_rtable;
-
 	tupDesc = RelationGetDescr(cstate->rel);
 	num_phys_attrs = tupDesc->natts;
 	num_defaults = 0;
@@ -3447,6 +3520,54 @@ BeginCopyFrom(ParseState *pstate,
 	cstate->defexprs = defexprs;
 	cstate->volatile_defexprs = volatile_defexprs;
 	cstate->num_defaults = num_defaults;
+}
+
+/*
+ * Setup to read tuples from a file for COPY FROM.
+ *
+ * 'rel': Used as a template for the tuples
+ * 'filename': Name of server-local file to read
+ * 'attnamelist': List of char *, columns to include. NIL selects all cols.
+ * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
+ *
+ * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ */
+CopyState
+BeginCopyFrom(ParseState *pstate,
+			  Relation rel,
+			  const char *filename,
+			  bool is_program,
+			  copy_data_source_cb data_source_cb,
+			  List *attnamelist,
+			  List *options)
+{
+	CopyState	cstate;
+	bool		pipe = (filename == NULL);
+	MemoryContext oldcontext;
+
+	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	/* Initialize state variables */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/* Set up variables to avoid per-attribute overhead. */
+	initStringInfo(&cstate->attribute_buf);
+	initStringInfo(&cstate->line_buf);
+	cstate->line_buf_converted = false;
+	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+
+	/* Assign range table, we'll need it in CopyFrom. */
+	if (pstate)
+		cstate->range_table = pstate->p_rtable;
+
+	PopulateCatalogInformation(cstate);
 	cstate->is_program = is_program;
 
 	if (data_source_cb)
@@ -3856,60 +3977,8 @@ CopyReadLine(CopyState cstate)
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
-	else
-	{
-		/*
-		 * If we didn't hit EOF, then we must have transferred the EOL marker
-		 * to line_buf along with the data.  Get rid of it.
-		 */
-		switch (cstate->eol_type)
-		{
-			case EOL_NL:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CR:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\r');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CRNL:
-				Assert(cstate->line_buf.len >= 2);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 2] == '\r');
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len -= 2;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_UNKNOWN:
-				/* shouldn't get here */
-				Assert(false);
-				break;
-		}
-	}
-
-	/* Done reading the line.  Convert it to server encoding. */
-	if (cstate->need_transcoding)
-	{
-		char	   *cvt;
-
-		cvt = pg_any_to_server(cstate->line_buf.data,
-							   cstate->line_buf.len,
-							   cstate->file_encoding);
-		if (cvt != cstate->line_buf.data)
-		{
-			/* transfer converted data back to line_buf */
-			resetStringInfo(&cstate->line_buf);
-			appendBinaryStringInfo(&cstate->line_buf, cvt, strlen(cvt));
-			pfree(cvt);
-		}
-	}
-
-	/* Now it's safe to use the buffer in error messages */
-	cstate->line_buf_converted = true;
 
+	CONVERT_TO_SERVER_ENCODING(cstate)
 	return result;
 }
 
@@ -4273,6 +4342,7 @@ not_end_of_copy:
 	 * Transfer any still-uncopied data to line_buf.
 	 */
 	REFILL_LINEBUF;
+	CLEAR_EOL_LINE()
 
 	return result;
 }
-- 
1.8.3.1

0002-Framework-for-leader-worker-in-parallel-copy.patchapplication/x-patch; name=0002-Framework-for-leader-worker-in-parallel-copy.patchDownload
From f852a2d53aa2107b90899df9b8c07824b131e498 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>, Bharath <bharath.rupireddyforpostgres@gmail.com>
Date: Wed, 24 Jun 2020 13:51:56 +0530
Subject: [PATCH 2/6] Framework for leader/worker in parallel copy

This patch has the framework for data structures in parallel copy, leader
initialization, worker initialization, shared memory updation, starting workers,
wait for workers and workers exiting.
---
 src/backend/access/transam/parallel.c       |   4 +
 src/backend/commands/copy.c                 | 865 +++++++++++++++++++++++++++-
 src/backend/replication/logical/tablesync.c |   2 +-
 src/include/commands/copy.h                 |   4 +
 src/tools/pgindent/typedefs.list            |   8 +
 5 files changed, 878 insertions(+), 5 deletions(-)

diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index 14a8690..09e7a19 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -25,6 +25,7 @@
 #include "catalog/pg_enum.h"
 #include "catalog/storage.h"
 #include "commands/async.h"
+#include "commands/copy.h"
 #include "executor/execParallel.h"
 #include "libpq/libpq.h"
 #include "libpq/pqformat.h"
@@ -145,6 +146,9 @@ static const struct
 	},
 	{
 		"parallel_vacuum_main", parallel_vacuum_main
+	},
+	{
+		"ParallelCopyMain", ParallelCopyMain
 	}
 };
 
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 33ee891..0a4d997 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -96,9 +96,138 @@ typedef enum CopyInsertMethod
 } CopyInsertMethod;
 
 #define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+
+#define DATA_BLOCK_SIZE RAW_BUF_SIZE
+#define RINGSIZE (10 * 1000)
+#define MAX_BLOCKS_COUNT 1000
+#define WORKER_CHUNK_COUNT 50	/* should be mod of RINGSIZE */
+
+#define	IsParallelCopy()		(cstate->is_parallel)
+#define IsLeader()				(cstate->pcdata->is_leader)
 #define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
 
 /*
+ * Copy data block information.
+ */
+typedef struct ParallelCopyDataBlock
+{
+	/* The number of unprocessed lines in the current block. */
+	pg_atomic_uint32 unprocessed_line_parts;
+
+	/*
+	 * If the current line data is continued into another block, following_block
+	 * will have the position where the remaining data need to be read.
+	 */
+	uint32	following_block;
+
+	/*
+	 * This flag will be set, when the leader finds out this block can be read
+	 * safely by the worker. This helps the worker to start processing the line
+	 * early where the line will be spread across many blocks and the worker
+	 * need not wait for the complete line to be processed.
+	 */
+	bool   curr_blk_completed;
+	char   data[DATA_BLOCK_SIZE]; /* data read from file */
+	uint8  skip_bytes;
+}ParallelCopyDataBlock;
+
+/*
+ * Individual line information.
+ * ParallelCopyLineBoundary is common data structure between leader & worker,
+ * this is protected by the following sequence in the leader & worker.
+ * Leader should operate in the following order:
+ * 1) update first_block, start_offset & cur_lineno in any order.
+ * 2) update line_size.
+ * 3) update line_state.
+ * Worker should operate in the following order:
+ * 1) read line_size.
+ * 2) only one worker should choose one line for processing, this is handled by
+ *    using pg_atomic_compare_exchange_u32, worker will change the sate to
+ *    LINE_WORKER_PROCESSING only if line_state is LINE_LEADER_POPULATED.
+ * 3) read first_block, start_offset & cur_lineno in any order.
+ */
+typedef struct ParallelCopyLineBoundary
+{
+	/* Position of the first block in data_blocks array. */
+	uint32				first_block;
+	uint32				start_offset;   /* start offset of the line */
+
+	/*
+	 * Size of the current line -1 means line is yet to be filled completely,
+	 * 0 means empty line, >0 means line filled with line size data.
+	 */
+	pg_atomic_uint32	line_size;
+	pg_atomic_uint32	line_state;		/* line state */
+	uint64				cur_lineno;		/* line number for error messages */
+}ParallelCopyLineBoundary;
+
+/*
+ * Circular queue used to store the line information.
+ */
+typedef struct ParallelCopyLineBoundaries
+{
+	/* Position for the leader to populate a line. */
+	uint32			leader_pos;
+
+	/* Data read from the file/stdin by the leader process. */
+	ParallelCopyLineBoundary	ring[RINGSIZE];
+}ParallelCopyLineBoundaries;
+
+/*
+ * Shared information among parallel copy workers. This will be allocated in the
+ * DSM segment.
+ */
+typedef struct ParallelCopyShmInfo
+{
+	bool					is_read_in_progress; /* file read status */
+
+	/*
+	 * Actual lines inserted by worker (some records will be filtered based on
+	 * where condition).
+	 */
+	pg_atomic_uint64			processed;
+	pg_atomic_uint64			total_worker_processed; /* total processed records by the workers */
+	uint64						populated; /* lines populated by leader */
+	uint32						cur_block_pos; /* current data block */
+	ParallelCopyDataBlock		data_blocks[MAX_BLOCKS_COUNT]; /* data block array */
+	FullTransactionId			full_transaction_id; /* xid for copy from statement */
+	CommandId					mycid;	/* command id */
+	ParallelCopyLineBoundaries	line_boundaries; /* line array */
+} ParallelCopyShmInfo;
+
+/*
+ * Parallel copy line buffer information.
+ */
+typedef struct ParallelCopyLineBuf
+{
+	StringInfoData		line_buf;
+	uint64				cur_lineno;	/* line number for error messages */
+}ParallelCopyLineBuf;
+
+/*
+ * Parallel copy data information.
+ */
+typedef struct ParallelCopyData
+{
+	Oid					relid;				/* relation id of the table */
+	ParallelCopyShmInfo	*pcshared_info;		/* common info in shared memory */
+	bool				is_leader;
+
+	/* line position which worker is processing */
+	uint32				worker_processed_pos;
+
+	/*
+	 * Local line_buf array, workers will copy it here and release the lines
+	 * for the leader to continue.
+	 */
+	ParallelCopyLineBuf	worker_line_buf[WORKER_CHUNK_COUNT];
+	uint32				worker_line_buf_count; /* Number of lines */
+
+	/* Current position in worker_line_buf */
+	uint32				worker_line_buf_pos;
+}ParallelCopyData;
+
+/*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
  * even though some fields are used in only some cases.
@@ -225,8 +354,66 @@ typedef struct CopyStateData
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
+	int			nworkers;
+	bool		is_parallel;
+	ParallelCopyData *pcdata;
 } CopyStateData;
 
+/*
+ * This structure helps in storing the common data from CopyStateData that are
+ * required by the workers. This information will then be allocated and stored
+ * into the DSM for the worker to retrieve and copy it to CopyStateData.
+ */
+typedef struct ParallelCopyCommonKeyData
+{
+	/* low-level state data */
+	CopyDest            copy_dest;		/* type of copy source/destination */
+	int                 file_encoding;	/* file or remote side's character encoding */
+	bool                need_transcoding;	/* file encoding diff from server? */
+	bool                encoding_embeds_ascii;	/* ASCII can be non-first byte? */
+
+	/* parameters from the COPY command */
+	bool                csv_mode;		/* Comma Separated Value format? */
+	bool                header_line;	/* CSV header line? */
+	int                 null_print_len; /* length of same */
+	bool                force_quote_all;	/* FORCE_QUOTE *? */
+	bool                convert_selectively;	/* do selective binary conversion? */
+
+	/* Working state for COPY FROM */
+	AttrNumber          num_defaults;
+	Oid                 relid;
+}ParallelCopyCommonKeyData;
+
+/*
+ * This structure will help in converting a List data type into the below
+ * structure format with the count having the number of elements in the list and
+ * the info having the List elements appended contigously. This converted
+ * structure will be allocated in shared memory and stored in DSM for the worker
+ * to retrieve and later convert it back to List data type.
+ */
+typedef struct ParallelCopyKeyListInfo
+{
+	int	count;		/* count of attributes */
+
+	/* string info in the form info followed by info1, info2... infon  */
+	char    info[1];
+} ParallelCopyKeyListInfo;
+
+/*
+ * List of internal parallel copy function pointers.
+ */
+static const struct
+{
+	char *fn_name;
+	copy_data_source_cb fn_addr;
+}			InternalParallelCopyFuncPtrs[] =
+
+{
+	{
+		"copy_read_data", copy_read_data
+	},
+};
+
 /* DestReceiver for COPY (query) TO */
 typedef struct
 {
@@ -256,6 +443,23 @@ typedef struct
 /* Trim the list of buffers back down to this number after flushing */
 #define MAX_PARTITION_BUFFERS	32
 
+/* DSM keys for parallel copy.  */
+#define PARALLEL_COPY_KEY_SHARED_INFO		    1
+#define PARALLEL_COPY_KEY_CSTATE				2
+#define PARALLEL_COPY_KEY_NULL_PRINT			3
+#define PARALLEL_COPY_KEY_NULL_PRINT_CLIENT		4
+#define PARALLEL_COPY_KEY_DELIM					5
+#define PARALLEL_COPY_KEY_QUOTE					6
+#define PARALLEL_COPY_KEY_ESCAPE				7
+#define PARALLEL_COPY_KEY_ATTNAME_LIST			8
+#define PARALLEL_COPY_KEY_FORCE_QUOTE_LIST  	9
+#define PARALLEL_COPY_KEY_NOT_NULL_LIST		   10
+#define PARALLEL_COPY_KEY_NULL_LIST			   11
+#define PARALLEL_COPY_KEY_CONVERT_LIST		   12
+#define PARALLEL_COPY_KEY_DATASOURCE_CB		   13
+#define PARALLEL_COPY_KEY_WHERE_CLAUSE_STR     14
+#define PARALLEL_COPY_KEY_RANGE_TABLE		   15
+
 /* Stores multi-insert data related to a single relation in CopyFrom. */
 typedef struct CopyMultiInsertBuffer
 {
@@ -476,10 +680,596 @@ static bool CopyGetInt32(CopyState cstate, int32 *val);
 static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 
+static pg_attribute_always_inline void EndParallelCopy(ParallelContext *pcxt);
 static void PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tup_desc,
 							   List *attnamelist);
+static pg_attribute_always_inline copy_data_source_cb LookupParallelCopyFnPtr(const char *funcname);
+static pg_attribute_always_inline char* LookupParallelCopyFnStr(copy_data_source_cb fn_addr);
+
+/*
+ * CopyCommonInfoForWorker - Copy shared_cstate using cstate information.
+ */
+static pg_attribute_always_inline void
+CopyCommonInfoForWorker(CopyState cstate, ParallelCopyCommonKeyData *shared_cstate)
+{
+	shared_cstate->copy_dest = cstate->copy_dest;
+	shared_cstate->file_encoding = cstate->file_encoding;
+	shared_cstate->need_transcoding = cstate->need_transcoding;
+	shared_cstate->encoding_embeds_ascii = cstate->encoding_embeds_ascii;
+	shared_cstate->csv_mode = cstate->csv_mode;
+	shared_cstate->header_line = cstate->header_line;
+	shared_cstate->null_print_len = cstate->null_print_len;
+	shared_cstate->force_quote_all = cstate->force_quote_all;
+	shared_cstate->convert_selectively = cstate->convert_selectively;
+	shared_cstate->num_defaults = cstate->num_defaults;
+	shared_cstate->relid = cstate->pcdata->relid;
+}
+
+/*
+ * RetrieveSharedString - Retrieve the string from shared memory.
+ */
+static void
+RetrieveSharedString(shm_toc *toc, int sharedkey, char **copystr)
+{
+	char *shared_str_val = (char *)shm_toc_lookup(toc, sharedkey, true);
+	if (shared_str_val)
+		*copystr = pstrdup(shared_str_val);
+}
+
+/*
+ * RetrieveSharedList - Retrieve the list from shared memory.
+ */
+static void
+RetrieveSharedList(shm_toc *toc, int sharedkey, List **copylist)
+{
+	ParallelCopyKeyListInfo *listinformation = (ParallelCopyKeyListInfo *)shm_toc_lookup(toc, sharedkey,
+														   true);
+	if (listinformation)
+	{
+		int	length  = 0;
+		int count;
+
+		for (count = 0; count < listinformation->count; count++)
+		{
+			char *attname = (char *)(listinformation->info + length);
+			length += strlen(attname) + 1;
+			*copylist = lappend(*copylist, makeString(attname));
+		}
+	}
+}
+
+/*
+ * CopyListSharedMemory - Copy the list into shared memory.
+ */
+static void
+CopyListSharedMemory(List *inputlist, Size memsize, ParallelCopyKeyListInfo *sharedlistinfo)
+{
+	ListCell   *l;
+	int			length  = 0;
+
+	MemSet(sharedlistinfo, 0, memsize);
+	foreach(l, inputlist)
+	{
+		char	   *name = strVal(lfirst(l));
+		memcpy((char *)(sharedlistinfo->info + length), name, strlen(name));
+		sharedlistinfo->count++;
+		length += strlen(name) + 1;
+	}
+}
+
+/*
+ * ComputeListSize - compute the list size.
+ */
+static int
+ComputeListSize(List *inputlist)
+{
+	int est_size = sizeof(int);
+	if (inputlist != NIL)
+	{
+		ListCell   *l;
+		foreach(l, inputlist)
+			est_size += strlen(strVal(lfirst(l))) + 1;
+	}
+
+	return est_size;
+}
+
+/*
+ * EstimateLineKeysStr - Estimate the size required in shared memory for the
+ * input string.
+ */
+static void
+EstimateLineKeysStr(ParallelContext *pcxt, char *inputstr)
+{
+	if (inputstr)
+	{
+		shm_toc_estimate_chunk(&pcxt->estimator, strlen(inputstr) + 1);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+}
+
+/*
+ * EstimateLineKeysList - Estimate the size required in shared memory for the
+ * input list.
+ */
+static void
+EstimateLineKeysList(ParallelContext *pcxt, List *inputlist,
+		Size *est_list_size)
+{
+	if (inputlist != NIL)
+	{
+		*est_list_size = ComputeListSize(inputlist);
+		shm_toc_estimate_chunk(&pcxt->estimator, *est_list_size);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+}
 
 /*
+ * InsertStringShm - Insert a string into shared memory.
+ */
+static void
+InsertStringShm(ParallelContext *pcxt, int key, char *inputstr)
+{
+	if (inputstr)
+	{
+		char *shmptr = (char *)shm_toc_allocate(pcxt->toc,
+												strlen(inputstr) + 1);
+		strcpy(shmptr, inputstr);
+		shm_toc_insert(pcxt->toc, key, shmptr);
+	}
+}
+
+/*
+ * InsertListShm - Insert a list into shared memory.
+ */
+static void
+InsertListShm(ParallelContext *pcxt, int key, List *inputlist,
+			  Size est_list_size)
+{
+	if (inputlist != NIL)
+	{
+		ParallelCopyKeyListInfo *sharedlistinfo = (ParallelCopyKeyListInfo *)shm_toc_allocate(pcxt->toc,
+																est_list_size);
+		CopyListSharedMemory(inputlist, est_list_size, sharedlistinfo);
+		shm_toc_insert(pcxt->toc, key, sharedlistinfo);
+	}
+}
+
+/*
+ * BeginParallelCopy - start parallel copy tasks.
+ *
+ * Get the number of workers required to perform the parallel copy. The data
+ * structures that are required by the parallel workers will be initialized, the
+ * size required in DSM will be calculated and the necessary keys will be loaded
+ * in the DSM. The specified number of workers will then be launched.
+ *
+ */
+static ParallelContext*
+BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
+{
+	ParallelContext *pcxt;
+	ParallelCopyShmInfo *shared_info_ptr;
+	ParallelCopyCommonKeyData *shared_cstate;
+	FullTransactionId full_transaction_id;
+	Size est_shared_info;
+	Size est_cstateshared;
+	Size est_att_list_size;
+	Size est_quote_list_size;
+	Size est_notnull_list_size;
+	Size est_null_list_size;
+	Size est_convert_list_size;
+	Size est_datasource_cb_size;
+	int  count = 0;
+	char *whereClauseStr = NULL;
+	char *rangeTableStr = NULL;
+	int  parallel_workers = 0;
+	ParallelCopyData *pcdata;
+
+	parallel_workers = Min(nworkers, max_worker_processes);
+
+	/* Can't perform copy in parallel */
+	if (parallel_workers <= 0)
+	{
+		elog(WARNING,
+			 "No workers available, copy will be run in non-parallel mode");
+		return NULL;
+	}
+
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	cstate->pcdata = pcdata;
+
+	EnterParallelMode();
+	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
+								 parallel_workers);
+	Assert(pcxt->nworkers > 0);
+
+	/*
+	 * Estimate size for shared information for PARALLEL_COPY_KEY_SHARED_INFO
+	 */
+	est_shared_info = sizeof(ParallelCopyShmInfo);
+	shm_toc_estimate_chunk(&pcxt->estimator, est_shared_info);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_CSTATE */
+	est_cstateshared = 	MAXALIGN(sizeof(ParallelCopyCommonKeyData));
+	shm_toc_estimate_chunk(&pcxt->estimator, est_cstateshared);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	EstimateLineKeysStr(pcxt, cstate->null_print);
+	EstimateLineKeysStr(pcxt, cstate->null_print_client);
+	EstimateLineKeysStr(pcxt, cstate->delim);
+	EstimateLineKeysStr(pcxt, cstate->quote);
+	EstimateLineKeysStr(pcxt, cstate->escape);
+
+	if (cstate->whereClause != NULL)
+	{
+		whereClauseStr = nodeToString(cstate->whereClause);
+		EstimateLineKeysStr(pcxt, whereClauseStr);
+	}
+
+	if (cstate->range_table != NULL)
+	{
+		rangeTableStr = nodeToString(cstate->range_table);
+		EstimateLineKeysStr(pcxt, rangeTableStr);
+	}
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_XID. */
+	shm_toc_estimate_chunk(&pcxt->estimator, sizeof(FullTransactionId));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_ATTNAME_LIST.
+	 */
+	EstimateLineKeysList(pcxt, attnamelist, &est_att_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_FORCE_QUOTE_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->force_quote, &est_quote_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_NOT_NULL_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->force_notnull,
+							 &est_notnull_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_NULL_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->force_null, &est_null_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_CONVERT_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->convert_select,
+							 &est_convert_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_DATASOURCE_CB.
+	 */
+	if (cstate->data_source_cb)
+	{
+		char *functionname = LookupParallelCopyFnStr(cstate->data_source_cb);
+		est_datasource_cb_size = strlen(functionname) + 1;
+		shm_toc_estimate_chunk(&pcxt->estimator, est_datasource_cb_size);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+
+	InitializeParallelDSM(pcxt);
+
+	/* If no DSM segment was available, back out (do serial copy) */
+	if (pcxt->seg == NULL)
+	{
+		EndParallelCopy(pcxt);
+		elog(WARNING,
+			 "DSM segments not available, copy will be run in non-parallel mode");
+		return NULL;
+	}
+
+	/* Allocate shared memory for PARALLEL_COPY_KEY_SHARED_INFO */
+	shared_info_ptr = (ParallelCopyShmInfo *) shm_toc_allocate(pcxt->toc,
+													   est_shared_info);
+	MemSet(shared_info_ptr, 0, est_shared_info);
+	shared_info_ptr->is_read_in_progress = true;
+	shared_info_ptr->cur_block_pos = -1;
+	shared_info_ptr->full_transaction_id = full_transaction_id;
+	shared_info_ptr->mycid = GetCurrentCommandId(true);
+	for (count = 0; count < RINGSIZE; count++)
+	{
+		ParallelCopyLineBoundary *lineInfo = &shared_info_ptr->line_boundaries.ring[count];
+		pg_atomic_init_u32(&(lineInfo->line_size), -1);
+	}
+
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_SHARED_INFO, shared_info_ptr);
+	pcdata->pcshared_info = shared_info_ptr;
+	pcdata->relid = relid;
+
+	/* Store shared build state, for which we reserved space. */
+	shared_cstate = (ParallelCopyCommonKeyData *)shm_toc_allocate(pcxt->toc,
+															est_cstateshared);
+
+	/* copy cstate variables. */
+	CopyCommonInfoForWorker(cstate, shared_cstate);
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_CSTATE, shared_cstate);
+
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_NULL_PRINT, cstate->null_print);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_NULL_PRINT_CLIENT,
+					  cstate->null_print_client);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_DELIM, cstate->delim);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_QUOTE, cstate->quote);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_ESCAPE, cstate->escape);
+
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_ATTNAME_LIST,
+					attnamelist, est_att_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_FORCE_QUOTE_LIST,
+					cstate->force_quote, est_quote_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_NOT_NULL_LIST,
+					cstate->force_notnull, est_notnull_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_NULL_LIST, cstate->force_null,
+					est_null_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_CONVERT_LIST,
+					cstate->convert_select, est_convert_list_size);
+
+	if (cstate->data_source_cb)
+	{
+		char *functionname = LookupParallelCopyFnStr(cstate->data_source_cb);
+		char *data_source_cb = (char *) shm_toc_allocate(pcxt->toc,
+														 est_datasource_cb_size);
+		strcpy(data_source_cb, functionname);
+		shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_DATASOURCE_CB,
+					   data_source_cb);
+	}
+
+	if (cstate->whereClause)
+		InsertStringShm(pcxt, PARALLEL_COPY_KEY_WHERE_CLAUSE_STR,
+						whereClauseStr);
+
+	if(cstate->range_table)
+		InsertStringShm(pcxt, PARALLEL_COPY_KEY_RANGE_TABLE, rangeTableStr);
+
+	LaunchParallelWorkers(pcxt);
+	if (pcxt->nworkers_launched == 0)
+	{
+		EndParallelCopy(pcxt);
+		elog(WARNING,
+			 "No workers available, copy will be run in non-parallel mode");
+		return NULL;
+	}
+
+	/*
+	 * Caller needs to wait for all launched workers when we return.  Make sure
+	 * that the failure-to-start case will not hang forever.
+	 */
+	WaitForParallelWorkersToAttach(pcxt);
+
+	pcdata->is_leader = true;
+	cstate->is_parallel = true;
+	return pcxt;
+}
+
+/*
+ * EndParallelCopy - end the parallel copy tasks.
+ */
+static pg_attribute_always_inline void
+EndParallelCopy(ParallelContext *pcxt)
+{
+	Assert(!IsParallelWorker());
+
+	DestroyParallelContext(pcxt);
+	ExitParallelMode();
+}
+
+/*
+ * ParallelWorkerInitialization - Initialize parallel worker.
+ */
+static void
+ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
+		CopyState cstate, List *attnamelist)
+{
+	uint32		count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	cstate->copy_dest = shared_cstate->copy_dest;
+	cstate->file_encoding = shared_cstate->file_encoding;
+	cstate->need_transcoding = shared_cstate->need_transcoding;
+	cstate->encoding_embeds_ascii = shared_cstate->encoding_embeds_ascii;
+	cstate->csv_mode = shared_cstate->csv_mode;
+	cstate->header_line = shared_cstate->header_line;
+	cstate->null_print_len = shared_cstate->null_print_len;
+	cstate->force_quote_all = shared_cstate->force_quote_all;
+	cstate->convert_selectively = shared_cstate->convert_selectively;
+	cstate->num_defaults = shared_cstate->num_defaults;
+	pcdata->relid = shared_cstate->relid;
+
+	PopulateGlobalsForCopyFrom(cstate, tup_desc, attnamelist);
+
+	/* Initialize state variables. */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/* Set up variables to avoid per-attribute overhead. */
+	initStringInfo(&cstate->attribute_buf);
+
+	initStringInfo(&cstate->line_buf);
+	for (count = 0; count < WORKER_CHUNK_COUNT;count++)
+		initStringInfo(&pcdata->worker_line_buf[count].line_buf);
+
+	cstate->line_buf_converted = false;
+	cstate->raw_buf = NULL;
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+}
+/*
+ * ParallelCopyMain - parallel copy worker's code.
+ *
+ * Where clause handling, convert tuple to columns, add default null values for
+ * the missing columns that are not present in that record. Find the partition
+ * if it is partitioned table, invoke before row insert Triggers, handle
+ * constraints and insert the tuples.
+ */
+void
+ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
+{
+	CopyState cstate;
+	ParallelCopyData *pcdata;
+	ParallelCopyShmInfo *pcshared_info;
+	ParallelCopyCommonKeyData *shared_cstate;
+	Relation	rel = NULL;
+	MemoryContext oldcontext;
+	List *attlist = NIL;
+	char *data_source_cb;
+	char *whereClauseStr = NULL;
+	char *rangeTableStr = NULL;
+
+	/* Allocate workspace and zero all fields. */
+	cstate = (CopyStateData *) palloc0(sizeof(CopyStateData));
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	cstate->pcdata = pcdata;
+	pcdata->is_leader = false;
+	pcdata->worker_processed_pos = -1;
+	cstate->is_parallel = true;
+
+	/*
+	 * We allocate everything used by a cstate in a new memory context. This
+	 * avoids memory leaks during repeated use of COPY in a query.
+	 */
+	cstate->copycontext = AllocSetContextCreate(CurrentMemoryContext,
+												"COPY",
+												ALLOCSET_DEFAULT_SIZES);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	pcshared_info = (ParallelCopyShmInfo *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_SHARED_INFO,
+														false);
+
+	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
+
+	pcdata->pcshared_info = pcshared_info;
+
+	shared_cstate = (ParallelCopyCommonKeyData *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE,
+														   false);
+
+	cstate->null_print = (char *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_NULL_PRINT,
+												true);
+	cstate->null_print_client = (char *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_NULL_PRINT_CLIENT,
+													   true);
+
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_DELIM, &cstate->delim);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_QUOTE, &cstate->quote);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_ESCAPE, &cstate->escape);
+
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_ATTNAME_LIST, &attlist);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_FORCE_QUOTE_LIST, &cstate->force_quote);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_NOT_NULL_LIST, &cstate->force_notnull);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_NULL_LIST, &cstate->force_null);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_CONVERT_LIST, &cstate->convert_select);
+	data_source_cb = (char *)shm_toc_lookup(toc,
+											PARALLEL_COPY_KEY_DATASOURCE_CB,
+											true);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_WHERE_CLAUSE_STR, &whereClauseStr);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_RANGE_TABLE, &rangeTableStr);
+
+	if (data_source_cb)
+		cstate->data_source_cb = LookupParallelCopyFnPtr(data_source_cb);
+
+	if (whereClauseStr)
+	{
+		Node *whereClauseCnvrtdFrmStr = (Node *) stringToNode(whereClauseStr);
+		cstate->whereClause = whereClauseCnvrtdFrmStr;
+	}
+
+	if (rangeTableStr)
+	{
+		List *rangeTableCnvrtdFrmStr = (List *) stringToNode(rangeTableStr);
+		cstate->range_table = rangeTableCnvrtdFrmStr;
+	}
+
+	/* Open and lock the relation, using the appropriate lock type. */
+	rel = table_open(shared_cstate->relid, RowExclusiveLock);
+	cstate->rel = rel;
+	ParallelWorkerInitialization(shared_cstate, cstate, attlist);
+
+	CopyFrom(cstate);
+
+	if (rel != NULL)
+		table_close(rel, RowExclusiveLock);
+
+	MemoryContextSwitchTo(oldcontext);
+	return;
+}
+/*
+ * ParallelCopyLeader - parallel copy leader's functionality.
+ *
+ * Leader will populate the shared memory and share it across the workers.
+ * Leader will read the table data from the file and copy the contents to block.
+ * Leader will then read the input contents and identify the data based on line
+ * beaks. This information is called line. The line will be populate in
+ * ParallelCopyLineBoundary. Workers will then pick up this information and
+ * insert in to table. Leader will do this till it completes processing the
+ * file. Leader executes the before statement if before statement trigger is
+ * present. Leader read the data from input file. Leader then loads data to data
+ * blocks as and when required block by block. Leader traverses through the data
+ * block to identify one line. It gets a free line to copy the information, if
+ * there is no free line it will wait till there is one free line.
+ * Server copies  the identified lines information into lines. This process is
+ * repeated till the complete file is processed.
+ * Leader will wait till all the lines populated are processed by the workers
+ * and exits.
+ */
+static void
+ParallelCopyLeader(CopyState cstate)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
+
+	pcshared_info->is_read_in_progress = false;
+	cstate->cur_lineno = 0;
+}
+/*
+ * LookupParallelCopyFnPtr - Look up parallel copy function pointer.
+ */
+static pg_attribute_always_inline copy_data_source_cb
+LookupParallelCopyFnPtr(const char *funcname)
+{
+	int			i;
+
+	for (i = 0; i < lengthof(InternalParallelCopyFuncPtrs); i++)
+	{
+		if (strcmp(InternalParallelCopyFuncPtrs[i].fn_name, funcname) == 0)
+			return InternalParallelCopyFuncPtrs[i].fn_addr;
+	}
+
+	/* We can only reach this by programming error. */
+	elog(ERROR, "internal function \"%s\" not found", funcname);
+}
+
+/*
+ * LookupParallelCopyFnStr - Lookup function string from a function pointer.
+ */
+static pg_attribute_always_inline char*
+LookupParallelCopyFnStr(copy_data_source_cb fn_addr)
+{
+	int			i;
+
+	for (i = 0; i < lengthof(InternalParallelCopyFuncPtrs); i++)
+	{
+		if (InternalParallelCopyFuncPtrs[i].fn_addr == fn_addr)
+			return InternalParallelCopyFuncPtrs[i].fn_name;
+	}
+
+	/* We can only reach this by programming error. */
+	elog(ERROR, "internal function pointer not found");
+}
+/*
  * Send copy start/stop messages for frontend copies.  These have changed
  * in past protocol redesigns.
  */
@@ -1149,6 +1939,7 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 
 	if (is_from)
 	{
+		ParallelContext *pcxt = NULL;
 		Assert(rel);
 
 		/* check read-only transaction and parallel mode */
@@ -1158,7 +1949,24 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 		cstate = BeginCopyFrom(pstate, rel, stmt->filename, stmt->is_program,
 							   NULL, stmt->attlist, stmt->options);
 		cstate->whereClause = whereClause;
-		*processed = CopyFrom(cstate);	/* copy from file to database */
+		cstate->is_parallel = false;
+
+		if (cstate->nworkers > 0)
+			pcxt = BeginParallelCopy(cstate->nworkers, cstate, stmt->attlist,
+									 relid);
+
+		if (pcxt)
+		{
+			ParallelCopyLeader(cstate);
+
+			/* Wait for all copy workers to finish */
+			WaitForParallelWorkersToFinish(pcxt);
+			*processed = pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
+			EndParallelCopy(pcxt);
+		}
+		else
+			*processed = CopyFrom(cstate); /* copy from file to database */
+
 		EndCopyFrom(cstate);
 	}
 	else
@@ -1207,6 +2015,7 @@ ProcessCopyOptions(ParseState *pstate,
 	cstate->is_copy_from = is_from;
 
 	cstate->file_encoding = -1;
+	cstate->nworkers = -1;
 
 	/* Extract options from the statement node tree */
 	foreach(option, options)
@@ -1375,6 +2184,53 @@ ProcessCopyOptions(ParseState *pstate,
 								defel->defname),
 						 parser_errposition(pstate, defel->location)));
 		}
+		else if (strcmp(defel->defname, "parallel") == 0)
+		{
+			char *endptr, *str;
+			long val;
+
+			if (!cstate->is_copy_from)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("parallel option supported only for copy from"),
+						 parser_errposition(pstate, defel->location)));
+			if (cstate->nworkers >= 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options"),
+						 parser_errposition(pstate, defel->location)));
+
+			str = defGetString(defel);
+
+			errno = 0; /* To distinguish success/failure after call */
+			val = strtol(str, &endptr, 10);
+
+			/* Check for various possible errors */
+			if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
+				|| (errno != 0 && val == 0) ||
+				*endptr)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("improper use of argument to option \"%s\"",
+								defel->defname),
+						 parser_errposition(pstate, defel->location)));
+
+			if (endptr == str)
+			   ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("no digits were found in argument to option \"%s\"",
+								defel->defname),
+						 parser_errposition(pstate, defel->location)));
+
+			cstate->nworkers = (int) val;
+
+			if (cstate->nworkers <= 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("argument to option \"%s\" must be a positive integer greater than zero",
+								defel->defname),
+						 parser_errposition(pstate, defel->location)));
+		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_SYNTAX_ERROR),
@@ -1727,12 +2583,13 @@ BeginCopy(ParseState *pstate,
 }
 
 /*
- * PopulateGlobalsForCopyFrom - Populates the common variables required for copy
- * from operation. This is a helper function for BeginCopy function.
+ * PopulateCatalogInformation - Populates the common variables required for copy
+ * from operation. This is a helper function for BeginCopy &
+ * ParallelWorkerInitialization function.
  */
 static void
 PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tupDesc,
-							List *attnamelist)
+						   List *attnamelist)
 {
 	int			num_phys_attrs;
 
diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c
index c27d970..b3787c1 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -557,7 +557,7 @@ make_copy_attnamelist(LogicalRepRelMapEntry *rel)
  * Data source callback for the COPY FROM, which reads from the remote
  * connection and passes the data back to our local COPY.
  */
-static int
+int
 copy_read_data(void *outbuf, int minread, int maxread)
 {
 	int			bytesread = 0;
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index c639833..5dc95ac 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -14,6 +14,7 @@
 #ifndef COPY_H
 #define COPY_H
 
+#include "access/parallel.h"
 #include "nodes/execnodes.h"
 #include "nodes/parsenodes.h"
 #include "parser/parse_node.h"
@@ -41,4 +42,7 @@ extern uint64 CopyFrom(CopyState cstate);
 
 extern DestReceiver *CreateCopyDestReceiver(void);
 
+extern void ParallelCopyMain(dsm_segment *seg, shm_toc *toc);
+
+extern int copy_read_data(void *outbuf, int minread, int maxread);
 #endif							/* COPY_H */
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 7eaaad1..6a42ac4 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1699,6 +1699,14 @@ ParallelBitmapHeapState
 ParallelBlockTableScanDesc
 ParallelCompletionPtr
 ParallelContext
+ParallelCopyLineBoundaries
+ParallelCopyLineBoundary
+ParallelCopyCommonKeyData
+ParallelCopyData
+ParallelCopyDataBlock
+ParallelCopyKeyListInfo
+ParallelCopyLineBuf
+ParallelCopyShmInfo
 ParallelExecutorInfo
 ParallelHashGrowth
 ParallelHashJoinBatch
-- 
1.8.3.1

0003-Allow-copy-from-command-to-process-data-from-file-ST.patchapplication/x-patch; name=0003-Allow-copy-from-command-to-process-data-from-file-ST.patchDownload
From 47d27d300dea6adf9af6d688044e04770d1d8650 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>, Bharath <bharath.rupireddyforpostgres@gmail.com>
Date: Mon, 6 Jul 2020 14:33:12 +0530
Subject: [PATCH 3/6] Allow copy from command to process data from file/STDIN
 contents to a table in parallel.

This feature allows the copy from to leverage multiple CPUs in order to copy
data from file/STDIN to a table. This adds a PARALLEL option to COPY FROM
command where the user can specify the number of workers that can be used
to perform the COPY FROM command. Specifying zero as number of workers will
disable parallelism.
The backend, to which the "COPY FROM" query is submitted acts as leader with
the responsibility of reading data from the file/stdin, launching at most n
number of workers as specified with PARALLEL 'n' option in the "COPY FROM"
query. The leader populates the common data required for the workers execution
in the DSM and shares it with the workers. The leader then executes before
statement triggers if there exists any. Leader populates DSM lines which
includes the start offset and line size, while populating the lines it reads
as many blocks as required into the DSM data blocks from the file. Each block
is of 64K size. The leader parses the data to identify a line, the existing
logic from CopyReadLineText which identifies the lines with some changes was
used for this. Leader checks if a free line is available to copy the
information, if there is no free line it waits till the required line is
freed up by the worker and then copies the identified lines information
(offset & line size) into the DSM lines. This process is repeated till the
complete file is processed. Simultaneously, the workers cache the lines(50)
locally into the local memory and release the lines to the leader for further
populating. Each worker processes the lines that it cached and inserts it into
the table. The leader does not participate in the insertion of data, leaders
only responsibility will be to identify the lines as fast as possible for the
workers to do the actual copy operation. The leader waits till all the lines
populated are processed by the workers and exits.
---
 src/backend/access/common/toast_internals.c |  11 +-
 src/backend/access/heap/heapam.c            |  13 -
 src/backend/access/transam/xact.c           |  31 +
 src/backend/commands/copy.c                 | 900 ++++++++++++++++++++++++++--
 src/include/access/xact.h                   |   2 +
 src/tools/pgindent/typedefs.list            |   1 +
 6 files changed, 906 insertions(+), 52 deletions(-)

diff --git a/src/backend/access/common/toast_internals.c b/src/backend/access/common/toast_internals.c
index 25a81e5..586d53d 100644
--- a/src/backend/access/common/toast_internals.c
+++ b/src/backend/access/common/toast_internals.c
@@ -17,6 +17,7 @@
 #include "access/genam.h"
 #include "access/heapam.h"
 #include "access/heaptoast.h"
+#include "access/parallel.h"
 #include "access/table.h"
 #include "access/toast_internals.h"
 #include "access/xact.h"
@@ -116,7 +117,15 @@ toast_save_datum(Relation rel, Datum value,
 	TupleDesc	toasttupDesc;
 	Datum		t_values[3];
 	bool		t_isnull[3];
-	CommandId	mycid = GetCurrentCommandId(true);
+
+	/*
+	 * Parallel copy can insert toast tuples, in case of parallel copy the
+	 * command would have been set already by calling AssignCommandIdForWorker.
+	 * For parallel copy call GetCurrentCommandId to get currentCommandId by
+	 * passing used as false, as this is taken care earlier.
+	 */
+	CommandId	mycid = IsParallelWorker() ? GetCurrentCommandId(false) :
+											 GetCurrentCommandId(true);
 	struct varlena *result;
 	struct varatt_external toast_pointer;
 	union
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 537913d..28f3a98 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2012,19 +2012,6 @@ static HeapTuple
 heap_prepare_insert(Relation relation, HeapTuple tup, TransactionId xid,
 					CommandId cid, int options)
 {
-	/*
-	 * Parallel operations are required to be strictly read-only in a parallel
-	 * worker.  Parallel inserts are not safe even in the leader in the
-	 * general case, because group locking means that heavyweight locks for
-	 * relation extension or GIN page locks will not conflict between members
-	 * of a lock group, but we don't prohibit that case here because there are
-	 * useful special cases that we can safely allow, such as CREATE TABLE AS.
-	 */
-	if (IsParallelWorker())
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_TRANSACTION_STATE),
-				 errmsg("cannot insert tuples in a parallel worker")));
-
 	tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
 	tup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK);
 	tup->t_data->t_infomask |= HEAP_XMAX_INVALID;
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 905dc7d..ed4009e 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -502,6 +502,37 @@ GetCurrentFullTransactionIdIfAny(void)
 }
 
 /*
+ *	AssignFullTransactionIdForWorker
+ *
+ * For parallel copy, transaction id of leader will be used by the workers.
+ */
+void
+AssignFullTransactionIdForWorker(FullTransactionId fullTransactionId)
+{
+	TransactionState s = CurrentTransactionState;
+
+	Assert((IsInParallelMode() || IsParallelWorker()));
+	s->fullTransactionId = fullTransactionId;
+}
+
+/*
+ *	AssignCommandIdForWorker
+ *
+ * For parallel copy, command id of leader will be used by the workers.
+ */
+void
+AssignCommandIdForWorker(CommandId commandId, bool used)
+{
+	Assert((IsInParallelMode() || IsParallelWorker()));
+
+	/* this is global to a transaction, not subtransaction-local */
+	if (used)
+		currentCommandIdUsed = true;
+
+	currentCommandId = commandId;
+}
+
+/*
  *	MarkCurrentTransactionIdLoggedIfAny
  *
  * Remember that the current xid - if it is assigned - now has been wal logged.
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 0a4d997..048f2d2 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -26,6 +26,7 @@
 #include "access/xlog.h"
 #include "catalog/dependency.h"
 #include "catalog/pg_authid.h"
+#include "catalog/pg_proc_d.h"
 #include "catalog/pg_type.h"
 #include "commands/copy.h"
 #include "commands/defrem.h"
@@ -40,11 +41,13 @@
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
+#include "optimizer/clauses.h"
 #include "optimizer/optimizer.h"
 #include "parser/parse_coerce.h"
 #include "parser/parse_collate.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_relation.h"
+#include "pgstat.h"
 #include "port/pg_bswap.h"
 #include "rewrite/rewriteHandler.h"
 #include "storage/fd.h"
@@ -95,6 +98,18 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
+/*
+ * State of the line.
+ */
+typedef enum ParallelCopyLineState
+{
+	LINE_INIT,					/* initial state of line */
+	LINE_LEADER_POPULATING,		/* leader processing line */
+	LINE_LEADER_POPULATED,		/* leader completed populating line */
+	LINE_WORKER_PROCESSING,		/* worker processing line */
+	LINE_WORKER_PROCESSED		/* worker completed processing line */
+}ParallelCopyLineState;
+
 #define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
 
 #define DATA_BLOCK_SIZE RAW_BUF_SIZE
@@ -538,9 +553,13 @@ if (1) \
 { \
 	if (raw_buf_ptr > cstate->raw_buf_index) \
 	{ \
-		appendBinaryStringInfo(&cstate->line_buf, \
-							 cstate->raw_buf + cstate->raw_buf_index, \
-							   raw_buf_ptr - cstate->raw_buf_index); \
+		if (!IsParallelCopy()) \
+			appendBinaryStringInfo(&cstate->line_buf, \
+								   cstate->raw_buf + cstate->raw_buf_index, \
+								   raw_buf_ptr - cstate->raw_buf_index); \
+		else \
+			line_size +=  raw_buf_ptr - cstate->raw_buf_index; \
+		\
 		cstate->raw_buf_index = raw_buf_ptr; \
 	} \
 } else ((void) 0)
@@ -553,13 +572,40 @@ if (1) \
 	goto not_end_of_copy; \
 } else ((void) 0)
 
+/* Begin parallel copy Macros */
+#define SET_NEWLINE_SIZE() \
+{ \
+	if (cstate->eol_type == EOL_NL || cstate->eol_type == EOL_CR) \
+		new_line_size = 1; \
+	else if (cstate->eol_type == EOL_CRNL) \
+		new_line_size = 2; \
+	else \
+		new_line_size = 0; \
+}
+
+/*
+ * COPY_WAIT_TO_PROCESS - Wait before continuing to process.
+ */
+#define COPY_WAIT_TO_PROCESS() \
+{ \
+	CHECK_FOR_INTERRUPTS(); \
+	(void) WaitLatch(MyLatch, \
+					 WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH, \
+					 1L, WAIT_EVENT_PG_SLEEP); \
+	ResetLatch(MyLatch); \
+}
+
+/* End parallel copy Macros */
+
 /*
  * CONVERT_TO_SERVER_ENCODING - convert contents to server encoding.
  */
 #define CONVERT_TO_SERVER_ENCODING(cstate) \
 { \
 	/* Done reading the line.  Convert it to server encoding. */ \
-	if (cstate->need_transcoding) \
+	if (cstate->need_transcoding && \
+		(!IsParallelCopy() || \
+		 (IsParallelCopy() && !IsLeader()))) \
 	{ \
 		char	   *cvt; \
 		cvt = pg_any_to_server(cstate->line_buf.data, \
@@ -618,22 +664,38 @@ if (1) \
  * CLEAR_EOL_LINE - Wrapper for clearing EOL.
  */
 #define CLEAR_EOL_LINE() \
-if (!result && !IsHeaderLine()) \
-	CLEAR_EOL_FROM_COPIED_DATA(cstate->line_buf.data, \
-								cstate->line_buf.len, \
-								cstate->line_buf.len) \
+{ \
+	if (!result && !IsHeaderLine()) \
+	{ \
+		if (IsParallelCopy()) \
+			CLEAR_EOL_FROM_COPIED_DATA(cstate->raw_buf, \
+									   raw_buf_ptr, line_size) \
+		else \
+			CLEAR_EOL_FROM_COPIED_DATA(cstate->line_buf.data, \
+									   cstate->line_buf.len, \
+									   cstate->line_buf.len) \
+	} \
+}
 
 /*
  * INCREMENTPROCESSED - Increment the lines processed.
  */
-#define INCREMENTPROCESSED(processed)  \
-processed++;
+#define INCREMENTPROCESSED(processed) \
+{ \
+	if (!IsParallelCopy()) \
+		processed++; \
+	else \
+		pg_atomic_add_fetch_u64(&cstate->pcdata->pcshared_info->processed, 1); \
+}
 
 /*
  * GETPROCESSED - Get the lines processed.
  */
 #define GETPROCESSED(processed) \
-return processed;
+if (!IsParallelCopy()) \
+	return processed; \
+else \
+	return pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
 
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
@@ -681,8 +743,12 @@ static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 
 static pg_attribute_always_inline void EndParallelCopy(ParallelContext *pcxt);
+static void ExecBeforeStmtTrigger(CopyState cstate);
+static void CheckTargetRelValidity(CopyState cstate);
 static void PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tup_desc,
 							   List *attnamelist);
+static void PopulateCatalogInformation(CopyState cstate);
+static pg_attribute_always_inline uint32 GetLinePosition(CopyState cstate);
 static pg_attribute_always_inline copy_data_source_cb LookupParallelCopyFnPtr(const char *funcname);
 static pg_attribute_always_inline char* LookupParallelCopyFnStr(copy_data_source_cb fn_addr);
 
@@ -836,6 +902,137 @@ InsertListShm(ParallelContext *pcxt, int key, List *inputlist,
 }
 
 /*
+ * IsTriggerFunctionParallelSafe - Check if the trigger function is parallel
+ * safe for the triggers. Return false if any one of the trigger has parallel
+ * unsafe function.
+ */
+static pg_attribute_always_inline bool
+IsTriggerFunctionParallelSafe(TriggerDesc *trigdesc)
+{
+	int	i;
+	for (i = 0; i < trigdesc->numtriggers; i++)
+	{
+		Trigger    *trigger = &trigdesc->triggers[i];
+		int 		trigtype = RI_TRIGGER_NONE;
+
+		if (func_parallel(trigger->tgfoid) != PROPARALLEL_SAFE)
+			return false;
+
+		/* If the trigger is parallel safe, also look for RI_TRIGGER. */
+		trigtype = RI_FKey_trigger_type(trigger->tgfoid);
+		if (trigtype == RI_TRIGGER_PK || trigtype == RI_TRIGGER_FK)
+			return false;
+	}
+
+	return true;
+}
+
+/*
+ * CheckExprParallelSafety - determine parallel safety of volatile expressions
+ * in default clause of column definition or in where clause and return true if
+ * they are parallel safe.
+ */
+static pg_attribute_always_inline bool
+CheckExprParallelSafety(CopyState cstate)
+{
+	if (contain_volatile_functions(cstate->whereClause))
+	{
+		if (max_parallel_hazard((Query *)cstate->whereClause) != PROPARALLEL_SAFE)
+			return false;
+	}
+
+	/*
+	 * Check if any of the column has volatile default expression. if yes, and
+	 * they are not parallel safe, then parallelism is not allowed. For
+	 * instance, if there are any serial/bigserial columns for which nextval()
+	 * default expression which is parallel unsafe is associated, parallelism
+	 * should not be allowed. In non parallel copy volatile functions are not
+	 * checked for nextval().
+	 */
+	if (cstate->defexprs != NULL && cstate->num_defaults != 0)
+	{
+		int     i;
+		for (i = 0; i < cstate->num_defaults; i++)
+		{
+			bool volatile_expr = contain_volatile_functions((Node *)cstate->defexprs[i]->expr);
+			if (volatile_expr &&
+				(max_parallel_hazard((Query *)cstate->defexprs[i]->expr)) !=
+				 PROPARALLEL_SAFE)
+				return false;
+		}
+	}
+
+	return true;
+}
+
+/*
+ * FindInsertMethod - determine insert mode single, multi, or multi conditional.
+ */
+static pg_attribute_always_inline CopyInsertMethod
+FindInsertMethod(CopyState cstate)
+{
+	if (cstate->rel->trigdesc != NULL &&
+		(cstate->rel->trigdesc->trig_insert_before_row ||
+		 cstate->rel->trigdesc->trig_insert_instead_row))
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
+			cstate->rel->trigdesc != NULL &&
+			cstate->rel->trigdesc->trig_insert_new_table)
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+		return CIM_MULTI_CONDITIONAL;
+
+	return CIM_MULTI;
+}
+
+/*
+ * IsParallelCopyAllowed - check for the cases where parallel copy is not
+ * applicable.
+ */
+static pg_attribute_always_inline bool
+IsParallelCopyAllowed(CopyState cstate)
+{
+	/* Parallel copy not allowed for frontend (2.0 protocol) & binary option. */
+	if ((cstate->copy_dest == COPY_OLD_FE) || cstate->binary)
+		return false;
+
+	/* Check if copy is into foreign table or temporary table. */
+	if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
+		RelationUsesLocalBuffers(cstate->rel))
+		return false;
+
+	/* Check if trigger function is parallel safe. */
+	if (cstate->rel->trigdesc != NULL &&
+		!IsTriggerFunctionParallelSafe(cstate->rel->trigdesc))
+		return false;
+
+	/*
+	 * Check if there is after statement or instead of trigger or transition
+	 * table triggers.
+	 */
+	if (cstate->rel->trigdesc != NULL &&
+		(cstate->rel->trigdesc->trig_insert_after_statement ||
+		 cstate->rel->trigdesc->trig_insert_instead_row ||
+		 cstate->rel->trigdesc->trig_insert_new_table))
+		return false;
+
+	/* Check if the volatile expressions are parallel safe, if present any. */
+	if (!CheckExprParallelSafety(cstate))
+		return false;
+
+	/* Check if the insertion mode is single. */
+	if (FindInsertMethod(cstate) == CIM_SINGLE)
+		return false;
+
+	return true;
+}
+
+/*
  * BeginParallelCopy - start parallel copy tasks.
  *
  * Get the number of workers required to perform the parallel copy. The data
@@ -865,6 +1062,8 @@ BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
 	int  parallel_workers = 0;
 	ParallelCopyData *pcdata;
 
+	CheckTargetRelValidity(cstate);
+
 	parallel_workers = Min(nworkers, max_worker_processes);
 
 	/* Can't perform copy in parallel */
@@ -878,6 +1077,19 @@ BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
 	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
 	cstate->pcdata = pcdata;
 
+	/*
+	 * User chosen parallel copy. Determine if the parallel copy is actually
+	 * allowed. If not, go with the non-parallel mode.
+	 */
+	if (!IsParallelCopyAllowed(cstate))
+	{
+		elog(WARNING,
+			 "Parallel copy not supported for specified table, copy will be run in non-parallel mode");
+		return NULL;
+	}
+
+	full_transaction_id = GetCurrentFullTransactionId();
+
 	EnterParallelMode();
 	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
 								 parallel_workers);
@@ -1108,7 +1320,211 @@ ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
 	cstate->line_buf_converted = false;
 	cstate->raw_buf = NULL;
 	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+
+	PopulateCatalogInformation(cstate);
+
+	/* Create workspace for CopyReadAttributes results. */
+	if (!cstate->binary)
+	{
+		AttrNumber	attr_count = list_length(cstate->attnumlist);
+
+		cstate->max_fields = attr_count;
+		cstate->raw_fields = (char **)palloc(attr_count * sizeof(char *));
+	}
+}
+
+/*
+ * CacheLineInfo - Cache the line information to local memory.
+ */
+static bool
+CacheLineInfo(CopyState cstate, uint32 buff_count)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	uint32			write_pos;
+	ParallelCopyDataBlock *data_blk_ptr;
+	ParallelCopyLineBoundary *lineInfo;
+	uint32 offset;
+	int dataSize;
+	int copiedSize = 0;
+
+	resetStringInfo(&pcdata->worker_line_buf[buff_count].line_buf);
+	write_pos = GetLinePosition(cstate);
+	if (-1 == write_pos)
+		return true;
+
+	/* Get the current line information. */
+	lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+	if (pg_atomic_read_u32(&lineInfo->line_size) == 0)
+		goto empty_data_line_update;
+
+	/* Get the block information. */
+	data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+	/* Get the offset information from where the data must be copied. */
+	offset = lineInfo->start_offset;
+	pcdata->worker_line_buf[buff_count].cur_lineno = lineInfo->cur_lineno;
+
+	elog(DEBUG1, "[Worker] Processing - line position:%d, block:%d, unprocessed lines:%d, offset:%d, line size:%d",
+				 write_pos, lineInfo->first_block,
+				 pg_atomic_read_u32(&data_blk_ptr->unprocessed_line_parts),
+				 offset, pg_atomic_read_u32(&lineInfo->line_size));
+
+	for (;;)
+	{
+		uint8 skip_bytes = data_blk_ptr->skip_bytes;
+		/*
+		 * There is a possibility that the above loop has come out because
+		 * data_blk_ptr->curr_blk_completed is set, but dataSize read might
+		 * be an old value, if data_blk_ptr->curr_blk_completed and the line is
+		 * completed, line_size will be set. Read the line_size again to be
+		 * sure if it is complete or partial block.
+		 */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+		if (dataSize)
+		{
+			int remainingSize = dataSize - copiedSize;
+			if (!remainingSize)
+				break;
+
+			/* Whole line is in current block. */
+			if (remainingSize + offset + skip_bytes < DATA_BLOCK_SIZE)
+			{
+				appendBinaryStringInfo(&pcdata->worker_line_buf[buff_count].line_buf,
+									   &data_blk_ptr->data[offset],
+									   remainingSize);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts,
+										1);
+				break;
+			}
+			else
+			{
+				/* Line is spread across the blocks. */
+				uint32 lineInCurrentBlock =  (DATA_BLOCK_SIZE - skip_bytes) - offset;
+				appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+										 &data_blk_ptr->data[offset],
+										 lineInCurrentBlock);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+				copiedSize += lineInCurrentBlock;
+				while (copiedSize < dataSize)
+				{
+					uint32 currentBlockCopySize;
+					ParallelCopyDataBlock *currBlkPtr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+					skip_bytes = currBlkPtr->skip_bytes;
+
+					/*
+					 * If complete data is present in current block use
+					 * dataSize - copiedSize, or copy the whole block from
+					 * current block.
+					 */
+					currentBlockCopySize = Min(dataSize - copiedSize, DATA_BLOCK_SIZE - skip_bytes);
+					appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+											 &currBlkPtr->data[0],
+											 currentBlockCopySize);
+					pg_atomic_sub_fetch_u32(&currBlkPtr->unprocessed_line_parts, 1);
+					copiedSize += currentBlockCopySize;
+					data_blk_ptr = currBlkPtr;
+				}
+
+				break;
+			}
+		}
+		else
+		{
+			/* Copy this complete block from the current offset. */
+			uint32 lineInCurrentBlock =  (DATA_BLOCK_SIZE - skip_bytes) - offset;
+			appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+									 &data_blk_ptr->data[offset],
+									 lineInCurrentBlock);
+			pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+			copiedSize += lineInCurrentBlock;
+
+			/*
+			 * Reset the offset. For the first copy, copy from the offset. For
+			 * the subsequent copy the complete block.
+			 */
+			offset = 0;
+
+			/* Set data_blk_ptr to the following block. */
+			data_blk_ptr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+		}
+
+		for (;;)
+		{
+			/* Get the size of this line */
+			dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+			/*
+			 * If the data is present in current block lineInfo.line_size
+			 * will be updated. If the data is spread across the blocks either
+			 * of lineInfo.line_size or data_blk_ptr->curr_blk_completed can
+			 * be updated. lineInfo.line_size will be updated if the complete
+			 * read is finished. data_blk_ptr->curr_blk_completed will be
+			 * updated if processing of current block is finished and data
+			 * processing is not finished.
+			 */
+			if (data_blk_ptr->curr_blk_completed || (dataSize != -1))
+				break;
+
+			COPY_WAIT_TO_PROCESS()
+		}
+	}
+
+empty_data_line_update:
+	elog(DEBUG1, "[Worker] Completed processing line:%d", write_pos);
+	pg_atomic_write_u32(&lineInfo->line_state, LINE_WORKER_PROCESSED);
+	pg_atomic_write_u32(&lineInfo->line_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+	return false;
+}
+
+/*
+ * GetWorkerLine - Returns a line for worker to process.
+ */
+static bool
+GetWorkerLine(CopyState cstate)
+{
+	uint32 buff_count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+
+	/*
+	 * Copy the line data to line_buf and release the line position so that the
+	 * worker can continue loading data.
+	 */
+	if (pcdata->worker_line_buf_pos < pcdata->worker_line_buf_count)
+		goto return_line;
+
+	pcdata->worker_line_buf_pos = 0;
+	pcdata->worker_line_buf_count = 0;
+
+	for (buff_count = 0; buff_count < WORKER_CHUNK_COUNT; buff_count++)
+	{
+		bool result = CacheLineInfo(cstate, buff_count);
+		if (result)
+			break;
+
+		pcdata->worker_line_buf_count++;
+	}
+
+	if (pcdata->worker_line_buf_count)
+		goto return_line;
+	else
+		resetStringInfo(&cstate->line_buf);
+
+	return true;
+
+return_line:
+	cstate->line_buf = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].line_buf;
+	cstate->cur_lineno = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].cur_lineno;
+	cstate->line_buf_valid = true;
+
+	/* Mark that encoding conversion hasn't occurred yet. */
+	cstate->line_buf_converted = false;
+	CONVERT_TO_SERVER_ENCODING(cstate)
+	pcdata->worker_line_buf_pos++;
+	return false;
 }
+
 /*
  * ParallelCopyMain - parallel copy worker's code.
  *
@@ -1154,6 +1570,8 @@ ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
 	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
 
 	pcdata->pcshared_info = pcshared_info;
+	AssignFullTransactionIdForWorker(pcshared_info->full_transaction_id);
+	AssignCommandIdForWorker(pcshared_info->mycid, true);
 
 	shared_cstate = (ParallelCopyCommonKeyData *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE,
 														   false);
@@ -1206,6 +1624,34 @@ ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
 	MemoryContextSwitchTo(oldcontext);
 	return;
 }
+
+/*
+ * UpdateBlockInLineInfo - Update the line information.
+ */
+static pg_attribute_always_inline int
+UpdateBlockInLineInfo(CopyState cstate, uint32 blk_pos,
+					   uint32 offset, uint32 line_size, uint32 line_state)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyLineBoundaries *lineBoundaryPtr = &pcshared_info->line_boundaries;
+	ParallelCopyLineBoundary *lineInfo;
+	int line_pos = lineBoundaryPtr->leader_pos;
+
+	/* Update the line information for the worker to pick and process. */
+	lineInfo = &lineBoundaryPtr->ring[line_pos];
+	while (pg_atomic_read_u32(&lineInfo->line_size) != -1)
+		COPY_WAIT_TO_PROCESS()
+
+	lineInfo->first_block = blk_pos;
+	lineInfo->start_offset = offset;
+	lineInfo->cur_lineno = cstate->cur_lineno;
+	pg_atomic_write_u32(&lineInfo->line_size, line_size);
+	pg_atomic_write_u32(&lineInfo->line_state, line_state);
+	lineBoundaryPtr->leader_pos = (lineBoundaryPtr->leader_pos + 1) % RINGSIZE;
+
+	return line_pos;
+}
+
 /*
  * ParallelCopyLeader - parallel copy leader's functionality.
  *
@@ -1231,9 +1677,161 @@ ParallelCopyLeader(CopyState cstate)
 	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
 	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
 
+	/* Execute the before statement triggers from the leader */
+	ExecBeforeStmtTrigger(cstate);
+
+	/* On input just throw the header line away. */
+	if (cstate->cur_lineno == 0 && cstate->header_line)
+	{
+		cstate->cur_lineno++;
+		if (CopyReadLine(cstate))
+		{
+			pcshared_info->is_read_in_progress = false;
+			return;			/* done */
+		}
+	}
+
+	for (;;)
+	{
+		bool done;
+		cstate->cur_lineno++;
+
+		/* Actually read the line into memory here. */
+		done = CopyReadLine(cstate);
+
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			break;
+	}
+
 	pcshared_info->is_read_in_progress = false;
 	cstate->cur_lineno = 0;
 }
+
+/*
+ * GetLinePosition - return the line position that worker should process.
+ */
+static uint32
+GetLinePosition(CopyState cstate)
+{
+	ParallelCopyData *pcdata = cstate->pcdata;
+	ParallelCopyShmInfo *pcshared_info = pcdata->pcshared_info;
+	uint32  previous_pos = pcdata->worker_processed_pos;
+	uint32 write_pos = (previous_pos == -1) ? 0 : (previous_pos + 1) % RINGSIZE;
+	for (;;)
+	{
+		int		dataSize;
+		bool	is_read_in_progress = pcshared_info->is_read_in_progress;
+		ParallelCopyLineBoundary *lineInfo;
+		ParallelCopyDataBlock *data_blk_ptr;
+		ParallelCopyLineState line_state = LINE_LEADER_POPULATED;
+		ParallelCopyLineState curr_line_state;
+		CHECK_FOR_INTERRUPTS();
+
+		/* File read completed & no elements to process. */
+		if (!is_read_in_progress &&
+			(pcshared_info->populated ==
+			 pg_atomic_read_u64(&pcshared_info->total_worker_processed)))
+		{
+			write_pos = -1;
+			break;
+		}
+
+		/* Get the current line information. */
+		lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+		curr_line_state = pg_atomic_read_u32(&lineInfo->line_state);
+		if ((write_pos % WORKER_CHUNK_COUNT == 0) &&
+			(curr_line_state == LINE_WORKER_PROCESSED ||
+			 curr_line_state == LINE_WORKER_PROCESSING))
+		{
+			pcdata->worker_processed_pos = write_pos;
+			write_pos = (write_pos + WORKER_CHUNK_COUNT) %  RINGSIZE;
+			continue;
+		}
+
+		/* Get the size of this line. */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+		if (dataSize != 0) /* If not an empty line. */
+		{
+			/* Get the block information. */
+			data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+			if (!data_blk_ptr->curr_blk_completed && (dataSize == -1))
+			{
+				/* Wait till the current line or block is added. */
+				COPY_WAIT_TO_PROCESS()
+				continue;
+			}
+		}
+
+		/* Make sure that no worker has consumed this element. */
+		if (pg_atomic_compare_exchange_u32(&lineInfo->line_state,
+										   &line_state, LINE_WORKER_PROCESSING))
+			break;
+	}
+
+	pcdata->worker_processed_pos = write_pos;
+	return write_pos;
+}
+
+/*
+ * GetFreeCopyBlock - Get a free block for data to be copied.
+ */
+static pg_attribute_always_inline uint32
+GetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	int count = 0;
+	uint32 last_free_block = pcshared_info->cur_block_pos;
+	uint32 block_pos = (last_free_block != -1) ? ((last_free_block + 1) % MAX_BLOCKS_COUNT): 0;
+
+	/*
+	 * Get a new block for copying data, don't check curent block, current
+	 * block will have some unprocessed data.
+	 */
+	while (count < (MAX_BLOCKS_COUNT - 1))
+	{
+		ParallelCopyDataBlock *dataBlkPtr = &pcshared_info->data_blocks[block_pos];
+		uint32 unprocessed_line_parts = pg_atomic_read_u32(&dataBlkPtr->unprocessed_line_parts);
+		if (unprocessed_line_parts == 0)
+		{
+			dataBlkPtr->curr_blk_completed = false;
+			dataBlkPtr->skip_bytes = 0;
+			pcshared_info->cur_block_pos = block_pos;
+			return block_pos;
+		}
+
+		block_pos = (block_pos + 1) % MAX_BLOCKS_COUNT;
+		count++;
+	}
+
+	return -1;
+}
+
+/*
+ * WaitGetFreeCopyBlock - If there are no blocks available, wait and get a block
+ * for copying data.
+ */
+static uint32
+WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	uint32 new_free_pos = -1;
+	for (;;)
+	{
+		new_free_pos = GetFreeCopyBlock(pcshared_info);
+		if (new_free_pos != -1)	/* We have got one block, break now. */
+			break;
+
+		COPY_WAIT_TO_PROCESS()
+	}
+
+	return new_free_pos;
+}
+
 /*
  * LookupParallelCopyFnPtr - Look up parallel copy function pointer.
  */
@@ -1269,6 +1867,146 @@ LookupParallelCopyFnStr(copy_data_source_cb fn_addr)
 	/* We can only reach this by programming error. */
 	elog(ERROR, "internal function pointer not found");
 }
+
+/*
+ * SetRawBufForLoad - Set raw_buf to the shared memory where the file data must
+ * be read.
+ */
+static void
+SetRawBufForLoad(CopyState cstate, uint32 line_size, uint32 copy_buf_len,
+				 uint32 raw_buf_ptr, char **copy_raw_buf)
+{
+	ParallelCopyShmInfo	*pcshared_info;
+	uint32 cur_block_pos;
+	uint32 next_block_pos;
+	ParallelCopyDataBlock	*cur_data_blk_ptr = NULL;
+	ParallelCopyDataBlock	*next_data_blk_ptr = NULL;
+
+	if (!IsParallelCopy())
+		return;
+
+	pcshared_info = cstate->pcdata->pcshared_info;
+	cur_block_pos = pcshared_info->cur_block_pos;
+	cur_data_blk_ptr = (cstate->raw_buf) ? &pcshared_info->data_blocks[cur_block_pos] : NULL;
+	next_block_pos = WaitGetFreeCopyBlock(pcshared_info);
+	next_data_blk_ptr = &pcshared_info->data_blocks[next_block_pos];
+
+	/* set raw_buf to the data block in shared memory */
+	cstate->raw_buf = next_data_blk_ptr->data;
+	*copy_raw_buf = cstate->raw_buf;
+	if (cur_data_blk_ptr && line_size)
+	{
+		/*
+		 * Mark the previous block as completed, worker can start copying this
+		 * data.
+		 */
+		cur_data_blk_ptr->following_block = next_block_pos;
+		pg_atomic_add_fetch_u32(&cur_data_blk_ptr->unprocessed_line_parts, 1);
+		cur_data_blk_ptr->skip_bytes = copy_buf_len - raw_buf_ptr;
+		cur_data_blk_ptr->curr_blk_completed = true;
+	}
+}
+
+/*
+ * EndLineParallelCopy - Update the line information in shared memory.
+ */
+static void
+EndLineParallelCopy(CopyState cstate, uint32 line_pos, uint32 line_size,
+					 uint32 raw_buf_ptr)
+{
+	uint8 new_line_size;
+	if (!IsParallelCopy())
+		return;
+
+	if (!IsHeaderLine())
+	{
+		ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+		ParallelCopyLineBoundaries *lineBoundaryPtr = &pcshared_info->line_boundaries;
+		SET_NEWLINE_SIZE()
+		if (line_size)
+		{
+			ParallelCopyLineBoundary *lineInfo = &lineBoundaryPtr->ring[line_pos];
+			/*
+			 * If the new_line_size > raw_buf_ptr, then the new block has only
+			 * new line char content. The unprocessed count should not be
+			 * increased in this case.
+			 */
+			if (raw_buf_ptr > new_line_size)
+			{
+				uint32 cur_block_pos = pcshared_info->cur_block_pos;
+				ParallelCopyDataBlock *curr_data_blk_ptr = &pcshared_info->data_blocks[cur_block_pos];
+				pg_atomic_add_fetch_u32(&curr_data_blk_ptr->unprocessed_line_parts, 1);
+			}
+
+			/* Update line size. */
+			pg_atomic_write_u32(&lineInfo->line_size, line_size);
+			pg_atomic_write_u32(&lineInfo->line_state, LINE_LEADER_POPULATED);
+			elog(DEBUG1, "[Leader] After adding - line position:%d, line_size:%d",
+						 line_pos, line_size);
+			pcshared_info->populated++;
+		}
+		else if (new_line_size)
+		{
+			/* This means only new line char, empty record should be inserted.*/
+			ParallelCopyLineBoundary *lineInfo;
+			line_pos = UpdateBlockInLineInfo(cstate, -1, -1, 0,
+											   LINE_LEADER_POPULATED);
+			lineInfo = &lineBoundaryPtr->ring[line_pos];
+			elog(DEBUG1, "[Leader] Added empty line with offset:%d, line position:%d, line size:%d",
+						 lineInfo->start_offset, line_pos,
+						 pg_atomic_read_u32(&lineInfo->line_size));
+			pcshared_info->populated++;
+		}
+	}
+}
+
+/*
+ * ExecBeforeStmtTrigger - Execute the before statement trigger, this will be
+ * executed for parallel copy by the leader process.
+ */
+static void
+ExecBeforeStmtTrigger(CopyState cstate)
+{
+	EState	   *estate = CreateExecutorState();
+	ResultRelInfo *resultRelInfo;
+
+	Assert(IsLeader());
+
+	/*
+	 * We need a ResultRelInfo so we can use the regular executor's
+	 * index-entry-making machinery.  (There used to be a huge amount of code
+	 * here that basically duplicated execUtils.c ...)
+	 */
+	resultRelInfo = makeNode(ResultRelInfo);
+	InitResultRelInfo(resultRelInfo,
+					  cstate->rel,
+					  1,		/* must match rel's position in range_table */
+					  NULL,
+					  0);
+
+	/* Verify the named relation is a valid target for INSERT */
+	CheckValidResultRel(resultRelInfo, CMD_INSERT);
+
+	estate->es_result_relations = resultRelInfo;
+	estate->es_num_result_relations = 1;
+	estate->es_result_relation_info = resultRelInfo;
+
+	ExecInitRangeTable(estate, cstate->range_table);
+
+	/*
+	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
+	 * should do this for COPY, since it's not really an "INSERT" statement as
+	 * such. However, executing these triggers maintains consistency with the
+	 * EACH ROW triggers that we already fire on COPY.
+	 */
+	ExecBSInsertTriggers(estate, resultRelInfo);
+
+	/* Close any trigger target relations */
+	ExecCleanUpTriggerState(estate);
+
+	FreeExecutorState(estate);
+}
+
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
  * in past protocol redesigns.
@@ -3698,7 +4436,8 @@ CopyFrom(CopyState cstate)
 
 	PartitionTupleRouting *proute = NULL;
 	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
+	CommandId	mycid = IsParallelCopy() ? GetCurrentCommandId(false) :
+										   GetCurrentCommandId(true);
 	int			ti_options = 0; /* start with default options for insert */
 	BulkInsertState bistate = NULL;
 	CopyInsertMethod insertMethod;
@@ -3708,7 +4447,14 @@ CopyFrom(CopyState cstate)
 	bool		has_instead_insert_row_trig;
 	bool		leafpart_use_multi_insert = false;
 
-	CheckTargetRelValidity(cstate);
+	/*
+	 * Perform this check if it is not parallel copy. In case of parallel
+	 * copy, this check is done by the leader, so that if any invalid case
+	 * exist the copy from command will error out from the leader itself,
+	 * avoiding launching workers, just to throw error.
+	 */
+	if (!IsParallelCopy())
+		CheckTargetRelValidity(cstate);
 
 	/*
 	 * If the target file is new-in-transaction, we assume that checking FSM
@@ -3897,13 +4643,16 @@ CopyFrom(CopyState cstate)
 	has_instead_insert_row_trig = (resultRelInfo->ri_TrigDesc &&
 								   resultRelInfo->ri_TrigDesc->trig_insert_instead_row);
 
-	/*
-	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
-	 * should do this for COPY, since it's not really an "INSERT" statement as
-	 * such. However, executing these triggers maintains consistency with the
-	 * EACH ROW triggers that we already fire on COPY.
-	 */
-	ExecBSInsertTriggers(estate, resultRelInfo);
+	if (!IsParallelCopy())
+	{
+		/*
+		 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
+		 * should do this for COPY, since it's not really an "INSERT" statement as
+		 * such. However, executing these triggers maintains consistency with the
+		 * EACH ROW triggers that we already fire on COPY.
+		 */
+		ExecBSInsertTriggers(estate, resultRelInfo);
+	}
 
 	econtext = GetPerTupleExprContext(estate);
 
@@ -4003,6 +4752,16 @@ CopyFrom(CopyState cstate)
 					!has_instead_insert_row_trig &&
 					resultRelInfo->ri_FdwRoutine == NULL;
 
+				/*
+				 * If the table has any partitions that are either foreign or
+				 * has BEFORE/INSTEAD OF triggers, we can't perform copy
+				 * operations with parallel workers.
+				 */
+				if (!leafpart_use_multi_insert && IsParallelWorker())
+					ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							errmsg("cannot perform PARALLEL COPY if partition has BEFORE/INSTEAD OF triggers, or if the partition is foreign partition"),
+							errhint("Try COPY without PARALLEL option")));
+
 				/* Set the multi-insert buffer to use for this partition. */
 				if (leafpart_use_multi_insert)
 				{
@@ -4417,7 +5176,7 @@ BeginCopyFrom(ParseState *pstate,
 	initStringInfo(&cstate->attribute_buf);
 	initStringInfo(&cstate->line_buf);
 	cstate->line_buf_converted = false;
-	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+	cstate->raw_buf = (IsParallelCopy()) ? NULL : (char *) palloc(RAW_BUF_SIZE + 1);
 	cstate->raw_buf_index = cstate->raw_buf_len = 0;
 
 	/* Assign range table, we'll need it in CopyFrom. */
@@ -4561,26 +5320,35 @@ NextCopyFromRawFields(CopyState cstate, char ***fields, int *nfields)
 	/* only available for text or csv input */
 	Assert(!cstate->binary);
 
-	/* on input just throw the header line away */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (IsParallelCopy())
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
-			return false;		/* done */
+		done = GetWorkerLine(cstate);
+		if (done && cstate->line_buf.len == 0)
+			return false;
 	}
+	else
+	{
+		/* on input just throw the header line away */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
+		{
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+				return false;		/* done */
+		}
 
-	cstate->cur_lineno++;
+		cstate->cur_lineno++;
 
-	/* Actually read the line into memory here */
-	done = CopyReadLine(cstate);
+		/* Actually read the line into memory here */
+		done = CopyReadLine(cstate);
 
-	/*
-	 * EOF at start of line means we're done.  If we see EOF after some
-	 * characters, we act as though it was newline followed by EOF, ie,
-	 * process the line and then exit loop on next iteration.
-	 */
-	if (done && cstate->line_buf.len == 0)
-		return false;
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			return false;
+	}
 
 	/* Parse the line into de-escaped field values */
 	if (cstate->csv_mode)
@@ -4828,9 +5596,31 @@ CopyReadLine(CopyState cstate)
 		 */
 		if (cstate->copy_dest == COPY_NEW_FE)
 		{
+			bool bIsFirst = true;
 			do
 			{
-				cstate->raw_buf_index = cstate->raw_buf_len;
+				if (!IsParallelCopy())
+					cstate->raw_buf_index = cstate->raw_buf_len;
+				else
+				{
+					if (cstate->raw_buf_index == RAW_BUF_SIZE)
+					{
+						/* Get a new block if it is the first time, From the
+						 * subsequent time, reset the index and re-use the same
+						 * block.
+						 */
+						if (bIsFirst)
+						{
+							ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+							uint32 block_pos = WaitGetFreeCopyBlock(pcshared_info);
+							cstate->raw_buf = pcshared_info->data_blocks[block_pos].data;
+							bIsFirst = false;
+						}
+
+						cstate->raw_buf_index = cstate->raw_buf_len = 0;
+					}
+				}
+
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
@@ -4860,6 +5650,11 @@ CopyReadLineText(CopyState cstate)
 	char		quotec = '\0';
 	char		escapec = '\0';
 
+	/* For parallel copy */
+	uint32			 line_size = 0;
+	int				 line_pos = 0;
+
+	cstate->eol_type = EOL_UNKNOWN;
 	if (cstate->csv_mode)
 	{
 		quotec = cstate->quote[0];
@@ -4914,6 +5709,8 @@ CopyReadLineText(CopyState cstate)
 		if (raw_buf_ptr >= copy_buf_len || need_data)
 		{
 			REFILL_LINEBUF;
+			SetRawBufForLoad(cstate, line_size, copy_buf_len, raw_buf_ptr,
+							 &copy_raw_buf);
 
 			/*
 			 * Try to read some more data.  This will certainly reset
@@ -5138,9 +5935,15 @@ CopyReadLineText(CopyState cstate)
 				 * discard the data and the \. sequence.
 				 */
 				if (prev_raw_ptr > cstate->raw_buf_index)
-					appendBinaryStringInfo(&cstate->line_buf,
+				{
+					if (!IsParallelCopy())
+						appendBinaryStringInfo(&cstate->line_buf,
 										   cstate->raw_buf + cstate->raw_buf_index,
 										   prev_raw_ptr - cstate->raw_buf_index);
+					else
+						line_size += prev_raw_ptr - cstate->raw_buf_index;
+				}
+
 				cstate->raw_buf_index = raw_buf_ptr;
 				result = true;	/* report EOF */
 				break;
@@ -5192,6 +5995,26 @@ not_end_of_copy:
 			IF_NEED_REFILL_AND_EOF_BREAK(mblen - 1);
 			raw_buf_ptr += mblen - 1;
 		}
+
+		/*
+		 * Skip the header line. Update the line here, this cannot be done at
+		 * the beginning, as there is a possibility that file contains empty
+		 * lines.
+		 */
+		if (IsParallelCopy() && first_char_in_line && !IsHeaderLine())
+		{
+			ParallelCopyShmInfo	*pcshared_info = cstate->pcdata->pcshared_info;
+			ParallelCopyLineBoundary *lineInfo;
+			uint32			 line_first_block = pcshared_info->cur_block_pos;
+			line_pos = UpdateBlockInLineInfo(cstate,
+											   line_first_block,
+											   cstate->raw_buf_index, -1,
+											   LINE_LEADER_POPULATING);
+			lineInfo = &pcshared_info->line_boundaries.ring[line_pos];
+			elog(DEBUG1, "[Leader] Adding - block:%d, offset:%d, line position:%d",
+						 line_first_block,	lineInfo->start_offset, line_pos);
+		}
+
 		first_char_in_line = false;
 	}							/* end of outer loop */
 
@@ -5200,6 +6023,7 @@ not_end_of_copy:
 	 */
 	REFILL_LINEBUF;
 	CLEAR_EOL_LINE()
+	EndLineParallelCopy(cstate, line_pos, line_size, raw_buf_ptr);
 
 	return result;
 }
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index db19187..20dafb7 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -381,6 +381,8 @@ extern FullTransactionId GetTopFullTransactionId(void);
 extern FullTransactionId GetTopFullTransactionIdIfAny(void);
 extern FullTransactionId GetCurrentFullTransactionId(void);
 extern FullTransactionId GetCurrentFullTransactionIdIfAny(void);
+extern void AssignFullTransactionIdForWorker(FullTransactionId fullTransactionId);
+extern void AssignCommandIdForWorker(CommandId commandId, bool used);
 extern void MarkCurrentTransactionIdLoggedIfAny(void);
 extern bool SubTransactionIsActive(SubTransactionId subxid);
 extern CommandId GetCurrentCommandId(bool used);
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 6a42ac4..86a7620 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1701,6 +1701,7 @@ ParallelCompletionPtr
 ParallelContext
 ParallelCopyLineBoundaries
 ParallelCopyLineBoundary
+ParallelCopyLineState
 ParallelCopyCommonKeyData
 ParallelCopyData
 ParallelCopyDataBlock
-- 
1.8.3.1

0004-Documentation-for-parallel-copy.patchapplication/x-patch; name=0004-Documentation-for-parallel-copy.patchDownload
From d04485ce9e4768cbab3f2722dadcf032586fda33 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 17 Jun 2020 07:34:56 +0530
Subject: [PATCH 4/6] Documentation for parallel copy.

This patch has the documentation changes for parallel copy.
---
 doc/src/sgml/ref/copy.sgml | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/doc/src/sgml/ref/copy.sgml b/doc/src/sgml/ref/copy.sgml
index 18189ab..95d349d 100644
--- a/doc/src/sgml/ref/copy.sgml
+++ b/doc/src/sgml/ref/copy.sgml
@@ -37,6 +37,7 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
     DELIMITER '<replaceable class="parameter">delimiter_character</replaceable>'
     NULL '<replaceable class="parameter">null_string</replaceable>'
     HEADER [ <replaceable class="parameter">boolean</replaceable> ]
+    PARALLEL <replaceable class="parameter">integer</replaceable>
     QUOTE '<replaceable class="parameter">quote_character</replaceable>'
     ESCAPE '<replaceable class="parameter">escape_character</replaceable>'
     FORCE_QUOTE { ( <replaceable class="parameter">column_name</replaceable> [, ...] ) | * }
@@ -275,6 +276,21 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
    </varlistentry>
 
    <varlistentry>
+    <term><literal>PARALLEL</literal></term>
+    <listitem>
+     <para>
+      Perform <command>COPY FROM</command> in parallel using <replaceable
+      class="parameter"> integer</replaceable> background workers.  Please
+      note that it is not guaranteed that the number of parallel workers
+      specified in <replaceable class="parameter">integer</replaceable> will
+      be used during execution.  It is possible for a copy to run with fewer
+      workers than specified, or even with no workers at all.  This option is
+      allowed only in <command>COPY FROM</command>.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><literal>QUOTE</literal></term>
     <listitem>
      <para>
-- 
1.8.3.1

0005-Tests-for-parallel-copy.patchapplication/x-patch; name=0005-Tests-for-parallel-copy.patchDownload
From cd57bede56d817a95ae251ab4b3c543c73bcf9a8 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 17 Jun 2020 07:37:26 +0530
Subject: [PATCH 5/6] Tests for parallel copy.

This patch has the tests for parallel copy.
---
 src/test/regress/expected/copy2.out | 210 +++++++++++++++++++++++++++++++++++-
 src/test/regress/input/copy.source  |  12 +++
 src/test/regress/output/copy.source |  12 +++
 src/test/regress/sql/copy2.sql      | 208 ++++++++++++++++++++++++++++++++++-
 4 files changed, 434 insertions(+), 8 deletions(-)

diff --git a/src/test/regress/expected/copy2.out b/src/test/regress/expected/copy2.out
index e40287d..ef75148 100644
--- a/src/test/regress/expected/copy2.out
+++ b/src/test/regress/expected/copy2.out
@@ -254,18 +254,32 @@ It is "perfect".|
 "It is ""perfect"".","	"
 "",
 --test that we read consecutive LFs properly
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 COPY testnl FROM stdin CSV;
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+SELECT * FROM testnl;
+ a |          b           | c 
+---+----------------------+---
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+(2 rows)
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 COPY testeoc FROM stdin CSV;
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
 COPY testeoc TO stdout CSV;
 a\.
 \.b
 c\.d
 "\."
 -- test handling of nonstandard null marker that violates escaping rules
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 COPY testnull TO stdout WITH NULL AS E'\\0';
 1	\\0
@@ -280,6 +294,15 @@ SELECT * FROM testnull;
     | 
 (4 rows)
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 1);
+SELECT * FROM testnull;
+ a  | b  
+----+----
+ 42 | \0
+    | 
+(2 rows)
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -349,6 +372,34 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+SELECT * FROM vistest;
+ a  
+----
+ a2
+ b
+(2 rows)
+
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+COMMIT;
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 SELECT * FROM vistest;
  a 
@@ -409,7 +460,7 @@ SELECT * FROM vistest;
 (2 rows)
 
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -420,6 +471,8 @@ CREATE TEMP TABLE forcetest (
 -- should succeed with no effect ("b" remains an empty string, "c" remains NULL)
 BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 1);
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
  b |  c   
@@ -430,6 +483,8 @@ SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
 BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 1);
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
  c |  d   
@@ -486,6 +541,31 @@ select * from check_con_tbl;
    
 (2 rows)
 
+\d+ check_con_tbl
+                               Table "public.check_con_tbl"
+ Column |  Type   | Collation | Nullable | Default | Storage | Stats target | Description 
+--------+---------+-----------+----------+---------+---------+--------------+-------------
+ f1     | integer |           |          |         | plain   |              | 
+Check constraints:
+    "check_con_tbl_check" CHECK (check_con_function(check_con_tbl.*))
+
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 1);
+NOTICE:  input = {"f1":1}
+NOTICE:  input = {"f1":null}
+copy check_con_tbl from stdin with (parallel 1);
+NOTICE:  input = {"f1":0}
+ERROR:  new row for relation "check_con_tbl" violates check constraint "check_con_tbl_check"
+DETAIL:  Failing row contains (0).
+CONTEXT:  COPY check_con_tbl, line 1: "0"
+parallel worker
+select * from check_con_tbl;
+ f1 
+----
+  1
+   
+(2 rows)
+
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
 CREATE ROLE regress_rls_copy_user_colperms;
@@ -600,8 +680,130 @@ SELECT * FROM instead_of_insert_tbl;
 (2 rows)
 
 COMMIT;
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+COPY test_parallel_copy (a, b, c, d, e) from stdin with (PARALLEL 1);
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1, FORMAT 'csv', HEADER);
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0');
+ERROR:  argument to option "parallel" must be a positive integer greater than zero
+LINE 1: COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0'...
+                                                        ^
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri from stdin with (FORMAT csv, DELIMITER ',', PARALLEL 1);
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1) WHERE height > random() * 65;
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- temporary table copy: should peform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+COPY temp_test (a) from stdin with (PARALLEL 1);
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) from stdin with (PARALLEL 1);
+ERROR:  column "xyz" of relation "test_parallel_copy" does not exist
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) from stdin with (PARALLEL 1);
+ERROR:  column "d" specified more than once
+-- missing data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  invalid input syntax for type integer: ""
+CONTEXT:  COPY test_parallel_copy, line 0, column a: ""
+parallel worker
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2000	230	23	23"
+parallel worker
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2001	231	\N	\N"
+parallel worker
+-- extra data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  extra data after last expected column
+CONTEXT:  COPY test_parallel_copy, line 1: "2002	232	40	50	60	70	80"
+parallel worker
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) from stdin with (delimiter ',', null 'x', PARALLEL 1) ;
+COPY test_parallel_copy from stdin WITH (DELIMITER ';', NULL '', PARALLEL 1);
+COPY test_parallel_copy from stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL 1);
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = 50004;
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a > 60003;
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE f > 60003;
+ERROR:  column "f" does not exist
+LINE 1: ..._parallel_copy from stdin WITH (PARALLEL 1) WHERE f > 60003;
+                                                             ^
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+ERROR:  missing FROM-clause entry for table "x"
+LINE 1: ...rallel_copy from stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+                                                                  ^
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (SELECT 1 FROM x);
+ERROR:  cannot use subquery in COPY FROM WHERE condition
+LINE 1: ...arallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (SELECT...
+                                                             ^
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (generate_series(1,5));
+ERROR:  set-returning functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...lel_copy from stdin WITH (PARALLEL 1) WHERE a IN (generate_s...
+                                                             ^
+COPY test_parallel_copy from stdin WITH(PARALLEL 1) WHERE a = row_number() over(b);
+ERROR:  window functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...rallel_copy from stdin WITH(PARALLEL 1) WHERE a = row_number...
+                                                             ^
+-- check results of copy in
+SELECT * FROM test_parallel_copy;
+   a   | b  |     c      |    d    |    e    
+-------+----+------------+---------+---------
+     1 | 11 | test_c1    | test_d1 | test_e1
+     2 | 12 | test_c2    | test_d2 | test_e2
+       |  3 | stuff      | test_d3 | 
+       |  4 | stuff      | test_d4 | 
+       |  5 | stuff      | test_d5 | 
+       |    | 45         | 80      | 90
+       |    | x          | \x      | \x
+       |    | ,          | \,      | \
+  3000 |    | c          |         | 
+  4000 |    | C          |         | 
+  4001 |  1 | empty      |         | 
+  4002 |  2 | null       |         | 
+  4003 |  3 | Backslash  | \       | \
+  4004 |  4 | BackslashX | \X      | \X
+  4005 |  5 | N          | N       | N
+  4006 |  6 | BackslashN | \N      | \N
+  4007 |  7 | XX         | XX      | XX
+  4008 |  8 | Delimiter  | :       | :
+ 50004 | 25 | 35         | 45      | 55
+ 60004 | 25 | 35         | 45      | 55
+ 60005 | 26 | 36         | 46      | 56
+(21 rows)
+
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
 DROP TABLE x, y;
diff --git a/src/test/regress/input/copy.source b/src/test/regress/input/copy.source
index a1d529a..159c058 100644
--- a/src/test/regress/input/copy.source
+++ b/src/test/regress/input/copy.source
@@ -15,6 +15,13 @@ DELETE FROM onek;
 
 COPY onek FROM '@abs_builddir@/results/onek.data';
 
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+
+SELECT COUNT(*) FROM tenk1;
+
+TRUNCATE tenk1;
+
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
@@ -159,6 +166,11 @@ truncate parted_copytest;
 
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
 
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
+
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/output/copy.source b/src/test/regress/output/copy.source
index 938d355..c3003fe 100644
--- a/src/test/regress/output/copy.source
+++ b/src/test/regress/output/copy.source
@@ -9,6 +9,15 @@ COPY onek FROM '@abs_srcdir@/data/onek.data';
 COPY onek TO '@abs_builddir@/results/onek.data';
 DELETE FROM onek;
 COPY onek FROM '@abs_builddir@/results/onek.data';
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+SELECT COUNT(*) FROM tenk1;
+ count 
+-------
+ 10000
+(1 row)
+
+TRUNCATE tenk1;
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
 COPY person FROM '@abs_srcdir@/data/person.data';
@@ -113,6 +122,9 @@ insert into parted_copytest select x,1,'One' from generate_series(1011,1020) x;
 copy (select * from parted_copytest order by a) to '@abs_builddir@/results/parted_copytest.csv';
 truncate parted_copytest;
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/sql/copy2.sql b/src/test/regress/sql/copy2.sql
index 902f4fa..032cea9 100644
--- a/src/test/regress/sql/copy2.sql
+++ b/src/test/regress/sql/copy2.sql
@@ -157,7 +157,7 @@ COPY y TO stdout (FORMAT CSV, FORCE_QUOTE *);
 
 --test that we read consecutive LFs properly
 
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 
 COPY testnl FROM stdin CSV;
 1,"a field with two LFs
@@ -165,8 +165,16 @@ COPY testnl FROM stdin CSV;
 inside",2
 \.
 
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+1,"a field with two LFs
+
+inside",2
+\.
+
+SELECT * FROM testnl;
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 
 COPY testeoc FROM stdin CSV;
 a\.
@@ -175,11 +183,19 @@ c\.d
 "\."
 \.
 
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+a\.
+\.b
+c\.d
+"\."
+\.
+
 COPY testeoc TO stdout CSV;
 
 -- test handling of nonstandard null marker that violates escaping rules
 
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 
 COPY testnull TO stdout WITH NULL AS E'\\0';
@@ -191,6 +207,14 @@ COPY testnull FROM stdin WITH NULL AS E'\\0';
 
 SELECT * FROM testnull;
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 1);
+42	\\0
+\0	\0
+\.
+
+SELECT * FROM testnull;
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -235,6 +259,23 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+a2
+b
+\.
+SELECT * FROM vistest;
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+d2
+e
+\.
+SELECT * FROM vistest;
+COMMIT;
+SELECT * FROM vistest;
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 x
 y
@@ -284,7 +325,7 @@ SELECT * FROM vistest;
 COMMIT;
 SELECT * FROM vistest;
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -297,6 +338,10 @@ BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
 1,,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 1);
+1,,""
+\.
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
@@ -304,6 +349,10 @@ BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
 2,'a',,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 1);
+2,'a',,""
+\.
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
 -- should fail with not-null constraint violation
@@ -339,6 +388,16 @@ copy check_con_tbl from stdin;
 0
 \.
 select * from check_con_tbl;
+\d+ check_con_tbl
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 1);
+1
+\N
+\.
+copy check_con_tbl from stdin with (parallel 1);
+0
+\.
+select * from check_con_tbl;
 
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
@@ -440,8 +499,149 @@ test1
 SELECT * FROM instead_of_insert_tbl;
 COMMIT;
 
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+
+COPY test_parallel_copy (a, b, c, d, e) from stdin with (PARALLEL 1);
+1	11	test_c1	test_d1	test_e1
+2	12	test_c2	test_d2	test_e2
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+3	test_d3
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+4	test_d4
+5	test_d5
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1, FORMAT 'csv', HEADER);
+b	d
+\.
+
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0');
+
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri from stdin with (FORMAT csv, DELIMITER ',', PARALLEL 1);
+10
+\.
+
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1) WHERE height > random() * 65;
+60,60,60
+\.
+
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+60
+\.
+
+-- temporary table copy: should peform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+
+COPY temp_test (a) from stdin with (PARALLEL 1);
+10
+\.
+
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) from stdin with (PARALLEL 1);
+
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) from stdin with (PARALLEL 1);
+
+-- missing data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+
+\.
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+2000	230	23	23
+\.
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+2001	231	\N	\N
+\.
+
+-- extra data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+2002	232	40	50	60	70	80
+\.
+
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) from stdin with (delimiter ',', null 'x', PARALLEL 1) ;
+x,45,80,90
+x,\x,\\x,\\\x
+x,\,,\\\,,\\
+\.
+
+COPY test_parallel_copy from stdin WITH (DELIMITER ';', NULL '', PARALLEL 1);
+3000;;c;;
+\.
+
+COPY test_parallel_copy from stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL 1);
+4000:\X:C:\X:\X
+4001:1:empty::
+4002:2:null:\X:\X
+4003:3:Backslash:\\:\\
+4004:4:BackslashX:\\X:\\X
+4005:5:N:\N:\N
+4006:6:BackslashN:\\N:\\N
+4007:7:XX:\XX:\XX
+4008:8:Delimiter:\::\:
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = 50004;
+50003	24	34	44	54
+50004	25	35	45 	55
+50005	26	36	46	56
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a > 60003;
+60001	22	32	42	52
+60002	23	33	43	53
+60003	24	34	44	54
+60004	25	35	45	55
+60005	26	36	46	56
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE f > 60003;
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (SELECT 1 FROM x);
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (generate_series(1,5));
+
+COPY test_parallel_copy from stdin WITH(PARALLEL 1) WHERE a = row_number() over(b);
+
+-- check results of copy in
+SELECT * FROM test_parallel_copy;
+
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
 DROP TABLE x, y;
-- 
1.8.3.1

0006-Parallel-Copy-For-Binary-Format-Files.patchapplication/x-patch; name=0006-Parallel-Copy-For-Binary-Format-Files.patchDownload
From 4a1eb9d091eb8cf82e101a1e8db683ebe22cbe88 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddy@enterprisedb.com>
Date: Fri, 26 Jun 2020 11:43:48 +0530
Subject: [PATCH 6/6] Parallel Copy For Binary Format Files

Leader reads data from the file into the DSM data blocks each of 64K size.
It also identifies each tuple data block id, start offset, end offset,
tuple size and updates this information in the ring data structure.
Workers parallely read the tuple information from the ring data structure,
the actual tuple data from the data blocks and parallely insert the tuples
into the table.
---
 src/backend/commands/copy.c | 697 +++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 627 insertions(+), 70 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 048f2d2..5eafd5d 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -220,6 +220,16 @@ typedef struct ParallelCopyLineBuf
 }ParallelCopyLineBuf;
 
 /*
+ * Tuple boundary information used for parallel copy
+ * for binary format files.
+ */
+typedef struct ParallelCopyTupleInfo
+{
+	uint32 offset;
+	uint32 block_id;
+}ParallelCopyTupleInfo;
+
+/*
  * Parallel copy data information.
  */
 typedef struct ParallelCopyData
@@ -240,6 +250,11 @@ typedef struct ParallelCopyData
 
 	/* Current position in worker_line_buf */
 	uint32				worker_line_buf_pos;
+
+	/*
+	 * For binary formatted files
+	 */
+	ParallelCopyDataBlock *curr_data_block;
 }ParallelCopyData;
 
 /*
@@ -397,6 +412,7 @@ typedef struct ParallelCopyCommonKeyData
 	/* Working state for COPY FROM */
 	AttrNumber          num_defaults;
 	Oid                 relid;
+	bool 				binary;
 }ParallelCopyCommonKeyData;
 
 /*
@@ -697,6 +713,56 @@ if (!IsParallelCopy()) \
 else \
 	return pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
 
+/*
+ * CHECK_FIELD_COUNT - Handles the error cases for field count
+ * for binary format files.
+ */
+#define CHECK_FIELD_COUNT \
+{\
+	if (fld_count == -1) \
+	{ \
+		if (IsParallelCopy() && \
+			!IsLeader()) \
+			return true; \
+		else if (IsParallelCopy() && \
+			IsLeader()) \
+		{ \
+			if (cstate->pcdata->curr_data_block->data[cstate->raw_buf_index + sizeof(fld_count)] != 0) \
+				ereport(ERROR, \
+						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+						errmsg("received copy data after EOF marker"))); \
+			return true; \
+		} \
+		else \
+		{ \
+			/* \
+			* Received EOF marker.  In a V3-protocol copy, wait for the \
+			* protocol-level EOF, and complain if it doesn't come \
+			* immediately.  This ensures that we correctly handle CopyFail, \
+			* if client chooses to send that now. \
+			* \
+			* Note that we MUST NOT try to read more data in an old-protocol \
+			* copy, since there is no protocol-level EOF marker then.  We \
+			* could go either way for copy from file, but choose to throw \
+			* error if there's data after the EOF marker, for consistency \
+			* with the new-protocol case. \
+			*/ \
+			char		dummy; \
+			if (cstate->copy_dest != COPY_OLD_FE && \
+				CopyGetData(cstate, &dummy, 1, 1) > 0) \
+				ereport(ERROR, \
+						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+						errmsg("received copy data after EOF marker"))); \
+				return false; \
+		} \
+	} \
+	if (fld_count != cstate->max_fields) \
+		ereport(ERROR, \
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+				errmsg("row field count is %d, expected %d", \
+				(int) fld_count, cstate->max_fields))); \
+}
+
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
 
@@ -751,6 +817,16 @@ static void PopulateCatalogInformation(CopyState cstate);
 static pg_attribute_always_inline uint32 GetLinePosition(CopyState cstate);
 static pg_attribute_always_inline copy_data_source_cb LookupParallelCopyFnPtr(const char *funcname);
 static pg_attribute_always_inline char* LookupParallelCopyFnStr(copy_data_source_cb fn_addr);
+static uint32 WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info);
+static pg_attribute_always_inline bool CopyReadBinaryTupleLeader(CopyState cstate);
+static pg_attribute_always_inline void CopyReadBinaryAttributeLeader(CopyState cstate,
+										FmgrInfo *flinfo, Oid typioparam, int32 typmod,
+										uint32 *new_block_pos, int m, ParallelCopyTupleInfo *tuple_start_info_ptr,
+										ParallelCopyTupleInfo *tuple_end_info_ptr, uint32 *line_size);
+static pg_attribute_always_inline bool CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls);
+static pg_attribute_always_inline Datum CopyReadBinaryAttributeWorker(CopyState cstate, FmgrInfo *flinfo,
+										  Oid typioparam, int32 typmod, bool *isnull);
+static void AdjustFieldInfo(CopyState cstate, uint8 mode);
 
 /*
  * CopyCommonInfoForWorker - Copy shared_cstate using cstate information.
@@ -769,6 +845,7 @@ CopyCommonInfoForWorker(CopyState cstate, ParallelCopyCommonKeyData *shared_csta
 	shared_cstate->convert_selectively = cstate->convert_selectively;
 	shared_cstate->num_defaults = cstate->num_defaults;
 	shared_cstate->relid = cstate->pcdata->relid;
+	shared_cstate->binary = cstate->binary;
 }
 
 /*
@@ -997,8 +1074,8 @@ FindInsertMethod(CopyState cstate)
 static pg_attribute_always_inline bool
 IsParallelCopyAllowed(CopyState cstate)
 {
-	/* Parallel copy not allowed for frontend (2.0 protocol) & binary option. */
-	if ((cstate->copy_dest == COPY_OLD_FE) || cstate->binary)
+	/* Parallel copy not allowed for frontend (2.0 protocol). */
+	if (cstate->copy_dest == COPY_OLD_FE)
 		return false;
 
 	/* Check if copy is into foreign table or temporary table. */
@@ -1299,6 +1376,7 @@ ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
 	cstate->convert_selectively = shared_cstate->convert_selectively;
 	cstate->num_defaults = shared_cstate->num_defaults;
 	pcdata->relid = shared_cstate->relid;
+	cstate->binary = shared_cstate->binary;
 
 	PopulateGlobalsForCopyFrom(cstate, tup_desc, attnamelist);
 
@@ -1314,7 +1392,7 @@ ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
 	initStringInfo(&cstate->attribute_buf);
 
 	initStringInfo(&cstate->line_buf);
-	for (count = 0; count < WORKER_CHUNK_COUNT;count++)
+	for (count = 0; count < WORKER_CHUNK_COUNT; count++)
 		initStringInfo(&pcdata->worker_line_buf[count].line_buf);
 
 	cstate->line_buf_converted = false;
@@ -1680,32 +1758,66 @@ ParallelCopyLeader(CopyState cstate)
 	/* Execute the before statement triggers from the leader */
 	ExecBeforeStmtTrigger(cstate);
 
-	/* On input just throw the header line away. */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (!cstate->binary)
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
+		/* On input just throw the header line away. */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
 		{
-			pcshared_info->is_read_in_progress = false;
-			return;			/* done */
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+			{
+				pcshared_info->is_read_in_progress = false;
+				return;			/* done */
+			}
 		}
-	}
 
-	for (;;)
-	{
-		bool done;
-		cstate->cur_lineno++;
+		for (;;)
+		{
+			bool done;
+			cstate->cur_lineno++;
 
-		/* Actually read the line into memory here. */
-		done = CopyReadLine(cstate);
+			/* Actually read the line into memory here. */
+			done = CopyReadLine(cstate);
 
-		/*
-		 * EOF at start of line means we're done.  If we see EOF after some
-		 * characters, we act as though it was newline followed by EOF, ie,
-		 * process the line and then exit loop on next iteration.
+			/*
+			* EOF at start of line means we're done.  If we see EOF after some
+			* characters, we act as though it was newline followed by EOF, ie,
+			* process the line and then exit loop on next iteration.
+			*/
+			if (done && cstate->line_buf.len == 0)
+				break;
+		}
+	}
+	else
+	{
+		/* binary format */
+		/* for paralle copy leader, fill in the error
+		 * context inforation here, in case any failures
+		 * while determining tuple offsets, leader
+		 * would throw the errors with proper context.
 		 */
-		if (done && cstate->line_buf.len == 0)
-			break;
+		ErrorContextCallback errcallback;
+		errcallback.callback = CopyFromErrorCallback;
+		errcallback.arg = (void *) cstate;
+		errcallback.previous = error_context_stack;
+		error_context_stack = &errcallback;
+
+		cstate->pcdata->curr_data_block = NULL;
+		cstate->raw_buf_index = 0;
+		pcshared_info->populated = 0;
+		cstate->cur_lineno = 0;
+		cstate->max_fields = list_length(cstate->attnumlist);
+
+		for (;;)
+		{
+			bool eof = false;
+			cstate->cur_lineno++;
+
+			eof = CopyReadBinaryTupleLeader(cstate);
+
+			if (eof)
+				break;
+		}
 	}
 
 	pcshared_info->is_read_in_progress = false;
@@ -1713,7 +1825,463 @@ ParallelCopyLeader(CopyState cstate)
 }
 
 /*
- * GetLinePosition - return the line position that worker should process.
+ * AdjustFieldInfo - gets a new block, updates the
+ * current offset, calculates the skip bytes.
+ * Works in two modes, 1 for field count
+ * 2 for field size
+ */
+static void
+AdjustFieldInfo(CopyState cstate, uint8 mode)
+{
+	ParallelCopyDataBlock *data_block = NULL;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	uint8 movebytes = 0;
+	uint32 block_pos;
+	uint32 prev_block_pos;
+	int readbytes = 0;
+
+	prev_block_pos = pcshared_info->cur_block_pos;
+
+	block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+	movebytes = DATA_BLOCK_SIZE - cstate->raw_buf_index;
+
+	cstate->pcdata->curr_data_block->skip_bytes = movebytes;
+
+	data_block = &pcshared_info->data_blocks[block_pos];
+
+	if (movebytes > 0)
+		memmove(&data_block->data[0], &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index],
+			movebytes);
+
+	elog(DEBUG1, "LEADER - field info is spread across data blocks - moved %d bytes from current block %u to %u block",
+		movebytes, prev_block_pos, block_pos);
+
+	readbytes = CopyGetData(cstate, &data_block->data[movebytes], 1, (DATA_BLOCK_SIZE - movebytes));
+
+	elog(DEBUG1, "LEADER - bytes read from file after field info is moved to next data block %d", readbytes);
+
+	if (cstate->reached_eof)
+		ereport(ERROR,
+			(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				errmsg("unexpected EOF in COPY data")));
+
+	if (mode == 1)
+	{
+		cstate->pcdata->curr_data_block = data_block;
+		cstate->raw_buf_index = 0;
+	}
+	else if(mode == 2)
+	{
+		ParallelCopyDataBlock *prev_data_block = NULL;
+		prev_data_block = cstate->pcdata->curr_data_block;
+		prev_data_block->following_block = block_pos;
+		cstate->pcdata->curr_data_block = data_block;
+
+		if (prev_data_block->curr_blk_completed  == false)
+			prev_data_block->curr_blk_completed = true;
+
+		cstate->raw_buf_index = 0;
+	}
+}
+
+/*
+ * CopyReadBinaryTupleLeader - leader reads data from binary formatted file
+ * to data blocks and identies tuple boundaries/offsets so that workers
+ * can work on the data blocks data.
+ */
+static pg_attribute_always_inline bool
+CopyReadBinaryTupleLeader(CopyState cstate)
+{
+	int readbytes = 0;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	uint32 block_pos;
+	int16		fld_count;
+	ListCell   *cur;
+	FmgrInfo   *in_functions = cstate->in_functions;
+	Oid		   *typioparams = cstate->typioparams;
+	TupleDesc	tupDesc = RelationGetDescr(cstate->rel);
+	uint32      new_block_pos;
+	uint32      line_size = -1;
+	ParallelCopyTupleInfo curr_tuple_start_info;
+	ParallelCopyTupleInfo curr_tuple_end_info;
+
+	curr_tuple_start_info.block_id = -1;
+	curr_tuple_start_info.offset = -1;
+	curr_tuple_end_info.block_id = -1;
+	curr_tuple_end_info.offset = -1;
+
+	if (cstate->pcdata->curr_data_block == NULL)
+	{
+		block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+		cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[block_pos];
+
+		cstate->raw_buf_index = 0;
+
+		readbytes = CopyGetData(cstate, &cstate->pcdata->curr_data_block->data, 1, DATA_BLOCK_SIZE);
+
+		elog(DEBUG1, "LEADER - bytes read from file %d", readbytes);
+
+		if (cstate->reached_eof)
+			return true;
+	}
+
+	if (cstate->raw_buf_index + sizeof(fld_count) >= (DATA_BLOCK_SIZE - 1))
+		AdjustFieldInfo(cstate, 1);
+
+	memcpy(&fld_count, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_count));
+
+	fld_count = (int16) pg_ntoh16(fld_count);
+
+	CHECK_FIELD_COUNT;
+
+	cstate->raw_buf_index = cstate->raw_buf_index + sizeof(fld_count);
+	new_block_pos = pcshared_info->cur_block_pos;
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			attnum = lfirst_int(cur);
+		int			m = attnum - 1;
+		Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+		cstate->cur_attname = NameStr(att->attname);
+
+		CopyReadBinaryAttributeLeader(cstate,
+									&in_functions[m],
+									typioparams[m],
+									att->atttypmod,
+									&new_block_pos,
+									m,
+									&curr_tuple_start_info,
+									&curr_tuple_end_info,
+									&line_size);
+
+		cstate->cur_attname = NULL;
+	}
+
+	if (line_size > 0)
+	{
+		int line_pos = UpdateBlockInLineInfo(cstate,
+											curr_tuple_start_info.block_id,
+											curr_tuple_start_info.offset,
+											line_size,
+											LINE_LEADER_POPULATED);
+
+		pcshared_info->populated++;
+
+		elog(DEBUG1, "LEADER - adding - block:%u, offset:%u, line size:%u line position:%d",
+						 curr_tuple_start_info.block_id,
+						 curr_tuple_start_info.offset,
+						 line_size, line_pos);
+	}
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryAttributeLeader - leader identifies boundaries/offsets
+ * for each attribute/column, it moves on to next data block if the
+ * attribute/column is spread across data blocks.
+ */
+static pg_attribute_always_inline void
+CopyReadBinaryAttributeLeader(CopyState cstate, FmgrInfo *flinfo,
+	Oid typioparam, int32 typmod, uint32 *new_block_pos,
+	int m, ParallelCopyTupleInfo *tuple_start_info_ptr,
+	ParallelCopyTupleInfo *tuple_end_info_ptr, uint32 *line_size)
+{
+	int32		fld_size;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+	if (m == 0)
+	{
+		tuple_start_info_ptr->block_id = pcshared_info->cur_block_pos;
+		/* raw_buf_index would have moved away size of field count bytes
+		   in the caller, so move back to store the tuple start offset.
+		*/
+		tuple_start_info_ptr->offset =  cstate->raw_buf_index - sizeof(int16);
+	}
+
+	if ((cstate->raw_buf_index + sizeof(fld_size)) >= (DATA_BLOCK_SIZE - 1))
+	{
+		AdjustFieldInfo(cstate, 2);
+		*new_block_pos = pcshared_info->cur_block_pos;
+	}
+
+	memcpy(&fld_size, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_size));
+
+	cstate->raw_buf_index = cstate->raw_buf_index + sizeof(fld_size);
+
+	fld_size = (int32) pg_ntoh32(fld_size);
+
+	if (fld_size == 0)
+		ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("unexpected EOF in COPY data")));
+
+	if (fld_size < -1)
+		ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("invalid field size")));
+
+	if ((DATA_BLOCK_SIZE - cstate->raw_buf_index) >= fld_size)
+	{
+		cstate->raw_buf_index = cstate->raw_buf_index + fld_size;
+	}
+	else
+	{
+		ParallelCopyDataBlock *data_block = NULL;
+		ParallelCopyDataBlock *prev_data_block = NULL;
+		uint32 block_pos = *new_block_pos;
+		int readbytes;
+		int32 requiredblocks = 0;
+		int32 remainingbytesincurrdatablock = DATA_BLOCK_SIZE - cstate->raw_buf_index;
+		int i = 0;
+
+		/* field size can spread across multiple data blocks,
+		 * calculate the number of required data blocks and try to get
+		 * those many data blocks.
+		 */
+		requiredblocks = (int32)(fld_size - remainingbytesincurrdatablock)/(int32)DATA_BLOCK_SIZE;
+
+		if ((fld_size - remainingbytesincurrdatablock)%DATA_BLOCK_SIZE != 0)
+			requiredblocks++;
+
+		i = requiredblocks;
+
+		while(i > 0)
+		{
+			data_block = NULL;
+			prev_data_block = NULL;
+			readbytes = 0;
+
+			block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+			data_block = &pcshared_info->data_blocks[block_pos];
+
+			readbytes = CopyGetData(cstate, &data_block->data[0], 1, DATA_BLOCK_SIZE);
+
+			elog(DEBUG1, "LEADER - bytes read from file after detecting that tuple is spread across data blocks %d", readbytes);
+
+			/* eof here means that most probably,
+			 * the field size would have been corrupted.
+			 */
+			if (cstate->reached_eof)
+				ereport(ERROR,
+					(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+					errmsg("unexpected EOF in COPY data")));
+
+			prev_data_block = cstate->pcdata->curr_data_block;
+			prev_data_block->following_block = block_pos;
+
+			if (prev_data_block->curr_blk_completed  == false)
+				prev_data_block->curr_blk_completed = true;
+
+			cstate->pcdata->curr_data_block = data_block;
+
+			i--;
+		}
+
+		cstate->raw_buf_index = fld_size - (((requiredblocks - 1) * DATA_BLOCK_SIZE) +
+									remainingbytesincurrdatablock);
+
+		/* raw_buf_index should never cross data block size,
+		 * as the required number of data blocks would have
+		 * been obtained in the above while loop.
+		 */
+		Assert(cstate->raw_buf_index <= DATA_BLOCK_SIZE);
+
+		*new_block_pos = block_pos;
+	}
+
+	if (m == cstate->max_fields - 1)
+	{
+		tuple_end_info_ptr->block_id = *new_block_pos;
+		tuple_end_info_ptr->offset =  cstate->raw_buf_index - 1;
+
+		if (tuple_start_info_ptr->block_id == tuple_end_info_ptr->block_id)
+		{
+			elog(DEBUG1,"LEADER - tuple lies in a single data block");
+
+			*line_size = tuple_end_info_ptr->offset - tuple_start_info_ptr->offset + 1;
+			pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[tuple_start_info_ptr->block_id].unprocessed_line_parts, 1);
+		}
+		else
+		{
+			uint32 following_block_id = pcshared_info->data_blocks[tuple_start_info_ptr->block_id].following_block;
+
+			elog(DEBUG1,"LEADER - tuple is spread across data blocks");
+
+			*line_size = DATA_BLOCK_SIZE - tuple_start_info_ptr->offset -
+				pcshared_info->data_blocks[tuple_start_info_ptr->block_id].skip_bytes;
+
+			pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[tuple_start_info_ptr->block_id].unprocessed_line_parts, 1);
+
+			while (following_block_id != tuple_end_info_ptr->block_id)
+			{
+				*line_size = *line_size + DATA_BLOCK_SIZE - pcshared_info->data_blocks[following_block_id].skip_bytes;
+
+				pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[following_block_id].unprocessed_line_parts, 1);
+
+				following_block_id = pcshared_info->data_blocks[following_block_id].following_block;
+
+				if (following_block_id == -1)
+					break;
+			}
+
+			if (following_block_id != -1)
+				pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[following_block_id].unprocessed_line_parts, 1);
+
+			*line_size = *line_size + tuple_end_info_ptr->offset + 1;
+		}
+	}
+}
+
+/*
+ * CopyReadBinaryTupleWorker - each worker reads data from data blocks after
+ * getting leader-identified tuple offsets from ring data structure.
+ */
+static pg_attribute_always_inline bool
+CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls)
+{
+	uint32 line_pos;
+	ParallelCopyLineBoundary *line_info;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	int16		fld_count;
+	ListCell   *cur;
+	FmgrInfo   *in_functions = cstate->in_functions;
+	Oid		   *typioparams = cstate->typioparams;
+	TupleDesc	tupDesc = RelationGetDescr(cstate->rel);
+
+	line_pos = GetLinePosition(cstate);
+
+	if (line_pos == -1)
+		return true;
+
+	line_info = &pcshared_info->line_boundaries.ring[line_pos];
+	cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[line_info->first_block];
+	cstate->raw_buf_index = line_info->start_offset;
+
+	if (cstate->raw_buf_index + sizeof(fld_count) >= (DATA_BLOCK_SIZE - 1))
+		/*the case where field count spread across datablocks should never occur.
+		  as the leader would have moved it to next block*/
+		elog(DEBUG1, "WORKER - field count spread across datablocks should never occur");
+
+	memcpy(&fld_count, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_count));
+	fld_count = (int16) pg_ntoh16(fld_count);
+
+	CHECK_FIELD_COUNT;
+
+	cstate->raw_buf_index = cstate->raw_buf_index + sizeof(fld_count);
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			attnum = lfirst_int(cur);
+		int			m = attnum - 1;
+		Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+		cstate->cur_attname = NameStr(att->attname);
+
+		values[m] = CopyReadBinaryAttributeWorker(cstate,
+											&in_functions[m],
+											typioparams[m],
+											att->atttypmod,
+											&nulls[m]);
+		cstate->cur_attname = NULL;
+	}
+
+	pg_atomic_sub_fetch_u32(&cstate->pcdata->curr_data_block->unprocessed_line_parts, 1);
+	line_info->start_offset = -1;
+	pg_atomic_write_u32(&line_info->line_state, LINE_WORKER_PROCESSED);
+	pg_atomic_write_u32(&line_info->line_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryAttributeWorker - leader identifies boundaries/offsets
+ * for each attribute/column, it moves on to next data block if the
+ * attribute/column is spread across data blocks.
+ */
+static pg_attribute_always_inline Datum
+CopyReadBinaryAttributeWorker(CopyState cstate, FmgrInfo *flinfo,
+		Oid typioparam, int32 typmod, bool *isnull)
+{
+	int32		fld_size;
+	Datum		result;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+	if ((cstate->raw_buf_index + sizeof(fld_size)) >= (DATA_BLOCK_SIZE - 1))
+	{
+		ParallelCopyDataBlock *prev_data_block = cstate->pcdata->curr_data_block;
+
+		elog(DEBUG1, "WORKER - field size is spread across data blocks");
+
+		cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[cstate->pcdata->curr_data_block->following_block];
+		pg_atomic_sub_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+		cstate->raw_buf_index = 0;
+	}
+
+	memcpy(&fld_size, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_size));
+	fld_size = (int32) pg_ntoh32(fld_size);
+
+	if (fld_size == 0)
+		ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("unexpected EOF in COPY data")));
+
+	if (fld_size < -1)
+		ereport(ERROR,
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+				 errmsg("invalid field size")));
+
+	cstate->raw_buf_index = cstate->raw_buf_index + sizeof(fld_size);
+
+	/* reset attribute_buf to empty, and load raw data in it */
+	resetStringInfo(&cstate->attribute_buf);
+
+	enlargeStringInfo(&cstate->attribute_buf, fld_size);
+
+	if ((DATA_BLOCK_SIZE - cstate->raw_buf_index) >= fld_size)
+	{
+		elog(DEBUG1, "WORKER - tuple lies in single data block");
+
+		memcpy(&cstate->attribute_buf.data[0],&cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], fld_size);
+		cstate->raw_buf_index = cstate->raw_buf_index + fld_size;
+	}
+	else
+	{
+		ParallelCopyDataBlock *prev_data_block = cstate->pcdata->curr_data_block;
+
+		elog(DEBUG1, "WORKER - tuple is spread across data blocks");
+
+		memcpy(&cstate->attribute_buf.data[0], &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index],
+				(DATA_BLOCK_SIZE - cstate->raw_buf_index));
+		cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[cstate->pcdata->curr_data_block->following_block];
+		pg_atomic_sub_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+		memcpy(&cstate->attribute_buf.data[DATA_BLOCK_SIZE - cstate->raw_buf_index],
+			&cstate->pcdata->curr_data_block->data[0], (fld_size - (DATA_BLOCK_SIZE - cstate->raw_buf_index)));
+		cstate->raw_buf_index = fld_size - (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+	}
+
+	cstate->attribute_buf.len = fld_size;
+	cstate->attribute_buf.data[fld_size] = '\0';
+
+	/* Call the column type's binary input converter */
+	result = ReceiveFunctionCall(flinfo, &cstate->attribute_buf,
+								 typioparam, typmod);
+
+	/* Trouble if it didn't eat the whole buffer */
+	if (cstate->attribute_buf.cursor != cstate->attribute_buf.len)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+				 errmsg("incorrect binary data format")));
+
+	*isnull = false;
+	return result;
+}
+
+/*
+ * GetLinePosition - return the line position that worker should pcdata->process.
  */
 static uint32
 GetLinePosition(CopyState cstate)
@@ -1801,7 +2369,9 @@ GetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
 		{
 			dataBlkPtr->curr_blk_completed = false;
 			dataBlkPtr->skip_bytes = 0;
+			dataBlkPtr->following_block = -1;
 			pcshared_info->cur_block_pos = block_pos;
+			MemSet(&dataBlkPtr->data[0], 0, DATA_BLOCK_SIZE);
 			return block_pos;
 		}
 
@@ -5476,60 +6046,47 @@ NextCopyFrom(CopyState cstate, ExprContext *econtext,
 	else
 	{
 		/* binary */
-		int16		fld_count;
-		ListCell   *cur;
-
-		cstate->cur_lineno++;
-
-		if (!CopyGetInt16(cstate, &fld_count))
+		if (!IsParallelCopy())
 		{
-			/* EOF detected (end of file, or protocol-level EOF) */
-			return false;
-		}
+			int16		fld_count;
+			ListCell   *cur;
 
-		if (fld_count == -1)
-		{
-			/*
-			 * Received EOF marker.  In a V3-protocol copy, wait for the
-			 * protocol-level EOF, and complain if it doesn't come
-			 * immediately.  This ensures that we correctly handle CopyFail,
-			 * if client chooses to send that now.
-			 *
-			 * Note that we MUST NOT try to read more data in an old-protocol
-			 * copy, since there is no protocol-level EOF marker then.  We
-			 * could go either way for copy from file, but choose to throw
-			 * error if there's data after the EOF marker, for consistency
-			 * with the new-protocol case.
-			 */
-			char		dummy;
+			cstate->cur_lineno++;
+			cstate->max_fields = list_length(cstate->attnumlist);
 
-			if (cstate->copy_dest != COPY_OLD_FE &&
-				CopyGetData(cstate, &dummy, 1, 1) > 0)
-				ereport(ERROR,
-						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-						 errmsg("received copy data after EOF marker")));
-			return false;
-		}
+			if (!CopyGetInt16(cstate, &fld_count))
+			{
+				/* EOF detected (end of file, or protocol-level EOF) */
+				return false;
+			}
 
-		if (fld_count != attr_count)
-			ereport(ERROR,
-					(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-					 errmsg("row field count is %d, expected %d",
-							(int) fld_count, attr_count)));
+			CHECK_FIELD_COUNT;
 
-		foreach(cur, cstate->attnumlist)
+			foreach(cur, cstate->attnumlist)
+			{
+				int			attnum = lfirst_int(cur);
+				int			m = attnum - 1;
+				Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+
+				cstate->cur_attname = NameStr(att->attname);
+				values[m] = CopyReadBinaryAttribute(cstate,
+													&in_functions[m],
+													typioparams[m],
+													att->atttypmod,
+													&nulls[m]);
+				cstate->cur_attname = NULL;
+			}
+		}
+		else
 		{
-			int			attnum = lfirst_int(cur);
-			int			m = attnum - 1;
-			Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+			bool eof = false;
+			cstate->cur_lineno++;
+			cstate->max_fields = list_length(cstate->attnumlist);
 
-			cstate->cur_attname = NameStr(att->attname);
-			values[m] = CopyReadBinaryAttribute(cstate,
-												&in_functions[m],
-												typioparams[m],
-												att->atttypmod,
-												&nulls[m]);
-			cstate->cur_attname = NULL;
+			eof = CopyReadBinaryTupleWorker(cstate, values, nulls);
+
+			if (eof)
+				return false;
 		}
 	}
 
-- 
1.8.3.1

#108vignesh C
vignesh21@gmail.com
In reply to: Bharath Rupireddy (#102)
Re: Parallel copy

On Wed, Jun 24, 2020 at 1:41 PM Bharath Rupireddy
<bharath.rupireddyforpostgres@gmail.com> wrote:

Along with the review comments addressed
patch(0006-Parallel-Copy-For-Binary-Format-Files.patch) also attaching
all other latest series of patches(0001 to 0005) from [1], the order
of applying patches is from 0001 to 0006.

[1] /messages/by-id/CALDaNm0H3N9gK7CMheoaXkO99g=uAPA93nSZXu0xDarPyPY6sg@mail.gmail.com

Some comments:

+       movebytes = DATA_BLOCK_SIZE - cstate->raw_buf_index;
+
+       cstate->pcdata->curr_data_block->skip_bytes = movebytes;
+
+       data_block = &pcshared_info->data_blocks[block_pos];
+
+       if (movebytes > 0)
+               memmove(&data_block->data[0],
&cstate->pcdata->curr_data_block->data[cstate->raw_buf_index],
+                       movebytes);
we can create a local variable and use in place of
cstate->pcdata->curr_data_block.
+       if (cstate->raw_buf_index + sizeof(fld_count) >= (DATA_BLOCK_SIZE - 1))
+               AdjustFieldInfo(cstate, 1);
+
+       memcpy(&fld_count,
&cstate->pcdata->curr_data_block->data[cstate->raw_buf_index],
sizeof(fld_count));
Should this be like below, as the remaining size can fit in current block:
       if (cstate->raw_buf_index + sizeof(fld_count) >= DATA_BLOCK_SIZE)
+       if ((cstate->raw_buf_index + sizeof(fld_size)) >= (DATA_BLOCK_SIZE - 1))
+       {
+               AdjustFieldInfo(cstate, 2);
+               *new_block_pos = pcshared_info->cur_block_pos;
+       }
Same like above.
+       movebytes = DATA_BLOCK_SIZE - cstate->raw_buf_index;
+
+       cstate->pcdata->curr_data_block->skip_bytes = movebytes;
+
+       data_block = &pcshared_info->data_blocks[block_pos];
+
+       if (movebytes > 0)
Instead of the above check, we can have an assert check for movebytes.
+       if (mode == 1)
+       {
+               cstate->pcdata->curr_data_block = data_block;
+               cstate->raw_buf_index = 0;
+       }
+       else if(mode == 2)
+       {
+               ParallelCopyDataBlock *prev_data_block = NULL;
+               prev_data_block = cstate->pcdata->curr_data_block;
+               prev_data_block->following_block = block_pos;
+               cstate->pcdata->curr_data_block = data_block;
+
+               if (prev_data_block->curr_blk_completed  == false)
+                       prev_data_block->curr_blk_completed = true;
+
+               cstate->raw_buf_index = 0;
+       }

This code is common for both, keep in common flow and remove if (mode == 1)
cstate->pcdata->curr_data_block = data_block;
cstate->raw_buf_index = 0;

+#define CHECK_FIELD_COUNT \
+{\
+       if (fld_count == -1) \
+       { \
+               if (IsParallelCopy() && \
+                       !IsLeader()) \
+                       return true; \
+               else if (IsParallelCopy() && \
+                       IsLeader()) \
+               { \
+                       if
(cstate->pcdata->curr_data_block->data[cstate->raw_buf_index +
sizeof(fld_count)] != 0) \
+                               ereport(ERROR, \
+
(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+                                               errmsg("received copy
data after EOF marker"))); \
+                       return true; \
+               } \
We only copy sizeof(fld_count), Shouldn't we check fld_count !=
cstate->max_fields? Am I missing something here?
+       if ((cstate->raw_buf_index + sizeof(fld_size)) >= (DATA_BLOCK_SIZE - 1))
+       {
+               AdjustFieldInfo(cstate, 2);
+               *new_block_pos = pcshared_info->cur_block_pos;
+       }
+
+       memcpy(&fld_size,
&cstate->pcdata->curr_data_block->data[cstate->raw_buf_index],
sizeof(fld_size));
+
+       cstate->raw_buf_index = cstate->raw_buf_index + sizeof(fld_size);
+
+       fld_size = (int32) pg_ntoh32(fld_size);
+
+       if (fld_size == 0)
+               ereport(ERROR,
+                               (errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+                                errmsg("unexpected EOF in COPY data")));
+
+       if (fld_size < -1)
+               ereport(ERROR,
+                               (errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+                                errmsg("invalid field size")));
+
+       if ((DATA_BLOCK_SIZE - cstate->raw_buf_index) >= fld_size)
+       {
+               cstate->raw_buf_index = cstate->raw_buf_index + fld_size;
+       }
We can keep the check like cstate->raw_buf_index + fld_size < ..., for
better readability and consistency.
+static pg_attribute_always_inline void
+CopyReadBinaryAttributeLeader(CopyState cstate, FmgrInfo *flinfo,
+       Oid typioparam, int32 typmod, uint32 *new_block_pos,
+       int m, ParallelCopyTupleInfo *tuple_start_info_ptr,
+       ParallelCopyTupleInfo *tuple_end_info_ptr, uint32 *line_size)
flinfo, typioparam & typmod is not used, we can remove the parameter.
+static pg_attribute_always_inline void
+CopyReadBinaryAttributeLeader(CopyState cstate, FmgrInfo *flinfo,
+       Oid typioparam, int32 typmod, uint32 *new_block_pos,
+       int m, ParallelCopyTupleInfo *tuple_start_info_ptr,
+       ParallelCopyTupleInfo *tuple_end_info_ptr, uint32 *line_size)
I felt this function need not be an inline function.
+               /* binary format */
+               /* for paralle copy leader, fill in the error
There are some typos, run spell check
+               /* raw_buf_index should never cross data block size,
+                * as the required number of data blocks would have
+                * been obtained in the above while loop.
+                */
There are few places, commenting style should be changed to postgres style
+       if (cstate->pcdata->curr_data_block == NULL)
+       {
+               block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+               cstate->pcdata->curr_data_block =
&pcshared_info->data_blocks[block_pos];
+
+               cstate->raw_buf_index = 0;
+
+               readbytes = CopyGetData(cstate,
&cstate->pcdata->curr_data_block->data, 1, DATA_BLOCK_SIZE);
+
+               elog(DEBUG1, "LEADER - bytes read from file %d", readbytes);
+
+               if (cstate->reached_eof)
+                       return true;
+       }
There are many empty lines, these are not required.
+       if (cstate->raw_buf_index + sizeof(fld_count) >= (DATA_BLOCK_SIZE - 1))
+               AdjustFieldInfo(cstate, 1);
+
+       memcpy(&fld_count,
&cstate->pcdata->curr_data_block->data[cstate->raw_buf_index],
sizeof(fld_count));
+
+       fld_count = (int16) pg_ntoh16(fld_count);
+
+       CHECK_FIELD_COUNT;
+
+       cstate->raw_buf_index = cstate->raw_buf_index + sizeof(fld_count);
+       new_block_pos = pcshared_info->cur_block_pos;
You can run pg_indent once for the changes.
+       if (mode == 1)
+       {
+               cstate->pcdata->curr_data_block = data_block;
+               cstate->raw_buf_index = 0;
+       }
+       else if(mode == 2)
+       {
Could use macros for 1 & 2 for better readability.
+               if (tuple_start_info_ptr->block_id ==
tuple_end_info_ptr->block_id)
+               {
+                       elog(DEBUG1,"LEADER - tuple lies in a single
data block");
+
+                       *line_size = tuple_end_info_ptr->offset -
tuple_start_info_ptr->offset + 1;
+
pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[tuple_start_info_ptr->block_id].unprocessed_line_parts,
1);
+               }
+               else
+               {
+                       uint32 following_block_id =
pcshared_info->data_blocks[tuple_start_info_ptr->block_id].following_block;
+
+                       elog(DEBUG1,"LEADER - tuple is spread across
data blocks");
+
+                       *line_size = DATA_BLOCK_SIZE -
tuple_start_info_ptr->offset -
+
pcshared_info->data_blocks[tuple_start_info_ptr->block_id].skip_bytes;
+
+
pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[tuple_start_info_ptr->block_id].unprocessed_line_parts,
1);
+
+                       while (following_block_id !=
tuple_end_info_ptr->block_id)
+                       {
+                               *line_size = *line_size +
DATA_BLOCK_SIZE -
pcshared_info->data_blocks[following_block_id].skip_bytes;
+
+
pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[following_block_id].unprocessed_line_parts,
1);
+
+                               following_block_id =
pcshared_info->data_blocks[following_block_id].following_block;
+
+                               if (following_block_id == -1)
+                                       break;
+                       }
+
+                       if (following_block_id != -1)
+
pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[following_block_id].unprocessed_line_parts,
1);
+
+                       *line_size = *line_size +
tuple_end_info_ptr->offset + 1;
+               }
We could calculate the size as we parse and identify one record, if we
do that way this can be removed.

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

#109Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: vignesh C (#108)
6 attachment(s)
Re: Parallel copy

Thanks Vignesh for the review. Addressed the comments in 0006 patch.

we can create a local variable and use in place of
cstate->pcdata->curr_data_block.

Done.

+       if (cstate->raw_buf_index + sizeof(fld_count) >= (DATA_BLOCK_SIZE - 1))
+               AdjustFieldInfo(cstate, 1);
+
+       memcpy(&fld_count,
&cstate->pcdata->curr_data_block->data[cstate->raw_buf_index],
sizeof(fld_count));
Should this be like below, as the remaining size can fit in current block:
if (cstate->raw_buf_index + sizeof(fld_count) >= DATA_BLOCK_SIZE)
+       if ((cstate->raw_buf_index + sizeof(fld_size)) >= (DATA_BLOCK_SIZE - 1))
+       {
+               AdjustFieldInfo(cstate, 2);
+               *new_block_pos = pcshared_info->cur_block_pos;
+       }
Same like above.

Yes you are right. Changed.

+       movebytes = DATA_BLOCK_SIZE - cstate->raw_buf_index;
+
+       cstate->pcdata->curr_data_block->skip_bytes = movebytes;
+
+       data_block = &pcshared_info->data_blocks[block_pos];
+
+       if (movebytes > 0)
Instead of the above check, we can have an assert check for movebytes.

No, we can't use assert here. For the edge case where the current data
block is full to the size DATA_BLOCK_SIZE, then movebytes will be 0,
but we need to get a new data block. We avoid memmove by having
movebytes>0 check.

+       if (mode == 1)
+       {
+               cstate->pcdata->curr_data_block = data_block;
+               cstate->raw_buf_index = 0;
+       }
+       else if(mode == 2)
+       {
+               ParallelCopyDataBlock *prev_data_block = NULL;
+               prev_data_block = cstate->pcdata->curr_data_block;
+               prev_data_block->following_block = block_pos;
+               cstate->pcdata->curr_data_block = data_block;
+
+               if (prev_data_block->curr_blk_completed  == false)
+                       prev_data_block->curr_blk_completed = true;
+
+               cstate->raw_buf_index = 0;
+       }

This code is common for both, keep in common flow and remove if (mode == 1)
cstate->pcdata->curr_data_block = data_block;
cstate->raw_buf_index = 0;

Done.

+#define CHECK_FIELD_COUNT \
+{\
+       if (fld_count == -1) \
+       { \
+               if (IsParallelCopy() && \
+                       !IsLeader()) \
+                       return true; \
+               else if (IsParallelCopy() && \
+                       IsLeader()) \
+               { \
+                       if
(cstate->pcdata->curr_data_block->data[cstate->raw_buf_index +
sizeof(fld_count)] != 0) \
+                               ereport(ERROR, \
+
(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+                                               errmsg("received copy
data after EOF marker"))); \
+                       return true; \
+               } \
We only copy sizeof(fld_count), Shouldn't we check fld_count !=
cstate->max_fields? Am I missing something here?

fld_count != cstate->max_fields check is done after the above checks.

+       if ((DATA_BLOCK_SIZE - cstate->raw_buf_index) >= fld_size)
+       {
+               cstate->raw_buf_index = cstate->raw_buf_index + fld_size;
+       }
We can keep the check like cstate->raw_buf_index + fld_size < ..., for
better readability and consistency.

I think this is okay. It gives a good meaning that available bytes in
the current data block is greater or equal to fld_size then, the tuple
lies in the current data block.

+static pg_attribute_always_inline void
+CopyReadBinaryAttributeLeader(CopyState cstate, FmgrInfo *flinfo,
+       Oid typioparam, int32 typmod, uint32 *new_block_pos,
+       int m, ParallelCopyTupleInfo *tuple_start_info_ptr,
+       ParallelCopyTupleInfo *tuple_end_info_ptr, uint32 *line_size)
flinfo, typioparam & typmod is not used, we can remove the parameter.

Done.

+static pg_attribute_always_inline void
+CopyReadBinaryAttributeLeader(CopyState cstate, FmgrInfo *flinfo,
+       Oid typioparam, int32 typmod, uint32 *new_block_pos,
+       int m, ParallelCopyTupleInfo *tuple_start_info_ptr,
+       ParallelCopyTupleInfo *tuple_end_info_ptr, uint32 *line_size)
I felt this function need not be an inline function.

Yes. Changed.

+               /* binary format */
+               /* for paralle copy leader, fill in the error
There are some typos, run spell check

Done.

+               /* raw_buf_index should never cross data block size,
+                * as the required number of data blocks would have
+                * been obtained in the above while loop.
+                */
There are few places, commenting style should be changed to postgres style

Changed.

+       if (cstate->pcdata->curr_data_block == NULL)
+       {
+               block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+               cstate->pcdata->curr_data_block =
&pcshared_info->data_blocks[block_pos];
+
+               cstate->raw_buf_index = 0;
+
+               readbytes = CopyGetData(cstate,
&cstate->pcdata->curr_data_block->data, 1, DATA_BLOCK_SIZE);
+
+               elog(DEBUG1, "LEADER - bytes read from file %d", readbytes);
+
+               if (cstate->reached_eof)
+                       return true;
+       }
There are many empty lines, these are not required.

Removed.

+
+       fld_count = (int16) pg_ntoh16(fld_count);
+
+       CHECK_FIELD_COUNT;
+
+       cstate->raw_buf_index = cstate->raw_buf_index + sizeof(fld_count);
+       new_block_pos = pcshared_info->cur_block_pos;
You can run pg_indent once for the changes.

I ran pg_indent and observed that there are many places getting
modified by pg_indent. If we need to run pg_indet on copy.c for
parallel copy alone, then first, we need to run on plane copy.c and
take those changes and then run for all parallel copy files. I think
we better run pg_indent, for all the parallel copy patches once and
for all, maybe just before we kind of finish up all the code reviews.

+       if (mode == 1)
+       {
+               cstate->pcdata->curr_data_block = data_block;
+               cstate->raw_buf_index = 0;
+       }
+       else if(mode == 2)
+       {
Could use macros for 1 & 2 for better readability.

Done.

+
+                               if (following_block_id == -1)
+                                       break;
+                       }
+
+                       if (following_block_id != -1)
+
pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[following_block_id].unprocessed_line_parts,
1);
+
+                       *line_size = *line_size +
tuple_end_info_ptr->offset + 1;
+               }
We could calculate the size as we parse and identify one record, if we
do that way this can be removed.

Done.

With Regards,
Bharath Rupireddy.
EnterpriseDB: http://www.enterprisedb.com

Attachments:

0001-Copy-code-readjustment-to-support-parallel-copy.patchapplication/octet-stream; name=0001-Copy-code-readjustment-to-support-parallel-copy.patchDownload
From fe65142a5d461cf457ea87abdd62ab88feb62bea Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Tue, 23 Jun 2020 06:49:22 +0530
Subject: [PATCH 1/6] Copy code readjustment to support parallel copy.

This patch has the copy code slightly readjusted so that the common code is
separated to functions/macros, these functions/macros will be used by the
workers in the parallel copy code of the upcoming patches. EOL removal is moved
from CopyReadLine to CopyReadLineText, this change was required because in case
of parallel copy the record identification and record updation is done in
CopyReadLineText, before record information is updated in shared memory the new
line characters should be removed.
---
 src/backend/commands/copy.c | 372 ++++++++++++++++++++++++++------------------
 1 file changed, 221 insertions(+), 151 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 3e199bd..33ee891 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -95,6 +95,9 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
+#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+#define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
+
 /*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
@@ -219,7 +222,6 @@ typedef struct CopyStateData
 	 * converts it.  Note: we guarantee that there is a \0 at
 	 * raw_buf[raw_buf_len].
 	 */
-#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
@@ -347,6 +349,88 @@ if (1) \
 	goto not_end_of_copy; \
 } else ((void) 0)
 
+/*
+ * CONVERT_TO_SERVER_ENCODING - convert contents to server encoding.
+ */
+#define CONVERT_TO_SERVER_ENCODING(cstate) \
+{ \
+	/* Done reading the line.  Convert it to server encoding. */ \
+	if (cstate->need_transcoding) \
+	{ \
+		char	   *cvt; \
+		cvt = pg_any_to_server(cstate->line_buf.data, \
+							   cstate->line_buf.len, \
+							   cstate->file_encoding); \
+		if (cvt != cstate->line_buf.data) \
+		{ \
+			/* transfer converted data back to line_buf */ \
+			resetStringInfo(&cstate->line_buf); \
+			appendBinaryStringInfo(&cstate->line_buf, cvt, strlen(cvt)); \
+			pfree(cvt); \
+		} \
+	} \
+	/* Now it's safe to use the buffer in error messages */ \
+	cstate->line_buf_converted = true; \
+}
+
+/*
+ * CLEAR_EOL_FROM_COPIED_DATA - Clear EOL from the copied data.
+ */
+#define CLEAR_EOL_FROM_COPIED_DATA(copy_line_data, copy_line_pos, copy_line_size) \
+{ \
+	/* \
+	 * If we didn't hit EOF, then we must have transferred the EOL marker \
+	 * to line_buf along with the data.  Get rid of it. \
+	 */ \
+   switch (cstate->eol_type) \
+   { \
+	   case EOL_NL: \
+		   Assert(copy_line_size >= 1); \
+		   Assert(copy_line_data[copy_line_pos - 1] == '\n'); \
+		   copy_line_data[copy_line_pos - 1] = '\0'; \
+		   copy_line_size--; \
+		   break; \
+	   case EOL_CR: \
+		   Assert(copy_line_size >= 1); \
+		   Assert(copy_line_data[copy_line_pos - 1] == '\r'); \
+		   copy_line_data[copy_line_pos - 1] = '\0'; \
+		   copy_line_size--; \
+		   break; \
+	   case EOL_CRNL: \
+		   Assert(copy_line_size >= 2); \
+		   Assert(copy_line_data[copy_line_pos - 2] == '\r'); \
+		   Assert(copy_line_data[copy_line_pos - 1] == '\n'); \
+		   copy_line_data[copy_line_pos - 2] = '\0'; \
+		   copy_line_size -= 2; \
+		   break; \
+	   case EOL_UNKNOWN: \
+		   /* shouldn't get here */ \
+		   Assert(false); \
+		   break; \
+   } \
+}
+
+/*
+ * CLEAR_EOL_LINE - Wrapper for clearing EOL.
+ */
+#define CLEAR_EOL_LINE() \
+if (!result && !IsHeaderLine()) \
+	CLEAR_EOL_FROM_COPIED_DATA(cstate->line_buf.data, \
+								cstate->line_buf.len, \
+								cstate->line_buf.len) \
+
+/*
+ * INCREMENTPROCESSED - Increment the lines processed.
+ */
+#define INCREMENTPROCESSED(processed)  \
+processed++;
+
+/*
+ * GETPROCESSED - Get the lines processed.
+ */
+#define GETPROCESSED(processed) \
+return processed;
+
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
 
@@ -392,6 +476,8 @@ static bool CopyGetInt32(CopyState cstate, int32 *val);
 static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 
+static void PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tup_desc,
+							   List *attnamelist);
 
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
@@ -793,6 +879,7 @@ CopyLoadRawBuf(CopyState cstate)
 {
 	int			nbytes;
 	int			inbytes;
+	int         minread = 1;
 
 	if (cstate->raw_buf_index < cstate->raw_buf_len)
 	{
@@ -804,8 +891,11 @@ CopyLoadRawBuf(CopyState cstate)
 	else
 		nbytes = 0;				/* no data need be saved */
 
+	if (cstate->copy_dest == COPY_NEW_FE)
+		minread = RAW_BUF_SIZE - nbytes;
+
 	inbytes = CopyGetData(cstate, cstate->raw_buf + nbytes,
-						  1, RAW_BUF_SIZE - nbytes);
+						  minread, RAW_BUF_SIZE - nbytes);
 	nbytes += inbytes;
 	cstate->raw_buf[nbytes] = '\0';
 	cstate->raw_buf_index = 0;
@@ -1463,7 +1553,6 @@ BeginCopy(ParseState *pstate,
 {
 	CopyState	cstate;
 	TupleDesc	tupDesc;
-	int			num_phys_attrs;
 	MemoryContext oldcontext;
 
 	/* Allocate workspace and zero all fields */
@@ -1629,6 +1718,24 @@ BeginCopy(ParseState *pstate,
 		tupDesc = cstate->queryDesc->tupDesc;
 	}
 
+	PopulateGlobalsForCopyFrom(cstate, tupDesc, attnamelist);
+	cstate->copy_dest = COPY_FILE;	/* default */
+
+	MemoryContextSwitchTo(oldcontext);
+
+	return cstate;
+}
+
+/*
+ * PopulateGlobalsForCopyFrom - Populates the common variables required for copy
+ * from operation. This is a helper function for BeginCopy function.
+ */
+static void
+PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tupDesc,
+							List *attnamelist)
+{
+	int			num_phys_attrs;
+
 	/* Generate or convert list of attributes to process */
 	cstate->attnumlist = CopyGetAttnums(tupDesc, cstate->rel, attnamelist);
 
@@ -1748,12 +1855,6 @@ BeginCopy(ParseState *pstate,
 		 pg_database_encoding_max_length() > 1);
 	/* See Multibyte encoding comment above */
 	cstate->encoding_embeds_ascii = PG_ENCODING_IS_CLIENT_ONLY(cstate->file_encoding);
-
-	cstate->copy_dest = COPY_FILE;	/* default */
-
-	MemoryContextSwitchTo(oldcontext);
-
-	return cstate;
 }
 
 /*
@@ -2642,32 +2743,11 @@ CopyMultiInsertInfoStore(CopyMultiInsertInfo *miinfo, ResultRelInfo *rri,
 }
 
 /*
- * Copy FROM file to relation.
+ * Check if the relation specified in copy from is valid.
  */
-uint64
-CopyFrom(CopyState cstate)
+static void
+CheckTargetRelValidity(CopyState cstate)
 {
-	ResultRelInfo *resultRelInfo;
-	ResultRelInfo *target_resultRelInfo;
-	ResultRelInfo *prevResultRelInfo = NULL;
-	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
-	ModifyTableState *mtstate;
-	ExprContext *econtext;
-	TupleTableSlot *singleslot = NULL;
-	MemoryContext oldcontext = CurrentMemoryContext;
-
-	PartitionTupleRouting *proute = NULL;
-	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
-	int			ti_options = 0; /* start with default options for insert */
-	BulkInsertState bistate = NULL;
-	CopyInsertMethod insertMethod;
-	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
-	uint64		processed = 0;
-	bool		has_before_insert_row_trig;
-	bool		has_instead_insert_row_trig;
-	bool		leafpart_use_multi_insert = false;
-
 	Assert(cstate->rel);
 
 	/*
@@ -2704,27 +2784,6 @@ CopyFrom(CopyState cstate)
 							RelationGetRelationName(cstate->rel))));
 	}
 
-	/*
-	 * If the target file is new-in-transaction, we assume that checking FSM
-	 * for free space is a waste of time.  This could possibly be wrong, but
-	 * it's unlikely.
-	 */
-	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
-		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
-		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
-		ti_options |= TABLE_INSERT_SKIP_FSM;
-
-	/*
-	 * Optimize if new relfilenode was created in this subxact or one of its
-	 * committed children and we won't see those rows later as part of an
-	 * earlier scan or command. The subxact test ensures that if this subxact
-	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
-	 * that the stronger test of exactly which subtransaction created it is
-	 * crucial for correctness of this optimization. The test for an earlier
-	 * scan or command tolerates false negatives. FREEZE causes other sessions
-	 * to see rows they would not see under MVCC, and a false negative merely
-	 * spreads that anomaly to the current session.
-	 */
 	if (cstate->freeze)
 	{
 		/*
@@ -2762,9 +2821,61 @@ CopyFrom(CopyState cstate)
 			ereport(ERROR,
 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 					 errmsg("cannot perform COPY FREEZE because the table was not created or truncated in the current subtransaction")));
+	}
+}
+
+/*
+ * Copy FROM file to relation.
+ */
+uint64
+CopyFrom(CopyState cstate)
+{
+	ResultRelInfo *resultRelInfo;
+	ResultRelInfo *target_resultRelInfo;
+	ResultRelInfo *prevResultRelInfo = NULL;
+	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
+	ModifyTableState *mtstate;
+	ExprContext *econtext;
+	TupleTableSlot *singleslot = NULL;
+	MemoryContext oldcontext = CurrentMemoryContext;
+
+	PartitionTupleRouting *proute = NULL;
+	ErrorContextCallback errcallback;
+	CommandId	mycid = GetCurrentCommandId(true);
+	int			ti_options = 0; /* start with default options for insert */
+	BulkInsertState bistate = NULL;
+	CopyInsertMethod insertMethod;
+	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
+	uint64		processed = 0;
+	bool		has_before_insert_row_trig;
+	bool		has_instead_insert_row_trig;
+	bool		leafpart_use_multi_insert = false;
+
+	CheckTargetRelValidity(cstate);
 
+	/*
+	 * If the target file is new-in-transaction, we assume that checking FSM
+	 * for free space is a waste of time.  This could possibly be wrong, but
+	 * it's unlikely.
+	 */
+	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
+		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
+		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
+		ti_options |= TABLE_INSERT_SKIP_FSM;
+
+	/*
+	 * Optimize if new relfilenode was created in this subxact or one of its
+	 * committed children and we won't see those rows later as part of an
+	 * earlier scan or command. The subxact test ensures that if this subxact
+	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
+	 * that the stronger test of exactly which subtransaction created it is
+	 * crucial for correctness of this optimization. The test for an earlier
+	 * scan or command tolerates false negatives. FREEZE causes other sessions
+	 * to see rows they would not see under MVCC, and a false negative merely
+	 * spreads that anomaly to the current session.
+	 */
+	if (cstate->freeze)
 		ti_options |= TABLE_INSERT_FROZEN;
-	}
 
 	/*
 	 * We need a ResultRelInfo so we can use the regular executor's
@@ -3257,7 +3368,7 @@ CopyFrom(CopyState cstate)
 			 * or FDW; this is the same definition used by nodeModifyTable.c
 			 * for counting tuples inserted by an INSERT command.
 			 */
-			processed++;
+			INCREMENTPROCESSED(processed)
 		}
 	}
 
@@ -3312,30 +3423,15 @@ CopyFrom(CopyState cstate)
 
 	FreeExecutorState(estate);
 
-	return processed;
+	GETPROCESSED(processed)
 }
 
 /*
- * Setup to read tuples from a file for COPY FROM.
- *
- * 'rel': Used as a template for the tuples
- * 'filename': Name of server-local file to read
- * 'attnamelist': List of char *, columns to include. NIL selects all cols.
- * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
- *
- * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ * PopulateCatalogInformation - populate the catalog information.
  */
-CopyState
-BeginCopyFrom(ParseState *pstate,
-			  Relation rel,
-			  const char *filename,
-			  bool is_program,
-			  copy_data_source_cb data_source_cb,
-			  List *attnamelist,
-			  List *options)
+static void
+PopulateCatalogInformation(CopyState cstate)
 {
-	CopyState	cstate;
-	bool		pipe = (filename == NULL);
 	TupleDesc	tupDesc;
 	AttrNumber	num_phys_attrs,
 				num_defaults;
@@ -3345,31 +3441,8 @@ BeginCopyFrom(ParseState *pstate,
 	Oid			in_func_oid;
 	int		   *defmap;
 	ExprState **defexprs;
-	MemoryContext oldcontext;
 	bool		volatile_defexprs;
 
-	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
-	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
-
-	/* Initialize state variables */
-	cstate->reached_eof = false;
-	cstate->eol_type = EOL_UNKNOWN;
-	cstate->cur_relname = RelationGetRelationName(cstate->rel);
-	cstate->cur_lineno = 0;
-	cstate->cur_attname = NULL;
-	cstate->cur_attval = NULL;
-
-	/* Set up variables to avoid per-attribute overhead. */
-	initStringInfo(&cstate->attribute_buf);
-	initStringInfo(&cstate->line_buf);
-	cstate->line_buf_converted = false;
-	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
-	cstate->raw_buf_index = cstate->raw_buf_len = 0;
-
-	/* Assign range table, we'll need it in CopyFrom. */
-	if (pstate)
-		cstate->range_table = pstate->p_rtable;
-
 	tupDesc = RelationGetDescr(cstate->rel);
 	num_phys_attrs = tupDesc->natts;
 	num_defaults = 0;
@@ -3447,6 +3520,54 @@ BeginCopyFrom(ParseState *pstate,
 	cstate->defexprs = defexprs;
 	cstate->volatile_defexprs = volatile_defexprs;
 	cstate->num_defaults = num_defaults;
+}
+
+/*
+ * Setup to read tuples from a file for COPY FROM.
+ *
+ * 'rel': Used as a template for the tuples
+ * 'filename': Name of server-local file to read
+ * 'attnamelist': List of char *, columns to include. NIL selects all cols.
+ * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
+ *
+ * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ */
+CopyState
+BeginCopyFrom(ParseState *pstate,
+			  Relation rel,
+			  const char *filename,
+			  bool is_program,
+			  copy_data_source_cb data_source_cb,
+			  List *attnamelist,
+			  List *options)
+{
+	CopyState	cstate;
+	bool		pipe = (filename == NULL);
+	MemoryContext oldcontext;
+
+	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	/* Initialize state variables */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/* Set up variables to avoid per-attribute overhead. */
+	initStringInfo(&cstate->attribute_buf);
+	initStringInfo(&cstate->line_buf);
+	cstate->line_buf_converted = false;
+	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+
+	/* Assign range table, we'll need it in CopyFrom. */
+	if (pstate)
+		cstate->range_table = pstate->p_rtable;
+
+	PopulateCatalogInformation(cstate);
 	cstate->is_program = is_program;
 
 	if (data_source_cb)
@@ -3856,60 +3977,8 @@ CopyReadLine(CopyState cstate)
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
-	else
-	{
-		/*
-		 * If we didn't hit EOF, then we must have transferred the EOL marker
-		 * to line_buf along with the data.  Get rid of it.
-		 */
-		switch (cstate->eol_type)
-		{
-			case EOL_NL:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CR:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\r');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CRNL:
-				Assert(cstate->line_buf.len >= 2);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 2] == '\r');
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len -= 2;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_UNKNOWN:
-				/* shouldn't get here */
-				Assert(false);
-				break;
-		}
-	}
-
-	/* Done reading the line.  Convert it to server encoding. */
-	if (cstate->need_transcoding)
-	{
-		char	   *cvt;
-
-		cvt = pg_any_to_server(cstate->line_buf.data,
-							   cstate->line_buf.len,
-							   cstate->file_encoding);
-		if (cvt != cstate->line_buf.data)
-		{
-			/* transfer converted data back to line_buf */
-			resetStringInfo(&cstate->line_buf);
-			appendBinaryStringInfo(&cstate->line_buf, cvt, strlen(cvt));
-			pfree(cvt);
-		}
-	}
-
-	/* Now it's safe to use the buffer in error messages */
-	cstate->line_buf_converted = true;
 
+	CONVERT_TO_SERVER_ENCODING(cstate)
 	return result;
 }
 
@@ -4273,6 +4342,7 @@ not_end_of_copy:
 	 * Transfer any still-uncopied data to line_buf.
 	 */
 	REFILL_LINEBUF;
+	CLEAR_EOL_LINE()
 
 	return result;
 }
-- 
1.8.3.1

0002-Framework-for-leader-worker-in-parallel-copy.patchapplication/octet-stream; name=0002-Framework-for-leader-worker-in-parallel-copy.patchDownload
From f852a2d53aa2107b90899df9b8c07824b131e498 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>, Bharath <bharath.rupireddyforpostgres@gmail.com>
Date: Wed, 24 Jun 2020 13:51:56 +0530
Subject: [PATCH 2/6] Framework for leader/worker in parallel copy

This patch has the framework for data structures in parallel copy, leader
initialization, worker initialization, shared memory updation, starting workers,
wait for workers and workers exiting.
---
 src/backend/access/transam/parallel.c       |   4 +
 src/backend/commands/copy.c                 | 865 +++++++++++++++++++++++++++-
 src/backend/replication/logical/tablesync.c |   2 +-
 src/include/commands/copy.h                 |   4 +
 src/tools/pgindent/typedefs.list            |   8 +
 5 files changed, 878 insertions(+), 5 deletions(-)

diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index 14a8690..09e7a19 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -25,6 +25,7 @@
 #include "catalog/pg_enum.h"
 #include "catalog/storage.h"
 #include "commands/async.h"
+#include "commands/copy.h"
 #include "executor/execParallel.h"
 #include "libpq/libpq.h"
 #include "libpq/pqformat.h"
@@ -145,6 +146,9 @@ static const struct
 	},
 	{
 		"parallel_vacuum_main", parallel_vacuum_main
+	},
+	{
+		"ParallelCopyMain", ParallelCopyMain
 	}
 };
 
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 33ee891..0a4d997 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -96,9 +96,138 @@ typedef enum CopyInsertMethod
 } CopyInsertMethod;
 
 #define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+
+#define DATA_BLOCK_SIZE RAW_BUF_SIZE
+#define RINGSIZE (10 * 1000)
+#define MAX_BLOCKS_COUNT 1000
+#define WORKER_CHUNK_COUNT 50	/* should be mod of RINGSIZE */
+
+#define	IsParallelCopy()		(cstate->is_parallel)
+#define IsLeader()				(cstate->pcdata->is_leader)
 #define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
 
 /*
+ * Copy data block information.
+ */
+typedef struct ParallelCopyDataBlock
+{
+	/* The number of unprocessed lines in the current block. */
+	pg_atomic_uint32 unprocessed_line_parts;
+
+	/*
+	 * If the current line data is continued into another block, following_block
+	 * will have the position where the remaining data need to be read.
+	 */
+	uint32	following_block;
+
+	/*
+	 * This flag will be set, when the leader finds out this block can be read
+	 * safely by the worker. This helps the worker to start processing the line
+	 * early where the line will be spread across many blocks and the worker
+	 * need not wait for the complete line to be processed.
+	 */
+	bool   curr_blk_completed;
+	char   data[DATA_BLOCK_SIZE]; /* data read from file */
+	uint8  skip_bytes;
+}ParallelCopyDataBlock;
+
+/*
+ * Individual line information.
+ * ParallelCopyLineBoundary is common data structure between leader & worker,
+ * this is protected by the following sequence in the leader & worker.
+ * Leader should operate in the following order:
+ * 1) update first_block, start_offset & cur_lineno in any order.
+ * 2) update line_size.
+ * 3) update line_state.
+ * Worker should operate in the following order:
+ * 1) read line_size.
+ * 2) only one worker should choose one line for processing, this is handled by
+ *    using pg_atomic_compare_exchange_u32, worker will change the sate to
+ *    LINE_WORKER_PROCESSING only if line_state is LINE_LEADER_POPULATED.
+ * 3) read first_block, start_offset & cur_lineno in any order.
+ */
+typedef struct ParallelCopyLineBoundary
+{
+	/* Position of the first block in data_blocks array. */
+	uint32				first_block;
+	uint32				start_offset;   /* start offset of the line */
+
+	/*
+	 * Size of the current line -1 means line is yet to be filled completely,
+	 * 0 means empty line, >0 means line filled with line size data.
+	 */
+	pg_atomic_uint32	line_size;
+	pg_atomic_uint32	line_state;		/* line state */
+	uint64				cur_lineno;		/* line number for error messages */
+}ParallelCopyLineBoundary;
+
+/*
+ * Circular queue used to store the line information.
+ */
+typedef struct ParallelCopyLineBoundaries
+{
+	/* Position for the leader to populate a line. */
+	uint32			leader_pos;
+
+	/* Data read from the file/stdin by the leader process. */
+	ParallelCopyLineBoundary	ring[RINGSIZE];
+}ParallelCopyLineBoundaries;
+
+/*
+ * Shared information among parallel copy workers. This will be allocated in the
+ * DSM segment.
+ */
+typedef struct ParallelCopyShmInfo
+{
+	bool					is_read_in_progress; /* file read status */
+
+	/*
+	 * Actual lines inserted by worker (some records will be filtered based on
+	 * where condition).
+	 */
+	pg_atomic_uint64			processed;
+	pg_atomic_uint64			total_worker_processed; /* total processed records by the workers */
+	uint64						populated; /* lines populated by leader */
+	uint32						cur_block_pos; /* current data block */
+	ParallelCopyDataBlock		data_blocks[MAX_BLOCKS_COUNT]; /* data block array */
+	FullTransactionId			full_transaction_id; /* xid for copy from statement */
+	CommandId					mycid;	/* command id */
+	ParallelCopyLineBoundaries	line_boundaries; /* line array */
+} ParallelCopyShmInfo;
+
+/*
+ * Parallel copy line buffer information.
+ */
+typedef struct ParallelCopyLineBuf
+{
+	StringInfoData		line_buf;
+	uint64				cur_lineno;	/* line number for error messages */
+}ParallelCopyLineBuf;
+
+/*
+ * Parallel copy data information.
+ */
+typedef struct ParallelCopyData
+{
+	Oid					relid;				/* relation id of the table */
+	ParallelCopyShmInfo	*pcshared_info;		/* common info in shared memory */
+	bool				is_leader;
+
+	/* line position which worker is processing */
+	uint32				worker_processed_pos;
+
+	/*
+	 * Local line_buf array, workers will copy it here and release the lines
+	 * for the leader to continue.
+	 */
+	ParallelCopyLineBuf	worker_line_buf[WORKER_CHUNK_COUNT];
+	uint32				worker_line_buf_count; /* Number of lines */
+
+	/* Current position in worker_line_buf */
+	uint32				worker_line_buf_pos;
+}ParallelCopyData;
+
+/*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
  * even though some fields are used in only some cases.
@@ -225,8 +354,66 @@ typedef struct CopyStateData
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
+	int			nworkers;
+	bool		is_parallel;
+	ParallelCopyData *pcdata;
 } CopyStateData;
 
+/*
+ * This structure helps in storing the common data from CopyStateData that are
+ * required by the workers. This information will then be allocated and stored
+ * into the DSM for the worker to retrieve and copy it to CopyStateData.
+ */
+typedef struct ParallelCopyCommonKeyData
+{
+	/* low-level state data */
+	CopyDest            copy_dest;		/* type of copy source/destination */
+	int                 file_encoding;	/* file or remote side's character encoding */
+	bool                need_transcoding;	/* file encoding diff from server? */
+	bool                encoding_embeds_ascii;	/* ASCII can be non-first byte? */
+
+	/* parameters from the COPY command */
+	bool                csv_mode;		/* Comma Separated Value format? */
+	bool                header_line;	/* CSV header line? */
+	int                 null_print_len; /* length of same */
+	bool                force_quote_all;	/* FORCE_QUOTE *? */
+	bool                convert_selectively;	/* do selective binary conversion? */
+
+	/* Working state for COPY FROM */
+	AttrNumber          num_defaults;
+	Oid                 relid;
+}ParallelCopyCommonKeyData;
+
+/*
+ * This structure will help in converting a List data type into the below
+ * structure format with the count having the number of elements in the list and
+ * the info having the List elements appended contigously. This converted
+ * structure will be allocated in shared memory and stored in DSM for the worker
+ * to retrieve and later convert it back to List data type.
+ */
+typedef struct ParallelCopyKeyListInfo
+{
+	int	count;		/* count of attributes */
+
+	/* string info in the form info followed by info1, info2... infon  */
+	char    info[1];
+} ParallelCopyKeyListInfo;
+
+/*
+ * List of internal parallel copy function pointers.
+ */
+static const struct
+{
+	char *fn_name;
+	copy_data_source_cb fn_addr;
+}			InternalParallelCopyFuncPtrs[] =
+
+{
+	{
+		"copy_read_data", copy_read_data
+	},
+};
+
 /* DestReceiver for COPY (query) TO */
 typedef struct
 {
@@ -256,6 +443,23 @@ typedef struct
 /* Trim the list of buffers back down to this number after flushing */
 #define MAX_PARTITION_BUFFERS	32
 
+/* DSM keys for parallel copy.  */
+#define PARALLEL_COPY_KEY_SHARED_INFO		    1
+#define PARALLEL_COPY_KEY_CSTATE				2
+#define PARALLEL_COPY_KEY_NULL_PRINT			3
+#define PARALLEL_COPY_KEY_NULL_PRINT_CLIENT		4
+#define PARALLEL_COPY_KEY_DELIM					5
+#define PARALLEL_COPY_KEY_QUOTE					6
+#define PARALLEL_COPY_KEY_ESCAPE				7
+#define PARALLEL_COPY_KEY_ATTNAME_LIST			8
+#define PARALLEL_COPY_KEY_FORCE_QUOTE_LIST  	9
+#define PARALLEL_COPY_KEY_NOT_NULL_LIST		   10
+#define PARALLEL_COPY_KEY_NULL_LIST			   11
+#define PARALLEL_COPY_KEY_CONVERT_LIST		   12
+#define PARALLEL_COPY_KEY_DATASOURCE_CB		   13
+#define PARALLEL_COPY_KEY_WHERE_CLAUSE_STR     14
+#define PARALLEL_COPY_KEY_RANGE_TABLE		   15
+
 /* Stores multi-insert data related to a single relation in CopyFrom. */
 typedef struct CopyMultiInsertBuffer
 {
@@ -476,10 +680,596 @@ static bool CopyGetInt32(CopyState cstate, int32 *val);
 static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 
+static pg_attribute_always_inline void EndParallelCopy(ParallelContext *pcxt);
 static void PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tup_desc,
 							   List *attnamelist);
+static pg_attribute_always_inline copy_data_source_cb LookupParallelCopyFnPtr(const char *funcname);
+static pg_attribute_always_inline char* LookupParallelCopyFnStr(copy_data_source_cb fn_addr);
+
+/*
+ * CopyCommonInfoForWorker - Copy shared_cstate using cstate information.
+ */
+static pg_attribute_always_inline void
+CopyCommonInfoForWorker(CopyState cstate, ParallelCopyCommonKeyData *shared_cstate)
+{
+	shared_cstate->copy_dest = cstate->copy_dest;
+	shared_cstate->file_encoding = cstate->file_encoding;
+	shared_cstate->need_transcoding = cstate->need_transcoding;
+	shared_cstate->encoding_embeds_ascii = cstate->encoding_embeds_ascii;
+	shared_cstate->csv_mode = cstate->csv_mode;
+	shared_cstate->header_line = cstate->header_line;
+	shared_cstate->null_print_len = cstate->null_print_len;
+	shared_cstate->force_quote_all = cstate->force_quote_all;
+	shared_cstate->convert_selectively = cstate->convert_selectively;
+	shared_cstate->num_defaults = cstate->num_defaults;
+	shared_cstate->relid = cstate->pcdata->relid;
+}
+
+/*
+ * RetrieveSharedString - Retrieve the string from shared memory.
+ */
+static void
+RetrieveSharedString(shm_toc *toc, int sharedkey, char **copystr)
+{
+	char *shared_str_val = (char *)shm_toc_lookup(toc, sharedkey, true);
+	if (shared_str_val)
+		*copystr = pstrdup(shared_str_val);
+}
+
+/*
+ * RetrieveSharedList - Retrieve the list from shared memory.
+ */
+static void
+RetrieveSharedList(shm_toc *toc, int sharedkey, List **copylist)
+{
+	ParallelCopyKeyListInfo *listinformation = (ParallelCopyKeyListInfo *)shm_toc_lookup(toc, sharedkey,
+														   true);
+	if (listinformation)
+	{
+		int	length  = 0;
+		int count;
+
+		for (count = 0; count < listinformation->count; count++)
+		{
+			char *attname = (char *)(listinformation->info + length);
+			length += strlen(attname) + 1;
+			*copylist = lappend(*copylist, makeString(attname));
+		}
+	}
+}
+
+/*
+ * CopyListSharedMemory - Copy the list into shared memory.
+ */
+static void
+CopyListSharedMemory(List *inputlist, Size memsize, ParallelCopyKeyListInfo *sharedlistinfo)
+{
+	ListCell   *l;
+	int			length  = 0;
+
+	MemSet(sharedlistinfo, 0, memsize);
+	foreach(l, inputlist)
+	{
+		char	   *name = strVal(lfirst(l));
+		memcpy((char *)(sharedlistinfo->info + length), name, strlen(name));
+		sharedlistinfo->count++;
+		length += strlen(name) + 1;
+	}
+}
+
+/*
+ * ComputeListSize - compute the list size.
+ */
+static int
+ComputeListSize(List *inputlist)
+{
+	int est_size = sizeof(int);
+	if (inputlist != NIL)
+	{
+		ListCell   *l;
+		foreach(l, inputlist)
+			est_size += strlen(strVal(lfirst(l))) + 1;
+	}
+
+	return est_size;
+}
+
+/*
+ * EstimateLineKeysStr - Estimate the size required in shared memory for the
+ * input string.
+ */
+static void
+EstimateLineKeysStr(ParallelContext *pcxt, char *inputstr)
+{
+	if (inputstr)
+	{
+		shm_toc_estimate_chunk(&pcxt->estimator, strlen(inputstr) + 1);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+}
+
+/*
+ * EstimateLineKeysList - Estimate the size required in shared memory for the
+ * input list.
+ */
+static void
+EstimateLineKeysList(ParallelContext *pcxt, List *inputlist,
+		Size *est_list_size)
+{
+	if (inputlist != NIL)
+	{
+		*est_list_size = ComputeListSize(inputlist);
+		shm_toc_estimate_chunk(&pcxt->estimator, *est_list_size);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+}
 
 /*
+ * InsertStringShm - Insert a string into shared memory.
+ */
+static void
+InsertStringShm(ParallelContext *pcxt, int key, char *inputstr)
+{
+	if (inputstr)
+	{
+		char *shmptr = (char *)shm_toc_allocate(pcxt->toc,
+												strlen(inputstr) + 1);
+		strcpy(shmptr, inputstr);
+		shm_toc_insert(pcxt->toc, key, shmptr);
+	}
+}
+
+/*
+ * InsertListShm - Insert a list into shared memory.
+ */
+static void
+InsertListShm(ParallelContext *pcxt, int key, List *inputlist,
+			  Size est_list_size)
+{
+	if (inputlist != NIL)
+	{
+		ParallelCopyKeyListInfo *sharedlistinfo = (ParallelCopyKeyListInfo *)shm_toc_allocate(pcxt->toc,
+																est_list_size);
+		CopyListSharedMemory(inputlist, est_list_size, sharedlistinfo);
+		shm_toc_insert(pcxt->toc, key, sharedlistinfo);
+	}
+}
+
+/*
+ * BeginParallelCopy - start parallel copy tasks.
+ *
+ * Get the number of workers required to perform the parallel copy. The data
+ * structures that are required by the parallel workers will be initialized, the
+ * size required in DSM will be calculated and the necessary keys will be loaded
+ * in the DSM. The specified number of workers will then be launched.
+ *
+ */
+static ParallelContext*
+BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
+{
+	ParallelContext *pcxt;
+	ParallelCopyShmInfo *shared_info_ptr;
+	ParallelCopyCommonKeyData *shared_cstate;
+	FullTransactionId full_transaction_id;
+	Size est_shared_info;
+	Size est_cstateshared;
+	Size est_att_list_size;
+	Size est_quote_list_size;
+	Size est_notnull_list_size;
+	Size est_null_list_size;
+	Size est_convert_list_size;
+	Size est_datasource_cb_size;
+	int  count = 0;
+	char *whereClauseStr = NULL;
+	char *rangeTableStr = NULL;
+	int  parallel_workers = 0;
+	ParallelCopyData *pcdata;
+
+	parallel_workers = Min(nworkers, max_worker_processes);
+
+	/* Can't perform copy in parallel */
+	if (parallel_workers <= 0)
+	{
+		elog(WARNING,
+			 "No workers available, copy will be run in non-parallel mode");
+		return NULL;
+	}
+
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	cstate->pcdata = pcdata;
+
+	EnterParallelMode();
+	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
+								 parallel_workers);
+	Assert(pcxt->nworkers > 0);
+
+	/*
+	 * Estimate size for shared information for PARALLEL_COPY_KEY_SHARED_INFO
+	 */
+	est_shared_info = sizeof(ParallelCopyShmInfo);
+	shm_toc_estimate_chunk(&pcxt->estimator, est_shared_info);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_CSTATE */
+	est_cstateshared = 	MAXALIGN(sizeof(ParallelCopyCommonKeyData));
+	shm_toc_estimate_chunk(&pcxt->estimator, est_cstateshared);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	EstimateLineKeysStr(pcxt, cstate->null_print);
+	EstimateLineKeysStr(pcxt, cstate->null_print_client);
+	EstimateLineKeysStr(pcxt, cstate->delim);
+	EstimateLineKeysStr(pcxt, cstate->quote);
+	EstimateLineKeysStr(pcxt, cstate->escape);
+
+	if (cstate->whereClause != NULL)
+	{
+		whereClauseStr = nodeToString(cstate->whereClause);
+		EstimateLineKeysStr(pcxt, whereClauseStr);
+	}
+
+	if (cstate->range_table != NULL)
+	{
+		rangeTableStr = nodeToString(cstate->range_table);
+		EstimateLineKeysStr(pcxt, rangeTableStr);
+	}
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_XID. */
+	shm_toc_estimate_chunk(&pcxt->estimator, sizeof(FullTransactionId));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_ATTNAME_LIST.
+	 */
+	EstimateLineKeysList(pcxt, attnamelist, &est_att_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_FORCE_QUOTE_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->force_quote, &est_quote_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_NOT_NULL_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->force_notnull,
+							 &est_notnull_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_NULL_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->force_null, &est_null_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_CONVERT_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->convert_select,
+							 &est_convert_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_DATASOURCE_CB.
+	 */
+	if (cstate->data_source_cb)
+	{
+		char *functionname = LookupParallelCopyFnStr(cstate->data_source_cb);
+		est_datasource_cb_size = strlen(functionname) + 1;
+		shm_toc_estimate_chunk(&pcxt->estimator, est_datasource_cb_size);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+
+	InitializeParallelDSM(pcxt);
+
+	/* If no DSM segment was available, back out (do serial copy) */
+	if (pcxt->seg == NULL)
+	{
+		EndParallelCopy(pcxt);
+		elog(WARNING,
+			 "DSM segments not available, copy will be run in non-parallel mode");
+		return NULL;
+	}
+
+	/* Allocate shared memory for PARALLEL_COPY_KEY_SHARED_INFO */
+	shared_info_ptr = (ParallelCopyShmInfo *) shm_toc_allocate(pcxt->toc,
+													   est_shared_info);
+	MemSet(shared_info_ptr, 0, est_shared_info);
+	shared_info_ptr->is_read_in_progress = true;
+	shared_info_ptr->cur_block_pos = -1;
+	shared_info_ptr->full_transaction_id = full_transaction_id;
+	shared_info_ptr->mycid = GetCurrentCommandId(true);
+	for (count = 0; count < RINGSIZE; count++)
+	{
+		ParallelCopyLineBoundary *lineInfo = &shared_info_ptr->line_boundaries.ring[count];
+		pg_atomic_init_u32(&(lineInfo->line_size), -1);
+	}
+
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_SHARED_INFO, shared_info_ptr);
+	pcdata->pcshared_info = shared_info_ptr;
+	pcdata->relid = relid;
+
+	/* Store shared build state, for which we reserved space. */
+	shared_cstate = (ParallelCopyCommonKeyData *)shm_toc_allocate(pcxt->toc,
+															est_cstateshared);
+
+	/* copy cstate variables. */
+	CopyCommonInfoForWorker(cstate, shared_cstate);
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_CSTATE, shared_cstate);
+
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_NULL_PRINT, cstate->null_print);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_NULL_PRINT_CLIENT,
+					  cstate->null_print_client);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_DELIM, cstate->delim);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_QUOTE, cstate->quote);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_ESCAPE, cstate->escape);
+
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_ATTNAME_LIST,
+					attnamelist, est_att_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_FORCE_QUOTE_LIST,
+					cstate->force_quote, est_quote_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_NOT_NULL_LIST,
+					cstate->force_notnull, est_notnull_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_NULL_LIST, cstate->force_null,
+					est_null_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_CONVERT_LIST,
+					cstate->convert_select, est_convert_list_size);
+
+	if (cstate->data_source_cb)
+	{
+		char *functionname = LookupParallelCopyFnStr(cstate->data_source_cb);
+		char *data_source_cb = (char *) shm_toc_allocate(pcxt->toc,
+														 est_datasource_cb_size);
+		strcpy(data_source_cb, functionname);
+		shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_DATASOURCE_CB,
+					   data_source_cb);
+	}
+
+	if (cstate->whereClause)
+		InsertStringShm(pcxt, PARALLEL_COPY_KEY_WHERE_CLAUSE_STR,
+						whereClauseStr);
+
+	if(cstate->range_table)
+		InsertStringShm(pcxt, PARALLEL_COPY_KEY_RANGE_TABLE, rangeTableStr);
+
+	LaunchParallelWorkers(pcxt);
+	if (pcxt->nworkers_launched == 0)
+	{
+		EndParallelCopy(pcxt);
+		elog(WARNING,
+			 "No workers available, copy will be run in non-parallel mode");
+		return NULL;
+	}
+
+	/*
+	 * Caller needs to wait for all launched workers when we return.  Make sure
+	 * that the failure-to-start case will not hang forever.
+	 */
+	WaitForParallelWorkersToAttach(pcxt);
+
+	pcdata->is_leader = true;
+	cstate->is_parallel = true;
+	return pcxt;
+}
+
+/*
+ * EndParallelCopy - end the parallel copy tasks.
+ */
+static pg_attribute_always_inline void
+EndParallelCopy(ParallelContext *pcxt)
+{
+	Assert(!IsParallelWorker());
+
+	DestroyParallelContext(pcxt);
+	ExitParallelMode();
+}
+
+/*
+ * ParallelWorkerInitialization - Initialize parallel worker.
+ */
+static void
+ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
+		CopyState cstate, List *attnamelist)
+{
+	uint32		count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	cstate->copy_dest = shared_cstate->copy_dest;
+	cstate->file_encoding = shared_cstate->file_encoding;
+	cstate->need_transcoding = shared_cstate->need_transcoding;
+	cstate->encoding_embeds_ascii = shared_cstate->encoding_embeds_ascii;
+	cstate->csv_mode = shared_cstate->csv_mode;
+	cstate->header_line = shared_cstate->header_line;
+	cstate->null_print_len = shared_cstate->null_print_len;
+	cstate->force_quote_all = shared_cstate->force_quote_all;
+	cstate->convert_selectively = shared_cstate->convert_selectively;
+	cstate->num_defaults = shared_cstate->num_defaults;
+	pcdata->relid = shared_cstate->relid;
+
+	PopulateGlobalsForCopyFrom(cstate, tup_desc, attnamelist);
+
+	/* Initialize state variables. */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/* Set up variables to avoid per-attribute overhead. */
+	initStringInfo(&cstate->attribute_buf);
+
+	initStringInfo(&cstate->line_buf);
+	for (count = 0; count < WORKER_CHUNK_COUNT;count++)
+		initStringInfo(&pcdata->worker_line_buf[count].line_buf);
+
+	cstate->line_buf_converted = false;
+	cstate->raw_buf = NULL;
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+}
+/*
+ * ParallelCopyMain - parallel copy worker's code.
+ *
+ * Where clause handling, convert tuple to columns, add default null values for
+ * the missing columns that are not present in that record. Find the partition
+ * if it is partitioned table, invoke before row insert Triggers, handle
+ * constraints and insert the tuples.
+ */
+void
+ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
+{
+	CopyState cstate;
+	ParallelCopyData *pcdata;
+	ParallelCopyShmInfo *pcshared_info;
+	ParallelCopyCommonKeyData *shared_cstate;
+	Relation	rel = NULL;
+	MemoryContext oldcontext;
+	List *attlist = NIL;
+	char *data_source_cb;
+	char *whereClauseStr = NULL;
+	char *rangeTableStr = NULL;
+
+	/* Allocate workspace and zero all fields. */
+	cstate = (CopyStateData *) palloc0(sizeof(CopyStateData));
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	cstate->pcdata = pcdata;
+	pcdata->is_leader = false;
+	pcdata->worker_processed_pos = -1;
+	cstate->is_parallel = true;
+
+	/*
+	 * We allocate everything used by a cstate in a new memory context. This
+	 * avoids memory leaks during repeated use of COPY in a query.
+	 */
+	cstate->copycontext = AllocSetContextCreate(CurrentMemoryContext,
+												"COPY",
+												ALLOCSET_DEFAULT_SIZES);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	pcshared_info = (ParallelCopyShmInfo *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_SHARED_INFO,
+														false);
+
+	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
+
+	pcdata->pcshared_info = pcshared_info;
+
+	shared_cstate = (ParallelCopyCommonKeyData *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE,
+														   false);
+
+	cstate->null_print = (char *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_NULL_PRINT,
+												true);
+	cstate->null_print_client = (char *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_NULL_PRINT_CLIENT,
+													   true);
+
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_DELIM, &cstate->delim);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_QUOTE, &cstate->quote);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_ESCAPE, &cstate->escape);
+
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_ATTNAME_LIST, &attlist);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_FORCE_QUOTE_LIST, &cstate->force_quote);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_NOT_NULL_LIST, &cstate->force_notnull);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_NULL_LIST, &cstate->force_null);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_CONVERT_LIST, &cstate->convert_select);
+	data_source_cb = (char *)shm_toc_lookup(toc,
+											PARALLEL_COPY_KEY_DATASOURCE_CB,
+											true);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_WHERE_CLAUSE_STR, &whereClauseStr);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_RANGE_TABLE, &rangeTableStr);
+
+	if (data_source_cb)
+		cstate->data_source_cb = LookupParallelCopyFnPtr(data_source_cb);
+
+	if (whereClauseStr)
+	{
+		Node *whereClauseCnvrtdFrmStr = (Node *) stringToNode(whereClauseStr);
+		cstate->whereClause = whereClauseCnvrtdFrmStr;
+	}
+
+	if (rangeTableStr)
+	{
+		List *rangeTableCnvrtdFrmStr = (List *) stringToNode(rangeTableStr);
+		cstate->range_table = rangeTableCnvrtdFrmStr;
+	}
+
+	/* Open and lock the relation, using the appropriate lock type. */
+	rel = table_open(shared_cstate->relid, RowExclusiveLock);
+	cstate->rel = rel;
+	ParallelWorkerInitialization(shared_cstate, cstate, attlist);
+
+	CopyFrom(cstate);
+
+	if (rel != NULL)
+		table_close(rel, RowExclusiveLock);
+
+	MemoryContextSwitchTo(oldcontext);
+	return;
+}
+/*
+ * ParallelCopyLeader - parallel copy leader's functionality.
+ *
+ * Leader will populate the shared memory and share it across the workers.
+ * Leader will read the table data from the file and copy the contents to block.
+ * Leader will then read the input contents and identify the data based on line
+ * beaks. This information is called line. The line will be populate in
+ * ParallelCopyLineBoundary. Workers will then pick up this information and
+ * insert in to table. Leader will do this till it completes processing the
+ * file. Leader executes the before statement if before statement trigger is
+ * present. Leader read the data from input file. Leader then loads data to data
+ * blocks as and when required block by block. Leader traverses through the data
+ * block to identify one line. It gets a free line to copy the information, if
+ * there is no free line it will wait till there is one free line.
+ * Server copies  the identified lines information into lines. This process is
+ * repeated till the complete file is processed.
+ * Leader will wait till all the lines populated are processed by the workers
+ * and exits.
+ */
+static void
+ParallelCopyLeader(CopyState cstate)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
+
+	pcshared_info->is_read_in_progress = false;
+	cstate->cur_lineno = 0;
+}
+/*
+ * LookupParallelCopyFnPtr - Look up parallel copy function pointer.
+ */
+static pg_attribute_always_inline copy_data_source_cb
+LookupParallelCopyFnPtr(const char *funcname)
+{
+	int			i;
+
+	for (i = 0; i < lengthof(InternalParallelCopyFuncPtrs); i++)
+	{
+		if (strcmp(InternalParallelCopyFuncPtrs[i].fn_name, funcname) == 0)
+			return InternalParallelCopyFuncPtrs[i].fn_addr;
+	}
+
+	/* We can only reach this by programming error. */
+	elog(ERROR, "internal function \"%s\" not found", funcname);
+}
+
+/*
+ * LookupParallelCopyFnStr - Lookup function string from a function pointer.
+ */
+static pg_attribute_always_inline char*
+LookupParallelCopyFnStr(copy_data_source_cb fn_addr)
+{
+	int			i;
+
+	for (i = 0; i < lengthof(InternalParallelCopyFuncPtrs); i++)
+	{
+		if (InternalParallelCopyFuncPtrs[i].fn_addr == fn_addr)
+			return InternalParallelCopyFuncPtrs[i].fn_name;
+	}
+
+	/* We can only reach this by programming error. */
+	elog(ERROR, "internal function pointer not found");
+}
+/*
  * Send copy start/stop messages for frontend copies.  These have changed
  * in past protocol redesigns.
  */
@@ -1149,6 +1939,7 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 
 	if (is_from)
 	{
+		ParallelContext *pcxt = NULL;
 		Assert(rel);
 
 		/* check read-only transaction and parallel mode */
@@ -1158,7 +1949,24 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 		cstate = BeginCopyFrom(pstate, rel, stmt->filename, stmt->is_program,
 							   NULL, stmt->attlist, stmt->options);
 		cstate->whereClause = whereClause;
-		*processed = CopyFrom(cstate);	/* copy from file to database */
+		cstate->is_parallel = false;
+
+		if (cstate->nworkers > 0)
+			pcxt = BeginParallelCopy(cstate->nworkers, cstate, stmt->attlist,
+									 relid);
+
+		if (pcxt)
+		{
+			ParallelCopyLeader(cstate);
+
+			/* Wait for all copy workers to finish */
+			WaitForParallelWorkersToFinish(pcxt);
+			*processed = pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
+			EndParallelCopy(pcxt);
+		}
+		else
+			*processed = CopyFrom(cstate); /* copy from file to database */
+
 		EndCopyFrom(cstate);
 	}
 	else
@@ -1207,6 +2015,7 @@ ProcessCopyOptions(ParseState *pstate,
 	cstate->is_copy_from = is_from;
 
 	cstate->file_encoding = -1;
+	cstate->nworkers = -1;
 
 	/* Extract options from the statement node tree */
 	foreach(option, options)
@@ -1375,6 +2184,53 @@ ProcessCopyOptions(ParseState *pstate,
 								defel->defname),
 						 parser_errposition(pstate, defel->location)));
 		}
+		else if (strcmp(defel->defname, "parallel") == 0)
+		{
+			char *endptr, *str;
+			long val;
+
+			if (!cstate->is_copy_from)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("parallel option supported only for copy from"),
+						 parser_errposition(pstate, defel->location)));
+			if (cstate->nworkers >= 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options"),
+						 parser_errposition(pstate, defel->location)));
+
+			str = defGetString(defel);
+
+			errno = 0; /* To distinguish success/failure after call */
+			val = strtol(str, &endptr, 10);
+
+			/* Check for various possible errors */
+			if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
+				|| (errno != 0 && val == 0) ||
+				*endptr)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("improper use of argument to option \"%s\"",
+								defel->defname),
+						 parser_errposition(pstate, defel->location)));
+
+			if (endptr == str)
+			   ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("no digits were found in argument to option \"%s\"",
+								defel->defname),
+						 parser_errposition(pstate, defel->location)));
+
+			cstate->nworkers = (int) val;
+
+			if (cstate->nworkers <= 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("argument to option \"%s\" must be a positive integer greater than zero",
+								defel->defname),
+						 parser_errposition(pstate, defel->location)));
+		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_SYNTAX_ERROR),
@@ -1727,12 +2583,13 @@ BeginCopy(ParseState *pstate,
 }
 
 /*
- * PopulateGlobalsForCopyFrom - Populates the common variables required for copy
- * from operation. This is a helper function for BeginCopy function.
+ * PopulateCatalogInformation - Populates the common variables required for copy
+ * from operation. This is a helper function for BeginCopy &
+ * ParallelWorkerInitialization function.
  */
 static void
 PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tupDesc,
-							List *attnamelist)
+						   List *attnamelist)
 {
 	int			num_phys_attrs;
 
diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c
index c27d970..b3787c1 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -557,7 +557,7 @@ make_copy_attnamelist(LogicalRepRelMapEntry *rel)
  * Data source callback for the COPY FROM, which reads from the remote
  * connection and passes the data back to our local COPY.
  */
-static int
+int
 copy_read_data(void *outbuf, int minread, int maxread)
 {
 	int			bytesread = 0;
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index c639833..5dc95ac 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -14,6 +14,7 @@
 #ifndef COPY_H
 #define COPY_H
 
+#include "access/parallel.h"
 #include "nodes/execnodes.h"
 #include "nodes/parsenodes.h"
 #include "parser/parse_node.h"
@@ -41,4 +42,7 @@ extern uint64 CopyFrom(CopyState cstate);
 
 extern DestReceiver *CreateCopyDestReceiver(void);
 
+extern void ParallelCopyMain(dsm_segment *seg, shm_toc *toc);
+
+extern int copy_read_data(void *outbuf, int minread, int maxread);
 #endif							/* COPY_H */
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 7eaaad1..6a42ac4 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1699,6 +1699,14 @@ ParallelBitmapHeapState
 ParallelBlockTableScanDesc
 ParallelCompletionPtr
 ParallelContext
+ParallelCopyLineBoundaries
+ParallelCopyLineBoundary
+ParallelCopyCommonKeyData
+ParallelCopyData
+ParallelCopyDataBlock
+ParallelCopyKeyListInfo
+ParallelCopyLineBuf
+ParallelCopyShmInfo
 ParallelExecutorInfo
 ParallelHashGrowth
 ParallelHashJoinBatch
-- 
1.8.3.1

0003-Allow-copy-from-command-to-process-data-from-file-ST.patchapplication/octet-stream; name=0003-Allow-copy-from-command-to-process-data-from-file-ST.patchDownload
From 47d27d300dea6adf9af6d688044e04770d1d8650 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>, Bharath <bharath.rupireddyforpostgres@gmail.com>
Date: Mon, 6 Jul 2020 14:33:12 +0530
Subject: [PATCH 3/6] Allow copy from command to process data from file/STDIN
 contents to a table in parallel.

This feature allows the copy from to leverage multiple CPUs in order to copy
data from file/STDIN to a table. This adds a PARALLEL option to COPY FROM
command where the user can specify the number of workers that can be used
to perform the COPY FROM command. Specifying zero as number of workers will
disable parallelism.
The backend, to which the "COPY FROM" query is submitted acts as leader with
the responsibility of reading data from the file/stdin, launching at most n
number of workers as specified with PARALLEL 'n' option in the "COPY FROM"
query. The leader populates the common data required for the workers execution
in the DSM and shares it with the workers. The leader then executes before
statement triggers if there exists any. Leader populates DSM lines which
includes the start offset and line size, while populating the lines it reads
as many blocks as required into the DSM data blocks from the file. Each block
is of 64K size. The leader parses the data to identify a line, the existing
logic from CopyReadLineText which identifies the lines with some changes was
used for this. Leader checks if a free line is available to copy the
information, if there is no free line it waits till the required line is
freed up by the worker and then copies the identified lines information
(offset & line size) into the DSM lines. This process is repeated till the
complete file is processed. Simultaneously, the workers cache the lines(50)
locally into the local memory and release the lines to the leader for further
populating. Each worker processes the lines that it cached and inserts it into
the table. The leader does not participate in the insertion of data, leaders
only responsibility will be to identify the lines as fast as possible for the
workers to do the actual copy operation. The leader waits till all the lines
populated are processed by the workers and exits.
---
 src/backend/access/common/toast_internals.c |  11 +-
 src/backend/access/heap/heapam.c            |  13 -
 src/backend/access/transam/xact.c           |  31 +
 src/backend/commands/copy.c                 | 900 ++++++++++++++++++++++++++--
 src/include/access/xact.h                   |   2 +
 src/tools/pgindent/typedefs.list            |   1 +
 6 files changed, 906 insertions(+), 52 deletions(-)

diff --git a/src/backend/access/common/toast_internals.c b/src/backend/access/common/toast_internals.c
index 25a81e5..586d53d 100644
--- a/src/backend/access/common/toast_internals.c
+++ b/src/backend/access/common/toast_internals.c
@@ -17,6 +17,7 @@
 #include "access/genam.h"
 #include "access/heapam.h"
 #include "access/heaptoast.h"
+#include "access/parallel.h"
 #include "access/table.h"
 #include "access/toast_internals.h"
 #include "access/xact.h"
@@ -116,7 +117,15 @@ toast_save_datum(Relation rel, Datum value,
 	TupleDesc	toasttupDesc;
 	Datum		t_values[3];
 	bool		t_isnull[3];
-	CommandId	mycid = GetCurrentCommandId(true);
+
+	/*
+	 * Parallel copy can insert toast tuples, in case of parallel copy the
+	 * command would have been set already by calling AssignCommandIdForWorker.
+	 * For parallel copy call GetCurrentCommandId to get currentCommandId by
+	 * passing used as false, as this is taken care earlier.
+	 */
+	CommandId	mycid = IsParallelWorker() ? GetCurrentCommandId(false) :
+											 GetCurrentCommandId(true);
 	struct varlena *result;
 	struct varatt_external toast_pointer;
 	union
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 537913d..28f3a98 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2012,19 +2012,6 @@ static HeapTuple
 heap_prepare_insert(Relation relation, HeapTuple tup, TransactionId xid,
 					CommandId cid, int options)
 {
-	/*
-	 * Parallel operations are required to be strictly read-only in a parallel
-	 * worker.  Parallel inserts are not safe even in the leader in the
-	 * general case, because group locking means that heavyweight locks for
-	 * relation extension or GIN page locks will not conflict between members
-	 * of a lock group, but we don't prohibit that case here because there are
-	 * useful special cases that we can safely allow, such as CREATE TABLE AS.
-	 */
-	if (IsParallelWorker())
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_TRANSACTION_STATE),
-				 errmsg("cannot insert tuples in a parallel worker")));
-
 	tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
 	tup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK);
 	tup->t_data->t_infomask |= HEAP_XMAX_INVALID;
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 905dc7d..ed4009e 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -502,6 +502,37 @@ GetCurrentFullTransactionIdIfAny(void)
 }
 
 /*
+ *	AssignFullTransactionIdForWorker
+ *
+ * For parallel copy, transaction id of leader will be used by the workers.
+ */
+void
+AssignFullTransactionIdForWorker(FullTransactionId fullTransactionId)
+{
+	TransactionState s = CurrentTransactionState;
+
+	Assert((IsInParallelMode() || IsParallelWorker()));
+	s->fullTransactionId = fullTransactionId;
+}
+
+/*
+ *	AssignCommandIdForWorker
+ *
+ * For parallel copy, command id of leader will be used by the workers.
+ */
+void
+AssignCommandIdForWorker(CommandId commandId, bool used)
+{
+	Assert((IsInParallelMode() || IsParallelWorker()));
+
+	/* this is global to a transaction, not subtransaction-local */
+	if (used)
+		currentCommandIdUsed = true;
+
+	currentCommandId = commandId;
+}
+
+/*
  *	MarkCurrentTransactionIdLoggedIfAny
  *
  * Remember that the current xid - if it is assigned - now has been wal logged.
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 0a4d997..048f2d2 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -26,6 +26,7 @@
 #include "access/xlog.h"
 #include "catalog/dependency.h"
 #include "catalog/pg_authid.h"
+#include "catalog/pg_proc_d.h"
 #include "catalog/pg_type.h"
 #include "commands/copy.h"
 #include "commands/defrem.h"
@@ -40,11 +41,13 @@
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
+#include "optimizer/clauses.h"
 #include "optimizer/optimizer.h"
 #include "parser/parse_coerce.h"
 #include "parser/parse_collate.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_relation.h"
+#include "pgstat.h"
 #include "port/pg_bswap.h"
 #include "rewrite/rewriteHandler.h"
 #include "storage/fd.h"
@@ -95,6 +98,18 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
+/*
+ * State of the line.
+ */
+typedef enum ParallelCopyLineState
+{
+	LINE_INIT,					/* initial state of line */
+	LINE_LEADER_POPULATING,		/* leader processing line */
+	LINE_LEADER_POPULATED,		/* leader completed populating line */
+	LINE_WORKER_PROCESSING,		/* worker processing line */
+	LINE_WORKER_PROCESSED		/* worker completed processing line */
+}ParallelCopyLineState;
+
 #define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
 
 #define DATA_BLOCK_SIZE RAW_BUF_SIZE
@@ -538,9 +553,13 @@ if (1) \
 { \
 	if (raw_buf_ptr > cstate->raw_buf_index) \
 	{ \
-		appendBinaryStringInfo(&cstate->line_buf, \
-							 cstate->raw_buf + cstate->raw_buf_index, \
-							   raw_buf_ptr - cstate->raw_buf_index); \
+		if (!IsParallelCopy()) \
+			appendBinaryStringInfo(&cstate->line_buf, \
+								   cstate->raw_buf + cstate->raw_buf_index, \
+								   raw_buf_ptr - cstate->raw_buf_index); \
+		else \
+			line_size +=  raw_buf_ptr - cstate->raw_buf_index; \
+		\
 		cstate->raw_buf_index = raw_buf_ptr; \
 	} \
 } else ((void) 0)
@@ -553,13 +572,40 @@ if (1) \
 	goto not_end_of_copy; \
 } else ((void) 0)
 
+/* Begin parallel copy Macros */
+#define SET_NEWLINE_SIZE() \
+{ \
+	if (cstate->eol_type == EOL_NL || cstate->eol_type == EOL_CR) \
+		new_line_size = 1; \
+	else if (cstate->eol_type == EOL_CRNL) \
+		new_line_size = 2; \
+	else \
+		new_line_size = 0; \
+}
+
+/*
+ * COPY_WAIT_TO_PROCESS - Wait before continuing to process.
+ */
+#define COPY_WAIT_TO_PROCESS() \
+{ \
+	CHECK_FOR_INTERRUPTS(); \
+	(void) WaitLatch(MyLatch, \
+					 WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH, \
+					 1L, WAIT_EVENT_PG_SLEEP); \
+	ResetLatch(MyLatch); \
+}
+
+/* End parallel copy Macros */
+
 /*
  * CONVERT_TO_SERVER_ENCODING - convert contents to server encoding.
  */
 #define CONVERT_TO_SERVER_ENCODING(cstate) \
 { \
 	/* Done reading the line.  Convert it to server encoding. */ \
-	if (cstate->need_transcoding) \
+	if (cstate->need_transcoding && \
+		(!IsParallelCopy() || \
+		 (IsParallelCopy() && !IsLeader()))) \
 	{ \
 		char	   *cvt; \
 		cvt = pg_any_to_server(cstate->line_buf.data, \
@@ -618,22 +664,38 @@ if (1) \
  * CLEAR_EOL_LINE - Wrapper for clearing EOL.
  */
 #define CLEAR_EOL_LINE() \
-if (!result && !IsHeaderLine()) \
-	CLEAR_EOL_FROM_COPIED_DATA(cstate->line_buf.data, \
-								cstate->line_buf.len, \
-								cstate->line_buf.len) \
+{ \
+	if (!result && !IsHeaderLine()) \
+	{ \
+		if (IsParallelCopy()) \
+			CLEAR_EOL_FROM_COPIED_DATA(cstate->raw_buf, \
+									   raw_buf_ptr, line_size) \
+		else \
+			CLEAR_EOL_FROM_COPIED_DATA(cstate->line_buf.data, \
+									   cstate->line_buf.len, \
+									   cstate->line_buf.len) \
+	} \
+}
 
 /*
  * INCREMENTPROCESSED - Increment the lines processed.
  */
-#define INCREMENTPROCESSED(processed)  \
-processed++;
+#define INCREMENTPROCESSED(processed) \
+{ \
+	if (!IsParallelCopy()) \
+		processed++; \
+	else \
+		pg_atomic_add_fetch_u64(&cstate->pcdata->pcshared_info->processed, 1); \
+}
 
 /*
  * GETPROCESSED - Get the lines processed.
  */
 #define GETPROCESSED(processed) \
-return processed;
+if (!IsParallelCopy()) \
+	return processed; \
+else \
+	return pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
 
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
@@ -681,8 +743,12 @@ static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 
 static pg_attribute_always_inline void EndParallelCopy(ParallelContext *pcxt);
+static void ExecBeforeStmtTrigger(CopyState cstate);
+static void CheckTargetRelValidity(CopyState cstate);
 static void PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tup_desc,
 							   List *attnamelist);
+static void PopulateCatalogInformation(CopyState cstate);
+static pg_attribute_always_inline uint32 GetLinePosition(CopyState cstate);
 static pg_attribute_always_inline copy_data_source_cb LookupParallelCopyFnPtr(const char *funcname);
 static pg_attribute_always_inline char* LookupParallelCopyFnStr(copy_data_source_cb fn_addr);
 
@@ -836,6 +902,137 @@ InsertListShm(ParallelContext *pcxt, int key, List *inputlist,
 }
 
 /*
+ * IsTriggerFunctionParallelSafe - Check if the trigger function is parallel
+ * safe for the triggers. Return false if any one of the trigger has parallel
+ * unsafe function.
+ */
+static pg_attribute_always_inline bool
+IsTriggerFunctionParallelSafe(TriggerDesc *trigdesc)
+{
+	int	i;
+	for (i = 0; i < trigdesc->numtriggers; i++)
+	{
+		Trigger    *trigger = &trigdesc->triggers[i];
+		int 		trigtype = RI_TRIGGER_NONE;
+
+		if (func_parallel(trigger->tgfoid) != PROPARALLEL_SAFE)
+			return false;
+
+		/* If the trigger is parallel safe, also look for RI_TRIGGER. */
+		trigtype = RI_FKey_trigger_type(trigger->tgfoid);
+		if (trigtype == RI_TRIGGER_PK || trigtype == RI_TRIGGER_FK)
+			return false;
+	}
+
+	return true;
+}
+
+/*
+ * CheckExprParallelSafety - determine parallel safety of volatile expressions
+ * in default clause of column definition or in where clause and return true if
+ * they are parallel safe.
+ */
+static pg_attribute_always_inline bool
+CheckExprParallelSafety(CopyState cstate)
+{
+	if (contain_volatile_functions(cstate->whereClause))
+	{
+		if (max_parallel_hazard((Query *)cstate->whereClause) != PROPARALLEL_SAFE)
+			return false;
+	}
+
+	/*
+	 * Check if any of the column has volatile default expression. if yes, and
+	 * they are not parallel safe, then parallelism is not allowed. For
+	 * instance, if there are any serial/bigserial columns for which nextval()
+	 * default expression which is parallel unsafe is associated, parallelism
+	 * should not be allowed. In non parallel copy volatile functions are not
+	 * checked for nextval().
+	 */
+	if (cstate->defexprs != NULL && cstate->num_defaults != 0)
+	{
+		int     i;
+		for (i = 0; i < cstate->num_defaults; i++)
+		{
+			bool volatile_expr = contain_volatile_functions((Node *)cstate->defexprs[i]->expr);
+			if (volatile_expr &&
+				(max_parallel_hazard((Query *)cstate->defexprs[i]->expr)) !=
+				 PROPARALLEL_SAFE)
+				return false;
+		}
+	}
+
+	return true;
+}
+
+/*
+ * FindInsertMethod - determine insert mode single, multi, or multi conditional.
+ */
+static pg_attribute_always_inline CopyInsertMethod
+FindInsertMethod(CopyState cstate)
+{
+	if (cstate->rel->trigdesc != NULL &&
+		(cstate->rel->trigdesc->trig_insert_before_row ||
+		 cstate->rel->trigdesc->trig_insert_instead_row))
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
+			cstate->rel->trigdesc != NULL &&
+			cstate->rel->trigdesc->trig_insert_new_table)
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+		return CIM_MULTI_CONDITIONAL;
+
+	return CIM_MULTI;
+}
+
+/*
+ * IsParallelCopyAllowed - check for the cases where parallel copy is not
+ * applicable.
+ */
+static pg_attribute_always_inline bool
+IsParallelCopyAllowed(CopyState cstate)
+{
+	/* Parallel copy not allowed for frontend (2.0 protocol) & binary option. */
+	if ((cstate->copy_dest == COPY_OLD_FE) || cstate->binary)
+		return false;
+
+	/* Check if copy is into foreign table or temporary table. */
+	if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
+		RelationUsesLocalBuffers(cstate->rel))
+		return false;
+
+	/* Check if trigger function is parallel safe. */
+	if (cstate->rel->trigdesc != NULL &&
+		!IsTriggerFunctionParallelSafe(cstate->rel->trigdesc))
+		return false;
+
+	/*
+	 * Check if there is after statement or instead of trigger or transition
+	 * table triggers.
+	 */
+	if (cstate->rel->trigdesc != NULL &&
+		(cstate->rel->trigdesc->trig_insert_after_statement ||
+		 cstate->rel->trigdesc->trig_insert_instead_row ||
+		 cstate->rel->trigdesc->trig_insert_new_table))
+		return false;
+
+	/* Check if the volatile expressions are parallel safe, if present any. */
+	if (!CheckExprParallelSafety(cstate))
+		return false;
+
+	/* Check if the insertion mode is single. */
+	if (FindInsertMethod(cstate) == CIM_SINGLE)
+		return false;
+
+	return true;
+}
+
+/*
  * BeginParallelCopy - start parallel copy tasks.
  *
  * Get the number of workers required to perform the parallel copy. The data
@@ -865,6 +1062,8 @@ BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
 	int  parallel_workers = 0;
 	ParallelCopyData *pcdata;
 
+	CheckTargetRelValidity(cstate);
+
 	parallel_workers = Min(nworkers, max_worker_processes);
 
 	/* Can't perform copy in parallel */
@@ -878,6 +1077,19 @@ BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
 	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
 	cstate->pcdata = pcdata;
 
+	/*
+	 * User chosen parallel copy. Determine if the parallel copy is actually
+	 * allowed. If not, go with the non-parallel mode.
+	 */
+	if (!IsParallelCopyAllowed(cstate))
+	{
+		elog(WARNING,
+			 "Parallel copy not supported for specified table, copy will be run in non-parallel mode");
+		return NULL;
+	}
+
+	full_transaction_id = GetCurrentFullTransactionId();
+
 	EnterParallelMode();
 	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
 								 parallel_workers);
@@ -1108,7 +1320,211 @@ ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
 	cstate->line_buf_converted = false;
 	cstate->raw_buf = NULL;
 	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+
+	PopulateCatalogInformation(cstate);
+
+	/* Create workspace for CopyReadAttributes results. */
+	if (!cstate->binary)
+	{
+		AttrNumber	attr_count = list_length(cstate->attnumlist);
+
+		cstate->max_fields = attr_count;
+		cstate->raw_fields = (char **)palloc(attr_count * sizeof(char *));
+	}
+}
+
+/*
+ * CacheLineInfo - Cache the line information to local memory.
+ */
+static bool
+CacheLineInfo(CopyState cstate, uint32 buff_count)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	uint32			write_pos;
+	ParallelCopyDataBlock *data_blk_ptr;
+	ParallelCopyLineBoundary *lineInfo;
+	uint32 offset;
+	int dataSize;
+	int copiedSize = 0;
+
+	resetStringInfo(&pcdata->worker_line_buf[buff_count].line_buf);
+	write_pos = GetLinePosition(cstate);
+	if (-1 == write_pos)
+		return true;
+
+	/* Get the current line information. */
+	lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+	if (pg_atomic_read_u32(&lineInfo->line_size) == 0)
+		goto empty_data_line_update;
+
+	/* Get the block information. */
+	data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+	/* Get the offset information from where the data must be copied. */
+	offset = lineInfo->start_offset;
+	pcdata->worker_line_buf[buff_count].cur_lineno = lineInfo->cur_lineno;
+
+	elog(DEBUG1, "[Worker] Processing - line position:%d, block:%d, unprocessed lines:%d, offset:%d, line size:%d",
+				 write_pos, lineInfo->first_block,
+				 pg_atomic_read_u32(&data_blk_ptr->unprocessed_line_parts),
+				 offset, pg_atomic_read_u32(&lineInfo->line_size));
+
+	for (;;)
+	{
+		uint8 skip_bytes = data_blk_ptr->skip_bytes;
+		/*
+		 * There is a possibility that the above loop has come out because
+		 * data_blk_ptr->curr_blk_completed is set, but dataSize read might
+		 * be an old value, if data_blk_ptr->curr_blk_completed and the line is
+		 * completed, line_size will be set. Read the line_size again to be
+		 * sure if it is complete or partial block.
+		 */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+		if (dataSize)
+		{
+			int remainingSize = dataSize - copiedSize;
+			if (!remainingSize)
+				break;
+
+			/* Whole line is in current block. */
+			if (remainingSize + offset + skip_bytes < DATA_BLOCK_SIZE)
+			{
+				appendBinaryStringInfo(&pcdata->worker_line_buf[buff_count].line_buf,
+									   &data_blk_ptr->data[offset],
+									   remainingSize);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts,
+										1);
+				break;
+			}
+			else
+			{
+				/* Line is spread across the blocks. */
+				uint32 lineInCurrentBlock =  (DATA_BLOCK_SIZE - skip_bytes) - offset;
+				appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+										 &data_blk_ptr->data[offset],
+										 lineInCurrentBlock);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+				copiedSize += lineInCurrentBlock;
+				while (copiedSize < dataSize)
+				{
+					uint32 currentBlockCopySize;
+					ParallelCopyDataBlock *currBlkPtr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+					skip_bytes = currBlkPtr->skip_bytes;
+
+					/*
+					 * If complete data is present in current block use
+					 * dataSize - copiedSize, or copy the whole block from
+					 * current block.
+					 */
+					currentBlockCopySize = Min(dataSize - copiedSize, DATA_BLOCK_SIZE - skip_bytes);
+					appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+											 &currBlkPtr->data[0],
+											 currentBlockCopySize);
+					pg_atomic_sub_fetch_u32(&currBlkPtr->unprocessed_line_parts, 1);
+					copiedSize += currentBlockCopySize;
+					data_blk_ptr = currBlkPtr;
+				}
+
+				break;
+			}
+		}
+		else
+		{
+			/* Copy this complete block from the current offset. */
+			uint32 lineInCurrentBlock =  (DATA_BLOCK_SIZE - skip_bytes) - offset;
+			appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+									 &data_blk_ptr->data[offset],
+									 lineInCurrentBlock);
+			pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+			copiedSize += lineInCurrentBlock;
+
+			/*
+			 * Reset the offset. For the first copy, copy from the offset. For
+			 * the subsequent copy the complete block.
+			 */
+			offset = 0;
+
+			/* Set data_blk_ptr to the following block. */
+			data_blk_ptr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+		}
+
+		for (;;)
+		{
+			/* Get the size of this line */
+			dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+			/*
+			 * If the data is present in current block lineInfo.line_size
+			 * will be updated. If the data is spread across the blocks either
+			 * of lineInfo.line_size or data_blk_ptr->curr_blk_completed can
+			 * be updated. lineInfo.line_size will be updated if the complete
+			 * read is finished. data_blk_ptr->curr_blk_completed will be
+			 * updated if processing of current block is finished and data
+			 * processing is not finished.
+			 */
+			if (data_blk_ptr->curr_blk_completed || (dataSize != -1))
+				break;
+
+			COPY_WAIT_TO_PROCESS()
+		}
+	}
+
+empty_data_line_update:
+	elog(DEBUG1, "[Worker] Completed processing line:%d", write_pos);
+	pg_atomic_write_u32(&lineInfo->line_state, LINE_WORKER_PROCESSED);
+	pg_atomic_write_u32(&lineInfo->line_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+	return false;
+}
+
+/*
+ * GetWorkerLine - Returns a line for worker to process.
+ */
+static bool
+GetWorkerLine(CopyState cstate)
+{
+	uint32 buff_count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+
+	/*
+	 * Copy the line data to line_buf and release the line position so that the
+	 * worker can continue loading data.
+	 */
+	if (pcdata->worker_line_buf_pos < pcdata->worker_line_buf_count)
+		goto return_line;
+
+	pcdata->worker_line_buf_pos = 0;
+	pcdata->worker_line_buf_count = 0;
+
+	for (buff_count = 0; buff_count < WORKER_CHUNK_COUNT; buff_count++)
+	{
+		bool result = CacheLineInfo(cstate, buff_count);
+		if (result)
+			break;
+
+		pcdata->worker_line_buf_count++;
+	}
+
+	if (pcdata->worker_line_buf_count)
+		goto return_line;
+	else
+		resetStringInfo(&cstate->line_buf);
+
+	return true;
+
+return_line:
+	cstate->line_buf = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].line_buf;
+	cstate->cur_lineno = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].cur_lineno;
+	cstate->line_buf_valid = true;
+
+	/* Mark that encoding conversion hasn't occurred yet. */
+	cstate->line_buf_converted = false;
+	CONVERT_TO_SERVER_ENCODING(cstate)
+	pcdata->worker_line_buf_pos++;
+	return false;
 }
+
 /*
  * ParallelCopyMain - parallel copy worker's code.
  *
@@ -1154,6 +1570,8 @@ ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
 	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
 
 	pcdata->pcshared_info = pcshared_info;
+	AssignFullTransactionIdForWorker(pcshared_info->full_transaction_id);
+	AssignCommandIdForWorker(pcshared_info->mycid, true);
 
 	shared_cstate = (ParallelCopyCommonKeyData *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE,
 														   false);
@@ -1206,6 +1624,34 @@ ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
 	MemoryContextSwitchTo(oldcontext);
 	return;
 }
+
+/*
+ * UpdateBlockInLineInfo - Update the line information.
+ */
+static pg_attribute_always_inline int
+UpdateBlockInLineInfo(CopyState cstate, uint32 blk_pos,
+					   uint32 offset, uint32 line_size, uint32 line_state)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyLineBoundaries *lineBoundaryPtr = &pcshared_info->line_boundaries;
+	ParallelCopyLineBoundary *lineInfo;
+	int line_pos = lineBoundaryPtr->leader_pos;
+
+	/* Update the line information for the worker to pick and process. */
+	lineInfo = &lineBoundaryPtr->ring[line_pos];
+	while (pg_atomic_read_u32(&lineInfo->line_size) != -1)
+		COPY_WAIT_TO_PROCESS()
+
+	lineInfo->first_block = blk_pos;
+	lineInfo->start_offset = offset;
+	lineInfo->cur_lineno = cstate->cur_lineno;
+	pg_atomic_write_u32(&lineInfo->line_size, line_size);
+	pg_atomic_write_u32(&lineInfo->line_state, line_state);
+	lineBoundaryPtr->leader_pos = (lineBoundaryPtr->leader_pos + 1) % RINGSIZE;
+
+	return line_pos;
+}
+
 /*
  * ParallelCopyLeader - parallel copy leader's functionality.
  *
@@ -1231,9 +1677,161 @@ ParallelCopyLeader(CopyState cstate)
 	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
 	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
 
+	/* Execute the before statement triggers from the leader */
+	ExecBeforeStmtTrigger(cstate);
+
+	/* On input just throw the header line away. */
+	if (cstate->cur_lineno == 0 && cstate->header_line)
+	{
+		cstate->cur_lineno++;
+		if (CopyReadLine(cstate))
+		{
+			pcshared_info->is_read_in_progress = false;
+			return;			/* done */
+		}
+	}
+
+	for (;;)
+	{
+		bool done;
+		cstate->cur_lineno++;
+
+		/* Actually read the line into memory here. */
+		done = CopyReadLine(cstate);
+
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			break;
+	}
+
 	pcshared_info->is_read_in_progress = false;
 	cstate->cur_lineno = 0;
 }
+
+/*
+ * GetLinePosition - return the line position that worker should process.
+ */
+static uint32
+GetLinePosition(CopyState cstate)
+{
+	ParallelCopyData *pcdata = cstate->pcdata;
+	ParallelCopyShmInfo *pcshared_info = pcdata->pcshared_info;
+	uint32  previous_pos = pcdata->worker_processed_pos;
+	uint32 write_pos = (previous_pos == -1) ? 0 : (previous_pos + 1) % RINGSIZE;
+	for (;;)
+	{
+		int		dataSize;
+		bool	is_read_in_progress = pcshared_info->is_read_in_progress;
+		ParallelCopyLineBoundary *lineInfo;
+		ParallelCopyDataBlock *data_blk_ptr;
+		ParallelCopyLineState line_state = LINE_LEADER_POPULATED;
+		ParallelCopyLineState curr_line_state;
+		CHECK_FOR_INTERRUPTS();
+
+		/* File read completed & no elements to process. */
+		if (!is_read_in_progress &&
+			(pcshared_info->populated ==
+			 pg_atomic_read_u64(&pcshared_info->total_worker_processed)))
+		{
+			write_pos = -1;
+			break;
+		}
+
+		/* Get the current line information. */
+		lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+		curr_line_state = pg_atomic_read_u32(&lineInfo->line_state);
+		if ((write_pos % WORKER_CHUNK_COUNT == 0) &&
+			(curr_line_state == LINE_WORKER_PROCESSED ||
+			 curr_line_state == LINE_WORKER_PROCESSING))
+		{
+			pcdata->worker_processed_pos = write_pos;
+			write_pos = (write_pos + WORKER_CHUNK_COUNT) %  RINGSIZE;
+			continue;
+		}
+
+		/* Get the size of this line. */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+		if (dataSize != 0) /* If not an empty line. */
+		{
+			/* Get the block information. */
+			data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+			if (!data_blk_ptr->curr_blk_completed && (dataSize == -1))
+			{
+				/* Wait till the current line or block is added. */
+				COPY_WAIT_TO_PROCESS()
+				continue;
+			}
+		}
+
+		/* Make sure that no worker has consumed this element. */
+		if (pg_atomic_compare_exchange_u32(&lineInfo->line_state,
+										   &line_state, LINE_WORKER_PROCESSING))
+			break;
+	}
+
+	pcdata->worker_processed_pos = write_pos;
+	return write_pos;
+}
+
+/*
+ * GetFreeCopyBlock - Get a free block for data to be copied.
+ */
+static pg_attribute_always_inline uint32
+GetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	int count = 0;
+	uint32 last_free_block = pcshared_info->cur_block_pos;
+	uint32 block_pos = (last_free_block != -1) ? ((last_free_block + 1) % MAX_BLOCKS_COUNT): 0;
+
+	/*
+	 * Get a new block for copying data, don't check curent block, current
+	 * block will have some unprocessed data.
+	 */
+	while (count < (MAX_BLOCKS_COUNT - 1))
+	{
+		ParallelCopyDataBlock *dataBlkPtr = &pcshared_info->data_blocks[block_pos];
+		uint32 unprocessed_line_parts = pg_atomic_read_u32(&dataBlkPtr->unprocessed_line_parts);
+		if (unprocessed_line_parts == 0)
+		{
+			dataBlkPtr->curr_blk_completed = false;
+			dataBlkPtr->skip_bytes = 0;
+			pcshared_info->cur_block_pos = block_pos;
+			return block_pos;
+		}
+
+		block_pos = (block_pos + 1) % MAX_BLOCKS_COUNT;
+		count++;
+	}
+
+	return -1;
+}
+
+/*
+ * WaitGetFreeCopyBlock - If there are no blocks available, wait and get a block
+ * for copying data.
+ */
+static uint32
+WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	uint32 new_free_pos = -1;
+	for (;;)
+	{
+		new_free_pos = GetFreeCopyBlock(pcshared_info);
+		if (new_free_pos != -1)	/* We have got one block, break now. */
+			break;
+
+		COPY_WAIT_TO_PROCESS()
+	}
+
+	return new_free_pos;
+}
+
 /*
  * LookupParallelCopyFnPtr - Look up parallel copy function pointer.
  */
@@ -1269,6 +1867,146 @@ LookupParallelCopyFnStr(copy_data_source_cb fn_addr)
 	/* We can only reach this by programming error. */
 	elog(ERROR, "internal function pointer not found");
 }
+
+/*
+ * SetRawBufForLoad - Set raw_buf to the shared memory where the file data must
+ * be read.
+ */
+static void
+SetRawBufForLoad(CopyState cstate, uint32 line_size, uint32 copy_buf_len,
+				 uint32 raw_buf_ptr, char **copy_raw_buf)
+{
+	ParallelCopyShmInfo	*pcshared_info;
+	uint32 cur_block_pos;
+	uint32 next_block_pos;
+	ParallelCopyDataBlock	*cur_data_blk_ptr = NULL;
+	ParallelCopyDataBlock	*next_data_blk_ptr = NULL;
+
+	if (!IsParallelCopy())
+		return;
+
+	pcshared_info = cstate->pcdata->pcshared_info;
+	cur_block_pos = pcshared_info->cur_block_pos;
+	cur_data_blk_ptr = (cstate->raw_buf) ? &pcshared_info->data_blocks[cur_block_pos] : NULL;
+	next_block_pos = WaitGetFreeCopyBlock(pcshared_info);
+	next_data_blk_ptr = &pcshared_info->data_blocks[next_block_pos];
+
+	/* set raw_buf to the data block in shared memory */
+	cstate->raw_buf = next_data_blk_ptr->data;
+	*copy_raw_buf = cstate->raw_buf;
+	if (cur_data_blk_ptr && line_size)
+	{
+		/*
+		 * Mark the previous block as completed, worker can start copying this
+		 * data.
+		 */
+		cur_data_blk_ptr->following_block = next_block_pos;
+		pg_atomic_add_fetch_u32(&cur_data_blk_ptr->unprocessed_line_parts, 1);
+		cur_data_blk_ptr->skip_bytes = copy_buf_len - raw_buf_ptr;
+		cur_data_blk_ptr->curr_blk_completed = true;
+	}
+}
+
+/*
+ * EndLineParallelCopy - Update the line information in shared memory.
+ */
+static void
+EndLineParallelCopy(CopyState cstate, uint32 line_pos, uint32 line_size,
+					 uint32 raw_buf_ptr)
+{
+	uint8 new_line_size;
+	if (!IsParallelCopy())
+		return;
+
+	if (!IsHeaderLine())
+	{
+		ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+		ParallelCopyLineBoundaries *lineBoundaryPtr = &pcshared_info->line_boundaries;
+		SET_NEWLINE_SIZE()
+		if (line_size)
+		{
+			ParallelCopyLineBoundary *lineInfo = &lineBoundaryPtr->ring[line_pos];
+			/*
+			 * If the new_line_size > raw_buf_ptr, then the new block has only
+			 * new line char content. The unprocessed count should not be
+			 * increased in this case.
+			 */
+			if (raw_buf_ptr > new_line_size)
+			{
+				uint32 cur_block_pos = pcshared_info->cur_block_pos;
+				ParallelCopyDataBlock *curr_data_blk_ptr = &pcshared_info->data_blocks[cur_block_pos];
+				pg_atomic_add_fetch_u32(&curr_data_blk_ptr->unprocessed_line_parts, 1);
+			}
+
+			/* Update line size. */
+			pg_atomic_write_u32(&lineInfo->line_size, line_size);
+			pg_atomic_write_u32(&lineInfo->line_state, LINE_LEADER_POPULATED);
+			elog(DEBUG1, "[Leader] After adding - line position:%d, line_size:%d",
+						 line_pos, line_size);
+			pcshared_info->populated++;
+		}
+		else if (new_line_size)
+		{
+			/* This means only new line char, empty record should be inserted.*/
+			ParallelCopyLineBoundary *lineInfo;
+			line_pos = UpdateBlockInLineInfo(cstate, -1, -1, 0,
+											   LINE_LEADER_POPULATED);
+			lineInfo = &lineBoundaryPtr->ring[line_pos];
+			elog(DEBUG1, "[Leader] Added empty line with offset:%d, line position:%d, line size:%d",
+						 lineInfo->start_offset, line_pos,
+						 pg_atomic_read_u32(&lineInfo->line_size));
+			pcshared_info->populated++;
+		}
+	}
+}
+
+/*
+ * ExecBeforeStmtTrigger - Execute the before statement trigger, this will be
+ * executed for parallel copy by the leader process.
+ */
+static void
+ExecBeforeStmtTrigger(CopyState cstate)
+{
+	EState	   *estate = CreateExecutorState();
+	ResultRelInfo *resultRelInfo;
+
+	Assert(IsLeader());
+
+	/*
+	 * We need a ResultRelInfo so we can use the regular executor's
+	 * index-entry-making machinery.  (There used to be a huge amount of code
+	 * here that basically duplicated execUtils.c ...)
+	 */
+	resultRelInfo = makeNode(ResultRelInfo);
+	InitResultRelInfo(resultRelInfo,
+					  cstate->rel,
+					  1,		/* must match rel's position in range_table */
+					  NULL,
+					  0);
+
+	/* Verify the named relation is a valid target for INSERT */
+	CheckValidResultRel(resultRelInfo, CMD_INSERT);
+
+	estate->es_result_relations = resultRelInfo;
+	estate->es_num_result_relations = 1;
+	estate->es_result_relation_info = resultRelInfo;
+
+	ExecInitRangeTable(estate, cstate->range_table);
+
+	/*
+	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
+	 * should do this for COPY, since it's not really an "INSERT" statement as
+	 * such. However, executing these triggers maintains consistency with the
+	 * EACH ROW triggers that we already fire on COPY.
+	 */
+	ExecBSInsertTriggers(estate, resultRelInfo);
+
+	/* Close any trigger target relations */
+	ExecCleanUpTriggerState(estate);
+
+	FreeExecutorState(estate);
+}
+
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
  * in past protocol redesigns.
@@ -3698,7 +4436,8 @@ CopyFrom(CopyState cstate)
 
 	PartitionTupleRouting *proute = NULL;
 	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
+	CommandId	mycid = IsParallelCopy() ? GetCurrentCommandId(false) :
+										   GetCurrentCommandId(true);
 	int			ti_options = 0; /* start with default options for insert */
 	BulkInsertState bistate = NULL;
 	CopyInsertMethod insertMethod;
@@ -3708,7 +4447,14 @@ CopyFrom(CopyState cstate)
 	bool		has_instead_insert_row_trig;
 	bool		leafpart_use_multi_insert = false;
 
-	CheckTargetRelValidity(cstate);
+	/*
+	 * Perform this check if it is not parallel copy. In case of parallel
+	 * copy, this check is done by the leader, so that if any invalid case
+	 * exist the copy from command will error out from the leader itself,
+	 * avoiding launching workers, just to throw error.
+	 */
+	if (!IsParallelCopy())
+		CheckTargetRelValidity(cstate);
 
 	/*
 	 * If the target file is new-in-transaction, we assume that checking FSM
@@ -3897,13 +4643,16 @@ CopyFrom(CopyState cstate)
 	has_instead_insert_row_trig = (resultRelInfo->ri_TrigDesc &&
 								   resultRelInfo->ri_TrigDesc->trig_insert_instead_row);
 
-	/*
-	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
-	 * should do this for COPY, since it's not really an "INSERT" statement as
-	 * such. However, executing these triggers maintains consistency with the
-	 * EACH ROW triggers that we already fire on COPY.
-	 */
-	ExecBSInsertTriggers(estate, resultRelInfo);
+	if (!IsParallelCopy())
+	{
+		/*
+		 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
+		 * should do this for COPY, since it's not really an "INSERT" statement as
+		 * such. However, executing these triggers maintains consistency with the
+		 * EACH ROW triggers that we already fire on COPY.
+		 */
+		ExecBSInsertTriggers(estate, resultRelInfo);
+	}
 
 	econtext = GetPerTupleExprContext(estate);
 
@@ -4003,6 +4752,16 @@ CopyFrom(CopyState cstate)
 					!has_instead_insert_row_trig &&
 					resultRelInfo->ri_FdwRoutine == NULL;
 
+				/*
+				 * If the table has any partitions that are either foreign or
+				 * has BEFORE/INSTEAD OF triggers, we can't perform copy
+				 * operations with parallel workers.
+				 */
+				if (!leafpart_use_multi_insert && IsParallelWorker())
+					ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							errmsg("cannot perform PARALLEL COPY if partition has BEFORE/INSTEAD OF triggers, or if the partition is foreign partition"),
+							errhint("Try COPY without PARALLEL option")));
+
 				/* Set the multi-insert buffer to use for this partition. */
 				if (leafpart_use_multi_insert)
 				{
@@ -4417,7 +5176,7 @@ BeginCopyFrom(ParseState *pstate,
 	initStringInfo(&cstate->attribute_buf);
 	initStringInfo(&cstate->line_buf);
 	cstate->line_buf_converted = false;
-	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+	cstate->raw_buf = (IsParallelCopy()) ? NULL : (char *) palloc(RAW_BUF_SIZE + 1);
 	cstate->raw_buf_index = cstate->raw_buf_len = 0;
 
 	/* Assign range table, we'll need it in CopyFrom. */
@@ -4561,26 +5320,35 @@ NextCopyFromRawFields(CopyState cstate, char ***fields, int *nfields)
 	/* only available for text or csv input */
 	Assert(!cstate->binary);
 
-	/* on input just throw the header line away */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (IsParallelCopy())
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
-			return false;		/* done */
+		done = GetWorkerLine(cstate);
+		if (done && cstate->line_buf.len == 0)
+			return false;
 	}
+	else
+	{
+		/* on input just throw the header line away */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
+		{
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+				return false;		/* done */
+		}
 
-	cstate->cur_lineno++;
+		cstate->cur_lineno++;
 
-	/* Actually read the line into memory here */
-	done = CopyReadLine(cstate);
+		/* Actually read the line into memory here */
+		done = CopyReadLine(cstate);
 
-	/*
-	 * EOF at start of line means we're done.  If we see EOF after some
-	 * characters, we act as though it was newline followed by EOF, ie,
-	 * process the line and then exit loop on next iteration.
-	 */
-	if (done && cstate->line_buf.len == 0)
-		return false;
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			return false;
+	}
 
 	/* Parse the line into de-escaped field values */
 	if (cstate->csv_mode)
@@ -4828,9 +5596,31 @@ CopyReadLine(CopyState cstate)
 		 */
 		if (cstate->copy_dest == COPY_NEW_FE)
 		{
+			bool bIsFirst = true;
 			do
 			{
-				cstate->raw_buf_index = cstate->raw_buf_len;
+				if (!IsParallelCopy())
+					cstate->raw_buf_index = cstate->raw_buf_len;
+				else
+				{
+					if (cstate->raw_buf_index == RAW_BUF_SIZE)
+					{
+						/* Get a new block if it is the first time, From the
+						 * subsequent time, reset the index and re-use the same
+						 * block.
+						 */
+						if (bIsFirst)
+						{
+							ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+							uint32 block_pos = WaitGetFreeCopyBlock(pcshared_info);
+							cstate->raw_buf = pcshared_info->data_blocks[block_pos].data;
+							bIsFirst = false;
+						}
+
+						cstate->raw_buf_index = cstate->raw_buf_len = 0;
+					}
+				}
+
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
@@ -4860,6 +5650,11 @@ CopyReadLineText(CopyState cstate)
 	char		quotec = '\0';
 	char		escapec = '\0';
 
+	/* For parallel copy */
+	uint32			 line_size = 0;
+	int				 line_pos = 0;
+
+	cstate->eol_type = EOL_UNKNOWN;
 	if (cstate->csv_mode)
 	{
 		quotec = cstate->quote[0];
@@ -4914,6 +5709,8 @@ CopyReadLineText(CopyState cstate)
 		if (raw_buf_ptr >= copy_buf_len || need_data)
 		{
 			REFILL_LINEBUF;
+			SetRawBufForLoad(cstate, line_size, copy_buf_len, raw_buf_ptr,
+							 &copy_raw_buf);
 
 			/*
 			 * Try to read some more data.  This will certainly reset
@@ -5138,9 +5935,15 @@ CopyReadLineText(CopyState cstate)
 				 * discard the data and the \. sequence.
 				 */
 				if (prev_raw_ptr > cstate->raw_buf_index)
-					appendBinaryStringInfo(&cstate->line_buf,
+				{
+					if (!IsParallelCopy())
+						appendBinaryStringInfo(&cstate->line_buf,
 										   cstate->raw_buf + cstate->raw_buf_index,
 										   prev_raw_ptr - cstate->raw_buf_index);
+					else
+						line_size += prev_raw_ptr - cstate->raw_buf_index;
+				}
+
 				cstate->raw_buf_index = raw_buf_ptr;
 				result = true;	/* report EOF */
 				break;
@@ -5192,6 +5995,26 @@ not_end_of_copy:
 			IF_NEED_REFILL_AND_EOF_BREAK(mblen - 1);
 			raw_buf_ptr += mblen - 1;
 		}
+
+		/*
+		 * Skip the header line. Update the line here, this cannot be done at
+		 * the beginning, as there is a possibility that file contains empty
+		 * lines.
+		 */
+		if (IsParallelCopy() && first_char_in_line && !IsHeaderLine())
+		{
+			ParallelCopyShmInfo	*pcshared_info = cstate->pcdata->pcshared_info;
+			ParallelCopyLineBoundary *lineInfo;
+			uint32			 line_first_block = pcshared_info->cur_block_pos;
+			line_pos = UpdateBlockInLineInfo(cstate,
+											   line_first_block,
+											   cstate->raw_buf_index, -1,
+											   LINE_LEADER_POPULATING);
+			lineInfo = &pcshared_info->line_boundaries.ring[line_pos];
+			elog(DEBUG1, "[Leader] Adding - block:%d, offset:%d, line position:%d",
+						 line_first_block,	lineInfo->start_offset, line_pos);
+		}
+
 		first_char_in_line = false;
 	}							/* end of outer loop */
 
@@ -5200,6 +6023,7 @@ not_end_of_copy:
 	 */
 	REFILL_LINEBUF;
 	CLEAR_EOL_LINE()
+	EndLineParallelCopy(cstate, line_pos, line_size, raw_buf_ptr);
 
 	return result;
 }
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index db19187..20dafb7 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -381,6 +381,8 @@ extern FullTransactionId GetTopFullTransactionId(void);
 extern FullTransactionId GetTopFullTransactionIdIfAny(void);
 extern FullTransactionId GetCurrentFullTransactionId(void);
 extern FullTransactionId GetCurrentFullTransactionIdIfAny(void);
+extern void AssignFullTransactionIdForWorker(FullTransactionId fullTransactionId);
+extern void AssignCommandIdForWorker(CommandId commandId, bool used);
 extern void MarkCurrentTransactionIdLoggedIfAny(void);
 extern bool SubTransactionIsActive(SubTransactionId subxid);
 extern CommandId GetCurrentCommandId(bool used);
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 6a42ac4..86a7620 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1701,6 +1701,7 @@ ParallelCompletionPtr
 ParallelContext
 ParallelCopyLineBoundaries
 ParallelCopyLineBoundary
+ParallelCopyLineState
 ParallelCopyCommonKeyData
 ParallelCopyData
 ParallelCopyDataBlock
-- 
1.8.3.1

0004-Documentation-for-parallel-copy.patchapplication/octet-stream; name=0004-Documentation-for-parallel-copy.patchDownload
From d04485ce9e4768cbab3f2722dadcf032586fda33 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 17 Jun 2020 07:34:56 +0530
Subject: [PATCH 4/6] Documentation for parallel copy.

This patch has the documentation changes for parallel copy.
---
 doc/src/sgml/ref/copy.sgml | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/doc/src/sgml/ref/copy.sgml b/doc/src/sgml/ref/copy.sgml
index 18189ab..95d349d 100644
--- a/doc/src/sgml/ref/copy.sgml
+++ b/doc/src/sgml/ref/copy.sgml
@@ -37,6 +37,7 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
     DELIMITER '<replaceable class="parameter">delimiter_character</replaceable>'
     NULL '<replaceable class="parameter">null_string</replaceable>'
     HEADER [ <replaceable class="parameter">boolean</replaceable> ]
+    PARALLEL <replaceable class="parameter">integer</replaceable>
     QUOTE '<replaceable class="parameter">quote_character</replaceable>'
     ESCAPE '<replaceable class="parameter">escape_character</replaceable>'
     FORCE_QUOTE { ( <replaceable class="parameter">column_name</replaceable> [, ...] ) | * }
@@ -275,6 +276,21 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
    </varlistentry>
 
    <varlistentry>
+    <term><literal>PARALLEL</literal></term>
+    <listitem>
+     <para>
+      Perform <command>COPY FROM</command> in parallel using <replaceable
+      class="parameter"> integer</replaceable> background workers.  Please
+      note that it is not guaranteed that the number of parallel workers
+      specified in <replaceable class="parameter">integer</replaceable> will
+      be used during execution.  It is possible for a copy to run with fewer
+      workers than specified, or even with no workers at all.  This option is
+      allowed only in <command>COPY FROM</command>.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><literal>QUOTE</literal></term>
     <listitem>
      <para>
-- 
1.8.3.1

0005-Tests-for-parallel-copy.patchapplication/octet-stream; name=0005-Tests-for-parallel-copy.patchDownload
From cd57bede56d817a95ae251ab4b3c543c73bcf9a8 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 17 Jun 2020 07:37:26 +0530
Subject: [PATCH 5/6] Tests for parallel copy.

This patch has the tests for parallel copy.
---
 src/test/regress/expected/copy2.out | 210 +++++++++++++++++++++++++++++++++++-
 src/test/regress/input/copy.source  |  12 +++
 src/test/regress/output/copy.source |  12 +++
 src/test/regress/sql/copy2.sql      | 208 ++++++++++++++++++++++++++++++++++-
 4 files changed, 434 insertions(+), 8 deletions(-)

diff --git a/src/test/regress/expected/copy2.out b/src/test/regress/expected/copy2.out
index e40287d..ef75148 100644
--- a/src/test/regress/expected/copy2.out
+++ b/src/test/regress/expected/copy2.out
@@ -254,18 +254,32 @@ It is "perfect".|
 "It is ""perfect"".","	"
 "",
 --test that we read consecutive LFs properly
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 COPY testnl FROM stdin CSV;
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+SELECT * FROM testnl;
+ a |          b           | c 
+---+----------------------+---
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+(2 rows)
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 COPY testeoc FROM stdin CSV;
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
 COPY testeoc TO stdout CSV;
 a\.
 \.b
 c\.d
 "\."
 -- test handling of nonstandard null marker that violates escaping rules
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 COPY testnull TO stdout WITH NULL AS E'\\0';
 1	\\0
@@ -280,6 +294,15 @@ SELECT * FROM testnull;
     | 
 (4 rows)
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 1);
+SELECT * FROM testnull;
+ a  | b  
+----+----
+ 42 | \0
+    | 
+(2 rows)
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -349,6 +372,34 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+SELECT * FROM vistest;
+ a  
+----
+ a2
+ b
+(2 rows)
+
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+COMMIT;
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 SELECT * FROM vistest;
  a 
@@ -409,7 +460,7 @@ SELECT * FROM vistest;
 (2 rows)
 
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -420,6 +471,8 @@ CREATE TEMP TABLE forcetest (
 -- should succeed with no effect ("b" remains an empty string, "c" remains NULL)
 BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 1);
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
  b |  c   
@@ -430,6 +483,8 @@ SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
 BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 1);
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
  c |  d   
@@ -486,6 +541,31 @@ select * from check_con_tbl;
    
 (2 rows)
 
+\d+ check_con_tbl
+                               Table "public.check_con_tbl"
+ Column |  Type   | Collation | Nullable | Default | Storage | Stats target | Description 
+--------+---------+-----------+----------+---------+---------+--------------+-------------
+ f1     | integer |           |          |         | plain   |              | 
+Check constraints:
+    "check_con_tbl_check" CHECK (check_con_function(check_con_tbl.*))
+
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 1);
+NOTICE:  input = {"f1":1}
+NOTICE:  input = {"f1":null}
+copy check_con_tbl from stdin with (parallel 1);
+NOTICE:  input = {"f1":0}
+ERROR:  new row for relation "check_con_tbl" violates check constraint "check_con_tbl_check"
+DETAIL:  Failing row contains (0).
+CONTEXT:  COPY check_con_tbl, line 1: "0"
+parallel worker
+select * from check_con_tbl;
+ f1 
+----
+  1
+   
+(2 rows)
+
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
 CREATE ROLE regress_rls_copy_user_colperms;
@@ -600,8 +680,130 @@ SELECT * FROM instead_of_insert_tbl;
 (2 rows)
 
 COMMIT;
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+COPY test_parallel_copy (a, b, c, d, e) from stdin with (PARALLEL 1);
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1, FORMAT 'csv', HEADER);
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0');
+ERROR:  argument to option "parallel" must be a positive integer greater than zero
+LINE 1: COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0'...
+                                                        ^
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri from stdin with (FORMAT csv, DELIMITER ',', PARALLEL 1);
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1) WHERE height > random() * 65;
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- temporary table copy: should peform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+COPY temp_test (a) from stdin with (PARALLEL 1);
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) from stdin with (PARALLEL 1);
+ERROR:  column "xyz" of relation "test_parallel_copy" does not exist
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) from stdin with (PARALLEL 1);
+ERROR:  column "d" specified more than once
+-- missing data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  invalid input syntax for type integer: ""
+CONTEXT:  COPY test_parallel_copy, line 0, column a: ""
+parallel worker
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2000	230	23	23"
+parallel worker
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2001	231	\N	\N"
+parallel worker
+-- extra data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  extra data after last expected column
+CONTEXT:  COPY test_parallel_copy, line 1: "2002	232	40	50	60	70	80"
+parallel worker
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) from stdin with (delimiter ',', null 'x', PARALLEL 1) ;
+COPY test_parallel_copy from stdin WITH (DELIMITER ';', NULL '', PARALLEL 1);
+COPY test_parallel_copy from stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL 1);
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = 50004;
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a > 60003;
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE f > 60003;
+ERROR:  column "f" does not exist
+LINE 1: ..._parallel_copy from stdin WITH (PARALLEL 1) WHERE f > 60003;
+                                                             ^
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+ERROR:  missing FROM-clause entry for table "x"
+LINE 1: ...rallel_copy from stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+                                                                  ^
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (SELECT 1 FROM x);
+ERROR:  cannot use subquery in COPY FROM WHERE condition
+LINE 1: ...arallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (SELECT...
+                                                             ^
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (generate_series(1,5));
+ERROR:  set-returning functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...lel_copy from stdin WITH (PARALLEL 1) WHERE a IN (generate_s...
+                                                             ^
+COPY test_parallel_copy from stdin WITH(PARALLEL 1) WHERE a = row_number() over(b);
+ERROR:  window functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...rallel_copy from stdin WITH(PARALLEL 1) WHERE a = row_number...
+                                                             ^
+-- check results of copy in
+SELECT * FROM test_parallel_copy;
+   a   | b  |     c      |    d    |    e    
+-------+----+------------+---------+---------
+     1 | 11 | test_c1    | test_d1 | test_e1
+     2 | 12 | test_c2    | test_d2 | test_e2
+       |  3 | stuff      | test_d3 | 
+       |  4 | stuff      | test_d4 | 
+       |  5 | stuff      | test_d5 | 
+       |    | 45         | 80      | 90
+       |    | x          | \x      | \x
+       |    | ,          | \,      | \
+  3000 |    | c          |         | 
+  4000 |    | C          |         | 
+  4001 |  1 | empty      |         | 
+  4002 |  2 | null       |         | 
+  4003 |  3 | Backslash  | \       | \
+  4004 |  4 | BackslashX | \X      | \X
+  4005 |  5 | N          | N       | N
+  4006 |  6 | BackslashN | \N      | \N
+  4007 |  7 | XX         | XX      | XX
+  4008 |  8 | Delimiter  | :       | :
+ 50004 | 25 | 35         | 45      | 55
+ 60004 | 25 | 35         | 45      | 55
+ 60005 | 26 | 36         | 46      | 56
+(21 rows)
+
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
 DROP TABLE x, y;
diff --git a/src/test/regress/input/copy.source b/src/test/regress/input/copy.source
index a1d529a..159c058 100644
--- a/src/test/regress/input/copy.source
+++ b/src/test/regress/input/copy.source
@@ -15,6 +15,13 @@ DELETE FROM onek;
 
 COPY onek FROM '@abs_builddir@/results/onek.data';
 
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+
+SELECT COUNT(*) FROM tenk1;
+
+TRUNCATE tenk1;
+
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
@@ -159,6 +166,11 @@ truncate parted_copytest;
 
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
 
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
+
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/output/copy.source b/src/test/regress/output/copy.source
index 938d355..c3003fe 100644
--- a/src/test/regress/output/copy.source
+++ b/src/test/regress/output/copy.source
@@ -9,6 +9,15 @@ COPY onek FROM '@abs_srcdir@/data/onek.data';
 COPY onek TO '@abs_builddir@/results/onek.data';
 DELETE FROM onek;
 COPY onek FROM '@abs_builddir@/results/onek.data';
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+SELECT COUNT(*) FROM tenk1;
+ count 
+-------
+ 10000
+(1 row)
+
+TRUNCATE tenk1;
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
 COPY person FROM '@abs_srcdir@/data/person.data';
@@ -113,6 +122,9 @@ insert into parted_copytest select x,1,'One' from generate_series(1011,1020) x;
 copy (select * from parted_copytest order by a) to '@abs_builddir@/results/parted_copytest.csv';
 truncate parted_copytest;
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/sql/copy2.sql b/src/test/regress/sql/copy2.sql
index 902f4fa..032cea9 100644
--- a/src/test/regress/sql/copy2.sql
+++ b/src/test/regress/sql/copy2.sql
@@ -157,7 +157,7 @@ COPY y TO stdout (FORMAT CSV, FORCE_QUOTE *);
 
 --test that we read consecutive LFs properly
 
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 
 COPY testnl FROM stdin CSV;
 1,"a field with two LFs
@@ -165,8 +165,16 @@ COPY testnl FROM stdin CSV;
 inside",2
 \.
 
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+1,"a field with two LFs
+
+inside",2
+\.
+
+SELECT * FROM testnl;
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 
 COPY testeoc FROM stdin CSV;
 a\.
@@ -175,11 +183,19 @@ c\.d
 "\."
 \.
 
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+a\.
+\.b
+c\.d
+"\."
+\.
+
 COPY testeoc TO stdout CSV;
 
 -- test handling of nonstandard null marker that violates escaping rules
 
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 
 COPY testnull TO stdout WITH NULL AS E'\\0';
@@ -191,6 +207,14 @@ COPY testnull FROM stdin WITH NULL AS E'\\0';
 
 SELECT * FROM testnull;
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 1);
+42	\\0
+\0	\0
+\.
+
+SELECT * FROM testnull;
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -235,6 +259,23 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+a2
+b
+\.
+SELECT * FROM vistest;
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+d2
+e
+\.
+SELECT * FROM vistest;
+COMMIT;
+SELECT * FROM vistest;
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 x
 y
@@ -284,7 +325,7 @@ SELECT * FROM vistest;
 COMMIT;
 SELECT * FROM vistest;
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -297,6 +338,10 @@ BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
 1,,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 1);
+1,,""
+\.
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
@@ -304,6 +349,10 @@ BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
 2,'a',,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 1);
+2,'a',,""
+\.
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
 -- should fail with not-null constraint violation
@@ -339,6 +388,16 @@ copy check_con_tbl from stdin;
 0
 \.
 select * from check_con_tbl;
+\d+ check_con_tbl
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 1);
+1
+\N
+\.
+copy check_con_tbl from stdin with (parallel 1);
+0
+\.
+select * from check_con_tbl;
 
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
@@ -440,8 +499,149 @@ test1
 SELECT * FROM instead_of_insert_tbl;
 COMMIT;
 
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+
+COPY test_parallel_copy (a, b, c, d, e) from stdin with (PARALLEL 1);
+1	11	test_c1	test_d1	test_e1
+2	12	test_c2	test_d2	test_e2
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+3	test_d3
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+4	test_d4
+5	test_d5
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1, FORMAT 'csv', HEADER);
+b	d
+\.
+
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0');
+
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri from stdin with (FORMAT csv, DELIMITER ',', PARALLEL 1);
+10
+\.
+
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1) WHERE height > random() * 65;
+60,60,60
+\.
+
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+60
+\.
+
+-- temporary table copy: should peform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+
+COPY temp_test (a) from stdin with (PARALLEL 1);
+10
+\.
+
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) from stdin with (PARALLEL 1);
+
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) from stdin with (PARALLEL 1);
+
+-- missing data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+
+\.
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+2000	230	23	23
+\.
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+2001	231	\N	\N
+\.
+
+-- extra data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+2002	232	40	50	60	70	80
+\.
+
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) from stdin with (delimiter ',', null 'x', PARALLEL 1) ;
+x,45,80,90
+x,\x,\\x,\\\x
+x,\,,\\\,,\\
+\.
+
+COPY test_parallel_copy from stdin WITH (DELIMITER ';', NULL '', PARALLEL 1);
+3000;;c;;
+\.
+
+COPY test_parallel_copy from stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL 1);
+4000:\X:C:\X:\X
+4001:1:empty::
+4002:2:null:\X:\X
+4003:3:Backslash:\\:\\
+4004:4:BackslashX:\\X:\\X
+4005:5:N:\N:\N
+4006:6:BackslashN:\\N:\\N
+4007:7:XX:\XX:\XX
+4008:8:Delimiter:\::\:
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = 50004;
+50003	24	34	44	54
+50004	25	35	45 	55
+50005	26	36	46	56
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a > 60003;
+60001	22	32	42	52
+60002	23	33	43	53
+60003	24	34	44	54
+60004	25	35	45	55
+60005	26	36	46	56
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE f > 60003;
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (SELECT 1 FROM x);
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (generate_series(1,5));
+
+COPY test_parallel_copy from stdin WITH(PARALLEL 1) WHERE a = row_number() over(b);
+
+-- check results of copy in
+SELECT * FROM test_parallel_copy;
+
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
 DROP TABLE x, y;
-- 
1.8.3.1

0006-Parallel-Copy-For-Binary-Format-Files.patchapplication/octet-stream; name=0006-Parallel-Copy-For-Binary-Format-Files.patchDownload
From dbcf9dcfc87d8e5eed4d56b2a079a64258c591c6 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddy@enterprisedb.com>
Date: Sat, 11 Jul 2020 11:39:50 +0530
Subject: [PATCH v10] Parallel Copy For Binary Format Files

Leader reads data from the file into the DSM data blocks each of 64K size.
It also identifies each tuple data block id, start offset, end offset,
tuple size and updates this information in the ring data structure.
Workers parallely read the tuple information from the ring data structure,
the actual tuple data from the data blocks and parallely insert the tuples
into the table.
---
 src/backend/commands/copy.c | 655 +++++++++++++++++++++++++++++++-----
 1 file changed, 574 insertions(+), 81 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 048f2d2cb6..a4e4163c32 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -219,6 +219,17 @@ typedef struct ParallelCopyLineBuf
 	uint64				cur_lineno;	/* line number for error messages */
 }ParallelCopyLineBuf;
 
+/*
+ * Represents the usage mode for CopyReadBinaryGetDataBlock.
+ */
+typedef enum FieldInfoType
+{
+	FIELD_NONE = 0,
+	FIELD_COUNT,
+	FIELD_SIZE,
+	FIELD_DATA
+} FieldInfoType;
+
 /*
  * Parallel copy data information.
  */
@@ -240,6 +251,9 @@ typedef struct ParallelCopyData
 
 	/* Current position in worker_line_buf */
 	uint32				worker_line_buf_pos;
+
+	/* For binary formatted files */
+	ParallelCopyDataBlock *curr_data_block;
 }ParallelCopyData;
 
 /*
@@ -397,6 +411,7 @@ typedef struct ParallelCopyCommonKeyData
 	/* Working state for COPY FROM */
 	AttrNumber          num_defaults;
 	Oid                 relid;
+	bool 				binary;
 }ParallelCopyCommonKeyData;
 
 /*
@@ -502,7 +517,6 @@ typedef struct CopyMultiInsertInfo
 	int			ti_options;		/* table insert options */
 } CopyMultiInsertInfo;
 
-
 /*
  * These macros centralize code used to process line_buf and raw_buf buffers.
  * They are macros because they often do continue/break control and to avoid
@@ -697,8 +711,110 @@ if (!IsParallelCopy()) \
 else \
 	return pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
 
-static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
+/*
+ * CHECK_FIELD_COUNT - Handles the error cases for field count
+ * for binary format files.
+ */
+#define CHECK_FIELD_COUNT \
+{\
+	if (fld_count == -1) \
+	{ \
+		if (IsParallelCopy() && \
+			!IsLeader()) \
+			return true; \
+		else if (IsParallelCopy() && \
+			IsLeader()) \
+		{ \
+			if (cstate->pcdata->curr_data_block->data[cstate->raw_buf_index + sizeof(fld_count)] != 0) \
+				ereport(ERROR, \
+						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+						errmsg("received copy data after EOF marker"))); \
+			return true; \
+		} \
+		else \
+		{ \
+			/* \
+			* Received EOF marker.  In a V3-protocol copy, wait for the \
+			* protocol-level EOF, and complain if it doesn't come \
+			* immediately.  This ensures that we correctly handle CopyFail, \
+			* if client chooses to send that now. \
+			* \
+			* Note that we MUST NOT try to read more data in an old-protocol \
+			* copy, since there is no protocol-level EOF marker then.  We \
+			* could go either way for copy from file, but choose to throw \
+			* error if there's data after the EOF marker, for consistency \
+			* with the new-protocol case. \
+			*/ \
+			char		dummy; \
+			if (cstate->copy_dest != COPY_OLD_FE && \
+				CopyGetData(cstate, &dummy, 1, 1) > 0) \
+				ereport(ERROR, \
+						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+						errmsg("received copy data after EOF marker"))); \
+				return false; \
+		} \
+	} \
+	if (fld_count != cstate->max_fields) \
+		ereport(ERROR, \
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+				errmsg("row field count is %d, expected %d", \
+				(int) fld_count, cstate->max_fields))); \
+}
+
+/*
+ * CHECK_FIELD_SIZE - Handles the error case for field size
+ * for binary format files.
+ */
+#define CHECK_FIELD_SIZE(fld_size) \
+{ \
+	if (fld_size < -1) \
+		ereport(ERROR, \
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+				errmsg("invalid field size")));\
+}
+
+/*
+ * EOF_ERROR - Error statement for EOF for binary format
+ * files.
+ */
+#define EOF_ERROR \
+{ \
+	ereport(ERROR, \
+		(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+		errmsg("unexpected EOF in COPY data")));\
+}
+
+/*
+ * GET_RAW_BUF_INDEX - Caclulates the raw buf index for the cases
+ * where the data spread is across multiple data blocks.
+ */
+#define GET_RAW_BUF_INDEX(raw_buf_index, fld_size, required_blks, curr_blk_bytes) \
+{ \
+	raw_buf_index = fld_size - (((required_blks - 1) * DATA_BLOCK_SIZE) + curr_blk_bytes); \
+}
+
+/*
+ * GET_REQUIRED_BLOCKS - Caclulates the number of data
+ * blocks required for the cases where the data spread
+ * is across multiple data blocks.
+ */
+#define GET_REQUIRED_BLOCKS(required_blks, fld_size, curr_blk_bytes) \
+{ \
+	/* \
+	 * field size can spread across multiple data blocks, \
+	 * calculate the number of required data blocks and try to get \
+	 * those many data blocks. \
+	 */ \
+	required_blks = (int32)(fld_size - curr_blk_bytes)/(int32)DATA_BLOCK_SIZE; \
+	/* \
+	 * check if we need the data block for the field data \
+	 * bytes that are not modulus of data block size. \
+	 */ \
+	if ((fld_size - curr_blk_bytes)%DATA_BLOCK_SIZE != 0) \
+		required_blks++; \
+}
 
+static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
 /* non-export function prototypes */
 static CopyState BeginCopy(ParseState *pstate, bool is_from, Relation rel,
@@ -751,6 +867,13 @@ static void PopulateCatalogInformation(CopyState cstate);
 static pg_attribute_always_inline uint32 GetLinePosition(CopyState cstate);
 static pg_attribute_always_inline copy_data_source_cb LookupParallelCopyFnPtr(const char *funcname);
 static pg_attribute_always_inline char* LookupParallelCopyFnStr(copy_data_source_cb fn_addr);
+static uint32 WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info);
+static bool CopyReadBinaryTupleLeader(CopyState cstate);
+static void CopyReadBinaryFindTupleSize(CopyState cstate, uint32 *line_size);
+static bool CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls);
+static Datum CopyReadBinaryAttributeWorker(CopyState cstate, FmgrInfo *flinfo,
+										  Oid typioparam, int32 typmod, bool *isnull);
+static void CopyReadBinaryGetDataBlock(CopyState cstate, FieldInfoType field_info);
 
 /*
  * CopyCommonInfoForWorker - Copy shared_cstate using cstate information.
@@ -769,6 +892,7 @@ CopyCommonInfoForWorker(CopyState cstate, ParallelCopyCommonKeyData *shared_csta
 	shared_cstate->convert_selectively = cstate->convert_selectively;
 	shared_cstate->num_defaults = cstate->num_defaults;
 	shared_cstate->relid = cstate->pcdata->relid;
+	shared_cstate->binary = cstate->binary;
 }
 
 /*
@@ -997,8 +1121,8 @@ FindInsertMethod(CopyState cstate)
 static pg_attribute_always_inline bool
 IsParallelCopyAllowed(CopyState cstate)
 {
-	/* Parallel copy not allowed for frontend (2.0 protocol) & binary option. */
-	if ((cstate->copy_dest == COPY_OLD_FE) || cstate->binary)
+	/* Parallel copy not allowed for frontend (2.0 protocol). */
+	if (cstate->copy_dest == COPY_OLD_FE)
 		return false;
 
 	/* Check if copy is into foreign table or temporary table. */
@@ -1299,6 +1423,7 @@ ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
 	cstate->convert_selectively = shared_cstate->convert_selectively;
 	cstate->num_defaults = shared_cstate->num_defaults;
 	pcdata->relid = shared_cstate->relid;
+	cstate->binary = shared_cstate->binary;
 
 	PopulateGlobalsForCopyFrom(cstate, tup_desc, attnamelist);
 
@@ -1314,7 +1439,7 @@ ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
 	initStringInfo(&cstate->attribute_buf);
 
 	initStringInfo(&cstate->line_buf);
-	for (count = 0; count < WORKER_CHUNK_COUNT;count++)
+	for (count = 0; count < WORKER_CHUNK_COUNT; count++)
 		initStringInfo(&pcdata->worker_line_buf[count].line_buf);
 
 	cstate->line_buf_converted = false;
@@ -1680,32 +1805,66 @@ ParallelCopyLeader(CopyState cstate)
 	/* Execute the before statement triggers from the leader */
 	ExecBeforeStmtTrigger(cstate);
 
-	/* On input just throw the header line away. */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (!cstate->binary)
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
+		/* On input just throw the header line away. */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
 		{
-			pcshared_info->is_read_in_progress = false;
-			return;			/* done */
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+			{
+				pcshared_info->is_read_in_progress = false;
+				return;			/* done */
+			}
 		}
-	}
 
-	for (;;)
-	{
-		bool done;
-		cstate->cur_lineno++;
+		for (;;)
+		{
+			bool done;
+			cstate->cur_lineno++;
 
-		/* Actually read the line into memory here. */
-		done = CopyReadLine(cstate);
+			/* Actually read the line into memory here. */
+			done = CopyReadLine(cstate);
 
+			/*
+			* EOF at start of line means we're done.  If we see EOF after some
+			* characters, we act as though it was newline followed by EOF, ie,
+			* process the line and then exit loop on next iteration.
+			*/
+			if (done && cstate->line_buf.len == 0)
+				break;
+		}
+	}
+	else
+	{
 		/*
-		 * EOF at start of line means we're done.  If we see EOF after some
-		 * characters, we act as though it was newline followed by EOF, ie,
-		 * process the line and then exit loop on next iteration.
+		 * Binary Format Files.
+		 * For parallel copy leader, fill in the error
+		 * context inforation here, in case any failures
+		 * while determining tuple offsets, leader
+		 * would throw the errors with proper context.
 		 */
-		if (done && cstate->line_buf.len == 0)
-			break;
+		ErrorContextCallback errcallback;
+		errcallback.callback = CopyFromErrorCallback;
+		errcallback.arg = (void *) cstate;
+		errcallback.previous = error_context_stack;
+		error_context_stack = &errcallback;
+		cstate->pcdata->curr_data_block = NULL;
+		cstate->raw_buf_index = 0;
+		pcshared_info->populated = 0;
+		cstate->cur_lineno = 0;
+		cstate->max_fields = list_length(cstate->attnumlist);
+
+		for (;;)
+		{
+			bool eof = false;
+			cstate->cur_lineno++;
+
+			eof = CopyReadBinaryTupleLeader(cstate);
+
+			if (eof)
+				break;
+		}
 	}
 
 	pcshared_info->is_read_in_progress = false;
@@ -1713,7 +1872,357 @@ ParallelCopyLeader(CopyState cstate)
 }
 
 /*
- * GetLinePosition - return the line position that worker should process.
+ * CopyReadBinaryGetDataBlock - gets a new block, updates
+ * the current offset, calculates the skip bytes.
+ */
+static void
+CopyReadBinaryGetDataBlock(CopyState cstate, FieldInfoType field_info)
+{
+	ParallelCopyDataBlock *data_block = NULL;
+	ParallelCopyDataBlock *curr_data_block = cstate->pcdata->curr_data_block;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	uint8 move_bytes = 0;
+	uint32 block_pos;
+	uint32 prev_block_pos;
+	int read_bytes = 0;
+
+	prev_block_pos = pcshared_info->cur_block_pos;
+
+	block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+	if (field_info == FIELD_SIZE || field_info == FIELD_COUNT)
+		move_bytes = (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+
+	if (curr_data_block != NULL)
+		curr_data_block->skip_bytes = move_bytes;
+
+	data_block = &pcshared_info->data_blocks[block_pos];
+
+	if (move_bytes > 0 && curr_data_block != NULL)
+		memmove(&data_block->data[0], &curr_data_block->data[cstate->raw_buf_index], move_bytes);
+
+	elog(DEBUG1, "LEADER - field info %d is spread across data blocks - moved %d bytes from current block %u to %u block",
+		field_info, move_bytes, prev_block_pos, block_pos);
+
+	read_bytes = CopyGetData(cstate, &data_block->data[move_bytes], 1, (DATA_BLOCK_SIZE - move_bytes));
+
+	if (field_info == FIELD_NONE && cstate->reached_eof)
+		return;
+
+	if (cstate->reached_eof)
+		EOF_ERROR;
+
+	elog(DEBUG1, "LEADER - bytes read from file %d", read_bytes);
+
+	if(field_info == FIELD_SIZE || field_info == FIELD_DATA)
+	{
+		ParallelCopyDataBlock *prev_data_block = NULL;
+		prev_data_block = curr_data_block;
+		prev_data_block->following_block = block_pos;
+
+		if (prev_data_block->curr_blk_completed  == false)
+			prev_data_block->curr_blk_completed = true;
+
+		pg_atomic_add_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+	}
+
+	cstate->pcdata->curr_data_block = data_block;
+	cstate->raw_buf_index = 0;
+}
+
+/*
+ * CopyReadBinaryTupleLeader - leader reads data from binary formatted file
+ * to data blocks and identies tuple boundaries/offsets so that workers
+ * can work on the data blocks data.
+ */
+static bool
+CopyReadBinaryTupleLeader(CopyState cstate)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	int16		fld_count;
+	uint32      line_size = 0;
+	uint32 		start_block_pos;
+	uint32		start_offset;
+
+	if (cstate->pcdata->curr_data_block == NULL)
+	{
+		CopyReadBinaryGetDataBlock(cstate, FIELD_NONE);
+
+		/*
+		 * no data is read from file here. one possibility
+		 * to be here could be that the binary file just
+		 * has a valid signature but nothing else.
+		 */
+		if (cstate->reached_eof)
+			return true;
+	}
+
+	if ((cstate->raw_buf_index + sizeof(fld_count)) >= DATA_BLOCK_SIZE)
+		CopyReadBinaryGetDataBlock(cstate, FIELD_COUNT);
+
+	memcpy(&fld_count, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_count));
+	fld_count = (int16) pg_ntoh16(fld_count);
+	CHECK_FIELD_COUNT;
+	start_offset = cstate->raw_buf_index;
+	cstate->raw_buf_index += sizeof(fld_count);
+	line_size += sizeof(fld_count);
+	start_block_pos = pcshared_info->cur_block_pos;
+
+	CopyReadBinaryFindTupleSize(cstate, &line_size);
+
+	pg_atomic_add_fetch_u32(&cstate->pcdata->curr_data_block->unprocessed_line_parts, 1);
+
+	if (line_size > 0)
+	{
+		int line_pos = UpdateBlockInLineInfo(cstate,
+											start_block_pos,
+											start_offset,
+											line_size,
+											LINE_LEADER_POPULATED);
+
+		pcshared_info->populated++;
+		elog(DEBUG1, "LEADER - adding - block:%u, offset:%u, line size:%u line position:%d",
+				start_block_pos, start_offset, line_size, line_pos);
+	}
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryFindTupleSize - leader identifies boundaries/
+ * offsets for each attribute/column and finally results in the
+ * tuple/row size. It moves on to next data block if the attribute/
+ * column is spread across data blocks.
+ */
+static void
+CopyReadBinaryFindTupleSize(CopyState cstate, uint32 *line_size)
+{
+	int32		fld_size;
+	ListCell   *cur;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			att_num = lfirst_int(cur);
+		Form_pg_attribute att = TupleDescAttr(tup_desc, (att_num - 1));
+		cstate->cur_attname = NameStr(att->attname);
+		fld_size = 0;
+
+		if ((cstate->raw_buf_index + sizeof(fld_size)) >= DATA_BLOCK_SIZE)
+			CopyReadBinaryGetDataBlock(cstate, FIELD_SIZE);
+
+		memcpy(&fld_size, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_size));
+		cstate->raw_buf_index += sizeof(fld_size);
+		*line_size += sizeof(fld_size);
+		fld_size = (int32) pg_ntoh32(fld_size);
+
+		CHECK_FIELD_SIZE(fld_size);
+
+		*line_size += fld_size;
+
+		if ((DATA_BLOCK_SIZE - cstate->raw_buf_index) >= fld_size)
+		{
+			cstate->raw_buf_index += fld_size;
+			elog(DEBUG1, "LEADER - tuple lies in he same data block");
+		}
+		else
+		{
+			int32 required_blks = 0;
+			int32 curr_blk_bytes = (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+			int i = 0;
+
+			GET_REQUIRED_BLOCKS(required_blks, fld_size, curr_blk_bytes);
+
+			i = required_blks;
+
+			while(i > 0)
+			{
+				CopyReadBinaryGetDataBlock(cstate, FIELD_DATA);
+				i--;
+			}
+
+			GET_RAW_BUF_INDEX(cstate->raw_buf_index, fld_size, required_blks, curr_blk_bytes);
+
+			/*
+			 * raw_buf_index should never cross data block size,
+			 * as the required number of data blocks would have
+			 * been obtained in the above while loop.
+			 */
+			Assert(cstate->raw_buf_index <= DATA_BLOCK_SIZE);
+		}
+		cstate->cur_attname = NULL;
+	}
+}
+
+/*
+ * CopyReadBinaryTupleWorker - each worker reads data from data blocks after
+ * getting leader-identified tuple offsets from ring data structure.
+ */
+static bool
+CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls)
+{
+	uint32 		line_pos;
+	ParallelCopyLineBoundary *line_info;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	int16		fld_count;
+	ListCell   *cur;
+	FmgrInfo   *in_functions = cstate->in_functions;
+	Oid		   *typioparams = cstate->typioparams;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	line_pos = GetLinePosition(cstate);
+
+	if (line_pos == -1)
+		return true;
+
+	line_info = &pcshared_info->line_boundaries.ring[line_pos];
+	cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[line_info->first_block];
+	cstate->raw_buf_index = line_info->start_offset;
+
+#if 0
+	if (cstate->raw_buf_index + sizeof(fld_count) >= DATA_BLOCK_SIZE)
+	{
+		/*
+		 * The case where field count spread across datablocks should never occur,
+		 * as the leader would have moved it to next block. enable this if block
+		 * for debugging purposes only.
+		 */
+		elog(DEBUG1, "WORKER - field count spread across datablocks should never occur");
+	}
+#endif
+
+	memcpy(&fld_count, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_count));
+	fld_count = (int16) pg_ntoh16(fld_count);
+
+	CHECK_FIELD_COUNT;
+
+	cstate->raw_buf_index += sizeof(fld_count);
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			att_num = lfirst_int(cur);
+		int			m = att_num - 1;
+		Form_pg_attribute att = TupleDescAttr(tup_desc, m);
+		cstate->cur_attname = NameStr(att->attname);
+
+		values[m] = CopyReadBinaryAttributeWorker(cstate,
+											&in_functions[m],
+											typioparams[m],
+											att->atttypmod,
+											&nulls[m]);
+		cstate->cur_attname = NULL;
+	}
+
+	pg_atomic_sub_fetch_u32(&cstate->pcdata->curr_data_block->unprocessed_line_parts, 1);
+	line_info->start_offset = -1;
+	pg_atomic_write_u32(&line_info->line_state, LINE_WORKER_PROCESSED);
+	pg_atomic_write_u32(&line_info->line_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryAttributeWorker - leader identifies boundaries/offsets
+ * for each attribute/column, it moves on to next data block if the
+ * attribute/column is spread across data blocks.
+ */
+static Datum
+CopyReadBinaryAttributeWorker(CopyState cstate, FmgrInfo *flinfo,
+		Oid typioparam, int32 typmod, bool *isnull)
+{
+	int32		fld_size;
+	Datum		result;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+	if ((cstate->raw_buf_index + sizeof(fld_size)) >= DATA_BLOCK_SIZE)
+	{
+		ParallelCopyDataBlock *prev_data_block = cstate->pcdata->curr_data_block;
+		elog(DEBUG1, "WORKER - field size is spread across data blocks");
+		cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[prev_data_block->following_block];
+		pg_atomic_sub_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+		cstate->raw_buf_index = 0;
+	}
+
+	memcpy(&fld_size, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_size));
+	fld_size = (int32) pg_ntoh32(fld_size);
+
+	CHECK_FIELD_SIZE(fld_size);
+
+	cstate->raw_buf_index += sizeof(fld_size);
+
+	/* reset attribute_buf to empty, and load raw data in it */
+	resetStringInfo(&cstate->attribute_buf);
+
+	enlargeStringInfo(&cstate->attribute_buf, fld_size);
+
+	if ((DATA_BLOCK_SIZE - cstate->raw_buf_index) >= fld_size)
+	{
+		elog(DEBUG1, "WORKER - tuple lies in single data block");
+		memcpy(&cstate->attribute_buf.data[0],&cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], fld_size);
+		cstate->raw_buf_index += fld_size;
+	}
+	else
+	{
+		uint32 att_buf_idx = 0;
+		uint32 copy_bytes = 0;
+		int32 required_blks = 0;
+		int32 curr_blk_bytes = (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+		ParallelCopyDataBlock *prev_data_block = NULL;
+		int i = 0;
+
+		GET_REQUIRED_BLOCKS(required_blks, fld_size, curr_blk_bytes);
+
+		i = required_blks;
+		prev_data_block = cstate->pcdata->curr_data_block;
+		elog(DEBUG1, "WORKER - tuple is spread across data blocks");
+		memcpy(&cstate->attribute_buf.data[0], &prev_data_block->data[cstate->raw_buf_index],
+				curr_blk_bytes);
+		copy_bytes = curr_blk_bytes;
+		att_buf_idx = curr_blk_bytes;
+
+		while (i>0)
+		{
+			cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[prev_data_block->following_block];
+			pg_atomic_sub_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+			cstate->raw_buf_index = 0;
+			copy_bytes = fld_size - att_buf_idx;
+
+			/*
+			 * the bytes that are yet to be taken into att buff are more than
+			 * the entire data block size, but only take the data block size
+			 * elements.
+			 */
+			if (copy_bytes >= DATA_BLOCK_SIZE)
+				copy_bytes = DATA_BLOCK_SIZE;
+
+			memcpy(&cstate->attribute_buf.data[att_buf_idx],
+				&cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], copy_bytes);
+			att_buf_idx += copy_bytes;
+			i--;
+		}
+		GET_RAW_BUF_INDEX(cstate->raw_buf_index, fld_size, required_blks, curr_blk_bytes);
+	}
+
+	cstate->attribute_buf.len = fld_size;
+	cstate->attribute_buf.data[fld_size] = '\0';
+
+	/* Call the column type's binary input converter */
+	result = ReceiveFunctionCall(flinfo, &cstate->attribute_buf,
+								 typioparam, typmod);
+
+	/* Trouble if it didn't eat the whole buffer */
+	if (cstate->attribute_buf.cursor != cstate->attribute_buf.len)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+				 errmsg("incorrect binary data format")));
+
+	*isnull = false;
+	return result;
+}
+
+/*
+ * GetLinePosition - return the line position that worker should pcdata->process.
  */
 static uint32
 GetLinePosition(CopyState cstate)
@@ -1801,7 +2310,9 @@ GetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
 		{
 			dataBlkPtr->curr_blk_completed = false;
 			dataBlkPtr->skip_bytes = 0;
+			dataBlkPtr->following_block = -1;
 			pcshared_info->cur_block_pos = block_pos;
+			MemSet(&dataBlkPtr->data[0], 0, DATA_BLOCK_SIZE);
 			return block_pos;
 		}
 
@@ -5476,60 +5987,47 @@ NextCopyFrom(CopyState cstate, ExprContext *econtext,
 	else
 	{
 		/* binary */
-		int16		fld_count;
-		ListCell   *cur;
-
-		cstate->cur_lineno++;
-
-		if (!CopyGetInt16(cstate, &fld_count))
+		if (!IsParallelCopy())
 		{
-			/* EOF detected (end of file, or protocol-level EOF) */
-			return false;
-		}
+			int16		fld_count;
+			ListCell   *cur;
 
-		if (fld_count == -1)
-		{
-			/*
-			 * Received EOF marker.  In a V3-protocol copy, wait for the
-			 * protocol-level EOF, and complain if it doesn't come
-			 * immediately.  This ensures that we correctly handle CopyFail,
-			 * if client chooses to send that now.
-			 *
-			 * Note that we MUST NOT try to read more data in an old-protocol
-			 * copy, since there is no protocol-level EOF marker then.  We
-			 * could go either way for copy from file, but choose to throw
-			 * error if there's data after the EOF marker, for consistency
-			 * with the new-protocol case.
-			 */
-			char		dummy;
+			cstate->cur_lineno++;
+			cstate->max_fields = list_length(cstate->attnumlist);
 
-			if (cstate->copy_dest != COPY_OLD_FE &&
-				CopyGetData(cstate, &dummy, 1, 1) > 0)
-				ereport(ERROR,
-						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-						 errmsg("received copy data after EOF marker")));
-			return false;
-		}
+			if (!CopyGetInt16(cstate, &fld_count))
+			{
+				/* EOF detected (end of file, or protocol-level EOF) */
+				return false;
+			}
 
-		if (fld_count != attr_count)
-			ereport(ERROR,
-					(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-					 errmsg("row field count is %d, expected %d",
-							(int) fld_count, attr_count)));
+			CHECK_FIELD_COUNT;
 
-		foreach(cur, cstate->attnumlist)
+			foreach(cur, cstate->attnumlist)
+			{
+				int			attnum = lfirst_int(cur);
+				int			m = attnum - 1;
+				Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+
+				cstate->cur_attname = NameStr(att->attname);
+				values[m] = CopyReadBinaryAttribute(cstate,
+													&in_functions[m],
+													typioparams[m],
+													att->atttypmod,
+													&nulls[m]);
+				cstate->cur_attname = NULL;
+			}
+		}
+		else
 		{
-			int			attnum = lfirst_int(cur);
-			int			m = attnum - 1;
-			Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+			bool eof = false;
+			cstate->cur_lineno++;
+			cstate->max_fields = list_length(cstate->attnumlist);
 
-			cstate->cur_attname = NameStr(att->attname);
-			values[m] = CopyReadBinaryAttribute(cstate,
-												&in_functions[m],
-												typioparams[m],
-												att->atttypmod,
-												&nulls[m]);
-			cstate->cur_attname = NULL;
+			eof = CopyReadBinaryTupleWorker(cstate, values, nulls);
+
+			if (eof)
+				return false;
 		}
 	}
 
@@ -6465,18 +6963,15 @@ CopyReadBinaryAttribute(CopyState cstate, FmgrInfo *flinfo,
 	Datum		result;
 
 	if (!CopyGetInt32(cstate, &fld_size))
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("unexpected EOF in COPY data")));
+		EOF_ERROR;
+
 	if (fld_size == -1)
 	{
 		*isnull = true;
 		return ReceiveFunctionCall(flinfo, NULL, typioparam, typmod);
 	}
-	if (fld_size < 0)
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("invalid field size")));
+
+	CHECK_FIELD_SIZE(fld_size);
 
 	/* reset attribute_buf to empty, and load raw data in it */
 	resetStringInfo(&cstate->attribute_buf);
@@ -6484,9 +6979,7 @@ CopyReadBinaryAttribute(CopyState cstate, FmgrInfo *flinfo,
 	enlargeStringInfo(&cstate->attribute_buf, fld_size);
 	if (CopyGetData(cstate, cstate->attribute_buf.data,
 					fld_size, fld_size) != fld_size)
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("unexpected EOF in COPY data")));
+		EOF_ERROR;
 
 	cstate->attribute_buf.len = fld_size;
 	cstate->attribute_buf.data[fld_size] = '\0';
-- 
2.25.1

#110Rafia Sabih
rafia.pghackers@gmail.com
In reply to: Bharath Rupireddy (#109)
Re: Parallel copy

On Sat, 11 Jul 2020 at 08:55, Bharath Rupireddy
<bharath.rupireddyforpostgres@gmail.com> wrote:

Thanks Vignesh for the review. Addressed the comments in 0006 patch.

we can create a local variable and use in place of
cstate->pcdata->curr_data_block.

Done.

+       if (cstate->raw_buf_index + sizeof(fld_count) >= (DATA_BLOCK_SIZE - 1))
+               AdjustFieldInfo(cstate, 1);
+
+       memcpy(&fld_count,
&cstate->pcdata->curr_data_block->data[cstate->raw_buf_index],
sizeof(fld_count));
Should this be like below, as the remaining size can fit in current block:
if (cstate->raw_buf_index + sizeof(fld_count) >= DATA_BLOCK_SIZE)
+       if ((cstate->raw_buf_index + sizeof(fld_size)) >= (DATA_BLOCK_SIZE - 1))
+       {
+               AdjustFieldInfo(cstate, 2);
+               *new_block_pos = pcshared_info->cur_block_pos;
+       }
Same like above.

Yes you are right. Changed.

+       movebytes = DATA_BLOCK_SIZE - cstate->raw_buf_index;
+
+       cstate->pcdata->curr_data_block->skip_bytes = movebytes;
+
+       data_block = &pcshared_info->data_blocks[block_pos];
+
+       if (movebytes > 0)
Instead of the above check, we can have an assert check for movebytes.

No, we can't use assert here. For the edge case where the current data
block is full to the size DATA_BLOCK_SIZE, then movebytes will be 0,
but we need to get a new data block. We avoid memmove by having
movebytes>0 check.

+       if (mode == 1)
+       {
+               cstate->pcdata->curr_data_block = data_block;
+               cstate->raw_buf_index = 0;
+       }
+       else if(mode == 2)
+       {
+               ParallelCopyDataBlock *prev_data_block = NULL;
+               prev_data_block = cstate->pcdata->curr_data_block;
+               prev_data_block->following_block = block_pos;
+               cstate->pcdata->curr_data_block = data_block;
+
+               if (prev_data_block->curr_blk_completed  == false)
+                       prev_data_block->curr_blk_completed = true;
+
+               cstate->raw_buf_index = 0;
+       }

This code is common for both, keep in common flow and remove if (mode == 1)
cstate->pcdata->curr_data_block = data_block;
cstate->raw_buf_index = 0;

Done.

+#define CHECK_FIELD_COUNT \
+{\
+       if (fld_count == -1) \
+       { \
+               if (IsParallelCopy() && \
+                       !IsLeader()) \
+                       return true; \
+               else if (IsParallelCopy() && \
+                       IsLeader()) \
+               { \
+                       if
(cstate->pcdata->curr_data_block->data[cstate->raw_buf_index +
sizeof(fld_count)] != 0) \
+                               ereport(ERROR, \
+
(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+                                               errmsg("received copy
data after EOF marker"))); \
+                       return true; \
+               } \
We only copy sizeof(fld_count), Shouldn't we check fld_count !=
cstate->max_fields? Am I missing something here?

fld_count != cstate->max_fields check is done after the above checks.

+       if ((DATA_BLOCK_SIZE - cstate->raw_buf_index) >= fld_size)
+       {
+               cstate->raw_buf_index = cstate->raw_buf_index + fld_size;
+       }
We can keep the check like cstate->raw_buf_index + fld_size < ..., for
better readability and consistency.

I think this is okay. It gives a good meaning that available bytes in
the current data block is greater or equal to fld_size then, the tuple
lies in the current data block.

+static pg_attribute_always_inline void
+CopyReadBinaryAttributeLeader(CopyState cstate, FmgrInfo *flinfo,
+       Oid typioparam, int32 typmod, uint32 *new_block_pos,
+       int m, ParallelCopyTupleInfo *tuple_start_info_ptr,
+       ParallelCopyTupleInfo *tuple_end_info_ptr, uint32 *line_size)
flinfo, typioparam & typmod is not used, we can remove the parameter.

Done.

+static pg_attribute_always_inline void
+CopyReadBinaryAttributeLeader(CopyState cstate, FmgrInfo *flinfo,
+       Oid typioparam, int32 typmod, uint32 *new_block_pos,
+       int m, ParallelCopyTupleInfo *tuple_start_info_ptr,
+       ParallelCopyTupleInfo *tuple_end_info_ptr, uint32 *line_size)
I felt this function need not be an inline function.

Yes. Changed.

+               /* binary format */
+               /* for paralle copy leader, fill in the error
There are some typos, run spell check

Done.

+               /* raw_buf_index should never cross data block size,
+                * as the required number of data blocks would have
+                * been obtained in the above while loop.
+                */
There are few places, commenting style should be changed to postgres style

Changed.

+       if (cstate->pcdata->curr_data_block == NULL)
+       {
+               block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+               cstate->pcdata->curr_data_block =
&pcshared_info->data_blocks[block_pos];
+
+               cstate->raw_buf_index = 0;
+
+               readbytes = CopyGetData(cstate,
&cstate->pcdata->curr_data_block->data, 1, DATA_BLOCK_SIZE);
+
+               elog(DEBUG1, "LEADER - bytes read from file %d", readbytes);
+
+               if (cstate->reached_eof)
+                       return true;
+       }
There are many empty lines, these are not required.

Removed.

+
+       fld_count = (int16) pg_ntoh16(fld_count);
+
+       CHECK_FIELD_COUNT;
+
+       cstate->raw_buf_index = cstate->raw_buf_index + sizeof(fld_count);
+       new_block_pos = pcshared_info->cur_block_pos;
You can run pg_indent once for the changes.

I ran pg_indent and observed that there are many places getting
modified by pg_indent. If we need to run pg_indet on copy.c for
parallel copy alone, then first, we need to run on plane copy.c and
take those changes and then run for all parallel copy files. I think
we better run pg_indent, for all the parallel copy patches once and
for all, maybe just before we kind of finish up all the code reviews.

+       if (mode == 1)
+       {
+               cstate->pcdata->curr_data_block = data_block;
+               cstate->raw_buf_index = 0;
+       }
+       else if(mode == 2)
+       {
Could use macros for 1 & 2 for better readability.

Done.

+
+                               if (following_block_id == -1)
+                                       break;
+                       }
+
+                       if (following_block_id != -1)
+
pg_atomic_add_fetch_u32(&pcshared_info->data_blocks[following_block_id].unprocessed_line_parts,
1);
+
+                       *line_size = *line_size +
tuple_end_info_ptr->offset + 1;
+               }
We could calculate the size as we parse and identify one record, if we
do that way this can be removed.

Done.

Hi Bharath,

I was looking forward to review this patch-set but unfortunately it is
showing a reject in copy.c, and might need a rebase.
I was applying on master over the commit-
cd22d3cdb9bd9963c694c01a8c0232bbae3ddcfb.

--
Regards,
Rafia Sabih

#111Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Rafia Sabih (#110)
6 attachment(s)
Re: Parallel copy

Hi Bharath,

I was looking forward to review this patch-set but unfortunately it is
showing a reject in copy.c, and might need a rebase.
I was applying on master over the commit-
cd22d3cdb9bd9963c694c01a8c0232bbae3ddcfb.

Thanks for showing interest. Please find the patch set rebased to
latest commit b1e48bbe64a411666bb1928b9741e112e267836d.

With Regards,
Bharath Rupireddy.
EnterpriseDB: http://www.enterprisedb.com

Attachments:

0002-Framework-for-leader-worker-in-parallel-copy.patchapplication/octet-stream; name=0002-Framework-for-leader-worker-in-parallel-copy.patchDownload
From f852a2d53aa2107b90899df9b8c07824b131e498 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>, Bharath <bharath.rupireddyforpostgres@gmail.com>
Date: Wed, 24 Jun 2020 13:51:56 +0530
Subject: [PATCH 2/6] Framework for leader/worker in parallel copy

This patch has the framework for data structures in parallel copy, leader
initialization, worker initialization, shared memory updation, starting workers,
wait for workers and workers exiting.
---
 src/backend/access/transam/parallel.c       |   4 +
 src/backend/commands/copy.c                 | 865 +++++++++++++++++++++++++++-
 src/backend/replication/logical/tablesync.c |   2 +-
 src/include/commands/copy.h                 |   4 +
 src/tools/pgindent/typedefs.list            |   8 +
 5 files changed, 878 insertions(+), 5 deletions(-)

diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index 14a8690..09e7a19 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -25,6 +25,7 @@
 #include "catalog/pg_enum.h"
 #include "catalog/storage.h"
 #include "commands/async.h"
+#include "commands/copy.h"
 #include "executor/execParallel.h"
 #include "libpq/libpq.h"
 #include "libpq/pqformat.h"
@@ -145,6 +146,9 @@ static const struct
 	},
 	{
 		"parallel_vacuum_main", parallel_vacuum_main
+	},
+	{
+		"ParallelCopyMain", ParallelCopyMain
 	}
 };
 
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 33ee891..0a4d997 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -96,9 +96,138 @@ typedef enum CopyInsertMethod
 } CopyInsertMethod;
 
 #define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+
+#define DATA_BLOCK_SIZE RAW_BUF_SIZE
+#define RINGSIZE (10 * 1000)
+#define MAX_BLOCKS_COUNT 1000
+#define WORKER_CHUNK_COUNT 50	/* should be mod of RINGSIZE */
+
+#define	IsParallelCopy()		(cstate->is_parallel)
+#define IsLeader()				(cstate->pcdata->is_leader)
 #define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
 
 /*
+ * Copy data block information.
+ */
+typedef struct ParallelCopyDataBlock
+{
+	/* The number of unprocessed lines in the current block. */
+	pg_atomic_uint32 unprocessed_line_parts;
+
+	/*
+	 * If the current line data is continued into another block, following_block
+	 * will have the position where the remaining data need to be read.
+	 */
+	uint32	following_block;
+
+	/*
+	 * This flag will be set, when the leader finds out this block can be read
+	 * safely by the worker. This helps the worker to start processing the line
+	 * early where the line will be spread across many blocks and the worker
+	 * need not wait for the complete line to be processed.
+	 */
+	bool   curr_blk_completed;
+	char   data[DATA_BLOCK_SIZE]; /* data read from file */
+	uint8  skip_bytes;
+}ParallelCopyDataBlock;
+
+/*
+ * Individual line information.
+ * ParallelCopyLineBoundary is common data structure between leader & worker,
+ * this is protected by the following sequence in the leader & worker.
+ * Leader should operate in the following order:
+ * 1) update first_block, start_offset & cur_lineno in any order.
+ * 2) update line_size.
+ * 3) update line_state.
+ * Worker should operate in the following order:
+ * 1) read line_size.
+ * 2) only one worker should choose one line for processing, this is handled by
+ *    using pg_atomic_compare_exchange_u32, worker will change the sate to
+ *    LINE_WORKER_PROCESSING only if line_state is LINE_LEADER_POPULATED.
+ * 3) read first_block, start_offset & cur_lineno in any order.
+ */
+typedef struct ParallelCopyLineBoundary
+{
+	/* Position of the first block in data_blocks array. */
+	uint32				first_block;
+	uint32				start_offset;   /* start offset of the line */
+
+	/*
+	 * Size of the current line -1 means line is yet to be filled completely,
+	 * 0 means empty line, >0 means line filled with line size data.
+	 */
+	pg_atomic_uint32	line_size;
+	pg_atomic_uint32	line_state;		/* line state */
+	uint64				cur_lineno;		/* line number for error messages */
+}ParallelCopyLineBoundary;
+
+/*
+ * Circular queue used to store the line information.
+ */
+typedef struct ParallelCopyLineBoundaries
+{
+	/* Position for the leader to populate a line. */
+	uint32			leader_pos;
+
+	/* Data read from the file/stdin by the leader process. */
+	ParallelCopyLineBoundary	ring[RINGSIZE];
+}ParallelCopyLineBoundaries;
+
+/*
+ * Shared information among parallel copy workers. This will be allocated in the
+ * DSM segment.
+ */
+typedef struct ParallelCopyShmInfo
+{
+	bool					is_read_in_progress; /* file read status */
+
+	/*
+	 * Actual lines inserted by worker (some records will be filtered based on
+	 * where condition).
+	 */
+	pg_atomic_uint64			processed;
+	pg_atomic_uint64			total_worker_processed; /* total processed records by the workers */
+	uint64						populated; /* lines populated by leader */
+	uint32						cur_block_pos; /* current data block */
+	ParallelCopyDataBlock		data_blocks[MAX_BLOCKS_COUNT]; /* data block array */
+	FullTransactionId			full_transaction_id; /* xid for copy from statement */
+	CommandId					mycid;	/* command id */
+	ParallelCopyLineBoundaries	line_boundaries; /* line array */
+} ParallelCopyShmInfo;
+
+/*
+ * Parallel copy line buffer information.
+ */
+typedef struct ParallelCopyLineBuf
+{
+	StringInfoData		line_buf;
+	uint64				cur_lineno;	/* line number for error messages */
+}ParallelCopyLineBuf;
+
+/*
+ * Parallel copy data information.
+ */
+typedef struct ParallelCopyData
+{
+	Oid					relid;				/* relation id of the table */
+	ParallelCopyShmInfo	*pcshared_info;		/* common info in shared memory */
+	bool				is_leader;
+
+	/* line position which worker is processing */
+	uint32				worker_processed_pos;
+
+	/*
+	 * Local line_buf array, workers will copy it here and release the lines
+	 * for the leader to continue.
+	 */
+	ParallelCopyLineBuf	worker_line_buf[WORKER_CHUNK_COUNT];
+	uint32				worker_line_buf_count; /* Number of lines */
+
+	/* Current position in worker_line_buf */
+	uint32				worker_line_buf_pos;
+}ParallelCopyData;
+
+/*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
  * even though some fields are used in only some cases.
@@ -225,8 +354,66 @@ typedef struct CopyStateData
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
+	int			nworkers;
+	bool		is_parallel;
+	ParallelCopyData *pcdata;
 } CopyStateData;
 
+/*
+ * This structure helps in storing the common data from CopyStateData that are
+ * required by the workers. This information will then be allocated and stored
+ * into the DSM for the worker to retrieve and copy it to CopyStateData.
+ */
+typedef struct ParallelCopyCommonKeyData
+{
+	/* low-level state data */
+	CopyDest            copy_dest;		/* type of copy source/destination */
+	int                 file_encoding;	/* file or remote side's character encoding */
+	bool                need_transcoding;	/* file encoding diff from server? */
+	bool                encoding_embeds_ascii;	/* ASCII can be non-first byte? */
+
+	/* parameters from the COPY command */
+	bool                csv_mode;		/* Comma Separated Value format? */
+	bool                header_line;	/* CSV header line? */
+	int                 null_print_len; /* length of same */
+	bool                force_quote_all;	/* FORCE_QUOTE *? */
+	bool                convert_selectively;	/* do selective binary conversion? */
+
+	/* Working state for COPY FROM */
+	AttrNumber          num_defaults;
+	Oid                 relid;
+}ParallelCopyCommonKeyData;
+
+/*
+ * This structure will help in converting a List data type into the below
+ * structure format with the count having the number of elements in the list and
+ * the info having the List elements appended contigously. This converted
+ * structure will be allocated in shared memory and stored in DSM for the worker
+ * to retrieve and later convert it back to List data type.
+ */
+typedef struct ParallelCopyKeyListInfo
+{
+	int	count;		/* count of attributes */
+
+	/* string info in the form info followed by info1, info2... infon  */
+	char    info[1];
+} ParallelCopyKeyListInfo;
+
+/*
+ * List of internal parallel copy function pointers.
+ */
+static const struct
+{
+	char *fn_name;
+	copy_data_source_cb fn_addr;
+}			InternalParallelCopyFuncPtrs[] =
+
+{
+	{
+		"copy_read_data", copy_read_data
+	},
+};
+
 /* DestReceiver for COPY (query) TO */
 typedef struct
 {
@@ -256,6 +443,23 @@ typedef struct
 /* Trim the list of buffers back down to this number after flushing */
 #define MAX_PARTITION_BUFFERS	32
 
+/* DSM keys for parallel copy.  */
+#define PARALLEL_COPY_KEY_SHARED_INFO		    1
+#define PARALLEL_COPY_KEY_CSTATE				2
+#define PARALLEL_COPY_KEY_NULL_PRINT			3
+#define PARALLEL_COPY_KEY_NULL_PRINT_CLIENT		4
+#define PARALLEL_COPY_KEY_DELIM					5
+#define PARALLEL_COPY_KEY_QUOTE					6
+#define PARALLEL_COPY_KEY_ESCAPE				7
+#define PARALLEL_COPY_KEY_ATTNAME_LIST			8
+#define PARALLEL_COPY_KEY_FORCE_QUOTE_LIST  	9
+#define PARALLEL_COPY_KEY_NOT_NULL_LIST		   10
+#define PARALLEL_COPY_KEY_NULL_LIST			   11
+#define PARALLEL_COPY_KEY_CONVERT_LIST		   12
+#define PARALLEL_COPY_KEY_DATASOURCE_CB		   13
+#define PARALLEL_COPY_KEY_WHERE_CLAUSE_STR     14
+#define PARALLEL_COPY_KEY_RANGE_TABLE		   15
+
 /* Stores multi-insert data related to a single relation in CopyFrom. */
 typedef struct CopyMultiInsertBuffer
 {
@@ -476,10 +680,596 @@ static bool CopyGetInt32(CopyState cstate, int32 *val);
 static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 
+static pg_attribute_always_inline void EndParallelCopy(ParallelContext *pcxt);
 static void PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tup_desc,
 							   List *attnamelist);
+static pg_attribute_always_inline copy_data_source_cb LookupParallelCopyFnPtr(const char *funcname);
+static pg_attribute_always_inline char* LookupParallelCopyFnStr(copy_data_source_cb fn_addr);
+
+/*
+ * CopyCommonInfoForWorker - Copy shared_cstate using cstate information.
+ */
+static pg_attribute_always_inline void
+CopyCommonInfoForWorker(CopyState cstate, ParallelCopyCommonKeyData *shared_cstate)
+{
+	shared_cstate->copy_dest = cstate->copy_dest;
+	shared_cstate->file_encoding = cstate->file_encoding;
+	shared_cstate->need_transcoding = cstate->need_transcoding;
+	shared_cstate->encoding_embeds_ascii = cstate->encoding_embeds_ascii;
+	shared_cstate->csv_mode = cstate->csv_mode;
+	shared_cstate->header_line = cstate->header_line;
+	shared_cstate->null_print_len = cstate->null_print_len;
+	shared_cstate->force_quote_all = cstate->force_quote_all;
+	shared_cstate->convert_selectively = cstate->convert_selectively;
+	shared_cstate->num_defaults = cstate->num_defaults;
+	shared_cstate->relid = cstate->pcdata->relid;
+}
+
+/*
+ * RetrieveSharedString - Retrieve the string from shared memory.
+ */
+static void
+RetrieveSharedString(shm_toc *toc, int sharedkey, char **copystr)
+{
+	char *shared_str_val = (char *)shm_toc_lookup(toc, sharedkey, true);
+	if (shared_str_val)
+		*copystr = pstrdup(shared_str_val);
+}
+
+/*
+ * RetrieveSharedList - Retrieve the list from shared memory.
+ */
+static void
+RetrieveSharedList(shm_toc *toc, int sharedkey, List **copylist)
+{
+	ParallelCopyKeyListInfo *listinformation = (ParallelCopyKeyListInfo *)shm_toc_lookup(toc, sharedkey,
+														   true);
+	if (listinformation)
+	{
+		int	length  = 0;
+		int count;
+
+		for (count = 0; count < listinformation->count; count++)
+		{
+			char *attname = (char *)(listinformation->info + length);
+			length += strlen(attname) + 1;
+			*copylist = lappend(*copylist, makeString(attname));
+		}
+	}
+}
+
+/*
+ * CopyListSharedMemory - Copy the list into shared memory.
+ */
+static void
+CopyListSharedMemory(List *inputlist, Size memsize, ParallelCopyKeyListInfo *sharedlistinfo)
+{
+	ListCell   *l;
+	int			length  = 0;
+
+	MemSet(sharedlistinfo, 0, memsize);
+	foreach(l, inputlist)
+	{
+		char	   *name = strVal(lfirst(l));
+		memcpy((char *)(sharedlistinfo->info + length), name, strlen(name));
+		sharedlistinfo->count++;
+		length += strlen(name) + 1;
+	}
+}
+
+/*
+ * ComputeListSize - compute the list size.
+ */
+static int
+ComputeListSize(List *inputlist)
+{
+	int est_size = sizeof(int);
+	if (inputlist != NIL)
+	{
+		ListCell   *l;
+		foreach(l, inputlist)
+			est_size += strlen(strVal(lfirst(l))) + 1;
+	}
+
+	return est_size;
+}
+
+/*
+ * EstimateLineKeysStr - Estimate the size required in shared memory for the
+ * input string.
+ */
+static void
+EstimateLineKeysStr(ParallelContext *pcxt, char *inputstr)
+{
+	if (inputstr)
+	{
+		shm_toc_estimate_chunk(&pcxt->estimator, strlen(inputstr) + 1);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+}
+
+/*
+ * EstimateLineKeysList - Estimate the size required in shared memory for the
+ * input list.
+ */
+static void
+EstimateLineKeysList(ParallelContext *pcxt, List *inputlist,
+		Size *est_list_size)
+{
+	if (inputlist != NIL)
+	{
+		*est_list_size = ComputeListSize(inputlist);
+		shm_toc_estimate_chunk(&pcxt->estimator, *est_list_size);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+}
 
 /*
+ * InsertStringShm - Insert a string into shared memory.
+ */
+static void
+InsertStringShm(ParallelContext *pcxt, int key, char *inputstr)
+{
+	if (inputstr)
+	{
+		char *shmptr = (char *)shm_toc_allocate(pcxt->toc,
+												strlen(inputstr) + 1);
+		strcpy(shmptr, inputstr);
+		shm_toc_insert(pcxt->toc, key, shmptr);
+	}
+}
+
+/*
+ * InsertListShm - Insert a list into shared memory.
+ */
+static void
+InsertListShm(ParallelContext *pcxt, int key, List *inputlist,
+			  Size est_list_size)
+{
+	if (inputlist != NIL)
+	{
+		ParallelCopyKeyListInfo *sharedlistinfo = (ParallelCopyKeyListInfo *)shm_toc_allocate(pcxt->toc,
+																est_list_size);
+		CopyListSharedMemory(inputlist, est_list_size, sharedlistinfo);
+		shm_toc_insert(pcxt->toc, key, sharedlistinfo);
+	}
+}
+
+/*
+ * BeginParallelCopy - start parallel copy tasks.
+ *
+ * Get the number of workers required to perform the parallel copy. The data
+ * structures that are required by the parallel workers will be initialized, the
+ * size required in DSM will be calculated and the necessary keys will be loaded
+ * in the DSM. The specified number of workers will then be launched.
+ *
+ */
+static ParallelContext*
+BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
+{
+	ParallelContext *pcxt;
+	ParallelCopyShmInfo *shared_info_ptr;
+	ParallelCopyCommonKeyData *shared_cstate;
+	FullTransactionId full_transaction_id;
+	Size est_shared_info;
+	Size est_cstateshared;
+	Size est_att_list_size;
+	Size est_quote_list_size;
+	Size est_notnull_list_size;
+	Size est_null_list_size;
+	Size est_convert_list_size;
+	Size est_datasource_cb_size;
+	int  count = 0;
+	char *whereClauseStr = NULL;
+	char *rangeTableStr = NULL;
+	int  parallel_workers = 0;
+	ParallelCopyData *pcdata;
+
+	parallel_workers = Min(nworkers, max_worker_processes);
+
+	/* Can't perform copy in parallel */
+	if (parallel_workers <= 0)
+	{
+		elog(WARNING,
+			 "No workers available, copy will be run in non-parallel mode");
+		return NULL;
+	}
+
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	cstate->pcdata = pcdata;
+
+	EnterParallelMode();
+	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
+								 parallel_workers);
+	Assert(pcxt->nworkers > 0);
+
+	/*
+	 * Estimate size for shared information for PARALLEL_COPY_KEY_SHARED_INFO
+	 */
+	est_shared_info = sizeof(ParallelCopyShmInfo);
+	shm_toc_estimate_chunk(&pcxt->estimator, est_shared_info);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_CSTATE */
+	est_cstateshared = 	MAXALIGN(sizeof(ParallelCopyCommonKeyData));
+	shm_toc_estimate_chunk(&pcxt->estimator, est_cstateshared);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	EstimateLineKeysStr(pcxt, cstate->null_print);
+	EstimateLineKeysStr(pcxt, cstate->null_print_client);
+	EstimateLineKeysStr(pcxt, cstate->delim);
+	EstimateLineKeysStr(pcxt, cstate->quote);
+	EstimateLineKeysStr(pcxt, cstate->escape);
+
+	if (cstate->whereClause != NULL)
+	{
+		whereClauseStr = nodeToString(cstate->whereClause);
+		EstimateLineKeysStr(pcxt, whereClauseStr);
+	}
+
+	if (cstate->range_table != NULL)
+	{
+		rangeTableStr = nodeToString(cstate->range_table);
+		EstimateLineKeysStr(pcxt, rangeTableStr);
+	}
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_XID. */
+	shm_toc_estimate_chunk(&pcxt->estimator, sizeof(FullTransactionId));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_ATTNAME_LIST.
+	 */
+	EstimateLineKeysList(pcxt, attnamelist, &est_att_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_FORCE_QUOTE_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->force_quote, &est_quote_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_NOT_NULL_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->force_notnull,
+							 &est_notnull_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_NULL_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->force_null, &est_null_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_CONVERT_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->convert_select,
+							 &est_convert_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_DATASOURCE_CB.
+	 */
+	if (cstate->data_source_cb)
+	{
+		char *functionname = LookupParallelCopyFnStr(cstate->data_source_cb);
+		est_datasource_cb_size = strlen(functionname) + 1;
+		shm_toc_estimate_chunk(&pcxt->estimator, est_datasource_cb_size);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+
+	InitializeParallelDSM(pcxt);
+
+	/* If no DSM segment was available, back out (do serial copy) */
+	if (pcxt->seg == NULL)
+	{
+		EndParallelCopy(pcxt);
+		elog(WARNING,
+			 "DSM segments not available, copy will be run in non-parallel mode");
+		return NULL;
+	}
+
+	/* Allocate shared memory for PARALLEL_COPY_KEY_SHARED_INFO */
+	shared_info_ptr = (ParallelCopyShmInfo *) shm_toc_allocate(pcxt->toc,
+													   est_shared_info);
+	MemSet(shared_info_ptr, 0, est_shared_info);
+	shared_info_ptr->is_read_in_progress = true;
+	shared_info_ptr->cur_block_pos = -1;
+	shared_info_ptr->full_transaction_id = full_transaction_id;
+	shared_info_ptr->mycid = GetCurrentCommandId(true);
+	for (count = 0; count < RINGSIZE; count++)
+	{
+		ParallelCopyLineBoundary *lineInfo = &shared_info_ptr->line_boundaries.ring[count];
+		pg_atomic_init_u32(&(lineInfo->line_size), -1);
+	}
+
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_SHARED_INFO, shared_info_ptr);
+	pcdata->pcshared_info = shared_info_ptr;
+	pcdata->relid = relid;
+
+	/* Store shared build state, for which we reserved space. */
+	shared_cstate = (ParallelCopyCommonKeyData *)shm_toc_allocate(pcxt->toc,
+															est_cstateshared);
+
+	/* copy cstate variables. */
+	CopyCommonInfoForWorker(cstate, shared_cstate);
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_CSTATE, shared_cstate);
+
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_NULL_PRINT, cstate->null_print);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_NULL_PRINT_CLIENT,
+					  cstate->null_print_client);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_DELIM, cstate->delim);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_QUOTE, cstate->quote);
+	InsertStringShm(pcxt, PARALLEL_COPY_KEY_ESCAPE, cstate->escape);
+
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_ATTNAME_LIST,
+					attnamelist, est_att_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_FORCE_QUOTE_LIST,
+					cstate->force_quote, est_quote_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_NOT_NULL_LIST,
+					cstate->force_notnull, est_notnull_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_NULL_LIST, cstate->force_null,
+					est_null_list_size);
+	InsertListShm(pcxt, PARALLEL_COPY_KEY_CONVERT_LIST,
+					cstate->convert_select, est_convert_list_size);
+
+	if (cstate->data_source_cb)
+	{
+		char *functionname = LookupParallelCopyFnStr(cstate->data_source_cb);
+		char *data_source_cb = (char *) shm_toc_allocate(pcxt->toc,
+														 est_datasource_cb_size);
+		strcpy(data_source_cb, functionname);
+		shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_DATASOURCE_CB,
+					   data_source_cb);
+	}
+
+	if (cstate->whereClause)
+		InsertStringShm(pcxt, PARALLEL_COPY_KEY_WHERE_CLAUSE_STR,
+						whereClauseStr);
+
+	if(cstate->range_table)
+		InsertStringShm(pcxt, PARALLEL_COPY_KEY_RANGE_TABLE, rangeTableStr);
+
+	LaunchParallelWorkers(pcxt);
+	if (pcxt->nworkers_launched == 0)
+	{
+		EndParallelCopy(pcxt);
+		elog(WARNING,
+			 "No workers available, copy will be run in non-parallel mode");
+		return NULL;
+	}
+
+	/*
+	 * Caller needs to wait for all launched workers when we return.  Make sure
+	 * that the failure-to-start case will not hang forever.
+	 */
+	WaitForParallelWorkersToAttach(pcxt);
+
+	pcdata->is_leader = true;
+	cstate->is_parallel = true;
+	return pcxt;
+}
+
+/*
+ * EndParallelCopy - end the parallel copy tasks.
+ */
+static pg_attribute_always_inline void
+EndParallelCopy(ParallelContext *pcxt)
+{
+	Assert(!IsParallelWorker());
+
+	DestroyParallelContext(pcxt);
+	ExitParallelMode();
+}
+
+/*
+ * ParallelWorkerInitialization - Initialize parallel worker.
+ */
+static void
+ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
+		CopyState cstate, List *attnamelist)
+{
+	uint32		count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	cstate->copy_dest = shared_cstate->copy_dest;
+	cstate->file_encoding = shared_cstate->file_encoding;
+	cstate->need_transcoding = shared_cstate->need_transcoding;
+	cstate->encoding_embeds_ascii = shared_cstate->encoding_embeds_ascii;
+	cstate->csv_mode = shared_cstate->csv_mode;
+	cstate->header_line = shared_cstate->header_line;
+	cstate->null_print_len = shared_cstate->null_print_len;
+	cstate->force_quote_all = shared_cstate->force_quote_all;
+	cstate->convert_selectively = shared_cstate->convert_selectively;
+	cstate->num_defaults = shared_cstate->num_defaults;
+	pcdata->relid = shared_cstate->relid;
+
+	PopulateGlobalsForCopyFrom(cstate, tup_desc, attnamelist);
+
+	/* Initialize state variables. */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/* Set up variables to avoid per-attribute overhead. */
+	initStringInfo(&cstate->attribute_buf);
+
+	initStringInfo(&cstate->line_buf);
+	for (count = 0; count < WORKER_CHUNK_COUNT;count++)
+		initStringInfo(&pcdata->worker_line_buf[count].line_buf);
+
+	cstate->line_buf_converted = false;
+	cstate->raw_buf = NULL;
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+}
+/*
+ * ParallelCopyMain - parallel copy worker's code.
+ *
+ * Where clause handling, convert tuple to columns, add default null values for
+ * the missing columns that are not present in that record. Find the partition
+ * if it is partitioned table, invoke before row insert Triggers, handle
+ * constraints and insert the tuples.
+ */
+void
+ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
+{
+	CopyState cstate;
+	ParallelCopyData *pcdata;
+	ParallelCopyShmInfo *pcshared_info;
+	ParallelCopyCommonKeyData *shared_cstate;
+	Relation	rel = NULL;
+	MemoryContext oldcontext;
+	List *attlist = NIL;
+	char *data_source_cb;
+	char *whereClauseStr = NULL;
+	char *rangeTableStr = NULL;
+
+	/* Allocate workspace and zero all fields. */
+	cstate = (CopyStateData *) palloc0(sizeof(CopyStateData));
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	cstate->pcdata = pcdata;
+	pcdata->is_leader = false;
+	pcdata->worker_processed_pos = -1;
+	cstate->is_parallel = true;
+
+	/*
+	 * We allocate everything used by a cstate in a new memory context. This
+	 * avoids memory leaks during repeated use of COPY in a query.
+	 */
+	cstate->copycontext = AllocSetContextCreate(CurrentMemoryContext,
+												"COPY",
+												ALLOCSET_DEFAULT_SIZES);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	pcshared_info = (ParallelCopyShmInfo *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_SHARED_INFO,
+														false);
+
+	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
+
+	pcdata->pcshared_info = pcshared_info;
+
+	shared_cstate = (ParallelCopyCommonKeyData *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE,
+														   false);
+
+	cstate->null_print = (char *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_NULL_PRINT,
+												true);
+	cstate->null_print_client = (char *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_NULL_PRINT_CLIENT,
+													   true);
+
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_DELIM, &cstate->delim);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_QUOTE, &cstate->quote);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_ESCAPE, &cstate->escape);
+
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_ATTNAME_LIST, &attlist);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_FORCE_QUOTE_LIST, &cstate->force_quote);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_NOT_NULL_LIST, &cstate->force_notnull);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_NULL_LIST, &cstate->force_null);
+	RetrieveSharedList(toc, PARALLEL_COPY_KEY_CONVERT_LIST, &cstate->convert_select);
+	data_source_cb = (char *)shm_toc_lookup(toc,
+											PARALLEL_COPY_KEY_DATASOURCE_CB,
+											true);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_WHERE_CLAUSE_STR, &whereClauseStr);
+	RetrieveSharedString(toc, PARALLEL_COPY_KEY_RANGE_TABLE, &rangeTableStr);
+
+	if (data_source_cb)
+		cstate->data_source_cb = LookupParallelCopyFnPtr(data_source_cb);
+
+	if (whereClauseStr)
+	{
+		Node *whereClauseCnvrtdFrmStr = (Node *) stringToNode(whereClauseStr);
+		cstate->whereClause = whereClauseCnvrtdFrmStr;
+	}
+
+	if (rangeTableStr)
+	{
+		List *rangeTableCnvrtdFrmStr = (List *) stringToNode(rangeTableStr);
+		cstate->range_table = rangeTableCnvrtdFrmStr;
+	}
+
+	/* Open and lock the relation, using the appropriate lock type. */
+	rel = table_open(shared_cstate->relid, RowExclusiveLock);
+	cstate->rel = rel;
+	ParallelWorkerInitialization(shared_cstate, cstate, attlist);
+
+	CopyFrom(cstate);
+
+	if (rel != NULL)
+		table_close(rel, RowExclusiveLock);
+
+	MemoryContextSwitchTo(oldcontext);
+	return;
+}
+/*
+ * ParallelCopyLeader - parallel copy leader's functionality.
+ *
+ * Leader will populate the shared memory and share it across the workers.
+ * Leader will read the table data from the file and copy the contents to block.
+ * Leader will then read the input contents and identify the data based on line
+ * beaks. This information is called line. The line will be populate in
+ * ParallelCopyLineBoundary. Workers will then pick up this information and
+ * insert in to table. Leader will do this till it completes processing the
+ * file. Leader executes the before statement if before statement trigger is
+ * present. Leader read the data from input file. Leader then loads data to data
+ * blocks as and when required block by block. Leader traverses through the data
+ * block to identify one line. It gets a free line to copy the information, if
+ * there is no free line it will wait till there is one free line.
+ * Server copies  the identified lines information into lines. This process is
+ * repeated till the complete file is processed.
+ * Leader will wait till all the lines populated are processed by the workers
+ * and exits.
+ */
+static void
+ParallelCopyLeader(CopyState cstate)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
+
+	pcshared_info->is_read_in_progress = false;
+	cstate->cur_lineno = 0;
+}
+/*
+ * LookupParallelCopyFnPtr - Look up parallel copy function pointer.
+ */
+static pg_attribute_always_inline copy_data_source_cb
+LookupParallelCopyFnPtr(const char *funcname)
+{
+	int			i;
+
+	for (i = 0; i < lengthof(InternalParallelCopyFuncPtrs); i++)
+	{
+		if (strcmp(InternalParallelCopyFuncPtrs[i].fn_name, funcname) == 0)
+			return InternalParallelCopyFuncPtrs[i].fn_addr;
+	}
+
+	/* We can only reach this by programming error. */
+	elog(ERROR, "internal function \"%s\" not found", funcname);
+}
+
+/*
+ * LookupParallelCopyFnStr - Lookup function string from a function pointer.
+ */
+static pg_attribute_always_inline char*
+LookupParallelCopyFnStr(copy_data_source_cb fn_addr)
+{
+	int			i;
+
+	for (i = 0; i < lengthof(InternalParallelCopyFuncPtrs); i++)
+	{
+		if (InternalParallelCopyFuncPtrs[i].fn_addr == fn_addr)
+			return InternalParallelCopyFuncPtrs[i].fn_name;
+	}
+
+	/* We can only reach this by programming error. */
+	elog(ERROR, "internal function pointer not found");
+}
+/*
  * Send copy start/stop messages for frontend copies.  These have changed
  * in past protocol redesigns.
  */
@@ -1149,6 +1939,7 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 
 	if (is_from)
 	{
+		ParallelContext *pcxt = NULL;
 		Assert(rel);
 
 		/* check read-only transaction and parallel mode */
@@ -1158,7 +1949,24 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 		cstate = BeginCopyFrom(pstate, rel, stmt->filename, stmt->is_program,
 							   NULL, stmt->attlist, stmt->options);
 		cstate->whereClause = whereClause;
-		*processed = CopyFrom(cstate);	/* copy from file to database */
+		cstate->is_parallel = false;
+
+		if (cstate->nworkers > 0)
+			pcxt = BeginParallelCopy(cstate->nworkers, cstate, stmt->attlist,
+									 relid);
+
+		if (pcxt)
+		{
+			ParallelCopyLeader(cstate);
+
+			/* Wait for all copy workers to finish */
+			WaitForParallelWorkersToFinish(pcxt);
+			*processed = pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
+			EndParallelCopy(pcxt);
+		}
+		else
+			*processed = CopyFrom(cstate); /* copy from file to database */
+
 		EndCopyFrom(cstate);
 	}
 	else
@@ -1207,6 +2015,7 @@ ProcessCopyOptions(ParseState *pstate,
 	cstate->is_copy_from = is_from;
 
 	cstate->file_encoding = -1;
+	cstate->nworkers = -1;
 
 	/* Extract options from the statement node tree */
 	foreach(option, options)
@@ -1375,6 +2184,53 @@ ProcessCopyOptions(ParseState *pstate,
 								defel->defname),
 						 parser_errposition(pstate, defel->location)));
 		}
+		else if (strcmp(defel->defname, "parallel") == 0)
+		{
+			char *endptr, *str;
+			long val;
+
+			if (!cstate->is_copy_from)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("parallel option supported only for copy from"),
+						 parser_errposition(pstate, defel->location)));
+			if (cstate->nworkers >= 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options"),
+						 parser_errposition(pstate, defel->location)));
+
+			str = defGetString(defel);
+
+			errno = 0; /* To distinguish success/failure after call */
+			val = strtol(str, &endptr, 10);
+
+			/* Check for various possible errors */
+			if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
+				|| (errno != 0 && val == 0) ||
+				*endptr)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("improper use of argument to option \"%s\"",
+								defel->defname),
+						 parser_errposition(pstate, defel->location)));
+
+			if (endptr == str)
+			   ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("no digits were found in argument to option \"%s\"",
+								defel->defname),
+						 parser_errposition(pstate, defel->location)));
+
+			cstate->nworkers = (int) val;
+
+			if (cstate->nworkers <= 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("argument to option \"%s\" must be a positive integer greater than zero",
+								defel->defname),
+						 parser_errposition(pstate, defel->location)));
+		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_SYNTAX_ERROR),
@@ -1727,12 +2583,13 @@ BeginCopy(ParseState *pstate,
 }
 
 /*
- * PopulateGlobalsForCopyFrom - Populates the common variables required for copy
- * from operation. This is a helper function for BeginCopy function.
+ * PopulateCatalogInformation - Populates the common variables required for copy
+ * from operation. This is a helper function for BeginCopy &
+ * ParallelWorkerInitialization function.
  */
 static void
 PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tupDesc,
-							List *attnamelist)
+						   List *attnamelist)
 {
 	int			num_phys_attrs;
 
diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c
index c27d970..b3787c1 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -557,7 +557,7 @@ make_copy_attnamelist(LogicalRepRelMapEntry *rel)
  * Data source callback for the COPY FROM, which reads from the remote
  * connection and passes the data back to our local COPY.
  */
-static int
+int
 copy_read_data(void *outbuf, int minread, int maxread)
 {
 	int			bytesread = 0;
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index c639833..5dc95ac 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -14,6 +14,7 @@
 #ifndef COPY_H
 #define COPY_H
 
+#include "access/parallel.h"
 #include "nodes/execnodes.h"
 #include "nodes/parsenodes.h"
 #include "parser/parse_node.h"
@@ -41,4 +42,7 @@ extern uint64 CopyFrom(CopyState cstate);
 
 extern DestReceiver *CreateCopyDestReceiver(void);
 
+extern void ParallelCopyMain(dsm_segment *seg, shm_toc *toc);
+
+extern int copy_read_data(void *outbuf, int minread, int maxread);
 #endif							/* COPY_H */
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 7eaaad1..6a42ac4 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1699,6 +1699,14 @@ ParallelBitmapHeapState
 ParallelBlockTableScanDesc
 ParallelCompletionPtr
 ParallelContext
+ParallelCopyLineBoundaries
+ParallelCopyLineBoundary
+ParallelCopyCommonKeyData
+ParallelCopyData
+ParallelCopyDataBlock
+ParallelCopyKeyListInfo
+ParallelCopyLineBuf
+ParallelCopyShmInfo
 ParallelExecutorInfo
 ParallelHashGrowth
 ParallelHashJoinBatch
-- 
1.8.3.1

0001-Copy-code-readjustment-to-support-parallel-copy.patchapplication/octet-stream; name=0001-Copy-code-readjustment-to-support-parallel-copy.patchDownload
From cb04472cb10fbb8c4da4d3073b29c4dff3c51bce Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddy@enterprisedb.com>
Date: Sun, 12 Jul 2020 17:20:49 +0530
Subject: [PATCH 1/6] Copy code readjustment to support parallel copy.

This patch has the copy code slightly readjusted so that the common code is
separated to functions/macros, these functions/macros will be used by the
workers in the parallel copy code of the upcoming patches. EOL removal is moved
from CopyReadLine to CopyReadLineText, this change was required because in case
of parallel copy the record identification and record updation is done in
CopyReadLineText, before record information is updated in shared memory the new
line characters should be removed.
---
 src/backend/commands/copy.c | 386 +++++++++++++++++++++---------------
 1 file changed, 228 insertions(+), 158 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 99d1457180..17e270c3d1 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -95,6 +95,9 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
+#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+#define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
+
 /*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
@@ -222,7 +225,6 @@ typedef struct CopyStateData
 	 * converts it.  Note: we guarantee that there is a \0 at
 	 * raw_buf[raw_buf_len].
 	 */
-#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
@@ -350,6 +352,88 @@ if (1) \
 	goto not_end_of_copy; \
 } else ((void) 0)
 
+/*
+ * CONVERT_TO_SERVER_ENCODING - convert contents to server encoding.
+ */
+#define CONVERT_TO_SERVER_ENCODING(cstate) \
+{ \
+	/* Done reading the line.  Convert it to server encoding. */ \
+	if (cstate->need_transcoding) \
+	{ \
+		char	   *cvt; \
+		cvt = pg_any_to_server(cstate->line_buf.data, \
+							   cstate->line_buf.len, \
+							   cstate->file_encoding); \
+		if (cvt != cstate->line_buf.data) \
+		{ \
+			/* transfer converted data back to line_buf */ \
+			resetStringInfo(&cstate->line_buf); \
+			appendBinaryStringInfo(&cstate->line_buf, cvt, strlen(cvt)); \
+			pfree(cvt); \
+		} \
+	} \
+	/* Now it's safe to use the buffer in error messages */ \
+	cstate->line_buf_converted = true; \
+}
+
+/*
+ * CLEAR_EOL_FROM_COPIED_DATA - Clear EOL from the copied data.
+ */
+#define CLEAR_EOL_FROM_COPIED_DATA(copy_line_data, copy_line_pos, copy_line_size) \
+{ \
+	/* \
+	 * If we didn't hit EOF, then we must have transferred the EOL marker \
+	 * to line_buf along with the data.  Get rid of it. \
+	 */ \
+   switch (cstate->eol_type) \
+   { \
+	   case EOL_NL: \
+		   Assert(copy_line_size >= 1); \
+		   Assert(copy_line_data[copy_line_pos - 1] == '\n'); \
+		   copy_line_data[copy_line_pos - 1] = '\0'; \
+		   copy_line_size--; \
+		   break; \
+	   case EOL_CR: \
+		   Assert(copy_line_size >= 1); \
+		   Assert(copy_line_data[copy_line_pos - 1] == '\r'); \
+		   copy_line_data[copy_line_pos - 1] = '\0'; \
+		   copy_line_size--; \
+		   break; \
+	   case EOL_CRNL: \
+		   Assert(copy_line_size >= 2); \
+		   Assert(copy_line_data[copy_line_pos - 2] == '\r'); \
+		   Assert(copy_line_data[copy_line_pos - 1] == '\n'); \
+		   copy_line_data[copy_line_pos - 2] = '\0'; \
+		   copy_line_size -= 2; \
+		   break; \
+	   case EOL_UNKNOWN: \
+		   /* shouldn't get here */ \
+		   Assert(false); \
+		   break; \
+   } \
+}
+
+/*
+ * CLEAR_EOL_LINE - Wrapper for clearing EOL.
+ */
+#define CLEAR_EOL_LINE() \
+if (!result && !IsHeaderLine()) \
+	CLEAR_EOL_FROM_COPIED_DATA(cstate->line_buf.data, \
+								cstate->line_buf.len, \
+								cstate->line_buf.len) \
+
+/*
+ * INCREMENTPROCESSED - Increment the lines processed.
+ */
+#define INCREMENTPROCESSED(processed)  \
+processed++;
+
+/*
+ * GETPROCESSED - Get the lines processed.
+ */
+#define GETPROCESSED(processed) \
+return processed;
+
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
 
@@ -395,6 +479,8 @@ static bool CopyGetInt32(CopyState cstate, int32 *val);
 static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 
+static void PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tup_desc,
+							   List *attnamelist);
 
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
@@ -796,6 +882,7 @@ CopyLoadRawBuf(CopyState cstate)
 {
 	int			nbytes;
 	int			inbytes;
+	int         minread = 1;
 
 	if (cstate->raw_buf_index < cstate->raw_buf_len)
 	{
@@ -807,8 +894,11 @@ CopyLoadRawBuf(CopyState cstate)
 	else
 		nbytes = 0;				/* no data need be saved */
 
+	if (cstate->copy_dest == COPY_NEW_FE)
+		minread = RAW_BUF_SIZE - nbytes;
+
 	inbytes = CopyGetData(cstate, cstate->raw_buf + nbytes,
-						  1, RAW_BUF_SIZE - nbytes);
+						  minread, RAW_BUF_SIZE - nbytes);
 	nbytes += inbytes;
 	cstate->raw_buf[nbytes] = '\0';
 	cstate->raw_buf_index = 0;
@@ -1466,7 +1556,6 @@ BeginCopy(ParseState *pstate,
 {
 	CopyState	cstate;
 	TupleDesc	tupDesc;
-	int			num_phys_attrs;
 	MemoryContext oldcontext;
 
 	/* Allocate workspace and zero all fields */
@@ -1632,6 +1721,24 @@ BeginCopy(ParseState *pstate,
 		tupDesc = cstate->queryDesc->tupDesc;
 	}
 
+	PopulateGlobalsForCopyFrom(cstate, tupDesc, attnamelist);
+	cstate->copy_dest = COPY_FILE;	/* default */
+
+	MemoryContextSwitchTo(oldcontext);
+
+	return cstate;
+}
+
+/*
+ * PopulateGlobalsForCopyFrom - Populates the common variables required for copy
+ * from operation. This is a helper function for BeginCopy function.
+ */
+static void
+PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tupDesc,
+							List *attnamelist)
+{
+	int			num_phys_attrs;
+
 	/* Generate or convert list of attributes to process */
 	cstate->attnumlist = CopyGetAttnums(tupDesc, cstate->rel, attnamelist);
 
@@ -1751,12 +1858,6 @@ BeginCopy(ParseState *pstate,
 		 pg_database_encoding_max_length() > 1);
 	/* See Multibyte encoding comment above */
 	cstate->encoding_embeds_ascii = PG_ENCODING_IS_CLIENT_ONLY(cstate->file_encoding);
-
-	cstate->copy_dest = COPY_FILE;	/* default */
-
-	MemoryContextSwitchTo(oldcontext);
-
-	return cstate;
 }
 
 /*
@@ -2645,32 +2746,11 @@ CopyMultiInsertInfoStore(CopyMultiInsertInfo *miinfo, ResultRelInfo *rri,
 }
 
 /*
- * Copy FROM file to relation.
+ * Check if the relation specified in copy from is valid.
  */
-uint64
-CopyFrom(CopyState cstate)
+static void
+CheckTargetRelValidity(CopyState cstate)
 {
-	ResultRelInfo *resultRelInfo;
-	ResultRelInfo *target_resultRelInfo;
-	ResultRelInfo *prevResultRelInfo = NULL;
-	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
-	ModifyTableState *mtstate;
-	ExprContext *econtext;
-	TupleTableSlot *singleslot = NULL;
-	MemoryContext oldcontext = CurrentMemoryContext;
-
-	PartitionTupleRouting *proute = NULL;
-	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
-	int			ti_options = 0; /* start with default options for insert */
-	BulkInsertState bistate = NULL;
-	CopyInsertMethod insertMethod;
-	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
-	uint64		processed = 0;
-	bool		has_before_insert_row_trig;
-	bool		has_instead_insert_row_trig;
-	bool		leafpart_use_multi_insert = false;
-
 	Assert(cstate->rel);
 
 	/*
@@ -2707,27 +2787,6 @@ CopyFrom(CopyState cstate)
 							RelationGetRelationName(cstate->rel))));
 	}
 
-	/*
-	 * If the target file is new-in-transaction, we assume that checking FSM
-	 * for free space is a waste of time.  This could possibly be wrong, but
-	 * it's unlikely.
-	 */
-	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
-		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
-		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
-		ti_options |= TABLE_INSERT_SKIP_FSM;
-
-	/*
-	 * Optimize if new relfilenode was created in this subxact or one of its
-	 * committed children and we won't see those rows later as part of an
-	 * earlier scan or command. The subxact test ensures that if this subxact
-	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
-	 * that the stronger test of exactly which subtransaction created it is
-	 * crucial for correctness of this optimization. The test for an earlier
-	 * scan or command tolerates false negatives. FREEZE causes other sessions
-	 * to see rows they would not see under MVCC, and a false negative merely
-	 * spreads that anomaly to the current session.
-	 */
 	if (cstate->freeze)
 	{
 		/*
@@ -2765,9 +2824,61 @@ CopyFrom(CopyState cstate)
 			ereport(ERROR,
 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 					 errmsg("cannot perform COPY FREEZE because the table was not created or truncated in the current subtransaction")));
+	}
+}
 
+/*
+ * Copy FROM file to relation.
+ */
+uint64
+CopyFrom(CopyState cstate)
+{
+	ResultRelInfo *resultRelInfo;
+	ResultRelInfo *target_resultRelInfo;
+	ResultRelInfo *prevResultRelInfo = NULL;
+	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
+	ModifyTableState *mtstate;
+	ExprContext *econtext;
+	TupleTableSlot *singleslot = NULL;
+	MemoryContext oldcontext = CurrentMemoryContext;
+
+	PartitionTupleRouting *proute = NULL;
+	ErrorContextCallback errcallback;
+	CommandId	mycid = GetCurrentCommandId(true);
+	int			ti_options = 0; /* start with default options for insert */
+	BulkInsertState bistate = NULL;
+	CopyInsertMethod insertMethod;
+	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
+	uint64		processed = 0;
+	bool		has_before_insert_row_trig;
+	bool		has_instead_insert_row_trig;
+	bool		leafpart_use_multi_insert = false;
+
+	CheckTargetRelValidity(cstate);
+
+	/*
+	 * If the target file is new-in-transaction, we assume that checking FSM
+	 * for free space is a waste of time.  This could possibly be wrong, but
+	 * it's unlikely.
+	 */
+	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
+		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
+		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
+		ti_options |= TABLE_INSERT_SKIP_FSM;
+
+	/*
+	 * Optimize if new relfilenode was created in this subxact or one of its
+	 * committed children and we won't see those rows later as part of an
+	 * earlier scan or command. The subxact test ensures that if this subxact
+	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
+	 * that the stronger test of exactly which subtransaction created it is
+	 * crucial for correctness of this optimization. The test for an earlier
+	 * scan or command tolerates false negatives. FREEZE causes other sessions
+	 * to see rows they would not see under MVCC, and a false negative merely
+	 * spreads that anomaly to the current session.
+	 */
+	if (cstate->freeze)
 		ti_options |= TABLE_INSERT_FROZEN;
-	}
 
 	/*
 	 * We need a ResultRelInfo so we can use the regular executor's
@@ -3260,7 +3371,7 @@ CopyFrom(CopyState cstate)
 			 * or FDW; this is the same definition used by nodeModifyTable.c
 			 * for counting tuples inserted by an INSERT command.
 			 */
-			processed++;
+			INCREMENTPROCESSED(processed)
 		}
 	}
 
@@ -3315,30 +3426,15 @@ CopyFrom(CopyState cstate)
 
 	FreeExecutorState(estate);
 
-	return processed;
+	GETPROCESSED(processed)
 }
 
 /*
- * Setup to read tuples from a file for COPY FROM.
- *
- * 'rel': Used as a template for the tuples
- * 'filename': Name of server-local file to read
- * 'attnamelist': List of char *, columns to include. NIL selects all cols.
- * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
- *
- * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ * PopulateCatalogInformation - populate the catalog information.
  */
-CopyState
-BeginCopyFrom(ParseState *pstate,
-			  Relation rel,
-			  const char *filename,
-			  bool is_program,
-			  copy_data_source_cb data_source_cb,
-			  List *attnamelist,
-			  List *options)
+static void
+PopulateCatalogInformation(CopyState cstate)
 {
-	CopyState	cstate;
-	bool		pipe = (filename == NULL);
 	TupleDesc	tupDesc;
 	AttrNumber	num_phys_attrs,
 				num_defaults;
@@ -3348,38 +3444,8 @@ BeginCopyFrom(ParseState *pstate,
 	Oid			in_func_oid;
 	int		   *defmap;
 	ExprState **defexprs;
-	MemoryContext oldcontext;
 	bool		volatile_defexprs;
 
-	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
-	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
-
-	/* Initialize state variables */
-	cstate->reached_eof = false;
-	cstate->eol_type = EOL_UNKNOWN;
-	cstate->cur_relname = RelationGetRelationName(cstate->rel);
-	cstate->cur_lineno = 0;
-	cstate->cur_attname = NULL;
-	cstate->cur_attval = NULL;
-
-	/*
-	 * Set up variables to avoid per-attribute overhead.  attribute_buf is
-	 * used in both text and binary modes, but we use line_buf and raw_buf
-	 * only in text mode.
-	 */
-	initStringInfo(&cstate->attribute_buf);
-	if (!cstate->binary)
-	{
-		initStringInfo(&cstate->line_buf);
-		cstate->line_buf_converted = false;
-		cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
-		cstate->raw_buf_index = cstate->raw_buf_len = 0;
-	}
-
-	/* Assign range table, we'll need it in CopyFrom. */
-	if (pstate)
-		cstate->range_table = pstate->p_rtable;
-
 	tupDesc = RelationGetDescr(cstate->rel);
 	num_phys_attrs = tupDesc->natts;
 	num_defaults = 0;
@@ -3457,6 +3523,61 @@ BeginCopyFrom(ParseState *pstate,
 	cstate->defexprs = defexprs;
 	cstate->volatile_defexprs = volatile_defexprs;
 	cstate->num_defaults = num_defaults;
+}
+
+/*
+ * Setup to read tuples from a file for COPY FROM.
+ *
+ * 'rel': Used as a template for the tuples
+ * 'filename': Name of server-local file to read
+ * 'attnamelist': List of char *, columns to include. NIL selects all cols.
+ * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
+ *
+ * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ */
+CopyState
+BeginCopyFrom(ParseState *pstate,
+			  Relation rel,
+			  const char *filename,
+			  bool is_program,
+			  copy_data_source_cb data_source_cb,
+			  List *attnamelist,
+			  List *options)
+{
+	CopyState	cstate;
+	bool		pipe = (filename == NULL);
+	MemoryContext oldcontext;
+
+	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	/* Initialize state variables */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/*
+	 * Set up variables to avoid per-attribute overhead.  attribute_buf is
+	 * used in both text and binary modes, but we use line_buf and raw_buf
+	 * only in text mode.
+	 */
+	initStringInfo(&cstate->attribute_buf);
+	if (!cstate->binary)
+	{
+		initStringInfo(&cstate->line_buf);
+		cstate->line_buf_converted = false;
+		cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+		cstate->raw_buf_index = cstate->raw_buf_len = 0;
+	}
+
+	/* Assign range table, we'll need it in CopyFrom. */
+	if (pstate)
+		cstate->range_table = pstate->p_rtable;
+
+	PopulateCatalogInformation(cstate);
 	cstate->is_program = is_program;
 
 	if (data_source_cb)
@@ -3866,60 +3987,8 @@ CopyReadLine(CopyState cstate)
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
-	else
-	{
-		/*
-		 * If we didn't hit EOF, then we must have transferred the EOL marker
-		 * to line_buf along with the data.  Get rid of it.
-		 */
-		switch (cstate->eol_type)
-		{
-			case EOL_NL:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CR:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\r');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CRNL:
-				Assert(cstate->line_buf.len >= 2);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 2] == '\r');
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len -= 2;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_UNKNOWN:
-				/* shouldn't get here */
-				Assert(false);
-				break;
-		}
-	}
-
-	/* Done reading the line.  Convert it to server encoding. */
-	if (cstate->need_transcoding)
-	{
-		char	   *cvt;
-
-		cvt = pg_any_to_server(cstate->line_buf.data,
-							   cstate->line_buf.len,
-							   cstate->file_encoding);
-		if (cvt != cstate->line_buf.data)
-		{
-			/* transfer converted data back to line_buf */
-			resetStringInfo(&cstate->line_buf);
-			appendBinaryStringInfo(&cstate->line_buf, cvt, strlen(cvt));
-			pfree(cvt);
-		}
-	}
-
-	/* Now it's safe to use the buffer in error messages */
-	cstate->line_buf_converted = true;
 
+	CONVERT_TO_SERVER_ENCODING(cstate)
 	return result;
 }
 
@@ -4283,6 +4352,7 @@ not_end_of_copy:
 	 * Transfer any still-uncopied data to line_buf.
 	 */
 	REFILL_LINEBUF;
+	CLEAR_EOL_LINE()
 
 	return result;
 }
-- 
2.25.1

0003-Allow-copy-from-command-to-process-data-from-file.patchapplication/octet-stream; name=0003-Allow-copy-from-command-to-process-data-from-file.patchDownload
From a3ea5cdbc62441af763800220d21b4a05a33738f Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddy@enterprisedb.com>
Date: Sun, 12 Jul 2020 17:33:14 +0530
Subject: [PATCH 3/6] Allow copy from command to process data from file/STDIN 
 contents to a table in parallel.

This feature allows the copy from to leverage multiple CPUs in order to copy
data from file/STDIN to a table. This adds a PARALLEL option to COPY FROM
command where the user can specify the number of workers that can be used
to perform the COPY FROM command. Specifying zero as number of workers will
disable parallelism.
The backend, to which the "COPY FROM" query is submitted acts as leader with
the responsibility of reading data from the file/stdin, launching at most n
number of workers as specified with PARALLEL 'n' option in the "COPY FROM"
query. The leader populates the common data required for the workers execution
in the DSM and shares it with the workers. The leader then executes before
statement triggers if there exists any. Leader populates DSM lines which
includes the start offset and line size, while populating the lines it reads
as many blocks as required into the DSM data blocks from the file. Each block
is of 64K size. The leader parses the data to identify a line, the existing
logic from CopyReadLineText which identifies the lines with some changes was
used for this. Leader checks if a free line is available to copy the
information, if there is no free line it waits till the required line is
freed up by the worker and then copies the identified lines information
(offset & line size) into the DSM lines. This process is repeated till the
complete file is processed. Simultaneously, the workers cache the lines(50)
locally into the local memory and release the lines to the leader for further
populating. Each worker processes the lines that it cached and inserts it into
the table. The leader does not participate in the insertion of data, leaders
only responsibility will be to identify the lines as fast as possible for the
workers to do the actual copy operation. The leader waits till all the lines
populated are processed by the workers and exits.
---
 src/backend/access/common/toast_internals.c |  11 +-
 src/backend/access/heap/heapam.c            |  13 -
 src/backend/access/transam/xact.c           |  31 +
 src/backend/commands/copy.c                 | 900 +++++++++++++++++++-
 src/include/access/xact.h                   |   2 +
 src/tools/pgindent/typedefs.list            |   1 +
 6 files changed, 906 insertions(+), 52 deletions(-)

diff --git a/src/backend/access/common/toast_internals.c b/src/backend/access/common/toast_internals.c
index 25a81e5ec6..586d53dd53 100644
--- a/src/backend/access/common/toast_internals.c
+++ b/src/backend/access/common/toast_internals.c
@@ -17,6 +17,7 @@
 #include "access/genam.h"
 #include "access/heapam.h"
 #include "access/heaptoast.h"
+#include "access/parallel.h"
 #include "access/table.h"
 #include "access/toast_internals.h"
 #include "access/xact.h"
@@ -116,7 +117,15 @@ toast_save_datum(Relation rel, Datum value,
 	TupleDesc	toasttupDesc;
 	Datum		t_values[3];
 	bool		t_isnull[3];
-	CommandId	mycid = GetCurrentCommandId(true);
+
+	/*
+	 * Parallel copy can insert toast tuples, in case of parallel copy the
+	 * command would have been set already by calling AssignCommandIdForWorker.
+	 * For parallel copy call GetCurrentCommandId to get currentCommandId by
+	 * passing used as false, as this is taken care earlier.
+	 */
+	CommandId	mycid = IsParallelWorker() ? GetCurrentCommandId(false) :
+											 GetCurrentCommandId(true);
 	struct varlena *result;
 	struct varatt_external toast_pointer;
 	union
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 7bd45703aa..862c4987f7 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2012,19 +2012,6 @@ static HeapTuple
 heap_prepare_insert(Relation relation, HeapTuple tup, TransactionId xid,
 					CommandId cid, int options)
 {
-	/*
-	 * Parallel operations are required to be strictly read-only in a parallel
-	 * worker.  Parallel inserts are not safe even in the leader in the
-	 * general case, because group locking means that heavyweight locks for
-	 * relation extension or GIN page locks will not conflict between members
-	 * of a lock group, but we don't prohibit that case here because there are
-	 * useful special cases that we can safely allow, such as CREATE TABLE AS.
-	 */
-	if (IsParallelWorker())
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_TRANSACTION_STATE),
-				 errmsg("cannot insert tuples in a parallel worker")));
-
 	tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
 	tup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK);
 	tup->t_data->t_infomask |= HEAP_XMAX_INVALID;
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index b3ee7fa7ea..94988b6739 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -501,6 +501,37 @@ GetCurrentFullTransactionIdIfAny(void)
 	return CurrentTransactionState->fullTransactionId;
 }
 
+/*
+ *	AssignFullTransactionIdForWorker
+ *
+ * For parallel copy, transaction id of leader will be used by the workers.
+ */
+void
+AssignFullTransactionIdForWorker(FullTransactionId fullTransactionId)
+{
+	TransactionState s = CurrentTransactionState;
+
+	Assert((IsInParallelMode() || IsParallelWorker()));
+	s->fullTransactionId = fullTransactionId;
+}
+
+/*
+ *	AssignCommandIdForWorker
+ *
+ * For parallel copy, command id of leader will be used by the workers.
+ */
+void
+AssignCommandIdForWorker(CommandId commandId, bool used)
+{
+	Assert((IsInParallelMode() || IsParallelWorker()));
+
+	/* this is global to a transaction, not subtransaction-local */
+	if (used)
+		currentCommandIdUsed = true;
+
+	currentCommandId = commandId;
+}
+
 /*
  *	MarkCurrentTransactionIdLoggedIfAny
  *
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 973d20de6e..d17fbb77c6 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -26,6 +26,7 @@
 #include "access/xlog.h"
 #include "catalog/dependency.h"
 #include "catalog/pg_authid.h"
+#include "catalog/pg_proc_d.h"
 #include "catalog/pg_type.h"
 #include "commands/copy.h"
 #include "commands/defrem.h"
@@ -40,11 +41,13 @@
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
+#include "optimizer/clauses.h"
 #include "optimizer/optimizer.h"
 #include "parser/parse_coerce.h"
 #include "parser/parse_collate.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_relation.h"
+#include "pgstat.h"
 #include "port/pg_bswap.h"
 #include "rewrite/rewriteHandler.h"
 #include "storage/fd.h"
@@ -95,6 +98,18 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
+/*
+ * State of the line.
+ */
+typedef enum ParallelCopyLineState
+{
+	LINE_INIT,					/* initial state of line */
+	LINE_LEADER_POPULATING,		/* leader processing line */
+	LINE_LEADER_POPULATED,		/* leader completed populating line */
+	LINE_WORKER_PROCESSING,		/* worker processing line */
+	LINE_WORKER_PROCESSED		/* worker completed processing line */
+}ParallelCopyLineState;
+
 #define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
 
 #define DATA_BLOCK_SIZE RAW_BUF_SIZE
@@ -541,9 +556,13 @@ if (1) \
 { \
 	if (raw_buf_ptr > cstate->raw_buf_index) \
 	{ \
-		appendBinaryStringInfo(&cstate->line_buf, \
-							 cstate->raw_buf + cstate->raw_buf_index, \
-							   raw_buf_ptr - cstate->raw_buf_index); \
+		if (!IsParallelCopy()) \
+			appendBinaryStringInfo(&cstate->line_buf, \
+								   cstate->raw_buf + cstate->raw_buf_index, \
+								   raw_buf_ptr - cstate->raw_buf_index); \
+		else \
+			line_size +=  raw_buf_ptr - cstate->raw_buf_index; \
+		\
 		cstate->raw_buf_index = raw_buf_ptr; \
 	} \
 } else ((void) 0)
@@ -556,13 +575,40 @@ if (1) \
 	goto not_end_of_copy; \
 } else ((void) 0)
 
+/* Begin parallel copy Macros */
+#define SET_NEWLINE_SIZE() \
+{ \
+	if (cstate->eol_type == EOL_NL || cstate->eol_type == EOL_CR) \
+		new_line_size = 1; \
+	else if (cstate->eol_type == EOL_CRNL) \
+		new_line_size = 2; \
+	else \
+		new_line_size = 0; \
+}
+
+/*
+ * COPY_WAIT_TO_PROCESS - Wait before continuing to process.
+ */
+#define COPY_WAIT_TO_PROCESS() \
+{ \
+	CHECK_FOR_INTERRUPTS(); \
+	(void) WaitLatch(MyLatch, \
+					 WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH, \
+					 1L, WAIT_EVENT_PG_SLEEP); \
+	ResetLatch(MyLatch); \
+}
+
+/* End parallel copy Macros */
+
 /*
  * CONVERT_TO_SERVER_ENCODING - convert contents to server encoding.
  */
 #define CONVERT_TO_SERVER_ENCODING(cstate) \
 { \
 	/* Done reading the line.  Convert it to server encoding. */ \
-	if (cstate->need_transcoding) \
+	if (cstate->need_transcoding && \
+		(!IsParallelCopy() || \
+		 (IsParallelCopy() && !IsLeader()))) \
 	{ \
 		char	   *cvt; \
 		cvt = pg_any_to_server(cstate->line_buf.data, \
@@ -621,22 +667,38 @@ if (1) \
  * CLEAR_EOL_LINE - Wrapper for clearing EOL.
  */
 #define CLEAR_EOL_LINE() \
-if (!result && !IsHeaderLine()) \
-	CLEAR_EOL_FROM_COPIED_DATA(cstate->line_buf.data, \
-								cstate->line_buf.len, \
-								cstate->line_buf.len) \
+{ \
+	if (!result && !IsHeaderLine()) \
+	{ \
+		if (IsParallelCopy()) \
+			CLEAR_EOL_FROM_COPIED_DATA(cstate->raw_buf, \
+									   raw_buf_ptr, line_size) \
+		else \
+			CLEAR_EOL_FROM_COPIED_DATA(cstate->line_buf.data, \
+									   cstate->line_buf.len, \
+									   cstate->line_buf.len) \
+	} \
+}
 
 /*
  * INCREMENTPROCESSED - Increment the lines processed.
  */
-#define INCREMENTPROCESSED(processed)  \
-processed++;
+#define INCREMENTPROCESSED(processed) \
+{ \
+	if (!IsParallelCopy()) \
+		processed++; \
+	else \
+		pg_atomic_add_fetch_u64(&cstate->pcdata->pcshared_info->processed, 1); \
+}
 
 /*
  * GETPROCESSED - Get the lines processed.
  */
 #define GETPROCESSED(processed) \
-return processed;
+if (!IsParallelCopy()) \
+	return processed; \
+else \
+	return pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
 
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
@@ -684,8 +746,12 @@ static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 
 static pg_attribute_always_inline void EndParallelCopy(ParallelContext *pcxt);
+static void ExecBeforeStmtTrigger(CopyState cstate);
+static void CheckTargetRelValidity(CopyState cstate);
 static void PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tup_desc,
 							   List *attnamelist);
+static void PopulateCatalogInformation(CopyState cstate);
+static pg_attribute_always_inline uint32 GetLinePosition(CopyState cstate);
 static pg_attribute_always_inline copy_data_source_cb LookupParallelCopyFnPtr(const char *funcname);
 static pg_attribute_always_inline char* LookupParallelCopyFnStr(copy_data_source_cb fn_addr);
 
@@ -838,6 +904,137 @@ InsertListShm(ParallelContext *pcxt, int key, List *inputlist,
 	}
 }
 
+/*
+ * IsTriggerFunctionParallelSafe - Check if the trigger function is parallel
+ * safe for the triggers. Return false if any one of the trigger has parallel
+ * unsafe function.
+ */
+static pg_attribute_always_inline bool
+IsTriggerFunctionParallelSafe(TriggerDesc *trigdesc)
+{
+	int	i;
+	for (i = 0; i < trigdesc->numtriggers; i++)
+	{
+		Trigger    *trigger = &trigdesc->triggers[i];
+		int 		trigtype = RI_TRIGGER_NONE;
+
+		if (func_parallel(trigger->tgfoid) != PROPARALLEL_SAFE)
+			return false;
+
+		/* If the trigger is parallel safe, also look for RI_TRIGGER. */
+		trigtype = RI_FKey_trigger_type(trigger->tgfoid);
+		if (trigtype == RI_TRIGGER_PK || trigtype == RI_TRIGGER_FK)
+			return false;
+	}
+
+	return true;
+}
+
+/*
+ * CheckExprParallelSafety - determine parallel safety of volatile expressions
+ * in default clause of column definition or in where clause and return true if
+ * they are parallel safe.
+ */
+static pg_attribute_always_inline bool
+CheckExprParallelSafety(CopyState cstate)
+{
+	if (contain_volatile_functions(cstate->whereClause))
+	{
+		if (max_parallel_hazard((Query *)cstate->whereClause) != PROPARALLEL_SAFE)
+			return false;
+	}
+
+	/*
+	 * Check if any of the column has volatile default expression. if yes, and
+	 * they are not parallel safe, then parallelism is not allowed. For
+	 * instance, if there are any serial/bigserial columns for which nextval()
+	 * default expression which is parallel unsafe is associated, parallelism
+	 * should not be allowed. In non parallel copy volatile functions are not
+	 * checked for nextval().
+	 */
+	if (cstate->defexprs != NULL && cstate->num_defaults != 0)
+	{
+		int     i;
+		for (i = 0; i < cstate->num_defaults; i++)
+		{
+			bool volatile_expr = contain_volatile_functions((Node *)cstate->defexprs[i]->expr);
+			if (volatile_expr &&
+				(max_parallel_hazard((Query *)cstate->defexprs[i]->expr)) !=
+				 PROPARALLEL_SAFE)
+				return false;
+		}
+	}
+
+	return true;
+}
+
+/*
+ * FindInsertMethod - determine insert mode single, multi, or multi conditional.
+ */
+static pg_attribute_always_inline CopyInsertMethod
+FindInsertMethod(CopyState cstate)
+{
+	if (cstate->rel->trigdesc != NULL &&
+		(cstate->rel->trigdesc->trig_insert_before_row ||
+		 cstate->rel->trigdesc->trig_insert_instead_row))
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
+			cstate->rel->trigdesc != NULL &&
+			cstate->rel->trigdesc->trig_insert_new_table)
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+		return CIM_MULTI_CONDITIONAL;
+
+	return CIM_MULTI;
+}
+
+/*
+ * IsParallelCopyAllowed - check for the cases where parallel copy is not
+ * applicable.
+ */
+static pg_attribute_always_inline bool
+IsParallelCopyAllowed(CopyState cstate)
+{
+	/* Parallel copy not allowed for frontend (2.0 protocol) & binary option. */
+	if ((cstate->copy_dest == COPY_OLD_FE) || cstate->binary)
+		return false;
+
+	/* Check if copy is into foreign table or temporary table. */
+	if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
+		RelationUsesLocalBuffers(cstate->rel))
+		return false;
+
+	/* Check if trigger function is parallel safe. */
+	if (cstate->rel->trigdesc != NULL &&
+		!IsTriggerFunctionParallelSafe(cstate->rel->trigdesc))
+		return false;
+
+	/*
+	 * Check if there is after statement or instead of trigger or transition
+	 * table triggers.
+	 */
+	if (cstate->rel->trigdesc != NULL &&
+		(cstate->rel->trigdesc->trig_insert_after_statement ||
+		 cstate->rel->trigdesc->trig_insert_instead_row ||
+		 cstate->rel->trigdesc->trig_insert_new_table))
+		return false;
+
+	/* Check if the volatile expressions are parallel safe, if present any. */
+	if (!CheckExprParallelSafety(cstate))
+		return false;
+
+	/* Check if the insertion mode is single. */
+	if (FindInsertMethod(cstate) == CIM_SINGLE)
+		return false;
+
+	return true;
+}
+
 /*
  * BeginParallelCopy - start parallel copy tasks.
  *
@@ -868,6 +1065,8 @@ BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
 	int  parallel_workers = 0;
 	ParallelCopyData *pcdata;
 
+	CheckTargetRelValidity(cstate);
+
 	parallel_workers = Min(nworkers, max_worker_processes);
 
 	/* Can't perform copy in parallel */
@@ -881,6 +1080,19 @@ BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
 	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
 	cstate->pcdata = pcdata;
 
+	/*
+	 * User chosen parallel copy. Determine if the parallel copy is actually
+	 * allowed. If not, go with the non-parallel mode.
+	 */
+	if (!IsParallelCopyAllowed(cstate))
+	{
+		elog(WARNING,
+			 "Parallel copy not supported for specified table, copy will be run in non-parallel mode");
+		return NULL;
+	}
+
+	full_transaction_id = GetCurrentFullTransactionId();
+
 	EnterParallelMode();
 	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
 								 parallel_workers);
@@ -1111,7 +1323,211 @@ ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
 	cstate->line_buf_converted = false;
 	cstate->raw_buf = NULL;
 	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+
+	PopulateCatalogInformation(cstate);
+
+	/* Create workspace for CopyReadAttributes results. */
+	if (!cstate->binary)
+	{
+		AttrNumber	attr_count = list_length(cstate->attnumlist);
+
+		cstate->max_fields = attr_count;
+		cstate->raw_fields = (char **)palloc(attr_count * sizeof(char *));
+	}
+}
+
+/*
+ * CacheLineInfo - Cache the line information to local memory.
+ */
+static bool
+CacheLineInfo(CopyState cstate, uint32 buff_count)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	uint32			write_pos;
+	ParallelCopyDataBlock *data_blk_ptr;
+	ParallelCopyLineBoundary *lineInfo;
+	uint32 offset;
+	int dataSize;
+	int copiedSize = 0;
+
+	resetStringInfo(&pcdata->worker_line_buf[buff_count].line_buf);
+	write_pos = GetLinePosition(cstate);
+	if (-1 == write_pos)
+		return true;
+
+	/* Get the current line information. */
+	lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+	if (pg_atomic_read_u32(&lineInfo->line_size) == 0)
+		goto empty_data_line_update;
+
+	/* Get the block information. */
+	data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+	/* Get the offset information from where the data must be copied. */
+	offset = lineInfo->start_offset;
+	pcdata->worker_line_buf[buff_count].cur_lineno = lineInfo->cur_lineno;
+
+	elog(DEBUG1, "[Worker] Processing - line position:%d, block:%d, unprocessed lines:%d, offset:%d, line size:%d",
+				 write_pos, lineInfo->first_block,
+				 pg_atomic_read_u32(&data_blk_ptr->unprocessed_line_parts),
+				 offset, pg_atomic_read_u32(&lineInfo->line_size));
+
+	for (;;)
+	{
+		uint8 skip_bytes = data_blk_ptr->skip_bytes;
+		/*
+		 * There is a possibility that the above loop has come out because
+		 * data_blk_ptr->curr_blk_completed is set, but dataSize read might
+		 * be an old value, if data_blk_ptr->curr_blk_completed and the line is
+		 * completed, line_size will be set. Read the line_size again to be
+		 * sure if it is complete or partial block.
+		 */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+		if (dataSize)
+		{
+			int remainingSize = dataSize - copiedSize;
+			if (!remainingSize)
+				break;
+
+			/* Whole line is in current block. */
+			if (remainingSize + offset + skip_bytes < DATA_BLOCK_SIZE)
+			{
+				appendBinaryStringInfo(&pcdata->worker_line_buf[buff_count].line_buf,
+									   &data_blk_ptr->data[offset],
+									   remainingSize);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts,
+										1);
+				break;
+			}
+			else
+			{
+				/* Line is spread across the blocks. */
+				uint32 lineInCurrentBlock =  (DATA_BLOCK_SIZE - skip_bytes) - offset;
+				appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+										 &data_blk_ptr->data[offset],
+										 lineInCurrentBlock);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+				copiedSize += lineInCurrentBlock;
+				while (copiedSize < dataSize)
+				{
+					uint32 currentBlockCopySize;
+					ParallelCopyDataBlock *currBlkPtr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+					skip_bytes = currBlkPtr->skip_bytes;
+
+					/*
+					 * If complete data is present in current block use
+					 * dataSize - copiedSize, or copy the whole block from
+					 * current block.
+					 */
+					currentBlockCopySize = Min(dataSize - copiedSize, DATA_BLOCK_SIZE - skip_bytes);
+					appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+											 &currBlkPtr->data[0],
+											 currentBlockCopySize);
+					pg_atomic_sub_fetch_u32(&currBlkPtr->unprocessed_line_parts, 1);
+					copiedSize += currentBlockCopySize;
+					data_blk_ptr = currBlkPtr;
+				}
+
+				break;
+			}
+		}
+		else
+		{
+			/* Copy this complete block from the current offset. */
+			uint32 lineInCurrentBlock =  (DATA_BLOCK_SIZE - skip_bytes) - offset;
+			appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+									 &data_blk_ptr->data[offset],
+									 lineInCurrentBlock);
+			pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+			copiedSize += lineInCurrentBlock;
+
+			/*
+			 * Reset the offset. For the first copy, copy from the offset. For
+			 * the subsequent copy the complete block.
+			 */
+			offset = 0;
+
+			/* Set data_blk_ptr to the following block. */
+			data_blk_ptr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+		}
+
+		for (;;)
+		{
+			/* Get the size of this line */
+			dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+			/*
+			 * If the data is present in current block lineInfo.line_size
+			 * will be updated. If the data is spread across the blocks either
+			 * of lineInfo.line_size or data_blk_ptr->curr_blk_completed can
+			 * be updated. lineInfo.line_size will be updated if the complete
+			 * read is finished. data_blk_ptr->curr_blk_completed will be
+			 * updated if processing of current block is finished and data
+			 * processing is not finished.
+			 */
+			if (data_blk_ptr->curr_blk_completed || (dataSize != -1))
+				break;
+
+			COPY_WAIT_TO_PROCESS()
+		}
+	}
+
+empty_data_line_update:
+	elog(DEBUG1, "[Worker] Completed processing line:%d", write_pos);
+	pg_atomic_write_u32(&lineInfo->line_state, LINE_WORKER_PROCESSED);
+	pg_atomic_write_u32(&lineInfo->line_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+	return false;
+}
+
+/*
+ * GetWorkerLine - Returns a line for worker to process.
+ */
+static bool
+GetWorkerLine(CopyState cstate)
+{
+	uint32 buff_count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+
+	/*
+	 * Copy the line data to line_buf and release the line position so that the
+	 * worker can continue loading data.
+	 */
+	if (pcdata->worker_line_buf_pos < pcdata->worker_line_buf_count)
+		goto return_line;
+
+	pcdata->worker_line_buf_pos = 0;
+	pcdata->worker_line_buf_count = 0;
+
+	for (buff_count = 0; buff_count < WORKER_CHUNK_COUNT; buff_count++)
+	{
+		bool result = CacheLineInfo(cstate, buff_count);
+		if (result)
+			break;
+
+		pcdata->worker_line_buf_count++;
+	}
+
+	if (pcdata->worker_line_buf_count)
+		goto return_line;
+	else
+		resetStringInfo(&cstate->line_buf);
+
+	return true;
+
+return_line:
+	cstate->line_buf = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].line_buf;
+	cstate->cur_lineno = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].cur_lineno;
+	cstate->line_buf_valid = true;
+
+	/* Mark that encoding conversion hasn't occurred yet. */
+	cstate->line_buf_converted = false;
+	CONVERT_TO_SERVER_ENCODING(cstate)
+	pcdata->worker_line_buf_pos++;
+	return false;
 }
+
 /*
  * ParallelCopyMain - parallel copy worker's code.
  *
@@ -1157,6 +1573,8 @@ ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
 	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
 
 	pcdata->pcshared_info = pcshared_info;
+	AssignFullTransactionIdForWorker(pcshared_info->full_transaction_id);
+	AssignCommandIdForWorker(pcshared_info->mycid, true);
 
 	shared_cstate = (ParallelCopyCommonKeyData *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE,
 														   false);
@@ -1209,6 +1627,34 @@ ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
 	MemoryContextSwitchTo(oldcontext);
 	return;
 }
+
+/*
+ * UpdateBlockInLineInfo - Update the line information.
+ */
+static pg_attribute_always_inline int
+UpdateBlockInLineInfo(CopyState cstate, uint32 blk_pos,
+					   uint32 offset, uint32 line_size, uint32 line_state)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyLineBoundaries *lineBoundaryPtr = &pcshared_info->line_boundaries;
+	ParallelCopyLineBoundary *lineInfo;
+	int line_pos = lineBoundaryPtr->leader_pos;
+
+	/* Update the line information for the worker to pick and process. */
+	lineInfo = &lineBoundaryPtr->ring[line_pos];
+	while (pg_atomic_read_u32(&lineInfo->line_size) != -1)
+		COPY_WAIT_TO_PROCESS()
+
+	lineInfo->first_block = blk_pos;
+	lineInfo->start_offset = offset;
+	lineInfo->cur_lineno = cstate->cur_lineno;
+	pg_atomic_write_u32(&lineInfo->line_size, line_size);
+	pg_atomic_write_u32(&lineInfo->line_state, line_state);
+	lineBoundaryPtr->leader_pos = (lineBoundaryPtr->leader_pos + 1) % RINGSIZE;
+
+	return line_pos;
+}
+
 /*
  * ParallelCopyLeader - parallel copy leader's functionality.
  *
@@ -1234,9 +1680,161 @@ ParallelCopyLeader(CopyState cstate)
 	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
 	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
 
+	/* Execute the before statement triggers from the leader */
+	ExecBeforeStmtTrigger(cstate);
+
+	/* On input just throw the header line away. */
+	if (cstate->cur_lineno == 0 && cstate->header_line)
+	{
+		cstate->cur_lineno++;
+		if (CopyReadLine(cstate))
+		{
+			pcshared_info->is_read_in_progress = false;
+			return;			/* done */
+		}
+	}
+
+	for (;;)
+	{
+		bool done;
+		cstate->cur_lineno++;
+
+		/* Actually read the line into memory here. */
+		done = CopyReadLine(cstate);
+
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			break;
+	}
+
 	pcshared_info->is_read_in_progress = false;
 	cstate->cur_lineno = 0;
 }
+
+/*
+ * GetLinePosition - return the line position that worker should process.
+ */
+static uint32
+GetLinePosition(CopyState cstate)
+{
+	ParallelCopyData *pcdata = cstate->pcdata;
+	ParallelCopyShmInfo *pcshared_info = pcdata->pcshared_info;
+	uint32  previous_pos = pcdata->worker_processed_pos;
+	uint32 write_pos = (previous_pos == -1) ? 0 : (previous_pos + 1) % RINGSIZE;
+	for (;;)
+	{
+		int		dataSize;
+		bool	is_read_in_progress = pcshared_info->is_read_in_progress;
+		ParallelCopyLineBoundary *lineInfo;
+		ParallelCopyDataBlock *data_blk_ptr;
+		ParallelCopyLineState line_state = LINE_LEADER_POPULATED;
+		ParallelCopyLineState curr_line_state;
+		CHECK_FOR_INTERRUPTS();
+
+		/* File read completed & no elements to process. */
+		if (!is_read_in_progress &&
+			(pcshared_info->populated ==
+			 pg_atomic_read_u64(&pcshared_info->total_worker_processed)))
+		{
+			write_pos = -1;
+			break;
+		}
+
+		/* Get the current line information. */
+		lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+		curr_line_state = pg_atomic_read_u32(&lineInfo->line_state);
+		if ((write_pos % WORKER_CHUNK_COUNT == 0) &&
+			(curr_line_state == LINE_WORKER_PROCESSED ||
+			 curr_line_state == LINE_WORKER_PROCESSING))
+		{
+			pcdata->worker_processed_pos = write_pos;
+			write_pos = (write_pos + WORKER_CHUNK_COUNT) %  RINGSIZE;
+			continue;
+		}
+
+		/* Get the size of this line. */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+		if (dataSize != 0) /* If not an empty line. */
+		{
+			/* Get the block information. */
+			data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+			if (!data_blk_ptr->curr_blk_completed && (dataSize == -1))
+			{
+				/* Wait till the current line or block is added. */
+				COPY_WAIT_TO_PROCESS()
+				continue;
+			}
+		}
+
+		/* Make sure that no worker has consumed this element. */
+		if (pg_atomic_compare_exchange_u32(&lineInfo->line_state,
+										   &line_state, LINE_WORKER_PROCESSING))
+			break;
+	}
+
+	pcdata->worker_processed_pos = write_pos;
+	return write_pos;
+}
+
+/*
+ * GetFreeCopyBlock - Get a free block for data to be copied.
+ */
+static pg_attribute_always_inline uint32
+GetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	int count = 0;
+	uint32 last_free_block = pcshared_info->cur_block_pos;
+	uint32 block_pos = (last_free_block != -1) ? ((last_free_block + 1) % MAX_BLOCKS_COUNT): 0;
+
+	/*
+	 * Get a new block for copying data, don't check curent block, current
+	 * block will have some unprocessed data.
+	 */
+	while (count < (MAX_BLOCKS_COUNT - 1))
+	{
+		ParallelCopyDataBlock *dataBlkPtr = &pcshared_info->data_blocks[block_pos];
+		uint32 unprocessed_line_parts = pg_atomic_read_u32(&dataBlkPtr->unprocessed_line_parts);
+		if (unprocessed_line_parts == 0)
+		{
+			dataBlkPtr->curr_blk_completed = false;
+			dataBlkPtr->skip_bytes = 0;
+			pcshared_info->cur_block_pos = block_pos;
+			return block_pos;
+		}
+
+		block_pos = (block_pos + 1) % MAX_BLOCKS_COUNT;
+		count++;
+	}
+
+	return -1;
+}
+
+/*
+ * WaitGetFreeCopyBlock - If there are no blocks available, wait and get a block
+ * for copying data.
+ */
+static uint32
+WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	uint32 new_free_pos = -1;
+	for (;;)
+	{
+		new_free_pos = GetFreeCopyBlock(pcshared_info);
+		if (new_free_pos != -1)	/* We have got one block, break now. */
+			break;
+
+		COPY_WAIT_TO_PROCESS()
+	}
+
+	return new_free_pos;
+}
+
 /*
  * LookupParallelCopyFnPtr - Look up parallel copy function pointer.
  */
@@ -1272,6 +1870,146 @@ LookupParallelCopyFnStr(copy_data_source_cb fn_addr)
 	/* We can only reach this by programming error. */
 	elog(ERROR, "internal function pointer not found");
 }
+
+/*
+ * SetRawBufForLoad - Set raw_buf to the shared memory where the file data must
+ * be read.
+ */
+static void
+SetRawBufForLoad(CopyState cstate, uint32 line_size, uint32 copy_buf_len,
+				 uint32 raw_buf_ptr, char **copy_raw_buf)
+{
+	ParallelCopyShmInfo	*pcshared_info;
+	uint32 cur_block_pos;
+	uint32 next_block_pos;
+	ParallelCopyDataBlock	*cur_data_blk_ptr = NULL;
+	ParallelCopyDataBlock	*next_data_blk_ptr = NULL;
+
+	if (!IsParallelCopy())
+		return;
+
+	pcshared_info = cstate->pcdata->pcshared_info;
+	cur_block_pos = pcshared_info->cur_block_pos;
+	cur_data_blk_ptr = (cstate->raw_buf) ? &pcshared_info->data_blocks[cur_block_pos] : NULL;
+	next_block_pos = WaitGetFreeCopyBlock(pcshared_info);
+	next_data_blk_ptr = &pcshared_info->data_blocks[next_block_pos];
+
+	/* set raw_buf to the data block in shared memory */
+	cstate->raw_buf = next_data_blk_ptr->data;
+	*copy_raw_buf = cstate->raw_buf;
+	if (cur_data_blk_ptr && line_size)
+	{
+		/*
+		 * Mark the previous block as completed, worker can start copying this
+		 * data.
+		 */
+		cur_data_blk_ptr->following_block = next_block_pos;
+		pg_atomic_add_fetch_u32(&cur_data_blk_ptr->unprocessed_line_parts, 1);
+		cur_data_blk_ptr->skip_bytes = copy_buf_len - raw_buf_ptr;
+		cur_data_blk_ptr->curr_blk_completed = true;
+	}
+}
+
+/*
+ * EndLineParallelCopy - Update the line information in shared memory.
+ */
+static void
+EndLineParallelCopy(CopyState cstate, uint32 line_pos, uint32 line_size,
+					 uint32 raw_buf_ptr)
+{
+	uint8 new_line_size;
+	if (!IsParallelCopy())
+		return;
+
+	if (!IsHeaderLine())
+	{
+		ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+		ParallelCopyLineBoundaries *lineBoundaryPtr = &pcshared_info->line_boundaries;
+		SET_NEWLINE_SIZE()
+		if (line_size)
+		{
+			ParallelCopyLineBoundary *lineInfo = &lineBoundaryPtr->ring[line_pos];
+			/*
+			 * If the new_line_size > raw_buf_ptr, then the new block has only
+			 * new line char content. The unprocessed count should not be
+			 * increased in this case.
+			 */
+			if (raw_buf_ptr > new_line_size)
+			{
+				uint32 cur_block_pos = pcshared_info->cur_block_pos;
+				ParallelCopyDataBlock *curr_data_blk_ptr = &pcshared_info->data_blocks[cur_block_pos];
+				pg_atomic_add_fetch_u32(&curr_data_blk_ptr->unprocessed_line_parts, 1);
+			}
+
+			/* Update line size. */
+			pg_atomic_write_u32(&lineInfo->line_size, line_size);
+			pg_atomic_write_u32(&lineInfo->line_state, LINE_LEADER_POPULATED);
+			elog(DEBUG1, "[Leader] After adding - line position:%d, line_size:%d",
+						 line_pos, line_size);
+			pcshared_info->populated++;
+		}
+		else if (new_line_size)
+		{
+			/* This means only new line char, empty record should be inserted.*/
+			ParallelCopyLineBoundary *lineInfo;
+			line_pos = UpdateBlockInLineInfo(cstate, -1, -1, 0,
+											   LINE_LEADER_POPULATED);
+			lineInfo = &lineBoundaryPtr->ring[line_pos];
+			elog(DEBUG1, "[Leader] Added empty line with offset:%d, line position:%d, line size:%d",
+						 lineInfo->start_offset, line_pos,
+						 pg_atomic_read_u32(&lineInfo->line_size));
+			pcshared_info->populated++;
+		}
+	}
+}
+
+/*
+ * ExecBeforeStmtTrigger - Execute the before statement trigger, this will be
+ * executed for parallel copy by the leader process.
+ */
+static void
+ExecBeforeStmtTrigger(CopyState cstate)
+{
+	EState	   *estate = CreateExecutorState();
+	ResultRelInfo *resultRelInfo;
+
+	Assert(IsLeader());
+
+	/*
+	 * We need a ResultRelInfo so we can use the regular executor's
+	 * index-entry-making machinery.  (There used to be a huge amount of code
+	 * here that basically duplicated execUtils.c ...)
+	 */
+	resultRelInfo = makeNode(ResultRelInfo);
+	InitResultRelInfo(resultRelInfo,
+					  cstate->rel,
+					  1,		/* must match rel's position in range_table */
+					  NULL,
+					  0);
+
+	/* Verify the named relation is a valid target for INSERT */
+	CheckValidResultRel(resultRelInfo, CMD_INSERT);
+
+	estate->es_result_relations = resultRelInfo;
+	estate->es_num_result_relations = 1;
+	estate->es_result_relation_info = resultRelInfo;
+
+	ExecInitRangeTable(estate, cstate->range_table);
+
+	/*
+	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
+	 * should do this for COPY, since it's not really an "INSERT" statement as
+	 * such. However, executing these triggers maintains consistency with the
+	 * EACH ROW triggers that we already fire on COPY.
+	 */
+	ExecBSInsertTriggers(estate, resultRelInfo);
+
+	/* Close any trigger target relations */
+	ExecCleanUpTriggerState(estate);
+
+	FreeExecutorState(estate);
+}
+
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
  * in past protocol redesigns.
@@ -3701,7 +4439,8 @@ CopyFrom(CopyState cstate)
 
 	PartitionTupleRouting *proute = NULL;
 	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
+	CommandId	mycid = IsParallelCopy() ? GetCurrentCommandId(false) :
+										   GetCurrentCommandId(true);
 	int			ti_options = 0; /* start with default options for insert */
 	BulkInsertState bistate = NULL;
 	CopyInsertMethod insertMethod;
@@ -3711,7 +4450,14 @@ CopyFrom(CopyState cstate)
 	bool		has_instead_insert_row_trig;
 	bool		leafpart_use_multi_insert = false;
 
-	CheckTargetRelValidity(cstate);
+	/*
+	 * Perform this check if it is not parallel copy. In case of parallel
+	 * copy, this check is done by the leader, so that if any invalid case
+	 * exist the copy from command will error out from the leader itself,
+	 * avoiding launching workers, just to throw error.
+	 */
+	if (!IsParallelCopy())
+		CheckTargetRelValidity(cstate);
 
 	/*
 	 * If the target file is new-in-transaction, we assume that checking FSM
@@ -3900,13 +4646,16 @@ CopyFrom(CopyState cstate)
 	has_instead_insert_row_trig = (resultRelInfo->ri_TrigDesc &&
 								   resultRelInfo->ri_TrigDesc->trig_insert_instead_row);
 
-	/*
-	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
-	 * should do this for COPY, since it's not really an "INSERT" statement as
-	 * such. However, executing these triggers maintains consistency with the
-	 * EACH ROW triggers that we already fire on COPY.
-	 */
-	ExecBSInsertTriggers(estate, resultRelInfo);
+	if (!IsParallelCopy())
+	{
+		/*
+		 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
+		 * should do this for COPY, since it's not really an "INSERT" statement as
+		 * such. However, executing these triggers maintains consistency with the
+		 * EACH ROW triggers that we already fire on COPY.
+		 */
+		ExecBSInsertTriggers(estate, resultRelInfo);
+	}
 
 	econtext = GetPerTupleExprContext(estate);
 
@@ -4006,6 +4755,16 @@ CopyFrom(CopyState cstate)
 					!has_instead_insert_row_trig &&
 					resultRelInfo->ri_FdwRoutine == NULL;
 
+				/*
+				 * If the table has any partitions that are either foreign or
+				 * has BEFORE/INSTEAD OF triggers, we can't perform copy
+				 * operations with parallel workers.
+				 */
+				if (!leafpart_use_multi_insert && IsParallelWorker())
+					ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							errmsg("cannot perform PARALLEL COPY if partition has BEFORE/INSTEAD OF triggers, or if the partition is foreign partition"),
+							errhint("Try COPY without PARALLEL option")));
+
 				/* Set the multi-insert buffer to use for this partition. */
 				if (leafpart_use_multi_insert)
 				{
@@ -4426,7 +5185,7 @@ BeginCopyFrom(ParseState *pstate,
 	{
 		initStringInfo(&cstate->line_buf);
 		cstate->line_buf_converted = false;
-		cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+		cstate->raw_buf = (IsParallelCopy()) ? NULL : (char *) palloc(RAW_BUF_SIZE + 1);
 		cstate->raw_buf_index = cstate->raw_buf_len = 0;
 	}
 
@@ -4571,26 +5330,35 @@ NextCopyFromRawFields(CopyState cstate, char ***fields, int *nfields)
 	/* only available for text or csv input */
 	Assert(!cstate->binary);
 
-	/* on input just throw the header line away */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (IsParallelCopy())
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
-			return false;		/* done */
+		done = GetWorkerLine(cstate);
+		if (done && cstate->line_buf.len == 0)
+			return false;
 	}
+	else
+	{
+		/* on input just throw the header line away */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
+		{
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+				return false;		/* done */
+		}
 
-	cstate->cur_lineno++;
+		cstate->cur_lineno++;
 
-	/* Actually read the line into memory here */
-	done = CopyReadLine(cstate);
+		/* Actually read the line into memory here */
+		done = CopyReadLine(cstate);
 
-	/*
-	 * EOF at start of line means we're done.  If we see EOF after some
-	 * characters, we act as though it was newline followed by EOF, ie,
-	 * process the line and then exit loop on next iteration.
-	 */
-	if (done && cstate->line_buf.len == 0)
-		return false;
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			return false;
+	}
 
 	/* Parse the line into de-escaped field values */
 	if (cstate->csv_mode)
@@ -4838,9 +5606,31 @@ CopyReadLine(CopyState cstate)
 		 */
 		if (cstate->copy_dest == COPY_NEW_FE)
 		{
+			bool bIsFirst = true;
 			do
 			{
-				cstate->raw_buf_index = cstate->raw_buf_len;
+				if (!IsParallelCopy())
+					cstate->raw_buf_index = cstate->raw_buf_len;
+				else
+				{
+					if (cstate->raw_buf_index == RAW_BUF_SIZE)
+					{
+						/* Get a new block if it is the first time, From the
+						 * subsequent time, reset the index and re-use the same
+						 * block.
+						 */
+						if (bIsFirst)
+						{
+							ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+							uint32 block_pos = WaitGetFreeCopyBlock(pcshared_info);
+							cstate->raw_buf = pcshared_info->data_blocks[block_pos].data;
+							bIsFirst = false;
+						}
+
+						cstate->raw_buf_index = cstate->raw_buf_len = 0;
+					}
+				}
+
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
@@ -4870,6 +5660,11 @@ CopyReadLineText(CopyState cstate)
 	char		quotec = '\0';
 	char		escapec = '\0';
 
+	/* For parallel copy */
+	uint32			 line_size = 0;
+	int				 line_pos = 0;
+
+	cstate->eol_type = EOL_UNKNOWN;
 	if (cstate->csv_mode)
 	{
 		quotec = cstate->quote[0];
@@ -4924,6 +5719,8 @@ CopyReadLineText(CopyState cstate)
 		if (raw_buf_ptr >= copy_buf_len || need_data)
 		{
 			REFILL_LINEBUF;
+			SetRawBufForLoad(cstate, line_size, copy_buf_len, raw_buf_ptr,
+							 &copy_raw_buf);
 
 			/*
 			 * Try to read some more data.  This will certainly reset
@@ -5148,9 +5945,15 @@ CopyReadLineText(CopyState cstate)
 				 * discard the data and the \. sequence.
 				 */
 				if (prev_raw_ptr > cstate->raw_buf_index)
-					appendBinaryStringInfo(&cstate->line_buf,
+				{
+					if (!IsParallelCopy())
+						appendBinaryStringInfo(&cstate->line_buf,
 										   cstate->raw_buf + cstate->raw_buf_index,
 										   prev_raw_ptr - cstate->raw_buf_index);
+					else
+						line_size += prev_raw_ptr - cstate->raw_buf_index;
+				}
+
 				cstate->raw_buf_index = raw_buf_ptr;
 				result = true;	/* report EOF */
 				break;
@@ -5202,6 +6005,26 @@ not_end_of_copy:
 			IF_NEED_REFILL_AND_EOF_BREAK(mblen - 1);
 			raw_buf_ptr += mblen - 1;
 		}
+
+		/*
+		 * Skip the header line. Update the line here, this cannot be done at
+		 * the beginning, as there is a possibility that file contains empty
+		 * lines.
+		 */
+		if (IsParallelCopy() && first_char_in_line && !IsHeaderLine())
+		{
+			ParallelCopyShmInfo	*pcshared_info = cstate->pcdata->pcshared_info;
+			ParallelCopyLineBoundary *lineInfo;
+			uint32			 line_first_block = pcshared_info->cur_block_pos;
+			line_pos = UpdateBlockInLineInfo(cstate,
+											   line_first_block,
+											   cstate->raw_buf_index, -1,
+											   LINE_LEADER_POPULATING);
+			lineInfo = &pcshared_info->line_boundaries.ring[line_pos];
+			elog(DEBUG1, "[Leader] Adding - block:%d, offset:%d, line position:%d",
+						 line_first_block,	lineInfo->start_offset, line_pos);
+		}
+
 		first_char_in_line = false;
 	}							/* end of outer loop */
 
@@ -5210,6 +6033,7 @@ not_end_of_copy:
 	 */
 	REFILL_LINEBUF;
 	CLEAR_EOL_LINE()
+	EndLineParallelCopy(cstate, line_pos, line_size, raw_buf_ptr);
 
 	return result;
 }
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index db191879b9..20dafb75ba 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -381,6 +381,8 @@ extern FullTransactionId GetTopFullTransactionId(void);
 extern FullTransactionId GetTopFullTransactionIdIfAny(void);
 extern FullTransactionId GetCurrentFullTransactionId(void);
 extern FullTransactionId GetCurrentFullTransactionIdIfAny(void);
+extern void AssignFullTransactionIdForWorker(FullTransactionId fullTransactionId);
+extern void AssignCommandIdForWorker(CommandId commandId, bool used);
 extern void MarkCurrentTransactionIdLoggedIfAny(void);
 extern bool SubTransactionIsActive(SubTransactionId subxid);
 extern CommandId GetCurrentCommandId(bool used);
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 6a42ac425a..86a76208b7 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1701,6 +1701,7 @@ ParallelCompletionPtr
 ParallelContext
 ParallelCopyLineBoundaries
 ParallelCopyLineBoundary
+ParallelCopyLineState
 ParallelCopyCommonKeyData
 ParallelCopyData
 ParallelCopyDataBlock
-- 
2.25.1

0004-Documentation-for-parallel-copy.patchapplication/octet-stream; name=0004-Documentation-for-parallel-copy.patchDownload
From d04485ce9e4768cbab3f2722dadcf032586fda33 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 17 Jun 2020 07:34:56 +0530
Subject: [PATCH 4/6] Documentation for parallel copy.

This patch has the documentation changes for parallel copy.
---
 doc/src/sgml/ref/copy.sgml | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/doc/src/sgml/ref/copy.sgml b/doc/src/sgml/ref/copy.sgml
index 18189ab..95d349d 100644
--- a/doc/src/sgml/ref/copy.sgml
+++ b/doc/src/sgml/ref/copy.sgml
@@ -37,6 +37,7 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
     DELIMITER '<replaceable class="parameter">delimiter_character</replaceable>'
     NULL '<replaceable class="parameter">null_string</replaceable>'
     HEADER [ <replaceable class="parameter">boolean</replaceable> ]
+    PARALLEL <replaceable class="parameter">integer</replaceable>
     QUOTE '<replaceable class="parameter">quote_character</replaceable>'
     ESCAPE '<replaceable class="parameter">escape_character</replaceable>'
     FORCE_QUOTE { ( <replaceable class="parameter">column_name</replaceable> [, ...] ) | * }
@@ -275,6 +276,21 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
    </varlistentry>
 
    <varlistentry>
+    <term><literal>PARALLEL</literal></term>
+    <listitem>
+     <para>
+      Perform <command>COPY FROM</command> in parallel using <replaceable
+      class="parameter"> integer</replaceable> background workers.  Please
+      note that it is not guaranteed that the number of parallel workers
+      specified in <replaceable class="parameter">integer</replaceable> will
+      be used during execution.  It is possible for a copy to run with fewer
+      workers than specified, or even with no workers at all.  This option is
+      allowed only in <command>COPY FROM</command>.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><literal>QUOTE</literal></term>
     <listitem>
      <para>
-- 
1.8.3.1

0005-Tests-for-parallel-copy.patchapplication/octet-stream; name=0005-Tests-for-parallel-copy.patchDownload
From cd57bede56d817a95ae251ab4b3c543c73bcf9a8 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 17 Jun 2020 07:37:26 +0530
Subject: [PATCH 5/6] Tests for parallel copy.

This patch has the tests for parallel copy.
---
 src/test/regress/expected/copy2.out | 210 +++++++++++++++++++++++++++++++++++-
 src/test/regress/input/copy.source  |  12 +++
 src/test/regress/output/copy.source |  12 +++
 src/test/regress/sql/copy2.sql      | 208 ++++++++++++++++++++++++++++++++++-
 4 files changed, 434 insertions(+), 8 deletions(-)

diff --git a/src/test/regress/expected/copy2.out b/src/test/regress/expected/copy2.out
index e40287d..ef75148 100644
--- a/src/test/regress/expected/copy2.out
+++ b/src/test/regress/expected/copy2.out
@@ -254,18 +254,32 @@ It is "perfect".|
 "It is ""perfect"".","	"
 "",
 --test that we read consecutive LFs properly
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 COPY testnl FROM stdin CSV;
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+SELECT * FROM testnl;
+ a |          b           | c 
+---+----------------------+---
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+(2 rows)
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 COPY testeoc FROM stdin CSV;
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
 COPY testeoc TO stdout CSV;
 a\.
 \.b
 c\.d
 "\."
 -- test handling of nonstandard null marker that violates escaping rules
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 COPY testnull TO stdout WITH NULL AS E'\\0';
 1	\\0
@@ -280,6 +294,15 @@ SELECT * FROM testnull;
     | 
 (4 rows)
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 1);
+SELECT * FROM testnull;
+ a  | b  
+----+----
+ 42 | \0
+    | 
+(2 rows)
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -349,6 +372,34 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+SELECT * FROM vistest;
+ a  
+----
+ a2
+ b
+(2 rows)
+
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+COMMIT;
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 SELECT * FROM vistest;
  a 
@@ -409,7 +460,7 @@ SELECT * FROM vistest;
 (2 rows)
 
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -420,6 +471,8 @@ CREATE TEMP TABLE forcetest (
 -- should succeed with no effect ("b" remains an empty string, "c" remains NULL)
 BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 1);
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
  b |  c   
@@ -430,6 +483,8 @@ SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
 BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 1);
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
  c |  d   
@@ -486,6 +541,31 @@ select * from check_con_tbl;
    
 (2 rows)
 
+\d+ check_con_tbl
+                               Table "public.check_con_tbl"
+ Column |  Type   | Collation | Nullable | Default | Storage | Stats target | Description 
+--------+---------+-----------+----------+---------+---------+--------------+-------------
+ f1     | integer |           |          |         | plain   |              | 
+Check constraints:
+    "check_con_tbl_check" CHECK (check_con_function(check_con_tbl.*))
+
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 1);
+NOTICE:  input = {"f1":1}
+NOTICE:  input = {"f1":null}
+copy check_con_tbl from stdin with (parallel 1);
+NOTICE:  input = {"f1":0}
+ERROR:  new row for relation "check_con_tbl" violates check constraint "check_con_tbl_check"
+DETAIL:  Failing row contains (0).
+CONTEXT:  COPY check_con_tbl, line 1: "0"
+parallel worker
+select * from check_con_tbl;
+ f1 
+----
+  1
+   
+(2 rows)
+
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
 CREATE ROLE regress_rls_copy_user_colperms;
@@ -600,8 +680,130 @@ SELECT * FROM instead_of_insert_tbl;
 (2 rows)
 
 COMMIT;
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+COPY test_parallel_copy (a, b, c, d, e) from stdin with (PARALLEL 1);
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1, FORMAT 'csv', HEADER);
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0');
+ERROR:  argument to option "parallel" must be a positive integer greater than zero
+LINE 1: COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0'...
+                                                        ^
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri from stdin with (FORMAT csv, DELIMITER ',', PARALLEL 1);
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1) WHERE height > random() * 65;
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- temporary table copy: should peform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+COPY temp_test (a) from stdin with (PARALLEL 1);
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) from stdin with (PARALLEL 1);
+ERROR:  column "xyz" of relation "test_parallel_copy" does not exist
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) from stdin with (PARALLEL 1);
+ERROR:  column "d" specified more than once
+-- missing data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  invalid input syntax for type integer: ""
+CONTEXT:  COPY test_parallel_copy, line 0, column a: ""
+parallel worker
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2000	230	23	23"
+parallel worker
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2001	231	\N	\N"
+parallel worker
+-- extra data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  extra data after last expected column
+CONTEXT:  COPY test_parallel_copy, line 1: "2002	232	40	50	60	70	80"
+parallel worker
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) from stdin with (delimiter ',', null 'x', PARALLEL 1) ;
+COPY test_parallel_copy from stdin WITH (DELIMITER ';', NULL '', PARALLEL 1);
+COPY test_parallel_copy from stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL 1);
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = 50004;
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a > 60003;
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE f > 60003;
+ERROR:  column "f" does not exist
+LINE 1: ..._parallel_copy from stdin WITH (PARALLEL 1) WHERE f > 60003;
+                                                             ^
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+ERROR:  missing FROM-clause entry for table "x"
+LINE 1: ...rallel_copy from stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+                                                                  ^
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (SELECT 1 FROM x);
+ERROR:  cannot use subquery in COPY FROM WHERE condition
+LINE 1: ...arallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (SELECT...
+                                                             ^
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (generate_series(1,5));
+ERROR:  set-returning functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...lel_copy from stdin WITH (PARALLEL 1) WHERE a IN (generate_s...
+                                                             ^
+COPY test_parallel_copy from stdin WITH(PARALLEL 1) WHERE a = row_number() over(b);
+ERROR:  window functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...rallel_copy from stdin WITH(PARALLEL 1) WHERE a = row_number...
+                                                             ^
+-- check results of copy in
+SELECT * FROM test_parallel_copy;
+   a   | b  |     c      |    d    |    e    
+-------+----+------------+---------+---------
+     1 | 11 | test_c1    | test_d1 | test_e1
+     2 | 12 | test_c2    | test_d2 | test_e2
+       |  3 | stuff      | test_d3 | 
+       |  4 | stuff      | test_d4 | 
+       |  5 | stuff      | test_d5 | 
+       |    | 45         | 80      | 90
+       |    | x          | \x      | \x
+       |    | ,          | \,      | \
+  3000 |    | c          |         | 
+  4000 |    | C          |         | 
+  4001 |  1 | empty      |         | 
+  4002 |  2 | null       |         | 
+  4003 |  3 | Backslash  | \       | \
+  4004 |  4 | BackslashX | \X      | \X
+  4005 |  5 | N          | N       | N
+  4006 |  6 | BackslashN | \N      | \N
+  4007 |  7 | XX         | XX      | XX
+  4008 |  8 | Delimiter  | :       | :
+ 50004 | 25 | 35         | 45      | 55
+ 60004 | 25 | 35         | 45      | 55
+ 60005 | 26 | 36         | 46      | 56
+(21 rows)
+
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
 DROP TABLE x, y;
diff --git a/src/test/regress/input/copy.source b/src/test/regress/input/copy.source
index a1d529a..159c058 100644
--- a/src/test/regress/input/copy.source
+++ b/src/test/regress/input/copy.source
@@ -15,6 +15,13 @@ DELETE FROM onek;
 
 COPY onek FROM '@abs_builddir@/results/onek.data';
 
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+
+SELECT COUNT(*) FROM tenk1;
+
+TRUNCATE tenk1;
+
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
@@ -159,6 +166,11 @@ truncate parted_copytest;
 
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
 
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
+
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/output/copy.source b/src/test/regress/output/copy.source
index 938d355..c3003fe 100644
--- a/src/test/regress/output/copy.source
+++ b/src/test/regress/output/copy.source
@@ -9,6 +9,15 @@ COPY onek FROM '@abs_srcdir@/data/onek.data';
 COPY onek TO '@abs_builddir@/results/onek.data';
 DELETE FROM onek;
 COPY onek FROM '@abs_builddir@/results/onek.data';
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+SELECT COUNT(*) FROM tenk1;
+ count 
+-------
+ 10000
+(1 row)
+
+TRUNCATE tenk1;
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
 COPY person FROM '@abs_srcdir@/data/person.data';
@@ -113,6 +122,9 @@ insert into parted_copytest select x,1,'One' from generate_series(1011,1020) x;
 copy (select * from parted_copytest order by a) to '@abs_builddir@/results/parted_copytest.csv';
 truncate parted_copytest;
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/sql/copy2.sql b/src/test/regress/sql/copy2.sql
index 902f4fa..032cea9 100644
--- a/src/test/regress/sql/copy2.sql
+++ b/src/test/regress/sql/copy2.sql
@@ -157,7 +157,7 @@ COPY y TO stdout (FORMAT CSV, FORCE_QUOTE *);
 
 --test that we read consecutive LFs properly
 
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 
 COPY testnl FROM stdin CSV;
 1,"a field with two LFs
@@ -165,8 +165,16 @@ COPY testnl FROM stdin CSV;
 inside",2
 \.
 
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+1,"a field with two LFs
+
+inside",2
+\.
+
+SELECT * FROM testnl;
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 
 COPY testeoc FROM stdin CSV;
 a\.
@@ -175,11 +183,19 @@ c\.d
 "\."
 \.
 
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+a\.
+\.b
+c\.d
+"\."
+\.
+
 COPY testeoc TO stdout CSV;
 
 -- test handling of nonstandard null marker that violates escaping rules
 
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 
 COPY testnull TO stdout WITH NULL AS E'\\0';
@@ -191,6 +207,14 @@ COPY testnull FROM stdin WITH NULL AS E'\\0';
 
 SELECT * FROM testnull;
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 1);
+42	\\0
+\0	\0
+\.
+
+SELECT * FROM testnull;
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -235,6 +259,23 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+a2
+b
+\.
+SELECT * FROM vistest;
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+d2
+e
+\.
+SELECT * FROM vistest;
+COMMIT;
+SELECT * FROM vistest;
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 x
 y
@@ -284,7 +325,7 @@ SELECT * FROM vistest;
 COMMIT;
 SELECT * FROM vistest;
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -297,6 +338,10 @@ BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
 1,,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 1);
+1,,""
+\.
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
@@ -304,6 +349,10 @@ BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
 2,'a',,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 1);
+2,'a',,""
+\.
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
 -- should fail with not-null constraint violation
@@ -339,6 +388,16 @@ copy check_con_tbl from stdin;
 0
 \.
 select * from check_con_tbl;
+\d+ check_con_tbl
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 1);
+1
+\N
+\.
+copy check_con_tbl from stdin with (parallel 1);
+0
+\.
+select * from check_con_tbl;
 
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
@@ -440,8 +499,149 @@ test1
 SELECT * FROM instead_of_insert_tbl;
 COMMIT;
 
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+
+COPY test_parallel_copy (a, b, c, d, e) from stdin with (PARALLEL 1);
+1	11	test_c1	test_d1	test_e1
+2	12	test_c2	test_d2	test_e2
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+3	test_d3
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+4	test_d4
+5	test_d5
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1, FORMAT 'csv', HEADER);
+b	d
+\.
+
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0');
+
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri from stdin with (FORMAT csv, DELIMITER ',', PARALLEL 1);
+10
+\.
+
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1) WHERE height > random() * 65;
+60,60,60
+\.
+
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+60
+\.
+
+-- temporary table copy: should peform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+
+COPY temp_test (a) from stdin with (PARALLEL 1);
+10
+\.
+
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) from stdin with (PARALLEL 1);
+
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) from stdin with (PARALLEL 1);
+
+-- missing data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+
+\.
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+2000	230	23	23
+\.
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+2001	231	\N	\N
+\.
+
+-- extra data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+2002	232	40	50	60	70	80
+\.
+
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) from stdin with (delimiter ',', null 'x', PARALLEL 1) ;
+x,45,80,90
+x,\x,\\x,\\\x
+x,\,,\\\,,\\
+\.
+
+COPY test_parallel_copy from stdin WITH (DELIMITER ';', NULL '', PARALLEL 1);
+3000;;c;;
+\.
+
+COPY test_parallel_copy from stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL 1);
+4000:\X:C:\X:\X
+4001:1:empty::
+4002:2:null:\X:\X
+4003:3:Backslash:\\:\\
+4004:4:BackslashX:\\X:\\X
+4005:5:N:\N:\N
+4006:6:BackslashN:\\N:\\N
+4007:7:XX:\XX:\XX
+4008:8:Delimiter:\::\:
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = 50004;
+50003	24	34	44	54
+50004	25	35	45 	55
+50005	26	36	46	56
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a > 60003;
+60001	22	32	42	52
+60002	23	33	43	53
+60003	24	34	44	54
+60004	25	35	45	55
+60005	26	36	46	56
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE f > 60003;
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (SELECT 1 FROM x);
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (generate_series(1,5));
+
+COPY test_parallel_copy from stdin WITH(PARALLEL 1) WHERE a = row_number() over(b);
+
+-- check results of copy in
+SELECT * FROM test_parallel_copy;
+
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
 DROP TABLE x, y;
-- 
1.8.3.1

0006-Parallel-Copy-For-Binary-Format-Files.patchapplication/octet-stream; name=0006-Parallel-Copy-For-Binary-Format-Files.patchDownload
From dbcf9dcfc87d8e5eed4d56b2a079a64258c591c6 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddy@enterprisedb.com>
Date: Sat, 11 Jul 2020 11:39:50 +0530
Subject: [PATCH v10] Parallel Copy For Binary Format Files

Leader reads data from the file into the DSM data blocks each of 64K size.
It also identifies each tuple data block id, start offset, end offset,
tuple size and updates this information in the ring data structure.
Workers parallely read the tuple information from the ring data structure,
the actual tuple data from the data blocks and parallely insert the tuples
into the table.
---
 src/backend/commands/copy.c | 655 +++++++++++++++++++++++++++++++-----
 1 file changed, 574 insertions(+), 81 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 048f2d2cb6..a4e4163c32 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -219,6 +219,17 @@ typedef struct ParallelCopyLineBuf
 	uint64				cur_lineno;	/* line number for error messages */
 }ParallelCopyLineBuf;
 
+/*
+ * Represents the usage mode for CopyReadBinaryGetDataBlock.
+ */
+typedef enum FieldInfoType
+{
+	FIELD_NONE = 0,
+	FIELD_COUNT,
+	FIELD_SIZE,
+	FIELD_DATA
+} FieldInfoType;
+
 /*
  * Parallel copy data information.
  */
@@ -240,6 +251,9 @@ typedef struct ParallelCopyData
 
 	/* Current position in worker_line_buf */
 	uint32				worker_line_buf_pos;
+
+	/* For binary formatted files */
+	ParallelCopyDataBlock *curr_data_block;
 }ParallelCopyData;
 
 /*
@@ -397,6 +411,7 @@ typedef struct ParallelCopyCommonKeyData
 	/* Working state for COPY FROM */
 	AttrNumber          num_defaults;
 	Oid                 relid;
+	bool 				binary;
 }ParallelCopyCommonKeyData;
 
 /*
@@ -502,7 +517,6 @@ typedef struct CopyMultiInsertInfo
 	int			ti_options;		/* table insert options */
 } CopyMultiInsertInfo;
 
-
 /*
  * These macros centralize code used to process line_buf and raw_buf buffers.
  * They are macros because they often do continue/break control and to avoid
@@ -697,8 +711,110 @@ if (!IsParallelCopy()) \
 else \
 	return pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
 
-static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
+/*
+ * CHECK_FIELD_COUNT - Handles the error cases for field count
+ * for binary format files.
+ */
+#define CHECK_FIELD_COUNT \
+{\
+	if (fld_count == -1) \
+	{ \
+		if (IsParallelCopy() && \
+			!IsLeader()) \
+			return true; \
+		else if (IsParallelCopy() && \
+			IsLeader()) \
+		{ \
+			if (cstate->pcdata->curr_data_block->data[cstate->raw_buf_index + sizeof(fld_count)] != 0) \
+				ereport(ERROR, \
+						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+						errmsg("received copy data after EOF marker"))); \
+			return true; \
+		} \
+		else \
+		{ \
+			/* \
+			* Received EOF marker.  In a V3-protocol copy, wait for the \
+			* protocol-level EOF, and complain if it doesn't come \
+			* immediately.  This ensures that we correctly handle CopyFail, \
+			* if client chooses to send that now. \
+			* \
+			* Note that we MUST NOT try to read more data in an old-protocol \
+			* copy, since there is no protocol-level EOF marker then.  We \
+			* could go either way for copy from file, but choose to throw \
+			* error if there's data after the EOF marker, for consistency \
+			* with the new-protocol case. \
+			*/ \
+			char		dummy; \
+			if (cstate->copy_dest != COPY_OLD_FE && \
+				CopyGetData(cstate, &dummy, 1, 1) > 0) \
+				ereport(ERROR, \
+						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+						errmsg("received copy data after EOF marker"))); \
+				return false; \
+		} \
+	} \
+	if (fld_count != cstate->max_fields) \
+		ereport(ERROR, \
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+				errmsg("row field count is %d, expected %d", \
+				(int) fld_count, cstate->max_fields))); \
+}
+
+/*
+ * CHECK_FIELD_SIZE - Handles the error case for field size
+ * for binary format files.
+ */
+#define CHECK_FIELD_SIZE(fld_size) \
+{ \
+	if (fld_size < -1) \
+		ereport(ERROR, \
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+				errmsg("invalid field size")));\
+}
+
+/*
+ * EOF_ERROR - Error statement for EOF for binary format
+ * files.
+ */
+#define EOF_ERROR \
+{ \
+	ereport(ERROR, \
+		(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+		errmsg("unexpected EOF in COPY data")));\
+}
+
+/*
+ * GET_RAW_BUF_INDEX - Caclulates the raw buf index for the cases
+ * where the data spread is across multiple data blocks.
+ */
+#define GET_RAW_BUF_INDEX(raw_buf_index, fld_size, required_blks, curr_blk_bytes) \
+{ \
+	raw_buf_index = fld_size - (((required_blks - 1) * DATA_BLOCK_SIZE) + curr_blk_bytes); \
+}
+
+/*
+ * GET_REQUIRED_BLOCKS - Caclulates the number of data
+ * blocks required for the cases where the data spread
+ * is across multiple data blocks.
+ */
+#define GET_REQUIRED_BLOCKS(required_blks, fld_size, curr_blk_bytes) \
+{ \
+	/* \
+	 * field size can spread across multiple data blocks, \
+	 * calculate the number of required data blocks and try to get \
+	 * those many data blocks. \
+	 */ \
+	required_blks = (int32)(fld_size - curr_blk_bytes)/(int32)DATA_BLOCK_SIZE; \
+	/* \
+	 * check if we need the data block for the field data \
+	 * bytes that are not modulus of data block size. \
+	 */ \
+	if ((fld_size - curr_blk_bytes)%DATA_BLOCK_SIZE != 0) \
+		required_blks++; \
+}
 
+static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
 /* non-export function prototypes */
 static CopyState BeginCopy(ParseState *pstate, bool is_from, Relation rel,
@@ -751,6 +867,13 @@ static void PopulateCatalogInformation(CopyState cstate);
 static pg_attribute_always_inline uint32 GetLinePosition(CopyState cstate);
 static pg_attribute_always_inline copy_data_source_cb LookupParallelCopyFnPtr(const char *funcname);
 static pg_attribute_always_inline char* LookupParallelCopyFnStr(copy_data_source_cb fn_addr);
+static uint32 WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info);
+static bool CopyReadBinaryTupleLeader(CopyState cstate);
+static void CopyReadBinaryFindTupleSize(CopyState cstate, uint32 *line_size);
+static bool CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls);
+static Datum CopyReadBinaryAttributeWorker(CopyState cstate, FmgrInfo *flinfo,
+										  Oid typioparam, int32 typmod, bool *isnull);
+static void CopyReadBinaryGetDataBlock(CopyState cstate, FieldInfoType field_info);
 
 /*
  * CopyCommonInfoForWorker - Copy shared_cstate using cstate information.
@@ -769,6 +892,7 @@ CopyCommonInfoForWorker(CopyState cstate, ParallelCopyCommonKeyData *shared_csta
 	shared_cstate->convert_selectively = cstate->convert_selectively;
 	shared_cstate->num_defaults = cstate->num_defaults;
 	shared_cstate->relid = cstate->pcdata->relid;
+	shared_cstate->binary = cstate->binary;
 }
 
 /*
@@ -997,8 +1121,8 @@ FindInsertMethod(CopyState cstate)
 static pg_attribute_always_inline bool
 IsParallelCopyAllowed(CopyState cstate)
 {
-	/* Parallel copy not allowed for frontend (2.0 protocol) & binary option. */
-	if ((cstate->copy_dest == COPY_OLD_FE) || cstate->binary)
+	/* Parallel copy not allowed for frontend (2.0 protocol). */
+	if (cstate->copy_dest == COPY_OLD_FE)
 		return false;
 
 	/* Check if copy is into foreign table or temporary table. */
@@ -1299,6 +1423,7 @@ ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
 	cstate->convert_selectively = shared_cstate->convert_selectively;
 	cstate->num_defaults = shared_cstate->num_defaults;
 	pcdata->relid = shared_cstate->relid;
+	cstate->binary = shared_cstate->binary;
 
 	PopulateGlobalsForCopyFrom(cstate, tup_desc, attnamelist);
 
@@ -1314,7 +1439,7 @@ ParallelWorkerInitialization(ParallelCopyCommonKeyData *shared_cstate,
 	initStringInfo(&cstate->attribute_buf);
 
 	initStringInfo(&cstate->line_buf);
-	for (count = 0; count < WORKER_CHUNK_COUNT;count++)
+	for (count = 0; count < WORKER_CHUNK_COUNT; count++)
 		initStringInfo(&pcdata->worker_line_buf[count].line_buf);
 
 	cstate->line_buf_converted = false;
@@ -1680,32 +1805,66 @@ ParallelCopyLeader(CopyState cstate)
 	/* Execute the before statement triggers from the leader */
 	ExecBeforeStmtTrigger(cstate);
 
-	/* On input just throw the header line away. */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (!cstate->binary)
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
+		/* On input just throw the header line away. */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
 		{
-			pcshared_info->is_read_in_progress = false;
-			return;			/* done */
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+			{
+				pcshared_info->is_read_in_progress = false;
+				return;			/* done */
+			}
 		}
-	}
 
-	for (;;)
-	{
-		bool done;
-		cstate->cur_lineno++;
+		for (;;)
+		{
+			bool done;
+			cstate->cur_lineno++;
 
-		/* Actually read the line into memory here. */
-		done = CopyReadLine(cstate);
+			/* Actually read the line into memory here. */
+			done = CopyReadLine(cstate);
 
+			/*
+			* EOF at start of line means we're done.  If we see EOF after some
+			* characters, we act as though it was newline followed by EOF, ie,
+			* process the line and then exit loop on next iteration.
+			*/
+			if (done && cstate->line_buf.len == 0)
+				break;
+		}
+	}
+	else
+	{
 		/*
-		 * EOF at start of line means we're done.  If we see EOF after some
-		 * characters, we act as though it was newline followed by EOF, ie,
-		 * process the line and then exit loop on next iteration.
+		 * Binary Format Files.
+		 * For parallel copy leader, fill in the error
+		 * context inforation here, in case any failures
+		 * while determining tuple offsets, leader
+		 * would throw the errors with proper context.
 		 */
-		if (done && cstate->line_buf.len == 0)
-			break;
+		ErrorContextCallback errcallback;
+		errcallback.callback = CopyFromErrorCallback;
+		errcallback.arg = (void *) cstate;
+		errcallback.previous = error_context_stack;
+		error_context_stack = &errcallback;
+		cstate->pcdata->curr_data_block = NULL;
+		cstate->raw_buf_index = 0;
+		pcshared_info->populated = 0;
+		cstate->cur_lineno = 0;
+		cstate->max_fields = list_length(cstate->attnumlist);
+
+		for (;;)
+		{
+			bool eof = false;
+			cstate->cur_lineno++;
+
+			eof = CopyReadBinaryTupleLeader(cstate);
+
+			if (eof)
+				break;
+		}
 	}
 
 	pcshared_info->is_read_in_progress = false;
@@ -1713,7 +1872,357 @@ ParallelCopyLeader(CopyState cstate)
 }
 
 /*
- * GetLinePosition - return the line position that worker should process.
+ * CopyReadBinaryGetDataBlock - gets a new block, updates
+ * the current offset, calculates the skip bytes.
+ */
+static void
+CopyReadBinaryGetDataBlock(CopyState cstate, FieldInfoType field_info)
+{
+	ParallelCopyDataBlock *data_block = NULL;
+	ParallelCopyDataBlock *curr_data_block = cstate->pcdata->curr_data_block;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	uint8 move_bytes = 0;
+	uint32 block_pos;
+	uint32 prev_block_pos;
+	int read_bytes = 0;
+
+	prev_block_pos = pcshared_info->cur_block_pos;
+
+	block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+	if (field_info == FIELD_SIZE || field_info == FIELD_COUNT)
+		move_bytes = (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+
+	if (curr_data_block != NULL)
+		curr_data_block->skip_bytes = move_bytes;
+
+	data_block = &pcshared_info->data_blocks[block_pos];
+
+	if (move_bytes > 0 && curr_data_block != NULL)
+		memmove(&data_block->data[0], &curr_data_block->data[cstate->raw_buf_index], move_bytes);
+
+	elog(DEBUG1, "LEADER - field info %d is spread across data blocks - moved %d bytes from current block %u to %u block",
+		field_info, move_bytes, prev_block_pos, block_pos);
+
+	read_bytes = CopyGetData(cstate, &data_block->data[move_bytes], 1, (DATA_BLOCK_SIZE - move_bytes));
+
+	if (field_info == FIELD_NONE && cstate->reached_eof)
+		return;
+
+	if (cstate->reached_eof)
+		EOF_ERROR;
+
+	elog(DEBUG1, "LEADER - bytes read from file %d", read_bytes);
+
+	if(field_info == FIELD_SIZE || field_info == FIELD_DATA)
+	{
+		ParallelCopyDataBlock *prev_data_block = NULL;
+		prev_data_block = curr_data_block;
+		prev_data_block->following_block = block_pos;
+
+		if (prev_data_block->curr_blk_completed  == false)
+			prev_data_block->curr_blk_completed = true;
+
+		pg_atomic_add_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+	}
+
+	cstate->pcdata->curr_data_block = data_block;
+	cstate->raw_buf_index = 0;
+}
+
+/*
+ * CopyReadBinaryTupleLeader - leader reads data from binary formatted file
+ * to data blocks and identies tuple boundaries/offsets so that workers
+ * can work on the data blocks data.
+ */
+static bool
+CopyReadBinaryTupleLeader(CopyState cstate)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	int16		fld_count;
+	uint32      line_size = 0;
+	uint32 		start_block_pos;
+	uint32		start_offset;
+
+	if (cstate->pcdata->curr_data_block == NULL)
+	{
+		CopyReadBinaryGetDataBlock(cstate, FIELD_NONE);
+
+		/*
+		 * no data is read from file here. one possibility
+		 * to be here could be that the binary file just
+		 * has a valid signature but nothing else.
+		 */
+		if (cstate->reached_eof)
+			return true;
+	}
+
+	if ((cstate->raw_buf_index + sizeof(fld_count)) >= DATA_BLOCK_SIZE)
+		CopyReadBinaryGetDataBlock(cstate, FIELD_COUNT);
+
+	memcpy(&fld_count, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_count));
+	fld_count = (int16) pg_ntoh16(fld_count);
+	CHECK_FIELD_COUNT;
+	start_offset = cstate->raw_buf_index;
+	cstate->raw_buf_index += sizeof(fld_count);
+	line_size += sizeof(fld_count);
+	start_block_pos = pcshared_info->cur_block_pos;
+
+	CopyReadBinaryFindTupleSize(cstate, &line_size);
+
+	pg_atomic_add_fetch_u32(&cstate->pcdata->curr_data_block->unprocessed_line_parts, 1);
+
+	if (line_size > 0)
+	{
+		int line_pos = UpdateBlockInLineInfo(cstate,
+											start_block_pos,
+											start_offset,
+											line_size,
+											LINE_LEADER_POPULATED);
+
+		pcshared_info->populated++;
+		elog(DEBUG1, "LEADER - adding - block:%u, offset:%u, line size:%u line position:%d",
+				start_block_pos, start_offset, line_size, line_pos);
+	}
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryFindTupleSize - leader identifies boundaries/
+ * offsets for each attribute/column and finally results in the
+ * tuple/row size. It moves on to next data block if the attribute/
+ * column is spread across data blocks.
+ */
+static void
+CopyReadBinaryFindTupleSize(CopyState cstate, uint32 *line_size)
+{
+	int32		fld_size;
+	ListCell   *cur;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			att_num = lfirst_int(cur);
+		Form_pg_attribute att = TupleDescAttr(tup_desc, (att_num - 1));
+		cstate->cur_attname = NameStr(att->attname);
+		fld_size = 0;
+
+		if ((cstate->raw_buf_index + sizeof(fld_size)) >= DATA_BLOCK_SIZE)
+			CopyReadBinaryGetDataBlock(cstate, FIELD_SIZE);
+
+		memcpy(&fld_size, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_size));
+		cstate->raw_buf_index += sizeof(fld_size);
+		*line_size += sizeof(fld_size);
+		fld_size = (int32) pg_ntoh32(fld_size);
+
+		CHECK_FIELD_SIZE(fld_size);
+
+		*line_size += fld_size;
+
+		if ((DATA_BLOCK_SIZE - cstate->raw_buf_index) >= fld_size)
+		{
+			cstate->raw_buf_index += fld_size;
+			elog(DEBUG1, "LEADER - tuple lies in he same data block");
+		}
+		else
+		{
+			int32 required_blks = 0;
+			int32 curr_blk_bytes = (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+			int i = 0;
+
+			GET_REQUIRED_BLOCKS(required_blks, fld_size, curr_blk_bytes);
+
+			i = required_blks;
+
+			while(i > 0)
+			{
+				CopyReadBinaryGetDataBlock(cstate, FIELD_DATA);
+				i--;
+			}
+
+			GET_RAW_BUF_INDEX(cstate->raw_buf_index, fld_size, required_blks, curr_blk_bytes);
+
+			/*
+			 * raw_buf_index should never cross data block size,
+			 * as the required number of data blocks would have
+			 * been obtained in the above while loop.
+			 */
+			Assert(cstate->raw_buf_index <= DATA_BLOCK_SIZE);
+		}
+		cstate->cur_attname = NULL;
+	}
+}
+
+/*
+ * CopyReadBinaryTupleWorker - each worker reads data from data blocks after
+ * getting leader-identified tuple offsets from ring data structure.
+ */
+static bool
+CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls)
+{
+	uint32 		line_pos;
+	ParallelCopyLineBoundary *line_info;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	int16		fld_count;
+	ListCell   *cur;
+	FmgrInfo   *in_functions = cstate->in_functions;
+	Oid		   *typioparams = cstate->typioparams;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	line_pos = GetLinePosition(cstate);
+
+	if (line_pos == -1)
+		return true;
+
+	line_info = &pcshared_info->line_boundaries.ring[line_pos];
+	cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[line_info->first_block];
+	cstate->raw_buf_index = line_info->start_offset;
+
+#if 0
+	if (cstate->raw_buf_index + sizeof(fld_count) >= DATA_BLOCK_SIZE)
+	{
+		/*
+		 * The case where field count spread across datablocks should never occur,
+		 * as the leader would have moved it to next block. enable this if block
+		 * for debugging purposes only.
+		 */
+		elog(DEBUG1, "WORKER - field count spread across datablocks should never occur");
+	}
+#endif
+
+	memcpy(&fld_count, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_count));
+	fld_count = (int16) pg_ntoh16(fld_count);
+
+	CHECK_FIELD_COUNT;
+
+	cstate->raw_buf_index += sizeof(fld_count);
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			att_num = lfirst_int(cur);
+		int			m = att_num - 1;
+		Form_pg_attribute att = TupleDescAttr(tup_desc, m);
+		cstate->cur_attname = NameStr(att->attname);
+
+		values[m] = CopyReadBinaryAttributeWorker(cstate,
+											&in_functions[m],
+											typioparams[m],
+											att->atttypmod,
+											&nulls[m]);
+		cstate->cur_attname = NULL;
+	}
+
+	pg_atomic_sub_fetch_u32(&cstate->pcdata->curr_data_block->unprocessed_line_parts, 1);
+	line_info->start_offset = -1;
+	pg_atomic_write_u32(&line_info->line_state, LINE_WORKER_PROCESSED);
+	pg_atomic_write_u32(&line_info->line_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryAttributeWorker - leader identifies boundaries/offsets
+ * for each attribute/column, it moves on to next data block if the
+ * attribute/column is spread across data blocks.
+ */
+static Datum
+CopyReadBinaryAttributeWorker(CopyState cstate, FmgrInfo *flinfo,
+		Oid typioparam, int32 typmod, bool *isnull)
+{
+	int32		fld_size;
+	Datum		result;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+	if ((cstate->raw_buf_index + sizeof(fld_size)) >= DATA_BLOCK_SIZE)
+	{
+		ParallelCopyDataBlock *prev_data_block = cstate->pcdata->curr_data_block;
+		elog(DEBUG1, "WORKER - field size is spread across data blocks");
+		cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[prev_data_block->following_block];
+		pg_atomic_sub_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+		cstate->raw_buf_index = 0;
+	}
+
+	memcpy(&fld_size, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_size));
+	fld_size = (int32) pg_ntoh32(fld_size);
+
+	CHECK_FIELD_SIZE(fld_size);
+
+	cstate->raw_buf_index += sizeof(fld_size);
+
+	/* reset attribute_buf to empty, and load raw data in it */
+	resetStringInfo(&cstate->attribute_buf);
+
+	enlargeStringInfo(&cstate->attribute_buf, fld_size);
+
+	if ((DATA_BLOCK_SIZE - cstate->raw_buf_index) >= fld_size)
+	{
+		elog(DEBUG1, "WORKER - tuple lies in single data block");
+		memcpy(&cstate->attribute_buf.data[0],&cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], fld_size);
+		cstate->raw_buf_index += fld_size;
+	}
+	else
+	{
+		uint32 att_buf_idx = 0;
+		uint32 copy_bytes = 0;
+		int32 required_blks = 0;
+		int32 curr_blk_bytes = (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+		ParallelCopyDataBlock *prev_data_block = NULL;
+		int i = 0;
+
+		GET_REQUIRED_BLOCKS(required_blks, fld_size, curr_blk_bytes);
+
+		i = required_blks;
+		prev_data_block = cstate->pcdata->curr_data_block;
+		elog(DEBUG1, "WORKER - tuple is spread across data blocks");
+		memcpy(&cstate->attribute_buf.data[0], &prev_data_block->data[cstate->raw_buf_index],
+				curr_blk_bytes);
+		copy_bytes = curr_blk_bytes;
+		att_buf_idx = curr_blk_bytes;
+
+		while (i>0)
+		{
+			cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[prev_data_block->following_block];
+			pg_atomic_sub_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+			cstate->raw_buf_index = 0;
+			copy_bytes = fld_size - att_buf_idx;
+
+			/*
+			 * the bytes that are yet to be taken into att buff are more than
+			 * the entire data block size, but only take the data block size
+			 * elements.
+			 */
+			if (copy_bytes >= DATA_BLOCK_SIZE)
+				copy_bytes = DATA_BLOCK_SIZE;
+
+			memcpy(&cstate->attribute_buf.data[att_buf_idx],
+				&cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], copy_bytes);
+			att_buf_idx += copy_bytes;
+			i--;
+		}
+		GET_RAW_BUF_INDEX(cstate->raw_buf_index, fld_size, required_blks, curr_blk_bytes);
+	}
+
+	cstate->attribute_buf.len = fld_size;
+	cstate->attribute_buf.data[fld_size] = '\0';
+
+	/* Call the column type's binary input converter */
+	result = ReceiveFunctionCall(flinfo, &cstate->attribute_buf,
+								 typioparam, typmod);
+
+	/* Trouble if it didn't eat the whole buffer */
+	if (cstate->attribute_buf.cursor != cstate->attribute_buf.len)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+				 errmsg("incorrect binary data format")));
+
+	*isnull = false;
+	return result;
+}
+
+/*
+ * GetLinePosition - return the line position that worker should pcdata->process.
  */
 static uint32
 GetLinePosition(CopyState cstate)
@@ -1801,7 +2310,9 @@ GetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
 		{
 			dataBlkPtr->curr_blk_completed = false;
 			dataBlkPtr->skip_bytes = 0;
+			dataBlkPtr->following_block = -1;
 			pcshared_info->cur_block_pos = block_pos;
+			MemSet(&dataBlkPtr->data[0], 0, DATA_BLOCK_SIZE);
 			return block_pos;
 		}
 
@@ -5476,60 +5987,47 @@ NextCopyFrom(CopyState cstate, ExprContext *econtext,
 	else
 	{
 		/* binary */
-		int16		fld_count;
-		ListCell   *cur;
-
-		cstate->cur_lineno++;
-
-		if (!CopyGetInt16(cstate, &fld_count))
+		if (!IsParallelCopy())
 		{
-			/* EOF detected (end of file, or protocol-level EOF) */
-			return false;
-		}
+			int16		fld_count;
+			ListCell   *cur;
 
-		if (fld_count == -1)
-		{
-			/*
-			 * Received EOF marker.  In a V3-protocol copy, wait for the
-			 * protocol-level EOF, and complain if it doesn't come
-			 * immediately.  This ensures that we correctly handle CopyFail,
-			 * if client chooses to send that now.
-			 *
-			 * Note that we MUST NOT try to read more data in an old-protocol
-			 * copy, since there is no protocol-level EOF marker then.  We
-			 * could go either way for copy from file, but choose to throw
-			 * error if there's data after the EOF marker, for consistency
-			 * with the new-protocol case.
-			 */
-			char		dummy;
+			cstate->cur_lineno++;
+			cstate->max_fields = list_length(cstate->attnumlist);
 
-			if (cstate->copy_dest != COPY_OLD_FE &&
-				CopyGetData(cstate, &dummy, 1, 1) > 0)
-				ereport(ERROR,
-						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-						 errmsg("received copy data after EOF marker")));
-			return false;
-		}
+			if (!CopyGetInt16(cstate, &fld_count))
+			{
+				/* EOF detected (end of file, or protocol-level EOF) */
+				return false;
+			}
 
-		if (fld_count != attr_count)
-			ereport(ERROR,
-					(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-					 errmsg("row field count is %d, expected %d",
-							(int) fld_count, attr_count)));
+			CHECK_FIELD_COUNT;
 
-		foreach(cur, cstate->attnumlist)
+			foreach(cur, cstate->attnumlist)
+			{
+				int			attnum = lfirst_int(cur);
+				int			m = attnum - 1;
+				Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+
+				cstate->cur_attname = NameStr(att->attname);
+				values[m] = CopyReadBinaryAttribute(cstate,
+													&in_functions[m],
+													typioparams[m],
+													att->atttypmod,
+													&nulls[m]);
+				cstate->cur_attname = NULL;
+			}
+		}
+		else
 		{
-			int			attnum = lfirst_int(cur);
-			int			m = attnum - 1;
-			Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+			bool eof = false;
+			cstate->cur_lineno++;
+			cstate->max_fields = list_length(cstate->attnumlist);
 
-			cstate->cur_attname = NameStr(att->attname);
-			values[m] = CopyReadBinaryAttribute(cstate,
-												&in_functions[m],
-												typioparams[m],
-												att->atttypmod,
-												&nulls[m]);
-			cstate->cur_attname = NULL;
+			eof = CopyReadBinaryTupleWorker(cstate, values, nulls);
+
+			if (eof)
+				return false;
 		}
 	}
 
@@ -6465,18 +6963,15 @@ CopyReadBinaryAttribute(CopyState cstate, FmgrInfo *flinfo,
 	Datum		result;
 
 	if (!CopyGetInt32(cstate, &fld_size))
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("unexpected EOF in COPY data")));
+		EOF_ERROR;
+
 	if (fld_size == -1)
 	{
 		*isnull = true;
 		return ReceiveFunctionCall(flinfo, NULL, typioparam, typmod);
 	}
-	if (fld_size < 0)
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("invalid field size")));
+
+	CHECK_FIELD_SIZE(fld_size);
 
 	/* reset attribute_buf to empty, and load raw data in it */
 	resetStringInfo(&cstate->attribute_buf);
@@ -6484,9 +6979,7 @@ CopyReadBinaryAttribute(CopyState cstate, FmgrInfo *flinfo,
 	enlargeStringInfo(&cstate->attribute_buf, fld_size);
 	if (CopyGetData(cstate, cstate->attribute_buf.data,
 					fld_size, fld_size) != fld_size)
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("unexpected EOF in COPY data")));
+		EOF_ERROR;
 
 	cstate->attribute_buf.len = fld_size;
 	cstate->attribute_buf.data[fld_size] = '\0';
-- 
2.25.1

#112Amit Kapila
amit.kapila16@gmail.com
In reply to: Bharath Rupireddy (#111)
Re: Parallel copy

On Sun, Jul 12, 2020 at 5:48 PM Bharath Rupireddy
<bharath.rupireddyforpostgres@gmail.com> wrote:

Hi Bharath,

I was looking forward to review this patch-set but unfortunately it is
showing a reject in copy.c, and might need a rebase.
I was applying on master over the commit-
cd22d3cdb9bd9963c694c01a8c0232bbae3ddcfb.

Thanks for showing interest. Please find the patch set rebased to
latest commit b1e48bbe64a411666bb1928b9741e112e267836d.

Few comments:
====================
0001-Copy-code-readjustment-to-support-parallel-copy

I am not sure converting the code to macros is a good idea, it makes
this code harder to read.  Also, there are a few changes which I am
not sure are necessary.
1.
+/*
+ * CLEAR_EOL_FROM_COPIED_DATA - Clear EOL from the copied data.
+ */
+#define CLEAR_EOL_FROM_COPIED_DATA(copy_line_data, copy_line_pos,
copy_line_size) \
+{ \
+ /* \
+ * If we didn't hit EOF, then we must have transferred the EOL marker \
+ * to line_buf along with the data.  Get rid of it. \
+ */ \
+   switch (cstate->eol_type) \
+   { \
+    case EOL_NL: \
+    Assert(copy_line_size >= 1); \
+    Assert(copy_line_data[copy_line_pos - 1] == '\n'); \
+    copy_line_data[copy_line_pos - 1] = '\0'; \
+    copy_line_size--; \
+    break; \
+    case EOL_CR: \
+    Assert(copy_line_size >= 1); \
+    Assert(copy_line_data[copy_line_pos - 1] == '\r'); \
+    copy_line_data[copy_line_pos - 1] = '\0'; \
+    copy_line_size--; \
+    break; \
+    case EOL_CRNL: \
+    Assert(copy_line_size >= 2); \
+    Assert(copy_line_data[copy_line_pos - 2] == '\r'); \
+    Assert(copy_line_data[copy_line_pos - 1] == '\n'); \
+    copy_line_data[copy_line_pos - 2] = '\0'; \
+    copy_line_size -= 2; \
+    break; \
+    case EOL_UNKNOWN: \
+    /* shouldn't get here */ \
+    Assert(false); \
+    break; \
+   } \
+}

In the original code, we are using only len and buffer, here we are
using position, length/size and buffer. Is it really required or can
we do with just len and buffer?

2.
+/*
+ * INCREMENTPROCESSED - Increment the lines processed.
+ */
+#define INCREMENTPROCESSED(processed)  \
+processed++;
+
+/*
+ * GETPROCESSED - Get the lines processed.
+ */
+#define GETPROCESSED(processed) \
+return processed;
+

I don't like converting above to macros. I don't think converting
such things to macros will buy us much.

0002-Framework-for-leader-worker-in-parallel-copy
3.
 /*
+ * Copy data block information.
+ */
+typedef struct ParallelCopyDataBlock

It is better to add a few comments atop this data structure to explain
how it is used?

4.
+ * ParallelCopyLineBoundary is common data structure between leader & worker,
+ * this is protected by the following sequence in the leader & worker.
+ * Leader should operate in the following order:
+ * 1) update first_block, start_offset & cur_lineno in any order.
+ * 2) update line_size.
+ * 3) update line_state.
+ * Worker should operate in the following order:
+ * 1) read line_size.
+ * 2) only one worker should choose one line for processing, this is handled by
+ *    using pg_atomic_compare_exchange_u32, worker will change the sate to
+ *    LINE_WORKER_PROCESSING only if line_state is LINE_LEADER_POPULATED.
+ * 3) read first_block, start_offset & cur_lineno in any order.
+ */
+typedef struct ParallelCopyLineBoundary

Here, you have mentioned how workers and leader should operate to make
sure access to the data is sane. However, you have not explained what
is the problem if they don't do so and it is not apparent to me.
Also, it is not very clear what is the purpose of this data structure
from comments.

5.
+/*
+ * Circular queue used to store the line information.
+ */
+typedef struct ParallelCopyLineBoundaries
+{
+ /* Position for the leader to populate a line. */
+ uint32 leader_pos;

I don't think the variable needs to be named as leader_pos, it is okay
to name it is as 'pos' as the comment above it explains its usage.

7.
+#define DATA_BLOCK_SIZE RAW_BUF_SIZE
+#define RINGSIZE (10 * 1000)
+#define MAX_BLOCKS_COUNT 1000
+#define WORKER_CHUNK_COUNT 50 /* should be mod of RINGSIZE */

It would be good if you can write a few comments to explain why you
have chosen these default values.

8.
ParallelCopyCommonKeyData, shall we name this as
SerializedParallelCopyState or something like that? For example, see
SerializedSnapshotData which has been used to pass snapshot
information to passed to workers.

9.
+CopyCommonInfoForWorker(CopyState cstate, ParallelCopyCommonKeyData
*shared_cstate)

If you agree with point-8, then let's name this as
SerializeParallelCopyState. See, if there is more usage of similar
types in the patch then lets change those as well.

10.
+ * in the DSM. The specified number of workers will then be launched.
+ *
+ */
+static ParallelContext*
+BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)

No need of an extra line with only '*' in the above multi-line comment.

11.
BeginParallelCopy(..)
{
..
+ EstimateLineKeysStr(pcxt, cstate->null_print);
+ EstimateLineKeysStr(pcxt, cstate->null_print_client);
+ EstimateLineKeysStr(pcxt, cstate->delim);
+ EstimateLineKeysStr(pcxt, cstate->quote);
+ EstimateLineKeysStr(pcxt, cstate->escape);
..
}

Why do we need to do this separately for each variable of cstate?
Can't we serialize it along with other members of
SerializeParallelCopyState (a new name for ParallelCopyCommonKeyData)?

12.
BeginParallelCopy(..)
{
..
+ LaunchParallelWorkers(pcxt);
+ if (pcxt->nworkers_launched == 0)
+ {
+ EndParallelCopy(pcxt);
+ elog(WARNING,
+ "No workers available, copy will be run in non-parallel mode");
..
}

I don't see the need to issue a WARNING if we are not able to launch
workers. We don't do that for other cases where we fail to launch
workers.

13.
+}
+/*
+ * ParallelCopyMain -
..
+}
+/*
+ * ParallelCopyLeader

One line space is required before starting a new function.

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#113vignesh C
vignesh21@gmail.com
In reply to: Amit Kapila (#112)
6 attachment(s)
Re: Parallel copy

Thanks for the comments Amit.
On Wed, Jul 15, 2020 at 10:34 AM Amit Kapila <amit.kapila16@gmail.com> wrote:

Few comments:
====================
0001-Copy-code-readjustment-to-support-parallel-copy

I am not sure converting the code to macros is a good idea, it makes
this code harder to read.  Also, there are a few changes which I am
not sure are necessary.
1.
+/*
+ * CLEAR_EOL_FROM_COPIED_DATA - Clear EOL from the copied data.
+ */
+#define CLEAR_EOL_FROM_COPIED_DATA(copy_line_data, copy_line_pos,
copy_line_size) \
+{ \
+ /* \
+ * If we didn't hit EOF, then we must have transferred the EOL marker \
+ * to line_buf along with the data.  Get rid of it. \
+ */ \
+   switch (cstate->eol_type) \
+   { \
+    case EOL_NL: \
+    Assert(copy_line_size >= 1); \
+    Assert(copy_line_data[copy_line_pos - 1] == '\n'); \
+    copy_line_data[copy_line_pos - 1] = '\0'; \
+    copy_line_size--; \
+    break; \
+    case EOL_CR: \
+    Assert(copy_line_size >= 1); \
+    Assert(copy_line_data[copy_line_pos - 1] == '\r'); \
+    copy_line_data[copy_line_pos - 1] = '\0'; \
+    copy_line_size--; \
+    break; \
+    case EOL_CRNL: \
+    Assert(copy_line_size >= 2); \
+    Assert(copy_line_data[copy_line_pos - 2] == '\r'); \
+    Assert(copy_line_data[copy_line_pos - 1] == '\n'); \
+    copy_line_data[copy_line_pos - 2] = '\0'; \
+    copy_line_size -= 2; \
+    break; \
+    case EOL_UNKNOWN: \
+    /* shouldn't get here */ \
+    Assert(false); \
+    break; \
+   } \
+}

In the original code, we are using only len and buffer, here we are
using position, length/size and buffer. Is it really required or can
we do with just len and buffer?

Position is required so that we can have common code for parallel &
non-parallel copy, in case of parallel copy position & length will
differ as they can spread across multiple data blocks. Retained the
variables as is.
Changed the macro to function.

2.
+/*
+ * INCREMENTPROCESSED - Increment the lines processed.
+ */
+#define INCREMENTPROCESSED(processed)  \
+processed++;
+
+/*
+ * GETPROCESSED - Get the lines processed.
+ */
+#define GETPROCESSED(processed) \
+return processed;
+

I don't like converting above to macros. I don't think converting
such things to macros will buy us much.

This macro will be extended to in
0003-Allow-copy-from-command-to-process-data-from-file.patch:
+#define INCREMENTPROCESSED(processed) \
+{ \
+       if (!IsParallelCopy()) \
+               processed++; \
+       else \
+
pg_atomic_add_fetch_u64(&cstate->pcdata->pcshared_info->processed, 1);
\
+}

This need to be made to macro so that it can handle both parallel copy
and non parallel copy.
Retaining this as macro, if you insist I can move the change to
0003-Allow-copy-from-command-to-process-data-from-file.patch patch.

0002-Framework-for-leader-worker-in-parallel-copy
3.
/*
+ * Copy data block information.
+ */
+typedef struct ParallelCopyDataBlock

It is better to add a few comments atop this data structure to explain
how it is used?

Fixed.

4.
+ * ParallelCopyLineBoundary is common data structure between leader & worker,
+ * this is protected by the following sequence in the leader & worker.
+ * Leader should operate in the following order:
+ * 1) update first_block, start_offset & cur_lineno in any order.
+ * 2) update line_size.
+ * 3) update line_state.
+ * Worker should operate in the following order:
+ * 1) read line_size.
+ * 2) only one worker should choose one line for processing, this is handled by
+ *    using pg_atomic_compare_exchange_u32, worker will change the sate to
+ *    LINE_WORKER_PROCESSING only if line_state is LINE_LEADER_POPULATED.
+ * 3) read first_block, start_offset & cur_lineno in any order.
+ */
+typedef struct ParallelCopyLineBoundary

Here, you have mentioned how workers and leader should operate to make
sure access to the data is sane. However, you have not explained what
is the problem if they don't do so and it is not apparent to me.
Also, it is not very clear what is the purpose of this data structure
from comments.

Fixed

5.
+/*
+ * Circular queue used to store the line information.
+ */
+typedef struct ParallelCopyLineBoundaries
+{
+ /* Position for the leader to populate a line. */
+ uint32 leader_pos;

I don't think the variable needs to be named as leader_pos, it is okay
to name it is as 'pos' as the comment above it explains its usage.

Fixed

7.
+#define DATA_BLOCK_SIZE RAW_BUF_SIZE
+#define RINGSIZE (10 * 1000)
+#define MAX_BLOCKS_COUNT 1000
+#define WORKER_CHUNK_COUNT 50 /* should be mod of RINGSIZE */

It would be good if you can write a few comments to explain why you
have chosen these default values.

Fixed

8.
ParallelCopyCommonKeyData, shall we name this as
SerializedParallelCopyState or something like that? For example, see
SerializedSnapshotData which has been used to pass snapshot
information to passed to workers.

Renamed as suggested

9.
+CopyCommonInfoForWorker(CopyState cstate, ParallelCopyCommonKeyData
*shared_cstate)

If you agree with point-8, then let's name this as
SerializeParallelCopyState. See, if there is more usage of similar
types in the patch then lets change those as well.

Fixed

10.
+ * in the DSM. The specified number of workers will then be launched.
+ *
+ */
+static ParallelContext*
+BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)

No need of an extra line with only '*' in the above multi-line comment.

Fixed

11.
BeginParallelCopy(..)
{
..
+ EstimateLineKeysStr(pcxt, cstate->null_print);
+ EstimateLineKeysStr(pcxt, cstate->null_print_client);
+ EstimateLineKeysStr(pcxt, cstate->delim);
+ EstimateLineKeysStr(pcxt, cstate->quote);
+ EstimateLineKeysStr(pcxt, cstate->escape);
..
}

Why do we need to do this separately for each variable of cstate?
Can't we serialize it along with other members of
SerializeParallelCopyState (a new name for ParallelCopyCommonKeyData)?

These are variable length string variables, I felt we will not be able
to serialize along with other members and need to be serialized
separately.

12.
BeginParallelCopy(..)
{
..
+ LaunchParallelWorkers(pcxt);
+ if (pcxt->nworkers_launched == 0)
+ {
+ EndParallelCopy(pcxt);
+ elog(WARNING,
+ "No workers available, copy will be run in non-parallel mode");
..
}

I don't see the need to issue a WARNING if we are not able to launch
workers. We don't do that for other cases where we fail to launch
workers.

Fixed

13.
+}
+/*
+ * ParallelCopyMain -
..
+}
+/*
+ * ParallelCopyLeader

One line space is required before starting a new function.

Fixed

Please find the updated patch with the fixes included.

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

Attachments:

0001-Copy-code-readjustment-to-support-parallel-copy.patchapplication/x-patch; name=0001-Copy-code-readjustment-to-support-parallel-copy.patchDownload
From e4d85e2d78c8496248e5fa08e144bd50a14c2173 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Thu, 16 Jul 2020 21:51:25 +0530
Subject: [PATCH 1/6] Copy code readjustment to support parallel copy.

This patch has the copy code slightly readjusted so that the common code is
separated to functions/macros, these functions/macros will be used by the
workers in the parallel copy code of the upcoming patches. EOL removal is moved
from CopyReadLine to CopyReadLineText, this change was required because in case
of parallel copy the record identification and record updation is done in
CopyReadLineText, before record information is updated in shared memory the new
line characters should be removed.
---
 src/backend/commands/copy.c | 361 ++++++++++++++++++++++++++------------------
 1 file changed, 218 insertions(+), 143 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 44da71c..09419ea 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -95,6 +95,9 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
+#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+#define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
+
 /*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
@@ -222,7 +225,6 @@ typedef struct CopyStateData
 	 * converts it.  Note: we guarantee that there is a \0 at
 	 * raw_buf[raw_buf_len].
 	 */
-#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
@@ -350,6 +352,27 @@ if (1) \
 	goto not_end_of_copy; \
 } else ((void) 0)
 
+/*
+ * CLEAR_EOL_LINE - Wrapper for clearing EOL.
+ */
+#define CLEAR_EOL_LINE() \
+if (!result && !IsHeaderLine()) \
+	ClearEOLFromCopiedData(cstate, cstate->line_buf.data, \
+						   cstate->line_buf.len, \
+						   &cstate->line_buf.len) \
+
+/*
+ * INCREMENTPROCESSED - Increment the lines processed.
+ */
+#define INCREMENTPROCESSED(processed)  \
+processed++;
+
+/*
+ * GETPROCESSED - Get the lines processed.
+ */
+#define GETPROCESSED(processed) \
+return processed;
+
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
 
@@ -395,7 +418,11 @@ static bool CopyGetInt32(CopyState cstate, int32 *val);
 static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 
-
+static void PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tup_desc,
+									   List *attnamelist);
+static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
+								   int copy_line_pos, int *copy_line_size);
+static void ConvertToServerEncoding(CopyState cstate);
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
  * in past protocol redesigns.
@@ -796,6 +823,7 @@ CopyLoadRawBuf(CopyState cstate)
 {
 	int			nbytes;
 	int			inbytes;
+	int         minread = 1;
 
 	if (cstate->raw_buf_index < cstate->raw_buf_len)
 	{
@@ -807,8 +835,11 @@ CopyLoadRawBuf(CopyState cstate)
 	else
 		nbytes = 0;				/* no data need be saved */
 
+	if (cstate->copy_dest == COPY_NEW_FE)
+		minread = RAW_BUF_SIZE - nbytes;
+
 	inbytes = CopyGetData(cstate, cstate->raw_buf + nbytes,
-						  1, RAW_BUF_SIZE - nbytes);
+						  minread, RAW_BUF_SIZE - nbytes);
 	nbytes += inbytes;
 	cstate->raw_buf[nbytes] = '\0';
 	cstate->raw_buf_index = 0;
@@ -1466,7 +1497,6 @@ BeginCopy(ParseState *pstate,
 {
 	CopyState	cstate;
 	TupleDesc	tupDesc;
-	int			num_phys_attrs;
 	MemoryContext oldcontext;
 
 	/* Allocate workspace and zero all fields */
@@ -1632,6 +1662,24 @@ BeginCopy(ParseState *pstate,
 		tupDesc = cstate->queryDesc->tupDesc;
 	}
 
+	PopulateGlobalsForCopyFrom(cstate, tupDesc, attnamelist);
+	cstate->copy_dest = COPY_FILE;	/* default */
+
+	MemoryContextSwitchTo(oldcontext);
+
+	return cstate;
+}
+
+/*
+ * PopulateGlobalsForCopyFrom - Populates the common variables required for copy
+ * from operation. This is a helper function for BeginCopy function.
+ */
+static void
+PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tupDesc,
+							List *attnamelist)
+{
+	int			num_phys_attrs;
+
 	/* Generate or convert list of attributes to process */
 	cstate->attnumlist = CopyGetAttnums(tupDesc, cstate->rel, attnamelist);
 
@@ -1751,12 +1799,6 @@ BeginCopy(ParseState *pstate,
 		 pg_database_encoding_max_length() > 1);
 	/* See Multibyte encoding comment above */
 	cstate->encoding_embeds_ascii = PG_ENCODING_IS_CLIENT_ONLY(cstate->file_encoding);
-
-	cstate->copy_dest = COPY_FILE;	/* default */
-
-	MemoryContextSwitchTo(oldcontext);
-
-	return cstate;
 }
 
 /*
@@ -2648,32 +2690,11 @@ CopyMultiInsertInfoStore(CopyMultiInsertInfo *miinfo, ResultRelInfo *rri,
 }
 
 /*
- * Copy FROM file to relation.
+ * Check if the relation specified in copy from is valid.
  */
-uint64
-CopyFrom(CopyState cstate)
+static void
+CheckTargetRelValidity(CopyState cstate)
 {
-	ResultRelInfo *resultRelInfo;
-	ResultRelInfo *target_resultRelInfo;
-	ResultRelInfo *prevResultRelInfo = NULL;
-	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
-	ModifyTableState *mtstate;
-	ExprContext *econtext;
-	TupleTableSlot *singleslot = NULL;
-	MemoryContext oldcontext = CurrentMemoryContext;
-
-	PartitionTupleRouting *proute = NULL;
-	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
-	int			ti_options = 0; /* start with default options for insert */
-	BulkInsertState bistate = NULL;
-	CopyInsertMethod insertMethod;
-	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
-	uint64		processed = 0;
-	bool		has_before_insert_row_trig;
-	bool		has_instead_insert_row_trig;
-	bool		leafpart_use_multi_insert = false;
-
 	Assert(cstate->rel);
 
 	/*
@@ -2710,27 +2731,6 @@ CopyFrom(CopyState cstate)
 							RelationGetRelationName(cstate->rel))));
 	}
 
-	/*
-	 * If the target file is new-in-transaction, we assume that checking FSM
-	 * for free space is a waste of time.  This could possibly be wrong, but
-	 * it's unlikely.
-	 */
-	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
-		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
-		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
-		ti_options |= TABLE_INSERT_SKIP_FSM;
-
-	/*
-	 * Optimize if new relfilenode was created in this subxact or one of its
-	 * committed children and we won't see those rows later as part of an
-	 * earlier scan or command. The subxact test ensures that if this subxact
-	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
-	 * that the stronger test of exactly which subtransaction created it is
-	 * crucial for correctness of this optimization. The test for an earlier
-	 * scan or command tolerates false negatives. FREEZE causes other sessions
-	 * to see rows they would not see under MVCC, and a false negative merely
-	 * spreads that anomaly to the current session.
-	 */
 	if (cstate->freeze)
 	{
 		/*
@@ -2768,9 +2768,61 @@ CopyFrom(CopyState cstate)
 			ereport(ERROR,
 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 					 errmsg("cannot perform COPY FREEZE because the table was not created or truncated in the current subtransaction")));
+	}
+}
+
+/*
+ * Copy FROM file to relation.
+ */
+uint64
+CopyFrom(CopyState cstate)
+{
+	ResultRelInfo *resultRelInfo;
+	ResultRelInfo *target_resultRelInfo;
+	ResultRelInfo *prevResultRelInfo = NULL;
+	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
+	ModifyTableState *mtstate;
+	ExprContext *econtext;
+	TupleTableSlot *singleslot = NULL;
+	MemoryContext oldcontext = CurrentMemoryContext;
 
+	PartitionTupleRouting *proute = NULL;
+	ErrorContextCallback errcallback;
+	CommandId	mycid = GetCurrentCommandId(true);
+	int			ti_options = 0; /* start with default options for insert */
+	BulkInsertState bistate = NULL;
+	CopyInsertMethod insertMethod;
+	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
+	uint64		processed = 0;
+	bool		has_before_insert_row_trig;
+	bool		has_instead_insert_row_trig;
+	bool		leafpart_use_multi_insert = false;
+
+	CheckTargetRelValidity(cstate);
+
+	/*
+	 * If the target file is new-in-transaction, we assume that checking FSM
+	 * for free space is a waste of time.  This could possibly be wrong, but
+	 * it's unlikely.
+	 */
+	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
+		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
+		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
+		ti_options |= TABLE_INSERT_SKIP_FSM;
+
+	/*
+	 * Optimize if new relfilenode was created in this subxact or one of its
+	 * committed children and we won't see those rows later as part of an
+	 * earlier scan or command. The subxact test ensures that if this subxact
+	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
+	 * that the stronger test of exactly which subtransaction created it is
+	 * crucial for correctness of this optimization. The test for an earlier
+	 * scan or command tolerates false negatives. FREEZE causes other sessions
+	 * to see rows they would not see under MVCC, and a false negative merely
+	 * spreads that anomaly to the current session.
+	 */
+	if (cstate->freeze)
 		ti_options |= TABLE_INSERT_FROZEN;
-	}
 
 	/*
 	 * We need a ResultRelInfo so we can use the regular executor's
@@ -3263,7 +3315,7 @@ CopyFrom(CopyState cstate)
 			 * or FDW; this is the same definition used by nodeModifyTable.c
 			 * for counting tuples inserted by an INSERT command.
 			 */
-			processed++;
+			INCREMENTPROCESSED(processed)
 		}
 	}
 
@@ -3318,30 +3370,15 @@ CopyFrom(CopyState cstate)
 
 	FreeExecutorState(estate);
 
-	return processed;
+	GETPROCESSED(processed)
 }
 
 /*
- * Setup to read tuples from a file for COPY FROM.
- *
- * 'rel': Used as a template for the tuples
- * 'filename': Name of server-local file to read
- * 'attnamelist': List of char *, columns to include. NIL selects all cols.
- * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
- *
- * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ * PopulateCatalogInformation - populate the catalog information.
  */
-CopyState
-BeginCopyFrom(ParseState *pstate,
-			  Relation rel,
-			  const char *filename,
-			  bool is_program,
-			  copy_data_source_cb data_source_cb,
-			  List *attnamelist,
-			  List *options)
+static void
+PopulateCatalogInformation(CopyState cstate)
 {
-	CopyState	cstate;
-	bool		pipe = (filename == NULL);
 	TupleDesc	tupDesc;
 	AttrNumber	num_phys_attrs,
 				num_defaults;
@@ -3351,38 +3388,8 @@ BeginCopyFrom(ParseState *pstate,
 	Oid			in_func_oid;
 	int		   *defmap;
 	ExprState **defexprs;
-	MemoryContext oldcontext;
 	bool		volatile_defexprs;
 
-	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
-	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
-
-	/* Initialize state variables */
-	cstate->reached_eof = false;
-	cstate->eol_type = EOL_UNKNOWN;
-	cstate->cur_relname = RelationGetRelationName(cstate->rel);
-	cstate->cur_lineno = 0;
-	cstate->cur_attname = NULL;
-	cstate->cur_attval = NULL;
-
-	/*
-	 * Set up variables to avoid per-attribute overhead.  attribute_buf is
-	 * used in both text and binary modes, but we use line_buf and raw_buf
-	 * only in text mode.
-	 */
-	initStringInfo(&cstate->attribute_buf);
-	if (!cstate->binary)
-	{
-		initStringInfo(&cstate->line_buf);
-		cstate->line_buf_converted = false;
-		cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
-		cstate->raw_buf_index = cstate->raw_buf_len = 0;
-	}
-
-	/* Assign range table, we'll need it in CopyFrom. */
-	if (pstate)
-		cstate->range_table = pstate->p_rtable;
-
 	tupDesc = RelationGetDescr(cstate->rel);
 	num_phys_attrs = tupDesc->natts;
 	num_defaults = 0;
@@ -3460,6 +3467,61 @@ BeginCopyFrom(ParseState *pstate,
 	cstate->defexprs = defexprs;
 	cstate->volatile_defexprs = volatile_defexprs;
 	cstate->num_defaults = num_defaults;
+}
+
+/*
+ * Setup to read tuples from a file for COPY FROM.
+ *
+ * 'rel': Used as a template for the tuples
+ * 'filename': Name of server-local file to read
+ * 'attnamelist': List of char *, columns to include. NIL selects all cols.
+ * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
+ *
+ * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ */
+CopyState
+BeginCopyFrom(ParseState *pstate,
+			  Relation rel,
+			  const char *filename,
+			  bool is_program,
+			  copy_data_source_cb data_source_cb,
+			  List *attnamelist,
+			  List *options)
+{
+	CopyState	cstate;
+	bool		pipe = (filename == NULL);
+	MemoryContext oldcontext;
+
+	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	/* Initialize state variables */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/*
+	 * Set up variables to avoid per-attribute overhead.  attribute_buf is
+	 * used in both text and binary modes, but we use line_buf and raw_buf
+	 * only in text mode.
+	 */
+	initStringInfo(&cstate->attribute_buf);
+	if (!cstate->binary)
+	{
+		initStringInfo(&cstate->line_buf);
+		cstate->line_buf_converted = false;
+		cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+		cstate->raw_buf_index = cstate->raw_buf_len = 0;
+	}
+
+	/* Assign range table, we'll need it in CopyFrom. */
+	if (pstate)
+		cstate->range_table = pstate->p_rtable;
+
+	PopulateCatalogInformation(cstate);
 	cstate->is_program = is_program;
 
 	if (data_source_cb)
@@ -3869,45 +3931,60 @@ CopyReadLine(CopyState cstate)
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
-	else
-	{
-		/*
-		 * If we didn't hit EOF, then we must have transferred the EOL marker
-		 * to line_buf along with the data.  Get rid of it.
-		 */
-		switch (cstate->eol_type)
-		{
-			case EOL_NL:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CR:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\r');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CRNL:
-				Assert(cstate->line_buf.len >= 2);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 2] == '\r');
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len -= 2;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_UNKNOWN:
-				/* shouldn't get here */
-				Assert(false);
-				break;
-		}
-	}
 
+	ConvertToServerEncoding(cstate);
+	return result;
+}
+
+/*
+ * ClearEOLFromCopiedData - Clear EOL from the copied data.
+ */
+static void
+ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
+					   int copy_line_pos, int *copy_line_size)
+{
+	/*
+	 * If we didn't hit EOF, then we must have transferred the EOL marker
+	 * to line_buf along with the data.  Get rid of it.
+	 */
+   switch (cstate->eol_type)
+   {
+	   case EOL_NL:
+		   Assert(*copy_line_size >= 1);
+		   Assert(copy_line_data[copy_line_pos - 1] == '\n');
+		   copy_line_data[copy_line_pos - 1] = '\0';
+		   (*copy_line_size)--;
+		   break;
+	   case EOL_CR:
+		   Assert(*copy_line_size >= 1);
+		   Assert(copy_line_data[copy_line_pos - 1] == '\r');
+		   copy_line_data[copy_line_pos - 1] = '\0';
+		   (*copy_line_size)--;
+		   break;
+	   case EOL_CRNL:
+		   Assert(*copy_line_size >= 2);
+		   Assert(copy_line_data[copy_line_pos - 2] == '\r');
+		   Assert(copy_line_data[copy_line_pos - 1] == '\n');
+		   copy_line_data[copy_line_pos - 2] = '\0';
+		   *copy_line_size -= 2;
+		   break;
+	   case EOL_UNKNOWN:
+		   /* shouldn't get here */
+		   Assert(false);
+		   break;
+   }
+}
+
+/*
+ * ConvertToServerEncoding - convert contents to server encoding.
+ */
+static void
+ConvertToServerEncoding(CopyState cstate)
+{
 	/* Done reading the line.  Convert it to server encoding. */
 	if (cstate->need_transcoding)
 	{
 		char	   *cvt;
-
 		cvt = pg_any_to_server(cstate->line_buf.data,
 							   cstate->line_buf.len,
 							   cstate->file_encoding);
@@ -3919,11 +3996,8 @@ CopyReadLine(CopyState cstate)
 			pfree(cvt);
 		}
 	}
-
 	/* Now it's safe to use the buffer in error messages */
 	cstate->line_buf_converted = true;
-
-	return result;
 }
 
 /*
@@ -4286,6 +4360,7 @@ not_end_of_copy:
 	 * Transfer any still-uncopied data to line_buf.
 	 */
 	REFILL_LINEBUF;
+	CLEAR_EOL_LINE();
 
 	return result;
 }
-- 
1.8.3.1

0002-Framework-for-leader-worker-in-parallel-copy.patchapplication/x-patch; name=0002-Framework-for-leader-worker-in-parallel-copy.patchDownload
From 68704caa97bf06ca4fbc87751118c9b0f7f324c9 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Thu, 16 Jul 2020 21:53:11 +0530
Subject: [PATCH 2/6] Framework for leader/worker in parallel copy

This patch has the framework for data structures in parallel copy, leader
initialization, worker initialization, shared memory updation, starting workers,
wait for workers and workers exiting.
---
 src/backend/access/transam/parallel.c       |   4 +
 src/backend/commands/copy.c                 | 897 +++++++++++++++++++++++++++-
 src/backend/replication/logical/tablesync.c |   2 +-
 src/include/commands/copy.h                 |   4 +
 src/tools/pgindent/typedefs.list            |   8 +
 5 files changed, 910 insertions(+), 5 deletions(-)

diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index b042696..a3cff4b 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -25,6 +25,7 @@
 #include "catalog/pg_enum.h"
 #include "catalog/storage.h"
 #include "commands/async.h"
+#include "commands/copy.h"
 #include "executor/execParallel.h"
 #include "libpq/libpq.h"
 #include "libpq/pqformat.h"
@@ -145,6 +146,9 @@ static const struct
 	},
 	{
 		"parallel_vacuum_main", parallel_vacuum_main
+	},
+	{
+		"ParallelCopyMain", ParallelCopyMain
 	}
 };
 
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 09419ea..50da871 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -96,9 +96,174 @@ typedef enum CopyInsertMethod
 } CopyInsertMethod;
 
 #define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+
+/*
+ * The macros DATA_BLOCK_SIZE, RINGSIZE & MAX_BLOCKS_COUNT stores the records
+ * read from the file that need to be inserted into the relation. These values
+ * help in handover of multiple records with significant size of data to be
+ * processed by each of the workers to make sure there is no context swich & the
+ * work is fairly distrtibuted among the workers. This number showed best
+ * results in the performance tests.
+ */
+#define DATA_BLOCK_SIZE RAW_BUF_SIZE
+
+/* It can hold upto 10000 record information for worker to process. */
+#define RINGSIZE (10 * 1000)
+
+/* It can hold 1000 blocks of 64K data in DSM to be processed by the worker. */
+#define MAX_BLOCKS_COUNT 1000
+
+/*
+ * Each worker will be allocated WORKER_CHUNK_COUNT of records from DSM data
+ * block to process to avoid lock contention. This value should be mode of
+ * RINGSIZE, as wrap around cases is currently not handled while selecting the
+ * WORKER_CHUNK_COUNT by the worker.
+ */
+#define WORKER_CHUNK_COUNT 50
+
+#define	IsParallelCopy()		(cstate->is_parallel)
+#define IsLeader()				(cstate->pcdata->is_leader)
 #define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
 
 /*
+ * Copy data block information.
+ * ParallelCopyDataBlock's will be created in DSM. Data read from file will be
+ * copied in these DSM data blockes. The leader process identifies the records
+ * and the record information will be shared to the workers. The workers will
+ * insert the records into the table. There can be one or more number of records
+ * in each of the data block based on the record size.
+ */
+typedef struct ParallelCopyDataBlock
+{
+	/* The number of unprocessed lines in the current block. */
+	pg_atomic_uint32 unprocessed_line_parts;
+
+	/*
+	 * If the current line data is continued into another block, following_block
+	 * will have the position where the remaining data need to be read.
+	 */
+	uint32	following_block;
+
+	/*
+	 * This flag will be set, when the leader finds out this block can be read
+	 * safely by the worker. This helps the worker to start processing the line
+	 * early where the line will be spread across many blocks and the worker
+	 * need not wait for the complete line to be processed.
+	 */
+	bool   curr_blk_completed;
+	char   data[DATA_BLOCK_SIZE]; /* data read from file */
+	uint8  skip_bytes;
+}ParallelCopyDataBlock;
+
+/*
+ * Individual line information.
+ * ParallelCopyLineBoundary is common data structure between leader & worker,
+ * Leader process will be populating data block, data block offset & the size of
+ * the record in DSM for the workers to copy the data into the relation.
+ * This is protected by the following sequence in the leader & worker. If they
+ * don't follow this order the worker might process wrong line_size and leader
+ * might populate the information which worker has not yet processed or in the
+ * process of processing.
+ * Leader should operate in the following order:
+ * 1) check if line_size is -1, if not wait, it means worker is still
+ * processing.
+ * 2) set line_state to LINE_LEADER_POPULATING.
+ * 3) update first_block, start_offset & cur_lineno in any order.
+ * 4) update line_size.
+ * 5) update line_state to LINE_LEADER_POPULATED.
+ * Worker should operate in the following order:
+ * 1) check line_state is LINE_LEADER_POPULATED, if not it means leader is still
+ * populating the data.
+ * 2) read line_size.
+ * 3) only one worker should choose one line for processing, this is handled by
+ *    using pg_atomic_compare_exchange_u32, worker will change the sate to
+ *    LINE_WORKER_PROCESSING only if line_state is LINE_LEADER_POPULATED.
+ * 4) read first_block, start_offset & cur_lineno in any order.
+ * 5) process line_size data.
+ * 6) update line_size to -1.
+ */
+typedef struct ParallelCopyLineBoundary
+{
+	/* Position of the first block in data_blocks array. */
+	uint32				first_block;
+	uint32				start_offset;   /* start offset of the line */
+
+	/*
+	 * Size of the current line -1 means line is yet to be filled completely,
+	 * 0 means empty line, >0 means line filled with line size data.
+	 */
+	pg_atomic_uint32	line_size;
+	pg_atomic_uint32	line_state;		/* line state */
+	uint64				cur_lineno;		/* line number for error messages */
+}ParallelCopyLineBoundary;
+
+/*
+ * Circular queue used to store the line information.
+ */
+typedef struct ParallelCopyLineBoundaries
+{
+	/* Position for the leader to populate a line. */
+	uint32			pos;
+
+	/* Data read from the file/stdin by the leader process. */
+	ParallelCopyLineBoundary	ring[RINGSIZE];
+}ParallelCopyLineBoundaries;
+
+/*
+ * Shared information among parallel copy workers. This will be allocated in the
+ * DSM segment.
+ */
+typedef struct ParallelCopyShmInfo
+{
+	bool					is_read_in_progress; /* file read status */
+
+	/*
+	 * Actual lines inserted by worker (some records will be filtered based on
+	 * where condition).
+	 */
+	pg_atomic_uint64			processed;
+	pg_atomic_uint64			total_worker_processed; /* total processed records by the workers */
+	uint64						populated; /* lines populated by leader */
+	uint32						cur_block_pos; /* current data block */
+	ParallelCopyDataBlock		data_blocks[MAX_BLOCKS_COUNT]; /* data block array */
+	FullTransactionId			full_transaction_id; /* xid for copy from statement */
+	CommandId					mycid;	/* command id */
+	ParallelCopyLineBoundaries	line_boundaries; /* line array */
+} ParallelCopyShmInfo;
+
+/*
+ * Parallel copy line buffer information.
+ */
+typedef struct ParallelCopyLineBuf
+{
+	StringInfoData		line_buf;
+	uint64				cur_lineno;	/* line number for error messages */
+}ParallelCopyLineBuf;
+
+/*
+ * Parallel copy data information.
+ */
+typedef struct ParallelCopyData
+{
+	Oid					relid;				/* relation id of the table */
+	ParallelCopyShmInfo	*pcshared_info;		/* common info in shared memory */
+	bool				is_leader;
+
+	/* line position which worker is processing */
+	uint32				worker_processed_pos;
+
+	/*
+	 * Local line_buf array, workers will copy it here and release the lines
+	 * for the leader to continue.
+	 */
+	ParallelCopyLineBuf	worker_line_buf[WORKER_CHUNK_COUNT];
+	uint32				worker_line_buf_count; /* Number of lines */
+
+	/* Current position in worker_line_buf */
+	uint32				worker_line_buf_pos;
+}ParallelCopyData;
+
+/*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
  * even though some fields are used in only some cases.
@@ -228,8 +393,66 @@ typedef struct CopyStateData
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
+	int			nworkers;
+	bool		is_parallel;
+	ParallelCopyData *pcdata;
 } CopyStateData;
 
+/*
+ * This structure helps in storing the common data from CopyStateData that are
+ * required by the workers. This information will then be allocated and stored
+ * into the DSM for the worker to retrieve and copy it to CopyStateData.
+ */
+typedef struct SerializedParallelCopyState
+{
+	/* low-level state data */
+	CopyDest            copy_dest;		/* type of copy source/destination */
+	int                 file_encoding;	/* file or remote side's character encoding */
+	bool                need_transcoding;	/* file encoding diff from server? */
+	bool                encoding_embeds_ascii;	/* ASCII can be non-first byte? */
+
+	/* parameters from the COPY command */
+	bool                csv_mode;		/* Comma Separated Value format? */
+	bool                header_line;	/* CSV header line? */
+	int                 null_print_len; /* length of same */
+	bool                force_quote_all;	/* FORCE_QUOTE *? */
+	bool                convert_selectively;	/* do selective binary conversion? */
+
+	/* Working state for COPY FROM */
+	AttrNumber          num_defaults;
+	Oid                 relid;
+}SerializedParallelCopyState;
+
+/*
+ * This structure will help in converting a List data type into the below
+ * structure format with the count having the number of elements in the list and
+ * the info having the List elements appended contigously. This converted
+ * structure will be allocated in shared memory and stored in DSM for the worker
+ * to retrieve and later convert it back to List data type.
+ */
+typedef struct ParallelCopyKeyListInfo
+{
+	int	count;		/* count of attributes */
+
+	/* string info in the form info followed by info1, info2... infon  */
+	char    info[1];
+} ParallelCopyKeyListInfo;
+
+/*
+ * List of internal parallel copy function pointers.
+ */
+static const struct
+{
+	char *fn_name;
+	copy_data_source_cb fn_addr;
+}			InternalParallelCopyFuncPtrs[] =
+
+{
+	{
+		"copy_read_data", copy_read_data
+	},
+};
+
 /* DestReceiver for COPY (query) TO */
 typedef struct
 {
@@ -259,6 +482,23 @@ typedef struct
 /* Trim the list of buffers back down to this number after flushing */
 #define MAX_PARTITION_BUFFERS	32
 
+/* DSM keys for parallel copy.  */
+#define PARALLEL_COPY_KEY_SHARED_INFO		    1
+#define PARALLEL_COPY_KEY_CSTATE				2
+#define PARALLEL_COPY_KEY_NULL_PRINT			3
+#define PARALLEL_COPY_KEY_NULL_PRINT_CLIENT		4
+#define PARALLEL_COPY_KEY_DELIM					5
+#define PARALLEL_COPY_KEY_QUOTE					6
+#define PARALLEL_COPY_KEY_ESCAPE				7
+#define PARALLEL_COPY_KEY_ATTNAME_LIST			8
+#define PARALLEL_COPY_KEY_FORCE_QUOTE_LIST  	9
+#define PARALLEL_COPY_KEY_NOT_NULL_LIST		   10
+#define PARALLEL_COPY_KEY_NULL_LIST			   11
+#define PARALLEL_COPY_KEY_CONVERT_LIST		   12
+#define PARALLEL_COPY_KEY_DATASOURCE_CB		   13
+#define PARALLEL_COPY_KEY_WHERE_CLAUSE_STR     14
+#define PARALLEL_COPY_KEY_RANGE_TABLE		   15
+
 /* Stores multi-insert data related to a single relation in CopyFrom. */
 typedef struct CopyMultiInsertBuffer
 {
@@ -418,11 +658,593 @@ static bool CopyGetInt32(CopyState cstate, int32 *val);
 static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 
+static pg_attribute_always_inline void EndParallelCopy(ParallelContext *pcxt);
 static void PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tup_desc,
 									   List *attnamelist);
 static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
 								   int copy_line_pos, int *copy_line_size);
 static void ConvertToServerEncoding(CopyState cstate);
+static pg_attribute_always_inline copy_data_source_cb LookupParallelCopyFnPtr(const char *funcname);
+static pg_attribute_always_inline char* LookupParallelCopyFnStr(copy_data_source_cb fn_addr);
+
+/*
+ * SerializeParallelCopyState - Copy shared_cstate using cstate information.
+ */
+static pg_attribute_always_inline void
+SerializeParallelCopyState(CopyState cstate, SerializedParallelCopyState *shared_cstate)
+{
+	shared_cstate->copy_dest = cstate->copy_dest;
+	shared_cstate->file_encoding = cstate->file_encoding;
+	shared_cstate->need_transcoding = cstate->need_transcoding;
+	shared_cstate->encoding_embeds_ascii = cstate->encoding_embeds_ascii;
+	shared_cstate->csv_mode = cstate->csv_mode;
+	shared_cstate->header_line = cstate->header_line;
+	shared_cstate->null_print_len = cstate->null_print_len;
+	shared_cstate->force_quote_all = cstate->force_quote_all;
+	shared_cstate->convert_selectively = cstate->convert_selectively;
+	shared_cstate->num_defaults = cstate->num_defaults;
+	shared_cstate->relid = cstate->pcdata->relid;
+}
+
+/*
+ * DeserializeString - Retrieve the string from shared memory.
+ */
+static void
+DeserializeString(shm_toc *toc, int sharedkey, char **copystr)
+{
+	char *shared_str_val = (char *)shm_toc_lookup(toc, sharedkey, true);
+	if (shared_str_val)
+		*copystr = pstrdup(shared_str_val);
+}
+
+/*
+ * DeserializeList - Retrieve the list from shared memory.
+ */
+static void
+DeserializeList(shm_toc *toc, int sharedkey, List **copylist)
+{
+	ParallelCopyKeyListInfo *listinformation = (ParallelCopyKeyListInfo *)shm_toc_lookup(toc, sharedkey,
+														   true);
+	if (listinformation)
+	{
+		int	length  = 0;
+		int count;
+
+		for (count = 0; count < listinformation->count; count++)
+		{
+			char *attname = (char *)(listinformation->info + length);
+			length += strlen(attname) + 1;
+			*copylist = lappend(*copylist, makeString(attname));
+		}
+	}
+}
+
+/*
+ * CopyListSharedMemory - Copy the list into shared memory.
+ */
+static void
+CopyListSharedMemory(List *inputlist, Size memsize, ParallelCopyKeyListInfo *sharedlistinfo)
+{
+	ListCell   *l;
+	int			length  = 0;
+
+	MemSet(sharedlistinfo, 0, memsize);
+	foreach(l, inputlist)
+	{
+		char	   *name = strVal(lfirst(l));
+		memcpy((char *)(sharedlistinfo->info + length), name, strlen(name));
+		sharedlistinfo->count++;
+		length += strlen(name) + 1;
+	}
+}
+
+/*
+ * ComputeListSize - compute the list size.
+ */
+static int
+ComputeListSize(List *inputlist)
+{
+	int est_size = sizeof(int);
+	if (inputlist != NIL)
+	{
+		ListCell   *l;
+		foreach(l, inputlist)
+			est_size += strlen(strVal(lfirst(l))) + 1;
+	}
+
+	return est_size;
+}
+
+/*
+ * EstimateLineKeysStr - Estimate the size required in shared memory for the
+ * input string.
+ */
+static void
+EstimateLineKeysStr(ParallelContext *pcxt, char *inputstr)
+{
+	if (inputstr)
+	{
+		shm_toc_estimate_chunk(&pcxt->estimator, strlen(inputstr) + 1);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+}
+
+/*
+ * EstimateLineKeysList - Estimate the size required in shared memory for the
+ * input list.
+ */
+static void
+EstimateLineKeysList(ParallelContext *pcxt, List *inputlist,
+		Size *est_list_size)
+{
+	if (inputlist != NIL)
+	{
+		*est_list_size = ComputeListSize(inputlist);
+		shm_toc_estimate_chunk(&pcxt->estimator, *est_list_size);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+}
+
+/*
+ * SerializeString - Insert a string into shared memory.
+ */
+static void
+SerializeString(ParallelContext *pcxt, int key, char *inputstr)
+{
+	if (inputstr)
+	{
+		char *shmptr = (char *)shm_toc_allocate(pcxt->toc,
+												strlen(inputstr) + 1);
+		strcpy(shmptr, inputstr);
+		shm_toc_insert(pcxt->toc, key, shmptr);
+	}
+}
+
+/*
+ * SerializeList - Insert a list into shared memory.
+ */
+static void
+SerializeList(ParallelContext *pcxt, int key, List *inputlist,
+			  Size est_list_size)
+{
+	if (inputlist != NIL)
+	{
+		ParallelCopyKeyListInfo *sharedlistinfo = (ParallelCopyKeyListInfo *)shm_toc_allocate(pcxt->toc,
+																est_list_size);
+		CopyListSharedMemory(inputlist, est_list_size, sharedlistinfo);
+		shm_toc_insert(pcxt->toc, key, sharedlistinfo);
+	}
+}
+
+/*
+ * BeginParallelCopy - start parallel copy tasks.
+ *
+ * Get the number of workers required to perform the parallel copy. The data
+ * structures that are required by the parallel workers will be initialized, the
+ * size required in DSM will be calculated and the necessary keys will be loaded
+ * in the DSM. The specified number of workers will then be launched.
+ */
+static ParallelContext*
+BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
+{
+	ParallelContext *pcxt;
+	ParallelCopyShmInfo *shared_info_ptr;
+	SerializedParallelCopyState *shared_cstate;
+	FullTransactionId full_transaction_id;
+	Size est_shared_info;
+	Size est_cstateshared;
+	Size est_att_list_size;
+	Size est_quote_list_size;
+	Size est_notnull_list_size;
+	Size est_null_list_size;
+	Size est_convert_list_size;
+	Size est_datasource_cb_size;
+	int  count = 0;
+	char *whereClauseStr = NULL;
+	char *rangeTableStr = NULL;
+	int  parallel_workers = 0;
+	ParallelCopyData *pcdata;
+
+	parallel_workers = Min(nworkers, max_worker_processes);
+
+	/* Can't perform copy in parallel */
+	if (parallel_workers <= 0)
+		return NULL;
+
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	cstate->pcdata = pcdata;
+
+	EnterParallelMode();
+	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
+								 parallel_workers);
+	Assert(pcxt->nworkers > 0);
+
+	/*
+	 * Estimate size for shared information for PARALLEL_COPY_KEY_SHARED_INFO
+	 */
+	est_shared_info = sizeof(ParallelCopyShmInfo);
+	shm_toc_estimate_chunk(&pcxt->estimator, est_shared_info);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_CSTATE */
+	est_cstateshared = 	MAXALIGN(sizeof(SerializedParallelCopyState));
+	shm_toc_estimate_chunk(&pcxt->estimator, est_cstateshared);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	EstimateLineKeysStr(pcxt, cstate->null_print);
+	EstimateLineKeysStr(pcxt, cstate->null_print_client);
+	EstimateLineKeysStr(pcxt, cstate->delim);
+	EstimateLineKeysStr(pcxt, cstate->quote);
+	EstimateLineKeysStr(pcxt, cstate->escape);
+
+	if (cstate->whereClause != NULL)
+	{
+		whereClauseStr = nodeToString(cstate->whereClause);
+		EstimateLineKeysStr(pcxt, whereClauseStr);
+	}
+
+	if (cstate->range_table != NULL)
+	{
+		rangeTableStr = nodeToString(cstate->range_table);
+		EstimateLineKeysStr(pcxt, rangeTableStr);
+	}
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_XID. */
+	shm_toc_estimate_chunk(&pcxt->estimator, sizeof(FullTransactionId));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_ATTNAME_LIST.
+	 */
+	EstimateLineKeysList(pcxt, attnamelist, &est_att_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_FORCE_QUOTE_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->force_quote, &est_quote_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_NOT_NULL_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->force_notnull,
+							 &est_notnull_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_NULL_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->force_null, &est_null_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_CONVERT_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->convert_select,
+							 &est_convert_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_DATASOURCE_CB.
+	 */
+	if (cstate->data_source_cb)
+	{
+		char *functionname = LookupParallelCopyFnStr(cstate->data_source_cb);
+		est_datasource_cb_size = strlen(functionname) + 1;
+		shm_toc_estimate_chunk(&pcxt->estimator, est_datasource_cb_size);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+
+	InitializeParallelDSM(pcxt);
+
+	/* If no DSM segment was available, back out (do serial copy) */
+	if (pcxt->seg == NULL)
+	{
+		EndParallelCopy(pcxt);
+		return NULL;
+	}
+
+	/* Allocate shared memory for PARALLEL_COPY_KEY_SHARED_INFO */
+	shared_info_ptr = (ParallelCopyShmInfo *) shm_toc_allocate(pcxt->toc,
+													   est_shared_info);
+	MemSet(shared_info_ptr, 0, est_shared_info);
+	shared_info_ptr->is_read_in_progress = true;
+	shared_info_ptr->cur_block_pos = -1;
+	shared_info_ptr->full_transaction_id = full_transaction_id;
+	shared_info_ptr->mycid = GetCurrentCommandId(true);
+	for (count = 0; count < RINGSIZE; count++)
+	{
+		ParallelCopyLineBoundary *lineInfo = &shared_info_ptr->line_boundaries.ring[count];
+		pg_atomic_init_u32(&(lineInfo->line_size), -1);
+	}
+
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_SHARED_INFO, shared_info_ptr);
+	pcdata->pcshared_info = shared_info_ptr;
+	pcdata->relid = relid;
+
+	/* Store shared build state, for which we reserved space. */
+	shared_cstate = (SerializedParallelCopyState *)shm_toc_allocate(pcxt->toc,
+															est_cstateshared);
+
+	/* copy cstate variables. */
+	SerializeParallelCopyState(cstate, shared_cstate);
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_CSTATE, shared_cstate);
+
+	SerializeString(pcxt, PARALLEL_COPY_KEY_NULL_PRINT, cstate->null_print);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_NULL_PRINT_CLIENT,
+					cstate->null_print_client);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_DELIM, cstate->delim);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_QUOTE, cstate->quote);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_ESCAPE, cstate->escape);
+
+	SerializeList(pcxt, PARALLEL_COPY_KEY_ATTNAME_LIST,
+					attnamelist, est_att_list_size);
+	SerializeList(pcxt, PARALLEL_COPY_KEY_FORCE_QUOTE_LIST,
+					cstate->force_quote, est_quote_list_size);
+	SerializeList(pcxt, PARALLEL_COPY_KEY_NOT_NULL_LIST,
+					cstate->force_notnull, est_notnull_list_size);
+	SerializeList(pcxt, PARALLEL_COPY_KEY_NULL_LIST, cstate->force_null,
+					est_null_list_size);
+	SerializeList(pcxt, PARALLEL_COPY_KEY_CONVERT_LIST,
+					cstate->convert_select, est_convert_list_size);
+
+	if (cstate->data_source_cb)
+	{
+		char *functionname = LookupParallelCopyFnStr(cstate->data_source_cb);
+		char *data_source_cb = (char *) shm_toc_allocate(pcxt->toc,
+														 est_datasource_cb_size);
+		strcpy(data_source_cb, functionname);
+		shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_DATASOURCE_CB,
+					   data_source_cb);
+	}
+
+	if (cstate->whereClause)
+		SerializeString(pcxt, PARALLEL_COPY_KEY_WHERE_CLAUSE_STR,
+						whereClauseStr);
+
+	if(cstate->range_table)
+		SerializeString(pcxt, PARALLEL_COPY_KEY_RANGE_TABLE, rangeTableStr);
+
+	LaunchParallelWorkers(pcxt);
+	if (pcxt->nworkers_launched == 0)
+	{
+		EndParallelCopy(pcxt);
+		return NULL;
+	}
+
+	/*
+	 * Caller needs to wait for all launched workers when we return.  Make sure
+	 * that the failure-to-start case will not hang forever.
+	 */
+	WaitForParallelWorkersToAttach(pcxt);
+
+	pcdata->is_leader = true;
+	cstate->is_parallel = true;
+	return pcxt;
+}
+
+/*
+ * EndParallelCopy - end the parallel copy tasks.
+ */
+static pg_attribute_always_inline void
+EndParallelCopy(ParallelContext *pcxt)
+{
+	Assert(!IsParallelWorker());
+
+	DestroyParallelContext(pcxt);
+	ExitParallelMode();
+}
+
+/*
+ * ParallelWorkerInitialization - Initialize parallel worker.
+ */
+static void
+ParallelWorkerInitialization(SerializedParallelCopyState *shared_cstate,
+		CopyState cstate, List *attnamelist)
+{
+	uint32		count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	cstate->copy_dest = shared_cstate->copy_dest;
+	cstate->file_encoding = shared_cstate->file_encoding;
+	cstate->need_transcoding = shared_cstate->need_transcoding;
+	cstate->encoding_embeds_ascii = shared_cstate->encoding_embeds_ascii;
+	cstate->csv_mode = shared_cstate->csv_mode;
+	cstate->header_line = shared_cstate->header_line;
+	cstate->null_print_len = shared_cstate->null_print_len;
+	cstate->force_quote_all = shared_cstate->force_quote_all;
+	cstate->convert_selectively = shared_cstate->convert_selectively;
+	cstate->num_defaults = shared_cstate->num_defaults;
+	pcdata->relid = shared_cstate->relid;
+
+	PopulateGlobalsForCopyFrom(cstate, tup_desc, attnamelist);
+
+	/* Initialize state variables. */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/* Set up variables to avoid per-attribute overhead. */
+	initStringInfo(&cstate->attribute_buf);
+
+	initStringInfo(&cstate->line_buf);
+	for (count = 0; count < WORKER_CHUNK_COUNT;count++)
+		initStringInfo(&pcdata->worker_line_buf[count].line_buf);
+
+	cstate->line_buf_converted = false;
+	cstate->raw_buf = NULL;
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+}
+
+/*
+ * ParallelCopyMain - parallel copy worker's code.
+ *
+ * Where clause handling, convert tuple to columns, add default null values for
+ * the missing columns that are not present in that record. Find the partition
+ * if it is partitioned table, invoke before row insert Triggers, handle
+ * constraints and insert the tuples.
+ */
+void
+ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
+{
+	CopyState cstate;
+	ParallelCopyData *pcdata;
+	ParallelCopyShmInfo *pcshared_info;
+	SerializedParallelCopyState *shared_cstate;
+	Relation	rel = NULL;
+	MemoryContext oldcontext;
+	List *attlist = NIL;
+	char *data_source_cb;
+	char *whereClauseStr = NULL;
+	char *rangeTableStr = NULL;
+
+	/* Allocate workspace and zero all fields. */
+	cstate = (CopyStateData *) palloc0(sizeof(CopyStateData));
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	cstate->pcdata = pcdata;
+	pcdata->is_leader = false;
+	pcdata->worker_processed_pos = -1;
+	cstate->is_parallel = true;
+
+	/*
+	 * We allocate everything used by a cstate in a new memory context. This
+	 * avoids memory leaks during repeated use of COPY in a query.
+	 */
+	cstate->copycontext = AllocSetContextCreate(CurrentMemoryContext,
+												"COPY",
+												ALLOCSET_DEFAULT_SIZES);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	pcshared_info = (ParallelCopyShmInfo *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_SHARED_INFO,
+														false);
+
+	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
+
+	pcdata->pcshared_info = pcshared_info;
+
+	shared_cstate = (SerializedParallelCopyState *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE,
+														   false);
+
+	cstate->null_print = (char *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_NULL_PRINT,
+												true);
+	cstate->null_print_client = (char *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_NULL_PRINT_CLIENT,
+													   true);
+
+	DeserializeString(toc, PARALLEL_COPY_KEY_DELIM, &cstate->delim);
+	DeserializeString(toc, PARALLEL_COPY_KEY_QUOTE, &cstate->quote);
+	DeserializeString(toc, PARALLEL_COPY_KEY_ESCAPE, &cstate->escape);
+
+	DeserializeList(toc, PARALLEL_COPY_KEY_ATTNAME_LIST, &attlist);
+	DeserializeList(toc, PARALLEL_COPY_KEY_FORCE_QUOTE_LIST, &cstate->force_quote);
+	DeserializeList(toc, PARALLEL_COPY_KEY_NOT_NULL_LIST, &cstate->force_notnull);
+	DeserializeList(toc, PARALLEL_COPY_KEY_NULL_LIST, &cstate->force_null);
+	DeserializeList(toc, PARALLEL_COPY_KEY_CONVERT_LIST, &cstate->convert_select);
+	data_source_cb = (char *)shm_toc_lookup(toc,
+											PARALLEL_COPY_KEY_DATASOURCE_CB,
+											true);
+	DeserializeString(toc, PARALLEL_COPY_KEY_WHERE_CLAUSE_STR, &whereClauseStr);
+	DeserializeString(toc, PARALLEL_COPY_KEY_RANGE_TABLE, &rangeTableStr);
+
+	if (data_source_cb)
+		cstate->data_source_cb = LookupParallelCopyFnPtr(data_source_cb);
+
+	if (whereClauseStr)
+	{
+		Node *whereClauseCnvrtdFrmStr = (Node *) stringToNode(whereClauseStr);
+		cstate->whereClause = whereClauseCnvrtdFrmStr;
+	}
+
+	if (rangeTableStr)
+	{
+		List *rangeTableCnvrtdFrmStr = (List *) stringToNode(rangeTableStr);
+		cstate->range_table = rangeTableCnvrtdFrmStr;
+	}
+
+	/* Open and lock the relation, using the appropriate lock type. */
+	rel = table_open(shared_cstate->relid, RowExclusiveLock);
+	cstate->rel = rel;
+	ParallelWorkerInitialization(shared_cstate, cstate, attlist);
+
+	CopyFrom(cstate);
+
+	if (rel != NULL)
+		table_close(rel, RowExclusiveLock);
+
+	MemoryContextSwitchTo(oldcontext);
+	return;
+}
+
+/*
+ * ParallelCopyLeader - parallel copy leader's functionality.
+ *
+ * Leader will populate the shared memory and share it across the workers.
+ * Leader will read the table data from the file and copy the contents to block.
+ * Leader will then read the input contents and identify the data based on line
+ * beaks. This information is called line. The line will be populate in
+ * ParallelCopyLineBoundary. Workers will then pick up this information and
+ * insert in to table. Leader will do this till it completes processing the
+ * file. Leader executes the before statement if before statement trigger is
+ * present. Leader read the data from input file. Leader then loads data to data
+ * blocks as and when required block by block. Leader traverses through the data
+ * block to identify one line. It gets a free line to copy the information, if
+ * there is no free line it will wait till there is one free line.
+ * Server copies  the identified lines information into lines. This process is
+ * repeated till the complete file is processed.
+ * Leader will wait till all the lines populated are processed by the workers
+ * and exits.
+ */
+static void
+ParallelCopyLeader(CopyState cstate)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
+
+	pcshared_info->is_read_in_progress = false;
+	cstate->cur_lineno = 0;
+}
+
+/*
+ * LookupParallelCopyFnPtr - Look up parallel copy function pointer.
+ */
+static pg_attribute_always_inline copy_data_source_cb
+LookupParallelCopyFnPtr(const char *funcname)
+{
+	int			i;
+
+	for (i = 0; i < lengthof(InternalParallelCopyFuncPtrs); i++)
+	{
+		if (strcmp(InternalParallelCopyFuncPtrs[i].fn_name, funcname) == 0)
+			return InternalParallelCopyFuncPtrs[i].fn_addr;
+	}
+
+	/* We can only reach this by programming error. */
+	elog(ERROR, "internal function \"%s\" not found", funcname);
+}
+
+/*
+ * LookupParallelCopyFnStr - Lookup function string from a function pointer.
+ */
+static pg_attribute_always_inline char*
+LookupParallelCopyFnStr(copy_data_source_cb fn_addr)
+{
+	int			i;
+
+	for (i = 0; i < lengthof(InternalParallelCopyFuncPtrs); i++)
+	{
+		if (InternalParallelCopyFuncPtrs[i].fn_addr == fn_addr)
+			return InternalParallelCopyFuncPtrs[i].fn_name;
+	}
+
+	/* We can only reach this by programming error. */
+	elog(ERROR, "internal function pointer not found");
+}
+
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
  * in past protocol redesigns.
@@ -1093,6 +1915,7 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 
 	if (is_from)
 	{
+		ParallelContext *pcxt = NULL;
 		Assert(rel);
 
 		/* check read-only transaction and parallel mode */
@@ -1102,7 +1925,24 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 		cstate = BeginCopyFrom(pstate, rel, stmt->filename, stmt->is_program,
 							   NULL, stmt->attlist, stmt->options);
 		cstate->whereClause = whereClause;
-		*processed = CopyFrom(cstate);	/* copy from file to database */
+		cstate->is_parallel = false;
+
+		if (cstate->nworkers > 0)
+			pcxt = BeginParallelCopy(cstate->nworkers, cstate, stmt->attlist,
+									 relid);
+
+		if (pcxt)
+		{
+			ParallelCopyLeader(cstate);
+
+			/* Wait for all copy workers to finish */
+			WaitForParallelWorkersToFinish(pcxt);
+			*processed = pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
+			EndParallelCopy(pcxt);
+		}
+		else
+			*processed = CopyFrom(cstate); /* copy from file to database */
+
 		EndCopyFrom(cstate);
 	}
 	else
@@ -1151,6 +1991,7 @@ ProcessCopyOptions(ParseState *pstate,
 	cstate->is_copy_from = is_from;
 
 	cstate->file_encoding = -1;
+	cstate->nworkers = -1;
 
 	/* Extract options from the statement node tree */
 	foreach(option, options)
@@ -1319,6 +2160,53 @@ ProcessCopyOptions(ParseState *pstate,
 								defel->defname),
 						 parser_errposition(pstate, defel->location)));
 		}
+		else if (strcmp(defel->defname, "parallel") == 0)
+		{
+			char *endptr, *str;
+			long val;
+
+			if (!cstate->is_copy_from)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("parallel option supported only for copy from"),
+						 parser_errposition(pstate, defel->location)));
+			if (cstate->nworkers >= 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options"),
+						 parser_errposition(pstate, defel->location)));
+
+			str = defGetString(defel);
+
+			errno = 0; /* To distinguish success/failure after call */
+			val = strtol(str, &endptr, 10);
+
+			/* Check for various possible errors */
+			if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
+				|| (errno != 0 && val == 0) ||
+				*endptr)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("improper use of argument to option \"%s\"",
+								defel->defname),
+						 parser_errposition(pstate, defel->location)));
+
+			if (endptr == str)
+			   ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("no digits were found in argument to option \"%s\"",
+								defel->defname),
+						 parser_errposition(pstate, defel->location)));
+
+			cstate->nworkers = (int) val;
+
+			if (cstate->nworkers <= 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("argument to option \"%s\" must be a positive integer greater than zero",
+								defel->defname),
+						 parser_errposition(pstate, defel->location)));
+		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_SYNTAX_ERROR),
@@ -1671,12 +2559,13 @@ BeginCopy(ParseState *pstate,
 }
 
 /*
- * PopulateGlobalsForCopyFrom - Populates the common variables required for copy
- * from operation. This is a helper function for BeginCopy function.
+ * PopulateCatalogInformation - Populates the common variables required for copy
+ * from operation. This is a helper function for BeginCopy &
+ * ParallelWorkerInitialization function.
  */
 static void
 PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tupDesc,
-							List *attnamelist)
+						   List *attnamelist)
 {
 	int			num_phys_attrs;
 
diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c
index c27d970..b3787c1 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -557,7 +557,7 @@ make_copy_attnamelist(LogicalRepRelMapEntry *rel)
  * Data source callback for the COPY FROM, which reads from the remote
  * connection and passes the data back to our local COPY.
  */
-static int
+int
 copy_read_data(void *outbuf, int minread, int maxread)
 {
 	int			bytesread = 0;
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index c639833..5dc95ac 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -14,6 +14,7 @@
 #ifndef COPY_H
 #define COPY_H
 
+#include "access/parallel.h"
 #include "nodes/execnodes.h"
 #include "nodes/parsenodes.h"
 #include "parser/parse_node.h"
@@ -41,4 +42,7 @@ extern uint64 CopyFrom(CopyState cstate);
 
 extern DestReceiver *CreateCopyDestReceiver(void);
 
+extern void ParallelCopyMain(dsm_segment *seg, shm_toc *toc);
+
+extern int copy_read_data(void *outbuf, int minread, int maxread);
 #endif							/* COPY_H */
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 7eaaad1..dd812b0 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1699,6 +1699,13 @@ ParallelBitmapHeapState
 ParallelBlockTableScanDesc
 ParallelCompletionPtr
 ParallelContext
+ParallelCopyLineBoundaries
+ParallelCopyLineBoundary
+ParallelCopyData
+ParallelCopyDataBlock
+ParallelCopyKeyListInfo
+ParallelCopyLineBuf
+ParallelCopyShmInfo
 ParallelExecutorInfo
 ParallelHashGrowth
 ParallelHashJoinBatch
@@ -2215,6 +2222,7 @@ SerCommitSeqNo
 SerialControl
 SerializableXactHandle
 SerializedActiveRelMaps
+SerializedParallelCopyState
 SerializedReindexState
 SerializedSnapshotData
 SerializedTransactionState
-- 
1.8.3.1

0003-Allow-copy-from-command-to-process-data-from-file-ST.patchapplication/x-patch; name=0003-Allow-copy-from-command-to-process-data-from-file-ST.patchDownload
From 6a1b095aeaa20b138d89161eaa08b4209038059f Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Thu, 16 Jul 2020 22:07:11 +0530
Subject: [PATCH 3/6] Allow copy from command to process data from file/STDIN
 contents to a table in parallel.

This feature allows the copy from to leverage multiple CPUs in order to copy
data from file/STDIN to a table. This adds a PARALLEL option to COPY FROM
command where the user can specify the number of workers that can be used
to perform the COPY FROM command. Specifying zero as number of workers will
disable parallelism.
The backend, to which the "COPY FROM" query is submitted acts as leader with
the responsibility of reading data from the file/stdin, launching at most n
number of workers as specified with PARALLEL 'n' option in the "COPY FROM"
query. The leader populates the common data required for the workers execution
in the DSM and shares it with the workers. The leader then executes before
statement triggers if there exists any. Leader populates DSM lines which
includes the start offset and line size, while populating the lines it reads
as many blocks as required into the DSM data blocks from the file. Each block
is of 64K size. The leader parses the data to identify a line, the existing
logic from CopyReadLineText which identifies the lines with some changes was
used for this. Leader checks if a free line is available to copy the
information, if there is no free line it waits till the required line is
freed up by the worker and then copies the identified lines information
(offset & line size) into the DSM lines. This process is repeated till the
complete file is processed. Simultaneously, the workers cache the lines(50)
locally into the local memory and release the lines to the leader for further
populating. Each worker processes the lines that it cached and inserts it into
the table. The leader does not participate in the insertion of data, leaders
only responsibility will be to identify the lines as fast as possible for the
workers to do the actual copy operation. The leader waits till all the lines
populated are processed by the workers and exits.
---
 src/backend/access/common/toast_internals.c |  11 +-
 src/backend/access/heap/heapam.c            |  13 -
 src/backend/access/transam/xact.c           |  31 +
 src/backend/commands/copy.c                 | 907 ++++++++++++++++++++++++++--
 src/include/access/xact.h                   |   2 +
 5 files changed, 910 insertions(+), 54 deletions(-)

diff --git a/src/backend/access/common/toast_internals.c b/src/backend/access/common/toast_internals.c
index 25a81e5..586d53d 100644
--- a/src/backend/access/common/toast_internals.c
+++ b/src/backend/access/common/toast_internals.c
@@ -17,6 +17,7 @@
 #include "access/genam.h"
 #include "access/heapam.h"
 #include "access/heaptoast.h"
+#include "access/parallel.h"
 #include "access/table.h"
 #include "access/toast_internals.h"
 #include "access/xact.h"
@@ -116,7 +117,15 @@ toast_save_datum(Relation rel, Datum value,
 	TupleDesc	toasttupDesc;
 	Datum		t_values[3];
 	bool		t_isnull[3];
-	CommandId	mycid = GetCurrentCommandId(true);
+
+	/*
+	 * Parallel copy can insert toast tuples, in case of parallel copy the
+	 * command would have been set already by calling AssignCommandIdForWorker.
+	 * For parallel copy call GetCurrentCommandId to get currentCommandId by
+	 * passing used as false, as this is taken care earlier.
+	 */
+	CommandId	mycid = IsParallelWorker() ? GetCurrentCommandId(false) :
+											 GetCurrentCommandId(true);
 	struct varlena *result;
 	struct varatt_external toast_pointer;
 	union
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index d881f4c..70ecd51 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2012,19 +2012,6 @@ static HeapTuple
 heap_prepare_insert(Relation relation, HeapTuple tup, TransactionId xid,
 					CommandId cid, int options)
 {
-	/*
-	 * Parallel operations are required to be strictly read-only in a parallel
-	 * worker.  Parallel inserts are not safe even in the leader in the
-	 * general case, because group locking means that heavyweight locks for
-	 * relation extension or GIN page locks will not conflict between members
-	 * of a lock group, but we don't prohibit that case here because there are
-	 * useful special cases that we can safely allow, such as CREATE TABLE AS.
-	 */
-	if (IsParallelWorker())
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_TRANSACTION_STATE),
-				 errmsg("cannot insert tuples in a parallel worker")));
-
 	tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
 	tup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK);
 	tup->t_data->t_infomask |= HEAP_XMAX_INVALID;
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index b3ee7fa..94988b6 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -502,6 +502,37 @@ GetCurrentFullTransactionIdIfAny(void)
 }
 
 /*
+ *	AssignFullTransactionIdForWorker
+ *
+ * For parallel copy, transaction id of leader will be used by the workers.
+ */
+void
+AssignFullTransactionIdForWorker(FullTransactionId fullTransactionId)
+{
+	TransactionState s = CurrentTransactionState;
+
+	Assert((IsInParallelMode() || IsParallelWorker()));
+	s->fullTransactionId = fullTransactionId;
+}
+
+/*
+ *	AssignCommandIdForWorker
+ *
+ * For parallel copy, command id of leader will be used by the workers.
+ */
+void
+AssignCommandIdForWorker(CommandId commandId, bool used)
+{
+	Assert((IsInParallelMode() || IsParallelWorker()));
+
+	/* this is global to a transaction, not subtransaction-local */
+	if (used)
+		currentCommandIdUsed = true;
+
+	currentCommandId = commandId;
+}
+
+/*
  *	MarkCurrentTransactionIdLoggedIfAny
  *
  * Remember that the current xid - if it is assigned - now has been wal logged.
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 50da871..b709b2f 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -26,6 +26,7 @@
 #include "access/xlog.h"
 #include "catalog/dependency.h"
 #include "catalog/pg_authid.h"
+#include "catalog/pg_proc_d.h"
 #include "catalog/pg_type.h"
 #include "commands/copy.h"
 #include "commands/defrem.h"
@@ -40,11 +41,13 @@
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
+#include "optimizer/clauses.h"
 #include "optimizer/optimizer.h"
 #include "parser/parse_coerce.h"
 #include "parser/parse_collate.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_relation.h"
+#include "pgstat.h"
 #include "port/pg_bswap.h"
 #include "rewrite/rewriteHandler.h"
 #include "storage/fd.h"
@@ -95,6 +98,18 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
+/*
+ * State of the line.
+ */
+typedef enum ParallelCopyLineState
+{
+	LINE_INIT,					/* initial state of line */
+	LINE_LEADER_POPULATING,		/* leader processing line */
+	LINE_LEADER_POPULATED,		/* leader completed populating line */
+	LINE_WORKER_PROCESSING,		/* worker processing line */
+	LINE_WORKER_PROCESSED		/* worker completed processing line */
+}ParallelCopyLineState;
+
 #define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
 
 /*
@@ -577,9 +592,13 @@ if (1) \
 { \
 	if (raw_buf_ptr > cstate->raw_buf_index) \
 	{ \
-		appendBinaryStringInfo(&cstate->line_buf, \
-							 cstate->raw_buf + cstate->raw_buf_index, \
-							   raw_buf_ptr - cstate->raw_buf_index); \
+		if (!IsParallelCopy()) \
+			appendBinaryStringInfo(&cstate->line_buf, \
+								   cstate->raw_buf + cstate->raw_buf_index, \
+								   raw_buf_ptr - cstate->raw_buf_index); \
+		else \
+			line_size +=  raw_buf_ptr - cstate->raw_buf_index; \
+		\
 		cstate->raw_buf_index = raw_buf_ptr; \
 	} \
 } else ((void) 0)
@@ -592,26 +611,76 @@ if (1) \
 	goto not_end_of_copy; \
 } else ((void) 0)
 
+/* Begin parallel copy Macros */
+#define SET_NEWLINE_SIZE() \
+{ \
+	if (cstate->eol_type == EOL_NL || cstate->eol_type == EOL_CR) \
+		new_line_size = 1; \
+	else if (cstate->eol_type == EOL_CRNL) \
+		new_line_size = 2; \
+	else \
+		new_line_size = 0; \
+}
+
+/* Begin parallel copy Macros */
+#define SET_NEWLINE_SIZE() \
+{ \
+	if (cstate->eol_type == EOL_NL || cstate->eol_type == EOL_CR) \
+		new_line_size = 1; \
+	else if (cstate->eol_type == EOL_CRNL) \
+		new_line_size = 2; \
+	else \
+		new_line_size = 0; \
+}
+
+/*
+ * COPY_WAIT_TO_PROCESS - Wait before continuing to process.
+ */
+#define COPY_WAIT_TO_PROCESS() \
+{ \
+	CHECK_FOR_INTERRUPTS(); \
+	(void) WaitLatch(MyLatch, \
+					 WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH, \
+					 1L, WAIT_EVENT_PG_SLEEP); \
+	ResetLatch(MyLatch); \
+}
+
 /*
  * CLEAR_EOL_LINE - Wrapper for clearing EOL.
  */
 #define CLEAR_EOL_LINE() \
 if (!result && !IsHeaderLine()) \
-	ClearEOLFromCopiedData(cstate, cstate->line_buf.data, \
-						   cstate->line_buf.len, \
-						   &cstate->line_buf.len) \
+{ \
+	if (IsParallelCopy()) \
+		ClearEOLFromCopiedData(cstate, cstate->raw_buf, \
+									raw_buf_ptr, &line_size); \
+	else \
+		ClearEOLFromCopiedData(cstate, cstate->line_buf.data, \
+									cstate->line_buf.len, \
+									&cstate->line_buf.len); \
+} \
 
 /*
  * INCREMENTPROCESSED - Increment the lines processed.
  */
-#define INCREMENTPROCESSED(processed)  \
-processed++;
+#define INCREMENTPROCESSED(processed) \
+{ \
+	if (!IsParallelCopy()) \
+		processed++; \
+	else \
+		pg_atomic_add_fetch_u64(&cstate->pcdata->pcshared_info->processed, 1); \
+}
 
 /*
  * GETPROCESSED - Get the lines processed.
  */
 #define GETPROCESSED(processed) \
-return processed;
+if (!IsParallelCopy()) \
+	return processed; \
+else \
+	return pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
+
+/* End parallel copy Macros */
 
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
@@ -666,7 +735,10 @@ static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
 static void ConvertToServerEncoding(CopyState cstate);
 static pg_attribute_always_inline copy_data_source_cb LookupParallelCopyFnPtr(const char *funcname);
 static pg_attribute_always_inline char* LookupParallelCopyFnStr(copy_data_source_cb fn_addr);
-
+static void ExecBeforeStmtTrigger(CopyState cstate);
+static void CheckTargetRelValidity(CopyState cstate);
+static void PopulateCatalogInformation(CopyState cstate);
+static pg_attribute_always_inline uint32 GetLinePosition(CopyState cstate);
 /*
  * SerializeParallelCopyState - Copy shared_cstate using cstate information.
  */
@@ -817,6 +889,137 @@ SerializeList(ParallelContext *pcxt, int key, List *inputlist,
 }
 
 /*
+ * IsTriggerFunctionParallelSafe - Check if the trigger function is parallel
+ * safe for the triggers. Return false if any one of the trigger has parallel
+ * unsafe function.
+ */
+static pg_attribute_always_inline bool
+IsTriggerFunctionParallelSafe(TriggerDesc *trigdesc)
+{
+	int	i;
+	for (i = 0; i < trigdesc->numtriggers; i++)
+	{
+		Trigger    *trigger = &trigdesc->triggers[i];
+		int 		trigtype = RI_TRIGGER_NONE;
+
+		if (func_parallel(trigger->tgfoid) != PROPARALLEL_SAFE)
+			return false;
+
+		/* If the trigger is parallel safe, also look for RI_TRIGGER. */
+		trigtype = RI_FKey_trigger_type(trigger->tgfoid);
+		if (trigtype == RI_TRIGGER_PK || trigtype == RI_TRIGGER_FK)
+			return false;
+	}
+
+	return true;
+}
+
+/*
+ * CheckExprParallelSafety - determine parallel safety of volatile expressions
+ * in default clause of column definition or in where clause and return true if
+ * they are parallel safe.
+ */
+static pg_attribute_always_inline bool
+CheckExprParallelSafety(CopyState cstate)
+{
+	if (contain_volatile_functions(cstate->whereClause))
+	{
+		if (max_parallel_hazard((Query *)cstate->whereClause) != PROPARALLEL_SAFE)
+			return false;
+	}
+
+	/*
+	 * Check if any of the column has volatile default expression. if yes, and
+	 * they are not parallel safe, then parallelism is not allowed. For
+	 * instance, if there are any serial/bigserial columns for which nextval()
+	 * default expression which is parallel unsafe is associated, parallelism
+	 * should not be allowed. In non parallel copy volatile functions are not
+	 * checked for nextval().
+	 */
+	if (cstate->defexprs != NULL && cstate->num_defaults != 0)
+	{
+		int     i;
+		for (i = 0; i < cstate->num_defaults; i++)
+		{
+			bool volatile_expr = contain_volatile_functions((Node *)cstate->defexprs[i]->expr);
+			if (volatile_expr &&
+				(max_parallel_hazard((Query *)cstate->defexprs[i]->expr)) !=
+				 PROPARALLEL_SAFE)
+				return false;
+		}
+	}
+
+	return true;
+}
+
+/*
+ * FindInsertMethod - determine insert mode single, multi, or multi conditional.
+ */
+static pg_attribute_always_inline CopyInsertMethod
+FindInsertMethod(CopyState cstate)
+{
+	if (cstate->rel->trigdesc != NULL &&
+		(cstate->rel->trigdesc->trig_insert_before_row ||
+		 cstate->rel->trigdesc->trig_insert_instead_row))
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
+			cstate->rel->trigdesc != NULL &&
+			cstate->rel->trigdesc->trig_insert_new_table)
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+		return CIM_MULTI_CONDITIONAL;
+
+	return CIM_MULTI;
+}
+
+/*
+ * IsParallelCopyAllowed - check for the cases where parallel copy is not
+ * applicable.
+ */
+static pg_attribute_always_inline bool
+IsParallelCopyAllowed(CopyState cstate)
+{
+	/* Parallel copy not allowed for frontend (2.0 protocol) & binary option. */
+	if ((cstate->copy_dest == COPY_OLD_FE) || cstate->binary)
+		return false;
+
+	/* Check if copy is into foreign table or temporary table. */
+	if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
+		RelationUsesLocalBuffers(cstate->rel))
+		return false;
+
+	/* Check if trigger function is parallel safe. */
+	if (cstate->rel->trigdesc != NULL &&
+		!IsTriggerFunctionParallelSafe(cstate->rel->trigdesc))
+		return false;
+
+	/*
+	 * Check if there is after statement or instead of trigger or transition
+	 * table triggers.
+	 */
+	if (cstate->rel->trigdesc != NULL &&
+		(cstate->rel->trigdesc->trig_insert_after_statement ||
+		 cstate->rel->trigdesc->trig_insert_instead_row ||
+		 cstate->rel->trigdesc->trig_insert_new_table))
+		return false;
+
+	/* Check if the volatile expressions are parallel safe, if present any. */
+	if (!CheckExprParallelSafety(cstate))
+		return false;
+
+	/* Check if the insertion mode is single. */
+	if (FindInsertMethod(cstate) == CIM_SINGLE)
+		return false;
+
+	return true;
+}
+
+/*
  * BeginParallelCopy - start parallel copy tasks.
  *
  * Get the number of workers required to perform the parallel copy. The data
@@ -845,6 +1048,8 @@ BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
 	int  parallel_workers = 0;
 	ParallelCopyData *pcdata;
 
+	CheckTargetRelValidity(cstate);
+
 	parallel_workers = Min(nworkers, max_worker_processes);
 
 	/* Can't perform copy in parallel */
@@ -854,6 +1059,19 @@ BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
 	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
 	cstate->pcdata = pcdata;
 
+	/*
+	 * User chosen parallel copy. Determine if the parallel copy is actually
+	 * allowed. If not, go with the non-parallel mode.
+	 */
+	if (!IsParallelCopyAllowed(cstate))
+	{
+		elog(WARNING,
+			 "Parallel copy not supported for specified table, copy will be run in non-parallel mode");
+		return NULL;
+	}
+
+	full_transaction_id = GetCurrentFullTransactionId();
+
 	EnterParallelMode();
 	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
 								 parallel_workers);
@@ -1080,9 +1298,212 @@ ParallelWorkerInitialization(SerializedParallelCopyState *shared_cstate,
 	cstate->line_buf_converted = false;
 	cstate->raw_buf = NULL;
 	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+	
+	PopulateCatalogInformation(cstate);
+
+	/* Create workspace for CopyReadAttributes results. */
+	if (!cstate->binary)
+	{
+		AttrNumber	attr_count = list_length(cstate->attnumlist);
+
+		cstate->max_fields = attr_count;
+		cstate->raw_fields = (char **)palloc(attr_count * sizeof(char *));
+	}
 }
 
 /*
+ * CacheLineInfo - Cache the line information to local memory.
+ */
+static bool
+CacheLineInfo(CopyState cstate, uint32 buff_count)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	uint32			write_pos;
+	ParallelCopyDataBlock *data_blk_ptr;
+	ParallelCopyLineBoundary *lineInfo;
+	uint32 offset;
+	int dataSize;
+	int copiedSize = 0;
+
+	resetStringInfo(&pcdata->worker_line_buf[buff_count].line_buf);
+	write_pos = GetLinePosition(cstate);
+	if (-1 == write_pos)
+		return true;
+
+	/* Get the current line information. */
+	lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+	if (pg_atomic_read_u32(&lineInfo->line_size) == 0)
+		goto empty_data_line_update;
+
+	/* Get the block information. */
+	data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+	/* Get the offset information from where the data must be copied. */
+	offset = lineInfo->start_offset;
+	pcdata->worker_line_buf[buff_count].cur_lineno = lineInfo->cur_lineno;
+
+	elog(DEBUG1, "[Worker] Processing - line position:%d, block:%d, unprocessed lines:%d, offset:%d, line size:%d",
+				 write_pos, lineInfo->first_block,
+				 pg_atomic_read_u32(&data_blk_ptr->unprocessed_line_parts),
+				 offset, pg_atomic_read_u32(&lineInfo->line_size));
+
+	for (;;)
+	{
+		uint8 skip_bytes = data_blk_ptr->skip_bytes;
+		/*
+		 * There is a possibility that the above loop has come out because
+		 * data_blk_ptr->curr_blk_completed is set, but dataSize read might
+		 * be an old value, if data_blk_ptr->curr_blk_completed and the line is
+		 * completed, line_size will be set. Read the line_size again to be
+		 * sure if it is complete or partial block.
+		 */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+		if (dataSize)
+		{
+			int remainingSize = dataSize - copiedSize;
+			if (!remainingSize)
+				break;
+
+			/* Whole line is in current block. */
+			if (remainingSize + offset + skip_bytes < DATA_BLOCK_SIZE)
+			{
+				appendBinaryStringInfo(&pcdata->worker_line_buf[buff_count].line_buf,
+									   &data_blk_ptr->data[offset],
+									   remainingSize);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts,
+										1);
+				break;
+			}
+			else
+			{
+				/* Line is spread across the blocks. */
+				uint32 lineInCurrentBlock =  (DATA_BLOCK_SIZE - skip_bytes) - offset;
+				appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+										 &data_blk_ptr->data[offset],
+										 lineInCurrentBlock);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+				copiedSize += lineInCurrentBlock;
+				while (copiedSize < dataSize)
+				{
+					uint32 currentBlockCopySize;
+					ParallelCopyDataBlock *currBlkPtr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+					skip_bytes = currBlkPtr->skip_bytes;
+
+					/*
+					 * If complete data is present in current block use
+					 * dataSize - copiedSize, or copy the whole block from
+					 * current block.
+					 */
+					currentBlockCopySize = Min(dataSize - copiedSize, DATA_BLOCK_SIZE - skip_bytes);
+					appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+											 &currBlkPtr->data[0],
+											 currentBlockCopySize);
+					pg_atomic_sub_fetch_u32(&currBlkPtr->unprocessed_line_parts, 1);
+					copiedSize += currentBlockCopySize;
+					data_blk_ptr = currBlkPtr;
+				}
+
+				break;
+			}
+		}
+		else
+		{
+			/* Copy this complete block from the current offset. */
+			uint32 lineInCurrentBlock =  (DATA_BLOCK_SIZE - skip_bytes) - offset;
+			appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+									 &data_blk_ptr->data[offset],
+									 lineInCurrentBlock);
+			pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+			copiedSize += lineInCurrentBlock;
+
+			/*
+			 * Reset the offset. For the first copy, copy from the offset. For
+			 * the subsequent copy the complete block.
+			 */
+			offset = 0;
+
+			/* Set data_blk_ptr to the following block. */
+			data_blk_ptr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+		}
+
+		for (;;)
+		{
+			/* Get the size of this line */
+			dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+			/*
+			 * If the data is present in current block lineInfo.line_size
+			 * will be updated. If the data is spread across the blocks either
+			 * of lineInfo.line_size or data_blk_ptr->curr_blk_completed can
+			 * be updated. lineInfo.line_size will be updated if the complete
+			 * read is finished. data_blk_ptr->curr_blk_completed will be
+			 * updated if processing of current block is finished and data
+			 * processing is not finished.
+			 */
+			if (data_blk_ptr->curr_blk_completed || (dataSize != -1))
+				break;
+
+			COPY_WAIT_TO_PROCESS()
+		}
+	}
+
+empty_data_line_update:
+	elog(DEBUG1, "[Worker] Completed processing line:%d", write_pos);
+	pg_atomic_write_u32(&lineInfo->line_state, LINE_WORKER_PROCESSED);
+	pg_atomic_write_u32(&lineInfo->line_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+	return false;
+}
+
+/*
+ * GetWorkerLine - Returns a line for worker to process.
+ */
+static bool
+GetWorkerLine(CopyState cstate)
+{
+	uint32 buff_count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+
+	/*
+	 * Copy the line data to line_buf and release the line position so that the
+	 * worker can continue loading data.
+	 */
+	if (pcdata->worker_line_buf_pos < pcdata->worker_line_buf_count)
+		goto return_line;
+
+	pcdata->worker_line_buf_pos = 0;
+	pcdata->worker_line_buf_count = 0;
+
+	for (buff_count = 0; buff_count < WORKER_CHUNK_COUNT; buff_count++)
+	{
+		bool result = CacheLineInfo(cstate, buff_count);
+		if (result)
+			break;
+
+		pcdata->worker_line_buf_count++;
+	}
+
+	if (pcdata->worker_line_buf_count)
+		goto return_line;
+	else
+		resetStringInfo(&cstate->line_buf);
+
+	return true;
+
+return_line:
+	cstate->line_buf = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].line_buf;
+	cstate->cur_lineno = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].cur_lineno;
+	cstate->line_buf_valid = true;
+
+	/* Mark that encoding conversion hasn't occurred yet. */
+	cstate->line_buf_converted = false;
+	ConvertToServerEncoding(cstate);
+	pcdata->worker_line_buf_pos++;
+	return false;
+ }
+
+/*
  * ParallelCopyMain - parallel copy worker's code.
  *
  * Where clause handling, convert tuple to columns, add default null values for
@@ -1127,6 +1548,8 @@ ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
 	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
 
 	pcdata->pcshared_info = pcshared_info;
+	AssignFullTransactionIdForWorker(pcshared_info->full_transaction_id);
+	AssignCommandIdForWorker(pcshared_info->mycid, true);
 
 	shared_cstate = (SerializedParallelCopyState *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE,
 														   false);
@@ -1181,6 +1604,33 @@ ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
 }
 
 /*
+ * UpdateBlockInLineInfo - Update the line information.
+ */
+static pg_attribute_always_inline int
+UpdateBlockInLineInfo(CopyState cstate, uint32 blk_pos,
+					   uint32 offset, uint32 line_size, uint32 line_state)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyLineBoundaries *lineBoundaryPtr = &pcshared_info->line_boundaries;
+	ParallelCopyLineBoundary *lineInfo;
+	int line_pos = lineBoundaryPtr->pos;
+
+	/* Update the line information for the worker to pick and process. */
+	lineInfo = &lineBoundaryPtr->ring[line_pos];
+	while (pg_atomic_read_u32(&lineInfo->line_size) != -1)
+		COPY_WAIT_TO_PROCESS()
+
+	lineInfo->first_block = blk_pos;
+	lineInfo->start_offset = offset;
+	lineInfo->cur_lineno = cstate->cur_lineno;
+	pg_atomic_write_u32(&lineInfo->line_size, line_size);
+	pg_atomic_write_u32(&lineInfo->line_state, line_state);
+	lineBoundaryPtr->pos = (lineBoundaryPtr->pos + 1) % RINGSIZE;
+
+	return line_pos;
+}
+
+/*
  * ParallelCopyLeader - parallel copy leader's functionality.
  *
  * Leader will populate the shared memory and share it across the workers.
@@ -1205,8 +1655,159 @@ ParallelCopyLeader(CopyState cstate)
 	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
 	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
 
-	pcshared_info->is_read_in_progress = false;
-	cstate->cur_lineno = 0;
+	/* Execute the before statement triggers from the leader */
+	ExecBeforeStmtTrigger(cstate);
+
+	/* On input just throw the header line away. */
+	if (cstate->cur_lineno == 0 && cstate->header_line)
+	{
+		cstate->cur_lineno++;
+		if (CopyReadLine(cstate))
+		{
+			pcshared_info->is_read_in_progress = false;
+			return;			/* done */
+		}
+	}
+
+	for (;;)
+	{
+		bool done;
+		cstate->cur_lineno++;
+
+		/* Actually read the line into memory here. */
+		done = CopyReadLine(cstate);
+
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			break;
+	}
+
+ 	pcshared_info->is_read_in_progress = false;
+ 	cstate->cur_lineno = 0;
+ }
+
+/*
+ * GetLinePosition - return the line position that worker should process.
+ */
+static uint32
+GetLinePosition(CopyState cstate)
+{
+	ParallelCopyData *pcdata = cstate->pcdata;
+	ParallelCopyShmInfo *pcshared_info = pcdata->pcshared_info;
+	uint32  previous_pos = pcdata->worker_processed_pos;
+	uint32 write_pos = (previous_pos == -1) ? 0 : (previous_pos + 1) % RINGSIZE;
+	for (;;)
+	{
+		int		dataSize;
+		bool	is_read_in_progress = pcshared_info->is_read_in_progress;
+		ParallelCopyLineBoundary *lineInfo;
+		ParallelCopyDataBlock *data_blk_ptr;
+		ParallelCopyLineState line_state = LINE_LEADER_POPULATED;
+		ParallelCopyLineState curr_line_state;
+		CHECK_FOR_INTERRUPTS();
+
+		/* File read completed & no elements to process. */
+		if (!is_read_in_progress &&
+			(pcshared_info->populated ==
+			 pg_atomic_read_u64(&pcshared_info->total_worker_processed)))
+		{
+			write_pos = -1;
+			break;
+		}
+
+		/* Get the current line information. */
+		lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+		curr_line_state = pg_atomic_read_u32(&lineInfo->line_state);
+		if ((write_pos % WORKER_CHUNK_COUNT == 0) &&
+			(curr_line_state == LINE_WORKER_PROCESSED ||
+			 curr_line_state == LINE_WORKER_PROCESSING))
+		{
+			pcdata->worker_processed_pos = write_pos;
+			write_pos = (write_pos + WORKER_CHUNK_COUNT) %  RINGSIZE;
+			continue;
+		}
+
+		/* Get the size of this line. */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+		if (dataSize != 0) /* If not an empty line. */
+		{
+			/* Get the block information. */
+			data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+			if (!data_blk_ptr->curr_blk_completed && (dataSize == -1))
+			{
+				/* Wait till the current line or block is added. */
+				COPY_WAIT_TO_PROCESS()
+				continue;
+			}
+		}
+
+		/* Make sure that no worker has consumed this element. */
+		if (pg_atomic_compare_exchange_u32(&lineInfo->line_state,
+										   &line_state, LINE_WORKER_PROCESSING))
+			break;
+	}
+
+	pcdata->worker_processed_pos = write_pos;
+	return write_pos;
+}
+
+/*
+ * GetFreeCopyBlock - Get a free block for data to be copied.
+ */
+static pg_attribute_always_inline uint32
+GetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	int count = 0;
+	uint32 last_free_block = pcshared_info->cur_block_pos;
+	uint32 block_pos = (last_free_block != -1) ? ((last_free_block + 1) % MAX_BLOCKS_COUNT): 0;
+
+	/*
+	 * Get a new block for copying data, don't check curent block, current
+	 * block will have some unprocessed data.
+	 */
+	while (count < (MAX_BLOCKS_COUNT - 1))
+	{
+		ParallelCopyDataBlock *dataBlkPtr = &pcshared_info->data_blocks[block_pos];
+		uint32 unprocessed_line_parts = pg_atomic_read_u32(&dataBlkPtr->unprocessed_line_parts);
+		if (unprocessed_line_parts == 0)
+		{
+			dataBlkPtr->curr_blk_completed = false;
+			dataBlkPtr->skip_bytes = 0;
+			pcshared_info->cur_block_pos = block_pos;
+			return block_pos;
+		}
+
+		block_pos = (block_pos + 1) % MAX_BLOCKS_COUNT;
+		count++;
+	}
+
+	return -1;
+}
+
+/*
+ * WaitGetFreeCopyBlock - If there are no blocks available, wait and get a block
+ * for copying data.
+ */
+static uint32
+WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	uint32 new_free_pos = -1;
+	for (;;)
+	{
+		new_free_pos = GetFreeCopyBlock(pcshared_info);
+		if (new_free_pos != -1)	/* We have got one block, break now. */
+			break;
+
+		COPY_WAIT_TO_PROCESS()
+	}
+
+	return new_free_pos;
 }
 
 /*
@@ -1246,6 +1847,145 @@ LookupParallelCopyFnStr(copy_data_source_cb fn_addr)
 }
 
 /*
+ * SetRawBufForLoad - Set raw_buf to the shared memory where the file data must
+ * be read.
+ */
+static void
+SetRawBufForLoad(CopyState cstate, uint32 line_size, uint32 copy_buf_len,
+				 uint32 raw_buf_ptr, char **copy_raw_buf)
+{
+	ParallelCopyShmInfo	*pcshared_info;
+	uint32 cur_block_pos;
+	uint32 next_block_pos;
+	ParallelCopyDataBlock	*cur_data_blk_ptr = NULL;
+	ParallelCopyDataBlock	*next_data_blk_ptr = NULL;
+
+	if (!IsParallelCopy())
+		return;
+
+	pcshared_info = cstate->pcdata->pcshared_info;
+	cur_block_pos = pcshared_info->cur_block_pos;
+	cur_data_blk_ptr = (cstate->raw_buf) ? &pcshared_info->data_blocks[cur_block_pos] : NULL;
+	next_block_pos = WaitGetFreeCopyBlock(pcshared_info);
+	next_data_blk_ptr = &pcshared_info->data_blocks[next_block_pos];
+
+	/* set raw_buf to the data block in shared memory */
+	cstate->raw_buf = next_data_blk_ptr->data;
+	*copy_raw_buf = cstate->raw_buf;
+	if (cur_data_blk_ptr && line_size)
+	{
+		/*
+		 * Mark the previous block as completed, worker can start copying this
+		 * data.
+		 */
+		cur_data_blk_ptr->following_block = next_block_pos;
+		pg_atomic_add_fetch_u32(&cur_data_blk_ptr->unprocessed_line_parts, 1);
+		cur_data_blk_ptr->skip_bytes = copy_buf_len - raw_buf_ptr;
+		cur_data_blk_ptr->curr_blk_completed = true;
+	}
+}
+
+/*
+ * EndLineParallelCopy - Update the line information in shared memory.
+ */
+static void
+EndLineParallelCopy(CopyState cstate, uint32 line_pos, uint32 line_size,
+					 uint32 raw_buf_ptr)
+{
+	uint8 new_line_size;
+	if (!IsParallelCopy())
+		return;
+
+	if (!IsHeaderLine())
+	{
+		ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+		ParallelCopyLineBoundaries *lineBoundaryPtr = &pcshared_info->line_boundaries;
+		SET_NEWLINE_SIZE()
+		if (line_size)
+		{
+			ParallelCopyLineBoundary *lineInfo = &lineBoundaryPtr->ring[line_pos];
+			/*
+			 * If the new_line_size > raw_buf_ptr, then the new block has only
+			 * new line char content. The unprocessed count should not be
+			 * increased in this case.
+			 */
+			if (raw_buf_ptr > new_line_size)
+			{
+				uint32 cur_block_pos = pcshared_info->cur_block_pos;
+				ParallelCopyDataBlock *curr_data_blk_ptr = &pcshared_info->data_blocks[cur_block_pos];
+				pg_atomic_add_fetch_u32(&curr_data_blk_ptr->unprocessed_line_parts, 1);
+			}
+
+			/* Update line size. */
+			pg_atomic_write_u32(&lineInfo->line_size, line_size);
+			pg_atomic_write_u32(&lineInfo->line_state, LINE_LEADER_POPULATED);
+			elog(DEBUG1, "[Leader] After adding - line position:%d, line_size:%d",
+						 line_pos, line_size);
+			pcshared_info->populated++;
+		}
+		else if (new_line_size)
+		{
+			/* This means only new line char, empty record should be inserted.*/
+			ParallelCopyLineBoundary *lineInfo;
+			line_pos = UpdateBlockInLineInfo(cstate, -1, -1, 0,
+											   LINE_LEADER_POPULATED);
+			lineInfo = &lineBoundaryPtr->ring[line_pos];
+			elog(DEBUG1, "[Leader] Added empty line with offset:%d, line position:%d, line size:%d",
+						 lineInfo->start_offset, line_pos,
+						 pg_atomic_read_u32(&lineInfo->line_size));
+			pcshared_info->populated++;
+		}
+	}
+}
+
+/*
+ * ExecBeforeStmtTrigger - Execute the before statement trigger, this will be
+ * executed for parallel copy by the leader process.
+ */
+static void
+ExecBeforeStmtTrigger(CopyState cstate)
+{
+	EState	   *estate = CreateExecutorState();
+	ResultRelInfo *resultRelInfo;
+
+	Assert(IsLeader());
+
+	/*
+	 * We need a ResultRelInfo so we can use the regular executor's
+	 * index-entry-making machinery.  (There used to be a huge amount of code
+	 * here that basically duplicated execUtils.c ...)
+	 */
+	resultRelInfo = makeNode(ResultRelInfo);
+	InitResultRelInfo(resultRelInfo,
+					  cstate->rel,
+					  1,		/* must match rel's position in range_table */
+					  NULL,
+					  0);
+
+	/* Verify the named relation is a valid target for INSERT */
+	CheckValidResultRel(resultRelInfo, CMD_INSERT);
+
+	estate->es_result_relations = resultRelInfo;
+	estate->es_num_result_relations = 1;
+	estate->es_result_relation_info = resultRelInfo;
+
+	ExecInitRangeTable(estate, cstate->range_table);
+
+	/*
+	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
+	 * should do this for COPY, since it's not really an "INSERT" statement as
+	 * such. However, executing these triggers maintains consistency with the
+	 * EACH ROW triggers that we already fire on COPY.
+	 */
+	ExecBSInsertTriggers(estate, resultRelInfo);
+
+	/* Close any trigger target relations */
+	ExecCleanUpTriggerState(estate);
+
+	FreeExecutorState(estate);
+}
+
+/*
  * Send copy start/stop messages for frontend copies.  These have changed
  * in past protocol redesigns.
  */
@@ -3677,7 +4417,8 @@ CopyFrom(CopyState cstate)
 
 	PartitionTupleRouting *proute = NULL;
 	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
+	CommandId	mycid = IsParallelCopy() ? GetCurrentCommandId(false) :
+										   GetCurrentCommandId(true);
 	int			ti_options = 0; /* start with default options for insert */
 	BulkInsertState bistate = NULL;
 	CopyInsertMethod insertMethod;
@@ -3687,7 +4428,14 @@ CopyFrom(CopyState cstate)
 	bool		has_instead_insert_row_trig;
 	bool		leafpart_use_multi_insert = false;
 
-	CheckTargetRelValidity(cstate);
+	/*
+	 * Perform this check if it is not parallel copy. In case of parallel
+	 * copy, this check is done by the leader, so that if any invalid case
+	 * exist the copy from command will error out from the leader itself,
+	 * avoiding launching workers, just to throw error.
+	 */
+	if (!IsParallelCopy())
+		CheckTargetRelValidity(cstate);
 
 	/*
 	 * If the target file is new-in-transaction, we assume that checking FSM
@@ -3876,13 +4624,16 @@ CopyFrom(CopyState cstate)
 	has_instead_insert_row_trig = (resultRelInfo->ri_TrigDesc &&
 								   resultRelInfo->ri_TrigDesc->trig_insert_instead_row);
 
-	/*
-	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
-	 * should do this for COPY, since it's not really an "INSERT" statement as
-	 * such. However, executing these triggers maintains consistency with the
-	 * EACH ROW triggers that we already fire on COPY.
-	 */
-	ExecBSInsertTriggers(estate, resultRelInfo);
+	if (!IsParallelCopy())
+	{
+		/*
+		 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
+		 * should do this for COPY, since it's not really an "INSERT" statement as
+		 * such. However, executing these triggers maintains consistency with the
+		 * EACH ROW triggers that we already fire on COPY.
+		 */
+		ExecBSInsertTriggers(estate, resultRelInfo);
+	}
 
 	econtext = GetPerTupleExprContext(estate);
 
@@ -3982,6 +4733,16 @@ CopyFrom(CopyState cstate)
 					!has_instead_insert_row_trig &&
 					resultRelInfo->ri_FdwRoutine == NULL;
 
+				/*
+				 * If the table has any partitions that are either foreign or
+				 * has BEFORE/INSTEAD OF triggers, we can't perform copy
+				 * operations with parallel workers.
+				 */
+				if (!leafpart_use_multi_insert && IsParallelWorker())
+					ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							errmsg("cannot perform PARALLEL COPY if partition has BEFORE/INSTEAD OF triggers, or if the partition is foreign partition"),
+							errhint("Try COPY without PARALLEL option")));
+
 				/* Set the multi-insert buffer to use for this partition. */
 				if (leafpart_use_multi_insert)
 				{
@@ -4402,7 +5163,7 @@ BeginCopyFrom(ParseState *pstate,
 	{
 		initStringInfo(&cstate->line_buf);
 		cstate->line_buf_converted = false;
-		cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+		cstate->raw_buf = (IsParallelCopy()) ? NULL : (char *) palloc(RAW_BUF_SIZE + 1);
 		cstate->raw_buf_index = cstate->raw_buf_len = 0;
 	}
 
@@ -4547,26 +5308,35 @@ NextCopyFromRawFields(CopyState cstate, char ***fields, int *nfields)
 	/* only available for text or csv input */
 	Assert(!cstate->binary);
 
-	/* on input just throw the header line away */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (IsParallelCopy())
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
-			return false;		/* done */
+		done = GetWorkerLine(cstate);
+		if (done && cstate->line_buf.len == 0)
+			return false;
 	}
+	else
+	{
+		/* on input just throw the header line away */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
+		{
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+				return false;		/* done */
+		}
 
-	cstate->cur_lineno++;
+		cstate->cur_lineno++;
 
-	/* Actually read the line into memory here */
-	done = CopyReadLine(cstate);
+		/* Actually read the line into memory here */
+		done = CopyReadLine(cstate);
 
-	/*
-	 * EOF at start of line means we're done.  If we see EOF after some
-	 * characters, we act as though it was newline followed by EOF, ie,
-	 * process the line and then exit loop on next iteration.
-	 */
-	if (done && cstate->line_buf.len == 0)
-		return false;
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			return false;
+	}
 
 	/* Parse the line into de-escaped field values */
 	if (cstate->csv_mode)
@@ -4814,9 +5584,31 @@ CopyReadLine(CopyState cstate)
 		 */
 		if (cstate->copy_dest == COPY_NEW_FE)
 		{
+			bool bIsFirst = true;
 			do
 			{
-				cstate->raw_buf_index = cstate->raw_buf_len;
+				if (!IsParallelCopy())
+					cstate->raw_buf_index = cstate->raw_buf_len;
+				else
+				{
+					if (cstate->raw_buf_index == RAW_BUF_SIZE)
+					{
+						/* Get a new block if it is the first time, From the
+						 * subsequent time, reset the index and re-use the same
+						 * block.
+						 */
+						if (bIsFirst)
+						{
+							ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+							uint32 block_pos = WaitGetFreeCopyBlock(pcshared_info);
+							cstate->raw_buf = pcshared_info->data_blocks[block_pos].data;
+							bIsFirst = false;
+						}
+
+						cstate->raw_buf_index = cstate->raw_buf_len = 0;
+					}
+				}
+
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
@@ -4871,7 +5663,8 @@ static void
 ConvertToServerEncoding(CopyState cstate)
 {
 	/* Done reading the line.  Convert it to server encoding. */
-	if (cstate->need_transcoding)
+	if (cstate->need_transcoding &&
+		(!IsParallelCopy() || (IsParallelCopy() && !IsLeader())))
 	{
 		char	   *cvt;
 		cvt = pg_any_to_server(cstate->line_buf.data,
@@ -4910,6 +5703,11 @@ CopyReadLineText(CopyState cstate)
 	char		quotec = '\0';
 	char		escapec = '\0';
 
+	/* For parallel copy */
+	int			line_size = 0;
+	int			line_pos = 0;
+
+	cstate->eol_type = EOL_UNKNOWN;
 	if (cstate->csv_mode)
 	{
 		quotec = cstate->quote[0];
@@ -4964,6 +5762,8 @@ CopyReadLineText(CopyState cstate)
 		if (raw_buf_ptr >= copy_buf_len || need_data)
 		{
 			REFILL_LINEBUF;
+			SetRawBufForLoad(cstate, line_size, copy_buf_len, raw_buf_ptr,
+							 &copy_raw_buf);
 
 			/*
 			 * Try to read some more data.  This will certainly reset
@@ -5188,9 +5988,15 @@ CopyReadLineText(CopyState cstate)
 				 * discard the data and the \. sequence.
 				 */
 				if (prev_raw_ptr > cstate->raw_buf_index)
-					appendBinaryStringInfo(&cstate->line_buf,
+				{
+					if (!IsParallelCopy())
+						appendBinaryStringInfo(&cstate->line_buf,
 										   cstate->raw_buf + cstate->raw_buf_index,
 										   prev_raw_ptr - cstate->raw_buf_index);
+					else
+						line_size += prev_raw_ptr - cstate->raw_buf_index;
+				}
+
 				cstate->raw_buf_index = raw_buf_ptr;
 				result = true;	/* report EOF */
 				break;
@@ -5242,6 +6048,26 @@ not_end_of_copy:
 			IF_NEED_REFILL_AND_EOF_BREAK(mblen - 1);
 			raw_buf_ptr += mblen - 1;
 		}
+
+		/*
+		 * Skip the header line. Update the line here, this cannot be done at
+		 * the beginning, as there is a possibility that file contains empty
+		 * lines.
+		 */
+		if (IsParallelCopy() && first_char_in_line && !IsHeaderLine())
+		{
+			ParallelCopyShmInfo	*pcshared_info = cstate->pcdata->pcshared_info;
+			ParallelCopyLineBoundary *lineInfo;
+			uint32			 line_first_block = pcshared_info->cur_block_pos;
+			line_pos = UpdateBlockInLineInfo(cstate,
+											   line_first_block,
+											   cstate->raw_buf_index, -1,
+											   LINE_LEADER_POPULATING);
+			lineInfo = &pcshared_info->line_boundaries.ring[line_pos];
+			elog(DEBUG1, "[Leader] Adding - block:%d, offset:%d, line position:%d",
+						 line_first_block,	lineInfo->start_offset, line_pos);
+		}
+
 		first_char_in_line = false;
 	}							/* end of outer loop */
 
@@ -5250,6 +6076,7 @@ not_end_of_copy:
 	 */
 	REFILL_LINEBUF;
 	CLEAR_EOL_LINE();
+	EndLineParallelCopy(cstate, line_pos, line_size, raw_buf_ptr);
 
 	return result;
 }
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index db19187..20dafb7 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -381,6 +381,8 @@ extern FullTransactionId GetTopFullTransactionId(void);
 extern FullTransactionId GetTopFullTransactionIdIfAny(void);
 extern FullTransactionId GetCurrentFullTransactionId(void);
 extern FullTransactionId GetCurrentFullTransactionIdIfAny(void);
+extern void AssignFullTransactionIdForWorker(FullTransactionId fullTransactionId);
+extern void AssignCommandIdForWorker(CommandId commandId, bool used);
 extern void MarkCurrentTransactionIdLoggedIfAny(void);
 extern bool SubTransactionIsActive(SubTransactionId subxid);
 extern CommandId GetCurrentCommandId(bool used);
-- 
1.8.3.1

0004-Documentation-for-parallel-copy.patchapplication/x-patch; name=0004-Documentation-for-parallel-copy.patchDownload
From 065975f77b0ddfe06911b68abee2fec27e695afa Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Thu, 16 Jul 2020 22:07:34 +0530
Subject: [PATCH 4/6] Documentation for parallel copy.

This patch has the documentation changes for parallel copy.
---
 doc/src/sgml/ref/copy.sgml | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/doc/src/sgml/ref/copy.sgml b/doc/src/sgml/ref/copy.sgml
index 18189ab..95d349d 100644
--- a/doc/src/sgml/ref/copy.sgml
+++ b/doc/src/sgml/ref/copy.sgml
@@ -37,6 +37,7 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
     DELIMITER '<replaceable class="parameter">delimiter_character</replaceable>'
     NULL '<replaceable class="parameter">null_string</replaceable>'
     HEADER [ <replaceable class="parameter">boolean</replaceable> ]
+    PARALLEL <replaceable class="parameter">integer</replaceable>
     QUOTE '<replaceable class="parameter">quote_character</replaceable>'
     ESCAPE '<replaceable class="parameter">escape_character</replaceable>'
     FORCE_QUOTE { ( <replaceable class="parameter">column_name</replaceable> [, ...] ) | * }
@@ -275,6 +276,21 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
    </varlistentry>
 
    <varlistentry>
+    <term><literal>PARALLEL</literal></term>
+    <listitem>
+     <para>
+      Perform <command>COPY FROM</command> in parallel using <replaceable
+      class="parameter"> integer</replaceable> background workers.  Please
+      note that it is not guaranteed that the number of parallel workers
+      specified in <replaceable class="parameter">integer</replaceable> will
+      be used during execution.  It is possible for a copy to run with fewer
+      workers than specified, or even with no workers at all.  This option is
+      allowed only in <command>COPY FROM</command>.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><literal>QUOTE</literal></term>
     <listitem>
      <para>
-- 
1.8.3.1

0005-Tests-for-parallel-copy.patchapplication/x-patch; name=0005-Tests-for-parallel-copy.patchDownload
From 28c62ea99cf3ed6700028c077a3e41d2f3398a22 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Thu, 16 Jul 2020 22:10:11 +0530
Subject: [PATCH 5/6] Tests for parallel copy.

This patch has the tests for parallel copy.
---
 src/test/regress/expected/copy2.out | 210 +++++++++++++++++++++++++++++++++++-
 src/test/regress/input/copy.source  |  12 +++
 src/test/regress/output/copy.source |  12 +++
 src/test/regress/sql/copy2.sql      | 208 ++++++++++++++++++++++++++++++++++-
 4 files changed, 434 insertions(+), 8 deletions(-)

diff --git a/src/test/regress/expected/copy2.out b/src/test/regress/expected/copy2.out
index e40287d..ef75148 100644
--- a/src/test/regress/expected/copy2.out
+++ b/src/test/regress/expected/copy2.out
@@ -254,18 +254,32 @@ It is "perfect".|
 "It is ""perfect"".","	"
 "",
 --test that we read consecutive LFs properly
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 COPY testnl FROM stdin CSV;
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+SELECT * FROM testnl;
+ a |          b           | c 
+---+----------------------+---
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+(2 rows)
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 COPY testeoc FROM stdin CSV;
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
 COPY testeoc TO stdout CSV;
 a\.
 \.b
 c\.d
 "\."
 -- test handling of nonstandard null marker that violates escaping rules
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 COPY testnull TO stdout WITH NULL AS E'\\0';
 1	\\0
@@ -280,6 +294,15 @@ SELECT * FROM testnull;
     | 
 (4 rows)
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 1);
+SELECT * FROM testnull;
+ a  | b  
+----+----
+ 42 | \0
+    | 
+(2 rows)
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -349,6 +372,34 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+SELECT * FROM vistest;
+ a  
+----
+ a2
+ b
+(2 rows)
+
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+COMMIT;
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 SELECT * FROM vistest;
  a 
@@ -409,7 +460,7 @@ SELECT * FROM vistest;
 (2 rows)
 
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -420,6 +471,8 @@ CREATE TEMP TABLE forcetest (
 -- should succeed with no effect ("b" remains an empty string, "c" remains NULL)
 BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 1);
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
  b |  c   
@@ -430,6 +483,8 @@ SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
 BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 1);
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
  c |  d   
@@ -486,6 +541,31 @@ select * from check_con_tbl;
    
 (2 rows)
 
+\d+ check_con_tbl
+                               Table "public.check_con_tbl"
+ Column |  Type   | Collation | Nullable | Default | Storage | Stats target | Description 
+--------+---------+-----------+----------+---------+---------+--------------+-------------
+ f1     | integer |           |          |         | plain   |              | 
+Check constraints:
+    "check_con_tbl_check" CHECK (check_con_function(check_con_tbl.*))
+
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 1);
+NOTICE:  input = {"f1":1}
+NOTICE:  input = {"f1":null}
+copy check_con_tbl from stdin with (parallel 1);
+NOTICE:  input = {"f1":0}
+ERROR:  new row for relation "check_con_tbl" violates check constraint "check_con_tbl_check"
+DETAIL:  Failing row contains (0).
+CONTEXT:  COPY check_con_tbl, line 1: "0"
+parallel worker
+select * from check_con_tbl;
+ f1 
+----
+  1
+   
+(2 rows)
+
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
 CREATE ROLE regress_rls_copy_user_colperms;
@@ -600,8 +680,130 @@ SELECT * FROM instead_of_insert_tbl;
 (2 rows)
 
 COMMIT;
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+COPY test_parallel_copy (a, b, c, d, e) from stdin with (PARALLEL 1);
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1, FORMAT 'csv', HEADER);
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0');
+ERROR:  argument to option "parallel" must be a positive integer greater than zero
+LINE 1: COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0'...
+                                                        ^
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri from stdin with (FORMAT csv, DELIMITER ',', PARALLEL 1);
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1) WHERE height > random() * 65;
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- temporary table copy: should peform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+COPY temp_test (a) from stdin with (PARALLEL 1);
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) from stdin with (PARALLEL 1);
+ERROR:  column "xyz" of relation "test_parallel_copy" does not exist
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) from stdin with (PARALLEL 1);
+ERROR:  column "d" specified more than once
+-- missing data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  invalid input syntax for type integer: ""
+CONTEXT:  COPY test_parallel_copy, line 0, column a: ""
+parallel worker
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2000	230	23	23"
+parallel worker
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2001	231	\N	\N"
+parallel worker
+-- extra data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  extra data after last expected column
+CONTEXT:  COPY test_parallel_copy, line 1: "2002	232	40	50	60	70	80"
+parallel worker
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) from stdin with (delimiter ',', null 'x', PARALLEL 1) ;
+COPY test_parallel_copy from stdin WITH (DELIMITER ';', NULL '', PARALLEL 1);
+COPY test_parallel_copy from stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL 1);
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = 50004;
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a > 60003;
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE f > 60003;
+ERROR:  column "f" does not exist
+LINE 1: ..._parallel_copy from stdin WITH (PARALLEL 1) WHERE f > 60003;
+                                                             ^
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+ERROR:  missing FROM-clause entry for table "x"
+LINE 1: ...rallel_copy from stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+                                                                  ^
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (SELECT 1 FROM x);
+ERROR:  cannot use subquery in COPY FROM WHERE condition
+LINE 1: ...arallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (SELECT...
+                                                             ^
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (generate_series(1,5));
+ERROR:  set-returning functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...lel_copy from stdin WITH (PARALLEL 1) WHERE a IN (generate_s...
+                                                             ^
+COPY test_parallel_copy from stdin WITH(PARALLEL 1) WHERE a = row_number() over(b);
+ERROR:  window functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...rallel_copy from stdin WITH(PARALLEL 1) WHERE a = row_number...
+                                                             ^
+-- check results of copy in
+SELECT * FROM test_parallel_copy;
+   a   | b  |     c      |    d    |    e    
+-------+----+------------+---------+---------
+     1 | 11 | test_c1    | test_d1 | test_e1
+     2 | 12 | test_c2    | test_d2 | test_e2
+       |  3 | stuff      | test_d3 | 
+       |  4 | stuff      | test_d4 | 
+       |  5 | stuff      | test_d5 | 
+       |    | 45         | 80      | 90
+       |    | x          | \x      | \x
+       |    | ,          | \,      | \
+  3000 |    | c          |         | 
+  4000 |    | C          |         | 
+  4001 |  1 | empty      |         | 
+  4002 |  2 | null       |         | 
+  4003 |  3 | Backslash  | \       | \
+  4004 |  4 | BackslashX | \X      | \X
+  4005 |  5 | N          | N       | N
+  4006 |  6 | BackslashN | \N      | \N
+  4007 |  7 | XX         | XX      | XX
+  4008 |  8 | Delimiter  | :       | :
+ 50004 | 25 | 35         | 45      | 55
+ 60004 | 25 | 35         | 45      | 55
+ 60005 | 26 | 36         | 46      | 56
+(21 rows)
+
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
 DROP TABLE x, y;
diff --git a/src/test/regress/input/copy.source b/src/test/regress/input/copy.source
index a1d529a..159c058 100644
--- a/src/test/regress/input/copy.source
+++ b/src/test/regress/input/copy.source
@@ -15,6 +15,13 @@ DELETE FROM onek;
 
 COPY onek FROM '@abs_builddir@/results/onek.data';
 
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+
+SELECT COUNT(*) FROM tenk1;
+
+TRUNCATE tenk1;
+
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
@@ -159,6 +166,11 @@ truncate parted_copytest;
 
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
 
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
+
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/output/copy.source b/src/test/regress/output/copy.source
index 938d355..c3003fe 100644
--- a/src/test/regress/output/copy.source
+++ b/src/test/regress/output/copy.source
@@ -9,6 +9,15 @@ COPY onek FROM '@abs_srcdir@/data/onek.data';
 COPY onek TO '@abs_builddir@/results/onek.data';
 DELETE FROM onek;
 COPY onek FROM '@abs_builddir@/results/onek.data';
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+SELECT COUNT(*) FROM tenk1;
+ count 
+-------
+ 10000
+(1 row)
+
+TRUNCATE tenk1;
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
 COPY person FROM '@abs_srcdir@/data/person.data';
@@ -113,6 +122,9 @@ insert into parted_copytest select x,1,'One' from generate_series(1011,1020) x;
 copy (select * from parted_copytest order by a) to '@abs_builddir@/results/parted_copytest.csv';
 truncate parted_copytest;
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/sql/copy2.sql b/src/test/regress/sql/copy2.sql
index 902f4fa..032cea9 100644
--- a/src/test/regress/sql/copy2.sql
+++ b/src/test/regress/sql/copy2.sql
@@ -157,7 +157,7 @@ COPY y TO stdout (FORMAT CSV, FORCE_QUOTE *);
 
 --test that we read consecutive LFs properly
 
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 
 COPY testnl FROM stdin CSV;
 1,"a field with two LFs
@@ -165,8 +165,16 @@ COPY testnl FROM stdin CSV;
 inside",2
 \.
 
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+1,"a field with two LFs
+
+inside",2
+\.
+
+SELECT * FROM testnl;
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 
 COPY testeoc FROM stdin CSV;
 a\.
@@ -175,11 +183,19 @@ c\.d
 "\."
 \.
 
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+a\.
+\.b
+c\.d
+"\."
+\.
+
 COPY testeoc TO stdout CSV;
 
 -- test handling of nonstandard null marker that violates escaping rules
 
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 
 COPY testnull TO stdout WITH NULL AS E'\\0';
@@ -191,6 +207,14 @@ COPY testnull FROM stdin WITH NULL AS E'\\0';
 
 SELECT * FROM testnull;
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 1);
+42	\\0
+\0	\0
+\.
+
+SELECT * FROM testnull;
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -235,6 +259,23 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+a2
+b
+\.
+SELECT * FROM vistest;
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+d2
+e
+\.
+SELECT * FROM vistest;
+COMMIT;
+SELECT * FROM vistest;
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 x
 y
@@ -284,7 +325,7 @@ SELECT * FROM vistest;
 COMMIT;
 SELECT * FROM vistest;
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -297,6 +338,10 @@ BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
 1,,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 1);
+1,,""
+\.
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
@@ -304,6 +349,10 @@ BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
 2,'a',,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 1);
+2,'a',,""
+\.
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
 -- should fail with not-null constraint violation
@@ -339,6 +388,16 @@ copy check_con_tbl from stdin;
 0
 \.
 select * from check_con_tbl;
+\d+ check_con_tbl
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 1);
+1
+\N
+\.
+copy check_con_tbl from stdin with (parallel 1);
+0
+\.
+select * from check_con_tbl;
 
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
@@ -440,8 +499,149 @@ test1
 SELECT * FROM instead_of_insert_tbl;
 COMMIT;
 
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+
+COPY test_parallel_copy (a, b, c, d, e) from stdin with (PARALLEL 1);
+1	11	test_c1	test_d1	test_e1
+2	12	test_c2	test_d2	test_e2
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+3	test_d3
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+4	test_d4
+5	test_d5
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1, FORMAT 'csv', HEADER);
+b	d
+\.
+
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0');
+
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri from stdin with (FORMAT csv, DELIMITER ',', PARALLEL 1);
+10
+\.
+
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1) WHERE height > random() * 65;
+60,60,60
+\.
+
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+60
+\.
+
+-- temporary table copy: should peform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+
+COPY temp_test (a) from stdin with (PARALLEL 1);
+10
+\.
+
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) from stdin with (PARALLEL 1);
+
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) from stdin with (PARALLEL 1);
+
+-- missing data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+
+\.
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+2000	230	23	23
+\.
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+2001	231	\N	\N
+\.
+
+-- extra data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+2002	232	40	50	60	70	80
+\.
+
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) from stdin with (delimiter ',', null 'x', PARALLEL 1) ;
+x,45,80,90
+x,\x,\\x,\\\x
+x,\,,\\\,,\\
+\.
+
+COPY test_parallel_copy from stdin WITH (DELIMITER ';', NULL '', PARALLEL 1);
+3000;;c;;
+\.
+
+COPY test_parallel_copy from stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL 1);
+4000:\X:C:\X:\X
+4001:1:empty::
+4002:2:null:\X:\X
+4003:3:Backslash:\\:\\
+4004:4:BackslashX:\\X:\\X
+4005:5:N:\N:\N
+4006:6:BackslashN:\\N:\\N
+4007:7:XX:\XX:\XX
+4008:8:Delimiter:\::\:
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = 50004;
+50003	24	34	44	54
+50004	25	35	45 	55
+50005	26	36	46	56
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a > 60003;
+60001	22	32	42	52
+60002	23	33	43	53
+60003	24	34	44	54
+60004	25	35	45	55
+60005	26	36	46	56
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE f > 60003;
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (SELECT 1 FROM x);
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (generate_series(1,5));
+
+COPY test_parallel_copy from stdin WITH(PARALLEL 1) WHERE a = row_number() over(b);
+
+-- check results of copy in
+SELECT * FROM test_parallel_copy;
+
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
 DROP TABLE x, y;
-- 
1.8.3.1

0006-Parallel-Copy-For-Binary-Format-Files.patchapplication/x-patch; name=0006-Parallel-Copy-For-Binary-Format-Files.patchDownload
From 6cf067d7b4600322a3f980a37adaa924e41bf07a Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Thu, 16 Jul 2020 22:15:37 +0530
Subject: [PATCH 6/6] Parallel Copy For Binary Format Files

Leader reads data from the file into the DSM data blocks each of 64K size.
It also identifies each tuple data block id, start offset, end offset,
tuple size and updates this information in the ring data structure.
Workers parallely read the tuple information from the ring data structure,
the actual tuple data from the data blocks and parallely insert the tuples
into the table.
---
 src/backend/commands/copy.c | 656 ++++++++++++++++++++++++++++++++++++++------
 1 file changed, 575 insertions(+), 81 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index b709b2f..3b8fe7d 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -256,6 +256,17 @@ typedef struct ParallelCopyLineBuf
 }ParallelCopyLineBuf;
 
 /*
+ * Represents the usage mode for CopyReadBinaryGetDataBlock.
+ */
+typedef enum FieldInfoType
+{
+	FIELD_NONE = 0,
+	FIELD_COUNT,
+	FIELD_SIZE,
+	FIELD_DATA
+} FieldInfoType;
+
+/*
  * Parallel copy data information.
  */
 typedef struct ParallelCopyData
@@ -276,6 +287,9 @@ typedef struct ParallelCopyData
 
 	/* Current position in worker_line_buf */
 	uint32				worker_line_buf_pos;
+
+	/* For binary formatted files */
+	ParallelCopyDataBlock *curr_data_block;
 }ParallelCopyData;
 
 /*
@@ -436,6 +450,7 @@ typedef struct SerializedParallelCopyState
 	/* Working state for COPY FROM */
 	AttrNumber          num_defaults;
 	Oid                 relid;
+	bool				binary;
 }SerializedParallelCopyState;
 
 /*
@@ -541,7 +556,6 @@ typedef struct CopyMultiInsertInfo
 	int			ti_options;		/* table insert options */
 } CopyMultiInsertInfo;
 
-
 /*
  * These macros centralize code used to process line_buf and raw_buf buffers.
  * They are macros because they often do continue/break control and to avoid
@@ -682,8 +696,110 @@ else \
 
 /* End parallel copy Macros */
 
-static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
+/*
+ * CHECK_FIELD_COUNT - Handles the error cases for field count
+ * for binary format files.
+ */
+#define CHECK_FIELD_COUNT \
+{\
+	if (fld_count == -1) \
+	{ \
+		if (IsParallelCopy() && \
+			!IsLeader()) \
+			return true; \
+		else if (IsParallelCopy() && \
+			IsLeader()) \
+		{ \
+			if (cstate->pcdata->curr_data_block->data[cstate->raw_buf_index + sizeof(fld_count)] != 0) \
+				ereport(ERROR, \
+						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+						errmsg("received copy data after EOF marker"))); \
+			return true; \
+		} \
+		else \
+		{ \
+			/* \
+			* Received EOF marker.  In a V3-protocol copy, wait for the \
+			* protocol-level EOF, and complain if it doesn't come \
+			* immediately.  This ensures that we correctly handle CopyFail, \
+			* if client chooses to send that now. \
+			* \
+			* Note that we MUST NOT try to read more data in an old-protocol \
+			* copy, since there is no protocol-level EOF marker then.  We \
+			* could go either way for copy from file, but choose to throw \
+			* error if there's data after the EOF marker, for consistency \
+			* with the new-protocol case. \
+			*/ \
+			char		dummy; \
+			if (cstate->copy_dest != COPY_OLD_FE && \
+				CopyGetData(cstate, &dummy, 1, 1) > 0) \
+				ereport(ERROR, \
+						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+						errmsg("received copy data after EOF marker"))); \
+				return false; \
+		} \
+	} \
+	if (fld_count != cstate->max_fields) \
+		ereport(ERROR, \
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+				errmsg("row field count is %d, expected %d", \
+				(int) fld_count, cstate->max_fields))); \
+}
+
+/*
+ * CHECK_FIELD_SIZE - Handles the error case for field size
+ * for binary format files.
+ */
+#define CHECK_FIELD_SIZE(fld_size) \
+{ \
+	if (fld_size < -1) \
+		ereport(ERROR, \
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+				errmsg("invalid field size")));\
+}
 
+/*
+ * EOF_ERROR - Error statement for EOF for binary format
+ * files.
+ */
+#define EOF_ERROR \
+{ \
+	ereport(ERROR, \
+		(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+		errmsg("unexpected EOF in COPY data")));\
+}
+
+/*
+ * GET_RAW_BUF_INDEX - Caclulates the raw buf index for the cases
+ * where the data spread is across multiple data blocks.
+ */
+#define GET_RAW_BUF_INDEX(raw_buf_index, fld_size, required_blks, curr_blk_bytes) \
+{ \
+	raw_buf_index = fld_size - (((required_blks - 1) * DATA_BLOCK_SIZE) + curr_blk_bytes); \
+}
+
+/*
+ * GET_REQUIRED_BLOCKS - Caclulates the number of data
+ * blocks required for the cases where the data spread
+ * is across multiple data blocks.
+ */
+#define GET_REQUIRED_BLOCKS(required_blks, fld_size, curr_blk_bytes) \
+{ \
+	/* \
+	 * field size can spread across multiple data blocks, \
+	 * calculate the number of required data blocks and try to get \
+	 * those many data blocks. \
+	 */ \
+	required_blks = (int32)(fld_size - curr_blk_bytes)/(int32)DATA_BLOCK_SIZE; \
+	/* \
+	 * check if we need the data block for the field data \
+	 * bytes that are not modulus of data block size. \
+	 */ \
+	if ((fld_size - curr_blk_bytes)%DATA_BLOCK_SIZE != 0) \
+		required_blks++; \
+}
+
+static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
 /* non-export function prototypes */
 static CopyState BeginCopy(ParseState *pstate, bool is_from, Relation rel,
@@ -739,6 +855,14 @@ static void ExecBeforeStmtTrigger(CopyState cstate);
 static void CheckTargetRelValidity(CopyState cstate);
 static void PopulateCatalogInformation(CopyState cstate);
 static pg_attribute_always_inline uint32 GetLinePosition(CopyState cstate);
+static uint32 WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info);
+static bool CopyReadBinaryTupleLeader(CopyState cstate);
+static void CopyReadBinaryFindTupleSize(CopyState cstate, uint32 *line_size);
+static bool CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls);
+static Datum CopyReadBinaryAttributeWorker(CopyState cstate, FmgrInfo *flinfo,
+										   Oid typioparam, int32 typmod, bool *isnull);
+static void CopyReadBinaryGetDataBlock(CopyState cstate, FieldInfoType field_info);
+
 /*
  * SerializeParallelCopyState - Copy shared_cstate using cstate information.
  */
@@ -756,6 +880,7 @@ SerializeParallelCopyState(CopyState cstate, SerializedParallelCopyState *shared
 	shared_cstate->convert_selectively = cstate->convert_selectively;
 	shared_cstate->num_defaults = cstate->num_defaults;
 	shared_cstate->relid = cstate->pcdata->relid;
+	shared_cstate->binary = cstate->binary;
 }
 
 /*
@@ -984,8 +1109,8 @@ FindInsertMethod(CopyState cstate)
 static pg_attribute_always_inline bool
 IsParallelCopyAllowed(CopyState cstate)
 {
-	/* Parallel copy not allowed for frontend (2.0 protocol) & binary option. */
-	if ((cstate->copy_dest == COPY_OLD_FE) || cstate->binary)
+	/* Parallel copy not allowed for frontend (2.0 protocol). */
+	if (cstate->copy_dest == COPY_OLD_FE)
 		return false;
 
 	/* Check if copy is into foreign table or temporary table. */
@@ -1277,6 +1402,7 @@ ParallelWorkerInitialization(SerializedParallelCopyState *shared_cstate,
 	cstate->convert_selectively = shared_cstate->convert_selectively;
 	cstate->num_defaults = shared_cstate->num_defaults;
 	pcdata->relid = shared_cstate->relid;
+	cstate->binary = shared_cstate->binary;
 
 	PopulateGlobalsForCopyFrom(cstate, tup_desc, attnamelist);
 
@@ -1292,7 +1418,7 @@ ParallelWorkerInitialization(SerializedParallelCopyState *shared_cstate,
 	initStringInfo(&cstate->attribute_buf);
 
 	initStringInfo(&cstate->line_buf);
-	for (count = 0; count < WORKER_CHUNK_COUNT;count++)
+	for (count = 0; count < WORKER_CHUNK_COUNT; count++)
 		initStringInfo(&pcdata->worker_line_buf[count].line_buf);
 
 	cstate->line_buf_converted = false;
@@ -1658,32 +1784,66 @@ ParallelCopyLeader(CopyState cstate)
 	/* Execute the before statement triggers from the leader */
 	ExecBeforeStmtTrigger(cstate);
 
-	/* On input just throw the header line away. */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (!cstate->binary)
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
+		/* On input just throw the header line away. */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
 		{
-			pcshared_info->is_read_in_progress = false;
-			return;			/* done */
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+			{
+				pcshared_info->is_read_in_progress = false;
+				return;			/* done */
+			}
 		}
-	}
 
-	for (;;)
-	{
-		bool done;
-		cstate->cur_lineno++;
+		for (;;)
+		{
+			bool done;
+			cstate->cur_lineno++;
 
-		/* Actually read the line into memory here. */
-		done = CopyReadLine(cstate);
+			/* Actually read the line into memory here. */
+			done = CopyReadLine(cstate);
 
+			/*
+			* EOF at start of line means we're done.  If we see EOF after some
+			* characters, we act as though it was newline followed by EOF, ie,
+			* process the line and then exit loop on next iteration.
+			*/
+			if (done && cstate->line_buf.len == 0)
+				break;
+		}
+	}
+	else
+	{
 		/*
-		 * EOF at start of line means we're done.  If we see EOF after some
-		 * characters, we act as though it was newline followed by EOF, ie,
-		 * process the line and then exit loop on next iteration.
+		 * Binary Format Files.
+		 * For parallel copy leader, fill in the error
+		 * context inforation here, in case any failures
+		 * while determining tuple offsets, leader
+		 * would throw the errors with proper context.
 		 */
-		if (done && cstate->line_buf.len == 0)
-			break;
+		ErrorContextCallback errcallback;
+		errcallback.callback = CopyFromErrorCallback;
+		errcallback.arg = (void *) cstate;
+		errcallback.previous = error_context_stack;
+		error_context_stack = &errcallback;
+		cstate->pcdata->curr_data_block = NULL;
+		cstate->raw_buf_index = 0;
+		pcshared_info->populated = 0;
+		cstate->cur_lineno = 0;
+		cstate->max_fields = list_length(cstate->attnumlist);
+
+		for (;;)
+		{
+			bool eof = false;
+			cstate->cur_lineno++;
+
+			eof = CopyReadBinaryTupleLeader(cstate);
+
+			if (eof)
+				break;
+		}
 	}
 
  	pcshared_info->is_read_in_progress = false;
@@ -1691,7 +1851,357 @@ ParallelCopyLeader(CopyState cstate)
  }
 
 /*
- * GetLinePosition - return the line position that worker should process.
+ * CopyReadBinaryGetDataBlock - gets a new block, updates
+ * the current offset, calculates the skip bytes.
+ */
+static void
+CopyReadBinaryGetDataBlock(CopyState cstate, FieldInfoType field_info)
+{
+	ParallelCopyDataBlock *data_block = NULL;
+	ParallelCopyDataBlock *curr_data_block = cstate->pcdata->curr_data_block;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	uint8 move_bytes = 0;
+	uint32 block_pos;
+	uint32 prev_block_pos;
+	int read_bytes = 0;
+
+	prev_block_pos = pcshared_info->cur_block_pos;
+
+	block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+	if (field_info == FIELD_SIZE || field_info == FIELD_COUNT)
+		move_bytes = (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+
+	if (curr_data_block != NULL)
+		curr_data_block->skip_bytes = move_bytes;
+
+	data_block = &pcshared_info->data_blocks[block_pos];
+
+	if (move_bytes > 0 && curr_data_block != NULL)
+		memmove(&data_block->data[0], &curr_data_block->data[cstate->raw_buf_index], move_bytes);
+
+	elog(DEBUG1, "LEADER - field info %d is spread across data blocks - moved %d bytes from current block %u to %u block",
+		field_info, move_bytes, prev_block_pos, block_pos);
+
+	read_bytes = CopyGetData(cstate, &data_block->data[move_bytes], 1, (DATA_BLOCK_SIZE - move_bytes));
+
+	if (field_info == FIELD_NONE && cstate->reached_eof)
+		return;
+
+	if (cstate->reached_eof)
+		EOF_ERROR;
+
+	elog(DEBUG1, "LEADER - bytes read from file %d", read_bytes);
+
+	if(field_info == FIELD_SIZE || field_info == FIELD_DATA)
+	{
+		ParallelCopyDataBlock *prev_data_block = NULL;
+		prev_data_block = curr_data_block;
+		prev_data_block->following_block = block_pos;
+
+		if (prev_data_block->curr_blk_completed  == false)
+			prev_data_block->curr_blk_completed = true;
+
+		pg_atomic_add_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+	}
+
+	cstate->pcdata->curr_data_block = data_block;
+	cstate->raw_buf_index = 0;
+}
+
+/*
+ * CopyReadBinaryTupleLeader - leader reads data from binary formatted file
+ * to data blocks and identies tuple boundaries/offsets so that workers
+ * can work on the data blocks data.
+ */
+static bool
+CopyReadBinaryTupleLeader(CopyState cstate)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	int16		fld_count;
+	uint32      line_size = 0;
+	uint32 		start_block_pos;
+	uint32		start_offset;
+
+	if (cstate->pcdata->curr_data_block == NULL)
+	{
+		CopyReadBinaryGetDataBlock(cstate, FIELD_NONE);
+
+		/*
+		 * no data is read from file here. one possibility
+		 * to be here could be that the binary file just
+		 * has a valid signature but nothing else.
+		 */
+		if (cstate->reached_eof)
+			return true;
+	}
+
+	if ((cstate->raw_buf_index + sizeof(fld_count)) >= DATA_BLOCK_SIZE)
+		CopyReadBinaryGetDataBlock(cstate, FIELD_COUNT);
+
+	memcpy(&fld_count, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_count));
+	fld_count = (int16) pg_ntoh16(fld_count);
+	CHECK_FIELD_COUNT;
+	start_offset = cstate->raw_buf_index;
+	cstate->raw_buf_index += sizeof(fld_count);
+	line_size += sizeof(fld_count);
+	start_block_pos = pcshared_info->cur_block_pos;
+
+	CopyReadBinaryFindTupleSize(cstate, &line_size);
+
+	pg_atomic_add_fetch_u32(&cstate->pcdata->curr_data_block->unprocessed_line_parts, 1);
+
+	if (line_size > 0)
+	{
+		int line_pos = UpdateBlockInLineInfo(cstate,
+											start_block_pos,
+											start_offset,
+											line_size,
+											LINE_LEADER_POPULATED);
+
+		pcshared_info->populated++;
+		elog(DEBUG1, "LEADER - adding - block:%u, offset:%u, line size:%u line position:%d",
+				start_block_pos, start_offset, line_size, line_pos);
+	}
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryFindTupleSize - leader identifies boundaries/
+ * offsets for each attribute/column and finally results in the
+ * tuple/row size. It moves on to next data block if the attribute/
+ * column is spread across data blocks.
+ */
+static void
+CopyReadBinaryFindTupleSize(CopyState cstate, uint32 *line_size)
+{
+	int32		fld_size;
+	ListCell   *cur;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			att_num = lfirst_int(cur);
+		Form_pg_attribute att = TupleDescAttr(tup_desc, (att_num - 1));
+		cstate->cur_attname = NameStr(att->attname);
+		fld_size = 0;
+
+		if ((cstate->raw_buf_index + sizeof(fld_size)) >= DATA_BLOCK_SIZE)
+			CopyReadBinaryGetDataBlock(cstate, FIELD_SIZE);
+
+		memcpy(&fld_size, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_size));
+		cstate->raw_buf_index += sizeof(fld_size);
+		*line_size += sizeof(fld_size);
+		fld_size = (int32) pg_ntoh32(fld_size);
+
+		CHECK_FIELD_SIZE(fld_size);
+
+		*line_size += fld_size;
+
+		if ((DATA_BLOCK_SIZE - cstate->raw_buf_index) >= fld_size)
+		{
+			cstate->raw_buf_index += fld_size;
+			elog(DEBUG1, "LEADER - tuple lies in he same data block");
+		}
+		else
+		{
+			int32 required_blks = 0;
+			int32 curr_blk_bytes = (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+			int i = 0;
+
+			GET_REQUIRED_BLOCKS(required_blks, fld_size, curr_blk_bytes);
+
+			i = required_blks;
+
+			while(i > 0)
+			{
+				CopyReadBinaryGetDataBlock(cstate, FIELD_DATA);
+				i--;
+			}
+
+			GET_RAW_BUF_INDEX(cstate->raw_buf_index, fld_size, required_blks, curr_blk_bytes);
+
+			/*
+			 * raw_buf_index should never cross data block size,
+			 * as the required number of data blocks would have
+			 * been obtained in the above while loop.
+			 */
+			Assert(cstate->raw_buf_index <= DATA_BLOCK_SIZE);
+		}
+		cstate->cur_attname = NULL;
+	}
+}
+
+/*
+ * CopyReadBinaryTupleWorker - each worker reads data from data blocks after
+ * getting leader-identified tuple offsets from ring data structure.
+ */
+static bool
+CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls)
+{
+	uint32 		line_pos;
+	ParallelCopyLineBoundary *line_info;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	int16		fld_count;
+	ListCell   *cur;
+	FmgrInfo   *in_functions = cstate->in_functions;
+	Oid		   *typioparams = cstate->typioparams;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	line_pos = GetLinePosition(cstate);
+
+	if (line_pos == -1)
+		return true;
+
+	line_info = &pcshared_info->line_boundaries.ring[line_pos];
+	cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[line_info->first_block];
+	cstate->raw_buf_index = line_info->start_offset;
+
+#if 0
+	if (cstate->raw_buf_index + sizeof(fld_count) >= DATA_BLOCK_SIZE)
+	{
+		/*
+		 * The case where field count spread across datablocks should never occur,
+		 * as the leader would have moved it to next block. enable this if block
+		 * for debugging purposes only.
+		 */
+		elog(DEBUG1, "WORKER - field count spread across datablocks should never occur");
+	}
+#endif
+
+	memcpy(&fld_count, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_count));
+	fld_count = (int16) pg_ntoh16(fld_count);
+
+	CHECK_FIELD_COUNT;
+
+	cstate->raw_buf_index += sizeof(fld_count);
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			att_num = lfirst_int(cur);
+		int			m = att_num - 1;
+		Form_pg_attribute att = TupleDescAttr(tup_desc, m);
+		cstate->cur_attname = NameStr(att->attname);
+
+		values[m] = CopyReadBinaryAttributeWorker(cstate,
+											&in_functions[m],
+											typioparams[m],
+											att->atttypmod,
+											&nulls[m]);
+		cstate->cur_attname = NULL;
+	}
+
+	pg_atomic_sub_fetch_u32(&cstate->pcdata->curr_data_block->unprocessed_line_parts, 1);
+	line_info->start_offset = -1;
+	pg_atomic_write_u32(&line_info->line_state, LINE_WORKER_PROCESSED);
+	pg_atomic_write_u32(&line_info->line_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryAttributeWorker - leader identifies boundaries/offsets
+ * for each attribute/column, it moves on to next data block if the
+ * attribute/column is spread across data blocks.
+ */
+static Datum
+CopyReadBinaryAttributeWorker(CopyState cstate, FmgrInfo *flinfo,
+		Oid typioparam, int32 typmod, bool *isnull)
+{
+	int32		fld_size;
+	Datum		result;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+	if ((cstate->raw_buf_index + sizeof(fld_size)) >= DATA_BLOCK_SIZE)
+	{
+		ParallelCopyDataBlock *prev_data_block = cstate->pcdata->curr_data_block;
+		elog(DEBUG1, "WORKER - field size is spread across data blocks");
+		cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[prev_data_block->following_block];
+		pg_atomic_sub_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+		cstate->raw_buf_index = 0;
+	}
+
+	memcpy(&fld_size, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_size));
+	fld_size = (int32) pg_ntoh32(fld_size);
+
+	CHECK_FIELD_SIZE(fld_size);
+
+	cstate->raw_buf_index += sizeof(fld_size);
+
+	/* reset attribute_buf to empty, and load raw data in it */
+	resetStringInfo(&cstate->attribute_buf);
+
+	enlargeStringInfo(&cstate->attribute_buf, fld_size);
+
+	if ((DATA_BLOCK_SIZE - cstate->raw_buf_index) >= fld_size)
+	{
+		elog(DEBUG1, "WORKER - tuple lies in single data block");
+		memcpy(&cstate->attribute_buf.data[0],&cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], fld_size);
+		cstate->raw_buf_index += fld_size;
+	}
+	else
+	{
+		uint32 att_buf_idx = 0;
+		uint32 copy_bytes = 0;
+		int32 required_blks = 0;
+		int32 curr_blk_bytes = (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+		ParallelCopyDataBlock *prev_data_block = NULL;
+		int i = 0;
+
+		GET_REQUIRED_BLOCKS(required_blks, fld_size, curr_blk_bytes);
+
+		i = required_blks;
+		prev_data_block = cstate->pcdata->curr_data_block;
+		elog(DEBUG1, "WORKER - tuple is spread across data blocks");
+		memcpy(&cstate->attribute_buf.data[0], &prev_data_block->data[cstate->raw_buf_index],
+				curr_blk_bytes);
+		copy_bytes = curr_blk_bytes;
+		att_buf_idx = curr_blk_bytes;
+
+		while (i>0)
+		{
+			cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[prev_data_block->following_block];
+			pg_atomic_sub_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+			cstate->raw_buf_index = 0;
+			copy_bytes = fld_size - att_buf_idx;
+
+			/*
+			 * the bytes that are yet to be taken into att buff are more than
+			 * the entire data block size, but only take the data block size
+			 * elements.
+			 */
+			if (copy_bytes >= DATA_BLOCK_SIZE)
+				copy_bytes = DATA_BLOCK_SIZE;
+
+			memcpy(&cstate->attribute_buf.data[att_buf_idx],
+				&cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], copy_bytes);
+			att_buf_idx += copy_bytes;
+			i--;
+		}
+		GET_RAW_BUF_INDEX(cstate->raw_buf_index, fld_size, required_blks, curr_blk_bytes);
+	}
+
+	cstate->attribute_buf.len = fld_size;
+	cstate->attribute_buf.data[fld_size] = '\0';
+
+	/* Call the column type's binary input converter */
+	result = ReceiveFunctionCall(flinfo, &cstate->attribute_buf,
+								 typioparam, typmod);
+
+	/* Trouble if it didn't eat the whole buffer */
+	if (cstate->attribute_buf.cursor != cstate->attribute_buf.len)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+				 errmsg("incorrect binary data format")));
+
+	*isnull = false;
+	return result;
+}
+
+/*
+ * GetLinePosition - return the line position that worker should pcdata->process.
  */
 static uint32
 GetLinePosition(CopyState cstate)
@@ -1779,7 +2289,9 @@ GetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
 		{
 			dataBlkPtr->curr_blk_completed = false;
 			dataBlkPtr->skip_bytes = 0;
+			dataBlkPtr->following_block = -1;
 			pcshared_info->cur_block_pos = block_pos;
+			MemSet(&dataBlkPtr->data[0], 0, DATA_BLOCK_SIZE);
 			return block_pos;
 		}
 
@@ -5464,60 +5976,47 @@ NextCopyFrom(CopyState cstate, ExprContext *econtext,
 	else
 	{
 		/* binary */
-		int16		fld_count;
-		ListCell   *cur;
-
-		cstate->cur_lineno++;
-
-		if (!CopyGetInt16(cstate, &fld_count))
+		if (!IsParallelCopy())
 		{
-			/* EOF detected (end of file, or protocol-level EOF) */
-			return false;
-		}
+			int16		fld_count;
+			ListCell   *cur;
 
-		if (fld_count == -1)
-		{
-			/*
-			 * Received EOF marker.  In a V3-protocol copy, wait for the
-			 * protocol-level EOF, and complain if it doesn't come
-			 * immediately.  This ensures that we correctly handle CopyFail,
-			 * if client chooses to send that now.
-			 *
-			 * Note that we MUST NOT try to read more data in an old-protocol
-			 * copy, since there is no protocol-level EOF marker then.  We
-			 * could go either way for copy from file, but choose to throw
-			 * error if there's data after the EOF marker, for consistency
-			 * with the new-protocol case.
-			 */
-			char		dummy;
+			cstate->cur_lineno++;
+			cstate->max_fields = list_length(cstate->attnumlist);
 
-			if (cstate->copy_dest != COPY_OLD_FE &&
-				CopyGetData(cstate, &dummy, 1, 1) > 0)
-				ereport(ERROR,
-						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-						 errmsg("received copy data after EOF marker")));
-			return false;
-		}
+			if (!CopyGetInt16(cstate, &fld_count))
+			{
+				/* EOF detected (end of file, or protocol-level EOF) */
+				return false;
+			}
 
-		if (fld_count != attr_count)
-			ereport(ERROR,
-					(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-					 errmsg("row field count is %d, expected %d",
-							(int) fld_count, attr_count)));
+			CHECK_FIELD_COUNT;
 
-		foreach(cur, cstate->attnumlist)
+			foreach(cur, cstate->attnumlist)
+			{
+				int			attnum = lfirst_int(cur);
+				int			m = attnum - 1;
+				Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+
+				cstate->cur_attname = NameStr(att->attname);
+				values[m] = CopyReadBinaryAttribute(cstate,
+													&in_functions[m],
+													typioparams[m],
+													att->atttypmod,
+													&nulls[m]);
+				cstate->cur_attname = NULL;
+			}
+		}
+		else
 		{
-			int			attnum = lfirst_int(cur);
-			int			m = attnum - 1;
-			Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+			bool eof = false;
+			cstate->cur_lineno++;
+			cstate->max_fields = list_length(cstate->attnumlist);
 
-			cstate->cur_attname = NameStr(att->attname);
-			values[m] = CopyReadBinaryAttribute(cstate,
-												&in_functions[m],
-												typioparams[m],
-												att->atttypmod,
-												&nulls[m]);
-			cstate->cur_attname = NULL;
+			eof = CopyReadBinaryTupleWorker(cstate, values, nulls);
+
+			if (eof)
+				return false;
 		}
 	}
 
@@ -6518,18 +7017,15 @@ CopyReadBinaryAttribute(CopyState cstate, FmgrInfo *flinfo,
 	Datum		result;
 
 	if (!CopyGetInt32(cstate, &fld_size))
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("unexpected EOF in COPY data")));
+		EOF_ERROR;
+
 	if (fld_size == -1)
 	{
 		*isnull = true;
 		return ReceiveFunctionCall(flinfo, NULL, typioparam, typmod);
 	}
-	if (fld_size < 0)
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("invalid field size")));
+
+	CHECK_FIELD_SIZE(fld_size);
 
 	/* reset attribute_buf to empty, and load raw data in it */
 	resetStringInfo(&cstate->attribute_buf);
@@ -6537,9 +7033,7 @@ CopyReadBinaryAttribute(CopyState cstate, FmgrInfo *flinfo,
 	enlargeStringInfo(&cstate->attribute_buf, fld_size);
 	if (CopyGetData(cstate, cstate->attribute_buf.data,
 					fld_size, fld_size) != fld_size)
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("unexpected EOF in COPY data")));
+		EOF_ERROR;
 
 	cstate->attribute_buf.len = fld_size;
 	cstate->attribute_buf.data[fld_size] = '\0';
-- 
1.8.3.1

#114vignesh C
vignesh21@gmail.com
In reply to: vignesh C (#113)
6 attachment(s)
Re: Parallel copy

Please find the updated patch with the fixes included.

Patch 0003-Allow-copy-from-command-to-process-data-from-file-ST.patch
had few indentation issues, I have fixed and attached the patch for
the same.

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

Attachments:

0006-Parallel-Copy-For-Binary-Format-Files.patchtext/x-patch; charset=US-ASCII; name=0006-Parallel-Copy-For-Binary-Format-Files.patchDownload
From ab3b3ddeb080112a408ab6560cd2aa1e9acd1374 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Fri, 17 Jul 2020 13:18:54 +0530
Subject: [PATCH 6/6] Parallel Copy For Binary Format Files

Leader reads data from the file into the DSM data blocks each of 64K size.
It also identifies each tuple data block id, start offset, end offset,
tuple size and updates this information in the ring data structure.
Workers parallely read the tuple information from the ring data structure,
the actual tuple data from the data blocks and parallely insert the tuples
into the table.
---
 src/backend/commands/copy.c | 656 ++++++++++++++++++++++++++++++++++++++------
 1 file changed, 575 insertions(+), 81 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index d4cc4d2..e147893 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -256,6 +256,17 @@ typedef struct ParallelCopyLineBuf
 }ParallelCopyLineBuf;
 
 /*
+ * Represents the usage mode for CopyReadBinaryGetDataBlock.
+ */
+typedef enum FieldInfoType
+{
+	FIELD_NONE = 0,
+	FIELD_COUNT,
+	FIELD_SIZE,
+	FIELD_DATA
+} FieldInfoType;
+
+/*
  * Parallel copy data information.
  */
 typedef struct ParallelCopyData
@@ -276,6 +287,9 @@ typedef struct ParallelCopyData
 
 	/* Current position in worker_line_buf */
 	uint32				worker_line_buf_pos;
+
+	/* For binary formatted files */
+	ParallelCopyDataBlock *curr_data_block;
 }ParallelCopyData;
 
 /*
@@ -436,6 +450,7 @@ typedef struct SerializedParallelCopyState
 	/* Working state for COPY FROM */
 	AttrNumber          num_defaults;
 	Oid                 relid;
+	bool				binary;
 }SerializedParallelCopyState;
 
 /*
@@ -541,7 +556,6 @@ typedef struct CopyMultiInsertInfo
 	int			ti_options;		/* table insert options */
 } CopyMultiInsertInfo;
 
-
 /*
  * These macros centralize code used to process line_buf and raw_buf buffers.
  * They are macros because they often do continue/break control and to avoid
@@ -671,8 +685,110 @@ else \
 
 /* End parallel copy Macros */
 
-static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
+/*
+ * CHECK_FIELD_COUNT - Handles the error cases for field count
+ * for binary format files.
+ */
+#define CHECK_FIELD_COUNT \
+{\
+	if (fld_count == -1) \
+	{ \
+		if (IsParallelCopy() && \
+			!IsLeader()) \
+			return true; \
+		else if (IsParallelCopy() && \
+			IsLeader()) \
+		{ \
+			if (cstate->pcdata->curr_data_block->data[cstate->raw_buf_index + sizeof(fld_count)] != 0) \
+				ereport(ERROR, \
+						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+						errmsg("received copy data after EOF marker"))); \
+			return true; \
+		} \
+		else \
+		{ \
+			/* \
+			* Received EOF marker.  In a V3-protocol copy, wait for the \
+			* protocol-level EOF, and complain if it doesn't come \
+			* immediately.  This ensures that we correctly handle CopyFail, \
+			* if client chooses to send that now. \
+			* \
+			* Note that we MUST NOT try to read more data in an old-protocol \
+			* copy, since there is no protocol-level EOF marker then.  We \
+			* could go either way for copy from file, but choose to throw \
+			* error if there's data after the EOF marker, for consistency \
+			* with the new-protocol case. \
+			*/ \
+			char		dummy; \
+			if (cstate->copy_dest != COPY_OLD_FE && \
+				CopyGetData(cstate, &dummy, 1, 1) > 0) \
+				ereport(ERROR, \
+						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+						errmsg("received copy data after EOF marker"))); \
+				return false; \
+		} \
+	} \
+	if (fld_count != cstate->max_fields) \
+		ereport(ERROR, \
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+				errmsg("row field count is %d, expected %d", \
+				(int) fld_count, cstate->max_fields))); \
+}
+
+/*
+ * CHECK_FIELD_SIZE - Handles the error case for field size
+ * for binary format files.
+ */
+#define CHECK_FIELD_SIZE(fld_size) \
+{ \
+	if (fld_size < -1) \
+		ereport(ERROR, \
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+				errmsg("invalid field size")));\
+}
 
+/*
+ * EOF_ERROR - Error statement for EOF for binary format
+ * files.
+ */
+#define EOF_ERROR \
+{ \
+	ereport(ERROR, \
+		(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+		errmsg("unexpected EOF in COPY data")));\
+}
+
+/*
+ * GET_RAW_BUF_INDEX - Caclulates the raw buf index for the cases
+ * where the data spread is across multiple data blocks.
+ */
+#define GET_RAW_BUF_INDEX(raw_buf_index, fld_size, required_blks, curr_blk_bytes) \
+{ \
+	raw_buf_index = fld_size - (((required_blks - 1) * DATA_BLOCK_SIZE) + curr_blk_bytes); \
+}
+
+/*
+ * GET_REQUIRED_BLOCKS - Caclulates the number of data
+ * blocks required for the cases where the data spread
+ * is across multiple data blocks.
+ */
+#define GET_REQUIRED_BLOCKS(required_blks, fld_size, curr_blk_bytes) \
+{ \
+	/* \
+	 * field size can spread across multiple data blocks, \
+	 * calculate the number of required data blocks and try to get \
+	 * those many data blocks. \
+	 */ \
+	required_blks = (int32)(fld_size - curr_blk_bytes)/(int32)DATA_BLOCK_SIZE; \
+	/* \
+	 * check if we need the data block for the field data \
+	 * bytes that are not modulus of data block size. \
+	 */ \
+	if ((fld_size - curr_blk_bytes)%DATA_BLOCK_SIZE != 0) \
+		required_blks++; \
+}
+
+static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
 /* non-export function prototypes */
 static CopyState BeginCopy(ParseState *pstate, bool is_from, Relation rel,
@@ -728,6 +844,14 @@ static void ExecBeforeStmtTrigger(CopyState cstate);
 static void CheckTargetRelValidity(CopyState cstate);
 static void PopulateCatalogInformation(CopyState cstate);
 static pg_attribute_always_inline uint32 GetLinePosition(CopyState cstate);
+static uint32 WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info);
+static bool CopyReadBinaryTupleLeader(CopyState cstate);
+static void CopyReadBinaryFindTupleSize(CopyState cstate, uint32 *line_size);
+static bool CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls);
+static Datum CopyReadBinaryAttributeWorker(CopyState cstate, FmgrInfo *flinfo,
+										   Oid typioparam, int32 typmod, bool *isnull);
+static void CopyReadBinaryGetDataBlock(CopyState cstate, FieldInfoType field_info);
+
 /*
  * SerializeParallelCopyState - Copy shared_cstate using cstate information.
  */
@@ -745,6 +869,7 @@ SerializeParallelCopyState(CopyState cstate, SerializedParallelCopyState *shared
 	shared_cstate->convert_selectively = cstate->convert_selectively;
 	shared_cstate->num_defaults = cstate->num_defaults;
 	shared_cstate->relid = cstate->pcdata->relid;
+	shared_cstate->binary = cstate->binary;
 }
 
 /*
@@ -973,8 +1098,8 @@ FindInsertMethod(CopyState cstate)
 static pg_attribute_always_inline bool
 IsParallelCopyAllowed(CopyState cstate)
 {
-	/* Parallel copy not allowed for frontend (2.0 protocol) & binary option. */
-	if ((cstate->copy_dest == COPY_OLD_FE) || cstate->binary)
+	/* Parallel copy not allowed for frontend (2.0 protocol). */
+	if (cstate->copy_dest == COPY_OLD_FE)
 		return false;
 
 	/* Check if copy is into foreign table or temporary table. */
@@ -1266,6 +1391,7 @@ ParallelWorkerInitialization(SerializedParallelCopyState *shared_cstate,
 	cstate->convert_selectively = shared_cstate->convert_selectively;
 	cstate->num_defaults = shared_cstate->num_defaults;
 	pcdata->relid = shared_cstate->relid;
+	cstate->binary = shared_cstate->binary;
 
 	PopulateGlobalsForCopyFrom(cstate, tup_desc, attnamelist);
 
@@ -1281,7 +1407,7 @@ ParallelWorkerInitialization(SerializedParallelCopyState *shared_cstate,
 	initStringInfo(&cstate->attribute_buf);
 
 	initStringInfo(&cstate->line_buf);
-	for (count = 0; count < WORKER_CHUNK_COUNT;count++)
+	for (count = 0; count < WORKER_CHUNK_COUNT; count++)
 		initStringInfo(&pcdata->worker_line_buf[count].line_buf);
 
 	cstate->line_buf_converted = false;
@@ -1647,32 +1773,66 @@ ParallelCopyLeader(CopyState cstate)
 	/* Execute the before statement triggers from the leader */
 	ExecBeforeStmtTrigger(cstate);
 
-	/* On input just throw the header line away. */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (!cstate->binary)
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
+		/* On input just throw the header line away. */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
 		{
-			pcshared_info->is_read_in_progress = false;
-			return;			/* done */
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+			{
+				pcshared_info->is_read_in_progress = false;
+				return;			/* done */
+			}
 		}
-	}
 
-	for (;;)
-	{
-		bool done;
-		cstate->cur_lineno++;
+		for (;;)
+		{
+			bool done;
+			cstate->cur_lineno++;
 
-		/* Actually read the line into memory here. */
-		done = CopyReadLine(cstate);
+			/* Actually read the line into memory here. */
+			done = CopyReadLine(cstate);
 
+			/*
+			* EOF at start of line means we're done.  If we see EOF after some
+			* characters, we act as though it was newline followed by EOF, ie,
+			* process the line and then exit loop on next iteration.
+			*/
+			if (done && cstate->line_buf.len == 0)
+				break;
+		}
+	}
+	else
+	{
 		/*
-		 * EOF at start of line means we're done.  If we see EOF after some
-		 * characters, we act as though it was newline followed by EOF, ie,
-		 * process the line and then exit loop on next iteration.
+		 * Binary Format Files.
+		 * For parallel copy leader, fill in the error
+		 * context inforation here, in case any failures
+		 * while determining tuple offsets, leader
+		 * would throw the errors with proper context.
 		 */
-		if (done && cstate->line_buf.len == 0)
-			break;
+		ErrorContextCallback errcallback;
+		errcallback.callback = CopyFromErrorCallback;
+		errcallback.arg = (void *) cstate;
+		errcallback.previous = error_context_stack;
+		error_context_stack = &errcallback;
+		cstate->pcdata->curr_data_block = NULL;
+		cstate->raw_buf_index = 0;
+		pcshared_info->populated = 0;
+		cstate->cur_lineno = 0;
+		cstate->max_fields = list_length(cstate->attnumlist);
+
+		for (;;)
+		{
+			bool eof = false;
+			cstate->cur_lineno++;
+
+			eof = CopyReadBinaryTupleLeader(cstate);
+
+			if (eof)
+				break;
+		}
 	}
 
 	pcshared_info->is_read_in_progress = false;
@@ -1680,7 +1840,357 @@ ParallelCopyLeader(CopyState cstate)
  }
 
 /*
- * GetLinePosition - return the line position that worker should process.
+ * CopyReadBinaryGetDataBlock - gets a new block, updates
+ * the current offset, calculates the skip bytes.
+ */
+static void
+CopyReadBinaryGetDataBlock(CopyState cstate, FieldInfoType field_info)
+{
+	ParallelCopyDataBlock *data_block = NULL;
+	ParallelCopyDataBlock *curr_data_block = cstate->pcdata->curr_data_block;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	uint8 move_bytes = 0;
+	uint32 block_pos;
+	uint32 prev_block_pos;
+	int read_bytes = 0;
+
+	prev_block_pos = pcshared_info->cur_block_pos;
+
+	block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+	if (field_info == FIELD_SIZE || field_info == FIELD_COUNT)
+		move_bytes = (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+
+	if (curr_data_block != NULL)
+		curr_data_block->skip_bytes = move_bytes;
+
+	data_block = &pcshared_info->data_blocks[block_pos];
+
+	if (move_bytes > 0 && curr_data_block != NULL)
+		memmove(&data_block->data[0], &curr_data_block->data[cstate->raw_buf_index], move_bytes);
+
+	elog(DEBUG1, "LEADER - field info %d is spread across data blocks - moved %d bytes from current block %u to %u block",
+		field_info, move_bytes, prev_block_pos, block_pos);
+
+	read_bytes = CopyGetData(cstate, &data_block->data[move_bytes], 1, (DATA_BLOCK_SIZE - move_bytes));
+
+	if (field_info == FIELD_NONE && cstate->reached_eof)
+		return;
+
+	if (cstate->reached_eof)
+		EOF_ERROR;
+
+	elog(DEBUG1, "LEADER - bytes read from file %d", read_bytes);
+
+	if(field_info == FIELD_SIZE || field_info == FIELD_DATA)
+	{
+		ParallelCopyDataBlock *prev_data_block = NULL;
+		prev_data_block = curr_data_block;
+		prev_data_block->following_block = block_pos;
+
+		if (prev_data_block->curr_blk_completed  == false)
+			prev_data_block->curr_blk_completed = true;
+
+		pg_atomic_add_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+	}
+
+	cstate->pcdata->curr_data_block = data_block;
+	cstate->raw_buf_index = 0;
+}
+
+/*
+ * CopyReadBinaryTupleLeader - leader reads data from binary formatted file
+ * to data blocks and identies tuple boundaries/offsets so that workers
+ * can work on the data blocks data.
+ */
+static bool
+CopyReadBinaryTupleLeader(CopyState cstate)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	int16		fld_count;
+	uint32      line_size = 0;
+	uint32 		start_block_pos;
+	uint32		start_offset;
+
+	if (cstate->pcdata->curr_data_block == NULL)
+	{
+		CopyReadBinaryGetDataBlock(cstate, FIELD_NONE);
+
+		/*
+		 * no data is read from file here. one possibility
+		 * to be here could be that the binary file just
+		 * has a valid signature but nothing else.
+		 */
+		if (cstate->reached_eof)
+			return true;
+	}
+
+	if ((cstate->raw_buf_index + sizeof(fld_count)) >= DATA_BLOCK_SIZE)
+		CopyReadBinaryGetDataBlock(cstate, FIELD_COUNT);
+
+	memcpy(&fld_count, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_count));
+	fld_count = (int16) pg_ntoh16(fld_count);
+	CHECK_FIELD_COUNT;
+	start_offset = cstate->raw_buf_index;
+	cstate->raw_buf_index += sizeof(fld_count);
+	line_size += sizeof(fld_count);
+	start_block_pos = pcshared_info->cur_block_pos;
+
+	CopyReadBinaryFindTupleSize(cstate, &line_size);
+
+	pg_atomic_add_fetch_u32(&cstate->pcdata->curr_data_block->unprocessed_line_parts, 1);
+
+	if (line_size > 0)
+	{
+		int line_pos = UpdateBlockInLineInfo(cstate,
+											start_block_pos,
+											start_offset,
+											line_size,
+											LINE_LEADER_POPULATED);
+
+		pcshared_info->populated++;
+		elog(DEBUG1, "LEADER - adding - block:%u, offset:%u, line size:%u line position:%d",
+				start_block_pos, start_offset, line_size, line_pos);
+	}
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryFindTupleSize - leader identifies boundaries/
+ * offsets for each attribute/column and finally results in the
+ * tuple/row size. It moves on to next data block if the attribute/
+ * column is spread across data blocks.
+ */
+static void
+CopyReadBinaryFindTupleSize(CopyState cstate, uint32 *line_size)
+{
+	int32		fld_size;
+	ListCell   *cur;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			att_num = lfirst_int(cur);
+		Form_pg_attribute att = TupleDescAttr(tup_desc, (att_num - 1));
+		cstate->cur_attname = NameStr(att->attname);
+		fld_size = 0;
+
+		if ((cstate->raw_buf_index + sizeof(fld_size)) >= DATA_BLOCK_SIZE)
+			CopyReadBinaryGetDataBlock(cstate, FIELD_SIZE);
+
+		memcpy(&fld_size, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_size));
+		cstate->raw_buf_index += sizeof(fld_size);
+		*line_size += sizeof(fld_size);
+		fld_size = (int32) pg_ntoh32(fld_size);
+
+		CHECK_FIELD_SIZE(fld_size);
+
+		*line_size += fld_size;
+
+		if ((DATA_BLOCK_SIZE - cstate->raw_buf_index) >= fld_size)
+		{
+			cstate->raw_buf_index += fld_size;
+			elog(DEBUG1, "LEADER - tuple lies in he same data block");
+		}
+		else
+		{
+			int32 required_blks = 0;
+			int32 curr_blk_bytes = (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+			int i = 0;
+
+			GET_REQUIRED_BLOCKS(required_blks, fld_size, curr_blk_bytes);
+
+			i = required_blks;
+
+			while(i > 0)
+			{
+				CopyReadBinaryGetDataBlock(cstate, FIELD_DATA);
+				i--;
+			}
+
+			GET_RAW_BUF_INDEX(cstate->raw_buf_index, fld_size, required_blks, curr_blk_bytes);
+
+			/*
+			 * raw_buf_index should never cross data block size,
+			 * as the required number of data blocks would have
+			 * been obtained in the above while loop.
+			 */
+			Assert(cstate->raw_buf_index <= DATA_BLOCK_SIZE);
+		}
+		cstate->cur_attname = NULL;
+	}
+}
+
+/*
+ * CopyReadBinaryTupleWorker - each worker reads data from data blocks after
+ * getting leader-identified tuple offsets from ring data structure.
+ */
+static bool
+CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls)
+{
+	uint32 		line_pos;
+	ParallelCopyLineBoundary *line_info;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	int16		fld_count;
+	ListCell   *cur;
+	FmgrInfo   *in_functions = cstate->in_functions;
+	Oid		   *typioparams = cstate->typioparams;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	line_pos = GetLinePosition(cstate);
+
+	if (line_pos == -1)
+		return true;
+
+	line_info = &pcshared_info->line_boundaries.ring[line_pos];
+	cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[line_info->first_block];
+	cstate->raw_buf_index = line_info->start_offset;
+
+#if 0
+	if (cstate->raw_buf_index + sizeof(fld_count) >= DATA_BLOCK_SIZE)
+	{
+		/*
+		 * The case where field count spread across datablocks should never occur,
+		 * as the leader would have moved it to next block. enable this if block
+		 * for debugging purposes only.
+		 */
+		elog(DEBUG1, "WORKER - field count spread across datablocks should never occur");
+	}
+#endif
+
+	memcpy(&fld_count, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_count));
+	fld_count = (int16) pg_ntoh16(fld_count);
+
+	CHECK_FIELD_COUNT;
+
+	cstate->raw_buf_index += sizeof(fld_count);
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			att_num = lfirst_int(cur);
+		int			m = att_num - 1;
+		Form_pg_attribute att = TupleDescAttr(tup_desc, m);
+		cstate->cur_attname = NameStr(att->attname);
+
+		values[m] = CopyReadBinaryAttributeWorker(cstate,
+											&in_functions[m],
+											typioparams[m],
+											att->atttypmod,
+											&nulls[m]);
+		cstate->cur_attname = NULL;
+	}
+
+	pg_atomic_sub_fetch_u32(&cstate->pcdata->curr_data_block->unprocessed_line_parts, 1);
+	line_info->start_offset = -1;
+	pg_atomic_write_u32(&line_info->line_state, LINE_WORKER_PROCESSED);
+	pg_atomic_write_u32(&line_info->line_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryAttributeWorker - leader identifies boundaries/offsets
+ * for each attribute/column, it moves on to next data block if the
+ * attribute/column is spread across data blocks.
+ */
+static Datum
+CopyReadBinaryAttributeWorker(CopyState cstate, FmgrInfo *flinfo,
+		Oid typioparam, int32 typmod, bool *isnull)
+{
+	int32		fld_size;
+	Datum		result;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+	if ((cstate->raw_buf_index + sizeof(fld_size)) >= DATA_BLOCK_SIZE)
+	{
+		ParallelCopyDataBlock *prev_data_block = cstate->pcdata->curr_data_block;
+		elog(DEBUG1, "WORKER - field size is spread across data blocks");
+		cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[prev_data_block->following_block];
+		pg_atomic_sub_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+		cstate->raw_buf_index = 0;
+	}
+
+	memcpy(&fld_size, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_size));
+	fld_size = (int32) pg_ntoh32(fld_size);
+
+	CHECK_FIELD_SIZE(fld_size);
+
+	cstate->raw_buf_index += sizeof(fld_size);
+
+	/* reset attribute_buf to empty, and load raw data in it */
+	resetStringInfo(&cstate->attribute_buf);
+
+	enlargeStringInfo(&cstate->attribute_buf, fld_size);
+
+	if ((DATA_BLOCK_SIZE - cstate->raw_buf_index) >= fld_size)
+	{
+		elog(DEBUG1, "WORKER - tuple lies in single data block");
+		memcpy(&cstate->attribute_buf.data[0],&cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], fld_size);
+		cstate->raw_buf_index += fld_size;
+	}
+	else
+	{
+		uint32 att_buf_idx = 0;
+		uint32 copy_bytes = 0;
+		int32 required_blks = 0;
+		int32 curr_blk_bytes = (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+		ParallelCopyDataBlock *prev_data_block = NULL;
+		int i = 0;
+
+		GET_REQUIRED_BLOCKS(required_blks, fld_size, curr_blk_bytes);
+
+		i = required_blks;
+		prev_data_block = cstate->pcdata->curr_data_block;
+		elog(DEBUG1, "WORKER - tuple is spread across data blocks");
+		memcpy(&cstate->attribute_buf.data[0], &prev_data_block->data[cstate->raw_buf_index],
+				curr_blk_bytes);
+		copy_bytes = curr_blk_bytes;
+		att_buf_idx = curr_blk_bytes;
+
+		while (i>0)
+		{
+			cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[prev_data_block->following_block];
+			pg_atomic_sub_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+			cstate->raw_buf_index = 0;
+			copy_bytes = fld_size - att_buf_idx;
+
+			/*
+			 * the bytes that are yet to be taken into att buff are more than
+			 * the entire data block size, but only take the data block size
+			 * elements.
+			 */
+			if (copy_bytes >= DATA_BLOCK_SIZE)
+				copy_bytes = DATA_BLOCK_SIZE;
+
+			memcpy(&cstate->attribute_buf.data[att_buf_idx],
+				&cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], copy_bytes);
+			att_buf_idx += copy_bytes;
+			i--;
+		}
+		GET_RAW_BUF_INDEX(cstate->raw_buf_index, fld_size, required_blks, curr_blk_bytes);
+	}
+
+	cstate->attribute_buf.len = fld_size;
+	cstate->attribute_buf.data[fld_size] = '\0';
+
+	/* Call the column type's binary input converter */
+	result = ReceiveFunctionCall(flinfo, &cstate->attribute_buf,
+								 typioparam, typmod);
+
+	/* Trouble if it didn't eat the whole buffer */
+	if (cstate->attribute_buf.cursor != cstate->attribute_buf.len)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+				 errmsg("incorrect binary data format")));
+
+	*isnull = false;
+	return result;
+}
+
+/*
+ * GetLinePosition - return the line position that worker should pcdata->process.
  */
 static uint32
 GetLinePosition(CopyState cstate)
@@ -1768,7 +2278,9 @@ GetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
 		{
 			dataBlkPtr->curr_blk_completed = false;
 			dataBlkPtr->skip_bytes = 0;
+			dataBlkPtr->following_block = -1;
 			pcshared_info->cur_block_pos = block_pos;
+			MemSet(&dataBlkPtr->data[0], 0, DATA_BLOCK_SIZE);
 			return block_pos;
 		}
 
@@ -5453,60 +5965,47 @@ NextCopyFrom(CopyState cstate, ExprContext *econtext,
 	else
 	{
 		/* binary */
-		int16		fld_count;
-		ListCell   *cur;
-
-		cstate->cur_lineno++;
-
-		if (!CopyGetInt16(cstate, &fld_count))
+		if (!IsParallelCopy())
 		{
-			/* EOF detected (end of file, or protocol-level EOF) */
-			return false;
-		}
+			int16		fld_count;
+			ListCell   *cur;
 
-		if (fld_count == -1)
-		{
-			/*
-			 * Received EOF marker.  In a V3-protocol copy, wait for the
-			 * protocol-level EOF, and complain if it doesn't come
-			 * immediately.  This ensures that we correctly handle CopyFail,
-			 * if client chooses to send that now.
-			 *
-			 * Note that we MUST NOT try to read more data in an old-protocol
-			 * copy, since there is no protocol-level EOF marker then.  We
-			 * could go either way for copy from file, but choose to throw
-			 * error if there's data after the EOF marker, for consistency
-			 * with the new-protocol case.
-			 */
-			char		dummy;
+			cstate->cur_lineno++;
+			cstate->max_fields = list_length(cstate->attnumlist);
 
-			if (cstate->copy_dest != COPY_OLD_FE &&
-				CopyGetData(cstate, &dummy, 1, 1) > 0)
-				ereport(ERROR,
-						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-						 errmsg("received copy data after EOF marker")));
-			return false;
-		}
+			if (!CopyGetInt16(cstate, &fld_count))
+			{
+				/* EOF detected (end of file, or protocol-level EOF) */
+				return false;
+			}
 
-		if (fld_count != attr_count)
-			ereport(ERROR,
-					(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-					 errmsg("row field count is %d, expected %d",
-							(int) fld_count, attr_count)));
+			CHECK_FIELD_COUNT;
 
-		foreach(cur, cstate->attnumlist)
+			foreach(cur, cstate->attnumlist)
+			{
+				int			attnum = lfirst_int(cur);
+				int			m = attnum - 1;
+				Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+
+				cstate->cur_attname = NameStr(att->attname);
+				values[m] = CopyReadBinaryAttribute(cstate,
+													&in_functions[m],
+													typioparams[m],
+													att->atttypmod,
+													&nulls[m]);
+				cstate->cur_attname = NULL;
+			}
+		}
+		else
 		{
-			int			attnum = lfirst_int(cur);
-			int			m = attnum - 1;
-			Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+			bool eof = false;
+			cstate->cur_lineno++;
+			cstate->max_fields = list_length(cstate->attnumlist);
 
-			cstate->cur_attname = NameStr(att->attname);
-			values[m] = CopyReadBinaryAttribute(cstate,
-												&in_functions[m],
-												typioparams[m],
-												att->atttypmod,
-												&nulls[m]);
-			cstate->cur_attname = NULL;
+			eof = CopyReadBinaryTupleWorker(cstate, values, nulls);
+
+			if (eof)
+				return false;
 		}
 	}
 
@@ -6507,18 +7006,15 @@ CopyReadBinaryAttribute(CopyState cstate, FmgrInfo *flinfo,
 	Datum		result;
 
 	if (!CopyGetInt32(cstate, &fld_size))
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("unexpected EOF in COPY data")));
+		EOF_ERROR;
+
 	if (fld_size == -1)
 	{
 		*isnull = true;
 		return ReceiveFunctionCall(flinfo, NULL, typioparam, typmod);
 	}
-	if (fld_size < 0)
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("invalid field size")));
+
+	CHECK_FIELD_SIZE(fld_size);
 
 	/* reset attribute_buf to empty, and load raw data in it */
 	resetStringInfo(&cstate->attribute_buf);
@@ -6526,9 +7022,7 @@ CopyReadBinaryAttribute(CopyState cstate, FmgrInfo *flinfo,
 	enlargeStringInfo(&cstate->attribute_buf, fld_size);
 	if (CopyGetData(cstate, cstate->attribute_buf.data,
 					fld_size, fld_size) != fld_size)
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("unexpected EOF in COPY data")));
+		EOF_ERROR;
 
 	cstate->attribute_buf.len = fld_size;
 	cstate->attribute_buf.data[fld_size] = '\0';
-- 
1.8.3.1

0001-Copy-code-readjustment-to-support-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=0001-Copy-code-readjustment-to-support-parallel-copy.patchDownload
From d80c94ebf2922b539ba9abc21d2afea493b3deef Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Fri, 17 Jul 2020 13:15:29 +0530
Subject: [PATCH 1/6] Copy code readjustment to support parallel copy.

This patch has the copy code slightly readjusted so that the common code is
separated to functions/macros, these functions/macros will be used by the
workers in the parallel copy code of the upcoming patches. EOL removal is moved
from CopyReadLine to CopyReadLineText, this change was required because in case
of parallel copy the record identification and record updation is done in
CopyReadLineText, before record information is updated in shared memory the new
line characters should be removed.
---
 src/backend/commands/copy.c | 361 ++++++++++++++++++++++++++------------------
 1 file changed, 218 insertions(+), 143 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 44da71c..09419ea 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -95,6 +95,9 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
+#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+#define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
+
 /*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
@@ -222,7 +225,6 @@ typedef struct CopyStateData
 	 * converts it.  Note: we guarantee that there is a \0 at
 	 * raw_buf[raw_buf_len].
 	 */
-#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
@@ -350,6 +352,27 @@ if (1) \
 	goto not_end_of_copy; \
 } else ((void) 0)
 
+/*
+ * CLEAR_EOL_LINE - Wrapper for clearing EOL.
+ */
+#define CLEAR_EOL_LINE() \
+if (!result && !IsHeaderLine()) \
+	ClearEOLFromCopiedData(cstate, cstate->line_buf.data, \
+						   cstate->line_buf.len, \
+						   &cstate->line_buf.len) \
+
+/*
+ * INCREMENTPROCESSED - Increment the lines processed.
+ */
+#define INCREMENTPROCESSED(processed)  \
+processed++;
+
+/*
+ * GETPROCESSED - Get the lines processed.
+ */
+#define GETPROCESSED(processed) \
+return processed;
+
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
 
@@ -395,7 +418,11 @@ static bool CopyGetInt32(CopyState cstate, int32 *val);
 static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 
-
+static void PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tup_desc,
+									   List *attnamelist);
+static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
+								   int copy_line_pos, int *copy_line_size);
+static void ConvertToServerEncoding(CopyState cstate);
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
  * in past protocol redesigns.
@@ -796,6 +823,7 @@ CopyLoadRawBuf(CopyState cstate)
 {
 	int			nbytes;
 	int			inbytes;
+	int         minread = 1;
 
 	if (cstate->raw_buf_index < cstate->raw_buf_len)
 	{
@@ -807,8 +835,11 @@ CopyLoadRawBuf(CopyState cstate)
 	else
 		nbytes = 0;				/* no data need be saved */
 
+	if (cstate->copy_dest == COPY_NEW_FE)
+		minread = RAW_BUF_SIZE - nbytes;
+
 	inbytes = CopyGetData(cstate, cstate->raw_buf + nbytes,
-						  1, RAW_BUF_SIZE - nbytes);
+						  minread, RAW_BUF_SIZE - nbytes);
 	nbytes += inbytes;
 	cstate->raw_buf[nbytes] = '\0';
 	cstate->raw_buf_index = 0;
@@ -1466,7 +1497,6 @@ BeginCopy(ParseState *pstate,
 {
 	CopyState	cstate;
 	TupleDesc	tupDesc;
-	int			num_phys_attrs;
 	MemoryContext oldcontext;
 
 	/* Allocate workspace and zero all fields */
@@ -1632,6 +1662,24 @@ BeginCopy(ParseState *pstate,
 		tupDesc = cstate->queryDesc->tupDesc;
 	}
 
+	PopulateGlobalsForCopyFrom(cstate, tupDesc, attnamelist);
+	cstate->copy_dest = COPY_FILE;	/* default */
+
+	MemoryContextSwitchTo(oldcontext);
+
+	return cstate;
+}
+
+/*
+ * PopulateGlobalsForCopyFrom - Populates the common variables required for copy
+ * from operation. This is a helper function for BeginCopy function.
+ */
+static void
+PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tupDesc,
+							List *attnamelist)
+{
+	int			num_phys_attrs;
+
 	/* Generate or convert list of attributes to process */
 	cstate->attnumlist = CopyGetAttnums(tupDesc, cstate->rel, attnamelist);
 
@@ -1751,12 +1799,6 @@ BeginCopy(ParseState *pstate,
 		 pg_database_encoding_max_length() > 1);
 	/* See Multibyte encoding comment above */
 	cstate->encoding_embeds_ascii = PG_ENCODING_IS_CLIENT_ONLY(cstate->file_encoding);
-
-	cstate->copy_dest = COPY_FILE;	/* default */
-
-	MemoryContextSwitchTo(oldcontext);
-
-	return cstate;
 }
 
 /*
@@ -2648,32 +2690,11 @@ CopyMultiInsertInfoStore(CopyMultiInsertInfo *miinfo, ResultRelInfo *rri,
 }
 
 /*
- * Copy FROM file to relation.
+ * Check if the relation specified in copy from is valid.
  */
-uint64
-CopyFrom(CopyState cstate)
+static void
+CheckTargetRelValidity(CopyState cstate)
 {
-	ResultRelInfo *resultRelInfo;
-	ResultRelInfo *target_resultRelInfo;
-	ResultRelInfo *prevResultRelInfo = NULL;
-	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
-	ModifyTableState *mtstate;
-	ExprContext *econtext;
-	TupleTableSlot *singleslot = NULL;
-	MemoryContext oldcontext = CurrentMemoryContext;
-
-	PartitionTupleRouting *proute = NULL;
-	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
-	int			ti_options = 0; /* start with default options for insert */
-	BulkInsertState bistate = NULL;
-	CopyInsertMethod insertMethod;
-	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
-	uint64		processed = 0;
-	bool		has_before_insert_row_trig;
-	bool		has_instead_insert_row_trig;
-	bool		leafpart_use_multi_insert = false;
-
 	Assert(cstate->rel);
 
 	/*
@@ -2710,27 +2731,6 @@ CopyFrom(CopyState cstate)
 							RelationGetRelationName(cstate->rel))));
 	}
 
-	/*
-	 * If the target file is new-in-transaction, we assume that checking FSM
-	 * for free space is a waste of time.  This could possibly be wrong, but
-	 * it's unlikely.
-	 */
-	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
-		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
-		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
-		ti_options |= TABLE_INSERT_SKIP_FSM;
-
-	/*
-	 * Optimize if new relfilenode was created in this subxact or one of its
-	 * committed children and we won't see those rows later as part of an
-	 * earlier scan or command. The subxact test ensures that if this subxact
-	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
-	 * that the stronger test of exactly which subtransaction created it is
-	 * crucial for correctness of this optimization. The test for an earlier
-	 * scan or command tolerates false negatives. FREEZE causes other sessions
-	 * to see rows they would not see under MVCC, and a false negative merely
-	 * spreads that anomaly to the current session.
-	 */
 	if (cstate->freeze)
 	{
 		/*
@@ -2768,9 +2768,61 @@ CopyFrom(CopyState cstate)
 			ereport(ERROR,
 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 					 errmsg("cannot perform COPY FREEZE because the table was not created or truncated in the current subtransaction")));
+	}
+}
+
+/*
+ * Copy FROM file to relation.
+ */
+uint64
+CopyFrom(CopyState cstate)
+{
+	ResultRelInfo *resultRelInfo;
+	ResultRelInfo *target_resultRelInfo;
+	ResultRelInfo *prevResultRelInfo = NULL;
+	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
+	ModifyTableState *mtstate;
+	ExprContext *econtext;
+	TupleTableSlot *singleslot = NULL;
+	MemoryContext oldcontext = CurrentMemoryContext;
 
+	PartitionTupleRouting *proute = NULL;
+	ErrorContextCallback errcallback;
+	CommandId	mycid = GetCurrentCommandId(true);
+	int			ti_options = 0; /* start with default options for insert */
+	BulkInsertState bistate = NULL;
+	CopyInsertMethod insertMethod;
+	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
+	uint64		processed = 0;
+	bool		has_before_insert_row_trig;
+	bool		has_instead_insert_row_trig;
+	bool		leafpart_use_multi_insert = false;
+
+	CheckTargetRelValidity(cstate);
+
+	/*
+	 * If the target file is new-in-transaction, we assume that checking FSM
+	 * for free space is a waste of time.  This could possibly be wrong, but
+	 * it's unlikely.
+	 */
+	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
+		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
+		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
+		ti_options |= TABLE_INSERT_SKIP_FSM;
+
+	/*
+	 * Optimize if new relfilenode was created in this subxact or one of its
+	 * committed children and we won't see those rows later as part of an
+	 * earlier scan or command. The subxact test ensures that if this subxact
+	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
+	 * that the stronger test of exactly which subtransaction created it is
+	 * crucial for correctness of this optimization. The test for an earlier
+	 * scan or command tolerates false negatives. FREEZE causes other sessions
+	 * to see rows they would not see under MVCC, and a false negative merely
+	 * spreads that anomaly to the current session.
+	 */
+	if (cstate->freeze)
 		ti_options |= TABLE_INSERT_FROZEN;
-	}
 
 	/*
 	 * We need a ResultRelInfo so we can use the regular executor's
@@ -3263,7 +3315,7 @@ CopyFrom(CopyState cstate)
 			 * or FDW; this is the same definition used by nodeModifyTable.c
 			 * for counting tuples inserted by an INSERT command.
 			 */
-			processed++;
+			INCREMENTPROCESSED(processed)
 		}
 	}
 
@@ -3318,30 +3370,15 @@ CopyFrom(CopyState cstate)
 
 	FreeExecutorState(estate);
 
-	return processed;
+	GETPROCESSED(processed)
 }
 
 /*
- * Setup to read tuples from a file for COPY FROM.
- *
- * 'rel': Used as a template for the tuples
- * 'filename': Name of server-local file to read
- * 'attnamelist': List of char *, columns to include. NIL selects all cols.
- * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
- *
- * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ * PopulateCatalogInformation - populate the catalog information.
  */
-CopyState
-BeginCopyFrom(ParseState *pstate,
-			  Relation rel,
-			  const char *filename,
-			  bool is_program,
-			  copy_data_source_cb data_source_cb,
-			  List *attnamelist,
-			  List *options)
+static void
+PopulateCatalogInformation(CopyState cstate)
 {
-	CopyState	cstate;
-	bool		pipe = (filename == NULL);
 	TupleDesc	tupDesc;
 	AttrNumber	num_phys_attrs,
 				num_defaults;
@@ -3351,38 +3388,8 @@ BeginCopyFrom(ParseState *pstate,
 	Oid			in_func_oid;
 	int		   *defmap;
 	ExprState **defexprs;
-	MemoryContext oldcontext;
 	bool		volatile_defexprs;
 
-	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
-	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
-
-	/* Initialize state variables */
-	cstate->reached_eof = false;
-	cstate->eol_type = EOL_UNKNOWN;
-	cstate->cur_relname = RelationGetRelationName(cstate->rel);
-	cstate->cur_lineno = 0;
-	cstate->cur_attname = NULL;
-	cstate->cur_attval = NULL;
-
-	/*
-	 * Set up variables to avoid per-attribute overhead.  attribute_buf is
-	 * used in both text and binary modes, but we use line_buf and raw_buf
-	 * only in text mode.
-	 */
-	initStringInfo(&cstate->attribute_buf);
-	if (!cstate->binary)
-	{
-		initStringInfo(&cstate->line_buf);
-		cstate->line_buf_converted = false;
-		cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
-		cstate->raw_buf_index = cstate->raw_buf_len = 0;
-	}
-
-	/* Assign range table, we'll need it in CopyFrom. */
-	if (pstate)
-		cstate->range_table = pstate->p_rtable;
-
 	tupDesc = RelationGetDescr(cstate->rel);
 	num_phys_attrs = tupDesc->natts;
 	num_defaults = 0;
@@ -3460,6 +3467,61 @@ BeginCopyFrom(ParseState *pstate,
 	cstate->defexprs = defexprs;
 	cstate->volatile_defexprs = volatile_defexprs;
 	cstate->num_defaults = num_defaults;
+}
+
+/*
+ * Setup to read tuples from a file for COPY FROM.
+ *
+ * 'rel': Used as a template for the tuples
+ * 'filename': Name of server-local file to read
+ * 'attnamelist': List of char *, columns to include. NIL selects all cols.
+ * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
+ *
+ * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ */
+CopyState
+BeginCopyFrom(ParseState *pstate,
+			  Relation rel,
+			  const char *filename,
+			  bool is_program,
+			  copy_data_source_cb data_source_cb,
+			  List *attnamelist,
+			  List *options)
+{
+	CopyState	cstate;
+	bool		pipe = (filename == NULL);
+	MemoryContext oldcontext;
+
+	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	/* Initialize state variables */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/*
+	 * Set up variables to avoid per-attribute overhead.  attribute_buf is
+	 * used in both text and binary modes, but we use line_buf and raw_buf
+	 * only in text mode.
+	 */
+	initStringInfo(&cstate->attribute_buf);
+	if (!cstate->binary)
+	{
+		initStringInfo(&cstate->line_buf);
+		cstate->line_buf_converted = false;
+		cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+		cstate->raw_buf_index = cstate->raw_buf_len = 0;
+	}
+
+	/* Assign range table, we'll need it in CopyFrom. */
+	if (pstate)
+		cstate->range_table = pstate->p_rtable;
+
+	PopulateCatalogInformation(cstate);
 	cstate->is_program = is_program;
 
 	if (data_source_cb)
@@ -3869,45 +3931,60 @@ CopyReadLine(CopyState cstate)
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
-	else
-	{
-		/*
-		 * If we didn't hit EOF, then we must have transferred the EOL marker
-		 * to line_buf along with the data.  Get rid of it.
-		 */
-		switch (cstate->eol_type)
-		{
-			case EOL_NL:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CR:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\r');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CRNL:
-				Assert(cstate->line_buf.len >= 2);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 2] == '\r');
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len -= 2;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_UNKNOWN:
-				/* shouldn't get here */
-				Assert(false);
-				break;
-		}
-	}
 
+	ConvertToServerEncoding(cstate);
+	return result;
+}
+
+/*
+ * ClearEOLFromCopiedData - Clear EOL from the copied data.
+ */
+static void
+ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
+					   int copy_line_pos, int *copy_line_size)
+{
+	/*
+	 * If we didn't hit EOF, then we must have transferred the EOL marker
+	 * to line_buf along with the data.  Get rid of it.
+	 */
+   switch (cstate->eol_type)
+   {
+	   case EOL_NL:
+		   Assert(*copy_line_size >= 1);
+		   Assert(copy_line_data[copy_line_pos - 1] == '\n');
+		   copy_line_data[copy_line_pos - 1] = '\0';
+		   (*copy_line_size)--;
+		   break;
+	   case EOL_CR:
+		   Assert(*copy_line_size >= 1);
+		   Assert(copy_line_data[copy_line_pos - 1] == '\r');
+		   copy_line_data[copy_line_pos - 1] = '\0';
+		   (*copy_line_size)--;
+		   break;
+	   case EOL_CRNL:
+		   Assert(*copy_line_size >= 2);
+		   Assert(copy_line_data[copy_line_pos - 2] == '\r');
+		   Assert(copy_line_data[copy_line_pos - 1] == '\n');
+		   copy_line_data[copy_line_pos - 2] = '\0';
+		   *copy_line_size -= 2;
+		   break;
+	   case EOL_UNKNOWN:
+		   /* shouldn't get here */
+		   Assert(false);
+		   break;
+   }
+}
+
+/*
+ * ConvertToServerEncoding - convert contents to server encoding.
+ */
+static void
+ConvertToServerEncoding(CopyState cstate)
+{
 	/* Done reading the line.  Convert it to server encoding. */
 	if (cstate->need_transcoding)
 	{
 		char	   *cvt;
-
 		cvt = pg_any_to_server(cstate->line_buf.data,
 							   cstate->line_buf.len,
 							   cstate->file_encoding);
@@ -3919,11 +3996,8 @@ CopyReadLine(CopyState cstate)
 			pfree(cvt);
 		}
 	}
-
 	/* Now it's safe to use the buffer in error messages */
 	cstate->line_buf_converted = true;
-
-	return result;
 }
 
 /*
@@ -4286,6 +4360,7 @@ not_end_of_copy:
 	 * Transfer any still-uncopied data to line_buf.
 	 */
 	REFILL_LINEBUF;
+	CLEAR_EOL_LINE();
 
 	return result;
 }
-- 
1.8.3.1

0002-Framework-for-leader-worker-in-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=0002-Framework-for-leader-worker-in-parallel-copy.patchDownload
From fa5efa81c002d077a63d387ed43db96b5b16aabe Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Fri, 17 Jul 2020 13:16:08 +0530
Subject: [PATCH 2/6] Framework for leader/worker in parallel copy

This patch has the framework for data structures in parallel copy, leader
initialization, worker initialization, shared memory updation, starting workers,
wait for workers and workers exiting.
---
 src/backend/access/transam/parallel.c       |   4 +
 src/backend/commands/copy.c                 | 897 +++++++++++++++++++++++++++-
 src/backend/replication/logical/tablesync.c |   2 +-
 src/include/commands/copy.h                 |   4 +
 src/tools/pgindent/typedefs.list            |   8 +
 5 files changed, 910 insertions(+), 5 deletions(-)

diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index b042696..a3cff4b 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -25,6 +25,7 @@
 #include "catalog/pg_enum.h"
 #include "catalog/storage.h"
 #include "commands/async.h"
+#include "commands/copy.h"
 #include "executor/execParallel.h"
 #include "libpq/libpq.h"
 #include "libpq/pqformat.h"
@@ -145,6 +146,9 @@ static const struct
 	},
 	{
 		"parallel_vacuum_main", parallel_vacuum_main
+	},
+	{
+		"ParallelCopyMain", ParallelCopyMain
 	}
 };
 
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 09419ea..50da871 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -96,9 +96,174 @@ typedef enum CopyInsertMethod
 } CopyInsertMethod;
 
 #define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+
+/*
+ * The macros DATA_BLOCK_SIZE, RINGSIZE & MAX_BLOCKS_COUNT stores the records
+ * read from the file that need to be inserted into the relation. These values
+ * help in handover of multiple records with significant size of data to be
+ * processed by each of the workers to make sure there is no context swich & the
+ * work is fairly distrtibuted among the workers. This number showed best
+ * results in the performance tests.
+ */
+#define DATA_BLOCK_SIZE RAW_BUF_SIZE
+
+/* It can hold upto 10000 record information for worker to process. */
+#define RINGSIZE (10 * 1000)
+
+/* It can hold 1000 blocks of 64K data in DSM to be processed by the worker. */
+#define MAX_BLOCKS_COUNT 1000
+
+/*
+ * Each worker will be allocated WORKER_CHUNK_COUNT of records from DSM data
+ * block to process to avoid lock contention. This value should be mode of
+ * RINGSIZE, as wrap around cases is currently not handled while selecting the
+ * WORKER_CHUNK_COUNT by the worker.
+ */
+#define WORKER_CHUNK_COUNT 50
+
+#define	IsParallelCopy()		(cstate->is_parallel)
+#define IsLeader()				(cstate->pcdata->is_leader)
 #define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
 
 /*
+ * Copy data block information.
+ * ParallelCopyDataBlock's will be created in DSM. Data read from file will be
+ * copied in these DSM data blockes. The leader process identifies the records
+ * and the record information will be shared to the workers. The workers will
+ * insert the records into the table. There can be one or more number of records
+ * in each of the data block based on the record size.
+ */
+typedef struct ParallelCopyDataBlock
+{
+	/* The number of unprocessed lines in the current block. */
+	pg_atomic_uint32 unprocessed_line_parts;
+
+	/*
+	 * If the current line data is continued into another block, following_block
+	 * will have the position where the remaining data need to be read.
+	 */
+	uint32	following_block;
+
+	/*
+	 * This flag will be set, when the leader finds out this block can be read
+	 * safely by the worker. This helps the worker to start processing the line
+	 * early where the line will be spread across many blocks and the worker
+	 * need not wait for the complete line to be processed.
+	 */
+	bool   curr_blk_completed;
+	char   data[DATA_BLOCK_SIZE]; /* data read from file */
+	uint8  skip_bytes;
+}ParallelCopyDataBlock;
+
+/*
+ * Individual line information.
+ * ParallelCopyLineBoundary is common data structure between leader & worker,
+ * Leader process will be populating data block, data block offset & the size of
+ * the record in DSM for the workers to copy the data into the relation.
+ * This is protected by the following sequence in the leader & worker. If they
+ * don't follow this order the worker might process wrong line_size and leader
+ * might populate the information which worker has not yet processed or in the
+ * process of processing.
+ * Leader should operate in the following order:
+ * 1) check if line_size is -1, if not wait, it means worker is still
+ * processing.
+ * 2) set line_state to LINE_LEADER_POPULATING.
+ * 3) update first_block, start_offset & cur_lineno in any order.
+ * 4) update line_size.
+ * 5) update line_state to LINE_LEADER_POPULATED.
+ * Worker should operate in the following order:
+ * 1) check line_state is LINE_LEADER_POPULATED, if not it means leader is still
+ * populating the data.
+ * 2) read line_size.
+ * 3) only one worker should choose one line for processing, this is handled by
+ *    using pg_atomic_compare_exchange_u32, worker will change the sate to
+ *    LINE_WORKER_PROCESSING only if line_state is LINE_LEADER_POPULATED.
+ * 4) read first_block, start_offset & cur_lineno in any order.
+ * 5) process line_size data.
+ * 6) update line_size to -1.
+ */
+typedef struct ParallelCopyLineBoundary
+{
+	/* Position of the first block in data_blocks array. */
+	uint32				first_block;
+	uint32				start_offset;   /* start offset of the line */
+
+	/*
+	 * Size of the current line -1 means line is yet to be filled completely,
+	 * 0 means empty line, >0 means line filled with line size data.
+	 */
+	pg_atomic_uint32	line_size;
+	pg_atomic_uint32	line_state;		/* line state */
+	uint64				cur_lineno;		/* line number for error messages */
+}ParallelCopyLineBoundary;
+
+/*
+ * Circular queue used to store the line information.
+ */
+typedef struct ParallelCopyLineBoundaries
+{
+	/* Position for the leader to populate a line. */
+	uint32			pos;
+
+	/* Data read from the file/stdin by the leader process. */
+	ParallelCopyLineBoundary	ring[RINGSIZE];
+}ParallelCopyLineBoundaries;
+
+/*
+ * Shared information among parallel copy workers. This will be allocated in the
+ * DSM segment.
+ */
+typedef struct ParallelCopyShmInfo
+{
+	bool					is_read_in_progress; /* file read status */
+
+	/*
+	 * Actual lines inserted by worker (some records will be filtered based on
+	 * where condition).
+	 */
+	pg_atomic_uint64			processed;
+	pg_atomic_uint64			total_worker_processed; /* total processed records by the workers */
+	uint64						populated; /* lines populated by leader */
+	uint32						cur_block_pos; /* current data block */
+	ParallelCopyDataBlock		data_blocks[MAX_BLOCKS_COUNT]; /* data block array */
+	FullTransactionId			full_transaction_id; /* xid for copy from statement */
+	CommandId					mycid;	/* command id */
+	ParallelCopyLineBoundaries	line_boundaries; /* line array */
+} ParallelCopyShmInfo;
+
+/*
+ * Parallel copy line buffer information.
+ */
+typedef struct ParallelCopyLineBuf
+{
+	StringInfoData		line_buf;
+	uint64				cur_lineno;	/* line number for error messages */
+}ParallelCopyLineBuf;
+
+/*
+ * Parallel copy data information.
+ */
+typedef struct ParallelCopyData
+{
+	Oid					relid;				/* relation id of the table */
+	ParallelCopyShmInfo	*pcshared_info;		/* common info in shared memory */
+	bool				is_leader;
+
+	/* line position which worker is processing */
+	uint32				worker_processed_pos;
+
+	/*
+	 * Local line_buf array, workers will copy it here and release the lines
+	 * for the leader to continue.
+	 */
+	ParallelCopyLineBuf	worker_line_buf[WORKER_CHUNK_COUNT];
+	uint32				worker_line_buf_count; /* Number of lines */
+
+	/* Current position in worker_line_buf */
+	uint32				worker_line_buf_pos;
+}ParallelCopyData;
+
+/*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
  * even though some fields are used in only some cases.
@@ -228,8 +393,66 @@ typedef struct CopyStateData
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
+	int			nworkers;
+	bool		is_parallel;
+	ParallelCopyData *pcdata;
 } CopyStateData;
 
+/*
+ * This structure helps in storing the common data from CopyStateData that are
+ * required by the workers. This information will then be allocated and stored
+ * into the DSM for the worker to retrieve and copy it to CopyStateData.
+ */
+typedef struct SerializedParallelCopyState
+{
+	/* low-level state data */
+	CopyDest            copy_dest;		/* type of copy source/destination */
+	int                 file_encoding;	/* file or remote side's character encoding */
+	bool                need_transcoding;	/* file encoding diff from server? */
+	bool                encoding_embeds_ascii;	/* ASCII can be non-first byte? */
+
+	/* parameters from the COPY command */
+	bool                csv_mode;		/* Comma Separated Value format? */
+	bool                header_line;	/* CSV header line? */
+	int                 null_print_len; /* length of same */
+	bool                force_quote_all;	/* FORCE_QUOTE *? */
+	bool                convert_selectively;	/* do selective binary conversion? */
+
+	/* Working state for COPY FROM */
+	AttrNumber          num_defaults;
+	Oid                 relid;
+}SerializedParallelCopyState;
+
+/*
+ * This structure will help in converting a List data type into the below
+ * structure format with the count having the number of elements in the list and
+ * the info having the List elements appended contigously. This converted
+ * structure will be allocated in shared memory and stored in DSM for the worker
+ * to retrieve and later convert it back to List data type.
+ */
+typedef struct ParallelCopyKeyListInfo
+{
+	int	count;		/* count of attributes */
+
+	/* string info in the form info followed by info1, info2... infon  */
+	char    info[1];
+} ParallelCopyKeyListInfo;
+
+/*
+ * List of internal parallel copy function pointers.
+ */
+static const struct
+{
+	char *fn_name;
+	copy_data_source_cb fn_addr;
+}			InternalParallelCopyFuncPtrs[] =
+
+{
+	{
+		"copy_read_data", copy_read_data
+	},
+};
+
 /* DestReceiver for COPY (query) TO */
 typedef struct
 {
@@ -259,6 +482,23 @@ typedef struct
 /* Trim the list of buffers back down to this number after flushing */
 #define MAX_PARTITION_BUFFERS	32
 
+/* DSM keys for parallel copy.  */
+#define PARALLEL_COPY_KEY_SHARED_INFO		    1
+#define PARALLEL_COPY_KEY_CSTATE				2
+#define PARALLEL_COPY_KEY_NULL_PRINT			3
+#define PARALLEL_COPY_KEY_NULL_PRINT_CLIENT		4
+#define PARALLEL_COPY_KEY_DELIM					5
+#define PARALLEL_COPY_KEY_QUOTE					6
+#define PARALLEL_COPY_KEY_ESCAPE				7
+#define PARALLEL_COPY_KEY_ATTNAME_LIST			8
+#define PARALLEL_COPY_KEY_FORCE_QUOTE_LIST  	9
+#define PARALLEL_COPY_KEY_NOT_NULL_LIST		   10
+#define PARALLEL_COPY_KEY_NULL_LIST			   11
+#define PARALLEL_COPY_KEY_CONVERT_LIST		   12
+#define PARALLEL_COPY_KEY_DATASOURCE_CB		   13
+#define PARALLEL_COPY_KEY_WHERE_CLAUSE_STR     14
+#define PARALLEL_COPY_KEY_RANGE_TABLE		   15
+
 /* Stores multi-insert data related to a single relation in CopyFrom. */
 typedef struct CopyMultiInsertBuffer
 {
@@ -418,11 +658,593 @@ static bool CopyGetInt32(CopyState cstate, int32 *val);
 static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 
+static pg_attribute_always_inline void EndParallelCopy(ParallelContext *pcxt);
 static void PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tup_desc,
 									   List *attnamelist);
 static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
 								   int copy_line_pos, int *copy_line_size);
 static void ConvertToServerEncoding(CopyState cstate);
+static pg_attribute_always_inline copy_data_source_cb LookupParallelCopyFnPtr(const char *funcname);
+static pg_attribute_always_inline char* LookupParallelCopyFnStr(copy_data_source_cb fn_addr);
+
+/*
+ * SerializeParallelCopyState - Copy shared_cstate using cstate information.
+ */
+static pg_attribute_always_inline void
+SerializeParallelCopyState(CopyState cstate, SerializedParallelCopyState *shared_cstate)
+{
+	shared_cstate->copy_dest = cstate->copy_dest;
+	shared_cstate->file_encoding = cstate->file_encoding;
+	shared_cstate->need_transcoding = cstate->need_transcoding;
+	shared_cstate->encoding_embeds_ascii = cstate->encoding_embeds_ascii;
+	shared_cstate->csv_mode = cstate->csv_mode;
+	shared_cstate->header_line = cstate->header_line;
+	shared_cstate->null_print_len = cstate->null_print_len;
+	shared_cstate->force_quote_all = cstate->force_quote_all;
+	shared_cstate->convert_selectively = cstate->convert_selectively;
+	shared_cstate->num_defaults = cstate->num_defaults;
+	shared_cstate->relid = cstate->pcdata->relid;
+}
+
+/*
+ * DeserializeString - Retrieve the string from shared memory.
+ */
+static void
+DeserializeString(shm_toc *toc, int sharedkey, char **copystr)
+{
+	char *shared_str_val = (char *)shm_toc_lookup(toc, sharedkey, true);
+	if (shared_str_val)
+		*copystr = pstrdup(shared_str_val);
+}
+
+/*
+ * DeserializeList - Retrieve the list from shared memory.
+ */
+static void
+DeserializeList(shm_toc *toc, int sharedkey, List **copylist)
+{
+	ParallelCopyKeyListInfo *listinformation = (ParallelCopyKeyListInfo *)shm_toc_lookup(toc, sharedkey,
+														   true);
+	if (listinformation)
+	{
+		int	length  = 0;
+		int count;
+
+		for (count = 0; count < listinformation->count; count++)
+		{
+			char *attname = (char *)(listinformation->info + length);
+			length += strlen(attname) + 1;
+			*copylist = lappend(*copylist, makeString(attname));
+		}
+	}
+}
+
+/*
+ * CopyListSharedMemory - Copy the list into shared memory.
+ */
+static void
+CopyListSharedMemory(List *inputlist, Size memsize, ParallelCopyKeyListInfo *sharedlistinfo)
+{
+	ListCell   *l;
+	int			length  = 0;
+
+	MemSet(sharedlistinfo, 0, memsize);
+	foreach(l, inputlist)
+	{
+		char	   *name = strVal(lfirst(l));
+		memcpy((char *)(sharedlistinfo->info + length), name, strlen(name));
+		sharedlistinfo->count++;
+		length += strlen(name) + 1;
+	}
+}
+
+/*
+ * ComputeListSize - compute the list size.
+ */
+static int
+ComputeListSize(List *inputlist)
+{
+	int est_size = sizeof(int);
+	if (inputlist != NIL)
+	{
+		ListCell   *l;
+		foreach(l, inputlist)
+			est_size += strlen(strVal(lfirst(l))) + 1;
+	}
+
+	return est_size;
+}
+
+/*
+ * EstimateLineKeysStr - Estimate the size required in shared memory for the
+ * input string.
+ */
+static void
+EstimateLineKeysStr(ParallelContext *pcxt, char *inputstr)
+{
+	if (inputstr)
+	{
+		shm_toc_estimate_chunk(&pcxt->estimator, strlen(inputstr) + 1);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+}
+
+/*
+ * EstimateLineKeysList - Estimate the size required in shared memory for the
+ * input list.
+ */
+static void
+EstimateLineKeysList(ParallelContext *pcxt, List *inputlist,
+		Size *est_list_size)
+{
+	if (inputlist != NIL)
+	{
+		*est_list_size = ComputeListSize(inputlist);
+		shm_toc_estimate_chunk(&pcxt->estimator, *est_list_size);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+}
+
+/*
+ * SerializeString - Insert a string into shared memory.
+ */
+static void
+SerializeString(ParallelContext *pcxt, int key, char *inputstr)
+{
+	if (inputstr)
+	{
+		char *shmptr = (char *)shm_toc_allocate(pcxt->toc,
+												strlen(inputstr) + 1);
+		strcpy(shmptr, inputstr);
+		shm_toc_insert(pcxt->toc, key, shmptr);
+	}
+}
+
+/*
+ * SerializeList - Insert a list into shared memory.
+ */
+static void
+SerializeList(ParallelContext *pcxt, int key, List *inputlist,
+			  Size est_list_size)
+{
+	if (inputlist != NIL)
+	{
+		ParallelCopyKeyListInfo *sharedlistinfo = (ParallelCopyKeyListInfo *)shm_toc_allocate(pcxt->toc,
+																est_list_size);
+		CopyListSharedMemory(inputlist, est_list_size, sharedlistinfo);
+		shm_toc_insert(pcxt->toc, key, sharedlistinfo);
+	}
+}
+
+/*
+ * BeginParallelCopy - start parallel copy tasks.
+ *
+ * Get the number of workers required to perform the parallel copy. The data
+ * structures that are required by the parallel workers will be initialized, the
+ * size required in DSM will be calculated and the necessary keys will be loaded
+ * in the DSM. The specified number of workers will then be launched.
+ */
+static ParallelContext*
+BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
+{
+	ParallelContext *pcxt;
+	ParallelCopyShmInfo *shared_info_ptr;
+	SerializedParallelCopyState *shared_cstate;
+	FullTransactionId full_transaction_id;
+	Size est_shared_info;
+	Size est_cstateshared;
+	Size est_att_list_size;
+	Size est_quote_list_size;
+	Size est_notnull_list_size;
+	Size est_null_list_size;
+	Size est_convert_list_size;
+	Size est_datasource_cb_size;
+	int  count = 0;
+	char *whereClauseStr = NULL;
+	char *rangeTableStr = NULL;
+	int  parallel_workers = 0;
+	ParallelCopyData *pcdata;
+
+	parallel_workers = Min(nworkers, max_worker_processes);
+
+	/* Can't perform copy in parallel */
+	if (parallel_workers <= 0)
+		return NULL;
+
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	cstate->pcdata = pcdata;
+
+	EnterParallelMode();
+	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
+								 parallel_workers);
+	Assert(pcxt->nworkers > 0);
+
+	/*
+	 * Estimate size for shared information for PARALLEL_COPY_KEY_SHARED_INFO
+	 */
+	est_shared_info = sizeof(ParallelCopyShmInfo);
+	shm_toc_estimate_chunk(&pcxt->estimator, est_shared_info);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_CSTATE */
+	est_cstateshared = 	MAXALIGN(sizeof(SerializedParallelCopyState));
+	shm_toc_estimate_chunk(&pcxt->estimator, est_cstateshared);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	EstimateLineKeysStr(pcxt, cstate->null_print);
+	EstimateLineKeysStr(pcxt, cstate->null_print_client);
+	EstimateLineKeysStr(pcxt, cstate->delim);
+	EstimateLineKeysStr(pcxt, cstate->quote);
+	EstimateLineKeysStr(pcxt, cstate->escape);
+
+	if (cstate->whereClause != NULL)
+	{
+		whereClauseStr = nodeToString(cstate->whereClause);
+		EstimateLineKeysStr(pcxt, whereClauseStr);
+	}
+
+	if (cstate->range_table != NULL)
+	{
+		rangeTableStr = nodeToString(cstate->range_table);
+		EstimateLineKeysStr(pcxt, rangeTableStr);
+	}
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_XID. */
+	shm_toc_estimate_chunk(&pcxt->estimator, sizeof(FullTransactionId));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_ATTNAME_LIST.
+	 */
+	EstimateLineKeysList(pcxt, attnamelist, &est_att_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_FORCE_QUOTE_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->force_quote, &est_quote_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_NOT_NULL_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->force_notnull,
+							 &est_notnull_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_NULL_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->force_null, &est_null_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_CONVERT_LIST.
+	 */
+	EstimateLineKeysList(pcxt, cstate->convert_select,
+							 &est_convert_list_size);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_DATASOURCE_CB.
+	 */
+	if (cstate->data_source_cb)
+	{
+		char *functionname = LookupParallelCopyFnStr(cstate->data_source_cb);
+		est_datasource_cb_size = strlen(functionname) + 1;
+		shm_toc_estimate_chunk(&pcxt->estimator, est_datasource_cb_size);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+
+	InitializeParallelDSM(pcxt);
+
+	/* If no DSM segment was available, back out (do serial copy) */
+	if (pcxt->seg == NULL)
+	{
+		EndParallelCopy(pcxt);
+		return NULL;
+	}
+
+	/* Allocate shared memory for PARALLEL_COPY_KEY_SHARED_INFO */
+	shared_info_ptr = (ParallelCopyShmInfo *) shm_toc_allocate(pcxt->toc,
+													   est_shared_info);
+	MemSet(shared_info_ptr, 0, est_shared_info);
+	shared_info_ptr->is_read_in_progress = true;
+	shared_info_ptr->cur_block_pos = -1;
+	shared_info_ptr->full_transaction_id = full_transaction_id;
+	shared_info_ptr->mycid = GetCurrentCommandId(true);
+	for (count = 0; count < RINGSIZE; count++)
+	{
+		ParallelCopyLineBoundary *lineInfo = &shared_info_ptr->line_boundaries.ring[count];
+		pg_atomic_init_u32(&(lineInfo->line_size), -1);
+	}
+
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_SHARED_INFO, shared_info_ptr);
+	pcdata->pcshared_info = shared_info_ptr;
+	pcdata->relid = relid;
+
+	/* Store shared build state, for which we reserved space. */
+	shared_cstate = (SerializedParallelCopyState *)shm_toc_allocate(pcxt->toc,
+															est_cstateshared);
+
+	/* copy cstate variables. */
+	SerializeParallelCopyState(cstate, shared_cstate);
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_CSTATE, shared_cstate);
+
+	SerializeString(pcxt, PARALLEL_COPY_KEY_NULL_PRINT, cstate->null_print);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_NULL_PRINT_CLIENT,
+					cstate->null_print_client);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_DELIM, cstate->delim);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_QUOTE, cstate->quote);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_ESCAPE, cstate->escape);
+
+	SerializeList(pcxt, PARALLEL_COPY_KEY_ATTNAME_LIST,
+					attnamelist, est_att_list_size);
+	SerializeList(pcxt, PARALLEL_COPY_KEY_FORCE_QUOTE_LIST,
+					cstate->force_quote, est_quote_list_size);
+	SerializeList(pcxt, PARALLEL_COPY_KEY_NOT_NULL_LIST,
+					cstate->force_notnull, est_notnull_list_size);
+	SerializeList(pcxt, PARALLEL_COPY_KEY_NULL_LIST, cstate->force_null,
+					est_null_list_size);
+	SerializeList(pcxt, PARALLEL_COPY_KEY_CONVERT_LIST,
+					cstate->convert_select, est_convert_list_size);
+
+	if (cstate->data_source_cb)
+	{
+		char *functionname = LookupParallelCopyFnStr(cstate->data_source_cb);
+		char *data_source_cb = (char *) shm_toc_allocate(pcxt->toc,
+														 est_datasource_cb_size);
+		strcpy(data_source_cb, functionname);
+		shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_DATASOURCE_CB,
+					   data_source_cb);
+	}
+
+	if (cstate->whereClause)
+		SerializeString(pcxt, PARALLEL_COPY_KEY_WHERE_CLAUSE_STR,
+						whereClauseStr);
+
+	if(cstate->range_table)
+		SerializeString(pcxt, PARALLEL_COPY_KEY_RANGE_TABLE, rangeTableStr);
+
+	LaunchParallelWorkers(pcxt);
+	if (pcxt->nworkers_launched == 0)
+	{
+		EndParallelCopy(pcxt);
+		return NULL;
+	}
+
+	/*
+	 * Caller needs to wait for all launched workers when we return.  Make sure
+	 * that the failure-to-start case will not hang forever.
+	 */
+	WaitForParallelWorkersToAttach(pcxt);
+
+	pcdata->is_leader = true;
+	cstate->is_parallel = true;
+	return pcxt;
+}
+
+/*
+ * EndParallelCopy - end the parallel copy tasks.
+ */
+static pg_attribute_always_inline void
+EndParallelCopy(ParallelContext *pcxt)
+{
+	Assert(!IsParallelWorker());
+
+	DestroyParallelContext(pcxt);
+	ExitParallelMode();
+}
+
+/*
+ * ParallelWorkerInitialization - Initialize parallel worker.
+ */
+static void
+ParallelWorkerInitialization(SerializedParallelCopyState *shared_cstate,
+		CopyState cstate, List *attnamelist)
+{
+	uint32		count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	cstate->copy_dest = shared_cstate->copy_dest;
+	cstate->file_encoding = shared_cstate->file_encoding;
+	cstate->need_transcoding = shared_cstate->need_transcoding;
+	cstate->encoding_embeds_ascii = shared_cstate->encoding_embeds_ascii;
+	cstate->csv_mode = shared_cstate->csv_mode;
+	cstate->header_line = shared_cstate->header_line;
+	cstate->null_print_len = shared_cstate->null_print_len;
+	cstate->force_quote_all = shared_cstate->force_quote_all;
+	cstate->convert_selectively = shared_cstate->convert_selectively;
+	cstate->num_defaults = shared_cstate->num_defaults;
+	pcdata->relid = shared_cstate->relid;
+
+	PopulateGlobalsForCopyFrom(cstate, tup_desc, attnamelist);
+
+	/* Initialize state variables. */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/* Set up variables to avoid per-attribute overhead. */
+	initStringInfo(&cstate->attribute_buf);
+
+	initStringInfo(&cstate->line_buf);
+	for (count = 0; count < WORKER_CHUNK_COUNT;count++)
+		initStringInfo(&pcdata->worker_line_buf[count].line_buf);
+
+	cstate->line_buf_converted = false;
+	cstate->raw_buf = NULL;
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+}
+
+/*
+ * ParallelCopyMain - parallel copy worker's code.
+ *
+ * Where clause handling, convert tuple to columns, add default null values for
+ * the missing columns that are not present in that record. Find the partition
+ * if it is partitioned table, invoke before row insert Triggers, handle
+ * constraints and insert the tuples.
+ */
+void
+ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
+{
+	CopyState cstate;
+	ParallelCopyData *pcdata;
+	ParallelCopyShmInfo *pcshared_info;
+	SerializedParallelCopyState *shared_cstate;
+	Relation	rel = NULL;
+	MemoryContext oldcontext;
+	List *attlist = NIL;
+	char *data_source_cb;
+	char *whereClauseStr = NULL;
+	char *rangeTableStr = NULL;
+
+	/* Allocate workspace and zero all fields. */
+	cstate = (CopyStateData *) palloc0(sizeof(CopyStateData));
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	cstate->pcdata = pcdata;
+	pcdata->is_leader = false;
+	pcdata->worker_processed_pos = -1;
+	cstate->is_parallel = true;
+
+	/*
+	 * We allocate everything used by a cstate in a new memory context. This
+	 * avoids memory leaks during repeated use of COPY in a query.
+	 */
+	cstate->copycontext = AllocSetContextCreate(CurrentMemoryContext,
+												"COPY",
+												ALLOCSET_DEFAULT_SIZES);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	pcshared_info = (ParallelCopyShmInfo *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_SHARED_INFO,
+														false);
+
+	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
+
+	pcdata->pcshared_info = pcshared_info;
+
+	shared_cstate = (SerializedParallelCopyState *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE,
+														   false);
+
+	cstate->null_print = (char *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_NULL_PRINT,
+												true);
+	cstate->null_print_client = (char *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_NULL_PRINT_CLIENT,
+													   true);
+
+	DeserializeString(toc, PARALLEL_COPY_KEY_DELIM, &cstate->delim);
+	DeserializeString(toc, PARALLEL_COPY_KEY_QUOTE, &cstate->quote);
+	DeserializeString(toc, PARALLEL_COPY_KEY_ESCAPE, &cstate->escape);
+
+	DeserializeList(toc, PARALLEL_COPY_KEY_ATTNAME_LIST, &attlist);
+	DeserializeList(toc, PARALLEL_COPY_KEY_FORCE_QUOTE_LIST, &cstate->force_quote);
+	DeserializeList(toc, PARALLEL_COPY_KEY_NOT_NULL_LIST, &cstate->force_notnull);
+	DeserializeList(toc, PARALLEL_COPY_KEY_NULL_LIST, &cstate->force_null);
+	DeserializeList(toc, PARALLEL_COPY_KEY_CONVERT_LIST, &cstate->convert_select);
+	data_source_cb = (char *)shm_toc_lookup(toc,
+											PARALLEL_COPY_KEY_DATASOURCE_CB,
+											true);
+	DeserializeString(toc, PARALLEL_COPY_KEY_WHERE_CLAUSE_STR, &whereClauseStr);
+	DeserializeString(toc, PARALLEL_COPY_KEY_RANGE_TABLE, &rangeTableStr);
+
+	if (data_source_cb)
+		cstate->data_source_cb = LookupParallelCopyFnPtr(data_source_cb);
+
+	if (whereClauseStr)
+	{
+		Node *whereClauseCnvrtdFrmStr = (Node *) stringToNode(whereClauseStr);
+		cstate->whereClause = whereClauseCnvrtdFrmStr;
+	}
+
+	if (rangeTableStr)
+	{
+		List *rangeTableCnvrtdFrmStr = (List *) stringToNode(rangeTableStr);
+		cstate->range_table = rangeTableCnvrtdFrmStr;
+	}
+
+	/* Open and lock the relation, using the appropriate lock type. */
+	rel = table_open(shared_cstate->relid, RowExclusiveLock);
+	cstate->rel = rel;
+	ParallelWorkerInitialization(shared_cstate, cstate, attlist);
+
+	CopyFrom(cstate);
+
+	if (rel != NULL)
+		table_close(rel, RowExclusiveLock);
+
+	MemoryContextSwitchTo(oldcontext);
+	return;
+}
+
+/*
+ * ParallelCopyLeader - parallel copy leader's functionality.
+ *
+ * Leader will populate the shared memory and share it across the workers.
+ * Leader will read the table data from the file and copy the contents to block.
+ * Leader will then read the input contents and identify the data based on line
+ * beaks. This information is called line. The line will be populate in
+ * ParallelCopyLineBoundary. Workers will then pick up this information and
+ * insert in to table. Leader will do this till it completes processing the
+ * file. Leader executes the before statement if before statement trigger is
+ * present. Leader read the data from input file. Leader then loads data to data
+ * blocks as and when required block by block. Leader traverses through the data
+ * block to identify one line. It gets a free line to copy the information, if
+ * there is no free line it will wait till there is one free line.
+ * Server copies  the identified lines information into lines. This process is
+ * repeated till the complete file is processed.
+ * Leader will wait till all the lines populated are processed by the workers
+ * and exits.
+ */
+static void
+ParallelCopyLeader(CopyState cstate)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
+
+	pcshared_info->is_read_in_progress = false;
+	cstate->cur_lineno = 0;
+}
+
+/*
+ * LookupParallelCopyFnPtr - Look up parallel copy function pointer.
+ */
+static pg_attribute_always_inline copy_data_source_cb
+LookupParallelCopyFnPtr(const char *funcname)
+{
+	int			i;
+
+	for (i = 0; i < lengthof(InternalParallelCopyFuncPtrs); i++)
+	{
+		if (strcmp(InternalParallelCopyFuncPtrs[i].fn_name, funcname) == 0)
+			return InternalParallelCopyFuncPtrs[i].fn_addr;
+	}
+
+	/* We can only reach this by programming error. */
+	elog(ERROR, "internal function \"%s\" not found", funcname);
+}
+
+/*
+ * LookupParallelCopyFnStr - Lookup function string from a function pointer.
+ */
+static pg_attribute_always_inline char*
+LookupParallelCopyFnStr(copy_data_source_cb fn_addr)
+{
+	int			i;
+
+	for (i = 0; i < lengthof(InternalParallelCopyFuncPtrs); i++)
+	{
+		if (InternalParallelCopyFuncPtrs[i].fn_addr == fn_addr)
+			return InternalParallelCopyFuncPtrs[i].fn_name;
+	}
+
+	/* We can only reach this by programming error. */
+	elog(ERROR, "internal function pointer not found");
+}
+
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
  * in past protocol redesigns.
@@ -1093,6 +1915,7 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 
 	if (is_from)
 	{
+		ParallelContext *pcxt = NULL;
 		Assert(rel);
 
 		/* check read-only transaction and parallel mode */
@@ -1102,7 +1925,24 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 		cstate = BeginCopyFrom(pstate, rel, stmt->filename, stmt->is_program,
 							   NULL, stmt->attlist, stmt->options);
 		cstate->whereClause = whereClause;
-		*processed = CopyFrom(cstate);	/* copy from file to database */
+		cstate->is_parallel = false;
+
+		if (cstate->nworkers > 0)
+			pcxt = BeginParallelCopy(cstate->nworkers, cstate, stmt->attlist,
+									 relid);
+
+		if (pcxt)
+		{
+			ParallelCopyLeader(cstate);
+
+			/* Wait for all copy workers to finish */
+			WaitForParallelWorkersToFinish(pcxt);
+			*processed = pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
+			EndParallelCopy(pcxt);
+		}
+		else
+			*processed = CopyFrom(cstate); /* copy from file to database */
+
 		EndCopyFrom(cstate);
 	}
 	else
@@ -1151,6 +1991,7 @@ ProcessCopyOptions(ParseState *pstate,
 	cstate->is_copy_from = is_from;
 
 	cstate->file_encoding = -1;
+	cstate->nworkers = -1;
 
 	/* Extract options from the statement node tree */
 	foreach(option, options)
@@ -1319,6 +2160,53 @@ ProcessCopyOptions(ParseState *pstate,
 								defel->defname),
 						 parser_errposition(pstate, defel->location)));
 		}
+		else if (strcmp(defel->defname, "parallel") == 0)
+		{
+			char *endptr, *str;
+			long val;
+
+			if (!cstate->is_copy_from)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("parallel option supported only for copy from"),
+						 parser_errposition(pstate, defel->location)));
+			if (cstate->nworkers >= 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options"),
+						 parser_errposition(pstate, defel->location)));
+
+			str = defGetString(defel);
+
+			errno = 0; /* To distinguish success/failure after call */
+			val = strtol(str, &endptr, 10);
+
+			/* Check for various possible errors */
+			if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
+				|| (errno != 0 && val == 0) ||
+				*endptr)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("improper use of argument to option \"%s\"",
+								defel->defname),
+						 parser_errposition(pstate, defel->location)));
+
+			if (endptr == str)
+			   ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("no digits were found in argument to option \"%s\"",
+								defel->defname),
+						 parser_errposition(pstate, defel->location)));
+
+			cstate->nworkers = (int) val;
+
+			if (cstate->nworkers <= 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("argument to option \"%s\" must be a positive integer greater than zero",
+								defel->defname),
+						 parser_errposition(pstate, defel->location)));
+		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_SYNTAX_ERROR),
@@ -1671,12 +2559,13 @@ BeginCopy(ParseState *pstate,
 }
 
 /*
- * PopulateGlobalsForCopyFrom - Populates the common variables required for copy
- * from operation. This is a helper function for BeginCopy function.
+ * PopulateCatalogInformation - Populates the common variables required for copy
+ * from operation. This is a helper function for BeginCopy &
+ * ParallelWorkerInitialization function.
  */
 static void
 PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc	tupDesc,
-							List *attnamelist)
+						   List *attnamelist)
 {
 	int			num_phys_attrs;
 
diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c
index c27d970..b3787c1 100644
--- a/src/backend/replication/logical/tablesync.c
+++ b/src/backend/replication/logical/tablesync.c
@@ -557,7 +557,7 @@ make_copy_attnamelist(LogicalRepRelMapEntry *rel)
  * Data source callback for the COPY FROM, which reads from the remote
  * connection and passes the data back to our local COPY.
  */
-static int
+int
 copy_read_data(void *outbuf, int minread, int maxread)
 {
 	int			bytesread = 0;
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index c639833..5dc95ac 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -14,6 +14,7 @@
 #ifndef COPY_H
 #define COPY_H
 
+#include "access/parallel.h"
 #include "nodes/execnodes.h"
 #include "nodes/parsenodes.h"
 #include "parser/parse_node.h"
@@ -41,4 +42,7 @@ extern uint64 CopyFrom(CopyState cstate);
 
 extern DestReceiver *CreateCopyDestReceiver(void);
 
+extern void ParallelCopyMain(dsm_segment *seg, shm_toc *toc);
+
+extern int copy_read_data(void *outbuf, int minread, int maxread);
 #endif							/* COPY_H */
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 7eaaad1..dd812b0 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1699,6 +1699,13 @@ ParallelBitmapHeapState
 ParallelBlockTableScanDesc
 ParallelCompletionPtr
 ParallelContext
+ParallelCopyLineBoundaries
+ParallelCopyLineBoundary
+ParallelCopyData
+ParallelCopyDataBlock
+ParallelCopyKeyListInfo
+ParallelCopyLineBuf
+ParallelCopyShmInfo
 ParallelExecutorInfo
 ParallelHashGrowth
 ParallelHashJoinBatch
@@ -2215,6 +2222,7 @@ SerCommitSeqNo
 SerialControl
 SerializableXactHandle
 SerializedActiveRelMaps
+SerializedParallelCopyState
 SerializedReindexState
 SerializedSnapshotData
 SerializedTransactionState
-- 
1.8.3.1

0003-Allow-copy-from-command-to-process-data-from-file-ST.patchtext/x-patch; charset=US-ASCII; name=0003-Allow-copy-from-command-to-process-data-from-file-ST.patchDownload
From d2dfd7d398a571080da6ef29d17d983151278bde Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Fri, 17 Jul 2020 13:17:51 +0530
Subject: [PATCH 3/6] Allow copy from command to process data from file/STDIN
 contents to a table in parallel.

This feature allows the copy from to leverage multiple CPUs in order to copy
data from file/STDIN to a table. This adds a PARALLEL option to COPY FROM
command where the user can specify the number of workers that can be used
to perform the COPY FROM command. Specifying zero as number of workers will
disable parallelism.
The backend, to which the "COPY FROM" query is submitted acts as leader with
the responsibility of reading data from the file/stdin, launching at most n
number of workers as specified with PARALLEL 'n' option in the "COPY FROM"
query. The leader populates the common data required for the workers execution
in the DSM and shares it with the workers. The leader then executes before
statement triggers if there exists any. Leader populates DSM lines which
includes the start offset and line size, while populating the lines it reads
as many blocks as required into the DSM data blocks from the file. Each block
is of 64K size. The leader parses the data to identify a line, the existing
logic from CopyReadLineText which identifies the lines with some changes was
used for this. Leader checks if a free line is available to copy the
information, if there is no free line it waits till the required line is
freed up by the worker and then copies the identified lines information
(offset & line size) into the DSM lines. This process is repeated till the
complete file is processed. Simultaneously, the workers cache the lines(50)
locally into the local memory and release the lines to the leader for further
populating. Each worker processes the lines that it cached and inserts it into
the table. The leader does not participate in the insertion of data, leaders
only responsibility will be to identify the lines as fast as possible for the
workers to do the actual copy operation. The leader waits till all the lines
populated are processed by the workers and exits.
---
 src/backend/access/common/toast_internals.c |  11 +-
 src/backend/access/heap/heapam.c            |  13 -
 src/backend/access/transam/xact.c           |  31 +
 src/backend/commands/copy.c                 | 892 ++++++++++++++++++++++++++--
 src/include/access/xact.h                   |   2 +
 src/tools/pgindent/typedefs.list            |   1 +
 6 files changed, 898 insertions(+), 52 deletions(-)

diff --git a/src/backend/access/common/toast_internals.c b/src/backend/access/common/toast_internals.c
index 25a81e5..586d53d 100644
--- a/src/backend/access/common/toast_internals.c
+++ b/src/backend/access/common/toast_internals.c
@@ -17,6 +17,7 @@
 #include "access/genam.h"
 #include "access/heapam.h"
 #include "access/heaptoast.h"
+#include "access/parallel.h"
 #include "access/table.h"
 #include "access/toast_internals.h"
 #include "access/xact.h"
@@ -116,7 +117,15 @@ toast_save_datum(Relation rel, Datum value,
 	TupleDesc	toasttupDesc;
 	Datum		t_values[3];
 	bool		t_isnull[3];
-	CommandId	mycid = GetCurrentCommandId(true);
+
+	/*
+	 * Parallel copy can insert toast tuples, in case of parallel copy the
+	 * command would have been set already by calling AssignCommandIdForWorker.
+	 * For parallel copy call GetCurrentCommandId to get currentCommandId by
+	 * passing used as false, as this is taken care earlier.
+	 */
+	CommandId	mycid = IsParallelWorker() ? GetCurrentCommandId(false) :
+											 GetCurrentCommandId(true);
 	struct varlena *result;
 	struct varatt_external toast_pointer;
 	union
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index d881f4c..70ecd51 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2012,19 +2012,6 @@ static HeapTuple
 heap_prepare_insert(Relation relation, HeapTuple tup, TransactionId xid,
 					CommandId cid, int options)
 {
-	/*
-	 * Parallel operations are required to be strictly read-only in a parallel
-	 * worker.  Parallel inserts are not safe even in the leader in the
-	 * general case, because group locking means that heavyweight locks for
-	 * relation extension or GIN page locks will not conflict between members
-	 * of a lock group, but we don't prohibit that case here because there are
-	 * useful special cases that we can safely allow, such as CREATE TABLE AS.
-	 */
-	if (IsParallelWorker())
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_TRANSACTION_STATE),
-				 errmsg("cannot insert tuples in a parallel worker")));
-
 	tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
 	tup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK);
 	tup->t_data->t_infomask |= HEAP_XMAX_INVALID;
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index b3ee7fa..94988b6 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -502,6 +502,37 @@ GetCurrentFullTransactionIdIfAny(void)
 }
 
 /*
+ *	AssignFullTransactionIdForWorker
+ *
+ * For parallel copy, transaction id of leader will be used by the workers.
+ */
+void
+AssignFullTransactionIdForWorker(FullTransactionId fullTransactionId)
+{
+	TransactionState s = CurrentTransactionState;
+
+	Assert((IsInParallelMode() || IsParallelWorker()));
+	s->fullTransactionId = fullTransactionId;
+}
+
+/*
+ *	AssignCommandIdForWorker
+ *
+ * For parallel copy, command id of leader will be used by the workers.
+ */
+void
+AssignCommandIdForWorker(CommandId commandId, bool used)
+{
+	Assert((IsInParallelMode() || IsParallelWorker()));
+
+	/* this is global to a transaction, not subtransaction-local */
+	if (used)
+		currentCommandIdUsed = true;
+
+	currentCommandId = commandId;
+}
+
+/*
  *	MarkCurrentTransactionIdLoggedIfAny
  *
  * Remember that the current xid - if it is assigned - now has been wal logged.
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 50da871..d4cc4d2 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -26,6 +26,7 @@
 #include "access/xlog.h"
 #include "catalog/dependency.h"
 #include "catalog/pg_authid.h"
+#include "catalog/pg_proc_d.h"
 #include "catalog/pg_type.h"
 #include "commands/copy.h"
 #include "commands/defrem.h"
@@ -40,11 +41,13 @@
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
+#include "optimizer/clauses.h"
 #include "optimizer/optimizer.h"
 #include "parser/parse_coerce.h"
 #include "parser/parse_collate.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_relation.h"
+#include "pgstat.h"
 #include "port/pg_bswap.h"
 #include "rewrite/rewriteHandler.h"
 #include "storage/fd.h"
@@ -95,6 +98,18 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
+/*
+ * State of the line.
+ */
+typedef enum ParallelCopyLineState
+{
+	LINE_INIT,					/* initial state of line */
+	LINE_LEADER_POPULATING,		/* leader processing line */
+	LINE_LEADER_POPULATED,		/* leader completed populating line */
+	LINE_WORKER_PROCESSING,		/* worker processing line */
+	LINE_WORKER_PROCESSED		/* worker completed processing line */
+}ParallelCopyLineState;
+
 #define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
 
 /*
@@ -577,9 +592,13 @@ if (1) \
 { \
 	if (raw_buf_ptr > cstate->raw_buf_index) \
 	{ \
-		appendBinaryStringInfo(&cstate->line_buf, \
-							 cstate->raw_buf + cstate->raw_buf_index, \
-							   raw_buf_ptr - cstate->raw_buf_index); \
+		if (!IsParallelCopy()) \
+			appendBinaryStringInfo(&cstate->line_buf, \
+								   cstate->raw_buf + cstate->raw_buf_index, \
+								   raw_buf_ptr - cstate->raw_buf_index); \
+		else \
+			line_size +=  raw_buf_ptr - cstate->raw_buf_index; \
+		\
 		cstate->raw_buf_index = raw_buf_ptr; \
 	} \
 } else ((void) 0)
@@ -592,26 +611,65 @@ if (1) \
 	goto not_end_of_copy; \
 } else ((void) 0)
 
+/* Begin parallel copy Macros */
+#define SET_NEWLINE_SIZE() \
+{ \
+	if (cstate->eol_type == EOL_NL || cstate->eol_type == EOL_CR) \
+		new_line_size = 1; \
+	else if (cstate->eol_type == EOL_CRNL) \
+		new_line_size = 2; \
+	else \
+		new_line_size = 0; \
+}
+
+/*
+ * COPY_WAIT_TO_PROCESS - Wait before continuing to process.
+ */
+#define COPY_WAIT_TO_PROCESS() \
+{ \
+	CHECK_FOR_INTERRUPTS(); \
+	(void) WaitLatch(MyLatch, \
+					 WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH, \
+					 1L, WAIT_EVENT_PG_SLEEP); \
+	ResetLatch(MyLatch); \
+}
+
 /*
  * CLEAR_EOL_LINE - Wrapper for clearing EOL.
  */
 #define CLEAR_EOL_LINE() \
 if (!result && !IsHeaderLine()) \
-	ClearEOLFromCopiedData(cstate, cstate->line_buf.data, \
-						   cstate->line_buf.len, \
-						   &cstate->line_buf.len) \
+{ \
+	if (IsParallelCopy()) \
+		ClearEOLFromCopiedData(cstate, cstate->raw_buf, \
+									raw_buf_ptr, &line_size); \
+	else \
+		ClearEOLFromCopiedData(cstate, cstate->line_buf.data, \
+									cstate->line_buf.len, \
+									&cstate->line_buf.len); \
+} \
 
 /*
  * INCREMENTPROCESSED - Increment the lines processed.
  */
-#define INCREMENTPROCESSED(processed)  \
-processed++;
+#define INCREMENTPROCESSED(processed) \
+{ \
+	if (!IsParallelCopy()) \
+		processed++; \
+	else \
+		pg_atomic_add_fetch_u64(&cstate->pcdata->pcshared_info->processed, 1); \
+}
 
 /*
  * GETPROCESSED - Get the lines processed.
  */
 #define GETPROCESSED(processed) \
-return processed;
+if (!IsParallelCopy()) \
+	return processed; \
+else \
+	return pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
+
+/* End parallel copy Macros */
 
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
@@ -666,7 +724,10 @@ static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
 static void ConvertToServerEncoding(CopyState cstate);
 static pg_attribute_always_inline copy_data_source_cb LookupParallelCopyFnPtr(const char *funcname);
 static pg_attribute_always_inline char* LookupParallelCopyFnStr(copy_data_source_cb fn_addr);
-
+static void ExecBeforeStmtTrigger(CopyState cstate);
+static void CheckTargetRelValidity(CopyState cstate);
+static void PopulateCatalogInformation(CopyState cstate);
+static pg_attribute_always_inline uint32 GetLinePosition(CopyState cstate);
 /*
  * SerializeParallelCopyState - Copy shared_cstate using cstate information.
  */
@@ -817,6 +878,137 @@ SerializeList(ParallelContext *pcxt, int key, List *inputlist,
 }
 
 /*
+ * IsTriggerFunctionParallelSafe - Check if the trigger function is parallel
+ * safe for the triggers. Return false if any one of the trigger has parallel
+ * unsafe function.
+ */
+static pg_attribute_always_inline bool
+IsTriggerFunctionParallelSafe(TriggerDesc *trigdesc)
+{
+	int	i;
+	for (i = 0; i < trigdesc->numtriggers; i++)
+	{
+		Trigger    *trigger = &trigdesc->triggers[i];
+		int 		trigtype = RI_TRIGGER_NONE;
+
+		if (func_parallel(trigger->tgfoid) != PROPARALLEL_SAFE)
+			return false;
+
+		/* If the trigger is parallel safe, also look for RI_TRIGGER. */
+		trigtype = RI_FKey_trigger_type(trigger->tgfoid);
+		if (trigtype == RI_TRIGGER_PK || trigtype == RI_TRIGGER_FK)
+			return false;
+	}
+
+	return true;
+}
+
+/*
+ * CheckExprParallelSafety - determine parallel safety of volatile expressions
+ * in default clause of column definition or in where clause and return true if
+ * they are parallel safe.
+ */
+static pg_attribute_always_inline bool
+CheckExprParallelSafety(CopyState cstate)
+{
+	if (contain_volatile_functions(cstate->whereClause))
+	{
+		if (max_parallel_hazard((Query *)cstate->whereClause) != PROPARALLEL_SAFE)
+			return false;
+	}
+
+	/*
+	 * Check if any of the column has volatile default expression. if yes, and
+	 * they are not parallel safe, then parallelism is not allowed. For
+	 * instance, if there are any serial/bigserial columns for which nextval()
+	 * default expression which is parallel unsafe is associated, parallelism
+	 * should not be allowed. In non parallel copy volatile functions are not
+	 * checked for nextval().
+	 */
+	if (cstate->defexprs != NULL && cstate->num_defaults != 0)
+	{
+		int     i;
+		for (i = 0; i < cstate->num_defaults; i++)
+		{
+			bool volatile_expr = contain_volatile_functions((Node *)cstate->defexprs[i]->expr);
+			if (volatile_expr &&
+				(max_parallel_hazard((Query *)cstate->defexprs[i]->expr)) !=
+				 PROPARALLEL_SAFE)
+				return false;
+		}
+	}
+
+	return true;
+}
+
+/*
+ * FindInsertMethod - determine insert mode single, multi, or multi conditional.
+ */
+static pg_attribute_always_inline CopyInsertMethod
+FindInsertMethod(CopyState cstate)
+{
+	if (cstate->rel->trigdesc != NULL &&
+		(cstate->rel->trigdesc->trig_insert_before_row ||
+		 cstate->rel->trigdesc->trig_insert_instead_row))
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
+			cstate->rel->trigdesc != NULL &&
+			cstate->rel->trigdesc->trig_insert_new_table)
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+		return CIM_MULTI_CONDITIONAL;
+
+	return CIM_MULTI;
+}
+
+/*
+ * IsParallelCopyAllowed - check for the cases where parallel copy is not
+ * applicable.
+ */
+static pg_attribute_always_inline bool
+IsParallelCopyAllowed(CopyState cstate)
+{
+	/* Parallel copy not allowed for frontend (2.0 protocol) & binary option. */
+	if ((cstate->copy_dest == COPY_OLD_FE) || cstate->binary)
+		return false;
+
+	/* Check if copy is into foreign table or temporary table. */
+	if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
+		RelationUsesLocalBuffers(cstate->rel))
+		return false;
+
+	/* Check if trigger function is parallel safe. */
+	if (cstate->rel->trigdesc != NULL &&
+		!IsTriggerFunctionParallelSafe(cstate->rel->trigdesc))
+		return false;
+
+	/*
+	 * Check if there is after statement or instead of trigger or transition
+	 * table triggers.
+	 */
+	if (cstate->rel->trigdesc != NULL &&
+		(cstate->rel->trigdesc->trig_insert_after_statement ||
+		 cstate->rel->trigdesc->trig_insert_instead_row ||
+		 cstate->rel->trigdesc->trig_insert_new_table))
+		return false;
+
+	/* Check if the volatile expressions are parallel safe, if present any. */
+	if (!CheckExprParallelSafety(cstate))
+		return false;
+
+	/* Check if the insertion mode is single. */
+	if (FindInsertMethod(cstate) == CIM_SINGLE)
+		return false;
+
+	return true;
+}
+
+/*
  * BeginParallelCopy - start parallel copy tasks.
  *
  * Get the number of workers required to perform the parallel copy. The data
@@ -845,6 +1037,8 @@ BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
 	int  parallel_workers = 0;
 	ParallelCopyData *pcdata;
 
+	CheckTargetRelValidity(cstate);
+
 	parallel_workers = Min(nworkers, max_worker_processes);
 
 	/* Can't perform copy in parallel */
@@ -854,6 +1048,19 @@ BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
 	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
 	cstate->pcdata = pcdata;
 
+	/*
+	 * User chosen parallel copy. Determine if the parallel copy is actually
+	 * allowed. If not, go with the non-parallel mode.
+	 */
+	if (!IsParallelCopyAllowed(cstate))
+	{
+		elog(WARNING,
+			 "Parallel copy not supported for specified table, copy will be run in non-parallel mode");
+		return NULL;
+	}
+
+	full_transaction_id = GetCurrentFullTransactionId();
+
 	EnterParallelMode();
 	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
 								 parallel_workers);
@@ -1080,9 +1287,212 @@ ParallelWorkerInitialization(SerializedParallelCopyState *shared_cstate,
 	cstate->line_buf_converted = false;
 	cstate->raw_buf = NULL;
 	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+
+	PopulateCatalogInformation(cstate);
+
+	/* Create workspace for CopyReadAttributes results. */
+	if (!cstate->binary)
+	{
+		AttrNumber	attr_count = list_length(cstate->attnumlist);
+
+		cstate->max_fields = attr_count;
+		cstate->raw_fields = (char **)palloc(attr_count * sizeof(char *));
+	}
 }
 
 /*
+ * CacheLineInfo - Cache the line information to local memory.
+ */
+static bool
+CacheLineInfo(CopyState cstate, uint32 buff_count)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	uint32			write_pos;
+	ParallelCopyDataBlock *data_blk_ptr;
+	ParallelCopyLineBoundary *lineInfo;
+	uint32 offset;
+	int dataSize;
+	int copiedSize = 0;
+
+	resetStringInfo(&pcdata->worker_line_buf[buff_count].line_buf);
+	write_pos = GetLinePosition(cstate);
+	if (-1 == write_pos)
+		return true;
+
+	/* Get the current line information. */
+	lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+	if (pg_atomic_read_u32(&lineInfo->line_size) == 0)
+		goto empty_data_line_update;
+
+	/* Get the block information. */
+	data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+	/* Get the offset information from where the data must be copied. */
+	offset = lineInfo->start_offset;
+	pcdata->worker_line_buf[buff_count].cur_lineno = lineInfo->cur_lineno;
+
+	elog(DEBUG1, "[Worker] Processing - line position:%d, block:%d, unprocessed lines:%d, offset:%d, line size:%d",
+				 write_pos, lineInfo->first_block,
+				 pg_atomic_read_u32(&data_blk_ptr->unprocessed_line_parts),
+				 offset, pg_atomic_read_u32(&lineInfo->line_size));
+
+	for (;;)
+	{
+		uint8 skip_bytes = data_blk_ptr->skip_bytes;
+		/*
+		 * There is a possibility that the above loop has come out because
+		 * data_blk_ptr->curr_blk_completed is set, but dataSize read might
+		 * be an old value, if data_blk_ptr->curr_blk_completed and the line is
+		 * completed, line_size will be set. Read the line_size again to be
+		 * sure if it is complete or partial block.
+		 */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+		if (dataSize)
+		{
+			int remainingSize = dataSize - copiedSize;
+			if (!remainingSize)
+				break;
+
+			/* Whole line is in current block. */
+			if (remainingSize + offset + skip_bytes < DATA_BLOCK_SIZE)
+			{
+				appendBinaryStringInfo(&pcdata->worker_line_buf[buff_count].line_buf,
+									   &data_blk_ptr->data[offset],
+									   remainingSize);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts,
+										1);
+				break;
+			}
+			else
+			{
+				/* Line is spread across the blocks. */
+				uint32 lineInCurrentBlock =  (DATA_BLOCK_SIZE - skip_bytes) - offset;
+				appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+										 &data_blk_ptr->data[offset],
+										 lineInCurrentBlock);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+				copiedSize += lineInCurrentBlock;
+				while (copiedSize < dataSize)
+				{
+					uint32 currentBlockCopySize;
+					ParallelCopyDataBlock *currBlkPtr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+					skip_bytes = currBlkPtr->skip_bytes;
+
+					/*
+					 * If complete data is present in current block use
+					 * dataSize - copiedSize, or copy the whole block from
+					 * current block.
+					 */
+					currentBlockCopySize = Min(dataSize - copiedSize, DATA_BLOCK_SIZE - skip_bytes);
+					appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+											 &currBlkPtr->data[0],
+											 currentBlockCopySize);
+					pg_atomic_sub_fetch_u32(&currBlkPtr->unprocessed_line_parts, 1);
+					copiedSize += currentBlockCopySize;
+					data_blk_ptr = currBlkPtr;
+				}
+
+				break;
+			}
+		}
+		else
+		{
+			/* Copy this complete block from the current offset. */
+			uint32 lineInCurrentBlock =  (DATA_BLOCK_SIZE - skip_bytes) - offset;
+			appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+									 &data_blk_ptr->data[offset],
+									 lineInCurrentBlock);
+			pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+			copiedSize += lineInCurrentBlock;
+
+			/*
+			 * Reset the offset. For the first copy, copy from the offset. For
+			 * the subsequent copy the complete block.
+			 */
+			offset = 0;
+
+			/* Set data_blk_ptr to the following block. */
+			data_blk_ptr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+		}
+
+		for (;;)
+		{
+			/* Get the size of this line */
+			dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+			/*
+			 * If the data is present in current block lineInfo.line_size
+			 * will be updated. If the data is spread across the blocks either
+			 * of lineInfo.line_size or data_blk_ptr->curr_blk_completed can
+			 * be updated. lineInfo.line_size will be updated if the complete
+			 * read is finished. data_blk_ptr->curr_blk_completed will be
+			 * updated if processing of current block is finished and data
+			 * processing is not finished.
+			 */
+			if (data_blk_ptr->curr_blk_completed || (dataSize != -1))
+				break;
+
+			COPY_WAIT_TO_PROCESS()
+		}
+	}
+
+empty_data_line_update:
+	elog(DEBUG1, "[Worker] Completed processing line:%d", write_pos);
+	pg_atomic_write_u32(&lineInfo->line_state, LINE_WORKER_PROCESSED);
+	pg_atomic_write_u32(&lineInfo->line_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+	return false;
+}
+
+/*
+ * GetWorkerLine - Returns a line for worker to process.
+ */
+static bool
+GetWorkerLine(CopyState cstate)
+{
+	uint32 buff_count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+
+	/*
+	 * Copy the line data to line_buf and release the line position so that the
+	 * worker can continue loading data.
+	 */
+	if (pcdata->worker_line_buf_pos < pcdata->worker_line_buf_count)
+		goto return_line;
+
+	pcdata->worker_line_buf_pos = 0;
+	pcdata->worker_line_buf_count = 0;
+
+	for (buff_count = 0; buff_count < WORKER_CHUNK_COUNT; buff_count++)
+	{
+		bool result = CacheLineInfo(cstate, buff_count);
+		if (result)
+			break;
+
+		pcdata->worker_line_buf_count++;
+	}
+
+	if (pcdata->worker_line_buf_count)
+		goto return_line;
+	else
+		resetStringInfo(&cstate->line_buf);
+
+	return true;
+
+return_line:
+	cstate->line_buf = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].line_buf;
+	cstate->cur_lineno = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].cur_lineno;
+	cstate->line_buf_valid = true;
+
+	/* Mark that encoding conversion hasn't occurred yet. */
+	cstate->line_buf_converted = false;
+	ConvertToServerEncoding(cstate);
+	pcdata->worker_line_buf_pos++;
+	return false;
+ }
+
+/*
  * ParallelCopyMain - parallel copy worker's code.
  *
  * Where clause handling, convert tuple to columns, add default null values for
@@ -1127,6 +1537,8 @@ ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
 	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
 
 	pcdata->pcshared_info = pcshared_info;
+	AssignFullTransactionIdForWorker(pcshared_info->full_transaction_id);
+	AssignCommandIdForWorker(pcshared_info->mycid, true);
 
 	shared_cstate = (SerializedParallelCopyState *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE,
 														   false);
@@ -1181,6 +1593,33 @@ ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
 }
 
 /*
+ * UpdateBlockInLineInfo - Update the line information.
+ */
+static pg_attribute_always_inline int
+UpdateBlockInLineInfo(CopyState cstate, uint32 blk_pos,
+					   uint32 offset, uint32 line_size, uint32 line_state)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyLineBoundaries *lineBoundaryPtr = &pcshared_info->line_boundaries;
+	ParallelCopyLineBoundary *lineInfo;
+	int line_pos = lineBoundaryPtr->pos;
+
+	/* Update the line information for the worker to pick and process. */
+	lineInfo = &lineBoundaryPtr->ring[line_pos];
+	while (pg_atomic_read_u32(&lineInfo->line_size) != -1)
+		COPY_WAIT_TO_PROCESS()
+
+	lineInfo->first_block = blk_pos;
+	lineInfo->start_offset = offset;
+	lineInfo->cur_lineno = cstate->cur_lineno;
+	pg_atomic_write_u32(&lineInfo->line_size, line_size);
+	pg_atomic_write_u32(&lineInfo->line_state, line_state);
+	lineBoundaryPtr->pos = (lineBoundaryPtr->pos + 1) % RINGSIZE;
+
+	return line_pos;
+}
+
+/*
  * ParallelCopyLeader - parallel copy leader's functionality.
  *
  * Leader will populate the shared memory and share it across the workers.
@@ -1205,8 +1644,159 @@ ParallelCopyLeader(CopyState cstate)
 	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
 	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
 
+	/* Execute the before statement triggers from the leader */
+	ExecBeforeStmtTrigger(cstate);
+
+	/* On input just throw the header line away. */
+	if (cstate->cur_lineno == 0 && cstate->header_line)
+	{
+		cstate->cur_lineno++;
+		if (CopyReadLine(cstate))
+		{
+			pcshared_info->is_read_in_progress = false;
+			return;			/* done */
+		}
+	}
+
+	for (;;)
+	{
+		bool done;
+		cstate->cur_lineno++;
+
+		/* Actually read the line into memory here. */
+		done = CopyReadLine(cstate);
+
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			break;
+	}
+
 	pcshared_info->is_read_in_progress = false;
 	cstate->cur_lineno = 0;
+ }
+
+/*
+ * GetLinePosition - return the line position that worker should process.
+ */
+static uint32
+GetLinePosition(CopyState cstate)
+{
+	ParallelCopyData *pcdata = cstate->pcdata;
+	ParallelCopyShmInfo *pcshared_info = pcdata->pcshared_info;
+	uint32  previous_pos = pcdata->worker_processed_pos;
+	uint32 write_pos = (previous_pos == -1) ? 0 : (previous_pos + 1) % RINGSIZE;
+	for (;;)
+	{
+		int		dataSize;
+		bool	is_read_in_progress = pcshared_info->is_read_in_progress;
+		ParallelCopyLineBoundary *lineInfo;
+		ParallelCopyDataBlock *data_blk_ptr;
+		ParallelCopyLineState line_state = LINE_LEADER_POPULATED;
+		ParallelCopyLineState curr_line_state;
+		CHECK_FOR_INTERRUPTS();
+
+		/* File read completed & no elements to process. */
+		if (!is_read_in_progress &&
+			(pcshared_info->populated ==
+			 pg_atomic_read_u64(&pcshared_info->total_worker_processed)))
+		{
+			write_pos = -1;
+			break;
+		}
+
+		/* Get the current line information. */
+		lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+		curr_line_state = pg_atomic_read_u32(&lineInfo->line_state);
+		if ((write_pos % WORKER_CHUNK_COUNT == 0) &&
+			(curr_line_state == LINE_WORKER_PROCESSED ||
+			 curr_line_state == LINE_WORKER_PROCESSING))
+		{
+			pcdata->worker_processed_pos = write_pos;
+			write_pos = (write_pos + WORKER_CHUNK_COUNT) %  RINGSIZE;
+			continue;
+		}
+
+		/* Get the size of this line. */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+		if (dataSize != 0) /* If not an empty line. */
+		{
+			/* Get the block information. */
+			data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+			if (!data_blk_ptr->curr_blk_completed && (dataSize == -1))
+			{
+				/* Wait till the current line or block is added. */
+				COPY_WAIT_TO_PROCESS()
+				continue;
+			}
+		}
+
+		/* Make sure that no worker has consumed this element. */
+		if (pg_atomic_compare_exchange_u32(&lineInfo->line_state,
+										   &line_state, LINE_WORKER_PROCESSING))
+			break;
+	}
+
+	pcdata->worker_processed_pos = write_pos;
+	return write_pos;
+}
+
+/*
+ * GetFreeCopyBlock - Get a free block for data to be copied.
+ */
+static pg_attribute_always_inline uint32
+GetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	int count = 0;
+	uint32 last_free_block = pcshared_info->cur_block_pos;
+	uint32 block_pos = (last_free_block != -1) ? ((last_free_block + 1) % MAX_BLOCKS_COUNT): 0;
+
+	/*
+	 * Get a new block for copying data, don't check curent block, current
+	 * block will have some unprocessed data.
+	 */
+	while (count < (MAX_BLOCKS_COUNT - 1))
+	{
+		ParallelCopyDataBlock *dataBlkPtr = &pcshared_info->data_blocks[block_pos];
+		uint32 unprocessed_line_parts = pg_atomic_read_u32(&dataBlkPtr->unprocessed_line_parts);
+		if (unprocessed_line_parts == 0)
+		{
+			dataBlkPtr->curr_blk_completed = false;
+			dataBlkPtr->skip_bytes = 0;
+			pcshared_info->cur_block_pos = block_pos;
+			return block_pos;
+		}
+
+		block_pos = (block_pos + 1) % MAX_BLOCKS_COUNT;
+		count++;
+	}
+
+	return -1;
+}
+
+/*
+ * WaitGetFreeCopyBlock - If there are no blocks available, wait and get a block
+ * for copying data.
+ */
+static uint32
+WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	uint32 new_free_pos = -1;
+	for (;;)
+	{
+		new_free_pos = GetFreeCopyBlock(pcshared_info);
+		if (new_free_pos != -1)	/* We have got one block, break now. */
+			break;
+
+		COPY_WAIT_TO_PROCESS()
+	}
+
+	return new_free_pos;
 }
 
 /*
@@ -1246,6 +1836,145 @@ LookupParallelCopyFnStr(copy_data_source_cb fn_addr)
 }
 
 /*
+ * SetRawBufForLoad - Set raw_buf to the shared memory where the file data must
+ * be read.
+ */
+static void
+SetRawBufForLoad(CopyState cstate, uint32 line_size, uint32 copy_buf_len,
+				 uint32 raw_buf_ptr, char **copy_raw_buf)
+{
+	ParallelCopyShmInfo	*pcshared_info;
+	uint32 cur_block_pos;
+	uint32 next_block_pos;
+	ParallelCopyDataBlock	*cur_data_blk_ptr = NULL;
+	ParallelCopyDataBlock	*next_data_blk_ptr = NULL;
+
+	if (!IsParallelCopy())
+		return;
+
+	pcshared_info = cstate->pcdata->pcshared_info;
+	cur_block_pos = pcshared_info->cur_block_pos;
+	cur_data_blk_ptr = (cstate->raw_buf) ? &pcshared_info->data_blocks[cur_block_pos] : NULL;
+	next_block_pos = WaitGetFreeCopyBlock(pcshared_info);
+	next_data_blk_ptr = &pcshared_info->data_blocks[next_block_pos];
+
+	/* set raw_buf to the data block in shared memory */
+	cstate->raw_buf = next_data_blk_ptr->data;
+	*copy_raw_buf = cstate->raw_buf;
+	if (cur_data_blk_ptr && line_size)
+	{
+		/*
+		 * Mark the previous block as completed, worker can start copying this
+		 * data.
+		 */
+		cur_data_blk_ptr->following_block = next_block_pos;
+		pg_atomic_add_fetch_u32(&cur_data_blk_ptr->unprocessed_line_parts, 1);
+		cur_data_blk_ptr->skip_bytes = copy_buf_len - raw_buf_ptr;
+		cur_data_blk_ptr->curr_blk_completed = true;
+	}
+}
+
+/*
+ * EndLineParallelCopy - Update the line information in shared memory.
+ */
+static void
+EndLineParallelCopy(CopyState cstate, uint32 line_pos, uint32 line_size,
+					 uint32 raw_buf_ptr)
+{
+	uint8 new_line_size;
+	if (!IsParallelCopy())
+		return;
+
+	if (!IsHeaderLine())
+	{
+		ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+		ParallelCopyLineBoundaries *lineBoundaryPtr = &pcshared_info->line_boundaries;
+		SET_NEWLINE_SIZE()
+		if (line_size)
+		{
+			ParallelCopyLineBoundary *lineInfo = &lineBoundaryPtr->ring[line_pos];
+			/*
+			 * If the new_line_size > raw_buf_ptr, then the new block has only
+			 * new line char content. The unprocessed count should not be
+			 * increased in this case.
+			 */
+			if (raw_buf_ptr > new_line_size)
+			{
+				uint32 cur_block_pos = pcshared_info->cur_block_pos;
+				ParallelCopyDataBlock *curr_data_blk_ptr = &pcshared_info->data_blocks[cur_block_pos];
+				pg_atomic_add_fetch_u32(&curr_data_blk_ptr->unprocessed_line_parts, 1);
+			}
+
+			/* Update line size. */
+			pg_atomic_write_u32(&lineInfo->line_size, line_size);
+			pg_atomic_write_u32(&lineInfo->line_state, LINE_LEADER_POPULATED);
+			elog(DEBUG1, "[Leader] After adding - line position:%d, line_size:%d",
+						 line_pos, line_size);
+			pcshared_info->populated++;
+		}
+		else if (new_line_size)
+		{
+			/* This means only new line char, empty record should be inserted.*/
+			ParallelCopyLineBoundary *lineInfo;
+			line_pos = UpdateBlockInLineInfo(cstate, -1, -1, 0,
+											   LINE_LEADER_POPULATED);
+			lineInfo = &lineBoundaryPtr->ring[line_pos];
+			elog(DEBUG1, "[Leader] Added empty line with offset:%d, line position:%d, line size:%d",
+						 lineInfo->start_offset, line_pos,
+						 pg_atomic_read_u32(&lineInfo->line_size));
+			pcshared_info->populated++;
+		}
+	}
+}
+
+/*
+ * ExecBeforeStmtTrigger - Execute the before statement trigger, this will be
+ * executed for parallel copy by the leader process.
+ */
+static void
+ExecBeforeStmtTrigger(CopyState cstate)
+{
+	EState	   *estate = CreateExecutorState();
+	ResultRelInfo *resultRelInfo;
+
+	Assert(IsLeader());
+
+	/*
+	 * We need a ResultRelInfo so we can use the regular executor's
+	 * index-entry-making machinery.  (There used to be a huge amount of code
+	 * here that basically duplicated execUtils.c ...)
+	 */
+	resultRelInfo = makeNode(ResultRelInfo);
+	InitResultRelInfo(resultRelInfo,
+					  cstate->rel,
+					  1,		/* must match rel's position in range_table */
+					  NULL,
+					  0);
+
+	/* Verify the named relation is a valid target for INSERT */
+	CheckValidResultRel(resultRelInfo, CMD_INSERT);
+
+	estate->es_result_relations = resultRelInfo;
+	estate->es_num_result_relations = 1;
+	estate->es_result_relation_info = resultRelInfo;
+
+	ExecInitRangeTable(estate, cstate->range_table);
+
+	/*
+	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
+	 * should do this for COPY, since it's not really an "INSERT" statement as
+	 * such. However, executing these triggers maintains consistency with the
+	 * EACH ROW triggers that we already fire on COPY.
+	 */
+	ExecBSInsertTriggers(estate, resultRelInfo);
+
+	/* Close any trigger target relations */
+	ExecCleanUpTriggerState(estate);
+
+	FreeExecutorState(estate);
+}
+
+/*
  * Send copy start/stop messages for frontend copies.  These have changed
  * in past protocol redesigns.
  */
@@ -3677,7 +4406,8 @@ CopyFrom(CopyState cstate)
 
 	PartitionTupleRouting *proute = NULL;
 	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
+	CommandId	mycid = IsParallelCopy() ? GetCurrentCommandId(false) :
+										   GetCurrentCommandId(true);
 	int			ti_options = 0; /* start with default options for insert */
 	BulkInsertState bistate = NULL;
 	CopyInsertMethod insertMethod;
@@ -3687,7 +4417,14 @@ CopyFrom(CopyState cstate)
 	bool		has_instead_insert_row_trig;
 	bool		leafpart_use_multi_insert = false;
 
-	CheckTargetRelValidity(cstate);
+	/*
+	 * Perform this check if it is not parallel copy. In case of parallel
+	 * copy, this check is done by the leader, so that if any invalid case
+	 * exist the copy from command will error out from the leader itself,
+	 * avoiding launching workers, just to throw error.
+	 */
+	if (!IsParallelCopy())
+		CheckTargetRelValidity(cstate);
 
 	/*
 	 * If the target file is new-in-transaction, we assume that checking FSM
@@ -3876,13 +4613,16 @@ CopyFrom(CopyState cstate)
 	has_instead_insert_row_trig = (resultRelInfo->ri_TrigDesc &&
 								   resultRelInfo->ri_TrigDesc->trig_insert_instead_row);
 
-	/*
-	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
-	 * should do this for COPY, since it's not really an "INSERT" statement as
-	 * such. However, executing these triggers maintains consistency with the
-	 * EACH ROW triggers that we already fire on COPY.
-	 */
-	ExecBSInsertTriggers(estate, resultRelInfo);
+	if (!IsParallelCopy())
+	{
+		/*
+		 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
+		 * should do this for COPY, since it's not really an "INSERT" statement as
+		 * such. However, executing these triggers maintains consistency with the
+		 * EACH ROW triggers that we already fire on COPY.
+		 */
+		ExecBSInsertTriggers(estate, resultRelInfo);
+	}
 
 	econtext = GetPerTupleExprContext(estate);
 
@@ -3982,6 +4722,16 @@ CopyFrom(CopyState cstate)
 					!has_instead_insert_row_trig &&
 					resultRelInfo->ri_FdwRoutine == NULL;
 
+				/*
+				 * If the table has any partitions that are either foreign or
+				 * has BEFORE/INSTEAD OF triggers, we can't perform copy
+				 * operations with parallel workers.
+				 */
+				if (!leafpart_use_multi_insert && IsParallelWorker())
+					ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							errmsg("cannot perform PARALLEL COPY if partition has BEFORE/INSTEAD OF triggers, or if the partition is foreign partition"),
+							errhint("Try COPY without PARALLEL option")));
+
 				/* Set the multi-insert buffer to use for this partition. */
 				if (leafpart_use_multi_insert)
 				{
@@ -4402,7 +5152,7 @@ BeginCopyFrom(ParseState *pstate,
 	{
 		initStringInfo(&cstate->line_buf);
 		cstate->line_buf_converted = false;
-		cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+		cstate->raw_buf = (IsParallelCopy()) ? NULL : (char *) palloc(RAW_BUF_SIZE + 1);
 		cstate->raw_buf_index = cstate->raw_buf_len = 0;
 	}
 
@@ -4547,26 +5297,35 @@ NextCopyFromRawFields(CopyState cstate, char ***fields, int *nfields)
 	/* only available for text or csv input */
 	Assert(!cstate->binary);
 
-	/* on input just throw the header line away */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (IsParallelCopy())
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
-			return false;		/* done */
+		done = GetWorkerLine(cstate);
+		if (done && cstate->line_buf.len == 0)
+			return false;
 	}
+	else
+	{
+		/* on input just throw the header line away */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
+		{
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+				return false;		/* done */
+		}
 
-	cstate->cur_lineno++;
+		cstate->cur_lineno++;
 
-	/* Actually read the line into memory here */
-	done = CopyReadLine(cstate);
+		/* Actually read the line into memory here */
+		done = CopyReadLine(cstate);
 
-	/*
-	 * EOF at start of line means we're done.  If we see EOF after some
-	 * characters, we act as though it was newline followed by EOF, ie,
-	 * process the line and then exit loop on next iteration.
-	 */
-	if (done && cstate->line_buf.len == 0)
-		return false;
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			return false;
+	}
 
 	/* Parse the line into de-escaped field values */
 	if (cstate->csv_mode)
@@ -4814,9 +5573,31 @@ CopyReadLine(CopyState cstate)
 		 */
 		if (cstate->copy_dest == COPY_NEW_FE)
 		{
+			bool bIsFirst = true;
 			do
 			{
-				cstate->raw_buf_index = cstate->raw_buf_len;
+				if (!IsParallelCopy())
+					cstate->raw_buf_index = cstate->raw_buf_len;
+				else
+				{
+					if (cstate->raw_buf_index == RAW_BUF_SIZE)
+					{
+						/* Get a new block if it is the first time, From the
+						 * subsequent time, reset the index and re-use the same
+						 * block.
+						 */
+						if (bIsFirst)
+						{
+							ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+							uint32 block_pos = WaitGetFreeCopyBlock(pcshared_info);
+							cstate->raw_buf = pcshared_info->data_blocks[block_pos].data;
+							bIsFirst = false;
+						}
+
+						cstate->raw_buf_index = cstate->raw_buf_len = 0;
+					}
+				}
+
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
@@ -4871,7 +5652,8 @@ static void
 ConvertToServerEncoding(CopyState cstate)
 {
 	/* Done reading the line.  Convert it to server encoding. */
-	if (cstate->need_transcoding)
+	if (cstate->need_transcoding &&
+		(!IsParallelCopy() || (IsParallelCopy() && !IsLeader())))
 	{
 		char	   *cvt;
 		cvt = pg_any_to_server(cstate->line_buf.data,
@@ -4910,6 +5692,11 @@ CopyReadLineText(CopyState cstate)
 	char		quotec = '\0';
 	char		escapec = '\0';
 
+	/* For parallel copy */
+	int			line_size = 0;
+	int			line_pos = 0;
+
+	cstate->eol_type = EOL_UNKNOWN;
 	if (cstate->csv_mode)
 	{
 		quotec = cstate->quote[0];
@@ -4964,6 +5751,8 @@ CopyReadLineText(CopyState cstate)
 		if (raw_buf_ptr >= copy_buf_len || need_data)
 		{
 			REFILL_LINEBUF;
+			SetRawBufForLoad(cstate, line_size, copy_buf_len, raw_buf_ptr,
+							 &copy_raw_buf);
 
 			/*
 			 * Try to read some more data.  This will certainly reset
@@ -5188,9 +5977,15 @@ CopyReadLineText(CopyState cstate)
 				 * discard the data and the \. sequence.
 				 */
 				if (prev_raw_ptr > cstate->raw_buf_index)
-					appendBinaryStringInfo(&cstate->line_buf,
+				{
+					if (!IsParallelCopy())
+						appendBinaryStringInfo(&cstate->line_buf,
 										   cstate->raw_buf + cstate->raw_buf_index,
 										   prev_raw_ptr - cstate->raw_buf_index);
+					else
+						line_size += prev_raw_ptr - cstate->raw_buf_index;
+				}
+
 				cstate->raw_buf_index = raw_buf_ptr;
 				result = true;	/* report EOF */
 				break;
@@ -5242,6 +6037,26 @@ not_end_of_copy:
 			IF_NEED_REFILL_AND_EOF_BREAK(mblen - 1);
 			raw_buf_ptr += mblen - 1;
 		}
+
+		/*
+		 * Skip the header line. Update the line here, this cannot be done at
+		 * the beginning, as there is a possibility that file contains empty
+		 * lines.
+		 */
+		if (IsParallelCopy() && first_char_in_line && !IsHeaderLine())
+		{
+			ParallelCopyShmInfo	*pcshared_info = cstate->pcdata->pcshared_info;
+			ParallelCopyLineBoundary *lineInfo;
+			uint32			 line_first_block = pcshared_info->cur_block_pos;
+			line_pos = UpdateBlockInLineInfo(cstate,
+											   line_first_block,
+											   cstate->raw_buf_index, -1,
+											   LINE_LEADER_POPULATING);
+			lineInfo = &pcshared_info->line_boundaries.ring[line_pos];
+			elog(DEBUG1, "[Leader] Adding - block:%d, offset:%d, line position:%d",
+						 line_first_block,	lineInfo->start_offset, line_pos);
+		}
+
 		first_char_in_line = false;
 	}							/* end of outer loop */
 
@@ -5250,6 +6065,7 @@ not_end_of_copy:
 	 */
 	REFILL_LINEBUF;
 	CLEAR_EOL_LINE();
+	EndLineParallelCopy(cstate, line_pos, line_size, raw_buf_ptr);
 
 	return result;
 }
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index db19187..20dafb7 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -381,6 +381,8 @@ extern FullTransactionId GetTopFullTransactionId(void);
 extern FullTransactionId GetTopFullTransactionIdIfAny(void);
 extern FullTransactionId GetCurrentFullTransactionId(void);
 extern FullTransactionId GetCurrentFullTransactionIdIfAny(void);
+extern void AssignFullTransactionIdForWorker(FullTransactionId fullTransactionId);
+extern void AssignCommandIdForWorker(CommandId commandId, bool used);
 extern void MarkCurrentTransactionIdLoggedIfAny(void);
 extern bool SubTransactionIsActive(SubTransactionId subxid);
 extern CommandId GetCurrentCommandId(bool used);
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index dd812b0..d7879fd 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1705,6 +1705,7 @@ ParallelCopyData
 ParallelCopyDataBlock
 ParallelCopyKeyListInfo
 ParallelCopyLineBuf
+ParallelCopyLineState
 ParallelCopyShmInfo
 ParallelExecutorInfo
 ParallelHashGrowth
-- 
1.8.3.1

0004-Documentation-for-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=0004-Documentation-for-parallel-copy.patchDownload
From 6653f44f1adca06af0db7bd6438a8b15140f1f8f Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Fri, 17 Jul 2020 13:18:13 +0530
Subject: [PATCH 4/6] Documentation for parallel copy.

This patch has the documentation changes for parallel copy.
---
 doc/src/sgml/ref/copy.sgml | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/doc/src/sgml/ref/copy.sgml b/doc/src/sgml/ref/copy.sgml
index 18189ab..95d349d 100644
--- a/doc/src/sgml/ref/copy.sgml
+++ b/doc/src/sgml/ref/copy.sgml
@@ -37,6 +37,7 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
     DELIMITER '<replaceable class="parameter">delimiter_character</replaceable>'
     NULL '<replaceable class="parameter">null_string</replaceable>'
     HEADER [ <replaceable class="parameter">boolean</replaceable> ]
+    PARALLEL <replaceable class="parameter">integer</replaceable>
     QUOTE '<replaceable class="parameter">quote_character</replaceable>'
     ESCAPE '<replaceable class="parameter">escape_character</replaceable>'
     FORCE_QUOTE { ( <replaceable class="parameter">column_name</replaceable> [, ...] ) | * }
@@ -275,6 +276,21 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
    </varlistentry>
 
    <varlistentry>
+    <term><literal>PARALLEL</literal></term>
+    <listitem>
+     <para>
+      Perform <command>COPY FROM</command> in parallel using <replaceable
+      class="parameter"> integer</replaceable> background workers.  Please
+      note that it is not guaranteed that the number of parallel workers
+      specified in <replaceable class="parameter">integer</replaceable> will
+      be used during execution.  It is possible for a copy to run with fewer
+      workers than specified, or even with no workers at all.  This option is
+      allowed only in <command>COPY FROM</command>.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><literal>QUOTE</literal></term>
     <listitem>
      <para>
-- 
1.8.3.1

0005-Tests-for-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=0005-Tests-for-parallel-copy.patchDownload
From 4de7281c80911cd97e3937899f3c79af03c5f505 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Fri, 17 Jul 2020 13:18:36 +0530
Subject: [PATCH 5/6] Tests for parallel copy.

This patch has the tests for parallel copy.
---
 src/test/regress/expected/copy2.out | 210 +++++++++++++++++++++++++++++++++++-
 src/test/regress/input/copy.source  |  12 +++
 src/test/regress/output/copy.source |  12 +++
 src/test/regress/sql/copy2.sql      | 208 ++++++++++++++++++++++++++++++++++-
 4 files changed, 434 insertions(+), 8 deletions(-)

diff --git a/src/test/regress/expected/copy2.out b/src/test/regress/expected/copy2.out
index e40287d..ef75148 100644
--- a/src/test/regress/expected/copy2.out
+++ b/src/test/regress/expected/copy2.out
@@ -254,18 +254,32 @@ It is "perfect".|
 "It is ""perfect"".","	"
 "",
 --test that we read consecutive LFs properly
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 COPY testnl FROM stdin CSV;
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+SELECT * FROM testnl;
+ a |          b           | c 
+---+----------------------+---
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+(2 rows)
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 COPY testeoc FROM stdin CSV;
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
 COPY testeoc TO stdout CSV;
 a\.
 \.b
 c\.d
 "\."
 -- test handling of nonstandard null marker that violates escaping rules
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 COPY testnull TO stdout WITH NULL AS E'\\0';
 1	\\0
@@ -280,6 +294,15 @@ SELECT * FROM testnull;
     | 
 (4 rows)
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 1);
+SELECT * FROM testnull;
+ a  | b  
+----+----
+ 42 | \0
+    | 
+(2 rows)
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -349,6 +372,34 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+SELECT * FROM vistest;
+ a  
+----
+ a2
+ b
+(2 rows)
+
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+COMMIT;
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 SELECT * FROM vistest;
  a 
@@ -409,7 +460,7 @@ SELECT * FROM vistest;
 (2 rows)
 
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -420,6 +471,8 @@ CREATE TEMP TABLE forcetest (
 -- should succeed with no effect ("b" remains an empty string, "c" remains NULL)
 BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 1);
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
  b |  c   
@@ -430,6 +483,8 @@ SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
 BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 1);
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
  c |  d   
@@ -486,6 +541,31 @@ select * from check_con_tbl;
    
 (2 rows)
 
+\d+ check_con_tbl
+                               Table "public.check_con_tbl"
+ Column |  Type   | Collation | Nullable | Default | Storage | Stats target | Description 
+--------+---------+-----------+----------+---------+---------+--------------+-------------
+ f1     | integer |           |          |         | plain   |              | 
+Check constraints:
+    "check_con_tbl_check" CHECK (check_con_function(check_con_tbl.*))
+
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 1);
+NOTICE:  input = {"f1":1}
+NOTICE:  input = {"f1":null}
+copy check_con_tbl from stdin with (parallel 1);
+NOTICE:  input = {"f1":0}
+ERROR:  new row for relation "check_con_tbl" violates check constraint "check_con_tbl_check"
+DETAIL:  Failing row contains (0).
+CONTEXT:  COPY check_con_tbl, line 1: "0"
+parallel worker
+select * from check_con_tbl;
+ f1 
+----
+  1
+   
+(2 rows)
+
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
 CREATE ROLE regress_rls_copy_user_colperms;
@@ -600,8 +680,130 @@ SELECT * FROM instead_of_insert_tbl;
 (2 rows)
 
 COMMIT;
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+COPY test_parallel_copy (a, b, c, d, e) from stdin with (PARALLEL 1);
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1, FORMAT 'csv', HEADER);
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0');
+ERROR:  argument to option "parallel" must be a positive integer greater than zero
+LINE 1: COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0'...
+                                                        ^
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri from stdin with (FORMAT csv, DELIMITER ',', PARALLEL 1);
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1) WHERE height > random() * 65;
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- temporary table copy: should peform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+COPY temp_test (a) from stdin with (PARALLEL 1);
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) from stdin with (PARALLEL 1);
+ERROR:  column "xyz" of relation "test_parallel_copy" does not exist
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) from stdin with (PARALLEL 1);
+ERROR:  column "d" specified more than once
+-- missing data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  invalid input syntax for type integer: ""
+CONTEXT:  COPY test_parallel_copy, line 0, column a: ""
+parallel worker
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2000	230	23	23"
+parallel worker
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2001	231	\N	\N"
+parallel worker
+-- extra data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  extra data after last expected column
+CONTEXT:  COPY test_parallel_copy, line 1: "2002	232	40	50	60	70	80"
+parallel worker
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) from stdin with (delimiter ',', null 'x', PARALLEL 1) ;
+COPY test_parallel_copy from stdin WITH (DELIMITER ';', NULL '', PARALLEL 1);
+COPY test_parallel_copy from stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL 1);
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = 50004;
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a > 60003;
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE f > 60003;
+ERROR:  column "f" does not exist
+LINE 1: ..._parallel_copy from stdin WITH (PARALLEL 1) WHERE f > 60003;
+                                                             ^
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+ERROR:  missing FROM-clause entry for table "x"
+LINE 1: ...rallel_copy from stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+                                                                  ^
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (SELECT 1 FROM x);
+ERROR:  cannot use subquery in COPY FROM WHERE condition
+LINE 1: ...arallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (SELECT...
+                                                             ^
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (generate_series(1,5));
+ERROR:  set-returning functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...lel_copy from stdin WITH (PARALLEL 1) WHERE a IN (generate_s...
+                                                             ^
+COPY test_parallel_copy from stdin WITH(PARALLEL 1) WHERE a = row_number() over(b);
+ERROR:  window functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...rallel_copy from stdin WITH(PARALLEL 1) WHERE a = row_number...
+                                                             ^
+-- check results of copy in
+SELECT * FROM test_parallel_copy;
+   a   | b  |     c      |    d    |    e    
+-------+----+------------+---------+---------
+     1 | 11 | test_c1    | test_d1 | test_e1
+     2 | 12 | test_c2    | test_d2 | test_e2
+       |  3 | stuff      | test_d3 | 
+       |  4 | stuff      | test_d4 | 
+       |  5 | stuff      | test_d5 | 
+       |    | 45         | 80      | 90
+       |    | x          | \x      | \x
+       |    | ,          | \,      | \
+  3000 |    | c          |         | 
+  4000 |    | C          |         | 
+  4001 |  1 | empty      |         | 
+  4002 |  2 | null       |         | 
+  4003 |  3 | Backslash  | \       | \
+  4004 |  4 | BackslashX | \X      | \X
+  4005 |  5 | N          | N       | N
+  4006 |  6 | BackslashN | \N      | \N
+  4007 |  7 | XX         | XX      | XX
+  4008 |  8 | Delimiter  | :       | :
+ 50004 | 25 | 35         | 45      | 55
+ 60004 | 25 | 35         | 45      | 55
+ 60005 | 26 | 36         | 46      | 56
+(21 rows)
+
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
 DROP TABLE x, y;
diff --git a/src/test/regress/input/copy.source b/src/test/regress/input/copy.source
index a1d529a..159c058 100644
--- a/src/test/regress/input/copy.source
+++ b/src/test/regress/input/copy.source
@@ -15,6 +15,13 @@ DELETE FROM onek;
 
 COPY onek FROM '@abs_builddir@/results/onek.data';
 
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+
+SELECT COUNT(*) FROM tenk1;
+
+TRUNCATE tenk1;
+
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
@@ -159,6 +166,11 @@ truncate parted_copytest;
 
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
 
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
+
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/output/copy.source b/src/test/regress/output/copy.source
index 938d355..c3003fe 100644
--- a/src/test/regress/output/copy.source
+++ b/src/test/regress/output/copy.source
@@ -9,6 +9,15 @@ COPY onek FROM '@abs_srcdir@/data/onek.data';
 COPY onek TO '@abs_builddir@/results/onek.data';
 DELETE FROM onek;
 COPY onek FROM '@abs_builddir@/results/onek.data';
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+SELECT COUNT(*) FROM tenk1;
+ count 
+-------
+ 10000
+(1 row)
+
+TRUNCATE tenk1;
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
 COPY person FROM '@abs_srcdir@/data/person.data';
@@ -113,6 +122,9 @@ insert into parted_copytest select x,1,'One' from generate_series(1011,1020) x;
 copy (select * from parted_copytest order by a) to '@abs_builddir@/results/parted_copytest.csv';
 truncate parted_copytest;
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/sql/copy2.sql b/src/test/regress/sql/copy2.sql
index 902f4fa..032cea9 100644
--- a/src/test/regress/sql/copy2.sql
+++ b/src/test/regress/sql/copy2.sql
@@ -157,7 +157,7 @@ COPY y TO stdout (FORMAT CSV, FORCE_QUOTE *);
 
 --test that we read consecutive LFs properly
 
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 
 COPY testnl FROM stdin CSV;
 1,"a field with two LFs
@@ -165,8 +165,16 @@ COPY testnl FROM stdin CSV;
 inside",2
 \.
 
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+1,"a field with two LFs
+
+inside",2
+\.
+
+SELECT * FROM testnl;
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 
 COPY testeoc FROM stdin CSV;
 a\.
@@ -175,11 +183,19 @@ c\.d
 "\."
 \.
 
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+a\.
+\.b
+c\.d
+"\."
+\.
+
 COPY testeoc TO stdout CSV;
 
 -- test handling of nonstandard null marker that violates escaping rules
 
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 
 COPY testnull TO stdout WITH NULL AS E'\\0';
@@ -191,6 +207,14 @@ COPY testnull FROM stdin WITH NULL AS E'\\0';
 
 SELECT * FROM testnull;
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 1);
+42	\\0
+\0	\0
+\.
+
+SELECT * FROM testnull;
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -235,6 +259,23 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+a2
+b
+\.
+SELECT * FROM vistest;
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+d2
+e
+\.
+SELECT * FROM vistest;
+COMMIT;
+SELECT * FROM vistest;
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 x
 y
@@ -284,7 +325,7 @@ SELECT * FROM vistest;
 COMMIT;
 SELECT * FROM vistest;
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -297,6 +338,10 @@ BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
 1,,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 1);
+1,,""
+\.
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
@@ -304,6 +349,10 @@ BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
 2,'a',,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 1);
+2,'a',,""
+\.
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
 -- should fail with not-null constraint violation
@@ -339,6 +388,16 @@ copy check_con_tbl from stdin;
 0
 \.
 select * from check_con_tbl;
+\d+ check_con_tbl
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 1);
+1
+\N
+\.
+copy check_con_tbl from stdin with (parallel 1);
+0
+\.
+select * from check_con_tbl;
 
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
@@ -440,8 +499,149 @@ test1
 SELECT * FROM instead_of_insert_tbl;
 COMMIT;
 
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+
+COPY test_parallel_copy (a, b, c, d, e) from stdin with (PARALLEL 1);
+1	11	test_c1	test_d1	test_e1
+2	12	test_c2	test_d2	test_e2
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+3	test_d3
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+4	test_d4
+5	test_d5
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1, FORMAT 'csv', HEADER);
+b	d
+\.
+
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0');
+
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri from stdin with (FORMAT csv, DELIMITER ',', PARALLEL 1);
+10
+\.
+
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1) WHERE height > random() * 65;
+60,60,60
+\.
+
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+60
+\.
+
+-- temporary table copy: should peform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+
+COPY temp_test (a) from stdin with (PARALLEL 1);
+10
+\.
+
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) from stdin with (PARALLEL 1);
+
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) from stdin with (PARALLEL 1);
+
+-- missing data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+
+\.
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+2000	230	23	23
+\.
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+2001	231	\N	\N
+\.
+
+-- extra data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+2002	232	40	50	60	70	80
+\.
+
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) from stdin with (delimiter ',', null 'x', PARALLEL 1) ;
+x,45,80,90
+x,\x,\\x,\\\x
+x,\,,\\\,,\\
+\.
+
+COPY test_parallel_copy from stdin WITH (DELIMITER ';', NULL '', PARALLEL 1);
+3000;;c;;
+\.
+
+COPY test_parallel_copy from stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL 1);
+4000:\X:C:\X:\X
+4001:1:empty::
+4002:2:null:\X:\X
+4003:3:Backslash:\\:\\
+4004:4:BackslashX:\\X:\\X
+4005:5:N:\N:\N
+4006:6:BackslashN:\\N:\\N
+4007:7:XX:\XX:\XX
+4008:8:Delimiter:\::\:
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = 50004;
+50003	24	34	44	54
+50004	25	35	45 	55
+50005	26	36	46	56
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a > 60003;
+60001	22	32	42	52
+60002	23	33	43	53
+60003	24	34	44	54
+60004	25	35	45	55
+60005	26	36	46	56
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE f > 60003;
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (SELECT 1 FROM x);
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (generate_series(1,5));
+
+COPY test_parallel_copy from stdin WITH(PARALLEL 1) WHERE a = row_number() over(b);
+
+-- check results of copy in
+SELECT * FROM test_parallel_copy;
+
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
 DROP TABLE x, y;
-- 
1.8.3.1

#115Ashutosh Sharma
ashu.coek88@gmail.com
In reply to: vignesh C (#114)
Re: Parallel copy

Some review comments (mostly) from the leader side code changes:

1) Do we need a DSM key for the FORCE_QUOTE option? I think FORCE_QUOTE
option is only used with COPY TO and not COPY FROM so not sure why you have
added it.

PARALLEL_COPY_KEY_FORCE_QUOTE_LIST

2) Should we be allocating the parallel copy data structure only when it is
confirmed that the parallel copy is allowed?

pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
cstate->pcdata = pcdata;

Or, if you want it to be allocated before confirming if Parallel copy is
allowed or not, then I think it would be good to allocate it in
*cstate->copycontext* memory context so that when EndCopy is called towards
the end of the COPY FROM operation, the entire context itself gets deleted
thereby freeing the memory space allocated for pcdata. In fact it would be
good to ensure that all the local memory allocated inside the ctstate
structure gets allocated in the *cstate->copycontext* memory context.

3) Should we allow Parallel Copy when the insert method is
CIM_MULTI_CONDITIONAL?

+   /* Check if the insertion mode is single. */
+   if (FindInsertMethod(cstate) == CIM_SINGLE)
+       return false;

I know we have added checks in CopyFrom() to ensure that if any trigger
(before row or instead of) is found on any of partition being loaded with
data, then COPY FROM operation would fail, but does it mean that we are
okay to perform parallel copy on partitioned table. Have we done some
performance testing with the partitioned table where the data in the input
file needs to be routed to the different partitions?

4) There are lot of if-checks in IsParallelCopyAllowed function that are
checked in CopyFrom function as well which means in case of Parallel Copy
those checks will get executed multiple times (first by the leader and from
second time onwards by each worker process). Is that required?

5) Should the worker process be calling this function when the leader has
already called it once in ExecBeforeStmtTrigger()?

/* Verify the named relation is a valid target for INSERT */
CheckValidResultRel(resultRelInfo, CMD_INSERT);

6) I think it would be good to re-write the comments atop
ParallelCopyLeader(). From the present comments it appears as if you were
trying to put the information pointwise but somehow you ended up putting in
a paragraph. The comments also have some typos like *line beaks* which
possibly means line breaks. This is applicable for other comments as well
where you

7) Is the following checking equivalent to IsWorker()? If so, it would be
good to replace it with an IsWorker like macro to increase the readability.

(IsParallelCopy() && !IsLeader())

--
With Regards,
Ashutosh Sharma
EnterpriseDB:http://www.enterprisedb.com

On Fri, Jul 17, 2020 at 2:09 PM vignesh C <vignesh21@gmail.com> wrote:

Show quoted text

Please find the updated patch with the fixes included.

Patch 0003-Allow-copy-from-command-to-process-data-from-file-ST.patch
had few indentation issues, I have fixed and attached the patch for
the same.

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

#116Amit Kapila
amit.kapila16@gmail.com
In reply to: vignesh C (#114)
Re: Parallel copy

On Fri, Jul 17, 2020 at 2:09 PM vignesh C <vignesh21@gmail.com> wrote:

Please find the updated patch with the fixes included.

Patch 0003-Allow-copy-from-command-to-process-data-from-file-ST.patch
had few indentation issues, I have fixed and attached the patch for
the same.

Ensure to use the version with each patch-series as that makes it
easier for the reviewer to verify the changes done in the latest
version of the patch. One way is to use commands like "git
format-patch -6 -v <version_of_patch_series>" or you can add the
version number manually.

Review comments:
===================

0001-Copy-code-readjustment-to-support-parallel-copy
1.
@@ -807,8 +835,11 @@ CopyLoadRawBuf(CopyState cstate)
else
nbytes = 0; /* no data need be saved */

+ if (cstate->copy_dest == COPY_NEW_FE)
+ minread = RAW_BUF_SIZE - nbytes;
+
  inbytes = CopyGetData(cstate, cstate->raw_buf + nbytes,
-   1, RAW_BUF_SIZE - nbytes);
+   minread, RAW_BUF_SIZE - nbytes);

No comment to explain why this change is done?

0002-Framework-for-leader-worker-in-parallel-copy
2.
+ * ParallelCopyLineBoundary is common data structure between leader & worker,
+ * Leader process will be populating data block, data block offset &
the size of
+ * the record in DSM for the workers to copy the data into the relation.
+ * This is protected by the following sequence in the leader & worker. If they
+ * don't follow this order the worker might process wrong line_size and leader
+ * might populate the information which worker has not yet processed or in the
+ * process of processing.
+ * Leader should operate in the following order:
+ * 1) check if line_size is -1, if not wait, it means worker is still
+ * processing.
+ * 2) set line_state to LINE_LEADER_POPULATING.
+ * 3) update first_block, start_offset & cur_lineno in any order.
+ * 4) update line_size.
+ * 5) update line_state to LINE_LEADER_POPULATED.
+ * Worker should operate in the following order:
+ * 1) check line_state is LINE_LEADER_POPULATED, if not it means
leader is still
+ * populating the data.
+ * 2) read line_size.
+ * 3) only one worker should choose one line for processing, this is handled by
+ *    using pg_atomic_compare_exchange_u32, worker will change the sate to
+ *    LINE_WORKER_PROCESSING only if line_state is LINE_LEADER_POPULATED.
+ * 4) read first_block, start_offset & cur_lineno in any order.
+ * 5) process line_size data.
+ * 6) update line_size to -1.
+ */
+typedef struct ParallelCopyLineBoundary

Are we doing all this state management to avoid using locks while
processing lines? If so, I think we can use either spinlock or LWLock
to keep the main patch simple and then provide a later patch to make
it lock-less. This will allow us to first focus on the main design of
the patch rather than trying to make this datastructure processing
lock-less in the best possible way.

3.
+ /*
+ * Actual lines inserted by worker (some records will be filtered based on
+ * where condition).
+ */
+ pg_atomic_uint64 processed;
+ pg_atomic_uint64 total_worker_processed; /* total processed records
by the workers */

The difference between processed and total_worker_processed is not
clear. Can we expand the comments a bit?

4.
+ * SerializeList - Insert a list into shared memory.
+ */
+static void
+SerializeList(ParallelContext *pcxt, int key, List *inputlist,
+   Size est_list_size)
+{
+ if (inputlist != NIL)
+ {
+ ParallelCopyKeyListInfo *sharedlistinfo = (ParallelCopyKeyListInfo
*)shm_toc_allocate(pcxt->toc,
+ est_list_size);
+ CopyListSharedMemory(inputlist, est_list_size, sharedlistinfo);
+ shm_toc_insert(pcxt->toc, key, sharedlistinfo);
+ }
+}

Why do we need to write a special mechanism (CopyListSharedMemory) to
serialize a list. Why can't we use nodeToString? It should be able
to take care of List datatype, see outNode which is called from
nodeToString. Once you do that, I think you won't need even
EstimateLineKeysList, strlen should work instead.

Check, if you have any similar special handling for other types that
can be dealt with nodeToString?

5.
+ MemSet(shared_info_ptr, 0, est_shared_info);
+ shared_info_ptr->is_read_in_progress = true;
+ shared_info_ptr->cur_block_pos = -1;
+ shared_info_ptr->full_transaction_id = full_transaction_id;
+ shared_info_ptr->mycid = GetCurrentCommandId(true);
+ for (count = 0; count < RINGSIZE; count++)
+ {
+ ParallelCopyLineBoundary *lineInfo =
&shared_info_ptr->line_boundaries.ring[count];
+ pg_atomic_init_u32(&(lineInfo->line_size), -1);
+ }
+

You can move this initialization in a separate function.

6.
In function BeginParallelCopy(), you need to keep a provision to
collect wal_usage and buf_usage stats. See _bt_begin_parallel for
reference. Those will be required for pg_stat_statements.

7.
DeserializeString() -- it is better to name this function as RestoreString.
ParallelWorkerInitialization() -- it is better to name this function
as InitializeParallelCopyInfo or something like that, the current name
is quite confusing.
ParallelCopyLeader() -- how about ParallelCopyFrom? ParallelCopyLeader
doesn't sound good to me. You can suggest something else if you don't
like ParallelCopyFrom

8.
 /*
- * PopulateGlobalsForCopyFrom - Populates the common variables
required for copy
- * from operation. This is a helper function for BeginCopy function.
+ * PopulateCatalogInformation - Populates the common variables
required for copy
+ * from operation. This is a helper function for BeginCopy &
+ * ParallelWorkerInitialization function.
  */
 static void
 PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc tupDesc,
- List *attnamelist)
+    List *attnamelist)

The actual function name and the name in function header don't match.
I also don't like this function name, how about
PopulateCommonCstateInfo? Similarly how about changing
PopulateCatalogInformation to PopulateCstateCatalogInfo?

9.
+static const struct
+{
+ char *fn_name;
+ copy_data_source_cb fn_addr;
+} InternalParallelCopyFuncPtrs[] =
+
+{
+ {
+ "copy_read_data", copy_read_data
+ },
+};

The function copy_read_data is present in
src/backend/replication/logical/tablesync.c and seems to be used
during logical replication. Why do we want to expose this function as
part of this patch?

0003-Allow-copy-from-command-to-process-data-from-file-ST
10.
In the commit message, you have written "The leader does not
participate in the insertion of data, leaders only responsibility will
be to identify the lines as fast as possible for the workers to do the
actual copy operation. The leader waits till all the lines populated
are processed by the workers and exits."

I think you should also mention that we have chosen this design based
on the reason "that everything stalls if the leader doesn't accept
further input data, as well as when there are no available splitted
chunks so it doesn't seem like a good idea to have the leader do other
work. This is backed by the performance data where we have seen that
with 1 worker there is just a 5-10% (or whatever percentage difference
you have seen) performance difference)".

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#117vignesh C
vignesh21@gmail.com
In reply to: Amit Kapila (#116)
6 attachment(s)
Re: Parallel copy

Thanks for your comments Amit, i have worked on the comments, my thoughts
on the same are mentioned below.

On Tue, Jul 21, 2020 at 3:54 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Fri, Jul 17, 2020 at 2:09 PM vignesh C <vignesh21@gmail.com> wrote:

Please find the updated patch with the fixes included.

Patch 0003-Allow-copy-from-command-to-process-data-from-file-ST.patch
had few indentation issues, I have fixed and attached the patch for
the same.

Ensure to use the version with each patch-series as that makes it
easier for the reviewer to verify the changes done in the latest
version of the patch. One way is to use commands like "git
format-patch -6 -v <version_of_patch_series>" or you can add the
version number manually.

Taken care.

Review comments:
===================

0001-Copy-code-readjustment-to-support-parallel-copy
1.
@@ -807,8 +835,11 @@ CopyLoadRawBuf(CopyState cstate)
else
nbytes = 0; /* no data need be saved */

+ if (cstate->copy_dest == COPY_NEW_FE)
+ minread = RAW_BUF_SIZE - nbytes;
+
inbytes = CopyGetData(cstate, cstate->raw_buf + nbytes,
-   1, RAW_BUF_SIZE - nbytes);
+   minread, RAW_BUF_SIZE - nbytes);

No comment to explain why this change is done?

0002-Framework-for-leader-worker-in-parallel-copy

Currently CopyGetData copies a lesser amount of data to buffer even though
space is available in buffer because minread was passed as 1 to
CopyGetData. Because of this there are frequent call to CopyGetData for
fetching the data. In this case it will load only some data due to the
below check:
while (maxread > 0 && bytesread < minread && !cstate->reached_eof)
After reading some data bytesread will be greater than minread which is
passed as 1 and return with lesser amount of data, even though there is
some space.
This change is required for parallel copy feature as each time we get a new
DSM data block which is of 64K size and copy the data. If we copy less data
into DSM data blocks we might end up consuming all the DSM data blocks. I
felt this issue can be fixed as part of HEAD. Have posted a separate thread
[1]: /messages/by-id/CALDaNm0v4CjmvSnftYnx_9pOS_dKRG=O3NnBgJsQmi0KipvLog@mail.gmail.com
Can that go as a separate
patch or should we include it here?
[1]: /messages/by-id/CALDaNm0v4CjmvSnftYnx_9pOS_dKRG=O3NnBgJsQmi0KipvLog@mail.gmail.com
/messages/by-id/CALDaNm0v4CjmvSnftYnx_9pOS_dKRG=O3NnBgJsQmi0KipvLog@mail.gmail.com

2.
+ * ParallelCopyLineBoundary is common data structure between leader &

worker,

+ * Leader process will be populating data block, data block offset &
the size of
+ * the record in DSM for the workers to copy the data into the relation.
+ * This is protected by the following sequence in the leader & worker.

If they

+ * don't follow this order the worker might process wrong line_size and

leader

+ * might populate the information which worker has not yet processed or

in the

+ * process of processing.
+ * Leader should operate in the following order:
+ * 1) check if line_size is -1, if not wait, it means worker is still
+ * processing.
+ * 2) set line_state to LINE_LEADER_POPULATING.
+ * 3) update first_block, start_offset & cur_lineno in any order.
+ * 4) update line_size.
+ * 5) update line_state to LINE_LEADER_POPULATED.
+ * Worker should operate in the following order:
+ * 1) check line_state is LINE_LEADER_POPULATED, if not it means
leader is still
+ * populating the data.
+ * 2) read line_size.
+ * 3) only one worker should choose one line for processing, this is

handled by

+ * using pg_atomic_compare_exchange_u32, worker will change the sate

to

+ *    LINE_WORKER_PROCESSING only if line_state is LINE_LEADER_POPULATED.
+ * 4) read first_block, start_offset & cur_lineno in any order.
+ * 5) process line_size data.
+ * 6) update line_size to -1.
+ */
+typedef struct ParallelCopyLineBoundary

Are we doing all this state management to avoid using locks while
processing lines? If so, I think we can use either spinlock or LWLock
to keep the main patch simple and then provide a later patch to make
it lock-less. This will allow us to first focus on the main design of
the patch rather than trying to make this datastructure processing
lock-less in the best possible way.

The steps will be more or less same if we use spinlock too. step 1, step 3
& step 4 will be common we have to use lock & unlock instead of step 2 &
step 5. I feel we can retain the current implementation.

3.
+ /*
+ * Actual lines inserted by worker (some records will be filtered based

on

+ * where condition).
+ */
+ pg_atomic_uint64 processed;
+ pg_atomic_uint64 total_worker_processed; /* total processed records
by the workers */

The difference between processed and total_worker_processed is not
clear. Can we expand the comments a bit?

Fixed

4.
+ * SerializeList - Insert a list into shared memory.
+ */
+static void
+SerializeList(ParallelContext *pcxt, int key, List *inputlist,
+   Size est_list_size)
+{
+ if (inputlist != NIL)
+ {
+ ParallelCopyKeyListInfo *sharedlistinfo = (ParallelCopyKeyListInfo
*)shm_toc_allocate(pcxt->toc,
+ est_list_size);
+ CopyListSharedMemory(inputlist, est_list_size, sharedlistinfo);
+ shm_toc_insert(pcxt->toc, key, sharedlistinfo);
+ }
+}

Why do we need to write a special mechanism (CopyListSharedMemory) to
serialize a list. Why can't we use nodeToString? It should be able
to take care of List datatype, see outNode which is called from
nodeToString. Once you do that, I think you won't need even
EstimateLineKeysList, strlen should work instead.

Check, if you have any similar special handling for other types that
can be dealt with nodeToString?

Fixed

5.
+ MemSet(shared_info_ptr, 0, est_shared_info);
+ shared_info_ptr->is_read_in_progress = true;
+ shared_info_ptr->cur_block_pos = -1;
+ shared_info_ptr->full_transaction_id = full_transaction_id;
+ shared_info_ptr->mycid = GetCurrentCommandId(true);
+ for (count = 0; count < RINGSIZE; count++)
+ {
+ ParallelCopyLineBoundary *lineInfo =
&shared_info_ptr->line_boundaries.ring[count];
+ pg_atomic_init_u32(&(lineInfo->line_size), -1);
+ }
+

You can move this initialization in a separate function.

Fixed

6.
In function BeginParallelCopy(), you need to keep a provision to
collect wal_usage and buf_usage stats. See _bt_begin_parallel for
reference. Those will be required for pg_stat_statements.

Fixed

7.
DeserializeString() -- it is better to name this function as

RestoreString.

ParallelWorkerInitialization() -- it is better to name this function
as InitializeParallelCopyInfo or something like that, the current name
is quite confusing.
ParallelCopyLeader() -- how about ParallelCopyFrom? ParallelCopyLeader
doesn't sound good to me. You can suggest something else if you don't
like ParallelCopyFrom

Fixed

8.
/*
- * PopulateGlobalsForCopyFrom - Populates the common variables
required for copy
- * from operation. This is a helper function for BeginCopy function.
+ * PopulateCatalogInformation - Populates the common variables
required for copy
+ * from operation. This is a helper function for BeginCopy &
+ * ParallelWorkerInitialization function.
*/
static void
PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc tupDesc,
- List *attnamelist)
+    List *attnamelist)

The actual function name and the name in function header don't match.
I also don't like this function name, how about
PopulateCommonCstateInfo? Similarly how about changing
PopulateCatalogInformation to PopulateCstateCatalogInfo?

Fixed

9.
+static const struct
+{
+ char *fn_name;
+ copy_data_source_cb fn_addr;
+} InternalParallelCopyFuncPtrs[] =
+
+{
+ {
+ "copy_read_data", copy_read_data
+ },
+};

The function copy_read_data is present in
src/backend/replication/logical/tablesync.c and seems to be used
during logical replication. Why do we want to expose this function as
part of this patch?

I was thinking we could include the framework to support parallelism for
logical replication too and can be enhanced when it is needed. Now I have
removed this as part of the new patch provided, that can be added whenever
required.

0003-Allow-copy-from-command-to-process-data-from-file-ST
10.
In the commit message, you have written "The leader does not
participate in the insertion of data, leaders only responsibility will
be to identify the lines as fast as possible for the workers to do the
actual copy operation. The leader waits till all the lines populated
are processed by the workers and exits."

I think you should also mention that we have chosen this design based
on the reason "that everything stalls if the leader doesn't accept
further input data, as well as when there are no available splitted
chunks so it doesn't seem like a good idea to have the leader do other
work. This is backed by the performance data where we have seen that
with 1 worker there is just a 5-10% (or whatever percentage difference
you have seen) performance difference)".

Fixed.
Please find the new patch attached with the fixes.
Thoughts?

On Tue, Jul 21, 2020 at 3:54 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

Show quoted text

On Fri, Jul 17, 2020 at 2:09 PM vignesh C <vignesh21@gmail.com> wrote:

Please find the updated patch with the fixes included.

Patch 0003-Allow-copy-from-command-to-process-data-from-file-ST.patch
had few indentation issues, I have fixed and attached the patch for
the same.

Ensure to use the version with each patch-series as that makes it
easier for the reviewer to verify the changes done in the latest
version of the patch. One way is to use commands like "git
format-patch -6 -v <version_of_patch_series>" or you can add the
version number manually.

Review comments:
===================

0001-Copy-code-readjustment-to-support-parallel-copy
1.
@@ -807,8 +835,11 @@ CopyLoadRawBuf(CopyState cstate)
else
nbytes = 0; /* no data need be saved */

+ if (cstate->copy_dest == COPY_NEW_FE)
+ minread = RAW_BUF_SIZE - nbytes;
+
inbytes = CopyGetData(cstate, cstate->raw_buf + nbytes,
-   1, RAW_BUF_SIZE - nbytes);
+   minread, RAW_BUF_SIZE - nbytes);

No comment to explain why this change is done?

0002-Framework-for-leader-worker-in-parallel-copy
2.
+ * ParallelCopyLineBoundary is common data structure between leader &
worker,
+ * Leader process will be populating data block, data block offset &
the size of
+ * the record in DSM for the workers to copy the data into the relation.
+ * This is protected by the following sequence in the leader & worker. If
they
+ * don't follow this order the worker might process wrong line_size and
leader
+ * might populate the information which worker has not yet processed or
in the
+ * process of processing.
+ * Leader should operate in the following order:
+ * 1) check if line_size is -1, if not wait, it means worker is still
+ * processing.
+ * 2) set line_state to LINE_LEADER_POPULATING.
+ * 3) update first_block, start_offset & cur_lineno in any order.
+ * 4) update line_size.
+ * 5) update line_state to LINE_LEADER_POPULATED.
+ * Worker should operate in the following order:
+ * 1) check line_state is LINE_LEADER_POPULATED, if not it means
leader is still
+ * populating the data.
+ * 2) read line_size.
+ * 3) only one worker should choose one line for processing, this is
handled by
+ *    using pg_atomic_compare_exchange_u32, worker will change the sate to
+ *    LINE_WORKER_PROCESSING only if line_state is LINE_LEADER_POPULATED.
+ * 4) read first_block, start_offset & cur_lineno in any order.
+ * 5) process line_size data.
+ * 6) update line_size to -1.
+ */
+typedef struct ParallelCopyLineBoundary

Are we doing all this state management to avoid using locks while
processing lines? If so, I think we can use either spinlock or LWLock
to keep the main patch simple and then provide a later patch to make
it lock-less. This will allow us to first focus on the main design of
the patch rather than trying to make this datastructure processing
lock-less in the best possible way.

3.
+ /*
+ * Actual lines inserted by worker (some records will be filtered based on
+ * where condition).
+ */
+ pg_atomic_uint64 processed;
+ pg_atomic_uint64 total_worker_processed; /* total processed records
by the workers */

The difference between processed and total_worker_processed is not
clear. Can we expand the comments a bit?

4.
+ * SerializeList - Insert a list into shared memory.
+ */
+static void
+SerializeList(ParallelContext *pcxt, int key, List *inputlist,
+   Size est_list_size)
+{
+ if (inputlist != NIL)
+ {
+ ParallelCopyKeyListInfo *sharedlistinfo = (ParallelCopyKeyListInfo
*)shm_toc_allocate(pcxt->toc,
+ est_list_size);
+ CopyListSharedMemory(inputlist, est_list_size, sharedlistinfo);
+ shm_toc_insert(pcxt->toc, key, sharedlistinfo);
+ }
+}

Why do we need to write a special mechanism (CopyListSharedMemory) to
serialize a list. Why can't we use nodeToString? It should be able
to take care of List datatype, see outNode which is called from
nodeToString. Once you do that, I think you won't need even
EstimateLineKeysList, strlen should work instead.

Check, if you have any similar special handling for other types that
can be dealt with nodeToString?

5.
+ MemSet(shared_info_ptr, 0, est_shared_info);
+ shared_info_ptr->is_read_in_progress = true;
+ shared_info_ptr->cur_block_pos = -1;
+ shared_info_ptr->full_transaction_id = full_transaction_id;
+ shared_info_ptr->mycid = GetCurrentCommandId(true);
+ for (count = 0; count < RINGSIZE; count++)
+ {
+ ParallelCopyLineBoundary *lineInfo =
&shared_info_ptr->line_boundaries.ring[count];
+ pg_atomic_init_u32(&(lineInfo->line_size), -1);
+ }
+

You can move this initialization in a separate function.

6.
In function BeginParallelCopy(), you need to keep a provision to
collect wal_usage and buf_usage stats. See _bt_begin_parallel for
reference. Those will be required for pg_stat_statements.

7.
DeserializeString() -- it is better to name this function as RestoreString.
ParallelWorkerInitialization() -- it is better to name this function
as InitializeParallelCopyInfo or something like that, the current name
is quite confusing.
ParallelCopyLeader() -- how about ParallelCopyFrom? ParallelCopyLeader
doesn't sound good to me. You can suggest something else if you don't
like ParallelCopyFrom

8.
/*
- * PopulateGlobalsForCopyFrom - Populates the common variables
required for copy
- * from operation. This is a helper function for BeginCopy function.
+ * PopulateCatalogInformation - Populates the common variables
required for copy
+ * from operation. This is a helper function for BeginCopy &
+ * ParallelWorkerInitialization function.
*/
static void
PopulateGlobalsForCopyFrom(CopyState cstate, TupleDesc tupDesc,
- List *attnamelist)
+    List *attnamelist)

The actual function name and the name in function header don't match.
I also don't like this function name, how about
PopulateCommonCstateInfo? Similarly how about changing
PopulateCatalogInformation to PopulateCstateCatalogInfo?

9.
+static const struct
+{
+ char *fn_name;
+ copy_data_source_cb fn_addr;
+} InternalParallelCopyFuncPtrs[] =
+
+{
+ {
+ "copy_read_data", copy_read_data
+ },
+};

The function copy_read_data is present in
src/backend/replication/logical/tablesync.c and seems to be used
during logical replication. Why do we want to expose this function as
part of this patch?

0003-Allow-copy-from-command-to-process-data-from-file-ST
10.
In the commit message, you have written "The leader does not
participate in the insertion of data, leaders only responsibility will
be to identify the lines as fast as possible for the workers to do the
actual copy operation. The leader waits till all the lines populated
are processed by the workers and exits."

I think you should also mention that we have chosen this design based
on the reason "that everything stalls if the leader doesn't accept
further input data, as well as when there are no available splitted
chunks so it doesn't seem like a good idea to have the leader do other
work. This is backed by the performance data where we have seen that
with 1 worker there is just a 5-10% (or whatever percentage difference
you have seen) performance difference)".

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

Attachments:

v2-0001-Copy-code-readjustment-to-support-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=v2-0001-Copy-code-readjustment-to-support-parallel-copy.patchDownload
From 8207e4279b841705a00eb33cd9d19506e267f1c5 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 22 Jul 2020 10:38:11 +0530
Subject: [PATCH v2 1/6] Copy code readjustment to support parallel copy.

This patch has the copy code slightly readjusted so that the common code is
separated to functions/macros, these functions/macros will be used by the
workers in the parallel copy code of the upcoming patches. EOL removal is moved
from CopyReadLine to CopyReadLineText, this change was required because in case
of parallel copy the record identification and record updation is done in
CopyReadLineText, before record information is updated in shared memory the new
line characters should be removed.
---
 src/backend/commands/copy.c | 361 ++++++++++++++++++++++++++------------------
 1 file changed, 218 insertions(+), 143 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 44da71c..249e908 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -95,6 +95,9 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
+#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+#define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
+
 /*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
@@ -222,7 +225,6 @@ typedef struct CopyStateData
 	 * converts it.  Note: we guarantee that there is a \0 at
 	 * raw_buf[raw_buf_len].
 	 */
-#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
@@ -350,6 +352,27 @@ if (1) \
 	goto not_end_of_copy; \
 } else ((void) 0)
 
+/*
+ * CLEAR_EOL_LINE - Wrapper for clearing EOL.
+ */
+#define CLEAR_EOL_LINE() \
+if (!result && !IsHeaderLine()) \
+	ClearEOLFromCopiedData(cstate, cstate->line_buf.data, \
+						   cstate->line_buf.len, \
+						   &cstate->line_buf.len) \
+
+/*
+ * INCREMENTPROCESSED - Increment the lines processed.
+ */
+#define INCREMENTPROCESSED(processed)  \
+processed++;
+
+/*
+ * GETPROCESSED - Get the lines processed.
+ */
+#define GETPROCESSED(processed) \
+return processed;
+
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
 
@@ -395,7 +418,11 @@ static bool CopyGetInt32(CopyState cstate, int32 *val);
 static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 
-
+static void PopulateCommonCstateInfo(CopyState cstate, TupleDesc	tup_desc,
+									   List *attnamelist);
+static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
+								   int copy_line_pos, int *copy_line_size);
+static void ConvertToServerEncoding(CopyState cstate);
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
  * in past protocol redesigns.
@@ -796,6 +823,7 @@ CopyLoadRawBuf(CopyState cstate)
 {
 	int			nbytes;
 	int			inbytes;
+	int         minread = 1;
 
 	if (cstate->raw_buf_index < cstate->raw_buf_len)
 	{
@@ -807,8 +835,11 @@ CopyLoadRawBuf(CopyState cstate)
 	else
 		nbytes = 0;				/* no data need be saved */
 
+	if (cstate->copy_dest == COPY_NEW_FE)
+		minread = RAW_BUF_SIZE - nbytes;
+
 	inbytes = CopyGetData(cstate, cstate->raw_buf + nbytes,
-						  1, RAW_BUF_SIZE - nbytes);
+						  minread, RAW_BUF_SIZE - nbytes);
 	nbytes += inbytes;
 	cstate->raw_buf[nbytes] = '\0';
 	cstate->raw_buf_index = 0;
@@ -1466,7 +1497,6 @@ BeginCopy(ParseState *pstate,
 {
 	CopyState	cstate;
 	TupleDesc	tupDesc;
-	int			num_phys_attrs;
 	MemoryContext oldcontext;
 
 	/* Allocate workspace and zero all fields */
@@ -1632,6 +1662,24 @@ BeginCopy(ParseState *pstate,
 		tupDesc = cstate->queryDesc->tupDesc;
 	}
 
+	PopulateCommonCstateInfo(cstate, tupDesc, attnamelist);
+	cstate->copy_dest = COPY_FILE;	/* default */
+
+	MemoryContextSwitchTo(oldcontext);
+
+	return cstate;
+}
+
+/*
+ * PopulateCommonCstateInfo - Populates the common variables required for copy
+ * from operation. This is a helper function for BeginCopy function.
+ */
+static void
+PopulateCommonCstateInfo(CopyState cstate, TupleDesc	tupDesc,
+							List *attnamelist)
+{
+	int			num_phys_attrs;
+
 	/* Generate or convert list of attributes to process */
 	cstate->attnumlist = CopyGetAttnums(tupDesc, cstate->rel, attnamelist);
 
@@ -1751,12 +1799,6 @@ BeginCopy(ParseState *pstate,
 		 pg_database_encoding_max_length() > 1);
 	/* See Multibyte encoding comment above */
 	cstate->encoding_embeds_ascii = PG_ENCODING_IS_CLIENT_ONLY(cstate->file_encoding);
-
-	cstate->copy_dest = COPY_FILE;	/* default */
-
-	MemoryContextSwitchTo(oldcontext);
-
-	return cstate;
 }
 
 /*
@@ -2648,32 +2690,11 @@ CopyMultiInsertInfoStore(CopyMultiInsertInfo *miinfo, ResultRelInfo *rri,
 }
 
 /*
- * Copy FROM file to relation.
+ * Check if the relation specified in copy from is valid.
  */
-uint64
-CopyFrom(CopyState cstate)
+static void
+CheckTargetRelValidity(CopyState cstate)
 {
-	ResultRelInfo *resultRelInfo;
-	ResultRelInfo *target_resultRelInfo;
-	ResultRelInfo *prevResultRelInfo = NULL;
-	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
-	ModifyTableState *mtstate;
-	ExprContext *econtext;
-	TupleTableSlot *singleslot = NULL;
-	MemoryContext oldcontext = CurrentMemoryContext;
-
-	PartitionTupleRouting *proute = NULL;
-	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
-	int			ti_options = 0; /* start with default options for insert */
-	BulkInsertState bistate = NULL;
-	CopyInsertMethod insertMethod;
-	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
-	uint64		processed = 0;
-	bool		has_before_insert_row_trig;
-	bool		has_instead_insert_row_trig;
-	bool		leafpart_use_multi_insert = false;
-
 	Assert(cstate->rel);
 
 	/*
@@ -2710,27 +2731,6 @@ CopyFrom(CopyState cstate)
 							RelationGetRelationName(cstate->rel))));
 	}
 
-	/*
-	 * If the target file is new-in-transaction, we assume that checking FSM
-	 * for free space is a waste of time.  This could possibly be wrong, but
-	 * it's unlikely.
-	 */
-	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
-		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
-		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
-		ti_options |= TABLE_INSERT_SKIP_FSM;
-
-	/*
-	 * Optimize if new relfilenode was created in this subxact or one of its
-	 * committed children and we won't see those rows later as part of an
-	 * earlier scan or command. The subxact test ensures that if this subxact
-	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
-	 * that the stronger test of exactly which subtransaction created it is
-	 * crucial for correctness of this optimization. The test for an earlier
-	 * scan or command tolerates false negatives. FREEZE causes other sessions
-	 * to see rows they would not see under MVCC, and a false negative merely
-	 * spreads that anomaly to the current session.
-	 */
 	if (cstate->freeze)
 	{
 		/*
@@ -2768,9 +2768,61 @@ CopyFrom(CopyState cstate)
 			ereport(ERROR,
 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 					 errmsg("cannot perform COPY FREEZE because the table was not created or truncated in the current subtransaction")));
+	}
+}
+
+/*
+ * Copy FROM file to relation.
+ */
+uint64
+CopyFrom(CopyState cstate)
+{
+	ResultRelInfo *resultRelInfo;
+	ResultRelInfo *target_resultRelInfo;
+	ResultRelInfo *prevResultRelInfo = NULL;
+	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
+	ModifyTableState *mtstate;
+	ExprContext *econtext;
+	TupleTableSlot *singleslot = NULL;
+	MemoryContext oldcontext = CurrentMemoryContext;
 
+	PartitionTupleRouting *proute = NULL;
+	ErrorContextCallback errcallback;
+	CommandId	mycid = GetCurrentCommandId(true);
+	int			ti_options = 0; /* start with default options for insert */
+	BulkInsertState bistate = NULL;
+	CopyInsertMethod insertMethod;
+	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
+	uint64		processed = 0;
+	bool		has_before_insert_row_trig;
+	bool		has_instead_insert_row_trig;
+	bool		leafpart_use_multi_insert = false;
+
+	CheckTargetRelValidity(cstate);
+
+	/*
+	 * If the target file is new-in-transaction, we assume that checking FSM
+	 * for free space is a waste of time.  This could possibly be wrong, but
+	 * it's unlikely.
+	 */
+	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
+		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
+		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
+		ti_options |= TABLE_INSERT_SKIP_FSM;
+
+	/*
+	 * Optimize if new relfilenode was created in this subxact or one of its
+	 * committed children and we won't see those rows later as part of an
+	 * earlier scan or command. The subxact test ensures that if this subxact
+	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
+	 * that the stronger test of exactly which subtransaction created it is
+	 * crucial for correctness of this optimization. The test for an earlier
+	 * scan or command tolerates false negatives. FREEZE causes other sessions
+	 * to see rows they would not see under MVCC, and a false negative merely
+	 * spreads that anomaly to the current session.
+	 */
+	if (cstate->freeze)
 		ti_options |= TABLE_INSERT_FROZEN;
-	}
 
 	/*
 	 * We need a ResultRelInfo so we can use the regular executor's
@@ -3263,7 +3315,7 @@ CopyFrom(CopyState cstate)
 			 * or FDW; this is the same definition used by nodeModifyTable.c
 			 * for counting tuples inserted by an INSERT command.
 			 */
-			processed++;
+			INCREMENTPROCESSED(processed)
 		}
 	}
 
@@ -3318,30 +3370,15 @@ CopyFrom(CopyState cstate)
 
 	FreeExecutorState(estate);
 
-	return processed;
+	GETPROCESSED(processed)
 }
 
 /*
- * Setup to read tuples from a file for COPY FROM.
- *
- * 'rel': Used as a template for the tuples
- * 'filename': Name of server-local file to read
- * 'attnamelist': List of char *, columns to include. NIL selects all cols.
- * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
- *
- * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ * PopulateCstateCatalogInfo - populate the catalog information.
  */
-CopyState
-BeginCopyFrom(ParseState *pstate,
-			  Relation rel,
-			  const char *filename,
-			  bool is_program,
-			  copy_data_source_cb data_source_cb,
-			  List *attnamelist,
-			  List *options)
+static void
+PopulateCstateCatalogInfo(CopyState cstate)
 {
-	CopyState	cstate;
-	bool		pipe = (filename == NULL);
 	TupleDesc	tupDesc;
 	AttrNumber	num_phys_attrs,
 				num_defaults;
@@ -3351,38 +3388,8 @@ BeginCopyFrom(ParseState *pstate,
 	Oid			in_func_oid;
 	int		   *defmap;
 	ExprState **defexprs;
-	MemoryContext oldcontext;
 	bool		volatile_defexprs;
 
-	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
-	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
-
-	/* Initialize state variables */
-	cstate->reached_eof = false;
-	cstate->eol_type = EOL_UNKNOWN;
-	cstate->cur_relname = RelationGetRelationName(cstate->rel);
-	cstate->cur_lineno = 0;
-	cstate->cur_attname = NULL;
-	cstate->cur_attval = NULL;
-
-	/*
-	 * Set up variables to avoid per-attribute overhead.  attribute_buf is
-	 * used in both text and binary modes, but we use line_buf and raw_buf
-	 * only in text mode.
-	 */
-	initStringInfo(&cstate->attribute_buf);
-	if (!cstate->binary)
-	{
-		initStringInfo(&cstate->line_buf);
-		cstate->line_buf_converted = false;
-		cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
-		cstate->raw_buf_index = cstate->raw_buf_len = 0;
-	}
-
-	/* Assign range table, we'll need it in CopyFrom. */
-	if (pstate)
-		cstate->range_table = pstate->p_rtable;
-
 	tupDesc = RelationGetDescr(cstate->rel);
 	num_phys_attrs = tupDesc->natts;
 	num_defaults = 0;
@@ -3460,6 +3467,61 @@ BeginCopyFrom(ParseState *pstate,
 	cstate->defexprs = defexprs;
 	cstate->volatile_defexprs = volatile_defexprs;
 	cstate->num_defaults = num_defaults;
+}
+
+/*
+ * Setup to read tuples from a file for COPY FROM.
+ *
+ * 'rel': Used as a template for the tuples
+ * 'filename': Name of server-local file to read
+ * 'attnamelist': List of char *, columns to include. NIL selects all cols.
+ * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
+ *
+ * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ */
+CopyState
+BeginCopyFrom(ParseState *pstate,
+			  Relation rel,
+			  const char *filename,
+			  bool is_program,
+			  copy_data_source_cb data_source_cb,
+			  List *attnamelist,
+			  List *options)
+{
+	CopyState	cstate;
+	bool		pipe = (filename == NULL);
+	MemoryContext oldcontext;
+
+	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	/* Initialize state variables */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/*
+	 * Set up variables to avoid per-attribute overhead.  attribute_buf is
+	 * used in both text and binary modes, but we use line_buf and raw_buf
+	 * only in text mode.
+	 */
+	initStringInfo(&cstate->attribute_buf);
+	if (!cstate->binary)
+	{
+		initStringInfo(&cstate->line_buf);
+		cstate->line_buf_converted = false;
+		cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+		cstate->raw_buf_index = cstate->raw_buf_len = 0;
+	}
+
+	/* Assign range table, we'll need it in CopyFrom. */
+	if (pstate)
+		cstate->range_table = pstate->p_rtable;
+
+	PopulateCstateCatalogInfo(cstate);
 	cstate->is_program = is_program;
 
 	if (data_source_cb)
@@ -3869,45 +3931,60 @@ CopyReadLine(CopyState cstate)
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
-	else
-	{
-		/*
-		 * If we didn't hit EOF, then we must have transferred the EOL marker
-		 * to line_buf along with the data.  Get rid of it.
-		 */
-		switch (cstate->eol_type)
-		{
-			case EOL_NL:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CR:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\r');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CRNL:
-				Assert(cstate->line_buf.len >= 2);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 2] == '\r');
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len -= 2;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_UNKNOWN:
-				/* shouldn't get here */
-				Assert(false);
-				break;
-		}
-	}
 
+	ConvertToServerEncoding(cstate);
+	return result;
+}
+
+/*
+ * ClearEOLFromCopiedData - Clear EOL from the copied data.
+ */
+static void
+ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
+					   int copy_line_pos, int *copy_line_size)
+{
+	/*
+	 * If we didn't hit EOF, then we must have transferred the EOL marker
+	 * to line_buf along with the data.  Get rid of it.
+	 */
+   switch (cstate->eol_type)
+   {
+	   case EOL_NL:
+		   Assert(*copy_line_size >= 1);
+		   Assert(copy_line_data[copy_line_pos - 1] == '\n');
+		   copy_line_data[copy_line_pos - 1] = '\0';
+		   (*copy_line_size)--;
+		   break;
+	   case EOL_CR:
+		   Assert(*copy_line_size >= 1);
+		   Assert(copy_line_data[copy_line_pos - 1] == '\r');
+		   copy_line_data[copy_line_pos - 1] = '\0';
+		   (*copy_line_size)--;
+		   break;
+	   case EOL_CRNL:
+		   Assert(*copy_line_size >= 2);
+		   Assert(copy_line_data[copy_line_pos - 2] == '\r');
+		   Assert(copy_line_data[copy_line_pos - 1] == '\n');
+		   copy_line_data[copy_line_pos - 2] = '\0';
+		   *copy_line_size -= 2;
+		   break;
+	   case EOL_UNKNOWN:
+		   /* shouldn't get here */
+		   Assert(false);
+		   break;
+   }
+}
+
+/*
+ * ConvertToServerEncoding - convert contents to server encoding.
+ */
+static void
+ConvertToServerEncoding(CopyState cstate)
+{
 	/* Done reading the line.  Convert it to server encoding. */
 	if (cstate->need_transcoding)
 	{
 		char	   *cvt;
-
 		cvt = pg_any_to_server(cstate->line_buf.data,
 							   cstate->line_buf.len,
 							   cstate->file_encoding);
@@ -3919,11 +3996,8 @@ CopyReadLine(CopyState cstate)
 			pfree(cvt);
 		}
 	}
-
 	/* Now it's safe to use the buffer in error messages */
 	cstate->line_buf_converted = true;
-
-	return result;
 }
 
 /*
@@ -4286,6 +4360,7 @@ not_end_of_copy:
 	 * Transfer any still-uncopied data to line_buf.
 	 */
 	REFILL_LINEBUF;
+	CLEAR_EOL_LINE();
 
 	return result;
 }
-- 
1.8.3.1

v2-0002-Framework-for-leader-worker-in-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=v2-0002-Framework-for-leader-worker-in-parallel-copy.patchDownload
From 8e013d8d1e780d9d9c3fd60595b70ec6463e7a54 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 22 Jul 2020 18:51:08 +0530
Subject: [PATCH v2 2/6] Framework for leader/worker in parallel copy

This patch has the framework for data structures in parallel copy, leader
initialization, worker initialization, shared memory updation, starting workers,
wait for workers and workers exiting.
---
 src/backend/access/transam/parallel.c |   4 +
 src/backend/commands/copy.c           | 756 +++++++++++++++++++++++++++++++++-
 src/include/commands/copy.h           |   2 +
 src/tools/pgindent/typedefs.list      |   7 +
 4 files changed, 765 insertions(+), 4 deletions(-)

diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index b042696..a3cff4b 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -25,6 +25,7 @@
 #include "catalog/pg_enum.h"
 #include "catalog/storage.h"
 #include "commands/async.h"
+#include "commands/copy.h"
 #include "executor/execParallel.h"
 #include "libpq/libpq.h"
 #include "libpq/pqformat.h"
@@ -145,6 +146,9 @@ static const struct
 	},
 	{
 		"parallel_vacuum_main", parallel_vacuum_main
+	},
+	{
+		"ParallelCopyMain", ParallelCopyMain
 	}
 };
 
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 249e908..a3cf750 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -96,9 +96,180 @@ typedef enum CopyInsertMethod
 } CopyInsertMethod;
 
 #define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+
+/*
+ * The macros DATA_BLOCK_SIZE, RINGSIZE & MAX_BLOCKS_COUNT stores the records
+ * read from the file that need to be inserted into the relation. These values
+ * help in handover of multiple records with significant size of data to be
+ * processed by each of the workers to make sure there is no context switch & the
+ * work is fairly distributed among the workers. This number showed best
+ * results in the performance tests.
+ */
+#define DATA_BLOCK_SIZE RAW_BUF_SIZE
+
+/* It can hold upto 10000 record information for worker to process. */
+#define RINGSIZE (10 * 1000)
+
+/* It can hold 1000 blocks of 64K data in DSM to be processed by the worker. */
+#define MAX_BLOCKS_COUNT 1000
+
+/*
+ * Each worker will be allocated WORKER_CHUNK_COUNT of records from DSM data
+ * block to process to avoid lock contention. This value should be mode of
+ * RINGSIZE, as wrap around cases is currently not handled while selecting the
+ * WORKER_CHUNK_COUNT by the worker.
+ */
+#define WORKER_CHUNK_COUNT 50
+
+#define	IsParallelCopy()		(cstate->is_parallel)
+#define IsLeader()				(cstate->pcdata->is_leader)
 #define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
 
 /*
+ * Copy data block information.
+ * ParallelCopyDataBlock's will be created in DSM. Data read from file will be
+ * copied in these DSM data blocks. The leader process identifies the records
+ * and the record information will be shared to the workers. The workers will
+ * insert the records into the table. There can be one or more number of records
+ * in each of the data block based on the record size.
+ */
+typedef struct ParallelCopyDataBlock
+{
+	/* The number of unprocessed lines in the current block. */
+	pg_atomic_uint32 unprocessed_line_parts;
+
+	/*
+	 * If the current line data is continued into another block, following_block
+	 * will have the position where the remaining data need to be read.
+	 */
+	uint32	following_block;
+
+	/*
+	 * This flag will be set, when the leader finds out this block can be read
+	 * safely by the worker. This helps the worker to start processing the line
+	 * early where the line will be spread across many blocks and the worker
+	 * need not wait for the complete line to be processed.
+	 */
+	bool   curr_blk_completed;
+	char   data[DATA_BLOCK_SIZE]; /* data read from file */
+	uint8  skip_bytes;
+}ParallelCopyDataBlock;
+
+/*
+ * Individual line information.
+ * ParallelCopyLineBoundary is common data structure between leader & worker,
+ * Leader process will be populating data block, data block offset & the size of
+ * the record in DSM for the workers to copy the data into the relation.
+ * This is protected by the following sequence in the leader & worker. If they
+ * don't follow this order the worker might process wrong line_size and leader
+ * might populate the information which worker has not yet processed or in the
+ * process of processing.
+ * Leader should operate in the following order:
+ * 1) check if line_size is -1, if not wait, it means worker is still
+ * processing.
+ * 2) set line_state to LINE_LEADER_POPULATING.
+ * 3) update first_block, start_offset & cur_lineno in any order.
+ * 4) update line_size.
+ * 5) update line_state to LINE_LEADER_POPULATED.
+ * Worker should operate in the following order:
+ * 1) check line_state is LINE_LEADER_POPULATED, if not it means leader is still
+ * populating the data.
+ * 2) read line_size.
+ * 3) only one worker should choose one line for processing, this is handled by
+ *    using pg_atomic_compare_exchange_u32, worker will change the sate to
+ *    LINE_WORKER_PROCESSING only if line_state is LINE_LEADER_POPULATED.
+ * 4) read first_block, start_offset & cur_lineno in any order.
+ * 5) process line_size data.
+ * 6) update line_size to -1.
+ */
+typedef struct ParallelCopyLineBoundary
+{
+	/* Position of the first block in data_blocks array. */
+	uint32				first_block;
+	uint32				start_offset;   /* start offset of the line */
+
+	/*
+	 * Size of the current line -1 means line is yet to be filled completely,
+	 * 0 means empty line, >0 means line filled with line size data.
+	 */
+	pg_atomic_uint32	line_size;
+	pg_atomic_uint32	line_state;		/* line state */
+	uint64				cur_lineno;		/* line number for error messages */
+}ParallelCopyLineBoundary;
+
+/*
+ * Circular queue used to store the line information.
+ */
+typedef struct ParallelCopyLineBoundaries
+{
+	/* Position for the leader to populate a line. */
+	uint32			pos;
+
+	/* Data read from the file/stdin by the leader process. */
+	ParallelCopyLineBoundary	ring[RINGSIZE];
+}ParallelCopyLineBoundaries;
+
+/*
+ * Shared information among parallel copy workers. This will be allocated in the
+ * DSM segment.
+ */
+typedef struct ParallelCopyShmInfo
+{
+	bool					is_read_in_progress; /* file read status */
+
+	/*
+	 * Actual lines inserted by worker, will not be same as
+	 * total_worker_processed if where condition is specified along with copy.
+	 * This will be the actual records inserted into the relation.
+	 */
+	pg_atomic_uint64			processed;
+
+	/* 
+	 * The number of records currently processed by the worker, this will also
+	 * include the number of records that was filtered because of where clause.
+	 */
+	pg_atomic_uint64			total_worker_processed;
+	uint64						populated; /* lines populated by leader */
+	uint32						cur_block_pos; /* current data block */
+	ParallelCopyDataBlock		data_blocks[MAX_BLOCKS_COUNT]; /* data block array */
+	FullTransactionId			full_transaction_id; /* xid for copy from statement */
+	CommandId					mycid;	/* command id */
+	ParallelCopyLineBoundaries	line_boundaries; /* line array */
+} ParallelCopyShmInfo;
+
+/*
+ * Parallel copy line buffer information.
+ */
+typedef struct ParallelCopyLineBuf
+{
+	StringInfoData		line_buf;
+	uint64				cur_lineno;	/* line number for error messages */
+}ParallelCopyLineBuf;
+
+/*
+ * Parallel copy data information.
+ */
+typedef struct ParallelCopyData
+{
+	Oid					relid;				/* relation id of the table */
+	ParallelCopyShmInfo	*pcshared_info;		/* common info in shared memory */
+	bool				is_leader;
+
+	/* line position which worker is processing */
+	uint32				worker_processed_pos;
+
+	/*
+	 * Local line_buf array, workers will copy it here and release the lines
+	 * for the leader to continue.
+	 */
+	ParallelCopyLineBuf	worker_line_buf[WORKER_CHUNK_COUNT];
+	uint32				worker_line_buf_count; /* Number of lines */
+
+	/* Current position in worker_line_buf */
+	uint32				worker_line_buf_pos;
+}ParallelCopyData;
+
+/*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
  * even though some fields are used in only some cases.
@@ -228,8 +399,36 @@ typedef struct CopyStateData
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
+	int			nworkers;
+	bool		is_parallel;
+	ParallelCopyData *pcdata;
 } CopyStateData;
 
+/*
+ * This structure helps in storing the common data from CopyStateData that are
+ * required by the workers. This information will then be allocated and stored
+ * into the DSM for the worker to retrieve and copy it to CopyStateData.
+ */
+typedef struct SerializedParallelCopyState
+{
+	/* low-level state data */
+	CopyDest            copy_dest;		/* type of copy source/destination */
+	int                 file_encoding;	/* file or remote side's character encoding */
+	bool                need_transcoding;	/* file encoding diff from server? */
+	bool                encoding_embeds_ascii;	/* ASCII can be non-first byte? */
+
+	/* parameters from the COPY command */
+	bool                csv_mode;		/* Comma Separated Value format? */
+	bool                header_line;	/* CSV header line? */
+	int                 null_print_len; /* length of same */
+	bool                force_quote_all;	/* FORCE_QUOTE *? */
+	bool                convert_selectively;	/* do selective binary conversion? */
+
+	/* Working state for COPY FROM */
+	AttrNumber          num_defaults;
+	Oid                 relid;
+}SerializedParallelCopyState;
+
 /* DestReceiver for COPY (query) TO */
 typedef struct
 {
@@ -259,6 +458,22 @@ typedef struct
 /* Trim the list of buffers back down to this number after flushing */
 #define MAX_PARTITION_BUFFERS	32
 
+/* DSM keys for parallel copy.  */
+#define PARALLEL_COPY_KEY_SHARED_INFO		    1
+#define PARALLEL_COPY_KEY_CSTATE				2
+#define PARALLEL_COPY_KEY_NULL_PRINT			3
+#define PARALLEL_COPY_KEY_DELIM					4
+#define PARALLEL_COPY_KEY_QUOTE					5
+#define PARALLEL_COPY_KEY_ESCAPE				6
+#define PARALLEL_COPY_KEY_ATTNAME_LIST			7
+#define PARALLEL_COPY_KEY_NOT_NULL_LIST		    8
+#define PARALLEL_COPY_KEY_NULL_LIST			    9
+#define PARALLEL_COPY_KEY_CONVERT_LIST		   10
+#define PARALLEL_COPY_KEY_WHERE_CLAUSE_STR     11
+#define PARALLEL_COPY_KEY_RANGE_TABLE		   12
+#define PARALLEL_COPY_WAL_USAGE				   13
+#define PARALLEL_COPY_BUFFER_USAGE			   14
+
 /* Stores multi-insert data related to a single relation in CopyFrom. */
 typedef struct CopyMultiInsertBuffer
 {
@@ -418,11 +633,477 @@ static bool CopyGetInt32(CopyState cstate, int32 *val);
 static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 
+static pg_attribute_always_inline void EndParallelCopy(ParallelContext *pcxt);
 static void PopulateCommonCstateInfo(CopyState cstate, TupleDesc	tup_desc,
-									   List *attnamelist);
+									 List *attnamelist);
 static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
 								   int copy_line_pos, int *copy_line_size);
 static void ConvertToServerEncoding(CopyState cstate);
+
+/*
+ * SerializeParallelCopyState - Copy shared_cstate using cstate information.
+ */
+static pg_attribute_always_inline void
+SerializeParallelCopyState(CopyState cstate, SerializedParallelCopyState *shared_cstate)
+{
+	shared_cstate->copy_dest = cstate->copy_dest;
+	shared_cstate->file_encoding = cstate->file_encoding;
+	shared_cstate->need_transcoding = cstate->need_transcoding;
+	shared_cstate->encoding_embeds_ascii = cstate->encoding_embeds_ascii;
+	shared_cstate->csv_mode = cstate->csv_mode;
+	shared_cstate->header_line = cstate->header_line;
+	shared_cstate->null_print_len = cstate->null_print_len;
+	shared_cstate->force_quote_all = cstate->force_quote_all;
+	shared_cstate->convert_selectively = cstate->convert_selectively;
+	shared_cstate->num_defaults = cstate->num_defaults;
+	shared_cstate->relid = cstate->pcdata->relid;
+}
+
+/*
+ * RestoreString - Retrieve the string from shared memory.
+ */
+static void
+RestoreString(shm_toc *toc, int sharedkey, char **copystr)
+{
+	char *shared_str_val = (char *)shm_toc_lookup(toc, sharedkey, true);
+	if (shared_str_val)
+		*copystr = pstrdup(shared_str_val);
+}
+
+/*
+ * EstimateLineKeysStr - Estimate the size required in shared memory for the
+ * input string.
+ */
+static void
+EstimateLineKeysStr(ParallelContext *pcxt, char *inputstr)
+{
+	if (inputstr)
+	{
+		shm_toc_estimate_chunk(&pcxt->estimator, strlen(inputstr) + 1);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+}
+
+/*
+ * SerializeString - Insert a string into shared memory.
+ */
+static void
+SerializeString(ParallelContext *pcxt, int key, char *inputstr)
+{
+	if (inputstr)
+	{
+		char *shmptr = (char *)shm_toc_allocate(pcxt->toc,
+												strlen(inputstr) + 1);
+		strcpy(shmptr, inputstr);
+		shm_toc_insert(pcxt->toc, key, shmptr);
+	}
+}
+
+/*
+ * PopulateParallelCopyShmInfo - set ParallelCopyShmInfo.
+ */
+static void
+PopulateParallelCopyShmInfo(ParallelCopyShmInfo *shared_info_ptr,
+							FullTransactionId full_transaction_id)
+{
+	uint32 count;
+
+	MemSet(shared_info_ptr, 0, sizeof(ParallelCopyShmInfo));
+	shared_info_ptr->is_read_in_progress = true;
+	shared_info_ptr->cur_block_pos = -1;
+	shared_info_ptr->full_transaction_id = full_transaction_id;
+	shared_info_ptr->mycid = GetCurrentCommandId(true);
+	for (count = 0; count < RINGSIZE; count++)
+	{
+		ParallelCopyLineBoundary *lineInfo = &shared_info_ptr->line_boundaries.ring[count];
+		pg_atomic_init_u32(&(lineInfo->line_size), -1);
+	}
+}
+
+/*
+ * BeginParallelCopy - start parallel copy tasks.
+ *
+ * Get the number of workers required to perform the parallel copy. The data
+ * structures that are required by the parallel workers will be initialized, the
+ * size required in DSM will be calculated and the necessary keys will be loaded
+ * in the DSM. The specified number of workers will then be launched.
+ */
+static ParallelContext*
+BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
+{
+	ParallelContext *pcxt;
+	ParallelCopyShmInfo *shared_info_ptr;
+	SerializedParallelCopyState *shared_cstate;
+	FullTransactionId full_transaction_id;
+	Size est_cstateshared;
+	char *whereClauseStr = NULL;
+	char *rangeTableStr = NULL;
+	char *attnameListStr = NULL;
+	char *notnullListStr = NULL;
+	char *nullListStr = NULL;
+	char *convertListStr = NULL;
+	int  parallel_workers = 0;
+	WalUsage   *walusage;
+	BufferUsage *bufferusage;
+	ParallelCopyData *pcdata;
+	MemoryContext oldcontext;
+
+	parallel_workers = Min(nworkers, max_worker_processes);
+
+	/* Can't perform copy in parallel */
+	if (parallel_workers <= 0)
+		return NULL;
+
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	MemoryContextSwitchTo(oldcontext);
+	cstate->pcdata = pcdata;
+
+	EnterParallelMode();
+	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
+								 parallel_workers);
+	Assert(pcxt->nworkers > 0);
+
+	/*
+	 * Estimate size for shared information for PARALLEL_COPY_KEY_SHARED_INFO
+	 */
+	shm_toc_estimate_chunk(&pcxt->estimator, sizeof(ParallelCopyShmInfo));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_CSTATE */
+	est_cstateshared = 	MAXALIGN(sizeof(SerializedParallelCopyState));
+	shm_toc_estimate_chunk(&pcxt->estimator, est_cstateshared);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	EstimateLineKeysStr(pcxt, cstate->null_print);
+	EstimateLineKeysStr(pcxt, cstate->null_print_client);
+	EstimateLineKeysStr(pcxt, cstate->delim);
+	EstimateLineKeysStr(pcxt, cstate->quote);
+	EstimateLineKeysStr(pcxt, cstate->escape);
+
+	if (cstate->whereClause != NULL)
+	{
+		whereClauseStr = nodeToString(cstate->whereClause);
+		EstimateLineKeysStr(pcxt, whereClauseStr);
+	}
+
+	if (cstate->range_table != NULL)
+	{
+		rangeTableStr = nodeToString(cstate->range_table);
+		EstimateLineKeysStr(pcxt, rangeTableStr);
+	}
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_XID. */
+	shm_toc_estimate_chunk(&pcxt->estimator, sizeof(FullTransactionId));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_ATTNAME_LIST.
+	 */
+	if (attnamelist != NIL)
+	{
+		attnameListStr = nodeToString(attnamelist);
+		EstimateLineKeysStr(pcxt, attnameListStr);
+	}
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_NOT_NULL_LIST.
+	 */
+	if (cstate->force_notnull != NIL)
+	{
+		notnullListStr = nodeToString(cstate->force_notnull);
+		EstimateLineKeysStr(pcxt, notnullListStr);
+	}
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_NULL_LIST.
+	 */
+	if (cstate->force_null != NIL)
+	{
+		nullListStr = nodeToString(cstate->force_null);
+		EstimateLineKeysStr(pcxt, nullListStr);
+	}
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_CONVERT_LIST.
+	 */
+	if (cstate->convert_select != NIL)
+	{
+		convertListStr = nodeToString(cstate->convert_select);
+		EstimateLineKeysStr(pcxt, convertListStr);
+	}
+
+	/*
+	 * Estimate space for WalUsage and BufferUsage -- PARALLEL_COPY_WAL_USAGE
+	 * and PARALLEL_COPY_BUFFER_USAGE.
+	 */
+	shm_toc_estimate_chunk(&pcxt->estimator,
+						   mul_size(sizeof(WalUsage), pcxt->nworkers));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+	shm_toc_estimate_chunk(&pcxt->estimator,
+						   mul_size(sizeof(BufferUsage), pcxt->nworkers));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	InitializeParallelDSM(pcxt);
+
+	/* If no DSM segment was available, back out (do serial copy) */
+	if (pcxt->seg == NULL)
+	{
+		EndParallelCopy(pcxt);
+		return NULL;
+	}
+
+	/* Allocate shared memory for PARALLEL_COPY_KEY_SHARED_INFO */
+	shared_info_ptr = (ParallelCopyShmInfo *) shm_toc_allocate(pcxt->toc, sizeof(ParallelCopyShmInfo));
+	PopulateParallelCopyShmInfo(shared_info_ptr, full_transaction_id);
+
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_SHARED_INFO, shared_info_ptr);
+	pcdata->pcshared_info = shared_info_ptr;
+	pcdata->relid = relid;
+
+	/* Store shared build state, for which we reserved space. */
+	shared_cstate = (SerializedParallelCopyState *)shm_toc_allocate(pcxt->toc, est_cstateshared);
+
+	/* copy cstate variables. */
+	SerializeParallelCopyState(cstate, shared_cstate);
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_CSTATE, shared_cstate);
+
+	SerializeString(pcxt, PARALLEL_COPY_KEY_NULL_PRINT, cstate->null_print);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_DELIM, cstate->delim);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_QUOTE, cstate->quote);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_ESCAPE, cstate->escape);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_ATTNAME_LIST, attnameListStr);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_NOT_NULL_LIST, notnullListStr);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_NULL_LIST, nullListStr);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_CONVERT_LIST, convertListStr);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_WHERE_CLAUSE_STR, whereClauseStr);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_RANGE_TABLE, rangeTableStr);
+
+	/*
+	 * Allocate space for each worker's WalUsage and BufferUsage; no need to
+	 * initialize.
+	 */
+	walusage = shm_toc_allocate(pcxt->toc,
+								mul_size(sizeof(WalUsage), pcxt->nworkers));
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_WAL_USAGE, walusage);
+	bufferusage = shm_toc_allocate(pcxt->toc,
+								   mul_size(sizeof(BufferUsage), pcxt->nworkers));
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_BUFFER_USAGE, bufferusage);
+
+	LaunchParallelWorkers(pcxt);
+	if (pcxt->nworkers_launched == 0)
+	{
+		EndParallelCopy(pcxt);
+		return NULL;
+	}
+
+	/*
+	 * Caller needs to wait for all launched workers when we return.  Make sure
+	 * that the failure-to-start case will not hang forever.
+	 */
+	WaitForParallelWorkersToAttach(pcxt);
+
+	pcdata->is_leader = true;
+	cstate->is_parallel = true;
+	return pcxt;
+}
+
+/*
+ * EndParallelCopy - end the parallel copy tasks.
+ */
+static pg_attribute_always_inline void
+EndParallelCopy(ParallelContext *pcxt)
+{
+	Assert(!IsParallelWorker());
+
+	DestroyParallelContext(pcxt);
+	ExitParallelMode();
+}
+
+/*
+ * InitializeParallelCopyInfo - Initialize parallel worker.
+ */
+static void
+InitializeParallelCopyInfo(SerializedParallelCopyState *shared_cstate,
+		CopyState cstate, List *attnamelist)
+{
+	uint32		count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	cstate->copy_dest = shared_cstate->copy_dest;
+	cstate->file_encoding = shared_cstate->file_encoding;
+	cstate->need_transcoding = shared_cstate->need_transcoding;
+	cstate->encoding_embeds_ascii = shared_cstate->encoding_embeds_ascii;
+	cstate->csv_mode = shared_cstate->csv_mode;
+	cstate->header_line = shared_cstate->header_line;
+	cstate->null_print_len = shared_cstate->null_print_len;
+	cstate->force_quote_all = shared_cstate->force_quote_all;
+	cstate->convert_selectively = shared_cstate->convert_selectively;
+	cstate->num_defaults = shared_cstate->num_defaults;
+	pcdata->relid = shared_cstate->relid;
+
+	PopulateCommonCstateInfo(cstate, tup_desc, attnamelist);
+
+	/* Initialize state variables. */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/* Set up variables to avoid per-attribute overhead. */
+	initStringInfo(&cstate->attribute_buf);
+
+	initStringInfo(&cstate->line_buf);
+	for (count = 0; count < WORKER_CHUNK_COUNT; count++)
+		initStringInfo(&pcdata->worker_line_buf[count].line_buf);
+
+	cstate->line_buf_converted = false;
+	cstate->raw_buf = NULL;
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+}
+
+/*
+ * ParallelCopyMain - parallel copy worker's code.
+ *
+ * Where clause handling, convert tuple to columns, add default null values for
+ * the missing columns that are not present in that record. Find the partition
+ * if it is partitioned table, invoke before row insert Triggers, handle
+ * constraints and insert the tuples.
+ */
+void
+ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
+{
+	CopyState cstate;
+	ParallelCopyData *pcdata;
+	ParallelCopyShmInfo *pcshared_info;
+	SerializedParallelCopyState *shared_cstate;
+	Relation	rel = NULL;
+	MemoryContext oldcontext;
+	List *attlist = NIL;
+	char *whereClauseStr = NULL;
+	char *rangeTableStr = NULL;
+	char *attnameListStr = NULL;
+	char *notnullListStr = NULL;
+	char *nullListStr = NULL;
+	char *convertListStr = NULL;
+	WalUsage   *walusage;
+	BufferUsage *bufferusage;
+
+	/* Allocate workspace and zero all fields. */
+	cstate = (CopyStateData *) palloc0(sizeof(CopyStateData));
+
+	/*
+	 * We allocate everything used by a cstate in a new memory context. This
+	 * avoids memory leaks during repeated use of COPY in a query.
+	 */
+	cstate->copycontext = AllocSetContextCreate(CurrentMemoryContext,
+												"COPY",
+												ALLOCSET_DEFAULT_SIZES);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	cstate->pcdata = pcdata;
+	pcdata->is_leader = false;
+	pcdata->worker_processed_pos = -1;
+	cstate->is_parallel = true;
+	pcshared_info = (ParallelCopyShmInfo *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_SHARED_INFO, false);
+
+	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
+
+	pcdata->pcshared_info = pcshared_info;
+
+	shared_cstate = (SerializedParallelCopyState *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE, false);
+	cstate->null_print = (char *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_NULL_PRINT, true);
+
+	RestoreString(toc, PARALLEL_COPY_KEY_DELIM, &cstate->delim);
+	RestoreString(toc, PARALLEL_COPY_KEY_QUOTE, &cstate->quote);
+	RestoreString(toc, PARALLEL_COPY_KEY_ESCAPE, &cstate->escape);
+	RestoreString(toc, PARALLEL_COPY_KEY_ATTNAME_LIST, &attnameListStr);
+	if (attnameListStr)
+		attlist = (List *)stringToNode(attnameListStr);
+
+	RestoreString(toc, PARALLEL_COPY_KEY_NOT_NULL_LIST, &notnullListStr);
+	if (notnullListStr)
+		cstate->force_notnull = (List *)stringToNode(notnullListStr);
+
+	RestoreString(toc, PARALLEL_COPY_KEY_NULL_LIST, &nullListStr);
+	if (nullListStr)
+		cstate->force_null = (List *)stringToNode(nullListStr);
+
+	RestoreString(toc, PARALLEL_COPY_KEY_CONVERT_LIST, &convertListStr);
+	if (convertListStr)
+		cstate->convert_select = (List *)stringToNode(convertListStr);
+
+	RestoreString(toc, PARALLEL_COPY_KEY_WHERE_CLAUSE_STR, &whereClauseStr);
+	RestoreString(toc, PARALLEL_COPY_KEY_RANGE_TABLE, &rangeTableStr);
+
+	if (whereClauseStr)
+	{
+		Node *whereClauseCnvrtdFrmStr = (Node *) stringToNode(whereClauseStr);
+		cstate->whereClause = whereClauseCnvrtdFrmStr;
+	}
+
+	if (rangeTableStr)
+	{
+		List *rangeTableCnvrtdFrmStr = (List *) stringToNode(rangeTableStr);
+		cstate->range_table = rangeTableCnvrtdFrmStr;
+	}
+
+	/* Open and lock the relation, using the appropriate lock type. */
+	rel = table_open(shared_cstate->relid, RowExclusiveLock);
+	cstate->rel = rel;
+	InitializeParallelCopyInfo(shared_cstate, cstate, attlist);
+
+	CopyFrom(cstate);
+
+	if (rel != NULL)
+		table_close(rel, RowExclusiveLock);
+
+	/* Report WAL/buffer usage during parallel execution */
+	bufferusage = shm_toc_lookup(toc, PARALLEL_COPY_BUFFER_USAGE, false);
+	walusage = shm_toc_lookup(toc, PARALLEL_COPY_WAL_USAGE, false);
+	InstrEndParallelQuery(&bufferusage[ParallelWorkerNumber],
+						  &walusage[ParallelWorkerNumber]);
+
+	MemoryContextSwitchTo(oldcontext);
+	pfree(cstate);
+	return;
+}
+
+/*
+ * ParallelCopyFrom - parallel copy leader's functionality.
+ *
+ * Leader executes the before statement for before statement trigger, if before
+ * statement trigger is present. It will read the table data from the file and
+ * copy the contents to DSM data blocks. It will then read the input contents
+ * from the DSM data block and identify the records based on line breaks. This
+ * information is called line or a record that need to be inserted into a
+ * relation. The line information will be stored in ParallelCopyLineBoundary DSM
+ * data structure. Workers will then process this information and insert the
+ * data in to table. It will repeat this process until the all data is read from
+ * the file and all the DSM data blocks are processed. While processing if
+ * leader identifies that DSM Data blocks or DSM ParallelCopyLineBoundary data
+ * structures is full, leader will wait till the worker frees up some entries
+ * and repeat the process. It will wait till all the lines populated are
+ * processed by the workers and exits.
+ */
+static void
+ParallelCopyFrom(CopyState cstate)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
+
+	pcshared_info->is_read_in_progress = false;
+	cstate->cur_lineno = 0;
+}
+
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
  * in past protocol redesigns.
@@ -1093,6 +1774,7 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 
 	if (is_from)
 	{
+		ParallelContext *pcxt = NULL;
 		Assert(rel);
 
 		/* check read-only transaction and parallel mode */
@@ -1102,7 +1784,24 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 		cstate = BeginCopyFrom(pstate, rel, stmt->filename, stmt->is_program,
 							   NULL, stmt->attlist, stmt->options);
 		cstate->whereClause = whereClause;
-		*processed = CopyFrom(cstate);	/* copy from file to database */
+		cstate->is_parallel = false;
+
+		if (cstate->nworkers > 0)
+			pcxt = BeginParallelCopy(cstate->nworkers, cstate, stmt->attlist,
+									 relid);
+
+		if (pcxt)
+		{
+			ParallelCopyFrom(cstate);
+
+			/* Wait for all copy workers to finish */
+			WaitForParallelWorkersToFinish(pcxt);
+			*processed = pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
+			EndParallelCopy(pcxt);
+		}
+		else
+			*processed = CopyFrom(cstate); /* copy from file to database */
+
 		EndCopyFrom(cstate);
 	}
 	else
@@ -1151,6 +1850,7 @@ ProcessCopyOptions(ParseState *pstate,
 	cstate->is_copy_from = is_from;
 
 	cstate->file_encoding = -1;
+	cstate->nworkers = -1;
 
 	/* Extract options from the statement node tree */
 	foreach(option, options)
@@ -1319,6 +2019,53 @@ ProcessCopyOptions(ParseState *pstate,
 								defel->defname),
 						 parser_errposition(pstate, defel->location)));
 		}
+		else if (strcmp(defel->defname, "parallel") == 0)
+		{
+			char *endptr, *str;
+			long val;
+
+			if (!cstate->is_copy_from)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("parallel option supported only for copy from"),
+						 parser_errposition(pstate, defel->location)));
+			if (cstate->nworkers >= 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options"),
+						 parser_errposition(pstate, defel->location)));
+
+			str = defGetString(defel);
+
+			errno = 0; /* To distinguish success/failure after call */
+			val = strtol(str, &endptr, 10);
+
+			/* Check for various possible errors */
+			if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
+				|| (errno != 0 && val == 0) ||
+				*endptr)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("improper use of argument to option \"%s\"",
+								defel->defname),
+						 parser_errposition(pstate, defel->location)));
+
+			if (endptr == str)
+			   ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("no digits were found in argument to option \"%s\"",
+								defel->defname),
+						 parser_errposition(pstate, defel->location)));
+
+			cstate->nworkers = (int) val;
+
+			if (cstate->nworkers <= 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("argument to option \"%s\" must be a positive integer greater than zero",
+								defel->defname),
+						 parser_errposition(pstate, defel->location)));
+		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_SYNTAX_ERROR),
@@ -1672,11 +2419,12 @@ BeginCopy(ParseState *pstate,
 
 /*
  * PopulateCommonCstateInfo - Populates the common variables required for copy
- * from operation. This is a helper function for BeginCopy function.
+ * from operation. This is a helper function for BeginCopy &
+ * InitializeParallelCopyInfo function.
  */
 static void
 PopulateCommonCstateInfo(CopyState cstate, TupleDesc	tupDesc,
-							List *attnamelist)
+						 List *attnamelist)
 {
 	int			num_phys_attrs;
 
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index c639833..82843c6 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -14,6 +14,7 @@
 #ifndef COPY_H
 #define COPY_H
 
+#include "access/parallel.h"
 #include "nodes/execnodes.h"
 #include "nodes/parsenodes.h"
 #include "parser/parse_node.h"
@@ -41,4 +42,5 @@ extern uint64 CopyFrom(CopyState cstate);
 
 extern DestReceiver *CreateCopyDestReceiver(void);
 
+extern void ParallelCopyMain(dsm_segment *seg, shm_toc *toc);
 #endif							/* COPY_H */
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 7eaaad1..3a83d0f 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1699,6 +1699,12 @@ ParallelBitmapHeapState
 ParallelBlockTableScanDesc
 ParallelCompletionPtr
 ParallelContext
+ParallelCopyLineBoundaries
+ParallelCopyLineBoundary
+ParallelCopyData
+ParallelCopyDataBlock
+ParallelCopyLineBuf
+ParallelCopyShmInfo
 ParallelExecutorInfo
 ParallelHashGrowth
 ParallelHashJoinBatch
@@ -2215,6 +2221,7 @@ SerCommitSeqNo
 SerialControl
 SerializableXactHandle
 SerializedActiveRelMaps
+SerializedParallelCopyState
 SerializedReindexState
 SerializedSnapshotData
 SerializedTransactionState
-- 
1.8.3.1

v2-0003-Allow-copy-from-command-to-process-data-from-file.patchtext/x-patch; charset=US-ASCII; name=v2-0003-Allow-copy-from-command-to-process-data-from-file.patchDownload
From ca4254873e6dc7bd7f23943d14f7c3fd5c4e3cd1 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 22 Jul 2020 19:18:29 +0530
Subject: [PATCH v2 3/6] Allow copy from command to process data from
 file/STDIN contents to a table in parallel.

This feature allows the copy from to leverage multiple CPUs in order to copy
data from file/STDIN to a table. This adds a PARALLEL option to COPY FROM
command where the user can specify the number of workers that can be used
to perform the COPY FROM command. Specifying zero as number of workers will
disable parallelism.
The backend, to which the "COPY FROM" query is submitted acts as leader with
the responsibility of reading data from the file/stdin, launching at most n
number of workers as specified with PARALLEL 'n' option in the "COPY FROM"
query. The leader populates the common data required for the workers execution
in the DSM and shares it with the workers. The leader then executes before
statement triggers if there exists any. Leader populates DSM lines which
includes the start offset and line size, while populating the lines it reads
as many blocks as required into the DSM data blocks from the file. Each block
is of 64K size. The leader parses the data to identify a line, the existing
logic from CopyReadLineText which identifies the lines with some changes was
used for this. Leader checks if a free line is available to copy the
information, if there is no free line it waits till the required line is
freed up by the worker and then copies the identified lines information
(offset & line size) into the DSM lines. This process is repeated till the
complete file is processed. Simultaneously, the workers cache the lines(50)
locally into the local memory and release the lines to the leader for further
populating. Each worker processes the lines that it cached and inserts it into
the table. The leader does not participate in the insertion of data, leaders
only responsibility will be to identify the lines as fast as possible for the
workers to do the actual copy operation. The leader waits till all the lines
populated are processed by the workers and exits.
We have chosen this design based on the reason "that everything stalls if the
leader doesn't accept further input data, as well as when there are no
available splitted chunks so it doesn't seem like a good idea to have the
leader do other work.  This is backed by the performance data where we have
seen that with 1 worker there is just a 5-10% performance difference".
---
 src/backend/access/common/toast_internals.c |  11 +-
 src/backend/access/heap/heapam.c            |  13 -
 src/backend/access/transam/xact.c           |  31 +
 src/backend/commands/copy.c                 | 894 ++++++++++++++++++++++++++--
 src/include/access/xact.h                   |   2 +
 src/tools/pgindent/typedefs.list            |   1 +
 6 files changed, 899 insertions(+), 53 deletions(-)

diff --git a/src/backend/access/common/toast_internals.c b/src/backend/access/common/toast_internals.c
index 25a81e5..586d53d 100644
--- a/src/backend/access/common/toast_internals.c
+++ b/src/backend/access/common/toast_internals.c
@@ -17,6 +17,7 @@
 #include "access/genam.h"
 #include "access/heapam.h"
 #include "access/heaptoast.h"
+#include "access/parallel.h"
 #include "access/table.h"
 #include "access/toast_internals.h"
 #include "access/xact.h"
@@ -116,7 +117,15 @@ toast_save_datum(Relation rel, Datum value,
 	TupleDesc	toasttupDesc;
 	Datum		t_values[3];
 	bool		t_isnull[3];
-	CommandId	mycid = GetCurrentCommandId(true);
+
+	/*
+	 * Parallel copy can insert toast tuples, in case of parallel copy the
+	 * command would have been set already by calling AssignCommandIdForWorker.
+	 * For parallel copy call GetCurrentCommandId to get currentCommandId by
+	 * passing used as false, as this is taken care earlier.
+	 */
+	CommandId	mycid = IsParallelWorker() ? GetCurrentCommandId(false) :
+											 GetCurrentCommandId(true);
 	struct varlena *result;
 	struct varatt_external toast_pointer;
 	union
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index d881f4c..70ecd51 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2012,19 +2012,6 @@ static HeapTuple
 heap_prepare_insert(Relation relation, HeapTuple tup, TransactionId xid,
 					CommandId cid, int options)
 {
-	/*
-	 * Parallel operations are required to be strictly read-only in a parallel
-	 * worker.  Parallel inserts are not safe even in the leader in the
-	 * general case, because group locking means that heavyweight locks for
-	 * relation extension or GIN page locks will not conflict between members
-	 * of a lock group, but we don't prohibit that case here because there are
-	 * useful special cases that we can safely allow, such as CREATE TABLE AS.
-	 */
-	if (IsParallelWorker())
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_TRANSACTION_STATE),
-				 errmsg("cannot insert tuples in a parallel worker")));
-
 	tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
 	tup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK);
 	tup->t_data->t_infomask |= HEAP_XMAX_INVALID;
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index bd4c3cf..1aed74f 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -504,6 +504,37 @@ GetCurrentFullTransactionIdIfAny(void)
 }
 
 /*
+ *	AssignFullTransactionIdForWorker
+ *
+ * For parallel copy, transaction id of leader will be used by the workers.
+ */
+void
+AssignFullTransactionIdForWorker(FullTransactionId fullTransactionId)
+{
+	TransactionState s = CurrentTransactionState;
+
+	Assert((IsInParallelMode() || IsParallelWorker()));
+	s->fullTransactionId = fullTransactionId;
+}
+
+/*
+ *	AssignCommandIdForWorker
+ *
+ * For parallel copy, command id of leader will be used by the workers.
+ */
+void
+AssignCommandIdForWorker(CommandId commandId, bool used)
+{
+	Assert((IsInParallelMode() || IsParallelWorker()));
+
+	/* this is global to a transaction, not subtransaction-local */
+	if (used)
+		currentCommandIdUsed = true;
+
+	currentCommandId = commandId;
+}
+
+/*
  *	MarkCurrentTransactionIdLoggedIfAny
  *
  * Remember that the current xid - if it is assigned - now has been wal logged.
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index a3cf750..9b657ab 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -26,6 +26,7 @@
 #include "access/xlog.h"
 #include "catalog/dependency.h"
 #include "catalog/pg_authid.h"
+#include "catalog/pg_proc_d.h"
 #include "catalog/pg_type.h"
 #include "commands/copy.h"
 #include "commands/defrem.h"
@@ -40,11 +41,13 @@
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
+#include "optimizer/clauses.h"
 #include "optimizer/optimizer.h"
 #include "parser/parse_coerce.h"
 #include "parser/parse_collate.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_relation.h"
+#include "pgstat.h"
 #include "port/pg_bswap.h"
 #include "rewrite/rewriteHandler.h"
 #include "storage/fd.h"
@@ -95,6 +98,18 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
+/*
+ * State of the line.
+ */
+typedef enum ParallelCopyLineState
+{
+	LINE_INIT,					/* initial state of line */
+	LINE_LEADER_POPULATING,		/* leader processing line */
+	LINE_LEADER_POPULATED,		/* leader completed populating line */
+	LINE_WORKER_PROCESSING,		/* worker processing line */
+	LINE_WORKER_PROCESSED		/* worker completed processing line */
+}ParallelCopyLineState;
+
 #define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
 
 /*
@@ -123,6 +138,7 @@ typedef enum CopyInsertMethod
 
 #define	IsParallelCopy()		(cstate->is_parallel)
 #define IsLeader()				(cstate->pcdata->is_leader)
+#define IsWorker()				(IsParallelCopy() && !IsLeader())
 #define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
 
 /*
@@ -552,9 +568,13 @@ if (1) \
 { \
 	if (raw_buf_ptr > cstate->raw_buf_index) \
 	{ \
-		appendBinaryStringInfo(&cstate->line_buf, \
-							 cstate->raw_buf + cstate->raw_buf_index, \
-							   raw_buf_ptr - cstate->raw_buf_index); \
+		if (!IsParallelCopy()) \
+			appendBinaryStringInfo(&cstate->line_buf, \
+								   cstate->raw_buf + cstate->raw_buf_index, \
+								   raw_buf_ptr - cstate->raw_buf_index); \
+		else \
+			line_size +=  raw_buf_ptr - cstate->raw_buf_index; \
+		\
 		cstate->raw_buf_index = raw_buf_ptr; \
 	} \
 } else ((void) 0)
@@ -567,26 +587,65 @@ if (1) \
 	goto not_end_of_copy; \
 } else ((void) 0)
 
+/* Begin parallel copy Macros */
+#define SET_NEWLINE_SIZE() \
+{ \
+	if (cstate->eol_type == EOL_NL || cstate->eol_type == EOL_CR) \
+		new_line_size = 1; \
+	else if (cstate->eol_type == EOL_CRNL) \
+		new_line_size = 2; \
+	else \
+		new_line_size = 0; \
+}
+
+/*
+ * COPY_WAIT_TO_PROCESS - Wait before continuing to process.
+ */
+#define COPY_WAIT_TO_PROCESS() \
+{ \
+	CHECK_FOR_INTERRUPTS(); \
+	(void) WaitLatch(MyLatch, \
+					 WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH, \
+					 1L, WAIT_EVENT_PG_SLEEP); \
+	ResetLatch(MyLatch); \
+}
+
 /*
  * CLEAR_EOL_LINE - Wrapper for clearing EOL.
  */
 #define CLEAR_EOL_LINE() \
 if (!result && !IsHeaderLine()) \
-	ClearEOLFromCopiedData(cstate, cstate->line_buf.data, \
-						   cstate->line_buf.len, \
-						   &cstate->line_buf.len) \
+{ \
+	if (IsParallelCopy()) \
+		ClearEOLFromCopiedData(cstate, cstate->raw_buf, \
+									raw_buf_ptr, &line_size); \
+	else \
+		ClearEOLFromCopiedData(cstate, cstate->line_buf.data, \
+									cstate->line_buf.len, \
+									&cstate->line_buf.len); \
+} \
 
 /*
  * INCREMENTPROCESSED - Increment the lines processed.
  */
-#define INCREMENTPROCESSED(processed)  \
-processed++;
+#define INCREMENTPROCESSED(processed) \
+{ \
+	if (!IsParallelCopy()) \
+		processed++; \
+	else \
+		pg_atomic_add_fetch_u64(&cstate->pcdata->pcshared_info->processed, 1); \
+}
 
 /*
  * GETPROCESSED - Get the lines processed.
  */
 #define GETPROCESSED(processed) \
-return processed;
+if (!IsParallelCopy()) \
+	return processed; \
+else \
+	return pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
+
+/* End parallel copy Macros */
 
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
@@ -639,7 +698,10 @@ static void PopulateCommonCstateInfo(CopyState cstate, TupleDesc	tup_desc,
 static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
 								   int copy_line_pos, int *copy_line_size);
 static void ConvertToServerEncoding(CopyState cstate);
-
+static void ExecBeforeStmtTrigger(CopyState cstate);
+static void CheckTargetRelValidity(CopyState cstate);
+static void PopulateCstateCatalogInfo(CopyState cstate);
+static pg_attribute_always_inline uint32 GetLinePosition(CopyState cstate);
 /*
  * SerializeParallelCopyState - Copy shared_cstate using cstate information.
  */
@@ -721,6 +783,137 @@ PopulateParallelCopyShmInfo(ParallelCopyShmInfo *shared_info_ptr,
 }
 
 /*
+ * IsTriggerFunctionParallelSafe - Check if the trigger function is parallel
+ * safe for the triggers. Return false if any one of the trigger has parallel
+ * unsafe function.
+ */
+static pg_attribute_always_inline bool
+IsTriggerFunctionParallelSafe(TriggerDesc *trigdesc)
+{
+	int	i;
+	for (i = 0; i < trigdesc->numtriggers; i++)
+	{
+		Trigger    *trigger = &trigdesc->triggers[i];
+		int 		trigtype = RI_TRIGGER_NONE;
+
+		if (func_parallel(trigger->tgfoid) != PROPARALLEL_SAFE)
+			return false;
+
+		/* If the trigger is parallel safe, also look for RI_TRIGGER. */
+		trigtype = RI_FKey_trigger_type(trigger->tgfoid);
+		if (trigtype == RI_TRIGGER_PK || trigtype == RI_TRIGGER_FK)
+			return false;
+	}
+
+	return true;
+}
+
+/*
+ * CheckExprParallelSafety - determine parallel safety of volatile expressions
+ * in default clause of column definition or in where clause and return true if
+ * they are parallel safe.
+ */
+static pg_attribute_always_inline bool
+CheckExprParallelSafety(CopyState cstate)
+{
+	if (contain_volatile_functions(cstate->whereClause))
+	{
+		if (max_parallel_hazard((Query *)cstate->whereClause) != PROPARALLEL_SAFE)
+			return false;
+	}
+
+	/*
+	 * Check if any of the column has volatile default expression. if yes, and
+	 * they are not parallel safe, then parallelism is not allowed. For
+	 * instance, if there are any serial/bigserial columns for which nextval()
+	 * default expression which is parallel unsafe is associated, parallelism
+	 * should not be allowed. In non parallel copy volatile functions are not
+	 * checked for nextval().
+	 */
+	if (cstate->defexprs != NULL && cstate->num_defaults != 0)
+	{
+		int     i;
+		for (i = 0; i < cstate->num_defaults; i++)
+		{
+			bool volatile_expr = contain_volatile_functions((Node *)cstate->defexprs[i]->expr);
+			if (volatile_expr &&
+				(max_parallel_hazard((Query *)cstate->defexprs[i]->expr)) !=
+				 PROPARALLEL_SAFE)
+				return false;
+		}
+	}
+
+	return true;
+}
+
+/*
+ * FindInsertMethod - determine insert mode single, multi, or multi conditional.
+ */
+static pg_attribute_always_inline CopyInsertMethod
+FindInsertMethod(CopyState cstate)
+{
+	if (cstate->rel->trigdesc != NULL &&
+		(cstate->rel->trigdesc->trig_insert_before_row ||
+		 cstate->rel->trigdesc->trig_insert_instead_row))
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
+			cstate->rel->trigdesc != NULL &&
+			cstate->rel->trigdesc->trig_insert_new_table)
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+		return CIM_MULTI_CONDITIONAL;
+
+	return CIM_MULTI;
+}
+
+/*
+ * IsParallelCopyAllowed - check for the cases where parallel copy is not
+ * applicable.
+ */
+static pg_attribute_always_inline bool
+IsParallelCopyAllowed(CopyState cstate)
+{
+	/* Parallel copy not allowed for frontend (2.0 protocol) & binary option. */
+	if ((cstate->copy_dest == COPY_OLD_FE) || cstate->binary)
+		return false;
+
+	/* Check if copy is into foreign table or temporary table. */
+	if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
+		RelationUsesLocalBuffers(cstate->rel))
+		return false;
+
+	/* Check if trigger function is parallel safe. */
+	if (cstate->rel->trigdesc != NULL &&
+		!IsTriggerFunctionParallelSafe(cstate->rel->trigdesc))
+		return false;
+
+	/*
+	 * Check if there is after statement or instead of trigger or transition
+	 * table triggers.
+	 */
+	if (cstate->rel->trigdesc != NULL &&
+		(cstate->rel->trigdesc->trig_insert_after_statement ||
+		 cstate->rel->trigdesc->trig_insert_instead_row ||
+		 cstate->rel->trigdesc->trig_insert_new_table))
+		return false;
+
+	/* Check if the volatile expressions are parallel safe, if present any. */
+	if (!CheckExprParallelSafety(cstate))
+		return false;
+
+	/* Check if the insertion mode is single. */
+	if (FindInsertMethod(cstate) == CIM_SINGLE)
+		return false;
+
+	return true;
+}
+
+/*
  * BeginParallelCopy - start parallel copy tasks.
  *
  * Get the number of workers required to perform the parallel copy. The data
@@ -748,6 +941,7 @@ BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
 	ParallelCopyData *pcdata;
 	MemoryContext oldcontext;
 
+	CheckTargetRelValidity(cstate);
 	parallel_workers = Min(nworkers, max_worker_processes);
 
 	/* Can't perform copy in parallel */
@@ -759,6 +953,19 @@ BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
 	MemoryContextSwitchTo(oldcontext);
 	cstate->pcdata = pcdata;
 
+	/*
+	 * User chosen parallel copy. Determine if the parallel copy is actually
+	 * allowed. If not, go with the non-parallel mode.
+	 */
+	if (!IsParallelCopyAllowed(cstate))
+	{
+		elog(WARNING,
+			 "Parallel copy not supported for specified table, copy will be run in non-parallel mode");
+		return NULL;
+	}
+
+	full_transaction_id = GetCurrentFullTransactionId();
+
 	EnterParallelMode();
 	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
 								 parallel_workers);
@@ -967,9 +1174,212 @@ InitializeParallelCopyInfo(SerializedParallelCopyState *shared_cstate,
 	cstate->line_buf_converted = false;
 	cstate->raw_buf = NULL;
 	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+
+	PopulateCstateCatalogInfo(cstate);
+
+	/* Create workspace for CopyReadAttributes results. */
+	if (!cstate->binary)
+	{
+		AttrNumber	attr_count = list_length(cstate->attnumlist);
+
+		cstate->max_fields = attr_count;
+		cstate->raw_fields = (char **)palloc(attr_count * sizeof(char *));
+	}
 }
 
 /*
+ * CacheLineInfo - Cache the line information to local memory.
+ */
+static bool
+CacheLineInfo(CopyState cstate, uint32 buff_count)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	uint32			write_pos;
+	ParallelCopyDataBlock *data_blk_ptr;
+	ParallelCopyLineBoundary *lineInfo;
+	uint32 offset;
+	int dataSize;
+	int copiedSize = 0;
+
+	resetStringInfo(&pcdata->worker_line_buf[buff_count].line_buf);
+	write_pos = GetLinePosition(cstate);
+	if (-1 == write_pos)
+		return true;
+
+	/* Get the current line information. */
+	lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+	if (pg_atomic_read_u32(&lineInfo->line_size) == 0)
+		goto empty_data_line_update;
+
+	/* Get the block information. */
+	data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+	/* Get the offset information from where the data must be copied. */
+	offset = lineInfo->start_offset;
+	pcdata->worker_line_buf[buff_count].cur_lineno = lineInfo->cur_lineno;
+
+	elog(DEBUG1, "[Worker] Processing - line position:%d, block:%d, unprocessed lines:%d, offset:%d, line size:%d",
+				 write_pos, lineInfo->first_block,
+				 pg_atomic_read_u32(&data_blk_ptr->unprocessed_line_parts),
+				 offset, pg_atomic_read_u32(&lineInfo->line_size));
+
+	for (;;)
+	{
+		uint8 skip_bytes = data_blk_ptr->skip_bytes;
+		/*
+		 * There is a possibility that the above loop has come out because
+		 * data_blk_ptr->curr_blk_completed is set, but dataSize read might
+		 * be an old value, if data_blk_ptr->curr_blk_completed and the line is
+		 * completed, line_size will be set. Read the line_size again to be
+		 * sure if it is complete or partial block.
+		 */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+		if (dataSize)
+		{
+			int remainingSize = dataSize - copiedSize;
+			if (!remainingSize)
+				break;
+
+			/* Whole line is in current block. */
+			if (remainingSize + offset + skip_bytes < DATA_BLOCK_SIZE)
+			{
+				appendBinaryStringInfo(&pcdata->worker_line_buf[buff_count].line_buf,
+									   &data_blk_ptr->data[offset],
+									   remainingSize);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts,
+										1);
+				break;
+			}
+			else
+			{
+				/* Line is spread across the blocks. */
+				uint32 lineInCurrentBlock =  (DATA_BLOCK_SIZE - skip_bytes) - offset;
+				appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+										 &data_blk_ptr->data[offset],
+										 lineInCurrentBlock);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+				copiedSize += lineInCurrentBlock;
+				while (copiedSize < dataSize)
+				{
+					uint32 currentBlockCopySize;
+					ParallelCopyDataBlock *currBlkPtr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+					skip_bytes = currBlkPtr->skip_bytes;
+
+					/*
+					 * If complete data is present in current block use
+					 * dataSize - copiedSize, or copy the whole block from
+					 * current block.
+					 */
+					currentBlockCopySize = Min(dataSize - copiedSize, DATA_BLOCK_SIZE - skip_bytes);
+					appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+											 &currBlkPtr->data[0],
+											 currentBlockCopySize);
+					pg_atomic_sub_fetch_u32(&currBlkPtr->unprocessed_line_parts, 1);
+					copiedSize += currentBlockCopySize;
+					data_blk_ptr = currBlkPtr;
+				}
+
+				break;
+			}
+		}
+		else
+		{
+			/* Copy this complete block from the current offset. */
+			uint32 lineInCurrentBlock =  (DATA_BLOCK_SIZE - skip_bytes) - offset;
+			appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+									 &data_blk_ptr->data[offset],
+									 lineInCurrentBlock);
+			pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+			copiedSize += lineInCurrentBlock;
+
+			/*
+			 * Reset the offset. For the first copy, copy from the offset. For
+			 * the subsequent copy the complete block.
+			 */
+			offset = 0;
+
+			/* Set data_blk_ptr to the following block. */
+			data_blk_ptr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+		}
+
+		for (;;)
+		{
+			/* Get the size of this line */
+			dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+			/*
+			 * If the data is present in current block lineInfo.line_size
+			 * will be updated. If the data is spread across the blocks either
+			 * of lineInfo.line_size or data_blk_ptr->curr_blk_completed can
+			 * be updated. lineInfo.line_size will be updated if the complete
+			 * read is finished. data_blk_ptr->curr_blk_completed will be
+			 * updated if processing of current block is finished and data
+			 * processing is not finished.
+			 */
+			if (data_blk_ptr->curr_blk_completed || (dataSize != -1))
+				break;
+
+			COPY_WAIT_TO_PROCESS()
+		}
+	}
+
+empty_data_line_update:
+	elog(DEBUG1, "[Worker] Completed processing line:%d", write_pos);
+	pg_atomic_write_u32(&lineInfo->line_state, LINE_WORKER_PROCESSED);
+	pg_atomic_write_u32(&lineInfo->line_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+	return false;
+}
+
+/*
+ * GetWorkerLine - Returns a line for worker to process.
+ */
+static bool
+GetWorkerLine(CopyState cstate)
+{
+	uint32 buff_count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+
+	/*
+	 * Copy the line data to line_buf and release the line position so that the
+	 * worker can continue loading data.
+	 */
+	if (pcdata->worker_line_buf_pos < pcdata->worker_line_buf_count)
+		goto return_line;
+
+	pcdata->worker_line_buf_pos = 0;
+	pcdata->worker_line_buf_count = 0;
+
+	for (buff_count = 0; buff_count < WORKER_CHUNK_COUNT; buff_count++)
+	{
+		bool result = CacheLineInfo(cstate, buff_count);
+		if (result)
+			break;
+
+		pcdata->worker_line_buf_count++;
+	}
+
+	if (pcdata->worker_line_buf_count)
+		goto return_line;
+	else
+		resetStringInfo(&cstate->line_buf);
+
+	return true;
+
+return_line:
+	cstate->line_buf = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].line_buf;
+	cstate->cur_lineno = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].cur_lineno;
+	cstate->line_buf_valid = true;
+
+	/* Mark that encoding conversion hasn't occurred yet. */
+	cstate->line_buf_converted = false;
+	ConvertToServerEncoding(cstate);
+	pcdata->worker_line_buf_pos++;
+	return false;
+ }
+
+/*
  * ParallelCopyMain - parallel copy worker's code.
  *
  * Where clause handling, convert tuple to columns, add default null values for
@@ -1018,6 +1428,8 @@ ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
 	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
 
 	pcdata->pcshared_info = pcshared_info;
+	AssignFullTransactionIdForWorker(pcshared_info->full_transaction_id);
+	AssignCommandIdForWorker(pcshared_info->mycid, true);
 
 	shared_cstate = (SerializedParallelCopyState *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE, false);
 	cstate->null_print = (char *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_NULL_PRINT, true);
@@ -1078,6 +1490,33 @@ ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
 }
 
 /*
+ * UpdateBlockInLineInfo - Update the line information.
+ */
+static pg_attribute_always_inline int
+UpdateBlockInLineInfo(CopyState cstate, uint32 blk_pos,
+					   uint32 offset, uint32 line_size, uint32 line_state)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyLineBoundaries *lineBoundaryPtr = &pcshared_info->line_boundaries;
+	ParallelCopyLineBoundary *lineInfo;
+	int line_pos = lineBoundaryPtr->pos;
+
+	/* Update the line information for the worker to pick and process. */
+	lineInfo = &lineBoundaryPtr->ring[line_pos];
+	while (pg_atomic_read_u32(&lineInfo->line_size) != -1)
+		COPY_WAIT_TO_PROCESS()
+
+	lineInfo->first_block = blk_pos;
+	lineInfo->start_offset = offset;
+	lineInfo->cur_lineno = cstate->cur_lineno;
+	pg_atomic_write_u32(&lineInfo->line_size, line_size);
+	pg_atomic_write_u32(&lineInfo->line_state, line_state);
+	lineBoundaryPtr->pos = (lineBoundaryPtr->pos + 1) % RINGSIZE;
+
+	return line_pos;
+}
+
+/*
  * ParallelCopyFrom - parallel copy leader's functionality.
  *
  * Leader executes the before statement for before statement trigger, if before
@@ -1100,8 +1539,298 @@ ParallelCopyFrom(CopyState cstate)
 	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
 	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
 
+	/* Execute the before statement triggers from the leader */
+	ExecBeforeStmtTrigger(cstate);
+
+	/* On input just throw the header line away. */
+	if (cstate->cur_lineno == 0 && cstate->header_line)
+	{
+		cstate->cur_lineno++;
+		if (CopyReadLine(cstate))
+		{
+			pcshared_info->is_read_in_progress = false;
+			return;			/* done */
+		}
+	}
+
+	for (;;)
+	{
+		bool done;
+		cstate->cur_lineno++;
+
+		/* Actually read the line into memory here. */
+		done = CopyReadLine(cstate);
+
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			break;
+	}
+
 	pcshared_info->is_read_in_progress = false;
 	cstate->cur_lineno = 0;
+ }
+
+/*
+ * GetLinePosition - return the line position that worker should process.
+ */
+static uint32
+GetLinePosition(CopyState cstate)
+{
+	ParallelCopyData *pcdata = cstate->pcdata;
+	ParallelCopyShmInfo *pcshared_info = pcdata->pcshared_info;
+	uint32  previous_pos = pcdata->worker_processed_pos;
+	uint32 write_pos = (previous_pos == -1) ? 0 : (previous_pos + 1) % RINGSIZE;
+	for (;;)
+	{
+		int		dataSize;
+		bool	is_read_in_progress = pcshared_info->is_read_in_progress;
+		ParallelCopyLineBoundary *lineInfo;
+		ParallelCopyDataBlock *data_blk_ptr;
+		ParallelCopyLineState line_state = LINE_LEADER_POPULATED;
+		ParallelCopyLineState curr_line_state;
+		CHECK_FOR_INTERRUPTS();
+
+		/* File read completed & no elements to process. */
+		if (!is_read_in_progress &&
+			(pcshared_info->populated ==
+			 pg_atomic_read_u64(&pcshared_info->total_worker_processed)))
+		{
+			write_pos = -1;
+			break;
+		}
+
+		/* Get the current line information. */
+		lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+		curr_line_state = pg_atomic_read_u32(&lineInfo->line_state);
+		if ((write_pos % WORKER_CHUNK_COUNT == 0) &&
+			(curr_line_state == LINE_WORKER_PROCESSED ||
+			 curr_line_state == LINE_WORKER_PROCESSING))
+		{
+			pcdata->worker_processed_pos = write_pos;
+			write_pos = (write_pos + WORKER_CHUNK_COUNT) %  RINGSIZE;
+			continue;
+		}
+
+		/* Get the size of this line. */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+		if (dataSize != 0) /* If not an empty line. */
+		{
+			/* Get the block information. */
+			data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+			if (!data_blk_ptr->curr_blk_completed && (dataSize == -1))
+			{
+				/* Wait till the current line or block is added. */
+				COPY_WAIT_TO_PROCESS()
+				continue;
+			}
+		}
+
+		/* Make sure that no worker has consumed this element. */
+		if (pg_atomic_compare_exchange_u32(&lineInfo->line_state,
+										   &line_state, LINE_WORKER_PROCESSING))
+			break;
+	}
+
+	pcdata->worker_processed_pos = write_pos;
+	return write_pos;
+}
+
+/*
+ * GetFreeCopyBlock - Get a free block for data to be copied.
+ */
+static pg_attribute_always_inline uint32
+GetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	int count = 0;
+	uint32 last_free_block = pcshared_info->cur_block_pos;
+	uint32 block_pos = (last_free_block != -1) ? ((last_free_block + 1) % MAX_BLOCKS_COUNT): 0;
+
+	/*
+	 * Get a new block for copying data, don't check current block, current
+	 * block will have some unprocessed data.
+	 */
+	while (count < (MAX_BLOCKS_COUNT - 1))
+	{
+		ParallelCopyDataBlock *dataBlkPtr = &pcshared_info->data_blocks[block_pos];
+		uint32 unprocessed_line_parts = pg_atomic_read_u32(&dataBlkPtr->unprocessed_line_parts);
+		if (unprocessed_line_parts == 0)
+		{
+			dataBlkPtr->curr_blk_completed = false;
+			dataBlkPtr->skip_bytes = 0;
+			pcshared_info->cur_block_pos = block_pos;
+			return block_pos;
+		}
+
+		block_pos = (block_pos + 1) % MAX_BLOCKS_COUNT;
+		count++;
+	}
+
+	return -1;
+}
+
+/*
+ * WaitGetFreeCopyBlock - If there are no blocks available, wait and get a block
+ * for copying data.
+ */
+static uint32
+WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	uint32 new_free_pos = -1;
+	for (;;)
+	{
+		new_free_pos = GetFreeCopyBlock(pcshared_info);
+		if (new_free_pos != -1)	/* We have got one block, break now. */
+			break;
+
+		COPY_WAIT_TO_PROCESS()
+	}
+
+	return new_free_pos;
+}
+
+/*
+ * SetRawBufForLoad - Set raw_buf to the shared memory where the file data must
+ * be read.
+ */
+static void
+SetRawBufForLoad(CopyState cstate, uint32 line_size, uint32 copy_buf_len,
+				 uint32 raw_buf_ptr, char **copy_raw_buf)
+{
+	ParallelCopyShmInfo	*pcshared_info;
+	uint32 cur_block_pos;
+	uint32 next_block_pos;
+	ParallelCopyDataBlock	*cur_data_blk_ptr = NULL;
+	ParallelCopyDataBlock	*next_data_blk_ptr = NULL;
+
+	if (!IsParallelCopy())
+		return;
+
+	pcshared_info = cstate->pcdata->pcshared_info;
+	cur_block_pos = pcshared_info->cur_block_pos;
+	cur_data_blk_ptr = (cstate->raw_buf) ? &pcshared_info->data_blocks[cur_block_pos] : NULL;
+	next_block_pos = WaitGetFreeCopyBlock(pcshared_info);
+	next_data_blk_ptr = &pcshared_info->data_blocks[next_block_pos];
+
+	/* set raw_buf to the data block in shared memory */
+	cstate->raw_buf = next_data_blk_ptr->data;
+	*copy_raw_buf = cstate->raw_buf;
+	if (cur_data_blk_ptr && line_size)
+	{
+		/*
+		 * Mark the previous block as completed, worker can start copying this
+		 * data.
+		 */
+		cur_data_blk_ptr->following_block = next_block_pos;
+		pg_atomic_add_fetch_u32(&cur_data_blk_ptr->unprocessed_line_parts, 1);
+		cur_data_blk_ptr->skip_bytes = copy_buf_len - raw_buf_ptr;
+		cur_data_blk_ptr->curr_blk_completed = true;
+	}
+}
+
+/*
+ * EndLineParallelCopy - Update the line information in shared memory.
+ */
+static void
+EndLineParallelCopy(CopyState cstate, uint32 line_pos, uint32 line_size,
+					 uint32 raw_buf_ptr)
+{
+	uint8 new_line_size;
+	if (!IsParallelCopy())
+		return;
+
+	if (!IsHeaderLine())
+	{
+		ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+		ParallelCopyLineBoundaries *lineBoundaryPtr = &pcshared_info->line_boundaries;
+		SET_NEWLINE_SIZE()
+		if (line_size)
+		{
+			ParallelCopyLineBoundary *lineInfo = &lineBoundaryPtr->ring[line_pos];
+			/*
+			 * If the new_line_size > raw_buf_ptr, then the new block has only
+			 * new line char content. The unprocessed count should not be
+			 * increased in this case.
+			 */
+			if (raw_buf_ptr > new_line_size)
+			{
+				uint32 cur_block_pos = pcshared_info->cur_block_pos;
+				ParallelCopyDataBlock *curr_data_blk_ptr = &pcshared_info->data_blocks[cur_block_pos];
+				pg_atomic_add_fetch_u32(&curr_data_blk_ptr->unprocessed_line_parts, 1);
+			}
+
+			/* Update line size. */
+			pg_atomic_write_u32(&lineInfo->line_size, line_size);
+			pg_atomic_write_u32(&lineInfo->line_state, LINE_LEADER_POPULATED);
+			elog(DEBUG1, "[Leader] After adding - line position:%d, line_size:%d",
+						 line_pos, line_size);
+			pcshared_info->populated++;
+		}
+		else if (new_line_size)
+		{
+			/* This means only new line char, empty record should be inserted.*/
+			ParallelCopyLineBoundary *lineInfo;
+			line_pos = UpdateBlockInLineInfo(cstate, -1, -1, 0,
+											   LINE_LEADER_POPULATED);
+			lineInfo = &lineBoundaryPtr->ring[line_pos];
+			elog(DEBUG1, "[Leader] Added empty line with offset:%d, line position:%d, line size:%d",
+						 lineInfo->start_offset, line_pos,
+						 pg_atomic_read_u32(&lineInfo->line_size));
+			pcshared_info->populated++;
+		}
+	}
+}
+
+/*
+ * ExecBeforeStmtTrigger - Execute the before statement trigger, this will be
+ * executed for parallel copy by the leader process.
+ */
+static void
+ExecBeforeStmtTrigger(CopyState cstate)
+{
+	EState	   *estate = CreateExecutorState();
+	ResultRelInfo *resultRelInfo;
+
+	Assert(IsLeader());
+
+	/*
+	 * We need a ResultRelInfo so we can use the regular executor's
+	 * index-entry-making machinery.  (There used to be a huge amount of code
+	 * here that basically duplicated execUtils.c ...)
+	 */
+	resultRelInfo = makeNode(ResultRelInfo);
+	InitResultRelInfo(resultRelInfo,
+					  cstate->rel,
+					  1,		/* must match rel's position in range_table */
+					  NULL,
+					  0);
+
+	/* Verify the named relation is a valid target for INSERT */
+	CheckValidResultRel(resultRelInfo, CMD_INSERT);
+
+	estate->es_result_relations = resultRelInfo;
+	estate->es_num_result_relations = 1;
+	estate->es_result_relation_info = resultRelInfo;
+
+	ExecInitRangeTable(estate, cstate->range_table);
+
+	/*
+	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
+	 * should do this for COPY, since it's not really an "INSERT" statement as
+	 * such. However, executing these triggers maintains consistency with the
+	 * EACH ROW triggers that we already fire on COPY.
+	 */
+	ExecBSInsertTriggers(estate, resultRelInfo);
+
+	/* Close any trigger target relations */
+	ExecCleanUpTriggerState(estate);
+
+	FreeExecutorState(estate);
 }
 
 /*
@@ -3536,7 +4265,8 @@ CopyFrom(CopyState cstate)
 
 	PartitionTupleRouting *proute = NULL;
 	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
+	CommandId	mycid = IsParallelCopy() ? GetCurrentCommandId(false) :
+										   GetCurrentCommandId(true);
 	int			ti_options = 0; /* start with default options for insert */
 	BulkInsertState bistate = NULL;
 	CopyInsertMethod insertMethod;
@@ -3546,7 +4276,14 @@ CopyFrom(CopyState cstate)
 	bool		has_instead_insert_row_trig;
 	bool		leafpart_use_multi_insert = false;
 
-	CheckTargetRelValidity(cstate);
+	/*
+	 * Perform this check if it is not parallel copy. In case of parallel
+	 * copy, this check is done by the leader, so that if any invalid case
+	 * exist the copy from command will error out from the leader itself,
+	 * avoiding launching workers, just to throw error.
+	 */
+	if (!IsParallelCopy())
+		CheckTargetRelValidity(cstate);
 
 	/*
 	 * If the target file is new-in-transaction, we assume that checking FSM
@@ -3586,7 +4323,8 @@ CopyFrom(CopyState cstate)
 	target_resultRelInfo = resultRelInfo;
 
 	/* Verify the named relation is a valid target for INSERT */
-	CheckValidResultRel(resultRelInfo, CMD_INSERT);
+	if (!IsParallelCopy())
+		CheckValidResultRel(resultRelInfo, CMD_INSERT);
 
 	ExecOpenIndices(resultRelInfo, false);
 
@@ -3735,13 +4473,16 @@ CopyFrom(CopyState cstate)
 	has_instead_insert_row_trig = (resultRelInfo->ri_TrigDesc &&
 								   resultRelInfo->ri_TrigDesc->trig_insert_instead_row);
 
-	/*
-	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
-	 * should do this for COPY, since it's not really an "INSERT" statement as
-	 * such. However, executing these triggers maintains consistency with the
-	 * EACH ROW triggers that we already fire on COPY.
-	 */
-	ExecBSInsertTriggers(estate, resultRelInfo);
+	if (!IsParallelCopy())
+	{
+		/*
+		 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
+		 * should do this for COPY, since it's not really an "INSERT" statement as
+		 * such. However, executing these triggers maintains consistency with the
+		 * EACH ROW triggers that we already fire on COPY.
+		 */
+		ExecBSInsertTriggers(estate, resultRelInfo);
+	}
 
 	econtext = GetPerTupleExprContext(estate);
 
@@ -3841,6 +4582,16 @@ CopyFrom(CopyState cstate)
 					!has_instead_insert_row_trig &&
 					resultRelInfo->ri_FdwRoutine == NULL;
 
+				/*
+				 * If the table has any partitions that are either foreign or
+				 * has BEFORE/INSTEAD OF triggers, we can't perform copy
+				 * operations with parallel workers.
+				 */
+				if (!leafpart_use_multi_insert && IsParallelWorker())
+					ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							errmsg("cannot perform PARALLEL COPY if partition has BEFORE/INSTEAD OF triggers, or if the partition is foreign partition"),
+							errhint("Try COPY without PARALLEL option")));
+
 				/* Set the multi-insert buffer to use for this partition. */
 				if (leafpart_use_multi_insert)
 				{
@@ -4261,7 +5012,7 @@ BeginCopyFrom(ParseState *pstate,
 	{
 		initStringInfo(&cstate->line_buf);
 		cstate->line_buf_converted = false;
-		cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+		cstate->raw_buf = (IsParallelCopy()) ? NULL : (char *) palloc(RAW_BUF_SIZE + 1);
 		cstate->raw_buf_index = cstate->raw_buf_len = 0;
 	}
 
@@ -4406,26 +5157,35 @@ NextCopyFromRawFields(CopyState cstate, char ***fields, int *nfields)
 	/* only available for text or csv input */
 	Assert(!cstate->binary);
 
-	/* on input just throw the header line away */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (IsParallelCopy())
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
-			return false;		/* done */
+		done = GetWorkerLine(cstate);
+		if (done && cstate->line_buf.len == 0)
+			return false;
 	}
+	else
+	{
+		/* on input just throw the header line away */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
+		{
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+				return false;		/* done */
+		}
 
-	cstate->cur_lineno++;
+		cstate->cur_lineno++;
 
-	/* Actually read the line into memory here */
-	done = CopyReadLine(cstate);
+		/* Actually read the line into memory here */
+		done = CopyReadLine(cstate);
 
-	/*
-	 * EOF at start of line means we're done.  If we see EOF after some
-	 * characters, we act as though it was newline followed by EOF, ie,
-	 * process the line and then exit loop on next iteration.
-	 */
-	if (done && cstate->line_buf.len == 0)
-		return false;
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			return false;
+	}
 
 	/* Parse the line into de-escaped field values */
 	if (cstate->csv_mode)
@@ -4673,9 +5433,31 @@ CopyReadLine(CopyState cstate)
 		 */
 		if (cstate->copy_dest == COPY_NEW_FE)
 		{
+			bool bIsFirst = true;
 			do
 			{
-				cstate->raw_buf_index = cstate->raw_buf_len;
+				if (!IsParallelCopy())
+					cstate->raw_buf_index = cstate->raw_buf_len;
+				else
+				{
+					if (cstate->raw_buf_index == RAW_BUF_SIZE)
+					{
+						/* Get a new block if it is the first time, From the
+						 * subsequent time, reset the index and re-use the same
+						 * block.
+						 */
+						if (bIsFirst)
+						{
+							ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+							uint32 block_pos = WaitGetFreeCopyBlock(pcshared_info);
+							cstate->raw_buf = pcshared_info->data_blocks[block_pos].data;
+							bIsFirst = false;
+						}
+
+						cstate->raw_buf_index = cstate->raw_buf_len = 0;
+					}
+				}
+
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
@@ -4730,7 +5512,7 @@ static void
 ConvertToServerEncoding(CopyState cstate)
 {
 	/* Done reading the line.  Convert it to server encoding. */
-	if (cstate->need_transcoding)
+	if (cstate->need_transcoding && (!IsParallelCopy() || IsWorker()))
 	{
 		char	   *cvt;
 		cvt = pg_any_to_server(cstate->line_buf.data,
@@ -4769,6 +5551,11 @@ CopyReadLineText(CopyState cstate)
 	char		quotec = '\0';
 	char		escapec = '\0';
 
+	/* For parallel copy */
+	int			line_size = 0;
+	int			line_pos = 0;
+
+	cstate->eol_type = EOL_UNKNOWN;
 	if (cstate->csv_mode)
 	{
 		quotec = cstate->quote[0];
@@ -4823,6 +5610,8 @@ CopyReadLineText(CopyState cstate)
 		if (raw_buf_ptr >= copy_buf_len || need_data)
 		{
 			REFILL_LINEBUF;
+			SetRawBufForLoad(cstate, line_size, copy_buf_len, raw_buf_ptr,
+							 &copy_raw_buf);
 
 			/*
 			 * Try to read some more data.  This will certainly reset
@@ -5047,9 +5836,15 @@ CopyReadLineText(CopyState cstate)
 				 * discard the data and the \. sequence.
 				 */
 				if (prev_raw_ptr > cstate->raw_buf_index)
-					appendBinaryStringInfo(&cstate->line_buf,
+				{
+					if (!IsParallelCopy())
+						appendBinaryStringInfo(&cstate->line_buf,
 										   cstate->raw_buf + cstate->raw_buf_index,
 										   prev_raw_ptr - cstate->raw_buf_index);
+					else
+						line_size += prev_raw_ptr - cstate->raw_buf_index;
+				}
+
 				cstate->raw_buf_index = raw_buf_ptr;
 				result = true;	/* report EOF */
 				break;
@@ -5101,6 +5896,26 @@ not_end_of_copy:
 			IF_NEED_REFILL_AND_EOF_BREAK(mblen - 1);
 			raw_buf_ptr += mblen - 1;
 		}
+
+		/*
+		 * Skip the header line. Update the line here, this cannot be done at
+		 * the beginning, as there is a possibility that file contains empty
+		 * lines.
+		 */
+		if (IsParallelCopy() && first_char_in_line && !IsHeaderLine())
+		{
+			ParallelCopyShmInfo	*pcshared_info = cstate->pcdata->pcshared_info;
+			ParallelCopyLineBoundary *lineInfo;
+			uint32			 line_first_block = pcshared_info->cur_block_pos;
+			line_pos = UpdateBlockInLineInfo(cstate,
+											   line_first_block,
+											   cstate->raw_buf_index, -1,
+											   LINE_LEADER_POPULATING);
+			lineInfo = &pcshared_info->line_boundaries.ring[line_pos];
+			elog(DEBUG1, "[Leader] Adding - block:%d, offset:%d, line position:%d",
+						 line_first_block,	lineInfo->start_offset, line_pos);
+		}
+
 		first_char_in_line = false;
 	}							/* end of outer loop */
 
@@ -5109,6 +5924,7 @@ not_end_of_copy:
 	 */
 	REFILL_LINEBUF;
 	CLEAR_EOL_LINE();
+	EndLineParallelCopy(cstate, line_pos, line_size, raw_buf_ptr);
 
 	return result;
 }
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index aef8555..27fb3e3 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -381,6 +381,8 @@ extern FullTransactionId GetTopFullTransactionId(void);
 extern FullTransactionId GetTopFullTransactionIdIfAny(void);
 extern FullTransactionId GetCurrentFullTransactionId(void);
 extern FullTransactionId GetCurrentFullTransactionIdIfAny(void);
+extern void AssignFullTransactionIdForWorker(FullTransactionId fullTransactionId);
+extern void AssignCommandIdForWorker(CommandId commandId, bool used);
 extern void MarkCurrentTransactionIdLoggedIfAny(void);
 extern bool SubTransactionIsActive(SubTransactionId subxid);
 extern CommandId GetCurrentCommandId(bool used);
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 3a83d0f..ba93f65 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1704,6 +1704,7 @@ ParallelCopyLineBoundary
 ParallelCopyData
 ParallelCopyDataBlock
 ParallelCopyLineBuf
+ParallelCopyLineState
 ParallelCopyShmInfo
 ParallelExecutorInfo
 ParallelHashGrowth
-- 
1.8.3.1

v2-0004-Documentation-for-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=v2-0004-Documentation-for-parallel-copy.patchDownload
From f8ea98e3b3c97272a04b8ff0967f25aa648d6c41 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Tue, 21 Jul 2020 11:13:10 +0530
Subject: [PATCH v2 4/6] Documentation for parallel copy.

This patch has the documentation changes for parallel copy.
---
 doc/src/sgml/ref/copy.sgml | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/doc/src/sgml/ref/copy.sgml b/doc/src/sgml/ref/copy.sgml
index 18189ab..95d349d 100644
--- a/doc/src/sgml/ref/copy.sgml
+++ b/doc/src/sgml/ref/copy.sgml
@@ -37,6 +37,7 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
     DELIMITER '<replaceable class="parameter">delimiter_character</replaceable>'
     NULL '<replaceable class="parameter">null_string</replaceable>'
     HEADER [ <replaceable class="parameter">boolean</replaceable> ]
+    PARALLEL <replaceable class="parameter">integer</replaceable>
     QUOTE '<replaceable class="parameter">quote_character</replaceable>'
     ESCAPE '<replaceable class="parameter">escape_character</replaceable>'
     FORCE_QUOTE { ( <replaceable class="parameter">column_name</replaceable> [, ...] ) | * }
@@ -275,6 +276,21 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
    </varlistentry>
 
    <varlistentry>
+    <term><literal>PARALLEL</literal></term>
+    <listitem>
+     <para>
+      Perform <command>COPY FROM</command> in parallel using <replaceable
+      class="parameter"> integer</replaceable> background workers.  Please
+      note that it is not guaranteed that the number of parallel workers
+      specified in <replaceable class="parameter">integer</replaceable> will
+      be used during execution.  It is possible for a copy to run with fewer
+      workers than specified, or even with no workers at all.  This option is
+      allowed only in <command>COPY FROM</command>.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><literal>QUOTE</literal></term>
     <listitem>
      <para>
-- 
1.8.3.1

v2-0005-Tests-for-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=v2-0005-Tests-for-parallel-copy.patchDownload
From 12f284ae5b3ec9e8cb65fa958e5ff8de5e7458d5 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 22 Jul 2020 18:59:44 +0530
Subject: [PATCH v2 5/6] Tests for parallel copy.

This patch has the tests for parallel copy.
---
 src/test/regress/expected/copy2.out | 210 +++++++++++++++++++++++++++++++++++-
 src/test/regress/input/copy.source  |  12 +++
 src/test/regress/output/copy.source |  12 +++
 src/test/regress/sql/copy2.sql      | 208 ++++++++++++++++++++++++++++++++++-
 4 files changed, 434 insertions(+), 8 deletions(-)

diff --git a/src/test/regress/expected/copy2.out b/src/test/regress/expected/copy2.out
index e40287d..361d572 100644
--- a/src/test/regress/expected/copy2.out
+++ b/src/test/regress/expected/copy2.out
@@ -254,18 +254,32 @@ It is "perfect".|
 "It is ""perfect"".","	"
 "",
 --test that we read consecutive LFs properly
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 COPY testnl FROM stdin CSV;
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+SELECT * FROM testnl;
+ a |          b           | c 
+---+----------------------+---
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+(2 rows)
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 COPY testeoc FROM stdin CSV;
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
 COPY testeoc TO stdout CSV;
 a\.
 \.b
 c\.d
 "\."
 -- test handling of nonstandard null marker that violates escaping rules
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 COPY testnull TO stdout WITH NULL AS E'\\0';
 1	\\0
@@ -280,6 +294,15 @@ SELECT * FROM testnull;
     | 
 (4 rows)
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 1);
+SELECT * FROM testnull;
+ a  | b  
+----+----
+ 42 | \0
+    | 
+(2 rows)
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -349,6 +372,34 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+SELECT * FROM vistest;
+ a  
+----
+ a2
+ b
+(2 rows)
+
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+COMMIT;
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 SELECT * FROM vistest;
  a 
@@ -409,7 +460,7 @@ SELECT * FROM vistest;
 (2 rows)
 
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -420,6 +471,8 @@ CREATE TEMP TABLE forcetest (
 -- should succeed with no effect ("b" remains an empty string, "c" remains NULL)
 BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 1);
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
  b |  c   
@@ -430,6 +483,8 @@ SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
 BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 1);
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
  c |  d   
@@ -486,6 +541,31 @@ select * from check_con_tbl;
    
 (2 rows)
 
+\d+ check_con_tbl
+                               Table "public.check_con_tbl"
+ Column |  Type   | Collation | Nullable | Default | Storage | Stats target | Description 
+--------+---------+-----------+----------+---------+---------+--------------+-------------
+ f1     | integer |           |          |         | plain   |              | 
+Check constraints:
+    "check_con_tbl_check" CHECK (check_con_function(check_con_tbl.*))
+
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 1);
+NOTICE:  input = {"f1":1}
+NOTICE:  input = {"f1":null}
+copy check_con_tbl from stdin with (parallel 1);
+NOTICE:  input = {"f1":0}
+ERROR:  new row for relation "check_con_tbl" violates check constraint "check_con_tbl_check"
+DETAIL:  Failing row contains (0).
+CONTEXT:  COPY check_con_tbl, line 1: "0"
+parallel worker
+select * from check_con_tbl;
+ f1 
+----
+  1
+   
+(2 rows)
+
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
 CREATE ROLE regress_rls_copy_user_colperms;
@@ -600,8 +680,130 @@ SELECT * FROM instead_of_insert_tbl;
 (2 rows)
 
 COMMIT;
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+COPY test_parallel_copy (a, b, c, d, e) from stdin with (PARALLEL 1);
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1, FORMAT 'csv', HEADER);
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0');
+ERROR:  argument to option "parallel" must be a positive integer greater than zero
+LINE 1: COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0'...
+                                                        ^
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri from stdin with (FORMAT csv, DELIMITER ',', PARALLEL 1);
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1) WHERE height > random() * 65;
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- temporary table copy: should perform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+COPY temp_test (a) from stdin with (PARALLEL 1);
+WARNING:  Parallel copy not supported for specified table, copy will be run in non-parallel mode
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) from stdin with (PARALLEL 1);
+ERROR:  column "xyz" of relation "test_parallel_copy" does not exist
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) from stdin with (PARALLEL 1);
+ERROR:  column "d" specified more than once
+-- missing data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  invalid input syntax for type integer: ""
+CONTEXT:  COPY test_parallel_copy, line 0, column a: ""
+parallel worker
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2000	230	23	23"
+parallel worker
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2001	231	\N	\N"
+parallel worker
+-- extra data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  extra data after last expected column
+CONTEXT:  COPY test_parallel_copy, line 1: "2002	232	40	50	60	70	80"
+parallel worker
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) from stdin with (delimiter ',', null 'x', PARALLEL 1) ;
+COPY test_parallel_copy from stdin WITH (DELIMITER ';', NULL '', PARALLEL 1);
+COPY test_parallel_copy from stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL 1);
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = 50004;
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a > 60003;
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE f > 60003;
+ERROR:  column "f" does not exist
+LINE 1: ..._parallel_copy from stdin WITH (PARALLEL 1) WHERE f > 60003;
+                                                             ^
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+ERROR:  missing FROM-clause entry for table "x"
+LINE 1: ...rallel_copy from stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+                                                                  ^
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (SELECT 1 FROM x);
+ERROR:  cannot use subquery in COPY FROM WHERE condition
+LINE 1: ...arallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (SELECT...
+                                                             ^
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (generate_series(1,5));
+ERROR:  set-returning functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...lel_copy from stdin WITH (PARALLEL 1) WHERE a IN (generate_s...
+                                                             ^
+COPY test_parallel_copy from stdin WITH(PARALLEL 1) WHERE a = row_number() over(b);
+ERROR:  window functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...rallel_copy from stdin WITH(PARALLEL 1) WHERE a = row_number...
+                                                             ^
+-- check results of copy in
+SELECT * FROM test_parallel_copy;
+   a   | b  |     c      |    d    |    e    
+-------+----+------------+---------+---------
+     1 | 11 | test_c1    | test_d1 | test_e1
+     2 | 12 | test_c2    | test_d2 | test_e2
+       |  3 | stuff      | test_d3 | 
+       |  4 | stuff      | test_d4 | 
+       |  5 | stuff      | test_d5 | 
+       |    | 45         | 80      | 90
+       |    | x          | \x      | \x
+       |    | ,          | \,      | \
+  3000 |    | c          |         | 
+  4000 |    | C          |         | 
+  4001 |  1 | empty      |         | 
+  4002 |  2 | null       |         | 
+  4003 |  3 | Backslash  | \       | \
+  4004 |  4 | BackslashX | \X      | \X
+  4005 |  5 | N          | N       | N
+  4006 |  6 | BackslashN | \N      | \N
+  4007 |  7 | XX         | XX      | XX
+  4008 |  8 | Delimiter  | :       | :
+ 50004 | 25 | 35         | 45      | 55
+ 60004 | 25 | 35         | 45      | 55
+ 60005 | 26 | 36         | 46      | 56
+(21 rows)
+
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
 DROP TABLE x, y;
diff --git a/src/test/regress/input/copy.source b/src/test/regress/input/copy.source
index a1d529a..159c058 100644
--- a/src/test/regress/input/copy.source
+++ b/src/test/regress/input/copy.source
@@ -15,6 +15,13 @@ DELETE FROM onek;
 
 COPY onek FROM '@abs_builddir@/results/onek.data';
 
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+
+SELECT COUNT(*) FROM tenk1;
+
+TRUNCATE tenk1;
+
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
@@ -159,6 +166,11 @@ truncate parted_copytest;
 
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
 
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
+
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/output/copy.source b/src/test/regress/output/copy.source
index 938d355..c3003fe 100644
--- a/src/test/regress/output/copy.source
+++ b/src/test/regress/output/copy.source
@@ -9,6 +9,15 @@ COPY onek FROM '@abs_srcdir@/data/onek.data';
 COPY onek TO '@abs_builddir@/results/onek.data';
 DELETE FROM onek;
 COPY onek FROM '@abs_builddir@/results/onek.data';
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+SELECT COUNT(*) FROM tenk1;
+ count 
+-------
+ 10000
+(1 row)
+
+TRUNCATE tenk1;
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
 COPY person FROM '@abs_srcdir@/data/person.data';
@@ -113,6 +122,9 @@ insert into parted_copytest select x,1,'One' from generate_series(1011,1020) x;
 copy (select * from parted_copytest order by a) to '@abs_builddir@/results/parted_copytest.csv';
 truncate parted_copytest;
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/sql/copy2.sql b/src/test/regress/sql/copy2.sql
index 902f4fa..7015698 100644
--- a/src/test/regress/sql/copy2.sql
+++ b/src/test/regress/sql/copy2.sql
@@ -157,7 +157,7 @@ COPY y TO stdout (FORMAT CSV, FORCE_QUOTE *);
 
 --test that we read consecutive LFs properly
 
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 
 COPY testnl FROM stdin CSV;
 1,"a field with two LFs
@@ -165,8 +165,16 @@ COPY testnl FROM stdin CSV;
 inside",2
 \.
 
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+1,"a field with two LFs
+
+inside",2
+\.
+
+SELECT * FROM testnl;
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 
 COPY testeoc FROM stdin CSV;
 a\.
@@ -175,11 +183,19 @@ c\.d
 "\."
 \.
 
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+a\.
+\.b
+c\.d
+"\."
+\.
+
 COPY testeoc TO stdout CSV;
 
 -- test handling of nonstandard null marker that violates escaping rules
 
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 
 COPY testnull TO stdout WITH NULL AS E'\\0';
@@ -191,6 +207,14 @@ COPY testnull FROM stdin WITH NULL AS E'\\0';
 
 SELECT * FROM testnull;
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 1);
+42	\\0
+\0	\0
+\.
+
+SELECT * FROM testnull;
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -235,6 +259,23 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+a2
+b
+\.
+SELECT * FROM vistest;
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+d2
+e
+\.
+SELECT * FROM vistest;
+COMMIT;
+SELECT * FROM vistest;
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 x
 y
@@ -284,7 +325,7 @@ SELECT * FROM vistest;
 COMMIT;
 SELECT * FROM vistest;
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -297,6 +338,10 @@ BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
 1,,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 1);
+1,,""
+\.
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
@@ -304,6 +349,10 @@ BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
 2,'a',,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 1);
+2,'a',,""
+\.
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
 -- should fail with not-null constraint violation
@@ -339,6 +388,16 @@ copy check_con_tbl from stdin;
 0
 \.
 select * from check_con_tbl;
+\d+ check_con_tbl
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 1);
+1
+\N
+\.
+copy check_con_tbl from stdin with (parallel 1);
+0
+\.
+select * from check_con_tbl;
 
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
@@ -440,8 +499,149 @@ test1
 SELECT * FROM instead_of_insert_tbl;
 COMMIT;
 
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+
+COPY test_parallel_copy (a, b, c, d, e) from stdin with (PARALLEL 1);
+1	11	test_c1	test_d1	test_e1
+2	12	test_c2	test_d2	test_e2
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+3	test_d3
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+4	test_d4
+5	test_d5
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1, FORMAT 'csv', HEADER);
+b	d
+\.
+
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0');
+
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri from stdin with (FORMAT csv, DELIMITER ',', PARALLEL 1);
+10
+\.
+
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1) WHERE height > random() * 65;
+60,60,60
+\.
+
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+60
+\.
+
+-- temporary table copy: should perform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+
+COPY temp_test (a) from stdin with (PARALLEL 1);
+10
+\.
+
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) from stdin with (PARALLEL 1);
+
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) from stdin with (PARALLEL 1);
+
+-- missing data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+
+\.
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+2000	230	23	23
+\.
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+2001	231	\N	\N
+\.
+
+-- extra data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+2002	232	40	50	60	70	80
+\.
+
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) from stdin with (delimiter ',', null 'x', PARALLEL 1) ;
+x,45,80,90
+x,\x,\\x,\\\x
+x,\,,\\\,,\\
+\.
+
+COPY test_parallel_copy from stdin WITH (DELIMITER ';', NULL '', PARALLEL 1);
+3000;;c;;
+\.
+
+COPY test_parallel_copy from stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL 1);
+4000:\X:C:\X:\X
+4001:1:empty::
+4002:2:null:\X:\X
+4003:3:Backslash:\\:\\
+4004:4:BackslashX:\\X:\\X
+4005:5:N:\N:\N
+4006:6:BackslashN:\\N:\\N
+4007:7:XX:\XX:\XX
+4008:8:Delimiter:\::\:
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = 50004;
+50003	24	34	44	54
+50004	25	35	45 	55
+50005	26	36	46	56
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a > 60003;
+60001	22	32	42	52
+60002	23	33	43	53
+60003	24	34	44	54
+60004	25	35	45	55
+60005	26	36	46	56
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE f > 60003;
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (SELECT 1 FROM x);
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (generate_series(1,5));
+
+COPY test_parallel_copy from stdin WITH(PARALLEL 1) WHERE a = row_number() over(b);
+
+-- check results of copy in
+SELECT * FROM test_parallel_copy;
+
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
 DROP TABLE x, y;
-- 
1.8.3.1

v2-0006-Parallel-Copy-For-Binary-Format-Files.patchtext/x-patch; charset=US-ASCII; name=v2-0006-Parallel-Copy-For-Binary-Format-Files.patchDownload
From 7fbd84dc6a5b749f7eeb1d021887c8bd890e3a0f Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddy@enterprisedb.com>
Date: Wed, 22 Jul 2020 19:23:30 +0530
Subject: [PATCH v2 6/6] Parallel Copy For Binary Format Files

Leader reads data from the file into the DSM data blocks each of 64K size.
It also identifies each tuple data block id, start offset, end offset,
tuple size and updates this information in the ring data structure.
Workers parallelly read the tuple information from the ring data structure,
the actual tuple data from the data blocks and parallelly insert the tuples
into the table.
---
 src/backend/commands/copy.c | 654 ++++++++++++++++++++++++++++++++++++++------
 1 file changed, 574 insertions(+), 80 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 9b657ab..f19d359 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -263,6 +263,17 @@ typedef struct ParallelCopyLineBuf
 }ParallelCopyLineBuf;
 
 /*
+ * Represents the usage mode for CopyReadBinaryGetDataBlock.
+ */
+typedef enum FieldInfoType
+{
+	FIELD_NONE = 0,
+	FIELD_COUNT,
+	FIELD_SIZE,
+	FIELD_DATA
+} FieldInfoType;
+
+/*
  * Parallel copy data information.
  */
 typedef struct ParallelCopyData
@@ -283,6 +294,9 @@ typedef struct ParallelCopyData
 
 	/* Current position in worker_line_buf */
 	uint32				worker_line_buf_pos;
+
+	/* For binary formatted files */
+	ParallelCopyDataBlock *curr_data_block;
 }ParallelCopyData;
 
 /*
@@ -443,6 +457,7 @@ typedef struct SerializedParallelCopyState
 	/* Working state for COPY FROM */
 	AttrNumber          num_defaults;
 	Oid                 relid;
+	bool				binary;
 }SerializedParallelCopyState;
 
 /* DestReceiver for COPY (query) TO */
@@ -517,7 +532,6 @@ typedef struct CopyMultiInsertInfo
 	int			ti_options;		/* table insert options */
 } CopyMultiInsertInfo;
 
-
 /*
  * These macros centralize code used to process line_buf and raw_buf buffers.
  * They are macros because they often do continue/break control and to avoid
@@ -647,8 +661,110 @@ else \
 
 /* End parallel copy Macros */
 
-static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
+/*
+ * CHECK_FIELD_COUNT - Handles the error cases for field count
+ * for binary format files.
+ */
+#define CHECK_FIELD_COUNT \
+{\
+	if (fld_count == -1) \
+	{ \
+		if (IsParallelCopy() && \
+			!IsLeader()) \
+			return true; \
+		else if (IsParallelCopy() && \
+			IsLeader()) \
+		{ \
+			if (cstate->pcdata->curr_data_block->data[cstate->raw_buf_index + sizeof(fld_count)] != 0) \
+				ereport(ERROR, \
+						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+						errmsg("received copy data after EOF marker"))); \
+			return true; \
+		} \
+		else \
+		{ \
+			/* \
+			* Received EOF marker.  In a V3-protocol copy, wait for the \
+			* protocol-level EOF, and complain if it doesn't come \
+			* immediately.  This ensures that we correctly handle CopyFail, \
+			* if client chooses to send that now. \
+			* \
+			* Note that we MUST NOT try to read more data in an old-protocol \
+			* copy, since there is no protocol-level EOF marker then.  We \
+			* could go either way for copy from file, but choose to throw \
+			* error if there's data after the EOF marker, for consistency \
+			* with the new-protocol case. \
+			*/ \
+			char		dummy; \
+			if (cstate->copy_dest != COPY_OLD_FE && \
+				CopyGetData(cstate, &dummy, 1, 1) > 0) \
+				ereport(ERROR, \
+						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+						errmsg("received copy data after EOF marker"))); \
+				return false; \
+		} \
+	} \
+	if (fld_count != cstate->max_fields) \
+		ereport(ERROR, \
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+				errmsg("row field count is %d, expected %d", \
+				(int) fld_count, cstate->max_fields))); \
+}
+
+/*
+ * CHECK_FIELD_SIZE - Handles the error case for field size
+ * for binary format files.
+ */
+#define CHECK_FIELD_SIZE(fld_size) \
+{ \
+	if (fld_size < -1) \
+		ereport(ERROR, \
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+				errmsg("invalid field size")));\
+}
 
+/*
+ * EOF_ERROR - Error statement for EOF for binary format
+ * files.
+ */
+#define EOF_ERROR \
+{ \
+	ereport(ERROR, \
+		(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+		errmsg("unexpected EOF in COPY data")));\
+}
+
+/*
+ * GET_RAW_BUF_INDEX - Calculates the raw buf index for the cases
+ * where the data spread is across multiple data blocks.
+ */
+#define GET_RAW_BUF_INDEX(raw_buf_index, fld_size, required_blks, curr_blk_bytes) \
+{ \
+	raw_buf_index = fld_size - (((required_blks - 1) * DATA_BLOCK_SIZE) + curr_blk_bytes); \
+}
+
+/*
+ * GET_REQUIRED_BLOCKS - Calculates the number of data
+ * blocks required for the cases where the data spread
+ * is across multiple data blocks.
+ */
+#define GET_REQUIRED_BLOCKS(required_blks, fld_size, curr_blk_bytes) \
+{ \
+	/* \
+	 * field size can spread across multiple data blocks, \
+	 * calculate the number of required data blocks and try to get \
+	 * those many data blocks. \
+	 */ \
+	required_blks = (int32)(fld_size - curr_blk_bytes)/(int32)DATA_BLOCK_SIZE; \
+	/* \
+	 * check if we need the data block for the field data \
+	 * bytes that are not modulus of data block size. \
+	 */ \
+	if ((fld_size - curr_blk_bytes)%DATA_BLOCK_SIZE != 0) \
+		required_blks++; \
+}
+
+static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
 /* non-export function prototypes */
 static CopyState BeginCopy(ParseState *pstate, bool is_from, Relation rel,
@@ -702,6 +818,14 @@ static void ExecBeforeStmtTrigger(CopyState cstate);
 static void CheckTargetRelValidity(CopyState cstate);
 static void PopulateCstateCatalogInfo(CopyState cstate);
 static pg_attribute_always_inline uint32 GetLinePosition(CopyState cstate);
+static uint32 WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info);
+static bool CopyReadBinaryTupleLeader(CopyState cstate);
+static void CopyReadBinaryFindTupleSize(CopyState cstate, uint32 *line_size);
+static bool CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls);
+static Datum CopyReadBinaryAttributeWorker(CopyState cstate, FmgrInfo *flinfo,
+										   Oid typioparam, int32 typmod, bool *isnull);
+static void CopyReadBinaryGetDataBlock(CopyState cstate, FieldInfoType field_info);
+
 /*
  * SerializeParallelCopyState - Copy shared_cstate using cstate information.
  */
@@ -719,6 +843,7 @@ SerializeParallelCopyState(CopyState cstate, SerializedParallelCopyState *shared
 	shared_cstate->convert_selectively = cstate->convert_selectively;
 	shared_cstate->num_defaults = cstate->num_defaults;
 	shared_cstate->relid = cstate->pcdata->relid;
+	shared_cstate->binary = cstate->binary;
 }
 
 /*
@@ -878,8 +1003,8 @@ FindInsertMethod(CopyState cstate)
 static pg_attribute_always_inline bool
 IsParallelCopyAllowed(CopyState cstate)
 {
-	/* Parallel copy not allowed for frontend (2.0 protocol) & binary option. */
-	if ((cstate->copy_dest == COPY_OLD_FE) || cstate->binary)
+	/* Parallel copy not allowed for frontend (2.0 protocol). */
+	if (cstate->copy_dest == COPY_OLD_FE)
 		return false;
 
 	/* Check if copy is into foreign table or temporary table. */
@@ -1153,6 +1278,7 @@ InitializeParallelCopyInfo(SerializedParallelCopyState *shared_cstate,
 	cstate->convert_selectively = shared_cstate->convert_selectively;
 	cstate->num_defaults = shared_cstate->num_defaults;
 	pcdata->relid = shared_cstate->relid;
+	cstate->binary = shared_cstate->binary;
 
 	PopulateCommonCstateInfo(cstate, tup_desc, attnamelist);
 
@@ -1542,32 +1668,66 @@ ParallelCopyFrom(CopyState cstate)
 	/* Execute the before statement triggers from the leader */
 	ExecBeforeStmtTrigger(cstate);
 
-	/* On input just throw the header line away. */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (!cstate->binary)
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
+		/* On input just throw the header line away. */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
 		{
-			pcshared_info->is_read_in_progress = false;
-			return;			/* done */
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+			{
+				pcshared_info->is_read_in_progress = false;
+				return;			/* done */
+			}
 		}
-	}
 
-	for (;;)
-	{
-		bool done;
-		cstate->cur_lineno++;
+		for (;;)
+		{
+			bool done;
+			cstate->cur_lineno++;
 
-		/* Actually read the line into memory here. */
-		done = CopyReadLine(cstate);
+			/* Actually read the line into memory here. */
+			done = CopyReadLine(cstate);
 
+			/*
+			* EOF at start of line means we're done.  If we see EOF after some
+			* characters, we act as though it was newline followed by EOF, ie,
+			* process the line and then exit loop on next iteration.
+			*/
+			if (done && cstate->line_buf.len == 0)
+				break;
+		}
+	}
+	else
+	{
 		/*
-		 * EOF at start of line means we're done.  If we see EOF after some
-		 * characters, we act as though it was newline followed by EOF, ie,
-		 * process the line and then exit loop on next iteration.
+		 * Binary Format Files.
+		 * For parallel copy leader, fill in the error
+		 * context information here, in case any failures
+		 * while determining tuple offsets, leader
+		 * would throw the errors with proper context.
 		 */
-		if (done && cstate->line_buf.len == 0)
-			break;
+		ErrorContextCallback errcallback;
+		errcallback.callback = CopyFromErrorCallback;
+		errcallback.arg = (void *) cstate;
+		errcallback.previous = error_context_stack;
+		error_context_stack = &errcallback;
+		cstate->pcdata->curr_data_block = NULL;
+		cstate->raw_buf_index = 0;
+		pcshared_info->populated = 0;
+		cstate->cur_lineno = 0;
+		cstate->max_fields = list_length(cstate->attnumlist);
+
+		for (;;)
+		{
+			bool eof = false;
+			cstate->cur_lineno++;
+
+			eof = CopyReadBinaryTupleLeader(cstate);
+
+			if (eof)
+				break;
+		}
 	}
 
 	pcshared_info->is_read_in_progress = false;
@@ -1575,7 +1735,357 @@ ParallelCopyFrom(CopyState cstate)
  }
 
 /*
- * GetLinePosition - return the line position that worker should process.
+ * CopyReadBinaryGetDataBlock - gets a new block, updates
+ * the current offset, calculates the skip bytes.
+ */
+static void
+CopyReadBinaryGetDataBlock(CopyState cstate, FieldInfoType field_info)
+{
+	ParallelCopyDataBlock *data_block = NULL;
+	ParallelCopyDataBlock *curr_data_block = cstate->pcdata->curr_data_block;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	uint8 move_bytes = 0;
+	uint32 block_pos;
+	uint32 prev_block_pos;
+	int read_bytes = 0;
+
+	prev_block_pos = pcshared_info->cur_block_pos;
+
+	block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+	if (field_info == FIELD_SIZE || field_info == FIELD_COUNT)
+		move_bytes = (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+
+	if (curr_data_block != NULL)
+		curr_data_block->skip_bytes = move_bytes;
+
+	data_block = &pcshared_info->data_blocks[block_pos];
+
+	if (move_bytes > 0 && curr_data_block != NULL)
+		memmove(&data_block->data[0], &curr_data_block->data[cstate->raw_buf_index], move_bytes);
+
+	elog(DEBUG1, "LEADER - field info %d is spread across data blocks - moved %d bytes from current block %u to %u block",
+		field_info, move_bytes, prev_block_pos, block_pos);
+
+	read_bytes = CopyGetData(cstate, &data_block->data[move_bytes], 1, (DATA_BLOCK_SIZE - move_bytes));
+
+	if (field_info == FIELD_NONE && cstate->reached_eof)
+		return;
+
+	if (cstate->reached_eof)
+		EOF_ERROR;
+
+	elog(DEBUG1, "LEADER - bytes read from file %d", read_bytes);
+
+	if(field_info == FIELD_SIZE || field_info == FIELD_DATA)
+	{
+		ParallelCopyDataBlock *prev_data_block = NULL;
+		prev_data_block = curr_data_block;
+		prev_data_block->following_block = block_pos;
+
+		if (prev_data_block->curr_blk_completed  == false)
+			prev_data_block->curr_blk_completed = true;
+
+		pg_atomic_add_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+	}
+
+	cstate->pcdata->curr_data_block = data_block;
+	cstate->raw_buf_index = 0;
+}
+
+/*
+ * CopyReadBinaryTupleLeader - leader reads data from binary formatted file
+ * to data blocks and identifies tuple boundaries/offsets so that workers
+ * can work on the data blocks data.
+ */
+static bool
+CopyReadBinaryTupleLeader(CopyState cstate)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	int16		fld_count;
+	uint32      line_size = 0;
+	uint32 		start_block_pos;
+	uint32		start_offset;
+
+	if (cstate->pcdata->curr_data_block == NULL)
+	{
+		CopyReadBinaryGetDataBlock(cstate, FIELD_NONE);
+
+		/*
+		 * no data is read from file here. one possibility
+		 * to be here could be that the binary file just
+		 * has a valid signature but nothing else.
+		 */
+		if (cstate->reached_eof)
+			return true;
+	}
+
+	if ((cstate->raw_buf_index + sizeof(fld_count)) >= DATA_BLOCK_SIZE)
+		CopyReadBinaryGetDataBlock(cstate, FIELD_COUNT);
+
+	memcpy(&fld_count, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_count));
+	fld_count = (int16) pg_ntoh16(fld_count);
+	CHECK_FIELD_COUNT;
+	start_offset = cstate->raw_buf_index;
+	cstate->raw_buf_index += sizeof(fld_count);
+	line_size += sizeof(fld_count);
+	start_block_pos = pcshared_info->cur_block_pos;
+
+	CopyReadBinaryFindTupleSize(cstate, &line_size);
+
+	pg_atomic_add_fetch_u32(&cstate->pcdata->curr_data_block->unprocessed_line_parts, 1);
+
+	if (line_size > 0)
+	{
+		int line_pos = UpdateBlockInLineInfo(cstate,
+											start_block_pos,
+											start_offset,
+											line_size,
+											LINE_LEADER_POPULATED);
+
+		pcshared_info->populated++;
+		elog(DEBUG1, "LEADER - adding - block:%u, offset:%u, line size:%u line position:%d",
+				start_block_pos, start_offset, line_size, line_pos);
+	}
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryFindTupleSize - leader identifies boundaries/
+ * offsets for each attribute/column and finally results in the
+ * tuple/row size. It moves on to next data block if the attribute/
+ * column is spread across data blocks.
+ */
+static void
+CopyReadBinaryFindTupleSize(CopyState cstate, uint32 *line_size)
+{
+	int32		fld_size;
+	ListCell   *cur;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			att_num = lfirst_int(cur);
+		Form_pg_attribute att = TupleDescAttr(tup_desc, (att_num - 1));
+		cstate->cur_attname = NameStr(att->attname);
+		fld_size = 0;
+
+		if ((cstate->raw_buf_index + sizeof(fld_size)) >= DATA_BLOCK_SIZE)
+			CopyReadBinaryGetDataBlock(cstate, FIELD_SIZE);
+
+		memcpy(&fld_size, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_size));
+		cstate->raw_buf_index += sizeof(fld_size);
+		*line_size += sizeof(fld_size);
+		fld_size = (int32) pg_ntoh32(fld_size);
+
+		CHECK_FIELD_SIZE(fld_size);
+
+		*line_size += fld_size;
+
+		if ((DATA_BLOCK_SIZE - cstate->raw_buf_index) >= fld_size)
+		{
+			cstate->raw_buf_index += fld_size;
+			elog(DEBUG1, "LEADER - tuple lies in he same data block");
+		}
+		else
+		{
+			int32 required_blks = 0;
+			int32 curr_blk_bytes = (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+			int i = 0;
+
+			GET_REQUIRED_BLOCKS(required_blks, fld_size, curr_blk_bytes);
+
+			i = required_blks;
+
+			while(i > 0)
+			{
+				CopyReadBinaryGetDataBlock(cstate, FIELD_DATA);
+				i--;
+			}
+
+			GET_RAW_BUF_INDEX(cstate->raw_buf_index, fld_size, required_blks, curr_blk_bytes);
+
+			/*
+			 * raw_buf_index should never cross data block size,
+			 * as the required number of data blocks would have
+			 * been obtained in the above while loop.
+			 */
+			Assert(cstate->raw_buf_index <= DATA_BLOCK_SIZE);
+		}
+		cstate->cur_attname = NULL;
+	}
+}
+
+/*
+ * CopyReadBinaryTupleWorker - each worker reads data from data blocks after
+ * getting leader-identified tuple offsets from ring data structure.
+ */
+static bool
+CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls)
+{
+	uint32 		line_pos;
+	ParallelCopyLineBoundary *line_info;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	int16		fld_count;
+	ListCell   *cur;
+	FmgrInfo   *in_functions = cstate->in_functions;
+	Oid		   *typioparams = cstate->typioparams;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	line_pos = GetLinePosition(cstate);
+
+	if (line_pos == -1)
+		return true;
+
+	line_info = &pcshared_info->line_boundaries.ring[line_pos];
+	cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[line_info->first_block];
+	cstate->raw_buf_index = line_info->start_offset;
+
+#if 0
+	if (cstate->raw_buf_index + sizeof(fld_count) >= DATA_BLOCK_SIZE)
+	{
+		/*
+		 * The case where field count spread across datablocks should never occur,
+		 * as the leader would have moved it to next block. enable this if block
+		 * for debugging purposes only.
+		 */
+		elog(DEBUG1, "WORKER - field count spread across datablocks should never occur");
+	}
+#endif
+
+	memcpy(&fld_count, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_count));
+	fld_count = (int16) pg_ntoh16(fld_count);
+
+	CHECK_FIELD_COUNT;
+
+	cstate->raw_buf_index += sizeof(fld_count);
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			att_num = lfirst_int(cur);
+		int			m = att_num - 1;
+		Form_pg_attribute att = TupleDescAttr(tup_desc, m);
+		cstate->cur_attname = NameStr(att->attname);
+
+		values[m] = CopyReadBinaryAttributeWorker(cstate,
+											&in_functions[m],
+											typioparams[m],
+											att->atttypmod,
+											&nulls[m]);
+		cstate->cur_attname = NULL;
+	}
+
+	pg_atomic_sub_fetch_u32(&cstate->pcdata->curr_data_block->unprocessed_line_parts, 1);
+	line_info->start_offset = -1;
+	pg_atomic_write_u32(&line_info->line_state, LINE_WORKER_PROCESSED);
+	pg_atomic_write_u32(&line_info->line_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryAttributeWorker - leader identifies boundaries/offsets
+ * for each attribute/column, it moves on to next data block if the
+ * attribute/column is spread across data blocks.
+ */
+static Datum
+CopyReadBinaryAttributeWorker(CopyState cstate, FmgrInfo *flinfo,
+		Oid typioparam, int32 typmod, bool *isnull)
+{
+	int32		fld_size;
+	Datum		result;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+	if ((cstate->raw_buf_index + sizeof(fld_size)) >= DATA_BLOCK_SIZE)
+	{
+		ParallelCopyDataBlock *prev_data_block = cstate->pcdata->curr_data_block;
+		elog(DEBUG1, "WORKER - field size is spread across data blocks");
+		cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[prev_data_block->following_block];
+		pg_atomic_sub_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+		cstate->raw_buf_index = 0;
+	}
+
+	memcpy(&fld_size, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_size));
+	fld_size = (int32) pg_ntoh32(fld_size);
+
+	CHECK_FIELD_SIZE(fld_size);
+
+	cstate->raw_buf_index += sizeof(fld_size);
+
+	/* reset attribute_buf to empty, and load raw data in it */
+	resetStringInfo(&cstate->attribute_buf);
+
+	enlargeStringInfo(&cstate->attribute_buf, fld_size);
+
+	if ((DATA_BLOCK_SIZE - cstate->raw_buf_index) >= fld_size)
+	{
+		elog(DEBUG1, "WORKER - tuple lies in single data block");
+		memcpy(&cstate->attribute_buf.data[0],&cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], fld_size);
+		cstate->raw_buf_index += fld_size;
+	}
+	else
+	{
+		uint32 att_buf_idx = 0;
+		uint32 copy_bytes = 0;
+		int32 required_blks = 0;
+		int32 curr_blk_bytes = (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+		ParallelCopyDataBlock *prev_data_block = NULL;
+		int i = 0;
+
+		GET_REQUIRED_BLOCKS(required_blks, fld_size, curr_blk_bytes);
+
+		i = required_blks;
+		prev_data_block = cstate->pcdata->curr_data_block;
+		elog(DEBUG1, "WORKER - tuple is spread across data blocks");
+		memcpy(&cstate->attribute_buf.data[0], &prev_data_block->data[cstate->raw_buf_index],
+				curr_blk_bytes);
+		copy_bytes = curr_blk_bytes;
+		att_buf_idx = curr_blk_bytes;
+
+		while (i>0)
+		{
+			cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[prev_data_block->following_block];
+			pg_atomic_sub_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+			cstate->raw_buf_index = 0;
+			copy_bytes = fld_size - att_buf_idx;
+
+			/*
+			 * the bytes that are yet to be taken into att buff are more than
+			 * the entire data block size, but only take the data block size
+			 * elements.
+			 */
+			if (copy_bytes >= DATA_BLOCK_SIZE)
+				copy_bytes = DATA_BLOCK_SIZE;
+
+			memcpy(&cstate->attribute_buf.data[att_buf_idx],
+				&cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], copy_bytes);
+			att_buf_idx += copy_bytes;
+			i--;
+		}
+		GET_RAW_BUF_INDEX(cstate->raw_buf_index, fld_size, required_blks, curr_blk_bytes);
+	}
+
+	cstate->attribute_buf.len = fld_size;
+	cstate->attribute_buf.data[fld_size] = '\0';
+
+	/* Call the column type's binary input converter */
+	result = ReceiveFunctionCall(flinfo, &cstate->attribute_buf,
+								 typioparam, typmod);
+
+	/* Trouble if it didn't eat the whole buffer */
+	if (cstate->attribute_buf.cursor != cstate->attribute_buf.len)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+				 errmsg("incorrect binary data format")));
+
+	*isnull = false;
+	return result;
+}
+
+/*
+ * GetLinePosition - return the line position that worker should pcdata->process.
  */
 static uint32
 GetLinePosition(CopyState cstate)
@@ -1663,7 +2173,9 @@ GetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
 		{
 			dataBlkPtr->curr_blk_completed = false;
 			dataBlkPtr->skip_bytes = 0;
+			dataBlkPtr->following_block = -1;
 			pcshared_info->cur_block_pos = block_pos;
+			MemSet(&dataBlkPtr->data[0], 0, DATA_BLOCK_SIZE);
 			return block_pos;
 		}
 
@@ -5313,60 +5825,47 @@ NextCopyFrom(CopyState cstate, ExprContext *econtext,
 	else
 	{
 		/* binary */
-		int16		fld_count;
-		ListCell   *cur;
-
-		cstate->cur_lineno++;
-
-		if (!CopyGetInt16(cstate, &fld_count))
+		if (!IsParallelCopy())
 		{
-			/* EOF detected (end of file, or protocol-level EOF) */
-			return false;
-		}
+			int16		fld_count;
+			ListCell   *cur;
 
-		if (fld_count == -1)
-		{
-			/*
-			 * Received EOF marker.  In a V3-protocol copy, wait for the
-			 * protocol-level EOF, and complain if it doesn't come
-			 * immediately.  This ensures that we correctly handle CopyFail,
-			 * if client chooses to send that now.
-			 *
-			 * Note that we MUST NOT try to read more data in an old-protocol
-			 * copy, since there is no protocol-level EOF marker then.  We
-			 * could go either way for copy from file, but choose to throw
-			 * error if there's data after the EOF marker, for consistency
-			 * with the new-protocol case.
-			 */
-			char		dummy;
+			cstate->cur_lineno++;
+			cstate->max_fields = list_length(cstate->attnumlist);
 
-			if (cstate->copy_dest != COPY_OLD_FE &&
-				CopyGetData(cstate, &dummy, 1, 1) > 0)
-				ereport(ERROR,
-						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-						 errmsg("received copy data after EOF marker")));
-			return false;
-		}
+			if (!CopyGetInt16(cstate, &fld_count))
+			{
+				/* EOF detected (end of file, or protocol-level EOF) */
+				return false;
+			}
 
-		if (fld_count != attr_count)
-			ereport(ERROR,
-					(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-					 errmsg("row field count is %d, expected %d",
-							(int) fld_count, attr_count)));
+			CHECK_FIELD_COUNT;
 
-		foreach(cur, cstate->attnumlist)
+			foreach(cur, cstate->attnumlist)
+			{
+				int			attnum = lfirst_int(cur);
+				int			m = attnum - 1;
+				Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+
+				cstate->cur_attname = NameStr(att->attname);
+				values[m] = CopyReadBinaryAttribute(cstate,
+													&in_functions[m],
+													typioparams[m],
+													att->atttypmod,
+													&nulls[m]);
+				cstate->cur_attname = NULL;
+			}
+		}
+		else
 		{
-			int			attnum = lfirst_int(cur);
-			int			m = attnum - 1;
-			Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+			bool eof = false;
+			cstate->cur_lineno++;
+			cstate->max_fields = list_length(cstate->attnumlist);
 
-			cstate->cur_attname = NameStr(att->attname);
-			values[m] = CopyReadBinaryAttribute(cstate,
-												&in_functions[m],
-												typioparams[m],
-												att->atttypmod,
-												&nulls[m]);
-			cstate->cur_attname = NULL;
+			eof = CopyReadBinaryTupleWorker(cstate, values, nulls);
+
+			if (eof)
+				return false;
 		}
 	}
 
@@ -6366,18 +6865,15 @@ CopyReadBinaryAttribute(CopyState cstate, FmgrInfo *flinfo,
 	Datum		result;
 
 	if (!CopyGetInt32(cstate, &fld_size))
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("unexpected EOF in COPY data")));
+		EOF_ERROR;
+
 	if (fld_size == -1)
 	{
 		*isnull = true;
 		return ReceiveFunctionCall(flinfo, NULL, typioparam, typmod);
 	}
-	if (fld_size < 0)
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("invalid field size")));
+
+	CHECK_FIELD_SIZE(fld_size);
 
 	/* reset attribute_buf to empty, and load raw data in it */
 	resetStringInfo(&cstate->attribute_buf);
@@ -6385,9 +6881,7 @@ CopyReadBinaryAttribute(CopyState cstate, FmgrInfo *flinfo,
 	enlargeStringInfo(&cstate->attribute_buf, fld_size);
 	if (CopyGetData(cstate, cstate->attribute_buf.data,
 					fld_size, fld_size) != fld_size)
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("unexpected EOF in COPY data")));
+		EOF_ERROR;
 
 	cstate->attribute_buf.len = fld_size;
 	cstate->attribute_buf.data[fld_size] = '\0';
-- 
1.8.3.1

#118vignesh C
vignesh21@gmail.com
In reply to: Ashutosh Sharma (#115)
Re: Parallel copy

Thanks for reviewing and providing the comments Ashutosh.
Please find my thoughts below:

On Fri, Jul 17, 2020 at 7:18 PM Ashutosh Sharma <ashu.coek88@gmail.com>
wrote:

Some review comments (mostly) from the leader side code changes:

1) Do we need a DSM key for the FORCE_QUOTE option? I think FORCE_QUOTE

option is only used with COPY TO and not COPY FROM so not sure why you have
added it.

PARALLEL_COPY_KEY_FORCE_QUOTE_LIST

Fixed

2) Should we be allocating the parallel copy data structure only when it

is confirmed that the parallel copy is allowed?

pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
cstate->pcdata = pcdata;

Or, if you want it to be allocated before confirming if Parallel copy is

allowed or not, then I think it would be good to allocate it in
*cstate->copycontext* memory context so that when EndCopy is called towards
the end of the COPY FROM operation, the entire context itself gets deleted
thereby freeing the memory space allocated for pcdata. In fact it would be
good to ensure that all the local memory allocated inside the ctstate
structure gets allocated in the *cstate->copycontext* memory context.

Fixed

3) Should we allow Parallel Copy when the insert method is

CIM_MULTI_CONDITIONAL?

+   /* Check if the insertion mode is single. */
+   if (FindInsertMethod(cstate) == CIM_SINGLE)
+       return false;

I know we have added checks in CopyFrom() to ensure that if any trigger

(before row or instead of) is found on any of partition being loaded with
data, then COPY FROM operation would fail, but does it mean that we are
okay to perform parallel copy on partitioned table. Have we done some
performance testing with the partitioned table where the data in the input
file needs to be routed to the different partitions?

Partition data is handled like what Amit had told in one of earlier mails
[1]: /messages/by-id/CAA4eK1LQPxULxw8JpucX0PwzQQRk=q4jG32cU1us2+-mtzZUQg@mail.gmail.com
he will be sharing the results.

4) There are lot of if-checks in IsParallelCopyAllowed function that are

checked in CopyFrom function as well which means in case of Parallel Copy
those checks will get executed multiple times (first by the leader and from
second time onwards by each worker process). Is that required?

It is called from BeginParallelCopy, This will be called only once. This
change is ok.

5) Should the worker process be calling this function when the leader has

already called it once in ExecBeforeStmtTrigger()?

/* Verify the named relation is a valid target for INSERT */
CheckValidResultRel(resultRelInfo, CMD_INSERT);

Fixed.

6) I think it would be good to re-write the comments atop

ParallelCopyLeader(). From the present comments it appears as if you were
trying to put the information pointwise but somehow you ended up putting in
a paragraph. The comments also have some typos like *line beaks* which
possibly means line breaks. This is applicable for other comments as well
where you

Fixed.

7) Is the following checking equivalent to IsWorker()? If so, it would be

good to replace it with an IsWorker like macro to increase the readability.

(IsParallelCopy() && !IsLeader())

Fixed.

These have been fixed and the new patch is attached as part of my previous
mail.
[1]: /messages/by-id/CAA4eK1LQPxULxw8JpucX0PwzQQRk=q4jG32cU1us2+-mtzZUQg@mail.gmail.com
/messages/by-id/CAA4eK1LQPxULxw8JpucX0PwzQQRk=q4jG32cU1us2+-mtzZUQg@mail.gmail.com

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

#119Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: vignesh C (#118)
Re: Parallel copy

On Wed, Jul 22, 2020 at 7:56 PM vignesh C <vignesh21@gmail.com> wrote:

Thanks for reviewing and providing the comments Ashutosh.
Please find my thoughts below:

On Fri, Jul 17, 2020 at 7:18 PM Ashutosh Sharma <ashu.coek88@gmail.com>

wrote:

Some review comments (mostly) from the leader side code changes:

3) Should we allow Parallel Copy when the insert method is

CIM_MULTI_CONDITIONAL?

+   /* Check if the insertion mode is single. */
+   if (FindInsertMethod(cstate) == CIM_SINGLE)
+       return false;

I know we have added checks in CopyFrom() to ensure that if any trigger

(before row or instead of) is found on any of partition being loaded with
data, then COPY FROM operation would fail, but does it mean that we are
okay to perform parallel copy on partitioned table. Have we done some
performance testing with the partitioned table where the data in the input
file needs to be routed to the different partitions?

Partition data is handled like what Amit had told in one of earlier mails

[1]: . My colleague Bharath has run performance test with partition table, he will be sharing the results.
he will be sharing the results.

I ran tests for partitioned use cases - results are similar to that of non
partitioned cases[1]. My colleague Bharath has run performance test with partition table, he will be sharing the results..

parallel workers test case 1(exec time in sec): copy from csv file, 5.1GB,
10million tuples, 4 range partitions, 3 indexes on integer columns unique
data test case 2(exec time in sec): copy from csv file, 5.1GB, 10million
tuples, 4 range partitions, unique data
0 205.403(1X) 135(1X)
2 114.724(1.79X) 59.388(2.27X)
4 99.017(2.07X) 56.742(2.34X)
8 99.722(2.06X) 66.323(2.03X)
16 98.147(2.09X) 66.054(2.04X)
20 97.723(2.1X) 66.389(2.03X)
30 97.048(2.11X) 70.568(1.91X)

With Regards,
Bharath Rupireddy.
EnterpriseDB: http://www.enterprisedb.com

#120Amit Kapila
amit.kapila16@gmail.com
In reply to: Bharath Rupireddy (#119)
Re: Parallel copy

On Thu, Jul 23, 2020 at 8:51 AM Bharath Rupireddy <
bharath.rupireddyforpostgres@gmail.com> wrote:

On Wed, Jul 22, 2020 at 7:56 PM vignesh C <vignesh21@gmail.com> wrote:

Thanks for reviewing and providing the comments Ashutosh.
Please find my thoughts below:

On Fri, Jul 17, 2020 at 7:18 PM Ashutosh Sharma <ashu.coek88@gmail.com>

wrote:

Some review comments (mostly) from the leader side code changes:

3) Should we allow Parallel Copy when the insert method is

CIM_MULTI_CONDITIONAL?

+   /* Check if the insertion mode is single. */
+   if (FindInsertMethod(cstate) == CIM_SINGLE)
+       return false;

I know we have added checks in CopyFrom() to ensure that if any

trigger (before row or instead of) is found on any of partition being
loaded with data, then COPY FROM operation would fail, but does it mean
that we are okay to perform parallel copy on partitioned table. Have we
done some performance testing with the partitioned table where the data in
the input file needs to be routed to the different partitions?

Partition data is handled like what Amit had told in one of earlier

mails [1]. My colleague Bharath has run performance test with partition
table, he will be sharing the results.

I ran tests for partitioned use cases - results are similar to that of non
partitioned cases[1].

I could see the gain up to 10-11 times for non-partitioned cases [1]/messages/by-id/CALj2ACVR4WE98Per1H7ajosW8vafN16548O2UV8bG3p4D3XnPg@mail.gmail.com, can
we use similar test case here as well (with one of the indexes on text
column or having gist index) to see its impact?

[1]: /messages/by-id/CALj2ACVR4WE98Per1H7ajosW8vafN16548O2UV8bG3p4D3XnPg@mail.gmail.com
/messages/by-id/CALj2ACVR4WE98Per1H7ajosW8vafN16548O2UV8bG3p4D3XnPg@mail.gmail.com

--
With Regards,
Amit Kapila.
EnterpriseDB: http://www.enterprisedb.com

#121Ashutosh Sharma
ashu.coek88@gmail.com
In reply to: Bharath Rupireddy (#119)
Re: Parallel copy

I think, when doing the performance testing for partitioned table, it would
be good to also mention about the distribution of data in the input file.
One possible data distribution could be that we have let's say 100 tuples
in the input file, and every consecutive tuple belongs to a different
partition.

On Thu, Jul 23, 2020 at 8:51 AM Bharath Rupireddy <
bharath.rupireddyforpostgres@gmail.com> wrote:

Show quoted text

On Wed, Jul 22, 2020 at 7:56 PM vignesh C <vignesh21@gmail.com> wrote:

Thanks for reviewing and providing the comments Ashutosh.
Please find my thoughts below:

On Fri, Jul 17, 2020 at 7:18 PM Ashutosh Sharma <ashu.coek88@gmail.com>

wrote:

Some review comments (mostly) from the leader side code changes:

3) Should we allow Parallel Copy when the insert method is

CIM_MULTI_CONDITIONAL?

+   /* Check if the insertion mode is single. */
+   if (FindInsertMethod(cstate) == CIM_SINGLE)
+       return false;

I know we have added checks in CopyFrom() to ensure that if any

trigger (before row or instead of) is found on any of partition being
loaded with data, then COPY FROM operation would fail, but does it mean
that we are okay to perform parallel copy on partitioned table. Have we
done some performance testing with the partitioned table where the data in
the input file needs to be routed to the different partitions?

Partition data is handled like what Amit had told in one of earlier

mails [1]. My colleague Bharath has run performance test with partition
table, he will be sharing the results.

I ran tests for partitioned use cases - results are similar to that of non
partitioned cases[1].

parallel workers test case 1(exec time in sec): copy from csv file,
5.1GB, 10million tuples, 4 range partitions, 3 indexes on integer columns
unique data test case 2(exec time in sec): copy from csv file, 5.1GB,
10million tuples, 4 range partitions, unique data
0 205.403(1X) 135(1X)
2 114.724(1.79X) 59.388(2.27X)
4 99.017(2.07X) 56.742(2.34X)
8 99.722(2.06X) 66.323(2.03X)
16 98.147(2.09X) 66.054(2.04X)
20 97.723(2.1X) 66.389(2.03X)
30 97.048(2.11X) 70.568(1.91X)

With Regards,
Bharath Rupireddy.
EnterpriseDB: http://www.enterprisedb.com

#122Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Amit Kapila (#120)
Re: Parallel copy

On Thu, Jul 23, 2020 at 9:22 AM Amit Kapila <amit.kapila16@gmail.com> wrote:

I ran tests for partitioned use cases - results are similar to that of

non partitioned cases[1].

I could see the gain up to 10-11 times for non-partitioned cases [1], can

we use similar test case here as well (with one of the indexes on text
column or having gist index) to see its impact?

[1] -

/messages/by-id/CALj2ACVR4WE98Per1H7ajosW8vafN16548O2UV8bG3p4D3XnPg@mail.gmail.com

Thanks Amit! Please find the results of detailed testing done for
partitioned use cases:

Range Partitions: consecutive rows go into the same partitions.
parallel workers test case 1(exec time in sec): copy from csv file, 2
indexes on integer columns and 1 index on text column, 4 range partitions test
case 2(exec time in sec): copy from csv file, 1 gist index on text column,
4 range partitions test case 3(exec time in sec): copy from csv file, 3
indexes on integer columns, 4 range partitions
0 1051.924(1X) 785.052(1X) 205.403(1X)
2 589.576(1.78X) 421.974(1.86X) 114.724(1.79X)
4 321.960(3.27X) 230.997(3.4X) 99.017(2.07X)
8 199.245(5.23X) *156.132(5.02X)* 99.722(2.06X)
16 127.343(8.26X) 173.696(4.52X) 98.147(2.09X)
20 *122.029(8.62X)* 186.418(4.21X) 97.723(2.1X)
30 142.876(7.36X) 214.598(3.66X) *97.048(2.11X)*

On Thu, Jul 23, 2020 at 10:21 AM Ashutosh Sharma <ashu.coek88@gmail.com>
wrote:

I think, when doing the performance testing for partitioned table, it

would be good to also mention about the distribution of data in the input
file. One possible data distribution could be that we have let's say 100
tuples in the input file, and every consecutive tuple belongs to a
different partition.

To address Ashutosh's point, I used hash partitioning. Hope this helps to
clear the doubt.

Hash Partitions: where there are high chances that consecutive rows may go
into different partitions.
parallel workers test case 1(exec time in sec): copy from csv file, 2
indexes on integer columns and 1 index on text column, 4 hash partitions test
case 2(exec time in sec): copy from csv file, 1 gist index on text column,
4 hash partitions test case 3(exec time in sec): copy from csv file, 3
indexes on integer columns, 4 hash partitions
0 1060.884(1X) 812.283(1X) 207.745(1X)
2 572.542(1.85X) 418.454(1.94X) 107.850(1.93X)
4 298.132(3.56X) 227.367(3.57X) *83.895(2.48X)*
8 169.449(6.26X) 137.993(5.89X) 85.411(2.43X)
16 112.297(9.45X) 95.167(8.53X) 96.136(2.16X)
20 *101.546(10.45X)* *90.552(8.97X)* 97.066(2.14X)
30 113.877(9.32X) 127.17(6.38X) 96.819(2.14X)

With Regards,
Bharath Rupireddy.
EnterpriseDB: http://www.enterprisedb.com

#123vignesh C
vignesh21@gmail.com
In reply to: Bharath Rupireddy (#122)
5 attachment(s)
Re: Parallel copy

The patches were not applying because of the recent commits.
I have rebased the patch over head & attached.

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

On Thu, Jul 23, 2020 at 6:07 PM Bharath Rupireddy <
bharath.rupireddyforpostgres@gmail.com> wrote:

Show quoted text

On Thu, Jul 23, 2020 at 9:22 AM Amit Kapila <amit.kapila16@gmail.com>
wrote:

I ran tests for partitioned use cases - results are similar to that of

non partitioned cases[1].

I could see the gain up to 10-11 times for non-partitioned cases [1],

can we use similar test case here as well (with one of the indexes on text
column or having gist index) to see its impact?

[1] -

/messages/by-id/CALj2ACVR4WE98Per1H7ajosW8vafN16548O2UV8bG3p4D3XnPg@mail.gmail.com

Thanks Amit! Please find the results of detailed testing done for
partitioned use cases:

Range Partitions: consecutive rows go into the same partitions.
parallel workers test case 1(exec time in sec): copy from csv file, 2
indexes on integer columns and 1 index on text column, 4 range partitions test
case 2(exec time in sec): copy from csv file, 1 gist index on text column,
4 range partitions test case 3(exec time in sec): copy from csv file, 3
indexes on integer columns, 4 range partitions
0 1051.924(1X) 785.052(1X) 205.403(1X)
2 589.576(1.78X) 421.974(1.86X) 114.724(1.79X)
4 321.960(3.27X) 230.997(3.4X) 99.017(2.07X)
8 199.245(5.23X) *156.132(5.02X)* 99.722(2.06X)
16 127.343(8.26X) 173.696(4.52X) 98.147(2.09X)
20 *122.029(8.62X)* 186.418(4.21X) 97.723(2.1X)
30 142.876(7.36X) 214.598(3.66X) *97.048(2.11X)*

On Thu, Jul 23, 2020 at 10:21 AM Ashutosh Sharma <ashu.coek88@gmail.com>
wrote:

I think, when doing the performance testing for partitioned table, it

would be good to also mention about the distribution of data in the input
file. One possible data distribution could be that we have let's say 100
tuples in the input file, and every consecutive tuple belongs to a
different partition.

To address Ashutosh's point, I used hash partitioning. Hope this helps to
clear the doubt.

Hash Partitions: where there are high chances that consecutive rows may go
into different partitions.
parallel workers test case 1(exec time in sec): copy from csv file, 2
indexes on integer columns and 1 index on text column, 4 hash partitions test
case 2(exec time in sec): copy from csv file, 1 gist index on text column,
4 hash partitions test case 3(exec time in sec): copy from csv file, 3
indexes on integer columns, 4 hash partitions
0 1060.884(1X) 812.283(1X) 207.745(1X)
2 572.542(1.85X) 418.454(1.94X) 107.850(1.93X)
4 298.132(3.56X) 227.367(3.57X) *83.895(2.48X)*
8 169.449(6.26X) 137.993(5.89X) 85.411(2.43X)
16 112.297(9.45X) 95.167(8.53X) 96.136(2.16X)
20 *101.546(10.45X)* *90.552(8.97X)* 97.066(2.14X)
30 113.877(9.32X) 127.17(6.38X) 96.819(2.14X)

With Regards,
Bharath Rupireddy.
EnterpriseDB: http://www.enterprisedb.com

Attachments:

v2-0001-Copy-code-readjustment-to-support-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=v2-0001-Copy-code-readjustment-to-support-parallel-copy.patchDownload
From f2ba043af005c55961ed68c9a595cee58c46c79d Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Sat, 1 Aug 2020 08:52:48 +0530
Subject: [PATCH v2 1/5] Copy code readjustment to support parallel copy.

This patch has the copy code slightly readjusted so that the common code is
separated to functions/macros, these functions/macros will be used by the
workers in the parallel copy code of the upcoming patches. EOL removal is moved
from CopyReadLine to CopyReadLineText, this change was required because in case
of parallel copy the record identification and record updation is done in
CopyReadLineText, before record information is updated in shared memory the new
line characters should be removed.
---
 src/backend/commands/copy.c | 361 ++++++++++++++++++++++++++------------------
 1 file changed, 218 insertions(+), 143 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index db7d24a..3efafca 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -95,6 +95,9 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
+#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+#define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
+
 /*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
@@ -224,7 +227,6 @@ typedef struct CopyStateData
 	 * appropriate amounts of data from this buffer.  In both modes, we
 	 * guarantee that there is a \0 at raw_buf[raw_buf_len].
 	 */
-#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
@@ -354,6 +356,27 @@ if (1) \
 	goto not_end_of_copy; \
 } else ((void) 0)
 
+/*
+ * CLEAR_EOL_LINE - Wrapper for clearing EOL.
+ */
+#define CLEAR_EOL_LINE() \
+if (!result && !IsHeaderLine()) \
+	ClearEOLFromCopiedData(cstate, cstate->line_buf.data, \
+						   cstate->line_buf.len, \
+						   &cstate->line_buf.len) \
+
+/*
+ * INCREMENTPROCESSED - Increment the lines processed.
+ */
+#define INCREMENTPROCESSED(processed)  \
+processed++;
+
+/*
+ * GETPROCESSED - Get the lines processed.
+ */
+#define GETPROCESSED(processed) \
+return processed;
+
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
 
@@ -401,7 +424,11 @@ static bool CopyGetInt16(CopyState cstate, int16 *val);
 static bool CopyLoadRawBuf(CopyState cstate);
 static int	CopyReadBinaryData(CopyState cstate, char *dest, int nbytes);
 
-
+static void PopulateCommonCstateInfo(CopyState cstate, TupleDesc	tup_desc,
+									   List *attnamelist);
+static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
+								   int copy_line_pos, int *copy_line_size);
+static void ConvertToServerEncoding(CopyState cstate);
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
  * in past protocol redesigns.
@@ -801,14 +828,18 @@ CopyLoadRawBuf(CopyState cstate)
 {
 	int			nbytes = RAW_BUF_BYTES(cstate);
 	int			inbytes;
+	int         minread = 1;
 
 	/* Copy down the unprocessed data if any. */
 	if (nbytes > 0)
 		memmove(cstate->raw_buf, cstate->raw_buf + cstate->raw_buf_index,
 				nbytes);
 
+	if (cstate->copy_dest == COPY_NEW_FE)
+		minread = RAW_BUF_SIZE - nbytes;
+
 	inbytes = CopyGetData(cstate, cstate->raw_buf + nbytes,
-						  1, RAW_BUF_SIZE - nbytes);
+						  minread, RAW_BUF_SIZE - nbytes);
 	nbytes += inbytes;
 	cstate->raw_buf[nbytes] = '\0';
 	cstate->raw_buf_index = 0;
@@ -1514,7 +1545,6 @@ BeginCopy(ParseState *pstate,
 {
 	CopyState	cstate;
 	TupleDesc	tupDesc;
-	int			num_phys_attrs;
 	MemoryContext oldcontext;
 
 	/* Allocate workspace and zero all fields */
@@ -1680,6 +1710,24 @@ BeginCopy(ParseState *pstate,
 		tupDesc = cstate->queryDesc->tupDesc;
 	}
 
+	PopulateCommonCstateInfo(cstate, tupDesc, attnamelist);
+	cstate->copy_dest = COPY_FILE;	/* default */
+
+	MemoryContextSwitchTo(oldcontext);
+
+	return cstate;
+}
+
+/*
+ * PopulateCommonCstateInfo - Populates the common variables required for copy
+ * from operation. This is a helper function for BeginCopy function.
+ */
+static void
+PopulateCommonCstateInfo(CopyState cstate, TupleDesc	tupDesc,
+							List *attnamelist)
+{
+	int			num_phys_attrs;
+
 	/* Generate or convert list of attributes to process */
 	cstate->attnumlist = CopyGetAttnums(tupDesc, cstate->rel, attnamelist);
 
@@ -1799,12 +1847,6 @@ BeginCopy(ParseState *pstate,
 		 pg_database_encoding_max_length() > 1);
 	/* See Multibyte encoding comment above */
 	cstate->encoding_embeds_ascii = PG_ENCODING_IS_CLIENT_ONLY(cstate->file_encoding);
-
-	cstate->copy_dest = COPY_FILE;	/* default */
-
-	MemoryContextSwitchTo(oldcontext);
-
-	return cstate;
 }
 
 /*
@@ -2696,32 +2738,11 @@ CopyMultiInsertInfoStore(CopyMultiInsertInfo *miinfo, ResultRelInfo *rri,
 }
 
 /*
- * Copy FROM file to relation.
+ * Check if the relation specified in copy from is valid.
  */
-uint64
-CopyFrom(CopyState cstate)
+static void
+CheckTargetRelValidity(CopyState cstate)
 {
-	ResultRelInfo *resultRelInfo;
-	ResultRelInfo *target_resultRelInfo;
-	ResultRelInfo *prevResultRelInfo = NULL;
-	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
-	ModifyTableState *mtstate;
-	ExprContext *econtext;
-	TupleTableSlot *singleslot = NULL;
-	MemoryContext oldcontext = CurrentMemoryContext;
-
-	PartitionTupleRouting *proute = NULL;
-	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
-	int			ti_options = 0; /* start with default options for insert */
-	BulkInsertState bistate = NULL;
-	CopyInsertMethod insertMethod;
-	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
-	uint64		processed = 0;
-	bool		has_before_insert_row_trig;
-	bool		has_instead_insert_row_trig;
-	bool		leafpart_use_multi_insert = false;
-
 	Assert(cstate->rel);
 
 	/*
@@ -2758,27 +2779,6 @@ CopyFrom(CopyState cstate)
 							RelationGetRelationName(cstate->rel))));
 	}
 
-	/*
-	 * If the target file is new-in-transaction, we assume that checking FSM
-	 * for free space is a waste of time.  This could possibly be wrong, but
-	 * it's unlikely.
-	 */
-	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
-		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
-		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
-		ti_options |= TABLE_INSERT_SKIP_FSM;
-
-	/*
-	 * Optimize if new relfilenode was created in this subxact or one of its
-	 * committed children and we won't see those rows later as part of an
-	 * earlier scan or command. The subxact test ensures that if this subxact
-	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
-	 * that the stronger test of exactly which subtransaction created it is
-	 * crucial for correctness of this optimization. The test for an earlier
-	 * scan or command tolerates false negatives. FREEZE causes other sessions
-	 * to see rows they would not see under MVCC, and a false negative merely
-	 * spreads that anomaly to the current session.
-	 */
 	if (cstate->freeze)
 	{
 		/*
@@ -2816,9 +2816,61 @@ CopyFrom(CopyState cstate)
 			ereport(ERROR,
 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 					 errmsg("cannot perform COPY FREEZE because the table was not created or truncated in the current subtransaction")));
+	}
+}
+
+/*
+ * Copy FROM file to relation.
+ */
+uint64
+CopyFrom(CopyState cstate)
+{
+	ResultRelInfo *resultRelInfo;
+	ResultRelInfo *target_resultRelInfo;
+	ResultRelInfo *prevResultRelInfo = NULL;
+	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
+	ModifyTableState *mtstate;
+	ExprContext *econtext;
+	TupleTableSlot *singleslot = NULL;
+	MemoryContext oldcontext = CurrentMemoryContext;
+
+	PartitionTupleRouting *proute = NULL;
+	ErrorContextCallback errcallback;
+	CommandId	mycid = GetCurrentCommandId(true);
+	int			ti_options = 0; /* start with default options for insert */
+	BulkInsertState bistate = NULL;
+	CopyInsertMethod insertMethod;
+	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
+	uint64		processed = 0;
+	bool		has_before_insert_row_trig;
+	bool		has_instead_insert_row_trig;
+	bool		leafpart_use_multi_insert = false;
+
+	CheckTargetRelValidity(cstate);
 
+	/*
+	 * If the target file is new-in-transaction, we assume that checking FSM
+	 * for free space is a waste of time.  This could possibly be wrong, but
+	 * it's unlikely.
+	 */
+	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
+		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
+		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
+		ti_options |= TABLE_INSERT_SKIP_FSM;
+
+	/*
+	 * Optimize if new relfilenode was created in this subxact or one of its
+	 * committed children and we won't see those rows later as part of an
+	 * earlier scan or command. The subxact test ensures that if this subxact
+	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
+	 * that the stronger test of exactly which subtransaction created it is
+	 * crucial for correctness of this optimization. The test for an earlier
+	 * scan or command tolerates false negatives. FREEZE causes other sessions
+	 * to see rows they would not see under MVCC, and a false negative merely
+	 * spreads that anomaly to the current session.
+	 */
+	if (cstate->freeze)
 		ti_options |= TABLE_INSERT_FROZEN;
-	}
 
 	/*
 	 * We need a ResultRelInfo so we can use the regular executor's
@@ -3311,7 +3363,7 @@ CopyFrom(CopyState cstate)
 			 * or FDW; this is the same definition used by nodeModifyTable.c
 			 * for counting tuples inserted by an INSERT command.
 			 */
-			processed++;
+			INCREMENTPROCESSED(processed)
 		}
 	}
 
@@ -3366,30 +3418,15 @@ CopyFrom(CopyState cstate)
 
 	FreeExecutorState(estate);
 
-	return processed;
+	GETPROCESSED(processed)
 }
 
 /*
- * Setup to read tuples from a file for COPY FROM.
- *
- * 'rel': Used as a template for the tuples
- * 'filename': Name of server-local file to read
- * 'attnamelist': List of char *, columns to include. NIL selects all cols.
- * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
- *
- * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ * PopulateCstateCatalogInfo - populate the catalog information.
  */
-CopyState
-BeginCopyFrom(ParseState *pstate,
-			  Relation rel,
-			  const char *filename,
-			  bool is_program,
-			  copy_data_source_cb data_source_cb,
-			  List *attnamelist,
-			  List *options)
+static void
+PopulateCstateCatalogInfo(CopyState cstate)
 {
-	CopyState	cstate;
-	bool		pipe = (filename == NULL);
 	TupleDesc	tupDesc;
 	AttrNumber	num_phys_attrs,
 				num_defaults;
@@ -3399,38 +3436,8 @@ BeginCopyFrom(ParseState *pstate,
 	Oid			in_func_oid;
 	int		   *defmap;
 	ExprState **defexprs;
-	MemoryContext oldcontext;
 	bool		volatile_defexprs;
 
-	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
-	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
-
-	/* Initialize state variables */
-	cstate->reached_eof = false;
-	cstate->eol_type = EOL_UNKNOWN;
-	cstate->cur_relname = RelationGetRelationName(cstate->rel);
-	cstate->cur_lineno = 0;
-	cstate->cur_attname = NULL;
-	cstate->cur_attval = NULL;
-
-	/*
-	 * Set up variables to avoid per-attribute overhead.  attribute_buf and
-	 * raw_buf are used in both text and binary modes, but we use line_buf
-	 * only in text mode.
-	 */
-	initStringInfo(&cstate->attribute_buf);
-	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
-	cstate->raw_buf_index = cstate->raw_buf_len = 0;
-	if (!cstate->binary)
-	{
-		initStringInfo(&cstate->line_buf);
-		cstate->line_buf_converted = false;
-	}
-
-	/* Assign range table, we'll need it in CopyFrom. */
-	if (pstate)
-		cstate->range_table = pstate->p_rtable;
-
 	tupDesc = RelationGetDescr(cstate->rel);
 	num_phys_attrs = tupDesc->natts;
 	num_defaults = 0;
@@ -3508,6 +3515,61 @@ BeginCopyFrom(ParseState *pstate,
 	cstate->defexprs = defexprs;
 	cstate->volatile_defexprs = volatile_defexprs;
 	cstate->num_defaults = num_defaults;
+}
+
+/*
+ * Setup to read tuples from a file for COPY FROM.
+ *
+ * 'rel': Used as a template for the tuples
+ * 'filename': Name of server-local file to read
+ * 'attnamelist': List of char *, columns to include. NIL selects all cols.
+ * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
+ *
+ * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ */
+CopyState
+BeginCopyFrom(ParseState *pstate,
+			  Relation rel,
+			  const char *filename,
+			  bool is_program,
+			  copy_data_source_cb data_source_cb,
+			  List *attnamelist,
+			  List *options)
+{
+	CopyState	cstate;
+	bool		pipe = (filename == NULL);
+	MemoryContext oldcontext;
+
+	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	/* Initialize state variables */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/*
+	 * Set up variables to avoid per-attribute overhead.  attribute_buf is
+	 * used in both text and binary modes, but we use line_buf and raw_buf
+	 * only in text mode.
+	 */
+	initStringInfo(&cstate->attribute_buf);
+	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+	if (!cstate->binary)
+	{
+		initStringInfo(&cstate->line_buf);
+		cstate->line_buf_converted = false;
+	}
+
+	/* Assign range table, we'll need it in CopyFrom. */
+	if (pstate)
+		cstate->range_table = pstate->p_rtable;
+
+	PopulateCstateCatalogInfo(cstate);
 	cstate->is_program = is_program;
 
 	if (data_source_cb)
@@ -3917,45 +3979,60 @@ CopyReadLine(CopyState cstate)
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
-	else
-	{
-		/*
-		 * If we didn't hit EOF, then we must have transferred the EOL marker
-		 * to line_buf along with the data.  Get rid of it.
-		 */
-		switch (cstate->eol_type)
-		{
-			case EOL_NL:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CR:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\r');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CRNL:
-				Assert(cstate->line_buf.len >= 2);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 2] == '\r');
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len -= 2;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_UNKNOWN:
-				/* shouldn't get here */
-				Assert(false);
-				break;
-		}
-	}
 
+	ConvertToServerEncoding(cstate);
+	return result;
+}
+
+/*
+ * ClearEOLFromCopiedData - Clear EOL from the copied data.
+ */
+static void
+ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
+					   int copy_line_pos, int *copy_line_size)
+{
+	/*
+	 * If we didn't hit EOF, then we must have transferred the EOL marker
+	 * to line_buf along with the data.  Get rid of it.
+	 */
+   switch (cstate->eol_type)
+   {
+	   case EOL_NL:
+		   Assert(*copy_line_size >= 1);
+		   Assert(copy_line_data[copy_line_pos - 1] == '\n');
+		   copy_line_data[copy_line_pos - 1] = '\0';
+		   (*copy_line_size)--;
+		   break;
+	   case EOL_CR:
+		   Assert(*copy_line_size >= 1);
+		   Assert(copy_line_data[copy_line_pos - 1] == '\r');
+		   copy_line_data[copy_line_pos - 1] = '\0';
+		   (*copy_line_size)--;
+		   break;
+	   case EOL_CRNL:
+		   Assert(*copy_line_size >= 2);
+		   Assert(copy_line_data[copy_line_pos - 2] == '\r');
+		   Assert(copy_line_data[copy_line_pos - 1] == '\n');
+		   copy_line_data[copy_line_pos - 2] = '\0';
+		   *copy_line_size -= 2;
+		   break;
+	   case EOL_UNKNOWN:
+		   /* shouldn't get here */
+		   Assert(false);
+		   break;
+   }
+}
+
+/*
+ * ConvertToServerEncoding - convert contents to server encoding.
+ */
+static void
+ConvertToServerEncoding(CopyState cstate)
+{
 	/* Done reading the line.  Convert it to server encoding. */
 	if (cstate->need_transcoding)
 	{
 		char	   *cvt;
-
 		cvt = pg_any_to_server(cstate->line_buf.data,
 							   cstate->line_buf.len,
 							   cstate->file_encoding);
@@ -3967,11 +4044,8 @@ CopyReadLine(CopyState cstate)
 			pfree(cvt);
 		}
 	}
-
 	/* Now it's safe to use the buffer in error messages */
 	cstate->line_buf_converted = true;
-
-	return result;
 }
 
 /*
@@ -4334,6 +4408,7 @@ not_end_of_copy:
 	 * Transfer any still-uncopied data to line_buf.
 	 */
 	REFILL_LINEBUF;
+	CLEAR_EOL_LINE();
 
 	return result;
 }
-- 
1.8.3.1

v2-0002-Framework-for-leader-worker-in-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=v2-0002-Framework-for-leader-worker-in-parallel-copy.patchDownload
From 1bf7d74c7308e6eae807c0258322abbb3890aede Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Sat, 1 Aug 2020 08:56:39 +0530
Subject: [PATCH v2 2/5] Framework for leader/worker in parallel copy

This patch has the framework for data structures in parallel copy, leader
initialization, worker initialization, shared memory updation, starting workers,
wait for workers and workers exiting.
---
 src/backend/access/transam/parallel.c |   4 +
 src/backend/commands/copy.c           | 756 +++++++++++++++++++++++++++++++++-
 src/include/commands/copy.h           |   2 +
 src/tools/pgindent/typedefs.list      |   7 +
 4 files changed, 765 insertions(+), 4 deletions(-)

diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index b042696..a3cff4b 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -25,6 +25,7 @@
 #include "catalog/pg_enum.h"
 #include "catalog/storage.h"
 #include "commands/async.h"
+#include "commands/copy.h"
 #include "executor/execParallel.h"
 #include "libpq/libpq.h"
 #include "libpq/pqformat.h"
@@ -145,6 +146,9 @@ static const struct
 	},
 	{
 		"parallel_vacuum_main", parallel_vacuum_main
+	},
+	{
+		"ParallelCopyMain", ParallelCopyMain
 	}
 };
 
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 3efafca..3dcdfc1 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -96,9 +96,180 @@ typedef enum CopyInsertMethod
 } CopyInsertMethod;
 
 #define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+
+/*
+ * The macros DATA_BLOCK_SIZE, RINGSIZE & MAX_BLOCKS_COUNT stores the records
+ * read from the file that need to be inserted into the relation. These values
+ * help in handover of multiple records with significant size of data to be
+ * processed by each of the workers to make sure there is no context switch & the
+ * work is fairly distributed among the workers. This number showed best
+ * results in the performance tests.
+ */
+#define DATA_BLOCK_SIZE RAW_BUF_SIZE
+
+/* It can hold upto 10000 record information for worker to process. */
+#define RINGSIZE (10 * 1000)
+
+/* It can hold 1000 blocks of 64K data in DSM to be processed by the worker. */
+#define MAX_BLOCKS_COUNT 1000
+
+/*
+ * Each worker will be allocated WORKER_CHUNK_COUNT of records from DSM data
+ * block to process to avoid lock contention. This value should be mode of
+ * RINGSIZE, as wrap around cases is currently not handled while selecting the
+ * WORKER_CHUNK_COUNT by the worker.
+ */
+#define WORKER_CHUNK_COUNT 50
+
+#define	IsParallelCopy()		(cstate->is_parallel)
+#define IsLeader()				(cstate->pcdata->is_leader)
 #define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
 
 /*
+ * Copy data block information.
+ * ParallelCopyDataBlock's will be created in DSM. Data read from file will be
+ * copied in these DSM data blocks. The leader process identifies the records
+ * and the record information will be shared to the workers. The workers will
+ * insert the records into the table. There can be one or more number of records
+ * in each of the data block based on the record size.
+ */
+typedef struct ParallelCopyDataBlock
+{
+	/* The number of unprocessed lines in the current block. */
+	pg_atomic_uint32 unprocessed_line_parts;
+
+	/*
+	 * If the current line data is continued into another block, following_block
+	 * will have the position where the remaining data need to be read.
+	 */
+	uint32	following_block;
+
+	/*
+	 * This flag will be set, when the leader finds out this block can be read
+	 * safely by the worker. This helps the worker to start processing the line
+	 * early where the line will be spread across many blocks and the worker
+	 * need not wait for the complete line to be processed.
+	 */
+	bool   curr_blk_completed;
+	char   data[DATA_BLOCK_SIZE]; /* data read from file */
+	uint8  skip_bytes;
+}ParallelCopyDataBlock;
+
+/*
+ * Individual line information.
+ * ParallelCopyLineBoundary is common data structure between leader & worker,
+ * Leader process will be populating data block, data block offset & the size of
+ * the record in DSM for the workers to copy the data into the relation.
+ * This is protected by the following sequence in the leader & worker. If they
+ * don't follow this order the worker might process wrong line_size and leader
+ * might populate the information which worker has not yet processed or in the
+ * process of processing.
+ * Leader should operate in the following order:
+ * 1) check if line_size is -1, if not wait, it means worker is still
+ * processing.
+ * 2) set line_state to LINE_LEADER_POPULATING.
+ * 3) update first_block, start_offset & cur_lineno in any order.
+ * 4) update line_size.
+ * 5) update line_state to LINE_LEADER_POPULATED.
+ * Worker should operate in the following order:
+ * 1) check line_state is LINE_LEADER_POPULATED, if not it means leader is still
+ * populating the data.
+ * 2) read line_size.
+ * 3) only one worker should choose one line for processing, this is handled by
+ *    using pg_atomic_compare_exchange_u32, worker will change the sate to
+ *    LINE_WORKER_PROCESSING only if line_state is LINE_LEADER_POPULATED.
+ * 4) read first_block, start_offset & cur_lineno in any order.
+ * 5) process line_size data.
+ * 6) update line_size to -1.
+ */
+typedef struct ParallelCopyLineBoundary
+{
+	/* Position of the first block in data_blocks array. */
+	uint32				first_block;
+	uint32				start_offset;   /* start offset of the line */
+
+	/*
+	 * Size of the current line -1 means line is yet to be filled completely,
+	 * 0 means empty line, >0 means line filled with line size data.
+	 */
+	pg_atomic_uint32	line_size;
+	pg_atomic_uint32	line_state;		/* line state */
+	uint64				cur_lineno;		/* line number for error messages */
+}ParallelCopyLineBoundary;
+
+/*
+ * Circular queue used to store the line information.
+ */
+typedef struct ParallelCopyLineBoundaries
+{
+	/* Position for the leader to populate a line. */
+	uint32			pos;
+
+	/* Data read from the file/stdin by the leader process. */
+	ParallelCopyLineBoundary	ring[RINGSIZE];
+}ParallelCopyLineBoundaries;
+
+/*
+ * Shared information among parallel copy workers. This will be allocated in the
+ * DSM segment.
+ */
+typedef struct ParallelCopyShmInfo
+{
+	bool					is_read_in_progress; /* file read status */
+
+	/*
+	 * Actual lines inserted by worker, will not be same as
+	 * total_worker_processed if where condition is specified along with copy.
+	 * This will be the actual records inserted into the relation.
+	 */
+	pg_atomic_uint64			processed;
+
+	/*
+	 * The number of records currently processed by the worker, this will also
+	 * include the number of records that was filtered because of where clause.
+	 */
+	pg_atomic_uint64			total_worker_processed;
+	uint64						populated; /* lines populated by leader */
+	uint32						cur_block_pos; /* current data block */
+	ParallelCopyDataBlock		data_blocks[MAX_BLOCKS_COUNT]; /* data block array */
+	FullTransactionId			full_transaction_id; /* xid for copy from statement */
+	CommandId					mycid;	/* command id */
+	ParallelCopyLineBoundaries	line_boundaries; /* line array */
+} ParallelCopyShmInfo;
+
+/*
+ * Parallel copy line buffer information.
+ */
+typedef struct ParallelCopyLineBuf
+{
+	StringInfoData		line_buf;
+	uint64				cur_lineno;	/* line number for error messages */
+}ParallelCopyLineBuf;
+
+/*
+ * Parallel copy data information.
+ */
+typedef struct ParallelCopyData
+{
+	Oid					relid;				/* relation id of the table */
+	ParallelCopyShmInfo	*pcshared_info;		/* common info in shared memory */
+	bool				is_leader;
+
+	/* line position which worker is processing */
+	uint32				worker_processed_pos;
+
+	/*
+	 * Local line_buf array, workers will copy it here and release the lines
+	 * for the leader to continue.
+	 */
+	ParallelCopyLineBuf	worker_line_buf[WORKER_CHUNK_COUNT];
+	uint32				worker_line_buf_count; /* Number of lines */
+
+	/* Current position in worker_line_buf */
+	uint32				worker_line_buf_pos;
+}ParallelCopyData;
+
+/*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
  * even though some fields are used in only some cases.
@@ -230,10 +401,38 @@ typedef struct CopyStateData
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
+	int			nworkers;
+	bool		is_parallel;
+	ParallelCopyData *pcdata;
 	/* Shorthand for number of unconsumed bytes available in raw_buf */
 #define RAW_BUF_BYTES(cstate) ((cstate)->raw_buf_len - (cstate)->raw_buf_index)
 } CopyStateData;
 
+/*
+ * This structure helps in storing the common data from CopyStateData that are
+ * required by the workers. This information will then be allocated and stored
+ * into the DSM for the worker to retrieve and copy it to CopyStateData.
+ */
+typedef struct SerializedParallelCopyState
+{
+	/* low-level state data */
+	CopyDest            copy_dest;		/* type of copy source/destination */
+	int                 file_encoding;	/* file or remote side's character encoding */
+	bool                need_transcoding;	/* file encoding diff from server? */
+	bool                encoding_embeds_ascii;	/* ASCII can be non-first byte? */
+
+	/* parameters from the COPY command */
+	bool                csv_mode;		/* Comma Separated Value format? */
+	bool                header_line;	/* CSV header line? */
+	int                 null_print_len; /* length of same */
+	bool                force_quote_all;	/* FORCE_QUOTE *? */
+	bool                convert_selectively;	/* do selective binary conversion? */
+
+	/* Working state for COPY FROM */
+	AttrNumber          num_defaults;
+	Oid                 relid;
+}SerializedParallelCopyState;
+
 /* DestReceiver for COPY (query) TO */
 typedef struct
 {
@@ -263,6 +462,22 @@ typedef struct
 /* Trim the list of buffers back down to this number after flushing */
 #define MAX_PARTITION_BUFFERS	32
 
+/* DSM keys for parallel copy.  */
+#define PARALLEL_COPY_KEY_SHARED_INFO		    1
+#define PARALLEL_COPY_KEY_CSTATE				2
+#define PARALLEL_COPY_KEY_NULL_PRINT			3
+#define PARALLEL_COPY_KEY_DELIM					4
+#define PARALLEL_COPY_KEY_QUOTE					5
+#define PARALLEL_COPY_KEY_ESCAPE				6
+#define PARALLEL_COPY_KEY_ATTNAME_LIST			7
+#define PARALLEL_COPY_KEY_NOT_NULL_LIST		    8
+#define PARALLEL_COPY_KEY_NULL_LIST			    9
+#define PARALLEL_COPY_KEY_CONVERT_LIST		   10
+#define PARALLEL_COPY_KEY_WHERE_CLAUSE_STR     11
+#define PARALLEL_COPY_KEY_RANGE_TABLE		   12
+#define PARALLEL_COPY_WAL_USAGE				   13
+#define PARALLEL_COPY_BUFFER_USAGE			   14
+
 /* Stores multi-insert data related to a single relation in CopyFrom. */
 typedef struct CopyMultiInsertBuffer
 {
@@ -424,11 +639,477 @@ static bool CopyGetInt16(CopyState cstate, int16 *val);
 static bool CopyLoadRawBuf(CopyState cstate);
 static int	CopyReadBinaryData(CopyState cstate, char *dest, int nbytes);
 
+static pg_attribute_always_inline void EndParallelCopy(ParallelContext *pcxt);
 static void PopulateCommonCstateInfo(CopyState cstate, TupleDesc	tup_desc,
-									   List *attnamelist);
+									 List *attnamelist);
 static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
 								   int copy_line_pos, int *copy_line_size);
 static void ConvertToServerEncoding(CopyState cstate);
+
+/*
+ * SerializeParallelCopyState - Copy shared_cstate using cstate information.
+ */
+static pg_attribute_always_inline void
+SerializeParallelCopyState(CopyState cstate, SerializedParallelCopyState *shared_cstate)
+{
+	shared_cstate->copy_dest = cstate->copy_dest;
+	shared_cstate->file_encoding = cstate->file_encoding;
+	shared_cstate->need_transcoding = cstate->need_transcoding;
+	shared_cstate->encoding_embeds_ascii = cstate->encoding_embeds_ascii;
+	shared_cstate->csv_mode = cstate->csv_mode;
+	shared_cstate->header_line = cstate->header_line;
+	shared_cstate->null_print_len = cstate->null_print_len;
+	shared_cstate->force_quote_all = cstate->force_quote_all;
+	shared_cstate->convert_selectively = cstate->convert_selectively;
+	shared_cstate->num_defaults = cstate->num_defaults;
+	shared_cstate->relid = cstate->pcdata->relid;
+}
+
+/*
+ * RestoreString - Retrieve the string from shared memory.
+ */
+static void
+RestoreString(shm_toc *toc, int sharedkey, char **copystr)
+{
+	char *shared_str_val = (char *)shm_toc_lookup(toc, sharedkey, true);
+	if (shared_str_val)
+		*copystr = pstrdup(shared_str_val);
+}
+
+/*
+ * EstimateLineKeysStr - Estimate the size required in shared memory for the
+ * input string.
+ */
+static void
+EstimateLineKeysStr(ParallelContext *pcxt, char *inputstr)
+{
+	if (inputstr)
+	{
+		shm_toc_estimate_chunk(&pcxt->estimator, strlen(inputstr) + 1);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+}
+
+/*
+ * SerializeString - Insert a string into shared memory.
+ */
+static void
+SerializeString(ParallelContext *pcxt, int key, char *inputstr)
+{
+	if (inputstr)
+	{
+		char *shmptr = (char *)shm_toc_allocate(pcxt->toc,
+												strlen(inputstr) + 1);
+		strcpy(shmptr, inputstr);
+		shm_toc_insert(pcxt->toc, key, shmptr);
+	}
+}
+
+/*
+ * PopulateParallelCopyShmInfo - set ParallelCopyShmInfo.
+ */
+static void
+PopulateParallelCopyShmInfo(ParallelCopyShmInfo *shared_info_ptr,
+							FullTransactionId full_transaction_id)
+{
+	uint32 count;
+
+	MemSet(shared_info_ptr, 0, sizeof(ParallelCopyShmInfo));
+	shared_info_ptr->is_read_in_progress = true;
+	shared_info_ptr->cur_block_pos = -1;
+	shared_info_ptr->full_transaction_id = full_transaction_id;
+	shared_info_ptr->mycid = GetCurrentCommandId(true);
+	for (count = 0; count < RINGSIZE; count++)
+	{
+		ParallelCopyLineBoundary *lineInfo = &shared_info_ptr->line_boundaries.ring[count];
+		pg_atomic_init_u32(&(lineInfo->line_size), -1);
+	}
+}
+
+/*
+ * BeginParallelCopy - start parallel copy tasks.
+ *
+ * Get the number of workers required to perform the parallel copy. The data
+ * structures that are required by the parallel workers will be initialized, the
+ * size required in DSM will be calculated and the necessary keys will be loaded
+ * in the DSM. The specified number of workers will then be launched.
+ */
+static ParallelContext*
+BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
+{
+	ParallelContext *pcxt;
+	ParallelCopyShmInfo *shared_info_ptr;
+	SerializedParallelCopyState *shared_cstate;
+	FullTransactionId full_transaction_id;
+	Size est_cstateshared;
+	char *whereClauseStr = NULL;
+	char *rangeTableStr = NULL;
+	char *attnameListStr = NULL;
+	char *notnullListStr = NULL;
+	char *nullListStr = NULL;
+	char *convertListStr = NULL;
+	int  parallel_workers = 0;
+	WalUsage   *walusage;
+	BufferUsage *bufferusage;
+	ParallelCopyData *pcdata;
+	MemoryContext oldcontext;
+
+	parallel_workers = Min(nworkers, max_worker_processes);
+
+	/* Can't perform copy in parallel */
+	if (parallel_workers <= 0)
+		return NULL;
+
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	MemoryContextSwitchTo(oldcontext);
+	cstate->pcdata = pcdata;
+
+	EnterParallelMode();
+	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
+								 parallel_workers);
+	Assert(pcxt->nworkers > 0);
+
+	/*
+	 * Estimate size for shared information for PARALLEL_COPY_KEY_SHARED_INFO
+	 */
+	shm_toc_estimate_chunk(&pcxt->estimator, sizeof(ParallelCopyShmInfo));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_CSTATE */
+	est_cstateshared = 	MAXALIGN(sizeof(SerializedParallelCopyState));
+	shm_toc_estimate_chunk(&pcxt->estimator, est_cstateshared);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	EstimateLineKeysStr(pcxt, cstate->null_print);
+	EstimateLineKeysStr(pcxt, cstate->null_print_client);
+	EstimateLineKeysStr(pcxt, cstate->delim);
+	EstimateLineKeysStr(pcxt, cstate->quote);
+	EstimateLineKeysStr(pcxt, cstate->escape);
+
+	if (cstate->whereClause != NULL)
+	{
+		whereClauseStr = nodeToString(cstate->whereClause);
+		EstimateLineKeysStr(pcxt, whereClauseStr);
+	}
+
+	if (cstate->range_table != NULL)
+	{
+		rangeTableStr = nodeToString(cstate->range_table);
+		EstimateLineKeysStr(pcxt, rangeTableStr);
+	}
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_XID. */
+	shm_toc_estimate_chunk(&pcxt->estimator, sizeof(FullTransactionId));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_ATTNAME_LIST.
+	 */
+	if (attnamelist != NIL)
+	{
+		attnameListStr = nodeToString(attnamelist);
+		EstimateLineKeysStr(pcxt, attnameListStr);
+	}
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_NOT_NULL_LIST.
+	 */
+	if (cstate->force_notnull != NIL)
+	{
+		notnullListStr = nodeToString(cstate->force_notnull);
+		EstimateLineKeysStr(pcxt, notnullListStr);
+	}
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_NULL_LIST.
+	 */
+	if (cstate->force_null != NIL)
+	{
+		nullListStr = nodeToString(cstate->force_null);
+		EstimateLineKeysStr(pcxt, nullListStr);
+	}
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_CONVERT_LIST.
+	 */
+	if (cstate->convert_select != NIL)
+	{
+		convertListStr = nodeToString(cstate->convert_select);
+		EstimateLineKeysStr(pcxt, convertListStr);
+	}
+
+	/*
+	 * Estimate space for WalUsage and BufferUsage -- PARALLEL_COPY_WAL_USAGE
+	 * and PARALLEL_COPY_BUFFER_USAGE.
+	 */
+	shm_toc_estimate_chunk(&pcxt->estimator,
+						   mul_size(sizeof(WalUsage), pcxt->nworkers));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+	shm_toc_estimate_chunk(&pcxt->estimator,
+						   mul_size(sizeof(BufferUsage), pcxt->nworkers));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	InitializeParallelDSM(pcxt);
+
+	/* If no DSM segment was available, back out (do serial copy) */
+	if (pcxt->seg == NULL)
+	{
+		EndParallelCopy(pcxt);
+		return NULL;
+	}
+
+	/* Allocate shared memory for PARALLEL_COPY_KEY_SHARED_INFO */
+	shared_info_ptr = (ParallelCopyShmInfo *) shm_toc_allocate(pcxt->toc, sizeof(ParallelCopyShmInfo));
+	PopulateParallelCopyShmInfo(shared_info_ptr, full_transaction_id);
+
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_SHARED_INFO, shared_info_ptr);
+	pcdata->pcshared_info = shared_info_ptr;
+	pcdata->relid = relid;
+
+	/* Store shared build state, for which we reserved space. */
+	shared_cstate = (SerializedParallelCopyState *)shm_toc_allocate(pcxt->toc, est_cstateshared);
+
+	/* copy cstate variables. */
+	SerializeParallelCopyState(cstate, shared_cstate);
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_CSTATE, shared_cstate);
+
+	SerializeString(pcxt, PARALLEL_COPY_KEY_NULL_PRINT, cstate->null_print);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_DELIM, cstate->delim);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_QUOTE, cstate->quote);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_ESCAPE, cstate->escape);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_ATTNAME_LIST, attnameListStr);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_NOT_NULL_LIST, notnullListStr);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_NULL_LIST, nullListStr);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_CONVERT_LIST, convertListStr);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_WHERE_CLAUSE_STR, whereClauseStr);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_RANGE_TABLE, rangeTableStr);
+
+	/*
+	 * Allocate space for each worker's WalUsage and BufferUsage; no need to
+	 * initialize.
+	 */
+	walusage = shm_toc_allocate(pcxt->toc,
+								mul_size(sizeof(WalUsage), pcxt->nworkers));
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_WAL_USAGE, walusage);
+	bufferusage = shm_toc_allocate(pcxt->toc,
+								   mul_size(sizeof(BufferUsage), pcxt->nworkers));
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_BUFFER_USAGE, bufferusage);
+
+	LaunchParallelWorkers(pcxt);
+	if (pcxt->nworkers_launched == 0)
+	{
+		EndParallelCopy(pcxt);
+		return NULL;
+	}
+
+	/*
+	 * Caller needs to wait for all launched workers when we return.  Make sure
+	 * that the failure-to-start case will not hang forever.
+	 */
+	WaitForParallelWorkersToAttach(pcxt);
+
+	pcdata->is_leader = true;
+	cstate->is_parallel = true;
+	return pcxt;
+}
+
+/*
+ * EndParallelCopy - end the parallel copy tasks.
+ */
+static pg_attribute_always_inline void
+EndParallelCopy(ParallelContext *pcxt)
+{
+	Assert(!IsParallelWorker());
+
+	DestroyParallelContext(pcxt);
+	ExitParallelMode();
+}
+
+/*
+ * InitializeParallelCopyInfo - Initialize parallel worker.
+ */
+static void
+InitializeParallelCopyInfo(SerializedParallelCopyState *shared_cstate,
+		CopyState cstate, List *attnamelist)
+{
+	uint32		count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	cstate->copy_dest = shared_cstate->copy_dest;
+	cstate->file_encoding = shared_cstate->file_encoding;
+	cstate->need_transcoding = shared_cstate->need_transcoding;
+	cstate->encoding_embeds_ascii = shared_cstate->encoding_embeds_ascii;
+	cstate->csv_mode = shared_cstate->csv_mode;
+	cstate->header_line = shared_cstate->header_line;
+	cstate->null_print_len = shared_cstate->null_print_len;
+	cstate->force_quote_all = shared_cstate->force_quote_all;
+	cstate->convert_selectively = shared_cstate->convert_selectively;
+	cstate->num_defaults = shared_cstate->num_defaults;
+	pcdata->relid = shared_cstate->relid;
+
+	PopulateCommonCstateInfo(cstate, tup_desc, attnamelist);
+
+	/* Initialize state variables. */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/* Set up variables to avoid per-attribute overhead. */
+	initStringInfo(&cstate->attribute_buf);
+
+	initStringInfo(&cstate->line_buf);
+	for (count = 0; count < WORKER_CHUNK_COUNT; count++)
+		initStringInfo(&pcdata->worker_line_buf[count].line_buf);
+
+	cstate->line_buf_converted = false;
+	cstate->raw_buf = NULL;
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+}
+
+/*
+ * ParallelCopyMain - parallel copy worker's code.
+ *
+ * Where clause handling, convert tuple to columns, add default null values for
+ * the missing columns that are not present in that record. Find the partition
+ * if it is partitioned table, invoke before row insert Triggers, handle
+ * constraints and insert the tuples.
+ */
+void
+ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
+{
+	CopyState cstate;
+	ParallelCopyData *pcdata;
+	ParallelCopyShmInfo *pcshared_info;
+	SerializedParallelCopyState *shared_cstate;
+	Relation	rel = NULL;
+	MemoryContext oldcontext;
+	List *attlist = NIL;
+	char *whereClauseStr = NULL;
+	char *rangeTableStr = NULL;
+	char *attnameListStr = NULL;
+	char *notnullListStr = NULL;
+	char *nullListStr = NULL;
+	char *convertListStr = NULL;
+	WalUsage   *walusage;
+	BufferUsage *bufferusage;
+
+	/* Allocate workspace and zero all fields. */
+	cstate = (CopyStateData *) palloc0(sizeof(CopyStateData));
+
+	/*
+	 * We allocate everything used by a cstate in a new memory context. This
+	 * avoids memory leaks during repeated use of COPY in a query.
+	 */
+	cstate->copycontext = AllocSetContextCreate(CurrentMemoryContext,
+												"COPY",
+												ALLOCSET_DEFAULT_SIZES);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	cstate->pcdata = pcdata;
+	pcdata->is_leader = false;
+	pcdata->worker_processed_pos = -1;
+	cstate->is_parallel = true;
+	pcshared_info = (ParallelCopyShmInfo *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_SHARED_INFO, false);
+
+	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
+
+	pcdata->pcshared_info = pcshared_info;
+
+	shared_cstate = (SerializedParallelCopyState *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE, false);
+	cstate->null_print = (char *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_NULL_PRINT, true);
+
+	RestoreString(toc, PARALLEL_COPY_KEY_DELIM, &cstate->delim);
+	RestoreString(toc, PARALLEL_COPY_KEY_QUOTE, &cstate->quote);
+	RestoreString(toc, PARALLEL_COPY_KEY_ESCAPE, &cstate->escape);
+	RestoreString(toc, PARALLEL_COPY_KEY_ATTNAME_LIST, &attnameListStr);
+	if (attnameListStr)
+		attlist = (List *)stringToNode(attnameListStr);
+
+	RestoreString(toc, PARALLEL_COPY_KEY_NOT_NULL_LIST, &notnullListStr);
+	if (notnullListStr)
+		cstate->force_notnull = (List *)stringToNode(notnullListStr);
+
+	RestoreString(toc, PARALLEL_COPY_KEY_NULL_LIST, &nullListStr);
+	if (nullListStr)
+		cstate->force_null = (List *)stringToNode(nullListStr);
+
+	RestoreString(toc, PARALLEL_COPY_KEY_CONVERT_LIST, &convertListStr);
+	if (convertListStr)
+		cstate->convert_select = (List *)stringToNode(convertListStr);
+
+	RestoreString(toc, PARALLEL_COPY_KEY_WHERE_CLAUSE_STR, &whereClauseStr);
+	RestoreString(toc, PARALLEL_COPY_KEY_RANGE_TABLE, &rangeTableStr);
+
+	if (whereClauseStr)
+	{
+		Node *whereClauseCnvrtdFrmStr = (Node *) stringToNode(whereClauseStr);
+		cstate->whereClause = whereClauseCnvrtdFrmStr;
+	}
+
+	if (rangeTableStr)
+	{
+		List *rangeTableCnvrtdFrmStr = (List *) stringToNode(rangeTableStr);
+		cstate->range_table = rangeTableCnvrtdFrmStr;
+	}
+
+	/* Open and lock the relation, using the appropriate lock type. */
+	rel = table_open(shared_cstate->relid, RowExclusiveLock);
+	cstate->rel = rel;
+	InitializeParallelCopyInfo(shared_cstate, cstate, attlist);
+
+	CopyFrom(cstate);
+
+	if (rel != NULL)
+		table_close(rel, RowExclusiveLock);
+
+	/* Report WAL/buffer usage during parallel execution */
+	bufferusage = shm_toc_lookup(toc, PARALLEL_COPY_BUFFER_USAGE, false);
+	walusage = shm_toc_lookup(toc, PARALLEL_COPY_WAL_USAGE, false);
+	InstrEndParallelQuery(&bufferusage[ParallelWorkerNumber],
+						  &walusage[ParallelWorkerNumber]);
+
+	MemoryContextSwitchTo(oldcontext);
+	pfree(cstate);
+	return;
+}
+
+/*
+ * ParallelCopyFrom - parallel copy leader's functionality.
+ *
+ * Leader executes the before statement for before statement trigger, if before
+ * statement trigger is present. It will read the table data from the file and
+ * copy the contents to DSM data blocks. It will then read the input contents
+ * from the DSM data block and identify the records based on line breaks. This
+ * information is called line or a record that need to be inserted into a
+ * relation. The line information will be stored in ParallelCopyLineBoundary DSM
+ * data structure. Workers will then process this information and insert the
+ * data in to table. It will repeat this process until the all data is read from
+ * the file and all the DSM data blocks are processed. While processing if
+ * leader identifies that DSM Data blocks or DSM ParallelCopyLineBoundary data
+ * structures is full, leader will wait till the worker frees up some entries
+ * and repeat the process. It will wait till all the lines populated are
+ * processed by the workers and exits.
+ */
+static void
+ParallelCopyFrom(CopyState cstate)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
+
+	pcshared_info->is_read_in_progress = false;
+	cstate->cur_lineno = 0;
+}
+
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
  * in past protocol redesigns.
@@ -1141,6 +1822,7 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 
 	if (is_from)
 	{
+		ParallelContext *pcxt = NULL;
 		Assert(rel);
 
 		/* check read-only transaction and parallel mode */
@@ -1150,7 +1832,24 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 		cstate = BeginCopyFrom(pstate, rel, stmt->filename, stmt->is_program,
 							   NULL, stmt->attlist, stmt->options);
 		cstate->whereClause = whereClause;
-		*processed = CopyFrom(cstate);	/* copy from file to database */
+		cstate->is_parallel = false;
+
+		if (cstate->nworkers > 0)
+			pcxt = BeginParallelCopy(cstate->nworkers, cstate, stmt->attlist,
+									 relid);
+
+		if (pcxt)
+		{
+			ParallelCopyFrom(cstate);
+
+			/* Wait for all copy workers to finish */
+			WaitForParallelWorkersToFinish(pcxt);
+			*processed = pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
+			EndParallelCopy(pcxt);
+		}
+		else
+			*processed = CopyFrom(cstate); /* copy from file to database */
+
 		EndCopyFrom(cstate);
 	}
 	else
@@ -1199,6 +1898,7 @@ ProcessCopyOptions(ParseState *pstate,
 	cstate->is_copy_from = is_from;
 
 	cstate->file_encoding = -1;
+	cstate->nworkers = -1;
 
 	/* Extract options from the statement node tree */
 	foreach(option, options)
@@ -1367,6 +2067,53 @@ ProcessCopyOptions(ParseState *pstate,
 								defel->defname),
 						 parser_errposition(pstate, defel->location)));
 		}
+		else if (strcmp(defel->defname, "parallel") == 0)
+		{
+			char *endptr, *str;
+			long val;
+
+			if (!cstate->is_copy_from)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("parallel option supported only for copy from"),
+						 parser_errposition(pstate, defel->location)));
+			if (cstate->nworkers >= 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options"),
+						 parser_errposition(pstate, defel->location)));
+
+			str = defGetString(defel);
+
+			errno = 0; /* To distinguish success/failure after call */
+			val = strtol(str, &endptr, 10);
+
+			/* Check for various possible errors */
+			if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
+				|| (errno != 0 && val == 0) ||
+				*endptr)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("improper use of argument to option \"%s\"",
+								defel->defname),
+						 parser_errposition(pstate, defel->location)));
+
+			if (endptr == str)
+			   ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("no digits were found in argument to option \"%s\"",
+								defel->defname),
+						 parser_errposition(pstate, defel->location)));
+
+			cstate->nworkers = (int) val;
+
+			if (cstate->nworkers <= 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("argument to option \"%s\" must be a positive integer greater than zero",
+								defel->defname),
+						 parser_errposition(pstate, defel->location)));
+		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_SYNTAX_ERROR),
@@ -1720,11 +2467,12 @@ BeginCopy(ParseState *pstate,
 
 /*
  * PopulateCommonCstateInfo - Populates the common variables required for copy
- * from operation. This is a helper function for BeginCopy function.
+ * from operation. This is a helper function for BeginCopy &
+ * InitializeParallelCopyInfo function.
  */
 static void
 PopulateCommonCstateInfo(CopyState cstate, TupleDesc	tupDesc,
-							List *attnamelist)
+						 List *attnamelist)
 {
 	int			num_phys_attrs;
 
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index c639833..82843c6 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -14,6 +14,7 @@
 #ifndef COPY_H
 #define COPY_H
 
+#include "access/parallel.h"
 #include "nodes/execnodes.h"
 #include "nodes/parsenodes.h"
 #include "parser/parse_node.h"
@@ -41,4 +42,5 @@ extern uint64 CopyFrom(CopyState cstate);
 
 extern DestReceiver *CreateCopyDestReceiver(void);
 
+extern void ParallelCopyMain(dsm_segment *seg, shm_toc *toc);
 #endif							/* COPY_H */
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 7eaaad1..3a83d0f 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1699,6 +1699,12 @@ ParallelBitmapHeapState
 ParallelBlockTableScanDesc
 ParallelCompletionPtr
 ParallelContext
+ParallelCopyLineBoundaries
+ParallelCopyLineBoundary
+ParallelCopyData
+ParallelCopyDataBlock
+ParallelCopyLineBuf
+ParallelCopyShmInfo
 ParallelExecutorInfo
 ParallelHashGrowth
 ParallelHashJoinBatch
@@ -2215,6 +2221,7 @@ SerCommitSeqNo
 SerialControl
 SerializableXactHandle
 SerializedActiveRelMaps
+SerializedParallelCopyState
 SerializedReindexState
 SerializedSnapshotData
 SerializedTransactionState
-- 
1.8.3.1

v2-0003-Allow-copy-from-command-to-process-data-from-file.patchtext/x-patch; charset=US-ASCII; name=v2-0003-Allow-copy-from-command-to-process-data-from-file.patchDownload
From f3ec188c3c1e11fdbb716ec12862a891a95b396f Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Sat, 1 Aug 2020 09:31:42 +0530
Subject: [PATCH v2 3/5] Allow copy from command to process data from
 file/STDIN contents to a table in parallel.

This feature allows the copy from to leverage multiple CPUs in order to copy
data from file/STDIN to a table. This adds a PARALLEL option to COPY FROM
command where the user can specify the number of workers that can be used
to perform the COPY FROM command. Specifying zero as number of workers will
disable parallelism.
The backend, to which the "COPY FROM" query is submitted acts as leader with
the responsibility of reading data from the file/stdin, launching at most n
number of workers as specified with PARALLEL 'n' option in the "COPY FROM"
query. The leader populates the common data required for the workers execution
in the DSM and shares it with the workers. The leader then executes before
statement triggers if there exists any. Leader populates DSM lines which
includes the start offset and line size, while populating the lines it reads
as many blocks as required into the DSM data blocks from the file. Each block
is of 64K size. The leader parses the data to identify a line, the existing
logic from CopyReadLineText which identifies the lines with some changes was
used for this. Leader checks if a free line is available to copy the
information, if there is no free line it waits till the required line is
freed up by the worker and then copies the identified lines information
(offset & line size) into the DSM lines. This process is repeated till the
complete file is processed. Simultaneously, the workers cache the lines(50)
locally into the local memory and release the lines to the leader for further
populating. Each worker processes the lines that it cached and inserts it into
the table. The leader does not participate in the insertion of data, leaders
only responsibility will be to identify the lines as fast as possible for the
workers to do the actual copy operation. The leader waits till all the lines
populated are processed by the workers and exits.
We have chosen this design based on the reason "that everything stalls if the
leader doesn't accept further input data, as well as when there are no
available splitted chunks so it doesn't seem like a good idea to have the
leader do other work.  This is backed by the performance data where we have
seen that with 1 worker there is just a 5-10% performance difference".
---
 src/backend/access/common/toast_internals.c |  11 +-
 src/backend/access/heap/heapam.c            |  13 -
 src/backend/access/transam/xact.c           |  31 +
 src/backend/commands/copy.c                 | 890 ++++++++++++++++++++++++++--
 src/bin/psql/tab-complete.c                 |   2 +-
 src/include/access/xact.h                   |   2 +
 src/tools/pgindent/typedefs.list            |   1 +
 7 files changed, 896 insertions(+), 54 deletions(-)

diff --git a/src/backend/access/common/toast_internals.c b/src/backend/access/common/toast_internals.c
index 25a81e5..586d53d 100644
--- a/src/backend/access/common/toast_internals.c
+++ b/src/backend/access/common/toast_internals.c
@@ -17,6 +17,7 @@
 #include "access/genam.h"
 #include "access/heapam.h"
 #include "access/heaptoast.h"
+#include "access/parallel.h"
 #include "access/table.h"
 #include "access/toast_internals.h"
 #include "access/xact.h"
@@ -116,7 +117,15 @@ toast_save_datum(Relation rel, Datum value,
 	TupleDesc	toasttupDesc;
 	Datum		t_values[3];
 	bool		t_isnull[3];
-	CommandId	mycid = GetCurrentCommandId(true);
+
+	/*
+	 * Parallel copy can insert toast tuples, in case of parallel copy the
+	 * command would have been set already by calling AssignCommandIdForWorker.
+	 * For parallel copy call GetCurrentCommandId to get currentCommandId by
+	 * passing used as false, as this is taken care earlier.
+	 */
+	CommandId	mycid = IsParallelWorker() ? GetCurrentCommandId(false) :
+											 GetCurrentCommandId(true);
 	struct varlena *result;
 	struct varatt_external toast_pointer;
 	union
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 5eef225..bd7a7fc 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2023,19 +2023,6 @@ static HeapTuple
 heap_prepare_insert(Relation relation, HeapTuple tup, TransactionId xid,
 					CommandId cid, int options)
 {
-	/*
-	 * Parallel operations are required to be strictly read-only in a parallel
-	 * worker.  Parallel inserts are not safe even in the leader in the
-	 * general case, because group locking means that heavyweight locks for
-	 * relation extension or GIN page locks will not conflict between members
-	 * of a lock group, but we don't prohibit that case here because there are
-	 * useful special cases that we can safely allow, such as CREATE TABLE AS.
-	 */
-	if (IsParallelWorker())
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_TRANSACTION_STATE),
-				 errmsg("cannot insert tuples in a parallel worker")));
-
 	tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
 	tup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK);
 	tup->t_data->t_infomask |= HEAP_XMAX_INVALID;
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index d4f7c29..9bff390 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -504,6 +504,37 @@ GetCurrentFullTransactionIdIfAny(void)
 }
 
 /*
+ *	AssignFullTransactionIdForWorker
+ *
+ * For parallel copy, transaction id of leader will be used by the workers.
+ */
+void
+AssignFullTransactionIdForWorker(FullTransactionId fullTransactionId)
+{
+	TransactionState s = CurrentTransactionState;
+
+	Assert((IsInParallelMode() || IsParallelWorker()));
+	s->fullTransactionId = fullTransactionId;
+}
+
+/*
+ *	AssignCommandIdForWorker
+ *
+ * For parallel copy, command id of leader will be used by the workers.
+ */
+void
+AssignCommandIdForWorker(CommandId commandId, bool used)
+{
+	Assert((IsInParallelMode() || IsParallelWorker()));
+
+	/* this is global to a transaction, not subtransaction-local */
+	if (used)
+		currentCommandIdUsed = true;
+
+	currentCommandId = commandId;
+}
+
+/*
  *	MarkCurrentTransactionIdLoggedIfAny
  *
  * Remember that the current xid - if it is assigned - now has been wal logged.
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 3dcdfc1..c65fc98 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -26,6 +26,7 @@
 #include "access/xlog.h"
 #include "catalog/dependency.h"
 #include "catalog/pg_authid.h"
+#include "catalog/pg_proc_d.h"
 #include "catalog/pg_type.h"
 #include "commands/copy.h"
 #include "commands/defrem.h"
@@ -40,11 +41,13 @@
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
+#include "optimizer/clauses.h"
 #include "optimizer/optimizer.h"
 #include "parser/parse_coerce.h"
 #include "parser/parse_collate.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_relation.h"
+#include "pgstat.h"
 #include "port/pg_bswap.h"
 #include "rewrite/rewriteHandler.h"
 #include "storage/fd.h"
@@ -95,6 +98,18 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
+/*
+ * State of the line.
+ */
+typedef enum ParallelCopyLineState
+{
+	LINE_INIT,					/* initial state of line */
+	LINE_LEADER_POPULATING,		/* leader processing line */
+	LINE_LEADER_POPULATED,		/* leader completed populating line */
+	LINE_WORKER_PROCESSING,		/* worker processing line */
+	LINE_WORKER_PROCESSED		/* worker completed processing line */
+}ParallelCopyLineState;
+
 #define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
 
 /*
@@ -123,6 +138,7 @@ typedef enum CopyInsertMethod
 
 #define	IsParallelCopy()		(cstate->is_parallel)
 #define IsLeader()				(cstate->pcdata->is_leader)
+#define IsWorker()				(IsParallelCopy() && !IsLeader())
 #define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
 
 /*
@@ -556,9 +572,13 @@ if (1) \
 { \
 	if (raw_buf_ptr > cstate->raw_buf_index) \
 	{ \
-		appendBinaryStringInfo(&cstate->line_buf, \
-							 cstate->raw_buf + cstate->raw_buf_index, \
-							   raw_buf_ptr - cstate->raw_buf_index); \
+		if (!IsParallelCopy()) \
+			appendBinaryStringInfo(&cstate->line_buf, \
+								   cstate->raw_buf + cstate->raw_buf_index, \
+								   raw_buf_ptr - cstate->raw_buf_index); \
+		else \
+			line_size +=  raw_buf_ptr - cstate->raw_buf_index; \
+		\
 		cstate->raw_buf_index = raw_buf_ptr; \
 	} \
 } else ((void) 0)
@@ -571,26 +591,65 @@ if (1) \
 	goto not_end_of_copy; \
 } else ((void) 0)
 
+/* Begin parallel copy Macros */
+#define SET_NEWLINE_SIZE() \
+{ \
+	if (cstate->eol_type == EOL_NL || cstate->eol_type == EOL_CR) \
+		new_line_size = 1; \
+	else if (cstate->eol_type == EOL_CRNL) \
+		new_line_size = 2; \
+	else \
+		new_line_size = 0; \
+}
+
+/*
+ * COPY_WAIT_TO_PROCESS - Wait before continuing to process.
+ */
+#define COPY_WAIT_TO_PROCESS() \
+{ \
+	CHECK_FOR_INTERRUPTS(); \
+	(void) WaitLatch(MyLatch, \
+					 WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH, \
+					 1L, WAIT_EVENT_PG_SLEEP); \
+	ResetLatch(MyLatch); \
+}
+
 /*
  * CLEAR_EOL_LINE - Wrapper for clearing EOL.
  */
 #define CLEAR_EOL_LINE() \
 if (!result && !IsHeaderLine()) \
-	ClearEOLFromCopiedData(cstate, cstate->line_buf.data, \
-						   cstate->line_buf.len, \
-						   &cstate->line_buf.len) \
+{ \
+	if (IsParallelCopy()) \
+		ClearEOLFromCopiedData(cstate, cstate->raw_buf, \
+									raw_buf_ptr, &line_size); \
+	else \
+		ClearEOLFromCopiedData(cstate, cstate->line_buf.data, \
+									cstate->line_buf.len, \
+									&cstate->line_buf.len); \
+} \
 
 /*
  * INCREMENTPROCESSED - Increment the lines processed.
  */
-#define INCREMENTPROCESSED(processed)  \
-processed++;
+#define INCREMENTPROCESSED(processed) \
+{ \
+	if (!IsParallelCopy()) \
+		processed++; \
+	else \
+		pg_atomic_add_fetch_u64(&cstate->pcdata->pcshared_info->processed, 1); \
+}
 
 /*
  * GETPROCESSED - Get the lines processed.
  */
 #define GETPROCESSED(processed) \
-return processed;
+if (!IsParallelCopy()) \
+	return processed; \
+else \
+	return pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
+
+/* End parallel copy Macros */
 
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
@@ -645,7 +704,10 @@ static void PopulateCommonCstateInfo(CopyState cstate, TupleDesc	tup_desc,
 static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
 								   int copy_line_pos, int *copy_line_size);
 static void ConvertToServerEncoding(CopyState cstate);
-
+static void ExecBeforeStmtTrigger(CopyState cstate);
+static void CheckTargetRelValidity(CopyState cstate);
+static void PopulateCstateCatalogInfo(CopyState cstate);
+static pg_attribute_always_inline uint32 GetLinePosition(CopyState cstate);
 /*
  * SerializeParallelCopyState - Copy shared_cstate using cstate information.
  */
@@ -727,6 +789,137 @@ PopulateParallelCopyShmInfo(ParallelCopyShmInfo *shared_info_ptr,
 }
 
 /*
+ * IsTriggerFunctionParallelSafe - Check if the trigger function is parallel
+ * safe for the triggers. Return false if any one of the trigger has parallel
+ * unsafe function.
+ */
+static pg_attribute_always_inline bool
+IsTriggerFunctionParallelSafe(TriggerDesc *trigdesc)
+{
+	int	i;
+	for (i = 0; i < trigdesc->numtriggers; i++)
+	{
+		Trigger    *trigger = &trigdesc->triggers[i];
+		int 		trigtype = RI_TRIGGER_NONE;
+
+		if (func_parallel(trigger->tgfoid) != PROPARALLEL_SAFE)
+			return false;
+
+		/* If the trigger is parallel safe, also look for RI_TRIGGER. */
+		trigtype = RI_FKey_trigger_type(trigger->tgfoid);
+		if (trigtype == RI_TRIGGER_PK || trigtype == RI_TRIGGER_FK)
+			return false;
+	}
+
+	return true;
+}
+
+/*
+ * CheckExprParallelSafety - determine parallel safety of volatile expressions
+ * in default clause of column definition or in where clause and return true if
+ * they are parallel safe.
+ */
+static pg_attribute_always_inline bool
+CheckExprParallelSafety(CopyState cstate)
+{
+	if (contain_volatile_functions(cstate->whereClause))
+	{
+		if (max_parallel_hazard((Query *)cstate->whereClause) != PROPARALLEL_SAFE)
+			return false;
+	}
+
+	/*
+	 * Check if any of the column has volatile default expression. if yes, and
+	 * they are not parallel safe, then parallelism is not allowed. For
+	 * instance, if there are any serial/bigserial columns for which nextval()
+	 * default expression which is parallel unsafe is associated, parallelism
+	 * should not be allowed. In non parallel copy volatile functions are not
+	 * checked for nextval().
+	 */
+	if (cstate->defexprs != NULL && cstate->num_defaults != 0)
+	{
+		int     i;
+		for (i = 0; i < cstate->num_defaults; i++)
+		{
+			bool volatile_expr = contain_volatile_functions((Node *)cstate->defexprs[i]->expr);
+			if (volatile_expr &&
+				(max_parallel_hazard((Query *)cstate->defexprs[i]->expr)) !=
+				 PROPARALLEL_SAFE)
+				return false;
+		}
+	}
+
+	return true;
+}
+
+/*
+ * FindInsertMethod - determine insert mode single, multi, or multi conditional.
+ */
+static pg_attribute_always_inline CopyInsertMethod
+FindInsertMethod(CopyState cstate)
+{
+	if (cstate->rel->trigdesc != NULL &&
+		(cstate->rel->trigdesc->trig_insert_before_row ||
+		 cstate->rel->trigdesc->trig_insert_instead_row))
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
+			cstate->rel->trigdesc != NULL &&
+			cstate->rel->trigdesc->trig_insert_new_table)
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+		return CIM_MULTI_CONDITIONAL;
+
+	return CIM_MULTI;
+}
+
+/*
+ * IsParallelCopyAllowed - check for the cases where parallel copy is not
+ * applicable.
+ */
+static pg_attribute_always_inline bool
+IsParallelCopyAllowed(CopyState cstate)
+{
+	/* Parallel copy not allowed for frontend (2.0 protocol) & binary option. */
+	if ((cstate->copy_dest == COPY_OLD_FE) || cstate->binary)
+		return false;
+
+	/* Check if copy is into foreign table or temporary table. */
+	if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
+		RelationUsesLocalBuffers(cstate->rel))
+		return false;
+
+	/* Check if trigger function is parallel safe. */
+	if (cstate->rel->trigdesc != NULL &&
+		!IsTriggerFunctionParallelSafe(cstate->rel->trigdesc))
+		return false;
+
+	/*
+	 * Check if there is after statement or instead of trigger or transition
+	 * table triggers.
+	 */
+	if (cstate->rel->trigdesc != NULL &&
+		(cstate->rel->trigdesc->trig_insert_after_statement ||
+		 cstate->rel->trigdesc->trig_insert_instead_row ||
+		 cstate->rel->trigdesc->trig_insert_new_table))
+		return false;
+
+	/* Check if the volatile expressions are parallel safe, if present any. */
+	if (!CheckExprParallelSafety(cstate))
+		return false;
+
+	/* Check if the insertion mode is single. */
+	if (FindInsertMethod(cstate) == CIM_SINGLE)
+		return false;
+
+	return true;
+}
+
+/*
  * BeginParallelCopy - start parallel copy tasks.
  *
  * Get the number of workers required to perform the parallel copy. The data
@@ -754,6 +947,7 @@ BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
 	ParallelCopyData *pcdata;
 	MemoryContext oldcontext;
 
+	CheckTargetRelValidity(cstate);
 	parallel_workers = Min(nworkers, max_worker_processes);
 
 	/* Can't perform copy in parallel */
@@ -765,6 +959,15 @@ BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
 	MemoryContextSwitchTo(oldcontext);
 	cstate->pcdata = pcdata;
 
+	/*
+	 * User chosen parallel copy. Determine if the parallel copy is actually
+	 * allowed. If not, go with the non-parallel mode.
+	 */
+	if (!IsParallelCopyAllowed(cstate))
+		return NULL;
+
+	full_transaction_id = GetCurrentFullTransactionId();
+
 	EnterParallelMode();
 	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
 								 parallel_workers);
@@ -973,9 +1176,212 @@ InitializeParallelCopyInfo(SerializedParallelCopyState *shared_cstate,
 	cstate->line_buf_converted = false;
 	cstate->raw_buf = NULL;
 	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+
+	PopulateCstateCatalogInfo(cstate);
+
+	/* Create workspace for CopyReadAttributes results. */
+	if (!cstate->binary)
+	{
+		AttrNumber	attr_count = list_length(cstate->attnumlist);
+
+		cstate->max_fields = attr_count;
+		cstate->raw_fields = (char **)palloc(attr_count * sizeof(char *));
+	}
+}
+
+/*
+ * CacheLineInfo - Cache the line information to local memory.
+ */
+static bool
+CacheLineInfo(CopyState cstate, uint32 buff_count)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	uint32			write_pos;
+	ParallelCopyDataBlock *data_blk_ptr;
+	ParallelCopyLineBoundary *lineInfo;
+	uint32 offset;
+	int dataSize;
+	int copiedSize = 0;
+
+	resetStringInfo(&pcdata->worker_line_buf[buff_count].line_buf);
+	write_pos = GetLinePosition(cstate);
+	if (-1 == write_pos)
+		return true;
+
+	/* Get the current line information. */
+	lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+	if (pg_atomic_read_u32(&lineInfo->line_size) == 0)
+		goto empty_data_line_update;
+
+	/* Get the block information. */
+	data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+	/* Get the offset information from where the data must be copied. */
+	offset = lineInfo->start_offset;
+	pcdata->worker_line_buf[buff_count].cur_lineno = lineInfo->cur_lineno;
+
+	elog(DEBUG1, "[Worker] Processing - line position:%d, block:%d, unprocessed lines:%d, offset:%d, line size:%d",
+				 write_pos, lineInfo->first_block,
+				 pg_atomic_read_u32(&data_blk_ptr->unprocessed_line_parts),
+				 offset, pg_atomic_read_u32(&lineInfo->line_size));
+
+	for (;;)
+	{
+		uint8 skip_bytes = data_blk_ptr->skip_bytes;
+		/*
+		 * There is a possibility that the above loop has come out because
+		 * data_blk_ptr->curr_blk_completed is set, but dataSize read might
+		 * be an old value, if data_blk_ptr->curr_blk_completed and the line is
+		 * completed, line_size will be set. Read the line_size again to be
+		 * sure if it is complete or partial block.
+		 */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+		if (dataSize)
+		{
+			int remainingSize = dataSize - copiedSize;
+			if (!remainingSize)
+				break;
+
+			/* Whole line is in current block. */
+			if (remainingSize + offset + skip_bytes < DATA_BLOCK_SIZE)
+			{
+				appendBinaryStringInfo(&pcdata->worker_line_buf[buff_count].line_buf,
+									   &data_blk_ptr->data[offset],
+									   remainingSize);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts,
+										1);
+				break;
+			}
+			else
+			{
+				/* Line is spread across the blocks. */
+				uint32 lineInCurrentBlock =  (DATA_BLOCK_SIZE - skip_bytes) - offset;
+				appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+										 &data_blk_ptr->data[offset],
+										 lineInCurrentBlock);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+				copiedSize += lineInCurrentBlock;
+				while (copiedSize < dataSize)
+				{
+					uint32 currentBlockCopySize;
+					ParallelCopyDataBlock *currBlkPtr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+					skip_bytes = currBlkPtr->skip_bytes;
+
+					/*
+					 * If complete data is present in current block use
+					 * dataSize - copiedSize, or copy the whole block from
+					 * current block.
+					 */
+					currentBlockCopySize = Min(dataSize - copiedSize, DATA_BLOCK_SIZE - skip_bytes);
+					appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+											 &currBlkPtr->data[0],
+											 currentBlockCopySize);
+					pg_atomic_sub_fetch_u32(&currBlkPtr->unprocessed_line_parts, 1);
+					copiedSize += currentBlockCopySize;
+					data_blk_ptr = currBlkPtr;
+				}
+
+				break;
+			}
+		}
+		else
+		{
+			/* Copy this complete block from the current offset. */
+			uint32 lineInCurrentBlock =  (DATA_BLOCK_SIZE - skip_bytes) - offset;
+			appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+									 &data_blk_ptr->data[offset],
+									 lineInCurrentBlock);
+			pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+			copiedSize += lineInCurrentBlock;
+
+			/*
+			 * Reset the offset. For the first copy, copy from the offset. For
+			 * the subsequent copy the complete block.
+			 */
+			offset = 0;
+
+			/* Set data_blk_ptr to the following block. */
+			data_blk_ptr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+		}
+
+		for (;;)
+		{
+			/* Get the size of this line */
+			dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+			/*
+			 * If the data is present in current block lineInfo.line_size
+			 * will be updated. If the data is spread across the blocks either
+			 * of lineInfo.line_size or data_blk_ptr->curr_blk_completed can
+			 * be updated. lineInfo.line_size will be updated if the complete
+			 * read is finished. data_blk_ptr->curr_blk_completed will be
+			 * updated if processing of current block is finished and data
+			 * processing is not finished.
+			 */
+			if (data_blk_ptr->curr_blk_completed || (dataSize != -1))
+				break;
+
+			COPY_WAIT_TO_PROCESS()
+		}
+	}
+
+empty_data_line_update:
+	elog(DEBUG1, "[Worker] Completed processing line:%d", write_pos);
+	pg_atomic_write_u32(&lineInfo->line_state, LINE_WORKER_PROCESSED);
+	pg_atomic_write_u32(&lineInfo->line_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+	return false;
 }
 
 /*
+ * GetWorkerLine - Returns a line for worker to process.
+ */
+static bool
+GetWorkerLine(CopyState cstate)
+{
+	uint32 buff_count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+
+	/*
+	 * Copy the line data to line_buf and release the line position so that the
+	 * worker can continue loading data.
+	 */
+	if (pcdata->worker_line_buf_pos < pcdata->worker_line_buf_count)
+		goto return_line;
+
+	pcdata->worker_line_buf_pos = 0;
+	pcdata->worker_line_buf_count = 0;
+
+	for (buff_count = 0; buff_count < WORKER_CHUNK_COUNT; buff_count++)
+	{
+		bool result = CacheLineInfo(cstate, buff_count);
+		if (result)
+			break;
+
+		pcdata->worker_line_buf_count++;
+	}
+
+	if (pcdata->worker_line_buf_count)
+		goto return_line;
+	else
+		resetStringInfo(&cstate->line_buf);
+
+	return true;
+
+return_line:
+	cstate->line_buf = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].line_buf;
+	cstate->cur_lineno = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].cur_lineno;
+	cstate->line_buf_valid = true;
+
+	/* Mark that encoding conversion hasn't occurred yet. */
+	cstate->line_buf_converted = false;
+	ConvertToServerEncoding(cstate);
+	pcdata->worker_line_buf_pos++;
+	return false;
+ }
+
+/*
  * ParallelCopyMain - parallel copy worker's code.
  *
  * Where clause handling, convert tuple to columns, add default null values for
@@ -1024,6 +1430,8 @@ ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
 	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
 
 	pcdata->pcshared_info = pcshared_info;
+	AssignFullTransactionIdForWorker(pcshared_info->full_transaction_id);
+	AssignCommandIdForWorker(pcshared_info->mycid, true);
 
 	shared_cstate = (SerializedParallelCopyState *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE, false);
 	cstate->null_print = (char *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_NULL_PRINT, true);
@@ -1084,6 +1492,33 @@ ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
 }
 
 /*
+ * UpdateBlockInLineInfo - Update the line information.
+ */
+static pg_attribute_always_inline int
+UpdateBlockInLineInfo(CopyState cstate, uint32 blk_pos,
+					   uint32 offset, uint32 line_size, uint32 line_state)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyLineBoundaries *lineBoundaryPtr = &pcshared_info->line_boundaries;
+	ParallelCopyLineBoundary *lineInfo;
+	int line_pos = lineBoundaryPtr->pos;
+
+	/* Update the line information for the worker to pick and process. */
+	lineInfo = &lineBoundaryPtr->ring[line_pos];
+	while (pg_atomic_read_u32(&lineInfo->line_size) != -1)
+		COPY_WAIT_TO_PROCESS()
+
+	lineInfo->first_block = blk_pos;
+	lineInfo->start_offset = offset;
+	lineInfo->cur_lineno = cstate->cur_lineno;
+	pg_atomic_write_u32(&lineInfo->line_size, line_size);
+	pg_atomic_write_u32(&lineInfo->line_state, line_state);
+	lineBoundaryPtr->pos = (lineBoundaryPtr->pos + 1) % RINGSIZE;
+
+	return line_pos;
+}
+
+/*
  * ParallelCopyFrom - parallel copy leader's functionality.
  *
  * Leader executes the before statement for before statement trigger, if before
@@ -1106,8 +1541,298 @@ ParallelCopyFrom(CopyState cstate)
 	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
 	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
 
+	/* Execute the before statement triggers from the leader */
+	ExecBeforeStmtTrigger(cstate);
+
+	/* On input just throw the header line away. */
+	if (cstate->cur_lineno == 0 && cstate->header_line)
+	{
+		cstate->cur_lineno++;
+		if (CopyReadLine(cstate))
+		{
+			pcshared_info->is_read_in_progress = false;
+			return;			/* done */
+		}
+	}
+
+	for (;;)
+	{
+		bool done;
+		cstate->cur_lineno++;
+
+		/* Actually read the line into memory here. */
+		done = CopyReadLine(cstate);
+
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			break;
+	}
+
 	pcshared_info->is_read_in_progress = false;
 	cstate->cur_lineno = 0;
+ }
+
+/*
+ * GetLinePosition - return the line position that worker should process.
+ */
+static uint32
+GetLinePosition(CopyState cstate)
+{
+	ParallelCopyData *pcdata = cstate->pcdata;
+	ParallelCopyShmInfo *pcshared_info = pcdata->pcshared_info;
+	uint32  previous_pos = pcdata->worker_processed_pos;
+	uint32 write_pos = (previous_pos == -1) ? 0 : (previous_pos + 1) % RINGSIZE;
+	for (;;)
+	{
+		int		dataSize;
+		bool	is_read_in_progress = pcshared_info->is_read_in_progress;
+		ParallelCopyLineBoundary *lineInfo;
+		ParallelCopyDataBlock *data_blk_ptr;
+		ParallelCopyLineState line_state = LINE_LEADER_POPULATED;
+		ParallelCopyLineState curr_line_state;
+		CHECK_FOR_INTERRUPTS();
+
+		/* File read completed & no elements to process. */
+		if (!is_read_in_progress &&
+			(pcshared_info->populated ==
+			 pg_atomic_read_u64(&pcshared_info->total_worker_processed)))
+		{
+			write_pos = -1;
+			break;
+		}
+
+		/* Get the current line information. */
+		lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+		curr_line_state = pg_atomic_read_u32(&lineInfo->line_state);
+		if ((write_pos % WORKER_CHUNK_COUNT == 0) &&
+			(curr_line_state == LINE_WORKER_PROCESSED ||
+			 curr_line_state == LINE_WORKER_PROCESSING))
+		{
+			pcdata->worker_processed_pos = write_pos;
+			write_pos = (write_pos + WORKER_CHUNK_COUNT) %  RINGSIZE;
+			continue;
+		}
+
+		/* Get the size of this line. */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+		if (dataSize != 0) /* If not an empty line. */
+		{
+			/* Get the block information. */
+			data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+			if (!data_blk_ptr->curr_blk_completed && (dataSize == -1))
+			{
+				/* Wait till the current line or block is added. */
+				COPY_WAIT_TO_PROCESS()
+				continue;
+			}
+		}
+
+		/* Make sure that no worker has consumed this element. */
+		if (pg_atomic_compare_exchange_u32(&lineInfo->line_state,
+										   &line_state, LINE_WORKER_PROCESSING))
+			break;
+	}
+
+	pcdata->worker_processed_pos = write_pos;
+	return write_pos;
+}
+
+/*
+ * GetFreeCopyBlock - Get a free block for data to be copied.
+ */
+static pg_attribute_always_inline uint32
+GetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	int count = 0;
+	uint32 last_free_block = pcshared_info->cur_block_pos;
+	uint32 block_pos = (last_free_block != -1) ? ((last_free_block + 1) % MAX_BLOCKS_COUNT): 0;
+
+	/*
+	 * Get a new block for copying data, don't check current block, current
+	 * block will have some unprocessed data.
+	 */
+	while (count < (MAX_BLOCKS_COUNT - 1))
+	{
+		ParallelCopyDataBlock *dataBlkPtr = &pcshared_info->data_blocks[block_pos];
+		uint32 unprocessed_line_parts = pg_atomic_read_u32(&dataBlkPtr->unprocessed_line_parts);
+		if (unprocessed_line_parts == 0)
+		{
+			dataBlkPtr->curr_blk_completed = false;
+			dataBlkPtr->skip_bytes = 0;
+			pcshared_info->cur_block_pos = block_pos;
+			return block_pos;
+		}
+
+		block_pos = (block_pos + 1) % MAX_BLOCKS_COUNT;
+		count++;
+	}
+
+	return -1;
+}
+
+/*
+ * WaitGetFreeCopyBlock - If there are no blocks available, wait and get a block
+ * for copying data.
+ */
+static uint32
+WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	uint32 new_free_pos = -1;
+	for (;;)
+	{
+		new_free_pos = GetFreeCopyBlock(pcshared_info);
+		if (new_free_pos != -1)	/* We have got one block, break now. */
+			break;
+
+		COPY_WAIT_TO_PROCESS()
+	}
+
+	return new_free_pos;
+}
+
+/*
+ * SetRawBufForLoad - Set raw_buf to the shared memory where the file data must
+ * be read.
+ */
+static void
+SetRawBufForLoad(CopyState cstate, uint32 line_size, uint32 copy_buf_len,
+				 uint32 raw_buf_ptr, char **copy_raw_buf)
+{
+	ParallelCopyShmInfo	*pcshared_info;
+	uint32 cur_block_pos;
+	uint32 next_block_pos;
+	ParallelCopyDataBlock	*cur_data_blk_ptr = NULL;
+	ParallelCopyDataBlock	*next_data_blk_ptr = NULL;
+
+	if (!IsParallelCopy())
+		return;
+
+	pcshared_info = cstate->pcdata->pcshared_info;
+	cur_block_pos = pcshared_info->cur_block_pos;
+	cur_data_blk_ptr = (cstate->raw_buf) ? &pcshared_info->data_blocks[cur_block_pos] : NULL;
+	next_block_pos = WaitGetFreeCopyBlock(pcshared_info);
+	next_data_blk_ptr = &pcshared_info->data_blocks[next_block_pos];
+
+	/* set raw_buf to the data block in shared memory */
+	cstate->raw_buf = next_data_blk_ptr->data;
+	*copy_raw_buf = cstate->raw_buf;
+	if (cur_data_blk_ptr && line_size)
+	{
+		/*
+		 * Mark the previous block as completed, worker can start copying this
+		 * data.
+		 */
+		cur_data_blk_ptr->following_block = next_block_pos;
+		pg_atomic_add_fetch_u32(&cur_data_blk_ptr->unprocessed_line_parts, 1);
+		cur_data_blk_ptr->skip_bytes = copy_buf_len - raw_buf_ptr;
+		cur_data_blk_ptr->curr_blk_completed = true;
+	}
+}
+
+/*
+ * EndLineParallelCopy - Update the line information in shared memory.
+ */
+static void
+EndLineParallelCopy(CopyState cstate, uint32 line_pos, uint32 line_size,
+					 uint32 raw_buf_ptr)
+{
+	uint8 new_line_size;
+	if (!IsParallelCopy())
+		return;
+
+	if (!IsHeaderLine())
+	{
+		ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+		ParallelCopyLineBoundaries *lineBoundaryPtr = &pcshared_info->line_boundaries;
+		SET_NEWLINE_SIZE()
+		if (line_size)
+		{
+			ParallelCopyLineBoundary *lineInfo = &lineBoundaryPtr->ring[line_pos];
+			/*
+			 * If the new_line_size > raw_buf_ptr, then the new block has only
+			 * new line char content. The unprocessed count should not be
+			 * increased in this case.
+			 */
+			if (raw_buf_ptr > new_line_size)
+			{
+				uint32 cur_block_pos = pcshared_info->cur_block_pos;
+				ParallelCopyDataBlock *curr_data_blk_ptr = &pcshared_info->data_blocks[cur_block_pos];
+				pg_atomic_add_fetch_u32(&curr_data_blk_ptr->unprocessed_line_parts, 1);
+			}
+
+			/* Update line size. */
+			pg_atomic_write_u32(&lineInfo->line_size, line_size);
+			pg_atomic_write_u32(&lineInfo->line_state, LINE_LEADER_POPULATED);
+			elog(DEBUG1, "[Leader] After adding - line position:%d, line_size:%d",
+						 line_pos, line_size);
+			pcshared_info->populated++;
+		}
+		else if (new_line_size)
+		{
+			/* This means only new line char, empty record should be inserted.*/
+			ParallelCopyLineBoundary *lineInfo;
+			line_pos = UpdateBlockInLineInfo(cstate, -1, -1, 0,
+											   LINE_LEADER_POPULATED);
+			lineInfo = &lineBoundaryPtr->ring[line_pos];
+			elog(DEBUG1, "[Leader] Added empty line with offset:%d, line position:%d, line size:%d",
+						 lineInfo->start_offset, line_pos,
+						 pg_atomic_read_u32(&lineInfo->line_size));
+			pcshared_info->populated++;
+		}
+	}
+}
+
+/*
+ * ExecBeforeStmtTrigger - Execute the before statement trigger, this will be
+ * executed for parallel copy by the leader process.
+ */
+static void
+ExecBeforeStmtTrigger(CopyState cstate)
+{
+	EState	   *estate = CreateExecutorState();
+	ResultRelInfo *resultRelInfo;
+
+	Assert(IsLeader());
+
+	/*
+	 * We need a ResultRelInfo so we can use the regular executor's
+	 * index-entry-making machinery.  (There used to be a huge amount of code
+	 * here that basically duplicated execUtils.c ...)
+	 */
+	resultRelInfo = makeNode(ResultRelInfo);
+	InitResultRelInfo(resultRelInfo,
+					  cstate->rel,
+					  1,		/* must match rel's position in range_table */
+					  NULL,
+					  0);
+
+	/* Verify the named relation is a valid target for INSERT */
+	CheckValidResultRel(resultRelInfo, CMD_INSERT);
+
+	estate->es_result_relations = resultRelInfo;
+	estate->es_num_result_relations = 1;
+	estate->es_result_relation_info = resultRelInfo;
+
+	ExecInitRangeTable(estate, cstate->range_table);
+
+	/*
+	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
+	 * should do this for COPY, since it's not really an "INSERT" statement as
+	 * such. However, executing these triggers maintains consistency with the
+	 * EACH ROW triggers that we already fire on COPY.
+	 */
+	ExecBSInsertTriggers(estate, resultRelInfo);
+
+	/* Close any trigger target relations */
+	ExecCleanUpTriggerState(estate);
+
+	FreeExecutorState(estate);
 }
 
 /*
@@ -3584,7 +4309,8 @@ CopyFrom(CopyState cstate)
 
 	PartitionTupleRouting *proute = NULL;
 	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
+	CommandId	mycid = IsParallelCopy() ? GetCurrentCommandId(false) :
+										   GetCurrentCommandId(true);
 	int			ti_options = 0; /* start with default options for insert */
 	BulkInsertState bistate = NULL;
 	CopyInsertMethod insertMethod;
@@ -3594,7 +4320,14 @@ CopyFrom(CopyState cstate)
 	bool		has_instead_insert_row_trig;
 	bool		leafpart_use_multi_insert = false;
 
-	CheckTargetRelValidity(cstate);
+	/*
+	 * Perform this check if it is not parallel copy. In case of parallel
+	 * copy, this check is done by the leader, so that if any invalid case
+	 * exist the copy from command will error out from the leader itself,
+	 * avoiding launching workers, just to throw error.
+	 */
+	if (!IsParallelCopy())
+		CheckTargetRelValidity(cstate);
 
 	/*
 	 * If the target file is new-in-transaction, we assume that checking FSM
@@ -3634,7 +4367,8 @@ CopyFrom(CopyState cstate)
 	target_resultRelInfo = resultRelInfo;
 
 	/* Verify the named relation is a valid target for INSERT */
-	CheckValidResultRel(resultRelInfo, CMD_INSERT);
+	if (!IsParallelCopy())
+		CheckValidResultRel(resultRelInfo, CMD_INSERT);
 
 	ExecOpenIndices(resultRelInfo, false);
 
@@ -3783,13 +4517,16 @@ CopyFrom(CopyState cstate)
 	has_instead_insert_row_trig = (resultRelInfo->ri_TrigDesc &&
 								   resultRelInfo->ri_TrigDesc->trig_insert_instead_row);
 
-	/*
-	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
-	 * should do this for COPY, since it's not really an "INSERT" statement as
-	 * such. However, executing these triggers maintains consistency with the
-	 * EACH ROW triggers that we already fire on COPY.
-	 */
-	ExecBSInsertTriggers(estate, resultRelInfo);
+	if (!IsParallelCopy())
+	{
+		/*
+		 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
+		 * should do this for COPY, since it's not really an "INSERT" statement as
+		 * such. However, executing these triggers maintains consistency with the
+		 * EACH ROW triggers that we already fire on COPY.
+		 */
+		ExecBSInsertTriggers(estate, resultRelInfo);
+	}
 
 	econtext = GetPerTupleExprContext(estate);
 
@@ -3889,6 +4626,16 @@ CopyFrom(CopyState cstate)
 					!has_instead_insert_row_trig &&
 					resultRelInfo->ri_FdwRoutine == NULL;
 
+				/*
+				 * If the table has any partitions that are either foreign or
+				 * has BEFORE/INSTEAD OF triggers, we can't perform copy
+				 * operations with parallel workers.
+				 */
+				if (!leafpart_use_multi_insert && IsParallelWorker())
+					ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							errmsg("cannot perform PARALLEL COPY if partition has BEFORE/INSTEAD OF triggers, or if the partition is foreign partition"),
+							errhint("Try COPY without PARALLEL option")));
+
 				/* Set the multi-insert buffer to use for this partition. */
 				if (leafpart_use_multi_insert)
 				{
@@ -4305,7 +5052,7 @@ BeginCopyFrom(ParseState *pstate,
 	 * only in text mode.
 	 */
 	initStringInfo(&cstate->attribute_buf);
-	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+	cstate->raw_buf = (IsParallelCopy()) ? NULL : (char *) palloc(RAW_BUF_SIZE + 1);
 	cstate->raw_buf_index = cstate->raw_buf_len = 0;
 	if (!cstate->binary)
 	{
@@ -4454,26 +5201,35 @@ NextCopyFromRawFields(CopyState cstate, char ***fields, int *nfields)
 	/* only available for text or csv input */
 	Assert(!cstate->binary);
 
-	/* on input just throw the header line away */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (IsParallelCopy())
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
-			return false;		/* done */
+		done = GetWorkerLine(cstate);
+		if (done && cstate->line_buf.len == 0)
+			return false;
 	}
+	else
+	{
+		/* on input just throw the header line away */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
+		{
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+				return false;		/* done */
+		}
 
-	cstate->cur_lineno++;
+		cstate->cur_lineno++;
 
-	/* Actually read the line into memory here */
-	done = CopyReadLine(cstate);
+		/* Actually read the line into memory here */
+		done = CopyReadLine(cstate);
 
-	/*
-	 * EOF at start of line means we're done.  If we see EOF after some
-	 * characters, we act as though it was newline followed by EOF, ie,
-	 * process the line and then exit loop on next iteration.
-	 */
-	if (done && cstate->line_buf.len == 0)
-		return false;
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			return false;
+	}
 
 	/* Parse the line into de-escaped field values */
 	if (cstate->csv_mode)
@@ -4721,9 +5477,31 @@ CopyReadLine(CopyState cstate)
 		 */
 		if (cstate->copy_dest == COPY_NEW_FE)
 		{
+			bool bIsFirst = true;
 			do
 			{
-				cstate->raw_buf_index = cstate->raw_buf_len;
+				if (!IsParallelCopy())
+					cstate->raw_buf_index = cstate->raw_buf_len;
+				else
+				{
+					if (cstate->raw_buf_index == RAW_BUF_SIZE)
+					{
+						/* Get a new block if it is the first time, From the
+						 * subsequent time, reset the index and re-use the same
+						 * block.
+						 */
+						if (bIsFirst)
+						{
+							ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+							uint32 block_pos = WaitGetFreeCopyBlock(pcshared_info);
+							cstate->raw_buf = pcshared_info->data_blocks[block_pos].data;
+							bIsFirst = false;
+						}
+
+						cstate->raw_buf_index = cstate->raw_buf_len = 0;
+					}
+				}
+
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
@@ -4778,7 +5556,7 @@ static void
 ConvertToServerEncoding(CopyState cstate)
 {
 	/* Done reading the line.  Convert it to server encoding. */
-	if (cstate->need_transcoding)
+	if (cstate->need_transcoding && (!IsParallelCopy() || IsWorker()))
 	{
 		char	   *cvt;
 		cvt = pg_any_to_server(cstate->line_buf.data,
@@ -4817,6 +5595,11 @@ CopyReadLineText(CopyState cstate)
 	char		quotec = '\0';
 	char		escapec = '\0';
 
+	/* For parallel copy */
+	int			line_size = 0;
+	int			line_pos = 0;
+
+	cstate->eol_type = EOL_UNKNOWN;
 	if (cstate->csv_mode)
 	{
 		quotec = cstate->quote[0];
@@ -4871,6 +5654,8 @@ CopyReadLineText(CopyState cstate)
 		if (raw_buf_ptr >= copy_buf_len || need_data)
 		{
 			REFILL_LINEBUF;
+			SetRawBufForLoad(cstate, line_size, copy_buf_len, raw_buf_ptr,
+							 &copy_raw_buf);
 
 			/*
 			 * Try to read some more data.  This will certainly reset
@@ -5095,9 +5880,15 @@ CopyReadLineText(CopyState cstate)
 				 * discard the data and the \. sequence.
 				 */
 				if (prev_raw_ptr > cstate->raw_buf_index)
-					appendBinaryStringInfo(&cstate->line_buf,
+				{
+					if (!IsParallelCopy())
+						appendBinaryStringInfo(&cstate->line_buf,
 										   cstate->raw_buf + cstate->raw_buf_index,
 										   prev_raw_ptr - cstate->raw_buf_index);
+					else
+						line_size += prev_raw_ptr - cstate->raw_buf_index;
+				}
+
 				cstate->raw_buf_index = raw_buf_ptr;
 				result = true;	/* report EOF */
 				break;
@@ -5149,6 +5940,26 @@ not_end_of_copy:
 			IF_NEED_REFILL_AND_EOF_BREAK(mblen - 1);
 			raw_buf_ptr += mblen - 1;
 		}
+
+		/*
+		 * Skip the header line. Update the line here, this cannot be done at
+		 * the beginning, as there is a possibility that file contains empty
+		 * lines.
+		 */
+		if (IsParallelCopy() && first_char_in_line && !IsHeaderLine())
+		{
+			ParallelCopyShmInfo	*pcshared_info = cstate->pcdata->pcshared_info;
+			ParallelCopyLineBoundary *lineInfo;
+			uint32			 line_first_block = pcshared_info->cur_block_pos;
+			line_pos = UpdateBlockInLineInfo(cstate,
+											   line_first_block,
+											   cstate->raw_buf_index, -1,
+											   LINE_LEADER_POPULATING);
+			lineInfo = &pcshared_info->line_boundaries.ring[line_pos];
+			elog(DEBUG1, "[Leader] Adding - block:%d, offset:%d, line position:%d",
+						 line_first_block,	lineInfo->start_offset, line_pos);
+		}
+
 		first_char_in_line = false;
 	}							/* end of outer loop */
 
@@ -5157,6 +5968,7 @@ not_end_of_copy:
 	 */
 	REFILL_LINEBUF;
 	CLEAR_EOL_LINE();
+	EndLineParallelCopy(cstate, line_pos, line_size, raw_buf_ptr);
 
 	return result;
 }
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index c4af40b..c95db78 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -2353,7 +2353,7 @@ psql_completion(const char *text, int start, int end)
 	/* Complete COPY <sth> FROM|TO filename WITH ( */
 	else if (Matches("COPY|\\copy", MatchAny, "FROM|TO", MatchAny, "WITH", "("))
 		COMPLETE_WITH("FORMAT", "FREEZE", "DELIMITER", "NULL",
-					  "HEADER", "QUOTE", "ESCAPE", "FORCE_QUOTE",
+					  "HEADER", "PARALLEL", "QUOTE", "ESCAPE", "FORCE_QUOTE",
 					  "FORCE_NOT_NULL", "FORCE_NULL", "ENCODING");
 
 	/* Complete COPY <sth> FROM|TO filename WITH (FORMAT */
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index 5348011..4ea02f7 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -381,6 +381,8 @@ extern FullTransactionId GetTopFullTransactionId(void);
 extern FullTransactionId GetTopFullTransactionIdIfAny(void);
 extern FullTransactionId GetCurrentFullTransactionId(void);
 extern FullTransactionId GetCurrentFullTransactionIdIfAny(void);
+extern void AssignFullTransactionIdForWorker(FullTransactionId fullTransactionId);
+extern void AssignCommandIdForWorker(CommandId commandId, bool used);
 extern void MarkCurrentTransactionIdLoggedIfAny(void);
 extern bool SubTransactionIsActive(SubTransactionId subxid);
 extern CommandId GetCurrentCommandId(bool used);
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 3a83d0f..ba93f65 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1704,6 +1704,7 @@ ParallelCopyLineBoundary
 ParallelCopyData
 ParallelCopyDataBlock
 ParallelCopyLineBuf
+ParallelCopyLineState
 ParallelCopyShmInfo
 ParallelExecutorInfo
 ParallelHashGrowth
-- 
1.8.3.1

v2-0004-Documentation-for-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=v2-0004-Documentation-for-parallel-copy.patchDownload
From e543e3b3def9367bd30191ea334c26fb7e372b96 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Sat, 1 Aug 2020 09:00:36 +0530
Subject: [PATCH v2 4/5] Documentation for parallel copy.

This patch has the documentation changes for parallel copy.
---
 doc/src/sgml/ref/copy.sgml | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/doc/src/sgml/ref/copy.sgml b/doc/src/sgml/ref/copy.sgml
index 18189ab..95d349d 100644
--- a/doc/src/sgml/ref/copy.sgml
+++ b/doc/src/sgml/ref/copy.sgml
@@ -37,6 +37,7 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
     DELIMITER '<replaceable class="parameter">delimiter_character</replaceable>'
     NULL '<replaceable class="parameter">null_string</replaceable>'
     HEADER [ <replaceable class="parameter">boolean</replaceable> ]
+    PARALLEL <replaceable class="parameter">integer</replaceable>
     QUOTE '<replaceable class="parameter">quote_character</replaceable>'
     ESCAPE '<replaceable class="parameter">escape_character</replaceable>'
     FORCE_QUOTE { ( <replaceable class="parameter">column_name</replaceable> [, ...] ) | * }
@@ -275,6 +276,21 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
    </varlistentry>
 
    <varlistentry>
+    <term><literal>PARALLEL</literal></term>
+    <listitem>
+     <para>
+      Perform <command>COPY FROM</command> in parallel using <replaceable
+      class="parameter"> integer</replaceable> background workers.  Please
+      note that it is not guaranteed that the number of parallel workers
+      specified in <replaceable class="parameter">integer</replaceable> will
+      be used during execution.  It is possible for a copy to run with fewer
+      workers than specified, or even with no workers at all.  This option is
+      allowed only in <command>COPY FROM</command>.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><literal>QUOTE</literal></term>
     <listitem>
      <para>
-- 
1.8.3.1

v2-0005-Tests-for-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=v2-0005-Tests-for-parallel-copy.patchDownload
From ec2489bc2316da2aaa959e1e1c53df1f0a801d8a Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Sat, 1 Aug 2020 09:19:39 +0530
Subject: [PATCH v2 5/5] Tests for parallel copy.

This patch has the tests for parallel copy.
---
 src/test/regress/expected/copy2.out | 206 ++++++++++++++++++++++++++++++++++-
 src/test/regress/input/copy.source  |  12 +++
 src/test/regress/output/copy.source |  12 +++
 src/test/regress/sql/copy2.sql      | 208 +++++++++++++++++++++++++++++++++++-
 4 files changed, 430 insertions(+), 8 deletions(-)

diff --git a/src/test/regress/expected/copy2.out b/src/test/regress/expected/copy2.out
index e40287d..0e01fa0 100644
--- a/src/test/regress/expected/copy2.out
+++ b/src/test/regress/expected/copy2.out
@@ -254,18 +254,32 @@ It is "perfect".|
 "It is ""perfect"".","	"
 "",
 --test that we read consecutive LFs properly
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 COPY testnl FROM stdin CSV;
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+SELECT * FROM testnl;
+ a |          b           | c 
+---+----------------------+---
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+(2 rows)
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 COPY testeoc FROM stdin CSV;
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
 COPY testeoc TO stdout CSV;
 a\.
 \.b
 c\.d
 "\."
 -- test handling of nonstandard null marker that violates escaping rules
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 COPY testnull TO stdout WITH NULL AS E'\\0';
 1	\\0
@@ -280,6 +294,15 @@ SELECT * FROM testnull;
     | 
 (4 rows)
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 1);
+SELECT * FROM testnull;
+ a  | b  
+----+----
+ 42 | \0
+    | 
+(2 rows)
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -349,6 +372,34 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+SELECT * FROM vistest;
+ a  
+----
+ a2
+ b
+(2 rows)
+
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+COMMIT;
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 SELECT * FROM vistest;
  a 
@@ -409,7 +460,7 @@ SELECT * FROM vistest;
 (2 rows)
 
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -420,6 +471,8 @@ CREATE TEMP TABLE forcetest (
 -- should succeed with no effect ("b" remains an empty string, "c" remains NULL)
 BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 1);
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
  b |  c   
@@ -430,6 +483,8 @@ SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
 BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 1);
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
  c |  d   
@@ -486,6 +541,31 @@ select * from check_con_tbl;
    
 (2 rows)
 
+\d+ check_con_tbl
+                               Table "public.check_con_tbl"
+ Column |  Type   | Collation | Nullable | Default | Storage | Stats target | Description 
+--------+---------+-----------+----------+---------+---------+--------------+-------------
+ f1     | integer |           |          |         | plain   |              | 
+Check constraints:
+    "check_con_tbl_check" CHECK (check_con_function(check_con_tbl.*))
+
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 1);
+NOTICE:  input = {"f1":1}
+NOTICE:  input = {"f1":null}
+copy check_con_tbl from stdin with (parallel 1);
+NOTICE:  input = {"f1":0}
+ERROR:  new row for relation "check_con_tbl" violates check constraint "check_con_tbl_check"
+DETAIL:  Failing row contains (0).
+CONTEXT:  COPY check_con_tbl, line 1: "0"
+parallel worker
+select * from check_con_tbl;
+ f1 
+----
+  1
+   
+(2 rows)
+
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
 CREATE ROLE regress_rls_copy_user_colperms;
@@ -600,8 +680,126 @@ SELECT * FROM instead_of_insert_tbl;
 (2 rows)
 
 COMMIT;
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+COPY test_parallel_copy (a, b, c, d, e) from stdin with (PARALLEL 1);
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1, FORMAT 'csv', HEADER);
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0');
+ERROR:  argument to option "parallel" must be a positive integer greater than zero
+LINE 1: COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0'...
+                                                        ^
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri from stdin with (FORMAT csv, DELIMITER ',', PARALLEL 1);
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1) WHERE height > random() * 65;
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+-- temporary table copy: should perform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+COPY temp_test (a) from stdin with (PARALLEL 1);
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) from stdin with (PARALLEL 1);
+ERROR:  column "xyz" of relation "test_parallel_copy" does not exist
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) from stdin with (PARALLEL 1);
+ERROR:  column "d" specified more than once
+-- missing data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  invalid input syntax for type integer: ""
+CONTEXT:  COPY test_parallel_copy, line 0, column a: ""
+parallel worker
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2000	230	23	23"
+parallel worker
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2001	231	\N	\N"
+parallel worker
+-- extra data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  extra data after last expected column
+CONTEXT:  COPY test_parallel_copy, line 1: "2002	232	40	50	60	70	80"
+parallel worker
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) from stdin with (delimiter ',', null 'x', PARALLEL 1) ;
+COPY test_parallel_copy from stdin WITH (DELIMITER ';', NULL '', PARALLEL 1);
+COPY test_parallel_copy from stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL 1);
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = 50004;
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a > 60003;
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE f > 60003;
+ERROR:  column "f" does not exist
+LINE 1: ..._parallel_copy from stdin WITH (PARALLEL 1) WHERE f > 60003;
+                                                             ^
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+ERROR:  missing FROM-clause entry for table "x"
+LINE 1: ...rallel_copy from stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+                                                                  ^
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (SELECT 1 FROM x);
+ERROR:  cannot use subquery in COPY FROM WHERE condition
+LINE 1: ...arallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (SELECT...
+                                                             ^
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (generate_series(1,5));
+ERROR:  set-returning functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...lel_copy from stdin WITH (PARALLEL 1) WHERE a IN (generate_s...
+                                                             ^
+COPY test_parallel_copy from stdin WITH(PARALLEL 1) WHERE a = row_number() over(b);
+ERROR:  window functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...rallel_copy from stdin WITH(PARALLEL 1) WHERE a = row_number...
+                                                             ^
+-- check results of copy in
+SELECT * FROM test_parallel_copy;
+   a   | b  |     c      |    d    |    e    
+-------+----+------------+---------+---------
+     1 | 11 | test_c1    | test_d1 | test_e1
+     2 | 12 | test_c2    | test_d2 | test_e2
+       |  3 | stuff      | test_d3 | 
+       |  4 | stuff      | test_d4 | 
+       |  5 | stuff      | test_d5 | 
+       |    | 45         | 80      | 90
+       |    | x          | \x      | \x
+       |    | ,          | \,      | \
+  3000 |    | c          |         | 
+  4000 |    | C          |         | 
+  4001 |  1 | empty      |         | 
+  4002 |  2 | null       |         | 
+  4003 |  3 | Backslash  | \       | \
+  4004 |  4 | BackslashX | \X      | \X
+  4005 |  5 | N          | N       | N
+  4006 |  6 | BackslashN | \N      | \N
+  4007 |  7 | XX         | XX      | XX
+  4008 |  8 | Delimiter  | :       | :
+ 50004 | 25 | 35         | 45      | 55
+ 60004 | 25 | 35         | 45      | 55
+ 60005 | 26 | 36         | 46      | 56
+(21 rows)
+
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
 DROP TABLE x, y;
diff --git a/src/test/regress/input/copy.source b/src/test/regress/input/copy.source
index a1d529a..159c058 100644
--- a/src/test/regress/input/copy.source
+++ b/src/test/regress/input/copy.source
@@ -15,6 +15,13 @@ DELETE FROM onek;
 
 COPY onek FROM '@abs_builddir@/results/onek.data';
 
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+
+SELECT COUNT(*) FROM tenk1;
+
+TRUNCATE tenk1;
+
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
@@ -159,6 +166,11 @@ truncate parted_copytest;
 
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
 
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
+
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/output/copy.source b/src/test/regress/output/copy.source
index 938d355..c3003fe 100644
--- a/src/test/regress/output/copy.source
+++ b/src/test/regress/output/copy.source
@@ -9,6 +9,15 @@ COPY onek FROM '@abs_srcdir@/data/onek.data';
 COPY onek TO '@abs_builddir@/results/onek.data';
 DELETE FROM onek;
 COPY onek FROM '@abs_builddir@/results/onek.data';
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+SELECT COUNT(*) FROM tenk1;
+ count 
+-------
+ 10000
+(1 row)
+
+TRUNCATE tenk1;
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
 COPY person FROM '@abs_srcdir@/data/person.data';
@@ -113,6 +122,9 @@ insert into parted_copytest select x,1,'One' from generate_series(1011,1020) x;
 copy (select * from parted_copytest order by a) to '@abs_builddir@/results/parted_copytest.csv';
 truncate parted_copytest;
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/sql/copy2.sql b/src/test/regress/sql/copy2.sql
index 902f4fa..7015698 100644
--- a/src/test/regress/sql/copy2.sql
+++ b/src/test/regress/sql/copy2.sql
@@ -157,7 +157,7 @@ COPY y TO stdout (FORMAT CSV, FORCE_QUOTE *);
 
 --test that we read consecutive LFs properly
 
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 
 COPY testnl FROM stdin CSV;
 1,"a field with two LFs
@@ -165,8 +165,16 @@ COPY testnl FROM stdin CSV;
 inside",2
 \.
 
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+1,"a field with two LFs
+
+inside",2
+\.
+
+SELECT * FROM testnl;
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 
 COPY testeoc FROM stdin CSV;
 a\.
@@ -175,11 +183,19 @@ c\.d
 "\."
 \.
 
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+a\.
+\.b
+c\.d
+"\."
+\.
+
 COPY testeoc TO stdout CSV;
 
 -- test handling of nonstandard null marker that violates escaping rules
 
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 
 COPY testnull TO stdout WITH NULL AS E'\\0';
@@ -191,6 +207,14 @@ COPY testnull FROM stdin WITH NULL AS E'\\0';
 
 SELECT * FROM testnull;
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 1);
+42	\\0
+\0	\0
+\.
+
+SELECT * FROM testnull;
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -235,6 +259,23 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+a2
+b
+\.
+SELECT * FROM vistest;
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+d2
+e
+\.
+SELECT * FROM vistest;
+COMMIT;
+SELECT * FROM vistest;
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 x
 y
@@ -284,7 +325,7 @@ SELECT * FROM vistest;
 COMMIT;
 SELECT * FROM vistest;
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -297,6 +338,10 @@ BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
 1,,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 1);
+1,,""
+\.
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
@@ -304,6 +349,10 @@ BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
 2,'a',,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 1);
+2,'a',,""
+\.
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
 -- should fail with not-null constraint violation
@@ -339,6 +388,16 @@ copy check_con_tbl from stdin;
 0
 \.
 select * from check_con_tbl;
+\d+ check_con_tbl
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 1);
+1
+\N
+\.
+copy check_con_tbl from stdin with (parallel 1);
+0
+\.
+select * from check_con_tbl;
 
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
@@ -440,8 +499,149 @@ test1
 SELECT * FROM instead_of_insert_tbl;
 COMMIT;
 
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+
+COPY test_parallel_copy (a, b, c, d, e) from stdin with (PARALLEL 1);
+1	11	test_c1	test_d1	test_e1
+2	12	test_c2	test_d2	test_e2
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+3	test_d3
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+4	test_d4
+5	test_d5
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1, FORMAT 'csv', HEADER);
+b	d
+\.
+
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0');
+
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri from stdin with (FORMAT csv, DELIMITER ',', PARALLEL 1);
+10
+\.
+
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1) WHERE height > random() * 65;
+60,60,60
+\.
+
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+60
+\.
+
+-- temporary table copy: should perform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+
+COPY temp_test (a) from stdin with (PARALLEL 1);
+10
+\.
+
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) from stdin with (PARALLEL 1);
+
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) from stdin with (PARALLEL 1);
+
+-- missing data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+
+\.
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+2000	230	23	23
+\.
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+2001	231	\N	\N
+\.
+
+-- extra data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+2002	232	40	50	60	70	80
+\.
+
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) from stdin with (delimiter ',', null 'x', PARALLEL 1) ;
+x,45,80,90
+x,\x,\\x,\\\x
+x,\,,\\\,,\\
+\.
+
+COPY test_parallel_copy from stdin WITH (DELIMITER ';', NULL '', PARALLEL 1);
+3000;;c;;
+\.
+
+COPY test_parallel_copy from stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL 1);
+4000:\X:C:\X:\X
+4001:1:empty::
+4002:2:null:\X:\X
+4003:3:Backslash:\\:\\
+4004:4:BackslashX:\\X:\\X
+4005:5:N:\N:\N
+4006:6:BackslashN:\\N:\\N
+4007:7:XX:\XX:\XX
+4008:8:Delimiter:\::\:
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = 50004;
+50003	24	34	44	54
+50004	25	35	45 	55
+50005	26	36	46	56
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a > 60003;
+60001	22	32	42	52
+60002	23	33	43	53
+60003	24	34	44	54
+60004	25	35	45	55
+60005	26	36	46	56
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE f > 60003;
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (SELECT 1 FROM x);
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (generate_series(1,5));
+
+COPY test_parallel_copy from stdin WITH(PARALLEL 1) WHERE a = row_number() over(b);
+
+-- check results of copy in
+SELECT * FROM test_parallel_copy;
+
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
 DROP TABLE x, y;
-- 
1.8.3.1

#124Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: vignesh C (#123)
6 attachment(s)
Re: Parallel copy

On Sat, Aug 1, 2020 at 9:55 AM vignesh C <vignesh21@gmail.com> wrote:

The patches were not applying because of the recent commits.
I have rebased the patch over head & attached.

I rebased v2-0006-Parallel-Copy-For-Binary-Format-Files.patch.

Putting together all the patches rebased on to the latest commit
b8fdee7d0ca8bd2165d46fb1468f75571b706a01. Patches from 0001 to 0005
are rebased by Vignesh, that are from the previous mail and the patch
0006 is rebased by me.

Please consider this patch set for further review.

With Regards,
Bharath Rupireddy.
EnterpriseDB: http://www.enterprisedb.com

Attachments:

v2-0001-Copy-code-readjustment-to-support-parallel-copy.patchapplication/x-patch; name=v2-0001-Copy-code-readjustment-to-support-parallel-copy.patchDownload
From f2ba043af005c55961ed68c9a595cee58c46c79d Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Sat, 1 Aug 2020 08:52:48 +0530
Subject: [PATCH v2 1/5] Copy code readjustment to support parallel copy.

This patch has the copy code slightly readjusted so that the common code is
separated to functions/macros, these functions/macros will be used by the
workers in the parallel copy code of the upcoming patches. EOL removal is moved
from CopyReadLine to CopyReadLineText, this change was required because in case
of parallel copy the record identification and record updation is done in
CopyReadLineText, before record information is updated in shared memory the new
line characters should be removed.
---
 src/backend/commands/copy.c | 361 ++++++++++++++++++++++++++------------------
 1 file changed, 218 insertions(+), 143 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index db7d24a..3efafca 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -95,6 +95,9 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
+#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+#define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
+
 /*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
@@ -224,7 +227,6 @@ typedef struct CopyStateData
 	 * appropriate amounts of data from this buffer.  In both modes, we
 	 * guarantee that there is a \0 at raw_buf[raw_buf_len].
 	 */
-#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
@@ -354,6 +356,27 @@ if (1) \
 	goto not_end_of_copy; \
 } else ((void) 0)
 
+/*
+ * CLEAR_EOL_LINE - Wrapper for clearing EOL.
+ */
+#define CLEAR_EOL_LINE() \
+if (!result && !IsHeaderLine()) \
+	ClearEOLFromCopiedData(cstate, cstate->line_buf.data, \
+						   cstate->line_buf.len, \
+						   &cstate->line_buf.len) \
+
+/*
+ * INCREMENTPROCESSED - Increment the lines processed.
+ */
+#define INCREMENTPROCESSED(processed)  \
+processed++;
+
+/*
+ * GETPROCESSED - Get the lines processed.
+ */
+#define GETPROCESSED(processed) \
+return processed;
+
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
 
@@ -401,7 +424,11 @@ static bool CopyGetInt16(CopyState cstate, int16 *val);
 static bool CopyLoadRawBuf(CopyState cstate);
 static int	CopyReadBinaryData(CopyState cstate, char *dest, int nbytes);
 
-
+static void PopulateCommonCstateInfo(CopyState cstate, TupleDesc	tup_desc,
+									   List *attnamelist);
+static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
+								   int copy_line_pos, int *copy_line_size);
+static void ConvertToServerEncoding(CopyState cstate);
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
  * in past protocol redesigns.
@@ -801,14 +828,18 @@ CopyLoadRawBuf(CopyState cstate)
 {
 	int			nbytes = RAW_BUF_BYTES(cstate);
 	int			inbytes;
+	int         minread = 1;
 
 	/* Copy down the unprocessed data if any. */
 	if (nbytes > 0)
 		memmove(cstate->raw_buf, cstate->raw_buf + cstate->raw_buf_index,
 				nbytes);
 
+	if (cstate->copy_dest == COPY_NEW_FE)
+		minread = RAW_BUF_SIZE - nbytes;
+
 	inbytes = CopyGetData(cstate, cstate->raw_buf + nbytes,
-						  1, RAW_BUF_SIZE - nbytes);
+						  minread, RAW_BUF_SIZE - nbytes);
 	nbytes += inbytes;
 	cstate->raw_buf[nbytes] = '\0';
 	cstate->raw_buf_index = 0;
@@ -1514,7 +1545,6 @@ BeginCopy(ParseState *pstate,
 {
 	CopyState	cstate;
 	TupleDesc	tupDesc;
-	int			num_phys_attrs;
 	MemoryContext oldcontext;
 
 	/* Allocate workspace and zero all fields */
@@ -1680,6 +1710,24 @@ BeginCopy(ParseState *pstate,
 		tupDesc = cstate->queryDesc->tupDesc;
 	}
 
+	PopulateCommonCstateInfo(cstate, tupDesc, attnamelist);
+	cstate->copy_dest = COPY_FILE;	/* default */
+
+	MemoryContextSwitchTo(oldcontext);
+
+	return cstate;
+}
+
+/*
+ * PopulateCommonCstateInfo - Populates the common variables required for copy
+ * from operation. This is a helper function for BeginCopy function.
+ */
+static void
+PopulateCommonCstateInfo(CopyState cstate, TupleDesc	tupDesc,
+							List *attnamelist)
+{
+	int			num_phys_attrs;
+
 	/* Generate or convert list of attributes to process */
 	cstate->attnumlist = CopyGetAttnums(tupDesc, cstate->rel, attnamelist);
 
@@ -1799,12 +1847,6 @@ BeginCopy(ParseState *pstate,
 		 pg_database_encoding_max_length() > 1);
 	/* See Multibyte encoding comment above */
 	cstate->encoding_embeds_ascii = PG_ENCODING_IS_CLIENT_ONLY(cstate->file_encoding);
-
-	cstate->copy_dest = COPY_FILE;	/* default */
-
-	MemoryContextSwitchTo(oldcontext);
-
-	return cstate;
 }
 
 /*
@@ -2696,32 +2738,11 @@ CopyMultiInsertInfoStore(CopyMultiInsertInfo *miinfo, ResultRelInfo *rri,
 }
 
 /*
- * Copy FROM file to relation.
+ * Check if the relation specified in copy from is valid.
  */
-uint64
-CopyFrom(CopyState cstate)
+static void
+CheckTargetRelValidity(CopyState cstate)
 {
-	ResultRelInfo *resultRelInfo;
-	ResultRelInfo *target_resultRelInfo;
-	ResultRelInfo *prevResultRelInfo = NULL;
-	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
-	ModifyTableState *mtstate;
-	ExprContext *econtext;
-	TupleTableSlot *singleslot = NULL;
-	MemoryContext oldcontext = CurrentMemoryContext;
-
-	PartitionTupleRouting *proute = NULL;
-	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
-	int			ti_options = 0; /* start with default options for insert */
-	BulkInsertState bistate = NULL;
-	CopyInsertMethod insertMethod;
-	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
-	uint64		processed = 0;
-	bool		has_before_insert_row_trig;
-	bool		has_instead_insert_row_trig;
-	bool		leafpart_use_multi_insert = false;
-
 	Assert(cstate->rel);
 
 	/*
@@ -2758,27 +2779,6 @@ CopyFrom(CopyState cstate)
 							RelationGetRelationName(cstate->rel))));
 	}
 
-	/*
-	 * If the target file is new-in-transaction, we assume that checking FSM
-	 * for free space is a waste of time.  This could possibly be wrong, but
-	 * it's unlikely.
-	 */
-	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
-		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
-		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
-		ti_options |= TABLE_INSERT_SKIP_FSM;
-
-	/*
-	 * Optimize if new relfilenode was created in this subxact or one of its
-	 * committed children and we won't see those rows later as part of an
-	 * earlier scan or command. The subxact test ensures that if this subxact
-	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
-	 * that the stronger test of exactly which subtransaction created it is
-	 * crucial for correctness of this optimization. The test for an earlier
-	 * scan or command tolerates false negatives. FREEZE causes other sessions
-	 * to see rows they would not see under MVCC, and a false negative merely
-	 * spreads that anomaly to the current session.
-	 */
 	if (cstate->freeze)
 	{
 		/*
@@ -2816,9 +2816,61 @@ CopyFrom(CopyState cstate)
 			ereport(ERROR,
 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 					 errmsg("cannot perform COPY FREEZE because the table was not created or truncated in the current subtransaction")));
+	}
+}
+
+/*
+ * Copy FROM file to relation.
+ */
+uint64
+CopyFrom(CopyState cstate)
+{
+	ResultRelInfo *resultRelInfo;
+	ResultRelInfo *target_resultRelInfo;
+	ResultRelInfo *prevResultRelInfo = NULL;
+	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
+	ModifyTableState *mtstate;
+	ExprContext *econtext;
+	TupleTableSlot *singleslot = NULL;
+	MemoryContext oldcontext = CurrentMemoryContext;
+
+	PartitionTupleRouting *proute = NULL;
+	ErrorContextCallback errcallback;
+	CommandId	mycid = GetCurrentCommandId(true);
+	int			ti_options = 0; /* start with default options for insert */
+	BulkInsertState bistate = NULL;
+	CopyInsertMethod insertMethod;
+	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
+	uint64		processed = 0;
+	bool		has_before_insert_row_trig;
+	bool		has_instead_insert_row_trig;
+	bool		leafpart_use_multi_insert = false;
+
+	CheckTargetRelValidity(cstate);
 
+	/*
+	 * If the target file is new-in-transaction, we assume that checking FSM
+	 * for free space is a waste of time.  This could possibly be wrong, but
+	 * it's unlikely.
+	 */
+	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
+		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
+		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
+		ti_options |= TABLE_INSERT_SKIP_FSM;
+
+	/*
+	 * Optimize if new relfilenode was created in this subxact or one of its
+	 * committed children and we won't see those rows later as part of an
+	 * earlier scan or command. The subxact test ensures that if this subxact
+	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
+	 * that the stronger test of exactly which subtransaction created it is
+	 * crucial for correctness of this optimization. The test for an earlier
+	 * scan or command tolerates false negatives. FREEZE causes other sessions
+	 * to see rows they would not see under MVCC, and a false negative merely
+	 * spreads that anomaly to the current session.
+	 */
+	if (cstate->freeze)
 		ti_options |= TABLE_INSERT_FROZEN;
-	}
 
 	/*
 	 * We need a ResultRelInfo so we can use the regular executor's
@@ -3311,7 +3363,7 @@ CopyFrom(CopyState cstate)
 			 * or FDW; this is the same definition used by nodeModifyTable.c
 			 * for counting tuples inserted by an INSERT command.
 			 */
-			processed++;
+			INCREMENTPROCESSED(processed)
 		}
 	}
 
@@ -3366,30 +3418,15 @@ CopyFrom(CopyState cstate)
 
 	FreeExecutorState(estate);
 
-	return processed;
+	GETPROCESSED(processed)
 }
 
 /*
- * Setup to read tuples from a file for COPY FROM.
- *
- * 'rel': Used as a template for the tuples
- * 'filename': Name of server-local file to read
- * 'attnamelist': List of char *, columns to include. NIL selects all cols.
- * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
- *
- * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ * PopulateCstateCatalogInfo - populate the catalog information.
  */
-CopyState
-BeginCopyFrom(ParseState *pstate,
-			  Relation rel,
-			  const char *filename,
-			  bool is_program,
-			  copy_data_source_cb data_source_cb,
-			  List *attnamelist,
-			  List *options)
+static void
+PopulateCstateCatalogInfo(CopyState cstate)
 {
-	CopyState	cstate;
-	bool		pipe = (filename == NULL);
 	TupleDesc	tupDesc;
 	AttrNumber	num_phys_attrs,
 				num_defaults;
@@ -3399,38 +3436,8 @@ BeginCopyFrom(ParseState *pstate,
 	Oid			in_func_oid;
 	int		   *defmap;
 	ExprState **defexprs;
-	MemoryContext oldcontext;
 	bool		volatile_defexprs;
 
-	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
-	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
-
-	/* Initialize state variables */
-	cstate->reached_eof = false;
-	cstate->eol_type = EOL_UNKNOWN;
-	cstate->cur_relname = RelationGetRelationName(cstate->rel);
-	cstate->cur_lineno = 0;
-	cstate->cur_attname = NULL;
-	cstate->cur_attval = NULL;
-
-	/*
-	 * Set up variables to avoid per-attribute overhead.  attribute_buf and
-	 * raw_buf are used in both text and binary modes, but we use line_buf
-	 * only in text mode.
-	 */
-	initStringInfo(&cstate->attribute_buf);
-	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
-	cstate->raw_buf_index = cstate->raw_buf_len = 0;
-	if (!cstate->binary)
-	{
-		initStringInfo(&cstate->line_buf);
-		cstate->line_buf_converted = false;
-	}
-
-	/* Assign range table, we'll need it in CopyFrom. */
-	if (pstate)
-		cstate->range_table = pstate->p_rtable;
-
 	tupDesc = RelationGetDescr(cstate->rel);
 	num_phys_attrs = tupDesc->natts;
 	num_defaults = 0;
@@ -3508,6 +3515,61 @@ BeginCopyFrom(ParseState *pstate,
 	cstate->defexprs = defexprs;
 	cstate->volatile_defexprs = volatile_defexprs;
 	cstate->num_defaults = num_defaults;
+}
+
+/*
+ * Setup to read tuples from a file for COPY FROM.
+ *
+ * 'rel': Used as a template for the tuples
+ * 'filename': Name of server-local file to read
+ * 'attnamelist': List of char *, columns to include. NIL selects all cols.
+ * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
+ *
+ * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ */
+CopyState
+BeginCopyFrom(ParseState *pstate,
+			  Relation rel,
+			  const char *filename,
+			  bool is_program,
+			  copy_data_source_cb data_source_cb,
+			  List *attnamelist,
+			  List *options)
+{
+	CopyState	cstate;
+	bool		pipe = (filename == NULL);
+	MemoryContext oldcontext;
+
+	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	/* Initialize state variables */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/*
+	 * Set up variables to avoid per-attribute overhead.  attribute_buf is
+	 * used in both text and binary modes, but we use line_buf and raw_buf
+	 * only in text mode.
+	 */
+	initStringInfo(&cstate->attribute_buf);
+	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+	if (!cstate->binary)
+	{
+		initStringInfo(&cstate->line_buf);
+		cstate->line_buf_converted = false;
+	}
+
+	/* Assign range table, we'll need it in CopyFrom. */
+	if (pstate)
+		cstate->range_table = pstate->p_rtable;
+
+	PopulateCstateCatalogInfo(cstate);
 	cstate->is_program = is_program;
 
 	if (data_source_cb)
@@ -3917,45 +3979,60 @@ CopyReadLine(CopyState cstate)
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
-	else
-	{
-		/*
-		 * If we didn't hit EOF, then we must have transferred the EOL marker
-		 * to line_buf along with the data.  Get rid of it.
-		 */
-		switch (cstate->eol_type)
-		{
-			case EOL_NL:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CR:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\r');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CRNL:
-				Assert(cstate->line_buf.len >= 2);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 2] == '\r');
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len -= 2;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_UNKNOWN:
-				/* shouldn't get here */
-				Assert(false);
-				break;
-		}
-	}
 
+	ConvertToServerEncoding(cstate);
+	return result;
+}
+
+/*
+ * ClearEOLFromCopiedData - Clear EOL from the copied data.
+ */
+static void
+ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
+					   int copy_line_pos, int *copy_line_size)
+{
+	/*
+	 * If we didn't hit EOF, then we must have transferred the EOL marker
+	 * to line_buf along with the data.  Get rid of it.
+	 */
+   switch (cstate->eol_type)
+   {
+	   case EOL_NL:
+		   Assert(*copy_line_size >= 1);
+		   Assert(copy_line_data[copy_line_pos - 1] == '\n');
+		   copy_line_data[copy_line_pos - 1] = '\0';
+		   (*copy_line_size)--;
+		   break;
+	   case EOL_CR:
+		   Assert(*copy_line_size >= 1);
+		   Assert(copy_line_data[copy_line_pos - 1] == '\r');
+		   copy_line_data[copy_line_pos - 1] = '\0';
+		   (*copy_line_size)--;
+		   break;
+	   case EOL_CRNL:
+		   Assert(*copy_line_size >= 2);
+		   Assert(copy_line_data[copy_line_pos - 2] == '\r');
+		   Assert(copy_line_data[copy_line_pos - 1] == '\n');
+		   copy_line_data[copy_line_pos - 2] = '\0';
+		   *copy_line_size -= 2;
+		   break;
+	   case EOL_UNKNOWN:
+		   /* shouldn't get here */
+		   Assert(false);
+		   break;
+   }
+}
+
+/*
+ * ConvertToServerEncoding - convert contents to server encoding.
+ */
+static void
+ConvertToServerEncoding(CopyState cstate)
+{
 	/* Done reading the line.  Convert it to server encoding. */
 	if (cstate->need_transcoding)
 	{
 		char	   *cvt;
-
 		cvt = pg_any_to_server(cstate->line_buf.data,
 							   cstate->line_buf.len,
 							   cstate->file_encoding);
@@ -3967,11 +4044,8 @@ CopyReadLine(CopyState cstate)
 			pfree(cvt);
 		}
 	}
-
 	/* Now it's safe to use the buffer in error messages */
 	cstate->line_buf_converted = true;
-
-	return result;
 }
 
 /*
@@ -4334,6 +4408,7 @@ not_end_of_copy:
 	 * Transfer any still-uncopied data to line_buf.
 	 */
 	REFILL_LINEBUF;
+	CLEAR_EOL_LINE();
 
 	return result;
 }
-- 
1.8.3.1

v2-0002-Framework-for-leader-worker-in-parallel-copy.patchapplication/x-patch; name=v2-0002-Framework-for-leader-worker-in-parallel-copy.patchDownload
From 1bf7d74c7308e6eae807c0258322abbb3890aede Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Sat, 1 Aug 2020 08:56:39 +0530
Subject: [PATCH v2 2/5] Framework for leader/worker in parallel copy

This patch has the framework for data structures in parallel copy, leader
initialization, worker initialization, shared memory updation, starting workers,
wait for workers and workers exiting.
---
 src/backend/access/transam/parallel.c |   4 +
 src/backend/commands/copy.c           | 756 +++++++++++++++++++++++++++++++++-
 src/include/commands/copy.h           |   2 +
 src/tools/pgindent/typedefs.list      |   7 +
 4 files changed, 765 insertions(+), 4 deletions(-)

diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index b042696..a3cff4b 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -25,6 +25,7 @@
 #include "catalog/pg_enum.h"
 #include "catalog/storage.h"
 #include "commands/async.h"
+#include "commands/copy.h"
 #include "executor/execParallel.h"
 #include "libpq/libpq.h"
 #include "libpq/pqformat.h"
@@ -145,6 +146,9 @@ static const struct
 	},
 	{
 		"parallel_vacuum_main", parallel_vacuum_main
+	},
+	{
+		"ParallelCopyMain", ParallelCopyMain
 	}
 };
 
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 3efafca..3dcdfc1 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -96,9 +96,180 @@ typedef enum CopyInsertMethod
 } CopyInsertMethod;
 
 #define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+
+/*
+ * The macros DATA_BLOCK_SIZE, RINGSIZE & MAX_BLOCKS_COUNT stores the records
+ * read from the file that need to be inserted into the relation. These values
+ * help in handover of multiple records with significant size of data to be
+ * processed by each of the workers to make sure there is no context switch & the
+ * work is fairly distributed among the workers. This number showed best
+ * results in the performance tests.
+ */
+#define DATA_BLOCK_SIZE RAW_BUF_SIZE
+
+/* It can hold upto 10000 record information for worker to process. */
+#define RINGSIZE (10 * 1000)
+
+/* It can hold 1000 blocks of 64K data in DSM to be processed by the worker. */
+#define MAX_BLOCKS_COUNT 1000
+
+/*
+ * Each worker will be allocated WORKER_CHUNK_COUNT of records from DSM data
+ * block to process to avoid lock contention. This value should be mode of
+ * RINGSIZE, as wrap around cases is currently not handled while selecting the
+ * WORKER_CHUNK_COUNT by the worker.
+ */
+#define WORKER_CHUNK_COUNT 50
+
+#define	IsParallelCopy()		(cstate->is_parallel)
+#define IsLeader()				(cstate->pcdata->is_leader)
 #define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
 
 /*
+ * Copy data block information.
+ * ParallelCopyDataBlock's will be created in DSM. Data read from file will be
+ * copied in these DSM data blocks. The leader process identifies the records
+ * and the record information will be shared to the workers. The workers will
+ * insert the records into the table. There can be one or more number of records
+ * in each of the data block based on the record size.
+ */
+typedef struct ParallelCopyDataBlock
+{
+	/* The number of unprocessed lines in the current block. */
+	pg_atomic_uint32 unprocessed_line_parts;
+
+	/*
+	 * If the current line data is continued into another block, following_block
+	 * will have the position where the remaining data need to be read.
+	 */
+	uint32	following_block;
+
+	/*
+	 * This flag will be set, when the leader finds out this block can be read
+	 * safely by the worker. This helps the worker to start processing the line
+	 * early where the line will be spread across many blocks and the worker
+	 * need not wait for the complete line to be processed.
+	 */
+	bool   curr_blk_completed;
+	char   data[DATA_BLOCK_SIZE]; /* data read from file */
+	uint8  skip_bytes;
+}ParallelCopyDataBlock;
+
+/*
+ * Individual line information.
+ * ParallelCopyLineBoundary is common data structure between leader & worker,
+ * Leader process will be populating data block, data block offset & the size of
+ * the record in DSM for the workers to copy the data into the relation.
+ * This is protected by the following sequence in the leader & worker. If they
+ * don't follow this order the worker might process wrong line_size and leader
+ * might populate the information which worker has not yet processed or in the
+ * process of processing.
+ * Leader should operate in the following order:
+ * 1) check if line_size is -1, if not wait, it means worker is still
+ * processing.
+ * 2) set line_state to LINE_LEADER_POPULATING.
+ * 3) update first_block, start_offset & cur_lineno in any order.
+ * 4) update line_size.
+ * 5) update line_state to LINE_LEADER_POPULATED.
+ * Worker should operate in the following order:
+ * 1) check line_state is LINE_LEADER_POPULATED, if not it means leader is still
+ * populating the data.
+ * 2) read line_size.
+ * 3) only one worker should choose one line for processing, this is handled by
+ *    using pg_atomic_compare_exchange_u32, worker will change the sate to
+ *    LINE_WORKER_PROCESSING only if line_state is LINE_LEADER_POPULATED.
+ * 4) read first_block, start_offset & cur_lineno in any order.
+ * 5) process line_size data.
+ * 6) update line_size to -1.
+ */
+typedef struct ParallelCopyLineBoundary
+{
+	/* Position of the first block in data_blocks array. */
+	uint32				first_block;
+	uint32				start_offset;   /* start offset of the line */
+
+	/*
+	 * Size of the current line -1 means line is yet to be filled completely,
+	 * 0 means empty line, >0 means line filled with line size data.
+	 */
+	pg_atomic_uint32	line_size;
+	pg_atomic_uint32	line_state;		/* line state */
+	uint64				cur_lineno;		/* line number for error messages */
+}ParallelCopyLineBoundary;
+
+/*
+ * Circular queue used to store the line information.
+ */
+typedef struct ParallelCopyLineBoundaries
+{
+	/* Position for the leader to populate a line. */
+	uint32			pos;
+
+	/* Data read from the file/stdin by the leader process. */
+	ParallelCopyLineBoundary	ring[RINGSIZE];
+}ParallelCopyLineBoundaries;
+
+/*
+ * Shared information among parallel copy workers. This will be allocated in the
+ * DSM segment.
+ */
+typedef struct ParallelCopyShmInfo
+{
+	bool					is_read_in_progress; /* file read status */
+
+	/*
+	 * Actual lines inserted by worker, will not be same as
+	 * total_worker_processed if where condition is specified along with copy.
+	 * This will be the actual records inserted into the relation.
+	 */
+	pg_atomic_uint64			processed;
+
+	/*
+	 * The number of records currently processed by the worker, this will also
+	 * include the number of records that was filtered because of where clause.
+	 */
+	pg_atomic_uint64			total_worker_processed;
+	uint64						populated; /* lines populated by leader */
+	uint32						cur_block_pos; /* current data block */
+	ParallelCopyDataBlock		data_blocks[MAX_BLOCKS_COUNT]; /* data block array */
+	FullTransactionId			full_transaction_id; /* xid for copy from statement */
+	CommandId					mycid;	/* command id */
+	ParallelCopyLineBoundaries	line_boundaries; /* line array */
+} ParallelCopyShmInfo;
+
+/*
+ * Parallel copy line buffer information.
+ */
+typedef struct ParallelCopyLineBuf
+{
+	StringInfoData		line_buf;
+	uint64				cur_lineno;	/* line number for error messages */
+}ParallelCopyLineBuf;
+
+/*
+ * Parallel copy data information.
+ */
+typedef struct ParallelCopyData
+{
+	Oid					relid;				/* relation id of the table */
+	ParallelCopyShmInfo	*pcshared_info;		/* common info in shared memory */
+	bool				is_leader;
+
+	/* line position which worker is processing */
+	uint32				worker_processed_pos;
+
+	/*
+	 * Local line_buf array, workers will copy it here and release the lines
+	 * for the leader to continue.
+	 */
+	ParallelCopyLineBuf	worker_line_buf[WORKER_CHUNK_COUNT];
+	uint32				worker_line_buf_count; /* Number of lines */
+
+	/* Current position in worker_line_buf */
+	uint32				worker_line_buf_pos;
+}ParallelCopyData;
+
+/*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
  * even though some fields are used in only some cases.
@@ -230,10 +401,38 @@ typedef struct CopyStateData
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
+	int			nworkers;
+	bool		is_parallel;
+	ParallelCopyData *pcdata;
 	/* Shorthand for number of unconsumed bytes available in raw_buf */
 #define RAW_BUF_BYTES(cstate) ((cstate)->raw_buf_len - (cstate)->raw_buf_index)
 } CopyStateData;
 
+/*
+ * This structure helps in storing the common data from CopyStateData that are
+ * required by the workers. This information will then be allocated and stored
+ * into the DSM for the worker to retrieve and copy it to CopyStateData.
+ */
+typedef struct SerializedParallelCopyState
+{
+	/* low-level state data */
+	CopyDest            copy_dest;		/* type of copy source/destination */
+	int                 file_encoding;	/* file or remote side's character encoding */
+	bool                need_transcoding;	/* file encoding diff from server? */
+	bool                encoding_embeds_ascii;	/* ASCII can be non-first byte? */
+
+	/* parameters from the COPY command */
+	bool                csv_mode;		/* Comma Separated Value format? */
+	bool                header_line;	/* CSV header line? */
+	int                 null_print_len; /* length of same */
+	bool                force_quote_all;	/* FORCE_QUOTE *? */
+	bool                convert_selectively;	/* do selective binary conversion? */
+
+	/* Working state for COPY FROM */
+	AttrNumber          num_defaults;
+	Oid                 relid;
+}SerializedParallelCopyState;
+
 /* DestReceiver for COPY (query) TO */
 typedef struct
 {
@@ -263,6 +462,22 @@ typedef struct
 /* Trim the list of buffers back down to this number after flushing */
 #define MAX_PARTITION_BUFFERS	32
 
+/* DSM keys for parallel copy.  */
+#define PARALLEL_COPY_KEY_SHARED_INFO		    1
+#define PARALLEL_COPY_KEY_CSTATE				2
+#define PARALLEL_COPY_KEY_NULL_PRINT			3
+#define PARALLEL_COPY_KEY_DELIM					4
+#define PARALLEL_COPY_KEY_QUOTE					5
+#define PARALLEL_COPY_KEY_ESCAPE				6
+#define PARALLEL_COPY_KEY_ATTNAME_LIST			7
+#define PARALLEL_COPY_KEY_NOT_NULL_LIST		    8
+#define PARALLEL_COPY_KEY_NULL_LIST			    9
+#define PARALLEL_COPY_KEY_CONVERT_LIST		   10
+#define PARALLEL_COPY_KEY_WHERE_CLAUSE_STR     11
+#define PARALLEL_COPY_KEY_RANGE_TABLE		   12
+#define PARALLEL_COPY_WAL_USAGE				   13
+#define PARALLEL_COPY_BUFFER_USAGE			   14
+
 /* Stores multi-insert data related to a single relation in CopyFrom. */
 typedef struct CopyMultiInsertBuffer
 {
@@ -424,11 +639,477 @@ static bool CopyGetInt16(CopyState cstate, int16 *val);
 static bool CopyLoadRawBuf(CopyState cstate);
 static int	CopyReadBinaryData(CopyState cstate, char *dest, int nbytes);
 
+static pg_attribute_always_inline void EndParallelCopy(ParallelContext *pcxt);
 static void PopulateCommonCstateInfo(CopyState cstate, TupleDesc	tup_desc,
-									   List *attnamelist);
+									 List *attnamelist);
 static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
 								   int copy_line_pos, int *copy_line_size);
 static void ConvertToServerEncoding(CopyState cstate);
+
+/*
+ * SerializeParallelCopyState - Copy shared_cstate using cstate information.
+ */
+static pg_attribute_always_inline void
+SerializeParallelCopyState(CopyState cstate, SerializedParallelCopyState *shared_cstate)
+{
+	shared_cstate->copy_dest = cstate->copy_dest;
+	shared_cstate->file_encoding = cstate->file_encoding;
+	shared_cstate->need_transcoding = cstate->need_transcoding;
+	shared_cstate->encoding_embeds_ascii = cstate->encoding_embeds_ascii;
+	shared_cstate->csv_mode = cstate->csv_mode;
+	shared_cstate->header_line = cstate->header_line;
+	shared_cstate->null_print_len = cstate->null_print_len;
+	shared_cstate->force_quote_all = cstate->force_quote_all;
+	shared_cstate->convert_selectively = cstate->convert_selectively;
+	shared_cstate->num_defaults = cstate->num_defaults;
+	shared_cstate->relid = cstate->pcdata->relid;
+}
+
+/*
+ * RestoreString - Retrieve the string from shared memory.
+ */
+static void
+RestoreString(shm_toc *toc, int sharedkey, char **copystr)
+{
+	char *shared_str_val = (char *)shm_toc_lookup(toc, sharedkey, true);
+	if (shared_str_val)
+		*copystr = pstrdup(shared_str_val);
+}
+
+/*
+ * EstimateLineKeysStr - Estimate the size required in shared memory for the
+ * input string.
+ */
+static void
+EstimateLineKeysStr(ParallelContext *pcxt, char *inputstr)
+{
+	if (inputstr)
+	{
+		shm_toc_estimate_chunk(&pcxt->estimator, strlen(inputstr) + 1);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+}
+
+/*
+ * SerializeString - Insert a string into shared memory.
+ */
+static void
+SerializeString(ParallelContext *pcxt, int key, char *inputstr)
+{
+	if (inputstr)
+	{
+		char *shmptr = (char *)shm_toc_allocate(pcxt->toc,
+												strlen(inputstr) + 1);
+		strcpy(shmptr, inputstr);
+		shm_toc_insert(pcxt->toc, key, shmptr);
+	}
+}
+
+/*
+ * PopulateParallelCopyShmInfo - set ParallelCopyShmInfo.
+ */
+static void
+PopulateParallelCopyShmInfo(ParallelCopyShmInfo *shared_info_ptr,
+							FullTransactionId full_transaction_id)
+{
+	uint32 count;
+
+	MemSet(shared_info_ptr, 0, sizeof(ParallelCopyShmInfo));
+	shared_info_ptr->is_read_in_progress = true;
+	shared_info_ptr->cur_block_pos = -1;
+	shared_info_ptr->full_transaction_id = full_transaction_id;
+	shared_info_ptr->mycid = GetCurrentCommandId(true);
+	for (count = 0; count < RINGSIZE; count++)
+	{
+		ParallelCopyLineBoundary *lineInfo = &shared_info_ptr->line_boundaries.ring[count];
+		pg_atomic_init_u32(&(lineInfo->line_size), -1);
+	}
+}
+
+/*
+ * BeginParallelCopy - start parallel copy tasks.
+ *
+ * Get the number of workers required to perform the parallel copy. The data
+ * structures that are required by the parallel workers will be initialized, the
+ * size required in DSM will be calculated and the necessary keys will be loaded
+ * in the DSM. The specified number of workers will then be launched.
+ */
+static ParallelContext*
+BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
+{
+	ParallelContext *pcxt;
+	ParallelCopyShmInfo *shared_info_ptr;
+	SerializedParallelCopyState *shared_cstate;
+	FullTransactionId full_transaction_id;
+	Size est_cstateshared;
+	char *whereClauseStr = NULL;
+	char *rangeTableStr = NULL;
+	char *attnameListStr = NULL;
+	char *notnullListStr = NULL;
+	char *nullListStr = NULL;
+	char *convertListStr = NULL;
+	int  parallel_workers = 0;
+	WalUsage   *walusage;
+	BufferUsage *bufferusage;
+	ParallelCopyData *pcdata;
+	MemoryContext oldcontext;
+
+	parallel_workers = Min(nworkers, max_worker_processes);
+
+	/* Can't perform copy in parallel */
+	if (parallel_workers <= 0)
+		return NULL;
+
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	MemoryContextSwitchTo(oldcontext);
+	cstate->pcdata = pcdata;
+
+	EnterParallelMode();
+	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
+								 parallel_workers);
+	Assert(pcxt->nworkers > 0);
+
+	/*
+	 * Estimate size for shared information for PARALLEL_COPY_KEY_SHARED_INFO
+	 */
+	shm_toc_estimate_chunk(&pcxt->estimator, sizeof(ParallelCopyShmInfo));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_CSTATE */
+	est_cstateshared = 	MAXALIGN(sizeof(SerializedParallelCopyState));
+	shm_toc_estimate_chunk(&pcxt->estimator, est_cstateshared);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	EstimateLineKeysStr(pcxt, cstate->null_print);
+	EstimateLineKeysStr(pcxt, cstate->null_print_client);
+	EstimateLineKeysStr(pcxt, cstate->delim);
+	EstimateLineKeysStr(pcxt, cstate->quote);
+	EstimateLineKeysStr(pcxt, cstate->escape);
+
+	if (cstate->whereClause != NULL)
+	{
+		whereClauseStr = nodeToString(cstate->whereClause);
+		EstimateLineKeysStr(pcxt, whereClauseStr);
+	}
+
+	if (cstate->range_table != NULL)
+	{
+		rangeTableStr = nodeToString(cstate->range_table);
+		EstimateLineKeysStr(pcxt, rangeTableStr);
+	}
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_XID. */
+	shm_toc_estimate_chunk(&pcxt->estimator, sizeof(FullTransactionId));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_ATTNAME_LIST.
+	 */
+	if (attnamelist != NIL)
+	{
+		attnameListStr = nodeToString(attnamelist);
+		EstimateLineKeysStr(pcxt, attnameListStr);
+	}
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_NOT_NULL_LIST.
+	 */
+	if (cstate->force_notnull != NIL)
+	{
+		notnullListStr = nodeToString(cstate->force_notnull);
+		EstimateLineKeysStr(pcxt, notnullListStr);
+	}
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_NULL_LIST.
+	 */
+	if (cstate->force_null != NIL)
+	{
+		nullListStr = nodeToString(cstate->force_null);
+		EstimateLineKeysStr(pcxt, nullListStr);
+	}
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_CONVERT_LIST.
+	 */
+	if (cstate->convert_select != NIL)
+	{
+		convertListStr = nodeToString(cstate->convert_select);
+		EstimateLineKeysStr(pcxt, convertListStr);
+	}
+
+	/*
+	 * Estimate space for WalUsage and BufferUsage -- PARALLEL_COPY_WAL_USAGE
+	 * and PARALLEL_COPY_BUFFER_USAGE.
+	 */
+	shm_toc_estimate_chunk(&pcxt->estimator,
+						   mul_size(sizeof(WalUsage), pcxt->nworkers));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+	shm_toc_estimate_chunk(&pcxt->estimator,
+						   mul_size(sizeof(BufferUsage), pcxt->nworkers));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	InitializeParallelDSM(pcxt);
+
+	/* If no DSM segment was available, back out (do serial copy) */
+	if (pcxt->seg == NULL)
+	{
+		EndParallelCopy(pcxt);
+		return NULL;
+	}
+
+	/* Allocate shared memory for PARALLEL_COPY_KEY_SHARED_INFO */
+	shared_info_ptr = (ParallelCopyShmInfo *) shm_toc_allocate(pcxt->toc, sizeof(ParallelCopyShmInfo));
+	PopulateParallelCopyShmInfo(shared_info_ptr, full_transaction_id);
+
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_SHARED_INFO, shared_info_ptr);
+	pcdata->pcshared_info = shared_info_ptr;
+	pcdata->relid = relid;
+
+	/* Store shared build state, for which we reserved space. */
+	shared_cstate = (SerializedParallelCopyState *)shm_toc_allocate(pcxt->toc, est_cstateshared);
+
+	/* copy cstate variables. */
+	SerializeParallelCopyState(cstate, shared_cstate);
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_CSTATE, shared_cstate);
+
+	SerializeString(pcxt, PARALLEL_COPY_KEY_NULL_PRINT, cstate->null_print);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_DELIM, cstate->delim);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_QUOTE, cstate->quote);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_ESCAPE, cstate->escape);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_ATTNAME_LIST, attnameListStr);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_NOT_NULL_LIST, notnullListStr);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_NULL_LIST, nullListStr);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_CONVERT_LIST, convertListStr);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_WHERE_CLAUSE_STR, whereClauseStr);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_RANGE_TABLE, rangeTableStr);
+
+	/*
+	 * Allocate space for each worker's WalUsage and BufferUsage; no need to
+	 * initialize.
+	 */
+	walusage = shm_toc_allocate(pcxt->toc,
+								mul_size(sizeof(WalUsage), pcxt->nworkers));
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_WAL_USAGE, walusage);
+	bufferusage = shm_toc_allocate(pcxt->toc,
+								   mul_size(sizeof(BufferUsage), pcxt->nworkers));
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_BUFFER_USAGE, bufferusage);
+
+	LaunchParallelWorkers(pcxt);
+	if (pcxt->nworkers_launched == 0)
+	{
+		EndParallelCopy(pcxt);
+		return NULL;
+	}
+
+	/*
+	 * Caller needs to wait for all launched workers when we return.  Make sure
+	 * that the failure-to-start case will not hang forever.
+	 */
+	WaitForParallelWorkersToAttach(pcxt);
+
+	pcdata->is_leader = true;
+	cstate->is_parallel = true;
+	return pcxt;
+}
+
+/*
+ * EndParallelCopy - end the parallel copy tasks.
+ */
+static pg_attribute_always_inline void
+EndParallelCopy(ParallelContext *pcxt)
+{
+	Assert(!IsParallelWorker());
+
+	DestroyParallelContext(pcxt);
+	ExitParallelMode();
+}
+
+/*
+ * InitializeParallelCopyInfo - Initialize parallel worker.
+ */
+static void
+InitializeParallelCopyInfo(SerializedParallelCopyState *shared_cstate,
+		CopyState cstate, List *attnamelist)
+{
+	uint32		count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	cstate->copy_dest = shared_cstate->copy_dest;
+	cstate->file_encoding = shared_cstate->file_encoding;
+	cstate->need_transcoding = shared_cstate->need_transcoding;
+	cstate->encoding_embeds_ascii = shared_cstate->encoding_embeds_ascii;
+	cstate->csv_mode = shared_cstate->csv_mode;
+	cstate->header_line = shared_cstate->header_line;
+	cstate->null_print_len = shared_cstate->null_print_len;
+	cstate->force_quote_all = shared_cstate->force_quote_all;
+	cstate->convert_selectively = shared_cstate->convert_selectively;
+	cstate->num_defaults = shared_cstate->num_defaults;
+	pcdata->relid = shared_cstate->relid;
+
+	PopulateCommonCstateInfo(cstate, tup_desc, attnamelist);
+
+	/* Initialize state variables. */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/* Set up variables to avoid per-attribute overhead. */
+	initStringInfo(&cstate->attribute_buf);
+
+	initStringInfo(&cstate->line_buf);
+	for (count = 0; count < WORKER_CHUNK_COUNT; count++)
+		initStringInfo(&pcdata->worker_line_buf[count].line_buf);
+
+	cstate->line_buf_converted = false;
+	cstate->raw_buf = NULL;
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+}
+
+/*
+ * ParallelCopyMain - parallel copy worker's code.
+ *
+ * Where clause handling, convert tuple to columns, add default null values for
+ * the missing columns that are not present in that record. Find the partition
+ * if it is partitioned table, invoke before row insert Triggers, handle
+ * constraints and insert the tuples.
+ */
+void
+ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
+{
+	CopyState cstate;
+	ParallelCopyData *pcdata;
+	ParallelCopyShmInfo *pcshared_info;
+	SerializedParallelCopyState *shared_cstate;
+	Relation	rel = NULL;
+	MemoryContext oldcontext;
+	List *attlist = NIL;
+	char *whereClauseStr = NULL;
+	char *rangeTableStr = NULL;
+	char *attnameListStr = NULL;
+	char *notnullListStr = NULL;
+	char *nullListStr = NULL;
+	char *convertListStr = NULL;
+	WalUsage   *walusage;
+	BufferUsage *bufferusage;
+
+	/* Allocate workspace and zero all fields. */
+	cstate = (CopyStateData *) palloc0(sizeof(CopyStateData));
+
+	/*
+	 * We allocate everything used by a cstate in a new memory context. This
+	 * avoids memory leaks during repeated use of COPY in a query.
+	 */
+	cstate->copycontext = AllocSetContextCreate(CurrentMemoryContext,
+												"COPY",
+												ALLOCSET_DEFAULT_SIZES);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	cstate->pcdata = pcdata;
+	pcdata->is_leader = false;
+	pcdata->worker_processed_pos = -1;
+	cstate->is_parallel = true;
+	pcshared_info = (ParallelCopyShmInfo *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_SHARED_INFO, false);
+
+	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
+
+	pcdata->pcshared_info = pcshared_info;
+
+	shared_cstate = (SerializedParallelCopyState *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE, false);
+	cstate->null_print = (char *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_NULL_PRINT, true);
+
+	RestoreString(toc, PARALLEL_COPY_KEY_DELIM, &cstate->delim);
+	RestoreString(toc, PARALLEL_COPY_KEY_QUOTE, &cstate->quote);
+	RestoreString(toc, PARALLEL_COPY_KEY_ESCAPE, &cstate->escape);
+	RestoreString(toc, PARALLEL_COPY_KEY_ATTNAME_LIST, &attnameListStr);
+	if (attnameListStr)
+		attlist = (List *)stringToNode(attnameListStr);
+
+	RestoreString(toc, PARALLEL_COPY_KEY_NOT_NULL_LIST, &notnullListStr);
+	if (notnullListStr)
+		cstate->force_notnull = (List *)stringToNode(notnullListStr);
+
+	RestoreString(toc, PARALLEL_COPY_KEY_NULL_LIST, &nullListStr);
+	if (nullListStr)
+		cstate->force_null = (List *)stringToNode(nullListStr);
+
+	RestoreString(toc, PARALLEL_COPY_KEY_CONVERT_LIST, &convertListStr);
+	if (convertListStr)
+		cstate->convert_select = (List *)stringToNode(convertListStr);
+
+	RestoreString(toc, PARALLEL_COPY_KEY_WHERE_CLAUSE_STR, &whereClauseStr);
+	RestoreString(toc, PARALLEL_COPY_KEY_RANGE_TABLE, &rangeTableStr);
+
+	if (whereClauseStr)
+	{
+		Node *whereClauseCnvrtdFrmStr = (Node *) stringToNode(whereClauseStr);
+		cstate->whereClause = whereClauseCnvrtdFrmStr;
+	}
+
+	if (rangeTableStr)
+	{
+		List *rangeTableCnvrtdFrmStr = (List *) stringToNode(rangeTableStr);
+		cstate->range_table = rangeTableCnvrtdFrmStr;
+	}
+
+	/* Open and lock the relation, using the appropriate lock type. */
+	rel = table_open(shared_cstate->relid, RowExclusiveLock);
+	cstate->rel = rel;
+	InitializeParallelCopyInfo(shared_cstate, cstate, attlist);
+
+	CopyFrom(cstate);
+
+	if (rel != NULL)
+		table_close(rel, RowExclusiveLock);
+
+	/* Report WAL/buffer usage during parallel execution */
+	bufferusage = shm_toc_lookup(toc, PARALLEL_COPY_BUFFER_USAGE, false);
+	walusage = shm_toc_lookup(toc, PARALLEL_COPY_WAL_USAGE, false);
+	InstrEndParallelQuery(&bufferusage[ParallelWorkerNumber],
+						  &walusage[ParallelWorkerNumber]);
+
+	MemoryContextSwitchTo(oldcontext);
+	pfree(cstate);
+	return;
+}
+
+/*
+ * ParallelCopyFrom - parallel copy leader's functionality.
+ *
+ * Leader executes the before statement for before statement trigger, if before
+ * statement trigger is present. It will read the table data from the file and
+ * copy the contents to DSM data blocks. It will then read the input contents
+ * from the DSM data block and identify the records based on line breaks. This
+ * information is called line or a record that need to be inserted into a
+ * relation. The line information will be stored in ParallelCopyLineBoundary DSM
+ * data structure. Workers will then process this information and insert the
+ * data in to table. It will repeat this process until the all data is read from
+ * the file and all the DSM data blocks are processed. While processing if
+ * leader identifies that DSM Data blocks or DSM ParallelCopyLineBoundary data
+ * structures is full, leader will wait till the worker frees up some entries
+ * and repeat the process. It will wait till all the lines populated are
+ * processed by the workers and exits.
+ */
+static void
+ParallelCopyFrom(CopyState cstate)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
+
+	pcshared_info->is_read_in_progress = false;
+	cstate->cur_lineno = 0;
+}
+
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
  * in past protocol redesigns.
@@ -1141,6 +1822,7 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 
 	if (is_from)
 	{
+		ParallelContext *pcxt = NULL;
 		Assert(rel);
 
 		/* check read-only transaction and parallel mode */
@@ -1150,7 +1832,24 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 		cstate = BeginCopyFrom(pstate, rel, stmt->filename, stmt->is_program,
 							   NULL, stmt->attlist, stmt->options);
 		cstate->whereClause = whereClause;
-		*processed = CopyFrom(cstate);	/* copy from file to database */
+		cstate->is_parallel = false;
+
+		if (cstate->nworkers > 0)
+			pcxt = BeginParallelCopy(cstate->nworkers, cstate, stmt->attlist,
+									 relid);
+
+		if (pcxt)
+		{
+			ParallelCopyFrom(cstate);
+
+			/* Wait for all copy workers to finish */
+			WaitForParallelWorkersToFinish(pcxt);
+			*processed = pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
+			EndParallelCopy(pcxt);
+		}
+		else
+			*processed = CopyFrom(cstate); /* copy from file to database */
+
 		EndCopyFrom(cstate);
 	}
 	else
@@ -1199,6 +1898,7 @@ ProcessCopyOptions(ParseState *pstate,
 	cstate->is_copy_from = is_from;
 
 	cstate->file_encoding = -1;
+	cstate->nworkers = -1;
 
 	/* Extract options from the statement node tree */
 	foreach(option, options)
@@ -1367,6 +2067,53 @@ ProcessCopyOptions(ParseState *pstate,
 								defel->defname),
 						 parser_errposition(pstate, defel->location)));
 		}
+		else if (strcmp(defel->defname, "parallel") == 0)
+		{
+			char *endptr, *str;
+			long val;
+
+			if (!cstate->is_copy_from)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("parallel option supported only for copy from"),
+						 parser_errposition(pstate, defel->location)));
+			if (cstate->nworkers >= 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options"),
+						 parser_errposition(pstate, defel->location)));
+
+			str = defGetString(defel);
+
+			errno = 0; /* To distinguish success/failure after call */
+			val = strtol(str, &endptr, 10);
+
+			/* Check for various possible errors */
+			if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
+				|| (errno != 0 && val == 0) ||
+				*endptr)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("improper use of argument to option \"%s\"",
+								defel->defname),
+						 parser_errposition(pstate, defel->location)));
+
+			if (endptr == str)
+			   ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("no digits were found in argument to option \"%s\"",
+								defel->defname),
+						 parser_errposition(pstate, defel->location)));
+
+			cstate->nworkers = (int) val;
+
+			if (cstate->nworkers <= 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("argument to option \"%s\" must be a positive integer greater than zero",
+								defel->defname),
+						 parser_errposition(pstate, defel->location)));
+		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_SYNTAX_ERROR),
@@ -1720,11 +2467,12 @@ BeginCopy(ParseState *pstate,
 
 /*
  * PopulateCommonCstateInfo - Populates the common variables required for copy
- * from operation. This is a helper function for BeginCopy function.
+ * from operation. This is a helper function for BeginCopy &
+ * InitializeParallelCopyInfo function.
  */
 static void
 PopulateCommonCstateInfo(CopyState cstate, TupleDesc	tupDesc,
-							List *attnamelist)
+						 List *attnamelist)
 {
 	int			num_phys_attrs;
 
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index c639833..82843c6 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -14,6 +14,7 @@
 #ifndef COPY_H
 #define COPY_H
 
+#include "access/parallel.h"
 #include "nodes/execnodes.h"
 #include "nodes/parsenodes.h"
 #include "parser/parse_node.h"
@@ -41,4 +42,5 @@ extern uint64 CopyFrom(CopyState cstate);
 
 extern DestReceiver *CreateCopyDestReceiver(void);
 
+extern void ParallelCopyMain(dsm_segment *seg, shm_toc *toc);
 #endif							/* COPY_H */
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 7eaaad1..3a83d0f 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1699,6 +1699,12 @@ ParallelBitmapHeapState
 ParallelBlockTableScanDesc
 ParallelCompletionPtr
 ParallelContext
+ParallelCopyLineBoundaries
+ParallelCopyLineBoundary
+ParallelCopyData
+ParallelCopyDataBlock
+ParallelCopyLineBuf
+ParallelCopyShmInfo
 ParallelExecutorInfo
 ParallelHashGrowth
 ParallelHashJoinBatch
@@ -2215,6 +2221,7 @@ SerCommitSeqNo
 SerialControl
 SerializableXactHandle
 SerializedActiveRelMaps
+SerializedParallelCopyState
 SerializedReindexState
 SerializedSnapshotData
 SerializedTransactionState
-- 
1.8.3.1

v2-0003-Allow-copy-from-command-to-process-data-from-file.patchapplication/x-patch; name=v2-0003-Allow-copy-from-command-to-process-data-from-file.patchDownload
From f3ec188c3c1e11fdbb716ec12862a891a95b396f Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Sat, 1 Aug 2020 09:31:42 +0530
Subject: [PATCH v2 3/5] Allow copy from command to process data from
 file/STDIN contents to a table in parallel.

This feature allows the copy from to leverage multiple CPUs in order to copy
data from file/STDIN to a table. This adds a PARALLEL option to COPY FROM
command where the user can specify the number of workers that can be used
to perform the COPY FROM command. Specifying zero as number of workers will
disable parallelism.
The backend, to which the "COPY FROM" query is submitted acts as leader with
the responsibility of reading data from the file/stdin, launching at most n
number of workers as specified with PARALLEL 'n' option in the "COPY FROM"
query. The leader populates the common data required for the workers execution
in the DSM and shares it with the workers. The leader then executes before
statement triggers if there exists any. Leader populates DSM lines which
includes the start offset and line size, while populating the lines it reads
as many blocks as required into the DSM data blocks from the file. Each block
is of 64K size. The leader parses the data to identify a line, the existing
logic from CopyReadLineText which identifies the lines with some changes was
used for this. Leader checks if a free line is available to copy the
information, if there is no free line it waits till the required line is
freed up by the worker and then copies the identified lines information
(offset & line size) into the DSM lines. This process is repeated till the
complete file is processed. Simultaneously, the workers cache the lines(50)
locally into the local memory and release the lines to the leader for further
populating. Each worker processes the lines that it cached and inserts it into
the table. The leader does not participate in the insertion of data, leaders
only responsibility will be to identify the lines as fast as possible for the
workers to do the actual copy operation. The leader waits till all the lines
populated are processed by the workers and exits.
We have chosen this design based on the reason "that everything stalls if the
leader doesn't accept further input data, as well as when there are no
available splitted chunks so it doesn't seem like a good idea to have the
leader do other work.  This is backed by the performance data where we have
seen that with 1 worker there is just a 5-10% performance difference".
---
 src/backend/access/common/toast_internals.c |  11 +-
 src/backend/access/heap/heapam.c            |  13 -
 src/backend/access/transam/xact.c           |  31 +
 src/backend/commands/copy.c                 | 890 ++++++++++++++++++++++++++--
 src/bin/psql/tab-complete.c                 |   2 +-
 src/include/access/xact.h                   |   2 +
 src/tools/pgindent/typedefs.list            |   1 +
 7 files changed, 896 insertions(+), 54 deletions(-)

diff --git a/src/backend/access/common/toast_internals.c b/src/backend/access/common/toast_internals.c
index 25a81e5..586d53d 100644
--- a/src/backend/access/common/toast_internals.c
+++ b/src/backend/access/common/toast_internals.c
@@ -17,6 +17,7 @@
 #include "access/genam.h"
 #include "access/heapam.h"
 #include "access/heaptoast.h"
+#include "access/parallel.h"
 #include "access/table.h"
 #include "access/toast_internals.h"
 #include "access/xact.h"
@@ -116,7 +117,15 @@ toast_save_datum(Relation rel, Datum value,
 	TupleDesc	toasttupDesc;
 	Datum		t_values[3];
 	bool		t_isnull[3];
-	CommandId	mycid = GetCurrentCommandId(true);
+
+	/*
+	 * Parallel copy can insert toast tuples, in case of parallel copy the
+	 * command would have been set already by calling AssignCommandIdForWorker.
+	 * For parallel copy call GetCurrentCommandId to get currentCommandId by
+	 * passing used as false, as this is taken care earlier.
+	 */
+	CommandId	mycid = IsParallelWorker() ? GetCurrentCommandId(false) :
+											 GetCurrentCommandId(true);
 	struct varlena *result;
 	struct varatt_external toast_pointer;
 	union
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 5eef225..bd7a7fc 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2023,19 +2023,6 @@ static HeapTuple
 heap_prepare_insert(Relation relation, HeapTuple tup, TransactionId xid,
 					CommandId cid, int options)
 {
-	/*
-	 * Parallel operations are required to be strictly read-only in a parallel
-	 * worker.  Parallel inserts are not safe even in the leader in the
-	 * general case, because group locking means that heavyweight locks for
-	 * relation extension or GIN page locks will not conflict between members
-	 * of a lock group, but we don't prohibit that case here because there are
-	 * useful special cases that we can safely allow, such as CREATE TABLE AS.
-	 */
-	if (IsParallelWorker())
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_TRANSACTION_STATE),
-				 errmsg("cannot insert tuples in a parallel worker")));
-
 	tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
 	tup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK);
 	tup->t_data->t_infomask |= HEAP_XMAX_INVALID;
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index d4f7c29..9bff390 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -504,6 +504,37 @@ GetCurrentFullTransactionIdIfAny(void)
 }
 
 /*
+ *	AssignFullTransactionIdForWorker
+ *
+ * For parallel copy, transaction id of leader will be used by the workers.
+ */
+void
+AssignFullTransactionIdForWorker(FullTransactionId fullTransactionId)
+{
+	TransactionState s = CurrentTransactionState;
+
+	Assert((IsInParallelMode() || IsParallelWorker()));
+	s->fullTransactionId = fullTransactionId;
+}
+
+/*
+ *	AssignCommandIdForWorker
+ *
+ * For parallel copy, command id of leader will be used by the workers.
+ */
+void
+AssignCommandIdForWorker(CommandId commandId, bool used)
+{
+	Assert((IsInParallelMode() || IsParallelWorker()));
+
+	/* this is global to a transaction, not subtransaction-local */
+	if (used)
+		currentCommandIdUsed = true;
+
+	currentCommandId = commandId;
+}
+
+/*
  *	MarkCurrentTransactionIdLoggedIfAny
  *
  * Remember that the current xid - if it is assigned - now has been wal logged.
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 3dcdfc1..c65fc98 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -26,6 +26,7 @@
 #include "access/xlog.h"
 #include "catalog/dependency.h"
 #include "catalog/pg_authid.h"
+#include "catalog/pg_proc_d.h"
 #include "catalog/pg_type.h"
 #include "commands/copy.h"
 #include "commands/defrem.h"
@@ -40,11 +41,13 @@
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
+#include "optimizer/clauses.h"
 #include "optimizer/optimizer.h"
 #include "parser/parse_coerce.h"
 #include "parser/parse_collate.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_relation.h"
+#include "pgstat.h"
 #include "port/pg_bswap.h"
 #include "rewrite/rewriteHandler.h"
 #include "storage/fd.h"
@@ -95,6 +98,18 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
+/*
+ * State of the line.
+ */
+typedef enum ParallelCopyLineState
+{
+	LINE_INIT,					/* initial state of line */
+	LINE_LEADER_POPULATING,		/* leader processing line */
+	LINE_LEADER_POPULATED,		/* leader completed populating line */
+	LINE_WORKER_PROCESSING,		/* worker processing line */
+	LINE_WORKER_PROCESSED		/* worker completed processing line */
+}ParallelCopyLineState;
+
 #define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
 
 /*
@@ -123,6 +138,7 @@ typedef enum CopyInsertMethod
 
 #define	IsParallelCopy()		(cstate->is_parallel)
 #define IsLeader()				(cstate->pcdata->is_leader)
+#define IsWorker()				(IsParallelCopy() && !IsLeader())
 #define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
 
 /*
@@ -556,9 +572,13 @@ if (1) \
 { \
 	if (raw_buf_ptr > cstate->raw_buf_index) \
 	{ \
-		appendBinaryStringInfo(&cstate->line_buf, \
-							 cstate->raw_buf + cstate->raw_buf_index, \
-							   raw_buf_ptr - cstate->raw_buf_index); \
+		if (!IsParallelCopy()) \
+			appendBinaryStringInfo(&cstate->line_buf, \
+								   cstate->raw_buf + cstate->raw_buf_index, \
+								   raw_buf_ptr - cstate->raw_buf_index); \
+		else \
+			line_size +=  raw_buf_ptr - cstate->raw_buf_index; \
+		\
 		cstate->raw_buf_index = raw_buf_ptr; \
 	} \
 } else ((void) 0)
@@ -571,26 +591,65 @@ if (1) \
 	goto not_end_of_copy; \
 } else ((void) 0)
 
+/* Begin parallel copy Macros */
+#define SET_NEWLINE_SIZE() \
+{ \
+	if (cstate->eol_type == EOL_NL || cstate->eol_type == EOL_CR) \
+		new_line_size = 1; \
+	else if (cstate->eol_type == EOL_CRNL) \
+		new_line_size = 2; \
+	else \
+		new_line_size = 0; \
+}
+
+/*
+ * COPY_WAIT_TO_PROCESS - Wait before continuing to process.
+ */
+#define COPY_WAIT_TO_PROCESS() \
+{ \
+	CHECK_FOR_INTERRUPTS(); \
+	(void) WaitLatch(MyLatch, \
+					 WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH, \
+					 1L, WAIT_EVENT_PG_SLEEP); \
+	ResetLatch(MyLatch); \
+}
+
 /*
  * CLEAR_EOL_LINE - Wrapper for clearing EOL.
  */
 #define CLEAR_EOL_LINE() \
 if (!result && !IsHeaderLine()) \
-	ClearEOLFromCopiedData(cstate, cstate->line_buf.data, \
-						   cstate->line_buf.len, \
-						   &cstate->line_buf.len) \
+{ \
+	if (IsParallelCopy()) \
+		ClearEOLFromCopiedData(cstate, cstate->raw_buf, \
+									raw_buf_ptr, &line_size); \
+	else \
+		ClearEOLFromCopiedData(cstate, cstate->line_buf.data, \
+									cstate->line_buf.len, \
+									&cstate->line_buf.len); \
+} \
 
 /*
  * INCREMENTPROCESSED - Increment the lines processed.
  */
-#define INCREMENTPROCESSED(processed)  \
-processed++;
+#define INCREMENTPROCESSED(processed) \
+{ \
+	if (!IsParallelCopy()) \
+		processed++; \
+	else \
+		pg_atomic_add_fetch_u64(&cstate->pcdata->pcshared_info->processed, 1); \
+}
 
 /*
  * GETPROCESSED - Get the lines processed.
  */
 #define GETPROCESSED(processed) \
-return processed;
+if (!IsParallelCopy()) \
+	return processed; \
+else \
+	return pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
+
+/* End parallel copy Macros */
 
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
@@ -645,7 +704,10 @@ static void PopulateCommonCstateInfo(CopyState cstate, TupleDesc	tup_desc,
 static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
 								   int copy_line_pos, int *copy_line_size);
 static void ConvertToServerEncoding(CopyState cstate);
-
+static void ExecBeforeStmtTrigger(CopyState cstate);
+static void CheckTargetRelValidity(CopyState cstate);
+static void PopulateCstateCatalogInfo(CopyState cstate);
+static pg_attribute_always_inline uint32 GetLinePosition(CopyState cstate);
 /*
  * SerializeParallelCopyState - Copy shared_cstate using cstate information.
  */
@@ -727,6 +789,137 @@ PopulateParallelCopyShmInfo(ParallelCopyShmInfo *shared_info_ptr,
 }
 
 /*
+ * IsTriggerFunctionParallelSafe - Check if the trigger function is parallel
+ * safe for the triggers. Return false if any one of the trigger has parallel
+ * unsafe function.
+ */
+static pg_attribute_always_inline bool
+IsTriggerFunctionParallelSafe(TriggerDesc *trigdesc)
+{
+	int	i;
+	for (i = 0; i < trigdesc->numtriggers; i++)
+	{
+		Trigger    *trigger = &trigdesc->triggers[i];
+		int 		trigtype = RI_TRIGGER_NONE;
+
+		if (func_parallel(trigger->tgfoid) != PROPARALLEL_SAFE)
+			return false;
+
+		/* If the trigger is parallel safe, also look for RI_TRIGGER. */
+		trigtype = RI_FKey_trigger_type(trigger->tgfoid);
+		if (trigtype == RI_TRIGGER_PK || trigtype == RI_TRIGGER_FK)
+			return false;
+	}
+
+	return true;
+}
+
+/*
+ * CheckExprParallelSafety - determine parallel safety of volatile expressions
+ * in default clause of column definition or in where clause and return true if
+ * they are parallel safe.
+ */
+static pg_attribute_always_inline bool
+CheckExprParallelSafety(CopyState cstate)
+{
+	if (contain_volatile_functions(cstate->whereClause))
+	{
+		if (max_parallel_hazard((Query *)cstate->whereClause) != PROPARALLEL_SAFE)
+			return false;
+	}
+
+	/*
+	 * Check if any of the column has volatile default expression. if yes, and
+	 * they are not parallel safe, then parallelism is not allowed. For
+	 * instance, if there are any serial/bigserial columns for which nextval()
+	 * default expression which is parallel unsafe is associated, parallelism
+	 * should not be allowed. In non parallel copy volatile functions are not
+	 * checked for nextval().
+	 */
+	if (cstate->defexprs != NULL && cstate->num_defaults != 0)
+	{
+		int     i;
+		for (i = 0; i < cstate->num_defaults; i++)
+		{
+			bool volatile_expr = contain_volatile_functions((Node *)cstate->defexprs[i]->expr);
+			if (volatile_expr &&
+				(max_parallel_hazard((Query *)cstate->defexprs[i]->expr)) !=
+				 PROPARALLEL_SAFE)
+				return false;
+		}
+	}
+
+	return true;
+}
+
+/*
+ * FindInsertMethod - determine insert mode single, multi, or multi conditional.
+ */
+static pg_attribute_always_inline CopyInsertMethod
+FindInsertMethod(CopyState cstate)
+{
+	if (cstate->rel->trigdesc != NULL &&
+		(cstate->rel->trigdesc->trig_insert_before_row ||
+		 cstate->rel->trigdesc->trig_insert_instead_row))
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
+			cstate->rel->trigdesc != NULL &&
+			cstate->rel->trigdesc->trig_insert_new_table)
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+		return CIM_MULTI_CONDITIONAL;
+
+	return CIM_MULTI;
+}
+
+/*
+ * IsParallelCopyAllowed - check for the cases where parallel copy is not
+ * applicable.
+ */
+static pg_attribute_always_inline bool
+IsParallelCopyAllowed(CopyState cstate)
+{
+	/* Parallel copy not allowed for frontend (2.0 protocol) & binary option. */
+	if ((cstate->copy_dest == COPY_OLD_FE) || cstate->binary)
+		return false;
+
+	/* Check if copy is into foreign table or temporary table. */
+	if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
+		RelationUsesLocalBuffers(cstate->rel))
+		return false;
+
+	/* Check if trigger function is parallel safe. */
+	if (cstate->rel->trigdesc != NULL &&
+		!IsTriggerFunctionParallelSafe(cstate->rel->trigdesc))
+		return false;
+
+	/*
+	 * Check if there is after statement or instead of trigger or transition
+	 * table triggers.
+	 */
+	if (cstate->rel->trigdesc != NULL &&
+		(cstate->rel->trigdesc->trig_insert_after_statement ||
+		 cstate->rel->trigdesc->trig_insert_instead_row ||
+		 cstate->rel->trigdesc->trig_insert_new_table))
+		return false;
+
+	/* Check if the volatile expressions are parallel safe, if present any. */
+	if (!CheckExprParallelSafety(cstate))
+		return false;
+
+	/* Check if the insertion mode is single. */
+	if (FindInsertMethod(cstate) == CIM_SINGLE)
+		return false;
+
+	return true;
+}
+
+/*
  * BeginParallelCopy - start parallel copy tasks.
  *
  * Get the number of workers required to perform the parallel copy. The data
@@ -754,6 +947,7 @@ BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
 	ParallelCopyData *pcdata;
 	MemoryContext oldcontext;
 
+	CheckTargetRelValidity(cstate);
 	parallel_workers = Min(nworkers, max_worker_processes);
 
 	/* Can't perform copy in parallel */
@@ -765,6 +959,15 @@ BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
 	MemoryContextSwitchTo(oldcontext);
 	cstate->pcdata = pcdata;
 
+	/*
+	 * User chosen parallel copy. Determine if the parallel copy is actually
+	 * allowed. If not, go with the non-parallel mode.
+	 */
+	if (!IsParallelCopyAllowed(cstate))
+		return NULL;
+
+	full_transaction_id = GetCurrentFullTransactionId();
+
 	EnterParallelMode();
 	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
 								 parallel_workers);
@@ -973,9 +1176,212 @@ InitializeParallelCopyInfo(SerializedParallelCopyState *shared_cstate,
 	cstate->line_buf_converted = false;
 	cstate->raw_buf = NULL;
 	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+
+	PopulateCstateCatalogInfo(cstate);
+
+	/* Create workspace for CopyReadAttributes results. */
+	if (!cstate->binary)
+	{
+		AttrNumber	attr_count = list_length(cstate->attnumlist);
+
+		cstate->max_fields = attr_count;
+		cstate->raw_fields = (char **)palloc(attr_count * sizeof(char *));
+	}
+}
+
+/*
+ * CacheLineInfo - Cache the line information to local memory.
+ */
+static bool
+CacheLineInfo(CopyState cstate, uint32 buff_count)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	uint32			write_pos;
+	ParallelCopyDataBlock *data_blk_ptr;
+	ParallelCopyLineBoundary *lineInfo;
+	uint32 offset;
+	int dataSize;
+	int copiedSize = 0;
+
+	resetStringInfo(&pcdata->worker_line_buf[buff_count].line_buf);
+	write_pos = GetLinePosition(cstate);
+	if (-1 == write_pos)
+		return true;
+
+	/* Get the current line information. */
+	lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+	if (pg_atomic_read_u32(&lineInfo->line_size) == 0)
+		goto empty_data_line_update;
+
+	/* Get the block information. */
+	data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+	/* Get the offset information from where the data must be copied. */
+	offset = lineInfo->start_offset;
+	pcdata->worker_line_buf[buff_count].cur_lineno = lineInfo->cur_lineno;
+
+	elog(DEBUG1, "[Worker] Processing - line position:%d, block:%d, unprocessed lines:%d, offset:%d, line size:%d",
+				 write_pos, lineInfo->first_block,
+				 pg_atomic_read_u32(&data_blk_ptr->unprocessed_line_parts),
+				 offset, pg_atomic_read_u32(&lineInfo->line_size));
+
+	for (;;)
+	{
+		uint8 skip_bytes = data_blk_ptr->skip_bytes;
+		/*
+		 * There is a possibility that the above loop has come out because
+		 * data_blk_ptr->curr_blk_completed is set, but dataSize read might
+		 * be an old value, if data_blk_ptr->curr_blk_completed and the line is
+		 * completed, line_size will be set. Read the line_size again to be
+		 * sure if it is complete or partial block.
+		 */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+		if (dataSize)
+		{
+			int remainingSize = dataSize - copiedSize;
+			if (!remainingSize)
+				break;
+
+			/* Whole line is in current block. */
+			if (remainingSize + offset + skip_bytes < DATA_BLOCK_SIZE)
+			{
+				appendBinaryStringInfo(&pcdata->worker_line_buf[buff_count].line_buf,
+									   &data_blk_ptr->data[offset],
+									   remainingSize);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts,
+										1);
+				break;
+			}
+			else
+			{
+				/* Line is spread across the blocks. */
+				uint32 lineInCurrentBlock =  (DATA_BLOCK_SIZE - skip_bytes) - offset;
+				appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+										 &data_blk_ptr->data[offset],
+										 lineInCurrentBlock);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+				copiedSize += lineInCurrentBlock;
+				while (copiedSize < dataSize)
+				{
+					uint32 currentBlockCopySize;
+					ParallelCopyDataBlock *currBlkPtr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+					skip_bytes = currBlkPtr->skip_bytes;
+
+					/*
+					 * If complete data is present in current block use
+					 * dataSize - copiedSize, or copy the whole block from
+					 * current block.
+					 */
+					currentBlockCopySize = Min(dataSize - copiedSize, DATA_BLOCK_SIZE - skip_bytes);
+					appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+											 &currBlkPtr->data[0],
+											 currentBlockCopySize);
+					pg_atomic_sub_fetch_u32(&currBlkPtr->unprocessed_line_parts, 1);
+					copiedSize += currentBlockCopySize;
+					data_blk_ptr = currBlkPtr;
+				}
+
+				break;
+			}
+		}
+		else
+		{
+			/* Copy this complete block from the current offset. */
+			uint32 lineInCurrentBlock =  (DATA_BLOCK_SIZE - skip_bytes) - offset;
+			appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+									 &data_blk_ptr->data[offset],
+									 lineInCurrentBlock);
+			pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+			copiedSize += lineInCurrentBlock;
+
+			/*
+			 * Reset the offset. For the first copy, copy from the offset. For
+			 * the subsequent copy the complete block.
+			 */
+			offset = 0;
+
+			/* Set data_blk_ptr to the following block. */
+			data_blk_ptr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+		}
+
+		for (;;)
+		{
+			/* Get the size of this line */
+			dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+			/*
+			 * If the data is present in current block lineInfo.line_size
+			 * will be updated. If the data is spread across the blocks either
+			 * of lineInfo.line_size or data_blk_ptr->curr_blk_completed can
+			 * be updated. lineInfo.line_size will be updated if the complete
+			 * read is finished. data_blk_ptr->curr_blk_completed will be
+			 * updated if processing of current block is finished and data
+			 * processing is not finished.
+			 */
+			if (data_blk_ptr->curr_blk_completed || (dataSize != -1))
+				break;
+
+			COPY_WAIT_TO_PROCESS()
+		}
+	}
+
+empty_data_line_update:
+	elog(DEBUG1, "[Worker] Completed processing line:%d", write_pos);
+	pg_atomic_write_u32(&lineInfo->line_state, LINE_WORKER_PROCESSED);
+	pg_atomic_write_u32(&lineInfo->line_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+	return false;
 }
 
 /*
+ * GetWorkerLine - Returns a line for worker to process.
+ */
+static bool
+GetWorkerLine(CopyState cstate)
+{
+	uint32 buff_count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+
+	/*
+	 * Copy the line data to line_buf and release the line position so that the
+	 * worker can continue loading data.
+	 */
+	if (pcdata->worker_line_buf_pos < pcdata->worker_line_buf_count)
+		goto return_line;
+
+	pcdata->worker_line_buf_pos = 0;
+	pcdata->worker_line_buf_count = 0;
+
+	for (buff_count = 0; buff_count < WORKER_CHUNK_COUNT; buff_count++)
+	{
+		bool result = CacheLineInfo(cstate, buff_count);
+		if (result)
+			break;
+
+		pcdata->worker_line_buf_count++;
+	}
+
+	if (pcdata->worker_line_buf_count)
+		goto return_line;
+	else
+		resetStringInfo(&cstate->line_buf);
+
+	return true;
+
+return_line:
+	cstate->line_buf = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].line_buf;
+	cstate->cur_lineno = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].cur_lineno;
+	cstate->line_buf_valid = true;
+
+	/* Mark that encoding conversion hasn't occurred yet. */
+	cstate->line_buf_converted = false;
+	ConvertToServerEncoding(cstate);
+	pcdata->worker_line_buf_pos++;
+	return false;
+ }
+
+/*
  * ParallelCopyMain - parallel copy worker's code.
  *
  * Where clause handling, convert tuple to columns, add default null values for
@@ -1024,6 +1430,8 @@ ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
 	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
 
 	pcdata->pcshared_info = pcshared_info;
+	AssignFullTransactionIdForWorker(pcshared_info->full_transaction_id);
+	AssignCommandIdForWorker(pcshared_info->mycid, true);
 
 	shared_cstate = (SerializedParallelCopyState *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE, false);
 	cstate->null_print = (char *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_NULL_PRINT, true);
@@ -1084,6 +1492,33 @@ ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
 }
 
 /*
+ * UpdateBlockInLineInfo - Update the line information.
+ */
+static pg_attribute_always_inline int
+UpdateBlockInLineInfo(CopyState cstate, uint32 blk_pos,
+					   uint32 offset, uint32 line_size, uint32 line_state)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyLineBoundaries *lineBoundaryPtr = &pcshared_info->line_boundaries;
+	ParallelCopyLineBoundary *lineInfo;
+	int line_pos = lineBoundaryPtr->pos;
+
+	/* Update the line information for the worker to pick and process. */
+	lineInfo = &lineBoundaryPtr->ring[line_pos];
+	while (pg_atomic_read_u32(&lineInfo->line_size) != -1)
+		COPY_WAIT_TO_PROCESS()
+
+	lineInfo->first_block = blk_pos;
+	lineInfo->start_offset = offset;
+	lineInfo->cur_lineno = cstate->cur_lineno;
+	pg_atomic_write_u32(&lineInfo->line_size, line_size);
+	pg_atomic_write_u32(&lineInfo->line_state, line_state);
+	lineBoundaryPtr->pos = (lineBoundaryPtr->pos + 1) % RINGSIZE;
+
+	return line_pos;
+}
+
+/*
  * ParallelCopyFrom - parallel copy leader's functionality.
  *
  * Leader executes the before statement for before statement trigger, if before
@@ -1106,8 +1541,298 @@ ParallelCopyFrom(CopyState cstate)
 	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
 	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
 
+	/* Execute the before statement triggers from the leader */
+	ExecBeforeStmtTrigger(cstate);
+
+	/* On input just throw the header line away. */
+	if (cstate->cur_lineno == 0 && cstate->header_line)
+	{
+		cstate->cur_lineno++;
+		if (CopyReadLine(cstate))
+		{
+			pcshared_info->is_read_in_progress = false;
+			return;			/* done */
+		}
+	}
+
+	for (;;)
+	{
+		bool done;
+		cstate->cur_lineno++;
+
+		/* Actually read the line into memory here. */
+		done = CopyReadLine(cstate);
+
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			break;
+	}
+
 	pcshared_info->is_read_in_progress = false;
 	cstate->cur_lineno = 0;
+ }
+
+/*
+ * GetLinePosition - return the line position that worker should process.
+ */
+static uint32
+GetLinePosition(CopyState cstate)
+{
+	ParallelCopyData *pcdata = cstate->pcdata;
+	ParallelCopyShmInfo *pcshared_info = pcdata->pcshared_info;
+	uint32  previous_pos = pcdata->worker_processed_pos;
+	uint32 write_pos = (previous_pos == -1) ? 0 : (previous_pos + 1) % RINGSIZE;
+	for (;;)
+	{
+		int		dataSize;
+		bool	is_read_in_progress = pcshared_info->is_read_in_progress;
+		ParallelCopyLineBoundary *lineInfo;
+		ParallelCopyDataBlock *data_blk_ptr;
+		ParallelCopyLineState line_state = LINE_LEADER_POPULATED;
+		ParallelCopyLineState curr_line_state;
+		CHECK_FOR_INTERRUPTS();
+
+		/* File read completed & no elements to process. */
+		if (!is_read_in_progress &&
+			(pcshared_info->populated ==
+			 pg_atomic_read_u64(&pcshared_info->total_worker_processed)))
+		{
+			write_pos = -1;
+			break;
+		}
+
+		/* Get the current line information. */
+		lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+		curr_line_state = pg_atomic_read_u32(&lineInfo->line_state);
+		if ((write_pos % WORKER_CHUNK_COUNT == 0) &&
+			(curr_line_state == LINE_WORKER_PROCESSED ||
+			 curr_line_state == LINE_WORKER_PROCESSING))
+		{
+			pcdata->worker_processed_pos = write_pos;
+			write_pos = (write_pos + WORKER_CHUNK_COUNT) %  RINGSIZE;
+			continue;
+		}
+
+		/* Get the size of this line. */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+		if (dataSize != 0) /* If not an empty line. */
+		{
+			/* Get the block information. */
+			data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+			if (!data_blk_ptr->curr_blk_completed && (dataSize == -1))
+			{
+				/* Wait till the current line or block is added. */
+				COPY_WAIT_TO_PROCESS()
+				continue;
+			}
+		}
+
+		/* Make sure that no worker has consumed this element. */
+		if (pg_atomic_compare_exchange_u32(&lineInfo->line_state,
+										   &line_state, LINE_WORKER_PROCESSING))
+			break;
+	}
+
+	pcdata->worker_processed_pos = write_pos;
+	return write_pos;
+}
+
+/*
+ * GetFreeCopyBlock - Get a free block for data to be copied.
+ */
+static pg_attribute_always_inline uint32
+GetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	int count = 0;
+	uint32 last_free_block = pcshared_info->cur_block_pos;
+	uint32 block_pos = (last_free_block != -1) ? ((last_free_block + 1) % MAX_BLOCKS_COUNT): 0;
+
+	/*
+	 * Get a new block for copying data, don't check current block, current
+	 * block will have some unprocessed data.
+	 */
+	while (count < (MAX_BLOCKS_COUNT - 1))
+	{
+		ParallelCopyDataBlock *dataBlkPtr = &pcshared_info->data_blocks[block_pos];
+		uint32 unprocessed_line_parts = pg_atomic_read_u32(&dataBlkPtr->unprocessed_line_parts);
+		if (unprocessed_line_parts == 0)
+		{
+			dataBlkPtr->curr_blk_completed = false;
+			dataBlkPtr->skip_bytes = 0;
+			pcshared_info->cur_block_pos = block_pos;
+			return block_pos;
+		}
+
+		block_pos = (block_pos + 1) % MAX_BLOCKS_COUNT;
+		count++;
+	}
+
+	return -1;
+}
+
+/*
+ * WaitGetFreeCopyBlock - If there are no blocks available, wait and get a block
+ * for copying data.
+ */
+static uint32
+WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	uint32 new_free_pos = -1;
+	for (;;)
+	{
+		new_free_pos = GetFreeCopyBlock(pcshared_info);
+		if (new_free_pos != -1)	/* We have got one block, break now. */
+			break;
+
+		COPY_WAIT_TO_PROCESS()
+	}
+
+	return new_free_pos;
+}
+
+/*
+ * SetRawBufForLoad - Set raw_buf to the shared memory where the file data must
+ * be read.
+ */
+static void
+SetRawBufForLoad(CopyState cstate, uint32 line_size, uint32 copy_buf_len,
+				 uint32 raw_buf_ptr, char **copy_raw_buf)
+{
+	ParallelCopyShmInfo	*pcshared_info;
+	uint32 cur_block_pos;
+	uint32 next_block_pos;
+	ParallelCopyDataBlock	*cur_data_blk_ptr = NULL;
+	ParallelCopyDataBlock	*next_data_blk_ptr = NULL;
+
+	if (!IsParallelCopy())
+		return;
+
+	pcshared_info = cstate->pcdata->pcshared_info;
+	cur_block_pos = pcshared_info->cur_block_pos;
+	cur_data_blk_ptr = (cstate->raw_buf) ? &pcshared_info->data_blocks[cur_block_pos] : NULL;
+	next_block_pos = WaitGetFreeCopyBlock(pcshared_info);
+	next_data_blk_ptr = &pcshared_info->data_blocks[next_block_pos];
+
+	/* set raw_buf to the data block in shared memory */
+	cstate->raw_buf = next_data_blk_ptr->data;
+	*copy_raw_buf = cstate->raw_buf;
+	if (cur_data_blk_ptr && line_size)
+	{
+		/*
+		 * Mark the previous block as completed, worker can start copying this
+		 * data.
+		 */
+		cur_data_blk_ptr->following_block = next_block_pos;
+		pg_atomic_add_fetch_u32(&cur_data_blk_ptr->unprocessed_line_parts, 1);
+		cur_data_blk_ptr->skip_bytes = copy_buf_len - raw_buf_ptr;
+		cur_data_blk_ptr->curr_blk_completed = true;
+	}
+}
+
+/*
+ * EndLineParallelCopy - Update the line information in shared memory.
+ */
+static void
+EndLineParallelCopy(CopyState cstate, uint32 line_pos, uint32 line_size,
+					 uint32 raw_buf_ptr)
+{
+	uint8 new_line_size;
+	if (!IsParallelCopy())
+		return;
+
+	if (!IsHeaderLine())
+	{
+		ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+		ParallelCopyLineBoundaries *lineBoundaryPtr = &pcshared_info->line_boundaries;
+		SET_NEWLINE_SIZE()
+		if (line_size)
+		{
+			ParallelCopyLineBoundary *lineInfo = &lineBoundaryPtr->ring[line_pos];
+			/*
+			 * If the new_line_size > raw_buf_ptr, then the new block has only
+			 * new line char content. The unprocessed count should not be
+			 * increased in this case.
+			 */
+			if (raw_buf_ptr > new_line_size)
+			{
+				uint32 cur_block_pos = pcshared_info->cur_block_pos;
+				ParallelCopyDataBlock *curr_data_blk_ptr = &pcshared_info->data_blocks[cur_block_pos];
+				pg_atomic_add_fetch_u32(&curr_data_blk_ptr->unprocessed_line_parts, 1);
+			}
+
+			/* Update line size. */
+			pg_atomic_write_u32(&lineInfo->line_size, line_size);
+			pg_atomic_write_u32(&lineInfo->line_state, LINE_LEADER_POPULATED);
+			elog(DEBUG1, "[Leader] After adding - line position:%d, line_size:%d",
+						 line_pos, line_size);
+			pcshared_info->populated++;
+		}
+		else if (new_line_size)
+		{
+			/* This means only new line char, empty record should be inserted.*/
+			ParallelCopyLineBoundary *lineInfo;
+			line_pos = UpdateBlockInLineInfo(cstate, -1, -1, 0,
+											   LINE_LEADER_POPULATED);
+			lineInfo = &lineBoundaryPtr->ring[line_pos];
+			elog(DEBUG1, "[Leader] Added empty line with offset:%d, line position:%d, line size:%d",
+						 lineInfo->start_offset, line_pos,
+						 pg_atomic_read_u32(&lineInfo->line_size));
+			pcshared_info->populated++;
+		}
+	}
+}
+
+/*
+ * ExecBeforeStmtTrigger - Execute the before statement trigger, this will be
+ * executed for parallel copy by the leader process.
+ */
+static void
+ExecBeforeStmtTrigger(CopyState cstate)
+{
+	EState	   *estate = CreateExecutorState();
+	ResultRelInfo *resultRelInfo;
+
+	Assert(IsLeader());
+
+	/*
+	 * We need a ResultRelInfo so we can use the regular executor's
+	 * index-entry-making machinery.  (There used to be a huge amount of code
+	 * here that basically duplicated execUtils.c ...)
+	 */
+	resultRelInfo = makeNode(ResultRelInfo);
+	InitResultRelInfo(resultRelInfo,
+					  cstate->rel,
+					  1,		/* must match rel's position in range_table */
+					  NULL,
+					  0);
+
+	/* Verify the named relation is a valid target for INSERT */
+	CheckValidResultRel(resultRelInfo, CMD_INSERT);
+
+	estate->es_result_relations = resultRelInfo;
+	estate->es_num_result_relations = 1;
+	estate->es_result_relation_info = resultRelInfo;
+
+	ExecInitRangeTable(estate, cstate->range_table);
+
+	/*
+	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
+	 * should do this for COPY, since it's not really an "INSERT" statement as
+	 * such. However, executing these triggers maintains consistency with the
+	 * EACH ROW triggers that we already fire on COPY.
+	 */
+	ExecBSInsertTriggers(estate, resultRelInfo);
+
+	/* Close any trigger target relations */
+	ExecCleanUpTriggerState(estate);
+
+	FreeExecutorState(estate);
 }
 
 /*
@@ -3584,7 +4309,8 @@ CopyFrom(CopyState cstate)
 
 	PartitionTupleRouting *proute = NULL;
 	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
+	CommandId	mycid = IsParallelCopy() ? GetCurrentCommandId(false) :
+										   GetCurrentCommandId(true);
 	int			ti_options = 0; /* start with default options for insert */
 	BulkInsertState bistate = NULL;
 	CopyInsertMethod insertMethod;
@@ -3594,7 +4320,14 @@ CopyFrom(CopyState cstate)
 	bool		has_instead_insert_row_trig;
 	bool		leafpart_use_multi_insert = false;
 
-	CheckTargetRelValidity(cstate);
+	/*
+	 * Perform this check if it is not parallel copy. In case of parallel
+	 * copy, this check is done by the leader, so that if any invalid case
+	 * exist the copy from command will error out from the leader itself,
+	 * avoiding launching workers, just to throw error.
+	 */
+	if (!IsParallelCopy())
+		CheckTargetRelValidity(cstate);
 
 	/*
 	 * If the target file is new-in-transaction, we assume that checking FSM
@@ -3634,7 +4367,8 @@ CopyFrom(CopyState cstate)
 	target_resultRelInfo = resultRelInfo;
 
 	/* Verify the named relation is a valid target for INSERT */
-	CheckValidResultRel(resultRelInfo, CMD_INSERT);
+	if (!IsParallelCopy())
+		CheckValidResultRel(resultRelInfo, CMD_INSERT);
 
 	ExecOpenIndices(resultRelInfo, false);
 
@@ -3783,13 +4517,16 @@ CopyFrom(CopyState cstate)
 	has_instead_insert_row_trig = (resultRelInfo->ri_TrigDesc &&
 								   resultRelInfo->ri_TrigDesc->trig_insert_instead_row);
 
-	/*
-	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
-	 * should do this for COPY, since it's not really an "INSERT" statement as
-	 * such. However, executing these triggers maintains consistency with the
-	 * EACH ROW triggers that we already fire on COPY.
-	 */
-	ExecBSInsertTriggers(estate, resultRelInfo);
+	if (!IsParallelCopy())
+	{
+		/*
+		 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
+		 * should do this for COPY, since it's not really an "INSERT" statement as
+		 * such. However, executing these triggers maintains consistency with the
+		 * EACH ROW triggers that we already fire on COPY.
+		 */
+		ExecBSInsertTriggers(estate, resultRelInfo);
+	}
 
 	econtext = GetPerTupleExprContext(estate);
 
@@ -3889,6 +4626,16 @@ CopyFrom(CopyState cstate)
 					!has_instead_insert_row_trig &&
 					resultRelInfo->ri_FdwRoutine == NULL;
 
+				/*
+				 * If the table has any partitions that are either foreign or
+				 * has BEFORE/INSTEAD OF triggers, we can't perform copy
+				 * operations with parallel workers.
+				 */
+				if (!leafpart_use_multi_insert && IsParallelWorker())
+					ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							errmsg("cannot perform PARALLEL COPY if partition has BEFORE/INSTEAD OF triggers, or if the partition is foreign partition"),
+							errhint("Try COPY without PARALLEL option")));
+
 				/* Set the multi-insert buffer to use for this partition. */
 				if (leafpart_use_multi_insert)
 				{
@@ -4305,7 +5052,7 @@ BeginCopyFrom(ParseState *pstate,
 	 * only in text mode.
 	 */
 	initStringInfo(&cstate->attribute_buf);
-	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+	cstate->raw_buf = (IsParallelCopy()) ? NULL : (char *) palloc(RAW_BUF_SIZE + 1);
 	cstate->raw_buf_index = cstate->raw_buf_len = 0;
 	if (!cstate->binary)
 	{
@@ -4454,26 +5201,35 @@ NextCopyFromRawFields(CopyState cstate, char ***fields, int *nfields)
 	/* only available for text or csv input */
 	Assert(!cstate->binary);
 
-	/* on input just throw the header line away */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (IsParallelCopy())
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
-			return false;		/* done */
+		done = GetWorkerLine(cstate);
+		if (done && cstate->line_buf.len == 0)
+			return false;
 	}
+	else
+	{
+		/* on input just throw the header line away */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
+		{
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+				return false;		/* done */
+		}
 
-	cstate->cur_lineno++;
+		cstate->cur_lineno++;
 
-	/* Actually read the line into memory here */
-	done = CopyReadLine(cstate);
+		/* Actually read the line into memory here */
+		done = CopyReadLine(cstate);
 
-	/*
-	 * EOF at start of line means we're done.  If we see EOF after some
-	 * characters, we act as though it was newline followed by EOF, ie,
-	 * process the line and then exit loop on next iteration.
-	 */
-	if (done && cstate->line_buf.len == 0)
-		return false;
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			return false;
+	}
 
 	/* Parse the line into de-escaped field values */
 	if (cstate->csv_mode)
@@ -4721,9 +5477,31 @@ CopyReadLine(CopyState cstate)
 		 */
 		if (cstate->copy_dest == COPY_NEW_FE)
 		{
+			bool bIsFirst = true;
 			do
 			{
-				cstate->raw_buf_index = cstate->raw_buf_len;
+				if (!IsParallelCopy())
+					cstate->raw_buf_index = cstate->raw_buf_len;
+				else
+				{
+					if (cstate->raw_buf_index == RAW_BUF_SIZE)
+					{
+						/* Get a new block if it is the first time, From the
+						 * subsequent time, reset the index and re-use the same
+						 * block.
+						 */
+						if (bIsFirst)
+						{
+							ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+							uint32 block_pos = WaitGetFreeCopyBlock(pcshared_info);
+							cstate->raw_buf = pcshared_info->data_blocks[block_pos].data;
+							bIsFirst = false;
+						}
+
+						cstate->raw_buf_index = cstate->raw_buf_len = 0;
+					}
+				}
+
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
@@ -4778,7 +5556,7 @@ static void
 ConvertToServerEncoding(CopyState cstate)
 {
 	/* Done reading the line.  Convert it to server encoding. */
-	if (cstate->need_transcoding)
+	if (cstate->need_transcoding && (!IsParallelCopy() || IsWorker()))
 	{
 		char	   *cvt;
 		cvt = pg_any_to_server(cstate->line_buf.data,
@@ -4817,6 +5595,11 @@ CopyReadLineText(CopyState cstate)
 	char		quotec = '\0';
 	char		escapec = '\0';
 
+	/* For parallel copy */
+	int			line_size = 0;
+	int			line_pos = 0;
+
+	cstate->eol_type = EOL_UNKNOWN;
 	if (cstate->csv_mode)
 	{
 		quotec = cstate->quote[0];
@@ -4871,6 +5654,8 @@ CopyReadLineText(CopyState cstate)
 		if (raw_buf_ptr >= copy_buf_len || need_data)
 		{
 			REFILL_LINEBUF;
+			SetRawBufForLoad(cstate, line_size, copy_buf_len, raw_buf_ptr,
+							 &copy_raw_buf);
 
 			/*
 			 * Try to read some more data.  This will certainly reset
@@ -5095,9 +5880,15 @@ CopyReadLineText(CopyState cstate)
 				 * discard the data and the \. sequence.
 				 */
 				if (prev_raw_ptr > cstate->raw_buf_index)
-					appendBinaryStringInfo(&cstate->line_buf,
+				{
+					if (!IsParallelCopy())
+						appendBinaryStringInfo(&cstate->line_buf,
 										   cstate->raw_buf + cstate->raw_buf_index,
 										   prev_raw_ptr - cstate->raw_buf_index);
+					else
+						line_size += prev_raw_ptr - cstate->raw_buf_index;
+				}
+
 				cstate->raw_buf_index = raw_buf_ptr;
 				result = true;	/* report EOF */
 				break;
@@ -5149,6 +5940,26 @@ not_end_of_copy:
 			IF_NEED_REFILL_AND_EOF_BREAK(mblen - 1);
 			raw_buf_ptr += mblen - 1;
 		}
+
+		/*
+		 * Skip the header line. Update the line here, this cannot be done at
+		 * the beginning, as there is a possibility that file contains empty
+		 * lines.
+		 */
+		if (IsParallelCopy() && first_char_in_line && !IsHeaderLine())
+		{
+			ParallelCopyShmInfo	*pcshared_info = cstate->pcdata->pcshared_info;
+			ParallelCopyLineBoundary *lineInfo;
+			uint32			 line_first_block = pcshared_info->cur_block_pos;
+			line_pos = UpdateBlockInLineInfo(cstate,
+											   line_first_block,
+											   cstate->raw_buf_index, -1,
+											   LINE_LEADER_POPULATING);
+			lineInfo = &pcshared_info->line_boundaries.ring[line_pos];
+			elog(DEBUG1, "[Leader] Adding - block:%d, offset:%d, line position:%d",
+						 line_first_block,	lineInfo->start_offset, line_pos);
+		}
+
 		first_char_in_line = false;
 	}							/* end of outer loop */
 
@@ -5157,6 +5968,7 @@ not_end_of_copy:
 	 */
 	REFILL_LINEBUF;
 	CLEAR_EOL_LINE();
+	EndLineParallelCopy(cstate, line_pos, line_size, raw_buf_ptr);
 
 	return result;
 }
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index c4af40b..c95db78 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -2353,7 +2353,7 @@ psql_completion(const char *text, int start, int end)
 	/* Complete COPY <sth> FROM|TO filename WITH ( */
 	else if (Matches("COPY|\\copy", MatchAny, "FROM|TO", MatchAny, "WITH", "("))
 		COMPLETE_WITH("FORMAT", "FREEZE", "DELIMITER", "NULL",
-					  "HEADER", "QUOTE", "ESCAPE", "FORCE_QUOTE",
+					  "HEADER", "PARALLEL", "QUOTE", "ESCAPE", "FORCE_QUOTE",
 					  "FORCE_NOT_NULL", "FORCE_NULL", "ENCODING");
 
 	/* Complete COPY <sth> FROM|TO filename WITH (FORMAT */
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index 5348011..4ea02f7 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -381,6 +381,8 @@ extern FullTransactionId GetTopFullTransactionId(void);
 extern FullTransactionId GetTopFullTransactionIdIfAny(void);
 extern FullTransactionId GetCurrentFullTransactionId(void);
 extern FullTransactionId GetCurrentFullTransactionIdIfAny(void);
+extern void AssignFullTransactionIdForWorker(FullTransactionId fullTransactionId);
+extern void AssignCommandIdForWorker(CommandId commandId, bool used);
 extern void MarkCurrentTransactionIdLoggedIfAny(void);
 extern bool SubTransactionIsActive(SubTransactionId subxid);
 extern CommandId GetCurrentCommandId(bool used);
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 3a83d0f..ba93f65 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1704,6 +1704,7 @@ ParallelCopyLineBoundary
 ParallelCopyData
 ParallelCopyDataBlock
 ParallelCopyLineBuf
+ParallelCopyLineState
 ParallelCopyShmInfo
 ParallelExecutorInfo
 ParallelHashGrowth
-- 
1.8.3.1

v2-0004-Documentation-for-parallel-copy.patchapplication/x-patch; name=v2-0004-Documentation-for-parallel-copy.patchDownload
From e543e3b3def9367bd30191ea334c26fb7e372b96 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Sat, 1 Aug 2020 09:00:36 +0530
Subject: [PATCH v2 4/5] Documentation for parallel copy.

This patch has the documentation changes for parallel copy.
---
 doc/src/sgml/ref/copy.sgml | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/doc/src/sgml/ref/copy.sgml b/doc/src/sgml/ref/copy.sgml
index 18189ab..95d349d 100644
--- a/doc/src/sgml/ref/copy.sgml
+++ b/doc/src/sgml/ref/copy.sgml
@@ -37,6 +37,7 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
     DELIMITER '<replaceable class="parameter">delimiter_character</replaceable>'
     NULL '<replaceable class="parameter">null_string</replaceable>'
     HEADER [ <replaceable class="parameter">boolean</replaceable> ]
+    PARALLEL <replaceable class="parameter">integer</replaceable>
     QUOTE '<replaceable class="parameter">quote_character</replaceable>'
     ESCAPE '<replaceable class="parameter">escape_character</replaceable>'
     FORCE_QUOTE { ( <replaceable class="parameter">column_name</replaceable> [, ...] ) | * }
@@ -275,6 +276,21 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
    </varlistentry>
 
    <varlistentry>
+    <term><literal>PARALLEL</literal></term>
+    <listitem>
+     <para>
+      Perform <command>COPY FROM</command> in parallel using <replaceable
+      class="parameter"> integer</replaceable> background workers.  Please
+      note that it is not guaranteed that the number of parallel workers
+      specified in <replaceable class="parameter">integer</replaceable> will
+      be used during execution.  It is possible for a copy to run with fewer
+      workers than specified, or even with no workers at all.  This option is
+      allowed only in <command>COPY FROM</command>.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><literal>QUOTE</literal></term>
     <listitem>
      <para>
-- 
1.8.3.1

v2-0005-Tests-for-parallel-copy.patchapplication/x-patch; name=v2-0005-Tests-for-parallel-copy.patchDownload
From ec2489bc2316da2aaa959e1e1c53df1f0a801d8a Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Sat, 1 Aug 2020 09:19:39 +0530
Subject: [PATCH v2 5/5] Tests for parallel copy.

This patch has the tests for parallel copy.
---
 src/test/regress/expected/copy2.out | 206 ++++++++++++++++++++++++++++++++++-
 src/test/regress/input/copy.source  |  12 +++
 src/test/regress/output/copy.source |  12 +++
 src/test/regress/sql/copy2.sql      | 208 +++++++++++++++++++++++++++++++++++-
 4 files changed, 430 insertions(+), 8 deletions(-)

diff --git a/src/test/regress/expected/copy2.out b/src/test/regress/expected/copy2.out
index e40287d..0e01fa0 100644
--- a/src/test/regress/expected/copy2.out
+++ b/src/test/regress/expected/copy2.out
@@ -254,18 +254,32 @@ It is "perfect".|
 "It is ""perfect"".","	"
 "",
 --test that we read consecutive LFs properly
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 COPY testnl FROM stdin CSV;
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+SELECT * FROM testnl;
+ a |          b           | c 
+---+----------------------+---
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+(2 rows)
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 COPY testeoc FROM stdin CSV;
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
 COPY testeoc TO stdout CSV;
 a\.
 \.b
 c\.d
 "\."
 -- test handling of nonstandard null marker that violates escaping rules
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 COPY testnull TO stdout WITH NULL AS E'\\0';
 1	\\0
@@ -280,6 +294,15 @@ SELECT * FROM testnull;
     | 
 (4 rows)
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 1);
+SELECT * FROM testnull;
+ a  | b  
+----+----
+ 42 | \0
+    | 
+(2 rows)
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -349,6 +372,34 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+SELECT * FROM vistest;
+ a  
+----
+ a2
+ b
+(2 rows)
+
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+COMMIT;
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 SELECT * FROM vistest;
  a 
@@ -409,7 +460,7 @@ SELECT * FROM vistest;
 (2 rows)
 
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -420,6 +471,8 @@ CREATE TEMP TABLE forcetest (
 -- should succeed with no effect ("b" remains an empty string, "c" remains NULL)
 BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 1);
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
  b |  c   
@@ -430,6 +483,8 @@ SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
 BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 1);
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
  c |  d   
@@ -486,6 +541,31 @@ select * from check_con_tbl;
    
 (2 rows)
 
+\d+ check_con_tbl
+                               Table "public.check_con_tbl"
+ Column |  Type   | Collation | Nullable | Default | Storage | Stats target | Description 
+--------+---------+-----------+----------+---------+---------+--------------+-------------
+ f1     | integer |           |          |         | plain   |              | 
+Check constraints:
+    "check_con_tbl_check" CHECK (check_con_function(check_con_tbl.*))
+
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 1);
+NOTICE:  input = {"f1":1}
+NOTICE:  input = {"f1":null}
+copy check_con_tbl from stdin with (parallel 1);
+NOTICE:  input = {"f1":0}
+ERROR:  new row for relation "check_con_tbl" violates check constraint "check_con_tbl_check"
+DETAIL:  Failing row contains (0).
+CONTEXT:  COPY check_con_tbl, line 1: "0"
+parallel worker
+select * from check_con_tbl;
+ f1 
+----
+  1
+   
+(2 rows)
+
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
 CREATE ROLE regress_rls_copy_user_colperms;
@@ -600,8 +680,126 @@ SELECT * FROM instead_of_insert_tbl;
 (2 rows)
 
 COMMIT;
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+COPY test_parallel_copy (a, b, c, d, e) from stdin with (PARALLEL 1);
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1, FORMAT 'csv', HEADER);
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0');
+ERROR:  argument to option "parallel" must be a positive integer greater than zero
+LINE 1: COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0'...
+                                                        ^
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri from stdin with (FORMAT csv, DELIMITER ',', PARALLEL 1);
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1) WHERE height > random() * 65;
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+-- temporary table copy: should perform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+COPY temp_test (a) from stdin with (PARALLEL 1);
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) from stdin with (PARALLEL 1);
+ERROR:  column "xyz" of relation "test_parallel_copy" does not exist
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) from stdin with (PARALLEL 1);
+ERROR:  column "d" specified more than once
+-- missing data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  invalid input syntax for type integer: ""
+CONTEXT:  COPY test_parallel_copy, line 0, column a: ""
+parallel worker
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2000	230	23	23"
+parallel worker
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2001	231	\N	\N"
+parallel worker
+-- extra data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  extra data after last expected column
+CONTEXT:  COPY test_parallel_copy, line 1: "2002	232	40	50	60	70	80"
+parallel worker
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) from stdin with (delimiter ',', null 'x', PARALLEL 1) ;
+COPY test_parallel_copy from stdin WITH (DELIMITER ';', NULL '', PARALLEL 1);
+COPY test_parallel_copy from stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL 1);
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = 50004;
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a > 60003;
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE f > 60003;
+ERROR:  column "f" does not exist
+LINE 1: ..._parallel_copy from stdin WITH (PARALLEL 1) WHERE f > 60003;
+                                                             ^
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+ERROR:  missing FROM-clause entry for table "x"
+LINE 1: ...rallel_copy from stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+                                                                  ^
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (SELECT 1 FROM x);
+ERROR:  cannot use subquery in COPY FROM WHERE condition
+LINE 1: ...arallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (SELECT...
+                                                             ^
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (generate_series(1,5));
+ERROR:  set-returning functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...lel_copy from stdin WITH (PARALLEL 1) WHERE a IN (generate_s...
+                                                             ^
+COPY test_parallel_copy from stdin WITH(PARALLEL 1) WHERE a = row_number() over(b);
+ERROR:  window functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...rallel_copy from stdin WITH(PARALLEL 1) WHERE a = row_number...
+                                                             ^
+-- check results of copy in
+SELECT * FROM test_parallel_copy;
+   a   | b  |     c      |    d    |    e    
+-------+----+------------+---------+---------
+     1 | 11 | test_c1    | test_d1 | test_e1
+     2 | 12 | test_c2    | test_d2 | test_e2
+       |  3 | stuff      | test_d3 | 
+       |  4 | stuff      | test_d4 | 
+       |  5 | stuff      | test_d5 | 
+       |    | 45         | 80      | 90
+       |    | x          | \x      | \x
+       |    | ,          | \,      | \
+  3000 |    | c          |         | 
+  4000 |    | C          |         | 
+  4001 |  1 | empty      |         | 
+  4002 |  2 | null       |         | 
+  4003 |  3 | Backslash  | \       | \
+  4004 |  4 | BackslashX | \X      | \X
+  4005 |  5 | N          | N       | N
+  4006 |  6 | BackslashN | \N      | \N
+  4007 |  7 | XX         | XX      | XX
+  4008 |  8 | Delimiter  | :       | :
+ 50004 | 25 | 35         | 45      | 55
+ 60004 | 25 | 35         | 45      | 55
+ 60005 | 26 | 36         | 46      | 56
+(21 rows)
+
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
 DROP TABLE x, y;
diff --git a/src/test/regress/input/copy.source b/src/test/regress/input/copy.source
index a1d529a..159c058 100644
--- a/src/test/regress/input/copy.source
+++ b/src/test/regress/input/copy.source
@@ -15,6 +15,13 @@ DELETE FROM onek;
 
 COPY onek FROM '@abs_builddir@/results/onek.data';
 
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+
+SELECT COUNT(*) FROM tenk1;
+
+TRUNCATE tenk1;
+
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
@@ -159,6 +166,11 @@ truncate parted_copytest;
 
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
 
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
+
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/output/copy.source b/src/test/regress/output/copy.source
index 938d355..c3003fe 100644
--- a/src/test/regress/output/copy.source
+++ b/src/test/regress/output/copy.source
@@ -9,6 +9,15 @@ COPY onek FROM '@abs_srcdir@/data/onek.data';
 COPY onek TO '@abs_builddir@/results/onek.data';
 DELETE FROM onek;
 COPY onek FROM '@abs_builddir@/results/onek.data';
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+SELECT COUNT(*) FROM tenk1;
+ count 
+-------
+ 10000
+(1 row)
+
+TRUNCATE tenk1;
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
 COPY person FROM '@abs_srcdir@/data/person.data';
@@ -113,6 +122,9 @@ insert into parted_copytest select x,1,'One' from generate_series(1011,1020) x;
 copy (select * from parted_copytest order by a) to '@abs_builddir@/results/parted_copytest.csv';
 truncate parted_copytest;
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/sql/copy2.sql b/src/test/regress/sql/copy2.sql
index 902f4fa..7015698 100644
--- a/src/test/regress/sql/copy2.sql
+++ b/src/test/regress/sql/copy2.sql
@@ -157,7 +157,7 @@ COPY y TO stdout (FORMAT CSV, FORCE_QUOTE *);
 
 --test that we read consecutive LFs properly
 
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 
 COPY testnl FROM stdin CSV;
 1,"a field with two LFs
@@ -165,8 +165,16 @@ COPY testnl FROM stdin CSV;
 inside",2
 \.
 
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+1,"a field with two LFs
+
+inside",2
+\.
+
+SELECT * FROM testnl;
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 
 COPY testeoc FROM stdin CSV;
 a\.
@@ -175,11 +183,19 @@ c\.d
 "\."
 \.
 
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+a\.
+\.b
+c\.d
+"\."
+\.
+
 COPY testeoc TO stdout CSV;
 
 -- test handling of nonstandard null marker that violates escaping rules
 
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 
 COPY testnull TO stdout WITH NULL AS E'\\0';
@@ -191,6 +207,14 @@ COPY testnull FROM stdin WITH NULL AS E'\\0';
 
 SELECT * FROM testnull;
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 1);
+42	\\0
+\0	\0
+\.
+
+SELECT * FROM testnull;
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -235,6 +259,23 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+a2
+b
+\.
+SELECT * FROM vistest;
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+d2
+e
+\.
+SELECT * FROM vistest;
+COMMIT;
+SELECT * FROM vistest;
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 x
 y
@@ -284,7 +325,7 @@ SELECT * FROM vistest;
 COMMIT;
 SELECT * FROM vistest;
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -297,6 +338,10 @@ BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
 1,,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 1);
+1,,""
+\.
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
@@ -304,6 +349,10 @@ BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
 2,'a',,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 1);
+2,'a',,""
+\.
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
 -- should fail with not-null constraint violation
@@ -339,6 +388,16 @@ copy check_con_tbl from stdin;
 0
 \.
 select * from check_con_tbl;
+\d+ check_con_tbl
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 1);
+1
+\N
+\.
+copy check_con_tbl from stdin with (parallel 1);
+0
+\.
+select * from check_con_tbl;
 
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
@@ -440,8 +499,149 @@ test1
 SELECT * FROM instead_of_insert_tbl;
 COMMIT;
 
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+
+COPY test_parallel_copy (a, b, c, d, e) from stdin with (PARALLEL 1);
+1	11	test_c1	test_d1	test_e1
+2	12	test_c2	test_d2	test_e2
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+3	test_d3
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+4	test_d4
+5	test_d5
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1, FORMAT 'csv', HEADER);
+b	d
+\.
+
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0');
+
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri from stdin with (FORMAT csv, DELIMITER ',', PARALLEL 1);
+10
+\.
+
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1) WHERE height > random() * 65;
+60,60,60
+\.
+
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+60
+\.
+
+-- temporary table copy: should perform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+
+COPY temp_test (a) from stdin with (PARALLEL 1);
+10
+\.
+
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) from stdin with (PARALLEL 1);
+
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) from stdin with (PARALLEL 1);
+
+-- missing data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+
+\.
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+2000	230	23	23
+\.
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+2001	231	\N	\N
+\.
+
+-- extra data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+2002	232	40	50	60	70	80
+\.
+
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) from stdin with (delimiter ',', null 'x', PARALLEL 1) ;
+x,45,80,90
+x,\x,\\x,\\\x
+x,\,,\\\,,\\
+\.
+
+COPY test_parallel_copy from stdin WITH (DELIMITER ';', NULL '', PARALLEL 1);
+3000;;c;;
+\.
+
+COPY test_parallel_copy from stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL 1);
+4000:\X:C:\X:\X
+4001:1:empty::
+4002:2:null:\X:\X
+4003:3:Backslash:\\:\\
+4004:4:BackslashX:\\X:\\X
+4005:5:N:\N:\N
+4006:6:BackslashN:\\N:\\N
+4007:7:XX:\XX:\XX
+4008:8:Delimiter:\::\:
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = 50004;
+50003	24	34	44	54
+50004	25	35	45 	55
+50005	26	36	46	56
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a > 60003;
+60001	22	32	42	52
+60002	23	33	43	53
+60003	24	34	44	54
+60004	25	35	45	55
+60005	26	36	46	56
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE f > 60003;
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (SELECT 1 FROM x);
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (generate_series(1,5));
+
+COPY test_parallel_copy from stdin WITH(PARALLEL 1) WHERE a = row_number() over(b);
+
+-- check results of copy in
+SELECT * FROM test_parallel_copy;
+
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
 DROP TABLE x, y;
-- 
1.8.3.1

v2-0006-Parallel-Copy-For-Binary-Format-Files.patchapplication/x-patch; name=v2-0006-Parallel-Copy-For-Binary-Format-Files.patchDownload
From 26a401f1ece2dfca2414805c5ae2c71f156e9ae6 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddy@enterprisedb.com>
Date: Mon, 3 Aug 2020 11:58:35 +0530
Subject: [PATCH v2] Parallel Copy For Binary Format Files

Leader reads data from the file into the DSM data blocks each of 64K size.
It also identifies each tuple data block id, start offset, end offset,
tuple size and updates this information in the ring data structure.
Workers parallelly read the tuple information from the ring data structure,
the actual tuple data from the data blocks and parallelly insert the tuples
into the table.
---
 src/backend/commands/copy.c | 687 +++++++++++++++++++++++++++++++-----
 1 file changed, 602 insertions(+), 85 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index c65fc9866f..af24c20a3f 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -262,6 +262,17 @@ typedef struct ParallelCopyLineBuf
 	uint64				cur_lineno;	/* line number for error messages */
 }ParallelCopyLineBuf;
 
+/*
+ * Represents the usage mode for CopyReadBinaryGetDataBlock.
+ */
+typedef enum FieldInfoType
+{
+	FIELD_NONE = 0,
+	FIELD_COUNT,
+	FIELD_SIZE,
+	FIELD_DATA
+} FieldInfoType;
+
 /*
  * Parallel copy data information.
  */
@@ -283,6 +294,9 @@ typedef struct ParallelCopyData
 
 	/* Current position in worker_line_buf */
 	uint32				worker_line_buf_pos;
+
+	/* For binary formatted files */
+	ParallelCopyDataBlock *curr_data_block;
 }ParallelCopyData;
 
 /*
@@ -447,6 +461,7 @@ typedef struct SerializedParallelCopyState
 	/* Working state for COPY FROM */
 	AttrNumber          num_defaults;
 	Oid                 relid;
+	bool				binary;
 }SerializedParallelCopyState;
 
 /* DestReceiver for COPY (query) TO */
@@ -521,7 +536,6 @@ typedef struct CopyMultiInsertInfo
 	int			ti_options;		/* table insert options */
 } CopyMultiInsertInfo;
 
-
 /*
  * These macros centralize code used to process line_buf and raw_buf buffers.
  * They are macros because they often do continue/break control and to avoid
@@ -651,8 +665,110 @@ else \
 
 /* End parallel copy Macros */
 
-static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
+/*
+ * CHECK_FIELD_COUNT - Handles the error cases for field count
+ * for binary format files.
+ */
+#define CHECK_FIELD_COUNT \
+{\
+	if (fld_count == -1) \
+	{ \
+		if (IsParallelCopy() && \
+			!IsLeader()) \
+			return true; \
+		else if (IsParallelCopy() && \
+			IsLeader()) \
+		{ \
+			if (cstate->pcdata->curr_data_block->data[cstate->raw_buf_index + sizeof(fld_count)] != 0) \
+				ereport(ERROR, \
+						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+						errmsg("received copy data after EOF marker"))); \
+			return true; \
+		} \
+		else \
+		{ \
+			/* \
+			* Received EOF marker.  In a V3-protocol copy, wait for the \
+			* protocol-level EOF, and complain if it doesn't come \
+			* immediately.  This ensures that we correctly handle CopyFail, \
+			* if client chooses to send that now. \
+			* \
+			* Note that we MUST NOT try to read more data in an old-protocol \
+			* copy, since there is no protocol-level EOF marker then.  We \
+			* could go either way for copy from file, but choose to throw \
+			* error if there's data after the EOF marker, for consistency \
+			* with the new-protocol case. \
+			*/ \
+			char		dummy; \
+			if (cstate->copy_dest != COPY_OLD_FE && \
+				CopyReadBinaryData(cstate, &dummy, 1) > 0) \
+				ereport(ERROR, \
+						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+						errmsg("received copy data after EOF marker"))); \
+				return false; \
+		} \
+	} \
+	if (fld_count != cstate->max_fields) \
+		ereport(ERROR, \
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+				errmsg("row field count is %d, expected %d", \
+				(int) fld_count, cstate->max_fields))); \
+}
+
+/*
+ * CHECK_FIELD_SIZE - Handles the error case for field size
+ * for binary format files.
+ */
+#define CHECK_FIELD_SIZE(fld_size) \
+{ \
+	if (fld_size < -1) \
+		ereport(ERROR, \
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+				errmsg("invalid field size")));\
+}
 
+/*
+ * EOF_ERROR - Error statement for EOF for binary format
+ * files.
+ */
+#define EOF_ERROR \
+{ \
+	ereport(ERROR, \
+		(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+		errmsg("unexpected EOF in COPY data")));\
+}
+
+/*
+ * GET_RAW_BUF_INDEX - Calculates the raw buf index for the cases
+ * where the data spread is across multiple data blocks.
+ */
+#define GET_RAW_BUF_INDEX(raw_buf_index, fld_size, required_blks, curr_blk_bytes) \
+{ \
+	raw_buf_index = fld_size - (((required_blks - 1) * DATA_BLOCK_SIZE) + curr_blk_bytes); \
+}
+
+/*
+ * GET_REQUIRED_BLOCKS - Calculates the number of data
+ * blocks required for the cases where the data spread
+ * is across multiple data blocks.
+ */
+#define GET_REQUIRED_BLOCKS(required_blks, fld_size, curr_blk_bytes) \
+{ \
+	/* \
+	 * field size can spread across multiple data blocks, \
+	 * calculate the number of required data blocks and try to get \
+	 * those many data blocks. \
+	 */ \
+	required_blks = (int32)(fld_size - curr_blk_bytes)/(int32)DATA_BLOCK_SIZE; \
+	/* \
+	 * check if we need the data block for the field data \
+	 * bytes that are not modulus of data block size. \
+	 */ \
+	if ((fld_size - curr_blk_bytes)%DATA_BLOCK_SIZE != 0) \
+		required_blks++; \
+}
+
+static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
 /* non-export function prototypes */
 static CopyState BeginCopy(ParseState *pstate, bool is_from, Relation rel,
@@ -708,6 +824,14 @@ static void ExecBeforeStmtTrigger(CopyState cstate);
 static void CheckTargetRelValidity(CopyState cstate);
 static void PopulateCstateCatalogInfo(CopyState cstate);
 static pg_attribute_always_inline uint32 GetLinePosition(CopyState cstate);
+static uint32 WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info);
+static bool CopyReadBinaryTupleLeader(CopyState cstate);
+static void CopyReadBinaryFindTupleSize(CopyState cstate, uint32 *line_size);
+static bool CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls);
+static Datum CopyReadBinaryAttributeWorker(CopyState cstate, FmgrInfo *flinfo,
+										   Oid typioparam, int32 typmod, bool *isnull);
+static void CopyReadBinaryGetDataBlock(CopyState cstate, FieldInfoType field_info);
+
 /*
  * SerializeParallelCopyState - Copy shared_cstate using cstate information.
  */
@@ -725,6 +849,7 @@ SerializeParallelCopyState(CopyState cstate, SerializedParallelCopyState *shared
 	shared_cstate->convert_selectively = cstate->convert_selectively;
 	shared_cstate->num_defaults = cstate->num_defaults;
 	shared_cstate->relid = cstate->pcdata->relid;
+	shared_cstate->binary = cstate->binary;
 }
 
 /*
@@ -884,8 +1009,8 @@ FindInsertMethod(CopyState cstate)
 static pg_attribute_always_inline bool
 IsParallelCopyAllowed(CopyState cstate)
 {
-	/* Parallel copy not allowed for frontend (2.0 protocol) & binary option. */
-	if ((cstate->copy_dest == COPY_OLD_FE) || cstate->binary)
+	/* Parallel copy not allowed for frontend (2.0 protocol). */
+	if (cstate->copy_dest == COPY_OLD_FE)
 		return false;
 
 	/* Check if copy is into foreign table or temporary table. */
@@ -1155,6 +1280,7 @@ InitializeParallelCopyInfo(SerializedParallelCopyState *shared_cstate,
 	cstate->convert_selectively = shared_cstate->convert_selectively;
 	cstate->num_defaults = shared_cstate->num_defaults;
 	pcdata->relid = shared_cstate->relid;
+	cstate->binary = shared_cstate->binary;
 
 	PopulateCommonCstateInfo(cstate, tup_desc, attnamelist);
 
@@ -1541,35 +1667,72 @@ ParallelCopyFrom(CopyState cstate)
 	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
 	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
 
+	/* raw_buf is not used in parallel copy, instead data blocks are used.*/
+	pfree(cstate->raw_buf);
+
 	/* Execute the before statement triggers from the leader */
 	ExecBeforeStmtTrigger(cstate);
 
-	/* On input just throw the header line away. */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (!cstate->binary)
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
+		/* On input just throw the header line away. */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
 		{
-			pcshared_info->is_read_in_progress = false;
-			return;			/* done */
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+			{
+				pcshared_info->is_read_in_progress = false;
+				return;			/* done */
+			}
 		}
-	}
 
-	for (;;)
-	{
-		bool done;
-		cstate->cur_lineno++;
+		for (;;)
+		{
+			bool done;
+			cstate->cur_lineno++;
 
-		/* Actually read the line into memory here. */
-		done = CopyReadLine(cstate);
+			/* Actually read the line into memory here. */
+			done = CopyReadLine(cstate);
 
+			/*
+			* EOF at start of line means we're done.  If we see EOF after some
+			* characters, we act as though it was newline followed by EOF, ie,
+			* process the line and then exit loop on next iteration.
+			*/
+			if (done && cstate->line_buf.len == 0)
+				break;
+		}
+	}
+	else
+	{
 		/*
-		 * EOF at start of line means we're done.  If we see EOF after some
-		 * characters, we act as though it was newline followed by EOF, ie,
-		 * process the line and then exit loop on next iteration.
+		 * Binary Format Files.
+		 * For parallel copy leader, fill in the error
+		 * context information here, in case any failures
+		 * while determining tuple offsets, leader
+		 * would throw the errors with proper context.
 		 */
-		if (done && cstate->line_buf.len == 0)
-			break;
+		ErrorContextCallback errcallback;
+		errcallback.callback = CopyFromErrorCallback;
+		errcallback.arg = (void *) cstate;
+		errcallback.previous = error_context_stack;
+		error_context_stack = &errcallback;
+		cstate->pcdata->curr_data_block = NULL;
+		cstate->raw_buf_index = 0;
+		pcshared_info->populated = 0;
+		cstate->cur_lineno = 0;
+		cstate->max_fields = list_length(cstate->attnumlist);
+
+		for (;;)
+		{
+			bool eof = false;
+			cstate->cur_lineno++;
+
+			eof = CopyReadBinaryTupleLeader(cstate);
+
+			if (eof)
+				break;
+		}
 	}
 
 	pcshared_info->is_read_in_progress = false;
@@ -1577,7 +1740,355 @@ ParallelCopyFrom(CopyState cstate)
  }
 
 /*
- * GetLinePosition - return the line position that worker should process.
+ * CopyReadBinaryGetDataBlock - gets a new block, updates
+ * the current offset, calculates the skip bytes.
+ */
+static void
+CopyReadBinaryGetDataBlock(CopyState cstate, FieldInfoType field_info)
+{
+	ParallelCopyDataBlock *data_block = NULL;
+	ParallelCopyDataBlock *curr_data_block = cstate->pcdata->curr_data_block;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	uint8 move_bytes = 0;
+	uint32 block_pos;
+	uint32 prev_block_pos;
+	int read_bytes = 0;
+
+	prev_block_pos = pcshared_info->cur_block_pos;
+
+	block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+	if (field_info == FIELD_SIZE || field_info == FIELD_COUNT)
+		move_bytes = (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+
+	if (curr_data_block != NULL)
+		curr_data_block->skip_bytes = move_bytes;
+
+	data_block = &pcshared_info->data_blocks[block_pos];
+
+	if (move_bytes > 0 && curr_data_block != NULL)
+		memmove(&data_block->data[0], &curr_data_block->data[cstate->raw_buf_index], move_bytes);
+
+	elog(DEBUG1, "LEADER - field info %d is spread across data blocks - moved %d bytes from current block %u to %u block",
+		field_info, move_bytes, prev_block_pos, block_pos);
+
+	read_bytes = CopyGetData(cstate, &data_block->data[move_bytes], 1, (DATA_BLOCK_SIZE - move_bytes));
+
+	if (field_info == FIELD_NONE && cstate->reached_eof)
+		return;
+
+	if (cstate->reached_eof)
+		EOF_ERROR;
+
+	elog(DEBUG1, "LEADER - bytes read from file %d", read_bytes);
+
+	if(field_info == FIELD_SIZE || field_info == FIELD_DATA)
+	{
+		ParallelCopyDataBlock *prev_data_block = NULL;
+		prev_data_block = curr_data_block;
+		prev_data_block->following_block = block_pos;
+
+		if (prev_data_block->curr_blk_completed  == false)
+			prev_data_block->curr_blk_completed = true;
+
+		pg_atomic_add_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+	}
+
+	cstate->pcdata->curr_data_block = data_block;
+	cstate->raw_buf_index = 0;
+}
+
+/*
+ * CopyReadBinaryTupleLeader - leader reads data from binary formatted file
+ * to data blocks and identifies tuple boundaries/offsets so that workers
+ * can work on the data blocks data.
+ */
+static bool
+CopyReadBinaryTupleLeader(CopyState cstate)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	int16		fld_count;
+	uint32      line_size = 0;
+	uint32 		start_block_pos;
+	uint32		start_offset;
+
+	if (cstate->pcdata->curr_data_block == NULL)
+	{
+		CopyReadBinaryGetDataBlock(cstate, FIELD_NONE);
+
+		/*
+		 * no data is read from file here. one possibility
+		 * to be here could be that the binary file just
+		 * has a valid signature but nothing else.
+		 */
+		if (cstate->reached_eof)
+			return true;
+	}
+
+	if ((cstate->raw_buf_index + sizeof(fld_count)) >= DATA_BLOCK_SIZE)
+		CopyReadBinaryGetDataBlock(cstate, FIELD_COUNT);
+
+	memcpy(&fld_count, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_count));
+	fld_count = (int16) pg_ntoh16(fld_count);
+	CHECK_FIELD_COUNT;
+	start_offset = cstate->raw_buf_index;
+	cstate->raw_buf_index += sizeof(fld_count);
+	line_size += sizeof(fld_count);
+	start_block_pos = pcshared_info->cur_block_pos;
+
+	CopyReadBinaryFindTupleSize(cstate, &line_size);
+
+	pg_atomic_add_fetch_u32(&cstate->pcdata->curr_data_block->unprocessed_line_parts, 1);
+
+	if (line_size > 0)
+	{
+		int line_pos = UpdateBlockInLineInfo(cstate,
+											start_block_pos,
+											start_offset,
+											line_size,
+											LINE_LEADER_POPULATED);
+
+		pcshared_info->populated++;
+		elog(DEBUG1, "LEADER - adding - block:%u, offset:%u, line size:%u line position:%d",
+				start_block_pos, start_offset, line_size, line_pos);
+	}
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryFindTupleSize - leader identifies boundaries/
+ * offsets for each attribute/column and finally results in the
+ * tuple/row size. It moves on to next data block if the attribute/
+ * column is spread across data blocks.
+ */
+static void
+CopyReadBinaryFindTupleSize(CopyState cstate, uint32 *line_size)
+{
+	int32		fld_size;
+	ListCell   *cur;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			att_num = lfirst_int(cur);
+		Form_pg_attribute att = TupleDescAttr(tup_desc, (att_num - 1));
+		cstate->cur_attname = NameStr(att->attname);
+		fld_size = 0;
+
+		if ((cstate->raw_buf_index + sizeof(fld_size)) >= DATA_BLOCK_SIZE)
+			CopyReadBinaryGetDataBlock(cstate, FIELD_SIZE);
+
+		memcpy(&fld_size, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_size));
+		cstate->raw_buf_index += sizeof(fld_size);
+		*line_size += sizeof(fld_size);
+		fld_size = (int32) pg_ntoh32(fld_size);
+
+		CHECK_FIELD_SIZE(fld_size);
+
+		*line_size += fld_size;
+
+		if ((DATA_BLOCK_SIZE - cstate->raw_buf_index) >= fld_size)
+		{
+			cstate->raw_buf_index += fld_size;
+			elog(DEBUG1, "LEADER - tuple lies in he same data block");
+		}
+		else
+		{
+			int32 required_blks = 0;
+			int32 curr_blk_bytes = (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+			int i = 0;
+
+			GET_REQUIRED_BLOCKS(required_blks, fld_size, curr_blk_bytes);
+
+			i = required_blks;
+
+			while(i > 0)
+			{
+				CopyReadBinaryGetDataBlock(cstate, FIELD_DATA);
+				i--;
+			}
+
+			GET_RAW_BUF_INDEX(cstate->raw_buf_index, fld_size, required_blks, curr_blk_bytes);
+
+			/*
+			 * raw_buf_index should never cross data block size,
+			 * as the required number of data blocks would have
+			 * been obtained in the above while loop.
+			 */
+			Assert(cstate->raw_buf_index <= DATA_BLOCK_SIZE);
+		}
+		cstate->cur_attname = NULL;
+	}
+}
+
+/*
+ * CopyReadBinaryTupleWorker - each worker reads data from data blocks after
+ * getting leader-identified tuple offsets from ring data structure.
+ */
+static bool
+CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls)
+{
+	uint32 		line_pos;
+	ParallelCopyLineBoundary *line_info;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	int16		fld_count;
+	ListCell   *cur;
+	FmgrInfo   *in_functions = cstate->in_functions;
+	Oid		   *typioparams = cstate->typioparams;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	line_pos = GetLinePosition(cstate);
+
+	if (line_pos == -1)
+		return true;
+
+	line_info = &pcshared_info->line_boundaries.ring[line_pos];
+	cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[line_info->first_block];
+	cstate->raw_buf_index = line_info->start_offset;
+
+	if (cstate->raw_buf_index + sizeof(fld_count) >= DATA_BLOCK_SIZE)
+	{
+		/*
+		 * The case where field count spread across datablocks should never occur,
+		 * as the leader would have moved it to next block. this code exists for
+		 * debugging purposes only.
+		 */
+		elog(DEBUG1, "WORKER - field count spread across datablocks should never occur");
+	}
+
+	memcpy(&fld_count, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_count));
+	fld_count = (int16) pg_ntoh16(fld_count);
+
+	CHECK_FIELD_COUNT;
+
+	cstate->raw_buf_index += sizeof(fld_count);
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			att_num = lfirst_int(cur);
+		int			m = att_num - 1;
+		Form_pg_attribute att = TupleDescAttr(tup_desc, m);
+		cstate->cur_attname = NameStr(att->attname);
+
+		values[m] = CopyReadBinaryAttributeWorker(cstate,
+											&in_functions[m],
+											typioparams[m],
+											att->atttypmod,
+											&nulls[m]);
+		cstate->cur_attname = NULL;
+	}
+
+	pg_atomic_sub_fetch_u32(&cstate->pcdata->curr_data_block->unprocessed_line_parts, 1);
+	line_info->start_offset = -1;
+	pg_atomic_write_u32(&line_info->line_state, LINE_WORKER_PROCESSED);
+	pg_atomic_write_u32(&line_info->line_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryAttributeWorker - leader identifies boundaries/offsets
+ * for each attribute/column, it moves on to next data block if the
+ * attribute/column is spread across data blocks.
+ */
+static Datum
+CopyReadBinaryAttributeWorker(CopyState cstate, FmgrInfo *flinfo,
+		Oid typioparam, int32 typmod, bool *isnull)
+{
+	int32		fld_size;
+	Datum		result;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+	if ((cstate->raw_buf_index + sizeof(fld_size)) >= DATA_BLOCK_SIZE)
+	{
+		ParallelCopyDataBlock *prev_data_block = cstate->pcdata->curr_data_block;
+		elog(DEBUG1, "WORKER - field size is spread across data blocks");
+		cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[prev_data_block->following_block];
+		pg_atomic_sub_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+		cstate->raw_buf_index = 0;
+	}
+
+	memcpy(&fld_size, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_size));
+	fld_size = (int32) pg_ntoh32(fld_size);
+
+	CHECK_FIELD_SIZE(fld_size);
+
+	cstate->raw_buf_index += sizeof(fld_size);
+
+	/* reset attribute_buf to empty, and load raw data in it */
+	resetStringInfo(&cstate->attribute_buf);
+
+	enlargeStringInfo(&cstate->attribute_buf, fld_size);
+
+	if ((DATA_BLOCK_SIZE - cstate->raw_buf_index) >= fld_size)
+	{
+		elog(DEBUG1, "WORKER - tuple lies in single data block");
+		memcpy(&cstate->attribute_buf.data[0],&cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], fld_size);
+		cstate->raw_buf_index += fld_size;
+	}
+	else
+	{
+		uint32 att_buf_idx = 0;
+		uint32 copy_bytes = 0;
+		int32 required_blks = 0;
+		int32 curr_blk_bytes = (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+		ParallelCopyDataBlock *prev_data_block = NULL;
+		int i = 0;
+
+		GET_REQUIRED_BLOCKS(required_blks, fld_size, curr_blk_bytes);
+
+		i = required_blks;
+		prev_data_block = cstate->pcdata->curr_data_block;
+		elog(DEBUG1, "WORKER - tuple is spread across data blocks");
+		memcpy(&cstate->attribute_buf.data[0], &prev_data_block->data[cstate->raw_buf_index],
+				curr_blk_bytes);
+		copy_bytes = curr_blk_bytes;
+		att_buf_idx = curr_blk_bytes;
+
+		while (i>0)
+		{
+			cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[prev_data_block->following_block];
+			pg_atomic_sub_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+			cstate->raw_buf_index = 0;
+			copy_bytes = fld_size - att_buf_idx;
+
+			/*
+			 * the bytes that are yet to be taken into att buff are more than
+			 * the entire data block size, but only take the data block size
+			 * elements.
+			 */
+			if (copy_bytes >= DATA_BLOCK_SIZE)
+				copy_bytes = DATA_BLOCK_SIZE;
+
+			memcpy(&cstate->attribute_buf.data[att_buf_idx],
+				&cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], copy_bytes);
+			att_buf_idx += copy_bytes;
+			i--;
+		}
+		GET_RAW_BUF_INDEX(cstate->raw_buf_index, fld_size, required_blks, curr_blk_bytes);
+	}
+
+	cstate->attribute_buf.len = fld_size;
+	cstate->attribute_buf.data[fld_size] = '\0';
+
+	/* Call the column type's binary input converter */
+	result = ReceiveFunctionCall(flinfo, &cstate->attribute_buf,
+								 typioparam, typmod);
+
+	/* Trouble if it didn't eat the whole buffer */
+	if (cstate->attribute_buf.cursor != cstate->attribute_buf.len)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+				 errmsg("incorrect binary data format")));
+
+	*isnull = false;
+	return result;
+}
+
+/*
+ * GetLinePosition - return the line position that worker should pcdata->process.
  */
 static uint32
 GetLinePosition(CopyState cstate)
@@ -1665,7 +2176,9 @@ GetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
 		{
 			dataBlkPtr->curr_blk_completed = false;
 			dataBlkPtr->skip_bytes = 0;
+			dataBlkPtr->following_block = -1;
 			pcshared_info->cur_block_pos = block_pos;
+			MemSet(&dataBlkPtr->data[0], 0, DATA_BLOCK_SIZE);
 			return block_pos;
 		}
 
@@ -2181,10 +2694,26 @@ CopyGetInt32(CopyState cstate, int32 *val)
 {
 	uint32		buf;
 
-	if (CopyReadBinaryData(cstate, (char *) &buf, sizeof(buf)) != sizeof(buf))
+	/*
+	 * For parallel copy, avoid reading data to raw buf, read directly
+	 * from file, later the data will be read to parallel copy data
+	 * buffers.
+	 */
+	if (cstate->nworkers > 0)
 	{
-		*val = 0;				/* suppress compiler warning */
-		return false;
+		if (CopyGetData(cstate, &buf, sizeof(buf), sizeof(buf)) != sizeof(buf))
+		{
+			*val = 0;				/* suppress compiler warning */
+			return false;
+		}
+	}
+	else
+	{
+		if (CopyReadBinaryData(cstate, (char *) &buf, sizeof(buf)) != sizeof(buf))
+		{
+			*val = 0;				/* suppress compiler warning */
+			return false;
+		}
 	}
 	*val = (int32) pg_ntoh32(buf);
 	return true;
@@ -2573,7 +3102,15 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 			EndParallelCopy(pcxt);
 		}
 		else
+		{
+			/*
+			 * Reset nworkers to -1 here. This is useful in cases where user
+			 * specifies parallel workers, but, no worker is picked up, so go
+			 * back to non parallel mode value of nworkers.
+			 */
+			cstate->nworkers = -1;
 			*processed = CopyFrom(cstate); /* copy from file to database */
+		}
 
 		EndCopyFrom(cstate);
 	}
@@ -5052,7 +5589,7 @@ BeginCopyFrom(ParseState *pstate,
 	 * only in text mode.
 	 */
 	initStringInfo(&cstate->attribute_buf);
-	cstate->raw_buf = (IsParallelCopy()) ? NULL : (char *) palloc(RAW_BUF_SIZE + 1);
+	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
 	cstate->raw_buf_index = cstate->raw_buf_len = 0;
 	if (!cstate->binary)
 	{
@@ -5132,7 +5669,7 @@ BeginCopyFrom(ParseState *pstate,
 		int32		tmp;
 
 		/* Signature */
-		if (CopyReadBinaryData(cstate, readSig, 11) != 11 ||
+		if (CopyGetData(cstate, readSig, 11, 11) != 11 ||
 			memcmp(readSig, BinarySignature, 11) != 0)
 			ereport(ERROR,
 					(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
@@ -5160,7 +5697,7 @@ BeginCopyFrom(ParseState *pstate,
 		/* Skip extension header, if present */
 		while (tmp-- > 0)
 		{
-			if (CopyReadBinaryData(cstate, readSig, 1) != 1)
+			if (CopyGetData(cstate, readSig, 1, 1) != 1)
 				ereport(ERROR,
 						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
 						 errmsg("invalid COPY file header (wrong length)")));
@@ -5357,60 +5894,45 @@ NextCopyFrom(CopyState cstate, ExprContext *econtext,
 	else
 	{
 		/* binary */
-		int16		fld_count;
-		ListCell   *cur;
-
 		cstate->cur_lineno++;
+		cstate->max_fields = list_length(cstate->attnumlist);
 
-		if (!CopyGetInt16(cstate, &fld_count))
+		if (!IsParallelCopy())
 		{
-			/* EOF detected (end of file, or protocol-level EOF) */
-			return false;
-		}
+			int16		fld_count;
+			ListCell   *cur;
 
-		if (fld_count == -1)
-		{
-			/*
-			 * Received EOF marker.  In a V3-protocol copy, wait for the
-			 * protocol-level EOF, and complain if it doesn't come
-			 * immediately.  This ensures that we correctly handle CopyFail,
-			 * if client chooses to send that now.
-			 *
-			 * Note that we MUST NOT try to read more data in an old-protocol
-			 * copy, since there is no protocol-level EOF marker then.  We
-			 * could go either way for copy from file, but choose to throw
-			 * error if there's data after the EOF marker, for consistency
-			 * with the new-protocol case.
-			 */
-			char		dummy;
-
-			if (cstate->copy_dest != COPY_OLD_FE &&
-				CopyReadBinaryData(cstate, &dummy, 1) > 0)
-				ereport(ERROR,
-						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-						 errmsg("received copy data after EOF marker")));
-			return false;
-		}
+			if (!CopyGetInt16(cstate, &fld_count))
+			{
+				/* EOF detected (end of file, or protocol-level EOF) */
+				return false;
+			}
 
-		if (fld_count != attr_count)
-			ereport(ERROR,
-					(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-					 errmsg("row field count is %d, expected %d",
-							(int) fld_count, attr_count)));
+			CHECK_FIELD_COUNT;
 
-		foreach(cur, cstate->attnumlist)
+			foreach(cur, cstate->attnumlist)
+			{
+				int			attnum = lfirst_int(cur);
+				int			m = attnum - 1;
+				Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+
+				cstate->cur_attname = NameStr(att->attname);
+				values[m] = CopyReadBinaryAttribute(cstate,
+													&in_functions[m],
+													typioparams[m],
+													att->atttypmod,
+													&nulls[m]);
+				cstate->cur_attname = NULL;
+			}
+		}
+		else
 		{
-			int			attnum = lfirst_int(cur);
-			int			m = attnum - 1;
-			Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+			bool eof = false;
 
-			cstate->cur_attname = NameStr(att->attname);
-			values[m] = CopyReadBinaryAttribute(cstate,
-												&in_functions[m],
-												typioparams[m],
-												att->atttypmod,
-												&nulls[m]);
-			cstate->cur_attname = NULL;
+			eof = CopyReadBinaryTupleWorker(cstate, values, nulls);
+
+			if (eof)
+				return false;
 		}
 	}
 
@@ -6410,18 +6932,15 @@ CopyReadBinaryAttribute(CopyState cstate, FmgrInfo *flinfo,
 	Datum		result;
 
 	if (!CopyGetInt32(cstate, &fld_size))
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("unexpected EOF in COPY data")));
+		EOF_ERROR;
+
 	if (fld_size == -1)
 	{
 		*isnull = true;
 		return ReceiveFunctionCall(flinfo, NULL, typioparam, typmod);
 	}
-	if (fld_size < 0)
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("invalid field size")));
+
+	CHECK_FIELD_SIZE(fld_size);
 
 	/* reset attribute_buf to empty, and load raw data in it */
 	resetStringInfo(&cstate->attribute_buf);
@@ -6429,9 +6948,7 @@ CopyReadBinaryAttribute(CopyState cstate, FmgrInfo *flinfo,
 	enlargeStringInfo(&cstate->attribute_buf, fld_size);
 	if (CopyReadBinaryData(cstate, cstate->attribute_buf.data,
 						   fld_size) != fld_size)
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("unexpected EOF in COPY data")));
+		EOF_ERROR;
 
 	cstate->attribute_buf.len = fld_size;
 	cstate->attribute_buf.data[fld_size] = '\0';
-- 
2.25.1

#125Tomas Vondra
tomas.vondra@2ndquadrant.com
In reply to: Bharath Rupireddy (#124)
Re: Parallel copy

On Mon, Aug 03, 2020 at 12:33:48PM +0530, Bharath Rupireddy wrote:

On Sat, Aug 1, 2020 at 9:55 AM vignesh C <vignesh21@gmail.com> wrote:

The patches were not applying because of the recent commits.
I have rebased the patch over head & attached.

I rebased v2-0006-Parallel-Copy-For-Binary-Format-Files.patch.

Putting together all the patches rebased on to the latest commit
b8fdee7d0ca8bd2165d46fb1468f75571b706a01. Patches from 0001 to 0005
are rebased by Vignesh, that are from the previous mail and the patch
0006 is rebased by me.

Please consider this patch set for further review.

I'd suggest incrementing the version every time an updated version is
submitted, even if it's just a rebased version. It makes it clearer
which version of the code is being discussed, etc.

regards

--
Tomas Vondra http://www.2ndQuadrant.com
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

#126vignesh C
vignesh21@gmail.com
In reply to: Tomas Vondra (#125)
Re: Parallel copy

On Tue, Aug 4, 2020 at 9:51 PM Tomas Vondra
<tomas.vondra@2ndquadrant.com> wrote:

On Mon, Aug 03, 2020 at 12:33:48PM +0530, Bharath Rupireddy wrote:

On Sat, Aug 1, 2020 at 9:55 AM vignesh C <vignesh21@gmail.com> wrote:

The patches were not applying because of the recent commits.
I have rebased the patch over head & attached.

I rebased v2-0006-Parallel-Copy-For-Binary-Format-Files.patch.

Putting together all the patches rebased on to the latest commit
b8fdee7d0ca8bd2165d46fb1468f75571b706a01. Patches from 0001 to 0005
are rebased by Vignesh, that are from the previous mail and the patch
0006 is rebased by me.

Please consider this patch set for further review.

I'd suggest incrementing the version every time an updated version is
submitted, even if it's just a rebased version. It makes it clearer
which version of the code is being discussed, etc.

Sure, we will take care of this when we are sending the next set of patches.

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

#127Greg Nancarrow
gregn4422@gmail.com
In reply to: vignesh C (#126)
Re: Parallel copy

The following review has been posted through the commitfest application:
make installcheck-world: tested, passed
Implements feature: tested, passed
Spec compliant: tested, passed
Documentation: tested, failed

Hi,

I don't claim to yet understand all of the Postgres internals that this patch is updating and interacting with, so I'm still testing and debugging portions of this patch, but would like to give feedback on what I've noticed so far.
I have done some ad-hoc testing of the patch using parallel copies from text/csv/binary files and have not yet struck any execution problems other than some option validation and associated error messages on boundary cases.

One general question that I have: is there a user benefit (over the normal non-parallel COPY) to allowing "COPY ... FROM ... WITH (PARALLEL 1)"?

My following comments are broken down by patch:

(1) v2-0001-Copy-code-readjustment-to-support-parallel-copy.patch

(i) Whilst I can't entirely blame these patches for it (as they are following what is already there), I can't help noticing the use of numerous macros in src/backend/commands/copy.c which paste in multiple lines of code in various places.
It's getting a little out-of-hand. Surely the majority of these would be best inline functions instead?
Perhaps hasn't been done because too many parameters need to be passed - thoughts?

(2) v2-0002-Framework-for-leader-worker-in-parallel-copy.patch

(i) minor point: there are some tabbing/spacing issues in this patch (and the other patches), affecting alignment.
e.g. mixed tabs/spaces and misalignment in PARALLEL_COPY_KEY_xxx definitions

(ii)

+/*
+ * Each worker will be allocated WORKER_CHUNK_COUNT of records from DSM data
+ * block to process to avoid lock contention. This value should be mode of
+ * RINGSIZE, as wrap around cases is currently not handled while selecting the
+ * WORKER_CHUNK_COUNT by the worker.
+ */
+#define WORKER_CHUNK_COUNT 50

"This value should be mode of RINGSIZE ..."

-> typo: mode (mod? should evenly divide into RINGSIZE?)

(iii)
+ * using pg_atomic_compare_exchange_u32, worker will change the sate to

->typo: sate (should be "state")

(iv)

+ errmsg("parallel option supported only for copy from"),

-> suggest change to: errmsg("parallel option is supported only for COPY FROM"),

(v)

+			errno = 0; /* To distinguish success/failure after call */
+			val = strtol(str, &endptr, 10);
+
+			/* Check for various possible errors */
+			if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
+				|| (errno != 0 && val == 0) ||
+				*endptr)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("improper use of argument to option \"%s\"",
+								defel->defname),
+						 parser_errposition(pstate, defel->location)));
+
+			if (endptr == str)
+			   ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("no digits were found in argument to option \"%s\"",
+								defel->defname),
+						 parser_errposition(pstate, defel->location)));
+
+			cstate->nworkers = (int) val;
+
+			if (cstate->nworkers <= 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("argument to option \"%s\" must be a positive integer greater than zero",
+								defel->defname),
+						 parser_errposition(pstate, defel->location)));

I think this validation code needs to be improved, including the error messages (e.g. when can a "positive integer" NOT be greater than zero?)

There is some overlap in the "no digits were found" case between the two conditions above, depending, for example, if the argument is quoted.
Also, "improper use of argument to option" sounds a bit odd and vague to me.
Finally, not range checking before casting long to int can lead to allowing out-of-range int values like in the following case:

test=# copy mytable from '/myspace/test_pcopy/tmp.dat' (parallel '-2147483648');
ERROR: argument to option "parallel" must be a positive integer greater than zero
LINE 1: copy mytable from '/myspace/test_pcopy/tmp.dat' (parallel '-2...
^
BUT the following is allowed...

test=# copy mytable from '/myspace/test_pcopy/tmp.dat' (parallel '-2147483649');
COPY 1000000

I'd suggest to change the above validation code to do similar validation to that for the CREATE TABLE parallel_workers storage parameter (case RELOPT_TYPE_INT in reloptions.c). Like that code, wouldn't it be best to range-check the integer option value to be within a reasonable range, say 1 to 1024, with a corresponding errdetail message if possible?

(3) v2-0003-Allow-copy-from-command-to-process-data-from-file.patch

(i)

Patch comment says:

"This feature allows the copy from to leverage multiple CPUs in order to copy
data from file/STDIN to a table. This adds a PARALLEL option to COPY FROM
command where the user can specify the number of workers that can be used
to perform the COPY FROM command. Specifying zero as number of workers will
disable parallelism."

BUT - the changes to ProcessCopyOptions() specified in "v2-0002-Framework-for-leader-worker-in-parallel-copy.patch" do not allow zero workers to be specified - you get an error in that case. Patch comment should be updated accordingly.

(ii)

#define GETPROCESSED(processed) \
-return processed;
+if (!IsParallelCopy()) \
+	return processed; \
+else \
+	return pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
+

I think GETPROCESSED would be better named "RETURNPROCESSED".

(iii)

The below comment seems out- of-date with the current code - is it referring to the loop embedded at the bottom of the current loop that the comment is within?

+		/*
+		 * There is a possibility that the above loop has come out because
+		 * data_blk_ptr->curr_blk_completed is set, but dataSize read might
+		 * be an old value, if data_blk_ptr->curr_blk_completed and the line is
+		 * completed, line_size will be set. Read the line_size again to be
+		 * sure if it is complete or partial block.
+		 */

(iv)

I may be wrong here, but in the following block of code, isn't there a window of opportunity (however small) in which the line_state might be updated (LINE_WORKER_PROCESSED) by another worker just AFTER pg_atomic_read_u32() returns the current line_state which is put into curr_line_state, such that a write_pos update might be missed? And then a race-condition exists for reading/setting line_size (since line_size gets atomically set after line_state is set)?
If I am wrong in thinking this synchronization might not be correct, maybe the comments could be improved here to explain how this code is safe in that respect.

+		/* Get the current line information. */
+		lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+		curr_line_state = pg_atomic_read_u32(&lineInfo->line_state);
+		if ((write_pos % WORKER_CHUNK_COUNT == 0) &&
+			(curr_line_state == LINE_WORKER_PROCESSED ||
+			 curr_line_state == LINE_WORKER_PROCESSING))
+		{
+			pcdata->worker_processed_pos = write_pos;
+			write_pos = (write_pos + WORKER_CHUNK_COUNT) %  RINGSIZE;
+			continue;
+		}
+
+		/* Get the size of this line. */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+		if (dataSize != 0) /* If not an empty line. */
+		{
+			/* Get the block information. */
+			data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+			if (!data_blk_ptr->curr_blk_completed && (dataSize == -1))
+			{
+				/* Wait till the current line or block is added. */
+				COPY_WAIT_TO_PROCESS()
+				continue;
+			}
+		}
+
+		/* Make sure that no worker has consumed this element. */
+		if (pg_atomic_compare_exchange_u32(&lineInfo->line_state,
+										   &line_state, LINE_WORKER_PROCESSING))
+			break;

(4) v2-0004-Documentation-for-parallel-copy.patch

(i) I think that it is necessary to mention the "max_worker_processes" option in the description of the COPY statement PARALLEL option.

For example, something like:

+      Perform <command>COPY FROM</command> in parallel using <replaceable
+      class="parameter"> integer</replaceable> background workers.  Please
+      note that it is not guaranteed that the number of parallel workers
+      specified in <replaceable class="parameter">integer</replaceable> will
+      be used during execution.  It is possible for a copy to run with fewer
+      workers than specified, or even with no workers at all (for example, 
+      due to the setting of max_worker_processes).  This option is allowed
+      only in <command>COPY FROM</command>.

(5) v2-0005-Tests-for-parallel-copy.patch

(i) None of the provided tests seem to test beyond "PARALLEL 2"

(6) v2-0006-Parallel-Copy-For-Binary-Format-Files.patch

(i) In the ParallelCopyFrom() function, "cstate->raw_buf" is pfree()d:

+	/* raw_buf is not used in parallel copy, instead data blocks are used.*/
+	pfree(cstate->raw_buf);

This comment doesn't seem to be entirely true.
At least for text/csv file COPY FROM, cstate->raw_buf is subsequently referenced in the SetRawBufForLoad() function, which is called by CopyReadLineText():

cur_data_blk_ptr = (cstate->raw_buf) ? &pcshared_info->data_blocks[cur_block_pos] : NULL;

So I think cstate->raw_buf should be set to NULL after being pfree()d, and the comment fixed/adjusted.

(ii) This patch adds some macros (involving parallel copy checks) AFTER the comment:

/* End parallel copy Macros */

Regards,
Greg Nancarrow
Fujitsu Australia

#128vignesh C
vignesh21@gmail.com
In reply to: Greg Nancarrow (#127)
6 attachment(s)
Re: Parallel copy

Thanks Greg for reviewing the patch. Please find my thoughts for your comments.

On Wed, Aug 12, 2020 at 9:10 AM Greg Nancarrow <gregn4422@gmail.com> wrote:

I have done some ad-hoc testing of the patch using parallel copies from text/csv/binary files and have not yet struck any execution problems other than some option validation and associated error messages on boundary cases.

One general question that I have: is there a user benefit (over the normal non-parallel COPY) to allowing "COPY ... FROM ... WITH (PARALLEL 1)"?

There will be marginal improvement as worker only need to process the
data, need not do the file reading, file reading would have been done
by the main process. The real improvement can be seen from 2 workers
onwards.

My following comments are broken down by patch:

(1) v2-0001-Copy-code-readjustment-to-support-parallel-copy.patch

(i) Whilst I can't entirely blame these patches for it (as they are following what is already there), I can't help noticing the use of numerous macros in src/backend/commands/copy.c which paste in multiple lines of code in various places.
It's getting a little out-of-hand. Surely the majority of these would be best inline functions instead?
Perhaps hasn't been done because too many parameters need to be passed - thoughts?

I felt they have used macros mainly because it has a tight loop and
having macros gives better performance. I have added the macros
CLEAR_EOL_LINE, INCREMENTPROCESSED & GETPROCESSED as there will be
slight difference in parallel copy & non parallel copy for these. In
the remaining patches the macor will be extended to include parallel
copy logic. Instead of having checks in the core logic, thought of
keeping as macros so that the readability is good.

(2) v2-0002-Framework-for-leader-worker-in-parallel-copy.patch

(i) minor point: there are some tabbing/spacing issues in this patch (and the other patches), affecting alignment.
e.g. mixed tabs/spaces and misalignment in PARALLEL_COPY_KEY_xxx definitions

Fixed

(ii)

+/*
+ * Each worker will be allocated WORKER_CHUNK_COUNT of records from DSM data
+ * block to process to avoid lock contention. This value should be mode of
+ * RINGSIZE, as wrap around cases is currently not handled while selecting the
+ * WORKER_CHUNK_COUNT by the worker.
+ */
+#define WORKER_CHUNK_COUNT 50

"This value should be mode of RINGSIZE ..."

-> typo: mode (mod? should evenly divide into RINGSIZE?)

Fixed, changed it to divisible by.

(iii)
+ * using pg_atomic_compare_exchange_u32, worker will change the sate to

->typo: sate (should be "state")

Fixed

(iv)

+ errmsg("parallel option supported only for copy from"),

-> suggest change to: errmsg("parallel option is supported only for COPY FROM"),

Fixed

(v)

+                       errno = 0; /* To distinguish success/failure after call */
+                       val = strtol(str, &endptr, 10);
+
+                       /* Check for various possible errors */
+                       if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
+                               || (errno != 0 && val == 0) ||
+                               *endptr)
+                               ereport(ERROR,
+                                               (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                                                errmsg("improper use of argument to option \"%s\"",
+                                                               defel->defname),
+                                                parser_errposition(pstate, defel->location)));
+
+                       if (endptr == str)
+                          ereport(ERROR,
+                                               (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                                                errmsg("no digits were found in argument to option \"%s\"",
+                                                               defel->defname),
+                                                parser_errposition(pstate, defel->location)));
+
+                       cstate->nworkers = (int) val;
+
+                       if (cstate->nworkers <= 0)
+                               ereport(ERROR,
+                                               (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+                                                errmsg("argument to option \"%s\" must be a positive integer greater than zero",
+                                                               defel->defname),
+                                                parser_errposition(pstate, defel->location)));

I think this validation code needs to be improved, including the error messages (e.g. when can a "positive integer" NOT be greater than zero?)

There is some overlap in the "no digits were found" case between the two conditions above, depending, for example, if the argument is quoted.
Also, "improper use of argument to option" sounds a bit odd and vague to me.
Finally, not range checking before casting long to int can lead to allowing out-of-range int values like in the following case:

test=# copy mytable from '/myspace/test_pcopy/tmp.dat' (parallel '-2147483648');
ERROR: argument to option "parallel" must be a positive integer greater than zero
LINE 1: copy mytable from '/myspace/test_pcopy/tmp.dat' (parallel '-2...
^
BUT the following is allowed...

test=# copy mytable from '/myspace/test_pcopy/tmp.dat' (parallel '-2147483649');
COPY 1000000

I'd suggest to change the above validation code to do similar validation to that for the CREATE TABLE parallel_workers storage parameter (case RELOPT_TYPE_INT in reloptions.c). Like that code, wouldn't it be best to range-check the integer option value to be within a reasonable range, say 1 to 1024, with a corresponding errdetail message if possible?

Fixed, changed as suggested.

(3) v2-0003-Allow-copy-from-command-to-process-data-from-file.patch

(i)

Patch comment says:

"This feature allows the copy from to leverage multiple CPUs in order to copy
data from file/STDIN to a table. This adds a PARALLEL option to COPY FROM
command where the user can specify the number of workers that can be used
to perform the COPY FROM command. Specifying zero as number of workers will
disable parallelism."

BUT - the changes to ProcessCopyOptions() specified in "v2-0002-Framework-for-leader-worker-in-parallel-copy.patch" do not allow zero workers to be specified - you get an error in that case. Patch comment should be updated accordingly.

Removed "Specifying zero as number of workers will disable
parallelism". As the new value is range from 1 to 1024.

(ii)

#define GETPROCESSED(processed) \
-return processed;
+if (!IsParallelCopy()) \
+       return processed; \
+else \
+       return pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
+

I think GETPROCESSED would be better named "RETURNPROCESSED".

Fixed.

(iii)

The below comment seems out- of-date with the current code - is it referring to the loop embedded at the bottom of the current loop that the comment is within?

+               /*
+                * There is a possibility that the above loop has come out because
+                * data_blk_ptr->curr_blk_completed is set, but dataSize read might
+                * be an old value, if data_blk_ptr->curr_blk_completed and the line is
+                * completed, line_size will be set. Read the line_size again to be
+                * sure if it is complete or partial block.
+                */

Updated, it is referring to the embedded loop at the bottom of the current loop.

(iv)

I may be wrong here, but in the following block of code, isn't there a window of opportunity (however small) in which the line_state might be updated (LINE_WORKER_PROCESSED) by another worker just AFTER pg_atomic_read_u32() returns the current line_state which is put into curr_line_state, such that a write_pos update might be missed? And then a race-condition exists for reading/setting line_size (since line_size gets atomically set after line_state is set)?
If I am wrong in thinking this synchronization might not be correct, maybe the comments could be improved here to explain how this code is safe in that respect.

+               /* Get the current line information. */
+               lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+               curr_line_state = pg_atomic_read_u32(&lineInfo->line_state);
+               if ((write_pos % WORKER_CHUNK_COUNT == 0) &&
+                       (curr_line_state == LINE_WORKER_PROCESSED ||
+                        curr_line_state == LINE_WORKER_PROCESSING))
+               {
+                       pcdata->worker_processed_pos = write_pos;
+                       write_pos = (write_pos + WORKER_CHUNK_COUNT) %  RINGSIZE;
+                       continue;
+               }
+
+               /* Get the size of this line. */
+               dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+               if (dataSize != 0) /* If not an empty line. */
+               {
+                       /* Get the block information. */
+                       data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+                       if (!data_blk_ptr->curr_blk_completed && (dataSize == -1))
+                       {
+                               /* Wait till the current line or block is added. */
+                               COPY_WAIT_TO_PROCESS()
+                               continue;
+                       }
+               }
+
+               /* Make sure that no worker has consumed this element. */
+               if (pg_atomic_compare_exchange_u32(&lineInfo->line_state,
+                                                                                  &line_state, LINE_WORKER_PROCESSING))
+                       break;

This is not possible because of pg_atomic_compare_exchange_u32, this
will succeed only for one of the workers whose line_state is
LINE_LEADER_POPULATED, for other workers it will fail. This is
explained in detail above ParallelCopyLineBoundary.

(4) v2-0004-Documentation-for-parallel-copy.patch

(i) I think that it is necessary to mention the "max_worker_processes" option in the description of the COPY statement PARALLEL option.

For example, something like:

+      Perform <command>COPY FROM</command> in parallel using <replaceable
+      class="parameter"> integer</replaceable> background workers.  Please
+      note that it is not guaranteed that the number of parallel workers
+      specified in <replaceable class="parameter">integer</replaceable> will
+      be used during execution.  It is possible for a copy to run with fewer
+      workers than specified, or even with no workers at all (for example,
+      due to the setting of max_worker_processes).  This option is allowed
+      only in <command>COPY FROM</command>.

Fixed.

(5) v2-0005-Tests-for-parallel-copy.patch

(i) None of the provided tests seem to test beyond "PARALLEL 2"

I intentionally ran with 1 parallel worker, because when you specify
more than 1 parallel worker the order of record insertion can vary &
there may be random failures.

(6) v2-0006-Parallel-Copy-For-Binary-Format-Files.patch

(i) In the ParallelCopyFrom() function, "cstate->raw_buf" is pfree()d:

+       /* raw_buf is not used in parallel copy, instead data blocks are used.*/
+       pfree(cstate->raw_buf);

raw_buf is not used in parallel copy, instead raw_buf will be pointing
to shared memory data blocks. This memory was allocated as part of
BeginCopyFrom, uptil this point we cannot be 100% sure as copy can be
performed sequentially like in case max_worker_processes is not
available, if it switches to sequential mode raw_buf will be used
while performing copy operation. At this place we can safely free this
memory that was allocated.

This comment doesn't seem to be entirely true.
At least for text/csv file COPY FROM, cstate->raw_buf is subsequently referenced in the SetRawBufForLoad() function, which is called by CopyReadLineText():

cur_data_blk_ptr = (cstate->raw_buf) ? &pcshared_info->data_blocks[cur_block_pos] : NULL;

So I think cstate->raw_buf should be set to NULL after being pfree()d, and the comment fixed/adjusted.

(ii) This patch adds some macros (involving parallel copy checks) AFTER the comment:

/* End parallel copy Macros */

Fixed, moved the macros above the comment.

I have attached new set of patches with the fixes.
Thoughts?

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

Attachments:

v3-0001-Copy-code-readjustment-to-support-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=v3-0001-Copy-code-readjustment-to-support-parallel-copy.patchDownload
From ddba635791eb415ffae8136b6e77875d2fac353e Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Sat, 1 Aug 2020 08:52:48 +0530
Subject: [PATCH v3 1/6] Copy code readjustment to support parallel copy.

This patch has the copy code slightly readjusted so that the common code is
separated to functions/macros, these functions/macros will be used by the
workers in the parallel copy code of the upcoming patches. EOL removal is moved
from CopyReadLine to CopyReadLineText, this change was required because in case
of parallel copy the record identification and record updation is done in
CopyReadLineText, before record information is updated in shared memory the new
line characters should be removed.
---
 src/backend/commands/copy.c | 361 ++++++++++++++++++++++++++------------------
 1 file changed, 218 insertions(+), 143 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index db7d24a..436e458 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -95,6 +95,9 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
+#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+#define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
+
 /*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
@@ -224,7 +227,6 @@ typedef struct CopyStateData
 	 * appropriate amounts of data from this buffer.  In both modes, we
 	 * guarantee that there is a \0 at raw_buf[raw_buf_len].
 	 */
-#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
@@ -354,6 +356,27 @@ if (1) \
 	goto not_end_of_copy; \
 } else ((void) 0)
 
+/*
+ * CLEAR_EOL_LINE - Wrapper for clearing EOL.
+ */
+#define CLEAR_EOL_LINE() \
+if (!result && !IsHeaderLine()) \
+	ClearEOLFromCopiedData(cstate, cstate->line_buf.data, \
+						   cstate->line_buf.len, \
+						   &cstate->line_buf.len) \
+
+/*
+ * INCREMENTPROCESSED - Increment the lines processed.
+ */
+#define INCREMENTPROCESSED(processed)  \
+processed++;
+
+/*
+ * RETURNPROCESSED - Get the lines processed.
+ */
+#define RETURNPROCESSED(processed) \
+return processed;
+
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
 
@@ -401,7 +424,11 @@ static bool CopyGetInt16(CopyState cstate, int16 *val);
 static bool CopyLoadRawBuf(CopyState cstate);
 static int	CopyReadBinaryData(CopyState cstate, char *dest, int nbytes);
 
-
+static void PopulateCommonCstateInfo(CopyState cstate, TupleDesc	tup_desc,
+									   List *attnamelist);
+static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
+								   int copy_line_pos, int *copy_line_size);
+static void ConvertToServerEncoding(CopyState cstate);
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
  * in past protocol redesigns.
@@ -801,14 +828,18 @@ CopyLoadRawBuf(CopyState cstate)
 {
 	int			nbytes = RAW_BUF_BYTES(cstate);
 	int			inbytes;
+	int         minread = 1;
 
 	/* Copy down the unprocessed data if any. */
 	if (nbytes > 0)
 		memmove(cstate->raw_buf, cstate->raw_buf + cstate->raw_buf_index,
 				nbytes);
 
+	if (cstate->copy_dest == COPY_NEW_FE)
+		minread = RAW_BUF_SIZE - nbytes;
+
 	inbytes = CopyGetData(cstate, cstate->raw_buf + nbytes,
-						  1, RAW_BUF_SIZE - nbytes);
+						  minread, RAW_BUF_SIZE - nbytes);
 	nbytes += inbytes;
 	cstate->raw_buf[nbytes] = '\0';
 	cstate->raw_buf_index = 0;
@@ -1514,7 +1545,6 @@ BeginCopy(ParseState *pstate,
 {
 	CopyState	cstate;
 	TupleDesc	tupDesc;
-	int			num_phys_attrs;
 	MemoryContext oldcontext;
 
 	/* Allocate workspace and zero all fields */
@@ -1680,6 +1710,24 @@ BeginCopy(ParseState *pstate,
 		tupDesc = cstate->queryDesc->tupDesc;
 	}
 
+	PopulateCommonCstateInfo(cstate, tupDesc, attnamelist);
+	cstate->copy_dest = COPY_FILE;	/* default */
+
+	MemoryContextSwitchTo(oldcontext);
+
+	return cstate;
+}
+
+/*
+ * PopulateCommonCstateInfo - Populates the common variables required for copy
+ * from operation. This is a helper function for BeginCopy function.
+ */
+static void
+PopulateCommonCstateInfo(CopyState cstate, TupleDesc	tupDesc,
+							List *attnamelist)
+{
+	int			num_phys_attrs;
+
 	/* Generate or convert list of attributes to process */
 	cstate->attnumlist = CopyGetAttnums(tupDesc, cstate->rel, attnamelist);
 
@@ -1799,12 +1847,6 @@ BeginCopy(ParseState *pstate,
 		 pg_database_encoding_max_length() > 1);
 	/* See Multibyte encoding comment above */
 	cstate->encoding_embeds_ascii = PG_ENCODING_IS_CLIENT_ONLY(cstate->file_encoding);
-
-	cstate->copy_dest = COPY_FILE;	/* default */
-
-	MemoryContextSwitchTo(oldcontext);
-
-	return cstate;
 }
 
 /*
@@ -2696,32 +2738,11 @@ CopyMultiInsertInfoStore(CopyMultiInsertInfo *miinfo, ResultRelInfo *rri,
 }
 
 /*
- * Copy FROM file to relation.
+ * Check if the relation specified in copy from is valid.
  */
-uint64
-CopyFrom(CopyState cstate)
+static void
+CheckTargetRelValidity(CopyState cstate)
 {
-	ResultRelInfo *resultRelInfo;
-	ResultRelInfo *target_resultRelInfo;
-	ResultRelInfo *prevResultRelInfo = NULL;
-	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
-	ModifyTableState *mtstate;
-	ExprContext *econtext;
-	TupleTableSlot *singleslot = NULL;
-	MemoryContext oldcontext = CurrentMemoryContext;
-
-	PartitionTupleRouting *proute = NULL;
-	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
-	int			ti_options = 0; /* start with default options for insert */
-	BulkInsertState bistate = NULL;
-	CopyInsertMethod insertMethod;
-	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
-	uint64		processed = 0;
-	bool		has_before_insert_row_trig;
-	bool		has_instead_insert_row_trig;
-	bool		leafpart_use_multi_insert = false;
-
 	Assert(cstate->rel);
 
 	/*
@@ -2758,27 +2779,6 @@ CopyFrom(CopyState cstate)
 							RelationGetRelationName(cstate->rel))));
 	}
 
-	/*
-	 * If the target file is new-in-transaction, we assume that checking FSM
-	 * for free space is a waste of time.  This could possibly be wrong, but
-	 * it's unlikely.
-	 */
-	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
-		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
-		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
-		ti_options |= TABLE_INSERT_SKIP_FSM;
-
-	/*
-	 * Optimize if new relfilenode was created in this subxact or one of its
-	 * committed children and we won't see those rows later as part of an
-	 * earlier scan or command. The subxact test ensures that if this subxact
-	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
-	 * that the stronger test of exactly which subtransaction created it is
-	 * crucial for correctness of this optimization. The test for an earlier
-	 * scan or command tolerates false negatives. FREEZE causes other sessions
-	 * to see rows they would not see under MVCC, and a false negative merely
-	 * spreads that anomaly to the current session.
-	 */
 	if (cstate->freeze)
 	{
 		/*
@@ -2816,9 +2816,61 @@ CopyFrom(CopyState cstate)
 			ereport(ERROR,
 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 					 errmsg("cannot perform COPY FREEZE because the table was not created or truncated in the current subtransaction")));
+	}
+}
+
+/*
+ * Copy FROM file to relation.
+ */
+uint64
+CopyFrom(CopyState cstate)
+{
+	ResultRelInfo *resultRelInfo;
+	ResultRelInfo *target_resultRelInfo;
+	ResultRelInfo *prevResultRelInfo = NULL;
+	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
+	ModifyTableState *mtstate;
+	ExprContext *econtext;
+	TupleTableSlot *singleslot = NULL;
+	MemoryContext oldcontext = CurrentMemoryContext;
+
+	PartitionTupleRouting *proute = NULL;
+	ErrorContextCallback errcallback;
+	CommandId	mycid = GetCurrentCommandId(true);
+	int			ti_options = 0; /* start with default options for insert */
+	BulkInsertState bistate = NULL;
+	CopyInsertMethod insertMethod;
+	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
+	uint64		processed = 0;
+	bool		has_before_insert_row_trig;
+	bool		has_instead_insert_row_trig;
+	bool		leafpart_use_multi_insert = false;
+
+	CheckTargetRelValidity(cstate);
 
+	/*
+	 * If the target file is new-in-transaction, we assume that checking FSM
+	 * for free space is a waste of time.  This could possibly be wrong, but
+	 * it's unlikely.
+	 */
+	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
+		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
+		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
+		ti_options |= TABLE_INSERT_SKIP_FSM;
+
+	/*
+	 * Optimize if new relfilenode was created in this subxact or one of its
+	 * committed children and we won't see those rows later as part of an
+	 * earlier scan or command. The subxact test ensures that if this subxact
+	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
+	 * that the stronger test of exactly which subtransaction created it is
+	 * crucial for correctness of this optimization. The test for an earlier
+	 * scan or command tolerates false negatives. FREEZE causes other sessions
+	 * to see rows they would not see under MVCC, and a false negative merely
+	 * spreads that anomaly to the current session.
+	 */
+	if (cstate->freeze)
 		ti_options |= TABLE_INSERT_FROZEN;
-	}
 
 	/*
 	 * We need a ResultRelInfo so we can use the regular executor's
@@ -3311,7 +3363,7 @@ CopyFrom(CopyState cstate)
 			 * or FDW; this is the same definition used by nodeModifyTable.c
 			 * for counting tuples inserted by an INSERT command.
 			 */
-			processed++;
+			INCREMENTPROCESSED(processed)
 		}
 	}
 
@@ -3366,30 +3418,15 @@ CopyFrom(CopyState cstate)
 
 	FreeExecutorState(estate);
 
-	return processed;
+	RETURNPROCESSED(processed)
 }
 
 /*
- * Setup to read tuples from a file for COPY FROM.
- *
- * 'rel': Used as a template for the tuples
- * 'filename': Name of server-local file to read
- * 'attnamelist': List of char *, columns to include. NIL selects all cols.
- * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
- *
- * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ * PopulateCstateCatalogInfo - populate the catalog information.
  */
-CopyState
-BeginCopyFrom(ParseState *pstate,
-			  Relation rel,
-			  const char *filename,
-			  bool is_program,
-			  copy_data_source_cb data_source_cb,
-			  List *attnamelist,
-			  List *options)
+static void
+PopulateCstateCatalogInfo(CopyState cstate)
 {
-	CopyState	cstate;
-	bool		pipe = (filename == NULL);
 	TupleDesc	tupDesc;
 	AttrNumber	num_phys_attrs,
 				num_defaults;
@@ -3399,38 +3436,8 @@ BeginCopyFrom(ParseState *pstate,
 	Oid			in_func_oid;
 	int		   *defmap;
 	ExprState **defexprs;
-	MemoryContext oldcontext;
 	bool		volatile_defexprs;
 
-	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
-	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
-
-	/* Initialize state variables */
-	cstate->reached_eof = false;
-	cstate->eol_type = EOL_UNKNOWN;
-	cstate->cur_relname = RelationGetRelationName(cstate->rel);
-	cstate->cur_lineno = 0;
-	cstate->cur_attname = NULL;
-	cstate->cur_attval = NULL;
-
-	/*
-	 * Set up variables to avoid per-attribute overhead.  attribute_buf and
-	 * raw_buf are used in both text and binary modes, but we use line_buf
-	 * only in text mode.
-	 */
-	initStringInfo(&cstate->attribute_buf);
-	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
-	cstate->raw_buf_index = cstate->raw_buf_len = 0;
-	if (!cstate->binary)
-	{
-		initStringInfo(&cstate->line_buf);
-		cstate->line_buf_converted = false;
-	}
-
-	/* Assign range table, we'll need it in CopyFrom. */
-	if (pstate)
-		cstate->range_table = pstate->p_rtable;
-
 	tupDesc = RelationGetDescr(cstate->rel);
 	num_phys_attrs = tupDesc->natts;
 	num_defaults = 0;
@@ -3508,6 +3515,61 @@ BeginCopyFrom(ParseState *pstate,
 	cstate->defexprs = defexprs;
 	cstate->volatile_defexprs = volatile_defexprs;
 	cstate->num_defaults = num_defaults;
+}
+
+/*
+ * Setup to read tuples from a file for COPY FROM.
+ *
+ * 'rel': Used as a template for the tuples
+ * 'filename': Name of server-local file to read
+ * 'attnamelist': List of char *, columns to include. NIL selects all cols.
+ * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
+ *
+ * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ */
+CopyState
+BeginCopyFrom(ParseState *pstate,
+			  Relation rel,
+			  const char *filename,
+			  bool is_program,
+			  copy_data_source_cb data_source_cb,
+			  List *attnamelist,
+			  List *options)
+{
+	CopyState	cstate;
+	bool		pipe = (filename == NULL);
+	MemoryContext oldcontext;
+
+	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	/* Initialize state variables */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/*
+	 * Set up variables to avoid per-attribute overhead.  attribute_buf is
+	 * used in both text and binary modes, but we use line_buf and raw_buf
+	 * only in text mode.
+	 */
+	initStringInfo(&cstate->attribute_buf);
+	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+	if (!cstate->binary)
+	{
+		initStringInfo(&cstate->line_buf);
+		cstate->line_buf_converted = false;
+	}
+
+	/* Assign range table, we'll need it in CopyFrom. */
+	if (pstate)
+		cstate->range_table = pstate->p_rtable;
+
+	PopulateCstateCatalogInfo(cstate);
 	cstate->is_program = is_program;
 
 	if (data_source_cb)
@@ -3917,45 +3979,60 @@ CopyReadLine(CopyState cstate)
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
-	else
-	{
-		/*
-		 * If we didn't hit EOF, then we must have transferred the EOL marker
-		 * to line_buf along with the data.  Get rid of it.
-		 */
-		switch (cstate->eol_type)
-		{
-			case EOL_NL:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CR:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\r');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CRNL:
-				Assert(cstate->line_buf.len >= 2);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 2] == '\r');
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len -= 2;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_UNKNOWN:
-				/* shouldn't get here */
-				Assert(false);
-				break;
-		}
-	}
 
+	ConvertToServerEncoding(cstate);
+	return result;
+}
+
+/*
+ * ClearEOLFromCopiedData - Clear EOL from the copied data.
+ */
+static void
+ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
+					   int copy_line_pos, int *copy_line_size)
+{
+	/*
+	 * If we didn't hit EOF, then we must have transferred the EOL marker
+	 * to line_buf along with the data.  Get rid of it.
+	 */
+   switch (cstate->eol_type)
+   {
+	   case EOL_NL:
+		   Assert(*copy_line_size >= 1);
+		   Assert(copy_line_data[copy_line_pos - 1] == '\n');
+		   copy_line_data[copy_line_pos - 1] = '\0';
+		   (*copy_line_size)--;
+		   break;
+	   case EOL_CR:
+		   Assert(*copy_line_size >= 1);
+		   Assert(copy_line_data[copy_line_pos - 1] == '\r');
+		   copy_line_data[copy_line_pos - 1] = '\0';
+		   (*copy_line_size)--;
+		   break;
+	   case EOL_CRNL:
+		   Assert(*copy_line_size >= 2);
+		   Assert(copy_line_data[copy_line_pos - 2] == '\r');
+		   Assert(copy_line_data[copy_line_pos - 1] == '\n');
+		   copy_line_data[copy_line_pos - 2] = '\0';
+		   *copy_line_size -= 2;
+		   break;
+	   case EOL_UNKNOWN:
+		   /* shouldn't get here */
+		   Assert(false);
+		   break;
+   }
+}
+
+/*
+ * ConvertToServerEncoding - convert contents to server encoding.
+ */
+static void
+ConvertToServerEncoding(CopyState cstate)
+{
 	/* Done reading the line.  Convert it to server encoding. */
 	if (cstate->need_transcoding)
 	{
 		char	   *cvt;
-
 		cvt = pg_any_to_server(cstate->line_buf.data,
 							   cstate->line_buf.len,
 							   cstate->file_encoding);
@@ -3967,11 +4044,8 @@ CopyReadLine(CopyState cstate)
 			pfree(cvt);
 		}
 	}
-
 	/* Now it's safe to use the buffer in error messages */
 	cstate->line_buf_converted = true;
-
-	return result;
 }
 
 /*
@@ -4334,6 +4408,7 @@ not_end_of_copy:
 	 * Transfer any still-uncopied data to line_buf.
 	 */
 	REFILL_LINEBUF;
+	CLEAR_EOL_LINE();
 
 	return result;
 }
-- 
1.8.3.1

v3-0002-Framework-for-leader-worker-in-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=v3-0002-Framework-for-leader-worker-in-parallel-copy.patchDownload
From 7faaa1c10a793b5f0f94d35327af23b9ffe889b2 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Sat, 1 Aug 2020 08:56:39 +0530
Subject: [PATCH v3 2/6] Framework for leader/worker in parallel copy

This patch has the framework for data structures in parallel copy, leader
initialization, worker initialization, shared memory updation, starting workers,
wait for workers and workers exiting.
---
 src/backend/access/transam/parallel.c |   4 +
 src/backend/commands/copy.c           | 742 +++++++++++++++++++++++++++++++++-
 src/include/commands/copy.h           |   2 +
 src/tools/pgindent/typedefs.list      |   7 +
 4 files changed, 751 insertions(+), 4 deletions(-)

diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index b042696..a3cff4b 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -25,6 +25,7 @@
 #include "catalog/pg_enum.h"
 #include "catalog/storage.h"
 #include "commands/async.h"
+#include "commands/copy.h"
 #include "executor/execParallel.h"
 #include "libpq/libpq.h"
 #include "libpq/pqformat.h"
@@ -145,6 +146,9 @@ static const struct
 	},
 	{
 		"parallel_vacuum_main", parallel_vacuum_main
+	},
+	{
+		"ParallelCopyMain", ParallelCopyMain
 	}
 };
 
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 436e458..25ef664 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -96,9 +96,180 @@ typedef enum CopyInsertMethod
 } CopyInsertMethod;
 
 #define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+
+/*
+ * The macros DATA_BLOCK_SIZE, RINGSIZE & MAX_BLOCKS_COUNT stores the records
+ * read from the file that need to be inserted into the relation. These values
+ * help in handover of multiple records with significant size of data to be
+ * processed by each of the workers to make sure there is no context switch & the
+ * work is fairly distributed among the workers. This number showed best
+ * results in the performance tests.
+ */
+#define DATA_BLOCK_SIZE RAW_BUF_SIZE
+
+/* It can hold upto 10000 record information for worker to process. */
+#define RINGSIZE (10 * 1000)
+
+/* It can hold 1000 blocks of 64K data in DSM to be processed by the worker. */
+#define MAX_BLOCKS_COUNT 1000
+
+/*
+ * Each worker will be allocated WORKER_CHUNK_COUNT of records from DSM data
+ * block to process to avoid lock contention. This value should be divisible by
+ * RINGSIZE, as wrap around cases is currently not handled while selecting the
+ * WORKER_CHUNK_COUNT by the worker.
+ */
+#define WORKER_CHUNK_COUNT 50
+
+#define	IsParallelCopy()		(cstate->is_parallel)
+#define IsLeader()				(cstate->pcdata->is_leader)
 #define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
 
 /*
+ * Copy data block information.
+ * ParallelCopyDataBlock's will be created in DSM. Data read from file will be
+ * copied in these DSM data blocks. The leader process identifies the records
+ * and the record information will be shared to the workers. The workers will
+ * insert the records into the table. There can be one or more number of records
+ * in each of the data block based on the record size.
+ */
+typedef struct ParallelCopyDataBlock
+{
+	/* The number of unprocessed lines in the current block. */
+	pg_atomic_uint32 unprocessed_line_parts;
+
+	/*
+	 * If the current line data is continued into another block, following_block
+	 * will have the position where the remaining data need to be read.
+	 */
+	uint32	following_block;
+
+	/*
+	 * This flag will be set, when the leader finds out this block can be read
+	 * safely by the worker. This helps the worker to start processing the line
+	 * early where the line will be spread across many blocks and the worker
+	 * need not wait for the complete line to be processed.
+	 */
+	bool   curr_blk_completed;
+	char   data[DATA_BLOCK_SIZE]; /* data read from file */
+	uint8  skip_bytes;
+}ParallelCopyDataBlock;
+
+/*
+ * Individual line information.
+ * ParallelCopyLineBoundary is common data structure between leader & worker,
+ * Leader process will be populating data block, data block offset & the size of
+ * the record in DSM for the workers to copy the data into the relation.
+ * This is protected by the following sequence in the leader & worker. If they
+ * don't follow this order the worker might process wrong line_size and leader
+ * might populate the information which worker has not yet processed or in the
+ * process of processing.
+ * Leader should operate in the following order:
+ * 1) check if line_size is -1, if not wait, it means worker is still
+ * processing.
+ * 2) set line_state to LINE_LEADER_POPULATING.
+ * 3) update first_block, start_offset & cur_lineno in any order.
+ * 4) update line_size.
+ * 5) update line_state to LINE_LEADER_POPULATED.
+ * Worker should operate in the following order:
+ * 1) check line_state is LINE_LEADER_POPULATED, if not it means leader is still
+ * populating the data.
+ * 2) read line_size.
+ * 3) only one worker should choose one line for processing, this is handled by
+ *    using pg_atomic_compare_exchange_u32, worker will change the state to
+ *    LINE_WORKER_PROCESSING only if line_state is LINE_LEADER_POPULATED.
+ * 4) read first_block, start_offset & cur_lineno in any order.
+ * 5) process line_size data.
+ * 6) update line_size to -1.
+ */
+typedef struct ParallelCopyLineBoundary
+{
+	/* Position of the first block in data_blocks array. */
+	uint32				first_block;
+	uint32				start_offset;   /* start offset of the line */
+
+	/*
+	 * Size of the current line -1 means line is yet to be filled completely,
+	 * 0 means empty line, >0 means line filled with line size data.
+	 */
+	pg_atomic_uint32	line_size;
+	pg_atomic_uint32	line_state;		/* line state */
+	uint64				cur_lineno;		/* line number for error messages */
+}ParallelCopyLineBoundary;
+
+/*
+ * Circular queue used to store the line information.
+ */
+typedef struct ParallelCopyLineBoundaries
+{
+	/* Position for the leader to populate a line. */
+	uint32			pos;
+
+	/* Data read from the file/stdin by the leader process. */
+	ParallelCopyLineBoundary	ring[RINGSIZE];
+}ParallelCopyLineBoundaries;
+
+/*
+ * Shared information among parallel copy workers. This will be allocated in the
+ * DSM segment.
+ */
+typedef struct ParallelCopyShmInfo
+{
+	bool					is_read_in_progress; /* file read status */
+
+	/*
+	 * Actual lines inserted by worker, will not be same as
+	 * total_worker_processed if where condition is specified along with copy.
+	 * This will be the actual records inserted into the relation.
+	 */
+	pg_atomic_uint64			processed;
+
+	/*
+	 * The number of records currently processed by the worker, this will also
+	 * include the number of records that was filtered because of where clause.
+	 */
+	pg_atomic_uint64			total_worker_processed;
+	uint64						populated; /* lines populated by leader */
+	uint32						cur_block_pos; /* current data block */
+	ParallelCopyDataBlock		data_blocks[MAX_BLOCKS_COUNT]; /* data block array */
+	FullTransactionId			full_transaction_id; /* xid for copy from statement */
+	CommandId					mycid;	/* command id */
+	ParallelCopyLineBoundaries	line_boundaries; /* line array */
+} ParallelCopyShmInfo;
+
+/*
+ * Parallel copy line buffer information.
+ */
+typedef struct ParallelCopyLineBuf
+{
+	StringInfoData		line_buf;
+	uint64				cur_lineno;	/* line number for error messages */
+}ParallelCopyLineBuf;
+
+/*
+ * Parallel copy data information.
+ */
+typedef struct ParallelCopyData
+{
+	Oid					relid;				/* relation id of the table */
+	ParallelCopyShmInfo	*pcshared_info;		/* common info in shared memory */
+	bool				is_leader;
+
+	/* line position which worker is processing */
+	uint32				worker_processed_pos;
+
+	/*
+	 * Local line_buf array, workers will copy it here and release the lines
+	 * for the leader to continue.
+	 */
+	ParallelCopyLineBuf	worker_line_buf[WORKER_CHUNK_COUNT];
+	uint32				worker_line_buf_count; /* Number of lines */
+
+	/* Current position in worker_line_buf */
+	uint32				worker_line_buf_pos;
+}ParallelCopyData;
+
+/*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
  * even though some fields are used in only some cases.
@@ -230,10 +401,38 @@ typedef struct CopyStateData
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
+	int			nworkers;
+	bool		is_parallel;
+	ParallelCopyData *pcdata;
 	/* Shorthand for number of unconsumed bytes available in raw_buf */
 #define RAW_BUF_BYTES(cstate) ((cstate)->raw_buf_len - (cstate)->raw_buf_index)
 } CopyStateData;
 
+/*
+ * This structure helps in storing the common data from CopyStateData that are
+ * required by the workers. This information will then be allocated and stored
+ * into the DSM for the worker to retrieve and copy it to CopyStateData.
+ */
+typedef struct SerializedParallelCopyState
+{
+	/* low-level state data */
+	CopyDest            copy_dest;		/* type of copy source/destination */
+	int                 file_encoding;	/* file or remote side's character encoding */
+	bool                need_transcoding;	/* file encoding diff from server? */
+	bool                encoding_embeds_ascii;	/* ASCII can be non-first byte? */
+
+	/* parameters from the COPY command */
+	bool                csv_mode;		/* Comma Separated Value format? */
+	bool                header_line;	/* CSV header line? */
+	int                 null_print_len; /* length of same */
+	bool                force_quote_all;	/* FORCE_QUOTE *? */
+	bool                convert_selectively;	/* do selective binary conversion? */
+
+	/* Working state for COPY FROM */
+	AttrNumber          num_defaults;
+	Oid                 relid;
+}SerializedParallelCopyState;
+
 /* DestReceiver for COPY (query) TO */
 typedef struct
 {
@@ -263,6 +462,22 @@ typedef struct
 /* Trim the list of buffers back down to this number after flushing */
 #define MAX_PARTITION_BUFFERS	32
 
+/* DSM keys for parallel copy.  */
+#define PARALLEL_COPY_KEY_SHARED_INFO				1
+#define PARALLEL_COPY_KEY_CSTATE					2
+#define PARALLEL_COPY_KEY_NULL_PRINT				3
+#define PARALLEL_COPY_KEY_DELIM						4
+#define PARALLEL_COPY_KEY_QUOTE						5
+#define PARALLEL_COPY_KEY_ESCAPE					6
+#define PARALLEL_COPY_KEY_ATTNAME_LIST				7
+#define PARALLEL_COPY_KEY_NOT_NULL_LIST				8
+#define PARALLEL_COPY_KEY_NULL_LIST					9
+#define PARALLEL_COPY_KEY_CONVERT_LIST				10
+#define PARALLEL_COPY_KEY_WHERE_CLAUSE_STR			11
+#define PARALLEL_COPY_KEY_RANGE_TABLE				12
+#define PARALLEL_COPY_WAL_USAGE						13
+#define PARALLEL_COPY_BUFFER_USAGE					14
+
 /* Stores multi-insert data related to a single relation in CopyFrom. */
 typedef struct CopyMultiInsertBuffer
 {
@@ -424,11 +639,477 @@ static bool CopyGetInt16(CopyState cstate, int16 *val);
 static bool CopyLoadRawBuf(CopyState cstate);
 static int	CopyReadBinaryData(CopyState cstate, char *dest, int nbytes);
 
+static pg_attribute_always_inline void EndParallelCopy(ParallelContext *pcxt);
 static void PopulateCommonCstateInfo(CopyState cstate, TupleDesc	tup_desc,
-									   List *attnamelist);
+									 List *attnamelist);
 static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
 								   int copy_line_pos, int *copy_line_size);
 static void ConvertToServerEncoding(CopyState cstate);
+
+/*
+ * SerializeParallelCopyState - Copy shared_cstate using cstate information.
+ */
+static pg_attribute_always_inline void
+SerializeParallelCopyState(CopyState cstate, SerializedParallelCopyState *shared_cstate)
+{
+	shared_cstate->copy_dest = cstate->copy_dest;
+	shared_cstate->file_encoding = cstate->file_encoding;
+	shared_cstate->need_transcoding = cstate->need_transcoding;
+	shared_cstate->encoding_embeds_ascii = cstate->encoding_embeds_ascii;
+	shared_cstate->csv_mode = cstate->csv_mode;
+	shared_cstate->header_line = cstate->header_line;
+	shared_cstate->null_print_len = cstate->null_print_len;
+	shared_cstate->force_quote_all = cstate->force_quote_all;
+	shared_cstate->convert_selectively = cstate->convert_selectively;
+	shared_cstate->num_defaults = cstate->num_defaults;
+	shared_cstate->relid = cstate->pcdata->relid;
+}
+
+/*
+ * RestoreString - Retrieve the string from shared memory.
+ */
+static void
+RestoreString(shm_toc *toc, int sharedkey, char **copystr)
+{
+	char *shared_str_val = (char *)shm_toc_lookup(toc, sharedkey, true);
+	if (shared_str_val)
+		*copystr = pstrdup(shared_str_val);
+}
+
+/*
+ * EstimateLineKeysStr - Estimate the size required in shared memory for the
+ * input string.
+ */
+static void
+EstimateLineKeysStr(ParallelContext *pcxt, char *inputstr)
+{
+	if (inputstr)
+	{
+		shm_toc_estimate_chunk(&pcxt->estimator, strlen(inputstr) + 1);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+}
+
+/*
+ * SerializeString - Insert a string into shared memory.
+ */
+static void
+SerializeString(ParallelContext *pcxt, int key, char *inputstr)
+{
+	if (inputstr)
+	{
+		char *shmptr = (char *)shm_toc_allocate(pcxt->toc,
+												strlen(inputstr) + 1);
+		strcpy(shmptr, inputstr);
+		shm_toc_insert(pcxt->toc, key, shmptr);
+	}
+}
+
+/*
+ * PopulateParallelCopyShmInfo - set ParallelCopyShmInfo.
+ */
+static void
+PopulateParallelCopyShmInfo(ParallelCopyShmInfo *shared_info_ptr,
+							FullTransactionId full_transaction_id)
+{
+	uint32 count;
+
+	MemSet(shared_info_ptr, 0, sizeof(ParallelCopyShmInfo));
+	shared_info_ptr->is_read_in_progress = true;
+	shared_info_ptr->cur_block_pos = -1;
+	shared_info_ptr->full_transaction_id = full_transaction_id;
+	shared_info_ptr->mycid = GetCurrentCommandId(true);
+	for (count = 0; count < RINGSIZE; count++)
+	{
+		ParallelCopyLineBoundary *lineInfo = &shared_info_ptr->line_boundaries.ring[count];
+		pg_atomic_init_u32(&(lineInfo->line_size), -1);
+	}
+}
+
+/*
+ * BeginParallelCopy - start parallel copy tasks.
+ *
+ * Get the number of workers required to perform the parallel copy. The data
+ * structures that are required by the parallel workers will be initialized, the
+ * size required in DSM will be calculated and the necessary keys will be loaded
+ * in the DSM. The specified number of workers will then be launched.
+ */
+static ParallelContext*
+BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
+{
+	ParallelContext *pcxt;
+	ParallelCopyShmInfo *shared_info_ptr;
+	SerializedParallelCopyState *shared_cstate;
+	FullTransactionId full_transaction_id;
+	Size est_cstateshared;
+	char *whereClauseStr = NULL;
+	char *rangeTableStr = NULL;
+	char *attnameListStr = NULL;
+	char *notnullListStr = NULL;
+	char *nullListStr = NULL;
+	char *convertListStr = NULL;
+	int  parallel_workers = 0;
+	WalUsage   *walusage;
+	BufferUsage *bufferusage;
+	ParallelCopyData *pcdata;
+	MemoryContext oldcontext;
+
+	parallel_workers = Min(nworkers, max_worker_processes);
+
+	/* Can't perform copy in parallel */
+	if (parallel_workers <= 0)
+		return NULL;
+
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	MemoryContextSwitchTo(oldcontext);
+	cstate->pcdata = pcdata;
+
+	EnterParallelMode();
+	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
+								 parallel_workers);
+	Assert(pcxt->nworkers > 0);
+
+	/*
+	 * Estimate size for shared information for PARALLEL_COPY_KEY_SHARED_INFO
+	 */
+	shm_toc_estimate_chunk(&pcxt->estimator, sizeof(ParallelCopyShmInfo));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_CSTATE */
+	est_cstateshared = 	MAXALIGN(sizeof(SerializedParallelCopyState));
+	shm_toc_estimate_chunk(&pcxt->estimator, est_cstateshared);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	EstimateLineKeysStr(pcxt, cstate->null_print);
+	EstimateLineKeysStr(pcxt, cstate->null_print_client);
+	EstimateLineKeysStr(pcxt, cstate->delim);
+	EstimateLineKeysStr(pcxt, cstate->quote);
+	EstimateLineKeysStr(pcxt, cstate->escape);
+
+	if (cstate->whereClause != NULL)
+	{
+		whereClauseStr = nodeToString(cstate->whereClause);
+		EstimateLineKeysStr(pcxt, whereClauseStr);
+	}
+
+	if (cstate->range_table != NULL)
+	{
+		rangeTableStr = nodeToString(cstate->range_table);
+		EstimateLineKeysStr(pcxt, rangeTableStr);
+	}
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_XID. */
+	shm_toc_estimate_chunk(&pcxt->estimator, sizeof(FullTransactionId));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_ATTNAME_LIST.
+	 */
+	if (attnamelist != NIL)
+	{
+		attnameListStr = nodeToString(attnamelist);
+		EstimateLineKeysStr(pcxt, attnameListStr);
+	}
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_NOT_NULL_LIST.
+	 */
+	if (cstate->force_notnull != NIL)
+	{
+		notnullListStr = nodeToString(cstate->force_notnull);
+		EstimateLineKeysStr(pcxt, notnullListStr);
+	}
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_NULL_LIST.
+	 */
+	if (cstate->force_null != NIL)
+	{
+		nullListStr = nodeToString(cstate->force_null);
+		EstimateLineKeysStr(pcxt, nullListStr);
+	}
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_CONVERT_LIST.
+	 */
+	if (cstate->convert_select != NIL)
+	{
+		convertListStr = nodeToString(cstate->convert_select);
+		EstimateLineKeysStr(pcxt, convertListStr);
+	}
+
+	/*
+	 * Estimate space for WalUsage and BufferUsage -- PARALLEL_COPY_WAL_USAGE
+	 * and PARALLEL_COPY_BUFFER_USAGE.
+	 */
+	shm_toc_estimate_chunk(&pcxt->estimator,
+						   mul_size(sizeof(WalUsage), pcxt->nworkers));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+	shm_toc_estimate_chunk(&pcxt->estimator,
+						   mul_size(sizeof(BufferUsage), pcxt->nworkers));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	InitializeParallelDSM(pcxt);
+
+	/* If no DSM segment was available, back out (do serial copy) */
+	if (pcxt->seg == NULL)
+	{
+		EndParallelCopy(pcxt);
+		return NULL;
+	}
+
+	/* Allocate shared memory for PARALLEL_COPY_KEY_SHARED_INFO */
+	shared_info_ptr = (ParallelCopyShmInfo *) shm_toc_allocate(pcxt->toc, sizeof(ParallelCopyShmInfo));
+	PopulateParallelCopyShmInfo(shared_info_ptr, full_transaction_id);
+
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_SHARED_INFO, shared_info_ptr);
+	pcdata->pcshared_info = shared_info_ptr;
+	pcdata->relid = relid;
+
+	/* Store shared build state, for which we reserved space. */
+	shared_cstate = (SerializedParallelCopyState *)shm_toc_allocate(pcxt->toc, est_cstateshared);
+
+	/* copy cstate variables. */
+	SerializeParallelCopyState(cstate, shared_cstate);
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_CSTATE, shared_cstate);
+
+	SerializeString(pcxt, PARALLEL_COPY_KEY_NULL_PRINT, cstate->null_print);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_DELIM, cstate->delim);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_QUOTE, cstate->quote);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_ESCAPE, cstate->escape);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_ATTNAME_LIST, attnameListStr);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_NOT_NULL_LIST, notnullListStr);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_NULL_LIST, nullListStr);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_CONVERT_LIST, convertListStr);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_WHERE_CLAUSE_STR, whereClauseStr);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_RANGE_TABLE, rangeTableStr);
+
+	/*
+	 * Allocate space for each worker's WalUsage and BufferUsage; no need to
+	 * initialize.
+	 */
+	walusage = shm_toc_allocate(pcxt->toc,
+								mul_size(sizeof(WalUsage), pcxt->nworkers));
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_WAL_USAGE, walusage);
+	bufferusage = shm_toc_allocate(pcxt->toc,
+								   mul_size(sizeof(BufferUsage), pcxt->nworkers));
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_BUFFER_USAGE, bufferusage);
+
+	LaunchParallelWorkers(pcxt);
+	if (pcxt->nworkers_launched == 0)
+	{
+		EndParallelCopy(pcxt);
+		return NULL;
+	}
+
+	/*
+	 * Caller needs to wait for all launched workers when we return.  Make sure
+	 * that the failure-to-start case will not hang forever.
+	 */
+	WaitForParallelWorkersToAttach(pcxt);
+
+	pcdata->is_leader = true;
+	cstate->is_parallel = true;
+	return pcxt;
+}
+
+/*
+ * EndParallelCopy - end the parallel copy tasks.
+ */
+static pg_attribute_always_inline void
+EndParallelCopy(ParallelContext *pcxt)
+{
+	Assert(!IsParallelWorker());
+
+	DestroyParallelContext(pcxt);
+	ExitParallelMode();
+}
+
+/*
+ * InitializeParallelCopyInfo - Initialize parallel worker.
+ */
+static void
+InitializeParallelCopyInfo(SerializedParallelCopyState *shared_cstate,
+		CopyState cstate, List *attnamelist)
+{
+	uint32		count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	cstate->copy_dest = shared_cstate->copy_dest;
+	cstate->file_encoding = shared_cstate->file_encoding;
+	cstate->need_transcoding = shared_cstate->need_transcoding;
+	cstate->encoding_embeds_ascii = shared_cstate->encoding_embeds_ascii;
+	cstate->csv_mode = shared_cstate->csv_mode;
+	cstate->header_line = shared_cstate->header_line;
+	cstate->null_print_len = shared_cstate->null_print_len;
+	cstate->force_quote_all = shared_cstate->force_quote_all;
+	cstate->convert_selectively = shared_cstate->convert_selectively;
+	cstate->num_defaults = shared_cstate->num_defaults;
+	pcdata->relid = shared_cstate->relid;
+
+	PopulateCommonCstateInfo(cstate, tup_desc, attnamelist);
+
+	/* Initialize state variables. */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/* Set up variables to avoid per-attribute overhead. */
+	initStringInfo(&cstate->attribute_buf);
+
+	initStringInfo(&cstate->line_buf);
+	for (count = 0; count < WORKER_CHUNK_COUNT; count++)
+		initStringInfo(&pcdata->worker_line_buf[count].line_buf);
+
+	cstate->line_buf_converted = false;
+	cstate->raw_buf = NULL;
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+}
+
+/*
+ * ParallelCopyMain - parallel copy worker's code.
+ *
+ * Where clause handling, convert tuple to columns, add default null values for
+ * the missing columns that are not present in that record. Find the partition
+ * if it is partitioned table, invoke before row insert Triggers, handle
+ * constraints and insert the tuples.
+ */
+void
+ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
+{
+	CopyState cstate;
+	ParallelCopyData *pcdata;
+	ParallelCopyShmInfo *pcshared_info;
+	SerializedParallelCopyState *shared_cstate;
+	Relation	rel = NULL;
+	MemoryContext oldcontext;
+	List *attlist = NIL;
+	char *whereClauseStr = NULL;
+	char *rangeTableStr = NULL;
+	char *attnameListStr = NULL;
+	char *notnullListStr = NULL;
+	char *nullListStr = NULL;
+	char *convertListStr = NULL;
+	WalUsage   *walusage;
+	BufferUsage *bufferusage;
+
+	/* Allocate workspace and zero all fields. */
+	cstate = (CopyStateData *) palloc0(sizeof(CopyStateData));
+
+	/*
+	 * We allocate everything used by a cstate in a new memory context. This
+	 * avoids memory leaks during repeated use of COPY in a query.
+	 */
+	cstate->copycontext = AllocSetContextCreate(CurrentMemoryContext,
+												"COPY",
+												ALLOCSET_DEFAULT_SIZES);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	cstate->pcdata = pcdata;
+	pcdata->is_leader = false;
+	pcdata->worker_processed_pos = -1;
+	cstate->is_parallel = true;
+	pcshared_info = (ParallelCopyShmInfo *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_SHARED_INFO, false);
+
+	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
+
+	pcdata->pcshared_info = pcshared_info;
+
+	shared_cstate = (SerializedParallelCopyState *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE, false);
+	cstate->null_print = (char *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_NULL_PRINT, true);
+
+	RestoreString(toc, PARALLEL_COPY_KEY_DELIM, &cstate->delim);
+	RestoreString(toc, PARALLEL_COPY_KEY_QUOTE, &cstate->quote);
+	RestoreString(toc, PARALLEL_COPY_KEY_ESCAPE, &cstate->escape);
+	RestoreString(toc, PARALLEL_COPY_KEY_ATTNAME_LIST, &attnameListStr);
+	if (attnameListStr)
+		attlist = (List *)stringToNode(attnameListStr);
+
+	RestoreString(toc, PARALLEL_COPY_KEY_NOT_NULL_LIST, &notnullListStr);
+	if (notnullListStr)
+		cstate->force_notnull = (List *)stringToNode(notnullListStr);
+
+	RestoreString(toc, PARALLEL_COPY_KEY_NULL_LIST, &nullListStr);
+	if (nullListStr)
+		cstate->force_null = (List *)stringToNode(nullListStr);
+
+	RestoreString(toc, PARALLEL_COPY_KEY_CONVERT_LIST, &convertListStr);
+	if (convertListStr)
+		cstate->convert_select = (List *)stringToNode(convertListStr);
+
+	RestoreString(toc, PARALLEL_COPY_KEY_WHERE_CLAUSE_STR, &whereClauseStr);
+	RestoreString(toc, PARALLEL_COPY_KEY_RANGE_TABLE, &rangeTableStr);
+
+	if (whereClauseStr)
+	{
+		Node *whereClauseCnvrtdFrmStr = (Node *) stringToNode(whereClauseStr);
+		cstate->whereClause = whereClauseCnvrtdFrmStr;
+	}
+
+	if (rangeTableStr)
+	{
+		List *rangeTableCnvrtdFrmStr = (List *) stringToNode(rangeTableStr);
+		cstate->range_table = rangeTableCnvrtdFrmStr;
+	}
+
+	/* Open and lock the relation, using the appropriate lock type. */
+	rel = table_open(shared_cstate->relid, RowExclusiveLock);
+	cstate->rel = rel;
+	InitializeParallelCopyInfo(shared_cstate, cstate, attlist);
+
+	CopyFrom(cstate);
+
+	if (rel != NULL)
+		table_close(rel, RowExclusiveLock);
+
+	/* Report WAL/buffer usage during parallel execution */
+	bufferusage = shm_toc_lookup(toc, PARALLEL_COPY_BUFFER_USAGE, false);
+	walusage = shm_toc_lookup(toc, PARALLEL_COPY_WAL_USAGE, false);
+	InstrEndParallelQuery(&bufferusage[ParallelWorkerNumber],
+						  &walusage[ParallelWorkerNumber]);
+
+	MemoryContextSwitchTo(oldcontext);
+	pfree(cstate);
+	return;
+}
+
+/*
+ * ParallelCopyFrom - parallel copy leader's functionality.
+ *
+ * Leader executes the before statement for before statement trigger, if before
+ * statement trigger is present. It will read the table data from the file and
+ * copy the contents to DSM data blocks. It will then read the input contents
+ * from the DSM data block and identify the records based on line breaks. This
+ * information is called line or a record that need to be inserted into a
+ * relation. The line information will be stored in ParallelCopyLineBoundary DSM
+ * data structure. Workers will then process this information and insert the
+ * data in to table. It will repeat this process until the all data is read from
+ * the file and all the DSM data blocks are processed. While processing if
+ * leader identifies that DSM Data blocks or DSM ParallelCopyLineBoundary data
+ * structures is full, leader will wait till the worker frees up some entries
+ * and repeat the process. It will wait till all the lines populated are
+ * processed by the workers and exits.
+ */
+static void
+ParallelCopyFrom(CopyState cstate)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
+
+	pcshared_info->is_read_in_progress = false;
+	cstate->cur_lineno = 0;
+}
+
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
  * in past protocol redesigns.
@@ -1141,6 +1822,7 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 
 	if (is_from)
 	{
+		ParallelContext *pcxt = NULL;
 		Assert(rel);
 
 		/* check read-only transaction and parallel mode */
@@ -1150,7 +1832,24 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 		cstate = BeginCopyFrom(pstate, rel, stmt->filename, stmt->is_program,
 							   NULL, stmt->attlist, stmt->options);
 		cstate->whereClause = whereClause;
-		*processed = CopyFrom(cstate);	/* copy from file to database */
+		cstate->is_parallel = false;
+
+		if (cstate->nworkers > 0)
+			pcxt = BeginParallelCopy(cstate->nworkers, cstate, stmt->attlist,
+									 relid);
+
+		if (pcxt)
+		{
+			ParallelCopyFrom(cstate);
+
+			/* Wait for all copy workers to finish */
+			WaitForParallelWorkersToFinish(pcxt);
+			*processed = pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
+			EndParallelCopy(pcxt);
+		}
+		else
+			*processed = CopyFrom(cstate); /* copy from file to database */
+
 		EndCopyFrom(cstate);
 	}
 	else
@@ -1199,6 +1898,7 @@ ProcessCopyOptions(ParseState *pstate,
 	cstate->is_copy_from = is_from;
 
 	cstate->file_encoding = -1;
+	cstate->nworkers = -1;
 
 	/* Extract options from the statement node tree */
 	foreach(option, options)
@@ -1367,6 +2067,39 @@ ProcessCopyOptions(ParseState *pstate,
 								defel->defname),
 						 parser_errposition(pstate, defel->location)));
 		}
+		else if (strcmp(defel->defname, "parallel") == 0)
+		{
+			int val;
+			bool parsed;
+			char *strval;
+
+			if (!cstate->is_copy_from)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("parallel option is supported only for copy from"),
+						 parser_errposition(pstate, defel->location)));
+			if (cstate->nworkers >= 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options"),
+						 parser_errposition(pstate, defel->location)));
+
+			strval = defGetString(defel);
+			parsed = parse_int(strval, &val, 0, NULL);
+			if (!parsed)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+							errmsg("invalid value for integer option \"%s\": %s",
+								   defel->defname, strval)));
+			if (val < 1 || val > 1024)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+							errmsg("value %s out of bounds for option \"%s\"",
+								   strval, defel->defname),
+							errdetail("Valid values are between \"%d\" and \"%d\".",
+									  1, 1024)));
+			cstate->nworkers = val;
+		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_SYNTAX_ERROR),
@@ -1720,11 +2453,12 @@ BeginCopy(ParseState *pstate,
 
 /*
  * PopulateCommonCstateInfo - Populates the common variables required for copy
- * from operation. This is a helper function for BeginCopy function.
+ * from operation. This is a helper function for BeginCopy &
+ * InitializeParallelCopyInfo function.
  */
 static void
 PopulateCommonCstateInfo(CopyState cstate, TupleDesc	tupDesc,
-							List *attnamelist)
+						 List *attnamelist)
 {
 	int			num_phys_attrs;
 
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index c639833..82843c6 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -14,6 +14,7 @@
 #ifndef COPY_H
 #define COPY_H
 
+#include "access/parallel.h"
 #include "nodes/execnodes.h"
 #include "nodes/parsenodes.h"
 #include "parser/parse_node.h"
@@ -41,4 +42,5 @@ extern uint64 CopyFrom(CopyState cstate);
 
 extern DestReceiver *CreateCopyDestReceiver(void);
 
+extern void ParallelCopyMain(dsm_segment *seg, shm_toc *toc);
 #endif							/* COPY_H */
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index b4948ac..bb49b65 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1701,6 +1701,12 @@ ParallelBitmapHeapState
 ParallelBlockTableScanDesc
 ParallelCompletionPtr
 ParallelContext
+ParallelCopyLineBoundaries
+ParallelCopyLineBoundary
+ParallelCopyData
+ParallelCopyDataBlock
+ParallelCopyLineBuf
+ParallelCopyShmInfo
 ParallelExecutorInfo
 ParallelHashGrowth
 ParallelHashJoinBatch
@@ -2217,6 +2223,7 @@ SerCommitSeqNo
 SerialControl
 SerializableXactHandle
 SerializedActiveRelMaps
+SerializedParallelCopyState
 SerializedReindexState
 SerializedSnapshotData
 SerializedTransactionState
-- 
1.8.3.1

v3-0003-Allow-copy-from-command-to-process-data-from-file.patchtext/x-patch; charset=US-ASCII; name=v3-0003-Allow-copy-from-command-to-process-data-from-file.patchDownload
From c944b276b8f8b92a98d63d4a66ff931baa8fab1b Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Sat, 1 Aug 2020 09:31:42 +0530
Subject: [PATCH v3 3/6] Allow copy from command to process data from
 file/STDIN contents to a table in parallel.

This feature allows the copy from to leverage multiple CPUs in order to copy
data from file/STDIN to a table. This adds a PARALLEL option to COPY FROM
command where the user can specify the number of workers that can be used
to perform the COPY FROM command.
The backend, to which the "COPY FROM" query is submitted acts as leader with
the responsibility of reading data from the file/stdin, launching at most n
number of workers as specified with PARALLEL 'n' option in the "COPY FROM"
query. The leader populates the common data required for the workers execution
in the DSM and shares it with the workers. The leader then executes before
statement triggers if there exists any. Leader populates DSM lines which
includes the start offset and line size, while populating the lines it reads
as many blocks as required into the DSM data blocks from the file. Each block
is of 64K size. The leader parses the data to identify a line, the existing
logic from CopyReadLineText which identifies the lines with some changes was
used for this. Leader checks if a free line is available to copy the
information, if there is no free line it waits till the required line is
freed up by the worker and then copies the identified lines information
(offset & line size) into the DSM lines. This process is repeated till the
complete file is processed. Simultaneously, the workers cache the lines(50)
locally into the local memory and release the lines to the leader for further
populating. Each worker processes the lines that it cached and inserts it into
the table. The leader does not participate in the insertion of data, leaders
only responsibility will be to identify the lines as fast as possible for the
workers to do the actual copy operation. The leader waits till all the lines
populated are processed by the workers and exits.
We have chosen this design based on the reason "that everything stalls if the
leader doesn't accept further input data, as well as when there are no
available splitted chunks so it doesn't seem like a good idea to have the
leader do other work.  This is backed by the performance data where we have
seen that with 1 worker there is just a 5-10% performance difference".
---
 src/backend/access/common/toast_internals.c |  11 +-
 src/backend/access/heap/heapam.c            |  13 -
 src/backend/access/transam/xact.c           |  31 +
 src/backend/commands/copy.c                 | 892 ++++++++++++++++++++++++++--
 src/bin/psql/tab-complete.c                 |   2 +-
 src/include/access/xact.h                   |   2 +
 src/tools/pgindent/typedefs.list            |   1 +
 7 files changed, 898 insertions(+), 54 deletions(-)

diff --git a/src/backend/access/common/toast_internals.c b/src/backend/access/common/toast_internals.c
index 25a81e5..586d53d 100644
--- a/src/backend/access/common/toast_internals.c
+++ b/src/backend/access/common/toast_internals.c
@@ -17,6 +17,7 @@
 #include "access/genam.h"
 #include "access/heapam.h"
 #include "access/heaptoast.h"
+#include "access/parallel.h"
 #include "access/table.h"
 #include "access/toast_internals.h"
 #include "access/xact.h"
@@ -116,7 +117,15 @@ toast_save_datum(Relation rel, Datum value,
 	TupleDesc	toasttupDesc;
 	Datum		t_values[3];
 	bool		t_isnull[3];
-	CommandId	mycid = GetCurrentCommandId(true);
+
+	/*
+	 * Parallel copy can insert toast tuples, in case of parallel copy the
+	 * command would have been set already by calling AssignCommandIdForWorker.
+	 * For parallel copy call GetCurrentCommandId to get currentCommandId by
+	 * passing used as false, as this is taken care earlier.
+	 */
+	CommandId	mycid = IsParallelWorker() ? GetCurrentCommandId(false) :
+											 GetCurrentCommandId(true);
 	struct varlena *result;
 	struct varatt_external toast_pointer;
 	union
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index f75e1cf..fa005df 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2043,19 +2043,6 @@ static HeapTuple
 heap_prepare_insert(Relation relation, HeapTuple tup, TransactionId xid,
 					CommandId cid, int options)
 {
-	/*
-	 * Parallel operations are required to be strictly read-only in a parallel
-	 * worker.  Parallel inserts are not safe even in the leader in the
-	 * general case, because group locking means that heavyweight locks for
-	 * relation extension or GIN page locks will not conflict between members
-	 * of a lock group, but we don't prohibit that case here because there are
-	 * useful special cases that we can safely allow, such as CREATE TABLE AS.
-	 */
-	if (IsParallelWorker())
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_TRANSACTION_STATE),
-				 errmsg("cannot insert tuples in a parallel worker")));
-
 	tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
 	tup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK);
 	tup->t_data->t_infomask |= HEAP_XMAX_INVALID;
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 7ccb7d6..e2bcac2 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -517,6 +517,37 @@ GetCurrentFullTransactionIdIfAny(void)
 }
 
 /*
+ *	AssignFullTransactionIdForWorker
+ *
+ * For parallel copy, transaction id of leader will be used by the workers.
+ */
+void
+AssignFullTransactionIdForWorker(FullTransactionId fullTransactionId)
+{
+	TransactionState s = CurrentTransactionState;
+
+	Assert((IsInParallelMode() || IsParallelWorker()));
+	s->fullTransactionId = fullTransactionId;
+}
+
+/*
+ *	AssignCommandIdForWorker
+ *
+ * For parallel copy, command id of leader will be used by the workers.
+ */
+void
+AssignCommandIdForWorker(CommandId commandId, bool used)
+{
+	Assert((IsInParallelMode() || IsParallelWorker()));
+
+	/* this is global to a transaction, not subtransaction-local */
+	if (used)
+		currentCommandIdUsed = true;
+
+	currentCommandId = commandId;
+}
+
+/*
  *	MarkCurrentTransactionIdLoggedIfAny
  *
  * Remember that the current xid - if it is assigned - now has been wal logged.
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 25ef664..4c69a5d 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -26,6 +26,7 @@
 #include "access/xlog.h"
 #include "catalog/dependency.h"
 #include "catalog/pg_authid.h"
+#include "catalog/pg_proc_d.h"
 #include "catalog/pg_type.h"
 #include "commands/copy.h"
 #include "commands/defrem.h"
@@ -40,11 +41,13 @@
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
+#include "optimizer/clauses.h"
 #include "optimizer/optimizer.h"
 #include "parser/parse_coerce.h"
 #include "parser/parse_collate.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_relation.h"
+#include "pgstat.h"
 #include "port/pg_bswap.h"
 #include "rewrite/rewriteHandler.h"
 #include "storage/fd.h"
@@ -95,6 +98,18 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
+/*
+ * State of the line.
+ */
+typedef enum ParallelCopyLineState
+{
+	LINE_INIT,					/* initial state of line */
+	LINE_LEADER_POPULATING,		/* leader processing line */
+	LINE_LEADER_POPULATED,		/* leader completed populating line */
+	LINE_WORKER_PROCESSING,		/* worker processing line */
+	LINE_WORKER_PROCESSED		/* worker completed processing line */
+}ParallelCopyLineState;
+
 #define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
 
 /*
@@ -123,6 +138,7 @@ typedef enum CopyInsertMethod
 
 #define	IsParallelCopy()		(cstate->is_parallel)
 #define IsLeader()				(cstate->pcdata->is_leader)
+#define IsWorker()				(IsParallelCopy() && !IsLeader())
 #define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
 
 /*
@@ -556,9 +572,13 @@ if (1) \
 { \
 	if (raw_buf_ptr > cstate->raw_buf_index) \
 	{ \
-		appendBinaryStringInfo(&cstate->line_buf, \
-							 cstate->raw_buf + cstate->raw_buf_index, \
-							   raw_buf_ptr - cstate->raw_buf_index); \
+		if (!IsParallelCopy()) \
+			appendBinaryStringInfo(&cstate->line_buf, \
+								   cstate->raw_buf + cstate->raw_buf_index, \
+								   raw_buf_ptr - cstate->raw_buf_index); \
+		else \
+			line_size +=  raw_buf_ptr - cstate->raw_buf_index; \
+		\
 		cstate->raw_buf_index = raw_buf_ptr; \
 	} \
 } else ((void) 0)
@@ -571,26 +591,65 @@ if (1) \
 	goto not_end_of_copy; \
 } else ((void) 0)
 
+/* Begin parallel copy Macros */
+#define SET_NEWLINE_SIZE() \
+{ \
+	if (cstate->eol_type == EOL_NL || cstate->eol_type == EOL_CR) \
+		new_line_size = 1; \
+	else if (cstate->eol_type == EOL_CRNL) \
+		new_line_size = 2; \
+	else \
+		new_line_size = 0; \
+}
+
+/*
+ * COPY_WAIT_TO_PROCESS - Wait before continuing to process.
+ */
+#define COPY_WAIT_TO_PROCESS() \
+{ \
+	CHECK_FOR_INTERRUPTS(); \
+	(void) WaitLatch(MyLatch, \
+					 WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH, \
+					 1L, WAIT_EVENT_PG_SLEEP); \
+	ResetLatch(MyLatch); \
+}
+
 /*
  * CLEAR_EOL_LINE - Wrapper for clearing EOL.
  */
 #define CLEAR_EOL_LINE() \
 if (!result && !IsHeaderLine()) \
-	ClearEOLFromCopiedData(cstate, cstate->line_buf.data, \
-						   cstate->line_buf.len, \
-						   &cstate->line_buf.len) \
+{ \
+	if (IsParallelCopy()) \
+		ClearEOLFromCopiedData(cstate, cstate->raw_buf, \
+									raw_buf_ptr, &line_size); \
+	else \
+		ClearEOLFromCopiedData(cstate, cstate->line_buf.data, \
+									cstate->line_buf.len, \
+									&cstate->line_buf.len); \
+} \
 
 /*
  * INCREMENTPROCESSED - Increment the lines processed.
  */
-#define INCREMENTPROCESSED(processed)  \
-processed++;
+#define INCREMENTPROCESSED(processed) \
+{ \
+	if (!IsParallelCopy()) \
+		processed++; \
+	else \
+		pg_atomic_add_fetch_u64(&cstate->pcdata->pcshared_info->processed, 1); \
+}
 
 /*
  * RETURNPROCESSED - Get the lines processed.
  */
 #define RETURNPROCESSED(processed) \
-return processed;
+if (!IsParallelCopy()) \
+	return processed; \
+else \
+	return pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
+
+/* End parallel copy Macros */
 
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
@@ -645,7 +704,10 @@ static void PopulateCommonCstateInfo(CopyState cstate, TupleDesc	tup_desc,
 static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
 								   int copy_line_pos, int *copy_line_size);
 static void ConvertToServerEncoding(CopyState cstate);
-
+static void ExecBeforeStmtTrigger(CopyState cstate);
+static void CheckTargetRelValidity(CopyState cstate);
+static void PopulateCstateCatalogInfo(CopyState cstate);
+static pg_attribute_always_inline uint32 GetLinePosition(CopyState cstate);
 /*
  * SerializeParallelCopyState - Copy shared_cstate using cstate information.
  */
@@ -727,6 +789,137 @@ PopulateParallelCopyShmInfo(ParallelCopyShmInfo *shared_info_ptr,
 }
 
 /*
+ * IsTriggerFunctionParallelSafe - Check if the trigger function is parallel
+ * safe for the triggers. Return false if any one of the trigger has parallel
+ * unsafe function.
+ */
+static pg_attribute_always_inline bool
+IsTriggerFunctionParallelSafe(TriggerDesc *trigdesc)
+{
+	int	i;
+	for (i = 0; i < trigdesc->numtriggers; i++)
+	{
+		Trigger    *trigger = &trigdesc->triggers[i];
+		int 		trigtype = RI_TRIGGER_NONE;
+
+		if (func_parallel(trigger->tgfoid) != PROPARALLEL_SAFE)
+			return false;
+
+		/* If the trigger is parallel safe, also look for RI_TRIGGER. */
+		trigtype = RI_FKey_trigger_type(trigger->tgfoid);
+		if (trigtype == RI_TRIGGER_PK || trigtype == RI_TRIGGER_FK)
+			return false;
+	}
+
+	return true;
+}
+
+/*
+ * CheckExprParallelSafety - determine parallel safety of volatile expressions
+ * in default clause of column definition or in where clause and return true if
+ * they are parallel safe.
+ */
+static pg_attribute_always_inline bool
+CheckExprParallelSafety(CopyState cstate)
+{
+	if (contain_volatile_functions(cstate->whereClause))
+	{
+		if (max_parallel_hazard((Query *)cstate->whereClause) != PROPARALLEL_SAFE)
+			return false;
+	}
+
+	/*
+	 * Check if any of the column has volatile default expression. if yes, and
+	 * they are not parallel safe, then parallelism is not allowed. For
+	 * instance, if there are any serial/bigserial columns for which nextval()
+	 * default expression which is parallel unsafe is associated, parallelism
+	 * should not be allowed. In non parallel copy volatile functions are not
+	 * checked for nextval().
+	 */
+	if (cstate->defexprs != NULL && cstate->num_defaults != 0)
+	{
+		int     i;
+		for (i = 0; i < cstate->num_defaults; i++)
+		{
+			bool volatile_expr = contain_volatile_functions((Node *)cstate->defexprs[i]->expr);
+			if (volatile_expr &&
+				(max_parallel_hazard((Query *)cstate->defexprs[i]->expr)) !=
+				 PROPARALLEL_SAFE)
+				return false;
+		}
+	}
+
+	return true;
+}
+
+/*
+ * FindInsertMethod - determine insert mode single, multi, or multi conditional.
+ */
+static pg_attribute_always_inline CopyInsertMethod
+FindInsertMethod(CopyState cstate)
+{
+	if (cstate->rel->trigdesc != NULL &&
+		(cstate->rel->trigdesc->trig_insert_before_row ||
+		 cstate->rel->trigdesc->trig_insert_instead_row))
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
+			cstate->rel->trigdesc != NULL &&
+			cstate->rel->trigdesc->trig_insert_new_table)
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+		return CIM_MULTI_CONDITIONAL;
+
+	return CIM_MULTI;
+}
+
+/*
+ * IsParallelCopyAllowed - check for the cases where parallel copy is not
+ * applicable.
+ */
+static pg_attribute_always_inline bool
+IsParallelCopyAllowed(CopyState cstate)
+{
+	/* Parallel copy not allowed for frontend (2.0 protocol) & binary option. */
+	if ((cstate->copy_dest == COPY_OLD_FE) || cstate->binary)
+		return false;
+
+	/* Check if copy is into foreign table or temporary table. */
+	if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
+		RelationUsesLocalBuffers(cstate->rel))
+		return false;
+
+	/* Check if trigger function is parallel safe. */
+	if (cstate->rel->trigdesc != NULL &&
+		!IsTriggerFunctionParallelSafe(cstate->rel->trigdesc))
+		return false;
+
+	/*
+	 * Check if there is after statement or instead of trigger or transition
+	 * table triggers.
+	 */
+	if (cstate->rel->trigdesc != NULL &&
+		(cstate->rel->trigdesc->trig_insert_after_statement ||
+		 cstate->rel->trigdesc->trig_insert_instead_row ||
+		 cstate->rel->trigdesc->trig_insert_new_table))
+		return false;
+
+	/* Check if the volatile expressions are parallel safe, if present any. */
+	if (!CheckExprParallelSafety(cstate))
+		return false;
+
+	/* Check if the insertion mode is single. */
+	if (FindInsertMethod(cstate) == CIM_SINGLE)
+		return false;
+
+	return true;
+}
+
+/*
  * BeginParallelCopy - start parallel copy tasks.
  *
  * Get the number of workers required to perform the parallel copy. The data
@@ -754,6 +947,7 @@ BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
 	ParallelCopyData *pcdata;
 	MemoryContext oldcontext;
 
+	CheckTargetRelValidity(cstate);
 	parallel_workers = Min(nworkers, max_worker_processes);
 
 	/* Can't perform copy in parallel */
@@ -765,6 +959,15 @@ BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
 	MemoryContextSwitchTo(oldcontext);
 	cstate->pcdata = pcdata;
 
+	/*
+	 * User chosen parallel copy. Determine if the parallel copy is actually
+	 * allowed. If not, go with the non-parallel mode.
+	 */
+	if (!IsParallelCopyAllowed(cstate))
+		return NULL;
+
+	full_transaction_id = GetCurrentFullTransactionId();
+
 	EnterParallelMode();
 	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
 								 parallel_workers);
@@ -973,9 +1176,214 @@ InitializeParallelCopyInfo(SerializedParallelCopyState *shared_cstate,
 	cstate->line_buf_converted = false;
 	cstate->raw_buf = NULL;
 	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+
+	PopulateCstateCatalogInfo(cstate);
+
+	/* Create workspace for CopyReadAttributes results. */
+	if (!cstate->binary)
+	{
+		AttrNumber	attr_count = list_length(cstate->attnumlist);
+
+		cstate->max_fields = attr_count;
+		cstate->raw_fields = (char **)palloc(attr_count * sizeof(char *));
+	}
 }
 
 /*
+ * CacheLineInfo - Cache the line information to local memory.
+ */
+static bool
+CacheLineInfo(CopyState cstate, uint32 buff_count)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	uint32			write_pos;
+	ParallelCopyDataBlock *data_blk_ptr;
+	ParallelCopyLineBoundary *lineInfo;
+	uint32 offset;
+	int dataSize;
+	int copiedSize = 0;
+
+	resetStringInfo(&pcdata->worker_line_buf[buff_count].line_buf);
+	write_pos = GetLinePosition(cstate);
+	if (-1 == write_pos)
+		return true;
+
+	/* Get the current line information. */
+	lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+	if (pg_atomic_read_u32(&lineInfo->line_size) == 0)
+		goto empty_data_line_update;
+
+	/* Get the block information. */
+	data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+	/* Get the offset information from where the data must be copied. */
+	offset = lineInfo->start_offset;
+	pcdata->worker_line_buf[buff_count].cur_lineno = lineInfo->cur_lineno;
+
+	elog(DEBUG1, "[Worker] Processing - line position:%d, block:%d, unprocessed lines:%d, offset:%d, line size:%d",
+				 write_pos, lineInfo->first_block,
+				 pg_atomic_read_u32(&data_blk_ptr->unprocessed_line_parts),
+				 offset, pg_atomic_read_u32(&lineInfo->line_size));
+
+	for (;;)
+	{
+		uint8 skip_bytes = data_blk_ptr->skip_bytes;
+
+		/*
+		 * There is a possibility that the loop embedded at the bottom of the
+		 * current loop has come out because data_blk_ptr->curr_blk_completed
+		 * is set, but dataSize read might be an old value, if
+		 * data_blk_ptr->curr_blk_completed and the line is completed, line_size
+		 * will be set. Read the line_size again to be sure if it is completed
+		 * or partial block.
+		 */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+		if (dataSize)
+		{
+			int remainingSize = dataSize - copiedSize;
+			if (!remainingSize)
+				break;
+
+			/* Whole line is in current block. */
+			if (remainingSize + offset + skip_bytes < DATA_BLOCK_SIZE)
+			{
+				appendBinaryStringInfo(&pcdata->worker_line_buf[buff_count].line_buf,
+									   &data_blk_ptr->data[offset],
+									   remainingSize);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts,
+										1);
+				break;
+			}
+			else
+			{
+				/* Line is spread across the blocks. */
+				uint32 lineInCurrentBlock =  (DATA_BLOCK_SIZE - skip_bytes) - offset;
+				appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+										 &data_blk_ptr->data[offset],
+										 lineInCurrentBlock);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+				copiedSize += lineInCurrentBlock;
+				while (copiedSize < dataSize)
+				{
+					uint32 currentBlockCopySize;
+					ParallelCopyDataBlock *currBlkPtr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+					skip_bytes = currBlkPtr->skip_bytes;
+
+					/*
+					 * If complete data is present in current block use
+					 * dataSize - copiedSize, or copy the whole block from
+					 * current block.
+					 */
+					currentBlockCopySize = Min(dataSize - copiedSize, DATA_BLOCK_SIZE - skip_bytes);
+					appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+											 &currBlkPtr->data[0],
+											 currentBlockCopySize);
+					pg_atomic_sub_fetch_u32(&currBlkPtr->unprocessed_line_parts, 1);
+					copiedSize += currentBlockCopySize;
+					data_blk_ptr = currBlkPtr;
+				}
+
+				break;
+			}
+		}
+		else
+		{
+			/* Copy this complete block from the current offset. */
+			uint32 lineInCurrentBlock =  (DATA_BLOCK_SIZE - skip_bytes) - offset;
+			appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+									 &data_blk_ptr->data[offset],
+									 lineInCurrentBlock);
+			pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+			copiedSize += lineInCurrentBlock;
+
+			/*
+			 * Reset the offset. For the first copy, copy from the offset. For
+			 * the subsequent copy the complete block.
+			 */
+			offset = 0;
+
+			/* Set data_blk_ptr to the following block. */
+			data_blk_ptr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+		}
+
+		for (;;)
+		{
+			/* Get the size of this line */
+			dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+			/*
+			 * If the data is present in current block lineInfo. line_size
+			 * will be updated. If the data is spread across the blocks either
+			 * of lineInfo.line_size or data_blk_ptr->curr_blk_completed can
+			 * be updated. lineInfo.line_size will be updated if the complete
+			 * read is finished. data_blk_ptr->curr_blk_completed will be
+			 * updated if processing of current block is finished and data
+			 * processing is not finished.
+			 */
+			if (data_blk_ptr->curr_blk_completed || (dataSize != -1))
+				break;
+
+			COPY_WAIT_TO_PROCESS()
+		}
+	}
+
+empty_data_line_update:
+	elog(DEBUG1, "[Worker] Completed processing line:%d", write_pos);
+	pg_atomic_write_u32(&lineInfo->line_state, LINE_WORKER_PROCESSED);
+	pg_atomic_write_u32(&lineInfo->line_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+	return false;
+}
+
+/*
+ * GetWorkerLine - Returns a line for worker to process.
+ */
+static bool
+GetWorkerLine(CopyState cstate)
+{
+	uint32 buff_count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+
+	/*
+	 * Copy the line data to line_buf and release the line position so that the
+	 * worker can continue loading data.
+	 */
+	if (pcdata->worker_line_buf_pos < pcdata->worker_line_buf_count)
+		goto return_line;
+
+	pcdata->worker_line_buf_pos = 0;
+	pcdata->worker_line_buf_count = 0;
+
+	for (buff_count = 0; buff_count < WORKER_CHUNK_COUNT; buff_count++)
+	{
+		bool result = CacheLineInfo(cstate, buff_count);
+		if (result)
+			break;
+
+		pcdata->worker_line_buf_count++;
+	}
+
+	if (pcdata->worker_line_buf_count)
+		goto return_line;
+	else
+		resetStringInfo(&cstate->line_buf);
+
+	return true;
+
+return_line:
+	cstate->line_buf = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].line_buf;
+	cstate->cur_lineno = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].cur_lineno;
+	cstate->line_buf_valid = true;
+
+	/* Mark that encoding conversion hasn't occurred yet. */
+	cstate->line_buf_converted = false;
+	ConvertToServerEncoding(cstate);
+	pcdata->worker_line_buf_pos++;
+	return false;
+ }
+
+/*
  * ParallelCopyMain - parallel copy worker's code.
  *
  * Where clause handling, convert tuple to columns, add default null values for
@@ -1024,6 +1432,8 @@ ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
 	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
 
 	pcdata->pcshared_info = pcshared_info;
+	AssignFullTransactionIdForWorker(pcshared_info->full_transaction_id);
+	AssignCommandIdForWorker(pcshared_info->mycid, true);
 
 	shared_cstate = (SerializedParallelCopyState *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE, false);
 	cstate->null_print = (char *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_NULL_PRINT, true);
@@ -1084,6 +1494,33 @@ ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
 }
 
 /*
+ * UpdateBlockInLineInfo - Update the line information.
+ */
+static pg_attribute_always_inline int
+UpdateBlockInLineInfo(CopyState cstate, uint32 blk_pos,
+					   uint32 offset, uint32 line_size, uint32 line_state)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyLineBoundaries *lineBoundaryPtr = &pcshared_info->line_boundaries;
+	ParallelCopyLineBoundary *lineInfo;
+	int line_pos = lineBoundaryPtr->pos;
+
+	/* Update the line information for the worker to pick and process. */
+	lineInfo = &lineBoundaryPtr->ring[line_pos];
+	while (pg_atomic_read_u32(&lineInfo->line_size) != -1)
+		COPY_WAIT_TO_PROCESS()
+
+	lineInfo->first_block = blk_pos;
+	lineInfo->start_offset = offset;
+	lineInfo->cur_lineno = cstate->cur_lineno;
+	pg_atomic_write_u32(&lineInfo->line_size, line_size);
+	pg_atomic_write_u32(&lineInfo->line_state, line_state);
+	lineBoundaryPtr->pos = (lineBoundaryPtr->pos + 1) % RINGSIZE;
+
+	return line_pos;
+}
+
+/*
  * ParallelCopyFrom - parallel copy leader's functionality.
  *
  * Leader executes the before statement for before statement trigger, if before
@@ -1106,8 +1543,298 @@ ParallelCopyFrom(CopyState cstate)
 	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
 	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
 
+	/* Execute the before statement triggers from the leader */
+	ExecBeforeStmtTrigger(cstate);
+
+	/* On input just throw the header line away. */
+	if (cstate->cur_lineno == 0 && cstate->header_line)
+	{
+		cstate->cur_lineno++;
+		if (CopyReadLine(cstate))
+		{
+			pcshared_info->is_read_in_progress = false;
+			return;			/* done */
+		}
+	}
+
+	for (;;)
+	{
+		bool done;
+		cstate->cur_lineno++;
+
+		/* Actually read the line into memory here. */
+		done = CopyReadLine(cstate);
+
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			break;
+	}
+
 	pcshared_info->is_read_in_progress = false;
 	cstate->cur_lineno = 0;
+ }
+
+/*
+ * GetLinePosition - return the line position that worker should process.
+ */
+static uint32
+GetLinePosition(CopyState cstate)
+{
+	ParallelCopyData *pcdata = cstate->pcdata;
+	ParallelCopyShmInfo *pcshared_info = pcdata->pcshared_info;
+	uint32  previous_pos = pcdata->worker_processed_pos;
+	uint32 write_pos = (previous_pos == -1) ? 0 : (previous_pos + 1) % RINGSIZE;
+	for (;;)
+	{
+		int		dataSize;
+		bool	is_read_in_progress = pcshared_info->is_read_in_progress;
+		ParallelCopyLineBoundary *lineInfo;
+		ParallelCopyDataBlock *data_blk_ptr;
+		ParallelCopyLineState line_state = LINE_LEADER_POPULATED;
+		ParallelCopyLineState curr_line_state;
+		CHECK_FOR_INTERRUPTS();
+
+		/* File read completed & no elements to process. */
+		if (!is_read_in_progress &&
+			(pcshared_info->populated ==
+			 pg_atomic_read_u64(&pcshared_info->total_worker_processed)))
+		{
+			write_pos = -1;
+			break;
+		}
+
+		/* Get the current line information. */
+		lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+		curr_line_state = pg_atomic_read_u32(&lineInfo->line_state);
+		if ((write_pos % WORKER_CHUNK_COUNT == 0) &&
+			(curr_line_state == LINE_WORKER_PROCESSED ||
+			 curr_line_state == LINE_WORKER_PROCESSING))
+		{
+			pcdata->worker_processed_pos = write_pos;
+			write_pos = (write_pos + WORKER_CHUNK_COUNT) %  RINGSIZE;
+			continue;
+		}
+
+		/* Get the size of this line. */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+		if (dataSize != 0) /* If not an empty line. */
+		{
+			/* Get the block information. */
+			data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+			if (!data_blk_ptr->curr_blk_completed && (dataSize == -1))
+			{
+				/* Wait till the current line or block is added. */
+				COPY_WAIT_TO_PROCESS()
+				continue;
+			}
+		}
+
+		/* Make sure that no worker has consumed this element. */
+		if (pg_atomic_compare_exchange_u32(&lineInfo->line_state,
+										   &line_state, LINE_WORKER_PROCESSING))
+			break;
+	}
+
+	pcdata->worker_processed_pos = write_pos;
+	return write_pos;
+}
+
+/*
+ * GetFreeCopyBlock - Get a free block for data to be copied.
+ */
+static pg_attribute_always_inline uint32
+GetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	int count = 0;
+	uint32 last_free_block = pcshared_info->cur_block_pos;
+	uint32 block_pos = (last_free_block != -1) ? ((last_free_block + 1) % MAX_BLOCKS_COUNT): 0;
+
+	/*
+	 * Get a new block for copying data, don't check current block, current
+	 * block will have some unprocessed data.
+	 */
+	while (count < (MAX_BLOCKS_COUNT - 1))
+	{
+		ParallelCopyDataBlock *dataBlkPtr = &pcshared_info->data_blocks[block_pos];
+		uint32 unprocessed_line_parts = pg_atomic_read_u32(&dataBlkPtr->unprocessed_line_parts);
+		if (unprocessed_line_parts == 0)
+		{
+			dataBlkPtr->curr_blk_completed = false;
+			dataBlkPtr->skip_bytes = 0;
+			pcshared_info->cur_block_pos = block_pos;
+			return block_pos;
+		}
+
+		block_pos = (block_pos + 1) % MAX_BLOCKS_COUNT;
+		count++;
+	}
+
+	return -1;
+}
+
+/*
+ * WaitGetFreeCopyBlock - If there are no blocks available, wait and get a block
+ * for copying data.
+ */
+static uint32
+WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	uint32 new_free_pos = -1;
+	for (;;)
+	{
+		new_free_pos = GetFreeCopyBlock(pcshared_info);
+		if (new_free_pos != -1)	/* We have got one block, break now. */
+			break;
+
+		COPY_WAIT_TO_PROCESS()
+	}
+
+	return new_free_pos;
+}
+
+/*
+ * SetRawBufForLoad - Set raw_buf to the shared memory where the file data must
+ * be read.
+ */
+static void
+SetRawBufForLoad(CopyState cstate, uint32 line_size, uint32 copy_buf_len,
+				 uint32 raw_buf_ptr, char **copy_raw_buf)
+{
+	ParallelCopyShmInfo	*pcshared_info;
+	uint32 cur_block_pos;
+	uint32 next_block_pos;
+	ParallelCopyDataBlock	*cur_data_blk_ptr = NULL;
+	ParallelCopyDataBlock	*next_data_blk_ptr = NULL;
+
+	if (!IsParallelCopy())
+		return;
+
+	pcshared_info = cstate->pcdata->pcshared_info;
+	cur_block_pos = pcshared_info->cur_block_pos;
+	cur_data_blk_ptr = (cstate->raw_buf) ? &pcshared_info->data_blocks[cur_block_pos] : NULL;
+	next_block_pos = WaitGetFreeCopyBlock(pcshared_info);
+	next_data_blk_ptr = &pcshared_info->data_blocks[next_block_pos];
+
+	/* set raw_buf to the data block in shared memory */
+	cstate->raw_buf = next_data_blk_ptr->data;
+	*copy_raw_buf = cstate->raw_buf;
+	if (cur_data_blk_ptr && line_size)
+	{
+		/*
+		 * Mark the previous block as completed, worker can start copying this
+		 * data.
+		 */
+		cur_data_blk_ptr->following_block = next_block_pos;
+		pg_atomic_add_fetch_u32(&cur_data_blk_ptr->unprocessed_line_parts, 1);
+		cur_data_blk_ptr->skip_bytes = copy_buf_len - raw_buf_ptr;
+		cur_data_blk_ptr->curr_blk_completed = true;
+	}
+}
+
+/*
+ * EndLineParallelCopy - Update the line information in shared memory.
+ */
+static void
+EndLineParallelCopy(CopyState cstate, uint32 line_pos, uint32 line_size,
+					 uint32 raw_buf_ptr)
+{
+	uint8 new_line_size;
+	if (!IsParallelCopy())
+		return;
+
+	if (!IsHeaderLine())
+	{
+		ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+		ParallelCopyLineBoundaries *lineBoundaryPtr = &pcshared_info->line_boundaries;
+		SET_NEWLINE_SIZE()
+		if (line_size)
+		{
+			ParallelCopyLineBoundary *lineInfo = &lineBoundaryPtr->ring[line_pos];
+			/*
+			 * If the new_line_size > raw_buf_ptr, then the new block has only
+			 * new line char content. The unprocessed count should not be
+			 * increased in this case.
+			 */
+			if (raw_buf_ptr > new_line_size)
+			{
+				uint32 cur_block_pos = pcshared_info->cur_block_pos;
+				ParallelCopyDataBlock *curr_data_blk_ptr = &pcshared_info->data_blocks[cur_block_pos];
+				pg_atomic_add_fetch_u32(&curr_data_blk_ptr->unprocessed_line_parts, 1);
+			}
+
+			/* Update line size. */
+			pg_atomic_write_u32(&lineInfo->line_size, line_size);
+			pg_atomic_write_u32(&lineInfo->line_state, LINE_LEADER_POPULATED);
+			elog(DEBUG1, "[Leader] After adding - line position:%d, line_size:%d",
+						 line_pos, line_size);
+			pcshared_info->populated++;
+		}
+		else if (new_line_size)
+		{
+			/* This means only new line char, empty record should be inserted.*/
+			ParallelCopyLineBoundary *lineInfo;
+			line_pos = UpdateBlockInLineInfo(cstate, -1, -1, 0,
+											   LINE_LEADER_POPULATED);
+			lineInfo = &lineBoundaryPtr->ring[line_pos];
+			elog(DEBUG1, "[Leader] Added empty line with offset:%d, line position:%d, line size:%d",
+						 lineInfo->start_offset, line_pos,
+						 pg_atomic_read_u32(&lineInfo->line_size));
+			pcshared_info->populated++;
+		}
+	}
+}
+
+/*
+ * ExecBeforeStmtTrigger - Execute the before statement trigger, this will be
+ * executed for parallel copy by the leader process.
+ */
+static void
+ExecBeforeStmtTrigger(CopyState cstate)
+{
+	EState	   *estate = CreateExecutorState();
+	ResultRelInfo *resultRelInfo;
+
+	Assert(IsLeader());
+
+	/*
+	 * We need a ResultRelInfo so we can use the regular executor's
+	 * index-entry-making machinery.  (There used to be a huge amount of code
+	 * here that basically duplicated execUtils.c ...)
+	 */
+	resultRelInfo = makeNode(ResultRelInfo);
+	InitResultRelInfo(resultRelInfo,
+					  cstate->rel,
+					  1,		/* must match rel's position in range_table */
+					  NULL,
+					  0);
+
+	/* Verify the named relation is a valid target for INSERT */
+	CheckValidResultRel(resultRelInfo, CMD_INSERT);
+
+	estate->es_result_relations = resultRelInfo;
+	estate->es_num_result_relations = 1;
+	estate->es_result_relation_info = resultRelInfo;
+
+	ExecInitRangeTable(estate, cstate->range_table);
+
+	/*
+	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
+	 * should do this for COPY, since it's not really an "INSERT" statement as
+	 * such. However, executing these triggers maintains consistency with the
+	 * EACH ROW triggers that we already fire on COPY.
+	 */
+	ExecBSInsertTriggers(estate, resultRelInfo);
+
+	/* Close any trigger target relations */
+	ExecCleanUpTriggerState(estate);
+
+	FreeExecutorState(estate);
 }
 
 /*
@@ -3570,7 +4297,8 @@ CopyFrom(CopyState cstate)
 
 	PartitionTupleRouting *proute = NULL;
 	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
+	CommandId	mycid = IsParallelCopy() ? GetCurrentCommandId(false) :
+										   GetCurrentCommandId(true);
 	int			ti_options = 0; /* start with default options for insert */
 	BulkInsertState bistate = NULL;
 	CopyInsertMethod insertMethod;
@@ -3580,7 +4308,14 @@ CopyFrom(CopyState cstate)
 	bool		has_instead_insert_row_trig;
 	bool		leafpart_use_multi_insert = false;
 
-	CheckTargetRelValidity(cstate);
+	/*
+	 * Perform this check if it is not parallel copy. In case of parallel
+	 * copy, this check is done by the leader, so that if any invalid case
+	 * exist the copy from command will error out from the leader itself,
+	 * avoiding launching workers, just to throw error.
+	 */
+	if (!IsParallelCopy())
+		CheckTargetRelValidity(cstate);
 
 	/*
 	 * If the target file is new-in-transaction, we assume that checking FSM
@@ -3620,7 +4355,8 @@ CopyFrom(CopyState cstate)
 	target_resultRelInfo = resultRelInfo;
 
 	/* Verify the named relation is a valid target for INSERT */
-	CheckValidResultRel(resultRelInfo, CMD_INSERT);
+	if (!IsParallelCopy())
+		CheckValidResultRel(resultRelInfo, CMD_INSERT);
 
 	ExecOpenIndices(resultRelInfo, false);
 
@@ -3769,13 +4505,16 @@ CopyFrom(CopyState cstate)
 	has_instead_insert_row_trig = (resultRelInfo->ri_TrigDesc &&
 								   resultRelInfo->ri_TrigDesc->trig_insert_instead_row);
 
-	/*
-	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
-	 * should do this for COPY, since it's not really an "INSERT" statement as
-	 * such. However, executing these triggers maintains consistency with the
-	 * EACH ROW triggers that we already fire on COPY.
-	 */
-	ExecBSInsertTriggers(estate, resultRelInfo);
+	if (!IsParallelCopy())
+	{
+		/*
+		 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
+		 * should do this for COPY, since it's not really an "INSERT" statement as
+		 * such. However, executing these triggers maintains consistency with the
+		 * EACH ROW triggers that we already fire on COPY.
+		 */
+		ExecBSInsertTriggers(estate, resultRelInfo);
+	}
 
 	econtext = GetPerTupleExprContext(estate);
 
@@ -3875,6 +4614,16 @@ CopyFrom(CopyState cstate)
 					!has_instead_insert_row_trig &&
 					resultRelInfo->ri_FdwRoutine == NULL;
 
+				/*
+				 * If the table has any partitions that are either foreign or
+				 * has BEFORE/INSTEAD OF triggers, we can't perform copy
+				 * operations with parallel workers.
+				 */
+				if (!leafpart_use_multi_insert && IsParallelWorker())
+					ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							errmsg("cannot perform PARALLEL COPY if partition has BEFORE/INSTEAD OF triggers, or if the partition is foreign partition"),
+							errhint("Try COPY without PARALLEL option")));
+
 				/* Set the multi-insert buffer to use for this partition. */
 				if (leafpart_use_multi_insert)
 				{
@@ -4291,7 +5040,7 @@ BeginCopyFrom(ParseState *pstate,
 	 * only in text mode.
 	 */
 	initStringInfo(&cstate->attribute_buf);
-	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+	cstate->raw_buf = (IsParallelCopy()) ? NULL : (char *) palloc(RAW_BUF_SIZE + 1);
 	cstate->raw_buf_index = cstate->raw_buf_len = 0;
 	if (!cstate->binary)
 	{
@@ -4440,26 +5189,35 @@ NextCopyFromRawFields(CopyState cstate, char ***fields, int *nfields)
 	/* only available for text or csv input */
 	Assert(!cstate->binary);
 
-	/* on input just throw the header line away */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (IsParallelCopy())
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
-			return false;		/* done */
+		done = GetWorkerLine(cstate);
+		if (done && cstate->line_buf.len == 0)
+			return false;
 	}
+	else
+	{
+		/* on input just throw the header line away */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
+		{
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+				return false;		/* done */
+		}
 
-	cstate->cur_lineno++;
+		cstate->cur_lineno++;
 
-	/* Actually read the line into memory here */
-	done = CopyReadLine(cstate);
+		/* Actually read the line into memory here */
+		done = CopyReadLine(cstate);
 
-	/*
-	 * EOF at start of line means we're done.  If we see EOF after some
-	 * characters, we act as though it was newline followed by EOF, ie,
-	 * process the line and then exit loop on next iteration.
-	 */
-	if (done && cstate->line_buf.len == 0)
-		return false;
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			return false;
+	}
 
 	/* Parse the line into de-escaped field values */
 	if (cstate->csv_mode)
@@ -4707,9 +5465,31 @@ CopyReadLine(CopyState cstate)
 		 */
 		if (cstate->copy_dest == COPY_NEW_FE)
 		{
+			bool bIsFirst = true;
 			do
 			{
-				cstate->raw_buf_index = cstate->raw_buf_len;
+				if (!IsParallelCopy())
+					cstate->raw_buf_index = cstate->raw_buf_len;
+				else
+				{
+					if (cstate->raw_buf_index == RAW_BUF_SIZE)
+					{
+						/* Get a new block if it is the first time, From the
+						 * subsequent time, reset the index and re-use the same
+						 * block.
+						 */
+						if (bIsFirst)
+						{
+							ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+							uint32 block_pos = WaitGetFreeCopyBlock(pcshared_info);
+							cstate->raw_buf = pcshared_info->data_blocks[block_pos].data;
+							bIsFirst = false;
+						}
+
+						cstate->raw_buf_index = cstate->raw_buf_len = 0;
+					}
+				}
+
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
@@ -4764,7 +5544,7 @@ static void
 ConvertToServerEncoding(CopyState cstate)
 {
 	/* Done reading the line.  Convert it to server encoding. */
-	if (cstate->need_transcoding)
+	if (cstate->need_transcoding && (!IsParallelCopy() || IsWorker()))
 	{
 		char	   *cvt;
 		cvt = pg_any_to_server(cstate->line_buf.data,
@@ -4803,6 +5583,11 @@ CopyReadLineText(CopyState cstate)
 	char		quotec = '\0';
 	char		escapec = '\0';
 
+	/* For parallel copy */
+	int			line_size = 0;
+	int			line_pos = 0;
+
+	cstate->eol_type = EOL_UNKNOWN;
 	if (cstate->csv_mode)
 	{
 		quotec = cstate->quote[0];
@@ -4857,6 +5642,8 @@ CopyReadLineText(CopyState cstate)
 		if (raw_buf_ptr >= copy_buf_len || need_data)
 		{
 			REFILL_LINEBUF;
+			SetRawBufForLoad(cstate, line_size, copy_buf_len, raw_buf_ptr,
+							 &copy_raw_buf);
 
 			/*
 			 * Try to read some more data.  This will certainly reset
@@ -5081,9 +5868,15 @@ CopyReadLineText(CopyState cstate)
 				 * discard the data and the \. sequence.
 				 */
 				if (prev_raw_ptr > cstate->raw_buf_index)
-					appendBinaryStringInfo(&cstate->line_buf,
+				{
+					if (!IsParallelCopy())
+						appendBinaryStringInfo(&cstate->line_buf,
 										   cstate->raw_buf + cstate->raw_buf_index,
 										   prev_raw_ptr - cstate->raw_buf_index);
+					else
+						line_size += prev_raw_ptr - cstate->raw_buf_index;
+				}
+
 				cstate->raw_buf_index = raw_buf_ptr;
 				result = true;	/* report EOF */
 				break;
@@ -5135,6 +5928,26 @@ not_end_of_copy:
 			IF_NEED_REFILL_AND_EOF_BREAK(mblen - 1);
 			raw_buf_ptr += mblen - 1;
 		}
+
+		/*
+		 * Skip the header line. Update the line here, this cannot be done at
+		 * the beginning, as there is a possibility that file contains empty
+		 * lines.
+		 */
+		if (IsParallelCopy() && first_char_in_line && !IsHeaderLine())
+		{
+			ParallelCopyShmInfo	*pcshared_info = cstate->pcdata->pcshared_info;
+			ParallelCopyLineBoundary *lineInfo;
+			uint32			 line_first_block = pcshared_info->cur_block_pos;
+			line_pos = UpdateBlockInLineInfo(cstate,
+											   line_first_block,
+											   cstate->raw_buf_index, -1,
+											   LINE_LEADER_POPULATING);
+			lineInfo = &pcshared_info->line_boundaries.ring[line_pos];
+			elog(DEBUG1, "[Leader] Adding - block:%d, offset:%d, line position:%d",
+						 line_first_block,	lineInfo->start_offset, line_pos);
+		}
+
 		first_char_in_line = false;
 	}							/* end of outer loop */
 
@@ -5143,6 +5956,7 @@ not_end_of_copy:
 	 */
 	REFILL_LINEBUF;
 	CLEAR_EOL_LINE();
+	EndLineParallelCopy(cstate, line_pos, line_size, raw_buf_ptr);
 
 	return result;
 }
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index f41785f..81cc1f4 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -2353,7 +2353,7 @@ psql_completion(const char *text, int start, int end)
 	/* Complete COPY <sth> FROM|TO filename WITH ( */
 	else if (Matches("COPY|\\copy", MatchAny, "FROM|TO", MatchAny, "WITH", "("))
 		COMPLETE_WITH("FORMAT", "FREEZE", "DELIMITER", "NULL",
-					  "HEADER", "QUOTE", "ESCAPE", "FORCE_QUOTE",
+					  "HEADER", "PARALLEL", "QUOTE", "ESCAPE", "FORCE_QUOTE",
 					  "FORCE_NOT_NULL", "FORCE_NULL", "ENCODING");
 
 	/* Complete COPY <sth> FROM|TO filename WITH (FORMAT */
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index c18554b..94219e8 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -385,6 +385,8 @@ extern FullTransactionId GetTopFullTransactionId(void);
 extern FullTransactionId GetTopFullTransactionIdIfAny(void);
 extern FullTransactionId GetCurrentFullTransactionId(void);
 extern FullTransactionId GetCurrentFullTransactionIdIfAny(void);
+extern void AssignFullTransactionIdForWorker(FullTransactionId fullTransactionId);
+extern void AssignCommandIdForWorker(CommandId commandId, bool used);
 extern void MarkCurrentTransactionIdLoggedIfAny(void);
 extern bool SubTransactionIsActive(SubTransactionId subxid);
 extern CommandId GetCurrentCommandId(bool used);
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index bb49b65..120c7a6 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1706,6 +1706,7 @@ ParallelCopyLineBoundary
 ParallelCopyData
 ParallelCopyDataBlock
 ParallelCopyLineBuf
+ParallelCopyLineState
 ParallelCopyShmInfo
 ParallelExecutorInfo
 ParallelHashGrowth
-- 
1.8.3.1

v3-0004-Documentation-for-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=v3-0004-Documentation-for-parallel-copy.patchDownload
From 8969d183e86199c9035d47459217d5e46f51c49f Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Sat, 1 Aug 2020 09:00:36 +0530
Subject: [PATCH v3 4/6] Documentation for parallel copy.

This patch has the documentation changes for parallel copy.
---
 doc/src/sgml/ref/copy.sgml | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/doc/src/sgml/ref/copy.sgml b/doc/src/sgml/ref/copy.sgml
index 18189ab..2e023ed 100644
--- a/doc/src/sgml/ref/copy.sgml
+++ b/doc/src/sgml/ref/copy.sgml
@@ -37,6 +37,7 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
     DELIMITER '<replaceable class="parameter">delimiter_character</replaceable>'
     NULL '<replaceable class="parameter">null_string</replaceable>'
     HEADER [ <replaceable class="parameter">boolean</replaceable> ]
+    PARALLEL <replaceable class="parameter">integer</replaceable>
     QUOTE '<replaceable class="parameter">quote_character</replaceable>'
     ESCAPE '<replaceable class="parameter">escape_character</replaceable>'
     FORCE_QUOTE { ( <replaceable class="parameter">column_name</replaceable> [, ...] ) | * }
@@ -275,6 +276,22 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
    </varlistentry>
 
    <varlistentry>
+    <term><literal>PARALLEL</literal></term>
+    <listitem>
+     <para>
+      Perform <command>COPY FROM</command> in parallel using <replaceable
+      class="parameter"> integer</replaceable> background workers.  Please
+      note that it is not guaranteed that the number of parallel workers
+      specified in <replaceable class="parameter">integer</replaceable> will
+      be used during execution.  It is possible for a copy to run with fewer
+      workers than specified, or even with no workers at all (for example,
+      due to the setting of max_worker_processes). This option is allowed
+      only in <command>COPY FROM</command>.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><literal>QUOTE</literal></term>
     <listitem>
      <para>
-- 
1.8.3.1

v3-0005-Tests-for-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=v3-0005-Tests-for-parallel-copy.patchDownload
From d72e976bf5310679f2cbac8d91205fea169abbef Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Sat, 1 Aug 2020 09:19:39 +0530
Subject: [PATCH v3 5/6] Tests for parallel copy.

This patch has the tests for parallel copy.
---
 src/test/regress/expected/copy2.out | 205 ++++++++++++++++++++++++++++++++++-
 src/test/regress/input/copy.source  |  12 +++
 src/test/regress/output/copy.source |  12 +++
 src/test/regress/sql/copy2.sql      | 208 +++++++++++++++++++++++++++++++++++-
 4 files changed, 429 insertions(+), 8 deletions(-)

diff --git a/src/test/regress/expected/copy2.out b/src/test/regress/expected/copy2.out
index e40287d..7ae5d44 100644
--- a/src/test/regress/expected/copy2.out
+++ b/src/test/regress/expected/copy2.out
@@ -254,18 +254,32 @@ It is "perfect".|
 "It is ""perfect"".","	"
 "",
 --test that we read consecutive LFs properly
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 COPY testnl FROM stdin CSV;
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+SELECT * FROM testnl;
+ a |          b           | c 
+---+----------------------+---
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+(2 rows)
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 COPY testeoc FROM stdin CSV;
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
 COPY testeoc TO stdout CSV;
 a\.
 \.b
 c\.d
 "\."
 -- test handling of nonstandard null marker that violates escaping rules
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 COPY testnull TO stdout WITH NULL AS E'\\0';
 1	\\0
@@ -280,6 +294,15 @@ SELECT * FROM testnull;
     | 
 (4 rows)
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 1);
+SELECT * FROM testnull;
+ a  | b  
+----+----
+ 42 | \0
+    | 
+(2 rows)
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -349,6 +372,34 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+SELECT * FROM vistest;
+ a  
+----
+ a2
+ b
+(2 rows)
+
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+COMMIT;
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 SELECT * FROM vistest;
  a 
@@ -409,7 +460,7 @@ SELECT * FROM vistest;
 (2 rows)
 
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -420,6 +471,8 @@ CREATE TEMP TABLE forcetest (
 -- should succeed with no effect ("b" remains an empty string, "c" remains NULL)
 BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 1);
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
  b |  c   
@@ -430,6 +483,8 @@ SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
 BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 1);
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
  c |  d   
@@ -486,6 +541,31 @@ select * from check_con_tbl;
    
 (2 rows)
 
+\d+ check_con_tbl
+                               Table "public.check_con_tbl"
+ Column |  Type   | Collation | Nullable | Default | Storage | Stats target | Description 
+--------+---------+-----------+----------+---------+---------+--------------+-------------
+ f1     | integer |           |          |         | plain   |              | 
+Check constraints:
+    "check_con_tbl_check" CHECK (check_con_function(check_con_tbl.*))
+
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 1);
+NOTICE:  input = {"f1":1}
+NOTICE:  input = {"f1":null}
+copy check_con_tbl from stdin with (parallel 1);
+NOTICE:  input = {"f1":0}
+ERROR:  new row for relation "check_con_tbl" violates check constraint "check_con_tbl_check"
+DETAIL:  Failing row contains (0).
+CONTEXT:  COPY check_con_tbl, line 1: "0"
+parallel worker
+select * from check_con_tbl;
+ f1 
+----
+  1
+   
+(2 rows)
+
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
 CREATE ROLE regress_rls_copy_user_colperms;
@@ -600,8 +680,125 @@ SELECT * FROM instead_of_insert_tbl;
 (2 rows)
 
 COMMIT;
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+COPY test_parallel_copy (a, b, c, d, e) from stdin with (PARALLEL 1);
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1, FORMAT 'csv', HEADER);
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0');
+ERROR:  value 0 out of bounds for option "parallel"
+DETAIL:  Valid values are between "1" and "1024".
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri from stdin with (FORMAT csv, DELIMITER ',', PARALLEL 1);
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1) WHERE height > random() * 65;
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+-- temporary table copy: should perform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+COPY temp_test (a) from stdin with (PARALLEL 1);
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) from stdin with (PARALLEL 1);
+ERROR:  column "xyz" of relation "test_parallel_copy" does not exist
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) from stdin with (PARALLEL 1);
+ERROR:  column "d" specified more than once
+-- missing data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  invalid input syntax for type integer: ""
+CONTEXT:  COPY test_parallel_copy, line 0, column a: ""
+parallel worker
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2000	230	23	23"
+parallel worker
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2001	231	\N	\N"
+parallel worker
+-- extra data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  extra data after last expected column
+CONTEXT:  COPY test_parallel_copy, line 1: "2002	232	40	50	60	70	80"
+parallel worker
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) from stdin with (delimiter ',', null 'x', PARALLEL 1) ;
+COPY test_parallel_copy from stdin WITH (DELIMITER ';', NULL '', PARALLEL 1);
+COPY test_parallel_copy from stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL 1);
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = 50004;
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a > 60003;
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE f > 60003;
+ERROR:  column "f" does not exist
+LINE 1: ..._parallel_copy from stdin WITH (PARALLEL 1) WHERE f > 60003;
+                                                             ^
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+ERROR:  missing FROM-clause entry for table "x"
+LINE 1: ...rallel_copy from stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+                                                                  ^
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (SELECT 1 FROM x);
+ERROR:  cannot use subquery in COPY FROM WHERE condition
+LINE 1: ...arallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (SELECT...
+                                                             ^
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (generate_series(1,5));
+ERROR:  set-returning functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...lel_copy from stdin WITH (PARALLEL 1) WHERE a IN (generate_s...
+                                                             ^
+COPY test_parallel_copy from stdin WITH(PARALLEL 1) WHERE a = row_number() over(b);
+ERROR:  window functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...rallel_copy from stdin WITH(PARALLEL 1) WHERE a = row_number...
+                                                             ^
+-- check results of copy in
+SELECT * FROM test_parallel_copy;
+   a   | b  |     c      |    d    |    e    
+-------+----+------------+---------+---------
+     1 | 11 | test_c1    | test_d1 | test_e1
+     2 | 12 | test_c2    | test_d2 | test_e2
+       |  3 | stuff      | test_d3 | 
+       |  4 | stuff      | test_d4 | 
+       |  5 | stuff      | test_d5 | 
+       |    | 45         | 80      | 90
+       |    | x          | \x      | \x
+       |    | ,          | \,      | \
+  3000 |    | c          |         | 
+  4000 |    | C          |         | 
+  4001 |  1 | empty      |         | 
+  4002 |  2 | null       |         | 
+  4003 |  3 | Backslash  | \       | \
+  4004 |  4 | BackslashX | \X      | \X
+  4005 |  5 | N          | N       | N
+  4006 |  6 | BackslashN | \N      | \N
+  4007 |  7 | XX         | XX      | XX
+  4008 |  8 | Delimiter  | :       | :
+ 50004 | 25 | 35         | 45      | 55
+ 60004 | 25 | 35         | 45      | 55
+ 60005 | 26 | 36         | 46      | 56
+(21 rows)
+
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
 DROP TABLE x, y;
diff --git a/src/test/regress/input/copy.source b/src/test/regress/input/copy.source
index a1d529a..159c058 100644
--- a/src/test/regress/input/copy.source
+++ b/src/test/regress/input/copy.source
@@ -15,6 +15,13 @@ DELETE FROM onek;
 
 COPY onek FROM '@abs_builddir@/results/onek.data';
 
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+
+SELECT COUNT(*) FROM tenk1;
+
+TRUNCATE tenk1;
+
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
@@ -159,6 +166,11 @@ truncate parted_copytest;
 
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
 
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
+
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/output/copy.source b/src/test/regress/output/copy.source
index 938d355..c3003fe 100644
--- a/src/test/regress/output/copy.source
+++ b/src/test/regress/output/copy.source
@@ -9,6 +9,15 @@ COPY onek FROM '@abs_srcdir@/data/onek.data';
 COPY onek TO '@abs_builddir@/results/onek.data';
 DELETE FROM onek;
 COPY onek FROM '@abs_builddir@/results/onek.data';
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+SELECT COUNT(*) FROM tenk1;
+ count 
+-------
+ 10000
+(1 row)
+
+TRUNCATE tenk1;
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
 COPY person FROM '@abs_srcdir@/data/person.data';
@@ -113,6 +122,9 @@ insert into parted_copytest select x,1,'One' from generate_series(1011,1020) x;
 copy (select * from parted_copytest order by a) to '@abs_builddir@/results/parted_copytest.csv';
 truncate parted_copytest;
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/sql/copy2.sql b/src/test/regress/sql/copy2.sql
index 902f4fa..7015698 100644
--- a/src/test/regress/sql/copy2.sql
+++ b/src/test/regress/sql/copy2.sql
@@ -157,7 +157,7 @@ COPY y TO stdout (FORMAT CSV, FORCE_QUOTE *);
 
 --test that we read consecutive LFs properly
 
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 
 COPY testnl FROM stdin CSV;
 1,"a field with two LFs
@@ -165,8 +165,16 @@ COPY testnl FROM stdin CSV;
 inside",2
 \.
 
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+1,"a field with two LFs
+
+inside",2
+\.
+
+SELECT * FROM testnl;
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 
 COPY testeoc FROM stdin CSV;
 a\.
@@ -175,11 +183,19 @@ c\.d
 "\."
 \.
 
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+a\.
+\.b
+c\.d
+"\."
+\.
+
 COPY testeoc TO stdout CSV;
 
 -- test handling of nonstandard null marker that violates escaping rules
 
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 
 COPY testnull TO stdout WITH NULL AS E'\\0';
@@ -191,6 +207,14 @@ COPY testnull FROM stdin WITH NULL AS E'\\0';
 
 SELECT * FROM testnull;
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 1);
+42	\\0
+\0	\0
+\.
+
+SELECT * FROM testnull;
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -235,6 +259,23 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+a2
+b
+\.
+SELECT * FROM vistest;
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+d2
+e
+\.
+SELECT * FROM vistest;
+COMMIT;
+SELECT * FROM vistest;
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 x
 y
@@ -284,7 +325,7 @@ SELECT * FROM vistest;
 COMMIT;
 SELECT * FROM vistest;
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -297,6 +338,10 @@ BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
 1,,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 1);
+1,,""
+\.
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
@@ -304,6 +349,10 @@ BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
 2,'a',,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 1);
+2,'a',,""
+\.
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
 -- should fail with not-null constraint violation
@@ -339,6 +388,16 @@ copy check_con_tbl from stdin;
 0
 \.
 select * from check_con_tbl;
+\d+ check_con_tbl
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 1);
+1
+\N
+\.
+copy check_con_tbl from stdin with (parallel 1);
+0
+\.
+select * from check_con_tbl;
 
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
@@ -440,8 +499,149 @@ test1
 SELECT * FROM instead_of_insert_tbl;
 COMMIT;
 
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+
+COPY test_parallel_copy (a, b, c, d, e) from stdin with (PARALLEL 1);
+1	11	test_c1	test_d1	test_e1
+2	12	test_c2	test_d2	test_e2
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+3	test_d3
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+4	test_d4
+5	test_d5
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1, FORMAT 'csv', HEADER);
+b	d
+\.
+
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0');
+
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri from stdin with (FORMAT csv, DELIMITER ',', PARALLEL 1);
+10
+\.
+
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1) WHERE height > random() * 65;
+60,60,60
+\.
+
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+60
+\.
+
+-- temporary table copy: should perform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+
+COPY temp_test (a) from stdin with (PARALLEL 1);
+10
+\.
+
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) from stdin with (PARALLEL 1);
+
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) from stdin with (PARALLEL 1);
+
+-- missing data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+
+\.
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+2000	230	23	23
+\.
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+2001	231	\N	\N
+\.
+
+-- extra data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+2002	232	40	50	60	70	80
+\.
+
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) from stdin with (delimiter ',', null 'x', PARALLEL 1) ;
+x,45,80,90
+x,\x,\\x,\\\x
+x,\,,\\\,,\\
+\.
+
+COPY test_parallel_copy from stdin WITH (DELIMITER ';', NULL '', PARALLEL 1);
+3000;;c;;
+\.
+
+COPY test_parallel_copy from stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL 1);
+4000:\X:C:\X:\X
+4001:1:empty::
+4002:2:null:\X:\X
+4003:3:Backslash:\\:\\
+4004:4:BackslashX:\\X:\\X
+4005:5:N:\N:\N
+4006:6:BackslashN:\\N:\\N
+4007:7:XX:\XX:\XX
+4008:8:Delimiter:\::\:
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = 50004;
+50003	24	34	44	54
+50004	25	35	45 	55
+50005	26	36	46	56
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a > 60003;
+60001	22	32	42	52
+60002	23	33	43	53
+60003	24	34	44	54
+60004	25	35	45	55
+60005	26	36	46	56
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE f > 60003;
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (SELECT 1 FROM x);
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (generate_series(1,5));
+
+COPY test_parallel_copy from stdin WITH(PARALLEL 1) WHERE a = row_number() over(b);
+
+-- check results of copy in
+SELECT * FROM test_parallel_copy;
+
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
 DROP TABLE x, y;
-- 
1.8.3.1

v3-0006-Parallel-Copy-For-Binary-Format-Files.patchtext/x-patch; charset=US-ASCII; name=v3-0006-Parallel-Copy-For-Binary-Format-Files.patchDownload
From b351a756e59b6b3c21a058394b969877788f43b5 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddy@enterprisedb.com>
Date: Mon, 3 Aug 2020 11:58:35 +0530
Subject: [PATCH v3 6/6] Parallel Copy For Binary Format Files

Leader reads data from the file into the DSM data blocks each of 64K size.
It also identifies each tuple data block id, start offset, end offset,
tuple size and updates this information in the ring data structure.
Workers parallelly read the tuple information from the ring data structure,
the actual tuple data from the data blocks and parallelly insert the tuples
into the table.
---
 src/backend/commands/copy.c | 687 ++++++++++++++++++++++++++++++++++++++------
 1 file changed, 602 insertions(+), 85 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 4c69a5d..0948296 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -263,6 +263,17 @@ typedef struct ParallelCopyLineBuf
 }ParallelCopyLineBuf;
 
 /*
+ * Represents the usage mode for CopyReadBinaryGetDataBlock.
+ */
+typedef enum FieldInfoType
+{
+	FIELD_NONE = 0,
+	FIELD_COUNT,
+	FIELD_SIZE,
+	FIELD_DATA
+} FieldInfoType;
+
+/*
  * Parallel copy data information.
  */
 typedef struct ParallelCopyData
@@ -283,6 +294,9 @@ typedef struct ParallelCopyData
 
 	/* Current position in worker_line_buf */
 	uint32				worker_line_buf_pos;
+
+	/* For binary formatted files */
+	ParallelCopyDataBlock *curr_data_block;
 }ParallelCopyData;
 
 /*
@@ -447,6 +461,7 @@ typedef struct SerializedParallelCopyState
 	/* Working state for COPY FROM */
 	AttrNumber          num_defaults;
 	Oid                 relid;
+	bool				binary;
 }SerializedParallelCopyState;
 
 /* DestReceiver for COPY (query) TO */
@@ -521,7 +536,6 @@ typedef struct CopyMultiInsertInfo
 	int			ti_options;		/* table insert options */
 } CopyMultiInsertInfo;
 
-
 /*
  * These macros centralize code used to process line_buf and raw_buf buffers.
  * They are macros because they often do continue/break control and to avoid
@@ -649,11 +663,113 @@ if (!IsParallelCopy()) \
 else \
 	return pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
 
+/*
+ * CHECK_FIELD_COUNT - Handles the error cases for field count
+ * for binary format files.
+ */
+#define CHECK_FIELD_COUNT \
+{\
+	if (fld_count == -1) \
+	{ \
+		if (IsParallelCopy() && \
+			!IsLeader()) \
+			return true; \
+		else if (IsParallelCopy() && \
+			IsLeader()) \
+		{ \
+			if (cstate->pcdata->curr_data_block->data[cstate->raw_buf_index + sizeof(fld_count)] != 0) \
+				ereport(ERROR, \
+						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+						errmsg("received copy data after EOF marker"))); \
+			return true; \
+		} \
+		else \
+		{ \
+			/* \
+			* Received EOF marker.  In a V3-protocol copy, wait for the \
+			* protocol-level EOF, and complain if it doesn't come \
+			* immediately.  This ensures that we correctly handle CopyFail, \
+			* if client chooses to send that now. \
+			* \
+			* Note that we MUST NOT try to read more data in an old-protocol \
+			* copy, since there is no protocol-level EOF marker then.  We \
+			* could go either way for copy from file, but choose to throw \
+			* error if there's data after the EOF marker, for consistency \
+			* with the new-protocol case. \
+			*/ \
+			char		dummy; \
+			if (cstate->copy_dest != COPY_OLD_FE && \
+				CopyReadBinaryData(cstate, &dummy, 1) > 0) \
+				ereport(ERROR, \
+						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+						errmsg("received copy data after EOF marker"))); \
+				return false; \
+		} \
+	} \
+	if (fld_count != cstate->max_fields) \
+		ereport(ERROR, \
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+				errmsg("row field count is %d, expected %d", \
+				(int) fld_count, cstate->max_fields))); \
+}
+
+/*
+ * CHECK_FIELD_SIZE - Handles the error case for field size
+ * for binary format files.
+ */
+#define CHECK_FIELD_SIZE(fld_size) \
+{ \
+	if (fld_size < -1) \
+		ereport(ERROR, \
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+				errmsg("invalid field size")));\
+}
+
+/*
+ * EOF_ERROR - Error statement for EOF for binary format
+ * files.
+ */
+#define EOF_ERROR \
+{ \
+	ereport(ERROR, \
+		(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+		errmsg("unexpected EOF in COPY data")));\
+}
+
+/*
+ * GET_RAW_BUF_INDEX - Calculates the raw buf index for the cases
+ * where the data spread is across multiple data blocks.
+ */
+#define GET_RAW_BUF_INDEX(raw_buf_index, fld_size, required_blks, curr_blk_bytes) \
+{ \
+	raw_buf_index = fld_size - (((required_blks - 1) * DATA_BLOCK_SIZE) + curr_blk_bytes); \
+}
+
+/*
+ * GET_REQUIRED_BLOCKS - Calculates the number of data
+ * blocks required for the cases where the data spread
+ * is across multiple data blocks.
+ */
+#define GET_REQUIRED_BLOCKS(required_blks, fld_size, curr_blk_bytes) \
+{ \
+	/* \
+	 * field size can spread across multiple data blocks, \
+	 * calculate the number of required data blocks and try to get \
+	 * those many data blocks. \
+	 */ \
+	required_blks = (int32)(fld_size - curr_blk_bytes)/(int32)DATA_BLOCK_SIZE; \
+	/* \
+	 * check if we need the data block for the field data \
+	 * bytes that are not modulus of data block size. \
+	 */ \
+	if ((fld_size - curr_blk_bytes)%DATA_BLOCK_SIZE != 0) \
+		required_blks++; \
+}
+
 /* End parallel copy Macros */
 
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
-
 /* non-export function prototypes */
 static CopyState BeginCopy(ParseState *pstate, bool is_from, Relation rel,
 						   RawStmt *raw_query, Oid queryRelId, List *attnamelist,
@@ -708,6 +824,14 @@ static void ExecBeforeStmtTrigger(CopyState cstate);
 static void CheckTargetRelValidity(CopyState cstate);
 static void PopulateCstateCatalogInfo(CopyState cstate);
 static pg_attribute_always_inline uint32 GetLinePosition(CopyState cstate);
+static uint32 WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info);
+static bool CopyReadBinaryTupleLeader(CopyState cstate);
+static void CopyReadBinaryFindTupleSize(CopyState cstate, uint32 *line_size);
+static bool CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls);
+static Datum CopyReadBinaryAttributeWorker(CopyState cstate, FmgrInfo *flinfo,
+										   Oid typioparam, int32 typmod, bool *isnull);
+static void CopyReadBinaryGetDataBlock(CopyState cstate, FieldInfoType field_info);
+
 /*
  * SerializeParallelCopyState - Copy shared_cstate using cstate information.
  */
@@ -725,6 +849,7 @@ SerializeParallelCopyState(CopyState cstate, SerializedParallelCopyState *shared
 	shared_cstate->convert_selectively = cstate->convert_selectively;
 	shared_cstate->num_defaults = cstate->num_defaults;
 	shared_cstate->relid = cstate->pcdata->relid;
+	shared_cstate->binary = cstate->binary;
 }
 
 /*
@@ -884,8 +1009,8 @@ FindInsertMethod(CopyState cstate)
 static pg_attribute_always_inline bool
 IsParallelCopyAllowed(CopyState cstate)
 {
-	/* Parallel copy not allowed for frontend (2.0 protocol) & binary option. */
-	if ((cstate->copy_dest == COPY_OLD_FE) || cstate->binary)
+	/* Parallel copy not allowed for frontend (2.0 protocol). */
+	if (cstate->copy_dest == COPY_OLD_FE)
 		return false;
 
 	/* Check if copy is into foreign table or temporary table. */
@@ -1155,6 +1280,7 @@ InitializeParallelCopyInfo(SerializedParallelCopyState *shared_cstate,
 	cstate->convert_selectively = shared_cstate->convert_selectively;
 	cstate->num_defaults = shared_cstate->num_defaults;
 	pcdata->relid = shared_cstate->relid;
+	cstate->binary = shared_cstate->binary;
 
 	PopulateCommonCstateInfo(cstate, tup_desc, attnamelist);
 
@@ -1543,35 +1669,72 @@ ParallelCopyFrom(CopyState cstate)
 	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
 	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
 
+	/* raw_buf is not used in parallel copy, instead data blocks are used.*/
+	pfree(cstate->raw_buf);
+
 	/* Execute the before statement triggers from the leader */
 	ExecBeforeStmtTrigger(cstate);
 
-	/* On input just throw the header line away. */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (!cstate->binary)
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
+		/* On input just throw the header line away. */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
 		{
-			pcshared_info->is_read_in_progress = false;
-			return;			/* done */
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+			{
+				pcshared_info->is_read_in_progress = false;
+				return;			/* done */
+			}
 		}
-	}
 
-	for (;;)
-	{
-		bool done;
-		cstate->cur_lineno++;
+		for (;;)
+		{
+			bool done;
+			cstate->cur_lineno++;
 
-		/* Actually read the line into memory here. */
-		done = CopyReadLine(cstate);
+			/* Actually read the line into memory here. */
+			done = CopyReadLine(cstate);
 
+			/*
+			* EOF at start of line means we're done.  If we see EOF after some
+			* characters, we act as though it was newline followed by EOF, ie,
+			* process the line and then exit loop on next iteration.
+			*/
+			if (done && cstate->line_buf.len == 0)
+				break;
+		}
+	}
+	else
+	{
 		/*
-		 * EOF at start of line means we're done.  If we see EOF after some
-		 * characters, we act as though it was newline followed by EOF, ie,
-		 * process the line and then exit loop on next iteration.
+		 * Binary Format Files.
+		 * For parallel copy leader, fill in the error
+		 * context information here, in case any failures
+		 * while determining tuple offsets, leader
+		 * would throw the errors with proper context.
 		 */
-		if (done && cstate->line_buf.len == 0)
-			break;
+		ErrorContextCallback errcallback;
+		errcallback.callback = CopyFromErrorCallback;
+		errcallback.arg = (void *) cstate;
+		errcallback.previous = error_context_stack;
+		error_context_stack = &errcallback;
+		cstate->pcdata->curr_data_block = NULL;
+		cstate->raw_buf_index = 0;
+		pcshared_info->populated = 0;
+		cstate->cur_lineno = 0;
+		cstate->max_fields = list_length(cstate->attnumlist);
+
+		for (;;)
+		{
+			bool eof = false;
+			cstate->cur_lineno++;
+
+			eof = CopyReadBinaryTupleLeader(cstate);
+
+			if (eof)
+				break;
+		}
 	}
 
 	pcshared_info->is_read_in_progress = false;
@@ -1579,7 +1742,355 @@ ParallelCopyFrom(CopyState cstate)
  }
 
 /*
- * GetLinePosition - return the line position that worker should process.
+ * CopyReadBinaryGetDataBlock - gets a new block, updates
+ * the current offset, calculates the skip bytes.
+ */
+static void
+CopyReadBinaryGetDataBlock(CopyState cstate, FieldInfoType field_info)
+{
+	ParallelCopyDataBlock *data_block = NULL;
+	ParallelCopyDataBlock *curr_data_block = cstate->pcdata->curr_data_block;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	uint8 move_bytes = 0;
+	uint32 block_pos;
+	uint32 prev_block_pos;
+	int read_bytes = 0;
+
+	prev_block_pos = pcshared_info->cur_block_pos;
+
+	block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+	if (field_info == FIELD_SIZE || field_info == FIELD_COUNT)
+		move_bytes = (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+
+	if (curr_data_block != NULL)
+		curr_data_block->skip_bytes = move_bytes;
+
+	data_block = &pcshared_info->data_blocks[block_pos];
+
+	if (move_bytes > 0 && curr_data_block != NULL)
+		memmove(&data_block->data[0], &curr_data_block->data[cstate->raw_buf_index], move_bytes);
+
+	elog(DEBUG1, "LEADER - field info %d is spread across data blocks - moved %d bytes from current block %u to %u block",
+		field_info, move_bytes, prev_block_pos, block_pos);
+
+	read_bytes = CopyGetData(cstate, &data_block->data[move_bytes], 1, (DATA_BLOCK_SIZE - move_bytes));
+
+	if (field_info == FIELD_NONE && cstate->reached_eof)
+		return;
+
+	if (cstate->reached_eof)
+		EOF_ERROR;
+
+	elog(DEBUG1, "LEADER - bytes read from file %d", read_bytes);
+
+	if(field_info == FIELD_SIZE || field_info == FIELD_DATA)
+	{
+		ParallelCopyDataBlock *prev_data_block = NULL;
+		prev_data_block = curr_data_block;
+		prev_data_block->following_block = block_pos;
+
+		if (prev_data_block->curr_blk_completed  == false)
+			prev_data_block->curr_blk_completed = true;
+
+		pg_atomic_add_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+	}
+
+	cstate->pcdata->curr_data_block = data_block;
+	cstate->raw_buf_index = 0;
+}
+
+/*
+ * CopyReadBinaryTupleLeader - leader reads data from binary formatted file
+ * to data blocks and identifies tuple boundaries/offsets so that workers
+ * can work on the data blocks data.
+ */
+static bool
+CopyReadBinaryTupleLeader(CopyState cstate)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	int16		fld_count;
+	uint32      line_size = 0;
+	uint32 		start_block_pos;
+	uint32		start_offset;
+
+	if (cstate->pcdata->curr_data_block == NULL)
+	{
+		CopyReadBinaryGetDataBlock(cstate, FIELD_NONE);
+
+		/*
+		 * no data is read from file here. one possibility
+		 * to be here could be that the binary file just
+		 * has a valid signature but nothing else.
+		 */
+		if (cstate->reached_eof)
+			return true;
+	}
+
+	if ((cstate->raw_buf_index + sizeof(fld_count)) >= DATA_BLOCK_SIZE)
+		CopyReadBinaryGetDataBlock(cstate, FIELD_COUNT);
+
+	memcpy(&fld_count, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_count));
+	fld_count = (int16) pg_ntoh16(fld_count);
+	CHECK_FIELD_COUNT;
+	start_offset = cstate->raw_buf_index;
+	cstate->raw_buf_index += sizeof(fld_count);
+	line_size += sizeof(fld_count);
+	start_block_pos = pcshared_info->cur_block_pos;
+
+	CopyReadBinaryFindTupleSize(cstate, &line_size);
+
+	pg_atomic_add_fetch_u32(&cstate->pcdata->curr_data_block->unprocessed_line_parts, 1);
+
+	if (line_size > 0)
+	{
+		int line_pos = UpdateBlockInLineInfo(cstate,
+											start_block_pos,
+											start_offset,
+											line_size,
+											LINE_LEADER_POPULATED);
+
+		pcshared_info->populated++;
+		elog(DEBUG1, "LEADER - adding - block:%u, offset:%u, line size:%u line position:%d",
+				start_block_pos, start_offset, line_size, line_pos);
+	}
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryFindTupleSize - leader identifies boundaries/
+ * offsets for each attribute/column and finally results in the
+ * tuple/row size. It moves on to next data block if the attribute/
+ * column is spread across data blocks.
+ */
+static void
+CopyReadBinaryFindTupleSize(CopyState cstate, uint32 *line_size)
+{
+	int32		fld_size;
+	ListCell   *cur;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			att_num = lfirst_int(cur);
+		Form_pg_attribute att = TupleDescAttr(tup_desc, (att_num - 1));
+		cstate->cur_attname = NameStr(att->attname);
+		fld_size = 0;
+
+		if ((cstate->raw_buf_index + sizeof(fld_size)) >= DATA_BLOCK_SIZE)
+			CopyReadBinaryGetDataBlock(cstate, FIELD_SIZE);
+
+		memcpy(&fld_size, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_size));
+		cstate->raw_buf_index += sizeof(fld_size);
+		*line_size += sizeof(fld_size);
+		fld_size = (int32) pg_ntoh32(fld_size);
+
+		CHECK_FIELD_SIZE(fld_size);
+
+		*line_size += fld_size;
+
+		if ((DATA_BLOCK_SIZE - cstate->raw_buf_index) >= fld_size)
+		{
+			cstate->raw_buf_index += fld_size;
+			elog(DEBUG1, "LEADER - tuple lies in he same data block");
+		}
+		else
+		{
+			int32 required_blks = 0;
+			int32 curr_blk_bytes = (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+			int i = 0;
+
+			GET_REQUIRED_BLOCKS(required_blks, fld_size, curr_blk_bytes);
+
+			i = required_blks;
+
+			while(i > 0)
+			{
+				CopyReadBinaryGetDataBlock(cstate, FIELD_DATA);
+				i--;
+			}
+
+			GET_RAW_BUF_INDEX(cstate->raw_buf_index, fld_size, required_blks, curr_blk_bytes);
+
+			/*
+			 * raw_buf_index should never cross data block size,
+			 * as the required number of data blocks would have
+			 * been obtained in the above while loop.
+			 */
+			Assert(cstate->raw_buf_index <= DATA_BLOCK_SIZE);
+		}
+		cstate->cur_attname = NULL;
+	}
+}
+
+/*
+ * CopyReadBinaryTupleWorker - each worker reads data from data blocks after
+ * getting leader-identified tuple offsets from ring data structure.
+ */
+static bool
+CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls)
+{
+	uint32 		line_pos;
+	ParallelCopyLineBoundary *line_info;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	int16		fld_count;
+	ListCell   *cur;
+	FmgrInfo   *in_functions = cstate->in_functions;
+	Oid		   *typioparams = cstate->typioparams;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	line_pos = GetLinePosition(cstate);
+
+	if (line_pos == -1)
+		return true;
+
+	line_info = &pcshared_info->line_boundaries.ring[line_pos];
+	cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[line_info->first_block];
+	cstate->raw_buf_index = line_info->start_offset;
+
+	if (cstate->raw_buf_index + sizeof(fld_count) >= DATA_BLOCK_SIZE)
+	{
+		/*
+		 * The case where field count spread across datablocks should never occur,
+		 * as the leader would have moved it to next block. this code exists for
+		 * debugging purposes only.
+		 */
+		elog(DEBUG1, "WORKER - field count spread across datablocks should never occur");
+	}
+
+	memcpy(&fld_count, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_count));
+	fld_count = (int16) pg_ntoh16(fld_count);
+
+	CHECK_FIELD_COUNT;
+
+	cstate->raw_buf_index += sizeof(fld_count);
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			att_num = lfirst_int(cur);
+		int			m = att_num - 1;
+		Form_pg_attribute att = TupleDescAttr(tup_desc, m);
+		cstate->cur_attname = NameStr(att->attname);
+
+		values[m] = CopyReadBinaryAttributeWorker(cstate,
+											&in_functions[m],
+											typioparams[m],
+											att->atttypmod,
+											&nulls[m]);
+		cstate->cur_attname = NULL;
+	}
+
+	pg_atomic_sub_fetch_u32(&cstate->pcdata->curr_data_block->unprocessed_line_parts, 1);
+	line_info->start_offset = -1;
+	pg_atomic_write_u32(&line_info->line_state, LINE_WORKER_PROCESSED);
+	pg_atomic_write_u32(&line_info->line_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryAttributeWorker - leader identifies boundaries/offsets
+ * for each attribute/column, it moves on to next data block if the
+ * attribute/column is spread across data blocks.
+ */
+static Datum
+CopyReadBinaryAttributeWorker(CopyState cstate, FmgrInfo *flinfo,
+		Oid typioparam, int32 typmod, bool *isnull)
+{
+	int32		fld_size;
+	Datum		result;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+	if ((cstate->raw_buf_index + sizeof(fld_size)) >= DATA_BLOCK_SIZE)
+	{
+		ParallelCopyDataBlock *prev_data_block = cstate->pcdata->curr_data_block;
+		elog(DEBUG1, "WORKER - field size is spread across data blocks");
+		cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[prev_data_block->following_block];
+		pg_atomic_sub_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+		cstate->raw_buf_index = 0;
+	}
+
+	memcpy(&fld_size, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_size));
+	fld_size = (int32) pg_ntoh32(fld_size);
+
+	CHECK_FIELD_SIZE(fld_size);
+
+	cstate->raw_buf_index += sizeof(fld_size);
+
+	/* reset attribute_buf to empty, and load raw data in it */
+	resetStringInfo(&cstate->attribute_buf);
+
+	enlargeStringInfo(&cstate->attribute_buf, fld_size);
+
+	if ((DATA_BLOCK_SIZE - cstate->raw_buf_index) >= fld_size)
+	{
+		elog(DEBUG1, "WORKER - tuple lies in single data block");
+		memcpy(&cstate->attribute_buf.data[0],&cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], fld_size);
+		cstate->raw_buf_index += fld_size;
+	}
+	else
+	{
+		uint32 att_buf_idx = 0;
+		uint32 copy_bytes = 0;
+		int32 required_blks = 0;
+		int32 curr_blk_bytes = (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+		ParallelCopyDataBlock *prev_data_block = NULL;
+		int i = 0;
+
+		GET_REQUIRED_BLOCKS(required_blks, fld_size, curr_blk_bytes);
+
+		i = required_blks;
+		prev_data_block = cstate->pcdata->curr_data_block;
+		elog(DEBUG1, "WORKER - tuple is spread across data blocks");
+		memcpy(&cstate->attribute_buf.data[0], &prev_data_block->data[cstate->raw_buf_index],
+				curr_blk_bytes);
+		copy_bytes = curr_blk_bytes;
+		att_buf_idx = curr_blk_bytes;
+
+		while (i>0)
+		{
+			cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[prev_data_block->following_block];
+			pg_atomic_sub_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+			cstate->raw_buf_index = 0;
+			copy_bytes = fld_size - att_buf_idx;
+
+			/*
+			 * the bytes that are yet to be taken into att buff are more than
+			 * the entire data block size, but only take the data block size
+			 * elements.
+			 */
+			if (copy_bytes >= DATA_BLOCK_SIZE)
+				copy_bytes = DATA_BLOCK_SIZE;
+
+			memcpy(&cstate->attribute_buf.data[att_buf_idx],
+				&cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], copy_bytes);
+			att_buf_idx += copy_bytes;
+			i--;
+		}
+		GET_RAW_BUF_INDEX(cstate->raw_buf_index, fld_size, required_blks, curr_blk_bytes);
+	}
+
+	cstate->attribute_buf.len = fld_size;
+	cstate->attribute_buf.data[fld_size] = '\0';
+
+	/* Call the column type's binary input converter */
+	result = ReceiveFunctionCall(flinfo, &cstate->attribute_buf,
+								 typioparam, typmod);
+
+	/* Trouble if it didn't eat the whole buffer */
+	if (cstate->attribute_buf.cursor != cstate->attribute_buf.len)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+				 errmsg("incorrect binary data format")));
+
+	*isnull = false;
+	return result;
+}
+
+/*
+ * GetLinePosition - return the line position that worker should pcdata->process.
  */
 static uint32
 GetLinePosition(CopyState cstate)
@@ -1667,7 +2178,9 @@ GetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
 		{
 			dataBlkPtr->curr_blk_completed = false;
 			dataBlkPtr->skip_bytes = 0;
+			dataBlkPtr->following_block = -1;
 			pcshared_info->cur_block_pos = block_pos;
+			MemSet(&dataBlkPtr->data[0], 0, DATA_BLOCK_SIZE);
 			return block_pos;
 		}
 
@@ -2183,10 +2696,26 @@ CopyGetInt32(CopyState cstate, int32 *val)
 {
 	uint32		buf;
 
-	if (CopyReadBinaryData(cstate, (char *) &buf, sizeof(buf)) != sizeof(buf))
+	/*
+	 * For parallel copy, avoid reading data to raw buf, read directly
+	 * from file, later the data will be read to parallel copy data
+	 * buffers.
+	 */
+	if (cstate->nworkers > 0)
 	{
-		*val = 0;				/* suppress compiler warning */
-		return false;
+		if (CopyGetData(cstate, &buf, sizeof(buf), sizeof(buf)) != sizeof(buf))
+		{
+			*val = 0;				/* suppress compiler warning */
+			return false;
+		}
+	}
+	else
+	{
+		if (CopyReadBinaryData(cstate, (char *) &buf, sizeof(buf)) != sizeof(buf))
+		{
+			*val = 0;				/* suppress compiler warning */
+			return false;
+		}
 	}
 	*val = (int32) pg_ntoh32(buf);
 	return true;
@@ -2575,7 +3104,15 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 			EndParallelCopy(pcxt);
 		}
 		else
+		{
+			/*
+			 * Reset nworkers to -1 here. This is useful in cases where user
+			 * specifies parallel workers, but, no worker is picked up, so go
+			 * back to non parallel mode value of nworkers.
+			 */
+			cstate->nworkers = -1;
 			*processed = CopyFrom(cstate); /* copy from file to database */
+		}
 
 		EndCopyFrom(cstate);
 	}
@@ -5040,7 +5577,7 @@ BeginCopyFrom(ParseState *pstate,
 	 * only in text mode.
 	 */
 	initStringInfo(&cstate->attribute_buf);
-	cstate->raw_buf = (IsParallelCopy()) ? NULL : (char *) palloc(RAW_BUF_SIZE + 1);
+	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
 	cstate->raw_buf_index = cstate->raw_buf_len = 0;
 	if (!cstate->binary)
 	{
@@ -5120,7 +5657,7 @@ BeginCopyFrom(ParseState *pstate,
 		int32		tmp;
 
 		/* Signature */
-		if (CopyReadBinaryData(cstate, readSig, 11) != 11 ||
+		if (CopyGetData(cstate, readSig, 11, 11) != 11 ||
 			memcmp(readSig, BinarySignature, 11) != 0)
 			ereport(ERROR,
 					(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
@@ -5148,7 +5685,7 @@ BeginCopyFrom(ParseState *pstate,
 		/* Skip extension header, if present */
 		while (tmp-- > 0)
 		{
-			if (CopyReadBinaryData(cstate, readSig, 1) != 1)
+			if (CopyGetData(cstate, readSig, 1, 1) != 1)
 				ereport(ERROR,
 						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
 						 errmsg("invalid COPY file header (wrong length)")));
@@ -5345,60 +5882,45 @@ NextCopyFrom(CopyState cstate, ExprContext *econtext,
 	else
 	{
 		/* binary */
-		int16		fld_count;
-		ListCell   *cur;
-
 		cstate->cur_lineno++;
+		cstate->max_fields = list_length(cstate->attnumlist);
 
-		if (!CopyGetInt16(cstate, &fld_count))
+		if (!IsParallelCopy())
 		{
-			/* EOF detected (end of file, or protocol-level EOF) */
-			return false;
-		}
+			int16		fld_count;
+			ListCell   *cur;
 
-		if (fld_count == -1)
-		{
-			/*
-			 * Received EOF marker.  In a V3-protocol copy, wait for the
-			 * protocol-level EOF, and complain if it doesn't come
-			 * immediately.  This ensures that we correctly handle CopyFail,
-			 * if client chooses to send that now.
-			 *
-			 * Note that we MUST NOT try to read more data in an old-protocol
-			 * copy, since there is no protocol-level EOF marker then.  We
-			 * could go either way for copy from file, but choose to throw
-			 * error if there's data after the EOF marker, for consistency
-			 * with the new-protocol case.
-			 */
-			char		dummy;
-
-			if (cstate->copy_dest != COPY_OLD_FE &&
-				CopyReadBinaryData(cstate, &dummy, 1) > 0)
-				ereport(ERROR,
-						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-						 errmsg("received copy data after EOF marker")));
-			return false;
-		}
+			if (!CopyGetInt16(cstate, &fld_count))
+			{
+				/* EOF detected (end of file, or protocol-level EOF) */
+				return false;
+			}
 
-		if (fld_count != attr_count)
-			ereport(ERROR,
-					(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-					 errmsg("row field count is %d, expected %d",
-							(int) fld_count, attr_count)));
+			CHECK_FIELD_COUNT;
 
-		foreach(cur, cstate->attnumlist)
+			foreach(cur, cstate->attnumlist)
+			{
+				int			attnum = lfirst_int(cur);
+				int			m = attnum - 1;
+				Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+
+				cstate->cur_attname = NameStr(att->attname);
+				values[m] = CopyReadBinaryAttribute(cstate,
+													&in_functions[m],
+													typioparams[m],
+													att->atttypmod,
+													&nulls[m]);
+				cstate->cur_attname = NULL;
+			}
+		}
+		else
 		{
-			int			attnum = lfirst_int(cur);
-			int			m = attnum - 1;
-			Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+			bool eof = false;
 
-			cstate->cur_attname = NameStr(att->attname);
-			values[m] = CopyReadBinaryAttribute(cstate,
-												&in_functions[m],
-												typioparams[m],
-												att->atttypmod,
-												&nulls[m]);
-			cstate->cur_attname = NULL;
+			eof = CopyReadBinaryTupleWorker(cstate, values, nulls);
+
+			if (eof)
+				return false;
 		}
 	}
 
@@ -6398,18 +6920,15 @@ CopyReadBinaryAttribute(CopyState cstate, FmgrInfo *flinfo,
 	Datum		result;
 
 	if (!CopyGetInt32(cstate, &fld_size))
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("unexpected EOF in COPY data")));
+		EOF_ERROR;
+
 	if (fld_size == -1)
 	{
 		*isnull = true;
 		return ReceiveFunctionCall(flinfo, NULL, typioparam, typmod);
 	}
-	if (fld_size < 0)
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("invalid field size")));
+
+	CHECK_FIELD_SIZE(fld_size);
 
 	/* reset attribute_buf to empty, and load raw data in it */
 	resetStringInfo(&cstate->attribute_buf);
@@ -6417,9 +6936,7 @@ CopyReadBinaryAttribute(CopyState cstate, FmgrInfo *flinfo,
 	enlargeStringInfo(&cstate->attribute_buf, fld_size);
 	if (CopyReadBinaryData(cstate, cstate->attribute_buf.data,
 						   fld_size) != fld_size)
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("unexpected EOF in COPY data")));
+		EOF_ERROR;
 
 	cstate->attribute_buf.len = fld_size;
 	cstate->attribute_buf.data[fld_size] = '\0';
-- 
1.8.3.1

#129Greg Nancarrow
gregn4422@gmail.com
In reply to: vignesh C (#128)
Re: Parallel copy

Hi Vignesh,

Some further comments:

(1) v3-0002-Framework-for-leader-worker-in-parallel-copy.patch

+/*
+ * Each worker will be allocated WORKER_CHUNK_COUNT of records from DSM data
+ * block to process to avoid lock contention. This value should be divisible by
+ * RINGSIZE, as wrap around cases is currently not handled while selecting the
+ * WORKER_CHUNK_COUNT by the worker.
+ */
+#define WORKER_CHUNK_COUNT 50

"This value should be divisible by RINGSIZE" is not a correct
statement (since obviously 50 is not divisible by 10000).
It should say something like "This value should evenly divide into
RINGSIZE", or "RINGSIZE should be a multiple of WORKER_CHUNK_COUNT".

(2) v3-0003-Allow-copy-from-command-to-process-data-from-file.patch

(i)

+                       /*
+                        * If the data is present in current block
lineInfo. line_size
+                        * will be updated. If the data is spread
across the blocks either

Somehow a space has been put between "lineinfo." and "line_size".
It should be: "If the data is present in current block
lineInfo.line_size will be updated"

(ii)

This is not possible because of pg_atomic_compare_exchange_u32, this
will succeed only for one of the workers whose line_state is
LINE_LEADER_POPULATED, for other workers it will fail. This is
explained in detail above ParallelCopyLineBoundary.

Yes, but prior to that call to pg_atomic_compare_exchange_u32(),
aren't you separately reading line_state and line_state, so that
between those reads, it may have transitioned from leader to another
worker, such that the read line state ("cur_line_state", being checked
in the if block) may not actually match what is now in the line_state
and/or the read line_size ("dataSize") doesn't actually correspond to
the read line state?

(sorry, still not 100% convinced that the synchronization and checks
are safe in all cases)

(3) v3-0006-Parallel-Copy-For-Binary-Format-Files.patch

raw_buf is not used in parallel copy, instead raw_buf will be pointing
to shared memory data blocks. This memory was allocated as part of
BeginCopyFrom, uptil this point we cannot be 100% sure as copy can be
performed sequentially like in case max_worker_processes is not
available, if it switches to sequential mode raw_buf will be used
while performing copy operation. At this place we can safely free this
memory that was allocated

So the following code (which checks raw_buf, which still points to
memory that has been pfreed) is still valid?

In the SetRawBufForLoad() function, which is called by CopyReadLineText():

cur_data_blk_ptr = (cstate->raw_buf) ?
&pcshared_info->data_blocks[cur_block_pos] : NULL;

The above code looks a bit dicey to me. I stepped over that line in
the debugger when I debugged an instance of Parallel Copy, so it
definitely gets executed.
It makes me wonder what other code could possibly be checking raw_buf
and using it in some way, when in fact what it points to has been
pfreed.

Are you able to add the following line of code, or will it (somehow)
break logic that you are relying on?

pfree(cstate->raw_buf);
cstate->raw_buf = NULL; <=== I suggest that this line is added

Regards,
Greg Nancarrow
Fujitsu Australia

#130vignesh C
vignesh21@gmail.com
In reply to: Greg Nancarrow (#129)
6 attachment(s)
Re: Parallel copy

Thanks Greg for reviewing the patch. Please find my thoughts for your comments.

On Mon, Aug 17, 2020 at 9:44 AM Greg Nancarrow <gregn4422@gmail.com> wrote:

Some further comments:

(1) v3-0002-Framework-for-leader-worker-in-parallel-copy.patch

+/*
+ * Each worker will be allocated WORKER_CHUNK_COUNT of records from DSM data
+ * block to process to avoid lock contention. This value should be divisible by
+ * RINGSIZE, as wrap around cases is currently not handled while selecting the
+ * WORKER_CHUNK_COUNT by the worker.
+ */
+#define WORKER_CHUNK_COUNT 50

"This value should be divisible by RINGSIZE" is not a correct
statement (since obviously 50 is not divisible by 10000).
It should say something like "This value should evenly divide into
RINGSIZE", or "RINGSIZE should be a multiple of WORKER_CHUNK_COUNT".

Fixed. Changed it to RINGSIZE should be a multiple of WORKER_CHUNK_COUNT.

(2) v3-0003-Allow-copy-from-command-to-process-data-from-file.patch

(i)

+                       /*
+                        * If the data is present in current block
lineInfo. line_size
+                        * will be updated. If the data is spread
across the blocks either

Somehow a space has been put between "lineinfo." and "line_size".
It should be: "If the data is present in current block
lineInfo.line_size will be updated"

Fixed, changed it to lineinfo->line_size.

(ii)

This is not possible because of pg_atomic_compare_exchange_u32, this
will succeed only for one of the workers whose line_state is
LINE_LEADER_POPULATED, for other workers it will fail. This is
explained in detail above ParallelCopyLineBoundary.

Yes, but prior to that call to pg_atomic_compare_exchange_u32(),
aren't you separately reading line_state and line_state, so that
between those reads, it may have transitioned from leader to another
worker, such that the read line state ("cur_line_state", being checked
in the if block) may not actually match what is now in the line_state
and/or the read line_size ("dataSize") doesn't actually correspond to
the read line state?

(sorry, still not 100% convinced that the synchronization and checks
are safe in all cases)

I think that you are describing about the problem could happen in the
following case:
when we read curr_line_state, the value was LINE_WORKER_PROCESSED or
LINE_WORKER_PROCESSING. Then in some cases if the leader is very fast
compared to the workers then the leader quickly populates one line and
sets the state to LINE_LEADER_POPULATED. State is changed to
LINE_LEADER_POPULATED when we are checking the currr_line_state.
I feel this will not be a problem because, Leader will populate & wait
till some RING element is available to populate. In the meantime
worker has seen that state is LINE_WORKER_PROCESSED or
LINE_WORKER_PROCESSING(previous state that it read), worker has
identified that this chunk was processed by some other worker, worker
will move and try to get the next available chunk & insert those
records. It will keep continuing till it gets the next chunk to
process. Eventually one of the workers will get this chunk and process
it.

(3) v3-0006-Parallel-Copy-For-Binary-Format-Files.patch

raw_buf is not used in parallel copy, instead raw_buf will be pointing
to shared memory data blocks. This memory was allocated as part of
BeginCopyFrom, uptil this point we cannot be 100% sure as copy can be
performed sequentially like in case max_worker_processes is not
available, if it switches to sequential mode raw_buf will be used
while performing copy operation. At this place we can safely free this
memory that was allocated

So the following code (which checks raw_buf, which still points to
memory that has been pfreed) is still valid?

In the SetRawBufForLoad() function, which is called by CopyReadLineText():

cur_data_blk_ptr = (cstate->raw_buf) ?
&pcshared_info->data_blocks[cur_block_pos] : NULL;

The above code looks a bit dicey to me. I stepped over that line in
the debugger when I debugged an instance of Parallel Copy, so it
definitely gets executed.
It makes me wonder what other code could possibly be checking raw_buf
and using it in some way, when in fact what it points to has been
pfreed.

Are you able to add the following line of code, or will it (somehow)
break logic that you are relying on?

pfree(cstate->raw_buf);
cstate->raw_buf = NULL; <=== I suggest that this line is added

You are right, I have debugged & verified it sets it to an invalid
block which is not expected. There are chances this would have caused
some corruption in some machines. The suggested fix is required, I
have fixed it. I have moved this change to
0003-Allow-copy-from-command-to-process-data-from-file.patch as
0006-Parallel-Copy-For-Binary-Format-Files is only for Binary format
parallel copy & that change is common change for parallel copy.

I have attached new set of patches with the fixes.
Thoughts?

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

Attachments:

v4-0001-Copy-code-readjustment-to-support-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=v4-0001-Copy-code-readjustment-to-support-parallel-copy.patchDownload
From 896cb1f96f0a2215a097fffce94b50b2872b2c81 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Sat, 1 Aug 2020 08:52:48 +0530
Subject: [PATCH v4 1/6] Copy code readjustment to support parallel copy.

This patch has the copy code slightly readjusted so that the common code is
separated to functions/macros, these functions/macros will be used by the
workers in the parallel copy code of the upcoming patches. EOL removal is moved
from CopyReadLine to CopyReadLineText, this change was required because in case
of parallel copy the record identification and record updation is done in
CopyReadLineText, before record information is updated in shared memory the new
line characters should be removed.
---
 src/backend/commands/copy.c | 361 ++++++++++++++++++++++++++------------------
 1 file changed, 218 insertions(+), 143 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index db7d24a..436e458 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -95,6 +95,9 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
+#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+#define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
+
 /*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
@@ -224,7 +227,6 @@ typedef struct CopyStateData
 	 * appropriate amounts of data from this buffer.  In both modes, we
 	 * guarantee that there is a \0 at raw_buf[raw_buf_len].
 	 */
-#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
@@ -354,6 +356,27 @@ if (1) \
 	goto not_end_of_copy; \
 } else ((void) 0)
 
+/*
+ * CLEAR_EOL_LINE - Wrapper for clearing EOL.
+ */
+#define CLEAR_EOL_LINE() \
+if (!result && !IsHeaderLine()) \
+	ClearEOLFromCopiedData(cstate, cstate->line_buf.data, \
+						   cstate->line_buf.len, \
+						   &cstate->line_buf.len) \
+
+/*
+ * INCREMENTPROCESSED - Increment the lines processed.
+ */
+#define INCREMENTPROCESSED(processed)  \
+processed++;
+
+/*
+ * RETURNPROCESSED - Get the lines processed.
+ */
+#define RETURNPROCESSED(processed) \
+return processed;
+
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
 
@@ -401,7 +424,11 @@ static bool CopyGetInt16(CopyState cstate, int16 *val);
 static bool CopyLoadRawBuf(CopyState cstate);
 static int	CopyReadBinaryData(CopyState cstate, char *dest, int nbytes);
 
-
+static void PopulateCommonCstateInfo(CopyState cstate, TupleDesc	tup_desc,
+									   List *attnamelist);
+static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
+								   int copy_line_pos, int *copy_line_size);
+static void ConvertToServerEncoding(CopyState cstate);
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
  * in past protocol redesigns.
@@ -801,14 +828,18 @@ CopyLoadRawBuf(CopyState cstate)
 {
 	int			nbytes = RAW_BUF_BYTES(cstate);
 	int			inbytes;
+	int         minread = 1;
 
 	/* Copy down the unprocessed data if any. */
 	if (nbytes > 0)
 		memmove(cstate->raw_buf, cstate->raw_buf + cstate->raw_buf_index,
 				nbytes);
 
+	if (cstate->copy_dest == COPY_NEW_FE)
+		minread = RAW_BUF_SIZE - nbytes;
+
 	inbytes = CopyGetData(cstate, cstate->raw_buf + nbytes,
-						  1, RAW_BUF_SIZE - nbytes);
+						  minread, RAW_BUF_SIZE - nbytes);
 	nbytes += inbytes;
 	cstate->raw_buf[nbytes] = '\0';
 	cstate->raw_buf_index = 0;
@@ -1514,7 +1545,6 @@ BeginCopy(ParseState *pstate,
 {
 	CopyState	cstate;
 	TupleDesc	tupDesc;
-	int			num_phys_attrs;
 	MemoryContext oldcontext;
 
 	/* Allocate workspace and zero all fields */
@@ -1680,6 +1710,24 @@ BeginCopy(ParseState *pstate,
 		tupDesc = cstate->queryDesc->tupDesc;
 	}
 
+	PopulateCommonCstateInfo(cstate, tupDesc, attnamelist);
+	cstate->copy_dest = COPY_FILE;	/* default */
+
+	MemoryContextSwitchTo(oldcontext);
+
+	return cstate;
+}
+
+/*
+ * PopulateCommonCstateInfo - Populates the common variables required for copy
+ * from operation. This is a helper function for BeginCopy function.
+ */
+static void
+PopulateCommonCstateInfo(CopyState cstate, TupleDesc	tupDesc,
+							List *attnamelist)
+{
+	int			num_phys_attrs;
+
 	/* Generate or convert list of attributes to process */
 	cstate->attnumlist = CopyGetAttnums(tupDesc, cstate->rel, attnamelist);
 
@@ -1799,12 +1847,6 @@ BeginCopy(ParseState *pstate,
 		 pg_database_encoding_max_length() > 1);
 	/* See Multibyte encoding comment above */
 	cstate->encoding_embeds_ascii = PG_ENCODING_IS_CLIENT_ONLY(cstate->file_encoding);
-
-	cstate->copy_dest = COPY_FILE;	/* default */
-
-	MemoryContextSwitchTo(oldcontext);
-
-	return cstate;
 }
 
 /*
@@ -2696,32 +2738,11 @@ CopyMultiInsertInfoStore(CopyMultiInsertInfo *miinfo, ResultRelInfo *rri,
 }
 
 /*
- * Copy FROM file to relation.
+ * Check if the relation specified in copy from is valid.
  */
-uint64
-CopyFrom(CopyState cstate)
+static void
+CheckTargetRelValidity(CopyState cstate)
 {
-	ResultRelInfo *resultRelInfo;
-	ResultRelInfo *target_resultRelInfo;
-	ResultRelInfo *prevResultRelInfo = NULL;
-	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
-	ModifyTableState *mtstate;
-	ExprContext *econtext;
-	TupleTableSlot *singleslot = NULL;
-	MemoryContext oldcontext = CurrentMemoryContext;
-
-	PartitionTupleRouting *proute = NULL;
-	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
-	int			ti_options = 0; /* start with default options for insert */
-	BulkInsertState bistate = NULL;
-	CopyInsertMethod insertMethod;
-	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
-	uint64		processed = 0;
-	bool		has_before_insert_row_trig;
-	bool		has_instead_insert_row_trig;
-	bool		leafpart_use_multi_insert = false;
-
 	Assert(cstate->rel);
 
 	/*
@@ -2758,27 +2779,6 @@ CopyFrom(CopyState cstate)
 							RelationGetRelationName(cstate->rel))));
 	}
 
-	/*
-	 * If the target file is new-in-transaction, we assume that checking FSM
-	 * for free space is a waste of time.  This could possibly be wrong, but
-	 * it's unlikely.
-	 */
-	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
-		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
-		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
-		ti_options |= TABLE_INSERT_SKIP_FSM;
-
-	/*
-	 * Optimize if new relfilenode was created in this subxact or one of its
-	 * committed children and we won't see those rows later as part of an
-	 * earlier scan or command. The subxact test ensures that if this subxact
-	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
-	 * that the stronger test of exactly which subtransaction created it is
-	 * crucial for correctness of this optimization. The test for an earlier
-	 * scan or command tolerates false negatives. FREEZE causes other sessions
-	 * to see rows they would not see under MVCC, and a false negative merely
-	 * spreads that anomaly to the current session.
-	 */
 	if (cstate->freeze)
 	{
 		/*
@@ -2816,9 +2816,61 @@ CopyFrom(CopyState cstate)
 			ereport(ERROR,
 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 					 errmsg("cannot perform COPY FREEZE because the table was not created or truncated in the current subtransaction")));
+	}
+}
+
+/*
+ * Copy FROM file to relation.
+ */
+uint64
+CopyFrom(CopyState cstate)
+{
+	ResultRelInfo *resultRelInfo;
+	ResultRelInfo *target_resultRelInfo;
+	ResultRelInfo *prevResultRelInfo = NULL;
+	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
+	ModifyTableState *mtstate;
+	ExprContext *econtext;
+	TupleTableSlot *singleslot = NULL;
+	MemoryContext oldcontext = CurrentMemoryContext;
+
+	PartitionTupleRouting *proute = NULL;
+	ErrorContextCallback errcallback;
+	CommandId	mycid = GetCurrentCommandId(true);
+	int			ti_options = 0; /* start with default options for insert */
+	BulkInsertState bistate = NULL;
+	CopyInsertMethod insertMethod;
+	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
+	uint64		processed = 0;
+	bool		has_before_insert_row_trig;
+	bool		has_instead_insert_row_trig;
+	bool		leafpart_use_multi_insert = false;
+
+	CheckTargetRelValidity(cstate);
 
+	/*
+	 * If the target file is new-in-transaction, we assume that checking FSM
+	 * for free space is a waste of time.  This could possibly be wrong, but
+	 * it's unlikely.
+	 */
+	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
+		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
+		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
+		ti_options |= TABLE_INSERT_SKIP_FSM;
+
+	/*
+	 * Optimize if new relfilenode was created in this subxact or one of its
+	 * committed children and we won't see those rows later as part of an
+	 * earlier scan or command. The subxact test ensures that if this subxact
+	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
+	 * that the stronger test of exactly which subtransaction created it is
+	 * crucial for correctness of this optimization. The test for an earlier
+	 * scan or command tolerates false negatives. FREEZE causes other sessions
+	 * to see rows they would not see under MVCC, and a false negative merely
+	 * spreads that anomaly to the current session.
+	 */
+	if (cstate->freeze)
 		ti_options |= TABLE_INSERT_FROZEN;
-	}
 
 	/*
 	 * We need a ResultRelInfo so we can use the regular executor's
@@ -3311,7 +3363,7 @@ CopyFrom(CopyState cstate)
 			 * or FDW; this is the same definition used by nodeModifyTable.c
 			 * for counting tuples inserted by an INSERT command.
 			 */
-			processed++;
+			INCREMENTPROCESSED(processed)
 		}
 	}
 
@@ -3366,30 +3418,15 @@ CopyFrom(CopyState cstate)
 
 	FreeExecutorState(estate);
 
-	return processed;
+	RETURNPROCESSED(processed)
 }
 
 /*
- * Setup to read tuples from a file for COPY FROM.
- *
- * 'rel': Used as a template for the tuples
- * 'filename': Name of server-local file to read
- * 'attnamelist': List of char *, columns to include. NIL selects all cols.
- * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
- *
- * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ * PopulateCstateCatalogInfo - populate the catalog information.
  */
-CopyState
-BeginCopyFrom(ParseState *pstate,
-			  Relation rel,
-			  const char *filename,
-			  bool is_program,
-			  copy_data_source_cb data_source_cb,
-			  List *attnamelist,
-			  List *options)
+static void
+PopulateCstateCatalogInfo(CopyState cstate)
 {
-	CopyState	cstate;
-	bool		pipe = (filename == NULL);
 	TupleDesc	tupDesc;
 	AttrNumber	num_phys_attrs,
 				num_defaults;
@@ -3399,38 +3436,8 @@ BeginCopyFrom(ParseState *pstate,
 	Oid			in_func_oid;
 	int		   *defmap;
 	ExprState **defexprs;
-	MemoryContext oldcontext;
 	bool		volatile_defexprs;
 
-	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
-	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
-
-	/* Initialize state variables */
-	cstate->reached_eof = false;
-	cstate->eol_type = EOL_UNKNOWN;
-	cstate->cur_relname = RelationGetRelationName(cstate->rel);
-	cstate->cur_lineno = 0;
-	cstate->cur_attname = NULL;
-	cstate->cur_attval = NULL;
-
-	/*
-	 * Set up variables to avoid per-attribute overhead.  attribute_buf and
-	 * raw_buf are used in both text and binary modes, but we use line_buf
-	 * only in text mode.
-	 */
-	initStringInfo(&cstate->attribute_buf);
-	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
-	cstate->raw_buf_index = cstate->raw_buf_len = 0;
-	if (!cstate->binary)
-	{
-		initStringInfo(&cstate->line_buf);
-		cstate->line_buf_converted = false;
-	}
-
-	/* Assign range table, we'll need it in CopyFrom. */
-	if (pstate)
-		cstate->range_table = pstate->p_rtable;
-
 	tupDesc = RelationGetDescr(cstate->rel);
 	num_phys_attrs = tupDesc->natts;
 	num_defaults = 0;
@@ -3508,6 +3515,61 @@ BeginCopyFrom(ParseState *pstate,
 	cstate->defexprs = defexprs;
 	cstate->volatile_defexprs = volatile_defexprs;
 	cstate->num_defaults = num_defaults;
+}
+
+/*
+ * Setup to read tuples from a file for COPY FROM.
+ *
+ * 'rel': Used as a template for the tuples
+ * 'filename': Name of server-local file to read
+ * 'attnamelist': List of char *, columns to include. NIL selects all cols.
+ * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
+ *
+ * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ */
+CopyState
+BeginCopyFrom(ParseState *pstate,
+			  Relation rel,
+			  const char *filename,
+			  bool is_program,
+			  copy_data_source_cb data_source_cb,
+			  List *attnamelist,
+			  List *options)
+{
+	CopyState	cstate;
+	bool		pipe = (filename == NULL);
+	MemoryContext oldcontext;
+
+	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	/* Initialize state variables */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/*
+	 * Set up variables to avoid per-attribute overhead.  attribute_buf is
+	 * used in both text and binary modes, but we use line_buf and raw_buf
+	 * only in text mode.
+	 */
+	initStringInfo(&cstate->attribute_buf);
+	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+	if (!cstate->binary)
+	{
+		initStringInfo(&cstate->line_buf);
+		cstate->line_buf_converted = false;
+	}
+
+	/* Assign range table, we'll need it in CopyFrom. */
+	if (pstate)
+		cstate->range_table = pstate->p_rtable;
+
+	PopulateCstateCatalogInfo(cstate);
 	cstate->is_program = is_program;
 
 	if (data_source_cb)
@@ -3917,45 +3979,60 @@ CopyReadLine(CopyState cstate)
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
-	else
-	{
-		/*
-		 * If we didn't hit EOF, then we must have transferred the EOL marker
-		 * to line_buf along with the data.  Get rid of it.
-		 */
-		switch (cstate->eol_type)
-		{
-			case EOL_NL:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CR:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\r');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CRNL:
-				Assert(cstate->line_buf.len >= 2);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 2] == '\r');
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len -= 2;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_UNKNOWN:
-				/* shouldn't get here */
-				Assert(false);
-				break;
-		}
-	}
 
+	ConvertToServerEncoding(cstate);
+	return result;
+}
+
+/*
+ * ClearEOLFromCopiedData - Clear EOL from the copied data.
+ */
+static void
+ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
+					   int copy_line_pos, int *copy_line_size)
+{
+	/*
+	 * If we didn't hit EOF, then we must have transferred the EOL marker
+	 * to line_buf along with the data.  Get rid of it.
+	 */
+   switch (cstate->eol_type)
+   {
+	   case EOL_NL:
+		   Assert(*copy_line_size >= 1);
+		   Assert(copy_line_data[copy_line_pos - 1] == '\n');
+		   copy_line_data[copy_line_pos - 1] = '\0';
+		   (*copy_line_size)--;
+		   break;
+	   case EOL_CR:
+		   Assert(*copy_line_size >= 1);
+		   Assert(copy_line_data[copy_line_pos - 1] == '\r');
+		   copy_line_data[copy_line_pos - 1] = '\0';
+		   (*copy_line_size)--;
+		   break;
+	   case EOL_CRNL:
+		   Assert(*copy_line_size >= 2);
+		   Assert(copy_line_data[copy_line_pos - 2] == '\r');
+		   Assert(copy_line_data[copy_line_pos - 1] == '\n');
+		   copy_line_data[copy_line_pos - 2] = '\0';
+		   *copy_line_size -= 2;
+		   break;
+	   case EOL_UNKNOWN:
+		   /* shouldn't get here */
+		   Assert(false);
+		   break;
+   }
+}
+
+/*
+ * ConvertToServerEncoding - convert contents to server encoding.
+ */
+static void
+ConvertToServerEncoding(CopyState cstate)
+{
 	/* Done reading the line.  Convert it to server encoding. */
 	if (cstate->need_transcoding)
 	{
 		char	   *cvt;
-
 		cvt = pg_any_to_server(cstate->line_buf.data,
 							   cstate->line_buf.len,
 							   cstate->file_encoding);
@@ -3967,11 +4044,8 @@ CopyReadLine(CopyState cstate)
 			pfree(cvt);
 		}
 	}
-
 	/* Now it's safe to use the buffer in error messages */
 	cstate->line_buf_converted = true;
-
-	return result;
 }
 
 /*
@@ -4334,6 +4408,7 @@ not_end_of_copy:
 	 * Transfer any still-uncopied data to line_buf.
 	 */
 	REFILL_LINEBUF;
+	CLEAR_EOL_LINE();
 
 	return result;
 }
-- 
1.8.3.1

v4-0002-Framework-for-leader-worker-in-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=v4-0002-Framework-for-leader-worker-in-parallel-copy.patchDownload
From eb97b28ecaacfbd248d5662f15bd5e331821a03a Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Sat, 1 Aug 2020 08:56:39 +0530
Subject: [PATCH v4 2/6] Framework for leader/worker in parallel copy

This patch has the framework for data structures in parallel copy, leader
initialization, worker initialization, shared memory updation, starting workers,
wait for workers and workers exiting.
---
 src/backend/access/transam/parallel.c |   4 +
 src/backend/commands/copy.c           | 743 +++++++++++++++++++++++++++++++++-
 src/include/commands/copy.h           |   2 +
 src/tools/pgindent/typedefs.list      |   7 +
 4 files changed, 752 insertions(+), 4 deletions(-)

diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index b042696..a3cff4b 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -25,6 +25,7 @@
 #include "catalog/pg_enum.h"
 #include "catalog/storage.h"
 #include "commands/async.h"
+#include "commands/copy.h"
 #include "executor/execParallel.h"
 #include "libpq/libpq.h"
 #include "libpq/pqformat.h"
@@ -145,6 +146,9 @@ static const struct
 	},
 	{
 		"parallel_vacuum_main", parallel_vacuum_main
+	},
+	{
+		"ParallelCopyMain", ParallelCopyMain
 	}
 };
 
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 436e458..704bbd3 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -96,9 +96,181 @@ typedef enum CopyInsertMethod
 } CopyInsertMethod;
 
 #define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+
+/*
+ * The macros DATA_BLOCK_SIZE, RINGSIZE & MAX_BLOCKS_COUNT stores the records
+ * read from the file that need to be inserted into the relation. These values
+ * help in handover of multiple records with significant size of data to be
+ * processed by each of the workers to make sure there is no context switch & the
+ * work is fairly distributed among the workers. This number showed best
+ * results in the performance tests.
+ */
+#define DATA_BLOCK_SIZE RAW_BUF_SIZE
+
+/* It can hold 1000 blocks of 64K data in DSM to be processed by the worker. */
+#define MAX_BLOCKS_COUNT 1000
+
+/* It can hold upto 10000 record information for worker to process. RINGSIZE
+ * should be a multiple of WORKER_CHUNK_COUNT, as wrap around cases is currently
+ * not handled while selecting the WORKER_CHUNK_COUNT by the worker. */
+#define RINGSIZE (10 * 1000)
+
+/*
+ * Each worker will be allocated WORKER_CHUNK_COUNT of records from DSM data
+ * block to process to avoid lock contention. Read RINGSIZE comments before
+ * changing this value.
+ */
+#define WORKER_CHUNK_COUNT 50
+
+#define	IsParallelCopy()		(cstate->is_parallel)
+#define IsLeader()				(cstate->pcdata->is_leader)
 #define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
 
 /*
+ * Copy data block information.
+ * ParallelCopyDataBlock's will be created in DSM. Data read from file will be
+ * copied in these DSM data blocks. The leader process identifies the records
+ * and the record information will be shared to the workers. The workers will
+ * insert the records into the table. There can be one or more number of records
+ * in each of the data block based on the record size.
+ */
+typedef struct ParallelCopyDataBlock
+{
+	/* The number of unprocessed lines in the current block. */
+	pg_atomic_uint32 unprocessed_line_parts;
+
+	/*
+	 * If the current line data is continued into another block, following_block
+	 * will have the position where the remaining data need to be read.
+	 */
+	uint32	following_block;
+
+	/*
+	 * This flag will be set, when the leader finds out this block can be read
+	 * safely by the worker. This helps the worker to start processing the line
+	 * early where the line will be spread across many blocks and the worker
+	 * need not wait for the complete line to be processed.
+	 */
+	bool   curr_blk_completed;
+	char   data[DATA_BLOCK_SIZE]; /* data read from file */
+	uint8  skip_bytes;
+}ParallelCopyDataBlock;
+
+/*
+ * Individual line information.
+ * ParallelCopyLineBoundary is common data structure between leader & worker,
+ * Leader process will be populating data block, data block offset & the size of
+ * the record in DSM for the workers to copy the data into the relation.
+ * This is protected by the following sequence in the leader & worker. If they
+ * don't follow this order the worker might process wrong line_size and leader
+ * might populate the information which worker has not yet processed or in the
+ * process of processing.
+ * Leader should operate in the following order:
+ * 1) check if line_size is -1, if not wait, it means worker is still
+ * processing.
+ * 2) set line_state to LINE_LEADER_POPULATING.
+ * 3) update first_block, start_offset & cur_lineno in any order.
+ * 4) update line_size.
+ * 5) update line_state to LINE_LEADER_POPULATED.
+ * Worker should operate in the following order:
+ * 1) check line_state is LINE_LEADER_POPULATED, if not it means leader is still
+ * populating the data.
+ * 2) read line_size.
+ * 3) only one worker should choose one line for processing, this is handled by
+ *    using pg_atomic_compare_exchange_u32, worker will change the state to
+ *    LINE_WORKER_PROCESSING only if line_state is LINE_LEADER_POPULATED.
+ * 4) read first_block, start_offset & cur_lineno in any order.
+ * 5) process line_size data.
+ * 6) update line_size to -1.
+ */
+typedef struct ParallelCopyLineBoundary
+{
+	/* Position of the first block in data_blocks array. */
+	uint32				first_block;
+	uint32				start_offset;   /* start offset of the line */
+
+	/*
+	 * Size of the current line -1 means line is yet to be filled completely,
+	 * 0 means empty line, >0 means line filled with line size data.
+	 */
+	pg_atomic_uint32	line_size;
+	pg_atomic_uint32	line_state;		/* line state */
+	uint64				cur_lineno;		/* line number for error messages */
+}ParallelCopyLineBoundary;
+
+/*
+ * Circular queue used to store the line information.
+ */
+typedef struct ParallelCopyLineBoundaries
+{
+	/* Position for the leader to populate a line. */
+	uint32			pos;
+
+	/* Data read from the file/stdin by the leader process. */
+	ParallelCopyLineBoundary	ring[RINGSIZE];
+}ParallelCopyLineBoundaries;
+
+/*
+ * Shared information among parallel copy workers. This will be allocated in the
+ * DSM segment.
+ */
+typedef struct ParallelCopyShmInfo
+{
+	bool					is_read_in_progress; /* file read status */
+
+	/*
+	 * Actual lines inserted by worker, will not be same as
+	 * total_worker_processed if where condition is specified along with copy.
+	 * This will be the actual records inserted into the relation.
+	 */
+	pg_atomic_uint64			processed;
+
+	/*
+	 * The number of records currently processed by the worker, this will also
+	 * include the number of records that was filtered because of where clause.
+	 */
+	pg_atomic_uint64			total_worker_processed;
+	uint64						populated; /* lines populated by leader */
+	uint32						cur_block_pos; /* current data block */
+	ParallelCopyDataBlock		data_blocks[MAX_BLOCKS_COUNT]; /* data block array */
+	FullTransactionId			full_transaction_id; /* xid for copy from statement */
+	CommandId					mycid;	/* command id */
+	ParallelCopyLineBoundaries	line_boundaries; /* line array */
+} ParallelCopyShmInfo;
+
+/*
+ * Parallel copy line buffer information.
+ */
+typedef struct ParallelCopyLineBuf
+{
+	StringInfoData		line_buf;
+	uint64				cur_lineno;	/* line number for error messages */
+}ParallelCopyLineBuf;
+
+/*
+ * Parallel copy data information.
+ */
+typedef struct ParallelCopyData
+{
+	Oid					relid;				/* relation id of the table */
+	ParallelCopyShmInfo	*pcshared_info;		/* common info in shared memory */
+	bool				is_leader;
+
+	/* line position which worker is processing */
+	uint32				worker_processed_pos;
+
+	/*
+	 * Local line_buf array, workers will copy it here and release the lines
+	 * for the leader to continue.
+	 */
+	ParallelCopyLineBuf	worker_line_buf[WORKER_CHUNK_COUNT];
+	uint32				worker_line_buf_count; /* Number of lines */
+
+	/* Current position in worker_line_buf */
+	uint32				worker_line_buf_pos;
+}ParallelCopyData;
+
+/*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
  * even though some fields are used in only some cases.
@@ -230,10 +402,38 @@ typedef struct CopyStateData
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
+	int			nworkers;
+	bool		is_parallel;
+	ParallelCopyData *pcdata;
 	/* Shorthand for number of unconsumed bytes available in raw_buf */
 #define RAW_BUF_BYTES(cstate) ((cstate)->raw_buf_len - (cstate)->raw_buf_index)
 } CopyStateData;
 
+/*
+ * This structure helps in storing the common data from CopyStateData that are
+ * required by the workers. This information will then be allocated and stored
+ * into the DSM for the worker to retrieve and copy it to CopyStateData.
+ */
+typedef struct SerializedParallelCopyState
+{
+	/* low-level state data */
+	CopyDest            copy_dest;		/* type of copy source/destination */
+	int                 file_encoding;	/* file or remote side's character encoding */
+	bool                need_transcoding;	/* file encoding diff from server? */
+	bool                encoding_embeds_ascii;	/* ASCII can be non-first byte? */
+
+	/* parameters from the COPY command */
+	bool                csv_mode;		/* Comma Separated Value format? */
+	bool                header_line;	/* CSV header line? */
+	int                 null_print_len; /* length of same */
+	bool                force_quote_all;	/* FORCE_QUOTE *? */
+	bool                convert_selectively;	/* do selective binary conversion? */
+
+	/* Working state for COPY FROM */
+	AttrNumber          num_defaults;
+	Oid                 relid;
+}SerializedParallelCopyState;
+
 /* DestReceiver for COPY (query) TO */
 typedef struct
 {
@@ -263,6 +463,22 @@ typedef struct
 /* Trim the list of buffers back down to this number after flushing */
 #define MAX_PARTITION_BUFFERS	32
 
+/* DSM keys for parallel copy.  */
+#define PARALLEL_COPY_KEY_SHARED_INFO				1
+#define PARALLEL_COPY_KEY_CSTATE					2
+#define PARALLEL_COPY_KEY_NULL_PRINT				3
+#define PARALLEL_COPY_KEY_DELIM						4
+#define PARALLEL_COPY_KEY_QUOTE						5
+#define PARALLEL_COPY_KEY_ESCAPE					6
+#define PARALLEL_COPY_KEY_ATTNAME_LIST				7
+#define PARALLEL_COPY_KEY_NOT_NULL_LIST				8
+#define PARALLEL_COPY_KEY_NULL_LIST					9
+#define PARALLEL_COPY_KEY_CONVERT_LIST				10
+#define PARALLEL_COPY_KEY_WHERE_CLAUSE_STR			11
+#define PARALLEL_COPY_KEY_RANGE_TABLE				12
+#define PARALLEL_COPY_WAL_USAGE						13
+#define PARALLEL_COPY_BUFFER_USAGE					14
+
 /* Stores multi-insert data related to a single relation in CopyFrom. */
 typedef struct CopyMultiInsertBuffer
 {
@@ -424,11 +640,477 @@ static bool CopyGetInt16(CopyState cstate, int16 *val);
 static bool CopyLoadRawBuf(CopyState cstate);
 static int	CopyReadBinaryData(CopyState cstate, char *dest, int nbytes);
 
+static pg_attribute_always_inline void EndParallelCopy(ParallelContext *pcxt);
 static void PopulateCommonCstateInfo(CopyState cstate, TupleDesc	tup_desc,
-									   List *attnamelist);
+									 List *attnamelist);
 static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
 								   int copy_line_pos, int *copy_line_size);
 static void ConvertToServerEncoding(CopyState cstate);
+
+/*
+ * SerializeParallelCopyState - Copy shared_cstate using cstate information.
+ */
+static pg_attribute_always_inline void
+SerializeParallelCopyState(CopyState cstate, SerializedParallelCopyState *shared_cstate)
+{
+	shared_cstate->copy_dest = cstate->copy_dest;
+	shared_cstate->file_encoding = cstate->file_encoding;
+	shared_cstate->need_transcoding = cstate->need_transcoding;
+	shared_cstate->encoding_embeds_ascii = cstate->encoding_embeds_ascii;
+	shared_cstate->csv_mode = cstate->csv_mode;
+	shared_cstate->header_line = cstate->header_line;
+	shared_cstate->null_print_len = cstate->null_print_len;
+	shared_cstate->force_quote_all = cstate->force_quote_all;
+	shared_cstate->convert_selectively = cstate->convert_selectively;
+	shared_cstate->num_defaults = cstate->num_defaults;
+	shared_cstate->relid = cstate->pcdata->relid;
+}
+
+/*
+ * RestoreString - Retrieve the string from shared memory.
+ */
+static void
+RestoreString(shm_toc *toc, int sharedkey, char **copystr)
+{
+	char *shared_str_val = (char *)shm_toc_lookup(toc, sharedkey, true);
+	if (shared_str_val)
+		*copystr = pstrdup(shared_str_val);
+}
+
+/*
+ * EstimateLineKeysStr - Estimate the size required in shared memory for the
+ * input string.
+ */
+static void
+EstimateLineKeysStr(ParallelContext *pcxt, char *inputstr)
+{
+	if (inputstr)
+	{
+		shm_toc_estimate_chunk(&pcxt->estimator, strlen(inputstr) + 1);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+}
+
+/*
+ * SerializeString - Insert a string into shared memory.
+ */
+static void
+SerializeString(ParallelContext *pcxt, int key, char *inputstr)
+{
+	if (inputstr)
+	{
+		char *shmptr = (char *)shm_toc_allocate(pcxt->toc,
+												strlen(inputstr) + 1);
+		strcpy(shmptr, inputstr);
+		shm_toc_insert(pcxt->toc, key, shmptr);
+	}
+}
+
+/*
+ * PopulateParallelCopyShmInfo - set ParallelCopyShmInfo.
+ */
+static void
+PopulateParallelCopyShmInfo(ParallelCopyShmInfo *shared_info_ptr,
+							FullTransactionId full_transaction_id)
+{
+	uint32 count;
+
+	MemSet(shared_info_ptr, 0, sizeof(ParallelCopyShmInfo));
+	shared_info_ptr->is_read_in_progress = true;
+	shared_info_ptr->cur_block_pos = -1;
+	shared_info_ptr->full_transaction_id = full_transaction_id;
+	shared_info_ptr->mycid = GetCurrentCommandId(true);
+	for (count = 0; count < RINGSIZE; count++)
+	{
+		ParallelCopyLineBoundary *lineInfo = &shared_info_ptr->line_boundaries.ring[count];
+		pg_atomic_init_u32(&(lineInfo->line_size), -1);
+	}
+}
+
+/*
+ * BeginParallelCopy - start parallel copy tasks.
+ *
+ * Get the number of workers required to perform the parallel copy. The data
+ * structures that are required by the parallel workers will be initialized, the
+ * size required in DSM will be calculated and the necessary keys will be loaded
+ * in the DSM. The specified number of workers will then be launched.
+ */
+static ParallelContext*
+BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
+{
+	ParallelContext *pcxt;
+	ParallelCopyShmInfo *shared_info_ptr;
+	SerializedParallelCopyState *shared_cstate;
+	FullTransactionId full_transaction_id;
+	Size est_cstateshared;
+	char *whereClauseStr = NULL;
+	char *rangeTableStr = NULL;
+	char *attnameListStr = NULL;
+	char *notnullListStr = NULL;
+	char *nullListStr = NULL;
+	char *convertListStr = NULL;
+	int  parallel_workers = 0;
+	WalUsage   *walusage;
+	BufferUsage *bufferusage;
+	ParallelCopyData *pcdata;
+	MemoryContext oldcontext;
+
+	parallel_workers = Min(nworkers, max_worker_processes);
+
+	/* Can't perform copy in parallel */
+	if (parallel_workers <= 0)
+		return NULL;
+
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	MemoryContextSwitchTo(oldcontext);
+	cstate->pcdata = pcdata;
+
+	EnterParallelMode();
+	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
+								 parallel_workers);
+	Assert(pcxt->nworkers > 0);
+
+	/*
+	 * Estimate size for shared information for PARALLEL_COPY_KEY_SHARED_INFO
+	 */
+	shm_toc_estimate_chunk(&pcxt->estimator, sizeof(ParallelCopyShmInfo));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_CSTATE */
+	est_cstateshared = 	MAXALIGN(sizeof(SerializedParallelCopyState));
+	shm_toc_estimate_chunk(&pcxt->estimator, est_cstateshared);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	EstimateLineKeysStr(pcxt, cstate->null_print);
+	EstimateLineKeysStr(pcxt, cstate->null_print_client);
+	EstimateLineKeysStr(pcxt, cstate->delim);
+	EstimateLineKeysStr(pcxt, cstate->quote);
+	EstimateLineKeysStr(pcxt, cstate->escape);
+
+	if (cstate->whereClause != NULL)
+	{
+		whereClauseStr = nodeToString(cstate->whereClause);
+		EstimateLineKeysStr(pcxt, whereClauseStr);
+	}
+
+	if (cstate->range_table != NULL)
+	{
+		rangeTableStr = nodeToString(cstate->range_table);
+		EstimateLineKeysStr(pcxt, rangeTableStr);
+	}
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_XID. */
+	shm_toc_estimate_chunk(&pcxt->estimator, sizeof(FullTransactionId));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_ATTNAME_LIST.
+	 */
+	if (attnamelist != NIL)
+	{
+		attnameListStr = nodeToString(attnamelist);
+		EstimateLineKeysStr(pcxt, attnameListStr);
+	}
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_NOT_NULL_LIST.
+	 */
+	if (cstate->force_notnull != NIL)
+	{
+		notnullListStr = nodeToString(cstate->force_notnull);
+		EstimateLineKeysStr(pcxt, notnullListStr);
+	}
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_NULL_LIST.
+	 */
+	if (cstate->force_null != NIL)
+	{
+		nullListStr = nodeToString(cstate->force_null);
+		EstimateLineKeysStr(pcxt, nullListStr);
+	}
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_CONVERT_LIST.
+	 */
+	if (cstate->convert_select != NIL)
+	{
+		convertListStr = nodeToString(cstate->convert_select);
+		EstimateLineKeysStr(pcxt, convertListStr);
+	}
+
+	/*
+	 * Estimate space for WalUsage and BufferUsage -- PARALLEL_COPY_WAL_USAGE
+	 * and PARALLEL_COPY_BUFFER_USAGE.
+	 */
+	shm_toc_estimate_chunk(&pcxt->estimator,
+						   mul_size(sizeof(WalUsage), pcxt->nworkers));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+	shm_toc_estimate_chunk(&pcxt->estimator,
+						   mul_size(sizeof(BufferUsage), pcxt->nworkers));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	InitializeParallelDSM(pcxt);
+
+	/* If no DSM segment was available, back out (do serial copy) */
+	if (pcxt->seg == NULL)
+	{
+		EndParallelCopy(pcxt);
+		return NULL;
+	}
+
+	/* Allocate shared memory for PARALLEL_COPY_KEY_SHARED_INFO */
+	shared_info_ptr = (ParallelCopyShmInfo *) shm_toc_allocate(pcxt->toc, sizeof(ParallelCopyShmInfo));
+	PopulateParallelCopyShmInfo(shared_info_ptr, full_transaction_id);
+
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_SHARED_INFO, shared_info_ptr);
+	pcdata->pcshared_info = shared_info_ptr;
+	pcdata->relid = relid;
+
+	/* Store shared build state, for which we reserved space. */
+	shared_cstate = (SerializedParallelCopyState *)shm_toc_allocate(pcxt->toc, est_cstateshared);
+
+	/* copy cstate variables. */
+	SerializeParallelCopyState(cstate, shared_cstate);
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_CSTATE, shared_cstate);
+
+	SerializeString(pcxt, PARALLEL_COPY_KEY_NULL_PRINT, cstate->null_print);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_DELIM, cstate->delim);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_QUOTE, cstate->quote);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_ESCAPE, cstate->escape);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_ATTNAME_LIST, attnameListStr);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_NOT_NULL_LIST, notnullListStr);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_NULL_LIST, nullListStr);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_CONVERT_LIST, convertListStr);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_WHERE_CLAUSE_STR, whereClauseStr);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_RANGE_TABLE, rangeTableStr);
+
+	/*
+	 * Allocate space for each worker's WalUsage and BufferUsage; no need to
+	 * initialize.
+	 */
+	walusage = shm_toc_allocate(pcxt->toc,
+								mul_size(sizeof(WalUsage), pcxt->nworkers));
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_WAL_USAGE, walusage);
+	bufferusage = shm_toc_allocate(pcxt->toc,
+								   mul_size(sizeof(BufferUsage), pcxt->nworkers));
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_BUFFER_USAGE, bufferusage);
+
+	LaunchParallelWorkers(pcxt);
+	if (pcxt->nworkers_launched == 0)
+	{
+		EndParallelCopy(pcxt);
+		return NULL;
+	}
+
+	/*
+	 * Caller needs to wait for all launched workers when we return.  Make sure
+	 * that the failure-to-start case will not hang forever.
+	 */
+	WaitForParallelWorkersToAttach(pcxt);
+
+	pcdata->is_leader = true;
+	cstate->is_parallel = true;
+	return pcxt;
+}
+
+/*
+ * EndParallelCopy - end the parallel copy tasks.
+ */
+static pg_attribute_always_inline void
+EndParallelCopy(ParallelContext *pcxt)
+{
+	Assert(!IsParallelWorker());
+
+	DestroyParallelContext(pcxt);
+	ExitParallelMode();
+}
+
+/*
+ * InitializeParallelCopyInfo - Initialize parallel worker.
+ */
+static void
+InitializeParallelCopyInfo(SerializedParallelCopyState *shared_cstate,
+		CopyState cstate, List *attnamelist)
+{
+	uint32		count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	cstate->copy_dest = shared_cstate->copy_dest;
+	cstate->file_encoding = shared_cstate->file_encoding;
+	cstate->need_transcoding = shared_cstate->need_transcoding;
+	cstate->encoding_embeds_ascii = shared_cstate->encoding_embeds_ascii;
+	cstate->csv_mode = shared_cstate->csv_mode;
+	cstate->header_line = shared_cstate->header_line;
+	cstate->null_print_len = shared_cstate->null_print_len;
+	cstate->force_quote_all = shared_cstate->force_quote_all;
+	cstate->convert_selectively = shared_cstate->convert_selectively;
+	cstate->num_defaults = shared_cstate->num_defaults;
+	pcdata->relid = shared_cstate->relid;
+
+	PopulateCommonCstateInfo(cstate, tup_desc, attnamelist);
+
+	/* Initialize state variables. */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/* Set up variables to avoid per-attribute overhead. */
+	initStringInfo(&cstate->attribute_buf);
+
+	initStringInfo(&cstate->line_buf);
+	for (count = 0; count < WORKER_CHUNK_COUNT; count++)
+		initStringInfo(&pcdata->worker_line_buf[count].line_buf);
+
+	cstate->line_buf_converted = false;
+	cstate->raw_buf = NULL;
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+}
+
+/*
+ * ParallelCopyMain - parallel copy worker's code.
+ *
+ * Where clause handling, convert tuple to columns, add default null values for
+ * the missing columns that are not present in that record. Find the partition
+ * if it is partitioned table, invoke before row insert Triggers, handle
+ * constraints and insert the tuples.
+ */
+void
+ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
+{
+	CopyState cstate;
+	ParallelCopyData *pcdata;
+	ParallelCopyShmInfo *pcshared_info;
+	SerializedParallelCopyState *shared_cstate;
+	Relation	rel = NULL;
+	MemoryContext oldcontext;
+	List *attlist = NIL;
+	char *whereClauseStr = NULL;
+	char *rangeTableStr = NULL;
+	char *attnameListStr = NULL;
+	char *notnullListStr = NULL;
+	char *nullListStr = NULL;
+	char *convertListStr = NULL;
+	WalUsage   *walusage;
+	BufferUsage *bufferusage;
+
+	/* Allocate workspace and zero all fields. */
+	cstate = (CopyStateData *) palloc0(sizeof(CopyStateData));
+
+	/*
+	 * We allocate everything used by a cstate in a new memory context. This
+	 * avoids memory leaks during repeated use of COPY in a query.
+	 */
+	cstate->copycontext = AllocSetContextCreate(CurrentMemoryContext,
+												"COPY",
+												ALLOCSET_DEFAULT_SIZES);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	cstate->pcdata = pcdata;
+	pcdata->is_leader = false;
+	pcdata->worker_processed_pos = -1;
+	cstate->is_parallel = true;
+	pcshared_info = (ParallelCopyShmInfo *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_SHARED_INFO, false);
+
+	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
+
+	pcdata->pcshared_info = pcshared_info;
+
+	shared_cstate = (SerializedParallelCopyState *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE, false);
+	cstate->null_print = (char *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_NULL_PRINT, true);
+
+	RestoreString(toc, PARALLEL_COPY_KEY_DELIM, &cstate->delim);
+	RestoreString(toc, PARALLEL_COPY_KEY_QUOTE, &cstate->quote);
+	RestoreString(toc, PARALLEL_COPY_KEY_ESCAPE, &cstate->escape);
+	RestoreString(toc, PARALLEL_COPY_KEY_ATTNAME_LIST, &attnameListStr);
+	if (attnameListStr)
+		attlist = (List *)stringToNode(attnameListStr);
+
+	RestoreString(toc, PARALLEL_COPY_KEY_NOT_NULL_LIST, &notnullListStr);
+	if (notnullListStr)
+		cstate->force_notnull = (List *)stringToNode(notnullListStr);
+
+	RestoreString(toc, PARALLEL_COPY_KEY_NULL_LIST, &nullListStr);
+	if (nullListStr)
+		cstate->force_null = (List *)stringToNode(nullListStr);
+
+	RestoreString(toc, PARALLEL_COPY_KEY_CONVERT_LIST, &convertListStr);
+	if (convertListStr)
+		cstate->convert_select = (List *)stringToNode(convertListStr);
+
+	RestoreString(toc, PARALLEL_COPY_KEY_WHERE_CLAUSE_STR, &whereClauseStr);
+	RestoreString(toc, PARALLEL_COPY_KEY_RANGE_TABLE, &rangeTableStr);
+
+	if (whereClauseStr)
+	{
+		Node *whereClauseCnvrtdFrmStr = (Node *) stringToNode(whereClauseStr);
+		cstate->whereClause = whereClauseCnvrtdFrmStr;
+	}
+
+	if (rangeTableStr)
+	{
+		List *rangeTableCnvrtdFrmStr = (List *) stringToNode(rangeTableStr);
+		cstate->range_table = rangeTableCnvrtdFrmStr;
+	}
+
+	/* Open and lock the relation, using the appropriate lock type. */
+	rel = table_open(shared_cstate->relid, RowExclusiveLock);
+	cstate->rel = rel;
+	InitializeParallelCopyInfo(shared_cstate, cstate, attlist);
+
+	CopyFrom(cstate);
+
+	if (rel != NULL)
+		table_close(rel, RowExclusiveLock);
+
+	/* Report WAL/buffer usage during parallel execution */
+	bufferusage = shm_toc_lookup(toc, PARALLEL_COPY_BUFFER_USAGE, false);
+	walusage = shm_toc_lookup(toc, PARALLEL_COPY_WAL_USAGE, false);
+	InstrEndParallelQuery(&bufferusage[ParallelWorkerNumber],
+						  &walusage[ParallelWorkerNumber]);
+
+	MemoryContextSwitchTo(oldcontext);
+	pfree(cstate);
+	return;
+}
+
+/*
+ * ParallelCopyFrom - parallel copy leader's functionality.
+ *
+ * Leader executes the before statement for before statement trigger, if before
+ * statement trigger is present. It will read the table data from the file and
+ * copy the contents to DSM data blocks. It will then read the input contents
+ * from the DSM data block and identify the records based on line breaks. This
+ * information is called line or a record that need to be inserted into a
+ * relation. The line information will be stored in ParallelCopyLineBoundary DSM
+ * data structure. Workers will then process this information and insert the
+ * data in to table. It will repeat this process until the all data is read from
+ * the file and all the DSM data blocks are processed. While processing if
+ * leader identifies that DSM Data blocks or DSM ParallelCopyLineBoundary data
+ * structures is full, leader will wait till the worker frees up some entries
+ * and repeat the process. It will wait till all the lines populated are
+ * processed by the workers and exits.
+ */
+static void
+ParallelCopyFrom(CopyState cstate)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
+
+	pcshared_info->is_read_in_progress = false;
+	cstate->cur_lineno = 0;
+}
+
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
  * in past protocol redesigns.
@@ -1141,6 +1823,7 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 
 	if (is_from)
 	{
+		ParallelContext *pcxt = NULL;
 		Assert(rel);
 
 		/* check read-only transaction and parallel mode */
@@ -1150,7 +1833,24 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 		cstate = BeginCopyFrom(pstate, rel, stmt->filename, stmt->is_program,
 							   NULL, stmt->attlist, stmt->options);
 		cstate->whereClause = whereClause;
-		*processed = CopyFrom(cstate);	/* copy from file to database */
+		cstate->is_parallel = false;
+
+		if (cstate->nworkers > 0)
+			pcxt = BeginParallelCopy(cstate->nworkers, cstate, stmt->attlist,
+									 relid);
+
+		if (pcxt)
+		{
+			ParallelCopyFrom(cstate);
+
+			/* Wait for all copy workers to finish */
+			WaitForParallelWorkersToFinish(pcxt);
+			*processed = pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
+			EndParallelCopy(pcxt);
+		}
+		else
+			*processed = CopyFrom(cstate); /* copy from file to database */
+
 		EndCopyFrom(cstate);
 	}
 	else
@@ -1199,6 +1899,7 @@ ProcessCopyOptions(ParseState *pstate,
 	cstate->is_copy_from = is_from;
 
 	cstate->file_encoding = -1;
+	cstate->nworkers = -1;
 
 	/* Extract options from the statement node tree */
 	foreach(option, options)
@@ -1367,6 +2068,39 @@ ProcessCopyOptions(ParseState *pstate,
 								defel->defname),
 						 parser_errposition(pstate, defel->location)));
 		}
+		else if (strcmp(defel->defname, "parallel") == 0)
+		{
+			int val;
+			bool parsed;
+			char *strval;
+
+			if (!cstate->is_copy_from)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("parallel option is supported only for copy from"),
+						 parser_errposition(pstate, defel->location)));
+			if (cstate->nworkers >= 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options"),
+						 parser_errposition(pstate, defel->location)));
+
+			strval = defGetString(defel);
+			parsed = parse_int(strval, &val, 0, NULL);
+			if (!parsed)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+							errmsg("invalid value for integer option \"%s\": %s",
+								   defel->defname, strval)));
+			if (val < 1 || val > 1024)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+							errmsg("value %s out of bounds for option \"%s\"",
+								   strval, defel->defname),
+							errdetail("Valid values are between \"%d\" and \"%d\".",
+									  1, 1024)));
+			cstate->nworkers = val;
+		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_SYNTAX_ERROR),
@@ -1720,11 +2454,12 @@ BeginCopy(ParseState *pstate,
 
 /*
  * PopulateCommonCstateInfo - Populates the common variables required for copy
- * from operation. This is a helper function for BeginCopy function.
+ * from operation. This is a helper function for BeginCopy &
+ * InitializeParallelCopyInfo function.
  */
 static void
 PopulateCommonCstateInfo(CopyState cstate, TupleDesc	tupDesc,
-							List *attnamelist)
+						 List *attnamelist)
 {
 	int			num_phys_attrs;
 
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index c639833..82843c6 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -14,6 +14,7 @@
 #ifndef COPY_H
 #define COPY_H
 
+#include "access/parallel.h"
 #include "nodes/execnodes.h"
 #include "nodes/parsenodes.h"
 #include "parser/parse_node.h"
@@ -41,4 +42,5 @@ extern uint64 CopyFrom(CopyState cstate);
 
 extern DestReceiver *CreateCopyDestReceiver(void);
 
+extern void ParallelCopyMain(dsm_segment *seg, shm_toc *toc);
 #endif							/* COPY_H */
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 3d99046..a0e4ac7 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1700,6 +1700,12 @@ ParallelBitmapHeapState
 ParallelBlockTableScanDesc
 ParallelCompletionPtr
 ParallelContext
+ParallelCopyLineBoundaries
+ParallelCopyLineBoundary
+ParallelCopyData
+ParallelCopyDataBlock
+ParallelCopyLineBuf
+ParallelCopyShmInfo
 ParallelExecutorInfo
 ParallelHashGrowth
 ParallelHashJoinBatch
@@ -2216,6 +2222,7 @@ SerCommitSeqNo
 SerialControl
 SerializableXactHandle
 SerializedActiveRelMaps
+SerializedParallelCopyState
 SerializedReindexState
 SerializedSnapshotData
 SerializedTransactionState
-- 
1.8.3.1

v4-0003-Allow-copy-from-command-to-process-data-from-file.patchtext/x-patch; charset=US-ASCII; name=v4-0003-Allow-copy-from-command-to-process-data-from-file.patchDownload
From ba0bcdcf758d1fb779921b2ab615170a53ecdc4b Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Sat, 1 Aug 2020 09:31:42 +0530
Subject: [PATCH v4 3/6] Allow copy from command to process data from
 file/STDIN contents to a table in parallel.

This feature allows the copy from to leverage multiple CPUs in order to copy
data from file/STDIN to a table. This adds a PARALLEL option to COPY FROM
command where the user can specify the number of workers that can be used
to perform the COPY FROM command.
The backend, to which the "COPY FROM" query is submitted acts as leader with
the responsibility of reading data from the file/stdin, launching at most n
number of workers as specified with PARALLEL 'n' option in the "COPY FROM"
query. The leader populates the common data required for the workers execution
in the DSM and shares it with the workers. The leader then executes before
statement triggers if there exists any. Leader populates DSM lines which
includes the start offset and line size, while populating the lines it reads
as many blocks as required into the DSM data blocks from the file. Each block
is of 64K size. The leader parses the data to identify a line, the existing
logic from CopyReadLineText which identifies the lines with some changes was
used for this. Leader checks if a free line is available to copy the
information, if there is no free line it waits till the required line is
freed up by the worker and then copies the identified lines information
(offset & line size) into the DSM lines. This process is repeated till the
complete file is processed. Simultaneously, the workers cache the lines(50)
locally into the local memory and release the lines to the leader for further
populating. Each worker processes the lines that it cached and inserts it into
the table. The leader does not participate in the insertion of data, leaders
only responsibility will be to identify the lines as fast as possible for the
workers to do the actual copy operation. The leader waits till all the lines
populated are processed by the workers and exits.
We have chosen this design based on the reason "that everything stalls if the
leader doesn't accept further input data, as well as when there are no
available splitted chunks so it doesn't seem like a good idea to have the
leader do other work.  This is backed by the performance data where we have
seen that with 1 worker there is just a 5-10% performance difference".
---
 src/backend/access/common/toast_internals.c |  11 +-
 src/backend/access/heap/heapam.c            |  13 -
 src/backend/access/transam/xact.c           |  31 +
 src/backend/commands/copy.c                 | 896 ++++++++++++++++++++++++++--
 src/bin/psql/tab-complete.c                 |   2 +-
 src/include/access/xact.h                   |   2 +
 src/tools/pgindent/typedefs.list            |   1 +
 7 files changed, 902 insertions(+), 54 deletions(-)

diff --git a/src/backend/access/common/toast_internals.c b/src/backend/access/common/toast_internals.c
index 25a81e5..586d53d 100644
--- a/src/backend/access/common/toast_internals.c
+++ b/src/backend/access/common/toast_internals.c
@@ -17,6 +17,7 @@
 #include "access/genam.h"
 #include "access/heapam.h"
 #include "access/heaptoast.h"
+#include "access/parallel.h"
 #include "access/table.h"
 #include "access/toast_internals.h"
 #include "access/xact.h"
@@ -116,7 +117,15 @@ toast_save_datum(Relation rel, Datum value,
 	TupleDesc	toasttupDesc;
 	Datum		t_values[3];
 	bool		t_isnull[3];
-	CommandId	mycid = GetCurrentCommandId(true);
+
+	/*
+	 * Parallel copy can insert toast tuples, in case of parallel copy the
+	 * command would have been set already by calling AssignCommandIdForWorker.
+	 * For parallel copy call GetCurrentCommandId to get currentCommandId by
+	 * passing used as false, as this is taken care earlier.
+	 */
+	CommandId	mycid = IsParallelWorker() ? GetCurrentCommandId(false) :
+											 GetCurrentCommandId(true);
 	struct varlena *result;
 	struct varatt_external toast_pointer;
 	union
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 8eb276e..a5fa9f5 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2043,19 +2043,6 @@ static HeapTuple
 heap_prepare_insert(Relation relation, HeapTuple tup, TransactionId xid,
 					CommandId cid, int options)
 {
-	/*
-	 * Parallel operations are required to be strictly read-only in a parallel
-	 * worker.  Parallel inserts are not safe even in the leader in the
-	 * general case, because group locking means that heavyweight locks for
-	 * relation extension or GIN page locks will not conflict between members
-	 * of a lock group, but we don't prohibit that case here because there are
-	 * useful special cases that we can safely allow, such as CREATE TABLE AS.
-	 */
-	if (IsParallelWorker())
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_TRANSACTION_STATE),
-				 errmsg("cannot insert tuples in a parallel worker")));
-
 	tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
 	tup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK);
 	tup->t_data->t_infomask |= HEAP_XMAX_INVALID;
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index af6afce..e983f78 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -517,6 +517,37 @@ GetCurrentFullTransactionIdIfAny(void)
 }
 
 /*
+ *	AssignFullTransactionIdForWorker
+ *
+ * For parallel copy, transaction id of leader will be used by the workers.
+ */
+void
+AssignFullTransactionIdForWorker(FullTransactionId fullTransactionId)
+{
+	TransactionState s = CurrentTransactionState;
+
+	Assert((IsInParallelMode() || IsParallelWorker()));
+	s->fullTransactionId = fullTransactionId;
+}
+
+/*
+ *	AssignCommandIdForWorker
+ *
+ * For parallel copy, command id of leader will be used by the workers.
+ */
+void
+AssignCommandIdForWorker(CommandId commandId, bool used)
+{
+	Assert((IsInParallelMode() || IsParallelWorker()));
+
+	/* this is global to a transaction, not subtransaction-local */
+	if (used)
+		currentCommandIdUsed = true;
+
+	currentCommandId = commandId;
+}
+
+/*
  *	MarkCurrentTransactionIdLoggedIfAny
  *
  * Remember that the current xid - if it is assigned - now has been wal logged.
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 704bbd3..868ba4a 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -26,6 +26,7 @@
 #include "access/xlog.h"
 #include "catalog/dependency.h"
 #include "catalog/pg_authid.h"
+#include "catalog/pg_proc_d.h"
 #include "catalog/pg_type.h"
 #include "commands/copy.h"
 #include "commands/defrem.h"
@@ -40,11 +41,13 @@
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
+#include "optimizer/clauses.h"
 #include "optimizer/optimizer.h"
 #include "parser/parse_coerce.h"
 #include "parser/parse_collate.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_relation.h"
+#include "pgstat.h"
 #include "port/pg_bswap.h"
 #include "rewrite/rewriteHandler.h"
 #include "storage/fd.h"
@@ -95,6 +98,18 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
+/*
+ * State of the line.
+ */
+typedef enum ParallelCopyLineState
+{
+	LINE_INIT,					/* initial state of line */
+	LINE_LEADER_POPULATING,		/* leader processing line */
+	LINE_LEADER_POPULATED,		/* leader completed populating line */
+	LINE_WORKER_PROCESSING,		/* worker processing line */
+	LINE_WORKER_PROCESSED		/* worker completed processing line */
+}ParallelCopyLineState;
+
 #define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
 
 /*
@@ -124,6 +139,7 @@ typedef enum CopyInsertMethod
 
 #define	IsParallelCopy()		(cstate->is_parallel)
 #define IsLeader()				(cstate->pcdata->is_leader)
+#define IsWorker()				(IsParallelCopy() && !IsLeader())
 #define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
 
 /*
@@ -557,9 +573,13 @@ if (1) \
 { \
 	if (raw_buf_ptr > cstate->raw_buf_index) \
 	{ \
-		appendBinaryStringInfo(&cstate->line_buf, \
-							 cstate->raw_buf + cstate->raw_buf_index, \
-							   raw_buf_ptr - cstate->raw_buf_index); \
+		if (!IsParallelCopy()) \
+			appendBinaryStringInfo(&cstate->line_buf, \
+								   cstate->raw_buf + cstate->raw_buf_index, \
+								   raw_buf_ptr - cstate->raw_buf_index); \
+		else \
+			line_size +=  raw_buf_ptr - cstate->raw_buf_index; \
+		\
 		cstate->raw_buf_index = raw_buf_ptr; \
 	} \
 } else ((void) 0)
@@ -572,26 +592,65 @@ if (1) \
 	goto not_end_of_copy; \
 } else ((void) 0)
 
+/* Begin parallel copy Macros */
+#define SET_NEWLINE_SIZE() \
+{ \
+	if (cstate->eol_type == EOL_NL || cstate->eol_type == EOL_CR) \
+		new_line_size = 1; \
+	else if (cstate->eol_type == EOL_CRNL) \
+		new_line_size = 2; \
+	else \
+		new_line_size = 0; \
+}
+
+/*
+ * COPY_WAIT_TO_PROCESS - Wait before continuing to process.
+ */
+#define COPY_WAIT_TO_PROCESS() \
+{ \
+	CHECK_FOR_INTERRUPTS(); \
+	(void) WaitLatch(MyLatch, \
+					 WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH, \
+					 1L, WAIT_EVENT_PG_SLEEP); \
+	ResetLatch(MyLatch); \
+}
+
 /*
  * CLEAR_EOL_LINE - Wrapper for clearing EOL.
  */
 #define CLEAR_EOL_LINE() \
 if (!result && !IsHeaderLine()) \
-	ClearEOLFromCopiedData(cstate, cstate->line_buf.data, \
-						   cstate->line_buf.len, \
-						   &cstate->line_buf.len) \
+{ \
+	if (IsParallelCopy()) \
+		ClearEOLFromCopiedData(cstate, cstate->raw_buf, \
+									raw_buf_ptr, &line_size); \
+	else \
+		ClearEOLFromCopiedData(cstate, cstate->line_buf.data, \
+									cstate->line_buf.len, \
+									&cstate->line_buf.len); \
+} \
 
 /*
  * INCREMENTPROCESSED - Increment the lines processed.
  */
-#define INCREMENTPROCESSED(processed)  \
-processed++;
+#define INCREMENTPROCESSED(processed) \
+{ \
+	if (!IsParallelCopy()) \
+		processed++; \
+	else \
+		pg_atomic_add_fetch_u64(&cstate->pcdata->pcshared_info->processed, 1); \
+}
 
 /*
  * RETURNPROCESSED - Get the lines processed.
  */
 #define RETURNPROCESSED(processed) \
-return processed;
+if (!IsParallelCopy()) \
+	return processed; \
+else \
+	return pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
+
+/* End parallel copy Macros */
 
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
@@ -646,7 +705,10 @@ static void PopulateCommonCstateInfo(CopyState cstate, TupleDesc	tup_desc,
 static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
 								   int copy_line_pos, int *copy_line_size);
 static void ConvertToServerEncoding(CopyState cstate);
-
+static void ExecBeforeStmtTrigger(CopyState cstate);
+static void CheckTargetRelValidity(CopyState cstate);
+static void PopulateCstateCatalogInfo(CopyState cstate);
+static pg_attribute_always_inline uint32 GetLinePosition(CopyState cstate);
 /*
  * SerializeParallelCopyState - Copy shared_cstate using cstate information.
  */
@@ -728,6 +790,137 @@ PopulateParallelCopyShmInfo(ParallelCopyShmInfo *shared_info_ptr,
 }
 
 /*
+ * IsTriggerFunctionParallelSafe - Check if the trigger function is parallel
+ * safe for the triggers. Return false if any one of the trigger has parallel
+ * unsafe function.
+ */
+static pg_attribute_always_inline bool
+IsTriggerFunctionParallelSafe(TriggerDesc *trigdesc)
+{
+	int	i;
+	for (i = 0; i < trigdesc->numtriggers; i++)
+	{
+		Trigger    *trigger = &trigdesc->triggers[i];
+		int 		trigtype = RI_TRIGGER_NONE;
+
+		if (func_parallel(trigger->tgfoid) != PROPARALLEL_SAFE)
+			return false;
+
+		/* If the trigger is parallel safe, also look for RI_TRIGGER. */
+		trigtype = RI_FKey_trigger_type(trigger->tgfoid);
+		if (trigtype == RI_TRIGGER_PK || trigtype == RI_TRIGGER_FK)
+			return false;
+	}
+
+	return true;
+}
+
+/*
+ * CheckExprParallelSafety - determine parallel safety of volatile expressions
+ * in default clause of column definition or in where clause and return true if
+ * they are parallel safe.
+ */
+static pg_attribute_always_inline bool
+CheckExprParallelSafety(CopyState cstate)
+{
+	if (contain_volatile_functions(cstate->whereClause))
+	{
+		if (max_parallel_hazard((Query *)cstate->whereClause) != PROPARALLEL_SAFE)
+			return false;
+	}
+
+	/*
+	 * Check if any of the column has volatile default expression. if yes, and
+	 * they are not parallel safe, then parallelism is not allowed. For
+	 * instance, if there are any serial/bigserial columns for which nextval()
+	 * default expression which is parallel unsafe is associated, parallelism
+	 * should not be allowed. In non parallel copy volatile functions are not
+	 * checked for nextval().
+	 */
+	if (cstate->defexprs != NULL && cstate->num_defaults != 0)
+	{
+		int     i;
+		for (i = 0; i < cstate->num_defaults; i++)
+		{
+			bool volatile_expr = contain_volatile_functions((Node *)cstate->defexprs[i]->expr);
+			if (volatile_expr &&
+				(max_parallel_hazard((Query *)cstate->defexprs[i]->expr)) !=
+				 PROPARALLEL_SAFE)
+				return false;
+		}
+	}
+
+	return true;
+}
+
+/*
+ * FindInsertMethod - determine insert mode single, multi, or multi conditional.
+ */
+static pg_attribute_always_inline CopyInsertMethod
+FindInsertMethod(CopyState cstate)
+{
+	if (cstate->rel->trigdesc != NULL &&
+		(cstate->rel->trigdesc->trig_insert_before_row ||
+		 cstate->rel->trigdesc->trig_insert_instead_row))
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
+			cstate->rel->trigdesc != NULL &&
+			cstate->rel->trigdesc->trig_insert_new_table)
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+		return CIM_MULTI_CONDITIONAL;
+
+	return CIM_MULTI;
+}
+
+/*
+ * IsParallelCopyAllowed - check for the cases where parallel copy is not
+ * applicable.
+ */
+static pg_attribute_always_inline bool
+IsParallelCopyAllowed(CopyState cstate)
+{
+	/* Parallel copy not allowed for frontend (2.0 protocol) & binary option. */
+	if ((cstate->copy_dest == COPY_OLD_FE) || cstate->binary)
+		return false;
+
+	/* Check if copy is into foreign table or temporary table. */
+	if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
+		RelationUsesLocalBuffers(cstate->rel))
+		return false;
+
+	/* Check if trigger function is parallel safe. */
+	if (cstate->rel->trigdesc != NULL &&
+		!IsTriggerFunctionParallelSafe(cstate->rel->trigdesc))
+		return false;
+
+	/*
+	 * Check if there is after statement or instead of trigger or transition
+	 * table triggers.
+	 */
+	if (cstate->rel->trigdesc != NULL &&
+		(cstate->rel->trigdesc->trig_insert_after_statement ||
+		 cstate->rel->trigdesc->trig_insert_instead_row ||
+		 cstate->rel->trigdesc->trig_insert_new_table))
+		return false;
+
+	/* Check if the volatile expressions are parallel safe, if present any. */
+	if (!CheckExprParallelSafety(cstate))
+		return false;
+
+	/* Check if the insertion mode is single. */
+	if (FindInsertMethod(cstate) == CIM_SINGLE)
+		return false;
+
+	return true;
+}
+
+/*
  * BeginParallelCopy - start parallel copy tasks.
  *
  * Get the number of workers required to perform the parallel copy. The data
@@ -755,6 +948,7 @@ BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
 	ParallelCopyData *pcdata;
 	MemoryContext oldcontext;
 
+	CheckTargetRelValidity(cstate);
 	parallel_workers = Min(nworkers, max_worker_processes);
 
 	/* Can't perform copy in parallel */
@@ -766,6 +960,15 @@ BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
 	MemoryContextSwitchTo(oldcontext);
 	cstate->pcdata = pcdata;
 
+	/*
+	 * User chosen parallel copy. Determine if the parallel copy is actually
+	 * allowed. If not, go with the non-parallel mode.
+	 */
+	if (!IsParallelCopyAllowed(cstate))
+		return NULL;
+
+	full_transaction_id = GetCurrentFullTransactionId();
+
 	EnterParallelMode();
 	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
 								 parallel_workers);
@@ -974,9 +1177,214 @@ InitializeParallelCopyInfo(SerializedParallelCopyState *shared_cstate,
 	cstate->line_buf_converted = false;
 	cstate->raw_buf = NULL;
 	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+
+	PopulateCstateCatalogInfo(cstate);
+
+	/* Create workspace for CopyReadAttributes results. */
+	if (!cstate->binary)
+	{
+		AttrNumber	attr_count = list_length(cstate->attnumlist);
+
+		cstate->max_fields = attr_count;
+		cstate->raw_fields = (char **)palloc(attr_count * sizeof(char *));
+	}
+}
+
+/*
+ * CacheLineInfo - Cache the line information to local memory.
+ */
+static bool
+CacheLineInfo(CopyState cstate, uint32 buff_count)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	uint32			write_pos;
+	ParallelCopyDataBlock *data_blk_ptr;
+	ParallelCopyLineBoundary *lineInfo;
+	uint32 offset;
+	int dataSize;
+	int copiedSize = 0;
+
+	resetStringInfo(&pcdata->worker_line_buf[buff_count].line_buf);
+	write_pos = GetLinePosition(cstate);
+	if (-1 == write_pos)
+		return true;
+
+	/* Get the current line information. */
+	lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+	if (pg_atomic_read_u32(&lineInfo->line_size) == 0)
+		goto empty_data_line_update;
+
+	/* Get the block information. */
+	data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+	/* Get the offset information from where the data must be copied. */
+	offset = lineInfo->start_offset;
+	pcdata->worker_line_buf[buff_count].cur_lineno = lineInfo->cur_lineno;
+
+	elog(DEBUG1, "[Worker] Processing - line position:%d, block:%d, unprocessed lines:%d, offset:%d, line size:%d",
+				 write_pos, lineInfo->first_block,
+				 pg_atomic_read_u32(&data_blk_ptr->unprocessed_line_parts),
+				 offset, pg_atomic_read_u32(&lineInfo->line_size));
+
+	for (;;)
+	{
+		uint8 skip_bytes = data_blk_ptr->skip_bytes;
+
+		/*
+		 * There is a possibility that the loop embedded at the bottom of the
+		 * current loop has come out because data_blk_ptr->curr_blk_completed
+		 * is set, but dataSize read might be an old value, if
+		 * data_blk_ptr->curr_blk_completed and the line is completed, line_size
+		 * will be set. Read the line_size again to be sure if it is completed
+		 * or partial block.
+		 */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+		if (dataSize)
+		{
+			int remainingSize = dataSize - copiedSize;
+			if (!remainingSize)
+				break;
+
+			/* Whole line is in current block. */
+			if (remainingSize + offset + skip_bytes < DATA_BLOCK_SIZE)
+			{
+				appendBinaryStringInfo(&pcdata->worker_line_buf[buff_count].line_buf,
+									   &data_blk_ptr->data[offset],
+									   remainingSize);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts,
+										1);
+				break;
+			}
+			else
+			{
+				/* Line is spread across the blocks. */
+				uint32 lineInCurrentBlock =  (DATA_BLOCK_SIZE - skip_bytes) - offset;
+				appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+										 &data_blk_ptr->data[offset],
+										 lineInCurrentBlock);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+				copiedSize += lineInCurrentBlock;
+				while (copiedSize < dataSize)
+				{
+					uint32 currentBlockCopySize;
+					ParallelCopyDataBlock *currBlkPtr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+					skip_bytes = currBlkPtr->skip_bytes;
+
+					/*
+					 * If complete data is present in current block use
+					 * dataSize - copiedSize, or copy the whole block from
+					 * current block.
+					 */
+					currentBlockCopySize = Min(dataSize - copiedSize, DATA_BLOCK_SIZE - skip_bytes);
+					appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+											 &currBlkPtr->data[0],
+											 currentBlockCopySize);
+					pg_atomic_sub_fetch_u32(&currBlkPtr->unprocessed_line_parts, 1);
+					copiedSize += currentBlockCopySize;
+					data_blk_ptr = currBlkPtr;
+				}
+
+				break;
+			}
+		}
+		else
+		{
+			/* Copy this complete block from the current offset. */
+			uint32 lineInCurrentBlock =  (DATA_BLOCK_SIZE - skip_bytes) - offset;
+			appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+									 &data_blk_ptr->data[offset],
+									 lineInCurrentBlock);
+			pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+			copiedSize += lineInCurrentBlock;
+
+			/*
+			 * Reset the offset. For the first copy, copy from the offset. For
+			 * the subsequent copy the complete block.
+			 */
+			offset = 0;
+
+			/* Set data_blk_ptr to the following block. */
+			data_blk_ptr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+		}
+
+		for (;;)
+		{
+			/* Get the size of this line */
+			dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+			/*
+			 * If the data is present in current block lineInfo->line_size
+			 * will be updated. If the data is spread across the blocks either
+			 * of lineInfo->line_size or data_blk_ptr->curr_blk_completed can
+			 * be updated. lineInfo->line_size will be updated if the complete
+			 * read is finished. data_blk_ptr->curr_blk_completed will be
+			 * updated if processing of current block is finished and data
+			 * processing is not finished.
+			 */
+			if (data_blk_ptr->curr_blk_completed || (dataSize != -1))
+				break;
+
+			COPY_WAIT_TO_PROCESS()
+		}
+	}
+
+empty_data_line_update:
+	elog(DEBUG1, "[Worker] Completed processing line:%d", write_pos);
+	pg_atomic_write_u32(&lineInfo->line_state, LINE_WORKER_PROCESSED);
+	pg_atomic_write_u32(&lineInfo->line_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+	return false;
 }
 
 /*
+ * GetWorkerLine - Returns a line for worker to process.
+ */
+static bool
+GetWorkerLine(CopyState cstate)
+{
+	uint32 buff_count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+
+	/*
+	 * Copy the line data to line_buf and release the line position so that the
+	 * worker can continue loading data.
+	 */
+	if (pcdata->worker_line_buf_pos < pcdata->worker_line_buf_count)
+		goto return_line;
+
+	pcdata->worker_line_buf_pos = 0;
+	pcdata->worker_line_buf_count = 0;
+
+	for (buff_count = 0; buff_count < WORKER_CHUNK_COUNT; buff_count++)
+	{
+		bool result = CacheLineInfo(cstate, buff_count);
+		if (result)
+			break;
+
+		pcdata->worker_line_buf_count++;
+	}
+
+	if (pcdata->worker_line_buf_count)
+		goto return_line;
+	else
+		resetStringInfo(&cstate->line_buf);
+
+	return true;
+
+return_line:
+	cstate->line_buf = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].line_buf;
+	cstate->cur_lineno = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].cur_lineno;
+	cstate->line_buf_valid = true;
+
+	/* Mark that encoding conversion hasn't occurred yet. */
+	cstate->line_buf_converted = false;
+	ConvertToServerEncoding(cstate);
+	pcdata->worker_line_buf_pos++;
+	return false;
+ }
+
+/*
  * ParallelCopyMain - parallel copy worker's code.
  *
  * Where clause handling, convert tuple to columns, add default null values for
@@ -1025,6 +1433,8 @@ ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
 	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
 
 	pcdata->pcshared_info = pcshared_info;
+	AssignFullTransactionIdForWorker(pcshared_info->full_transaction_id);
+	AssignCommandIdForWorker(pcshared_info->mycid, true);
 
 	shared_cstate = (SerializedParallelCopyState *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE, false);
 	cstate->null_print = (char *)shm_toc_lookup(toc, PARALLEL_COPY_KEY_NULL_PRINT, true);
@@ -1085,6 +1495,33 @@ ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
 }
 
 /*
+ * UpdateBlockInLineInfo - Update the line information.
+ */
+static pg_attribute_always_inline int
+UpdateBlockInLineInfo(CopyState cstate, uint32 blk_pos,
+					   uint32 offset, uint32 line_size, uint32 line_state)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyLineBoundaries *lineBoundaryPtr = &pcshared_info->line_boundaries;
+	ParallelCopyLineBoundary *lineInfo;
+	int line_pos = lineBoundaryPtr->pos;
+
+	/* Update the line information for the worker to pick and process. */
+	lineInfo = &lineBoundaryPtr->ring[line_pos];
+	while (pg_atomic_read_u32(&lineInfo->line_size) != -1)
+		COPY_WAIT_TO_PROCESS()
+
+	lineInfo->first_block = blk_pos;
+	lineInfo->start_offset = offset;
+	lineInfo->cur_lineno = cstate->cur_lineno;
+	pg_atomic_write_u32(&lineInfo->line_size, line_size);
+	pg_atomic_write_u32(&lineInfo->line_state, line_state);
+	lineBoundaryPtr->pos = (lineBoundaryPtr->pos + 1) % RINGSIZE;
+
+	return line_pos;
+}
+
+/*
  * ParallelCopyFrom - parallel copy leader's functionality.
  *
  * Leader executes the before statement for before statement trigger, if before
@@ -1107,8 +1544,302 @@ ParallelCopyFrom(CopyState cstate)
 	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
 	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
 
+	/* raw_buf is not used in parallel copy, instead data blocks are used.*/
+	pfree(cstate->raw_buf);
+	cstate->raw_buf = NULL;
+
+	/* Execute the before statement triggers from the leader */
+	ExecBeforeStmtTrigger(cstate);
+
+	/* On input just throw the header line away. */
+	if (cstate->cur_lineno == 0 && cstate->header_line)
+	{
+		cstate->cur_lineno++;
+		if (CopyReadLine(cstate))
+		{
+			pcshared_info->is_read_in_progress = false;
+			return;			/* done */
+		}
+	}
+
+	for (;;)
+	{
+		bool done;
+		cstate->cur_lineno++;
+
+		/* Actually read the line into memory here. */
+		done = CopyReadLine(cstate);
+
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			break;
+	}
+
 	pcshared_info->is_read_in_progress = false;
 	cstate->cur_lineno = 0;
+ }
+
+/*
+ * GetLinePosition - return the line position that worker should process.
+ */
+static uint32
+GetLinePosition(CopyState cstate)
+{
+	ParallelCopyData *pcdata = cstate->pcdata;
+	ParallelCopyShmInfo *pcshared_info = pcdata->pcshared_info;
+	uint32  previous_pos = pcdata->worker_processed_pos;
+	uint32 write_pos = (previous_pos == -1) ? 0 : (previous_pos + 1) % RINGSIZE;
+	for (;;)
+	{
+		int		dataSize;
+		bool	is_read_in_progress = pcshared_info->is_read_in_progress;
+		ParallelCopyLineBoundary *lineInfo;
+		ParallelCopyDataBlock *data_blk_ptr;
+		ParallelCopyLineState line_state = LINE_LEADER_POPULATED;
+		ParallelCopyLineState curr_line_state;
+		CHECK_FOR_INTERRUPTS();
+
+		/* File read completed & no elements to process. */
+		if (!is_read_in_progress &&
+			(pcshared_info->populated ==
+			 pg_atomic_read_u64(&pcshared_info->total_worker_processed)))
+		{
+			write_pos = -1;
+			break;
+		}
+
+		/* Get the current line information. */
+		lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+		curr_line_state = pg_atomic_read_u32(&lineInfo->line_state);
+		if ((write_pos % WORKER_CHUNK_COUNT == 0) &&
+			(curr_line_state == LINE_WORKER_PROCESSED ||
+			 curr_line_state == LINE_WORKER_PROCESSING))
+		{
+			pcdata->worker_processed_pos = write_pos;
+			write_pos = (write_pos + WORKER_CHUNK_COUNT) %  RINGSIZE;
+			continue;
+		}
+
+		/* Get the size of this line. */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+		if (dataSize != 0) /* If not an empty line. */
+		{
+			/* Get the block information. */
+			data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+			if (!data_blk_ptr->curr_blk_completed && (dataSize == -1))
+			{
+				/* Wait till the current line or block is added. */
+				COPY_WAIT_TO_PROCESS()
+				continue;
+			}
+		}
+
+		/* Make sure that no worker has consumed this element. */
+		if (pg_atomic_compare_exchange_u32(&lineInfo->line_state,
+										   &line_state, LINE_WORKER_PROCESSING))
+			break;
+	}
+
+	pcdata->worker_processed_pos = write_pos;
+	return write_pos;
+}
+
+/*
+ * GetFreeCopyBlock - Get a free block for data to be copied.
+ */
+static pg_attribute_always_inline uint32
+GetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	int count = 0;
+	uint32 last_free_block = pcshared_info->cur_block_pos;
+	uint32 block_pos = (last_free_block != -1) ? ((last_free_block + 1) % MAX_BLOCKS_COUNT): 0;
+
+	/*
+	 * Get a new block for copying data, don't check current block, current
+	 * block will have some unprocessed data.
+	 */
+	while (count < (MAX_BLOCKS_COUNT - 1))
+	{
+		ParallelCopyDataBlock *dataBlkPtr = &pcshared_info->data_blocks[block_pos];
+		uint32 unprocessed_line_parts = pg_atomic_read_u32(&dataBlkPtr->unprocessed_line_parts);
+		if (unprocessed_line_parts == 0)
+		{
+			dataBlkPtr->curr_blk_completed = false;
+			dataBlkPtr->skip_bytes = 0;
+			pcshared_info->cur_block_pos = block_pos;
+			return block_pos;
+		}
+
+		block_pos = (block_pos + 1) % MAX_BLOCKS_COUNT;
+		count++;
+	}
+
+	return -1;
+}
+
+/*
+ * WaitGetFreeCopyBlock - If there are no blocks available, wait and get a block
+ * for copying data.
+ */
+static uint32
+WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	uint32 new_free_pos = -1;
+	for (;;)
+	{
+		new_free_pos = GetFreeCopyBlock(pcshared_info);
+		if (new_free_pos != -1)	/* We have got one block, break now. */
+			break;
+
+		COPY_WAIT_TO_PROCESS()
+	}
+
+	return new_free_pos;
+}
+
+/*
+ * SetRawBufForLoad - Set raw_buf to the shared memory where the file data must
+ * be read.
+ */
+static void
+SetRawBufForLoad(CopyState cstate, uint32 line_size, uint32 copy_buf_len,
+				 uint32 raw_buf_ptr, char **copy_raw_buf)
+{
+	ParallelCopyShmInfo	*pcshared_info;
+	uint32 cur_block_pos;
+	uint32 next_block_pos;
+	ParallelCopyDataBlock	*cur_data_blk_ptr = NULL;
+	ParallelCopyDataBlock	*next_data_blk_ptr = NULL;
+
+	if (!IsParallelCopy())
+		return;
+
+	pcshared_info = cstate->pcdata->pcshared_info;
+	cur_block_pos = pcshared_info->cur_block_pos;
+	cur_data_blk_ptr = (cstate->raw_buf) ? &pcshared_info->data_blocks[cur_block_pos] : NULL;
+	next_block_pos = WaitGetFreeCopyBlock(pcshared_info);
+	next_data_blk_ptr = &pcshared_info->data_blocks[next_block_pos];
+
+	/* set raw_buf to the data block in shared memory */
+	cstate->raw_buf = next_data_blk_ptr->data;
+	*copy_raw_buf = cstate->raw_buf;
+	if (cur_data_blk_ptr && line_size)
+	{
+		/*
+		 * Mark the previous block as completed, worker can start copying this
+		 * data.
+		 */
+		cur_data_blk_ptr->following_block = next_block_pos;
+		pg_atomic_add_fetch_u32(&cur_data_blk_ptr->unprocessed_line_parts, 1);
+		cur_data_blk_ptr->skip_bytes = copy_buf_len - raw_buf_ptr;
+		cur_data_blk_ptr->curr_blk_completed = true;
+	}
+}
+
+/*
+ * EndLineParallelCopy - Update the line information in shared memory.
+ */
+static void
+EndLineParallelCopy(CopyState cstate, uint32 line_pos, uint32 line_size,
+					 uint32 raw_buf_ptr)
+{
+	uint8 new_line_size;
+	if (!IsParallelCopy())
+		return;
+
+	if (!IsHeaderLine())
+	{
+		ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+		ParallelCopyLineBoundaries *lineBoundaryPtr = &pcshared_info->line_boundaries;
+		SET_NEWLINE_SIZE()
+		if (line_size)
+		{
+			ParallelCopyLineBoundary *lineInfo = &lineBoundaryPtr->ring[line_pos];
+			/*
+			 * If the new_line_size > raw_buf_ptr, then the new block has only
+			 * new line char content. The unprocessed count should not be
+			 * increased in this case.
+			 */
+			if (raw_buf_ptr > new_line_size)
+			{
+				uint32 cur_block_pos = pcshared_info->cur_block_pos;
+				ParallelCopyDataBlock *curr_data_blk_ptr = &pcshared_info->data_blocks[cur_block_pos];
+				pg_atomic_add_fetch_u32(&curr_data_blk_ptr->unprocessed_line_parts, 1);
+			}
+
+			/* Update line size. */
+			pg_atomic_write_u32(&lineInfo->line_size, line_size);
+			pg_atomic_write_u32(&lineInfo->line_state, LINE_LEADER_POPULATED);
+			elog(DEBUG1, "[Leader] After adding - line position:%d, line_size:%d",
+						 line_pos, line_size);
+			pcshared_info->populated++;
+		}
+		else if (new_line_size)
+		{
+			/* This means only new line char, empty record should be inserted.*/
+			ParallelCopyLineBoundary *lineInfo;
+			line_pos = UpdateBlockInLineInfo(cstate, -1, -1, 0,
+											   LINE_LEADER_POPULATED);
+			lineInfo = &lineBoundaryPtr->ring[line_pos];
+			elog(DEBUG1, "[Leader] Added empty line with offset:%d, line position:%d, line size:%d",
+						 lineInfo->start_offset, line_pos,
+						 pg_atomic_read_u32(&lineInfo->line_size));
+			pcshared_info->populated++;
+		}
+	}
+}
+
+/*
+ * ExecBeforeStmtTrigger - Execute the before statement trigger, this will be
+ * executed for parallel copy by the leader process.
+ */
+static void
+ExecBeforeStmtTrigger(CopyState cstate)
+{
+	EState	   *estate = CreateExecutorState();
+	ResultRelInfo *resultRelInfo;
+
+	Assert(IsLeader());
+
+	/*
+	 * We need a ResultRelInfo so we can use the regular executor's
+	 * index-entry-making machinery.  (There used to be a huge amount of code
+	 * here that basically duplicated execUtils.c ...)
+	 */
+	resultRelInfo = makeNode(ResultRelInfo);
+	InitResultRelInfo(resultRelInfo,
+					  cstate->rel,
+					  1,		/* must match rel's position in range_table */
+					  NULL,
+					  0);
+
+	/* Verify the named relation is a valid target for INSERT */
+	CheckValidResultRel(resultRelInfo, CMD_INSERT);
+
+	estate->es_result_relations = resultRelInfo;
+	estate->es_num_result_relations = 1;
+	estate->es_result_relation_info = resultRelInfo;
+
+	ExecInitRangeTable(estate, cstate->range_table);
+
+	/*
+	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
+	 * should do this for COPY, since it's not really an "INSERT" statement as
+	 * such. However, executing these triggers maintains consistency with the
+	 * EACH ROW triggers that we already fire on COPY.
+	 */
+	ExecBSInsertTriggers(estate, resultRelInfo);
+
+	/* Close any trigger target relations */
+	ExecCleanUpTriggerState(estate);
+
+	FreeExecutorState(estate);
 }
 
 /*
@@ -3571,7 +4302,8 @@ CopyFrom(CopyState cstate)
 
 	PartitionTupleRouting *proute = NULL;
 	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
+	CommandId	mycid = IsParallelCopy() ? GetCurrentCommandId(false) :
+										   GetCurrentCommandId(true);
 	int			ti_options = 0; /* start with default options for insert */
 	BulkInsertState bistate = NULL;
 	CopyInsertMethod insertMethod;
@@ -3581,7 +4313,14 @@ CopyFrom(CopyState cstate)
 	bool		has_instead_insert_row_trig;
 	bool		leafpart_use_multi_insert = false;
 
-	CheckTargetRelValidity(cstate);
+	/*
+	 * Perform this check if it is not parallel copy. In case of parallel
+	 * copy, this check is done by the leader, so that if any invalid case
+	 * exist the copy from command will error out from the leader itself,
+	 * avoiding launching workers, just to throw error.
+	 */
+	if (!IsParallelCopy())
+		CheckTargetRelValidity(cstate);
 
 	/*
 	 * If the target file is new-in-transaction, we assume that checking FSM
@@ -3621,7 +4360,8 @@ CopyFrom(CopyState cstate)
 	target_resultRelInfo = resultRelInfo;
 
 	/* Verify the named relation is a valid target for INSERT */
-	CheckValidResultRel(resultRelInfo, CMD_INSERT);
+	if (!IsParallelCopy())
+		CheckValidResultRel(resultRelInfo, CMD_INSERT);
 
 	ExecOpenIndices(resultRelInfo, false);
 
@@ -3770,13 +4510,16 @@ CopyFrom(CopyState cstate)
 	has_instead_insert_row_trig = (resultRelInfo->ri_TrigDesc &&
 								   resultRelInfo->ri_TrigDesc->trig_insert_instead_row);
 
-	/*
-	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
-	 * should do this for COPY, since it's not really an "INSERT" statement as
-	 * such. However, executing these triggers maintains consistency with the
-	 * EACH ROW triggers that we already fire on COPY.
-	 */
-	ExecBSInsertTriggers(estate, resultRelInfo);
+	if (!IsParallelCopy())
+	{
+		/*
+		 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
+		 * should do this for COPY, since it's not really an "INSERT" statement as
+		 * such. However, executing these triggers maintains consistency with the
+		 * EACH ROW triggers that we already fire on COPY.
+		 */
+		ExecBSInsertTriggers(estate, resultRelInfo);
+	}
 
 	econtext = GetPerTupleExprContext(estate);
 
@@ -3876,6 +4619,16 @@ CopyFrom(CopyState cstate)
 					!has_instead_insert_row_trig &&
 					resultRelInfo->ri_FdwRoutine == NULL;
 
+				/*
+				 * If the table has any partitions that are either foreign or
+				 * has BEFORE/INSTEAD OF triggers, we can't perform copy
+				 * operations with parallel workers.
+				 */
+				if (!leafpart_use_multi_insert && IsParallelWorker())
+					ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							errmsg("cannot perform PARALLEL COPY if partition has BEFORE/INSTEAD OF triggers, or if the partition is foreign partition"),
+							errhint("Try COPY without PARALLEL option")));
+
 				/* Set the multi-insert buffer to use for this partition. */
 				if (leafpart_use_multi_insert)
 				{
@@ -4292,7 +5045,7 @@ BeginCopyFrom(ParseState *pstate,
 	 * only in text mode.
 	 */
 	initStringInfo(&cstate->attribute_buf);
-	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+	cstate->raw_buf = (IsParallelCopy()) ? NULL : (char *) palloc(RAW_BUF_SIZE + 1);
 	cstate->raw_buf_index = cstate->raw_buf_len = 0;
 	if (!cstate->binary)
 	{
@@ -4441,26 +5194,35 @@ NextCopyFromRawFields(CopyState cstate, char ***fields, int *nfields)
 	/* only available for text or csv input */
 	Assert(!cstate->binary);
 
-	/* on input just throw the header line away */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (IsParallelCopy())
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
-			return false;		/* done */
+		done = GetWorkerLine(cstate);
+		if (done && cstate->line_buf.len == 0)
+			return false;
 	}
+	else
+	{
+		/* on input just throw the header line away */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
+		{
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+				return false;		/* done */
+		}
 
-	cstate->cur_lineno++;
+		cstate->cur_lineno++;
 
-	/* Actually read the line into memory here */
-	done = CopyReadLine(cstate);
+		/* Actually read the line into memory here */
+		done = CopyReadLine(cstate);
 
-	/*
-	 * EOF at start of line means we're done.  If we see EOF after some
-	 * characters, we act as though it was newline followed by EOF, ie,
-	 * process the line and then exit loop on next iteration.
-	 */
-	if (done && cstate->line_buf.len == 0)
-		return false;
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			return false;
+	}
 
 	/* Parse the line into de-escaped field values */
 	if (cstate->csv_mode)
@@ -4708,9 +5470,31 @@ CopyReadLine(CopyState cstate)
 		 */
 		if (cstate->copy_dest == COPY_NEW_FE)
 		{
+			bool bIsFirst = true;
 			do
 			{
-				cstate->raw_buf_index = cstate->raw_buf_len;
+				if (!IsParallelCopy())
+					cstate->raw_buf_index = cstate->raw_buf_len;
+				else
+				{
+					if (cstate->raw_buf_index == RAW_BUF_SIZE)
+					{
+						/* Get a new block if it is the first time, From the
+						 * subsequent time, reset the index and re-use the same
+						 * block.
+						 */
+						if (bIsFirst)
+						{
+							ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+							uint32 block_pos = WaitGetFreeCopyBlock(pcshared_info);
+							cstate->raw_buf = pcshared_info->data_blocks[block_pos].data;
+							bIsFirst = false;
+						}
+
+						cstate->raw_buf_index = cstate->raw_buf_len = 0;
+					}
+				}
+
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
@@ -4765,7 +5549,7 @@ static void
 ConvertToServerEncoding(CopyState cstate)
 {
 	/* Done reading the line.  Convert it to server encoding. */
-	if (cstate->need_transcoding)
+	if (cstate->need_transcoding && (!IsParallelCopy() || IsWorker()))
 	{
 		char	   *cvt;
 		cvt = pg_any_to_server(cstate->line_buf.data,
@@ -4804,6 +5588,11 @@ CopyReadLineText(CopyState cstate)
 	char		quotec = '\0';
 	char		escapec = '\0';
 
+	/* For parallel copy */
+	int			line_size = 0;
+	int			line_pos = 0;
+
+	cstate->eol_type = EOL_UNKNOWN;
 	if (cstate->csv_mode)
 	{
 		quotec = cstate->quote[0];
@@ -4858,6 +5647,8 @@ CopyReadLineText(CopyState cstate)
 		if (raw_buf_ptr >= copy_buf_len || need_data)
 		{
 			REFILL_LINEBUF;
+			SetRawBufForLoad(cstate, line_size, copy_buf_len, raw_buf_ptr,
+							 &copy_raw_buf);
 
 			/*
 			 * Try to read some more data.  This will certainly reset
@@ -5082,9 +5873,15 @@ CopyReadLineText(CopyState cstate)
 				 * discard the data and the \. sequence.
 				 */
 				if (prev_raw_ptr > cstate->raw_buf_index)
-					appendBinaryStringInfo(&cstate->line_buf,
+				{
+					if (!IsParallelCopy())
+						appendBinaryStringInfo(&cstate->line_buf,
 										   cstate->raw_buf + cstate->raw_buf_index,
 										   prev_raw_ptr - cstate->raw_buf_index);
+					else
+						line_size += prev_raw_ptr - cstate->raw_buf_index;
+				}
+
 				cstate->raw_buf_index = raw_buf_ptr;
 				result = true;	/* report EOF */
 				break;
@@ -5136,6 +5933,26 @@ not_end_of_copy:
 			IF_NEED_REFILL_AND_EOF_BREAK(mblen - 1);
 			raw_buf_ptr += mblen - 1;
 		}
+
+		/*
+		 * Skip the header line. Update the line here, this cannot be done at
+		 * the beginning, as there is a possibility that file contains empty
+		 * lines.
+		 */
+		if (IsParallelCopy() && first_char_in_line && !IsHeaderLine())
+		{
+			ParallelCopyShmInfo	*pcshared_info = cstate->pcdata->pcshared_info;
+			ParallelCopyLineBoundary *lineInfo;
+			uint32			 line_first_block = pcshared_info->cur_block_pos;
+			line_pos = UpdateBlockInLineInfo(cstate,
+											   line_first_block,
+											   cstate->raw_buf_index, -1,
+											   LINE_LEADER_POPULATING);
+			lineInfo = &pcshared_info->line_boundaries.ring[line_pos];
+			elog(DEBUG1, "[Leader] Adding - block:%d, offset:%d, line position:%d",
+						 line_first_block,	lineInfo->start_offset, line_pos);
+		}
+
 		first_char_in_line = false;
 	}							/* end of outer loop */
 
@@ -5144,6 +5961,7 @@ not_end_of_copy:
 	 */
 	REFILL_LINEBUF;
 	CLEAR_EOL_LINE();
+	EndLineParallelCopy(cstate, line_pos, line_size, raw_buf_ptr);
 
 	return result;
 }
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index f41785f..81cc1f4 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -2353,7 +2353,7 @@ psql_completion(const char *text, int start, int end)
 	/* Complete COPY <sth> FROM|TO filename WITH ( */
 	else if (Matches("COPY|\\copy", MatchAny, "FROM|TO", MatchAny, "WITH", "("))
 		COMPLETE_WITH("FORMAT", "FREEZE", "DELIMITER", "NULL",
-					  "HEADER", "QUOTE", "ESCAPE", "FORCE_QUOTE",
+					  "HEADER", "PARALLEL", "QUOTE", "ESCAPE", "FORCE_QUOTE",
 					  "FORCE_NOT_NULL", "FORCE_NULL", "ENCODING");
 
 	/* Complete COPY <sth> FROM|TO filename WITH (FORMAT */
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index df1b43a..71a6c9b 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -385,6 +385,8 @@ extern FullTransactionId GetTopFullTransactionId(void);
 extern FullTransactionId GetTopFullTransactionIdIfAny(void);
 extern FullTransactionId GetCurrentFullTransactionId(void);
 extern FullTransactionId GetCurrentFullTransactionIdIfAny(void);
+extern void AssignFullTransactionIdForWorker(FullTransactionId fullTransactionId);
+extern void AssignCommandIdForWorker(CommandId commandId, bool used);
 extern void MarkCurrentTransactionIdLoggedIfAny(void);
 extern bool SubTransactionIsActive(SubTransactionId subxid);
 extern CommandId GetCurrentCommandId(bool used);
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index a0e4ac7..5e5c534 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1705,6 +1705,7 @@ ParallelCopyLineBoundary
 ParallelCopyData
 ParallelCopyDataBlock
 ParallelCopyLineBuf
+ParallelCopyLineState
 ParallelCopyShmInfo
 ParallelExecutorInfo
 ParallelHashGrowth
-- 
1.8.3.1

v4-0004-Documentation-for-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=v4-0004-Documentation-for-parallel-copy.patchDownload
From 65bb658d94e36d3d0f44a19ffaaf60315988c548 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Sat, 1 Aug 2020 09:00:36 +0530
Subject: [PATCH v4 4/6] Documentation for parallel copy.

This patch has the documentation changes for parallel copy.
---
 doc/src/sgml/ref/copy.sgml | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/doc/src/sgml/ref/copy.sgml b/doc/src/sgml/ref/copy.sgml
index 18189ab..2e023ed 100644
--- a/doc/src/sgml/ref/copy.sgml
+++ b/doc/src/sgml/ref/copy.sgml
@@ -37,6 +37,7 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
     DELIMITER '<replaceable class="parameter">delimiter_character</replaceable>'
     NULL '<replaceable class="parameter">null_string</replaceable>'
     HEADER [ <replaceable class="parameter">boolean</replaceable> ]
+    PARALLEL <replaceable class="parameter">integer</replaceable>
     QUOTE '<replaceable class="parameter">quote_character</replaceable>'
     ESCAPE '<replaceable class="parameter">escape_character</replaceable>'
     FORCE_QUOTE { ( <replaceable class="parameter">column_name</replaceable> [, ...] ) | * }
@@ -275,6 +276,22 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
    </varlistentry>
 
    <varlistentry>
+    <term><literal>PARALLEL</literal></term>
+    <listitem>
+     <para>
+      Perform <command>COPY FROM</command> in parallel using <replaceable
+      class="parameter"> integer</replaceable> background workers.  Please
+      note that it is not guaranteed that the number of parallel workers
+      specified in <replaceable class="parameter">integer</replaceable> will
+      be used during execution.  It is possible for a copy to run with fewer
+      workers than specified, or even with no workers at all (for example,
+      due to the setting of max_worker_processes). This option is allowed
+      only in <command>COPY FROM</command>.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><literal>QUOTE</literal></term>
     <listitem>
      <para>
-- 
1.8.3.1

v4-0005-Tests-for-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=v4-0005-Tests-for-parallel-copy.patchDownload
From ff4f2e8ba3ebf9a6ee25b40450c41c8175ec3e7e Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Sat, 1 Aug 2020 09:19:39 +0530
Subject: [PATCH v4 5/6] Tests for parallel copy.

This patch has the tests for parallel copy.
---
 src/test/regress/expected/copy2.out | 205 ++++++++++++++++++++++++++++++++++-
 src/test/regress/input/copy.source  |  12 +++
 src/test/regress/output/copy.source |  12 +++
 src/test/regress/sql/copy2.sql      | 208 +++++++++++++++++++++++++++++++++++-
 4 files changed, 429 insertions(+), 8 deletions(-)

diff --git a/src/test/regress/expected/copy2.out b/src/test/regress/expected/copy2.out
index e40287d..7ae5d44 100644
--- a/src/test/regress/expected/copy2.out
+++ b/src/test/regress/expected/copy2.out
@@ -254,18 +254,32 @@ It is "perfect".|
 "It is ""perfect"".","	"
 "",
 --test that we read consecutive LFs properly
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 COPY testnl FROM stdin CSV;
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+SELECT * FROM testnl;
+ a |          b           | c 
+---+----------------------+---
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+(2 rows)
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 COPY testeoc FROM stdin CSV;
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
 COPY testeoc TO stdout CSV;
 a\.
 \.b
 c\.d
 "\."
 -- test handling of nonstandard null marker that violates escaping rules
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 COPY testnull TO stdout WITH NULL AS E'\\0';
 1	\\0
@@ -280,6 +294,15 @@ SELECT * FROM testnull;
     | 
 (4 rows)
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 1);
+SELECT * FROM testnull;
+ a  | b  
+----+----
+ 42 | \0
+    | 
+(2 rows)
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -349,6 +372,34 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+SELECT * FROM vistest;
+ a  
+----
+ a2
+ b
+(2 rows)
+
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+COMMIT;
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 SELECT * FROM vistest;
  a 
@@ -409,7 +460,7 @@ SELECT * FROM vistest;
 (2 rows)
 
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -420,6 +471,8 @@ CREATE TEMP TABLE forcetest (
 -- should succeed with no effect ("b" remains an empty string, "c" remains NULL)
 BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 1);
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
  b |  c   
@@ -430,6 +483,8 @@ SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
 BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 1);
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
  c |  d   
@@ -486,6 +541,31 @@ select * from check_con_tbl;
    
 (2 rows)
 
+\d+ check_con_tbl
+                               Table "public.check_con_tbl"
+ Column |  Type   | Collation | Nullable | Default | Storage | Stats target | Description 
+--------+---------+-----------+----------+---------+---------+--------------+-------------
+ f1     | integer |           |          |         | plain   |              | 
+Check constraints:
+    "check_con_tbl_check" CHECK (check_con_function(check_con_tbl.*))
+
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 1);
+NOTICE:  input = {"f1":1}
+NOTICE:  input = {"f1":null}
+copy check_con_tbl from stdin with (parallel 1);
+NOTICE:  input = {"f1":0}
+ERROR:  new row for relation "check_con_tbl" violates check constraint "check_con_tbl_check"
+DETAIL:  Failing row contains (0).
+CONTEXT:  COPY check_con_tbl, line 1: "0"
+parallel worker
+select * from check_con_tbl;
+ f1 
+----
+  1
+   
+(2 rows)
+
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
 CREATE ROLE regress_rls_copy_user_colperms;
@@ -600,8 +680,125 @@ SELECT * FROM instead_of_insert_tbl;
 (2 rows)
 
 COMMIT;
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+COPY test_parallel_copy (a, b, c, d, e) from stdin with (PARALLEL 1);
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1, FORMAT 'csv', HEADER);
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0');
+ERROR:  value 0 out of bounds for option "parallel"
+DETAIL:  Valid values are between "1" and "1024".
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri from stdin with (FORMAT csv, DELIMITER ',', PARALLEL 1);
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1) WHERE height > random() * 65;
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+-- temporary table copy: should perform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+COPY temp_test (a) from stdin with (PARALLEL 1);
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) from stdin with (PARALLEL 1);
+ERROR:  column "xyz" of relation "test_parallel_copy" does not exist
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) from stdin with (PARALLEL 1);
+ERROR:  column "d" specified more than once
+-- missing data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  invalid input syntax for type integer: ""
+CONTEXT:  COPY test_parallel_copy, line 0, column a: ""
+parallel worker
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2000	230	23	23"
+parallel worker
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2001	231	\N	\N"
+parallel worker
+-- extra data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  extra data after last expected column
+CONTEXT:  COPY test_parallel_copy, line 1: "2002	232	40	50	60	70	80"
+parallel worker
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) from stdin with (delimiter ',', null 'x', PARALLEL 1) ;
+COPY test_parallel_copy from stdin WITH (DELIMITER ';', NULL '', PARALLEL 1);
+COPY test_parallel_copy from stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL 1);
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = 50004;
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a > 60003;
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE f > 60003;
+ERROR:  column "f" does not exist
+LINE 1: ..._parallel_copy from stdin WITH (PARALLEL 1) WHERE f > 60003;
+                                                             ^
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+ERROR:  missing FROM-clause entry for table "x"
+LINE 1: ...rallel_copy from stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+                                                                  ^
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (SELECT 1 FROM x);
+ERROR:  cannot use subquery in COPY FROM WHERE condition
+LINE 1: ...arallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (SELECT...
+                                                             ^
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (generate_series(1,5));
+ERROR:  set-returning functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...lel_copy from stdin WITH (PARALLEL 1) WHERE a IN (generate_s...
+                                                             ^
+COPY test_parallel_copy from stdin WITH(PARALLEL 1) WHERE a = row_number() over(b);
+ERROR:  window functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...rallel_copy from stdin WITH(PARALLEL 1) WHERE a = row_number...
+                                                             ^
+-- check results of copy in
+SELECT * FROM test_parallel_copy;
+   a   | b  |     c      |    d    |    e    
+-------+----+------------+---------+---------
+     1 | 11 | test_c1    | test_d1 | test_e1
+     2 | 12 | test_c2    | test_d2 | test_e2
+       |  3 | stuff      | test_d3 | 
+       |  4 | stuff      | test_d4 | 
+       |  5 | stuff      | test_d5 | 
+       |    | 45         | 80      | 90
+       |    | x          | \x      | \x
+       |    | ,          | \,      | \
+  3000 |    | c          |         | 
+  4000 |    | C          |         | 
+  4001 |  1 | empty      |         | 
+  4002 |  2 | null       |         | 
+  4003 |  3 | Backslash  | \       | \
+  4004 |  4 | BackslashX | \X      | \X
+  4005 |  5 | N          | N       | N
+  4006 |  6 | BackslashN | \N      | \N
+  4007 |  7 | XX         | XX      | XX
+  4008 |  8 | Delimiter  | :       | :
+ 50004 | 25 | 35         | 45      | 55
+ 60004 | 25 | 35         | 45      | 55
+ 60005 | 26 | 36         | 46      | 56
+(21 rows)
+
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
 DROP TABLE x, y;
diff --git a/src/test/regress/input/copy.source b/src/test/regress/input/copy.source
index a1d529a..159c058 100644
--- a/src/test/regress/input/copy.source
+++ b/src/test/regress/input/copy.source
@@ -15,6 +15,13 @@ DELETE FROM onek;
 
 COPY onek FROM '@abs_builddir@/results/onek.data';
 
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+
+SELECT COUNT(*) FROM tenk1;
+
+TRUNCATE tenk1;
+
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
@@ -159,6 +166,11 @@ truncate parted_copytest;
 
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
 
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
+
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/output/copy.source b/src/test/regress/output/copy.source
index 938d355..c3003fe 100644
--- a/src/test/regress/output/copy.source
+++ b/src/test/regress/output/copy.source
@@ -9,6 +9,15 @@ COPY onek FROM '@abs_srcdir@/data/onek.data';
 COPY onek TO '@abs_builddir@/results/onek.data';
 DELETE FROM onek;
 COPY onek FROM '@abs_builddir@/results/onek.data';
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+SELECT COUNT(*) FROM tenk1;
+ count 
+-------
+ 10000
+(1 row)
+
+TRUNCATE tenk1;
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
 COPY person FROM '@abs_srcdir@/data/person.data';
@@ -113,6 +122,9 @@ insert into parted_copytest select x,1,'One' from generate_series(1011,1020) x;
 copy (select * from parted_copytest order by a) to '@abs_builddir@/results/parted_copytest.csv';
 truncate parted_copytest;
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/sql/copy2.sql b/src/test/regress/sql/copy2.sql
index 902f4fa..7015698 100644
--- a/src/test/regress/sql/copy2.sql
+++ b/src/test/regress/sql/copy2.sql
@@ -157,7 +157,7 @@ COPY y TO stdout (FORMAT CSV, FORCE_QUOTE *);
 
 --test that we read consecutive LFs properly
 
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 
 COPY testnl FROM stdin CSV;
 1,"a field with two LFs
@@ -165,8 +165,16 @@ COPY testnl FROM stdin CSV;
 inside",2
 \.
 
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+1,"a field with two LFs
+
+inside",2
+\.
+
+SELECT * FROM testnl;
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 
 COPY testeoc FROM stdin CSV;
 a\.
@@ -175,11 +183,19 @@ c\.d
 "\."
 \.
 
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+a\.
+\.b
+c\.d
+"\."
+\.
+
 COPY testeoc TO stdout CSV;
 
 -- test handling of nonstandard null marker that violates escaping rules
 
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 
 COPY testnull TO stdout WITH NULL AS E'\\0';
@@ -191,6 +207,14 @@ COPY testnull FROM stdin WITH NULL AS E'\\0';
 
 SELECT * FROM testnull;
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 1);
+42	\\0
+\0	\0
+\.
+
+SELECT * FROM testnull;
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -235,6 +259,23 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+a2
+b
+\.
+SELECT * FROM vistest;
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+d2
+e
+\.
+SELECT * FROM vistest;
+COMMIT;
+SELECT * FROM vistest;
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 x
 y
@@ -284,7 +325,7 @@ SELECT * FROM vistest;
 COMMIT;
 SELECT * FROM vistest;
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -297,6 +338,10 @@ BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
 1,,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 1);
+1,,""
+\.
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
@@ -304,6 +349,10 @@ BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
 2,'a',,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 1);
+2,'a',,""
+\.
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
 -- should fail with not-null constraint violation
@@ -339,6 +388,16 @@ copy check_con_tbl from stdin;
 0
 \.
 select * from check_con_tbl;
+\d+ check_con_tbl
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 1);
+1
+\N
+\.
+copy check_con_tbl from stdin with (parallel 1);
+0
+\.
+select * from check_con_tbl;
 
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
@@ -440,8 +499,149 @@ test1
 SELECT * FROM instead_of_insert_tbl;
 COMMIT;
 
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+
+COPY test_parallel_copy (a, b, c, d, e) from stdin with (PARALLEL 1);
+1	11	test_c1	test_d1	test_e1
+2	12	test_c2	test_d2	test_e2
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+3	test_d3
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+4	test_d4
+5	test_d5
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1, FORMAT 'csv', HEADER);
+b	d
+\.
+
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0');
+
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri from stdin with (FORMAT csv, DELIMITER ',', PARALLEL 1);
+10
+\.
+
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1) WHERE height > random() * 65;
+60,60,60
+\.
+
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+60
+\.
+
+-- temporary table copy: should perform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+
+COPY temp_test (a) from stdin with (PARALLEL 1);
+10
+\.
+
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) from stdin with (PARALLEL 1);
+
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) from stdin with (PARALLEL 1);
+
+-- missing data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+
+\.
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+2000	230	23	23
+\.
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+2001	231	\N	\N
+\.
+
+-- extra data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+2002	232	40	50	60	70	80
+\.
+
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) from stdin with (delimiter ',', null 'x', PARALLEL 1) ;
+x,45,80,90
+x,\x,\\x,\\\x
+x,\,,\\\,,\\
+\.
+
+COPY test_parallel_copy from stdin WITH (DELIMITER ';', NULL '', PARALLEL 1);
+3000;;c;;
+\.
+
+COPY test_parallel_copy from stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL 1);
+4000:\X:C:\X:\X
+4001:1:empty::
+4002:2:null:\X:\X
+4003:3:Backslash:\\:\\
+4004:4:BackslashX:\\X:\\X
+4005:5:N:\N:\N
+4006:6:BackslashN:\\N:\\N
+4007:7:XX:\XX:\XX
+4008:8:Delimiter:\::\:
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = 50004;
+50003	24	34	44	54
+50004	25	35	45 	55
+50005	26	36	46	56
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a > 60003;
+60001	22	32	42	52
+60002	23	33	43	53
+60003	24	34	44	54
+60004	25	35	45	55
+60005	26	36	46	56
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE f > 60003;
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (SELECT 1 FROM x);
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (generate_series(1,5));
+
+COPY test_parallel_copy from stdin WITH(PARALLEL 1) WHERE a = row_number() over(b);
+
+-- check results of copy in
+SELECT * FROM test_parallel_copy;
+
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
 DROP TABLE x, y;
-- 
1.8.3.1

v4-0006-Parallel-Copy-For-Binary-Format-Files.patchtext/x-patch; charset=US-ASCII; name=v4-0006-Parallel-Copy-For-Binary-Format-Files.patchDownload
From ccbd0cc315e2733a104dedb984ad5003f74c97e5 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Tue, 18 Aug 2020 16:17:14 +0530
Subject: [PATCH v4 6/6] Parallel Copy For Binary Format Files

Leader reads data from the file into the DSM data blocks each of 64K size.
It also identifies each tuple data block id, start offset, end offset,
tuple size and updates this information in the ring data structure.
Workers parallelly read the tuple information from the ring data structure,
the actual tuple data from the data blocks and parallelly insert the tuples
into the table.
---
 src/backend/commands/copy.c | 684 ++++++++++++++++++++++++++++++++++++++------
 1 file changed, 599 insertions(+), 85 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 868ba4a..f63dc49 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -264,6 +264,17 @@ typedef struct ParallelCopyLineBuf
 }ParallelCopyLineBuf;
 
 /*
+ * Represents the usage mode for CopyReadBinaryGetDataBlock.
+ */
+typedef enum FieldInfoType
+{
+	FIELD_NONE = 0,
+	FIELD_COUNT,
+	FIELD_SIZE,
+	FIELD_DATA
+} FieldInfoType;
+
+/*
  * Parallel copy data information.
  */
 typedef struct ParallelCopyData
@@ -284,6 +295,9 @@ typedef struct ParallelCopyData
 
 	/* Current position in worker_line_buf */
 	uint32				worker_line_buf_pos;
+
+	/* For binary formatted files */
+	ParallelCopyDataBlock *curr_data_block;
 }ParallelCopyData;
 
 /*
@@ -448,6 +462,7 @@ typedef struct SerializedParallelCopyState
 	/* Working state for COPY FROM */
 	AttrNumber          num_defaults;
 	Oid                 relid;
+	bool				binary;
 }SerializedParallelCopyState;
 
 /* DestReceiver for COPY (query) TO */
@@ -522,7 +537,6 @@ typedef struct CopyMultiInsertInfo
 	int			ti_options;		/* table insert options */
 } CopyMultiInsertInfo;
 
-
 /*
  * These macros centralize code used to process line_buf and raw_buf buffers.
  * They are macros because they often do continue/break control and to avoid
@@ -650,11 +664,113 @@ if (!IsParallelCopy()) \
 else \
 	return pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
 
+/*
+ * CHECK_FIELD_COUNT - Handles the error cases for field count
+ * for binary format files.
+ */
+#define CHECK_FIELD_COUNT \
+{\
+	if (fld_count == -1) \
+	{ \
+		if (IsParallelCopy() && \
+			!IsLeader()) \
+			return true; \
+		else if (IsParallelCopy() && \
+			IsLeader()) \
+		{ \
+			if (cstate->pcdata->curr_data_block->data[cstate->raw_buf_index + sizeof(fld_count)] != 0) \
+				ereport(ERROR, \
+						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+						errmsg("received copy data after EOF marker"))); \
+			return true; \
+		} \
+		else \
+		{ \
+			/* \
+			* Received EOF marker.  In a V3-protocol copy, wait for the \
+			* protocol-level EOF, and complain if it doesn't come \
+			* immediately.  This ensures that we correctly handle CopyFail, \
+			* if client chooses to send that now. \
+			* \
+			* Note that we MUST NOT try to read more data in an old-protocol \
+			* copy, since there is no protocol-level EOF marker then.  We \
+			* could go either way for copy from file, but choose to throw \
+			* error if there's data after the EOF marker, for consistency \
+			* with the new-protocol case. \
+			*/ \
+			char		dummy; \
+			if (cstate->copy_dest != COPY_OLD_FE && \
+				CopyReadBinaryData(cstate, &dummy, 1) > 0) \
+				ereport(ERROR, \
+						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+						errmsg("received copy data after EOF marker"))); \
+				return false; \
+		} \
+	} \
+	if (fld_count != cstate->max_fields) \
+		ereport(ERROR, \
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+				errmsg("row field count is %d, expected %d", \
+				(int) fld_count, cstate->max_fields))); \
+}
+
+/*
+ * CHECK_FIELD_SIZE - Handles the error case for field size
+ * for binary format files.
+ */
+#define CHECK_FIELD_SIZE(fld_size) \
+{ \
+	if (fld_size < -1) \
+		ereport(ERROR, \
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+				errmsg("invalid field size")));\
+}
+
+/*
+ * EOF_ERROR - Error statement for EOF for binary format
+ * files.
+ */
+#define EOF_ERROR \
+{ \
+	ereport(ERROR, \
+		(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+		errmsg("unexpected EOF in COPY data")));\
+}
+
+/*
+ * GET_RAW_BUF_INDEX - Calculates the raw buf index for the cases
+ * where the data spread is across multiple data blocks.
+ */
+#define GET_RAW_BUF_INDEX(raw_buf_index, fld_size, required_blks, curr_blk_bytes) \
+{ \
+	raw_buf_index = fld_size - (((required_blks - 1) * DATA_BLOCK_SIZE) + curr_blk_bytes); \
+}
+
+/*
+ * GET_REQUIRED_BLOCKS - Calculates the number of data
+ * blocks required for the cases where the data spread
+ * is across multiple data blocks.
+ */
+#define GET_REQUIRED_BLOCKS(required_blks, fld_size, curr_blk_bytes) \
+{ \
+	/* \
+	 * field size can spread across multiple data blocks, \
+	 * calculate the number of required data blocks and try to get \
+	 * those many data blocks. \
+	 */ \
+	required_blks = (int32)(fld_size - curr_blk_bytes)/(int32)DATA_BLOCK_SIZE; \
+	/* \
+	 * check if we need the data block for the field data \
+	 * bytes that are not modulus of data block size. \
+	 */ \
+	if ((fld_size - curr_blk_bytes)%DATA_BLOCK_SIZE != 0) \
+		required_blks++; \
+}
+
 /* End parallel copy Macros */
 
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
-
 /* non-export function prototypes */
 static CopyState BeginCopy(ParseState *pstate, bool is_from, Relation rel,
 						   RawStmt *raw_query, Oid queryRelId, List *attnamelist,
@@ -709,6 +825,14 @@ static void ExecBeforeStmtTrigger(CopyState cstate);
 static void CheckTargetRelValidity(CopyState cstate);
 static void PopulateCstateCatalogInfo(CopyState cstate);
 static pg_attribute_always_inline uint32 GetLinePosition(CopyState cstate);
+static uint32 WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info);
+static bool CopyReadBinaryTupleLeader(CopyState cstate);
+static void CopyReadBinaryFindTupleSize(CopyState cstate, uint32 *line_size);
+static bool CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls);
+static Datum CopyReadBinaryAttributeWorker(CopyState cstate, FmgrInfo *flinfo,
+										   Oid typioparam, int32 typmod, bool *isnull);
+static void CopyReadBinaryGetDataBlock(CopyState cstate, FieldInfoType field_info);
+
 /*
  * SerializeParallelCopyState - Copy shared_cstate using cstate information.
  */
@@ -726,6 +850,7 @@ SerializeParallelCopyState(CopyState cstate, SerializedParallelCopyState *shared
 	shared_cstate->convert_selectively = cstate->convert_selectively;
 	shared_cstate->num_defaults = cstate->num_defaults;
 	shared_cstate->relid = cstate->pcdata->relid;
+	shared_cstate->binary = cstate->binary;
 }
 
 /*
@@ -885,8 +1010,8 @@ FindInsertMethod(CopyState cstate)
 static pg_attribute_always_inline bool
 IsParallelCopyAllowed(CopyState cstate)
 {
-	/* Parallel copy not allowed for frontend (2.0 protocol) & binary option. */
-	if ((cstate->copy_dest == COPY_OLD_FE) || cstate->binary)
+	/* Parallel copy not allowed for frontend (2.0 protocol). */
+	if (cstate->copy_dest == COPY_OLD_FE)
 		return false;
 
 	/* Check if copy is into foreign table or temporary table. */
@@ -1156,6 +1281,7 @@ InitializeParallelCopyInfo(SerializedParallelCopyState *shared_cstate,
 	cstate->convert_selectively = shared_cstate->convert_selectively;
 	cstate->num_defaults = shared_cstate->num_defaults;
 	pcdata->relid = shared_cstate->relid;
+	cstate->binary = shared_cstate->binary;
 
 	PopulateCommonCstateInfo(cstate, tup_desc, attnamelist);
 
@@ -1551,32 +1677,66 @@ ParallelCopyFrom(CopyState cstate)
 	/* Execute the before statement triggers from the leader */
 	ExecBeforeStmtTrigger(cstate);
 
-	/* On input just throw the header line away. */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (!cstate->binary)
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
+		/* On input just throw the header line away. */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
 		{
-			pcshared_info->is_read_in_progress = false;
-			return;			/* done */
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+			{
+				pcshared_info->is_read_in_progress = false;
+				return;			/* done */
+			}
 		}
-	}
 
-	for (;;)
-	{
-		bool done;
-		cstate->cur_lineno++;
+		for (;;)
+		{
+			bool done;
+			cstate->cur_lineno++;
 
-		/* Actually read the line into memory here. */
-		done = CopyReadLine(cstate);
+			/* Actually read the line into memory here. */
+			done = CopyReadLine(cstate);
 
+			/*
+			* EOF at start of line means we're done.  If we see EOF after some
+			* characters, we act as though it was newline followed by EOF, ie,
+			* process the line and then exit loop on next iteration.
+			*/
+			if (done && cstate->line_buf.len == 0)
+				break;
+		}
+	}
+	else
+	{
 		/*
-		 * EOF at start of line means we're done.  If we see EOF after some
-		 * characters, we act as though it was newline followed by EOF, ie,
-		 * process the line and then exit loop on next iteration.
+		 * Binary Format Files.
+		 * For parallel copy leader, fill in the error
+		 * context information here, in case any failures
+		 * while determining tuple offsets, leader
+		 * would throw the errors with proper context.
 		 */
-		if (done && cstate->line_buf.len == 0)
-			break;
+		ErrorContextCallback errcallback;
+		errcallback.callback = CopyFromErrorCallback;
+		errcallback.arg = (void *) cstate;
+		errcallback.previous = error_context_stack;
+		error_context_stack = &errcallback;
+		cstate->pcdata->curr_data_block = NULL;
+		cstate->raw_buf_index = 0;
+		pcshared_info->populated = 0;
+		cstate->cur_lineno = 0;
+		cstate->max_fields = list_length(cstate->attnumlist);
+
+		for (;;)
+		{
+			bool eof = false;
+			cstate->cur_lineno++;
+
+			eof = CopyReadBinaryTupleLeader(cstate);
+
+			if (eof)
+				break;
+		}
 	}
 
 	pcshared_info->is_read_in_progress = false;
@@ -1584,7 +1744,355 @@ ParallelCopyFrom(CopyState cstate)
  }
 
 /*
- * GetLinePosition - return the line position that worker should process.
+ * CopyReadBinaryGetDataBlock - gets a new block, updates
+ * the current offset, calculates the skip bytes.
+ */
+static void
+CopyReadBinaryGetDataBlock(CopyState cstate, FieldInfoType field_info)
+{
+	ParallelCopyDataBlock *data_block = NULL;
+	ParallelCopyDataBlock *curr_data_block = cstate->pcdata->curr_data_block;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	uint8 move_bytes = 0;
+	uint32 block_pos;
+	uint32 prev_block_pos;
+	int read_bytes = 0;
+
+	prev_block_pos = pcshared_info->cur_block_pos;
+
+	block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+	if (field_info == FIELD_SIZE || field_info == FIELD_COUNT)
+		move_bytes = (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+
+	if (curr_data_block != NULL)
+		curr_data_block->skip_bytes = move_bytes;
+
+	data_block = &pcshared_info->data_blocks[block_pos];
+
+	if (move_bytes > 0 && curr_data_block != NULL)
+		memmove(&data_block->data[0], &curr_data_block->data[cstate->raw_buf_index], move_bytes);
+
+	elog(DEBUG1, "LEADER - field info %d is spread across data blocks - moved %d bytes from current block %u to %u block",
+		field_info, move_bytes, prev_block_pos, block_pos);
+
+	read_bytes = CopyGetData(cstate, &data_block->data[move_bytes], 1, (DATA_BLOCK_SIZE - move_bytes));
+
+	if (field_info == FIELD_NONE && cstate->reached_eof)
+		return;
+
+	if (cstate->reached_eof)
+		EOF_ERROR;
+
+	elog(DEBUG1, "LEADER - bytes read from file %d", read_bytes);
+
+	if(field_info == FIELD_SIZE || field_info == FIELD_DATA)
+	{
+		ParallelCopyDataBlock *prev_data_block = NULL;
+		prev_data_block = curr_data_block;
+		prev_data_block->following_block = block_pos;
+
+		if (prev_data_block->curr_blk_completed  == false)
+			prev_data_block->curr_blk_completed = true;
+
+		pg_atomic_add_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+	}
+
+	cstate->pcdata->curr_data_block = data_block;
+	cstate->raw_buf_index = 0;
+}
+
+/*
+ * CopyReadBinaryTupleLeader - leader reads data from binary formatted file
+ * to data blocks and identifies tuple boundaries/offsets so that workers
+ * can work on the data blocks data.
+ */
+static bool
+CopyReadBinaryTupleLeader(CopyState cstate)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	int16		fld_count;
+	uint32      line_size = 0;
+	uint32 		start_block_pos;
+	uint32		start_offset;
+
+	if (cstate->pcdata->curr_data_block == NULL)
+	{
+		CopyReadBinaryGetDataBlock(cstate, FIELD_NONE);
+
+		/*
+		 * no data is read from file here. one possibility
+		 * to be here could be that the binary file just
+		 * has a valid signature but nothing else.
+		 */
+		if (cstate->reached_eof)
+			return true;
+	}
+
+	if ((cstate->raw_buf_index + sizeof(fld_count)) >= DATA_BLOCK_SIZE)
+		CopyReadBinaryGetDataBlock(cstate, FIELD_COUNT);
+
+	memcpy(&fld_count, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_count));
+	fld_count = (int16) pg_ntoh16(fld_count);
+	CHECK_FIELD_COUNT;
+	start_offset = cstate->raw_buf_index;
+	cstate->raw_buf_index += sizeof(fld_count);
+	line_size += sizeof(fld_count);
+	start_block_pos = pcshared_info->cur_block_pos;
+
+	CopyReadBinaryFindTupleSize(cstate, &line_size);
+
+	pg_atomic_add_fetch_u32(&cstate->pcdata->curr_data_block->unprocessed_line_parts, 1);
+
+	if (line_size > 0)
+	{
+		int line_pos = UpdateBlockInLineInfo(cstate,
+											start_block_pos,
+											start_offset,
+											line_size,
+											LINE_LEADER_POPULATED);
+
+		pcshared_info->populated++;
+		elog(DEBUG1, "LEADER - adding - block:%u, offset:%u, line size:%u line position:%d",
+				start_block_pos, start_offset, line_size, line_pos);
+	}
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryFindTupleSize - leader identifies boundaries/
+ * offsets for each attribute/column and finally results in the
+ * tuple/row size. It moves on to next data block if the attribute/
+ * column is spread across data blocks.
+ */
+static void
+CopyReadBinaryFindTupleSize(CopyState cstate, uint32 *line_size)
+{
+	int32		fld_size;
+	ListCell   *cur;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			att_num = lfirst_int(cur);
+		Form_pg_attribute att = TupleDescAttr(tup_desc, (att_num - 1));
+		cstate->cur_attname = NameStr(att->attname);
+		fld_size = 0;
+
+		if ((cstate->raw_buf_index + sizeof(fld_size)) >= DATA_BLOCK_SIZE)
+			CopyReadBinaryGetDataBlock(cstate, FIELD_SIZE);
+
+		memcpy(&fld_size, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_size));
+		cstate->raw_buf_index += sizeof(fld_size);
+		*line_size += sizeof(fld_size);
+		fld_size = (int32) pg_ntoh32(fld_size);
+
+		CHECK_FIELD_SIZE(fld_size);
+
+		*line_size += fld_size;
+
+		if ((DATA_BLOCK_SIZE - cstate->raw_buf_index) >= fld_size)
+		{
+			cstate->raw_buf_index += fld_size;
+			elog(DEBUG1, "LEADER - tuple lies in he same data block");
+		}
+		else
+		{
+			int32 required_blks = 0;
+			int32 curr_blk_bytes = (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+			int i = 0;
+
+			GET_REQUIRED_BLOCKS(required_blks, fld_size, curr_blk_bytes);
+
+			i = required_blks;
+
+			while(i > 0)
+			{
+				CopyReadBinaryGetDataBlock(cstate, FIELD_DATA);
+				i--;
+			}
+
+			GET_RAW_BUF_INDEX(cstate->raw_buf_index, fld_size, required_blks, curr_blk_bytes);
+
+			/*
+			 * raw_buf_index should never cross data block size,
+			 * as the required number of data blocks would have
+			 * been obtained in the above while loop.
+			 */
+			Assert(cstate->raw_buf_index <= DATA_BLOCK_SIZE);
+		}
+		cstate->cur_attname = NULL;
+	}
+}
+
+/*
+ * CopyReadBinaryTupleWorker - each worker reads data from data blocks after
+ * getting leader-identified tuple offsets from ring data structure.
+ */
+static bool
+CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls)
+{
+	uint32 		line_pos;
+	ParallelCopyLineBoundary *line_info;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	int16		fld_count;
+	ListCell   *cur;
+	FmgrInfo   *in_functions = cstate->in_functions;
+	Oid		   *typioparams = cstate->typioparams;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	line_pos = GetLinePosition(cstate);
+
+	if (line_pos == -1)
+		return true;
+
+	line_info = &pcshared_info->line_boundaries.ring[line_pos];
+	cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[line_info->first_block];
+	cstate->raw_buf_index = line_info->start_offset;
+
+	if (cstate->raw_buf_index + sizeof(fld_count) >= DATA_BLOCK_SIZE)
+	{
+		/*
+		 * The case where field count spread across datablocks should never occur,
+		 * as the leader would have moved it to next block. this code exists for
+		 * debugging purposes only.
+		 */
+		elog(DEBUG1, "WORKER - field count spread across datablocks should never occur");
+	}
+
+	memcpy(&fld_count, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_count));
+	fld_count = (int16) pg_ntoh16(fld_count);
+
+	CHECK_FIELD_COUNT;
+
+	cstate->raw_buf_index += sizeof(fld_count);
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			att_num = lfirst_int(cur);
+		int			m = att_num - 1;
+		Form_pg_attribute att = TupleDescAttr(tup_desc, m);
+		cstate->cur_attname = NameStr(att->attname);
+
+		values[m] = CopyReadBinaryAttributeWorker(cstate,
+											&in_functions[m],
+											typioparams[m],
+											att->atttypmod,
+											&nulls[m]);
+		cstate->cur_attname = NULL;
+	}
+
+	pg_atomic_sub_fetch_u32(&cstate->pcdata->curr_data_block->unprocessed_line_parts, 1);
+	line_info->start_offset = -1;
+	pg_atomic_write_u32(&line_info->line_state, LINE_WORKER_PROCESSED);
+	pg_atomic_write_u32(&line_info->line_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryAttributeWorker - leader identifies boundaries/offsets
+ * for each attribute/column, it moves on to next data block if the
+ * attribute/column is spread across data blocks.
+ */
+static Datum
+CopyReadBinaryAttributeWorker(CopyState cstate, FmgrInfo *flinfo,
+		Oid typioparam, int32 typmod, bool *isnull)
+{
+	int32		fld_size;
+	Datum		result;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+	if ((cstate->raw_buf_index + sizeof(fld_size)) >= DATA_BLOCK_SIZE)
+	{
+		ParallelCopyDataBlock *prev_data_block = cstate->pcdata->curr_data_block;
+		elog(DEBUG1, "WORKER - field size is spread across data blocks");
+		cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[prev_data_block->following_block];
+		pg_atomic_sub_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+		cstate->raw_buf_index = 0;
+	}
+
+	memcpy(&fld_size, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_size));
+	fld_size = (int32) pg_ntoh32(fld_size);
+
+	CHECK_FIELD_SIZE(fld_size);
+
+	cstate->raw_buf_index += sizeof(fld_size);
+
+	/* reset attribute_buf to empty, and load raw data in it */
+	resetStringInfo(&cstate->attribute_buf);
+
+	enlargeStringInfo(&cstate->attribute_buf, fld_size);
+
+	if ((DATA_BLOCK_SIZE - cstate->raw_buf_index) >= fld_size)
+	{
+		elog(DEBUG1, "WORKER - tuple lies in single data block");
+		memcpy(&cstate->attribute_buf.data[0],&cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], fld_size);
+		cstate->raw_buf_index += fld_size;
+	}
+	else
+	{
+		uint32 att_buf_idx = 0;
+		uint32 copy_bytes = 0;
+		int32 required_blks = 0;
+		int32 curr_blk_bytes = (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+		ParallelCopyDataBlock *prev_data_block = NULL;
+		int i = 0;
+
+		GET_REQUIRED_BLOCKS(required_blks, fld_size, curr_blk_bytes);
+
+		i = required_blks;
+		prev_data_block = cstate->pcdata->curr_data_block;
+		elog(DEBUG1, "WORKER - tuple is spread across data blocks");
+		memcpy(&cstate->attribute_buf.data[0], &prev_data_block->data[cstate->raw_buf_index],
+				curr_blk_bytes);
+		copy_bytes = curr_blk_bytes;
+		att_buf_idx = curr_blk_bytes;
+
+		while (i>0)
+		{
+			cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[prev_data_block->following_block];
+			pg_atomic_sub_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+			cstate->raw_buf_index = 0;
+			copy_bytes = fld_size - att_buf_idx;
+
+			/*
+			 * the bytes that are yet to be taken into att buff are more than
+			 * the entire data block size, but only take the data block size
+			 * elements.
+			 */
+			if (copy_bytes >= DATA_BLOCK_SIZE)
+				copy_bytes = DATA_BLOCK_SIZE;
+
+			memcpy(&cstate->attribute_buf.data[att_buf_idx],
+				&cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], copy_bytes);
+			att_buf_idx += copy_bytes;
+			i--;
+		}
+		GET_RAW_BUF_INDEX(cstate->raw_buf_index, fld_size, required_blks, curr_blk_bytes);
+	}
+
+	cstate->attribute_buf.len = fld_size;
+	cstate->attribute_buf.data[fld_size] = '\0';
+
+	/* Call the column type's binary input converter */
+	result = ReceiveFunctionCall(flinfo, &cstate->attribute_buf,
+								 typioparam, typmod);
+
+	/* Trouble if it didn't eat the whole buffer */
+	if (cstate->attribute_buf.cursor != cstate->attribute_buf.len)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+				 errmsg("incorrect binary data format")));
+
+	*isnull = false;
+	return result;
+}
+
+/*
+ * GetLinePosition - return the line position that worker should pcdata->process.
  */
 static uint32
 GetLinePosition(CopyState cstate)
@@ -1672,7 +2180,9 @@ GetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
 		{
 			dataBlkPtr->curr_blk_completed = false;
 			dataBlkPtr->skip_bytes = 0;
+			dataBlkPtr->following_block = -1;
 			pcshared_info->cur_block_pos = block_pos;
+			MemSet(&dataBlkPtr->data[0], 0, DATA_BLOCK_SIZE);
 			return block_pos;
 		}
 
@@ -2188,10 +2698,26 @@ CopyGetInt32(CopyState cstate, int32 *val)
 {
 	uint32		buf;
 
-	if (CopyReadBinaryData(cstate, (char *) &buf, sizeof(buf)) != sizeof(buf))
+	/*
+	 * For parallel copy, avoid reading data to raw buf, read directly
+	 * from file, later the data will be read to parallel copy data
+	 * buffers.
+	 */
+	if (cstate->nworkers > 0)
 	{
-		*val = 0;				/* suppress compiler warning */
-		return false;
+		if (CopyGetData(cstate, &buf, sizeof(buf), sizeof(buf)) != sizeof(buf))
+		{
+			*val = 0;				/* suppress compiler warning */
+			return false;
+		}
+	}
+	else
+	{
+		if (CopyReadBinaryData(cstate, (char *) &buf, sizeof(buf)) != sizeof(buf))
+		{
+			*val = 0;				/* suppress compiler warning */
+			return false;
+		}
 	}
 	*val = (int32) pg_ntoh32(buf);
 	return true;
@@ -2580,7 +3106,15 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 			EndParallelCopy(pcxt);
 		}
 		else
+		{
+			/*
+			 * Reset nworkers to -1 here. This is useful in cases where user
+			 * specifies parallel workers, but, no worker is picked up, so go
+			 * back to non parallel mode value of nworkers.
+			 */
+			cstate->nworkers = -1;
 			*processed = CopyFrom(cstate); /* copy from file to database */
+		}
 
 		EndCopyFrom(cstate);
 	}
@@ -5045,7 +5579,7 @@ BeginCopyFrom(ParseState *pstate,
 	 * only in text mode.
 	 */
 	initStringInfo(&cstate->attribute_buf);
-	cstate->raw_buf = (IsParallelCopy()) ? NULL : (char *) palloc(RAW_BUF_SIZE + 1);
+	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
 	cstate->raw_buf_index = cstate->raw_buf_len = 0;
 	if (!cstate->binary)
 	{
@@ -5125,7 +5659,7 @@ BeginCopyFrom(ParseState *pstate,
 		int32		tmp;
 
 		/* Signature */
-		if (CopyReadBinaryData(cstate, readSig, 11) != 11 ||
+		if (CopyGetData(cstate, readSig, 11, 11) != 11 ||
 			memcmp(readSig, BinarySignature, 11) != 0)
 			ereport(ERROR,
 					(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
@@ -5153,7 +5687,7 @@ BeginCopyFrom(ParseState *pstate,
 		/* Skip extension header, if present */
 		while (tmp-- > 0)
 		{
-			if (CopyReadBinaryData(cstate, readSig, 1) != 1)
+			if (CopyGetData(cstate, readSig, 1, 1) != 1)
 				ereport(ERROR,
 						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
 						 errmsg("invalid COPY file header (wrong length)")));
@@ -5350,60 +5884,45 @@ NextCopyFrom(CopyState cstate, ExprContext *econtext,
 	else
 	{
 		/* binary */
-		int16		fld_count;
-		ListCell   *cur;
-
 		cstate->cur_lineno++;
+		cstate->max_fields = list_length(cstate->attnumlist);
 
-		if (!CopyGetInt16(cstate, &fld_count))
+		if (!IsParallelCopy())
 		{
-			/* EOF detected (end of file, or protocol-level EOF) */
-			return false;
-		}
+			int16		fld_count;
+			ListCell   *cur;
 
-		if (fld_count == -1)
-		{
-			/*
-			 * Received EOF marker.  In a V3-protocol copy, wait for the
-			 * protocol-level EOF, and complain if it doesn't come
-			 * immediately.  This ensures that we correctly handle CopyFail,
-			 * if client chooses to send that now.
-			 *
-			 * Note that we MUST NOT try to read more data in an old-protocol
-			 * copy, since there is no protocol-level EOF marker then.  We
-			 * could go either way for copy from file, but choose to throw
-			 * error if there's data after the EOF marker, for consistency
-			 * with the new-protocol case.
-			 */
-			char		dummy;
-
-			if (cstate->copy_dest != COPY_OLD_FE &&
-				CopyReadBinaryData(cstate, &dummy, 1) > 0)
-				ereport(ERROR,
-						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-						 errmsg("received copy data after EOF marker")));
-			return false;
-		}
+			if (!CopyGetInt16(cstate, &fld_count))
+			{
+				/* EOF detected (end of file, or protocol-level EOF) */
+				return false;
+			}
 
-		if (fld_count != attr_count)
-			ereport(ERROR,
-					(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-					 errmsg("row field count is %d, expected %d",
-							(int) fld_count, attr_count)));
+			CHECK_FIELD_COUNT;
 
-		foreach(cur, cstate->attnumlist)
+			foreach(cur, cstate->attnumlist)
+			{
+				int			attnum = lfirst_int(cur);
+				int			m = attnum - 1;
+				Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+
+				cstate->cur_attname = NameStr(att->attname);
+				values[m] = CopyReadBinaryAttribute(cstate,
+													&in_functions[m],
+													typioparams[m],
+													att->atttypmod,
+													&nulls[m]);
+				cstate->cur_attname = NULL;
+			}
+		}
+		else
 		{
-			int			attnum = lfirst_int(cur);
-			int			m = attnum - 1;
-			Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+			bool eof = false;
 
-			cstate->cur_attname = NameStr(att->attname);
-			values[m] = CopyReadBinaryAttribute(cstate,
-												&in_functions[m],
-												typioparams[m],
-												att->atttypmod,
-												&nulls[m]);
-			cstate->cur_attname = NULL;
+			eof = CopyReadBinaryTupleWorker(cstate, values, nulls);
+
+			if (eof)
+				return false;
 		}
 	}
 
@@ -6403,18 +6922,15 @@ CopyReadBinaryAttribute(CopyState cstate, FmgrInfo *flinfo,
 	Datum		result;
 
 	if (!CopyGetInt32(cstate, &fld_size))
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("unexpected EOF in COPY data")));
+		EOF_ERROR;
+
 	if (fld_size == -1)
 	{
 		*isnull = true;
 		return ReceiveFunctionCall(flinfo, NULL, typioparam, typmod);
 	}
-	if (fld_size < 0)
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("invalid field size")));
+
+	CHECK_FIELD_SIZE(fld_size);
 
 	/* reset attribute_buf to empty, and load raw data in it */
 	resetStringInfo(&cstate->attribute_buf);
@@ -6422,9 +6938,7 @@ CopyReadBinaryAttribute(CopyState cstate, FmgrInfo *flinfo,
 	enlargeStringInfo(&cstate->attribute_buf, fld_size);
 	if (CopyReadBinaryData(cstate, cstate->attribute_buf.data,
 						   fld_size) != fld_size)
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("unexpected EOF in COPY data")));
+		EOF_ERROR;
 
 	cstate->attribute_buf.len = fld_size;
 	cstate->attribute_buf.data[fld_size] = '\0';
-- 
1.8.3.1

#131Greg Nancarrow
gregn4422@gmail.com
In reply to: vignesh C (#130)
1 attachment(s)
Re: Parallel copy

I have attached new set of patches with the fixes.
Thoughts?

Hi Vignesh,

I don't really have any further comments on the code, but would like
to share some results of some Parallel Copy performance tests I ran
(attached).

The tests loaded a 5GB CSV data file into a 100 column table (of
different data types). The following were varied as part of the test:
- Number of workers (1 – 10)
- No indexes / 4-indexes
- Default settings / increased resources (shared_buffers,work_mem, etc.)

(I did not do any partition-related tests as I believe those type of
tests were previously performed)

I built Postgres (latest OSS code) with the latest Parallel Copy patches (v4).
The test system was a 32-core Intel Xeon E5-4650 server with 378GB of RAM.

I observed the following trends:
- For the data file size used, Parallel Copy achieved best performance
using about 9 – 10 workers. Larger data files may benefit from using
more workers. However, I couldn’t really see any better performance,
for example, from using 16 workers on a 10GB CSV data file compared to
using 8 workers. Results may also vary depending on machine
characteristics.
- Parallel Copy with 1 worker ran slower than normal Copy in a couple
of cases (I did question if allowing 1 worker was useful in my patch
review).
- Typical load time improvement (load factor) for Parallel Copy was
between 2x and 3x. Better load factors can be obtained by using larger
data files and/or more indexes.
- Increasing Postgres resources made little or no difference to
Parallel Copy performance when the target table had no indexes.
Increasing Postgres resources improved Parallel Copy performance when
the target table had indexes.

Regards,
Greg Nancarrow
Fujitsu Australia

Attachments:

parallel_copy_perf_summary_5GB_csv.txttext/plain; charset=US-ASCII; name=parallel_copy_perf_summary_5GB_csv.txtDownload
#132Amit Kapila
amit.kapila16@gmail.com
In reply to: Greg Nancarrow (#131)
Re: Parallel copy

On Thu, Aug 27, 2020 at 8:04 AM Greg Nancarrow <gregn4422@gmail.com> wrote:

I have attached new set of patches with the fixes.
Thoughts?

Hi Vignesh,

I don't really have any further comments on the code, but would like
to share some results of some Parallel Copy performance tests I ran
(attached).

The tests loaded a 5GB CSV data file into a 100 column table (of
different data types). The following were varied as part of the test:
- Number of workers (1 – 10)
- No indexes / 4-indexes
- Default settings / increased resources (shared_buffers,work_mem, etc.)

(I did not do any partition-related tests as I believe those type of
tests were previously performed)

I built Postgres (latest OSS code) with the latest Parallel Copy patches (v4).
The test system was a 32-core Intel Xeon E5-4650 server with 378GB of RAM.

I observed the following trends:
- For the data file size used, Parallel Copy achieved best performance
using about 9 – 10 workers. Larger data files may benefit from using
more workers. However, I couldn’t really see any better performance,
for example, from using 16 workers on a 10GB CSV data file compared to
using 8 workers. Results may also vary depending on machine
characteristics.
- Parallel Copy with 1 worker ran slower than normal Copy in a couple
of cases (I did question if allowing 1 worker was useful in my patch
review).

I think the reason is that for 1 worker case there is not much
parallelization as a leader doesn't perform the actual load work.
Vignesh, can you please once see if the results are reproducible at
your end, if so, we can once compare the perf profiles to see why in
some cases we get improvement and in other cases not. Based on that we
can decide whether to allow the 1 worker case or not.

- Typical load time improvement (load factor) for Parallel Copy was
between 2x and 3x. Better load factors can be obtained by using larger
data files and/or more indexes.

Nice improvement and I think you are right that with larger load data
we will get even better improvement.

--
With Regards,
Amit Kapila.

#133vignesh C
vignesh21@gmail.com
In reply to: Amit Kapila (#132)
Re: Parallel copy

On Thu, Aug 27, 2020 at 8:24 AM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Thu, Aug 27, 2020 at 8:04 AM Greg Nancarrow <gregn4422@gmail.com> wrote:

I have attached new set of patches with the fixes.
Thoughts?

Hi Vignesh,

I don't really have any further comments on the code, but would like
to share some results of some Parallel Copy performance tests I ran
(attached).

The tests loaded a 5GB CSV data file into a 100 column table (of
different data types). The following were varied as part of the test:
- Number of workers (1 – 10)
- No indexes / 4-indexes
- Default settings / increased resources (shared_buffers,work_mem, etc.)

(I did not do any partition-related tests as I believe those type of
tests were previously performed)

I built Postgres (latest OSS code) with the latest Parallel Copy patches (v4).
The test system was a 32-core Intel Xeon E5-4650 server with 378GB of RAM.

I observed the following trends:
- For the data file size used, Parallel Copy achieved best performance
using about 9 – 10 workers. Larger data files may benefit from using
more workers. However, I couldn’t really see any better performance,
for example, from using 16 workers on a 10GB CSV data file compared to
using 8 workers. Results may also vary depending on machine
characteristics.
- Parallel Copy with 1 worker ran slower than normal Copy in a couple
of cases (I did question if allowing 1 worker was useful in my patch
review).

I think the reason is that for 1 worker case there is not much
parallelization as a leader doesn't perform the actual load work.
Vignesh, can you please once see if the results are reproducible at
your end, if so, we can once compare the perf profiles to see why in
some cases we get improvement and in other cases not. Based on that we
can decide whether to allow the 1 worker case or not.

I will spend some time on this and update.

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

#134Amit Kapila
amit.kapila16@gmail.com
In reply to: vignesh C (#133)
Re: Parallel copy

On Thu, Aug 27, 2020 at 4:56 PM vignesh C <vignesh21@gmail.com> wrote:

On Thu, Aug 27, 2020 at 8:24 AM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Thu, Aug 27, 2020 at 8:04 AM Greg Nancarrow <gregn4422@gmail.com> wrote:

I have attached new set of patches with the fixes.
Thoughts?

Hi Vignesh,

I don't really have any further comments on the code, but would like
to share some results of some Parallel Copy performance tests I ran
(attached).

The tests loaded a 5GB CSV data file into a 100 column table (of
different data types). The following were varied as part of the test:
- Number of workers (1 – 10)
- No indexes / 4-indexes
- Default settings / increased resources (shared_buffers,work_mem, etc.)

(I did not do any partition-related tests as I believe those type of
tests were previously performed)

I built Postgres (latest OSS code) with the latest Parallel Copy patches (v4).
The test system was a 32-core Intel Xeon E5-4650 server with 378GB of RAM.

I observed the following trends:
- For the data file size used, Parallel Copy achieved best performance
using about 9 – 10 workers. Larger data files may benefit from using
more workers. However, I couldn’t really see any better performance,
for example, from using 16 workers on a 10GB CSV data file compared to
using 8 workers. Results may also vary depending on machine
characteristics.
- Parallel Copy with 1 worker ran slower than normal Copy in a couple
of cases (I did question if allowing 1 worker was useful in my patch
review).

I think the reason is that for 1 worker case there is not much
parallelization as a leader doesn't perform the actual load work.
Vignesh, can you please once see if the results are reproducible at
your end, if so, we can once compare the perf profiles to see why in
some cases we get improvement and in other cases not. Based on that we
can decide whether to allow the 1 worker case or not.

I will spend some time on this and update.

Thanks.

--
With Regards,
Amit Kapila.

#135vignesh C
vignesh21@gmail.com
In reply to: Greg Nancarrow (#131)
Re: Parallel copy

On Thu, Aug 27, 2020 at 8:04 AM Greg Nancarrow <gregn4422@gmail.com> wrote:

- Parallel Copy with 1 worker ran slower than normal Copy in a couple
of cases (I did question if allowing 1 worker was useful in my patch
review).

Thanks Greg for your review & testing.
I had executed various tests with 1GB, 2GB & 5GB with 100 columns without
parallel mode & with 1 parallel worker. Test result for the same is as
given below:
Test Without parallel mode With 1 Parallel worker
1GB csv file 100 columns
(100 bytes data in each column) 62 seconds 47 seconds (1.32X)
1GB csv file 100 columns
(1000 bytes data in each column) 89 seconds 78 seconds (1.14X)
2GB csv file 100 columns
(1 byte data in each column) 277 seconds 256 seconds (1.08X)
5GB csv file 100 columns
(100 byte data in each column) 515 seconds 445 seconds (1.16X)
I have run the tests multiple times and have noticed the similar execution
times in all the runs for the above tests.
In the above results there is slight improvement with 1 worker. In my tests
I did not observe the degradation for copy with 1 worker compared to the
non parallel copy. Can you share with me the script you used to generate
the data & the ddl of the table, so that it will help me check that
scenario you faced the problem.

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

#136Greg Nancarrow
gregn4422@gmail.com
In reply to: vignesh C (#135)
Re: Parallel copy

Hi Vignesh,

Can you share with me the script you used to generate the data & the ddl of the table, so that it will help me check that >scenario you faced the >problem.

Unfortunately I can't directly share it (considered company IP),
though having said that it's only doing something that is relatively
simple and unremarkable, so I'd expect it to be much like what you are
currently doing. I can describe it in general.

The table being used contains 100 columns (as I pointed out earlier),
with the first column of "bigserial" type, and the others of different
types like "character varying(255)", "numeric", "date" and "time
without timezone". There's about 60 of the "character varying(255)"
overall, with the other types interspersed.

When testing with indexes, 4 b-tree indexes were used that each
included the first column and then distinctly 9 other columns.

A CSV record (row) template file was created with test data
(corresponding to the table), and that was simply copied and appended
over and over with a record prefix in order to create the test data
file.
The following shell-script basically does it (but very slowly). I was
using a small C program to do similar, a lot faster.
In my case, N=2550000 produced about a 5GB CSV file.

file_out=data.csv; for i in {1..N}; do echo -n "$i," >> $file_out;
cat sample_record.csv >> $file_out; done

One other thing I should mention is that between each test run, I
cleared the OS page cache, as described here:
https://linuxhint.com/clear_cache_linux/
That way, each COPY FROM is not taking advantage of any OS-cached data
from a previous COPY FROM.

If your data is somehow significantly different and you want to (and
can) share your script, then I can try it in my environment.

Regards,
Greg

#137vignesh C
vignesh21@gmail.com
In reply to: Greg Nancarrow (#136)
2 attachment(s)
Re: Parallel copy

On Tue, Sep 1, 2020 at 3:39 PM Greg Nancarrow <gregn4422@gmail.com> wrote:

Hi Vignesh,

Can you share with me the script you used to generate the data & the ddl of the table, so that it will help me check that >scenario you faced the >problem.

Unfortunately I can't directly share it (considered company IP),
though having said that it's only doing something that is relatively
simple and unremarkable, so I'd expect it to be much like what you are
currently doing. I can describe it in general.

The table being used contains 100 columns (as I pointed out earlier),
with the first column of "bigserial" type, and the others of different
types like "character varying(255)", "numeric", "date" and "time
without timezone". There's about 60 of the "character varying(255)"
overall, with the other types interspersed.

When testing with indexes, 4 b-tree indexes were used that each
included the first column and then distinctly 9 other columns.

A CSV record (row) template file was created with test data
(corresponding to the table), and that was simply copied and appended
over and over with a record prefix in order to create the test data
file.
The following shell-script basically does it (but very slowly). I was
using a small C program to do similar, a lot faster.
In my case, N=2550000 produced about a 5GB CSV file.

file_out=data.csv; for i in {1..N}; do echo -n "$i," >> $file_out;
cat sample_record.csv >> $file_out; done

One other thing I should mention is that between each test run, I
cleared the OS page cache, as described here:
https://linuxhint.com/clear_cache_linux/
That way, each COPY FROM is not taking advantage of any OS-cached data
from a previous COPY FROM.

I will try with a similar test and check if I can reproduce.

If your data is somehow significantly different and you want to (and
can) share your script, then I can try it in my environment.

I have attached the scripts that I used for the test results I
mentioned in my previous mail. create.sql file has the table that I
used, insert_data_gen.txt has the insert data generation scripts. I
varied the count in insert_data_gen to generate csv files of 1GB, 2GB
& 5GB & varied the data to generate 1 char, 10 char & 100 char for
each column for various testing. You can rename insert_data_gen.txt to
insert_data_gen.sh & generate the csv file.

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

Attachments:

insert_data_gen.txttext/plain; charset=US-ASCII; name=insert_data_gen.txtDownload
create.sqlapplication/sql; name=create.sqlDownload
#138Greg Nancarrow
gregn4422@gmail.com
In reply to: vignesh C (#137)
Re: Parallel copy

On Wed, Sep 2, 2020 at 3:40 PM vignesh C <vignesh21@gmail.com> wrote:
I have attached the scripts that I used for the test results I
mentioned in my previous mail. create.sql file has the table that I
used, insert_data_gen.txt has the insert data generation scripts. I
varied the count in insert_data_gen to generate csv files of 1GB, 2GB
& 5GB & varied the data to generate 1 char, 10 char & 100 char for
each column for various testing. You can rename insert_data_gen.txt to
insert_data_gen.sh & generate the csv file.

Hi Vignesh,

I used your script and table definition, multiplying the number of
records to produce a 5GB and 9.5GB CSV file.
I got the following results:

(1) Postgres default settings, 5GB CSV (530000 rows):

Copy Type Duration (s) Load factor
===============================================
Normal Copy 132.197 -

Parallel Copy
(#workers)
1 98.428 1.34
2 52.753 2.51
3 37.630 3.51
4 33.554 3.94
5 33.636 3.93
6 33.821 3.91
7 34.270 3.86
8 34.465 3.84
9 34.315 3.85
10 33.543 3.94

(2) Postgres increased resources, 5GB CSV (530000 rows):

shared_buffers = 20% of RAM (total RAM = 376GB) = 76GB
work_mem = 10% of RAM = 38GB
maintenance_work_mem = 10% of RAM = 38GB
max_worker_processes = 16
max_parallel_workers = 16
checkpoint_timeout = 30min
max_wal_size=2GB

Copy Type Duration (s) Load factor
===============================================
Normal Copy 131.835 -

Parallel Copy
(#workers)
1 98.301 1.34
2 53.261 2.48
3 37.868 3.48
4 34.224 3.85
5 33.831 3.90
6 34.229 3.85
7 34.512 3.82
8 34.303 3.84
9 34.690 3.80
10 34.479 3.82

(3) Postgres default settings, 9.5GB CSV (1000000 rows):

Copy Type Duration (s) Load factor
===============================================
Normal Copy 248.503 -

Parallel Copy
(#workers)
1 185.724 1.34
2 99.832 2.49
3 70.560 3.52
4 63.328 3.92
5 63.182 3.93
6 64.108 3.88
7 64.131 3.87
8 64.350 3.86
9 64.293 3.87
10 63.818 3.89

(4) Postgres increased resources, 9.5GB CSV (1000000 rows):

shared_buffers = 20% of RAM (total RAM = 376GB) = 76GB
work_mem = 10% of RAM = 38GB
maintenance_work_mem = 10% of RAM = 38GB
max_worker_processes = 16
max_parallel_workers = 16
checkpoint_timeout = 30min
max_wal_size=2GB

Copy Type Duration (s) Load factor
===============================================
Normal Copy 248.647 -

Parallel Copy
(#workers)
1 182.236 1.36
2 92.814 2.68
3 67.347 3.69
4 63.839 3.89
5 62.672 3.97
6 63.873 3.89
7 64.930 3.83
8 63.885 3.89
9 62.397 3.98
10 64.477 3.86

So as you found, with this particular table definition and data, 1
parallel worker always performs better than normal copy.
The different result obtained for this particular case seems to be
caused by the following factors:
- different table definition (I used a variety of column types)
- amount of data per row (I used less data per row, so more rows per
same size data file)

As I previously observed, if the target table has no indexes,
increasing resources beyond the default settings makes little
difference to the performance.

Regards,
Greg Nancarrow
Fujitsu Australia

#139vignesh C
vignesh21@gmail.com
In reply to: Greg Nancarrow (#136)
Re: Parallel copy

On Tue, Sep 1, 2020 at 3:39 PM Greg Nancarrow <gregn4422@gmail.com> wrote:

Hi Vignesh,

Can you share with me the script you used to generate the data & the ddl of the table, so that it will help me check that >scenario you faced the >problem.

Unfortunately I can't directly share it (considered company IP),
though having said that it's only doing something that is relatively
simple and unremarkable, so I'd expect it to be much like what you are
currently doing. I can describe it in general.

The table being used contains 100 columns (as I pointed out earlier),
with the first column of "bigserial" type, and the others of different
types like "character varying(255)", "numeric", "date" and "time
without timezone". There's about 60 of the "character varying(255)"
overall, with the other types interspersed.

Thanks Greg for executing & sharing the results.
I tried with a similar test case that you suggested, I was not able to
reproduce the degradation scenario.
If it is possible, can you run perf for the scenario with 1 worker &
non parallel mode & share the perf results, we will be able to find
out which of the functions is consuming more time by doing a
comparison of the perf reports.
Steps for running perf:
1) get the postgres pid
2) perf record -a -g -p <above pid>
3) Run copy command
4) Execute "perf report -g" once copy finishes.

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

#140Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Amit Kapila (#1)
1 attachment(s)
Re: Parallel copy

On Fri, Sep 11, 2020 at 3:49 AM Greg Nancarrow <gregn4422@gmail.com> wrote:

I couldn't use the original machine from which I obtained the previous
results, but ended up using a 4-core CentOS7 VM, which showed a
similar pattern in the performance results for this test case.
I obtained the following results from loading a 2GB CSV file (1000000
rows, 4 indexes):

Copy Type Duration (s) Load factor
===============================================
Normal Copy 190.891 -

Parallel Copy
(#workers)
1 210.947 0.90

Hi Greg,

I tried to recreate the test case(attached) and I didn't find much
difference with the custom postgresql.config file.
Test case: 250000 tuples, 4 indexes(composite indexes with 10
columns), 3.7GB, 100 columns(as suggested by you and all the
varchar(255) columns are having 255 characters), exec time in sec.

With custom postgresql.conf[1]Postgres configuration used for above testing: shared_buffers = 40GB max_worker_processes = 32 max_parallel_maintenance_workers = 24 max_parallel_workers = 32 synchronous_commit = off checkpoint_timeout = 1d max_wal_size = 24GB min_wal_size = 15GB autovacuum = off, removed and recreated the data
directory after every run(I couldn't perform the OS page cache flush
due to some reasons. So, chose this recreation of data dir way, for
testing purpose):
HEAD: 129.547, 128.624, 128.890
Patch: 0 workers - 130.213, 131.298, 130.555
Patch: 1 worker - 127.757, 125.560, 128.275

With default postgresql.conf, removed and recreated the data directory
after every run:
HEAD: 138.276, 150.472, 153.304
Patch: 0 workers - 162.468, 149.423, 159.137
Patch: 1 worker - 136.055, 144.250, 137.916

Few questions:
1. Was the run performed with default postgresql.conf file? If not,
what are the changed configurations?
2. Are the readings for normal copy(190.891sec, mentioned by you
above) taken on HEAD or with patch, 0 workers? How much is the runtime
with your test case on HEAD(Without patch) and 0 workers(With patch)?
3. Was the run performed on release build?
4. Were the readings taken on multiple runs(say 3 or 4 times)?

[1]: Postgres configuration used for above testing: shared_buffers = 40GB max_worker_processes = 32 max_parallel_maintenance_workers = 24 max_parallel_workers = 32 synchronous_commit = off checkpoint_timeout = 1d max_wal_size = 24GB min_wal_size = 15GB autovacuum = off
shared_buffers = 40GB
max_worker_processes = 32
max_parallel_maintenance_workers = 24
max_parallel_workers = 32
synchronous_commit = off
checkpoint_timeout = 1d
max_wal_size = 24GB
min_wal_size = 15GB
autovacuum = off

With Regards,
Bharath Rupireddy.
EnterpriseDB: http://www.enterprisedb.com

Attachments:

testcase.rtftext/rtf; charset=US-ASCII; name=testcase.rtfDownload
#141Greg Nancarrow
gregn4422@gmail.com
In reply to: Bharath Rupireddy (#140)
1 attachment(s)
Re: Parallel copy

Hi Bharath,

On Tue, Sep 15, 2020 at 11:49 PM Bharath Rupireddy
<bharath.rupireddyforpostgres@gmail.com> wrote:

Few questions:
1. Was the run performed with default postgresql.conf file? If not,
what are the changed configurations?

Yes, just default settings.

2. Are the readings for normal copy(190.891sec, mentioned by you
above) taken on HEAD or with patch, 0 workers?

With patch

How much is the runtime
with your test case on HEAD(Without patch) and 0 workers(With patch)?

TBH, I didn't test that. Looking at the changes, I wouldn't expect a
degradation of performance for normal copy (you have tested, right?).

3. Was the run performed on release build?

For generating the perf data I sent (normal copy vs parallel copy with
1 worker), I used a debug build (-g -O0), as that is needed for
generating all the relevant perf data for Postgres code. Previously I
ran with a release build (-O2).

4. Were the readings taken on multiple runs(say 3 or 4 times)?

The readings I sent were from just one run (not averaged), but I did
run the tests several times to verify the readings were representative
of the pattern I was seeing.

Fortunately I have been given permission to share the exact table
definition and data I used, so you can check the behaviour and timings
on your own test machine.
Please see the attachment.
You can create the table using the table.sql and index_4.sql
definitions in the "sql" directory.
The data.csv file (to be loaded by COPY) can be created with the
included "dupdata" tool in the "input" directory, which you need to
build, then run, specifying a suitable number of records and path of
the template record (see README). Obviously the larger the number of
records, the larger the file ...
The table can then be loaded using COPY with "format csv" (and
"parallel N" if testing parallel copy).

Regards,
Greg Nancarrow
Fujitsu Australia

Attachments:

table_data_generation_files_to_share.zipapplication/zip; name=table_data_generation_files_to_share.zipDownload
#142Ashutosh Sharma
ashu.coek88@gmail.com
In reply to: vignesh C (#130)
Re: Parallel copy

Hi Vignesh,

I've spent some time today looking at your new set of patches and I've
some thoughts and queries which I would like to put here:

Why are these not part of the shared cstate structure?

SerializeString(pcxt, PARALLEL_COPY_KEY_NULL_PRINT, cstate->null_print);
SerializeString(pcxt, PARALLEL_COPY_KEY_DELIM, cstate->delim);
SerializeString(pcxt, PARALLEL_COPY_KEY_QUOTE, cstate->quote);
SerializeString(pcxt, PARALLEL_COPY_KEY_ESCAPE, cstate->escape);

I think in the refactoring patch we could replace all the cstate
variables that would be shared between the leader and workers with a
common structure which would be used even for a serial copy. Thoughts?

--

Have you tested your patch when encoding conversion is needed? If so,
could you please point out the email that has the test results.

--

Apart from above, I've noticed some cosmetic errors which I am sharing here:

+#define    IsParallelCopy()        (cstate->is_parallel)
+#define IsLeader()             (cstate->pcdata->is_leader)

This doesn't look to be properly aligned.

--

+   shared_info_ptr = (ParallelCopyShmInfo *)
shm_toc_allocate(pcxt->toc, sizeof(ParallelCopyShmInfo));
+   PopulateParallelCopyShmInfo(shared_info_ptr, full_transaction_id);

..

+   /* Store shared build state, for which we reserved space. */
+   shared_cstate = (SerializedParallelCopyState
*)shm_toc_allocate(pcxt->toc, est_cstateshared);

In the first case, while typecasting you've added a space between the
typename and the function but that is missing in the second case. I
think it would be good if you could make it consistent.

Same comment applies here as well:

+   pg_atomic_uint32    line_state;     /* line state */
+   uint64              cur_lineno;     /* line number for error messages */
+}ParallelCopyLineBoundary;

...

+   CommandId                   mycid;  /* command id */
+   ParallelCopyLineBoundaries  line_boundaries; /* line array */
+} ParallelCopyShmInfo;

There is no space between the closing brace and the structure name in
the first case but it is in the second one. So, again this doesn't
look consistent.

I could also find this type of inconsistency in comments. See below:

+/* It can hold upto 10000 record information for worker to process. RINGSIZE
+ * should be a multiple of WORKER_CHUNK_COUNT, as wrap around cases
is currently
+ * not handled while selecting the WORKER_CHUNK_COUNT by the worker. */
+#define RINGSIZE (10 * 1000)

...

+/*
+ * Each worker will be allocated WORKER_CHUNK_COUNT of records from DSM data
+ * block to process to avoid lock contention. Read RINGSIZE comments before
+ * changing this value.
+ */
+#define WORKER_CHUNK_COUNT 50

You may see these kinds of errors at other places as well if you scan
through your patch.

--
With Regards,
Ashutosh Sharma
EnterpriseDB:http://www.enterprisedb.com

Show quoted text

On Wed, Aug 19, 2020 at 11:51 AM vignesh C <vignesh21@gmail.com> wrote:

Thanks Greg for reviewing the patch. Please find my thoughts for your comments.

On Mon, Aug 17, 2020 at 9:44 AM Greg Nancarrow <gregn4422@gmail.com> wrote:

Some further comments:

(1) v3-0002-Framework-for-leader-worker-in-parallel-copy.patch

+/*
+ * Each worker will be allocated WORKER_CHUNK_COUNT of records from DSM data
+ * block to process to avoid lock contention. This value should be divisible by
+ * RINGSIZE, as wrap around cases is currently not handled while selecting the
+ * WORKER_CHUNK_COUNT by the worker.
+ */
+#define WORKER_CHUNK_COUNT 50

"This value should be divisible by RINGSIZE" is not a correct
statement (since obviously 50 is not divisible by 10000).
It should say something like "This value should evenly divide into
RINGSIZE", or "RINGSIZE should be a multiple of WORKER_CHUNK_COUNT".

Fixed. Changed it to RINGSIZE should be a multiple of WORKER_CHUNK_COUNT.

(2) v3-0003-Allow-copy-from-command-to-process-data-from-file.patch

(i)

+                       /*
+                        * If the data is present in current block
lineInfo. line_size
+                        * will be updated. If the data is spread
across the blocks either

Somehow a space has been put between "lineinfo." and "line_size".
It should be: "If the data is present in current block
lineInfo.line_size will be updated"

Fixed, changed it to lineinfo->line_size.

(ii)

This is not possible because of pg_atomic_compare_exchange_u32, this
will succeed only for one of the workers whose line_state is
LINE_LEADER_POPULATED, for other workers it will fail. This is
explained in detail above ParallelCopyLineBoundary.

Yes, but prior to that call to pg_atomic_compare_exchange_u32(),
aren't you separately reading line_state and line_state, so that
between those reads, it may have transitioned from leader to another
worker, such that the read line state ("cur_line_state", being checked
in the if block) may not actually match what is now in the line_state
and/or the read line_size ("dataSize") doesn't actually correspond to
the read line state?

(sorry, still not 100% convinced that the synchronization and checks
are safe in all cases)

I think that you are describing about the problem could happen in the
following case:
when we read curr_line_state, the value was LINE_WORKER_PROCESSED or
LINE_WORKER_PROCESSING. Then in some cases if the leader is very fast
compared to the workers then the leader quickly populates one line and
sets the state to LINE_LEADER_POPULATED. State is changed to
LINE_LEADER_POPULATED when we are checking the currr_line_state.
I feel this will not be a problem because, Leader will populate & wait
till some RING element is available to populate. In the meantime
worker has seen that state is LINE_WORKER_PROCESSED or
LINE_WORKER_PROCESSING(previous state that it read), worker has
identified that this chunk was processed by some other worker, worker
will move and try to get the next available chunk & insert those
records. It will keep continuing till it gets the next chunk to
process. Eventually one of the workers will get this chunk and process
it.

(3) v3-0006-Parallel-Copy-For-Binary-Format-Files.patch

raw_buf is not used in parallel copy, instead raw_buf will be pointing
to shared memory data blocks. This memory was allocated as part of
BeginCopyFrom, uptil this point we cannot be 100% sure as copy can be
performed sequentially like in case max_worker_processes is not
available, if it switches to sequential mode raw_buf will be used
while performing copy operation. At this place we can safely free this
memory that was allocated

So the following code (which checks raw_buf, which still points to
memory that has been pfreed) is still valid?

In the SetRawBufForLoad() function, which is called by CopyReadLineText():

cur_data_blk_ptr = (cstate->raw_buf) ?
&pcshared_info->data_blocks[cur_block_pos] : NULL;

The above code looks a bit dicey to me. I stepped over that line in
the debugger when I debugged an instance of Parallel Copy, so it
definitely gets executed.
It makes me wonder what other code could possibly be checking raw_buf
and using it in some way, when in fact what it points to has been
pfreed.

Are you able to add the following line of code, or will it (somehow)
break logic that you are relying on?

pfree(cstate->raw_buf);
cstate->raw_buf = NULL; <=== I suggest that this line is added

You are right, I have debugged & verified it sets it to an invalid
block which is not expected. There are chances this would have caused
some corruption in some machines. The suggested fix is required, I
have fixed it. I have moved this change to
0003-Allow-copy-from-command-to-process-data-from-file.patch as
0006-Parallel-Copy-For-Binary-Format-Files is only for Binary format
parallel copy & that change is common change for parallel copy.

I have attached new set of patches with the fixes.
Thoughts?

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

#143Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Greg Nancarrow (#141)
Re: Parallel copy

On Wed, Sep 16, 2020 at 1:20 PM Greg Nancarrow <gregn4422@gmail.com> wrote:

Fortunately I have been given permission to share the exact table
definition and data I used, so you can check the behaviour and timings
on your own test machine.

Thanks Greg for the script. I ran your test case and I didn't observe
any increase in exec time with 1 worker, indeed, we have benefitted a
few seconds from 0 to 1 worker as expected.

Execution time is in seconds. Each test case is executed 3 times on
release build. Each time the data directory is recreated.

Case 1: 1000000 rows, 2GB
With Patch, default configuration, 0 worker: 88.933, 92.261, 88.423
With Patch, default configuration, 1 worker: 73.825, 74.583, 72.678

With Patch, custom configuration, 0 worker: 76.191, 78.160, 78.822
With Patch, custom configuration, 1 worker: 61.289, 61.288, 60.573

Case 2: 2550000 rows, 5GB
With Patch, default configuration, 0 worker: 246.031, 188.323, 216.683
With Patch, default configuration, 1 worker: 156.299, 153.293, 170.307

With Patch, custom configuration, 0 worker: 197.234, 195.866, 196.049
With Patch, custom configuration, 1 worker: 157.173, 158.287, 157.090

[1]: Custom configuration is set up to ensure that no other processes influence the results. The postgresql.conf used: shared_buffers = 40GB synchronous_commit = off checkpoint_timeout = 1d max_wal_size = 24GB min_wal_size = 15GB autovacuum = off max_worker_processes = 32 max_parallel_maintenance_workers = 24 max_parallel_workers = 32
influence the results. The postgresql.conf used:
shared_buffers = 40GB
synchronous_commit = off
checkpoint_timeout = 1d
max_wal_size = 24GB
min_wal_size = 15GB
autovacuum = off
max_worker_processes = 32
max_parallel_maintenance_workers = 24
max_parallel_workers = 32

With Regards,
Bharath Rupireddy.
EnterpriseDB: http://www.enterprisedb.com

#144vignesh C
vignesh21@gmail.com
In reply to: Ashutosh Sharma (#142)
6 attachment(s)
Re: Parallel copy

Thanks Ashutosh for your comments.

On Wed, Sep 16, 2020 at 6:36 PM Ashutosh Sharma <ashu.coek88@gmail.com> wrote:

Hi Vignesh,

I've spent some time today looking at your new set of patches and I've
some thoughts and queries which I would like to put here:

Why are these not part of the shared cstate structure?

SerializeString(pcxt, PARALLEL_COPY_KEY_NULL_PRINT, cstate->null_print);
SerializeString(pcxt, PARALLEL_COPY_KEY_DELIM, cstate->delim);
SerializeString(pcxt, PARALLEL_COPY_KEY_QUOTE, cstate->quote);
SerializeString(pcxt, PARALLEL_COPY_KEY_ESCAPE, cstate->escape);

I have used shared_cstate mainly to share the integer & bool data
types from the leader to worker process. The above data types are of
char* data type, I will not be able to use it like how I could do it
for integer type. So I preferred to send these as separate keys to the
worker. Thoughts?

I think in the refactoring patch we could replace all the cstate
variables that would be shared between the leader and workers with a
common structure which would be used even for a serial copy. Thoughts?

Currently we are using shared_cstate only to share integer & bool data
types from leader to worker. Once worker retrieves the shared data for
integer & bool data types, worker will copy it to cstate. I preferred
this way because only for integer & bool we retrieve to shared_cstate
& copy it to cstate and for rest of the members any way we are
directly copying back to cstate. Thoughts?

Have you tested your patch when encoding conversion is needed? If so,
could you please point out the email that has the test results.

We have not yet done encoding testing, we will do and post the results
separately in the coming days.

Apart from above, I've noticed some cosmetic errors which I am sharing here:

+#define    IsParallelCopy()        (cstate->is_parallel)
+#define IsLeader()             (cstate->pcdata->is_leader)

This doesn't look to be properly aligned.

Fixed.

+   shared_info_ptr = (ParallelCopyShmInfo *)
shm_toc_allocate(pcxt->toc, sizeof(ParallelCopyShmInfo));
+   PopulateParallelCopyShmInfo(shared_info_ptr, full_transaction_id);

..

+   /* Store shared build state, for which we reserved space. */
+   shared_cstate = (SerializedParallelCopyState
*)shm_toc_allocate(pcxt->toc, est_cstateshared);

In the first case, while typecasting you've added a space between the
typename and the function but that is missing in the second case. I
think it would be good if you could make it consistent.

Fixed

Same comment applies here as well:

+   pg_atomic_uint32    line_state;     /* line state */
+   uint64              cur_lineno;     /* line number for error messages */
+}ParallelCopyLineBoundary;

...

+   CommandId                   mycid;  /* command id */
+   ParallelCopyLineBoundaries  line_boundaries; /* line array */
+} ParallelCopyShmInfo;

There is no space between the closing brace and the structure name in
the first case but it is in the second one. So, again this doesn't
look consistent.

Fixed

I could also find this type of inconsistency in comments. See below:

+/* It can hold upto 10000 record information for worker to process. RINGSIZE
+ * should be a multiple of WORKER_CHUNK_COUNT, as wrap around cases
is currently
+ * not handled while selecting the WORKER_CHUNK_COUNT by the worker. */
+#define RINGSIZE (10 * 1000)

...

+/*
+ * Each worker will be allocated WORKER_CHUNK_COUNT of records from DSM data
+ * block to process to avoid lock contention. Read RINGSIZE comments before
+ * changing this value.
+ */
+#define WORKER_CHUNK_COUNT 50

You may see these kinds of errors at other places as well if you scan
through your patch.

Fixed.

Please find the attached v5 patch which has the fixes for the same.
Thoughts?

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

Attachments:

v5-0001-Copy-code-readjustment-to-support-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=v5-0001-Copy-code-readjustment-to-support-parallel-copy.patchDownload
From 443297e9b1f842a78cdd37e6f273dbfa7a706897 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Sat, 1 Aug 2020 08:52:48 +0530
Subject: [PATCH v5 1/6] Copy code readjustment to support parallel copy.

This patch has the copy code slightly readjusted so that the common code is
separated to functions/macros, these functions/macros will be used by the
workers in the parallel copy code of the upcoming patches. EOL removal is moved
from CopyReadLine to CopyReadLineText, this change was required because in case
of parallel copy the record identification and record updation is done in
CopyReadLineText, before record information is updated in shared memory the new
line characters should be removed.
---
 src/backend/commands/copy.c | 360 ++++++++++++++++++++++++++------------------
 1 file changed, 217 insertions(+), 143 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 2047557..cf7277a 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -95,6 +95,9 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
+#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+#define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
+
 /*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
@@ -224,7 +227,6 @@ typedef struct CopyStateData
 	 * appropriate amounts of data from this buffer.  In both modes, we
 	 * guarantee that there is a \0 at raw_buf[raw_buf_len].
 	 */
-#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
@@ -354,6 +356,27 @@ if (1) \
 	goto not_end_of_copy; \
 } else ((void) 0)
 
+/*
+ * CLEAR_EOL_LINE - Wrapper for clearing EOL.
+ */
+#define CLEAR_EOL_LINE() \
+if (!result && !IsHeaderLine()) \
+	ClearEOLFromCopiedData(cstate, cstate->line_buf.data, \
+						   cstate->line_buf.len, \
+						   &cstate->line_buf.len) \
+
+/*
+ * INCREMENTPROCESSED - Increment the lines processed.
+ */
+#define INCREMENTPROCESSED(processed)  \
+processed++;
+
+/*
+ * RETURNPROCESSED - Get the lines processed.
+ */
+#define RETURNPROCESSED(processed) \
+return processed;
+
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
 
@@ -401,7 +424,11 @@ static bool CopyGetInt16(CopyState cstate, int16 *val);
 static bool CopyLoadRawBuf(CopyState cstate);
 static int	CopyReadBinaryData(CopyState cstate, char *dest, int nbytes);
 
-
+static void PopulateCommonCstateInfo(CopyState cstate, TupleDesc tup_desc,
+									 List *attnamelist);
+static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
+								   int copy_line_pos, int *copy_line_size);
+static void ConvertToServerEncoding(CopyState cstate);
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
  * in past protocol redesigns.
@@ -801,14 +828,18 @@ CopyLoadRawBuf(CopyState cstate)
 {
 	int			nbytes = RAW_BUF_BYTES(cstate);
 	int			inbytes;
+	int         minread = 1;
 
 	/* Copy down the unprocessed data if any. */
 	if (nbytes > 0)
 		memmove(cstate->raw_buf, cstate->raw_buf + cstate->raw_buf_index,
 				nbytes);
 
+	if (cstate->copy_dest == COPY_NEW_FE)
+		minread = RAW_BUF_SIZE - nbytes;
+
 	inbytes = CopyGetData(cstate, cstate->raw_buf + nbytes,
-						  1, RAW_BUF_SIZE - nbytes);
+						  minread, RAW_BUF_SIZE - nbytes);
 	nbytes += inbytes;
 	cstate->raw_buf[nbytes] = '\0';
 	cstate->raw_buf_index = 0;
@@ -1514,7 +1545,6 @@ BeginCopy(ParseState *pstate,
 {
 	CopyState	cstate;
 	TupleDesc	tupDesc;
-	int			num_phys_attrs;
 	MemoryContext oldcontext;
 
 	/* Allocate workspace and zero all fields */
@@ -1680,6 +1710,23 @@ BeginCopy(ParseState *pstate,
 		tupDesc = cstate->queryDesc->tupDesc;
 	}
 
+	PopulateCommonCstateInfo(cstate, tupDesc, attnamelist);
+	cstate->copy_dest = COPY_FILE;	/* default */
+
+	MemoryContextSwitchTo(oldcontext);
+
+	return cstate;
+}
+
+/*
+ * PopulateCommonCstateInfo - Populates the common variables required for copy
+ * from operation. This is a helper function for BeginCopy function.
+ */
+static void
+PopulateCommonCstateInfo(CopyState cstate, TupleDesc tupDesc, List *attnamelist)
+{
+	int			num_phys_attrs;
+
 	/* Generate or convert list of attributes to process */
 	cstate->attnumlist = CopyGetAttnums(tupDesc, cstate->rel, attnamelist);
 
@@ -1799,12 +1846,6 @@ BeginCopy(ParseState *pstate,
 		 pg_database_encoding_max_length() > 1);
 	/* See Multibyte encoding comment above */
 	cstate->encoding_embeds_ascii = PG_ENCODING_IS_CLIENT_ONLY(cstate->file_encoding);
-
-	cstate->copy_dest = COPY_FILE;	/* default */
-
-	MemoryContextSwitchTo(oldcontext);
-
-	return cstate;
 }
 
 /*
@@ -2696,32 +2737,11 @@ CopyMultiInsertInfoStore(CopyMultiInsertInfo *miinfo, ResultRelInfo *rri,
 }
 
 /*
- * Copy FROM file to relation.
+ * Check if the relation specified in copy from is valid.
  */
-uint64
-CopyFrom(CopyState cstate)
+static void
+CheckTargetRelValidity(CopyState cstate)
 {
-	ResultRelInfo *resultRelInfo;
-	ResultRelInfo *target_resultRelInfo;
-	ResultRelInfo *prevResultRelInfo = NULL;
-	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
-	ModifyTableState *mtstate;
-	ExprContext *econtext;
-	TupleTableSlot *singleslot = NULL;
-	MemoryContext oldcontext = CurrentMemoryContext;
-
-	PartitionTupleRouting *proute = NULL;
-	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
-	int			ti_options = 0; /* start with default options for insert */
-	BulkInsertState bistate = NULL;
-	CopyInsertMethod insertMethod;
-	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
-	uint64		processed = 0;
-	bool		has_before_insert_row_trig;
-	bool		has_instead_insert_row_trig;
-	bool		leafpart_use_multi_insert = false;
-
 	Assert(cstate->rel);
 
 	/*
@@ -2758,27 +2778,6 @@ CopyFrom(CopyState cstate)
 							RelationGetRelationName(cstate->rel))));
 	}
 
-	/*
-	 * If the target file is new-in-transaction, we assume that checking FSM
-	 * for free space is a waste of time.  This could possibly be wrong, but
-	 * it's unlikely.
-	 */
-	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
-		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
-		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
-		ti_options |= TABLE_INSERT_SKIP_FSM;
-
-	/*
-	 * Optimize if new relfilenode was created in this subxact or one of its
-	 * committed children and we won't see those rows later as part of an
-	 * earlier scan or command. The subxact test ensures that if this subxact
-	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
-	 * that the stronger test of exactly which subtransaction created it is
-	 * crucial for correctness of this optimization. The test for an earlier
-	 * scan or command tolerates false negatives. FREEZE causes other sessions
-	 * to see rows they would not see under MVCC, and a false negative merely
-	 * spreads that anomaly to the current session.
-	 */
 	if (cstate->freeze)
 	{
 		/*
@@ -2816,9 +2815,61 @@ CopyFrom(CopyState cstate)
 			ereport(ERROR,
 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 					 errmsg("cannot perform COPY FREEZE because the table was not created or truncated in the current subtransaction")));
+	}
+}
+
+/*
+ * Copy FROM file to relation.
+ */
+uint64
+CopyFrom(CopyState cstate)
+{
+	ResultRelInfo *resultRelInfo;
+	ResultRelInfo *target_resultRelInfo;
+	ResultRelInfo *prevResultRelInfo = NULL;
+	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
+	ModifyTableState *mtstate;
+	ExprContext *econtext;
+	TupleTableSlot *singleslot = NULL;
+	MemoryContext oldcontext = CurrentMemoryContext;
+
+	PartitionTupleRouting *proute = NULL;
+	ErrorContextCallback errcallback;
+	CommandId	mycid = GetCurrentCommandId(true);
+	int			ti_options = 0; /* start with default options for insert */
+	BulkInsertState bistate = NULL;
+	CopyInsertMethod insertMethod;
+	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
+	uint64		processed = 0;
+	bool		has_before_insert_row_trig;
+	bool		has_instead_insert_row_trig;
+	bool		leafpart_use_multi_insert = false;
+
+	CheckTargetRelValidity(cstate);
 
+	/*
+	 * If the target file is new-in-transaction, we assume that checking FSM
+	 * for free space is a waste of time.  This could possibly be wrong, but
+	 * it's unlikely.
+	 */
+	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
+		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
+		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
+		ti_options |= TABLE_INSERT_SKIP_FSM;
+
+	/*
+	 * Optimize if new relfilenode was created in this subxact or one of its
+	 * committed children and we won't see those rows later as part of an
+	 * earlier scan or command. The subxact test ensures that if this subxact
+	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
+	 * that the stronger test of exactly which subtransaction created it is
+	 * crucial for correctness of this optimization. The test for an earlier
+	 * scan or command tolerates false negatives. FREEZE causes other sessions
+	 * to see rows they would not see under MVCC, and a false negative merely
+	 * spreads that anomaly to the current session.
+	 */
+	if (cstate->freeze)
 		ti_options |= TABLE_INSERT_FROZEN;
-	}
 
 	/*
 	 * We need a ResultRelInfo so we can use the regular executor's
@@ -3311,7 +3362,7 @@ CopyFrom(CopyState cstate)
 			 * or FDW; this is the same definition used by nodeModifyTable.c
 			 * for counting tuples inserted by an INSERT command.
 			 */
-			processed++;
+			INCREMENTPROCESSED(processed)
 		}
 	}
 
@@ -3366,30 +3417,15 @@ CopyFrom(CopyState cstate)
 
 	FreeExecutorState(estate);
 
-	return processed;
+	RETURNPROCESSED(processed)
 }
 
 /*
- * Setup to read tuples from a file for COPY FROM.
- *
- * 'rel': Used as a template for the tuples
- * 'filename': Name of server-local file to read
- * 'attnamelist': List of char *, columns to include. NIL selects all cols.
- * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
- *
- * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ * PopulateCstateCatalogInfo - Populate the catalog information.
  */
-CopyState
-BeginCopyFrom(ParseState *pstate,
-			  Relation rel,
-			  const char *filename,
-			  bool is_program,
-			  copy_data_source_cb data_source_cb,
-			  List *attnamelist,
-			  List *options)
+static void
+PopulateCstateCatalogInfo(CopyState cstate)
 {
-	CopyState	cstate;
-	bool		pipe = (filename == NULL);
 	TupleDesc	tupDesc;
 	AttrNumber	num_phys_attrs,
 				num_defaults;
@@ -3399,38 +3435,8 @@ BeginCopyFrom(ParseState *pstate,
 	Oid			in_func_oid;
 	int		   *defmap;
 	ExprState **defexprs;
-	MemoryContext oldcontext;
 	bool		volatile_defexprs;
 
-	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
-	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
-
-	/* Initialize state variables */
-	cstate->reached_eof = false;
-	cstate->eol_type = EOL_UNKNOWN;
-	cstate->cur_relname = RelationGetRelationName(cstate->rel);
-	cstate->cur_lineno = 0;
-	cstate->cur_attname = NULL;
-	cstate->cur_attval = NULL;
-
-	/*
-	 * Set up variables to avoid per-attribute overhead.  attribute_buf and
-	 * raw_buf are used in both text and binary modes, but we use line_buf
-	 * only in text mode.
-	 */
-	initStringInfo(&cstate->attribute_buf);
-	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
-	cstate->raw_buf_index = cstate->raw_buf_len = 0;
-	if (!cstate->binary)
-	{
-		initStringInfo(&cstate->line_buf);
-		cstate->line_buf_converted = false;
-	}
-
-	/* Assign range table, we'll need it in CopyFrom. */
-	if (pstate)
-		cstate->range_table = pstate->p_rtable;
-
 	tupDesc = RelationGetDescr(cstate->rel);
 	num_phys_attrs = tupDesc->natts;
 	num_defaults = 0;
@@ -3508,6 +3514,61 @@ BeginCopyFrom(ParseState *pstate,
 	cstate->defexprs = defexprs;
 	cstate->volatile_defexprs = volatile_defexprs;
 	cstate->num_defaults = num_defaults;
+}
+
+/*
+ * Setup to read tuples from a file for COPY FROM.
+ *
+ * 'rel': Used as a template for the tuples
+ * 'filename': Name of server-local file to read
+ * 'attnamelist': List of char *, columns to include. NIL selects all cols.
+ * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
+ *
+ * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ */
+CopyState
+BeginCopyFrom(ParseState *pstate,
+			  Relation rel,
+			  const char *filename,
+			  bool is_program,
+			  copy_data_source_cb data_source_cb,
+			  List *attnamelist,
+			  List *options)
+{
+	CopyState	cstate;
+	bool		pipe = (filename == NULL);
+	MemoryContext oldcontext;
+
+	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	/* Initialize state variables */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/*
+	 * Set up variables to avoid per-attribute overhead.  attribute_buf is
+	 * used in both text and binary modes, but we use line_buf and raw_buf
+	 * only in text mode.
+	 */
+	initStringInfo(&cstate->attribute_buf);
+	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+	if (!cstate->binary)
+	{
+		initStringInfo(&cstate->line_buf);
+		cstate->line_buf_converted = false;
+	}
+
+	/* Assign range table, we'll need it in CopyFrom. */
+	if (pstate)
+		cstate->range_table = pstate->p_rtable;
+
+	PopulateCstateCatalogInfo(cstate);
 	cstate->is_program = is_program;
 
 	if (data_source_cb)
@@ -3917,45 +3978,60 @@ CopyReadLine(CopyState cstate)
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
-	else
-	{
-		/*
-		 * If we didn't hit EOF, then we must have transferred the EOL marker
-		 * to line_buf along with the data.  Get rid of it.
-		 */
-		switch (cstate->eol_type)
-		{
-			case EOL_NL:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CR:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\r');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CRNL:
-				Assert(cstate->line_buf.len >= 2);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 2] == '\r');
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len -= 2;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_UNKNOWN:
-				/* shouldn't get here */
-				Assert(false);
-				break;
-		}
-	}
 
+	ConvertToServerEncoding(cstate);
+	return result;
+}
+
+/*
+ * ClearEOLFromCopiedData - Clear EOL from the copied data.
+ */
+static void
+ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
+					   int copy_line_pos, int *copy_line_size)
+{
+	/*
+	 * If we didn't hit EOF, then we must have transferred the EOL marker
+	 * to line_buf along with the data.  Get rid of it.
+	 */
+   switch (cstate->eol_type)
+   {
+	   case EOL_NL:
+		   Assert(*copy_line_size >= 1);
+		   Assert(copy_line_data[copy_line_pos - 1] == '\n');
+		   copy_line_data[copy_line_pos - 1] = '\0';
+		   (*copy_line_size)--;
+		   break;
+	   case EOL_CR:
+		   Assert(*copy_line_size >= 1);
+		   Assert(copy_line_data[copy_line_pos - 1] == '\r');
+		   copy_line_data[copy_line_pos - 1] = '\0';
+		   (*copy_line_size)--;
+		   break;
+	   case EOL_CRNL:
+		   Assert(*copy_line_size >= 2);
+		   Assert(copy_line_data[copy_line_pos - 2] == '\r');
+		   Assert(copy_line_data[copy_line_pos - 1] == '\n');
+		   copy_line_data[copy_line_pos - 2] = '\0';
+		   *copy_line_size -= 2;
+		   break;
+	   case EOL_UNKNOWN:
+		   /* shouldn't get here */
+		   Assert(false);
+		   break;
+   }
+}
+
+/*
+ * ConvertToServerEncoding - Convert contents to server encoding.
+ */
+static void
+ConvertToServerEncoding(CopyState cstate)
+{
 	/* Done reading the line.  Convert it to server encoding. */
 	if (cstate->need_transcoding)
 	{
 		char	   *cvt;
-
 		cvt = pg_any_to_server(cstate->line_buf.data,
 							   cstate->line_buf.len,
 							   cstate->file_encoding);
@@ -3967,11 +4043,8 @@ CopyReadLine(CopyState cstate)
 			pfree(cvt);
 		}
 	}
-
 	/* Now it's safe to use the buffer in error messages */
 	cstate->line_buf_converted = true;
-
-	return result;
 }
 
 /*
@@ -4334,6 +4407,7 @@ not_end_of_copy:
 	 * Transfer any still-uncopied data to line_buf.
 	 */
 	REFILL_LINEBUF;
+	CLEAR_EOL_LINE();
 
 	return result;
 }
-- 
1.8.3.1

v5-0002-Framework-for-leader-worker-in-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=v5-0002-Framework-for-leader-worker-in-parallel-copy.patchDownload
From 84a641370debe73a8e4f32b2628d0cb2d21ab75b Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Tue, 22 Sep 2020 13:54:45 +0530
Subject: [PATCH v5 2/6] Framework for leader/worker in parallel copy

This patch has the framework for data structures in parallel copy, leader
initialization, worker initialization, shared memory updation, starting workers,
wait for workers and workers exiting.
---
 src/backend/access/transam/parallel.c |   4 +
 src/backend/commands/copy.c           | 742 +++++++++++++++++++++++++++++++++-
 src/include/commands/copy.h           |   2 +
 src/tools/pgindent/typedefs.list      |   7 +
 4 files changed, 753 insertions(+), 2 deletions(-)

diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index b042696..a3cff4b 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -25,6 +25,7 @@
 #include "catalog/pg_enum.h"
 #include "catalog/storage.h"
 #include "commands/async.h"
+#include "commands/copy.h"
 #include "executor/execParallel.h"
 #include "libpq/libpq.h"
 #include "libpq/pqformat.h"
@@ -145,6 +146,9 @@ static const struct
 	},
 	{
 		"parallel_vacuum_main", parallel_vacuum_main
+	},
+	{
+		"ParallelCopyMain", ParallelCopyMain
 	}
 };
 
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index cf7277a..cf16109 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -96,9 +96,183 @@ typedef enum CopyInsertMethod
 } CopyInsertMethod;
 
 #define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+
+/*
+ * The macros DATA_BLOCK_SIZE, RINGSIZE & MAX_BLOCKS_COUNT stores the records
+ * read from the file that need to be inserted into the relation. These values
+ * help in handover of multiple records with significant size of data to be
+ * processed by each of the workers to make sure there is no context switch & the
+ * work is fairly distributed among the workers. This number showed best
+ * results in the performance tests.
+ */
+#define DATA_BLOCK_SIZE RAW_BUF_SIZE
+
+/* It can hold 1000 blocks of 64K data in DSM to be processed by the worker. */
+#define MAX_BLOCKS_COUNT 1000
+
+/*
+ * It can hold upto 10000 record information for worker to process. RINGSIZE
+ * should be a multiple of WORKER_CHUNK_COUNT, as wrap around cases is currently
+ * not handled while selecting the WORKER_CHUNK_COUNT by the worker.
+ */
+#define RINGSIZE (10 * 1000)
+
+/*
+ * Each worker will be allocated WORKER_CHUNK_COUNT of records from DSM data
+ * block to process to avoid lock contention. Read RINGSIZE comments before
+ * changing this value.
+ */
+#define WORKER_CHUNK_COUNT 50
+
+#define IsParallelCopy()		(cstate->is_parallel)
+#define IsLeader()				(cstate->pcdata->is_leader)
 #define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
 
 /*
+ * Copy data block information.
+ * ParallelCopyDataBlock's will be created in DSM. Data read from file will be
+ * copied in these DSM data blocks. The leader process identifies the records
+ * and the record information will be shared to the workers. The workers will
+ * insert the records into the table. There can be one or more number of records
+ * in each of the data block based on the record size.
+ */
+typedef struct ParallelCopyDataBlock
+{
+	/* The number of unprocessed lines in the current block. */
+	pg_atomic_uint32 unprocessed_line_parts;
+
+	/*
+	 * If the current line data is continued into another block, following_block
+	 * will have the position where the remaining data need to be read.
+	 */
+	uint32	following_block;
+
+	/*
+	 * This flag will be set, when the leader finds out this block can be read
+	 * safely by the worker. This helps the worker to start processing the line
+	 * early where the line will be spread across many blocks and the worker
+	 * need not wait for the complete line to be processed.
+	 */
+	bool   curr_blk_completed;
+	char   data[DATA_BLOCK_SIZE]; /* data read from file */
+	uint8  skip_bytes;
+} ParallelCopyDataBlock;
+
+/*
+ * Individual line information.
+ * ParallelCopyLineBoundary is common data structure between leader & worker,
+ * Leader process will be populating data block, data block offset & the size of
+ * the record in DSM for the workers to copy the data into the relation.
+ * This is protected by the following sequence in the leader & worker. If they
+ * don't follow this order the worker might process wrong line_size and leader
+ * might populate the information which worker has not yet processed or in the
+ * process of processing.
+ * Leader should operate in the following order:
+ * 1) check if line_size is -1, if not wait, it means worker is still
+ * processing.
+ * 2) set line_state to LINE_LEADER_POPULATING.
+ * 3) update first_block, start_offset & cur_lineno in any order.
+ * 4) update line_size.
+ * 5) update line_state to LINE_LEADER_POPULATED.
+ * Worker should operate in the following order:
+ * 1) check line_state is LINE_LEADER_POPULATED, if not it means leader is still
+ * populating the data.
+ * 2) read line_size.
+ * 3) only one worker should choose one line for processing, this is handled by
+ *    using pg_atomic_compare_exchange_u32, worker will change the state to
+ *    LINE_WORKER_PROCESSING only if line_state is LINE_LEADER_POPULATED.
+ * 4) read first_block, start_offset & cur_lineno in any order.
+ * 5) process line_size data.
+ * 6) update line_size to -1.
+ */
+typedef struct ParallelCopyLineBoundary
+{
+	/* Position of the first block in data_blocks array. */
+	uint32				first_block;
+	uint32				start_offset;   /* start offset of the line */
+
+	/*
+	 * Size of the current line -1 means line is yet to be filled completely,
+	 * 0 means empty line, >0 means line filled with line size data.
+	 */
+	pg_atomic_uint32	line_size;
+	pg_atomic_uint32	line_state;		/* line state */
+	uint64				cur_lineno;		/* line number for error messages */
+} ParallelCopyLineBoundary;
+
+/*
+ * Circular queue used to store the line information.
+ */
+typedef struct ParallelCopyLineBoundaries
+{
+	/* Position for the leader to populate a line. */
+	uint32			pos;
+
+	/* Data read from the file/stdin by the leader process. */
+	ParallelCopyLineBoundary	ring[RINGSIZE];
+} ParallelCopyLineBoundaries;
+
+/*
+ * Shared information among parallel copy workers. This will be allocated in the
+ * DSM segment.
+ */
+typedef struct ParallelCopyShmInfo
+{
+	bool					is_read_in_progress; /* file read status */
+
+	/*
+	 * Actual lines inserted by worker, will not be same as
+	 * total_worker_processed if where condition is specified along with copy.
+	 * This will be the actual records inserted into the relation.
+	 */
+	pg_atomic_uint64			processed;
+
+	/*
+	 * The number of records currently processed by the worker, this will also
+	 * include the number of records that was filtered because of where clause.
+	 */
+	pg_atomic_uint64			total_worker_processed;
+	uint64						populated; /* lines populated by leader */
+	uint32						cur_block_pos; /* current data block */
+	ParallelCopyDataBlock		data_blocks[MAX_BLOCKS_COUNT]; /* data block array */
+	FullTransactionId			full_transaction_id; /* xid for copy from statement */
+	CommandId					mycid;	/* command id */
+	ParallelCopyLineBoundaries	line_boundaries; /* line array */
+} ParallelCopyShmInfo;
+
+/*
+ * Parallel copy line buffer information.
+ */
+typedef struct ParallelCopyLineBuf
+{
+	StringInfoData		line_buf;
+	uint64				cur_lineno;	/* line number for error messages */
+} ParallelCopyLineBuf;
+
+/*
+ * Parallel copy data information.
+ */
+typedef struct ParallelCopyData
+{
+	Oid					relid;				/* relation id of the table */
+	ParallelCopyShmInfo	*pcshared_info;		/* common info in shared memory */
+	bool				is_leader;
+
+	/* line position which worker is processing */
+	uint32				worker_processed_pos;
+
+	/*
+	 * Local line_buf array, workers will copy it here and release the lines
+	 * for the leader to continue.
+	 */
+	ParallelCopyLineBuf	worker_line_buf[WORKER_CHUNK_COUNT];
+	uint32				worker_line_buf_count; /* Number of lines */
+
+	/* Current position in worker_line_buf */
+	uint32				worker_line_buf_pos;
+} ParallelCopyData;
+
+/*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
  * even though some fields are used in only some cases.
@@ -230,10 +404,38 @@ typedef struct CopyStateData
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
+	int			nworkers;
+	bool		is_parallel;
+	ParallelCopyData *pcdata;
 	/* Shorthand for number of unconsumed bytes available in raw_buf */
 #define RAW_BUF_BYTES(cstate) ((cstate)->raw_buf_len - (cstate)->raw_buf_index)
 } CopyStateData;
 
+/*
+ * This structure helps in storing the common data from CopyStateData that are
+ * required by the workers. This information will then be allocated and stored
+ * into the DSM for the worker to retrieve and copy it to CopyStateData.
+ */
+typedef struct SerializedParallelCopyState
+{
+	/* low-level state data */
+	CopyDest            copy_dest;		/* type of copy source/destination */
+	int                 file_encoding;	/* file or remote side's character encoding */
+	bool                need_transcoding;	/* file encoding diff from server? */
+	bool                encoding_embeds_ascii;	/* ASCII can be non-first byte? */
+
+	/* parameters from the COPY command */
+	bool                csv_mode;		/* Comma Separated Value format? */
+	bool                header_line;	/* CSV header line? */
+	int                 null_print_len; /* length of same */
+	bool                force_quote_all;	/* FORCE_QUOTE *? */
+	bool                convert_selectively;	/* do selective binary conversion? */
+
+	/* Working state for COPY FROM */
+	AttrNumber          num_defaults;
+	Oid                 relid;
+} SerializedParallelCopyState;
+
 /* DestReceiver for COPY (query) TO */
 typedef struct
 {
@@ -263,6 +465,22 @@ typedef struct
 /* Trim the list of buffers back down to this number after flushing */
 #define MAX_PARTITION_BUFFERS	32
 
+/* DSM keys for parallel copy.  */
+#define PARALLEL_COPY_KEY_SHARED_INFO				1
+#define PARALLEL_COPY_KEY_CSTATE					2
+#define PARALLEL_COPY_KEY_NULL_PRINT				3
+#define PARALLEL_COPY_KEY_DELIM						4
+#define PARALLEL_COPY_KEY_QUOTE						5
+#define PARALLEL_COPY_KEY_ESCAPE					6
+#define PARALLEL_COPY_KEY_ATTNAME_LIST				7
+#define PARALLEL_COPY_KEY_NOT_NULL_LIST				8
+#define PARALLEL_COPY_KEY_NULL_LIST					9
+#define PARALLEL_COPY_KEY_CONVERT_LIST				10
+#define PARALLEL_COPY_KEY_WHERE_CLAUSE_STR			11
+#define PARALLEL_COPY_KEY_RANGE_TABLE				12
+#define PARALLEL_COPY_WAL_USAGE						13
+#define PARALLEL_COPY_BUFFER_USAGE					14
+
 /* Stores multi-insert data related to a single relation in CopyFrom. */
 typedef struct CopyMultiInsertBuffer
 {
@@ -424,11 +642,478 @@ static bool CopyGetInt16(CopyState cstate, int16 *val);
 static bool CopyLoadRawBuf(CopyState cstate);
 static int	CopyReadBinaryData(CopyState cstate, char *dest, int nbytes);
 
+static pg_attribute_always_inline void EndParallelCopy(ParallelContext *pcxt);
 static void PopulateCommonCstateInfo(CopyState cstate, TupleDesc tup_desc,
 									 List *attnamelist);
 static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
 								   int copy_line_pos, int *copy_line_size);
 static void ConvertToServerEncoding(CopyState cstate);
+
+
+/*
+ * SerializeParallelCopyState - Copy shared_cstate using cstate information.
+ */
+static pg_attribute_always_inline void
+SerializeParallelCopyState(CopyState cstate, SerializedParallelCopyState *shared_cstate)
+{
+	shared_cstate->copy_dest = cstate->copy_dest;
+	shared_cstate->file_encoding = cstate->file_encoding;
+	shared_cstate->need_transcoding = cstate->need_transcoding;
+	shared_cstate->encoding_embeds_ascii = cstate->encoding_embeds_ascii;
+	shared_cstate->csv_mode = cstate->csv_mode;
+	shared_cstate->header_line = cstate->header_line;
+	shared_cstate->null_print_len = cstate->null_print_len;
+	shared_cstate->force_quote_all = cstate->force_quote_all;
+	shared_cstate->convert_selectively = cstate->convert_selectively;
+	shared_cstate->num_defaults = cstate->num_defaults;
+	shared_cstate->relid = cstate->pcdata->relid;
+}
+
+/*
+ * RestoreString - Retrieve the string from shared memory.
+ */
+static void
+RestoreString(shm_toc *toc, int sharedkey, char **copystr)
+{
+	char *shared_str_val = (char *) shm_toc_lookup(toc, sharedkey, true);
+	if (shared_str_val)
+		*copystr = pstrdup(shared_str_val);
+}
+
+/*
+ * EstimateLineKeysStr - Estimate the size required in shared memory for the
+ * input string.
+ */
+static void
+EstimateLineKeysStr(ParallelContext *pcxt, char *inputstr)
+{
+	if (inputstr)
+	{
+		shm_toc_estimate_chunk(&pcxt->estimator, strlen(inputstr) + 1);
+		shm_toc_estimate_keys(&pcxt->estimator, 1);
+	}
+}
+
+/*
+ * SerializeString - Insert a string into shared memory.
+ */
+static void
+SerializeString(ParallelContext *pcxt, int key, char *inputstr)
+{
+	if (inputstr)
+	{
+		char *shmptr = (char *) shm_toc_allocate(pcxt->toc,
+												strlen(inputstr) + 1);
+		strcpy(shmptr, inputstr);
+		shm_toc_insert(pcxt->toc, key, shmptr);
+	}
+}
+
+/*
+ * PopulateParallelCopyShmInfo - Set ParallelCopyShmInfo.
+ */
+static void
+PopulateParallelCopyShmInfo(ParallelCopyShmInfo *shared_info_ptr,
+							FullTransactionId full_transaction_id)
+{
+	uint32 count;
+
+	MemSet(shared_info_ptr, 0, sizeof(ParallelCopyShmInfo));
+	shared_info_ptr->is_read_in_progress = true;
+	shared_info_ptr->cur_block_pos = -1;
+	shared_info_ptr->full_transaction_id = full_transaction_id;
+	shared_info_ptr->mycid = GetCurrentCommandId(true);
+	for (count = 0; count < RINGSIZE; count++)
+	{
+		ParallelCopyLineBoundary *lineInfo = &shared_info_ptr->line_boundaries.ring[count];
+		pg_atomic_init_u32(&(lineInfo->line_size), -1);
+	}
+}
+
+/*
+ * BeginParallelCopy - Start parallel copy tasks.
+ *
+ * Get the number of workers required to perform the parallel copy. The data
+ * structures that are required by the parallel workers will be initialized, the
+ * size required in DSM will be calculated and the necessary keys will be loaded
+ * in the DSM. The specified number of workers will then be launched.
+ */
+static ParallelContext*
+BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
+{
+	ParallelContext *pcxt;
+	ParallelCopyShmInfo *shared_info_ptr;
+	SerializedParallelCopyState *shared_cstate;
+	FullTransactionId full_transaction_id;
+	Size est_cstateshared;
+	char *whereClauseStr = NULL;
+	char *rangeTableStr = NULL;
+	char *attnameListStr = NULL;
+	char *notnullListStr = NULL;
+	char *nullListStr = NULL;
+	char *convertListStr = NULL;
+	int  parallel_workers = 0;
+	WalUsage   *walusage;
+	BufferUsage *bufferusage;
+	ParallelCopyData *pcdata;
+	MemoryContext oldcontext;
+
+	parallel_workers = Min(nworkers, max_worker_processes);
+
+	/* Can't perform copy in parallel */
+	if (parallel_workers <= 0)
+		return NULL;
+
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	MemoryContextSwitchTo(oldcontext);
+	cstate->pcdata = pcdata;
+
+	EnterParallelMode();
+	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
+								 parallel_workers);
+	Assert(pcxt->nworkers > 0);
+
+	/*
+	 * Estimate size for shared information for PARALLEL_COPY_KEY_SHARED_INFO
+	 */
+	shm_toc_estimate_chunk(&pcxt->estimator, sizeof(ParallelCopyShmInfo));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_CSTATE */
+	est_cstateshared = 	MAXALIGN(sizeof(SerializedParallelCopyState));
+	shm_toc_estimate_chunk(&pcxt->estimator, est_cstateshared);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	EstimateLineKeysStr(pcxt, cstate->null_print);
+	EstimateLineKeysStr(pcxt, cstate->null_print_client);
+	EstimateLineKeysStr(pcxt, cstate->delim);
+	EstimateLineKeysStr(pcxt, cstate->quote);
+	EstimateLineKeysStr(pcxt, cstate->escape);
+
+	if (cstate->whereClause != NULL)
+	{
+		whereClauseStr = nodeToString(cstate->whereClause);
+		EstimateLineKeysStr(pcxt, whereClauseStr);
+	}
+
+	if (cstate->range_table != NULL)
+	{
+		rangeTableStr = nodeToString(cstate->range_table);
+		EstimateLineKeysStr(pcxt, rangeTableStr);
+	}
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_XID. */
+	shm_toc_estimate_chunk(&pcxt->estimator, sizeof(FullTransactionId));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_ATTNAME_LIST.
+	 */
+	if (attnamelist != NIL)
+	{
+		attnameListStr = nodeToString(attnamelist);
+		EstimateLineKeysStr(pcxt, attnameListStr);
+	}
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_NOT_NULL_LIST.
+	 */
+	if (cstate->force_notnull != NIL)
+	{
+		notnullListStr = nodeToString(cstate->force_notnull);
+		EstimateLineKeysStr(pcxt, notnullListStr);
+	}
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_NULL_LIST.
+	 */
+	if (cstate->force_null != NIL)
+	{
+		nullListStr = nodeToString(cstate->force_null);
+		EstimateLineKeysStr(pcxt, nullListStr);
+	}
+
+	/*
+	 * Estimate the size for shared information for
+	 * PARALLEL_COPY_KEY_CONVERT_LIST.
+	 */
+	if (cstate->convert_select != NIL)
+	{
+		convertListStr = nodeToString(cstate->convert_select);
+		EstimateLineKeysStr(pcxt, convertListStr);
+	}
+
+	/*
+	 * Estimate space for WalUsage and BufferUsage -- PARALLEL_COPY_WAL_USAGE
+	 * and PARALLEL_COPY_BUFFER_USAGE.
+	 */
+	shm_toc_estimate_chunk(&pcxt->estimator,
+						   mul_size(sizeof(WalUsage), pcxt->nworkers));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+	shm_toc_estimate_chunk(&pcxt->estimator,
+						   mul_size(sizeof(BufferUsage), pcxt->nworkers));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	InitializeParallelDSM(pcxt);
+
+	/* If no DSM segment was available, back out (do serial copy) */
+	if (pcxt->seg == NULL)
+	{
+		EndParallelCopy(pcxt);
+		return NULL;
+	}
+
+	/* Allocate shared memory for PARALLEL_COPY_KEY_SHARED_INFO */
+	shared_info_ptr = (ParallelCopyShmInfo *) shm_toc_allocate(pcxt->toc, sizeof(ParallelCopyShmInfo));
+	PopulateParallelCopyShmInfo(shared_info_ptr, full_transaction_id);
+
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_SHARED_INFO, shared_info_ptr);
+	pcdata->pcshared_info = shared_info_ptr;
+	pcdata->relid = relid;
+
+	/* Store shared build state, for which we reserved space. */
+	shared_cstate = (SerializedParallelCopyState *) shm_toc_allocate(pcxt->toc, est_cstateshared);
+
+	/* copy cstate variables. */
+	SerializeParallelCopyState(cstate, shared_cstate);
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_CSTATE, shared_cstate);
+
+	SerializeString(pcxt, PARALLEL_COPY_KEY_NULL_PRINT, cstate->null_print);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_DELIM, cstate->delim);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_QUOTE, cstate->quote);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_ESCAPE, cstate->escape);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_ATTNAME_LIST, attnameListStr);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_NOT_NULL_LIST, notnullListStr);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_NULL_LIST, nullListStr);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_CONVERT_LIST, convertListStr);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_WHERE_CLAUSE_STR, whereClauseStr);
+	SerializeString(pcxt, PARALLEL_COPY_KEY_RANGE_TABLE, rangeTableStr);
+
+	/*
+	 * Allocate space for each worker's WalUsage and BufferUsage; no need to
+	 * initialize.
+	 */
+	walusage = shm_toc_allocate(pcxt->toc,
+								mul_size(sizeof(WalUsage), pcxt->nworkers));
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_WAL_USAGE, walusage);
+	bufferusage = shm_toc_allocate(pcxt->toc,
+								   mul_size(sizeof(BufferUsage), pcxt->nworkers));
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_BUFFER_USAGE, bufferusage);
+
+	LaunchParallelWorkers(pcxt);
+	if (pcxt->nworkers_launched == 0)
+	{
+		EndParallelCopy(pcxt);
+		return NULL;
+	}
+
+	/*
+	 * Caller needs to wait for all launched workers when we return.  Make sure
+	 * that the failure-to-start case will not hang forever.
+	 */
+	WaitForParallelWorkersToAttach(pcxt);
+
+	pcdata->is_leader = true;
+	cstate->is_parallel = true;
+	return pcxt;
+}
+
+/*
+ * EndParallelCopy - End the parallel copy tasks.
+ */
+static pg_attribute_always_inline void
+EndParallelCopy(ParallelContext *pcxt)
+{
+	Assert(!IsParallelWorker());
+
+	DestroyParallelContext(pcxt);
+	ExitParallelMode();
+}
+
+/*
+ * InitializeParallelCopyInfo - Initialize parallel worker.
+ */
+static void
+InitializeParallelCopyInfo(SerializedParallelCopyState *shared_cstate,
+		CopyState cstate, List *attnamelist)
+{
+	uint32		count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	cstate->copy_dest = shared_cstate->copy_dest;
+	cstate->file_encoding = shared_cstate->file_encoding;
+	cstate->need_transcoding = shared_cstate->need_transcoding;
+	cstate->encoding_embeds_ascii = shared_cstate->encoding_embeds_ascii;
+	cstate->csv_mode = shared_cstate->csv_mode;
+	cstate->header_line = shared_cstate->header_line;
+	cstate->null_print_len = shared_cstate->null_print_len;
+	cstate->force_quote_all = shared_cstate->force_quote_all;
+	cstate->convert_selectively = shared_cstate->convert_selectively;
+	cstate->num_defaults = shared_cstate->num_defaults;
+	pcdata->relid = shared_cstate->relid;
+
+	PopulateCommonCstateInfo(cstate, tup_desc, attnamelist);
+
+	/* Initialize state variables. */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/* Set up variables to avoid per-attribute overhead. */
+	initStringInfo(&cstate->attribute_buf);
+
+	initStringInfo(&cstate->line_buf);
+	for (count = 0; count < WORKER_CHUNK_COUNT; count++)
+		initStringInfo(&pcdata->worker_line_buf[count].line_buf);
+
+	cstate->line_buf_converted = false;
+	cstate->raw_buf = NULL;
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+}
+
+/*
+ * ParallelCopyMain - Parallel copy worker's code.
+ *
+ * Where clause handling, convert tuple to columns, add default null values for
+ * the missing columns that are not present in that record. Find the partition
+ * if it is partitioned table, invoke before row insert Triggers, handle
+ * constraints and insert the tuples.
+ */
+void
+ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
+{
+	CopyState cstate;
+	ParallelCopyData *pcdata;
+	ParallelCopyShmInfo *pcshared_info;
+	SerializedParallelCopyState *shared_cstate;
+	Relation	rel = NULL;
+	MemoryContext oldcontext;
+	List *attlist = NIL;
+	char *whereClauseStr = NULL;
+	char *rangeTableStr = NULL;
+	char *attnameListStr = NULL;
+	char *notnullListStr = NULL;
+	char *nullListStr = NULL;
+	char *convertListStr = NULL;
+	WalUsage   *walusage;
+	BufferUsage *bufferusage;
+
+	/* Allocate workspace and zero all fields. */
+	cstate = (CopyStateData *) palloc0(sizeof(CopyStateData));
+
+	/*
+	 * We allocate everything used by a cstate in a new memory context. This
+	 * avoids memory leaks during repeated use of COPY in a query.
+	 */
+	cstate->copycontext = AllocSetContextCreate(CurrentMemoryContext,
+												"COPY",
+												ALLOCSET_DEFAULT_SIZES);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	cstate->pcdata = pcdata;
+	pcdata->is_leader = false;
+	pcdata->worker_processed_pos = -1;
+	cstate->is_parallel = true;
+	pcshared_info = (ParallelCopyShmInfo *) shm_toc_lookup(toc, PARALLEL_COPY_KEY_SHARED_INFO, false);
+
+	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
+
+	pcdata->pcshared_info = pcshared_info;
+
+	shared_cstate = (SerializedParallelCopyState *) shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE, false);
+	cstate->null_print = (char *) shm_toc_lookup(toc, PARALLEL_COPY_KEY_NULL_PRINT, true);
+
+	RestoreString(toc, PARALLEL_COPY_KEY_DELIM, &cstate->delim);
+	RestoreString(toc, PARALLEL_COPY_KEY_QUOTE, &cstate->quote);
+	RestoreString(toc, PARALLEL_COPY_KEY_ESCAPE, &cstate->escape);
+	RestoreString(toc, PARALLEL_COPY_KEY_ATTNAME_LIST, &attnameListStr);
+	if (attnameListStr)
+		attlist = (List *) stringToNode(attnameListStr);
+
+	RestoreString(toc, PARALLEL_COPY_KEY_NOT_NULL_LIST, &notnullListStr);
+	if (notnullListStr)
+		cstate->force_notnull = (List *) stringToNode(notnullListStr);
+
+	RestoreString(toc, PARALLEL_COPY_KEY_NULL_LIST, &nullListStr);
+	if (nullListStr)
+		cstate->force_null = (List *) stringToNode(nullListStr);
+
+	RestoreString(toc, PARALLEL_COPY_KEY_CONVERT_LIST, &convertListStr);
+	if (convertListStr)
+		cstate->convert_select = (List *) stringToNode(convertListStr);
+
+	RestoreString(toc, PARALLEL_COPY_KEY_WHERE_CLAUSE_STR, &whereClauseStr);
+	RestoreString(toc, PARALLEL_COPY_KEY_RANGE_TABLE, &rangeTableStr);
+
+	if (whereClauseStr)
+	{
+		Node *whereClauseCnvrtdFrmStr = (Node *) stringToNode(whereClauseStr);
+		cstate->whereClause = whereClauseCnvrtdFrmStr;
+	}
+
+	if (rangeTableStr)
+	{
+		List *rangeTableCnvrtdFrmStr = (List *) stringToNode(rangeTableStr);
+		cstate->range_table = rangeTableCnvrtdFrmStr;
+	}
+
+	/* Open and lock the relation, using the appropriate lock type. */
+	rel = table_open(shared_cstate->relid, RowExclusiveLock);
+	cstate->rel = rel;
+	InitializeParallelCopyInfo(shared_cstate, cstate, attlist);
+
+	CopyFrom(cstate);
+
+	if (rel != NULL)
+		table_close(rel, RowExclusiveLock);
+
+	/* Report WAL/buffer usage during parallel execution */
+	bufferusage = shm_toc_lookup(toc, PARALLEL_COPY_BUFFER_USAGE, false);
+	walusage = shm_toc_lookup(toc, PARALLEL_COPY_WAL_USAGE, false);
+	InstrEndParallelQuery(&bufferusage[ParallelWorkerNumber],
+						  &walusage[ParallelWorkerNumber]);
+
+	MemoryContextSwitchTo(oldcontext);
+	pfree(cstate);
+	return;
+}
+
+/*
+ * ParallelCopyFrom - parallel copy leader's functionality.
+ *
+ * Leader executes the before statement for before statement trigger, if before
+ * statement trigger is present. It will read the table data from the file and
+ * copy the contents to DSM data blocks. It will then read the input contents
+ * from the DSM data block and identify the records based on line breaks. This
+ * information is called line or a record that need to be inserted into a
+ * relation. The line information will be stored in ParallelCopyLineBoundary DSM
+ * data structure. Workers will then process this information and insert the
+ * data in to table. It will repeat this process until the all data is read from
+ * the file and all the DSM data blocks are processed. While processing if
+ * leader identifies that DSM Data blocks or DSM ParallelCopyLineBoundary data
+ * structures is full, leader will wait till the worker frees up some entries
+ * and repeat the process. It will wait till all the lines populated are
+ * processed by the workers and exits.
+ */
+static void
+ParallelCopyFrom(CopyState cstate)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
+
+	pcshared_info->is_read_in_progress = false;
+	cstate->cur_lineno = 0;
+}
+
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
  * in past protocol redesigns.
@@ -1141,6 +1826,7 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 
 	if (is_from)
 	{
+		ParallelContext *pcxt = NULL;
 		Assert(rel);
 
 		/* check read-only transaction and parallel mode */
@@ -1150,7 +1836,24 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 		cstate = BeginCopyFrom(pstate, rel, stmt->filename, stmt->is_program,
 							   NULL, stmt->attlist, stmt->options);
 		cstate->whereClause = whereClause;
-		*processed = CopyFrom(cstate);	/* copy from file to database */
+		cstate->is_parallel = false;
+
+		if (cstate->nworkers > 0)
+			pcxt = BeginParallelCopy(cstate->nworkers, cstate, stmt->attlist,
+									 relid);
+
+		if (pcxt)
+		{
+			ParallelCopyFrom(cstate);
+
+			/* Wait for all copy workers to finish */
+			WaitForParallelWorkersToFinish(pcxt);
+			*processed = pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
+			EndParallelCopy(pcxt);
+		}
+		else
+			*processed = CopyFrom(cstate); /* copy from file to database */
+
 		EndCopyFrom(cstate);
 	}
 	else
@@ -1199,6 +1902,7 @@ ProcessCopyOptions(ParseState *pstate,
 	cstate->is_copy_from = is_from;
 
 	cstate->file_encoding = -1;
+	cstate->nworkers = -1;
 
 	/* Extract options from the statement node tree */
 	foreach(option, options)
@@ -1367,6 +2071,39 @@ ProcessCopyOptions(ParseState *pstate,
 								defel->defname),
 						 parser_errposition(pstate, defel->location)));
 		}
+		else if (strcmp(defel->defname, "parallel") == 0)
+		{
+			int val;
+			bool parsed;
+			char *strval;
+
+			if (!cstate->is_copy_from)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("parallel option is supported only for copy from"),
+						 parser_errposition(pstate, defel->location)));
+			if (cstate->nworkers >= 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options"),
+						 parser_errposition(pstate, defel->location)));
+
+			strval = defGetString(defel);
+			parsed = parse_int(strval, &val, 0, NULL);
+			if (!parsed)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+							errmsg("invalid value for integer option \"%s\": %s",
+								   defel->defname, strval)));
+			if (val < 1 || val > 1024)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+							errmsg("value %s out of bounds for option \"%s\"",
+								   strval, defel->defname),
+							errdetail("Valid values are between \"%d\" and \"%d\".",
+									  1, 1024)));
+			cstate->nworkers = val;
+		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_SYNTAX_ERROR),
@@ -1720,7 +2457,8 @@ BeginCopy(ParseState *pstate,
 
 /*
  * PopulateCommonCstateInfo - Populates the common variables required for copy
- * from operation. This is a helper function for BeginCopy function.
+ * from operation. This is a helper function for BeginCopy &
+ * InitializeParallelCopyInfo function.
  */
 static void
 PopulateCommonCstateInfo(CopyState cstate, TupleDesc tupDesc, List *attnamelist)
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index c639833..82843c6 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -14,6 +14,7 @@
 #ifndef COPY_H
 #define COPY_H
 
+#include "access/parallel.h"
 #include "nodes/execnodes.h"
 #include "nodes/parsenodes.h"
 #include "parser/parse_node.h"
@@ -41,4 +42,5 @@ extern uint64 CopyFrom(CopyState cstate);
 
 extern DestReceiver *CreateCopyDestReceiver(void);
 
+extern void ParallelCopyMain(dsm_segment *seg, shm_toc *toc);
 #endif							/* COPY_H */
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index b1afb34..509c695 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1702,6 +1702,12 @@ ParallelBitmapHeapState
 ParallelBlockTableScanDesc
 ParallelCompletionPtr
 ParallelContext
+ParallelCopyLineBoundaries
+ParallelCopyLineBoundary
+ParallelCopyData
+ParallelCopyDataBlock
+ParallelCopyLineBuf
+ParallelCopyShmInfo
 ParallelExecutorInfo
 ParallelHashGrowth
 ParallelHashJoinBatch
@@ -2219,6 +2225,7 @@ SerCommitSeqNo
 SerialControl
 SerializableXactHandle
 SerializedActiveRelMaps
+SerializedParallelCopyState
 SerializedReindexState
 SerializedSnapshotData
 SerializedTransactionState
-- 
1.8.3.1

v5-0003-Allow-copy-from-command-to-process-data-from-file.patchtext/x-patch; charset=US-ASCII; name=v5-0003-Allow-copy-from-command-to-process-data-from-file.patchDownload
From b7d2f516f9ae9088663d7e68247541ce6b019c40 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Tue, 22 Sep 2020 13:00:32 +0530
Subject: [PATCH v5 3/6] Allow copy from command to process data from
 file/STDIN contents to a table in parallel.

This feature allows the copy from to leverage multiple CPUs in order to copy
data from file/STDIN to a table. This adds a PARALLEL option to COPY FROM
command where the user can specify the number of workers that can be used
to perform the COPY FROM command.
The backend, to which the "COPY FROM" query is submitted acts as leader with
the responsibility of reading data from the file/stdin, launching at most n
number of workers as specified with PARALLEL 'n' option in the "COPY FROM"
query. The leader populates the common data required for the workers execution
in the DSM and shares it with the workers. The leader then executes before
statement triggers if there exists any. Leader populates DSM lines which
includes the start offset and line size, while populating the lines it reads
as many blocks as required into the DSM data blocks from the file. Each block
is of 64K size. The leader parses the data to identify a line, the existing
logic from CopyReadLineText which identifies the lines with some changes was
used for this. Leader checks if a free line is available to copy the
information, if there is no free line it waits till the required line is
freed up by the worker and then copies the identified lines information
(offset & line size) into the DSM lines. This process is repeated till the
complete file is processed. Simultaneously, the workers cache the lines(50)
locally into the local memory and release the lines to the leader for further
populating. Each worker processes the lines that it cached and inserts it into
the table. The leader does not participate in the insertion of data, leaders
only responsibility will be to identify the lines as fast as possible for the
workers to do the actual copy operation. The leader waits till all the lines
populated are processed by the workers and exits.
We have chosen this design based on the reason "that everything stalls if the
leader doesn't accept further input data, as well as when there are no
available splitted chunks so it doesn't seem like a good idea to have the
leader do other work.  This is backed by the performance data where we have
seen that with 1 worker there is just a 5-10% performance difference".
---
 src/backend/access/common/toast_internals.c |  11 +-
 src/backend/access/heap/heapam.c            |  11 -
 src/backend/access/transam/xact.c           |  31 +
 src/backend/commands/copy.c                 | 896 ++++++++++++++++++++++++++--
 src/bin/psql/tab-complete.c                 |   2 +-
 src/include/access/xact.h                   |   2 +
 src/tools/pgindent/typedefs.list            |   1 +
 7 files changed, 902 insertions(+), 52 deletions(-)

diff --git a/src/backend/access/common/toast_internals.c b/src/backend/access/common/toast_internals.c
index 25a81e5..586d53d 100644
--- a/src/backend/access/common/toast_internals.c
+++ b/src/backend/access/common/toast_internals.c
@@ -17,6 +17,7 @@
 #include "access/genam.h"
 #include "access/heapam.h"
 #include "access/heaptoast.h"
+#include "access/parallel.h"
 #include "access/table.h"
 #include "access/toast_internals.h"
 #include "access/xact.h"
@@ -116,7 +117,15 @@ toast_save_datum(Relation rel, Datum value,
 	TupleDesc	toasttupDesc;
 	Datum		t_values[3];
 	bool		t_isnull[3];
-	CommandId	mycid = GetCurrentCommandId(true);
+
+	/*
+	 * Parallel copy can insert toast tuples, in case of parallel copy the
+	 * command would have been set already by calling AssignCommandIdForWorker.
+	 * For parallel copy call GetCurrentCommandId to get currentCommandId by
+	 * passing used as false, as this is taken care earlier.
+	 */
+	CommandId	mycid = IsParallelWorker() ? GetCurrentCommandId(false) :
+											 GetCurrentCommandId(true);
 	struct varlena *result;
 	struct varatt_external toast_pointer;
 	union
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 1585861..1602525 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2043,17 +2043,6 @@ static HeapTuple
 heap_prepare_insert(Relation relation, HeapTuple tup, TransactionId xid,
 					CommandId cid, int options)
 {
-	/*
-	 * To allow parallel inserts, we need to ensure that they are safe to be
-	 * performed in workers. We have the infrastructure to allow parallel
-	 * inserts in general except for the cases where inserts generate a new
-	 * CommandId (eg. inserts into a table having a foreign key column).
-	 */
-	if (IsParallelWorker())
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_TRANSACTION_STATE),
-				 errmsg("cannot insert tuples in a parallel worker")));
-
 	tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
 	tup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK);
 	tup->t_data->t_infomask |= HEAP_XMAX_INVALID;
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index af6afce..e983f78 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -517,6 +517,37 @@ GetCurrentFullTransactionIdIfAny(void)
 }
 
 /*
+ *	AssignFullTransactionIdForWorker
+ *
+ * For parallel copy, transaction id of leader will be used by the workers.
+ */
+void
+AssignFullTransactionIdForWorker(FullTransactionId fullTransactionId)
+{
+	TransactionState s = CurrentTransactionState;
+
+	Assert((IsInParallelMode() || IsParallelWorker()));
+	s->fullTransactionId = fullTransactionId;
+}
+
+/*
+ *	AssignCommandIdForWorker
+ *
+ * For parallel copy, command id of leader will be used by the workers.
+ */
+void
+AssignCommandIdForWorker(CommandId commandId, bool used)
+{
+	Assert((IsInParallelMode() || IsParallelWorker()));
+
+	/* this is global to a transaction, not subtransaction-local */
+	if (used)
+		currentCommandIdUsed = true;
+
+	currentCommandId = commandId;
+}
+
+/*
  *	MarkCurrentTransactionIdLoggedIfAny
  *
  * Remember that the current xid - if it is assigned - now has been wal logged.
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index cf16109..ba188d7 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -26,6 +26,7 @@
 #include "access/xlog.h"
 #include "catalog/dependency.h"
 #include "catalog/pg_authid.h"
+#include "catalog/pg_proc_d.h"
 #include "catalog/pg_type.h"
 #include "commands/copy.h"
 #include "commands/defrem.h"
@@ -40,11 +41,13 @@
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
+#include "optimizer/clauses.h"
 #include "optimizer/optimizer.h"
 #include "parser/parse_coerce.h"
 #include "parser/parse_collate.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_relation.h"
+#include "pgstat.h"
 #include "port/pg_bswap.h"
 #include "rewrite/rewriteHandler.h"
 #include "storage/fd.h"
@@ -95,6 +98,18 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
+/*
+ * State of the line.
+ */
+typedef enum ParallelCopyLineState
+{
+	LINE_INIT,					/* initial state of line */
+	LINE_LEADER_POPULATING,		/* leader processing line */
+	LINE_LEADER_POPULATED,		/* leader completed populating line */
+	LINE_WORKER_PROCESSING,		/* worker processing line */
+	LINE_WORKER_PROCESSED		/* worker completed processing line */
+} ParallelCopyLineState;
+
 #define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
 
 /*
@@ -126,6 +141,7 @@ typedef enum CopyInsertMethod
 
 #define IsParallelCopy()		(cstate->is_parallel)
 #define IsLeader()				(cstate->pcdata->is_leader)
+#define IsWorker()				(IsParallelCopy() && !IsLeader())
 #define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
 
 /*
@@ -559,9 +575,13 @@ if (1) \
 { \
 	if (raw_buf_ptr > cstate->raw_buf_index) \
 	{ \
-		appendBinaryStringInfo(&cstate->line_buf, \
-							 cstate->raw_buf + cstate->raw_buf_index, \
-							   raw_buf_ptr - cstate->raw_buf_index); \
+		if (!IsParallelCopy()) \
+			appendBinaryStringInfo(&cstate->line_buf, \
+								   cstate->raw_buf + cstate->raw_buf_index, \
+								   raw_buf_ptr - cstate->raw_buf_index); \
+		else \
+			line_size +=  raw_buf_ptr - cstate->raw_buf_index; \
+		\
 		cstate->raw_buf_index = raw_buf_ptr; \
 	} \
 } else ((void) 0)
@@ -574,26 +594,65 @@ if (1) \
 	goto not_end_of_copy; \
 } else ((void) 0)
 
+/* Begin parallel copy Macros */
+#define SET_NEWLINE_SIZE() \
+{ \
+	if (cstate->eol_type == EOL_NL || cstate->eol_type == EOL_CR) \
+		new_line_size = 1; \
+	else if (cstate->eol_type == EOL_CRNL) \
+		new_line_size = 2; \
+	else \
+		new_line_size = 0; \
+}
+
+/*
+ * COPY_WAIT_TO_PROCESS - Wait before continuing to process.
+ */
+#define COPY_WAIT_TO_PROCESS() \
+{ \
+	CHECK_FOR_INTERRUPTS(); \
+	(void) WaitLatch(MyLatch, \
+					 WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH, \
+					 1L, WAIT_EVENT_PG_SLEEP); \
+	ResetLatch(MyLatch); \
+}
+
 /*
  * CLEAR_EOL_LINE - Wrapper for clearing EOL.
  */
 #define CLEAR_EOL_LINE() \
 if (!result && !IsHeaderLine()) \
-	ClearEOLFromCopiedData(cstate, cstate->line_buf.data, \
-						   cstate->line_buf.len, \
-						   &cstate->line_buf.len) \
+{ \
+	if (IsParallelCopy()) \
+		ClearEOLFromCopiedData(cstate, cstate->raw_buf, \
+									raw_buf_ptr, &line_size); \
+	else \
+		ClearEOLFromCopiedData(cstate, cstate->line_buf.data, \
+									cstate->line_buf.len, \
+									&cstate->line_buf.len); \
+} \
 
 /*
  * INCREMENTPROCESSED - Increment the lines processed.
  */
-#define INCREMENTPROCESSED(processed)  \
-processed++;
+#define INCREMENTPROCESSED(processed) \
+{ \
+	if (!IsParallelCopy()) \
+		processed++; \
+	else \
+		pg_atomic_add_fetch_u64(&cstate->pcdata->pcshared_info->processed, 1); \
+}
 
 /*
  * RETURNPROCESSED - Get the lines processed.
  */
 #define RETURNPROCESSED(processed) \
-return processed;
+if (!IsParallelCopy()) \
+	return processed; \
+else \
+	return pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
+
+/* End parallel copy Macros */
 
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
@@ -648,7 +707,10 @@ static void PopulateCommonCstateInfo(CopyState cstate, TupleDesc tup_desc,
 static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
 								   int copy_line_pos, int *copy_line_size);
 static void ConvertToServerEncoding(CopyState cstate);
-
+static void ExecBeforeStmtTrigger(CopyState cstate);
+static void CheckTargetRelValidity(CopyState cstate);
+static void PopulateCstateCatalogInfo(CopyState cstate);
+static pg_attribute_always_inline uint32 GetLinePosition(CopyState cstate);
 
 /*
  * SerializeParallelCopyState - Copy shared_cstate using cstate information.
@@ -731,6 +793,137 @@ PopulateParallelCopyShmInfo(ParallelCopyShmInfo *shared_info_ptr,
 }
 
 /*
+ * IsTriggerFunctionParallelSafe - Check if the trigger function is parallel
+ * safe for the triggers. Return false if any one of the trigger has parallel
+ * unsafe function.
+ */
+static pg_attribute_always_inline bool
+IsTriggerFunctionParallelSafe(TriggerDesc *trigdesc)
+{
+	int	i;
+	for (i = 0; i < trigdesc->numtriggers; i++)
+	{
+		Trigger    *trigger = &trigdesc->triggers[i];
+		int 		trigtype = RI_TRIGGER_NONE;
+
+		if (func_parallel(trigger->tgfoid) != PROPARALLEL_SAFE)
+			return false;
+
+		/* If the trigger is parallel safe, also look for RI_TRIGGER. */
+		trigtype = RI_FKey_trigger_type(trigger->tgfoid);
+		if (trigtype == RI_TRIGGER_PK || trigtype == RI_TRIGGER_FK)
+			return false;
+	}
+
+	return true;
+}
+
+/*
+ * CheckExprParallelSafety - Determine parallel safety of volatile expressions
+ * in default clause of column definition or in where clause and return true if
+ * they are parallel safe.
+ */
+static pg_attribute_always_inline bool
+CheckExprParallelSafety(CopyState cstate)
+{
+	if (contain_volatile_functions(cstate->whereClause))
+	{
+		if (max_parallel_hazard((Query *) cstate->whereClause) != PROPARALLEL_SAFE)
+			return false;
+	}
+
+	/*
+	 * Check if any of the column has volatile default expression. if yes, and
+	 * they are not parallel safe, then parallelism is not allowed. For
+	 * instance, if there are any serial/bigserial columns for which nextval()
+	 * default expression which is parallel unsafe is associated, parallelism
+	 * should not be allowed. In non parallel copy volatile functions are not
+	 * checked for nextval().
+	 */
+	if (cstate->defexprs != NULL && cstate->num_defaults != 0)
+	{
+		int     i;
+		for (i = 0; i < cstate->num_defaults; i++)
+		{
+			bool volatile_expr = contain_volatile_functions((Node *)cstate->defexprs[i]->expr);
+			if (volatile_expr &&
+				(max_parallel_hazard((Query *)cstate->defexprs[i]->expr)) !=
+				 PROPARALLEL_SAFE)
+				return false;
+		}
+	}
+
+	return true;
+}
+
+/*
+ * FindInsertMethod - Determine insert mode single, multi, or multi conditional.
+ */
+static pg_attribute_always_inline CopyInsertMethod
+FindInsertMethod(CopyState cstate)
+{
+	if (cstate->rel->trigdesc != NULL &&
+		(cstate->rel->trigdesc->trig_insert_before_row ||
+		 cstate->rel->trigdesc->trig_insert_instead_row))
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE &&
+			cstate->rel->trigdesc != NULL &&
+			cstate->rel->trigdesc->trig_insert_new_table)
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
+		return CIM_SINGLE;
+
+	if (cstate->rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+		return CIM_MULTI_CONDITIONAL;
+
+	return CIM_MULTI;
+}
+
+/*
+ * IsParallelCopyAllowed - Check for the cases where parallel copy is not
+ * applicable.
+ */
+static pg_attribute_always_inline bool
+IsParallelCopyAllowed(CopyState cstate)
+{
+	/* Parallel copy not allowed for frontend (2.0 protocol) & binary option. */
+	if ((cstate->copy_dest == COPY_OLD_FE) || cstate->binary)
+		return false;
+
+	/* Check if copy is into foreign table or temporary table. */
+	if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
+		RelationUsesLocalBuffers(cstate->rel))
+		return false;
+
+	/* Check if trigger function is parallel safe. */
+	if (cstate->rel->trigdesc != NULL &&
+		!IsTriggerFunctionParallelSafe(cstate->rel->trigdesc))
+		return false;
+
+	/*
+	 * Check if there is after statement or instead of trigger or transition
+	 * table triggers.
+	 */
+	if (cstate->rel->trigdesc != NULL &&
+		(cstate->rel->trigdesc->trig_insert_after_statement ||
+		 cstate->rel->trigdesc->trig_insert_instead_row ||
+		 cstate->rel->trigdesc->trig_insert_new_table))
+		return false;
+
+	/* Check if the volatile expressions are parallel safe, if present any. */
+	if (!CheckExprParallelSafety(cstate))
+		return false;
+
+	/* Check if the insertion mode is single. */
+	if (FindInsertMethod(cstate) == CIM_SINGLE)
+		return false;
+
+	return true;
+}
+
+/*
  * BeginParallelCopy - Start parallel copy tasks.
  *
  * Get the number of workers required to perform the parallel copy. The data
@@ -758,6 +951,7 @@ BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
 	ParallelCopyData *pcdata;
 	MemoryContext oldcontext;
 
+	CheckTargetRelValidity(cstate);
 	parallel_workers = Min(nworkers, max_worker_processes);
 
 	/* Can't perform copy in parallel */
@@ -769,6 +963,15 @@ BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
 	MemoryContextSwitchTo(oldcontext);
 	cstate->pcdata = pcdata;
 
+	/*
+	 * User chosen parallel copy. Determine if the parallel copy is actually
+	 * allowed. If not, go with the non-parallel mode.
+	 */
+	if (!IsParallelCopyAllowed(cstate))
+		return NULL;
+
+	full_transaction_id = GetCurrentFullTransactionId();
+
 	EnterParallelMode();
 	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
 								 parallel_workers);
@@ -977,9 +1180,214 @@ InitializeParallelCopyInfo(SerializedParallelCopyState *shared_cstate,
 	cstate->line_buf_converted = false;
 	cstate->raw_buf = NULL;
 	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+
+	PopulateCstateCatalogInfo(cstate);
+
+	/* Create workspace for CopyReadAttributes results. */
+	if (!cstate->binary)
+	{
+		AttrNumber	attr_count = list_length(cstate->attnumlist);
+
+		cstate->max_fields = attr_count;
+		cstate->raw_fields = (char **) palloc(attr_count * sizeof(char *));
+	}
+}
+
+/*
+ * CacheLineInfo - Cache the line information to local memory.
+ */
+static bool
+CacheLineInfo(CopyState cstate, uint32 buff_count)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	uint32			write_pos;
+	ParallelCopyDataBlock *data_blk_ptr;
+	ParallelCopyLineBoundary *lineInfo;
+	uint32 offset;
+	int dataSize;
+	int copiedSize = 0;
+
+	resetStringInfo(&pcdata->worker_line_buf[buff_count].line_buf);
+	write_pos = GetLinePosition(cstate);
+	if (-1 == write_pos)
+		return true;
+
+	/* Get the current line information. */
+	lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+	if (pg_atomic_read_u32(&lineInfo->line_size) == 0)
+		goto empty_data_line_update;
+
+	/* Get the block information. */
+	data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+	/* Get the offset information from where the data must be copied. */
+	offset = lineInfo->start_offset;
+	pcdata->worker_line_buf[buff_count].cur_lineno = lineInfo->cur_lineno;
+
+	elog(DEBUG1, "[Worker] Processing - line position:%d, block:%d, unprocessed lines:%d, offset:%d, line size:%d",
+				 write_pos, lineInfo->first_block,
+				 pg_atomic_read_u32(&data_blk_ptr->unprocessed_line_parts),
+				 offset, pg_atomic_read_u32(&lineInfo->line_size));
+
+	for (;;)
+	{
+		uint8 skip_bytes = data_blk_ptr->skip_bytes;
+
+		/*
+		 * There is a possibility that the loop embedded at the bottom of the
+		 * current loop has come out because data_blk_ptr->curr_blk_completed
+		 * is set, but dataSize read might be an old value, if
+		 * data_blk_ptr->curr_blk_completed and the line is completed, line_size
+		 * will be set. Read the line_size again to be sure if it is completed
+		 * or partial block.
+		 */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+		if (dataSize)
+		{
+			int remainingSize = dataSize - copiedSize;
+			if (!remainingSize)
+				break;
+
+			/* Whole line is in current block. */
+			if (remainingSize + offset + skip_bytes < DATA_BLOCK_SIZE)
+			{
+				appendBinaryStringInfo(&pcdata->worker_line_buf[buff_count].line_buf,
+									   &data_blk_ptr->data[offset],
+									   remainingSize);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts,
+										1);
+				break;
+			}
+			else
+			{
+				/* Line is spread across the blocks. */
+				uint32 lineInCurrentBlock =  (DATA_BLOCK_SIZE - skip_bytes) - offset;
+				appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+										 &data_blk_ptr->data[offset],
+										 lineInCurrentBlock);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+				copiedSize += lineInCurrentBlock;
+				while (copiedSize < dataSize)
+				{
+					uint32 currentBlockCopySize;
+					ParallelCopyDataBlock *currBlkPtr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+					skip_bytes = currBlkPtr->skip_bytes;
+
+					/*
+					 * If complete data is present in current block use
+					 * dataSize - copiedSize, or copy the whole block from
+					 * current block.
+					 */
+					currentBlockCopySize = Min(dataSize - copiedSize, DATA_BLOCK_SIZE - skip_bytes);
+					appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+											 &currBlkPtr->data[0],
+											 currentBlockCopySize);
+					pg_atomic_sub_fetch_u32(&currBlkPtr->unprocessed_line_parts, 1);
+					copiedSize += currentBlockCopySize;
+					data_blk_ptr = currBlkPtr;
+				}
+
+				break;
+			}
+		}
+		else
+		{
+			/* Copy this complete block from the current offset. */
+			uint32 lineInCurrentBlock =  (DATA_BLOCK_SIZE - skip_bytes) - offset;
+			appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+									 &data_blk_ptr->data[offset],
+									 lineInCurrentBlock);
+			pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+			copiedSize += lineInCurrentBlock;
+
+			/*
+			 * Reset the offset. For the first copy, copy from the offset. For
+			 * the subsequent copy the complete block.
+			 */
+			offset = 0;
+
+			/* Set data_blk_ptr to the following block. */
+			data_blk_ptr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+		}
+
+		for (;;)
+		{
+			/* Get the size of this line */
+			dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+			/*
+			 * If the data is present in current block lineInfo->line_size
+			 * will be updated. If the data is spread across the blocks either
+			 * of lineInfo->line_size or data_blk_ptr->curr_blk_completed can
+			 * be updated. lineInfo->line_size will be updated if the complete
+			 * read is finished. data_blk_ptr->curr_blk_completed will be
+			 * updated if processing of current block is finished and data
+			 * processing is not finished.
+			 */
+			if (data_blk_ptr->curr_blk_completed || (dataSize != -1))
+				break;
+
+			COPY_WAIT_TO_PROCESS()
+		}
+	}
+
+empty_data_line_update:
+	elog(DEBUG1, "[Worker] Completed processing line:%d", write_pos);
+	pg_atomic_write_u32(&lineInfo->line_state, LINE_WORKER_PROCESSED);
+	pg_atomic_write_u32(&lineInfo->line_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+	return false;
 }
 
 /*
+ * GetWorkerLine - Returns a line for worker to process.
+ */
+static bool
+GetWorkerLine(CopyState cstate)
+{
+	uint32 buff_count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+
+	/*
+	 * Copy the line data to line_buf and release the line position so that the
+	 * worker can continue loading data.
+	 */
+	if (pcdata->worker_line_buf_pos < pcdata->worker_line_buf_count)
+		goto return_line;
+
+	pcdata->worker_line_buf_pos = 0;
+	pcdata->worker_line_buf_count = 0;
+
+	for (buff_count = 0; buff_count < WORKER_CHUNK_COUNT; buff_count++)
+	{
+		bool result = CacheLineInfo(cstate, buff_count);
+		if (result)
+			break;
+
+		pcdata->worker_line_buf_count++;
+	}
+
+	if (pcdata->worker_line_buf_count)
+		goto return_line;
+	else
+		resetStringInfo(&cstate->line_buf);
+
+	return true;
+
+return_line:
+	cstate->line_buf = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].line_buf;
+	cstate->cur_lineno = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].cur_lineno;
+	cstate->line_buf_valid = true;
+
+	/* Mark that encoding conversion hasn't occurred yet. */
+	cstate->line_buf_converted = false;
+	ConvertToServerEncoding(cstate);
+	pcdata->worker_line_buf_pos++;
+	return false;
+ }
+
+/*
  * ParallelCopyMain - Parallel copy worker's code.
  *
  * Where clause handling, convert tuple to columns, add default null values for
@@ -1028,6 +1436,8 @@ ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
 	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
 
 	pcdata->pcshared_info = pcshared_info;
+	AssignFullTransactionIdForWorker(pcshared_info->full_transaction_id);
+	AssignCommandIdForWorker(pcshared_info->mycid, true);
 
 	shared_cstate = (SerializedParallelCopyState *) shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE, false);
 	cstate->null_print = (char *) shm_toc_lookup(toc, PARALLEL_COPY_KEY_NULL_PRINT, true);
@@ -1088,6 +1498,33 @@ ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
 }
 
 /*
+ * UpdateBlockInLineInfo - Update the line information.
+ */
+static pg_attribute_always_inline int
+UpdateBlockInLineInfo(CopyState cstate, uint32 blk_pos,
+					   uint32 offset, uint32 line_size, uint32 line_state)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyLineBoundaries *lineBoundaryPtr = &pcshared_info->line_boundaries;
+	ParallelCopyLineBoundary *lineInfo;
+	int line_pos = lineBoundaryPtr->pos;
+
+	/* Update the line information for the worker to pick and process. */
+	lineInfo = &lineBoundaryPtr->ring[line_pos];
+	while (pg_atomic_read_u32(&lineInfo->line_size) != -1)
+		COPY_WAIT_TO_PROCESS()
+
+	lineInfo->first_block = blk_pos;
+	lineInfo->start_offset = offset;
+	lineInfo->cur_lineno = cstate->cur_lineno;
+	pg_atomic_write_u32(&lineInfo->line_size, line_size);
+	pg_atomic_write_u32(&lineInfo->line_state, line_state);
+	lineBoundaryPtr->pos = (lineBoundaryPtr->pos + 1) % RINGSIZE;
+
+	return line_pos;
+}
+
+/*
  * ParallelCopyFrom - parallel copy leader's functionality.
  *
  * Leader executes the before statement for before statement trigger, if before
@@ -1110,8 +1547,302 @@ ParallelCopyFrom(CopyState cstate)
 	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
 	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
 
+	/* raw_buf is not used in parallel copy, instead data blocks are used.*/
+	pfree(cstate->raw_buf);
+	cstate->raw_buf = NULL;
+
+	/* Execute the before statement triggers from the leader */
+	ExecBeforeStmtTrigger(cstate);
+
+	/* On input just throw the header line away. */
+	if (cstate->cur_lineno == 0 && cstate->header_line)
+	{
+		cstate->cur_lineno++;
+		if (CopyReadLine(cstate))
+		{
+			pcshared_info->is_read_in_progress = false;
+			return;			/* done */
+		}
+	}
+
+	for (;;)
+	{
+		bool done;
+		cstate->cur_lineno++;
+
+		/* Actually read the line into memory here. */
+		done = CopyReadLine(cstate);
+
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			break;
+	}
+
 	pcshared_info->is_read_in_progress = false;
 	cstate->cur_lineno = 0;
+ }
+
+/*
+ * GetLinePosition - Return the line position that worker should process.
+ */
+static uint32
+GetLinePosition(CopyState cstate)
+{
+	ParallelCopyData *pcdata = cstate->pcdata;
+	ParallelCopyShmInfo *pcshared_info = pcdata->pcshared_info;
+	uint32  previous_pos = pcdata->worker_processed_pos;
+	uint32 write_pos = (previous_pos == -1) ? 0 : (previous_pos + 1) % RINGSIZE;
+	for (;;)
+	{
+		int		dataSize;
+		bool	is_read_in_progress = pcshared_info->is_read_in_progress;
+		ParallelCopyLineBoundary *lineInfo;
+		ParallelCopyDataBlock *data_blk_ptr;
+		ParallelCopyLineState line_state = LINE_LEADER_POPULATED;
+		ParallelCopyLineState curr_line_state;
+		CHECK_FOR_INTERRUPTS();
+
+		/* File read completed & no elements to process. */
+		if (!is_read_in_progress &&
+			(pcshared_info->populated ==
+			 pg_atomic_read_u64(&pcshared_info->total_worker_processed)))
+		{
+			write_pos = -1;
+			break;
+		}
+
+		/* Get the current line information. */
+		lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+		curr_line_state = pg_atomic_read_u32(&lineInfo->line_state);
+		if ((write_pos % WORKER_CHUNK_COUNT == 0) &&
+			(curr_line_state == LINE_WORKER_PROCESSED ||
+			 curr_line_state == LINE_WORKER_PROCESSING))
+		{
+			pcdata->worker_processed_pos = write_pos;
+			write_pos = (write_pos + WORKER_CHUNK_COUNT) %  RINGSIZE;
+			continue;
+		}
+
+		/* Get the size of this line. */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+		if (dataSize != 0) /* If not an empty line. */
+		{
+			/* Get the block information. */
+			data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+			if (!data_blk_ptr->curr_blk_completed && (dataSize == -1))
+			{
+				/* Wait till the current line or block is added. */
+				COPY_WAIT_TO_PROCESS()
+				continue;
+			}
+		}
+
+		/* Make sure that no worker has consumed this element. */
+		if (pg_atomic_compare_exchange_u32(&lineInfo->line_state,
+										   &line_state, LINE_WORKER_PROCESSING))
+			break;
+	}
+
+	pcdata->worker_processed_pos = write_pos;
+	return write_pos;
+}
+
+/*
+ * GetFreeCopyBlock - Get a free block for data to be copied.
+ */
+static pg_attribute_always_inline uint32
+GetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	int count = 0;
+	uint32 last_free_block = pcshared_info->cur_block_pos;
+	uint32 block_pos = (last_free_block != -1) ? ((last_free_block + 1) % MAX_BLOCKS_COUNT): 0;
+
+	/*
+	 * Get a new block for copying data, don't check current block, current
+	 * block will have some unprocessed data.
+	 */
+	while (count < (MAX_BLOCKS_COUNT - 1))
+	{
+		ParallelCopyDataBlock *dataBlkPtr = &pcshared_info->data_blocks[block_pos];
+		uint32 unprocessed_line_parts = pg_atomic_read_u32(&dataBlkPtr->unprocessed_line_parts);
+		if (unprocessed_line_parts == 0)
+		{
+			dataBlkPtr->curr_blk_completed = false;
+			dataBlkPtr->skip_bytes = 0;
+			pcshared_info->cur_block_pos = block_pos;
+			return block_pos;
+		}
+
+		block_pos = (block_pos + 1) % MAX_BLOCKS_COUNT;
+		count++;
+	}
+
+	return -1;
+}
+
+/*
+ * WaitGetFreeCopyBlock - If there are no blocks available, wait and get a block
+ * for copying data.
+ */
+static uint32
+WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	uint32 new_free_pos = -1;
+	for (;;)
+	{
+		new_free_pos = GetFreeCopyBlock(pcshared_info);
+		if (new_free_pos != -1)	/* We have got one block, break now. */
+			break;
+
+		COPY_WAIT_TO_PROCESS()
+	}
+
+	return new_free_pos;
+}
+
+/*
+ * SetRawBufForLoad - Set raw_buf to the shared memory where the file data must
+ * be read.
+ */
+static void
+SetRawBufForLoad(CopyState cstate, uint32 line_size, uint32 copy_buf_len,
+				 uint32 raw_buf_ptr, char **copy_raw_buf)
+{
+	ParallelCopyShmInfo	*pcshared_info;
+	uint32 cur_block_pos;
+	uint32 next_block_pos;
+	ParallelCopyDataBlock	*cur_data_blk_ptr = NULL;
+	ParallelCopyDataBlock	*next_data_blk_ptr = NULL;
+
+	if (!IsParallelCopy())
+		return;
+
+	pcshared_info = cstate->pcdata->pcshared_info;
+	cur_block_pos = pcshared_info->cur_block_pos;
+	cur_data_blk_ptr = (cstate->raw_buf) ? &pcshared_info->data_blocks[cur_block_pos] : NULL;
+	next_block_pos = WaitGetFreeCopyBlock(pcshared_info);
+	next_data_blk_ptr = &pcshared_info->data_blocks[next_block_pos];
+
+	/* set raw_buf to the data block in shared memory */
+	cstate->raw_buf = next_data_blk_ptr->data;
+	*copy_raw_buf = cstate->raw_buf;
+	if (cur_data_blk_ptr && line_size)
+	{
+		/*
+		 * Mark the previous block as completed, worker can start copying this
+		 * data.
+		 */
+		cur_data_blk_ptr->following_block = next_block_pos;
+		pg_atomic_add_fetch_u32(&cur_data_blk_ptr->unprocessed_line_parts, 1);
+		cur_data_blk_ptr->skip_bytes = copy_buf_len - raw_buf_ptr;
+		cur_data_blk_ptr->curr_blk_completed = true;
+	}
+}
+
+/*
+ * EndLineParallelCopy - Update the line information in shared memory.
+ */
+static void
+EndLineParallelCopy(CopyState cstate, uint32 line_pos, uint32 line_size,
+					 uint32 raw_buf_ptr)
+{
+	uint8 new_line_size;
+	if (!IsParallelCopy())
+		return;
+
+	if (!IsHeaderLine())
+	{
+		ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+		ParallelCopyLineBoundaries *lineBoundaryPtr = &pcshared_info->line_boundaries;
+		SET_NEWLINE_SIZE()
+		if (line_size)
+		{
+			ParallelCopyLineBoundary *lineInfo = &lineBoundaryPtr->ring[line_pos];
+			/*
+			 * If the new_line_size > raw_buf_ptr, then the new block has only
+			 * new line char content. The unprocessed count should not be
+			 * increased in this case.
+			 */
+			if (raw_buf_ptr > new_line_size)
+			{
+				uint32 cur_block_pos = pcshared_info->cur_block_pos;
+				ParallelCopyDataBlock *curr_data_blk_ptr = &pcshared_info->data_blocks[cur_block_pos];
+				pg_atomic_add_fetch_u32(&curr_data_blk_ptr->unprocessed_line_parts, 1);
+			}
+
+			/* Update line size. */
+			pg_atomic_write_u32(&lineInfo->line_size, line_size);
+			pg_atomic_write_u32(&lineInfo->line_state, LINE_LEADER_POPULATED);
+			elog(DEBUG1, "[Leader] After adding - line position:%d, line_size:%d",
+						 line_pos, line_size);
+			pcshared_info->populated++;
+		}
+		else if (new_line_size)
+		{
+			/* This means only new line char, empty record should be inserted.*/
+			ParallelCopyLineBoundary *lineInfo;
+			line_pos = UpdateBlockInLineInfo(cstate, -1, -1, 0,
+											   LINE_LEADER_POPULATED);
+			lineInfo = &lineBoundaryPtr->ring[line_pos];
+			elog(DEBUG1, "[Leader] Added empty line with offset:%d, line position:%d, line size:%d",
+						 lineInfo->start_offset, line_pos,
+						 pg_atomic_read_u32(&lineInfo->line_size));
+			pcshared_info->populated++;
+		}
+	}
+}
+
+/*
+ * ExecBeforeStmtTrigger - Execute the before statement trigger, this will be
+ * executed for parallel copy by the leader process.
+ */
+static void
+ExecBeforeStmtTrigger(CopyState cstate)
+{
+	EState	   *estate = CreateExecutorState();
+	ResultRelInfo *resultRelInfo;
+
+	Assert(IsLeader());
+
+	/*
+	 * We need a ResultRelInfo so we can use the regular executor's
+	 * index-entry-making machinery.  (There used to be a huge amount of code
+	 * here that basically duplicated execUtils.c ...)
+	 */
+	resultRelInfo = makeNode(ResultRelInfo);
+	InitResultRelInfo(resultRelInfo,
+					  cstate->rel,
+					  1,		/* must match rel's position in range_table */
+					  NULL,
+					  0);
+
+	/* Verify the named relation is a valid target for INSERT */
+	CheckValidResultRel(resultRelInfo, CMD_INSERT);
+
+	estate->es_result_relations = resultRelInfo;
+	estate->es_num_result_relations = 1;
+	estate->es_result_relation_info = resultRelInfo;
+
+	ExecInitRangeTable(estate, cstate->range_table);
+
+	/*
+	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
+	 * should do this for COPY, since it's not really an "INSERT" statement as
+	 * such. However, executing these triggers maintains consistency with the
+	 * EACH ROW triggers that we already fire on COPY.
+	 */
+	ExecBSInsertTriggers(estate, resultRelInfo);
+
+	/* Close any trigger target relations */
+	ExecCleanUpTriggerState(estate);
+
+	FreeExecutorState(estate);
 }
 
 /*
@@ -3573,7 +4304,8 @@ CopyFrom(CopyState cstate)
 
 	PartitionTupleRouting *proute = NULL;
 	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
+	CommandId	mycid = IsParallelCopy() ? GetCurrentCommandId(false) :
+										   GetCurrentCommandId(true);
 	int			ti_options = 0; /* start with default options for insert */
 	BulkInsertState bistate = NULL;
 	CopyInsertMethod insertMethod;
@@ -3583,7 +4315,14 @@ CopyFrom(CopyState cstate)
 	bool		has_instead_insert_row_trig;
 	bool		leafpart_use_multi_insert = false;
 
-	CheckTargetRelValidity(cstate);
+	/*
+	 * Perform this check if it is not parallel copy. In case of parallel
+	 * copy, this check is done by the leader, so that if any invalid case
+	 * exist the copy from command will error out from the leader itself,
+	 * avoiding launching workers, just to throw error.
+	 */
+	if (!IsParallelCopy())
+		CheckTargetRelValidity(cstate);
 
 	/*
 	 * If the target file is new-in-transaction, we assume that checking FSM
@@ -3623,7 +4362,8 @@ CopyFrom(CopyState cstate)
 	target_resultRelInfo = resultRelInfo;
 
 	/* Verify the named relation is a valid target for INSERT */
-	CheckValidResultRel(resultRelInfo, CMD_INSERT);
+	if (!IsParallelCopy())
+		CheckValidResultRel(resultRelInfo, CMD_INSERT);
 
 	ExecOpenIndices(resultRelInfo, false);
 
@@ -3772,13 +4512,16 @@ CopyFrom(CopyState cstate)
 	has_instead_insert_row_trig = (resultRelInfo->ri_TrigDesc &&
 								   resultRelInfo->ri_TrigDesc->trig_insert_instead_row);
 
-	/*
-	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
-	 * should do this for COPY, since it's not really an "INSERT" statement as
-	 * such. However, executing these triggers maintains consistency with the
-	 * EACH ROW triggers that we already fire on COPY.
-	 */
-	ExecBSInsertTriggers(estate, resultRelInfo);
+	if (!IsParallelCopy())
+	{
+		/*
+		 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
+		 * should do this for COPY, since it's not really an "INSERT" statement as
+		 * such. However, executing these triggers maintains consistency with the
+		 * EACH ROW triggers that we already fire on COPY.
+		 */
+		ExecBSInsertTriggers(estate, resultRelInfo);
+	}
 
 	econtext = GetPerTupleExprContext(estate);
 
@@ -3878,6 +4621,16 @@ CopyFrom(CopyState cstate)
 					!has_instead_insert_row_trig &&
 					resultRelInfo->ri_FdwRoutine == NULL;
 
+				/*
+				 * If the table has any partitions that are either foreign or
+				 * has BEFORE/INSTEAD OF triggers, we can't perform copy
+				 * operations with parallel workers.
+				 */
+				if (!leafpart_use_multi_insert && IsParallelWorker())
+					ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							errmsg("cannot perform PARALLEL COPY if partition has BEFORE/INSTEAD OF triggers, or if the partition is foreign partition"),
+							errhint("Try COPY without PARALLEL option")));
+
 				/* Set the multi-insert buffer to use for this partition. */
 				if (leafpart_use_multi_insert)
 				{
@@ -4294,7 +5047,7 @@ BeginCopyFrom(ParseState *pstate,
 	 * only in text mode.
 	 */
 	initStringInfo(&cstate->attribute_buf);
-	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+	cstate->raw_buf = (IsParallelCopy()) ? NULL : (char *) palloc(RAW_BUF_SIZE + 1);
 	cstate->raw_buf_index = cstate->raw_buf_len = 0;
 	if (!cstate->binary)
 	{
@@ -4443,26 +5196,35 @@ NextCopyFromRawFields(CopyState cstate, char ***fields, int *nfields)
 	/* only available for text or csv input */
 	Assert(!cstate->binary);
 
-	/* on input just throw the header line away */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (IsParallelCopy())
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
-			return false;		/* done */
+		done = GetWorkerLine(cstate);
+		if (done && cstate->line_buf.len == 0)
+			return false;
 	}
+	else
+	{
+		/* on input just throw the header line away */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
+		{
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+				return false;		/* done */
+		}
 
-	cstate->cur_lineno++;
+		cstate->cur_lineno++;
 
-	/* Actually read the line into memory here */
-	done = CopyReadLine(cstate);
+		/* Actually read the line into memory here */
+		done = CopyReadLine(cstate);
 
-	/*
-	 * EOF at start of line means we're done.  If we see EOF after some
-	 * characters, we act as though it was newline followed by EOF, ie,
-	 * process the line and then exit loop on next iteration.
-	 */
-	if (done && cstate->line_buf.len == 0)
-		return false;
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			return false;
+	}
 
 	/* Parse the line into de-escaped field values */
 	if (cstate->csv_mode)
@@ -4710,9 +5472,31 @@ CopyReadLine(CopyState cstate)
 		 */
 		if (cstate->copy_dest == COPY_NEW_FE)
 		{
+			bool bIsFirst = true;
 			do
 			{
-				cstate->raw_buf_index = cstate->raw_buf_len;
+				if (!IsParallelCopy())
+					cstate->raw_buf_index = cstate->raw_buf_len;
+				else
+				{
+					if (cstate->raw_buf_index == RAW_BUF_SIZE)
+					{
+						/* Get a new block if it is the first time, From the
+						 * subsequent time, reset the index and re-use the same
+						 * block.
+						 */
+						if (bIsFirst)
+						{
+							ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+							uint32 block_pos = WaitGetFreeCopyBlock(pcshared_info);
+							cstate->raw_buf = pcshared_info->data_blocks[block_pos].data;
+							bIsFirst = false;
+						}
+
+						cstate->raw_buf_index = cstate->raw_buf_len = 0;
+					}
+				}
+
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
@@ -4767,7 +5551,7 @@ static void
 ConvertToServerEncoding(CopyState cstate)
 {
 	/* Done reading the line.  Convert it to server encoding. */
-	if (cstate->need_transcoding)
+	if (cstate->need_transcoding && (!IsParallelCopy() || IsWorker()))
 	{
 		char	   *cvt;
 		cvt = pg_any_to_server(cstate->line_buf.data,
@@ -4806,6 +5590,11 @@ CopyReadLineText(CopyState cstate)
 	char		quotec = '\0';
 	char		escapec = '\0';
 
+	/* For parallel copy */
+	int			line_size = 0;
+	int			line_pos = 0;
+
+	cstate->eol_type = EOL_UNKNOWN;
 	if (cstate->csv_mode)
 	{
 		quotec = cstate->quote[0];
@@ -4860,6 +5649,8 @@ CopyReadLineText(CopyState cstate)
 		if (raw_buf_ptr >= copy_buf_len || need_data)
 		{
 			REFILL_LINEBUF;
+			SetRawBufForLoad(cstate, line_size, copy_buf_len, raw_buf_ptr,
+							 &copy_raw_buf);
 
 			/*
 			 * Try to read some more data.  This will certainly reset
@@ -5084,9 +5875,15 @@ CopyReadLineText(CopyState cstate)
 				 * discard the data and the \. sequence.
 				 */
 				if (prev_raw_ptr > cstate->raw_buf_index)
-					appendBinaryStringInfo(&cstate->line_buf,
+				{
+					if (!IsParallelCopy())
+						appendBinaryStringInfo(&cstate->line_buf,
 										   cstate->raw_buf + cstate->raw_buf_index,
 										   prev_raw_ptr - cstate->raw_buf_index);
+					else
+						line_size += prev_raw_ptr - cstate->raw_buf_index;
+				}
+
 				cstate->raw_buf_index = raw_buf_ptr;
 				result = true;	/* report EOF */
 				break;
@@ -5138,6 +5935,26 @@ not_end_of_copy:
 			IF_NEED_REFILL_AND_EOF_BREAK(mblen - 1);
 			raw_buf_ptr += mblen - 1;
 		}
+
+		/*
+		 * Skip the header line. Update the line here, this cannot be done at
+		 * the beginning, as there is a possibility that file contains empty
+		 * lines.
+		 */
+		if (IsParallelCopy() && first_char_in_line && !IsHeaderLine())
+		{
+			ParallelCopyShmInfo	*pcshared_info = cstate->pcdata->pcshared_info;
+			ParallelCopyLineBoundary *lineInfo;
+			uint32			 line_first_block = pcshared_info->cur_block_pos;
+			line_pos = UpdateBlockInLineInfo(cstate,
+											   line_first_block,
+											   cstate->raw_buf_index, -1,
+											   LINE_LEADER_POPULATING);
+			lineInfo = &pcshared_info->line_boundaries.ring[line_pos];
+			elog(DEBUG1, "[Leader] Adding - block:%d, offset:%d, line position:%d",
+						 line_first_block,	lineInfo->start_offset, line_pos);
+		}
+
 		first_char_in_line = false;
 	}							/* end of outer loop */
 
@@ -5146,6 +5963,7 @@ not_end_of_copy:
 	 */
 	REFILL_LINEBUF;
 	CLEAR_EOL_LINE();
+	EndLineParallelCopy(cstate, line_pos, line_size, raw_buf_ptr);
 
 	return result;
 }
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index 9c6f5ec..43fc823 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -2353,7 +2353,7 @@ psql_completion(const char *text, int start, int end)
 	/* Complete COPY <sth> FROM|TO filename WITH ( */
 	else if (Matches("COPY|\\copy", MatchAny, "FROM|TO", MatchAny, "WITH", "("))
 		COMPLETE_WITH("FORMAT", "FREEZE", "DELIMITER", "NULL",
-					  "HEADER", "QUOTE", "ESCAPE", "FORCE_QUOTE",
+					  "HEADER", "PARALLEL", "QUOTE", "ESCAPE", "FORCE_QUOTE",
 					  "FORCE_NOT_NULL", "FORCE_NULL", "ENCODING");
 
 	/* Complete COPY <sth> FROM|TO filename WITH (FORMAT */
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index df1b43a..71a6c9b 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -385,6 +385,8 @@ extern FullTransactionId GetTopFullTransactionId(void);
 extern FullTransactionId GetTopFullTransactionIdIfAny(void);
 extern FullTransactionId GetCurrentFullTransactionId(void);
 extern FullTransactionId GetCurrentFullTransactionIdIfAny(void);
+extern void AssignFullTransactionIdForWorker(FullTransactionId fullTransactionId);
+extern void AssignCommandIdForWorker(CommandId commandId, bool used);
 extern void MarkCurrentTransactionIdLoggedIfAny(void);
 extern bool SubTransactionIsActive(SubTransactionId subxid);
 extern CommandId GetCurrentCommandId(bool used);
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 509c695..e8d8ffd 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1707,6 +1707,7 @@ ParallelCopyLineBoundary
 ParallelCopyData
 ParallelCopyDataBlock
 ParallelCopyLineBuf
+ParallelCopyLineState
 ParallelCopyShmInfo
 ParallelExecutorInfo
 ParallelHashGrowth
-- 
1.8.3.1

v5-0004-Documentation-for-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=v5-0004-Documentation-for-parallel-copy.patchDownload
From 6a04ea9b0fbd62966d37212c7590f62c9d71b309 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Sat, 1 Aug 2020 09:00:36 +0530
Subject: [PATCH v5 4/6] Documentation for parallel copy.

This patch has the documentation changes for parallel copy.
---
 doc/src/sgml/ref/copy.sgml | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/doc/src/sgml/ref/copy.sgml b/doc/src/sgml/ref/copy.sgml
index 18189ab..2e023ed 100644
--- a/doc/src/sgml/ref/copy.sgml
+++ b/doc/src/sgml/ref/copy.sgml
@@ -37,6 +37,7 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
     DELIMITER '<replaceable class="parameter">delimiter_character</replaceable>'
     NULL '<replaceable class="parameter">null_string</replaceable>'
     HEADER [ <replaceable class="parameter">boolean</replaceable> ]
+    PARALLEL <replaceable class="parameter">integer</replaceable>
     QUOTE '<replaceable class="parameter">quote_character</replaceable>'
     ESCAPE '<replaceable class="parameter">escape_character</replaceable>'
     FORCE_QUOTE { ( <replaceable class="parameter">column_name</replaceable> [, ...] ) | * }
@@ -275,6 +276,22 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
    </varlistentry>
 
    <varlistentry>
+    <term><literal>PARALLEL</literal></term>
+    <listitem>
+     <para>
+      Perform <command>COPY FROM</command> in parallel using <replaceable
+      class="parameter"> integer</replaceable> background workers.  Please
+      note that it is not guaranteed that the number of parallel workers
+      specified in <replaceable class="parameter">integer</replaceable> will
+      be used during execution.  It is possible for a copy to run with fewer
+      workers than specified, or even with no workers at all (for example,
+      due to the setting of max_worker_processes). This option is allowed
+      only in <command>COPY FROM</command>.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><literal>QUOTE</literal></term>
     <listitem>
      <para>
-- 
1.8.3.1

v5-0005-Tests-for-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=v5-0005-Tests-for-parallel-copy.patchDownload
From f2b0635303b986ea944f38e9325b1f06c53a5060 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Sat, 1 Aug 2020 09:19:39 +0530
Subject: [PATCH v5 5/6] Tests for parallel copy.

This patch has the tests for parallel copy.
---
 src/test/regress/expected/copy2.out | 205 ++++++++++++++++++++++++++++++++++-
 src/test/regress/input/copy.source  |  12 +++
 src/test/regress/output/copy.source |  12 +++
 src/test/regress/sql/copy2.sql      | 208 +++++++++++++++++++++++++++++++++++-
 4 files changed, 429 insertions(+), 8 deletions(-)

diff --git a/src/test/regress/expected/copy2.out b/src/test/regress/expected/copy2.out
index e40287d..7ae5d44 100644
--- a/src/test/regress/expected/copy2.out
+++ b/src/test/regress/expected/copy2.out
@@ -254,18 +254,32 @@ It is "perfect".|
 "It is ""perfect"".","	"
 "",
 --test that we read consecutive LFs properly
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 COPY testnl FROM stdin CSV;
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+SELECT * FROM testnl;
+ a |          b           | c 
+---+----------------------+---
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+(2 rows)
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 COPY testeoc FROM stdin CSV;
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
 COPY testeoc TO stdout CSV;
 a\.
 \.b
 c\.d
 "\."
 -- test handling of nonstandard null marker that violates escaping rules
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 COPY testnull TO stdout WITH NULL AS E'\\0';
 1	\\0
@@ -280,6 +294,15 @@ SELECT * FROM testnull;
     | 
 (4 rows)
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 1);
+SELECT * FROM testnull;
+ a  | b  
+----+----
+ 42 | \0
+    | 
+(2 rows)
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -349,6 +372,34 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+SELECT * FROM vistest;
+ a  
+----
+ a2
+ b
+(2 rows)
+
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+COMMIT;
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 SELECT * FROM vistest;
  a 
@@ -409,7 +460,7 @@ SELECT * FROM vistest;
 (2 rows)
 
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -420,6 +471,8 @@ CREATE TEMP TABLE forcetest (
 -- should succeed with no effect ("b" remains an empty string, "c" remains NULL)
 BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 1);
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
  b |  c   
@@ -430,6 +483,8 @@ SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
 BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 1);
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
  c |  d   
@@ -486,6 +541,31 @@ select * from check_con_tbl;
    
 (2 rows)
 
+\d+ check_con_tbl
+                               Table "public.check_con_tbl"
+ Column |  Type   | Collation | Nullable | Default | Storage | Stats target | Description 
+--------+---------+-----------+----------+---------+---------+--------------+-------------
+ f1     | integer |           |          |         | plain   |              | 
+Check constraints:
+    "check_con_tbl_check" CHECK (check_con_function(check_con_tbl.*))
+
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 1);
+NOTICE:  input = {"f1":1}
+NOTICE:  input = {"f1":null}
+copy check_con_tbl from stdin with (parallel 1);
+NOTICE:  input = {"f1":0}
+ERROR:  new row for relation "check_con_tbl" violates check constraint "check_con_tbl_check"
+DETAIL:  Failing row contains (0).
+CONTEXT:  COPY check_con_tbl, line 1: "0"
+parallel worker
+select * from check_con_tbl;
+ f1 
+----
+  1
+   
+(2 rows)
+
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
 CREATE ROLE regress_rls_copy_user_colperms;
@@ -600,8 +680,125 @@ SELECT * FROM instead_of_insert_tbl;
 (2 rows)
 
 COMMIT;
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+COPY test_parallel_copy (a, b, c, d, e) from stdin with (PARALLEL 1);
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1, FORMAT 'csv', HEADER);
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0');
+ERROR:  value 0 out of bounds for option "parallel"
+DETAIL:  Valid values are between "1" and "1024".
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri from stdin with (FORMAT csv, DELIMITER ',', PARALLEL 1);
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1) WHERE height > random() * 65;
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+-- temporary table copy: should perform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+COPY temp_test (a) from stdin with (PARALLEL 1);
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) from stdin with (PARALLEL 1);
+ERROR:  column "xyz" of relation "test_parallel_copy" does not exist
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) from stdin with (PARALLEL 1);
+ERROR:  column "d" specified more than once
+-- missing data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  invalid input syntax for type integer: ""
+CONTEXT:  COPY test_parallel_copy, line 0, column a: ""
+parallel worker
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2000	230	23	23"
+parallel worker
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2001	231	\N	\N"
+parallel worker
+-- extra data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  extra data after last expected column
+CONTEXT:  COPY test_parallel_copy, line 1: "2002	232	40	50	60	70	80"
+parallel worker
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) from stdin with (delimiter ',', null 'x', PARALLEL 1) ;
+COPY test_parallel_copy from stdin WITH (DELIMITER ';', NULL '', PARALLEL 1);
+COPY test_parallel_copy from stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL 1);
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = 50004;
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a > 60003;
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE f > 60003;
+ERROR:  column "f" does not exist
+LINE 1: ..._parallel_copy from stdin WITH (PARALLEL 1) WHERE f > 60003;
+                                                             ^
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+ERROR:  missing FROM-clause entry for table "x"
+LINE 1: ...rallel_copy from stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+                                                                  ^
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (SELECT 1 FROM x);
+ERROR:  cannot use subquery in COPY FROM WHERE condition
+LINE 1: ...arallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (SELECT...
+                                                             ^
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (generate_series(1,5));
+ERROR:  set-returning functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...lel_copy from stdin WITH (PARALLEL 1) WHERE a IN (generate_s...
+                                                             ^
+COPY test_parallel_copy from stdin WITH(PARALLEL 1) WHERE a = row_number() over(b);
+ERROR:  window functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...rallel_copy from stdin WITH(PARALLEL 1) WHERE a = row_number...
+                                                             ^
+-- check results of copy in
+SELECT * FROM test_parallel_copy;
+   a   | b  |     c      |    d    |    e    
+-------+----+------------+---------+---------
+     1 | 11 | test_c1    | test_d1 | test_e1
+     2 | 12 | test_c2    | test_d2 | test_e2
+       |  3 | stuff      | test_d3 | 
+       |  4 | stuff      | test_d4 | 
+       |  5 | stuff      | test_d5 | 
+       |    | 45         | 80      | 90
+       |    | x          | \x      | \x
+       |    | ,          | \,      | \
+  3000 |    | c          |         | 
+  4000 |    | C          |         | 
+  4001 |  1 | empty      |         | 
+  4002 |  2 | null       |         | 
+  4003 |  3 | Backslash  | \       | \
+  4004 |  4 | BackslashX | \X      | \X
+  4005 |  5 | N          | N       | N
+  4006 |  6 | BackslashN | \N      | \N
+  4007 |  7 | XX         | XX      | XX
+  4008 |  8 | Delimiter  | :       | :
+ 50004 | 25 | 35         | 45      | 55
+ 60004 | 25 | 35         | 45      | 55
+ 60005 | 26 | 36         | 46      | 56
+(21 rows)
+
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
 DROP TABLE x, y;
diff --git a/src/test/regress/input/copy.source b/src/test/regress/input/copy.source
index a1d529a..159c058 100644
--- a/src/test/regress/input/copy.source
+++ b/src/test/regress/input/copy.source
@@ -15,6 +15,13 @@ DELETE FROM onek;
 
 COPY onek FROM '@abs_builddir@/results/onek.data';
 
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+
+SELECT COUNT(*) FROM tenk1;
+
+TRUNCATE tenk1;
+
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
@@ -159,6 +166,11 @@ truncate parted_copytest;
 
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
 
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
+
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/output/copy.source b/src/test/regress/output/copy.source
index 938d355..c3003fe 100644
--- a/src/test/regress/output/copy.source
+++ b/src/test/regress/output/copy.source
@@ -9,6 +9,15 @@ COPY onek FROM '@abs_srcdir@/data/onek.data';
 COPY onek TO '@abs_builddir@/results/onek.data';
 DELETE FROM onek;
 COPY onek FROM '@abs_builddir@/results/onek.data';
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+SELECT COUNT(*) FROM tenk1;
+ count 
+-------
+ 10000
+(1 row)
+
+TRUNCATE tenk1;
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
 COPY person FROM '@abs_srcdir@/data/person.data';
@@ -113,6 +122,9 @@ insert into parted_copytest select x,1,'One' from generate_series(1011,1020) x;
 copy (select * from parted_copytest order by a) to '@abs_builddir@/results/parted_copytest.csv';
 truncate parted_copytest;
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/sql/copy2.sql b/src/test/regress/sql/copy2.sql
index 902f4fa..7015698 100644
--- a/src/test/regress/sql/copy2.sql
+++ b/src/test/regress/sql/copy2.sql
@@ -157,7 +157,7 @@ COPY y TO stdout (FORMAT CSV, FORCE_QUOTE *);
 
 --test that we read consecutive LFs properly
 
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 
 COPY testnl FROM stdin CSV;
 1,"a field with two LFs
@@ -165,8 +165,16 @@ COPY testnl FROM stdin CSV;
 inside",2
 \.
 
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+1,"a field with two LFs
+
+inside",2
+\.
+
+SELECT * FROM testnl;
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 
 COPY testeoc FROM stdin CSV;
 a\.
@@ -175,11 +183,19 @@ c\.d
 "\."
 \.
 
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+a\.
+\.b
+c\.d
+"\."
+\.
+
 COPY testeoc TO stdout CSV;
 
 -- test handling of nonstandard null marker that violates escaping rules
 
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 
 COPY testnull TO stdout WITH NULL AS E'\\0';
@@ -191,6 +207,14 @@ COPY testnull FROM stdin WITH NULL AS E'\\0';
 
 SELECT * FROM testnull;
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 1);
+42	\\0
+\0	\0
+\.
+
+SELECT * FROM testnull;
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -235,6 +259,23 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+a2
+b
+\.
+SELECT * FROM vistest;
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+d2
+e
+\.
+SELECT * FROM vistest;
+COMMIT;
+SELECT * FROM vistest;
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 x
 y
@@ -284,7 +325,7 @@ SELECT * FROM vistest;
 COMMIT;
 SELECT * FROM vistest;
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -297,6 +338,10 @@ BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
 1,,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 1);
+1,,""
+\.
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
@@ -304,6 +349,10 @@ BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
 2,'a',,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 1);
+2,'a',,""
+\.
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
 -- should fail with not-null constraint violation
@@ -339,6 +388,16 @@ copy check_con_tbl from stdin;
 0
 \.
 select * from check_con_tbl;
+\d+ check_con_tbl
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 1);
+1
+\N
+\.
+copy check_con_tbl from stdin with (parallel 1);
+0
+\.
+select * from check_con_tbl;
 
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
@@ -440,8 +499,149 @@ test1
 SELECT * FROM instead_of_insert_tbl;
 COMMIT;
 
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+
+COPY test_parallel_copy (a, b, c, d, e) from stdin with (PARALLEL 1);
+1	11	test_c1	test_d1	test_e1
+2	12	test_c2	test_d2	test_e2
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+3	test_d3
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+4	test_d4
+5	test_d5
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1, FORMAT 'csv', HEADER);
+b	d
+\.
+
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0');
+
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri from stdin with (FORMAT csv, DELIMITER ',', PARALLEL 1);
+10
+\.
+
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1) WHERE height > random() * 65;
+60,60,60
+\.
+
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+60
+\.
+
+-- temporary table copy: should perform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+
+COPY temp_test (a) from stdin with (PARALLEL 1);
+10
+\.
+
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) from stdin with (PARALLEL 1);
+
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) from stdin with (PARALLEL 1);
+
+-- missing data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+
+\.
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+2000	230	23	23
+\.
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+2001	231	\N	\N
+\.
+
+-- extra data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+2002	232	40	50	60	70	80
+\.
+
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) from stdin with (delimiter ',', null 'x', PARALLEL 1) ;
+x,45,80,90
+x,\x,\\x,\\\x
+x,\,,\\\,,\\
+\.
+
+COPY test_parallel_copy from stdin WITH (DELIMITER ';', NULL '', PARALLEL 1);
+3000;;c;;
+\.
+
+COPY test_parallel_copy from stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL 1);
+4000:\X:C:\X:\X
+4001:1:empty::
+4002:2:null:\X:\X
+4003:3:Backslash:\\:\\
+4004:4:BackslashX:\\X:\\X
+4005:5:N:\N:\N
+4006:6:BackslashN:\\N:\\N
+4007:7:XX:\XX:\XX
+4008:8:Delimiter:\::\:
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = 50004;
+50003	24	34	44	54
+50004	25	35	45 	55
+50005	26	36	46	56
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a > 60003;
+60001	22	32	42	52
+60002	23	33	43	53
+60003	24	34	44	54
+60004	25	35	45	55
+60005	26	36	46	56
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE f > 60003;
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (SELECT 1 FROM x);
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (generate_series(1,5));
+
+COPY test_parallel_copy from stdin WITH(PARALLEL 1) WHERE a = row_number() over(b);
+
+-- check results of copy in
+SELECT * FROM test_parallel_copy;
+
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
 DROP TABLE x, y;
-- 
1.8.3.1

v5-0006-Parallel-Copy-For-Binary-Format-Files.patchtext/x-patch; charset=US-ASCII; name=v5-0006-Parallel-Copy-For-Binary-Format-Files.patchDownload
From 8dc40e5d290edd954b7914d3f8abe3de22b1667d Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Tue, 22 Sep 2020 13:43:10 +0530
Subject: [PATCH v5 6/6] Parallel Copy For Binary Format Files

Leader reads data from the file into the DSM data blocks each of 64K size.
It also identifies each tuple data block id, start offset, end offset,
tuple size and updates this information in the ring data structure.
Workers parallelly read the tuple information from the ring data structure,
the actual tuple data from the data blocks and parallelly insert the tuples
into the table.
---
 src/backend/commands/copy.c | 681 ++++++++++++++++++++++++++++++++++++++------
 1 file changed, 597 insertions(+), 84 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index ba188d7..5b1884a 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -266,6 +266,17 @@ typedef struct ParallelCopyLineBuf
 } ParallelCopyLineBuf;
 
 /*
+ * Represents the usage mode for CopyReadBinaryGetDataBlock.
+ */
+typedef enum FieldInfoType
+{
+	FIELD_NONE = 0,
+	FIELD_COUNT,
+	FIELD_SIZE,
+	FIELD_DATA
+} FieldInfoType;
+
+/*
  * Parallel copy data information.
  */
 typedef struct ParallelCopyData
@@ -286,6 +297,9 @@ typedef struct ParallelCopyData
 
 	/* Current position in worker_line_buf */
 	uint32				worker_line_buf_pos;
+
+	/* For binary formatted files */
+	ParallelCopyDataBlock *curr_data_block;
 } ParallelCopyData;
 
 /*
@@ -450,6 +464,7 @@ typedef struct SerializedParallelCopyState
 	/* Working state for COPY FROM */
 	AttrNumber          num_defaults;
 	Oid                 relid;
+	bool				binary;
 } SerializedParallelCopyState;
 
 /* DestReceiver for COPY (query) TO */
@@ -524,7 +539,6 @@ typedef struct CopyMultiInsertInfo
 	int			ti_options;		/* table insert options */
 } CopyMultiInsertInfo;
 
-
 /*
  * These macros centralize code used to process line_buf and raw_buf buffers.
  * They are macros because they often do continue/break control and to avoid
@@ -652,11 +666,113 @@ if (!IsParallelCopy()) \
 else \
 	return pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
 
+/*
+ * CHECK_FIELD_COUNT - Handles the error cases for field count
+ * for binary format files.
+ */
+#define CHECK_FIELD_COUNT \
+{\
+	if (fld_count == -1) \
+	{ \
+		if (IsParallelCopy() && \
+			!IsLeader()) \
+			return true; \
+		else if (IsParallelCopy() && \
+			IsLeader()) \
+		{ \
+			if (cstate->pcdata->curr_data_block->data[cstate->raw_buf_index + sizeof(fld_count)] != 0) \
+				ereport(ERROR, \
+						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+						errmsg("received copy data after EOF marker"))); \
+			return true; \
+		} \
+		else \
+		{ \
+			/* \
+			 * Received EOF marker.  In a V3-protocol copy, wait for the \
+			 * protocol-level EOF, and complain if it doesn't come \
+			 * immediately.  This ensures that we correctly handle CopyFail, \
+			 * if client chooses to send that now. \
+			 * \
+			 * Note that we MUST NOT try to read more data in an old-protocol \
+			 * copy, since there is no protocol-level EOF marker then.  We \
+			 * could go either way for copy from file, but choose to throw \
+			 * error if there's data after the EOF marker, for consistency \
+			 * with the new-protocol case. \
+			 */ \
+			char		dummy; \
+			if (cstate->copy_dest != COPY_OLD_FE && \
+				CopyReadBinaryData(cstate, &dummy, 1) > 0) \
+				ereport(ERROR, \
+						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+						errmsg("received copy data after EOF marker"))); \
+				return false; \
+		} \
+	} \
+	if (fld_count != cstate->max_fields) \
+		ereport(ERROR, \
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+				errmsg("row field count is %d, expected %d", \
+				(int) fld_count, cstate->max_fields))); \
+}
+
+/*
+ * CHECK_FIELD_SIZE - Handles the error case for field size
+ * for binary format files.
+ */
+#define CHECK_FIELD_SIZE(fld_size) \
+{ \
+	if (fld_size < -1) \
+		ereport(ERROR, \
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+				errmsg("invalid field size")));\
+}
+
+/*
+ * EOF_ERROR - Error statement for EOF for binary format
+ * files.
+ */
+#define EOF_ERROR \
+{ \
+	ereport(ERROR, \
+		(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+		errmsg("unexpected EOF in COPY data")));\
+}
+
+/*
+ * GET_RAW_BUF_INDEX - Calculates the raw buf index for the cases
+ * where the data spread is across multiple data blocks.
+ */
+#define GET_RAW_BUF_INDEX(raw_buf_index, fld_size, required_blks, curr_blk_bytes) \
+{ \
+	raw_buf_index = fld_size - (((required_blks - 1) * DATA_BLOCK_SIZE) + curr_blk_bytes); \
+}
+
+/*
+ * GET_REQUIRED_BLOCKS - Calculates the number of data
+ * blocks required for the cases where the data spread
+ * is across multiple data blocks.
+ */
+#define GET_REQUIRED_BLOCKS(required_blks, fld_size, curr_blk_bytes) \
+{ \
+	/* \
+	 * field size can spread across multiple data blocks, \
+	 * calculate the number of required data blocks and try to get \
+	 * those many data blocks. \
+	 */ \
+	required_blks = (int32)(fld_size - curr_blk_bytes)/(int32)DATA_BLOCK_SIZE; \
+	/* \
+	 * check if we need the data block for the field data \
+	 * bytes that are not modulus of data block size. \
+	 */ \
+	if ((fld_size - curr_blk_bytes)%DATA_BLOCK_SIZE != 0) \
+		required_blks++; \
+}
+
 /* End parallel copy Macros */
 
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
-
 /* non-export function prototypes */
 static CopyState BeginCopy(ParseState *pstate, bool is_from, Relation rel,
 						   RawStmt *raw_query, Oid queryRelId, List *attnamelist,
@@ -711,6 +827,13 @@ static void ExecBeforeStmtTrigger(CopyState cstate);
 static void CheckTargetRelValidity(CopyState cstate);
 static void PopulateCstateCatalogInfo(CopyState cstate);
 static pg_attribute_always_inline uint32 GetLinePosition(CopyState cstate);
+static uint32 WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info);
+static bool CopyReadBinaryTupleLeader(CopyState cstate);
+static void CopyReadBinaryFindTupleSize(CopyState cstate, uint32 *line_size);
+static bool CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls);
+static Datum CopyReadBinaryAttributeWorker(CopyState cstate, FmgrInfo *flinfo,
+										   Oid typioparam, int32 typmod, bool *isnull);
+static void CopyReadBinaryGetDataBlock(CopyState cstate, FieldInfoType field_info);
 
 /*
  * SerializeParallelCopyState - Copy shared_cstate using cstate information.
@@ -729,6 +852,7 @@ SerializeParallelCopyState(CopyState cstate, SerializedParallelCopyState *shared
 	shared_cstate->convert_selectively = cstate->convert_selectively;
 	shared_cstate->num_defaults = cstate->num_defaults;
 	shared_cstate->relid = cstate->pcdata->relid;
+	shared_cstate->binary = cstate->binary;
 }
 
 /*
@@ -888,8 +1012,8 @@ FindInsertMethod(CopyState cstate)
 static pg_attribute_always_inline bool
 IsParallelCopyAllowed(CopyState cstate)
 {
-	/* Parallel copy not allowed for frontend (2.0 protocol) & binary option. */
-	if ((cstate->copy_dest == COPY_OLD_FE) || cstate->binary)
+	/* Parallel copy not allowed for frontend (2.0 protocol). */
+	if (cstate->copy_dest == COPY_OLD_FE)
 		return false;
 
 	/* Check if copy is into foreign table or temporary table. */
@@ -1159,6 +1283,7 @@ InitializeParallelCopyInfo(SerializedParallelCopyState *shared_cstate,
 	cstate->convert_selectively = shared_cstate->convert_selectively;
 	cstate->num_defaults = shared_cstate->num_defaults;
 	pcdata->relid = shared_cstate->relid;
+	cstate->binary = shared_cstate->binary;
 
 	PopulateCommonCstateInfo(cstate, tup_desc, attnamelist);
 
@@ -1554,32 +1679,66 @@ ParallelCopyFrom(CopyState cstate)
 	/* Execute the before statement triggers from the leader */
 	ExecBeforeStmtTrigger(cstate);
 
-	/* On input just throw the header line away. */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (!cstate->binary)
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
+		/* On input just throw the header line away. */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
 		{
-			pcshared_info->is_read_in_progress = false;
-			return;			/* done */
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+			{
+				pcshared_info->is_read_in_progress = false;
+				return;			/* done */
+			}
 		}
-	}
 
-	for (;;)
-	{
-		bool done;
-		cstate->cur_lineno++;
+		for (;;)
+		{
+			bool done;
+			cstate->cur_lineno++;
 
-		/* Actually read the line into memory here. */
-		done = CopyReadLine(cstate);
+			/* Actually read the line into memory here. */
+			done = CopyReadLine(cstate);
 
+			/*
+			* EOF at start of line means we're done.  If we see EOF after some
+			* characters, we act as though it was newline followed by EOF, ie,
+			* process the line and then exit loop on next iteration.
+			*/
+			if (done && cstate->line_buf.len == 0)
+				break;
+		}
+	}
+	else
+	{
 		/*
-		 * EOF at start of line means we're done.  If we see EOF after some
-		 * characters, we act as though it was newline followed by EOF, ie,
-		 * process the line and then exit loop on next iteration.
+		 * Binary Format Files.
+		 * For parallel copy leader, fill in the error
+		 * context information here, in case any failures
+		 * while determining tuple offsets, leader
+		 * would throw the errors with proper context.
 		 */
-		if (done && cstate->line_buf.len == 0)
-			break;
+		ErrorContextCallback errcallback;
+		errcallback.callback = CopyFromErrorCallback;
+		errcallback.arg = (void *) cstate;
+		errcallback.previous = error_context_stack;
+		error_context_stack = &errcallback;
+		cstate->pcdata->curr_data_block = NULL;
+		cstate->raw_buf_index = 0;
+		pcshared_info->populated = 0;
+		cstate->cur_lineno = 0;
+		cstate->max_fields = list_length(cstate->attnumlist);
+
+		for (;;)
+		{
+			bool eof = false;
+			cstate->cur_lineno++;
+
+			eof = CopyReadBinaryTupleLeader(cstate);
+
+			if (eof)
+				break;
+		}
 	}
 
 	pcshared_info->is_read_in_progress = false;
@@ -1587,6 +1746,354 @@ ParallelCopyFrom(CopyState cstate)
  }
 
 /*
+ * CopyReadBinaryGetDataBlock - Gets a new block, updates
+ * the current offset, calculates the skip bytes.
+ */
+static void
+CopyReadBinaryGetDataBlock(CopyState cstate, FieldInfoType field_info)
+{
+	ParallelCopyDataBlock *data_block = NULL;
+	ParallelCopyDataBlock *curr_data_block = cstate->pcdata->curr_data_block;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	uint8 move_bytes = 0;
+	uint32 block_pos;
+	uint32 prev_block_pos;
+	int read_bytes = 0;
+
+	prev_block_pos = pcshared_info->cur_block_pos;
+
+	block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+	if (field_info == FIELD_SIZE || field_info == FIELD_COUNT)
+		move_bytes = (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+
+	if (curr_data_block != NULL)
+		curr_data_block->skip_bytes = move_bytes;
+
+	data_block = &pcshared_info->data_blocks[block_pos];
+
+	if (move_bytes > 0 && curr_data_block != NULL)
+		memmove(&data_block->data[0], &curr_data_block->data[cstate->raw_buf_index], move_bytes);
+
+	elog(DEBUG1, "LEADER - field info %d is spread across data blocks - moved %d bytes from current block %u to %u block",
+		field_info, move_bytes, prev_block_pos, block_pos);
+
+	read_bytes = CopyGetData(cstate, &data_block->data[move_bytes], 1, (DATA_BLOCK_SIZE - move_bytes));
+
+	if (field_info == FIELD_NONE && cstate->reached_eof)
+		return;
+
+	if (cstate->reached_eof)
+		EOF_ERROR;
+
+	elog(DEBUG1, "LEADER - bytes read from file %d", read_bytes);
+
+	if(field_info == FIELD_SIZE || field_info == FIELD_DATA)
+	{
+		ParallelCopyDataBlock *prev_data_block = NULL;
+		prev_data_block = curr_data_block;
+		prev_data_block->following_block = block_pos;
+
+		if (prev_data_block->curr_blk_completed  == false)
+			prev_data_block->curr_blk_completed = true;
+
+		pg_atomic_add_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+	}
+
+	cstate->pcdata->curr_data_block = data_block;
+	cstate->raw_buf_index = 0;
+}
+
+/*
+ * CopyReadBinaryTupleLeader - Leader reads data from binary formatted file
+ * to data blocks and identifies tuple boundaries/offsets so that workers
+ * can work on the data blocks data.
+ */
+static bool
+CopyReadBinaryTupleLeader(CopyState cstate)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	int16		fld_count;
+	uint32      line_size = 0;
+	uint32 		start_block_pos;
+	uint32		start_offset;
+
+	if (cstate->pcdata->curr_data_block == NULL)
+	{
+		CopyReadBinaryGetDataBlock(cstate, FIELD_NONE);
+
+		/*
+		 * no data is read from file here. one possibility
+		 * to be here could be that the binary file just
+		 * has a valid signature but nothing else.
+		 */
+		if (cstate->reached_eof)
+			return true;
+	}
+
+	if ((cstate->raw_buf_index + sizeof(fld_count)) >= DATA_BLOCK_SIZE)
+		CopyReadBinaryGetDataBlock(cstate, FIELD_COUNT);
+
+	memcpy(&fld_count, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_count));
+	fld_count = (int16) pg_ntoh16(fld_count);
+	CHECK_FIELD_COUNT;
+	start_offset = cstate->raw_buf_index;
+	cstate->raw_buf_index += sizeof(fld_count);
+	line_size += sizeof(fld_count);
+	start_block_pos = pcshared_info->cur_block_pos;
+
+	CopyReadBinaryFindTupleSize(cstate, &line_size);
+
+	pg_atomic_add_fetch_u32(&cstate->pcdata->curr_data_block->unprocessed_line_parts, 1);
+
+	if (line_size > 0)
+	{
+		int line_pos = UpdateBlockInLineInfo(cstate,
+											start_block_pos,
+											start_offset,
+											line_size,
+											LINE_LEADER_POPULATED);
+
+		pcshared_info->populated++;
+		elog(DEBUG1, "LEADER - adding - block:%u, offset:%u, line size:%u line position:%d",
+				start_block_pos, start_offset, line_size, line_pos);
+	}
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryFindTupleSize - Leader identifies boundaries/
+ * offsets for each attribute/column and finally results in the
+ * tuple/row size. It moves on to next data block if the attribute/
+ * column is spread across data blocks.
+ */
+static void
+CopyReadBinaryFindTupleSize(CopyState cstate, uint32 *line_size)
+{
+	int32		fld_size;
+	ListCell   *cur;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			att_num = lfirst_int(cur);
+		Form_pg_attribute att = TupleDescAttr(tup_desc, (att_num - 1));
+		cstate->cur_attname = NameStr(att->attname);
+		fld_size = 0;
+
+		if ((cstate->raw_buf_index + sizeof(fld_size)) >= DATA_BLOCK_SIZE)
+			CopyReadBinaryGetDataBlock(cstate, FIELD_SIZE);
+
+		memcpy(&fld_size, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_size));
+		cstate->raw_buf_index += sizeof(fld_size);
+		*line_size += sizeof(fld_size);
+		fld_size = (int32) pg_ntoh32(fld_size);
+
+		CHECK_FIELD_SIZE(fld_size);
+
+		*line_size += fld_size;
+
+		if ((DATA_BLOCK_SIZE - cstate->raw_buf_index) >= fld_size)
+		{
+			cstate->raw_buf_index += fld_size;
+			elog(DEBUG1, "LEADER - tuple lies in he same data block");
+		}
+		else
+		{
+			int32 required_blks = 0;
+			int32 curr_blk_bytes = (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+			int i = 0;
+
+			GET_REQUIRED_BLOCKS(required_blks, fld_size, curr_blk_bytes);
+
+			i = required_blks;
+
+			while(i > 0)
+			{
+				CopyReadBinaryGetDataBlock(cstate, FIELD_DATA);
+				i--;
+			}
+
+			GET_RAW_BUF_INDEX(cstate->raw_buf_index, fld_size, required_blks, curr_blk_bytes);
+
+			/*
+			 * raw_buf_index should never cross data block size,
+			 * as the required number of data blocks would have
+			 * been obtained in the above while loop.
+			 */
+			Assert(cstate->raw_buf_index <= DATA_BLOCK_SIZE);
+		}
+		cstate->cur_attname = NULL;
+	}
+}
+
+/*
+ * CopyReadBinaryTupleWorker - Each worker reads data from data blocks after
+ * getting leader-identified tuple offsets from ring data structure.
+ */
+static bool
+CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls)
+{
+	uint32 		line_pos;
+	ParallelCopyLineBoundary *line_info;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	int16		fld_count;
+	ListCell   *cur;
+	FmgrInfo   *in_functions = cstate->in_functions;
+	Oid		   *typioparams = cstate->typioparams;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	line_pos = GetLinePosition(cstate);
+
+	if (line_pos == -1)
+		return true;
+
+	line_info = &pcshared_info->line_boundaries.ring[line_pos];
+	cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[line_info->first_block];
+	cstate->raw_buf_index = line_info->start_offset;
+
+	if (cstate->raw_buf_index + sizeof(fld_count) >= DATA_BLOCK_SIZE)
+	{
+		/*
+		 * The case where field count spread across datablocks should never occur,
+		 * as the leader would have moved it to next block. this code exists for
+		 * debugging purposes only.
+		 */
+		elog(DEBUG1, "WORKER - field count spread across datablocks should never occur");
+	}
+
+	memcpy(&fld_count, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_count));
+	fld_count = (int16) pg_ntoh16(fld_count);
+
+	CHECK_FIELD_COUNT;
+
+	cstate->raw_buf_index += sizeof(fld_count);
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			att_num = lfirst_int(cur);
+		int			m = att_num - 1;
+		Form_pg_attribute att = TupleDescAttr(tup_desc, m);
+		cstate->cur_attname = NameStr(att->attname);
+
+		values[m] = CopyReadBinaryAttributeWorker(cstate,
+											&in_functions[m],
+											typioparams[m],
+											att->atttypmod,
+											&nulls[m]);
+		cstate->cur_attname = NULL;
+	}
+
+	pg_atomic_sub_fetch_u32(&cstate->pcdata->curr_data_block->unprocessed_line_parts, 1);
+	line_info->start_offset = -1;
+	pg_atomic_write_u32(&line_info->line_state, LINE_WORKER_PROCESSED);
+	pg_atomic_write_u32(&line_info->line_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryAttributeWorker - Leader identifies boundaries/offsets
+ * for each attribute/column, it moves on to next data block if the
+ * attribute/column is spread across data blocks.
+ */
+static Datum
+CopyReadBinaryAttributeWorker(CopyState cstate, FmgrInfo *flinfo,
+		Oid typioparam, int32 typmod, bool *isnull)
+{
+	int32		fld_size;
+	Datum		result;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+	if ((cstate->raw_buf_index + sizeof(fld_size)) >= DATA_BLOCK_SIZE)
+	{
+		ParallelCopyDataBlock *prev_data_block = cstate->pcdata->curr_data_block;
+		elog(DEBUG1, "WORKER - field size is spread across data blocks");
+		cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[prev_data_block->following_block];
+		pg_atomic_sub_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+		cstate->raw_buf_index = 0;
+	}
+
+	memcpy(&fld_size, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_size));
+	fld_size = (int32) pg_ntoh32(fld_size);
+
+	CHECK_FIELD_SIZE(fld_size);
+
+	cstate->raw_buf_index += sizeof(fld_size);
+
+	/* reset attribute_buf to empty, and load raw data in it */
+	resetStringInfo(&cstate->attribute_buf);
+
+	enlargeStringInfo(&cstate->attribute_buf, fld_size);
+
+	if ((DATA_BLOCK_SIZE - cstate->raw_buf_index) >= fld_size)
+	{
+		elog(DEBUG1, "WORKER - tuple lies in single data block");
+		memcpy(&cstate->attribute_buf.data[0],&cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], fld_size);
+		cstate->raw_buf_index += fld_size;
+	}
+	else
+	{
+		uint32 att_buf_idx = 0;
+		uint32 copy_bytes = 0;
+		int32 required_blks = 0;
+		int32 curr_blk_bytes = (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+		ParallelCopyDataBlock *prev_data_block = NULL;
+		int i = 0;
+
+		GET_REQUIRED_BLOCKS(required_blks, fld_size, curr_blk_bytes);
+
+		i = required_blks;
+		prev_data_block = cstate->pcdata->curr_data_block;
+		elog(DEBUG1, "WORKER - tuple is spread across data blocks");
+		memcpy(&cstate->attribute_buf.data[0], &prev_data_block->data[cstate->raw_buf_index],
+				curr_blk_bytes);
+		copy_bytes = curr_blk_bytes;
+		att_buf_idx = curr_blk_bytes;
+
+		while (i>0)
+		{
+			cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[prev_data_block->following_block];
+			pg_atomic_sub_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+			cstate->raw_buf_index = 0;
+			copy_bytes = fld_size - att_buf_idx;
+
+			/*
+			 * The bytes that are yet to be taken into att buff are more than
+			 * the entire data block size, but only take the data block size
+			 * elements.
+			 */
+			if (copy_bytes >= DATA_BLOCK_SIZE)
+				copy_bytes = DATA_BLOCK_SIZE;
+
+			memcpy(&cstate->attribute_buf.data[att_buf_idx],
+				&cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], copy_bytes);
+			att_buf_idx += copy_bytes;
+			i--;
+		}
+		GET_RAW_BUF_INDEX(cstate->raw_buf_index, fld_size, required_blks, curr_blk_bytes);
+	}
+
+	cstate->attribute_buf.len = fld_size;
+	cstate->attribute_buf.data[fld_size] = '\0';
+
+	/* Call the column type's binary input converter */
+	result = ReceiveFunctionCall(flinfo, &cstate->attribute_buf,
+								 typioparam, typmod);
+
+	/* Trouble if it didn't eat the whole buffer */
+	if (cstate->attribute_buf.cursor != cstate->attribute_buf.len)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+				 errmsg("incorrect binary data format")));
+
+	*isnull = false;
+	return result;
+}
+
+/*
  * GetLinePosition - Return the line position that worker should process.
  */
 static uint32
@@ -1675,7 +2182,9 @@ GetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
 		{
 			dataBlkPtr->curr_blk_completed = false;
 			dataBlkPtr->skip_bytes = 0;
+			dataBlkPtr->following_block = -1;
 			pcshared_info->cur_block_pos = block_pos;
+			MemSet(&dataBlkPtr->data[0], 0, DATA_BLOCK_SIZE);
 			return block_pos;
 		}
 
@@ -2191,10 +2700,26 @@ CopyGetInt32(CopyState cstate, int32 *val)
 {
 	uint32		buf;
 
-	if (CopyReadBinaryData(cstate, (char *) &buf, sizeof(buf)) != sizeof(buf))
+	/*
+	 * For parallel copy, avoid reading data to raw buf, read directly
+	 * from file, later the data will be read to parallel copy data
+	 * buffers.
+	 */
+	if (cstate->nworkers > 0)
 	{
-		*val = 0;				/* suppress compiler warning */
-		return false;
+		if (CopyGetData(cstate, &buf, sizeof(buf), sizeof(buf)) != sizeof(buf))
+		{
+			*val = 0;				/* suppress compiler warning */
+			return false;
+		}
+	}
+	else
+	{
+		if (CopyReadBinaryData(cstate, (char *) &buf, sizeof(buf)) != sizeof(buf))
+		{
+			*val = 0;				/* suppress compiler warning */
+			return false;
+		}
 	}
 	*val = (int32) pg_ntoh32(buf);
 	return true;
@@ -2583,7 +3108,15 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 			EndParallelCopy(pcxt);
 		}
 		else
+		{
+			/*
+			 * Reset nworkers to -1 here. This is useful in cases where user
+			 * specifies parallel workers, but, no worker is picked up, so go
+			 * back to non parallel mode value of nworkers.
+			 */
+			cstate->nworkers = -1;
 			*processed = CopyFrom(cstate); /* copy from file to database */
+		}
 
 		EndCopyFrom(cstate);
 	}
@@ -5047,7 +5580,7 @@ BeginCopyFrom(ParseState *pstate,
 	 * only in text mode.
 	 */
 	initStringInfo(&cstate->attribute_buf);
-	cstate->raw_buf = (IsParallelCopy()) ? NULL : (char *) palloc(RAW_BUF_SIZE + 1);
+	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
 	cstate->raw_buf_index = cstate->raw_buf_len = 0;
 	if (!cstate->binary)
 	{
@@ -5127,7 +5660,7 @@ BeginCopyFrom(ParseState *pstate,
 		int32		tmp;
 
 		/* Signature */
-		if (CopyReadBinaryData(cstate, readSig, 11) != 11 ||
+		if (CopyGetData(cstate, readSig, 11, 11) != 11 ||
 			memcmp(readSig, BinarySignature, 11) != 0)
 			ereport(ERROR,
 					(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
@@ -5155,7 +5688,7 @@ BeginCopyFrom(ParseState *pstate,
 		/* Skip extension header, if present */
 		while (tmp-- > 0)
 		{
-			if (CopyReadBinaryData(cstate, readSig, 1) != 1)
+			if (CopyGetData(cstate, readSig, 1, 1) != 1)
 				ereport(ERROR,
 						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
 						 errmsg("invalid COPY file header (wrong length)")));
@@ -5352,60 +5885,45 @@ NextCopyFrom(CopyState cstate, ExprContext *econtext,
 	else
 	{
 		/* binary */
-		int16		fld_count;
-		ListCell   *cur;
-
 		cstate->cur_lineno++;
+		cstate->max_fields = list_length(cstate->attnumlist);
 
-		if (!CopyGetInt16(cstate, &fld_count))
+		if (!IsParallelCopy())
 		{
-			/* EOF detected (end of file, or protocol-level EOF) */
-			return false;
-		}
+			int16		fld_count;
+			ListCell   *cur;
 
-		if (fld_count == -1)
-		{
-			/*
-			 * Received EOF marker.  In a V3-protocol copy, wait for the
-			 * protocol-level EOF, and complain if it doesn't come
-			 * immediately.  This ensures that we correctly handle CopyFail,
-			 * if client chooses to send that now.
-			 *
-			 * Note that we MUST NOT try to read more data in an old-protocol
-			 * copy, since there is no protocol-level EOF marker then.  We
-			 * could go either way for copy from file, but choose to throw
-			 * error if there's data after the EOF marker, for consistency
-			 * with the new-protocol case.
-			 */
-			char		dummy;
-
-			if (cstate->copy_dest != COPY_OLD_FE &&
-				CopyReadBinaryData(cstate, &dummy, 1) > 0)
-				ereport(ERROR,
-						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-						 errmsg("received copy data after EOF marker")));
-			return false;
-		}
+			if (!CopyGetInt16(cstate, &fld_count))
+			{
+				/* EOF detected (end of file, or protocol-level EOF) */
+				return false;
+			}
 
-		if (fld_count != attr_count)
-			ereport(ERROR,
-					(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-					 errmsg("row field count is %d, expected %d",
-							(int) fld_count, attr_count)));
+			CHECK_FIELD_COUNT;
 
-		foreach(cur, cstate->attnumlist)
+			foreach(cur, cstate->attnumlist)
+			{
+				int			attnum = lfirst_int(cur);
+				int			m = attnum - 1;
+				Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+
+				cstate->cur_attname = NameStr(att->attname);
+				values[m] = CopyReadBinaryAttribute(cstate,
+													&in_functions[m],
+													typioparams[m],
+													att->atttypmod,
+													&nulls[m]);
+				cstate->cur_attname = NULL;
+			}
+		}
+		else
 		{
-			int			attnum = lfirst_int(cur);
-			int			m = attnum - 1;
-			Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+			bool eof = false;
 
-			cstate->cur_attname = NameStr(att->attname);
-			values[m] = CopyReadBinaryAttribute(cstate,
-												&in_functions[m],
-												typioparams[m],
-												att->atttypmod,
-												&nulls[m]);
-			cstate->cur_attname = NULL;
+			eof = CopyReadBinaryTupleWorker(cstate, values, nulls);
+
+			if (eof)
+				return false;
 		}
 	}
 
@@ -6405,18 +6923,15 @@ CopyReadBinaryAttribute(CopyState cstate, FmgrInfo *flinfo,
 	Datum		result;
 
 	if (!CopyGetInt32(cstate, &fld_size))
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("unexpected EOF in COPY data")));
+		EOF_ERROR;
+
 	if (fld_size == -1)
 	{
 		*isnull = true;
 		return ReceiveFunctionCall(flinfo, NULL, typioparam, typmod);
 	}
-	if (fld_size < 0)
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("invalid field size")));
+
+	CHECK_FIELD_SIZE(fld_size);
 
 	/* reset attribute_buf to empty, and load raw data in it */
 	resetStringInfo(&cstate->attribute_buf);
@@ -6424,9 +6939,7 @@ CopyReadBinaryAttribute(CopyState cstate, FmgrInfo *flinfo,
 	enlargeStringInfo(&cstate->attribute_buf, fld_size);
 	if (CopyReadBinaryData(cstate, cstate->attribute_buf.data,
 						   fld_size) != fld_size)
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("unexpected EOF in COPY data")));
+		EOF_ERROR;
 
 	cstate->attribute_buf.len = fld_size;
 	cstate->attribute_buf.data[fld_size] = '\0';
-- 
1.8.3.1

#145Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Bharath Rupireddy (#143)
1 attachment(s)
Re: Parallel copy

On Thu, Sep 17, 2020 at 11:06 AM Bharath Rupireddy <
bharath.rupireddyforpostgres@gmail.com> wrote:

On Wed, Sep 16, 2020 at 1:20 PM Greg Nancarrow <gregn4422@gmail.com>

wrote:

Fortunately I have been given permission to share the exact table
definition and data I used, so you can check the behaviour and timings
on your own test machine.

Thanks Greg for the script. I ran your test case and I didn't observe
any increase in exec time with 1 worker, indeed, we have benefitted a
few seconds from 0 to 1 worker as expected.

Execution time is in seconds. Each test case is executed 3 times on
release build. Each time the data directory is recreated.

Case 1: 1000000 rows, 2GB
With Patch, default configuration, 0 worker: 88.933, 92.261, 88.423
With Patch, default configuration, 1 worker: 73.825, 74.583, 72.678

With Patch, custom configuration, 0 worker: 76.191, 78.160, 78.822
With Patch, custom configuration, 1 worker: 61.289, 61.288, 60.573

Case 2: 2550000 rows, 5GB
With Patch, default configuration, 0 worker: 246.031, 188.323, 216.683
With Patch, default configuration, 1 worker: 156.299, 153.293, 170.307

With Patch, custom configuration, 0 worker: 197.234, 195.866, 196.049
With Patch, custom configuration, 1 worker: 157.173, 158.287, 157.090

Hi Greg,

If you still observe the issue in your testing environment, I'm attaching a
testing patch(that applies on top of the latest parallel copy patch set
i.e. v5 1 to 6) to capture various timings such as total copy time in
leader and worker, index and table insertion time, leader and worker
waiting time. These logs are shown in the server log file.

Few things to follow before testing:
1. Is the table being dropped/truncated after the test with 0 workers and
before running with 1 worker? If not, then the index insertion time would
increase.[1]0 worker: LOG: totaltableinsertiontime = 25491.881 ms LOG: totalindexinsertiontime = 14136.104 ms LOG: totalcopytime = 75606.858 ms table is not dropped and so are indexes 1 worker: LOG: totalcopyworkerwaitingtime = 64.582 ms LOG: totaltableinsertiontime = 21360.875 ms LOG: totalindexinsertiontime = 24843.570 ms LOG: totalcopytimeworker = 69837.162 ms LOG: totalcopyleaderwaitingtime = 49548.441 ms LOG: totalcopytime = 69997.778 ms(for me it is increasing by 10 sec). This is obvious because
the 1st time index will be created from bottom up manner(from leaves to
root), but for the 2nd time it has to search and insert at the proper
leaves and inner B+Tree nodes.
2. If possible, can you also run with custom postgresql.conf settings[2]custom postgresql.conf configuration: shared_buffers = 40GB max_worker_processes = 32 max_parallel_maintenance_workers = 24 max_parallel_workers = 32 synchronous_commit = off checkpoint_timeout = 1d max_wal_size = 24GB min_wal_size = 15GB autovacuum = off
along with default? Just to ensure that other bg processes such as
checkpointer, autovacuum, bgwriter etc. don't affect our testcase. For
instance, with default postgresql.conf file, it looks like checkpointing[3]LOG: checkpoints are occurring too frequently (14 seconds apart) HINT: Consider increasing the configuration parameter "max_wal_size".
is happening frequently, could you please let us know if that happens at
your end?
3. Could you please run the test case 3 times at least? Just to ensure the
consistency of the issue.
4. I ran the tests in a performance test system where no other user
processes(except system processes) are running. Is it possible for you to
do the same?

Please capture and share the timing logs with us.

Here's a snapshot of how the added timings show up in the logs: ( I
captured this with your test case case 1: 1000000 rows, 2GB, custom
postgresql.conf file settings[2]custom postgresql.conf configuration: shared_buffers = 40GB max_worker_processes = 32 max_parallel_maintenance_workers = 24 max_parallel_workers = 32 synchronous_commit = off checkpoint_timeout = 1d max_wal_size = 24GB min_wal_size = 15GB autovacuum = off).
with 0 workers:
2020-09-22 10:49:27.508 BST [163910] LOG: totaltableinsertiontime =
24072.034 ms
2020-09-22 10:49:27.508 BST [163910] LOG: totalindexinsertiontime = 60.682
ms
2020-09-22 10:49:27.508 BST [163910] LOG: totalcopytime = 59664.594 ms

with 1 worker:
2020-09-22 10:53:58.409 BST [163947] LOG: totalcopyworkerwaitingtime =
59.815 ms
2020-09-22 10:53:58.409 BST [163947] LOG: totaltableinsertiontime =
23585.881 ms
2020-09-22 10:53:58.409 BST [163947] LOG: totalindexinsertiontime = 30.946
ms
2020-09-22 10:53:58.409 BST [163947] LOG: totalcopytimeworker = 47047.956
ms
2020-09-22 10:53:58.429 BST [163946] LOG: totalcopyleaderwaitingtime =
26746.744 ms
2020-09-22 10:53:58.429 BST [163946] LOG: totalcopytime = 47150.002 ms

[1]: 0 worker: LOG: totaltableinsertiontime = 25491.881 ms LOG: totalindexinsertiontime = 14136.104 ms LOG: totalcopytime = 75606.858 ms table is not dropped and so are indexes 1 worker: LOG: totalcopyworkerwaitingtime = 64.582 ms LOG: totaltableinsertiontime = 21360.875 ms LOG: totalindexinsertiontime = 24843.570 ms LOG: totalcopytimeworker = 69837.162 ms LOG: totalcopyleaderwaitingtime = 49548.441 ms LOG: totalcopytime = 69997.778 ms
0 worker:
LOG: totaltableinsertiontime = 25491.881 ms
LOG: totalindexinsertiontime = 14136.104 ms
LOG: totalcopytime = 75606.858 ms
table is not dropped and so are indexes
1 worker:
LOG: totalcopyworkerwaitingtime = 64.582 ms
LOG: totaltableinsertiontime = 21360.875 ms
LOG: totalindexinsertiontime = 24843.570 ms
LOG: totalcopytimeworker = 69837.162 ms
LOG: totalcopyleaderwaitingtime = 49548.441 ms
LOG: totalcopytime = 69997.778 ms

[2]: custom postgresql.conf configuration: shared_buffers = 40GB max_worker_processes = 32 max_parallel_maintenance_workers = 24 max_parallel_workers = 32 synchronous_commit = off checkpoint_timeout = 1d max_wal_size = 24GB min_wal_size = 15GB autovacuum = off
custom postgresql.conf configuration:
shared_buffers = 40GB
max_worker_processes = 32
max_parallel_maintenance_workers = 24
max_parallel_workers = 32
synchronous_commit = off
checkpoint_timeout = 1d
max_wal_size = 24GB
min_wal_size = 15GB
autovacuum = off

[3]: LOG: checkpoints are occurring too frequently (14 seconds apart) HINT: Consider increasing the configuration parameter "max_wal_size".
LOG: checkpoints are occurring too frequently (14 seconds apart)
HINT: Consider increasing the configuration parameter "max_wal_size".

With Regards,
Bharath Rupireddy.
EnterpriseDB: http://www.enterprisedb.com

Attachments:

v1-0001-Parallel-Copy-Exec-Time-Capture.patchapplication/octet-stream; name=v1-0001-Parallel-Copy-Exec-Time-Capture.patchDownload
From 28c5b37c2271b623f6bc4653d17f92dedb8722be Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddy@enterprisedb.com>
Date: Tue, 22 Sep 2020 15:12:27 +0530
Subject: [PATCH v2] Parallel Copy Exec Time Capture

A testing patch for capturing various timings such as total copy
time in leader and worker, index insertion time, leader and worker
waiting time.
---
 src/backend/commands/copy.c | 74 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 73 insertions(+), 1 deletion(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 5b1884acd8..cb72949e0e 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -65,6 +65,14 @@
 #define ISOCTAL(c) (((c) >= '0') && ((c) <= '7'))
 #define OCTVALUE(c) ((c) - '0')
 
+/* Global variables for capturing parallel copy execution times. */
+double totalcopytime;
+double totalcopytimeworker;
+double totalcopyleaderwaitingtime;
+double totalcopyworkerwaitingtime;
+double totaltableinsertiontime;
+double totalindexinsertiontime;
+
 /*
  * Represents the different source/dest cases we need to worry about at
  * the bottom level
@@ -1332,9 +1340,16 @@ CacheLineInfo(CopyState cstate, uint32 buff_count)
 	uint32 offset;
 	int dataSize;
 	int copiedSize = 0;
+	struct timespec before, after;
+	struct timespec before1, after1;
 
 	resetStringInfo(&pcdata->worker_line_buf[buff_count].line_buf);
+	INSTR_TIME_SET_CURRENT(before);
 	write_pos = GetLinePosition(cstate);
+	INSTR_TIME_SET_CURRENT(after);
+	INSTR_TIME_SUBTRACT(after, before);
+	totalcopyworkerwaitingtime += INSTR_TIME_GET_MILLISEC(after);
+
 	if (-1 == write_pos)
 		return true;
 
@@ -1436,6 +1451,7 @@ CacheLineInfo(CopyState cstate, uint32 buff_count)
 			data_blk_ptr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
 		}
 
+		INSTR_TIME_SET_CURRENT(before1);
 		for (;;)
 		{
 			/* Get the size of this line */
@@ -1455,6 +1471,9 @@ CacheLineInfo(CopyState cstate, uint32 buff_count)
 
 			COPY_WAIT_TO_PROCESS()
 		}
+		INSTR_TIME_SET_CURRENT(after1);
+		INSTR_TIME_SUBTRACT(after1, before1);
+		totalcopyworkerwaitingtime += INSTR_TIME_GET_MILLISEC(after1);
 	}
 
 empty_data_line_update:
@@ -1538,6 +1557,11 @@ ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
 	char *convertListStr = NULL;
 	WalUsage   *walusage;
 	BufferUsage *bufferusage;
+	struct timespec before, after;
+	totalcopytimeworker = 0;
+	totalcopyworkerwaitingtime = 0;
+	totaltableinsertiontime = 0;
+	totalindexinsertiontime = 0;
 
 	/* Allocate workspace and zero all fields. */
 	cstate = (CopyStateData *) palloc0(sizeof(CopyStateData));
@@ -1606,7 +1630,15 @@ ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
 	cstate->rel = rel;
 	InitializeParallelCopyInfo(shared_cstate, cstate, attlist);
 
+	INSTR_TIME_SET_CURRENT(before);
 	CopyFrom(cstate);
+	INSTR_TIME_SET_CURRENT(after);
+	INSTR_TIME_SUBTRACT(after, before);
+	totalcopytimeworker += INSTR_TIME_GET_MILLISEC(after);
+	ereport(LOG, (errmsg("totalcopyworkerwaitingtime = %.3f ms", totalcopyworkerwaitingtime), errhidestmt(true)));
+	ereport(LOG, (errmsg("totaltableinsertiontime = %.3f ms", totaltableinsertiontime), errhidestmt(true)));
+	ereport(LOG, (errmsg("totalindexinsertiontime = %.3f ms", totalindexinsertiontime), errhidestmt(true)));
+	ereport(LOG, (errmsg("totalcopytimeworker = %.3f ms", totalcopytimeworker), errhidestmt(true)));
 
 	if (rel != NULL)
 		table_close(rel, RowExclusiveLock);
@@ -1633,11 +1665,16 @@ UpdateBlockInLineInfo(CopyState cstate, uint32 blk_pos,
 	ParallelCopyLineBoundaries *lineBoundaryPtr = &pcshared_info->line_boundaries;
 	ParallelCopyLineBoundary *lineInfo;
 	int line_pos = lineBoundaryPtr->pos;
+	struct timespec before, after;
 
 	/* Update the line information for the worker to pick and process. */
 	lineInfo = &lineBoundaryPtr->ring[line_pos];
+	INSTR_TIME_SET_CURRENT(before);
 	while (pg_atomic_read_u32(&lineInfo->line_size) != -1)
 		COPY_WAIT_TO_PROCESS()
+	INSTR_TIME_SET_CURRENT(after);
+	INSTR_TIME_SUBTRACT(after, before);
+	totalcopyleaderwaitingtime += INSTR_TIME_GET_MILLISEC(after);
 
 	lineInfo->first_block = blk_pos;
 	lineInfo->start_offset = offset;
@@ -2203,6 +2240,8 @@ static uint32
 WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
 {
 	uint32 new_free_pos = -1;
+	struct timespec before, after;
+	INSTR_TIME_SET_CURRENT(before);
 	for (;;)
 	{
 		new_free_pos = GetFreeCopyBlock(pcshared_info);
@@ -2211,7 +2250,9 @@ WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
 
 		COPY_WAIT_TO_PROCESS()
 	}
-
+	INSTR_TIME_SET_CURRENT(after);
+	INSTR_TIME_SUBTRACT(after, before);
+	totalcopyleaderwaitingtime += INSTR_TIME_GET_MILLISEC(after);
 	return new_free_pos;
 }
 
@@ -3083,12 +3124,21 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 	if (is_from)
 	{
 		ParallelContext *pcxt = NULL;
+		struct timespec before, after;
 		Assert(rel);
+		totalcopytime = 0;
+		totalcopytimeworker = 0;
+		totalcopyleaderwaitingtime = 0;
+		totalcopyworkerwaitingtime = 0;
+		totaltableinsertiontime = 0;
+		totalindexinsertiontime = 0;
 
 		/* check read-only transaction and parallel mode */
 		if (XactReadOnly && !rel->rd_islocaltemp)
 			PreventCommandIfReadOnly("COPY FROM");
 
+		INSTR_TIME_SET_CURRENT(before);
+
 		cstate = BeginCopyFrom(pstate, rel, stmt->filename, stmt->is_program,
 							   NULL, stmt->attlist, stmt->options);
 		cstate->whereClause = whereClause;
@@ -3119,6 +3169,18 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 		}
 
 		EndCopyFrom(cstate);
+
+		INSTR_TIME_SET_CURRENT(after);
+		INSTR_TIME_SUBTRACT(after, before);
+		totalcopytime += INSTR_TIME_GET_MILLISEC(after);
+		if (pcxt != NULL)
+			ereport(LOG, (errmsg("totalcopyleaderwaitingtime = %.3f ms", totalcopyleaderwaitingtime), errhidestmt(true)));
+		if (pcxt == NULL)
+		{
+			ereport(LOG, (errmsg("totaltableinsertiontime = %.3f ms", totaltableinsertiontime), errhidestmt(true)));
+			ereport(LOG, (errmsg("totalindexinsertiontime = %.3f ms", totalindexinsertiontime), errhidestmt(true)));
+		}
+		ereport(LOG, (errmsg("totalcopytime = %.3f ms", totalcopytime), errhidestmt(true)));
 	}
 	else
 	{
@@ -4527,6 +4589,8 @@ CopyMultiInsertBufferFlush(CopyMultiInsertInfo *miinfo,
 	int			nused = buffer->nused;
 	ResultRelInfo *resultRelInfo = buffer->resultRelInfo;
 	TupleTableSlot **slots = buffer->slots;
+	struct timespec before, after;
+	struct timespec before1, after1;
 
 	/* Set es_result_relation_info to the ResultRelInfo we're flushing. */
 	estate->es_result_relation_info = resultRelInfo;
@@ -4543,14 +4607,19 @@ CopyMultiInsertBufferFlush(CopyMultiInsertInfo *miinfo,
 	 * context before calling it.
 	 */
 	oldcontext = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
+	INSTR_TIME_SET_CURRENT(before);
 	table_multi_insert(resultRelInfo->ri_RelationDesc,
 					   slots,
 					   nused,
 					   mycid,
 					   ti_options,
 					   buffer->bistate);
+	INSTR_TIME_SET_CURRENT(after);
+	INSTR_TIME_SUBTRACT(after, before);
+	totaltableinsertiontime += INSTR_TIME_GET_MILLISEC(after);
 	MemoryContextSwitchTo(oldcontext);
 
+	INSTR_TIME_SET_CURRENT(before1);
 	for (i = 0; i < nused; i++)
 	{
 		/*
@@ -4586,6 +4655,9 @@ CopyMultiInsertBufferFlush(CopyMultiInsertInfo *miinfo,
 
 		ExecClearTuple(slots[i]);
 	}
+	INSTR_TIME_SET_CURRENT(after1);
+	INSTR_TIME_SUBTRACT(after1, before1);
+	totalindexinsertiontime += INSTR_TIME_GET_MILLISEC(after1);
 
 	/* Mark that all slots are free */
 	buffer->nused = 0;
-- 
2.25.1

#146Greg Nancarrow
gregn4422@gmail.com
In reply to: Bharath Rupireddy (#145)
1 attachment(s)
Re: Parallel copy

Hi Bharath,

Few things to follow before testing:
1. Is the table being dropped/truncated after the test with 0 workers and before running with 1 worker? If not, then the index insertion time would increase.[1](for me it is increasing by 10 sec). This is obvious because the 1st time index will be created from bottom up manner(from leaves to root), but for the 2nd time it has to search and insert at the proper leaves and inner B+Tree nodes.

Yes, it' being truncated before running each and every COPY.

2. If possible, can you also run with custom postgresql.conf settings[2] along with default? Just to ensure that other bg processes such as checkpointer, autovacuum, bgwriter etc. don't affect our testcase. For instance, with default postgresql.conf file, it looks like checkpointing[3] is happening frequently, could you please let us know if that happens at your end?

Yes, have run with default and your custom settings. With default
settings, I can confirm that checkpointing is happening frequently
with the tests I've run here.

3. Could you please run the test case 3 times at least? Just to ensure the consistency of the issue.

Yes, have run 4 times. Seems to be a performance hit (whether normal
copy or parallel-1 copy) on the first COPY run on a freshly created
database. After that, results are consistent.

4. I ran the tests in a performance test system where no other user processes(except system processes) are running. Is it possible for you to do the same?

Please capture and share the timing logs with us.

Yes, I have ensured the system is as idle as possible prior to testing.

I have attached the test results obtained after building with your
Parallel Copy patch and testing patch applied (HEAD at
733fa9aa51c526582f100aa0d375e0eb9a6bce8b).

Test results show that Parallel COPY with 1 worker is performing
better than normal COPY in the test scenarios run. There is a
performance hit (regardless of COPY type) on the very first COPY run
on a freshly-created database.

I ran the test case 4 times. and also in reverse order, with truncate
run before each COPY (output and logs named xxxx_0_1 run normal COPY
then parallel COPY, and named xxxx_1_0 run parallel COPY and then
normal COPY).

Please refer to attached results.

Regards,
Greg

Attachments:

testing_patch_results.tar.gzapplication/gzip; name=testing_patch_results.tar.gzDownload
#147Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Greg Nancarrow (#146)
Re: Parallel copy

Thanks Greg for the testing.

On Thu, Sep 24, 2020 at 8:27 AM Greg Nancarrow <gregn4422@gmail.com> wrote:

3. Could you please run the test case 3 times at least? Just to ensure

the consistency of the issue.

Yes, have run 4 times. Seems to be a performance hit (whether normal
copy or parallel-1 copy) on the first COPY run on a freshly created
database. After that, results are consistent.

From the logs, I see that it is happening only with default
postgresql.conf, and there's inconsistency in table insertion times,
especially from the 1st time to 2nd time. Also, the table insertion time
variation is more. This is expected with the default postgresql.conf,
because of the background processes interference. That's the reason we
usually run with custom configuration to correctly measure the performance
gain.

br_default_0_1.log:
2020-09-23 22:32:36.944 JST [112616] LOG: totaltableinsertiontime =
155068.244 ms
2020-09-23 22:33:57.615 JST [11426] LOG: totaltableinsertiontime =
42096.275 ms
2020-09-23 22:37:39.192 JST [43097] LOG: totaltableinsertiontime =
29135.262 ms
2020-09-23 22:38:56.389 JST [54205] LOG: totaltableinsertiontime =
38953.912 ms
2020-09-23 22:40:27.573 JST [66485] LOG: totaltableinsertiontime =
27895.326 ms
2020-09-23 22:41:34.948 JST [77523] LOG: totaltableinsertiontime =
28929.642 ms
2020-09-23 22:43:18.938 JST [89857] LOG: totaltableinsertiontime =
30625.015 ms
2020-09-23 22:44:21.938 JST [101372] LOG: totaltableinsertiontime =
24624.045 ms

br_default_1_0.log:
2020-09-24 11:12:14.989 JST [56146] LOG: totaltableinsertiontime =
192068.350 ms
2020-09-24 11:13:38.228 JST [88455] LOG: totaltableinsertiontime =
30999.942 ms
2020-09-24 11:15:50.381 JST [108935] LOG: totaltableinsertiontime =
31673.204 ms
2020-09-24 11:17:14.260 JST [118541] LOG: totaltableinsertiontime =
31367.027 ms
2020-09-24 11:20:18.975 JST [17270] LOG: totaltableinsertiontime =
26858.924 ms
2020-09-24 11:22:17.822 JST [26852] LOG: totaltableinsertiontime =
66531.442 ms
2020-09-24 11:24:09.221 JST [47971] LOG: totaltableinsertiontime =
38943.384 ms
2020-09-24 11:25:30.955 JST [58849] LOG: totaltableinsertiontime =
28286.634 ms

br_custom_0_1.log:
2020-09-24 10:29:44.956 JST [110477] LOG: totaltableinsertiontime =
20207.928 ms
2020-09-24 10:30:49.570 JST [120568] LOG: totaltableinsertiontime =
23360.006 ms
2020-09-24 10:32:31.659 JST [2753] LOG: totaltableinsertiontime =
19837.588 ms
2020-09-24 10:35:49.245 JST [31118] LOG: totaltableinsertiontime =
21759.253 ms
2020-09-24 10:36:54.834 JST [41763] LOG: totaltableinsertiontime =
23547.323 ms
2020-09-24 10:38:53.507 JST [56779] LOG: totaltableinsertiontime =
21543.984 ms
2020-09-24 10:39:58.713 JST [67489] LOG: totaltableinsertiontime =
25254.563 ms

br_custom_1_0.log:
2020-09-24 10:49:03.242 JST [15308] LOG: totaltableinsertiontime =
16541.201 ms
2020-09-24 10:50:11.848 JST [23324] LOG: totaltableinsertiontime =
15076.577 ms
2020-09-24 10:51:24.497 JST [35394] LOG: totaltableinsertiontime =
16400.777 ms
2020-09-24 10:52:32.354 JST [42953] LOG: totaltableinsertiontime =
15591.051 ms
2020-09-24 10:54:30.327 JST [61136] LOG: totaltableinsertiontime =
16700.954 ms
2020-09-24 10:55:38.377 JST [68719] LOG: totaltableinsertiontime =
15435.150 ms
2020-09-24 10:57:08.927 JST [83335] LOG: totaltableinsertiontime =
17133.251 ms
2020-09-24 10:58:17.420 JST [90905] LOG: totaltableinsertiontime =
15352.753 ms

Test results show that Parallel COPY with 1 worker is performing
better than normal COPY in the test scenarios run.

Good to know :)

With Regards,
Bharath Rupireddy.
EnterpriseDB: http://www.enterprisedb.com

#148Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: vignesh C (#144)
Re: Parallel copy

Have you tested your patch when encoding conversion is needed? If so,
could you please point out the email that has the test results.

We have not yet done encoding testing, we will do and post the results
separately in the coming days.

Hi Ashutosh,

I ran the tests ensuring pg_server_to_any() gets called from copy.c. I
specified the encoding option of COPY command, with client and server
encodings being UTF-8.

Tests are performed with custom postgresql.conf[1]shared_buffers = 40GB max_worker_processes = 32 max_parallel_maintenance_workers = 24 max_parallel_workers = 32 synchronous_commit = off checkpoint_timeout = 1d max_wal_size = 24GB min_wal_size = 15GB autovacuum = off, 10million rows, 5.2GB
data. The results are of the triplet form (exec time in sec, number of
workers, gain)

Use case 1: 2 indexes on integer columns, 1 index on text column
(1174.395, 0, 1X), (1127.792, 1, 1.04X), (644.260, 2, 1.82X), (341.284, 4,
3.43X), (204.423, 8, 5.74X), (140.692, 16, 8.34X), (129.843, 20, 9.04X),
(134.511, 30, 8.72X)

Use case 2: 1 gist index on text column
(811.412, 0, 1X), (772.203, 1, 1.05X), (437.364, 2, 1.85X), (263.575, 4,
3.08X), (175.135, 8, 4.63X), (155.355, 16, 5.22X), (178.704, 20, 4.54X),
(199.402, 30, 4.06)

Use case 3: 3 indexes on integer columns
(220.680, 0, 1X), (185.096, 1, 1.19X), (134.811, 2, 1.64X), (114.585, 4,
1.92X), (107.707, 8, 2.05X), (101.253, 16, 2.18X), (100.749, 20, 2.19X),
(100.656, 30, 2.19X)

The results are similar to our earlier runs[2]/messages/by-id/CALDaNm13zK=JXfZWqZJsm3+2yagYDJc=eJBgE4i77-4PPNj7vw@mail.gmail.com.

[1]: shared_buffers = 40GB max_worker_processes = 32 max_parallel_maintenance_workers = 24 max_parallel_workers = 32 synchronous_commit = off checkpoint_timeout = 1d max_wal_size = 24GB min_wal_size = 15GB autovacuum = off
shared_buffers = 40GB
max_worker_processes = 32
max_parallel_maintenance_workers = 24
max_parallel_workers = 32
synchronous_commit = off
checkpoint_timeout = 1d
max_wal_size = 24GB
min_wal_size = 15GB
autovacuum = off

[2]: /messages/by-id/CALDaNm13zK=JXfZWqZJsm3+2yagYDJc=eJBgE4i77-4PPNj7vw@mail.gmail.com
/messages/by-id/CALDaNm13zK=JXfZWqZJsm3+2yagYDJc=eJBgE4i77-4PPNj7vw@mail.gmail.com

With Regards,
Bharath Rupireddy.
EnterpriseDB: http://www.enterprisedb.com

#149Ashutosh Sharma
ashu.coek88@gmail.com
In reply to: Bharath Rupireddy (#148)
Re: Parallel copy

On Thu, Sep 24, 2020 at 3:00 PM Bharath Rupireddy
<bharath.rupireddyforpostgres@gmail.com> wrote:

Have you tested your patch when encoding conversion is needed? If so,
could you please point out the email that has the test results.

We have not yet done encoding testing, we will do and post the results
separately in the coming days.

Hi Ashutosh,

I ran the tests ensuring pg_server_to_any() gets called from copy.c. I specified the encoding option of COPY command, with client and server encodings being UTF-8.

Thanks Bharath for the testing. The results look impressive.

--
With Regards,
Ashutosh Sharma
EnterpriseDB:http://www.enterprisedb.com

#150Amit Kapila
amit.kapila16@gmail.com
In reply to: vignesh C (#117)
Re: Parallel copy

On Wed, Jul 22, 2020 at 7:48 PM vignesh C <vignesh21@gmail.com> wrote:

On Tue, Jul 21, 2020 at 3:54 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

Review comments:
===================

0001-Copy-code-readjustment-to-support-parallel-copy
1.
@@ -807,8 +835,11 @@ CopyLoadRawBuf(CopyState cstate)
else
nbytes = 0; /* no data need be saved */

+ if (cstate->copy_dest == COPY_NEW_FE)
+ minread = RAW_BUF_SIZE - nbytes;
+
inbytes = CopyGetData(cstate, cstate->raw_buf + nbytes,
-   1, RAW_BUF_SIZE - nbytes);
+   minread, RAW_BUF_SIZE - nbytes);

No comment to explain why this change is done?

0002-Framework-for-leader-worker-in-parallel-copy

Currently CopyGetData copies a lesser amount of data to buffer even though space is available in buffer because minread was passed as 1 to CopyGetData. Because of this there are frequent call to CopyGetData for fetching the data. In this case it will load only some data due to the below check:
while (maxread > 0 && bytesread < minread && !cstate->reached_eof)
After reading some data bytesread will be greater than minread which is passed as 1 and return with lesser amount of data, even though there is some space.
This change is required for parallel copy feature as each time we get a new DSM data block which is of 64K size and copy the data. If we copy less data into DSM data blocks we might end up consuming all the DSM data blocks.

Why can't we reuse the DSM block which has unfilled space?

I felt this issue can be fixed as part of HEAD. Have posted a separate thread [1] for this. I'm planning to remove that change once it gets committed. Can that go as a separate
patch or should we include it here?
[1] - /messages/by-id/CALDaNm0v4CjmvSnftYnx_9pOS_dKRG=O3NnBgJsQmi0KipvLog@mail.gmail.com

I am convinced by the reason given by Kyotaro-San in that another
thread [1]/messages/by-id/20200911.155804.359271394064499501.horikyota.ntt@gmail.com and performance data shown by Peter that this can't be an
independent improvement and rather in some cases it can do harm. Now,
if you need it for a parallel-copy path then we can change it
specifically to the parallel-copy code path but I don't understand
your reason completely.

2.

..

+ */
+typedef struct ParallelCopyLineBoundary

Are we doing all this state management to avoid using locks while
processing lines? If so, I think we can use either spinlock or LWLock
to keep the main patch simple and then provide a later patch to make
it lock-less. This will allow us to first focus on the main design of
the patch rather than trying to make this datastructure processing
lock-less in the best possible way.

The steps will be more or less same if we use spinlock too. step 1, step 3 & step 4 will be common we have to use lock & unlock instead of step 2 & step 5. I feel we can retain the current implementation.

I'll study this in detail and let you know my opinion on the same but
in the meantime, I don't follow one part of this comment: "If they
don't follow this order the worker might process wrong line_size and
leader might populate the information which worker has not yet
processed or in the process of processing."

Do you want to say that leader might overwrite some information which
worker hasn't read yet? If so, it is not clear from the comment.
Another minor point about this comment:

+ * ParallelCopyLineBoundary is common data structure between leader & worker,
+ * Leader process will be populating data block, data block offset &
the size of

I think there should be a full-stop after worker instead of a comma.

6.
In function BeginParallelCopy(), you need to keep a provision to
collect wal_usage and buf_usage stats. See _bt_begin_parallel for
reference. Those will be required for pg_stat_statements.

Fixed

How did you ensure that this is fixed? Have you tested it, if so
please share the test? I see a basic problem with your fix.

+ /* Report WAL/buffer usage during parallel execution */
+ bufferusage = shm_toc_lookup(toc, PARALLEL_COPY_BUFFER_USAGE, false);
+ walusage = shm_toc_lookup(toc, PARALLEL_COPY_WAL_USAGE, false);
+ InstrEndParallelQuery(&bufferusage[ParallelWorkerNumber],
+   &walusage[ParallelWorkerNumber]);

You need to call InstrStartParallelQuery() before the actual operation
starts, without that stats won't be accurate? Also, after calling
WaitForParallelWorkersToFinish(), you need to accumulate the stats
collected from workers which neither you have done nor is possible
with the current code in your patch because you haven't made any
provision to capture them in BeginParallelCopy.

I suggest you look into lazy_parallel_vacuum_indexes() and
begin_parallel_vacuum() to understand how the buffer/wal usage stats
are accumulated. Also, please test this functionality using
pg_stat_statements.

0003-Allow-copy-from-command-to-process-data-from-file-ST
10.
In the commit message, you have written "The leader does not
participate in the insertion of data, leaders only responsibility will
be to identify the lines as fast as possible for the workers to do the
actual copy operation. The leader waits till all the lines populated
are processed by the workers and exits."

I think you should also mention that we have chosen this design based
on the reason "that everything stalls if the leader doesn't accept
further input data, as well as when there are no available splitted
chunks so it doesn't seem like a good idea to have the leader do other
work. This is backed by the performance data where we have seen that
with 1 worker there is just a 5-10% (or whatever percentage difference
you have seen) performance difference)".

Fixed.

Make it a one-paragraph starting from "The leader does not participate
in the insertion of data .... just a 5-10% performance difference".
Right now both the parts look a bit disconnected.

Few additional comments:
======================
v5-0001-Copy-code-readjustment-to-support-parallel-copy
---------------------------------------------------------------------------------
1.
+/*
+ * CLEAR_EOL_LINE - Wrapper for clearing EOL.
+ */
+#define CLEAR_EOL_LINE() \
+if (!result && !IsHeaderLine()) \
+ ClearEOLFromCopiedData(cstate, cstate->line_buf.data, \
+    cstate->line_buf.len, \
+    &cstate->line_buf.len) \

I don't like this macro. I think it is sufficient to move the common
code to be called from the parallel and non-parallel path in
ClearEOLFromCopiedData but I think the other checks can be done
in-place. I think having macros for such a thing makes code less
readable.

2.
-
+static void PopulateCommonCstateInfo(CopyState cstate, TupleDesc tup_desc,
+ List *attnamelist);

Spurious line removal.

v5-0002-Framework-for-leader-worker-in-parallel-copy
---------------------------------------------------------------------------
3.
+ FullTransactionId full_transaction_id; /* xid for copy from statement */
+ CommandId mycid; /* command id */
+ ParallelCopyLineBoundaries line_boundaries; /* line array */
+} ParallelCopyShmInfo;

We already serialize FullTransactionId and CommandId via
InitializeParallelDSM->SerializeTransactionState. Can't we reuse it? I
think recently Parallel Insert patch has also done something for this
[2]: /messages/by-id/CAJcOf-fn1nhEtaU91NvRuA3EbvbJGACMd4_c+Uu3XU5VMv37Aw@mail.gmail.com

v5-0004-Documentation-for-parallel-copy
-----------------------------------------------------------
1.  Perform <command>COPY FROM</command> in parallel using <replaceable
+      class="parameter"> integer</replaceable> background workers.

No need for space before integer.

[1]: /messages/by-id/20200911.155804.359271394064499501.horikyota.ntt@gmail.com
[2]: /messages/by-id/CAJcOf-fn1nhEtaU91NvRuA3EbvbJGACMd4_c+Uu3XU5VMv37Aw@mail.gmail.com

--
With Regards,
Amit Kapila.

#151Amit Kapila
amit.kapila16@gmail.com
In reply to: vignesh C (#144)
Re: Parallel copy

On Tue, Sep 22, 2020 at 2:44 PM vignesh C <vignesh21@gmail.com> wrote:

Thanks Ashutosh for your comments.

On Wed, Sep 16, 2020 at 6:36 PM Ashutosh Sharma <ashu.coek88@gmail.com> wrote:

Hi Vignesh,

I've spent some time today looking at your new set of patches and I've
some thoughts and queries which I would like to put here:

Why are these not part of the shared cstate structure?

SerializeString(pcxt, PARALLEL_COPY_KEY_NULL_PRINT, cstate->null_print);
SerializeString(pcxt, PARALLEL_COPY_KEY_DELIM, cstate->delim);
SerializeString(pcxt, PARALLEL_COPY_KEY_QUOTE, cstate->quote);
SerializeString(pcxt, PARALLEL_COPY_KEY_ESCAPE, cstate->escape);

I have used shared_cstate mainly to share the integer & bool data
types from the leader to worker process. The above data types are of
char* data type, I will not be able to use it like how I could do it
for integer type. So I preferred to send these as separate keys to the
worker. Thoughts?

I think the way you have written will work but if we go with
Ashutosh's proposal it will look elegant and in the future, if we need
to share more strings as part of cstate structure then that would be
easier. You can probably refer to EstimateParamListSpace,
SerializeParamList, and RestoreParamList to see how we can share
different types of data in one key.

--
With Regards,
Amit Kapila.

#152Ashutosh Sharma
ashu.coek88@gmail.com
In reply to: Amit Kapila (#151)
Re: Parallel copy

On Mon, Sep 28, 2020 at 3:01 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Tue, Sep 22, 2020 at 2:44 PM vignesh C <vignesh21@gmail.com> wrote:

Thanks Ashutosh for your comments.

On Wed, Sep 16, 2020 at 6:36 PM Ashutosh Sharma <ashu.coek88@gmail.com> wrote:

Hi Vignesh,

I've spent some time today looking at your new set of patches and I've
some thoughts and queries which I would like to put here:

Why are these not part of the shared cstate structure?

SerializeString(pcxt, PARALLEL_COPY_KEY_NULL_PRINT, cstate->null_print);
SerializeString(pcxt, PARALLEL_COPY_KEY_DELIM, cstate->delim);
SerializeString(pcxt, PARALLEL_COPY_KEY_QUOTE, cstate->quote);
SerializeString(pcxt, PARALLEL_COPY_KEY_ESCAPE, cstate->escape);

I have used shared_cstate mainly to share the integer & bool data
types from the leader to worker process. The above data types are of
char* data type, I will not be able to use it like how I could do it
for integer type. So I preferred to send these as separate keys to the
worker. Thoughts?

I think the way you have written will work but if we go with
Ashutosh's proposal it will look elegant and in the future, if we need
to share more strings as part of cstate structure then that would be
easier. You can probably refer to EstimateParamListSpace,
SerializeParamList, and RestoreParamList to see how we can share
different types of data in one key.

Yeah. And in addition to that it will also reduce the number of DSM
keys that we need to maintain.

--
With Regards,
Ashutosh Sharma
EnterpriseDB:http://www.enterprisedb.com

#153Greg Nancarrow
gregn4422@gmail.com
In reply to: vignesh C (#144)
Re: Parallel copy

Hi Vignesh and Bharath,

Seems like the Parallel Copy patch is regarding RI_TRIGGER_PK as
parallel-unsafe.
Can you explain why this is?

Regards,
Greg Nancarrow
Fujitsu Australia

#154Amit Kapila
amit.kapila16@gmail.com
In reply to: Amit Kapila (#150)
Re: Parallel copy

On Mon, Sep 28, 2020 at 12:19 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

Few additional comments:
======================

Some more comments:

v5-0002-Framework-for-leader-worker-in-parallel-copy
===========================================
1.
These values
+ * help in handover of multiple records with significant size of data to be
+ * processed by each of the workers to make sure there is no context
switch & the
+ * work is fairly distributed among the workers.

How about writing it as: "These values help in the handover of
multiple records with the significant size of data to be processed by
each of the workers. This also ensures there is no context switch and
the work is fairly distributed among the workers."

2. Can we keep WORKER_CHUNK_COUNT, MAX_BLOCKS_COUNT, and RINGSIZE as
power-of-two? Say WORKER_CHUNK_COUNT as 64, MAX_BLOCK_COUNT as 1024,
and accordingly choose RINGSIZE. At many places, we do that way. I
think it can sometimes help in faster processing due to cache size
requirements and in this case, I don't see a reason why we can't
choose these values to be power-of-two. If you agree with this change
then also do some performance testing after this change?

3.
+ bool   curr_blk_completed;
+ char   data[DATA_BLOCK_SIZE]; /* data read from file */
+ uint8  skip_bytes;
+} ParallelCopyDataBlock;

Is there a reason to keep skip_bytes after data? Normally the variable
size data is at the end of the structure. Also, there is no comment
explaining the purpose of skip_bytes.

4.
+ * Copy data block information.
+ * ParallelCopyDataBlock's will be created in DSM. Data read from file will be
+ * copied in these DSM data blocks. The leader process identifies the records
+ * and the record information will be shared to the workers. The workers will
+ * insert the records into the table. There can be one or more number
of records
+ * in each of the data block based on the record size.
+ */
+typedef struct ParallelCopyDataBlock

Keep one empty line after the description line like below. I also
suggested to do a minor tweak in the above sentence which is as
follows:

* Copy data block information.
*
* These data blocks are created in DSM. Data read ...

Try to follow a similar format in other comments as well.

5. I think it is better to move parallelism related code to a new file
(we can name it as copyParallel.c or something like that).

6. copy.c(1648,25): warning C4133: 'function': incompatible types -
from 'ParallelCopyLineState *' to 'uint32 *'
Getting above compilation warning on Windows.

v5-0003-Allow-copy-from-command-to-process-data-from-file
==================================================
1.
@@ -4294,7 +5047,7 @@ BeginCopyFrom(ParseState *pstate,
  * only in text mode.
  */
  initStringInfo(&cstate->attribute_buf);
- cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+ cstate->raw_buf = (IsParallelCopy()) ? NULL : (char *)
palloc(RAW_BUF_SIZE + 1);

Is there anyway IsParallelCopy can be true by this time? AFAICS, we do
anything about parallelism after this. If you want to save this
allocation then we need to move this after we determine that
parallelism can be used or not and accordingly the below code in the
patch needs to be changed.

* ParallelCopyFrom - parallel copy leader's functionality.
*
* Leader executes the before statement for before statement trigger, if before
@@ -1110,8 +1547,302 @@ ParallelCopyFrom(CopyState cstate)
ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
ereport(DEBUG1, (errmsg("Running parallel copy leader")));

+ /* raw_buf is not used in parallel copy, instead data blocks are used.*/
+ pfree(cstate->raw_buf);
+ cstate->raw_buf = NULL;

Is there anything else also the allocation of which depends on parallelism?

2.
+static pg_attribute_always_inline bool
+IsParallelCopyAllowed(CopyState cstate)
+{
+ /* Parallel copy not allowed for frontend (2.0 protocol) & binary option. */
+ if ((cstate->copy_dest == COPY_OLD_FE) || cstate->binary)
+ return false;
+
+ /* Check if copy is into foreign table or temporary table. */
+ if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
+ RelationUsesLocalBuffers(cstate->rel))
+ return false;
+
+ /* Check if trigger function is parallel safe. */
+ if (cstate->rel->trigdesc != NULL &&
+ !IsTriggerFunctionParallelSafe(cstate->rel->trigdesc))
+ return false;
+
+ /*
+ * Check if there is after statement or instead of trigger or transition
+ * table triggers.
+ */
+ if (cstate->rel->trigdesc != NULL &&
+ (cstate->rel->trigdesc->trig_insert_after_statement ||
+ cstate->rel->trigdesc->trig_insert_instead_row ||
+ cstate->rel->trigdesc->trig_insert_new_table))
+ return false;
+
+ /* Check if the volatile expressions are parallel safe, if present any. */
+ if (!CheckExprParallelSafety(cstate))
+ return false;
+
+ /* Check if the insertion mode is single. */
+ if (FindInsertMethod(cstate) == CIM_SINGLE)
+ return false;
+
+ return true;
+}

In the comments, we should write why parallelism is not allowed for a
particular case. The cases where parallel-unsafe clause is involved
are okay but it is not clear from comments why it is not allowed in
other cases.

3.
+ ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+ ParallelCopyLineBoundary *lineInfo;
+ uint32 line_first_block = pcshared_info->cur_block_pos;
+ line_pos = UpdateBlockInLineInfo(cstate,
+    line_first_block,
+    cstate->raw_buf_index, -1,
+    LINE_LEADER_POPULATING);
+ lineInfo = &pcshared_info->line_boundaries.ring[line_pos];
+ elog(DEBUG1, "[Leader] Adding - block:%d, offset:%d, line position:%d",
+ line_first_block, lineInfo->start_offset, line_pos);

Can we take all the code here inside function UpdateBlockInLineInfo? I
see that it is called from one other place but I guess most of the
surrounding code there can also be moved inside the function. Can we
change the name of the function to UpdateSharedLineInfo or something
like that and remove inline marking from this? I am not sure we want
to inline such big functions. If it make difference in performance
then we can probably consider it.

4.
EndLineParallelCopy()
{
..
+ /* Update line size. */
+ pg_atomic_write_u32(&lineInfo->line_size, line_size);
+ pg_atomic_write_u32(&lineInfo->line_state, LINE_LEADER_POPULATED);
+ elog(DEBUG1, "[Leader] After adding - line position:%d, line_size:%d",
+ line_pos, line_size);
..
}

Can we instead call UpdateSharedLineInfo (new function name for
UpdateBlockInLineInfo) to do this and maybe see it only updates the
required info? The idea is to centralize the code for updating
SharedLineInfo.

5.
+static uint32
+GetLinePosition(CopyState cstate)
+{
+ ParallelCopyData *pcdata = cstate->pcdata;
+ ParallelCopyShmInfo *pcshared_info = pcdata->pcshared_info;
+ uint32  previous_pos = pcdata->worker_processed_pos;
+ uint32 write_pos = (previous_pos == -1) ? 0 : (previous_pos + 1) % RINGSIZE;

It seems to me that each worker has to hop through all the processed
chunks before getting the chunk which it can process. This will work
but I think it is better if we have some shared counter which can tell
us the next chunk to be processed and avoid all the unnecessary work
of hopping to find the exact position.

v5-0004-Documentation-for-parallel-copy
-----------------------------------------
1. Can you add one or two examples towards the end of the page where
we have examples for other Copy options?

Please run pgindent on all patches as that will make the code look better.

From the testing perspective,
1. Test by having something force_parallel_mode = regress which means
that all existing Copy tests in the regression will be executed via
new worker code. You can have this as a test-only patch for now and
make sure all existing tests passed with this.
2. Do we have tests for toast tables? I think if you implement the
previous point some existing tests might cover it but I feel we should
have at least one or two tests for the same.
3. Have we checked the code coverage of the newly added code with
existing tests?

--
With Regards,
Amit Kapila.

#155vignesh C
vignesh21@gmail.com
In reply to: Amit Kapila (#154)
Re: Parallel copy

On Tue, Sep 29, 2020 at 6:30 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Mon, Sep 28, 2020 at 12:19 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

Few additional comments:
======================

Some more comments:

Thanks Amit for the comments, I will work on the comments and provide
a patch in the next few days.

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

#156Amit Kapila
amit.kapila16@gmail.com
In reply to: Greg Nancarrow (#153)
Re: Parallel copy

On Tue, Sep 29, 2020 at 3:16 PM Greg Nancarrow <gregn4422@gmail.com> wrote:

Hi Vignesh and Bharath,

Seems like the Parallel Copy patch is regarding RI_TRIGGER_PK as
parallel-unsafe.
Can you explain why this is?

I don't think we need to restrict this case and even if there is some
reason to do so then probably the same should be mentioned in the
comments.

--
With Regards,
Amit Kapila.

#157Tomas Vondra
tomas.vondra@2ndquadrant.com
In reply to: Bharath Rupireddy (#145)
Re: Parallel copy

Hello Vignesh,

I've done some basic benchmarking on the v4 version of the patches (but
AFAIKC the v5 should perform about the same), and some initial review.

For the benchmarking, I used the lineitem table from TPC-H - for 75GB
data set, this largest table is about 64GB once loaded, with another
54GB in 5 indexes. This is on a server with 32 cores, 64GB of RAM and
NVME storage.

The COPY duration with varying number of workers (specified using the
parallel COPY option) looks like this:

workers duration
---------------------
0 1366
1 1255
2 704
3 526
4 434
5 385
6 347
7 322
8 327

So this seems to work pretty well - initially we get almost linear
speedup, then it slows down (likely due to contention for locks, I/O
etc.). Not bad.

I've only done a quick review, but overall the patch looks in fairly
good shape.

1) I don't quite understand why we need INCREMENTPROCESSED and
RETURNPROCESSED, considering it just does ++ or return. It just
obfuscated the code, I think.

2) I find it somewhat strange that BeginParallelCopy can just decide not
to do parallel copy after all. Why not to do this decisions in the
caller? Or maybe it's fine this way, not sure.

3) AFAIK we don't modify typedefs.list in patches, so these changes
should be removed.

4) IsTriggerFunctionParallelSafe actually checks all triggers, not just
one, so the comment needs minor rewording.

regards

--
Tomas Vondra http://www.2ndQuadrant.com
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

#158Amit Kapila
amit.kapila16@gmail.com
In reply to: Tomas Vondra (#157)
Re: Parallel copy

On Sat, Oct 3, 2020 at 6:20 AM Tomas Vondra
<tomas.vondra@2ndquadrant.com> wrote:

Hello Vignesh,

I've done some basic benchmarking on the v4 version of the patches (but
AFAIKC the v5 should perform about the same), and some initial review.

For the benchmarking, I used the lineitem table from TPC-H - for 75GB
data set, this largest table is about 64GB once loaded, with another
54GB in 5 indexes. This is on a server with 32 cores, 64GB of RAM and
NVME storage.

The COPY duration with varying number of workers (specified using the
parallel COPY option) looks like this:

workers duration
---------------------
0 1366
1 1255
2 704
3 526
4 434
5 385
6 347
7 322
8 327

So this seems to work pretty well - initially we get almost linear
speedup, then it slows down (likely due to contention for locks, I/O
etc.). Not bad.

+1. These numbers (> 4x speed up) look good to me.

--
With Regards,
Amit Kapila.

#159vignesh C
vignesh21@gmail.com
In reply to: Amit Kapila (#150)
6 attachment(s)
Re: Parallel copy

On Mon, Sep 28, 2020 at 12:19 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Wed, Jul 22, 2020 at 7:48 PM vignesh C <vignesh21@gmail.com> wrote:

On Tue, Jul 21, 2020 at 3:54 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

Review comments:
===================

0001-Copy-code-readjustment-to-support-parallel-copy
1.
@@ -807,8 +835,11 @@ CopyLoadRawBuf(CopyState cstate)
else
nbytes = 0; /* no data need be saved */

+ if (cstate->copy_dest == COPY_NEW_FE)
+ minread = RAW_BUF_SIZE - nbytes;
+
inbytes = CopyGetData(cstate, cstate->raw_buf + nbytes,
-   1, RAW_BUF_SIZE - nbytes);
+   minread, RAW_BUF_SIZE - nbytes);

No comment to explain why this change is done?

0002-Framework-for-leader-worker-in-parallel-copy

Currently CopyGetData copies a lesser amount of data to buffer even though space is available in buffer because minread was passed as 1 to CopyGetData. Because of this there are frequent call to CopyGetData for fetching the data. In this case it will load only some data due to the below check:
while (maxread > 0 && bytesread < minread && !cstate->reached_eof)
After reading some data bytesread will be greater than minread which is passed as 1 and return with lesser amount of data, even though there is some space.
This change is required for parallel copy feature as each time we get a new DSM data block which is of 64K size and copy the data. If we copy less data into DSM data blocks we might end up consuming all the DSM data blocks.

Why can't we reuse the DSM block which has unfilled space?

I felt this issue can be fixed as part of HEAD. Have posted a separate thread [1] for this. I'm planning to remove that change once it gets committed. Can that go as a separate
patch or should we include it here?
[1] - /messages/by-id/CALDaNm0v4CjmvSnftYnx_9pOS_dKRG=O3NnBgJsQmi0KipvLog@mail.gmail.com

I am convinced by the reason given by Kyotaro-San in that another
thread [1] and performance data shown by Peter that this can't be an
independent improvement and rather in some cases it can do harm. Now,
if you need it for a parallel-copy path then we can change it
specifically to the parallel-copy code path but I don't understand
your reason completely.

Whenever we need data to be populated, we will get a new data block &
pass it to CopyGetData to populate the data. In case of file copy, the
server will completely fill the data block. We expect the data to be
filled completely. If data is available it will completely load the
complete data block in case of file copy. There is no scenario where
even if data is present a partial data block will be returned except
for EOF or no data available. But in case of STDIN data copy, even
though there is 8K data available in data block & 8K data available in
STDIN, CopyGetData will return as soon as libpq buffer data is more
than the minread. We will pass new data block every time to load data.
Every time we pass an 8K data block but CopyGetData loads a few bytes
in the new data block & returns. I wanted to keep the same data
population logic for both file copy & STDIN copy i.e copy full 8K data
blocks & then the populated data can be required. There is an
alternative solution I can have some special handling in case of STDIN
wherein the existing data block can be passed with the index from
where the data should be copied. Thoughts?

2.

..

+ */
+typedef struct ParallelCopyLineBoundary

Are we doing all this state management to avoid using locks while
processing lines? If so, I think we can use either spinlock or LWLock
to keep the main patch simple and then provide a later patch to make
it lock-less. This will allow us to first focus on the main design of
the patch rather than trying to make this datastructure processing
lock-less in the best possible way.

The steps will be more or less same if we use spinlock too. step 1, step 3 & step 4 will be common we have to use lock & unlock instead of step 2 & step 5. I feel we can retain the current implementation.

I'll study this in detail and let you know my opinion on the same but
in the meantime, I don't follow one part of this comment: "If they
don't follow this order the worker might process wrong line_size and
leader might populate the information which worker has not yet
processed or in the process of processing."

Do you want to say that leader might overwrite some information which
worker hasn't read yet? If so, it is not clear from the comment.
Another minor point about this comment:

Here leader and worker must follow these steps to avoid any corruption
or hang issue. Changed it to:
* The leader & worker process access the shared line information by following
* the below steps to avoid any data corruption or hang:

+ * ParallelCopyLineBoundary is common data structure between leader & worker,
+ * Leader process will be populating data block, data block offset &
the size of

I think there should be a full-stop after worker instead of a comma.

Changed it.

6.
In function BeginParallelCopy(), you need to keep a provision to
collect wal_usage and buf_usage stats. See _bt_begin_parallel for
reference. Those will be required for pg_stat_statements.

Fixed

How did you ensure that this is fixed? Have you tested it, if so
please share the test? I see a basic problem with your fix.

+ /* Report WAL/buffer usage during parallel execution */
+ bufferusage = shm_toc_lookup(toc, PARALLEL_COPY_BUFFER_USAGE, false);
+ walusage = shm_toc_lookup(toc, PARALLEL_COPY_WAL_USAGE, false);
+ InstrEndParallelQuery(&bufferusage[ParallelWorkerNumber],
+   &walusage[ParallelWorkerNumber]);

You need to call InstrStartParallelQuery() before the actual operation
starts, without that stats won't be accurate? Also, after calling
WaitForParallelWorkersToFinish(), you need to accumulate the stats
collected from workers which neither you have done nor is possible
with the current code in your patch because you haven't made any
provision to capture them in BeginParallelCopy.

I suggest you look into lazy_parallel_vacuum_indexes() and
begin_parallel_vacuum() to understand how the buffer/wal usage stats
are accumulated. Also, please test this functionality using
pg_stat_statements.

Made changes accordingly.
I have verified it using:
postgres=# select * from pg_stat_statements where query like '%copy%';
userid | dbid | queryid |
query
| plans | total_plan_time |
min_plan_time | max_plan_time | mean_plan_time | stddev_plan_time |
calls | total_exec_time | min_exec_time | max_exec_time |
mean_exec_time | stddev_exec_time | rows | shared_blks_hi
t | shared_blks_read | shared_blks_dirtied | shared_blks_written |
local_blks_hit | local_blks_read | local_blks_dirtied |
local_blks_written | temp_blks_read | temp_blks_written | blk_
read_time | blk_write_time | wal_records | wal_fpi | wal_bytes
--------+-------+----------------------+---------------------------------------------------------------------------------------------------------------------+-------+-----------------+-
--------------+---------------+----------------+------------------+-------+-----------------+---------------+---------------+----------------+------------------+--------+---------------
--+------------------+---------------------+---------------------+----------------+-----------------+--------------------+--------------------+----------------+-------------------+-----
----------+----------------+-------------+---------+-----------
10 | 13743 | -6947756673093447609 | copy hw from
'/home/vignesh/postgres/postgres/inst/bin/hw_175000.csv' with(format
csv, delimiter ',') | 0 | 0 |
0 | 0 | 0 | 0 |
1 | 265.195105 | 265.195105 | 265.195105 | 265.195105
| 0 | 175000 | 191
6 | 0 | 946 | 946 |
0 | 0 | 0 | 0
| 0 | 0 |
0 | 0 | 1116 | 0 | 3587203
10 | 13743 | 8570215596364326047 | copy hw from
'/home/vignesh/postgres/postgres/inst/bin/hw_175000.csv' with(format
csv, delimiter ',', parallel '2') | 0 | 0 |
0 | 0 | 0 | 0 |
1 | 35668.402482 | 35668.402482 | 35668.402482 | 35668.402482
| 0 | 175000 | 310
1 | 36 | 952 | 919 |
0 | 0 | 0 | 0
| 0 | 0 |
0 | 0 | 1119 | 6 | 3624405
(2 rows)

0003-Allow-copy-from-command-to-process-data-from-file-ST
10.
In the commit message, you have written "The leader does not
participate in the insertion of data, leaders only responsibility will
be to identify the lines as fast as possible for the workers to do the
actual copy operation. The leader waits till all the lines populated
are processed by the workers and exits."

I think you should also mention that we have chosen this design based
on the reason "that everything stalls if the leader doesn't accept
further input data, as well as when there are no available splitted
chunks so it doesn't seem like a good idea to have the leader do other
work. This is backed by the performance data where we have seen that
with 1 worker there is just a 5-10% (or whatever percentage difference
you have seen) performance difference)".

Fixed.

Make it a one-paragraph starting from "The leader does not participate
in the insertion of data .... just a 5-10% performance difference".
Right now both the parts look a bit disconnected.

Made the contents starting from "The leader does not" in a paragraph.

Few additional comments:
======================
v5-0001-Copy-code-readjustment-to-support-parallel-copy
---------------------------------------------------------------------------------
1.
+/*
+ * CLEAR_EOL_LINE - Wrapper for clearing EOL.
+ */
+#define CLEAR_EOL_LINE() \
+if (!result && !IsHeaderLine()) \
+ ClearEOLFromCopiedData(cstate, cstate->line_buf.data, \
+    cstate->line_buf.len, \
+    &cstate->line_buf.len) \

I don't like this macro. I think it is sufficient to move the common
code to be called from the parallel and non-parallel path in
ClearEOLFromCopiedData but I think the other checks can be done
in-place. I think having macros for such a thing makes code less
readable.

I have removed the macro & called ClearEOLFromCopiedData directly
wherever required.

2.
-
+static void PopulateCommonCstateInfo(CopyState cstate, TupleDesc tup_desc,
+ List *attnamelist);

Spurious line removal.

I have modified it to keep it as it is.

v5-0002-Framework-for-leader-worker-in-parallel-copy
---------------------------------------------------------------------------
3.
+ FullTransactionId full_transaction_id; /* xid for copy from statement */
+ CommandId mycid; /* command id */
+ ParallelCopyLineBoundaries line_boundaries; /* line array */
+} ParallelCopyShmInfo;

We already serialize FullTransactionId and CommandId via
InitializeParallelDSM->SerializeTransactionState. Can't we reuse it? I
think recently Parallel Insert patch has also done something for this
[2] so you can refer that if you want.

Changed it to remove setting of command id & full transaction id.
Added a function SetCurrentCommandIdUsedForWorker to set
currentCommandIdUsed to true & called GetCurrentCommandId by passing
!IsParallelCopy().

v5-0004-Documentation-for-parallel-copy
-----------------------------------------------------------
1.  Perform <command>COPY FROM</command> in parallel using <replaceable
+      class="parameter"> integer</replaceable> background workers.

No need for space before integer.

I have removed it.

Attached v6 patch with the fixes.

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

Attachments:

v6-0001-Copy-code-readjustment-to-support-parallel-copy.patchapplication/x-patch; name=v6-0001-Copy-code-readjustment-to-support-parallel-copy.patchDownload
From 2f6fda276f191a3b7a15c07c51199a154530ed09 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Sat, 1 Aug 2020 08:52:48 +0530
Subject: [PATCH v6 1/6] Copy code readjustment to support parallel copy.

This patch has the copy code slightly readjusted so that the common code is
separated to functions/macros, these functions/macros will be used by the
workers in the parallel copy code of the upcoming patches. EOL removal is moved
from CopyReadLine to CopyReadLineText, this change was required because in case
of parallel copy the record identification and record updation is done in
CopyReadLineText, before record information is updated in shared memory the new
line characters should be removed.
---
 src/backend/commands/copy.c | 356 +++++++++++++++++++++++++++-----------------
 1 file changed, 218 insertions(+), 138 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 2047557..f2848a1 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -95,6 +95,9 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
+#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+#define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
+
 /*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
@@ -224,7 +227,6 @@ typedef struct CopyStateData
 	 * appropriate amounts of data from this buffer.  In both modes, we
 	 * guarantee that there is a \0 at raw_buf[raw_buf_len].
 	 */
-#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
@@ -354,6 +356,18 @@ if (1) \
 	goto not_end_of_copy; \
 } else ((void) 0)
 
+/*
+ * Increment the lines processed.
+ */
+#define INCREMENTPROCESSED(processed)  \
+processed++;
+
+/*
+ * Get the lines processed.
+ */
+#define RETURNPROCESSED(processed) \
+return processed;
+
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
 
@@ -401,6 +415,12 @@ static bool CopyGetInt16(CopyState cstate, int16 *val);
 static bool CopyLoadRawBuf(CopyState cstate);
 static int	CopyReadBinaryData(CopyState cstate, char *dest, int nbytes);
 
+static void PopulateCommonCstateInfo(CopyState cstate, TupleDesc tup_desc,
+									 List *attnamelist);
+static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
+								   int copy_line_pos, int *copy_line_size);
+static void ConvertToServerEncoding(CopyState cstate);
+
 
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
@@ -801,14 +821,18 @@ CopyLoadRawBuf(CopyState cstate)
 {
 	int			nbytes = RAW_BUF_BYTES(cstate);
 	int			inbytes;
+	int			minread = 1;
 
 	/* Copy down the unprocessed data if any. */
 	if (nbytes > 0)
 		memmove(cstate->raw_buf, cstate->raw_buf + cstate->raw_buf_index,
 				nbytes);
 
+	if (cstate->copy_dest == COPY_NEW_FE)
+		minread = RAW_BUF_SIZE - nbytes;
+
 	inbytes = CopyGetData(cstate, cstate->raw_buf + nbytes,
-						  1, RAW_BUF_SIZE - nbytes);
+						  minread, RAW_BUF_SIZE - nbytes);
 	nbytes += inbytes;
 	cstate->raw_buf[nbytes] = '\0';
 	cstate->raw_buf_index = 0;
@@ -1514,7 +1538,6 @@ BeginCopy(ParseState *pstate,
 {
 	CopyState	cstate;
 	TupleDesc	tupDesc;
-	int			num_phys_attrs;
 	MemoryContext oldcontext;
 
 	/* Allocate workspace and zero all fields */
@@ -1680,6 +1703,25 @@ BeginCopy(ParseState *pstate,
 		tupDesc = cstate->queryDesc->tupDesc;
 	}
 
+	PopulateCommonCstateInfo(cstate, tupDesc, attnamelist);
+	cstate->copy_dest = COPY_FILE;	/* default */
+
+	MemoryContextSwitchTo(oldcontext);
+
+	return cstate;
+}
+
+/*
+ * PopulateCommonCstateInfo
+ *
+ * Populates the common variables required for copy from operation. This is a
+ * helper function for BeginCopy function.
+ */
+static void
+PopulateCommonCstateInfo(CopyState cstate, TupleDesc tupDesc, List *attnamelist)
+{
+	int			num_phys_attrs;
+
 	/* Generate or convert list of attributes to process */
 	cstate->attnumlist = CopyGetAttnums(tupDesc, cstate->rel, attnamelist);
 
@@ -1799,12 +1841,6 @@ BeginCopy(ParseState *pstate,
 		 pg_database_encoding_max_length() > 1);
 	/* See Multibyte encoding comment above */
 	cstate->encoding_embeds_ascii = PG_ENCODING_IS_CLIENT_ONLY(cstate->file_encoding);
-
-	cstate->copy_dest = COPY_FILE;	/* default */
-
-	MemoryContextSwitchTo(oldcontext);
-
-	return cstate;
 }
 
 /*
@@ -2696,32 +2732,13 @@ CopyMultiInsertInfoStore(CopyMultiInsertInfo *miinfo, ResultRelInfo *rri,
 }
 
 /*
- * Copy FROM file to relation.
+ * CheckTargetRelValidity
+ *
+ * Check if the relation specified in copy from is valid.
  */
-uint64
-CopyFrom(CopyState cstate)
+static void
+CheckTargetRelValidity(CopyState cstate)
 {
-	ResultRelInfo *resultRelInfo;
-	ResultRelInfo *target_resultRelInfo;
-	ResultRelInfo *prevResultRelInfo = NULL;
-	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
-	ModifyTableState *mtstate;
-	ExprContext *econtext;
-	TupleTableSlot *singleslot = NULL;
-	MemoryContext oldcontext = CurrentMemoryContext;
-
-	PartitionTupleRouting *proute = NULL;
-	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
-	int			ti_options = 0; /* start with default options for insert */
-	BulkInsertState bistate = NULL;
-	CopyInsertMethod insertMethod;
-	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
-	uint64		processed = 0;
-	bool		has_before_insert_row_trig;
-	bool		has_instead_insert_row_trig;
-	bool		leafpart_use_multi_insert = false;
-
 	Assert(cstate->rel);
 
 	/*
@@ -2758,27 +2775,6 @@ CopyFrom(CopyState cstate)
 							RelationGetRelationName(cstate->rel))));
 	}
 
-	/*
-	 * If the target file is new-in-transaction, we assume that checking FSM
-	 * for free space is a waste of time.  This could possibly be wrong, but
-	 * it's unlikely.
-	 */
-	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
-		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
-		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
-		ti_options |= TABLE_INSERT_SKIP_FSM;
-
-	/*
-	 * Optimize if new relfilenode was created in this subxact or one of its
-	 * committed children and we won't see those rows later as part of an
-	 * earlier scan or command. The subxact test ensures that if this subxact
-	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
-	 * that the stronger test of exactly which subtransaction created it is
-	 * crucial for correctness of this optimization. The test for an earlier
-	 * scan or command tolerates false negatives. FREEZE causes other sessions
-	 * to see rows they would not see under MVCC, and a false negative merely
-	 * spreads that anomaly to the current session.
-	 */
 	if (cstate->freeze)
 	{
 		/*
@@ -2816,9 +2812,61 @@ CopyFrom(CopyState cstate)
 			ereport(ERROR,
 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 					 errmsg("cannot perform COPY FREEZE because the table was not created or truncated in the current subtransaction")));
+	}
+}
+
+/*
+ * Copy FROM file to relation.
+ */
+uint64
+CopyFrom(CopyState cstate)
+{
+	ResultRelInfo *resultRelInfo;
+	ResultRelInfo *target_resultRelInfo;
+	ResultRelInfo *prevResultRelInfo = NULL;
+	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
+	ModifyTableState *mtstate;
+	ExprContext *econtext;
+	TupleTableSlot *singleslot = NULL;
+	MemoryContext oldcontext = CurrentMemoryContext;
+
+	PartitionTupleRouting *proute = NULL;
+	ErrorContextCallback errcallback;
+	CommandId	mycid = GetCurrentCommandId(true);
+	int			ti_options = 0; /* start with default options for insert */
+	BulkInsertState bistate = NULL;
+	CopyInsertMethod insertMethod;
+	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
+	uint64		processed = 0;
+	bool		has_before_insert_row_trig;
+	bool		has_instead_insert_row_trig;
+	bool		leafpart_use_multi_insert = false;
 
+	CheckTargetRelValidity(cstate);
+
+	/*
+	 * If the target file is new-in-transaction, we assume that checking FSM
+	 * for free space is a waste of time.  This could possibly be wrong, but
+	 * it's unlikely.
+	 */
+	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
+		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
+		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
+		ti_options |= TABLE_INSERT_SKIP_FSM;
+
+	/*
+	 * Optimize if new relfilenode was created in this subxact or one of its
+	 * committed children and we won't see those rows later as part of an
+	 * earlier scan or command. The subxact test ensures that if this subxact
+	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
+	 * that the stronger test of exactly which subtransaction created it is
+	 * crucial for correctness of this optimization. The test for an earlier
+	 * scan or command tolerates false negatives. FREEZE causes other sessions
+	 * to see rows they would not see under MVCC, and a false negative merely
+	 * spreads that anomaly to the current session.
+	 */
+	if (cstate->freeze)
 		ti_options |= TABLE_INSERT_FROZEN;
-	}
 
 	/*
 	 * We need a ResultRelInfo so we can use the regular executor's
@@ -3311,7 +3359,7 @@ CopyFrom(CopyState cstate)
 			 * or FDW; this is the same definition used by nodeModifyTable.c
 			 * for counting tuples inserted by an INSERT command.
 			 */
-			processed++;
+			INCREMENTPROCESSED(processed)
 		}
 	}
 
@@ -3366,30 +3414,17 @@ CopyFrom(CopyState cstate)
 
 	FreeExecutorState(estate);
 
-	return processed;
+	RETURNPROCESSED(processed)
 }
 
 /*
- * Setup to read tuples from a file for COPY FROM.
+ * PopulateCstateCatalogInfo
  *
- * 'rel': Used as a template for the tuples
- * 'filename': Name of server-local file to read
- * 'attnamelist': List of char *, columns to include. NIL selects all cols.
- * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
- *
- * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ * Populate the cstate catalog information.
  */
-CopyState
-BeginCopyFrom(ParseState *pstate,
-			  Relation rel,
-			  const char *filename,
-			  bool is_program,
-			  copy_data_source_cb data_source_cb,
-			  List *attnamelist,
-			  List *options)
+static void
+PopulateCstateCatalogInfo(CopyState cstate)
 {
-	CopyState	cstate;
-	bool		pipe = (filename == NULL);
 	TupleDesc	tupDesc;
 	AttrNumber	num_phys_attrs,
 				num_defaults;
@@ -3399,38 +3434,8 @@ BeginCopyFrom(ParseState *pstate,
 	Oid			in_func_oid;
 	int		   *defmap;
 	ExprState **defexprs;
-	MemoryContext oldcontext;
 	bool		volatile_defexprs;
 
-	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
-	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
-
-	/* Initialize state variables */
-	cstate->reached_eof = false;
-	cstate->eol_type = EOL_UNKNOWN;
-	cstate->cur_relname = RelationGetRelationName(cstate->rel);
-	cstate->cur_lineno = 0;
-	cstate->cur_attname = NULL;
-	cstate->cur_attval = NULL;
-
-	/*
-	 * Set up variables to avoid per-attribute overhead.  attribute_buf and
-	 * raw_buf are used in both text and binary modes, but we use line_buf
-	 * only in text mode.
-	 */
-	initStringInfo(&cstate->attribute_buf);
-	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
-	cstate->raw_buf_index = cstate->raw_buf_len = 0;
-	if (!cstate->binary)
-	{
-		initStringInfo(&cstate->line_buf);
-		cstate->line_buf_converted = false;
-	}
-
-	/* Assign range table, we'll need it in CopyFrom. */
-	if (pstate)
-		cstate->range_table = pstate->p_rtable;
-
 	tupDesc = RelationGetDescr(cstate->rel);
 	num_phys_attrs = tupDesc->natts;
 	num_defaults = 0;
@@ -3508,6 +3513,61 @@ BeginCopyFrom(ParseState *pstate,
 	cstate->defexprs = defexprs;
 	cstate->volatile_defexprs = volatile_defexprs;
 	cstate->num_defaults = num_defaults;
+}
+
+/*
+ * Setup to read tuples from a file for COPY FROM.
+ *
+ * 'rel': Used as a template for the tuples
+ * 'filename': Name of server-local file to read
+ * 'attnamelist': List of char *, columns to include. NIL selects all cols.
+ * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
+ *
+ * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ */
+CopyState
+BeginCopyFrom(ParseState *pstate,
+			  Relation rel,
+			  const char *filename,
+			  bool is_program,
+			  copy_data_source_cb data_source_cb,
+			  List *attnamelist,
+			  List *options)
+{
+	CopyState	cstate;
+	bool		pipe = (filename == NULL);
+	MemoryContext oldcontext;
+
+	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	/* Initialize state variables */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/*
+	 * Set up variables to avoid per-attribute overhead.  attribute_buf is
+	 * used in both text and binary modes, but we use line_buf and raw_buf
+	 * only in text mode.
+	 */
+	initStringInfo(&cstate->attribute_buf);
+	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+	if (!cstate->binary)
+	{
+		initStringInfo(&cstate->line_buf);
+		cstate->line_buf_converted = false;
+	}
+
+	/* Assign range table, we'll need it in CopyFrom. */
+	if (pstate)
+		cstate->range_table = pstate->p_rtable;
+
+	PopulateCstateCatalogInfo(cstate);
 	cstate->is_program = is_program;
 
 	if (data_source_cb)
@@ -3917,40 +3977,60 @@ CopyReadLine(CopyState cstate)
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
-	else
+
+	ConvertToServerEncoding(cstate);
+	return result;
+}
+
+/*
+ * ClearEOLFromCopiedData
+ *
+ * Clear EOL from the copied data.
+ */
+static void
+ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
+					   int copy_line_pos, int *copy_line_size)
+{
+	/*
+	 * If we didn't hit EOF, then we must have transferred the EOL marker to
+	 * line_buf along with the data.  Get rid of it.
+	 */
+	switch (cstate->eol_type)
 	{
-		/*
-		 * If we didn't hit EOF, then we must have transferred the EOL marker
-		 * to line_buf along with the data.  Get rid of it.
-		 */
-		switch (cstate->eol_type)
-		{
-			case EOL_NL:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CR:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\r');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CRNL:
-				Assert(cstate->line_buf.len >= 2);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 2] == '\r');
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len -= 2;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_UNKNOWN:
-				/* shouldn't get here */
-				Assert(false);
-				break;
-		}
+		case EOL_NL:
+			Assert(*copy_line_size >= 1);
+			Assert(copy_line_data[copy_line_pos - 1] == '\n');
+			copy_line_data[copy_line_pos - 1] = '\0';
+			(*copy_line_size)--;
+			break;
+		case EOL_CR:
+			Assert(*copy_line_size >= 1);
+			Assert(copy_line_data[copy_line_pos - 1] == '\r');
+			copy_line_data[copy_line_pos - 1] = '\0';
+			(*copy_line_size)--;
+			break;
+		case EOL_CRNL:
+			Assert(*copy_line_size >= 2);
+			Assert(copy_line_data[copy_line_pos - 2] == '\r');
+			Assert(copy_line_data[copy_line_pos - 1] == '\n');
+			copy_line_data[copy_line_pos - 2] = '\0';
+			*copy_line_size -= 2;
+			break;
+		case EOL_UNKNOWN:
+			/* shouldn't get here */
+			Assert(false);
+			break;
 	}
+}
 
+/*
+ * ConvertToServerEncoding
+ *
+ * Convert contents to server encoding.
+ */
+static void
+ConvertToServerEncoding(CopyState cstate)
+{
 	/* Done reading the line.  Convert it to server encoding. */
 	if (cstate->need_transcoding)
 	{
@@ -3967,11 +4047,8 @@ CopyReadLine(CopyState cstate)
 			pfree(cvt);
 		}
 	}
-
 	/* Now it's safe to use the buffer in error messages */
 	cstate->line_buf_converted = true;
-
-	return result;
 }
 
 /*
@@ -4334,6 +4411,9 @@ not_end_of_copy:
 	 * Transfer any still-uncopied data to line_buf.
 	 */
 	REFILL_LINEBUF;
+	if (!result && !IsHeaderLine())
+		ClearEOLFromCopiedData(cstate, cstate->line_buf.data,
+							   cstate->line_buf.len, &cstate->line_buf.len);
 
 	return result;
 }
-- 
1.8.3.1

v6-0002-Framework-for-leader-worker-in-parallel-copy.patchapplication/x-patch; name=v6-0002-Framework-for-leader-worker-in-parallel-copy.patchDownload
From 67e5240af5ebe803473acebaf0e8796fd2a05cdd Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 7 Oct 2020 17:18:17 +0530
Subject: [PATCH v6 2/6] Framework for leader/worker in parallel copy

This patch has the framework for data structures in parallel copy, leader
initialization, worker initialization, shared memory updation, starting workers,
wait for workers and workers exiting.
---
 src/backend/access/transam/parallel.c |   4 +
 src/backend/commands/Makefile         |   1 +
 src/backend/commands/copy.c           | 235 ++++++--------------
 src/include/commands/copy.h           | 389 +++++++++++++++++++++++++++++++++-
 src/tools/pgindent/typedefs.list      |   7 +
 5 files changed, 469 insertions(+), 167 deletions(-)

diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index b042696..a3cff4b 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -25,6 +25,7 @@
 #include "catalog/pg_enum.h"
 #include "catalog/storage.h"
 #include "commands/async.h"
+#include "commands/copy.h"
 #include "executor/execParallel.h"
 #include "libpq/libpq.h"
 #include "libpq/pqformat.h"
@@ -145,6 +146,9 @@ static const struct
 	},
 	{
 		"parallel_vacuum_main", parallel_vacuum_main
+	},
+	{
+		"ParallelCopyMain", ParallelCopyMain
 	}
 };
 
diff --git a/src/backend/commands/Makefile b/src/backend/commands/Makefile
index d4815d3..a224aac 100644
--- a/src/backend/commands/Makefile
+++ b/src/backend/commands/Makefile
@@ -24,6 +24,7 @@ OBJS = \
 	constraint.o \
 	conversioncmds.o \
 	copy.o \
+	copyparallel.o \
 	createas.o \
 	dbcommands.o \
 	define.o \
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index f2848a1..1e55a30 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -29,7 +29,6 @@
 #include "catalog/pg_type.h"
 #include "commands/copy.h"
 #include "commands/defrem.h"
-#include "commands/trigger.h"
 #include "executor/execPartition.h"
 #include "executor/executor.h"
 #include "executor/nodeModifyTable.h"
@@ -63,29 +62,6 @@
 #define OCTVALUE(c) ((c) - '0')
 
 /*
- * Represents the different source/dest cases we need to worry about at
- * the bottom level
- */
-typedef enum CopyDest
-{
-	COPY_FILE,					/* to/from file (or a piped program) */
-	COPY_OLD_FE,				/* to/from frontend (2.0 protocol) */
-	COPY_NEW_FE,				/* to/from frontend (3.0 protocol) */
-	COPY_CALLBACK				/* to/from callback function */
-} CopyDest;
-
-/*
- *	Represents the end-of-line terminator type of the input
- */
-typedef enum EolType
-{
-	EOL_UNKNOWN,
-	EOL_NL,
-	EOL_CR,
-	EOL_CRNL
-} EolType;
-
-/*
  * Represents the heap insert method to be used during COPY FROM.
  */
 typedef enum CopyInsertMethod
@@ -95,145 +71,10 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
-#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+#define IsParallelCopy()		(cstate->is_parallel)
+#define IsLeader()				(cstate->pcdata->is_leader)
 #define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
 
-/*
- * This struct contains all the state variables used throughout a COPY
- * operation. For simplicity, we use the same struct for all variants of COPY,
- * even though some fields are used in only some cases.
- *
- * Multi-byte encodings: all supported client-side encodings encode multi-byte
- * characters by having the first byte's high bit set. Subsequent bytes of the
- * character can have the high bit not set. When scanning data in such an
- * encoding to look for a match to a single-byte (ie ASCII) character, we must
- * use the full pg_encoding_mblen() machinery to skip over multibyte
- * characters, else we might find a false match to a trailing byte. In
- * supported server encodings, there is no possibility of a false match, and
- * it's faster to make useless comparisons to trailing bytes than it is to
- * invoke pg_encoding_mblen() to skip over them. encoding_embeds_ascii is true
- * when we have to do it the hard way.
- */
-typedef struct CopyStateData
-{
-	/* low-level state data */
-	CopyDest	copy_dest;		/* type of copy source/destination */
-	FILE	   *copy_file;		/* used if copy_dest == COPY_FILE */
-	StringInfo	fe_msgbuf;		/* used for all dests during COPY TO, only for
-								 * dest == COPY_NEW_FE in COPY FROM */
-	bool		is_copy_from;	/* COPY TO, or COPY FROM? */
-	bool		reached_eof;	/* true if we read to end of copy data (not
-								 * all copy_dest types maintain this) */
-	EolType		eol_type;		/* EOL type of input */
-	int			file_encoding;	/* file or remote side's character encoding */
-	bool		need_transcoding;	/* file encoding diff from server? */
-	bool		encoding_embeds_ascii;	/* ASCII can be non-first byte? */
-
-	/* parameters from the COPY command */
-	Relation	rel;			/* relation to copy to or from */
-	QueryDesc  *queryDesc;		/* executable query to copy from */
-	List	   *attnumlist;		/* integer list of attnums to copy */
-	char	   *filename;		/* filename, or NULL for STDIN/STDOUT */
-	bool		is_program;		/* is 'filename' a program to popen? */
-	copy_data_source_cb data_source_cb; /* function for reading data */
-	bool		binary;			/* binary format? */
-	bool		freeze;			/* freeze rows on loading? */
-	bool		csv_mode;		/* Comma Separated Value format? */
-	bool		header_line;	/* CSV header line? */
-	char	   *null_print;		/* NULL marker string (server encoding!) */
-	int			null_print_len; /* length of same */
-	char	   *null_print_client;	/* same converted to file encoding */
-	char	   *delim;			/* column delimiter (must be 1 byte) */
-	char	   *quote;			/* CSV quote char (must be 1 byte) */
-	char	   *escape;			/* CSV escape char (must be 1 byte) */
-	List	   *force_quote;	/* list of column names */
-	bool		force_quote_all;	/* FORCE_QUOTE *? */
-	bool	   *force_quote_flags;	/* per-column CSV FQ flags */
-	List	   *force_notnull;	/* list of column names */
-	bool	   *force_notnull_flags;	/* per-column CSV FNN flags */
-	List	   *force_null;		/* list of column names */
-	bool	   *force_null_flags;	/* per-column CSV FN flags */
-	bool		convert_selectively;	/* do selective binary conversion? */
-	List	   *convert_select; /* list of column names (can be NIL) */
-	bool	   *convert_select_flags;	/* per-column CSV/TEXT CS flags */
-	Node	   *whereClause;	/* WHERE condition (or NULL) */
-
-	/* these are just for error messages, see CopyFromErrorCallback */
-	const char *cur_relname;	/* table name for error messages */
-	uint64		cur_lineno;		/* line number for error messages */
-	const char *cur_attname;	/* current att for error messages */
-	const char *cur_attval;		/* current att value for error messages */
-
-	/*
-	 * Working state for COPY TO/FROM
-	 */
-	MemoryContext copycontext;	/* per-copy execution context */
-
-	/*
-	 * Working state for COPY TO
-	 */
-	FmgrInfo   *out_functions;	/* lookup info for output functions */
-	MemoryContext rowcontext;	/* per-row evaluation context */
-
-	/*
-	 * Working state for COPY FROM
-	 */
-	AttrNumber	num_defaults;
-	FmgrInfo   *in_functions;	/* array of input functions for each attrs */
-	Oid		   *typioparams;	/* array of element types for in_functions */
-	int		   *defmap;			/* array of default att numbers */
-	ExprState **defexprs;		/* array of default att expressions */
-	bool		volatile_defexprs;	/* is any of defexprs volatile? */
-	List	   *range_table;
-	ExprState  *qualexpr;
-
-	TransitionCaptureState *transition_capture;
-
-	/*
-	 * These variables are used to reduce overhead in COPY FROM.
-	 *
-	 * attribute_buf holds the separated, de-escaped text for each field of
-	 * the current line.  The CopyReadAttributes functions return arrays of
-	 * pointers into this buffer.  We avoid palloc/pfree overhead by re-using
-	 * the buffer on each cycle.
-	 *
-	 * In binary COPY FROM, attribute_buf holds the binary data for the
-	 * current field, but the usage is otherwise similar.
-	 */
-	StringInfoData attribute_buf;
-
-	/* field raw data pointers found by COPY FROM */
-
-	int			max_fields;
-	char	  **raw_fields;
-
-	/*
-	 * Similarly, line_buf holds the whole input line being processed. The
-	 * input cycle is first to read the whole line into line_buf, convert it
-	 * to server encoding there, and then extract the individual attribute
-	 * fields into attribute_buf.  line_buf is preserved unmodified so that we
-	 * can display it in error messages if appropriate.  (In binary mode,
-	 * line_buf is not used.)
-	 */
-	StringInfoData line_buf;
-	bool		line_buf_converted; /* converted to server encoding? */
-	bool		line_buf_valid; /* contains the row being processed? */
-
-	/*
-	 * Finally, raw_buf holds raw data read from the data source (file or
-	 * client connection).  In text mode, CopyReadLine parses this data
-	 * sufficiently to locate line boundaries, then transfers the data to
-	 * line_buf and converts it.  In binary mode, CopyReadBinaryData fetches
-	 * appropriate amounts of data from this buffer.  In both modes, we
-	 * guarantee that there is a \0 at raw_buf[raw_buf_len].
-	 */
-	char	   *raw_buf;
-	int			raw_buf_index;	/* next byte to process */
-	int			raw_buf_len;	/* total # of bytes stored */
-	/* Shorthand for number of unconsumed bytes available in raw_buf */
-#define RAW_BUF_BYTES(cstate) ((cstate)->raw_buf_len - (cstate)->raw_buf_index)
-} CopyStateData;
-
 /* DestReceiver for COPY (query) TO */
 typedef struct
 {
@@ -415,8 +256,6 @@ static bool CopyGetInt16(CopyState cstate, int16 *val);
 static bool CopyLoadRawBuf(CopyState cstate);
 static int	CopyReadBinaryData(CopyState cstate, char *dest, int nbytes);
 
-static void PopulateCommonCstateInfo(CopyState cstate, TupleDesc tup_desc,
-									 List *attnamelist);
 static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
 								   int copy_line_pos, int *copy_line_size);
 static void ConvertToServerEncoding(CopyState cstate);
@@ -1134,6 +973,8 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 
 	if (is_from)
 	{
+		ParallelContext *pcxt = NULL;
+
 		Assert(rel);
 
 		/* check read-only transaction and parallel mode */
@@ -1143,7 +984,35 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 		cstate = BeginCopyFrom(pstate, rel, stmt->filename, stmt->is_program,
 							   NULL, stmt->attlist, stmt->options);
 		cstate->whereClause = whereClause;
-		*processed = CopyFrom(cstate);	/* copy from file to database */
+		cstate->is_parallel = false;
+
+		if (cstate->nworkers > 0)
+			pcxt = BeginParallelCopy(cstate->nworkers, cstate, stmt->attlist,
+									 relid);
+
+		if (pcxt)
+		{
+			int			i;
+
+			ParallelCopyFrom(cstate);
+
+			/* Wait for all copy workers to finish */
+			WaitForParallelWorkersToFinish(pcxt);
+
+			/*
+			 * Next, accumulate WAL usage.  (This must wait for the workers to
+			 * finish, or we might get incomplete data.)
+			 */
+			for (i = 0; i < pcxt->nworkers_launched; i++)
+				InstrAccumParallelQuery(&cstate->pcdata->bufferusage[i],
+										&cstate->pcdata->walusage[i]);
+
+			*processed = pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
+			EndParallelCopy(pcxt);
+		}
+		else
+			*processed = CopyFrom(cstate);	/* copy from file to database */
+
 		EndCopyFrom(cstate);
 	}
 	else
@@ -1192,6 +1061,7 @@ ProcessCopyOptions(ParseState *pstate,
 	cstate->is_copy_from = is_from;
 
 	cstate->file_encoding = -1;
+	cstate->nworkers = -1;
 
 	/* Extract options from the statement node tree */
 	foreach(option, options)
@@ -1360,6 +1230,39 @@ ProcessCopyOptions(ParseState *pstate,
 								defel->defname),
 						 parser_errposition(pstate, defel->location)));
 		}
+		else if (strcmp(defel->defname, "parallel") == 0)
+		{
+			int			val;
+			bool		parsed;
+			char	   *strval;
+
+			if (!cstate->is_copy_from)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("parallel option is supported only for copy from"),
+						 parser_errposition(pstate, defel->location)));
+			if (cstate->nworkers >= 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options"),
+						 parser_errposition(pstate, defel->location)));
+
+			strval = defGetString(defel);
+			parsed = parse_int(strval, &val, 0, NULL);
+			if (!parsed)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("invalid value for integer option \"%s\": %s",
+								defel->defname, strval)));
+			if (val < 1 || val > 1024)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("value %s out of bounds for option \"%s\"",
+								strval, defel->defname),
+						 errdetail("Valid values are between \"%d\" and \"%d\".",
+								   1, 1024)));
+			cstate->nworkers = val;
+		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_SYNTAX_ERROR),
@@ -1715,9 +1618,9 @@ BeginCopy(ParseState *pstate,
  * PopulateCommonCstateInfo
  *
  * Populates the common variables required for copy from operation. This is a
- * helper function for BeginCopy function.
+ * helper function for BeginCopy & InitializeParallelCopyInfo function.
  */
-static void
+void
 PopulateCommonCstateInfo(CopyState cstate, TupleDesc tupDesc, List *attnamelist)
 {
 	int			num_phys_attrs;
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index c639833..cd2d56e 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -14,14 +14,394 @@
 #ifndef COPY_H
 #define COPY_H
 
+#include "access/parallel.h"
+#include "commands/trigger.h"
+#include "executor/executor.h"
 #include "nodes/execnodes.h"
 #include "nodes/parsenodes.h"
 #include "parser/parse_node.h"
 #include "tcop/dest.h"
 
+#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+
+/*
+ * The macros DATA_BLOCK_SIZE, RINGSIZE & MAX_BLOCKS_COUNT stores the records
+ * read from the file that need to be inserted into the relation. These values
+ * help in the handover of multiple records with the significant size of data to
+ * be processed by each of the workers. This also ensures there is no context
+ * switch and the work is fairly distributed among the workers. This number
+ * showed best results in the performance tests.
+ */
+#define DATA_BLOCK_SIZE RAW_BUF_SIZE
+
+/* It can hold 1023 blocks of 64K data in DSM to be processed by the worker. */
+#define MAX_BLOCKS_COUNT 1024
+
+/*
+ * It can hold upto 10240 record information for worker to process. RINGSIZE
+ * should be a multiple of WORKER_CHUNK_COUNT, as wrap around cases is currently
+ * not handled while selecting the WORKER_CHUNK_COUNT by the worker.
+ */
+#define RINGSIZE (10 * 1024)
+
+/*
+ * Each worker will be allocated WORKER_CHUNK_COUNT of records from DSM data
+ * block to process to avoid lock contention. Read RINGSIZE comments before
+ * changing this value.
+ */
+#define WORKER_CHUNK_COUNT 64
+
+/*
+ * Represents the different source/dest cases we need to worry about at
+ * the bottom level
+ */
+typedef enum CopyDest
+{
+	COPY_FILE,					/* to/from file (or a piped program) */
+	COPY_OLD_FE,				/* to/from frontend (2.0 protocol) */
+	COPY_NEW_FE,				/* to/from frontend (3.0 protocol) */
+	COPY_CALLBACK				/* to/from callback function */
+} CopyDest;
+
+/*
+ *	Represents the end-of-line terminator type of the input
+ */
+typedef enum EolType
+{
+	EOL_UNKNOWN,
+	EOL_NL,
+	EOL_CR,
+	EOL_CRNL
+} EolType;
+
+/*
+ * Copy data block information.
+ *
+ * These data blocks are created in DSM. Data read from file will be copied in
+ * these DSM data blocks. The leader process identifies the records and the
+ * record information will be shared to the workers. The workers will insert the
+ * records into the table. There can be one or more number of records in each of
+ * the data block based on the record size.
+ */
+typedef struct ParallelCopyDataBlock
+{
+	/* The number of unprocessed lines in the current block. */
+	pg_atomic_uint32 unprocessed_line_parts;
+
+	/*
+	 * If the current line data is continued into another block,
+	 * following_block will have the position where the remaining data need to
+	 * be read.
+	 */
+	uint32		following_block;
+
+	/*
+	 * This flag will be set, when the leader finds out this block can be read
+	 * safely by the worker. This helps the worker to start processing the
+	 * line early where the line will be spread across many blocks and the
+	 * worker need not wait for the complete line to be processed.
+	 */
+	bool		curr_blk_completed;
+
+	/*
+	 * Few bytes need to be skipped from this block, this will be set when a
+	 * sequence of characters like \r\n is expected, but end of our block
+	 * contained only \r. In this case we copy the data from \r into the new
+	 * block as they have to be processed together to identify end of line.
+	 * Worker will use skip_bytes to know that this data must be skipped from
+	 * this data block.
+	 */
+	uint8		skip_bytes;
+	char		data[DATA_BLOCK_SIZE];	/* data read from file */
+} ParallelCopyDataBlock;
+
+/*
+ * Individual line information.
+ *
+ * ParallelCopyLineBoundary is common data structure between leader & worker.
+ * Leader process will be populating data block, data block offset & the size of
+ * the record in DSM for the workers to copy the data into the relation.
+ * The leader & worker process access the shared line information by following
+ * the below steps to avoid any data corruption or hang:
+ * Leader should operate in the following order:
+ * 1) check if line_size is -1, if line_size is not -1 wait until line_size is
+ * set to -1 by the worker. If line_size is -1 it means worker is still
+ * processing.
+ * 2) set line_state to LINE_LEADER_POPULATING, so that the worker knows that
+ * leader is populating this line.
+ * 3) update first_block, start_offset & cur_lineno in any order.
+ * 4) update line_size.
+ * 5) update line_state to LINE_LEADER_POPULATED.
+ * Worker should operate in the following order:
+ * 1) check line_state is LINE_LEADER_POPULATED, if not it means leader is still
+ * populating the data.
+ * 2) read line_size to know the size of the data.
+ * 3) only one worker should choose one line for processing, this is handled by
+ *    using pg_atomic_compare_exchange_u32, worker will change the state to
+ *    LINE_WORKER_PROCESSING only if line_state is LINE_LEADER_POPULATED.
+ * 4) read first_block, start_offset & cur_lineno in any order.
+ * 5) process line_size data.
+ * 6) update line_size to -1.
+ */
+typedef struct ParallelCopyLineBoundary
+{
+	/* Position of the first block in data_blocks array. */
+	uint32		first_block;
+	uint32		start_offset;	/* start offset of the line */
+
+	/*
+	 * Size of the current line -1 means line is yet to be filled completely,
+	 * 0 means empty line, >0 means line filled with line size data.
+	 */
+	pg_atomic_uint32 line_size;
+	pg_atomic_uint32 line_state;	/* line state */
+	uint64		cur_lineno;		/* line number for error messages */
+} ParallelCopyLineBoundary;
+
+/*
+ * Circular queue used to store the line information.
+ */
+typedef struct ParallelCopyLineBoundaries
+{
+	/* Position for the leader to populate a line. */
+	uint32		pos;
+
+	/* Data read from the file/stdin by the leader process. */
+	ParallelCopyLineBoundary ring[RINGSIZE];
+} ParallelCopyLineBoundaries;
+
+/*
+ * Shared information among parallel copy workers. This will be allocated in the
+ * DSM segment.
+ */
+typedef struct ParallelCopyShmInfo
+{
+	bool		is_read_in_progress;	/* file read status */
+
+	/*
+	 * Actual lines inserted by worker, will not be same as
+	 * total_worker_processed if where condition is specified along with copy.
+	 * This will be the actual records inserted into the relation.
+	 */
+	pg_atomic_uint64 processed;
+
+	/*
+	 * The number of records currently processed by the worker, this will also
+	 * include the number of records that was filtered because of where
+	 * clause.
+	 */
+	pg_atomic_uint64 total_worker_processed;
+	uint64		populated;		/* lines populated by leader */
+	uint32		cur_block_pos;	/* current data block */
+	ParallelCopyDataBlock data_blocks[MAX_BLOCKS_COUNT];	/* data block array */
+	FullTransactionId full_transaction_id;	/* xid for copy from statement */
+	CommandId	mycid;			/* command id */
+	ParallelCopyLineBoundaries line_boundaries; /* line array */
+} ParallelCopyShmInfo;
+
+/*
+ * Parallel copy line buffer information.
+ */
+typedef struct ParallelCopyLineBuf
+{
+	StringInfoData line_buf;
+	uint64		cur_lineno;		/* line number for error messages */
+} ParallelCopyLineBuf;
+
+/*
+ * This structure helps in storing the common data from CopyStateData that are
+ * required by the workers. This information will then be allocated and stored
+ * into the DSM for the worker to retrieve and copy it to CopyStateData.
+ */
+typedef struct SerializedParallelCopyState
+{
+	/* low-level state data */
+	CopyDest	copy_dest;		/* type of copy source/destination */
+	int			file_encoding;	/* file or remote side's character encoding */
+	bool		need_transcoding;	/* file encoding diff from server? */
+	bool		encoding_embeds_ascii;	/* ASCII can be non-first byte? */
+
+	/* parameters from the COPY command */
+	bool		csv_mode;		/* Comma Separated Value format? */
+	bool		header_line;	/* CSV header line? */
+	int			null_print_len; /* length of same */
+	bool		force_quote_all;	/* FORCE_QUOTE *? */
+	bool		convert_selectively;	/* do selective binary conversion? */
+
+	/* Working state for COPY FROM */
+	AttrNumber	num_defaults;
+	Oid			relid;
+} SerializedParallelCopyState;
+
+/*
+ * Parallel copy data information.
+ */
+typedef struct ParallelCopyData
+{
+	Oid			relid;			/* relation id of the table */
+	ParallelCopyShmInfo *pcshared_info; /* common info in shared memory */
+	bool		is_leader;
+
+	WalUsage   *walusage;
+	BufferUsage *bufferusage;
+
+	/* line position which worker is processing */
+	uint32		worker_processed_pos;
+
+	/*
+	 * Local line_buf array, workers will copy it here and release the lines
+	 * for the leader to continue.
+	 */
+	ParallelCopyLineBuf worker_line_buf[WORKER_CHUNK_COUNT];
+	uint32		worker_line_buf_count;	/* Number of lines */
+
+	/* Current position in worker_line_buf */
+	uint32		worker_line_buf_pos;
+} ParallelCopyData;
+
+typedef int (*copy_data_source_cb) (void *outbuf, int minread, int maxread);
+
+/*
+ * This struct contains all the state variables used throughout a COPY
+ * operation. For simplicity, we use the same struct for all variants of COPY,
+ * even though some fields are used in only some cases.
+ *
+ * Multi-byte encodings: all supported client-side encodings encode multi-byte
+ * characters by having the first byte's high bit set. Subsequent bytes of the
+ * character can have the high bit not set. When scanning data in such an
+ * encoding to look for a match to a single-byte (ie ASCII) character, we must
+ * use the full pg_encoding_mblen() machinery to skip over multibyte
+ * characters, else we might find a false match to a trailing byte. In
+ * supported server encodings, there is no possibility of a false match, and
+ * it's faster to make useless comparisons to trailing bytes than it is to
+ * invoke pg_encoding_mblen() to skip over them. encoding_embeds_ascii is true
+ * when we have to do it the hard way.
+ */
+typedef struct CopyStateData
+{
+	/* low-level state data */
+	CopyDest	copy_dest;		/* type of copy source/destination */
+	FILE	   *copy_file;		/* used if copy_dest == COPY_FILE */
+	StringInfo	fe_msgbuf;		/* used for all dests during COPY TO, only for
+								 * dest == COPY_NEW_FE in COPY FROM */
+	bool		is_copy_from;	/* COPY TO, or COPY FROM? */
+	bool		reached_eof;	/* true if we read to end of copy data (not
+								 * all copy_dest types maintain this) */
+	EolType		eol_type;		/* EOL type of input */
+	int			file_encoding;	/* file or remote side's character encoding */
+	bool		need_transcoding;	/* file encoding diff from server? */
+	bool		encoding_embeds_ascii;	/* ASCII can be non-first byte? */
+
+	/* parameters from the COPY command */
+	Relation	rel;			/* relation to copy to or from */
+	QueryDesc  *queryDesc;		/* executable query to copy from */
+	List	   *attnumlist;		/* integer list of attnums to copy */
+	char	   *filename;		/* filename, or NULL for STDIN/STDOUT */
+	bool		is_program;		/* is 'filename' a program to popen? */
+	copy_data_source_cb data_source_cb; /* function for reading data */
+	bool		binary;			/* binary format? */
+	bool		freeze;			/* freeze rows on loading? */
+	bool		csv_mode;		/* Comma Separated Value format? */
+	bool		header_line;	/* CSV header line? */
+	char	   *null_print;		/* NULL marker string (server encoding!) */
+	int			null_print_len; /* length of same */
+	char	   *null_print_client;	/* same converted to file encoding */
+	char	   *delim;			/* column delimiter (must be 1 byte) */
+	char	   *quote;			/* CSV quote char (must be 1 byte) */
+	char	   *escape;			/* CSV escape char (must be 1 byte) */
+	List	   *force_quote;	/* list of column names */
+	bool		force_quote_all;	/* FORCE_QUOTE *? */
+	bool	   *force_quote_flags;	/* per-column CSV FQ flags */
+	List	   *force_notnull;	/* list of column names */
+	bool	   *force_notnull_flags;	/* per-column CSV FNN flags */
+	List	   *force_null;		/* list of column names */
+	bool	   *force_null_flags;	/* per-column CSV FN flags */
+	bool		convert_selectively;	/* do selective binary conversion? */
+	List	   *convert_select; /* list of column names (can be NIL) */
+	bool	   *convert_select_flags;	/* per-column CSV/TEXT CS flags */
+	Node	   *whereClause;	/* WHERE condition (or NULL) */
+
+	/* these are just for error messages, see CopyFromErrorCallback */
+	const char *cur_relname;	/* table name for error messages */
+	uint64		cur_lineno;		/* line number for error messages */
+	const char *cur_attname;	/* current att for error messages */
+	const char *cur_attval;		/* current att value for error messages */
+
+	/*
+	 * Working state for COPY TO/FROM
+	 */
+	MemoryContext copycontext;	/* per-copy execution context */
+
+	/*
+	 * Working state for COPY TO
+	 */
+	FmgrInfo   *out_functions;	/* lookup info for output functions */
+	MemoryContext rowcontext;	/* per-row evaluation context */
+
+	/*
+	 * Working state for COPY FROM
+	 */
+	AttrNumber	num_defaults;
+	FmgrInfo   *in_functions;	/* array of input functions for each attrs */
+	Oid		   *typioparams;	/* array of element types for in_functions */
+	int		   *defmap;			/* array of default att numbers */
+	ExprState **defexprs;		/* array of default att expressions */
+	bool		volatile_defexprs;	/* is any of defexprs volatile? */
+	List	   *range_table;
+	ExprState  *qualexpr;
+
+	TransitionCaptureState *transition_capture;
+
+	/*
+	 * These variables are used to reduce overhead in COPY FROM.
+	 *
+	 * attribute_buf holds the separated, de-escaped text for each field of
+	 * the current line.  The CopyReadAttributes functions return arrays of
+	 * pointers into this buffer.  We avoid palloc/pfree overhead by re-using
+	 * the buffer on each cycle.
+	 *
+	 * In binary COPY FROM, attribute_buf holds the binary data for the
+	 * current field, but the usage is otherwise similar.
+	 */
+	StringInfoData attribute_buf;
+
+	/* field raw data pointers found by COPY FROM */
+
+	int			max_fields;
+	char	  **raw_fields;
+
+	/*
+	 * Similarly, line_buf holds the whole input line being processed. The
+	 * input cycle is first to read the whole line into line_buf, convert it
+	 * to server encoding there, and then extract the individual attribute
+	 * fields into attribute_buf.  line_buf is preserved unmodified so that we
+	 * can display it in error messages if appropriate.  (In binary mode,
+	 * line_buf is not used.)
+	 */
+	StringInfoData line_buf;
+	bool		line_buf_converted; /* converted to server encoding? */
+	bool		line_buf_valid; /* contains the row being processed? */
+
+	/*
+	 * Finally, raw_buf holds raw data read from the data source (file or
+	 * client connection).  In text mode, CopyReadLine parses this data
+	 * sufficiently to locate line boundaries, then transfers the data to
+	 * line_buf and converts it.  In binary mode, CopyReadBinaryData fetches
+	 * appropriate amounts of data from this buffer.  In both modes, we
+	 * guarantee that there is a \0 at raw_buf[raw_buf_len].
+	 */
+	char	   *raw_buf;
+	int			raw_buf_index;	/* next byte to process */
+	int			raw_buf_len;	/* total # of bytes stored */
+	int			nworkers;
+	bool		is_parallel;
+	ParallelCopyData *pcdata;
+	/* Shorthand for number of unconsumed bytes available in raw_buf */
+#define RAW_BUF_BYTES(cstate) ((cstate)->raw_buf_len - (cstate)->raw_buf_index)
+} CopyStateData;
+
 /* CopyStateData is private in commands/copy.c */
 typedef struct CopyStateData *CopyState;
-typedef int (*copy_data_source_cb) (void *outbuf, int minread, int maxread);
 
 extern void DoCopy(ParseState *state, const CopyStmt *stmt,
 				   int stmt_location, int stmt_len,
@@ -41,4 +421,11 @@ extern uint64 CopyFrom(CopyState cstate);
 
 extern DestReceiver *CreateCopyDestReceiver(void);
 
+extern void PopulateCommonCstateInfo(CopyState cstate, TupleDesc tup_desc,
+									 List *attnamelist);
+
+extern void ParallelCopyMain(dsm_segment *seg, shm_toc *toc);
+extern ParallelContext *BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid);
+extern void ParallelCopyFrom(CopyState cstate);
+extern void EndParallelCopy(ParallelContext *pcxt);
 #endif							/* COPY_H */
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 9cd1179..f5b818b 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1702,6 +1702,12 @@ ParallelBitmapHeapState
 ParallelBlockTableScanDesc
 ParallelCompletionPtr
 ParallelContext
+ParallelCopyLineBoundaries
+ParallelCopyLineBoundary
+ParallelCopyData
+ParallelCopyDataBlock
+ParallelCopyLineBuf
+ParallelCopyShmInfo
 ParallelExecutorInfo
 ParallelHashGrowth
 ParallelHashJoinBatch
@@ -2219,6 +2225,7 @@ SerCommitSeqNo
 SerialControl
 SerializableXactHandle
 SerializedActiveRelMaps
+SerializedParallelCopyState
 SerializedReindexState
 SerializedSnapshotData
 SerializedTransactionState
-- 
1.8.3.1

v6-0003-Allow-copy-from-command-to-process-data-from-file.patchapplication/x-patch; name=v6-0003-Allow-copy-from-command-to-process-data-from-file.patchDownload
From eb1a33276d1f907d14e7e1962b1cd254b81e1587 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 7 Oct 2020 17:24:44 +0530
Subject: [PATCH v6 3/6] Allow copy from command to process data from
 file/STDIN contents to a table in parallel.

This feature allows the copy from to leverage multiple CPUs in order to copy
data from file/STDIN to a table. This adds a PARALLEL option to COPY FROM
command where the user can specify the number of workers that can be used
to perform the COPY FROM command.
The backend, to which the "COPY FROM" query is submitted acts as leader with
the responsibility of reading data from the file/stdin, launching at most n
number of workers as specified with PARALLEL 'n' option in the "COPY FROM"
query. The leader populates the common data required for the workers execution
in the DSM and shares it with the workers. The leader then executes before
statement triggers if there exists any. Leader populates DSM lines which
includes the start offset and line size, while populating the lines it reads
as many blocks as required into the DSM data blocks from the file. Each block
is of 64K size. The leader parses the data to identify a line, the existing
logic from CopyReadLineText which identifies the lines with some changes was
used for this. Leader checks if a free line is available to copy the
information, if there is no free line it waits till the required line is
freed up by the worker and then copies the identified lines information
(offset & line size) into the DSM lines. This process is repeated till the
complete file is processed. Simultaneously, the workers cache the lines(50)
locally into the local memory and release the lines to the leader for further
populating. Each worker processes the lines that it cached and inserts it into
the table.
The leader does not participate in the insertion of data, leaders only
responsibility will be to identify the lines as fast as possible for the
workers to do the actual copy operation. The leader waits till all the lines
populated are processed by the workers and exits. We have chosen this design
based on the reason "that everything stalls if the leader doesn't accept further
input data, as well as when there are no available splitted chunks so it doesn't
seem like a good idea to have the leader do other work.  This is backed by the
performance data where we have seen that with 1 worker there is just a 5-10%
performance difference".
---
 src/backend/access/common/toast_internals.c |   12 +-
 src/backend/access/heap/heapam.c            |   11 -
 src/backend/access/transam/xact.c           |   15 +
 src/backend/commands/copy.c                 |  220 +++--
 src/backend/commands/copyparallel.c         | 1269 +++++++++++++++++++++++++++
 src/bin/psql/tab-complete.c                 |    2 +-
 src/include/access/xact.h                   |    1 +
 src/include/commands/copy.h                 |   69 +-
 src/tools/pgindent/typedefs.list            |    1 +
 9 files changed, 1514 insertions(+), 86 deletions(-)
 create mode 100644 src/backend/commands/copyparallel.c

diff --git a/src/backend/access/common/toast_internals.c b/src/backend/access/common/toast_internals.c
index 25a81e5..70c070e 100644
--- a/src/backend/access/common/toast_internals.c
+++ b/src/backend/access/common/toast_internals.c
@@ -17,6 +17,7 @@
 #include "access/genam.h"
 #include "access/heapam.h"
 #include "access/heaptoast.h"
+#include "access/parallel.h"
 #include "access/table.h"
 #include "access/toast_internals.h"
 #include "access/xact.h"
@@ -116,7 +117,16 @@ toast_save_datum(Relation rel, Datum value,
 	TupleDesc	toasttupDesc;
 	Datum		t_values[3];
 	bool		t_isnull[3];
-	CommandId	mycid = GetCurrentCommandId(true);
+
+	/*
+	 * Parallel copy can insert toast tuples, in case of parallel copy the
+	 * command would have been set already by calling
+	 * AssignCommandIdForWorker. For parallel copy call GetCurrentCommandId to
+	 * get currentCommandId by passing used as false, as this is taken care
+	 * earlier.
+	 */
+	CommandId	mycid = IsParallelWorker() ? GetCurrentCommandId(false) :
+	GetCurrentCommandId(true);
 	struct varlena *result;
 	struct varatt_external toast_pointer;
 	union
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 1585861..1602525 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2043,17 +2043,6 @@ static HeapTuple
 heap_prepare_insert(Relation relation, HeapTuple tup, TransactionId xid,
 					CommandId cid, int options)
 {
-	/*
-	 * To allow parallel inserts, we need to ensure that they are safe to be
-	 * performed in workers. We have the infrastructure to allow parallel
-	 * inserts in general except for the cases where inserts generate a new
-	 * CommandId (eg. inserts into a table having a foreign key column).
-	 */
-	if (IsParallelWorker())
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_TRANSACTION_STATE),
-				 errmsg("cannot insert tuples in a parallel worker")));
-
 	tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
 	tup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK);
 	tup->t_data->t_infomask |= HEAP_XMAX_INVALID;
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index af6afce..0b3337c 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -776,6 +776,21 @@ GetCurrentCommandId(bool used)
 }
 
 /*
+ *	SetCurrentCommandIdUsedForWorker
+ *
+ * For a parallel worker, record that the currentCommandId has been used.
+ * This must only be called at the start of a parallel operation.
+ */
+void
+SetCurrentCommandIdUsedForWorker(void)
+{
+	Assert(IsParallelWorker() && !currentCommandIdUsed &&
+		   (currentCommandId != InvalidCommandId));
+
+	currentCommandIdUsed = true;
+}
+
+/*
  *	SetParallelStartTimestamps
  *
  * In a parallel worker, we should inherit the parent transaction's
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 1e55a30..dc006a5 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -61,20 +61,6 @@
 #define ISOCTAL(c) (((c) >= '0') && ((c) <= '7'))
 #define OCTVALUE(c) ((c) - '0')
 
-/*
- * Represents the heap insert method to be used during COPY FROM.
- */
-typedef enum CopyInsertMethod
-{
-	CIM_SINGLE,					/* use table_tuple_insert or fdw routine */
-	CIM_MULTI,					/* always use table_multi_insert */
-	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
-} CopyInsertMethod;
-
-#define IsParallelCopy()		(cstate->is_parallel)
-#define IsLeader()				(cstate->pcdata->is_leader)
-#define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
-
 /* DestReceiver for COPY (query) TO */
 typedef struct
 {
@@ -131,7 +117,6 @@ typedef struct CopyMultiInsertInfo
 	int			ti_options;		/* table insert options */
 } CopyMultiInsertInfo;
 
-
 /*
  * These macros centralize code used to process line_buf and raw_buf buffers.
  * They are macros because they often do continue/break control and to avoid
@@ -182,9 +167,13 @@ if (1) \
 { \
 	if (raw_buf_ptr > cstate->raw_buf_index) \
 	{ \
-		appendBinaryStringInfo(&cstate->line_buf, \
-							 cstate->raw_buf + cstate->raw_buf_index, \
-							   raw_buf_ptr - cstate->raw_buf_index); \
+		if (!IsParallelCopy()) \
+			appendBinaryStringInfo(&cstate->line_buf, \
+								   cstate->raw_buf + cstate->raw_buf_index, \
+								   raw_buf_ptr - cstate->raw_buf_index); \
+		else \
+			line_size +=  raw_buf_ptr - cstate->raw_buf_index; \
+		\
 		cstate->raw_buf_index = raw_buf_ptr; \
 	} \
 } else ((void) 0)
@@ -197,18 +186,6 @@ if (1) \
 	goto not_end_of_copy; \
 } else ((void) 0)
 
-/*
- * Increment the lines processed.
- */
-#define INCREMENTPROCESSED(processed)  \
-processed++;
-
-/*
- * Get the lines processed.
- */
-#define RETURNPROCESSED(processed) \
-return processed;
-
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
 
@@ -225,7 +202,6 @@ static void EndCopyTo(CopyState cstate);
 static uint64 DoCopyTo(CopyState cstate);
 static uint64 CopyTo(CopyState cstate);
 static void CopyOneRowTo(CopyState cstate, TupleTableSlot *slot);
-static bool CopyReadLine(CopyState cstate);
 static bool CopyReadLineText(CopyState cstate);
 static int	CopyReadAttributesText(CopyState cstate);
 static int	CopyReadAttributesCSV(CopyState cstate);
@@ -258,7 +234,6 @@ static int	CopyReadBinaryData(CopyState cstate, char *dest, int nbytes);
 
 static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
 								   int copy_line_pos, int *copy_line_size);
-static void ConvertToServerEncoding(CopyState cstate);
 
 
 /*
@@ -2639,7 +2614,7 @@ CopyMultiInsertInfoStore(CopyMultiInsertInfo *miinfo, ResultRelInfo *rri,
  *
  * Check if the relation specified in copy from is valid.
  */
-static void
+void
 CheckTargetRelValidity(CopyState cstate)
 {
 	Assert(cstate->rel);
@@ -2735,7 +2710,7 @@ CopyFrom(CopyState cstate)
 
 	PartitionTupleRouting *proute = NULL;
 	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
+	CommandId	mycid;
 	int			ti_options = 0; /* start with default options for insert */
 	BulkInsertState bistate = NULL;
 	CopyInsertMethod insertMethod;
@@ -2745,7 +2720,18 @@ CopyFrom(CopyState cstate)
 	bool		has_instead_insert_row_trig;
 	bool		leafpart_use_multi_insert = false;
 
-	CheckTargetRelValidity(cstate);
+	/*
+	 * Perform this check if it is not parallel copy. In case of parallel
+	 * copy, this check is done by the leader, so that if any invalid case
+	 * exist the copy from command will error out from the leader itself,
+	 * avoiding launching workers, just to throw error.
+	 */
+	if (!IsParallelCopy())
+		CheckTargetRelValidity(cstate);
+	else
+		SetCurrentCommandIdUsedForWorker();
+
+	mycid = GetCurrentCommandId(!IsParallelCopy());
 
 	/*
 	 * If the target file is new-in-transaction, we assume that checking FSM
@@ -2785,7 +2771,8 @@ CopyFrom(CopyState cstate)
 	target_resultRelInfo = resultRelInfo;
 
 	/* Verify the named relation is a valid target for INSERT */
-	CheckValidResultRel(resultRelInfo, CMD_INSERT);
+	if (!IsParallelCopy())
+		CheckValidResultRel(resultRelInfo, CMD_INSERT);
 
 	ExecOpenIndices(resultRelInfo, false);
 
@@ -2934,13 +2921,17 @@ CopyFrom(CopyState cstate)
 	has_instead_insert_row_trig = (resultRelInfo->ri_TrigDesc &&
 								   resultRelInfo->ri_TrigDesc->trig_insert_instead_row);
 
-	/*
-	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
-	 * should do this for COPY, since it's not really an "INSERT" statement as
-	 * such. However, executing these triggers maintains consistency with the
-	 * EACH ROW triggers that we already fire on COPY.
-	 */
-	ExecBSInsertTriggers(estate, resultRelInfo);
+	if (!IsParallelCopy())
+	{
+		/*
+		 * Check BEFORE STATEMENT insertion triggers. It's debatable whether
+		 * we should do this for COPY, since it's not really an "INSERT"
+		 * statement as such. However, executing these triggers maintains
+		 * consistency with the EACH ROW triggers that we already fire on
+		 * COPY.
+		 */
+		ExecBSInsertTriggers(estate, resultRelInfo);
+	}
 
 	econtext = GetPerTupleExprContext(estate);
 
@@ -3040,6 +3031,29 @@ CopyFrom(CopyState cstate)
 					!has_instead_insert_row_trig &&
 					resultRelInfo->ri_FdwRoutine == NULL;
 
+				/*
+				 * We may still be able to perform parallel inserts for
+				 * partitioned tables. However, the possibility of this
+				 * depends on which types of triggers exist on the partition.
+				 * We must not do parallel inserts if the partition is a
+				 * foreign table or it has any BEFORE/INSTEAD OF row triggers.
+				 * Since the partition's resultRelInfo are initialized only
+				 * when we actually insert the first tuple into them, we may
+				 * not know this info easily in the leader while deciding for
+				 * the parallelism. We would have gone ahead and allowed
+				 * parallelism. Now it's the time to throw an error and also
+				 * provide a hint to the user to not use parallelism. Throwing
+				 * an error seemed a simple approach than to look for all the
+				 * partitions in the leader while deciding for the
+				 * parallelism. Note that this error is thrown early, exactly
+				 * on the first tuple being inserted into the partition, so
+				 * not much work, that has been done so far, is wasted.
+				 */
+				if (!leafpart_use_multi_insert && IsParallelWorker())
+					ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+									errmsg("cannot perform PARALLEL COPY if partition has BEFORE/INSTEAD OF triggers, or if the partition is foreign partition"),
+									errhint("Try COPY without PARALLEL option")));
+
 				/* Set the multi-insert buffer to use for this partition. */
 				if (leafpart_use_multi_insert)
 				{
@@ -3325,7 +3339,7 @@ CopyFrom(CopyState cstate)
  *
  * Populate the cstate catalog information.
  */
-static void
+void
 PopulateCstateCatalogInfo(CopyState cstate)
 {
 	TupleDesc	tupDesc;
@@ -3607,26 +3621,35 @@ NextCopyFromRawFields(CopyState cstate, char ***fields, int *nfields)
 	/* only available for text or csv input */
 	Assert(!cstate->binary);
 
-	/* on input just throw the header line away */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (IsParallelCopy())
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
-			return false;		/* done */
+		done = GetWorkerLine(cstate);
+		if (done && cstate->line_buf.len == 0)
+			return false;
 	}
+	else
+	{
+		/* on input just throw the header line away */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
+		{
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+				return false;	/* done */
+		}
 
-	cstate->cur_lineno++;
+		cstate->cur_lineno++;
 
-	/* Actually read the line into memory here */
-	done = CopyReadLine(cstate);
+		/* Actually read the line into memory here */
+		done = CopyReadLine(cstate);
 
-	/*
-	 * EOF at start of line means we're done.  If we see EOF after some
-	 * characters, we act as though it was newline followed by EOF, ie,
-	 * process the line and then exit loop on next iteration.
-	 */
-	if (done && cstate->line_buf.len == 0)
-		return false;
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			return false;
+	}
 
 	/* Parse the line into de-escaped field values */
 	if (cstate->csv_mode)
@@ -3851,7 +3874,7 @@ EndCopyFrom(CopyState cstate)
  * by newline.  The terminating newline or EOF marker is not included
  * in the final value of line_buf.
  */
-static bool
+bool
 CopyReadLine(CopyState cstate)
 {
 	bool		result;
@@ -3874,9 +3897,34 @@ CopyReadLine(CopyState cstate)
 		 */
 		if (cstate->copy_dest == COPY_NEW_FE)
 		{
+			bool		bIsFirst = true;
+
 			do
 			{
-				cstate->raw_buf_index = cstate->raw_buf_len;
+				if (!IsParallelCopy())
+					cstate->raw_buf_index = cstate->raw_buf_len;
+				else
+				{
+					if (cstate->raw_buf_index == RAW_BUF_SIZE)
+					{
+						/*
+						 * Get a new block if it is the first time, From the
+						 * subsequent time, reset the index and re-use the
+						 * same block.
+						 */
+						if (bIsFirst)
+						{
+							ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+							uint32		block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+							cstate->raw_buf = pcshared_info->data_blocks[block_pos].data;
+							bIsFirst = false;
+						}
+
+						cstate->raw_buf_index = cstate->raw_buf_len = 0;
+					}
+				}
+
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
@@ -3931,11 +3979,11 @@ ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
  *
  * Convert contents to server encoding.
  */
-static void
+void
 ConvertToServerEncoding(CopyState cstate)
 {
 	/* Done reading the line.  Convert it to server encoding. */
-	if (cstate->need_transcoding)
+	if (cstate->need_transcoding && (!IsParallelCopy() || IsWorker()))
 	{
 		char	   *cvt;
 
@@ -3975,6 +4023,11 @@ CopyReadLineText(CopyState cstate)
 	char		quotec = '\0';
 	char		escapec = '\0';
 
+	/* For parallel copy */
+	int			line_size = 0;
+	uint32		line_pos = 0;
+
+	cstate->eol_type = EOL_UNKNOWN;
 	if (cstate->csv_mode)
 	{
 		quotec = cstate->quote[0];
@@ -4029,6 +4082,8 @@ CopyReadLineText(CopyState cstate)
 		if (raw_buf_ptr >= copy_buf_len || need_data)
 		{
 			REFILL_LINEBUF;
+			SetRawBufForLoad(cstate, line_size, copy_buf_len, raw_buf_ptr,
+							 &copy_raw_buf);
 
 			/*
 			 * Try to read some more data.  This will certainly reset
@@ -4253,9 +4308,15 @@ CopyReadLineText(CopyState cstate)
 				 * discard the data and the \. sequence.
 				 */
 				if (prev_raw_ptr > cstate->raw_buf_index)
-					appendBinaryStringInfo(&cstate->line_buf,
-										   cstate->raw_buf + cstate->raw_buf_index,
-										   prev_raw_ptr - cstate->raw_buf_index);
+				{
+					if (!IsParallelCopy())
+						appendBinaryStringInfo(&cstate->line_buf,
+											   cstate->raw_buf + cstate->raw_buf_index,
+											   prev_raw_ptr - cstate->raw_buf_index);
+					else
+						line_size += prev_raw_ptr - cstate->raw_buf_index;
+				}
+
 				cstate->raw_buf_index = raw_buf_ptr;
 				result = true;	/* report EOF */
 				break;
@@ -4307,6 +4368,22 @@ not_end_of_copy:
 			IF_NEED_REFILL_AND_EOF_BREAK(mblen - 1);
 			raw_buf_ptr += mblen - 1;
 		}
+
+		/*
+		 * Skip the header line. Update the line here, this cannot be done at
+		 * the beginning, as there is a possibility that file contains empty
+		 * lines.
+		 */
+		if (IsParallelCopy() && first_char_in_line && !IsHeaderLine())
+		{
+			ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+			line_pos = UpdateSharedLineInfo(cstate,
+											pcshared_info->cur_block_pos,
+											cstate->raw_buf_index, -1,
+											LINE_LEADER_POPULATING, -1);
+		}
+
 		first_char_in_line = false;
 	}							/* end of outer loop */
 
@@ -4315,9 +4392,16 @@ not_end_of_copy:
 	 */
 	REFILL_LINEBUF;
 	if (!result && !IsHeaderLine())
-		ClearEOLFromCopiedData(cstate, cstate->line_buf.data,
-							   cstate->line_buf.len, &cstate->line_buf.len);
+	{
+		if (IsParallelCopy())
+			ClearEOLFromCopiedData(cstate, cstate->raw_buf, raw_buf_ptr,
+								   &line_size);
+		else
+			ClearEOLFromCopiedData(cstate, cstate->line_buf.data,
+								   cstate->line_buf.len, &cstate->line_buf.len);
+	}
 
+	EndLineParallelCopy(cstate, line_pos, line_size, raw_buf_ptr);
 	return result;
 }
 
diff --git a/src/backend/commands/copyparallel.c b/src/backend/commands/copyparallel.c
new file mode 100644
index 0000000..6a44a01
--- /dev/null
+++ b/src/backend/commands/copyparallel.c
@@ -0,0 +1,1269 @@
+/*-------------------------------------------------------------------------
+ *
+ * copyparallel.c
+ *              Implements the Parallel COPY utility command
+ *
+ * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *        src/backend/commands/copyparallel.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/heapam.h"
+#include "catalog/pg_proc_d.h"
+#include "commands/copy.h"
+#include "optimizer/clauses.h"
+#include "optimizer/optimizer.h"
+#include "pgstat.h"
+#include "utils/lsyscache.h"
+
+/* DSM keys for parallel copy.  */
+#define PARALLEL_COPY_KEY_SHARED_INFO				1
+#define PARALLEL_COPY_KEY_CSTATE					2
+#define PARALLEL_COPY_WAL_USAGE						3
+#define PARALLEL_COPY_BUFFER_USAGE					4
+
+/* Begin parallel copy Macros */
+#define SET_NEWLINE_SIZE() \
+{ \
+	if (cstate->eol_type == EOL_NL || cstate->eol_type == EOL_CR) \
+		new_line_size = 1; \
+	else if (cstate->eol_type == EOL_CRNL) \
+		new_line_size = 2; \
+	else \
+		new_line_size = 0; \
+}
+
+/*
+ * COPY_WAIT_TO_PROCESS - Wait before continuing to process.
+ */
+#define COPY_WAIT_TO_PROCESS() \
+{ \
+	CHECK_FOR_INTERRUPTS(); \
+	(void) WaitLatch(MyLatch, \
+					 WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH, \
+					 1L, WAIT_EVENT_PG_SLEEP); \
+	ResetLatch(MyLatch); \
+}
+
+/*
+ * CopyStringToSharedMemory - Copy the string to shared memory.
+ */
+static void
+CopyStringToSharedMemory(CopyState cstate, char *srcPtr, char *destptr,
+						 uint32 *copiedsize)
+{
+	uint32		len = srcPtr ? strlen(srcPtr) + 1 : 0;
+
+	memcpy(destptr, (uint16 *) &len, sizeof(uint16));
+	*copiedsize += sizeof(uint16);
+	if (len)
+	{
+		memcpy(destptr + sizeof(uint16), srcPtr, len);
+		*copiedsize += len;
+	}
+}
+
+/*
+ * SerializeParallelCopyState - Serialize the data into shared memory.
+ */
+static void
+SerializeParallelCopyState(ParallelContext *pcxt, CopyState cstate,
+						   uint32 estimatedSize, char *whereClauseStr,
+						   char *rangeTableStr, char *attnameListStr,
+						   char *notnullListStr, char *nullListStr,
+						   char *convertListStr)
+{
+	SerializedParallelCopyState shared_cstate;
+	char	   *shmptr = (char *) shm_toc_allocate(pcxt->toc, estimatedSize + 1);
+	uint32		copiedsize = 0;
+
+	shared_cstate.copy_dest = cstate->copy_dest;
+	shared_cstate.file_encoding = cstate->file_encoding;
+	shared_cstate.need_transcoding = cstate->need_transcoding;
+	shared_cstate.encoding_embeds_ascii = cstate->encoding_embeds_ascii;
+	shared_cstate.csv_mode = cstate->csv_mode;
+	shared_cstate.header_line = cstate->header_line;
+	shared_cstate.null_print_len = cstate->null_print_len;
+	shared_cstate.force_quote_all = cstate->force_quote_all;
+	shared_cstate.convert_selectively = cstate->convert_selectively;
+	shared_cstate.num_defaults = cstate->num_defaults;
+	shared_cstate.relid = cstate->pcdata->relid;
+
+	memcpy(shmptr, (char *) &shared_cstate, sizeof(SerializedParallelCopyState));
+	copiedsize = sizeof(SerializedParallelCopyState);
+
+	CopyStringToSharedMemory(cstate, cstate->null_print, shmptr + copiedsize,
+							 &copiedsize);
+	CopyStringToSharedMemory(cstate, cstate->delim, shmptr + copiedsize,
+							 &copiedsize);
+	CopyStringToSharedMemory(cstate, cstate->quote, shmptr + copiedsize,
+							 &copiedsize);
+	CopyStringToSharedMemory(cstate, cstate->escape, shmptr + copiedsize,
+							 &copiedsize);
+	CopyStringToSharedMemory(cstate, attnameListStr, shmptr + copiedsize,
+							 &copiedsize);
+	CopyStringToSharedMemory(cstate, notnullListStr, shmptr + copiedsize,
+							 &copiedsize);
+	CopyStringToSharedMemory(cstate, nullListStr, shmptr + copiedsize,
+							 &copiedsize);
+	CopyStringToSharedMemory(cstate, convertListStr, shmptr + copiedsize,
+							 &copiedsize);
+	CopyStringToSharedMemory(cstate, whereClauseStr, shmptr + copiedsize,
+							 &copiedsize);
+	CopyStringToSharedMemory(cstate, rangeTableStr, shmptr + copiedsize,
+							 &copiedsize);
+
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_CSTATE, shmptr);
+}
+
+/*
+ * CopyNodeFromSharedMemory - Copy the shared memory & return the ptr.
+ */
+static char *
+CopyStringFromSharedMemory(char *srcPtr, uint32 *copiedsize)
+{
+	char	   *destptr = NULL;
+	uint16		len = 0;
+
+	memcpy((uint16 *) (&len), srcPtr, sizeof(uint16));
+	*copiedsize += sizeof(uint16);
+	if (len)
+	{
+		destptr = (char *) palloc0(len);
+		memcpy(destptr, srcPtr + sizeof(uint16), len);
+		*copiedsize += len;
+	}
+
+	return destptr;
+}
+
+/*
+ * CopyNodeFromSharedMemory - Copy the shared memory & convert it into node
+ * type.
+ */
+static void *
+CopyNodeFromSharedMemory(char *srcPtr, uint32 *copiedsize)
+{
+	char	   *destptr = NULL;
+	List	   *destList = NIL;
+	uint16		len = 0;
+
+	memcpy((uint16 *) (&len), srcPtr, sizeof(uint16));
+	*copiedsize += sizeof(uint16);
+	if (len)
+	{
+		destptr = (char *) palloc0(len);
+		memcpy(destptr, srcPtr + sizeof(uint16), len);
+		*copiedsize += len;
+		destList = (List *) stringToNode(destptr);
+		pfree(destptr);
+	}
+
+	return destList;
+}
+
+/*
+ * RestoreParallelCopyState - Retrieve the cstate from shared memory.
+ */
+static void
+RestoreParallelCopyState(shm_toc *toc, CopyState cstate, List **attlist)
+{
+	char	   *shared_str_val = (char *) shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE, true);
+	SerializedParallelCopyState shared_cstate = {0};
+	uint32		copiedsize = 0;
+
+	memcpy(&shared_cstate, (char *) shared_str_val, sizeof(SerializedParallelCopyState));
+	copiedsize = sizeof(SerializedParallelCopyState);
+
+	cstate->file_encoding = shared_cstate.file_encoding;
+	cstate->need_transcoding = shared_cstate.need_transcoding;
+	cstate->encoding_embeds_ascii = shared_cstate.encoding_embeds_ascii;
+	cstate->csv_mode = shared_cstate.csv_mode;
+	cstate->header_line = shared_cstate.header_line;
+	cstate->null_print_len = shared_cstate.null_print_len;
+	cstate->force_quote_all = shared_cstate.force_quote_all;
+	cstate->convert_selectively = shared_cstate.convert_selectively;
+	cstate->num_defaults = shared_cstate.num_defaults;
+	cstate->pcdata->relid = shared_cstate.relid;
+
+	cstate->null_print = CopyStringFromSharedMemory(shared_str_val + copiedsize,
+													&copiedsize);
+	cstate->delim = CopyStringFromSharedMemory(shared_str_val + copiedsize,
+											   &copiedsize);
+	cstate->quote = CopyStringFromSharedMemory(shared_str_val + copiedsize,
+											   &copiedsize);
+	cstate->escape = CopyStringFromSharedMemory(shared_str_val + copiedsize,
+												&copiedsize);
+
+	*attlist = (List *) CopyNodeFromSharedMemory(shared_str_val + copiedsize,
+												 &copiedsize);
+	cstate->force_notnull = (List *) CopyNodeFromSharedMemory(shared_str_val + copiedsize,
+															  &copiedsize);
+	cstate->force_null = (List *) CopyNodeFromSharedMemory(shared_str_val + copiedsize,
+														   &copiedsize);
+	cstate->convert_select = (List *) CopyNodeFromSharedMemory(shared_str_val + copiedsize,
+															   &copiedsize);
+	cstate->whereClause = (Node *) CopyNodeFromSharedMemory(shared_str_val + copiedsize,
+															&copiedsize);
+	cstate->range_table = (List *) CopyNodeFromSharedMemory(shared_str_val + copiedsize,
+															&copiedsize);
+}
+
+/*
+ * EstimateStringSize - Estimate the size required for the string in shared
+ * memory.
+ */
+static uint32
+EstimateStringSize(char *str)
+{
+	uint32		strsize = sizeof(uint16);
+
+	if (str)
+		strsize += strlen(str) + 1;
+
+	return strsize;
+}
+
+/*
+ * EstimateNodeSize - Convert the list to string & estimate the size required
+ * in shared memory.
+ */
+static uint32
+EstimateNodeSize(void *list, char **listStr)
+{
+	uint32		strsize = sizeof(uint16);
+
+	if (list != NIL)
+	{
+		*listStr = nodeToString(list);
+		strsize += strlen(*listStr) + 1;
+	}
+
+	return strsize;
+}
+
+/*
+ * EstimateCstateSize - Estimate the size required in shared memory for cstate
+ * variables.
+ */
+static uint32
+EstimateCstateSize(ParallelContext *pcxt, CopyState cstate, List *attnamelist,
+				   char **whereClauseStr, char **rangeTableStr,
+				   char **attnameListStr, char **notnullListStr,
+				   char **nullListStr, char **convertListStr)
+{
+	uint32		strsize = MAXALIGN(sizeof(SerializedParallelCopyState));
+
+	strsize += EstimateStringSize(cstate->null_print);
+	strsize += EstimateStringSize(cstate->delim);
+	strsize += EstimateStringSize(cstate->quote);
+	strsize += EstimateStringSize(cstate->escape);
+	strsize += EstimateNodeSize(attnamelist, attnameListStr);
+	strsize += EstimateNodeSize(cstate->force_notnull, notnullListStr);
+	strsize += EstimateNodeSize(cstate->force_null, nullListStr);
+	strsize += EstimateNodeSize(cstate->convert_select, convertListStr);
+	strsize += EstimateNodeSize(cstate->whereClause, whereClauseStr);
+	strsize += EstimateNodeSize(cstate->range_table, rangeTableStr);
+
+	strsize++;
+	shm_toc_estimate_chunk(&pcxt->estimator, strsize);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+	return strsize;
+}
+
+/*
+ * PopulateParallelCopyShmInfo - Set ParallelCopyShmInfo.
+ */
+static void
+PopulateParallelCopyShmInfo(ParallelCopyShmInfo *shared_info_ptr)
+{
+	uint32		count;
+
+	MemSet(shared_info_ptr, 0, sizeof(ParallelCopyShmInfo));
+	shared_info_ptr->is_read_in_progress = true;
+	shared_info_ptr->cur_block_pos = -1;
+	for (count = 0; count < RINGSIZE; count++)
+	{
+		ParallelCopyLineBoundary *lineInfo = &shared_info_ptr->line_boundaries.ring[count];
+
+		pg_atomic_init_u32(&(lineInfo->line_size), -1);
+	}
+}
+
+/*
+ * CheckTrigFunParallelSafety - For all triggers, check if the associated
+ * trigger functions are parallel safe. If at least one trigger function is
+ * parallel unsafe, we do not allow parallelism.
+ */
+static pg_attribute_always_inline bool
+CheckTrigFunParallelSafety(TriggerDesc *trigdesc)
+{
+	int			i;
+
+	for (i = 0; i < trigdesc->numtriggers; i++)
+	{
+		Trigger    *trigger = &trigdesc->triggers[i];
+		int			trigtype = RI_TRIGGER_NONE;
+
+		if (func_parallel(trigger->tgfoid) != PROPARALLEL_SAFE)
+			return false;
+
+		/* If the trigger is parallel safe, also look for RI_TRIGGER. */
+		trigtype = RI_FKey_trigger_type(trigger->tgfoid);
+
+		/*
+		 * No parallelism if foreign key check trigger is present. This is
+		 * because, while performing foreign key checks, we take KEY SHARE
+		 * lock on primary key table rows which inturn will increment the
+		 * command counter and updates the snapshot.  Since we share the
+		 * snapshots at the beginning of the command, we can't allow it to be
+		 * changed later. So, unless we do something special for it, we can't
+		 * allow parallelism in such cases.
+		 */
+		if (trigtype == RI_TRIGGER_FK)
+			return false;
+	}
+
+	return true;
+}
+
+/*
+ * CheckExprParallelSafety - Determine parallel safety of volatile expressions
+ * in default clause of column definition or in where clause and return true if
+ * they are parallel safe.
+ */
+static pg_attribute_always_inline bool
+CheckExprParallelSafety(CopyState cstate)
+{
+	if (contain_volatile_functions(cstate->whereClause))
+	{
+		if (max_parallel_hazard((Query *) cstate->whereClause) != PROPARALLEL_SAFE)
+			return false;
+	}
+
+	/*
+	 * Check if any of the column has volatile default expression. if yes, and
+	 * they are not parallel safe, then parallelism is not allowed. For
+	 * instance, if there are any serial/bigserial columns for which nextval()
+	 * default expression which is parallel unsafe is associated, parallelism
+	 * should not be allowed.
+	 */
+	if (cstate->defexprs != NULL && cstate->num_defaults != 0)
+	{
+		int			i;
+
+		for (i = 0; i < cstate->num_defaults; i++)
+		{
+			bool		volatile_expr = contain_volatile_functions((Node *) cstate->defexprs[i]->expr);
+
+			if (volatile_expr &&
+				(max_parallel_hazard((Query *) cstate->defexprs[i]->expr)) !=
+				PROPARALLEL_SAFE)
+				return false;
+		}
+	}
+
+	return true;
+}
+
+/*
+ * IsParallelCopyAllowed - Check for the cases where parallel copy is not
+ * applicable.
+ */
+static pg_attribute_always_inline bool
+IsParallelCopyAllowed(CopyState cstate)
+{
+	/* Parallel copy not allowed for frontend (2.0 protocol) & binary option. */
+	if ((cstate->copy_dest == COPY_OLD_FE) || cstate->binary)
+		return false;
+
+	/*
+	 * Check if copy is into foreign table. We can not allow parallelism in
+	 * this case because each worker needs to establish FDW connection and
+	 * operate in a separate transaction. Unless we have a capability to
+	 * provide two-phase commit protocol, we can not allow parallelism.
+	 *
+	 * Also check if copy is into temporary table. Since parallel workers can
+	 * not access temporary table, parallelism is not allowed.
+	 */
+	if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
+		RelationUsesLocalBuffers(cstate->rel))
+		return false;
+
+	/*
+	 * If there are volatile default expressions or where clause contain
+	 * volatile expressions, allow parallelism if they are parallel safe,
+	 * otherwise not.
+	 */
+	if (!CheckExprParallelSafety(cstate))
+		return false;
+
+	/* Check parallel safety of the trigger functions. */
+	if (cstate->rel->trigdesc != NULL &&
+		!CheckTrigFunParallelSafety(cstate->rel->trigdesc))
+		return false;
+
+	/*
+	 * When transition tables are involved (if after statement triggers are
+	 * present), we collect minimal tuples in the tuple store after processing
+	 * them so that later after statement triggers can access them.  Now, if
+	 * we want to enable parallelism for such cases, we instead need to store
+	 * and access tuples from shared tuple store.  However, it does not have
+	 * the facility to store tuples in-memory, so we always need to store and
+	 * access from a file which could be costly unless we also have an
+	 * additional way to store minimal tuples in shared memory till work_mem
+	 * and then in shared tuple store. It is possible to do all this to enable
+	 * parallel copy for such cases. Currently, we can disallow parallelism
+	 * for such cases and later allow if required.
+	 *
+	 * When there are BEFORE/AFTER/INSTEAD OF row triggers on the table. We do
+	 * not allow parallelism in such cases because such triggers might query
+	 * the table we are inserting into and act differently if the tuples that
+	 * have already been processed and prepared for insertion are not there.
+	 * Now, if we allow parallelism with such triggers the behaviour would
+	 * depend on if the parallel worker has already inserted or not that
+	 * particular tuples.
+	 */
+	if (cstate->rel->trigdesc != NULL &&
+		(cstate->rel->trigdesc->trig_insert_after_statement ||
+		 cstate->rel->trigdesc->trig_insert_new_table ||
+		 cstate->rel->trigdesc->trig_insert_before_row ||
+		 cstate->rel->trigdesc->trig_insert_after_row ||
+		 cstate->rel->trigdesc->trig_insert_instead_row))
+		return false;
+
+	return true;
+}
+
+/*
+ * BeginParallelCopy - Start parallel copy tasks.
+ *
+ * Get the number of workers required to perform the parallel copy. The data
+ * structures that are required by the parallel workers will be initialized, the
+ * size required in DSM will be calculated and the necessary keys will be loaded
+ * in the DSM. The specified number of workers will then be launched.
+ */
+ParallelContext *
+BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
+{
+	ParallelContext *pcxt;
+	ParallelCopyShmInfo *shared_info_ptr;
+	Size		est_cstateshared;
+	char	   *whereClauseStr = NULL;
+	char	   *rangeTableStr = NULL;
+	char	   *attnameListStr = NULL;
+	char	   *notnullListStr = NULL;
+	char	   *nullListStr = NULL;
+	char	   *convertListStr = NULL;
+	int			parallel_workers = 0;
+	WalUsage   *walusage;
+	BufferUsage *bufferusage;
+	ParallelCopyData *pcdata;
+	MemoryContext oldcontext;
+	uint32		strsize;
+
+	CheckTargetRelValidity(cstate);
+	parallel_workers = Min(nworkers, max_worker_processes);
+
+	/* Can't perform copy in parallel */
+	if (parallel_workers <= 0)
+		return NULL;
+
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	MemoryContextSwitchTo(oldcontext);
+	cstate->pcdata = pcdata;
+
+	/*
+	 * User chosen parallel copy. Determine if the parallel copy is actually
+	 * allowed. If not, go with the non-parallel mode.
+	 */
+	if (!IsParallelCopyAllowed(cstate))
+		return NULL;
+
+	(void) GetCurrentFullTransactionId();
+	(void) GetCurrentCommandId(true);
+
+	EnterParallelMode();
+	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
+								 parallel_workers);
+	Assert(pcxt->nworkers > 0);
+
+	/*
+	 * Estimate size for shared information for PARALLEL_COPY_KEY_SHARED_INFO
+	 */
+	shm_toc_estimate_chunk(&pcxt->estimator, sizeof(ParallelCopyShmInfo));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_CSTATE */
+	est_cstateshared = MAXALIGN(sizeof(SerializedParallelCopyState));
+	shm_toc_estimate_chunk(&pcxt->estimator, est_cstateshared);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	strsize = EstimateCstateSize(pcxt, cstate, attnamelist, &whereClauseStr,
+								 &rangeTableStr, &attnameListStr,
+								 &notnullListStr, &nullListStr,
+								 &convertListStr);
+
+	/*
+	 * Estimate space for WalUsage and BufferUsage -- PARALLEL_COPY_WAL_USAGE
+	 * and PARALLEL_COPY_BUFFER_USAGE.
+	 */
+	shm_toc_estimate_chunk(&pcxt->estimator,
+						   mul_size(sizeof(WalUsage), pcxt->nworkers));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+	shm_toc_estimate_chunk(&pcxt->estimator,
+						   mul_size(sizeof(BufferUsage), pcxt->nworkers));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	InitializeParallelDSM(pcxt);
+
+	/* If no DSM segment was available, back out (do serial copy) */
+	if (pcxt->seg == NULL)
+	{
+		EndParallelCopy(pcxt);
+		return NULL;
+	}
+
+	/* Allocate shared memory for PARALLEL_COPY_KEY_SHARED_INFO */
+	shared_info_ptr = (ParallelCopyShmInfo *) shm_toc_allocate(pcxt->toc, sizeof(ParallelCopyShmInfo));
+	PopulateParallelCopyShmInfo(shared_info_ptr);
+
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_SHARED_INFO, shared_info_ptr);
+	pcdata->pcshared_info = shared_info_ptr;
+	pcdata->relid = relid;
+
+	SerializeParallelCopyState(pcxt, cstate, strsize, whereClauseStr,
+							   rangeTableStr, attnameListStr, notnullListStr,
+							   nullListStr, convertListStr);
+
+	/*
+	 * Allocate space for each worker's WalUsage and BufferUsage; no need to
+	 * initialize.
+	 */
+	walusage = shm_toc_allocate(pcxt->toc,
+								mul_size(sizeof(WalUsage), pcxt->nworkers));
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_WAL_USAGE, walusage);
+	pcdata->walusage = walusage;
+	bufferusage = shm_toc_allocate(pcxt->toc,
+								   mul_size(sizeof(BufferUsage), pcxt->nworkers));
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_BUFFER_USAGE, bufferusage);
+	pcdata->bufferusage = bufferusage;
+
+	LaunchParallelWorkers(pcxt);
+	if (pcxt->nworkers_launched == 0)
+	{
+		EndParallelCopy(pcxt);
+		return NULL;
+	}
+
+	/*
+	 * Caller needs to wait for all launched workers when we return.  Make
+	 * sure that the failure-to-start case will not hang forever.
+	 */
+	WaitForParallelWorkersToAttach(pcxt);
+
+	pcdata->is_leader = true;
+	cstate->is_parallel = true;
+	return pcxt;
+}
+
+/*
+ * EndParallelCopy - End the parallel copy tasks.
+ */
+pg_attribute_always_inline void
+EndParallelCopy(ParallelContext *pcxt)
+{
+	Assert(!IsParallelWorker());
+
+	DestroyParallelContext(pcxt);
+	ExitParallelMode();
+}
+
+/*
+ * InitializeParallelCopyInfo - Initialize parallel worker.
+ */
+static void
+InitializeParallelCopyInfo(CopyState cstate, List *attnamelist)
+{
+	uint32		count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	PopulateCommonCstateInfo(cstate, tup_desc, attnamelist);
+
+	/* Initialize state variables. */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/* Set up variables to avoid per-attribute overhead. */
+	initStringInfo(&cstate->attribute_buf);
+
+	initStringInfo(&cstate->line_buf);
+	for (count = 0; count < WORKER_CHUNK_COUNT; count++)
+		initStringInfo(&pcdata->worker_line_buf[count].line_buf);
+
+	cstate->line_buf_converted = false;
+	cstate->raw_buf = NULL;
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+
+	PopulateCstateCatalogInfo(cstate);
+
+	/* Create workspace for CopyReadAttributes results. */
+	if (!cstate->binary)
+	{
+		AttrNumber	attr_count = list_length(cstate->attnumlist);
+
+		cstate->max_fields = attr_count;
+		cstate->raw_fields = (char **) palloc(attr_count * sizeof(char *));
+	}
+}
+
+/*
+ * CacheLineInfo - Cache the line information to local memory.
+ */
+static bool
+CacheLineInfo(CopyState cstate, uint32 buff_count)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	uint32		write_pos;
+	ParallelCopyDataBlock *data_blk_ptr;
+	ParallelCopyLineBoundary *lineInfo;
+	uint32		offset;
+	int			dataSize;
+	int			copiedSize = 0;
+
+	resetStringInfo(&pcdata->worker_line_buf[buff_count].line_buf);
+	write_pos = GetLinePosition(cstate);
+	if (-1 == write_pos)
+		return true;
+
+	/* Get the current line information. */
+	lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+	if (pg_atomic_read_u32(&lineInfo->line_size) == 0)
+		goto empty_data_line_update;
+
+	/* Get the block information. */
+	data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+	/* Get the offset information from where the data must be copied. */
+	offset = lineInfo->start_offset;
+	pcdata->worker_line_buf[buff_count].cur_lineno = lineInfo->cur_lineno;
+
+	elog(DEBUG1, "[Worker] Processing - line position:%d, block:%d, unprocessed lines:%d, offset:%d, line size:%d",
+		 write_pos, lineInfo->first_block,
+		 pg_atomic_read_u32(&data_blk_ptr->unprocessed_line_parts),
+		 offset, pg_atomic_read_u32(&lineInfo->line_size));
+
+	for (;;)
+	{
+		uint8		skip_bytes = data_blk_ptr->skip_bytes;
+
+		/*
+		 * There is a possibility that the loop embedded at the bottom of the
+		 * current loop has come out because data_blk_ptr->curr_blk_completed
+		 * is set, but dataSize read might be an old value, if
+		 * data_blk_ptr->curr_blk_completed and the line is completed,
+		 * line_size will be set. Read the line_size again to be sure if it is
+		 * completed or partial block.
+		 */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+		if (dataSize)
+		{
+			int			remainingSize = dataSize - copiedSize;
+
+			if (!remainingSize)
+				break;
+
+			/* Whole line is in current block. */
+			if (remainingSize + offset + skip_bytes < DATA_BLOCK_SIZE)
+			{
+				appendBinaryStringInfo(&pcdata->worker_line_buf[buff_count].line_buf,
+									   &data_blk_ptr->data[offset],
+									   remainingSize);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts,
+										1);
+				break;
+			}
+			else
+			{
+				/* Line is spread across the blocks. */
+				uint32		lineInCurrentBlock = (DATA_BLOCK_SIZE - skip_bytes) - offset;
+
+				appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+										 &data_blk_ptr->data[offset],
+										 lineInCurrentBlock);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+				copiedSize += lineInCurrentBlock;
+				while (copiedSize < dataSize)
+				{
+					uint32		currentBlockCopySize;
+					ParallelCopyDataBlock *currBlkPtr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+
+					skip_bytes = currBlkPtr->skip_bytes;
+
+					/*
+					 * If complete data is present in current block use
+					 * dataSize - copiedSize, or copy the whole block from
+					 * current block.
+					 */
+					currentBlockCopySize = Min(dataSize - copiedSize, DATA_BLOCK_SIZE - skip_bytes);
+					appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+											 &currBlkPtr->data[0],
+											 currentBlockCopySize);
+					pg_atomic_sub_fetch_u32(&currBlkPtr->unprocessed_line_parts, 1);
+					copiedSize += currentBlockCopySize;
+					data_blk_ptr = currBlkPtr;
+				}
+
+				break;
+			}
+		}
+		else
+		{
+			/* Copy this complete block from the current offset. */
+			uint32		lineInCurrentBlock = (DATA_BLOCK_SIZE - skip_bytes) - offset;
+
+			appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+									 &data_blk_ptr->data[offset],
+									 lineInCurrentBlock);
+			pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+			copiedSize += lineInCurrentBlock;
+
+			/*
+			 * Reset the offset. For the first copy, copy from the offset. For
+			 * the subsequent copy the complete block.
+			 */
+			offset = 0;
+
+			/* Set data_blk_ptr to the following block. */
+			data_blk_ptr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+		}
+
+		for (;;)
+		{
+			/* Get the size of this line */
+			dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+			/*
+			 * If the data is present in current block lineInfo->line_size
+			 * will be updated. If the data is spread across the blocks either
+			 * of lineInfo->line_size or data_blk_ptr->curr_blk_completed can
+			 * be updated. lineInfo->line_size will be updated if the complete
+			 * read is finished. data_blk_ptr->curr_blk_completed will be
+			 * updated if processing of current block is finished and data
+			 * processing is not finished.
+			 */
+			if (data_blk_ptr->curr_blk_completed || (dataSize != -1))
+				break;
+
+			COPY_WAIT_TO_PROCESS()
+		}
+	}
+
+empty_data_line_update:
+	elog(DEBUG1, "[Worker] Completed processing line:%d", write_pos);
+	pg_atomic_write_u32(&lineInfo->line_state, LINE_WORKER_PROCESSED);
+	pg_atomic_write_u32(&lineInfo->line_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+	return false;
+}
+
+/*
+ * GetWorkerLine - Returns a line for worker to process.
+ */
+bool
+GetWorkerLine(CopyState cstate)
+{
+	uint32		buff_count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+
+	/*
+	 * Copy the line data to line_buf and release the line position so that
+	 * the worker can continue loading data.
+	 */
+	if (pcdata->worker_line_buf_pos < pcdata->worker_line_buf_count)
+		goto return_line;
+
+	pcdata->worker_line_buf_pos = 0;
+	pcdata->worker_line_buf_count = 0;
+
+	for (buff_count = 0; buff_count < WORKER_CHUNK_COUNT; buff_count++)
+	{
+		bool		result = CacheLineInfo(cstate, buff_count);
+		if (result)
+			break;
+
+		pcdata->worker_line_buf_count++;
+	}
+
+	if (pcdata->worker_line_buf_count)
+		goto return_line;
+	else
+		resetStringInfo(&cstate->line_buf);
+
+	return true;
+
+return_line:
+	cstate->line_buf = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].line_buf;
+	cstate->cur_lineno = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].cur_lineno;
+	cstate->line_buf_valid = true;
+
+	/* Mark that encoding conversion hasn't occurred yet. */
+	cstate->line_buf_converted = false;
+	ConvertToServerEncoding(cstate);
+	pcdata->worker_line_buf_pos++;
+	return false;
+}
+
+/*
+ * ParallelCopyMain - Parallel copy worker's code.
+ *
+ * Where clause handling, convert tuple to columns, add default null values for
+ * the missing columns that are not present in that record. Find the partition
+ * if it is partitioned table, invoke before row insert Triggers, handle
+ * constraints and insert the tuples.
+ */
+void
+ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
+{
+	CopyState	cstate;
+	ParallelCopyData *pcdata;
+	ParallelCopyShmInfo *pcshared_info;
+	Relation	rel = NULL;
+	MemoryContext oldcontext;
+	List	   *attlist = NIL;
+	WalUsage   *walusage;
+	BufferUsage *bufferusage;
+
+	/* Allocate workspace and zero all fields. */
+	cstate = (CopyStateData *) palloc0(sizeof(CopyStateData));
+
+	/*
+	 * We allocate everything used by a cstate in a new memory context. This
+	 * avoids memory leaks during repeated use of COPY in a query.
+	 */
+	cstate->copycontext = AllocSetContextCreate(CurrentMemoryContext,
+												"COPY",
+												ALLOCSET_DEFAULT_SIZES);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	cstate->pcdata = pcdata;
+	pcdata->is_leader = false;
+	pcdata->worker_processed_pos = -1;
+	cstate->is_parallel = true;
+	pcshared_info = (ParallelCopyShmInfo *) shm_toc_lookup(toc, PARALLEL_COPY_KEY_SHARED_INFO, false);
+
+	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
+
+	pcdata->pcshared_info = pcshared_info;
+	RestoreParallelCopyState(toc, cstate, &attlist);
+
+	/* Open and lock the relation, using the appropriate lock type. */
+	rel = table_open(cstate->pcdata->relid, RowExclusiveLock);
+	cstate->rel = rel;
+	InitializeParallelCopyInfo(cstate, attlist);
+
+	/* Prepare to track buffer usage during parallel execution */
+	InstrStartParallelQuery();
+
+	CopyFrom(cstate);
+
+	if (rel != NULL)
+		table_close(rel, RowExclusiveLock);
+
+	/* Report WAL/buffer usage during parallel execution */
+	bufferusage = shm_toc_lookup(toc, PARALLEL_COPY_BUFFER_USAGE, false);
+	walusage = shm_toc_lookup(toc, PARALLEL_COPY_WAL_USAGE, false);
+	InstrEndParallelQuery(&bufferusage[ParallelWorkerNumber],
+						  &walusage[ParallelWorkerNumber]);
+
+	MemoryContextSwitchTo(oldcontext);
+	pfree(cstate);
+	return;
+}
+
+/*
+ * UpdateSharedLineInfo - Update the line information.
+ */
+uint32
+UpdateSharedLineInfo(CopyState cstate, uint32 blk_pos, uint32 offset,
+					 uint32 line_size, uint32 line_state, uint32 blk_line_pos)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyLineBoundaries *lineBoundaryPtr = &pcshared_info->line_boundaries;
+	ParallelCopyLineBoundary *lineInfo;
+	uint32		line_pos;
+
+	/* blk_line_pos will be valid in case line_pos was blocked earlier. */
+	if (blk_line_pos == -1)
+	{
+		line_pos = lineBoundaryPtr->pos;
+
+		/* Update the line information for the worker to pick and process. */
+		lineInfo = &lineBoundaryPtr->ring[line_pos];
+		while (pg_atomic_read_u32(&lineInfo->line_size) != -1)
+			COPY_WAIT_TO_PROCESS()
+
+				lineInfo->first_block = blk_pos;
+		lineInfo->start_offset = offset;
+		lineInfo->cur_lineno = cstate->cur_lineno;
+		lineBoundaryPtr->pos = (lineBoundaryPtr->pos + 1) % RINGSIZE;
+	}
+	else
+	{
+		line_pos = blk_line_pos;
+		lineInfo = &lineBoundaryPtr->ring[line_pos];
+	}
+
+	if (line_state == LINE_LEADER_POPULATED)
+	{
+		elog(DEBUG1, "[Leader] Added line with block:%d, offset:%d, line position:%d, line size:%d",
+			 lineInfo->first_block, lineInfo->start_offset, line_pos,
+			 pg_atomic_read_u32(&lineInfo->line_size));
+		pcshared_info->populated++;
+	}
+	else
+		elog(DEBUG1, "[Leader] Adding - block:%d, offset:%d, line position:%d",
+			 lineInfo->first_block, lineInfo->start_offset, line_pos);
+
+	pg_atomic_write_u32(&lineInfo->line_size, line_size);
+	pg_atomic_write_u32(&lineInfo->line_state, line_state);
+
+	return line_pos;
+}
+
+/*
+ * ParallelCopyFrom - parallel copy leader's functionality.
+ *
+ * Leader executes the before statement for before statement trigger, if before
+ * statement trigger is present. It will read the table data from the file and
+ * copy the contents to DSM data blocks. It will then read the input contents
+ * from the DSM data block and identify the records based on line breaks. This
+ * information is called line or a record that need to be inserted into a
+ * relation. The line information will be stored in ParallelCopyLineBoundary DSM
+ * data structure. Workers will then process this information and insert the
+ * data in to table. It will repeat this process until the all data is read from
+ * the file and all the DSM data blocks are processed. While processing if
+ * leader identifies that DSM Data blocks or DSM ParallelCopyLineBoundary data
+ * structures is full, leader will wait till the worker frees up some entries
+ * and repeat the process. It will wait till all the lines populated are
+ * processed by the workers and exits.
+ */
+void
+ParallelCopyFrom(CopyState cstate)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
+
+	/* raw_buf is not used in parallel copy, instead data blocks are used. */
+	pfree(cstate->raw_buf);
+	cstate->raw_buf = NULL;
+
+	/* Execute the before statement triggers from the leader */
+	ExecBeforeStmtTrigger(cstate);
+
+	/* On input just throw the header line away. */
+	if (cstate->cur_lineno == 0 && cstate->header_line)
+	{
+		cstate->cur_lineno++;
+		if (CopyReadLine(cstate))
+		{
+			pcshared_info->is_read_in_progress = false;
+			return;				/* done */
+		}
+	}
+
+	for (;;)
+	{
+		bool		done;
+
+		cstate->cur_lineno++;
+
+		/* Actually read the line into memory here. */
+		done = CopyReadLine(cstate);
+
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			break;
+	}
+
+	pcshared_info->is_read_in_progress = false;
+	cstate->cur_lineno = 0;
+}
+
+/*
+ * GetLinePosition - Return the line position once the leader has populated the
+ * data.
+ */
+uint32
+GetLinePosition(CopyState cstate)
+{
+	ParallelCopyData *pcdata = cstate->pcdata;
+	ParallelCopyShmInfo *pcshared_info = pcdata->pcshared_info;
+	uint32  previous_pos = pcdata->worker_processed_pos;
+	uint32 write_pos = (previous_pos == -1) ? 0 : (previous_pos + 1) % RINGSIZE;
+
+	for (;;)
+	{
+		int			dataSize;
+		bool		is_read_in_progress = pcshared_info->is_read_in_progress;
+		ParallelCopyLineBoundary *lineInfo;
+		ParallelCopyDataBlock *data_blk_ptr;
+		uint32		line_state = LINE_LEADER_POPULATED;
+		ParallelCopyLineState curr_line_state;
+
+		CHECK_FOR_INTERRUPTS();
+
+		/* File read completed & no elements to process. */
+		if (!is_read_in_progress &&
+			(pcshared_info->populated ==
+			 pg_atomic_read_u64(&pcshared_info->total_worker_processed)))
+		{
+			write_pos = -1;
+			break;
+		}
+
+		/* Get the current line information. */
+		lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+		curr_line_state = pg_atomic_read_u32(&lineInfo->line_state);
+		if ((write_pos % WORKER_CHUNK_COUNT == 0) &&
+			(curr_line_state == LINE_WORKER_PROCESSED ||
+			 curr_line_state == LINE_WORKER_PROCESSING))
+		{
+			pcdata->worker_processed_pos = write_pos;
+			write_pos = (write_pos + WORKER_CHUNK_COUNT) %  RINGSIZE;
+			continue;
+		}
+
+		/* Get the size of this line. */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+		if (dataSize != 0)		/* If not an empty line. */
+		{
+			/* Get the block information. */
+			data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+			if (!data_blk_ptr->curr_blk_completed && (dataSize == -1))
+			{
+				/* Wait till the current line or block is added. */
+				COPY_WAIT_TO_PROCESS()
+					continue;
+			}
+		}
+
+		/* Make sure that no worker has consumed this element. */
+		if (pg_atomic_compare_exchange_u32(&lineInfo->line_state,
+										   &line_state, LINE_WORKER_PROCESSING))
+			break;
+	}
+
+	pcdata->worker_processed_pos = write_pos;
+	return write_pos;
+}
+
+/*
+ * GetFreeCopyBlock - Get a free block for data to be copied.
+ */
+static pg_attribute_always_inline uint32
+GetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	int			count = 0;
+	uint32		last_free_block = pcshared_info->cur_block_pos;
+	uint32		block_pos = (last_free_block != -1) ? ((last_free_block + 1) % MAX_BLOCKS_COUNT) : 0;
+
+	/*
+	 * Get a new block for copying data, don't check current block, current
+	 * block will have some unprocessed data.
+	 */
+	while (count < (MAX_BLOCKS_COUNT - 1))
+	{
+		ParallelCopyDataBlock *dataBlkPtr = &pcshared_info->data_blocks[block_pos];
+		uint32		unprocessed_line_parts = pg_atomic_read_u32(&dataBlkPtr->unprocessed_line_parts);
+
+		if (unprocessed_line_parts == 0)
+		{
+			dataBlkPtr->curr_blk_completed = false;
+			dataBlkPtr->skip_bytes = 0;
+			dataBlkPtr->following_block = -1;
+			pcshared_info->cur_block_pos = block_pos;
+			MemSet(&dataBlkPtr->data[0], 0, DATA_BLOCK_SIZE);
+			return block_pos;
+		}
+
+		block_pos = (block_pos + 1) % MAX_BLOCKS_COUNT;
+		count++;
+	}
+
+	return -1;
+}
+
+/*
+ * WaitGetFreeCopyBlock - If there are no blocks available, wait and get a block
+ * for copying data.
+ */
+uint32
+WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	uint32		new_free_pos = -1;
+
+	for (;;)
+	{
+		new_free_pos = GetFreeCopyBlock(pcshared_info);
+		if (new_free_pos != -1) /* We have got one block, break now. */
+			break;
+
+		COPY_WAIT_TO_PROCESS()
+	}
+
+	return new_free_pos;
+}
+
+/*
+ * SetRawBufForLoad - Set raw_buf to the shared memory where the file data must
+ * be read.
+ */
+void
+SetRawBufForLoad(CopyState cstate, uint32 line_size, uint32 copy_buf_len,
+				 uint32 raw_buf_ptr, char **copy_raw_buf)
+{
+	ParallelCopyShmInfo *pcshared_info;
+	uint32		cur_block_pos;
+	uint32		next_block_pos;
+	ParallelCopyDataBlock *cur_data_blk_ptr = NULL;
+	ParallelCopyDataBlock *next_data_blk_ptr = NULL;
+
+	if (!IsParallelCopy())
+		return;
+
+	pcshared_info = cstate->pcdata->pcshared_info;
+	cur_block_pos = pcshared_info->cur_block_pos;
+	cur_data_blk_ptr = (cstate->raw_buf) ? &pcshared_info->data_blocks[cur_block_pos] : NULL;
+	next_block_pos = WaitGetFreeCopyBlock(pcshared_info);
+	next_data_blk_ptr = &pcshared_info->data_blocks[next_block_pos];
+
+	/* set raw_buf to the data block in shared memory */
+	cstate->raw_buf = next_data_blk_ptr->data;
+	*copy_raw_buf = cstate->raw_buf;
+	if (cur_data_blk_ptr && line_size)
+	{
+		/*
+		 * Mark the previous block as completed, worker can start copying this
+		 * data.
+		 */
+		cur_data_blk_ptr->following_block = next_block_pos;
+		pg_atomic_add_fetch_u32(&cur_data_blk_ptr->unprocessed_line_parts, 1);
+		cur_data_blk_ptr->skip_bytes = copy_buf_len - raw_buf_ptr;
+		cur_data_blk_ptr->curr_blk_completed = true;
+	}
+}
+
+/*
+ * EndLineParallelCopy - Update the line information in shared memory.
+ */
+void
+EndLineParallelCopy(CopyState cstate, uint32 line_pos, uint32 line_size,
+					uint32 raw_buf_ptr)
+{
+	uint8		new_line_size;
+
+	if (!IsParallelCopy())
+		return;
+
+	if (!IsHeaderLine())
+	{
+		ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+		SET_NEWLINE_SIZE()
+			if (line_size)
+		{
+			/*
+			 * If the new_line_size > raw_buf_ptr, then the new block has only
+			 * new line char content. The unprocessed count should not be
+			 * increased in this case.
+			 */
+			if (raw_buf_ptr > new_line_size)
+			{
+				uint32		cur_block_pos = pcshared_info->cur_block_pos;
+				ParallelCopyDataBlock *curr_data_blk_ptr = &pcshared_info->data_blocks[cur_block_pos];
+
+				pg_atomic_add_fetch_u32(&curr_data_blk_ptr->unprocessed_line_parts, 1);
+			}
+
+			/*
+			 * Update line size & line state, other members are already
+			 * updated.
+			 */
+			(void) UpdateSharedLineInfo(cstate, -1, -1, line_size,
+										LINE_LEADER_POPULATED, line_pos);
+		}
+		else if (new_line_size)
+			/* This means only new line char, empty record should be inserted. */
+			(void) UpdateSharedLineInfo(cstate, -1, -1, 0,
+										LINE_LEADER_POPULATED, -1);
+	}
+}
+
+/*
+ * ExecBeforeStmtTrigger - Execute the before statement trigger, this will be
+ * executed for parallel copy by the leader process.
+ */
+void
+ExecBeforeStmtTrigger(CopyState cstate)
+{
+	EState	   *estate = CreateExecutorState();
+	ResultRelInfo *resultRelInfo;
+
+	Assert(IsLeader());
+
+	/*
+	 * We need a ResultRelInfo so we can use the regular executor's
+	 * index-entry-making machinery.  (There used to be a huge amount of code
+	 * here that basically duplicated execUtils.c ...)
+	 */
+	resultRelInfo = makeNode(ResultRelInfo);
+	InitResultRelInfo(resultRelInfo,
+					  cstate->rel,
+					  1,		/* must match rel's position in range_table */
+					  NULL,
+					  0);
+
+	/* Verify the named relation is a valid target for INSERT */
+	CheckValidResultRel(resultRelInfo, CMD_INSERT);
+
+	estate->es_result_relations = resultRelInfo;
+	estate->es_num_result_relations = 1;
+	estate->es_result_relation_info = resultRelInfo;
+
+	ExecInitRangeTable(estate, cstate->range_table);
+
+	/*
+	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
+	 * should do this for COPY, since it's not really an "INSERT" statement as
+	 * such. However, executing these triggers maintains consistency with the
+	 * EACH ROW triggers that we already fire on COPY.
+	 */
+	ExecBSInsertTriggers(estate, resultRelInfo);
+
+	/* Close any trigger target relations */
+	ExecCleanUpTriggerState(estate);
+
+	FreeExecutorState(estate);
+}
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index 24c7b41..cf00256 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -2353,7 +2353,7 @@ psql_completion(const char *text, int start, int end)
 	/* Complete COPY <sth> FROM|TO filename WITH ( */
 	else if (Matches("COPY|\\copy", MatchAny, "FROM|TO", MatchAny, "WITH", "("))
 		COMPLETE_WITH("FORMAT", "FREEZE", "DELIMITER", "NULL",
-					  "HEADER", "QUOTE", "ESCAPE", "FORCE_QUOTE",
+					  "HEADER", "PARALLEL", "QUOTE", "ESCAPE", "FORCE_QUOTE",
 					  "FORCE_NOT_NULL", "FORCE_NULL", "ENCODING");
 
 	/* Complete COPY <sth> FROM|TO filename WITH (FORMAT */
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index df1b43a..96295bc 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -385,6 +385,7 @@ extern FullTransactionId GetTopFullTransactionId(void);
 extern FullTransactionId GetTopFullTransactionIdIfAny(void);
 extern FullTransactionId GetCurrentFullTransactionId(void);
 extern FullTransactionId GetCurrentFullTransactionIdIfAny(void);
+extern void SetCurrentCommandIdUsedForWorker(void);
 extern void MarkCurrentTransactionIdLoggedIfAny(void);
 extern bool SubTransactionIsActive(SubTransactionId subxid);
 extern CommandId GetCurrentCommandId(bool used);
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index cd2d56e..a9fe950 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -51,6 +51,31 @@
  */
 #define WORKER_CHUNK_COUNT 64
 
+#define IsParallelCopy()		(cstate->is_parallel)
+#define IsLeader()				(cstate->pcdata->is_leader)
+#define IsWorker()				(IsParallelCopy() && !IsLeader())
+#define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
+
+/*
+ * Increment the lines processed.
+ */
+#define INCREMENTPROCESSED(processed) \
+{ \
+	if (!IsParallelCopy()) \
+		processed++; \
+	else \
+		pg_atomic_add_fetch_u64(&cstate->pcdata->pcshared_info->processed, 1); \
+}
+
+/*
+ * Get the lines processed.
+ */
+#define RETURNPROCESSED(processed) \
+if (!IsParallelCopy()) \
+	return processed; \
+else \
+	return pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
+
 /*
  * Represents the different source/dest cases we need to worry about at
  * the bottom level
@@ -75,6 +100,28 @@ typedef enum EolType
 } EolType;
 
 /*
+ * State of the line.
+ */
+typedef enum ParallelCopyLineState
+{
+	LINE_INIT,					/* initial state of line */
+	LINE_LEADER_POPULATING,		/* leader processing line */
+	LINE_LEADER_POPULATED,		/* leader completed populating line */
+	LINE_WORKER_PROCESSING,		/* worker processing line */
+	LINE_WORKER_PROCESSED		/* worker completed processing line */
+} ParallelCopyLineState;
+
+/*
+ * Represents the heap insert method to be used during COPY FROM.
+ */
+typedef enum CopyInsertMethod
+{
+	CIM_SINGLE,					/* use table_tuple_insert or fdw routine */
+	CIM_MULTI,					/* always use table_multi_insert */
+	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
+} CopyInsertMethod;
+
+/*
  * Copy data block information.
  *
  * These data blocks are created in DSM. Data read from file will be copied in
@@ -194,8 +241,6 @@ typedef struct ParallelCopyShmInfo
 	uint64		populated;		/* lines populated by leader */
 	uint32		cur_block_pos;	/* current data block */
 	ParallelCopyDataBlock data_blocks[MAX_BLOCKS_COUNT];	/* data block array */
-	FullTransactionId full_transaction_id;	/* xid for copy from statement */
-	CommandId	mycid;			/* command id */
 	ParallelCopyLineBoundaries line_boundaries; /* line array */
 } ParallelCopyShmInfo;
 
@@ -242,12 +287,12 @@ typedef struct ParallelCopyData
 	ParallelCopyShmInfo *pcshared_info; /* common info in shared memory */
 	bool		is_leader;
 
+	/* line position which worker is processing */
+	uint32				worker_processed_pos;
+
 	WalUsage   *walusage;
 	BufferUsage *bufferusage;
 
-	/* line position which worker is processing */
-	uint32		worker_processed_pos;
-
 	/*
 	 * Local line_buf array, workers will copy it here and release the lines
 	 * for the leader to continue.
@@ -423,9 +468,23 @@ extern DestReceiver *CreateCopyDestReceiver(void);
 
 extern void PopulateCommonCstateInfo(CopyState cstate, TupleDesc tup_desc,
 									 List *attnamelist);
+extern void ConvertToServerEncoding(CopyState cstate);
 
 extern void ParallelCopyMain(dsm_segment *seg, shm_toc *toc);
 extern ParallelContext *BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid);
 extern void ParallelCopyFrom(CopyState cstate);
 extern void EndParallelCopy(ParallelContext *pcxt);
+extern void ExecBeforeStmtTrigger(CopyState cstate);
+extern void CheckTargetRelValidity(CopyState cstate);
+extern void PopulateCstateCatalogInfo(CopyState cstate);
+extern uint32 GetLinePosition(CopyState cstate);
+extern bool GetWorkerLine(CopyState cstate);
+extern bool CopyReadLine(CopyState cstate);
+extern uint32 WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info);
+extern void SetRawBufForLoad(CopyState cstate, uint32 line_size, uint32 copy_buf_len,
+							 uint32 raw_buf_ptr, char **copy_raw_buf);
+extern uint32 UpdateSharedLineInfo(CopyState cstate, uint32 blk_pos, uint32 offset,
+								   uint32 line_size, uint32 line_state, uint32 blk_line_pos);
+extern void EndLineParallelCopy(CopyState cstate, uint32 line_pos, uint32 line_size,
+								uint32 raw_buf_ptr);
 #endif							/* COPY_H */
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index f5b818b..a198bf0 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1707,6 +1707,7 @@ ParallelCopyLineBoundary
 ParallelCopyData
 ParallelCopyDataBlock
 ParallelCopyLineBuf
+ParallelCopyLineState
 ParallelCopyShmInfo
 ParallelExecutorInfo
 ParallelHashGrowth
-- 
1.8.3.1

v6-0004-Documentation-for-parallel-copy.patchapplication/x-patch; name=v6-0004-Documentation-for-parallel-copy.patchDownload
From 0dd69daa6794de67ca6398d4f72869ae3c17dcdb Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Sat, 1 Aug 2020 09:00:36 +0530
Subject: [PATCH v6 4/6] Documentation for parallel copy.

This patch has the documentation changes for parallel copy.
---
 doc/src/sgml/ref/copy.sgml | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/doc/src/sgml/ref/copy.sgml b/doc/src/sgml/ref/copy.sgml
index 18189ab..19b1979 100644
--- a/doc/src/sgml/ref/copy.sgml
+++ b/doc/src/sgml/ref/copy.sgml
@@ -37,6 +37,7 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
     DELIMITER '<replaceable class="parameter">delimiter_character</replaceable>'
     NULL '<replaceable class="parameter">null_string</replaceable>'
     HEADER [ <replaceable class="parameter">boolean</replaceable> ]
+    PARALLEL <replaceable class="parameter">integer</replaceable>
     QUOTE '<replaceable class="parameter">quote_character</replaceable>'
     ESCAPE '<replaceable class="parameter">escape_character</replaceable>'
     FORCE_QUOTE { ( <replaceable class="parameter">column_name</replaceable> [, ...] ) | * }
@@ -275,6 +276,22 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
    </varlistentry>
 
    <varlistentry>
+    <term><literal>PARALLEL</literal></term>
+    <listitem>
+     <para>
+      Perform <command>COPY FROM</command> in parallel using <replaceable
+      class="parameter">integer</replaceable> background workers.  Please
+      note that it is not guaranteed that the number of parallel workers
+      specified in <replaceable class="parameter">integer</replaceable> will
+      be used during execution.  It is possible for a copy to run with fewer
+      workers than specified, or even with no workers at all (for example,
+      due to the setting of max_worker_processes). This option is allowed
+      only in <command>COPY FROM</command>.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><literal>QUOTE</literal></term>
     <listitem>
      <para>
@@ -951,6 +968,20 @@ COPY country FROM '/usr1/proj/bray/sql/country_data';
   </para>
 
   <para>
+   To copy data parallelly from a file into the <literal>country</literal> table:
+<programlisting>
+COPY country FROM '/usr1/proj/bray/sql/country_data' WITH (PARALLEL 1);
+</programlisting>
+  </para>
+
+  <para>
+   To copy data parallelly from STDIN into the <literal>country</literal> table:
+<programlisting>
+COPY country FROM STDIN WITH (PARALLEL 1);
+</programlisting>
+  </para>
+
+  <para>
    To copy into a file just the countries whose names start with 'A':
 <programlisting>
 COPY (SELECT * FROM country WHERE country_name LIKE 'A%') TO '/usr1/proj/bray/sql/a_list_countries.copy';
-- 
1.8.3.1

v6-0005-Tests-for-parallel-copy.patchapplication/x-patch; name=v6-0005-Tests-for-parallel-copy.patchDownload
From 1f07a8f5128a2e295e6dda1ab667f8ca8fcffaff Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Sat, 1 Aug 2020 09:19:39 +0530
Subject: [PATCH v6 5/6] Tests for parallel copy.

This patch has the tests for parallel copy.
---
 src/test/regress/expected/copy2.out | 205 ++++++++++++++++++++++++++++++++++-
 src/test/regress/input/copy.source  |  12 +++
 src/test/regress/output/copy.source |  12 +++
 src/test/regress/sql/copy2.sql      | 208 +++++++++++++++++++++++++++++++++++-
 4 files changed, 429 insertions(+), 8 deletions(-)

diff --git a/src/test/regress/expected/copy2.out b/src/test/regress/expected/copy2.out
index e40287d..7ae5d44 100644
--- a/src/test/regress/expected/copy2.out
+++ b/src/test/regress/expected/copy2.out
@@ -254,18 +254,32 @@ It is "perfect".|
 "It is ""perfect"".","	"
 "",
 --test that we read consecutive LFs properly
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 COPY testnl FROM stdin CSV;
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+SELECT * FROM testnl;
+ a |          b           | c 
+---+----------------------+---
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+(2 rows)
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 COPY testeoc FROM stdin CSV;
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
 COPY testeoc TO stdout CSV;
 a\.
 \.b
 c\.d
 "\."
 -- test handling of nonstandard null marker that violates escaping rules
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 COPY testnull TO stdout WITH NULL AS E'\\0';
 1	\\0
@@ -280,6 +294,15 @@ SELECT * FROM testnull;
     | 
 (4 rows)
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 1);
+SELECT * FROM testnull;
+ a  | b  
+----+----
+ 42 | \0
+    | 
+(2 rows)
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -349,6 +372,34 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+SELECT * FROM vistest;
+ a  
+----
+ a2
+ b
+(2 rows)
+
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+COMMIT;
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 SELECT * FROM vistest;
  a 
@@ -409,7 +460,7 @@ SELECT * FROM vistest;
 (2 rows)
 
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -420,6 +471,8 @@ CREATE TEMP TABLE forcetest (
 -- should succeed with no effect ("b" remains an empty string, "c" remains NULL)
 BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 1);
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
  b |  c   
@@ -430,6 +483,8 @@ SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
 BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 1);
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
  c |  d   
@@ -486,6 +541,31 @@ select * from check_con_tbl;
    
 (2 rows)
 
+\d+ check_con_tbl
+                               Table "public.check_con_tbl"
+ Column |  Type   | Collation | Nullable | Default | Storage | Stats target | Description 
+--------+---------+-----------+----------+---------+---------+--------------+-------------
+ f1     | integer |           |          |         | plain   |              | 
+Check constraints:
+    "check_con_tbl_check" CHECK (check_con_function(check_con_tbl.*))
+
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 1);
+NOTICE:  input = {"f1":1}
+NOTICE:  input = {"f1":null}
+copy check_con_tbl from stdin with (parallel 1);
+NOTICE:  input = {"f1":0}
+ERROR:  new row for relation "check_con_tbl" violates check constraint "check_con_tbl_check"
+DETAIL:  Failing row contains (0).
+CONTEXT:  COPY check_con_tbl, line 1: "0"
+parallel worker
+select * from check_con_tbl;
+ f1 
+----
+  1
+   
+(2 rows)
+
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
 CREATE ROLE regress_rls_copy_user_colperms;
@@ -600,8 +680,125 @@ SELECT * FROM instead_of_insert_tbl;
 (2 rows)
 
 COMMIT;
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+COPY test_parallel_copy (a, b, c, d, e) from stdin with (PARALLEL 1);
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1, FORMAT 'csv', HEADER);
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0');
+ERROR:  value 0 out of bounds for option "parallel"
+DETAIL:  Valid values are between "1" and "1024".
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri from stdin with (FORMAT csv, DELIMITER ',', PARALLEL 1);
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1) WHERE height > random() * 65;
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+-- temporary table copy: should perform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+COPY temp_test (a) from stdin with (PARALLEL 1);
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) from stdin with (PARALLEL 1);
+ERROR:  column "xyz" of relation "test_parallel_copy" does not exist
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) from stdin with (PARALLEL 1);
+ERROR:  column "d" specified more than once
+-- missing data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  invalid input syntax for type integer: ""
+CONTEXT:  COPY test_parallel_copy, line 0, column a: ""
+parallel worker
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2000	230	23	23"
+parallel worker
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2001	231	\N	\N"
+parallel worker
+-- extra data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  extra data after last expected column
+CONTEXT:  COPY test_parallel_copy, line 1: "2002	232	40	50	60	70	80"
+parallel worker
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) from stdin with (delimiter ',', null 'x', PARALLEL 1) ;
+COPY test_parallel_copy from stdin WITH (DELIMITER ';', NULL '', PARALLEL 1);
+COPY test_parallel_copy from stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL 1);
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = 50004;
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a > 60003;
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE f > 60003;
+ERROR:  column "f" does not exist
+LINE 1: ..._parallel_copy from stdin WITH (PARALLEL 1) WHERE f > 60003;
+                                                             ^
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+ERROR:  missing FROM-clause entry for table "x"
+LINE 1: ...rallel_copy from stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+                                                                  ^
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (SELECT 1 FROM x);
+ERROR:  cannot use subquery in COPY FROM WHERE condition
+LINE 1: ...arallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (SELECT...
+                                                             ^
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (generate_series(1,5));
+ERROR:  set-returning functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...lel_copy from stdin WITH (PARALLEL 1) WHERE a IN (generate_s...
+                                                             ^
+COPY test_parallel_copy from stdin WITH(PARALLEL 1) WHERE a = row_number() over(b);
+ERROR:  window functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...rallel_copy from stdin WITH(PARALLEL 1) WHERE a = row_number...
+                                                             ^
+-- check results of copy in
+SELECT * FROM test_parallel_copy;
+   a   | b  |     c      |    d    |    e    
+-------+----+------------+---------+---------
+     1 | 11 | test_c1    | test_d1 | test_e1
+     2 | 12 | test_c2    | test_d2 | test_e2
+       |  3 | stuff      | test_d3 | 
+       |  4 | stuff      | test_d4 | 
+       |  5 | stuff      | test_d5 | 
+       |    | 45         | 80      | 90
+       |    | x          | \x      | \x
+       |    | ,          | \,      | \
+  3000 |    | c          |         | 
+  4000 |    | C          |         | 
+  4001 |  1 | empty      |         | 
+  4002 |  2 | null       |         | 
+  4003 |  3 | Backslash  | \       | \
+  4004 |  4 | BackslashX | \X      | \X
+  4005 |  5 | N          | N       | N
+  4006 |  6 | BackslashN | \N      | \N
+  4007 |  7 | XX         | XX      | XX
+  4008 |  8 | Delimiter  | :       | :
+ 50004 | 25 | 35         | 45      | 55
+ 60004 | 25 | 35         | 45      | 55
+ 60005 | 26 | 36         | 46      | 56
+(21 rows)
+
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
 DROP TABLE x, y;
diff --git a/src/test/regress/input/copy.source b/src/test/regress/input/copy.source
index a1d529a..159c058 100644
--- a/src/test/regress/input/copy.source
+++ b/src/test/regress/input/copy.source
@@ -15,6 +15,13 @@ DELETE FROM onek;
 
 COPY onek FROM '@abs_builddir@/results/onek.data';
 
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+
+SELECT COUNT(*) FROM tenk1;
+
+TRUNCATE tenk1;
+
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
@@ -159,6 +166,11 @@ truncate parted_copytest;
 
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
 
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
+
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/output/copy.source b/src/test/regress/output/copy.source
index 938d355..c3003fe 100644
--- a/src/test/regress/output/copy.source
+++ b/src/test/regress/output/copy.source
@@ -9,6 +9,15 @@ COPY onek FROM '@abs_srcdir@/data/onek.data';
 COPY onek TO '@abs_builddir@/results/onek.data';
 DELETE FROM onek;
 COPY onek FROM '@abs_builddir@/results/onek.data';
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+SELECT COUNT(*) FROM tenk1;
+ count 
+-------
+ 10000
+(1 row)
+
+TRUNCATE tenk1;
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
 COPY person FROM '@abs_srcdir@/data/person.data';
@@ -113,6 +122,9 @@ insert into parted_copytest select x,1,'One' from generate_series(1011,1020) x;
 copy (select * from parted_copytest order by a) to '@abs_builddir@/results/parted_copytest.csv';
 truncate parted_copytest;
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/sql/copy2.sql b/src/test/regress/sql/copy2.sql
index 902f4fa..7015698 100644
--- a/src/test/regress/sql/copy2.sql
+++ b/src/test/regress/sql/copy2.sql
@@ -157,7 +157,7 @@ COPY y TO stdout (FORMAT CSV, FORCE_QUOTE *);
 
 --test that we read consecutive LFs properly
 
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 
 COPY testnl FROM stdin CSV;
 1,"a field with two LFs
@@ -165,8 +165,16 @@ COPY testnl FROM stdin CSV;
 inside",2
 \.
 
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+1,"a field with two LFs
+
+inside",2
+\.
+
+SELECT * FROM testnl;
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 
 COPY testeoc FROM stdin CSV;
 a\.
@@ -175,11 +183,19 @@ c\.d
 "\."
 \.
 
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+a\.
+\.b
+c\.d
+"\."
+\.
+
 COPY testeoc TO stdout CSV;
 
 -- test handling of nonstandard null marker that violates escaping rules
 
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 
 COPY testnull TO stdout WITH NULL AS E'\\0';
@@ -191,6 +207,14 @@ COPY testnull FROM stdin WITH NULL AS E'\\0';
 
 SELECT * FROM testnull;
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 1);
+42	\\0
+\0	\0
+\.
+
+SELECT * FROM testnull;
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -235,6 +259,23 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+a2
+b
+\.
+SELECT * FROM vistest;
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+d2
+e
+\.
+SELECT * FROM vistest;
+COMMIT;
+SELECT * FROM vistest;
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 x
 y
@@ -284,7 +325,7 @@ SELECT * FROM vistest;
 COMMIT;
 SELECT * FROM vistest;
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -297,6 +338,10 @@ BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
 1,,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 1);
+1,,""
+\.
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
@@ -304,6 +349,10 @@ BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
 2,'a',,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 1);
+2,'a',,""
+\.
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
 -- should fail with not-null constraint violation
@@ -339,6 +388,16 @@ copy check_con_tbl from stdin;
 0
 \.
 select * from check_con_tbl;
+\d+ check_con_tbl
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 1);
+1
+\N
+\.
+copy check_con_tbl from stdin with (parallel 1);
+0
+\.
+select * from check_con_tbl;
 
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
@@ -440,8 +499,149 @@ test1
 SELECT * FROM instead_of_insert_tbl;
 COMMIT;
 
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+
+COPY test_parallel_copy (a, b, c, d, e) from stdin with (PARALLEL 1);
+1	11	test_c1	test_d1	test_e1
+2	12	test_c2	test_d2	test_e2
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+3	test_d3
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+4	test_d4
+5	test_d5
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1, FORMAT 'csv', HEADER);
+b	d
+\.
+
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0');
+
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri from stdin with (FORMAT csv, DELIMITER ',', PARALLEL 1);
+10
+\.
+
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1) WHERE height > random() * 65;
+60,60,60
+\.
+
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+60
+\.
+
+-- temporary table copy: should perform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+
+COPY temp_test (a) from stdin with (PARALLEL 1);
+10
+\.
+
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) from stdin with (PARALLEL 1);
+
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) from stdin with (PARALLEL 1);
+
+-- missing data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+
+\.
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+2000	230	23	23
+\.
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+2001	231	\N	\N
+\.
+
+-- extra data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+2002	232	40	50	60	70	80
+\.
+
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) from stdin with (delimiter ',', null 'x', PARALLEL 1) ;
+x,45,80,90
+x,\x,\\x,\\\x
+x,\,,\\\,,\\
+\.
+
+COPY test_parallel_copy from stdin WITH (DELIMITER ';', NULL '', PARALLEL 1);
+3000;;c;;
+\.
+
+COPY test_parallel_copy from stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL 1);
+4000:\X:C:\X:\X
+4001:1:empty::
+4002:2:null:\X:\X
+4003:3:Backslash:\\:\\
+4004:4:BackslashX:\\X:\\X
+4005:5:N:\N:\N
+4006:6:BackslashN:\\N:\\N
+4007:7:XX:\XX:\XX
+4008:8:Delimiter:\::\:
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = 50004;
+50003	24	34	44	54
+50004	25	35	45 	55
+50005	26	36	46	56
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a > 60003;
+60001	22	32	42	52
+60002	23	33	43	53
+60003	24	34	44	54
+60004	25	35	45	55
+60005	26	36	46	56
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE f > 60003;
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (SELECT 1 FROM x);
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (generate_series(1,5));
+
+COPY test_parallel_copy from stdin WITH(PARALLEL 1) WHERE a = row_number() over(b);
+
+-- check results of copy in
+SELECT * FROM test_parallel_copy;
+
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
 DROP TABLE x, y;
-- 
1.8.3.1

v6-0006-Parallel-Copy-For-Binary-Format-Files.patchapplication/x-patch; name=v6-0006-Parallel-Copy-For-Binary-Format-Files.patchDownload
From 3e5886767f10c3fae2d11c8014764da8127f4f77 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 7 Oct 2020 13:24:38 +0530
Subject: [PATCH v6 6/6] Parallel Copy For Binary Format Files

Leader reads data from the file into the DSM data blocks each of 64K size.
It also identifies each tuple data block id, start offset, end offset,
tuple size and updates this information in the ring data structure.
Workers parallelly read the tuple information from the ring data structure,
the actual tuple data from the data blocks and parallelly insert the tuples
into the table.
---
 src/backend/commands/copy.c         | 134 ++++++------
 src/backend/commands/copyparallel.c | 422 ++++++++++++++++++++++++++++++++++--
 src/include/commands/copy.h         | 126 +++++++++++
 3 files changed, 595 insertions(+), 87 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index dc006a5..2ea3a90 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -223,19 +223,14 @@ static void CopySendData(CopyState cstate, const void *databuf, int datasize);
 static void CopySendString(CopyState cstate, const char *str);
 static void CopySendChar(CopyState cstate, char c);
 static void CopySendEndOfRow(CopyState cstate);
-static int	CopyGetData(CopyState cstate, void *databuf,
-						int minread, int maxread);
 static void CopySendInt32(CopyState cstate, int32 val);
 static bool CopyGetInt32(CopyState cstate, int32 *val);
 static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 static bool CopyLoadRawBuf(CopyState cstate);
-static int	CopyReadBinaryData(CopyState cstate, char *dest, int nbytes);
-
 static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
 								   int copy_line_pos, int *copy_line_size);
 
-
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
  * in past protocol redesigns.
@@ -449,7 +444,7 @@ CopySendEndOfRow(CopyState cstate)
  *
  * NB: no data conversion is applied here.
  */
-static int
+int
 CopyGetData(CopyState cstate, void *databuf, int minread, int maxread)
 {
 	int			bytesread = 0;
@@ -582,10 +577,25 @@ CopyGetInt32(CopyState cstate, int32 *val)
 {
 	uint32		buf;
 
-	if (CopyReadBinaryData(cstate, (char *) &buf, sizeof(buf)) != sizeof(buf))
+	/*
+	 * For parallel copy, avoid reading data to raw buf, read directly from
+	 * file, later the data will be read to parallel copy data buffers.
+	 */
+	if (cstate->nworkers > 0)
 	{
-		*val = 0;				/* suppress compiler warning */
-		return false;
+		if (CopyGetData(cstate, &buf, sizeof(buf), sizeof(buf)) != sizeof(buf))
+		{
+			*val = 0;			/* suppress compiler warning */
+			return false;
+		}
+	}
+	else
+	{
+		if (CopyReadBinaryData(cstate, (char *) &buf, sizeof(buf)) != sizeof(buf))
+		{
+			*val = 0;			/* suppress compiler warning */
+			return false;
+		}
 	}
 	*val = (int32) pg_ntoh32(buf);
 	return true;
@@ -661,7 +671,7 @@ CopyLoadRawBuf(CopyState cstate)
  * and writes them to 'dest'.  Returns the number of bytes read (which
  * would be less than 'nbytes' only if we reach EOF).
  */
-static int
+int
 CopyReadBinaryData(CopyState cstate, char *dest, int nbytes)
 {
 	int			copied_bytes = 0;
@@ -986,7 +996,15 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 			EndParallelCopy(pcxt);
 		}
 		else
+		{
+			/*
+			 * Reset nworkers to -1 here. This is useful in cases where user
+			 * specifies parallel workers, but, no worker is picked up, so go
+			 * back to non parallel mode value of nworkers.
+			 */
+			cstate->nworkers = -1;
 			*processed = CopyFrom(cstate);	/* copy from file to database */
+		}
 
 		EndCopyFrom(cstate);
 	}
@@ -3552,7 +3570,7 @@ BeginCopyFrom(ParseState *pstate,
 		int32		tmp;
 
 		/* Signature */
-		if (CopyReadBinaryData(cstate, readSig, 11) != 11 ||
+		if (CopyGetData(cstate, readSig, 11, 11) != 11 ||
 			memcmp(readSig, BinarySignature, 11) != 0)
 			ereport(ERROR,
 					(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
@@ -3580,7 +3598,7 @@ BeginCopyFrom(ParseState *pstate,
 		/* Skip extension header, if present */
 		while (tmp-- > 0)
 		{
-			if (CopyReadBinaryData(cstate, readSig, 1) != 1)
+			if (CopyGetData(cstate, readSig, 1, 1) != 1)
 				ereport(ERROR,
 						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
 						 errmsg("invalid COPY file header (wrong length)")));
@@ -3777,60 +3795,45 @@ NextCopyFrom(CopyState cstate, ExprContext *econtext,
 	else
 	{
 		/* binary */
-		int16		fld_count;
-		ListCell   *cur;
-
 		cstate->cur_lineno++;
+		cstate->max_fields = list_length(cstate->attnumlist);
 
-		if (!CopyGetInt16(cstate, &fld_count))
+		if (!IsParallelCopy())
 		{
-			/* EOF detected (end of file, or protocol-level EOF) */
-			return false;
-		}
+			int16		fld_count;
+			ListCell   *cur;
 
-		if (fld_count == -1)
-		{
-			/*
-			 * Received EOF marker.  In a V3-protocol copy, wait for the
-			 * protocol-level EOF, and complain if it doesn't come
-			 * immediately.  This ensures that we correctly handle CopyFail,
-			 * if client chooses to send that now.
-			 *
-			 * Note that we MUST NOT try to read more data in an old-protocol
-			 * copy, since there is no protocol-level EOF marker then.  We
-			 * could go either way for copy from file, but choose to throw
-			 * error if there's data after the EOF marker, for consistency
-			 * with the new-protocol case.
-			 */
-			char		dummy;
-
-			if (cstate->copy_dest != COPY_OLD_FE &&
-				CopyReadBinaryData(cstate, &dummy, 1) > 0)
-				ereport(ERROR,
-						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-						 errmsg("received copy data after EOF marker")));
-			return false;
-		}
+			if (!CopyGetInt16(cstate, &fld_count))
+			{
+				/* EOF detected (end of file, or protocol-level EOF) */
+				return false;
+			}
 
-		if (fld_count != attr_count)
-			ereport(ERROR,
-					(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-					 errmsg("row field count is %d, expected %d",
-							(int) fld_count, attr_count)));
+			CHECK_FIELD_COUNT;
 
-		foreach(cur, cstate->attnumlist)
+			foreach(cur, cstate->attnumlist)
+			{
+				int			attnum = lfirst_int(cur);
+				int			m = attnum - 1;
+				Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+
+				cstate->cur_attname = NameStr(att->attname);
+				values[m] = CopyReadBinaryAttribute(cstate,
+													&in_functions[m],
+													typioparams[m],
+													att->atttypmod,
+													&nulls[m]);
+				cstate->cur_attname = NULL;
+			}
+		}
+		else
 		{
-			int			attnum = lfirst_int(cur);
-			int			m = attnum - 1;
-			Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+			bool		eof = false;
 
-			cstate->cur_attname = NameStr(att->attname);
-			values[m] = CopyReadBinaryAttribute(cstate,
-												&in_functions[m],
-												typioparams[m],
-												att->atttypmod,
-												&nulls[m]);
-			cstate->cur_attname = NULL;
+			eof = CopyReadBinaryTupleWorker(cstate, values, nulls);
+
+			if (eof)
+				return false;
 		}
 	}
 
@@ -4842,18 +4845,15 @@ CopyReadBinaryAttribute(CopyState cstate, FmgrInfo *flinfo,
 	Datum		result;
 
 	if (!CopyGetInt32(cstate, &fld_size))
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("unexpected EOF in COPY data")));
+		EOF_ERROR;
+
 	if (fld_size == -1)
 	{
 		*isnull = true;
 		return ReceiveFunctionCall(flinfo, NULL, typioparam, typmod);
 	}
-	if (fld_size < 0)
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("invalid field size")));
+
+	CHECK_FIELD_SIZE(fld_size);
 
 	/* reset attribute_buf to empty, and load raw data in it */
 	resetStringInfo(&cstate->attribute_buf);
@@ -4861,9 +4861,7 @@ CopyReadBinaryAttribute(CopyState cstate, FmgrInfo *flinfo,
 	enlargeStringInfo(&cstate->attribute_buf, fld_size);
 	if (CopyReadBinaryData(cstate, cstate->attribute_buf.data,
 						   fld_size) != fld_size)
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("unexpected EOF in COPY data")));
+		EOF_ERROR;
 
 	cstate->attribute_buf.len = fld_size;
 	cstate->attribute_buf.data[fld_size] = '\0';
diff --git a/src/backend/commands/copyparallel.c b/src/backend/commands/copyparallel.c
index 6a44a01..e8d1a99 100644
--- a/src/backend/commands/copyparallel.c
+++ b/src/backend/commands/copyparallel.c
@@ -94,6 +94,7 @@ SerializeParallelCopyState(ParallelContext *pcxt, CopyState cstate,
 	shared_cstate.convert_selectively = cstate->convert_selectively;
 	shared_cstate.num_defaults = cstate->num_defaults;
 	shared_cstate.relid = cstate->pcdata->relid;
+	shared_cstate.binary = cstate->binary;
 
 	memcpy(shmptr, (char *) &shared_cstate, sizeof(SerializedParallelCopyState));
 	copiedsize = sizeof(SerializedParallelCopyState);
@@ -191,6 +192,7 @@ RestoreParallelCopyState(shm_toc *toc, CopyState cstate, List **attlist)
 	cstate->convert_selectively = shared_cstate.convert_selectively;
 	cstate->num_defaults = shared_cstate.num_defaults;
 	cstate->pcdata->relid = shared_cstate.relid;
+	cstate->binary = shared_cstate.binary;
 
 	cstate->null_print = CopyStringFromSharedMemory(shared_str_val + copiedsize,
 													&copiedsize);
@@ -380,7 +382,7 @@ static pg_attribute_always_inline bool
 IsParallelCopyAllowed(CopyState cstate)
 {
 	/* Parallel copy not allowed for frontend (2.0 protocol) & binary option. */
-	if ((cstate->copy_dest == COPY_OLD_FE) || cstate->binary)
+	if (cstate->copy_dest == COPY_OLD_FE)
 		return false;
 
 	/*
@@ -976,33 +978,67 @@ ParallelCopyFrom(CopyState cstate)
 	/* Execute the before statement triggers from the leader */
 	ExecBeforeStmtTrigger(cstate);
 
-	/* On input just throw the header line away. */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (!cstate->binary)
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
+		/* On input just throw the header line away. */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
 		{
-			pcshared_info->is_read_in_progress = false;
-			return;				/* done */
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+			{
+				pcshared_info->is_read_in_progress = false;
+				return;			/* done */
+			}
 		}
-	}
 
-	for (;;)
-	{
-		bool		done;
+		for (;;)
+		{
+			bool		done;
 
-		cstate->cur_lineno++;
+			cstate->cur_lineno++;
 
-		/* Actually read the line into memory here. */
-		done = CopyReadLine(cstate);
+			/* Actually read the line into memory here. */
+			done = CopyReadLine(cstate);
 
+			/*
+			 * EOF at start of line means we're done.  If we see EOF after
+			 * some characters, we act as though it was newline followed by
+			 * EOF, ie, process the line and then exit loop on next iteration.
+			 */
+			if (done && cstate->line_buf.len == 0)
+				break;
+		}
+	}
+	else
+	{
 		/*
-		 * EOF at start of line means we're done.  If we see EOF after some
-		 * characters, we act as though it was newline followed by EOF, ie,
-		 * process the line and then exit loop on next iteration.
+		 * Binary Format Files. For parallel copy leader, fill in the error
+		 * context information here, in case any failures while determining
+		 * tuple offsets, leader would throw the errors with proper context.
 		 */
-		if (done && cstate->line_buf.len == 0)
-			break;
+		ErrorContextCallback errcallback;
+
+		errcallback.callback = CopyFromErrorCallback;
+		errcallback.arg = (void *) cstate;
+		errcallback.previous = error_context_stack;
+		error_context_stack = &errcallback;
+		cstate->pcdata->curr_data_block = NULL;
+		cstate->raw_buf_index = 0;
+		pcshared_info->populated = 0;
+		cstate->cur_lineno = 0;
+		cstate->max_fields = list_length(cstate->attnumlist);
+
+		for (;;)
+		{
+			bool		eof = false;
+
+			cstate->cur_lineno++;
+
+			eof = CopyReadBinaryTupleLeader(cstate);
+
+			if (eof)
+				break;
+		}
 	}
 
 	pcshared_info->is_read_in_progress = false;
@@ -1010,6 +1046,354 @@ ParallelCopyFrom(CopyState cstate)
 }
 
 /*
+ * CopyReadBinaryGetDataBlock
+ *
+ * Gets a new block, updates the current offset, calculates the skip bytes.
+ */
+void
+CopyReadBinaryGetDataBlock(CopyState cstate, FieldInfoType field_info)
+{
+	ParallelCopyDataBlock *data_block = NULL;
+	ParallelCopyDataBlock *curr_data_block = cstate->pcdata->curr_data_block;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	uint8		move_bytes = 0;
+	uint32		block_pos;
+	uint32		prev_block_pos;
+	int			read_bytes = 0;
+
+	prev_block_pos = pcshared_info->cur_block_pos;
+
+	block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+	if (field_info == FIELD_SIZE || field_info == FIELD_COUNT)
+		move_bytes = (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+
+	if (curr_data_block != NULL)
+		curr_data_block->skip_bytes = move_bytes;
+
+	data_block = &pcshared_info->data_blocks[block_pos];
+
+	if (move_bytes > 0 && curr_data_block != NULL)
+		memmove(&data_block->data[0], &curr_data_block->data[cstate->raw_buf_index], move_bytes);
+
+	elog(DEBUG1, "LEADER - field info %d is spread across data blocks - moved %d bytes from current block %u to %u block",
+		 field_info, move_bytes, prev_block_pos, block_pos);
+
+	read_bytes = CopyGetData(cstate, &data_block->data[move_bytes], 1, (DATA_BLOCK_SIZE - move_bytes));
+
+	if (field_info == FIELD_NONE && cstate->reached_eof)
+		return;
+
+	if (cstate->reached_eof)
+		EOF_ERROR;
+
+	elog(DEBUG1, "LEADER - bytes read from file %d", read_bytes);
+
+	if (field_info == FIELD_SIZE || field_info == FIELD_DATA)
+	{
+		ParallelCopyDataBlock *prev_data_block = NULL;
+
+		prev_data_block = curr_data_block;
+		prev_data_block->following_block = block_pos;
+
+		if (prev_data_block->curr_blk_completed == false)
+			prev_data_block->curr_blk_completed = true;
+
+		pg_atomic_add_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+	}
+
+	cstate->pcdata->curr_data_block = data_block;
+	cstate->raw_buf_index = 0;
+}
+
+/*
+ * CopyReadBinaryTupleLeader
+ *
+ * Leader reads data from binary formatted file to data blocks and identifies
+ * tuple boundaries/offsets so that workers can work on the data blocks data.
+ */
+bool
+CopyReadBinaryTupleLeader(CopyState cstate)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	int16		fld_count;
+	uint32		line_size = 0;
+	uint32		start_block_pos;
+	uint32		start_offset;
+
+	if (cstate->pcdata->curr_data_block == NULL)
+	{
+		CopyReadBinaryGetDataBlock(cstate, FIELD_NONE);
+
+		/*
+		 * no data is read from file here. one possibility to be here could be
+		 * that the binary file just has a valid signature but nothing else.
+		 */
+		if (cstate->reached_eof)
+			return true;
+	}
+
+	if ((cstate->raw_buf_index + sizeof(fld_count)) >= DATA_BLOCK_SIZE)
+		CopyReadBinaryGetDataBlock(cstate, FIELD_COUNT);
+
+	memcpy(&fld_count, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_count));
+	fld_count = (int16) pg_ntoh16(fld_count);
+	CHECK_FIELD_COUNT;
+	start_offset = cstate->raw_buf_index;
+	cstate->raw_buf_index += sizeof(fld_count);
+	line_size += sizeof(fld_count);
+	start_block_pos = pcshared_info->cur_block_pos;
+
+	CopyReadBinaryFindTupleSize(cstate, &line_size);
+
+	pg_atomic_add_fetch_u32(&cstate->pcdata->curr_data_block->unprocessed_line_parts, 1);
+
+	if (line_size > 0)
+		(void) UpdateSharedLineInfo(cstate, start_block_pos, start_offset,
+									line_size, LINE_LEADER_POPULATED, -1);
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryFindTupleSize
+ *
+ * Leader identifies boundaries/offsets for each attribute/column and finally
+ * results in the tuple/row size. It moves on to next data block if the
+ * attribute/column is spread across data blocks.
+ */
+void
+CopyReadBinaryFindTupleSize(CopyState cstate, uint32 *line_size)
+{
+	int32		fld_size;
+	ListCell   *cur;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			att_num = lfirst_int(cur);
+		Form_pg_attribute att = TupleDescAttr(tup_desc, (att_num - 1));
+
+		cstate->cur_attname = NameStr(att->attname);
+		fld_size = 0;
+
+		if ((cstate->raw_buf_index + sizeof(fld_size)) >= DATA_BLOCK_SIZE)
+			CopyReadBinaryGetDataBlock(cstate, FIELD_SIZE);
+
+		memcpy(&fld_size, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_size));
+		cstate->raw_buf_index += sizeof(fld_size);
+		*line_size += sizeof(fld_size);
+		fld_size = (int32) pg_ntoh32(fld_size);
+
+		CHECK_FIELD_SIZE(fld_size);
+
+		*line_size += fld_size;
+
+		if ((DATA_BLOCK_SIZE - cstate->raw_buf_index) >= fld_size)
+		{
+			cstate->raw_buf_index += fld_size;
+			elog(DEBUG1, "LEADER - tuple lies in he same data block");
+		}
+		else
+		{
+			int32		required_blks = 0;
+			int32		curr_blk_bytes = (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+			int			i = 0;
+
+			GET_REQUIRED_BLOCKS(required_blks, fld_size, curr_blk_bytes);
+
+			i = required_blks;
+
+			while (i > 0)
+			{
+				CopyReadBinaryGetDataBlock(cstate, FIELD_DATA);
+				i--;
+			}
+
+			GET_RAW_BUF_INDEX(cstate->raw_buf_index, fld_size, required_blks, curr_blk_bytes);
+
+			/*
+			 * raw_buf_index should never cross data block size, as the
+			 * required number of data blocks would have been obtained in the
+			 * above while loop.
+			 */
+			Assert(cstate->raw_buf_index <= DATA_BLOCK_SIZE);
+		}
+		cstate->cur_attname = NULL;
+	}
+}
+
+/*
+ * CopyReadBinaryTupleWorker
+ *
+ * Each worker reads data from data blocks after getting leader-identified tuple
+ * offsets from ring data structure.
+ */
+bool
+CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls)
+{
+	uint32		line_pos;
+	ParallelCopyLineBoundary *line_info;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	int16		fld_count;
+	ListCell   *cur;
+	FmgrInfo   *in_functions = cstate->in_functions;
+	Oid		   *typioparams = cstate->typioparams;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+
+	line_pos = GetLinePosition(cstate);
+	if (line_pos == -1)
+		return true;
+
+	line_info = &pcshared_info->line_boundaries.ring[line_pos];
+	cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[line_info->first_block];
+	cstate->raw_buf_index = line_info->start_offset;
+
+	if (cstate->raw_buf_index + sizeof(fld_count) >= DATA_BLOCK_SIZE)
+	{
+		/*
+		 * The case where field count spread across datablocks should never
+		 * occur, as the leader would have moved it to next block. this code
+		 * exists for debugging purposes only.
+		 */
+		elog(DEBUG1, "WORKER - field count spread across datablocks should never occur");
+	}
+
+	memcpy(&fld_count, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_count));
+	fld_count = (int16) pg_ntoh16(fld_count);
+
+	CHECK_FIELD_COUNT;
+
+	cstate->raw_buf_index += sizeof(fld_count);
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			att_num = lfirst_int(cur);
+		int			m = att_num - 1;
+		Form_pg_attribute att = TupleDescAttr(tup_desc, m);
+
+		cstate->cur_attname = NameStr(att->attname);
+
+		values[m] = CopyReadBinaryAttributeWorker(cstate,
+												  &in_functions[m],
+												  typioparams[m],
+												  att->atttypmod,
+												  &nulls[m]);
+		cstate->cur_attname = NULL;
+	}
+
+	pg_atomic_sub_fetch_u32(&cstate->pcdata->curr_data_block->unprocessed_line_parts, 1);
+	line_info->start_offset = -1;
+	pg_atomic_write_u32(&line_info->line_state, LINE_WORKER_PROCESSED);
+	pg_atomic_write_u32(&line_info->line_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryAttributeWorker
+ *
+ * Leader identifies boundaries/offsets for each attribute/column, it moves on
+ * to next data block if the attribute/column is spread across data blocks.
+ */
+Datum
+CopyReadBinaryAttributeWorker(CopyState cstate, FmgrInfo *flinfo,
+							  Oid typioparam, int32 typmod, bool *isnull)
+{
+	int32		fld_size;
+	Datum		result;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+	if ((cstate->raw_buf_index + sizeof(fld_size)) >= DATA_BLOCK_SIZE)
+	{
+		ParallelCopyDataBlock *prev_data_block = cstate->pcdata->curr_data_block;
+
+		elog(DEBUG1, "WORKER - field size is spread across data blocks");
+		cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[prev_data_block->following_block];
+		pg_atomic_sub_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+		cstate->raw_buf_index = 0;
+	}
+
+	memcpy(&fld_size, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_size));
+	fld_size = (int32) pg_ntoh32(fld_size);
+
+	CHECK_FIELD_SIZE(fld_size);
+
+	cstate->raw_buf_index += sizeof(fld_size);
+
+	/* reset attribute_buf to empty, and load raw data in it */
+	resetStringInfo(&cstate->attribute_buf);
+
+	enlargeStringInfo(&cstate->attribute_buf, fld_size);
+
+	if ((DATA_BLOCK_SIZE - cstate->raw_buf_index) >= fld_size)
+	{
+		elog(DEBUG1, "WORKER - tuple lies in single data block");
+		memcpy(&cstate->attribute_buf.data[0], &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], fld_size);
+		cstate->raw_buf_index += fld_size;
+	}
+	else
+	{
+		uint32		att_buf_idx = 0;
+		uint32		copy_bytes = 0;
+		int32		required_blks = 0;
+		int32		curr_blk_bytes = (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+		ParallelCopyDataBlock *prev_data_block = NULL;
+		int			i = 0;
+
+		GET_REQUIRED_BLOCKS(required_blks, fld_size, curr_blk_bytes);
+
+		i = required_blks;
+		prev_data_block = cstate->pcdata->curr_data_block;
+		elog(DEBUG1, "WORKER - tuple is spread across data blocks");
+		memcpy(&cstate->attribute_buf.data[0], &prev_data_block->data[cstate->raw_buf_index],
+			   curr_blk_bytes);
+		copy_bytes = curr_blk_bytes;
+		att_buf_idx = curr_blk_bytes;
+
+		while (i > 0)
+		{
+			cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[prev_data_block->following_block];
+			pg_atomic_sub_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+			cstate->raw_buf_index = 0;
+			copy_bytes = fld_size - att_buf_idx;
+
+			/*
+			 * The bytes that are yet to be taken into att buff are more than
+			 * the entire data block size, but only take the data block size
+			 * elements.
+			 */
+			if (copy_bytes >= DATA_BLOCK_SIZE)
+				copy_bytes = DATA_BLOCK_SIZE;
+
+			memcpy(&cstate->attribute_buf.data[att_buf_idx],
+				   &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], copy_bytes);
+			att_buf_idx += copy_bytes;
+			i--;
+		}
+		GET_RAW_BUF_INDEX(cstate->raw_buf_index, fld_size, required_blks, curr_blk_bytes);
+	}
+
+	cstate->attribute_buf.len = fld_size;
+	cstate->attribute_buf.data[fld_size] = '\0';
+
+	/* Call the column type's binary input converter */
+	result = ReceiveFunctionCall(flinfo, &cstate->attribute_buf,
+								 typioparam, typmod);
+
+	/* Trouble if it didn't eat the whole buffer */
+	if (cstate->attribute_buf.cursor != cstate->attribute_buf.len)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+				 errmsg("incorrect binary data format")));
+
+	*isnull = false;
+	return result;
+}
+
+/*
  * GetLinePosition - Return the line position once the leader has populated the
  * data.
  */
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index a9fe950..746c139 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -77,6 +77,109 @@ else \
 	return pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
 
 /*
+ * CHECK_FIELD_COUNT - Handles the error cases for field count
+ * for binary format files.
+ */
+#define CHECK_FIELD_COUNT \
+{\
+	if (fld_count == -1) \
+	{ \
+		if (IsParallelCopy() && \
+			!IsLeader()) \
+			return true; \
+		else if (IsParallelCopy() && \
+			IsLeader()) \
+		{ \
+			if (cstate->pcdata->curr_data_block->data[cstate->raw_buf_index + sizeof(fld_count)] != 0) \
+				ereport(ERROR, \
+						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+						errmsg("received copy data after EOF marker"))); \
+			return true; \
+		} \
+		else \
+		{ \
+			/* \
+			 * Received EOF marker.  In a V3-protocol copy, wait for the \
+			 * protocol-level EOF, and complain if it doesn't come \
+			 * immediately.  This ensures that we correctly handle CopyFail, \
+			 * if client chooses to send that now. \
+			 * \
+			 * Note that we MUST NOT try to read more data in an old-protocol \
+			 * copy, since there is no protocol-level EOF marker then.  We \
+			 * could go either way for copy from file, but choose to throw \
+			 * error if there's data after the EOF marker, for consistency \
+			 * with the new-protocol case. \
+			 */ \
+			char		dummy; \
+			if (cstate->copy_dest != COPY_OLD_FE && \
+				CopyReadBinaryData(cstate, &dummy, 1) > 0) \
+				ereport(ERROR, \
+						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+						errmsg("received copy data after EOF marker"))); \
+				return false; \
+		} \
+	} \
+	if (fld_count != cstate->max_fields) \
+		ereport(ERROR, \
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+				errmsg("row field count is %d, expected %d", \
+				(int) fld_count, cstate->max_fields))); \
+}
+
+/*
+ * CHECK_FIELD_SIZE - Handles the error case for field size
+ * for binary format files.
+ */
+#define CHECK_FIELD_SIZE(fld_size) \
+{ \
+	if (fld_size < -1) \
+		ereport(ERROR, \
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+				errmsg("invalid field size")));\
+}
+
+/*
+ * EOF_ERROR - Error statement for EOF for binary format
+ * files.
+ */
+#define EOF_ERROR \
+{ \
+	ereport(ERROR, \
+		(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+		errmsg("unexpected EOF in COPY data")));\
+}
+
+/*
+ * GET_RAW_BUF_INDEX - Calculates the raw buf index for the cases
+ * where the data spread is across multiple data blocks.
+ */
+#define GET_RAW_BUF_INDEX(raw_buf_index, fld_size, required_blks, curr_blk_bytes) \
+{ \
+	raw_buf_index = fld_size - (((required_blks - 1) * DATA_BLOCK_SIZE) + curr_blk_bytes); \
+}
+
+/*
+ * GET_REQUIRED_BLOCKS - Calculates the number of data
+ * blocks required for the cases where the data spread
+ * is across multiple data blocks.
+ */
+#define GET_REQUIRED_BLOCKS(required_blks, fld_size, curr_blk_bytes) \
+{ \
+	/* \
+	 * field size can spread across multiple data blocks, \
+	 * calculate the number of required data blocks and try to get \
+	 * those many data blocks. \
+	 */ \
+	required_blks = (int32)(fld_size - curr_blk_bytes)/(int32)DATA_BLOCK_SIZE; \
+	/* \
+	 * check if we need the data block for the field data \
+	 * bytes that are not modulus of data block size. \
+	 */ \
+	if ((fld_size - curr_blk_bytes)%DATA_BLOCK_SIZE != 0) \
+		required_blks++; \
+}
+
+/*
  * Represents the different source/dest cases we need to worry about at
  * the bottom level
  */
@@ -254,6 +357,17 @@ typedef struct ParallelCopyLineBuf
 } ParallelCopyLineBuf;
 
 /*
+ * Represents the usage mode for CopyReadBinaryGetDataBlock.
+ */
+typedef enum FieldInfoType
+{
+	FIELD_NONE = 0,
+	FIELD_COUNT,
+	FIELD_SIZE,
+	FIELD_DATA
+}			FieldInfoType;
+
+/*
  * This structure helps in storing the common data from CopyStateData that are
  * required by the workers. This information will then be allocated and stored
  * into the DSM for the worker to retrieve and copy it to CopyStateData.
@@ -276,6 +390,7 @@ typedef struct SerializedParallelCopyState
 	/* Working state for COPY FROM */
 	AttrNumber	num_defaults;
 	Oid			relid;
+	bool		binary;
 } SerializedParallelCopyState;
 
 /*
@@ -302,6 +417,9 @@ typedef struct ParallelCopyData
 
 	/* Current position in worker_line_buf */
 	uint32		worker_line_buf_pos;
+
+	/* For binary formatted files */
+	ParallelCopyDataBlock *curr_data_block;
 } ParallelCopyData;
 
 typedef int (*copy_data_source_cb) (void *outbuf, int minread, int maxread);
@@ -487,4 +605,12 @@ extern uint32 UpdateSharedLineInfo(CopyState cstate, uint32 blk_pos, uint32 offs
 								   uint32 line_size, uint32 line_state, uint32 blk_line_pos);
 extern void EndLineParallelCopy(CopyState cstate, uint32 line_pos, uint32 line_size,
 								uint32 raw_buf_ptr);
+extern int	CopyGetData(CopyState cstate, void *databuf, int minread, int maxread);
+extern int	CopyReadBinaryData(CopyState cstate, char *dest, int nbytes);
+extern bool CopyReadBinaryTupleLeader(CopyState cstate);
+extern bool CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls);
+extern void CopyReadBinaryFindTupleSize(CopyState cstate, uint32 *line_size);
+extern Datum CopyReadBinaryAttributeWorker(CopyState cstate, FmgrInfo *flinfo,
+										   Oid typioparam, int32 typmod, bool *isnull);
+extern void CopyReadBinaryGetDataBlock(CopyState cstate, FieldInfoType field_info);
 #endif							/* COPY_H */
-- 
1.8.3.1

#160vignesh C
vignesh21@gmail.com
In reply to: Greg Nancarrow (#153)
Re: Parallel copy

On Tue, Sep 29, 2020 at 3:16 PM Greg Nancarrow <gregn4422@gmail.com> wrote:

Hi Vignesh and Bharath,

Seems like the Parallel Copy patch is regarding RI_TRIGGER_PK as
parallel-unsafe.
Can you explain why this is?

Yes we don't need to restrict parallelism for RI_TRIGGER_PK cases as
we don't do any command counter increments while performing PK checks
as opposed to RI_TRIGGER_FK/foreign key checks. We have modified this
in the v6 patch set.

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

#161vignesh C
vignesh21@gmail.com
In reply to: Amit Kapila (#151)
Re: Parallel copy

On Mon, Sep 28, 2020 at 3:01 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Tue, Sep 22, 2020 at 2:44 PM vignesh C <vignesh21@gmail.com> wrote:

Thanks Ashutosh for your comments.

On Wed, Sep 16, 2020 at 6:36 PM Ashutosh Sharma <ashu.coek88@gmail.com> wrote:

Hi Vignesh,

I've spent some time today looking at your new set of patches and I've
some thoughts and queries which I would like to put here:

Why are these not part of the shared cstate structure?

SerializeString(pcxt, PARALLEL_COPY_KEY_NULL_PRINT, cstate->null_print);
SerializeString(pcxt, PARALLEL_COPY_KEY_DELIM, cstate->delim);
SerializeString(pcxt, PARALLEL_COPY_KEY_QUOTE, cstate->quote);
SerializeString(pcxt, PARALLEL_COPY_KEY_ESCAPE, cstate->escape);

I have used shared_cstate mainly to share the integer & bool data
types from the leader to worker process. The above data types are of
char* data type, I will not be able to use it like how I could do it
for integer type. So I preferred to send these as separate keys to the
worker. Thoughts?

I think the way you have written will work but if we go with
Ashutosh's proposal it will look elegant and in the future, if we need
to share more strings as part of cstate structure then that would be
easier. You can probably refer to EstimateParamListSpace,
SerializeParamList, and RestoreParamList to see how we can share
different types of data in one key.

Thanks for the solution Amit, I have fixed this and handled it in the
v6 patch shared in my previous mail.

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

#162Greg Nancarrow
gregn4422@gmail.com
In reply to: vignesh C (#159)
Re: Parallel copy

On Thu, Oct 8, 2020 at 5:44 AM vignesh C <vignesh21@gmail.com> wrote:

Attached v6 patch with the fixes.

Hi Vignesh,

I noticed a couple of issues when scanning the code in the following patch:

v6-0003-Allow-copy-from-command-to-process-data-from-file.patch

In the following code, it will put a junk uint16 value into *destptr
(and thus may well cause a crash) on a Big Endian architecture
(Solaris Sparc, s390x, etc.):
You're storing a (uint16) string length in a uint32 and then pulling
out the lower two bytes of the uint32 and copying them into the
location pointed to by destptr.

static void
+CopyStringToSharedMemory(CopyState cstate, char *srcPtr, char *destptr,
+ uint32 *copiedsize)
+{
+ uint32 len = srcPtr ? strlen(srcPtr) + 1 : 0;
+
+ memcpy(destptr, (uint16 *) &len, sizeof(uint16));
+ *copiedsize += sizeof(uint16);
+ if (len)
+ {
+ memcpy(destptr + sizeof(uint16), srcPtr, len);
+ *copiedsize += len;
+ }
+}

I suggest you change the code to:

uint16 len = srcPtr ? (uint16)strlen(srcPtr) + 1 : 0;
memcpy(destptr, &len, sizeof(uint16));

[I assume string length here can't ever exceed (65535 - 1), right?]

Looking a bit deeper into this, I'm wondering if in fact your
EstimateStringSize() and EstimateNodeSize() functions should be using
BUFFERALIGN() for EACH stored string/node (rather than just calling
shm_toc_estimate_chunk() once at the end, after the length of packed
strings and nodes has been estimated), to ensure alignment of start of
each string/node. Other Postgres code appears to be aligning each
stored chunk using shm_toc_estimate_chunk(). See the definition of
that macro and its current usages.

Then you could safely use:

uint16 len = srcPtr ? (uint16)strlen(srcPtr) + 1 : 0;
*(uint16 *)destptr = len;
*copiedsize += sizeof(uint16);
if (len)
{
memcpy(destptr + sizeof(uint16), srcPtr, len);
*copiedsize += len;
}

and in the CopyStringFromSharedMemory() function, then could safely use:

len = *(uint16 *)srcPtr;

The compiler may be smart enough to optimize-away the memcpy() in this
case anyway, but there are issues in doing this for architectures that
take a performance hit for unaligned access, or don't support
unaligned access.

Also, in CopyXXXXFromSharedMemory() functions, you should use palloc()
instead of palloc0(), as you're filling the entire palloc'd buffer
anyway, so no need to ask for additional MemSet() of all buffer bytes
to 0 prior to memcpy().

Regards,
Greg Nancarrow
Fujitsu Australia

#163vignesh C
vignesh21@gmail.com
In reply to: Ashutosh Sharma (#152)
Re: Parallel copy

On Mon, Sep 28, 2020 at 6:37 PM Ashutosh Sharma <ashu.coek88@gmail.com> wrote:

On Mon, Sep 28, 2020 at 3:01 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Tue, Sep 22, 2020 at 2:44 PM vignesh C <vignesh21@gmail.com> wrote:

Thanks Ashutosh for your comments.

On Wed, Sep 16, 2020 at 6:36 PM Ashutosh Sharma <ashu.coek88@gmail.com> wrote:

Hi Vignesh,

I've spent some time today looking at your new set of patches and I've
some thoughts and queries which I would like to put here:

Why are these not part of the shared cstate structure?

SerializeString(pcxt, PARALLEL_COPY_KEY_NULL_PRINT, cstate->null_print);
SerializeString(pcxt, PARALLEL_COPY_KEY_DELIM, cstate->delim);
SerializeString(pcxt, PARALLEL_COPY_KEY_QUOTE, cstate->quote);
SerializeString(pcxt, PARALLEL_COPY_KEY_ESCAPE, cstate->escape);

I have used shared_cstate mainly to share the integer & bool data
types from the leader to worker process. The above data types are of
char* data type, I will not be able to use it like how I could do it
for integer type. So I preferred to send these as separate keys to the
worker. Thoughts?

I think the way you have written will work but if we go with
Ashutosh's proposal it will look elegant and in the future, if we need
to share more strings as part of cstate structure then that would be
easier. You can probably refer to EstimateParamListSpace,
SerializeParamList, and RestoreParamList to see how we can share
different types of data in one key.

Yeah. And in addition to that it will also reduce the number of DSM
keys that we need to maintain.

Thanks Ashutosh, This is handled as part of the v6 patch set.

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

#164vignesh C
vignesh21@gmail.com
In reply to: Amit Kapila (#154)
Re: Parallel copy

On Tue, Sep 29, 2020 at 6:30 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Mon, Sep 28, 2020 at 12:19 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

Few additional comments:
======================

Some more comments:

v5-0002-Framework-for-leader-worker-in-parallel-copy
===========================================
1.
These values
+ * help in handover of multiple records with significant size of data to be
+ * processed by each of the workers to make sure there is no context
switch & the
+ * work is fairly distributed among the workers.

How about writing it as: "These values help in the handover of
multiple records with the significant size of data to be processed by
each of the workers. This also ensures there is no context switch and
the work is fairly distributed among the workers."

Changed as suggested.

2. Can we keep WORKER_CHUNK_COUNT, MAX_BLOCKS_COUNT, and RINGSIZE as
power-of-two? Say WORKER_CHUNK_COUNT as 64, MAX_BLOCK_COUNT as 1024,
and accordingly choose RINGSIZE. At many places, we do that way. I
think it can sometimes help in faster processing due to cache size
requirements and in this case, I don't see a reason why we can't
choose these values to be power-of-two. If you agree with this change
then also do some performance testing after this change?

Modified as suggested, Have checked few performance tests & verified
there is no degradation. We will post a performance run of this
separately in the coming days..

3.
+ bool   curr_blk_completed;
+ char   data[DATA_BLOCK_SIZE]; /* data read from file */
+ uint8  skip_bytes;
+} ParallelCopyDataBlock;

Is there a reason to keep skip_bytes after data? Normally the variable
size data is at the end of the structure. Also, there is no comment
explaining the purpose of skip_bytes.

Modified as suggested and added comments.

4.
+ * Copy data block information.
+ * ParallelCopyDataBlock's will be created in DSM. Data read from file will be
+ * copied in these DSM data blocks. The leader process identifies the records
+ * and the record information will be shared to the workers. The workers will
+ * insert the records into the table. There can be one or more number
of records
+ * in each of the data block based on the record size.
+ */
+typedef struct ParallelCopyDataBlock

Keep one empty line after the description line like below. I also
suggested to do a minor tweak in the above sentence which is as
follows:

* Copy data block information.
*
* These data blocks are created in DSM. Data read ...

Try to follow a similar format in other comments as well.

Modified as suggested.

5. I think it is better to move parallelism related code to a new file
(we can name it as copyParallel.c or something like that).

Modified, added copyparallel.c file to include copy parallelism
functionality & copyparallel.c file & some of the function prototype &
data structure were moved to copy.h header file so that it can be
shared between copy.c & copyparallel.c

6. copy.c(1648,25): warning C4133: 'function': incompatible types -
from 'ParallelCopyLineState *' to 'uint32 *'
Getting above compilation warning on Windows.

Modified the data type.

v5-0003-Allow-copy-from-command-to-process-data-from-file
==================================================
1.
@@ -4294,7 +5047,7 @@ BeginCopyFrom(ParseState *pstate,
* only in text mode.
*/
initStringInfo(&cstate->attribute_buf);
- cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+ cstate->raw_buf = (IsParallelCopy()) ? NULL : (char *)
palloc(RAW_BUF_SIZE + 1);

Is there anyway IsParallelCopy can be true by this time? AFAICS, we do
anything about parallelism after this. If you want to save this
allocation then we need to move this after we determine that
parallelism can be used or not and accordingly the below code in the
patch needs to be changed.

* ParallelCopyFrom - parallel copy leader's functionality.
*
* Leader executes the before statement for before statement trigger, if before
@@ -1110,8 +1547,302 @@ ParallelCopyFrom(CopyState cstate)
ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
ereport(DEBUG1, (errmsg("Running parallel copy leader")));

+ /* raw_buf is not used in parallel copy, instead data blocks are used.*/
+ pfree(cstate->raw_buf);
+ cstate->raw_buf = NULL;

Removed the palloc change, raw_buf will be allocated both for parallel
and non parallel copy. One other solution that I thought was to move
the memory allocation to CopyFrom, but this solution might affect fdw
where they use BeginCopyFrom, NextCopyFrom & EndCopyFrom. So I have
kept the allocation as in BeginCopyFrom & freeing for parallel copy in
ParallelCopyFrom.

Is there anything else also the allocation of which depends on parallelism?

I felt this is the only allocated memory that sequential copy requires
and which is not required in parallel copy.

2.
+static pg_attribute_always_inline bool
+IsParallelCopyAllowed(CopyState cstate)
+{
+ /* Parallel copy not allowed for frontend (2.0 protocol) & binary option. */
+ if ((cstate->copy_dest == COPY_OLD_FE) || cstate->binary)
+ return false;
+
+ /* Check if copy is into foreign table or temporary table. */
+ if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
+ RelationUsesLocalBuffers(cstate->rel))
+ return false;
+
+ /* Check if trigger function is parallel safe. */
+ if (cstate->rel->trigdesc != NULL &&
+ !IsTriggerFunctionParallelSafe(cstate->rel->trigdesc))
+ return false;
+
+ /*
+ * Check if there is after statement or instead of trigger or transition
+ * table triggers.
+ */
+ if (cstate->rel->trigdesc != NULL &&
+ (cstate->rel->trigdesc->trig_insert_after_statement ||
+ cstate->rel->trigdesc->trig_insert_instead_row ||
+ cstate->rel->trigdesc->trig_insert_new_table))
+ return false;
+
+ /* Check if the volatile expressions are parallel safe, if present any. */
+ if (!CheckExprParallelSafety(cstate))
+ return false;
+
+ /* Check if the insertion mode is single. */
+ if (FindInsertMethod(cstate) == CIM_SINGLE)
+ return false;
+
+ return true;
+}

In the comments, we should write why parallelism is not allowed for a
particular case. The cases where parallel-unsafe clause is involved
are okay but it is not clear from comments why it is not allowed in
other cases.

Added comments.

3.
+ ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+ ParallelCopyLineBoundary *lineInfo;
+ uint32 line_first_block = pcshared_info->cur_block_pos;
+ line_pos = UpdateBlockInLineInfo(cstate,
+    line_first_block,
+    cstate->raw_buf_index, -1,
+    LINE_LEADER_POPULATING);
+ lineInfo = &pcshared_info->line_boundaries.ring[line_pos];
+ elog(DEBUG1, "[Leader] Adding - block:%d, offset:%d, line position:%d",
+ line_first_block, lineInfo->start_offset, line_pos);

Can we take all the code here inside function UpdateBlockInLineInfo? I
see that it is called from one other place but I guess most of the
surrounding code there can also be moved inside the function. Can we
change the name of the function to UpdateSharedLineInfo or something
like that and remove inline marking from this? I am not sure we want
to inline such big functions. If it make difference in performance
then we can probably consider it.

Changed as suggested.

4.
EndLineParallelCopy()
{
..
+ /* Update line size. */
+ pg_atomic_write_u32(&lineInfo->line_size, line_size);
+ pg_atomic_write_u32(&lineInfo->line_state, LINE_LEADER_POPULATED);
+ elog(DEBUG1, "[Leader] After adding - line position:%d, line_size:%d",
+ line_pos, line_size);
..
}

Can we instead call UpdateSharedLineInfo (new function name for
UpdateBlockInLineInfo) to do this and maybe see it only updates the
required info? The idea is to centralize the code for updating
SharedLineInfo.

Updated as suggested.

5.
+static uint32
+GetLinePosition(CopyState cstate)
+{
+ ParallelCopyData *pcdata = cstate->pcdata;
+ ParallelCopyShmInfo *pcshared_info = pcdata->pcshared_info;
+ uint32  previous_pos = pcdata->worker_processed_pos;
+ uint32 write_pos = (previous_pos == -1) ? 0 : (previous_pos + 1) % RINGSIZE;

It seems to me that each worker has to hop through all the processed
chunks before getting the chunk which it can process. This will work
but I think it is better if we have some shared counter which can tell
us the next chunk to be processed and avoid all the unnecessary work
of hopping to find the exact position.

I had tried to have a spin lock & try to track this position instead
of hopping through the processed chunks. But I did not get the earlier
performance results, there was slight degradation:
Use case 2: 3 indexes on integer columns
Run on earlier patches without spinlock:
(220.680, 0, 1X), (185.096, 1, 1.19X), (134.811, 2, 1.64X), (114.585,
4, 1.92X), (107.707, 8, 2.05X), (101.253, 16, 2.18X), (100.749, 20,
2.19X), (100.656, 30, 2.19X)
Run on latest v6 patches with spinlock:
(216.059, 0, 1X), (177.639, 1, 1.22X), (145.213, 2, 1.49X), (126.370,
4, 1.71X), (121.013, 8, 1.78X), (102.933, 16, 2.1X), (103.000, 20,
2.1X), (100.308, 30, 2.15X)
I have not included these changes as there was some performance
degradation. I will try to come with a different solution for this and
discuss in the coming days. This point is not yet handled.

v5-0004-Documentation-for-parallel-copy
-----------------------------------------
1. Can you add one or two examples towards the end of the page where
we have examples for other Copy options?

Please run pgindent on all patches as that will make the code look better.

Have run pgindent on the latest patches.

From the testing perspective,
1. Test by having something force_parallel_mode = regress which means
that all existing Copy tests in the regression will be executed via
new worker code. You can have this as a test-only patch for now and
make sure all existing tests passed with this.
2. Do we have tests for toast tables? I think if you implement the
previous point some existing tests might cover it but I feel we should
have at least one or two tests for the same.
3. Have we checked the code coverage of the newly added code with
existing tests?

These will be handled in the next few days.

These changes are present as part of the v6 patch set.

I'm summarizing the pending open points so that I don't miss anything:
1) Performance test on latest patch set.
2) Testing points suggested.
3) Support of parallel copy for COPY_OLD_FE.
4) Worker has to hop through all the processed chunks before getting
the chunk which it can process.
5) Handling of Tomas's comments.
6) Handling of Greg's comments.

We plan to work on this & complete in the next few days.

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

#165Amit Kapila
amit.kapila16@gmail.com
In reply to: vignesh C (#159)
Re: Parallel copy

On Thu, Oct 8, 2020 at 12:14 AM vignesh C <vignesh21@gmail.com> wrote:

On Mon, Sep 28, 2020 at 12:19 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

I am convinced by the reason given by Kyotaro-San in that another
thread [1] and performance data shown by Peter that this can't be an
independent improvement and rather in some cases it can do harm. Now,
if you need it for a parallel-copy path then we can change it
specifically to the parallel-copy code path but I don't understand
your reason completely.

Whenever we need data to be populated, we will get a new data block &
pass it to CopyGetData to populate the data. In case of file copy, the
server will completely fill the data block. We expect the data to be
filled completely. If data is available it will completely load the
complete data block in case of file copy. There is no scenario where
even if data is present a partial data block will be returned except
for EOF or no data available. But in case of STDIN data copy, even
though there is 8K data available in data block & 8K data available in
STDIN, CopyGetData will return as soon as libpq buffer data is more
than the minread. We will pass new data block every time to load data.
Every time we pass an 8K data block but CopyGetData loads a few bytes
in the new data block & returns. I wanted to keep the same data
population logic for both file copy & STDIN copy i.e copy full 8K data
blocks & then the populated data can be required. There is an
alternative solution I can have some special handling in case of STDIN
wherein the existing data block can be passed with the index from
where the data should be copied. Thoughts?

What you are proposing as an alternative solution, isn't that what we
are doing without the patch? IIUC, you require this because of your
corresponding changes to handle COPY_NEW_FE in CopyReadLine(), is that
right? If so, what is the difficulty in making it behave similar to
the non-parallel case?

--
With Regards,
Amit Kapila.

#166Amit Kapila
amit.kapila16@gmail.com
In reply to: vignesh C (#159)
Re: Parallel copy

On Thu, Oct 8, 2020 at 12:14 AM vignesh C <vignesh21@gmail.com> wrote:

On Mon, Sep 28, 2020 at 12:19 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

+ */
+typedef struct ParallelCopyLineBoundary

Are we doing all this state management to avoid using locks while
processing lines? If so, I think we can use either spinlock or LWLock
to keep the main patch simple and then provide a later patch to make
it lock-less. This will allow us to first focus on the main design of
the patch rather than trying to make this datastructure processing
lock-less in the best possible way.

The steps will be more or less same if we use spinlock too. step 1, step 3 & step 4 will be common we have to use lock & unlock instead of step 2 & step 5. I feel we can retain the current implementation.

I'll study this in detail and let you know my opinion on the same but
in the meantime, I don't follow one part of this comment: "If they
don't follow this order the worker might process wrong line_size and
leader might populate the information which worker has not yet
processed or in the process of processing."

Do you want to say that leader might overwrite some information which
worker hasn't read yet? If so, it is not clear from the comment.
Another minor point about this comment:

Here leader and worker must follow these steps to avoid any corruption
or hang issue. Changed it to:
* The leader & worker process access the shared line information by following
* the below steps to avoid any data corruption or hang:

Actually, I wanted more on the lines why such corruption or hang can
happen? It might help reviewers to understand why you have followed
such a sequence.

How did you ensure that this is fixed? Have you tested it, if so
please share the test? I see a basic problem with your fix.

+ /* Report WAL/buffer usage during parallel execution */
+ bufferusage = shm_toc_lookup(toc, PARALLEL_COPY_BUFFER_USAGE, false);
+ walusage = shm_toc_lookup(toc, PARALLEL_COPY_WAL_USAGE, false);
+ InstrEndParallelQuery(&bufferusage[ParallelWorkerNumber],
+   &walusage[ParallelWorkerNumber]);

You need to call InstrStartParallelQuery() before the actual operation
starts, without that stats won't be accurate? Also, after calling
WaitForParallelWorkersToFinish(), you need to accumulate the stats
collected from workers which neither you have done nor is possible
with the current code in your patch because you haven't made any
provision to capture them in BeginParallelCopy.

I suggest you look into lazy_parallel_vacuum_indexes() and
begin_parallel_vacuum() to understand how the buffer/wal usage stats
are accumulated. Also, please test this functionality using
pg_stat_statements.

Made changes accordingly.
I have verified it using:
postgres=# select * from pg_stat_statements where query like '%copy%';
userid | dbid | queryid |
query
| plans | total_plan_time |
min_plan_time | max_plan_time | mean_plan_time | stddev_plan_time |
calls | total_exec_time | min_exec_time | max_exec_time |
mean_exec_time | stddev_exec_time | rows | shared_blks_hi
t | shared_blks_read | shared_blks_dirtied | shared_blks_written |
local_blks_hit | local_blks_read | local_blks_dirtied |
local_blks_written | temp_blks_read | temp_blks_written | blk_
read_time | blk_write_time | wal_records | wal_fpi | wal_bytes
--------+-------+----------------------+---------------------------------------------------------------------------------------------------------------------+-------+-----------------+-
--------------+---------------+----------------+------------------+-------+-----------------+---------------+---------------+----------------+------------------+--------+---------------
--+------------------+---------------------+---------------------+----------------+-----------------+--------------------+--------------------+----------------+-------------------+-----
----------+----------------+-------------+---------+-----------
10 | 13743 | -6947756673093447609 | copy hw from
'/home/vignesh/postgres/postgres/inst/bin/hw_175000.csv' with(format
csv, delimiter ',') | 0 | 0 |
0 | 0 | 0 | 0 |
1 | 265.195105 | 265.195105 | 265.195105 | 265.195105
| 0 | 175000 | 191
6 | 0 | 946 | 946 |
0 | 0 | 0 | 0
| 0 | 0 |
0 | 0 | 1116 | 0 | 3587203
10 | 13743 | 8570215596364326047 | copy hw from
'/home/vignesh/postgres/postgres/inst/bin/hw_175000.csv' with(format
csv, delimiter ',', parallel '2') | 0 | 0 |
0 | 0 | 0 | 0 |
1 | 35668.402482 | 35668.402482 | 35668.402482 | 35668.402482
| 0 | 175000 | 310
1 | 36 | 952 | 919 |
0 | 0 | 0 | 0
| 0 | 0 |
0 | 0 | 1119 | 6 | 3624405
(2 rows)

I am not able to properly parse the data but If understand the wal
data for non-parallel (1116 | 0 | 3587203) and parallel (1119
| 6 | 3624405) case doesn't seem to be the same. Is that
right? If so, why? Please ensure that no checkpoint happens for both
cases.

--
With Regards,
Amit Kapila.

#167Amit Kapila
amit.kapila16@gmail.com
In reply to: Greg Nancarrow (#162)
Re: Parallel copy

On Thu, Oct 8, 2020 at 8:43 AM Greg Nancarrow <gregn4422@gmail.com> wrote:

On Thu, Oct 8, 2020 at 5:44 AM vignesh C <vignesh21@gmail.com> wrote:

Attached v6 patch with the fixes.

Hi Vignesh,

I noticed a couple of issues when scanning the code in the following patch:

v6-0003-Allow-copy-from-command-to-process-data-from-file.patch

In the following code, it will put a junk uint16 value into *destptr
(and thus may well cause a crash) on a Big Endian architecture
(Solaris Sparc, s390x, etc.):
You're storing a (uint16) string length in a uint32 and then pulling
out the lower two bytes of the uint32 and copying them into the
location pointed to by destptr.

static void
+CopyStringToSharedMemory(CopyState cstate, char *srcPtr, char *destptr,
+ uint32 *copiedsize)
+{
+ uint32 len = srcPtr ? strlen(srcPtr) + 1 : 0;
+
+ memcpy(destptr, (uint16 *) &len, sizeof(uint16));
+ *copiedsize += sizeof(uint16);
+ if (len)
+ {
+ memcpy(destptr + sizeof(uint16), srcPtr, len);
+ *copiedsize += len;
+ }
+}

I suggest you change the code to:

uint16 len = srcPtr ? (uint16)strlen(srcPtr) + 1 : 0;
memcpy(destptr, &len, sizeof(uint16));

[I assume string length here can't ever exceed (65535 - 1), right?]

Your suggestion makes sense to me if the assumption related to string
length is correct. If we can't ensure that then we need to probably
use four bytes uint32 to store the length.

Looking a bit deeper into this, I'm wondering if in fact your
EstimateStringSize() and EstimateNodeSize() functions should be using
BUFFERALIGN() for EACH stored string/node (rather than just calling
shm_toc_estimate_chunk() once at the end, after the length of packed
strings and nodes has been estimated), to ensure alignment of start of
each string/node. Other Postgres code appears to be aligning each
stored chunk using shm_toc_estimate_chunk(). See the definition of
that macro and its current usages.

I am not sure if this required for the purpose of correctness. AFAIU,
we do store/estimate multiple parameters in same way at other places,
see EstimateParamListSpace and SerializeParamList. Do you have
something else in mind?

While looking at the latest code, I observed below issue in patch
v6-0003-Allow-copy-from-command-to-process-data-from-file:

+ /* Estimate the size for shared information for PARALLEL_COPY_KEY_CSTATE */
+ est_cstateshared = MAXALIGN(sizeof(SerializedParallelCopyState));
+ shm_toc_estimate_chunk(&pcxt->estimator, est_cstateshared);
+ shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+ strsize = EstimateCstateSize(pcxt, cstate, attnamelist, &whereClauseStr,
+ &rangeTableStr, &attnameListStr,
+ &notnullListStr, &nullListStr,
+ &convertListStr);

Here, do we need to separately estimate the size of
SerializedParallelCopyState when it is also done in
EstimateCstateSize?

--
With Regards,
Amit Kapila.

#168Greg Nancarrow
gregn4422@gmail.com
In reply to: Amit Kapila (#167)
Re: Parallel copy

On Fri, Oct 9, 2020 at 5:40 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

Looking a bit deeper into this, I'm wondering if in fact your
EstimateStringSize() and EstimateNodeSize() functions should be using
BUFFERALIGN() for EACH stored string/node (rather than just calling
shm_toc_estimate_chunk() once at the end, after the length of packed
strings and nodes has been estimated), to ensure alignment of start of
each string/node. Other Postgres code appears to be aligning each
stored chunk using shm_toc_estimate_chunk(). See the definition of
that macro and its current usages.

I am not sure if this required for the purpose of correctness. AFAIU,
we do store/estimate multiple parameters in same way at other places,
see EstimateParamListSpace and SerializeParamList. Do you have
something else in mind?

The point I was trying to make is that potentially more efficient code
can be used if the individual strings/nodes are aligned, rather than
packed (as they are now), but as you point out, there are already
cases (e.g. SerializeParamList) where within the separately-aligned
chunks the data is not aligned, so maybe not a big deal. Oh well,
without alignment, that means use of memcpy() cannot really be avoided
here for serializing/de-serializing ints etc., let's hope the compiler
optimizes it as best it can.

Regards,
Greg Nancarrow
Fujitsu Australia

#169Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Amit Kapila (#166)
6 attachment(s)
Re: Parallel copy

On Tue, Sep 29, 2020 at 6:30 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

From the testing perspective,
1. Test by having something force_parallel_mode = regress which means
that all existing Copy tests in the regression will be executed via
new worker code. You can have this as a test-only patch for now and
make sure all existing tests passed with this.

I don't think all the existing copy test cases(except the new test cases
added in the parallel copy patch set) would run inside the parallel worker
if force_parallel_mode is on. This is because, the parallelism will be
picked up for parallel copy only if parallel option is specified unlike
parallelism for select queries.

Anyways, I ran with force_parallel_mode on and regress. All copy related
tests and make check/make check-world ran fine.

2. Do we have tests for toast tables? I think if you implement the
previous point some existing tests might cover it but I feel we should
have at least one or two tests for the same.

Toast table use case 1: 10000 tuples, 9.6GB data, 3 indexes 2 on integer
columns, 1 on text column(not the toast column), csv file, each row is >
1320KB:
(222.767, 0, 1X), (134.171, 1, 1.66X), (93.749, 2, 2.38X), (93.672, 4,
2.38X), (94.827, 8, 2.35X), (93.766, 16, 2.37X), (98.153, 20, 2.27X),
(122.721, 30, 1.81X)

Toast table use case 2: 100000 tuples, 96GB data, 3 indexes 2 on integer
columns, 1 on text column(not the toast column), csv file, each row is >
1320KB:
(2255.032, 0, 1X), (1358.628, 1, 1.66X), (901.170, 2, 2.5X), (912.743, 4,
2.47X), (988.718, 8, 2.28X), (938.000, 16, 2.4X), (997.556, 20, 2.26X),
(1000.586, 30, 2.25X)

Toast table use case3: 10000 tuples, 9.6GB, no indexes, binary file, each
row is > 1320KB:
(136.983, 0, 1X), (136.418, 1, 1X), (81.896, 2, 1.66X), (62.929, 4, 2.16X),
(52.311, 8, 2.6X), (40.032, 16, 3.49X), (44.097, 20, 3.09X), (62.310, 30,
2.18X)

In the case of a Toast table, we could achieve upto 2.5X for csv files, and
3.5X for binary files. We are analyzing this point and will post an update
on our findings soon.

While testing for the Toast table case with a binary file, I discovered an
issue with the earlier v6-0006-Parallel-Copy-For-Binary-Format-Files.patch
from [1]/messages/by-id/CALDaNm29DJKy0-vozs8eeBRf2u3rbvPdZHCocrd0VjoWHS7h5A@mail.gmail.com, I fixed it and added the updated v6-0006 patch here. Please note
that I'm also attaching the 1 to 5 patches from version 6 just for
completion, that have no change from what Vignesh sent earlier in [1]/messages/by-id/CALDaNm29DJKy0-vozs8eeBRf2u3rbvPdZHCocrd0VjoWHS7h5A@mail.gmail.com.

3. Have we checked the code coverage of the newly added code with
existing tests?

So far, we manually ensured that most of the code parts are covered(see
below list of test cases). But we are also planning to do the code coverage
using some tool in the coming days.

Apart from the above tests, I also captured performance measurement on the
latest v6 patch set.

Use case 1: 10million rows, 5.2GB data,2 indexes on integer columns, 1
index on text column, csv file
(1168.484, 0, 1X), (1116.442, 1, 1.05X), (641.272, 2, 1.82X), (338.963, 4,
3.45X), (202.914, 8, 5.76X), (139.884, 16, 8.35X), (128.955, 20, 9.06X),
(131.898, 30, 8.86X)

Use case 2: 10million rows, 5.2GB data,2 indexes on integer columns, 1
index on text column, binary file
(1097.83, 0, 1X), (1095.735, 1, 1.002X), (625.610, 2, 1.75X), (319.833, 4,
3.43X), (186.908, 8, 5.87X), (132.115, 16, 8.31X), (128.854, 20, 8.52X),
(134.965, 30, 8.13X)

Use case 2: 10million rows, 5.2GB data, 3 indexes on integer columns, csv
file
(218.227, 0, 1X), (182.815, 1, 1.19X), (135.500, 2, 1.61), (113.954, 4,
1.91X), (106.243, 8, 2.05X), (101.222, 16, 2.15X), (100.378, 20, 2.17X),
(100.351, 30, 2.17X)

All the above tests are performed on the latest v6 patch set (attached here
in this thread) with custom postgresql.conf[1]/messages/by-id/CALDaNm29DJKy0-vozs8eeBRf2u3rbvPdZHCocrd0VjoWHS7h5A@mail.gmail.com. The results are of the
triplet form (exec time in sec, number of workers, gain)

Overall, we have below test cases to cover the code and for performance
measurements. We plan to run these tests whenever a new set of patches is
posted.

1. csv
2. binary
3. force parallel mode = regress
4. toast data csv and binary
5. foreign key check, before row, after row, before statement, after
statement, instead of triggers
6. partition case
7. foreign partitions and partitions having trigger cases
8. where clause having parallel unsafe and safe expression, default
parallel unsafe and safe expression
9. temp, global, local, unlogged, inherited tables cases, foreign tables

[1]: /messages/by-id/CALDaNm29DJKy0-vozs8eeBRf2u3rbvPdZHCocrd0VjoWHS7h5A@mail.gmail.com
/messages/by-id/CALDaNm29DJKy0-vozs8eeBRf2u3rbvPdZHCocrd0VjoWHS7h5A@mail.gmail.com
[2]: shared_buffers = 40GB max_worker_processes = 32 max_parallel_maintenance_workers = 24 max_parallel_workers = 32 synchronous_commit = off checkpoint_timeout = 1d max_wal_size = 24GB min_wal_size = 15GB autovacuum = off
shared_buffers = 40GB
max_worker_processes = 32
max_parallel_maintenance_workers = 24
max_parallel_workers = 32
synchronous_commit = off
checkpoint_timeout = 1d
max_wal_size = 24GB
min_wal_size = 15GB
autovacuum = off

With Regards,
Bharath Rupireddy.
EnterpriseDB: http://www.enterprisedb.com

Attachments:

v6-0001-Copy-code-readjustment-to-support-parallel-copy.patchapplication/octet-stream; name=v6-0001-Copy-code-readjustment-to-support-parallel-copy.patchDownload
From 2f6fda276f191a3b7a15c07c51199a154530ed09 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Sat, 1 Aug 2020 08:52:48 +0530
Subject: [PATCH v6 1/6] Copy code readjustment to support parallel copy.

This patch has the copy code slightly readjusted so that the common code is
separated to functions/macros, these functions/macros will be used by the
workers in the parallel copy code of the upcoming patches. EOL removal is moved
from CopyReadLine to CopyReadLineText, this change was required because in case
of parallel copy the record identification and record updation is done in
CopyReadLineText, before record information is updated in shared memory the new
line characters should be removed.
---
 src/backend/commands/copy.c | 356 +++++++++++++++++++++++++++-----------------
 1 file changed, 218 insertions(+), 138 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 2047557..f2848a1 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -95,6 +95,9 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
+#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+#define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
+
 /*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
@@ -224,7 +227,6 @@ typedef struct CopyStateData
 	 * appropriate amounts of data from this buffer.  In both modes, we
 	 * guarantee that there is a \0 at raw_buf[raw_buf_len].
 	 */
-#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
@@ -354,6 +356,18 @@ if (1) \
 	goto not_end_of_copy; \
 } else ((void) 0)
 
+/*
+ * Increment the lines processed.
+ */
+#define INCREMENTPROCESSED(processed)  \
+processed++;
+
+/*
+ * Get the lines processed.
+ */
+#define RETURNPROCESSED(processed) \
+return processed;
+
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
 
@@ -401,6 +415,12 @@ static bool CopyGetInt16(CopyState cstate, int16 *val);
 static bool CopyLoadRawBuf(CopyState cstate);
 static int	CopyReadBinaryData(CopyState cstate, char *dest, int nbytes);
 
+static void PopulateCommonCstateInfo(CopyState cstate, TupleDesc tup_desc,
+									 List *attnamelist);
+static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
+								   int copy_line_pos, int *copy_line_size);
+static void ConvertToServerEncoding(CopyState cstate);
+
 
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
@@ -801,14 +821,18 @@ CopyLoadRawBuf(CopyState cstate)
 {
 	int			nbytes = RAW_BUF_BYTES(cstate);
 	int			inbytes;
+	int			minread = 1;
 
 	/* Copy down the unprocessed data if any. */
 	if (nbytes > 0)
 		memmove(cstate->raw_buf, cstate->raw_buf + cstate->raw_buf_index,
 				nbytes);
 
+	if (cstate->copy_dest == COPY_NEW_FE)
+		minread = RAW_BUF_SIZE - nbytes;
+
 	inbytes = CopyGetData(cstate, cstate->raw_buf + nbytes,
-						  1, RAW_BUF_SIZE - nbytes);
+						  minread, RAW_BUF_SIZE - nbytes);
 	nbytes += inbytes;
 	cstate->raw_buf[nbytes] = '\0';
 	cstate->raw_buf_index = 0;
@@ -1514,7 +1538,6 @@ BeginCopy(ParseState *pstate,
 {
 	CopyState	cstate;
 	TupleDesc	tupDesc;
-	int			num_phys_attrs;
 	MemoryContext oldcontext;
 
 	/* Allocate workspace and zero all fields */
@@ -1680,6 +1703,25 @@ BeginCopy(ParseState *pstate,
 		tupDesc = cstate->queryDesc->tupDesc;
 	}
 
+	PopulateCommonCstateInfo(cstate, tupDesc, attnamelist);
+	cstate->copy_dest = COPY_FILE;	/* default */
+
+	MemoryContextSwitchTo(oldcontext);
+
+	return cstate;
+}
+
+/*
+ * PopulateCommonCstateInfo
+ *
+ * Populates the common variables required for copy from operation. This is a
+ * helper function for BeginCopy function.
+ */
+static void
+PopulateCommonCstateInfo(CopyState cstate, TupleDesc tupDesc, List *attnamelist)
+{
+	int			num_phys_attrs;
+
 	/* Generate or convert list of attributes to process */
 	cstate->attnumlist = CopyGetAttnums(tupDesc, cstate->rel, attnamelist);
 
@@ -1799,12 +1841,6 @@ BeginCopy(ParseState *pstate,
 		 pg_database_encoding_max_length() > 1);
 	/* See Multibyte encoding comment above */
 	cstate->encoding_embeds_ascii = PG_ENCODING_IS_CLIENT_ONLY(cstate->file_encoding);
-
-	cstate->copy_dest = COPY_FILE;	/* default */
-
-	MemoryContextSwitchTo(oldcontext);
-
-	return cstate;
 }
 
 /*
@@ -2696,32 +2732,13 @@ CopyMultiInsertInfoStore(CopyMultiInsertInfo *miinfo, ResultRelInfo *rri,
 }
 
 /*
- * Copy FROM file to relation.
+ * CheckTargetRelValidity
+ *
+ * Check if the relation specified in copy from is valid.
  */
-uint64
-CopyFrom(CopyState cstate)
+static void
+CheckTargetRelValidity(CopyState cstate)
 {
-	ResultRelInfo *resultRelInfo;
-	ResultRelInfo *target_resultRelInfo;
-	ResultRelInfo *prevResultRelInfo = NULL;
-	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
-	ModifyTableState *mtstate;
-	ExprContext *econtext;
-	TupleTableSlot *singleslot = NULL;
-	MemoryContext oldcontext = CurrentMemoryContext;
-
-	PartitionTupleRouting *proute = NULL;
-	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
-	int			ti_options = 0; /* start with default options for insert */
-	BulkInsertState bistate = NULL;
-	CopyInsertMethod insertMethod;
-	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
-	uint64		processed = 0;
-	bool		has_before_insert_row_trig;
-	bool		has_instead_insert_row_trig;
-	bool		leafpart_use_multi_insert = false;
-
 	Assert(cstate->rel);
 
 	/*
@@ -2758,27 +2775,6 @@ CopyFrom(CopyState cstate)
 							RelationGetRelationName(cstate->rel))));
 	}
 
-	/*
-	 * If the target file is new-in-transaction, we assume that checking FSM
-	 * for free space is a waste of time.  This could possibly be wrong, but
-	 * it's unlikely.
-	 */
-	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
-		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
-		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
-		ti_options |= TABLE_INSERT_SKIP_FSM;
-
-	/*
-	 * Optimize if new relfilenode was created in this subxact or one of its
-	 * committed children and we won't see those rows later as part of an
-	 * earlier scan or command. The subxact test ensures that if this subxact
-	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
-	 * that the stronger test of exactly which subtransaction created it is
-	 * crucial for correctness of this optimization. The test for an earlier
-	 * scan or command tolerates false negatives. FREEZE causes other sessions
-	 * to see rows they would not see under MVCC, and a false negative merely
-	 * spreads that anomaly to the current session.
-	 */
 	if (cstate->freeze)
 	{
 		/*
@@ -2816,9 +2812,61 @@ CopyFrom(CopyState cstate)
 			ereport(ERROR,
 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 					 errmsg("cannot perform COPY FREEZE because the table was not created or truncated in the current subtransaction")));
+	}
+}
+
+/*
+ * Copy FROM file to relation.
+ */
+uint64
+CopyFrom(CopyState cstate)
+{
+	ResultRelInfo *resultRelInfo;
+	ResultRelInfo *target_resultRelInfo;
+	ResultRelInfo *prevResultRelInfo = NULL;
+	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
+	ModifyTableState *mtstate;
+	ExprContext *econtext;
+	TupleTableSlot *singleslot = NULL;
+	MemoryContext oldcontext = CurrentMemoryContext;
+
+	PartitionTupleRouting *proute = NULL;
+	ErrorContextCallback errcallback;
+	CommandId	mycid = GetCurrentCommandId(true);
+	int			ti_options = 0; /* start with default options for insert */
+	BulkInsertState bistate = NULL;
+	CopyInsertMethod insertMethod;
+	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
+	uint64		processed = 0;
+	bool		has_before_insert_row_trig;
+	bool		has_instead_insert_row_trig;
+	bool		leafpart_use_multi_insert = false;
 
+	CheckTargetRelValidity(cstate);
+
+	/*
+	 * If the target file is new-in-transaction, we assume that checking FSM
+	 * for free space is a waste of time.  This could possibly be wrong, but
+	 * it's unlikely.
+	 */
+	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
+		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
+		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
+		ti_options |= TABLE_INSERT_SKIP_FSM;
+
+	/*
+	 * Optimize if new relfilenode was created in this subxact or one of its
+	 * committed children and we won't see those rows later as part of an
+	 * earlier scan or command. The subxact test ensures that if this subxact
+	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
+	 * that the stronger test of exactly which subtransaction created it is
+	 * crucial for correctness of this optimization. The test for an earlier
+	 * scan or command tolerates false negatives. FREEZE causes other sessions
+	 * to see rows they would not see under MVCC, and a false negative merely
+	 * spreads that anomaly to the current session.
+	 */
+	if (cstate->freeze)
 		ti_options |= TABLE_INSERT_FROZEN;
-	}
 
 	/*
 	 * We need a ResultRelInfo so we can use the regular executor's
@@ -3311,7 +3359,7 @@ CopyFrom(CopyState cstate)
 			 * or FDW; this is the same definition used by nodeModifyTable.c
 			 * for counting tuples inserted by an INSERT command.
 			 */
-			processed++;
+			INCREMENTPROCESSED(processed)
 		}
 	}
 
@@ -3366,30 +3414,17 @@ CopyFrom(CopyState cstate)
 
 	FreeExecutorState(estate);
 
-	return processed;
+	RETURNPROCESSED(processed)
 }
 
 /*
- * Setup to read tuples from a file for COPY FROM.
+ * PopulateCstateCatalogInfo
  *
- * 'rel': Used as a template for the tuples
- * 'filename': Name of server-local file to read
- * 'attnamelist': List of char *, columns to include. NIL selects all cols.
- * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
- *
- * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ * Populate the cstate catalog information.
  */
-CopyState
-BeginCopyFrom(ParseState *pstate,
-			  Relation rel,
-			  const char *filename,
-			  bool is_program,
-			  copy_data_source_cb data_source_cb,
-			  List *attnamelist,
-			  List *options)
+static void
+PopulateCstateCatalogInfo(CopyState cstate)
 {
-	CopyState	cstate;
-	bool		pipe = (filename == NULL);
 	TupleDesc	tupDesc;
 	AttrNumber	num_phys_attrs,
 				num_defaults;
@@ -3399,38 +3434,8 @@ BeginCopyFrom(ParseState *pstate,
 	Oid			in_func_oid;
 	int		   *defmap;
 	ExprState **defexprs;
-	MemoryContext oldcontext;
 	bool		volatile_defexprs;
 
-	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
-	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
-
-	/* Initialize state variables */
-	cstate->reached_eof = false;
-	cstate->eol_type = EOL_UNKNOWN;
-	cstate->cur_relname = RelationGetRelationName(cstate->rel);
-	cstate->cur_lineno = 0;
-	cstate->cur_attname = NULL;
-	cstate->cur_attval = NULL;
-
-	/*
-	 * Set up variables to avoid per-attribute overhead.  attribute_buf and
-	 * raw_buf are used in both text and binary modes, but we use line_buf
-	 * only in text mode.
-	 */
-	initStringInfo(&cstate->attribute_buf);
-	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
-	cstate->raw_buf_index = cstate->raw_buf_len = 0;
-	if (!cstate->binary)
-	{
-		initStringInfo(&cstate->line_buf);
-		cstate->line_buf_converted = false;
-	}
-
-	/* Assign range table, we'll need it in CopyFrom. */
-	if (pstate)
-		cstate->range_table = pstate->p_rtable;
-
 	tupDesc = RelationGetDescr(cstate->rel);
 	num_phys_attrs = tupDesc->natts;
 	num_defaults = 0;
@@ -3508,6 +3513,61 @@ BeginCopyFrom(ParseState *pstate,
 	cstate->defexprs = defexprs;
 	cstate->volatile_defexprs = volatile_defexprs;
 	cstate->num_defaults = num_defaults;
+}
+
+/*
+ * Setup to read tuples from a file for COPY FROM.
+ *
+ * 'rel': Used as a template for the tuples
+ * 'filename': Name of server-local file to read
+ * 'attnamelist': List of char *, columns to include. NIL selects all cols.
+ * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
+ *
+ * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ */
+CopyState
+BeginCopyFrom(ParseState *pstate,
+			  Relation rel,
+			  const char *filename,
+			  bool is_program,
+			  copy_data_source_cb data_source_cb,
+			  List *attnamelist,
+			  List *options)
+{
+	CopyState	cstate;
+	bool		pipe = (filename == NULL);
+	MemoryContext oldcontext;
+
+	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	/* Initialize state variables */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/*
+	 * Set up variables to avoid per-attribute overhead.  attribute_buf is
+	 * used in both text and binary modes, but we use line_buf and raw_buf
+	 * only in text mode.
+	 */
+	initStringInfo(&cstate->attribute_buf);
+	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+	if (!cstate->binary)
+	{
+		initStringInfo(&cstate->line_buf);
+		cstate->line_buf_converted = false;
+	}
+
+	/* Assign range table, we'll need it in CopyFrom. */
+	if (pstate)
+		cstate->range_table = pstate->p_rtable;
+
+	PopulateCstateCatalogInfo(cstate);
 	cstate->is_program = is_program;
 
 	if (data_source_cb)
@@ -3917,40 +3977,60 @@ CopyReadLine(CopyState cstate)
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
-	else
+
+	ConvertToServerEncoding(cstate);
+	return result;
+}
+
+/*
+ * ClearEOLFromCopiedData
+ *
+ * Clear EOL from the copied data.
+ */
+static void
+ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
+					   int copy_line_pos, int *copy_line_size)
+{
+	/*
+	 * If we didn't hit EOF, then we must have transferred the EOL marker to
+	 * line_buf along with the data.  Get rid of it.
+	 */
+	switch (cstate->eol_type)
 	{
-		/*
-		 * If we didn't hit EOF, then we must have transferred the EOL marker
-		 * to line_buf along with the data.  Get rid of it.
-		 */
-		switch (cstate->eol_type)
-		{
-			case EOL_NL:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CR:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\r');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CRNL:
-				Assert(cstate->line_buf.len >= 2);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 2] == '\r');
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len -= 2;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_UNKNOWN:
-				/* shouldn't get here */
-				Assert(false);
-				break;
-		}
+		case EOL_NL:
+			Assert(*copy_line_size >= 1);
+			Assert(copy_line_data[copy_line_pos - 1] == '\n');
+			copy_line_data[copy_line_pos - 1] = '\0';
+			(*copy_line_size)--;
+			break;
+		case EOL_CR:
+			Assert(*copy_line_size >= 1);
+			Assert(copy_line_data[copy_line_pos - 1] == '\r');
+			copy_line_data[copy_line_pos - 1] = '\0';
+			(*copy_line_size)--;
+			break;
+		case EOL_CRNL:
+			Assert(*copy_line_size >= 2);
+			Assert(copy_line_data[copy_line_pos - 2] == '\r');
+			Assert(copy_line_data[copy_line_pos - 1] == '\n');
+			copy_line_data[copy_line_pos - 2] = '\0';
+			*copy_line_size -= 2;
+			break;
+		case EOL_UNKNOWN:
+			/* shouldn't get here */
+			Assert(false);
+			break;
 	}
+}
 
+/*
+ * ConvertToServerEncoding
+ *
+ * Convert contents to server encoding.
+ */
+static void
+ConvertToServerEncoding(CopyState cstate)
+{
 	/* Done reading the line.  Convert it to server encoding. */
 	if (cstate->need_transcoding)
 	{
@@ -3967,11 +4047,8 @@ CopyReadLine(CopyState cstate)
 			pfree(cvt);
 		}
 	}
-
 	/* Now it's safe to use the buffer in error messages */
 	cstate->line_buf_converted = true;
-
-	return result;
 }
 
 /*
@@ -4334,6 +4411,9 @@ not_end_of_copy:
 	 * Transfer any still-uncopied data to line_buf.
 	 */
 	REFILL_LINEBUF;
+	if (!result && !IsHeaderLine())
+		ClearEOLFromCopiedData(cstate, cstate->line_buf.data,
+							   cstate->line_buf.len, &cstate->line_buf.len);
 
 	return result;
 }
-- 
1.8.3.1

v6-0002-Framework-for-leader-worker-in-parallel-copy.patchapplication/octet-stream; name=v6-0002-Framework-for-leader-worker-in-parallel-copy.patchDownload
From 67e5240af5ebe803473acebaf0e8796fd2a05cdd Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 7 Oct 2020 17:18:17 +0530
Subject: [PATCH v6 2/6] Framework for leader/worker in parallel copy

This patch has the framework for data structures in parallel copy, leader
initialization, worker initialization, shared memory updation, starting workers,
wait for workers and workers exiting.
---
 src/backend/access/transam/parallel.c |   4 +
 src/backend/commands/Makefile         |   1 +
 src/backend/commands/copy.c           | 235 ++++++--------------
 src/include/commands/copy.h           | 389 +++++++++++++++++++++++++++++++++-
 src/tools/pgindent/typedefs.list      |   7 +
 5 files changed, 469 insertions(+), 167 deletions(-)

diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index b042696..a3cff4b 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -25,6 +25,7 @@
 #include "catalog/pg_enum.h"
 #include "catalog/storage.h"
 #include "commands/async.h"
+#include "commands/copy.h"
 #include "executor/execParallel.h"
 #include "libpq/libpq.h"
 #include "libpq/pqformat.h"
@@ -145,6 +146,9 @@ static const struct
 	},
 	{
 		"parallel_vacuum_main", parallel_vacuum_main
+	},
+	{
+		"ParallelCopyMain", ParallelCopyMain
 	}
 };
 
diff --git a/src/backend/commands/Makefile b/src/backend/commands/Makefile
index d4815d3..a224aac 100644
--- a/src/backend/commands/Makefile
+++ b/src/backend/commands/Makefile
@@ -24,6 +24,7 @@ OBJS = \
 	constraint.o \
 	conversioncmds.o \
 	copy.o \
+	copyparallel.o \
 	createas.o \
 	dbcommands.o \
 	define.o \
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index f2848a1..1e55a30 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -29,7 +29,6 @@
 #include "catalog/pg_type.h"
 #include "commands/copy.h"
 #include "commands/defrem.h"
-#include "commands/trigger.h"
 #include "executor/execPartition.h"
 #include "executor/executor.h"
 #include "executor/nodeModifyTable.h"
@@ -63,29 +62,6 @@
 #define OCTVALUE(c) ((c) - '0')
 
 /*
- * Represents the different source/dest cases we need to worry about at
- * the bottom level
- */
-typedef enum CopyDest
-{
-	COPY_FILE,					/* to/from file (or a piped program) */
-	COPY_OLD_FE,				/* to/from frontend (2.0 protocol) */
-	COPY_NEW_FE,				/* to/from frontend (3.0 protocol) */
-	COPY_CALLBACK				/* to/from callback function */
-} CopyDest;
-
-/*
- *	Represents the end-of-line terminator type of the input
- */
-typedef enum EolType
-{
-	EOL_UNKNOWN,
-	EOL_NL,
-	EOL_CR,
-	EOL_CRNL
-} EolType;
-
-/*
  * Represents the heap insert method to be used during COPY FROM.
  */
 typedef enum CopyInsertMethod
@@ -95,145 +71,10 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
-#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+#define IsParallelCopy()		(cstate->is_parallel)
+#define IsLeader()				(cstate->pcdata->is_leader)
 #define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
 
-/*
- * This struct contains all the state variables used throughout a COPY
- * operation. For simplicity, we use the same struct for all variants of COPY,
- * even though some fields are used in only some cases.
- *
- * Multi-byte encodings: all supported client-side encodings encode multi-byte
- * characters by having the first byte's high bit set. Subsequent bytes of the
- * character can have the high bit not set. When scanning data in such an
- * encoding to look for a match to a single-byte (ie ASCII) character, we must
- * use the full pg_encoding_mblen() machinery to skip over multibyte
- * characters, else we might find a false match to a trailing byte. In
- * supported server encodings, there is no possibility of a false match, and
- * it's faster to make useless comparisons to trailing bytes than it is to
- * invoke pg_encoding_mblen() to skip over them. encoding_embeds_ascii is true
- * when we have to do it the hard way.
- */
-typedef struct CopyStateData
-{
-	/* low-level state data */
-	CopyDest	copy_dest;		/* type of copy source/destination */
-	FILE	   *copy_file;		/* used if copy_dest == COPY_FILE */
-	StringInfo	fe_msgbuf;		/* used for all dests during COPY TO, only for
-								 * dest == COPY_NEW_FE in COPY FROM */
-	bool		is_copy_from;	/* COPY TO, or COPY FROM? */
-	bool		reached_eof;	/* true if we read to end of copy data (not
-								 * all copy_dest types maintain this) */
-	EolType		eol_type;		/* EOL type of input */
-	int			file_encoding;	/* file or remote side's character encoding */
-	bool		need_transcoding;	/* file encoding diff from server? */
-	bool		encoding_embeds_ascii;	/* ASCII can be non-first byte? */
-
-	/* parameters from the COPY command */
-	Relation	rel;			/* relation to copy to or from */
-	QueryDesc  *queryDesc;		/* executable query to copy from */
-	List	   *attnumlist;		/* integer list of attnums to copy */
-	char	   *filename;		/* filename, or NULL for STDIN/STDOUT */
-	bool		is_program;		/* is 'filename' a program to popen? */
-	copy_data_source_cb data_source_cb; /* function for reading data */
-	bool		binary;			/* binary format? */
-	bool		freeze;			/* freeze rows on loading? */
-	bool		csv_mode;		/* Comma Separated Value format? */
-	bool		header_line;	/* CSV header line? */
-	char	   *null_print;		/* NULL marker string (server encoding!) */
-	int			null_print_len; /* length of same */
-	char	   *null_print_client;	/* same converted to file encoding */
-	char	   *delim;			/* column delimiter (must be 1 byte) */
-	char	   *quote;			/* CSV quote char (must be 1 byte) */
-	char	   *escape;			/* CSV escape char (must be 1 byte) */
-	List	   *force_quote;	/* list of column names */
-	bool		force_quote_all;	/* FORCE_QUOTE *? */
-	bool	   *force_quote_flags;	/* per-column CSV FQ flags */
-	List	   *force_notnull;	/* list of column names */
-	bool	   *force_notnull_flags;	/* per-column CSV FNN flags */
-	List	   *force_null;		/* list of column names */
-	bool	   *force_null_flags;	/* per-column CSV FN flags */
-	bool		convert_selectively;	/* do selective binary conversion? */
-	List	   *convert_select; /* list of column names (can be NIL) */
-	bool	   *convert_select_flags;	/* per-column CSV/TEXT CS flags */
-	Node	   *whereClause;	/* WHERE condition (or NULL) */
-
-	/* these are just for error messages, see CopyFromErrorCallback */
-	const char *cur_relname;	/* table name for error messages */
-	uint64		cur_lineno;		/* line number for error messages */
-	const char *cur_attname;	/* current att for error messages */
-	const char *cur_attval;		/* current att value for error messages */
-
-	/*
-	 * Working state for COPY TO/FROM
-	 */
-	MemoryContext copycontext;	/* per-copy execution context */
-
-	/*
-	 * Working state for COPY TO
-	 */
-	FmgrInfo   *out_functions;	/* lookup info for output functions */
-	MemoryContext rowcontext;	/* per-row evaluation context */
-
-	/*
-	 * Working state for COPY FROM
-	 */
-	AttrNumber	num_defaults;
-	FmgrInfo   *in_functions;	/* array of input functions for each attrs */
-	Oid		   *typioparams;	/* array of element types for in_functions */
-	int		   *defmap;			/* array of default att numbers */
-	ExprState **defexprs;		/* array of default att expressions */
-	bool		volatile_defexprs;	/* is any of defexprs volatile? */
-	List	   *range_table;
-	ExprState  *qualexpr;
-
-	TransitionCaptureState *transition_capture;
-
-	/*
-	 * These variables are used to reduce overhead in COPY FROM.
-	 *
-	 * attribute_buf holds the separated, de-escaped text for each field of
-	 * the current line.  The CopyReadAttributes functions return arrays of
-	 * pointers into this buffer.  We avoid palloc/pfree overhead by re-using
-	 * the buffer on each cycle.
-	 *
-	 * In binary COPY FROM, attribute_buf holds the binary data for the
-	 * current field, but the usage is otherwise similar.
-	 */
-	StringInfoData attribute_buf;
-
-	/* field raw data pointers found by COPY FROM */
-
-	int			max_fields;
-	char	  **raw_fields;
-
-	/*
-	 * Similarly, line_buf holds the whole input line being processed. The
-	 * input cycle is first to read the whole line into line_buf, convert it
-	 * to server encoding there, and then extract the individual attribute
-	 * fields into attribute_buf.  line_buf is preserved unmodified so that we
-	 * can display it in error messages if appropriate.  (In binary mode,
-	 * line_buf is not used.)
-	 */
-	StringInfoData line_buf;
-	bool		line_buf_converted; /* converted to server encoding? */
-	bool		line_buf_valid; /* contains the row being processed? */
-
-	/*
-	 * Finally, raw_buf holds raw data read from the data source (file or
-	 * client connection).  In text mode, CopyReadLine parses this data
-	 * sufficiently to locate line boundaries, then transfers the data to
-	 * line_buf and converts it.  In binary mode, CopyReadBinaryData fetches
-	 * appropriate amounts of data from this buffer.  In both modes, we
-	 * guarantee that there is a \0 at raw_buf[raw_buf_len].
-	 */
-	char	   *raw_buf;
-	int			raw_buf_index;	/* next byte to process */
-	int			raw_buf_len;	/* total # of bytes stored */
-	/* Shorthand for number of unconsumed bytes available in raw_buf */
-#define RAW_BUF_BYTES(cstate) ((cstate)->raw_buf_len - (cstate)->raw_buf_index)
-} CopyStateData;
-
 /* DestReceiver for COPY (query) TO */
 typedef struct
 {
@@ -415,8 +256,6 @@ static bool CopyGetInt16(CopyState cstate, int16 *val);
 static bool CopyLoadRawBuf(CopyState cstate);
 static int	CopyReadBinaryData(CopyState cstate, char *dest, int nbytes);
 
-static void PopulateCommonCstateInfo(CopyState cstate, TupleDesc tup_desc,
-									 List *attnamelist);
 static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
 								   int copy_line_pos, int *copy_line_size);
 static void ConvertToServerEncoding(CopyState cstate);
@@ -1134,6 +973,8 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 
 	if (is_from)
 	{
+		ParallelContext *pcxt = NULL;
+
 		Assert(rel);
 
 		/* check read-only transaction and parallel mode */
@@ -1143,7 +984,35 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 		cstate = BeginCopyFrom(pstate, rel, stmt->filename, stmt->is_program,
 							   NULL, stmt->attlist, stmt->options);
 		cstate->whereClause = whereClause;
-		*processed = CopyFrom(cstate);	/* copy from file to database */
+		cstate->is_parallel = false;
+
+		if (cstate->nworkers > 0)
+			pcxt = BeginParallelCopy(cstate->nworkers, cstate, stmt->attlist,
+									 relid);
+
+		if (pcxt)
+		{
+			int			i;
+
+			ParallelCopyFrom(cstate);
+
+			/* Wait for all copy workers to finish */
+			WaitForParallelWorkersToFinish(pcxt);
+
+			/*
+			 * Next, accumulate WAL usage.  (This must wait for the workers to
+			 * finish, or we might get incomplete data.)
+			 */
+			for (i = 0; i < pcxt->nworkers_launched; i++)
+				InstrAccumParallelQuery(&cstate->pcdata->bufferusage[i],
+										&cstate->pcdata->walusage[i]);
+
+			*processed = pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
+			EndParallelCopy(pcxt);
+		}
+		else
+			*processed = CopyFrom(cstate);	/* copy from file to database */
+
 		EndCopyFrom(cstate);
 	}
 	else
@@ -1192,6 +1061,7 @@ ProcessCopyOptions(ParseState *pstate,
 	cstate->is_copy_from = is_from;
 
 	cstate->file_encoding = -1;
+	cstate->nworkers = -1;
 
 	/* Extract options from the statement node tree */
 	foreach(option, options)
@@ -1360,6 +1230,39 @@ ProcessCopyOptions(ParseState *pstate,
 								defel->defname),
 						 parser_errposition(pstate, defel->location)));
 		}
+		else if (strcmp(defel->defname, "parallel") == 0)
+		{
+			int			val;
+			bool		parsed;
+			char	   *strval;
+
+			if (!cstate->is_copy_from)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("parallel option is supported only for copy from"),
+						 parser_errposition(pstate, defel->location)));
+			if (cstate->nworkers >= 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options"),
+						 parser_errposition(pstate, defel->location)));
+
+			strval = defGetString(defel);
+			parsed = parse_int(strval, &val, 0, NULL);
+			if (!parsed)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("invalid value for integer option \"%s\": %s",
+								defel->defname, strval)));
+			if (val < 1 || val > 1024)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("value %s out of bounds for option \"%s\"",
+								strval, defel->defname),
+						 errdetail("Valid values are between \"%d\" and \"%d\".",
+								   1, 1024)));
+			cstate->nworkers = val;
+		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_SYNTAX_ERROR),
@@ -1715,9 +1618,9 @@ BeginCopy(ParseState *pstate,
  * PopulateCommonCstateInfo
  *
  * Populates the common variables required for copy from operation. This is a
- * helper function for BeginCopy function.
+ * helper function for BeginCopy & InitializeParallelCopyInfo function.
  */
-static void
+void
 PopulateCommonCstateInfo(CopyState cstate, TupleDesc tupDesc, List *attnamelist)
 {
 	int			num_phys_attrs;
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index c639833..cd2d56e 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -14,14 +14,394 @@
 #ifndef COPY_H
 #define COPY_H
 
+#include "access/parallel.h"
+#include "commands/trigger.h"
+#include "executor/executor.h"
 #include "nodes/execnodes.h"
 #include "nodes/parsenodes.h"
 #include "parser/parse_node.h"
 #include "tcop/dest.h"
 
+#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+
+/*
+ * The macros DATA_BLOCK_SIZE, RINGSIZE & MAX_BLOCKS_COUNT stores the records
+ * read from the file that need to be inserted into the relation. These values
+ * help in the handover of multiple records with the significant size of data to
+ * be processed by each of the workers. This also ensures there is no context
+ * switch and the work is fairly distributed among the workers. This number
+ * showed best results in the performance tests.
+ */
+#define DATA_BLOCK_SIZE RAW_BUF_SIZE
+
+/* It can hold 1023 blocks of 64K data in DSM to be processed by the worker. */
+#define MAX_BLOCKS_COUNT 1024
+
+/*
+ * It can hold upto 10240 record information for worker to process. RINGSIZE
+ * should be a multiple of WORKER_CHUNK_COUNT, as wrap around cases is currently
+ * not handled while selecting the WORKER_CHUNK_COUNT by the worker.
+ */
+#define RINGSIZE (10 * 1024)
+
+/*
+ * Each worker will be allocated WORKER_CHUNK_COUNT of records from DSM data
+ * block to process to avoid lock contention. Read RINGSIZE comments before
+ * changing this value.
+ */
+#define WORKER_CHUNK_COUNT 64
+
+/*
+ * Represents the different source/dest cases we need to worry about at
+ * the bottom level
+ */
+typedef enum CopyDest
+{
+	COPY_FILE,					/* to/from file (or a piped program) */
+	COPY_OLD_FE,				/* to/from frontend (2.0 protocol) */
+	COPY_NEW_FE,				/* to/from frontend (3.0 protocol) */
+	COPY_CALLBACK				/* to/from callback function */
+} CopyDest;
+
+/*
+ *	Represents the end-of-line terminator type of the input
+ */
+typedef enum EolType
+{
+	EOL_UNKNOWN,
+	EOL_NL,
+	EOL_CR,
+	EOL_CRNL
+} EolType;
+
+/*
+ * Copy data block information.
+ *
+ * These data blocks are created in DSM. Data read from file will be copied in
+ * these DSM data blocks. The leader process identifies the records and the
+ * record information will be shared to the workers. The workers will insert the
+ * records into the table. There can be one or more number of records in each of
+ * the data block based on the record size.
+ */
+typedef struct ParallelCopyDataBlock
+{
+	/* The number of unprocessed lines in the current block. */
+	pg_atomic_uint32 unprocessed_line_parts;
+
+	/*
+	 * If the current line data is continued into another block,
+	 * following_block will have the position where the remaining data need to
+	 * be read.
+	 */
+	uint32		following_block;
+
+	/*
+	 * This flag will be set, when the leader finds out this block can be read
+	 * safely by the worker. This helps the worker to start processing the
+	 * line early where the line will be spread across many blocks and the
+	 * worker need not wait for the complete line to be processed.
+	 */
+	bool		curr_blk_completed;
+
+	/*
+	 * Few bytes need to be skipped from this block, this will be set when a
+	 * sequence of characters like \r\n is expected, but end of our block
+	 * contained only \r. In this case we copy the data from \r into the new
+	 * block as they have to be processed together to identify end of line.
+	 * Worker will use skip_bytes to know that this data must be skipped from
+	 * this data block.
+	 */
+	uint8		skip_bytes;
+	char		data[DATA_BLOCK_SIZE];	/* data read from file */
+} ParallelCopyDataBlock;
+
+/*
+ * Individual line information.
+ *
+ * ParallelCopyLineBoundary is common data structure between leader & worker.
+ * Leader process will be populating data block, data block offset & the size of
+ * the record in DSM for the workers to copy the data into the relation.
+ * The leader & worker process access the shared line information by following
+ * the below steps to avoid any data corruption or hang:
+ * Leader should operate in the following order:
+ * 1) check if line_size is -1, if line_size is not -1 wait until line_size is
+ * set to -1 by the worker. If line_size is -1 it means worker is still
+ * processing.
+ * 2) set line_state to LINE_LEADER_POPULATING, so that the worker knows that
+ * leader is populating this line.
+ * 3) update first_block, start_offset & cur_lineno in any order.
+ * 4) update line_size.
+ * 5) update line_state to LINE_LEADER_POPULATED.
+ * Worker should operate in the following order:
+ * 1) check line_state is LINE_LEADER_POPULATED, if not it means leader is still
+ * populating the data.
+ * 2) read line_size to know the size of the data.
+ * 3) only one worker should choose one line for processing, this is handled by
+ *    using pg_atomic_compare_exchange_u32, worker will change the state to
+ *    LINE_WORKER_PROCESSING only if line_state is LINE_LEADER_POPULATED.
+ * 4) read first_block, start_offset & cur_lineno in any order.
+ * 5) process line_size data.
+ * 6) update line_size to -1.
+ */
+typedef struct ParallelCopyLineBoundary
+{
+	/* Position of the first block in data_blocks array. */
+	uint32		first_block;
+	uint32		start_offset;	/* start offset of the line */
+
+	/*
+	 * Size of the current line -1 means line is yet to be filled completely,
+	 * 0 means empty line, >0 means line filled with line size data.
+	 */
+	pg_atomic_uint32 line_size;
+	pg_atomic_uint32 line_state;	/* line state */
+	uint64		cur_lineno;		/* line number for error messages */
+} ParallelCopyLineBoundary;
+
+/*
+ * Circular queue used to store the line information.
+ */
+typedef struct ParallelCopyLineBoundaries
+{
+	/* Position for the leader to populate a line. */
+	uint32		pos;
+
+	/* Data read from the file/stdin by the leader process. */
+	ParallelCopyLineBoundary ring[RINGSIZE];
+} ParallelCopyLineBoundaries;
+
+/*
+ * Shared information among parallel copy workers. This will be allocated in the
+ * DSM segment.
+ */
+typedef struct ParallelCopyShmInfo
+{
+	bool		is_read_in_progress;	/* file read status */
+
+	/*
+	 * Actual lines inserted by worker, will not be same as
+	 * total_worker_processed if where condition is specified along with copy.
+	 * This will be the actual records inserted into the relation.
+	 */
+	pg_atomic_uint64 processed;
+
+	/*
+	 * The number of records currently processed by the worker, this will also
+	 * include the number of records that was filtered because of where
+	 * clause.
+	 */
+	pg_atomic_uint64 total_worker_processed;
+	uint64		populated;		/* lines populated by leader */
+	uint32		cur_block_pos;	/* current data block */
+	ParallelCopyDataBlock data_blocks[MAX_BLOCKS_COUNT];	/* data block array */
+	FullTransactionId full_transaction_id;	/* xid for copy from statement */
+	CommandId	mycid;			/* command id */
+	ParallelCopyLineBoundaries line_boundaries; /* line array */
+} ParallelCopyShmInfo;
+
+/*
+ * Parallel copy line buffer information.
+ */
+typedef struct ParallelCopyLineBuf
+{
+	StringInfoData line_buf;
+	uint64		cur_lineno;		/* line number for error messages */
+} ParallelCopyLineBuf;
+
+/*
+ * This structure helps in storing the common data from CopyStateData that are
+ * required by the workers. This information will then be allocated and stored
+ * into the DSM for the worker to retrieve and copy it to CopyStateData.
+ */
+typedef struct SerializedParallelCopyState
+{
+	/* low-level state data */
+	CopyDest	copy_dest;		/* type of copy source/destination */
+	int			file_encoding;	/* file or remote side's character encoding */
+	bool		need_transcoding;	/* file encoding diff from server? */
+	bool		encoding_embeds_ascii;	/* ASCII can be non-first byte? */
+
+	/* parameters from the COPY command */
+	bool		csv_mode;		/* Comma Separated Value format? */
+	bool		header_line;	/* CSV header line? */
+	int			null_print_len; /* length of same */
+	bool		force_quote_all;	/* FORCE_QUOTE *? */
+	bool		convert_selectively;	/* do selective binary conversion? */
+
+	/* Working state for COPY FROM */
+	AttrNumber	num_defaults;
+	Oid			relid;
+} SerializedParallelCopyState;
+
+/*
+ * Parallel copy data information.
+ */
+typedef struct ParallelCopyData
+{
+	Oid			relid;			/* relation id of the table */
+	ParallelCopyShmInfo *pcshared_info; /* common info in shared memory */
+	bool		is_leader;
+
+	WalUsage   *walusage;
+	BufferUsage *bufferusage;
+
+	/* line position which worker is processing */
+	uint32		worker_processed_pos;
+
+	/*
+	 * Local line_buf array, workers will copy it here and release the lines
+	 * for the leader to continue.
+	 */
+	ParallelCopyLineBuf worker_line_buf[WORKER_CHUNK_COUNT];
+	uint32		worker_line_buf_count;	/* Number of lines */
+
+	/* Current position in worker_line_buf */
+	uint32		worker_line_buf_pos;
+} ParallelCopyData;
+
+typedef int (*copy_data_source_cb) (void *outbuf, int minread, int maxread);
+
+/*
+ * This struct contains all the state variables used throughout a COPY
+ * operation. For simplicity, we use the same struct for all variants of COPY,
+ * even though some fields are used in only some cases.
+ *
+ * Multi-byte encodings: all supported client-side encodings encode multi-byte
+ * characters by having the first byte's high bit set. Subsequent bytes of the
+ * character can have the high bit not set. When scanning data in such an
+ * encoding to look for a match to a single-byte (ie ASCII) character, we must
+ * use the full pg_encoding_mblen() machinery to skip over multibyte
+ * characters, else we might find a false match to a trailing byte. In
+ * supported server encodings, there is no possibility of a false match, and
+ * it's faster to make useless comparisons to trailing bytes than it is to
+ * invoke pg_encoding_mblen() to skip over them. encoding_embeds_ascii is true
+ * when we have to do it the hard way.
+ */
+typedef struct CopyStateData
+{
+	/* low-level state data */
+	CopyDest	copy_dest;		/* type of copy source/destination */
+	FILE	   *copy_file;		/* used if copy_dest == COPY_FILE */
+	StringInfo	fe_msgbuf;		/* used for all dests during COPY TO, only for
+								 * dest == COPY_NEW_FE in COPY FROM */
+	bool		is_copy_from;	/* COPY TO, or COPY FROM? */
+	bool		reached_eof;	/* true if we read to end of copy data (not
+								 * all copy_dest types maintain this) */
+	EolType		eol_type;		/* EOL type of input */
+	int			file_encoding;	/* file or remote side's character encoding */
+	bool		need_transcoding;	/* file encoding diff from server? */
+	bool		encoding_embeds_ascii;	/* ASCII can be non-first byte? */
+
+	/* parameters from the COPY command */
+	Relation	rel;			/* relation to copy to or from */
+	QueryDesc  *queryDesc;		/* executable query to copy from */
+	List	   *attnumlist;		/* integer list of attnums to copy */
+	char	   *filename;		/* filename, or NULL for STDIN/STDOUT */
+	bool		is_program;		/* is 'filename' a program to popen? */
+	copy_data_source_cb data_source_cb; /* function for reading data */
+	bool		binary;			/* binary format? */
+	bool		freeze;			/* freeze rows on loading? */
+	bool		csv_mode;		/* Comma Separated Value format? */
+	bool		header_line;	/* CSV header line? */
+	char	   *null_print;		/* NULL marker string (server encoding!) */
+	int			null_print_len; /* length of same */
+	char	   *null_print_client;	/* same converted to file encoding */
+	char	   *delim;			/* column delimiter (must be 1 byte) */
+	char	   *quote;			/* CSV quote char (must be 1 byte) */
+	char	   *escape;			/* CSV escape char (must be 1 byte) */
+	List	   *force_quote;	/* list of column names */
+	bool		force_quote_all;	/* FORCE_QUOTE *? */
+	bool	   *force_quote_flags;	/* per-column CSV FQ flags */
+	List	   *force_notnull;	/* list of column names */
+	bool	   *force_notnull_flags;	/* per-column CSV FNN flags */
+	List	   *force_null;		/* list of column names */
+	bool	   *force_null_flags;	/* per-column CSV FN flags */
+	bool		convert_selectively;	/* do selective binary conversion? */
+	List	   *convert_select; /* list of column names (can be NIL) */
+	bool	   *convert_select_flags;	/* per-column CSV/TEXT CS flags */
+	Node	   *whereClause;	/* WHERE condition (or NULL) */
+
+	/* these are just for error messages, see CopyFromErrorCallback */
+	const char *cur_relname;	/* table name for error messages */
+	uint64		cur_lineno;		/* line number for error messages */
+	const char *cur_attname;	/* current att for error messages */
+	const char *cur_attval;		/* current att value for error messages */
+
+	/*
+	 * Working state for COPY TO/FROM
+	 */
+	MemoryContext copycontext;	/* per-copy execution context */
+
+	/*
+	 * Working state for COPY TO
+	 */
+	FmgrInfo   *out_functions;	/* lookup info for output functions */
+	MemoryContext rowcontext;	/* per-row evaluation context */
+
+	/*
+	 * Working state for COPY FROM
+	 */
+	AttrNumber	num_defaults;
+	FmgrInfo   *in_functions;	/* array of input functions for each attrs */
+	Oid		   *typioparams;	/* array of element types for in_functions */
+	int		   *defmap;			/* array of default att numbers */
+	ExprState **defexprs;		/* array of default att expressions */
+	bool		volatile_defexprs;	/* is any of defexprs volatile? */
+	List	   *range_table;
+	ExprState  *qualexpr;
+
+	TransitionCaptureState *transition_capture;
+
+	/*
+	 * These variables are used to reduce overhead in COPY FROM.
+	 *
+	 * attribute_buf holds the separated, de-escaped text for each field of
+	 * the current line.  The CopyReadAttributes functions return arrays of
+	 * pointers into this buffer.  We avoid palloc/pfree overhead by re-using
+	 * the buffer on each cycle.
+	 *
+	 * In binary COPY FROM, attribute_buf holds the binary data for the
+	 * current field, but the usage is otherwise similar.
+	 */
+	StringInfoData attribute_buf;
+
+	/* field raw data pointers found by COPY FROM */
+
+	int			max_fields;
+	char	  **raw_fields;
+
+	/*
+	 * Similarly, line_buf holds the whole input line being processed. The
+	 * input cycle is first to read the whole line into line_buf, convert it
+	 * to server encoding there, and then extract the individual attribute
+	 * fields into attribute_buf.  line_buf is preserved unmodified so that we
+	 * can display it in error messages if appropriate.  (In binary mode,
+	 * line_buf is not used.)
+	 */
+	StringInfoData line_buf;
+	bool		line_buf_converted; /* converted to server encoding? */
+	bool		line_buf_valid; /* contains the row being processed? */
+
+	/*
+	 * Finally, raw_buf holds raw data read from the data source (file or
+	 * client connection).  In text mode, CopyReadLine parses this data
+	 * sufficiently to locate line boundaries, then transfers the data to
+	 * line_buf and converts it.  In binary mode, CopyReadBinaryData fetches
+	 * appropriate amounts of data from this buffer.  In both modes, we
+	 * guarantee that there is a \0 at raw_buf[raw_buf_len].
+	 */
+	char	   *raw_buf;
+	int			raw_buf_index;	/* next byte to process */
+	int			raw_buf_len;	/* total # of bytes stored */
+	int			nworkers;
+	bool		is_parallel;
+	ParallelCopyData *pcdata;
+	/* Shorthand for number of unconsumed bytes available in raw_buf */
+#define RAW_BUF_BYTES(cstate) ((cstate)->raw_buf_len - (cstate)->raw_buf_index)
+} CopyStateData;
+
 /* CopyStateData is private in commands/copy.c */
 typedef struct CopyStateData *CopyState;
-typedef int (*copy_data_source_cb) (void *outbuf, int minread, int maxread);
 
 extern void DoCopy(ParseState *state, const CopyStmt *stmt,
 				   int stmt_location, int stmt_len,
@@ -41,4 +421,11 @@ extern uint64 CopyFrom(CopyState cstate);
 
 extern DestReceiver *CreateCopyDestReceiver(void);
 
+extern void PopulateCommonCstateInfo(CopyState cstate, TupleDesc tup_desc,
+									 List *attnamelist);
+
+extern void ParallelCopyMain(dsm_segment *seg, shm_toc *toc);
+extern ParallelContext *BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid);
+extern void ParallelCopyFrom(CopyState cstate);
+extern void EndParallelCopy(ParallelContext *pcxt);
 #endif							/* COPY_H */
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 9cd1179..f5b818b 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1702,6 +1702,12 @@ ParallelBitmapHeapState
 ParallelBlockTableScanDesc
 ParallelCompletionPtr
 ParallelContext
+ParallelCopyLineBoundaries
+ParallelCopyLineBoundary
+ParallelCopyData
+ParallelCopyDataBlock
+ParallelCopyLineBuf
+ParallelCopyShmInfo
 ParallelExecutorInfo
 ParallelHashGrowth
 ParallelHashJoinBatch
@@ -2219,6 +2225,7 @@ SerCommitSeqNo
 SerialControl
 SerializableXactHandle
 SerializedActiveRelMaps
+SerializedParallelCopyState
 SerializedReindexState
 SerializedSnapshotData
 SerializedTransactionState
-- 
1.8.3.1

v6-0003-Allow-copy-from-command-to-process-data-from-file.patchapplication/octet-stream; name=v6-0003-Allow-copy-from-command-to-process-data-from-file.patchDownload
From eb1a33276d1f907d14e7e1962b1cd254b81e1587 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 7 Oct 2020 17:24:44 +0530
Subject: [PATCH v6 3/6] Allow copy from command to process data from
 file/STDIN contents to a table in parallel.

This feature allows the copy from to leverage multiple CPUs in order to copy
data from file/STDIN to a table. This adds a PARALLEL option to COPY FROM
command where the user can specify the number of workers that can be used
to perform the COPY FROM command.
The backend, to which the "COPY FROM" query is submitted acts as leader with
the responsibility of reading data from the file/stdin, launching at most n
number of workers as specified with PARALLEL 'n' option in the "COPY FROM"
query. The leader populates the common data required for the workers execution
in the DSM and shares it with the workers. The leader then executes before
statement triggers if there exists any. Leader populates DSM lines which
includes the start offset and line size, while populating the lines it reads
as many blocks as required into the DSM data blocks from the file. Each block
is of 64K size. The leader parses the data to identify a line, the existing
logic from CopyReadLineText which identifies the lines with some changes was
used for this. Leader checks if a free line is available to copy the
information, if there is no free line it waits till the required line is
freed up by the worker and then copies the identified lines information
(offset & line size) into the DSM lines. This process is repeated till the
complete file is processed. Simultaneously, the workers cache the lines(50)
locally into the local memory and release the lines to the leader for further
populating. Each worker processes the lines that it cached and inserts it into
the table.
The leader does not participate in the insertion of data, leaders only
responsibility will be to identify the lines as fast as possible for the
workers to do the actual copy operation. The leader waits till all the lines
populated are processed by the workers and exits. We have chosen this design
based on the reason "that everything stalls if the leader doesn't accept further
input data, as well as when there are no available splitted chunks so it doesn't
seem like a good idea to have the leader do other work.  This is backed by the
performance data where we have seen that with 1 worker there is just a 5-10%
performance difference".
---
 src/backend/access/common/toast_internals.c |   12 +-
 src/backend/access/heap/heapam.c            |   11 -
 src/backend/access/transam/xact.c           |   15 +
 src/backend/commands/copy.c                 |  220 +++--
 src/backend/commands/copyparallel.c         | 1269 +++++++++++++++++++++++++++
 src/bin/psql/tab-complete.c                 |    2 +-
 src/include/access/xact.h                   |    1 +
 src/include/commands/copy.h                 |   69 +-
 src/tools/pgindent/typedefs.list            |    1 +
 9 files changed, 1514 insertions(+), 86 deletions(-)
 create mode 100644 src/backend/commands/copyparallel.c

diff --git a/src/backend/access/common/toast_internals.c b/src/backend/access/common/toast_internals.c
index 25a81e5..70c070e 100644
--- a/src/backend/access/common/toast_internals.c
+++ b/src/backend/access/common/toast_internals.c
@@ -17,6 +17,7 @@
 #include "access/genam.h"
 #include "access/heapam.h"
 #include "access/heaptoast.h"
+#include "access/parallel.h"
 #include "access/table.h"
 #include "access/toast_internals.h"
 #include "access/xact.h"
@@ -116,7 +117,16 @@ toast_save_datum(Relation rel, Datum value,
 	TupleDesc	toasttupDesc;
 	Datum		t_values[3];
 	bool		t_isnull[3];
-	CommandId	mycid = GetCurrentCommandId(true);
+
+	/*
+	 * Parallel copy can insert toast tuples, in case of parallel copy the
+	 * command would have been set already by calling
+	 * AssignCommandIdForWorker. For parallel copy call GetCurrentCommandId to
+	 * get currentCommandId by passing used as false, as this is taken care
+	 * earlier.
+	 */
+	CommandId	mycid = IsParallelWorker() ? GetCurrentCommandId(false) :
+	GetCurrentCommandId(true);
 	struct varlena *result;
 	struct varatt_external toast_pointer;
 	union
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 1585861..1602525 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2043,17 +2043,6 @@ static HeapTuple
 heap_prepare_insert(Relation relation, HeapTuple tup, TransactionId xid,
 					CommandId cid, int options)
 {
-	/*
-	 * To allow parallel inserts, we need to ensure that they are safe to be
-	 * performed in workers. We have the infrastructure to allow parallel
-	 * inserts in general except for the cases where inserts generate a new
-	 * CommandId (eg. inserts into a table having a foreign key column).
-	 */
-	if (IsParallelWorker())
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_TRANSACTION_STATE),
-				 errmsg("cannot insert tuples in a parallel worker")));
-
 	tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
 	tup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK);
 	tup->t_data->t_infomask |= HEAP_XMAX_INVALID;
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index af6afce..0b3337c 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -776,6 +776,21 @@ GetCurrentCommandId(bool used)
 }
 
 /*
+ *	SetCurrentCommandIdUsedForWorker
+ *
+ * For a parallel worker, record that the currentCommandId has been used.
+ * This must only be called at the start of a parallel operation.
+ */
+void
+SetCurrentCommandIdUsedForWorker(void)
+{
+	Assert(IsParallelWorker() && !currentCommandIdUsed &&
+		   (currentCommandId != InvalidCommandId));
+
+	currentCommandIdUsed = true;
+}
+
+/*
  *	SetParallelStartTimestamps
  *
  * In a parallel worker, we should inherit the parent transaction's
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 1e55a30..dc006a5 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -61,20 +61,6 @@
 #define ISOCTAL(c) (((c) >= '0') && ((c) <= '7'))
 #define OCTVALUE(c) ((c) - '0')
 
-/*
- * Represents the heap insert method to be used during COPY FROM.
- */
-typedef enum CopyInsertMethod
-{
-	CIM_SINGLE,					/* use table_tuple_insert or fdw routine */
-	CIM_MULTI,					/* always use table_multi_insert */
-	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
-} CopyInsertMethod;
-
-#define IsParallelCopy()		(cstate->is_parallel)
-#define IsLeader()				(cstate->pcdata->is_leader)
-#define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
-
 /* DestReceiver for COPY (query) TO */
 typedef struct
 {
@@ -131,7 +117,6 @@ typedef struct CopyMultiInsertInfo
 	int			ti_options;		/* table insert options */
 } CopyMultiInsertInfo;
 
-
 /*
  * These macros centralize code used to process line_buf and raw_buf buffers.
  * They are macros because they often do continue/break control and to avoid
@@ -182,9 +167,13 @@ if (1) \
 { \
 	if (raw_buf_ptr > cstate->raw_buf_index) \
 	{ \
-		appendBinaryStringInfo(&cstate->line_buf, \
-							 cstate->raw_buf + cstate->raw_buf_index, \
-							   raw_buf_ptr - cstate->raw_buf_index); \
+		if (!IsParallelCopy()) \
+			appendBinaryStringInfo(&cstate->line_buf, \
+								   cstate->raw_buf + cstate->raw_buf_index, \
+								   raw_buf_ptr - cstate->raw_buf_index); \
+		else \
+			line_size +=  raw_buf_ptr - cstate->raw_buf_index; \
+		\
 		cstate->raw_buf_index = raw_buf_ptr; \
 	} \
 } else ((void) 0)
@@ -197,18 +186,6 @@ if (1) \
 	goto not_end_of_copy; \
 } else ((void) 0)
 
-/*
- * Increment the lines processed.
- */
-#define INCREMENTPROCESSED(processed)  \
-processed++;
-
-/*
- * Get the lines processed.
- */
-#define RETURNPROCESSED(processed) \
-return processed;
-
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
 
@@ -225,7 +202,6 @@ static void EndCopyTo(CopyState cstate);
 static uint64 DoCopyTo(CopyState cstate);
 static uint64 CopyTo(CopyState cstate);
 static void CopyOneRowTo(CopyState cstate, TupleTableSlot *slot);
-static bool CopyReadLine(CopyState cstate);
 static bool CopyReadLineText(CopyState cstate);
 static int	CopyReadAttributesText(CopyState cstate);
 static int	CopyReadAttributesCSV(CopyState cstate);
@@ -258,7 +234,6 @@ static int	CopyReadBinaryData(CopyState cstate, char *dest, int nbytes);
 
 static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
 								   int copy_line_pos, int *copy_line_size);
-static void ConvertToServerEncoding(CopyState cstate);
 
 
 /*
@@ -2639,7 +2614,7 @@ CopyMultiInsertInfoStore(CopyMultiInsertInfo *miinfo, ResultRelInfo *rri,
  *
  * Check if the relation specified in copy from is valid.
  */
-static void
+void
 CheckTargetRelValidity(CopyState cstate)
 {
 	Assert(cstate->rel);
@@ -2735,7 +2710,7 @@ CopyFrom(CopyState cstate)
 
 	PartitionTupleRouting *proute = NULL;
 	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
+	CommandId	mycid;
 	int			ti_options = 0; /* start with default options for insert */
 	BulkInsertState bistate = NULL;
 	CopyInsertMethod insertMethod;
@@ -2745,7 +2720,18 @@ CopyFrom(CopyState cstate)
 	bool		has_instead_insert_row_trig;
 	bool		leafpart_use_multi_insert = false;
 
-	CheckTargetRelValidity(cstate);
+	/*
+	 * Perform this check if it is not parallel copy. In case of parallel
+	 * copy, this check is done by the leader, so that if any invalid case
+	 * exist the copy from command will error out from the leader itself,
+	 * avoiding launching workers, just to throw error.
+	 */
+	if (!IsParallelCopy())
+		CheckTargetRelValidity(cstate);
+	else
+		SetCurrentCommandIdUsedForWorker();
+
+	mycid = GetCurrentCommandId(!IsParallelCopy());
 
 	/*
 	 * If the target file is new-in-transaction, we assume that checking FSM
@@ -2785,7 +2771,8 @@ CopyFrom(CopyState cstate)
 	target_resultRelInfo = resultRelInfo;
 
 	/* Verify the named relation is a valid target for INSERT */
-	CheckValidResultRel(resultRelInfo, CMD_INSERT);
+	if (!IsParallelCopy())
+		CheckValidResultRel(resultRelInfo, CMD_INSERT);
 
 	ExecOpenIndices(resultRelInfo, false);
 
@@ -2934,13 +2921,17 @@ CopyFrom(CopyState cstate)
 	has_instead_insert_row_trig = (resultRelInfo->ri_TrigDesc &&
 								   resultRelInfo->ri_TrigDesc->trig_insert_instead_row);
 
-	/*
-	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
-	 * should do this for COPY, since it's not really an "INSERT" statement as
-	 * such. However, executing these triggers maintains consistency with the
-	 * EACH ROW triggers that we already fire on COPY.
-	 */
-	ExecBSInsertTriggers(estate, resultRelInfo);
+	if (!IsParallelCopy())
+	{
+		/*
+		 * Check BEFORE STATEMENT insertion triggers. It's debatable whether
+		 * we should do this for COPY, since it's not really an "INSERT"
+		 * statement as such. However, executing these triggers maintains
+		 * consistency with the EACH ROW triggers that we already fire on
+		 * COPY.
+		 */
+		ExecBSInsertTriggers(estate, resultRelInfo);
+	}
 
 	econtext = GetPerTupleExprContext(estate);
 
@@ -3040,6 +3031,29 @@ CopyFrom(CopyState cstate)
 					!has_instead_insert_row_trig &&
 					resultRelInfo->ri_FdwRoutine == NULL;
 
+				/*
+				 * We may still be able to perform parallel inserts for
+				 * partitioned tables. However, the possibility of this
+				 * depends on which types of triggers exist on the partition.
+				 * We must not do parallel inserts if the partition is a
+				 * foreign table or it has any BEFORE/INSTEAD OF row triggers.
+				 * Since the partition's resultRelInfo are initialized only
+				 * when we actually insert the first tuple into them, we may
+				 * not know this info easily in the leader while deciding for
+				 * the parallelism. We would have gone ahead and allowed
+				 * parallelism. Now it's the time to throw an error and also
+				 * provide a hint to the user to not use parallelism. Throwing
+				 * an error seemed a simple approach than to look for all the
+				 * partitions in the leader while deciding for the
+				 * parallelism. Note that this error is thrown early, exactly
+				 * on the first tuple being inserted into the partition, so
+				 * not much work, that has been done so far, is wasted.
+				 */
+				if (!leafpart_use_multi_insert && IsParallelWorker())
+					ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+									errmsg("cannot perform PARALLEL COPY if partition has BEFORE/INSTEAD OF triggers, or if the partition is foreign partition"),
+									errhint("Try COPY without PARALLEL option")));
+
 				/* Set the multi-insert buffer to use for this partition. */
 				if (leafpart_use_multi_insert)
 				{
@@ -3325,7 +3339,7 @@ CopyFrom(CopyState cstate)
  *
  * Populate the cstate catalog information.
  */
-static void
+void
 PopulateCstateCatalogInfo(CopyState cstate)
 {
 	TupleDesc	tupDesc;
@@ -3607,26 +3621,35 @@ NextCopyFromRawFields(CopyState cstate, char ***fields, int *nfields)
 	/* only available for text or csv input */
 	Assert(!cstate->binary);
 
-	/* on input just throw the header line away */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (IsParallelCopy())
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
-			return false;		/* done */
+		done = GetWorkerLine(cstate);
+		if (done && cstate->line_buf.len == 0)
+			return false;
 	}
+	else
+	{
+		/* on input just throw the header line away */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
+		{
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+				return false;	/* done */
+		}
 
-	cstate->cur_lineno++;
+		cstate->cur_lineno++;
 
-	/* Actually read the line into memory here */
-	done = CopyReadLine(cstate);
+		/* Actually read the line into memory here */
+		done = CopyReadLine(cstate);
 
-	/*
-	 * EOF at start of line means we're done.  If we see EOF after some
-	 * characters, we act as though it was newline followed by EOF, ie,
-	 * process the line and then exit loop on next iteration.
-	 */
-	if (done && cstate->line_buf.len == 0)
-		return false;
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			return false;
+	}
 
 	/* Parse the line into de-escaped field values */
 	if (cstate->csv_mode)
@@ -3851,7 +3874,7 @@ EndCopyFrom(CopyState cstate)
  * by newline.  The terminating newline or EOF marker is not included
  * in the final value of line_buf.
  */
-static bool
+bool
 CopyReadLine(CopyState cstate)
 {
 	bool		result;
@@ -3874,9 +3897,34 @@ CopyReadLine(CopyState cstate)
 		 */
 		if (cstate->copy_dest == COPY_NEW_FE)
 		{
+			bool		bIsFirst = true;
+
 			do
 			{
-				cstate->raw_buf_index = cstate->raw_buf_len;
+				if (!IsParallelCopy())
+					cstate->raw_buf_index = cstate->raw_buf_len;
+				else
+				{
+					if (cstate->raw_buf_index == RAW_BUF_SIZE)
+					{
+						/*
+						 * Get a new block if it is the first time, From the
+						 * subsequent time, reset the index and re-use the
+						 * same block.
+						 */
+						if (bIsFirst)
+						{
+							ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+							uint32		block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+							cstate->raw_buf = pcshared_info->data_blocks[block_pos].data;
+							bIsFirst = false;
+						}
+
+						cstate->raw_buf_index = cstate->raw_buf_len = 0;
+					}
+				}
+
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
@@ -3931,11 +3979,11 @@ ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
  *
  * Convert contents to server encoding.
  */
-static void
+void
 ConvertToServerEncoding(CopyState cstate)
 {
 	/* Done reading the line.  Convert it to server encoding. */
-	if (cstate->need_transcoding)
+	if (cstate->need_transcoding && (!IsParallelCopy() || IsWorker()))
 	{
 		char	   *cvt;
 
@@ -3975,6 +4023,11 @@ CopyReadLineText(CopyState cstate)
 	char		quotec = '\0';
 	char		escapec = '\0';
 
+	/* For parallel copy */
+	int			line_size = 0;
+	uint32		line_pos = 0;
+
+	cstate->eol_type = EOL_UNKNOWN;
 	if (cstate->csv_mode)
 	{
 		quotec = cstate->quote[0];
@@ -4029,6 +4082,8 @@ CopyReadLineText(CopyState cstate)
 		if (raw_buf_ptr >= copy_buf_len || need_data)
 		{
 			REFILL_LINEBUF;
+			SetRawBufForLoad(cstate, line_size, copy_buf_len, raw_buf_ptr,
+							 &copy_raw_buf);
 
 			/*
 			 * Try to read some more data.  This will certainly reset
@@ -4253,9 +4308,15 @@ CopyReadLineText(CopyState cstate)
 				 * discard the data and the \. sequence.
 				 */
 				if (prev_raw_ptr > cstate->raw_buf_index)
-					appendBinaryStringInfo(&cstate->line_buf,
-										   cstate->raw_buf + cstate->raw_buf_index,
-										   prev_raw_ptr - cstate->raw_buf_index);
+				{
+					if (!IsParallelCopy())
+						appendBinaryStringInfo(&cstate->line_buf,
+											   cstate->raw_buf + cstate->raw_buf_index,
+											   prev_raw_ptr - cstate->raw_buf_index);
+					else
+						line_size += prev_raw_ptr - cstate->raw_buf_index;
+				}
+
 				cstate->raw_buf_index = raw_buf_ptr;
 				result = true;	/* report EOF */
 				break;
@@ -4307,6 +4368,22 @@ not_end_of_copy:
 			IF_NEED_REFILL_AND_EOF_BREAK(mblen - 1);
 			raw_buf_ptr += mblen - 1;
 		}
+
+		/*
+		 * Skip the header line. Update the line here, this cannot be done at
+		 * the beginning, as there is a possibility that file contains empty
+		 * lines.
+		 */
+		if (IsParallelCopy() && first_char_in_line && !IsHeaderLine())
+		{
+			ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+			line_pos = UpdateSharedLineInfo(cstate,
+											pcshared_info->cur_block_pos,
+											cstate->raw_buf_index, -1,
+											LINE_LEADER_POPULATING, -1);
+		}
+
 		first_char_in_line = false;
 	}							/* end of outer loop */
 
@@ -4315,9 +4392,16 @@ not_end_of_copy:
 	 */
 	REFILL_LINEBUF;
 	if (!result && !IsHeaderLine())
-		ClearEOLFromCopiedData(cstate, cstate->line_buf.data,
-							   cstate->line_buf.len, &cstate->line_buf.len);
+	{
+		if (IsParallelCopy())
+			ClearEOLFromCopiedData(cstate, cstate->raw_buf, raw_buf_ptr,
+								   &line_size);
+		else
+			ClearEOLFromCopiedData(cstate, cstate->line_buf.data,
+								   cstate->line_buf.len, &cstate->line_buf.len);
+	}
 
+	EndLineParallelCopy(cstate, line_pos, line_size, raw_buf_ptr);
 	return result;
 }
 
diff --git a/src/backend/commands/copyparallel.c b/src/backend/commands/copyparallel.c
new file mode 100644
index 0000000..6a44a01
--- /dev/null
+++ b/src/backend/commands/copyparallel.c
@@ -0,0 +1,1269 @@
+/*-------------------------------------------------------------------------
+ *
+ * copyparallel.c
+ *              Implements the Parallel COPY utility command
+ *
+ * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *        src/backend/commands/copyparallel.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/heapam.h"
+#include "catalog/pg_proc_d.h"
+#include "commands/copy.h"
+#include "optimizer/clauses.h"
+#include "optimizer/optimizer.h"
+#include "pgstat.h"
+#include "utils/lsyscache.h"
+
+/* DSM keys for parallel copy.  */
+#define PARALLEL_COPY_KEY_SHARED_INFO				1
+#define PARALLEL_COPY_KEY_CSTATE					2
+#define PARALLEL_COPY_WAL_USAGE						3
+#define PARALLEL_COPY_BUFFER_USAGE					4
+
+/* Begin parallel copy Macros */
+#define SET_NEWLINE_SIZE() \
+{ \
+	if (cstate->eol_type == EOL_NL || cstate->eol_type == EOL_CR) \
+		new_line_size = 1; \
+	else if (cstate->eol_type == EOL_CRNL) \
+		new_line_size = 2; \
+	else \
+		new_line_size = 0; \
+}
+
+/*
+ * COPY_WAIT_TO_PROCESS - Wait before continuing to process.
+ */
+#define COPY_WAIT_TO_PROCESS() \
+{ \
+	CHECK_FOR_INTERRUPTS(); \
+	(void) WaitLatch(MyLatch, \
+					 WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH, \
+					 1L, WAIT_EVENT_PG_SLEEP); \
+	ResetLatch(MyLatch); \
+}
+
+/*
+ * CopyStringToSharedMemory - Copy the string to shared memory.
+ */
+static void
+CopyStringToSharedMemory(CopyState cstate, char *srcPtr, char *destptr,
+						 uint32 *copiedsize)
+{
+	uint32		len = srcPtr ? strlen(srcPtr) + 1 : 0;
+
+	memcpy(destptr, (uint16 *) &len, sizeof(uint16));
+	*copiedsize += sizeof(uint16);
+	if (len)
+	{
+		memcpy(destptr + sizeof(uint16), srcPtr, len);
+		*copiedsize += len;
+	}
+}
+
+/*
+ * SerializeParallelCopyState - Serialize the data into shared memory.
+ */
+static void
+SerializeParallelCopyState(ParallelContext *pcxt, CopyState cstate,
+						   uint32 estimatedSize, char *whereClauseStr,
+						   char *rangeTableStr, char *attnameListStr,
+						   char *notnullListStr, char *nullListStr,
+						   char *convertListStr)
+{
+	SerializedParallelCopyState shared_cstate;
+	char	   *shmptr = (char *) shm_toc_allocate(pcxt->toc, estimatedSize + 1);
+	uint32		copiedsize = 0;
+
+	shared_cstate.copy_dest = cstate->copy_dest;
+	shared_cstate.file_encoding = cstate->file_encoding;
+	shared_cstate.need_transcoding = cstate->need_transcoding;
+	shared_cstate.encoding_embeds_ascii = cstate->encoding_embeds_ascii;
+	shared_cstate.csv_mode = cstate->csv_mode;
+	shared_cstate.header_line = cstate->header_line;
+	shared_cstate.null_print_len = cstate->null_print_len;
+	shared_cstate.force_quote_all = cstate->force_quote_all;
+	shared_cstate.convert_selectively = cstate->convert_selectively;
+	shared_cstate.num_defaults = cstate->num_defaults;
+	shared_cstate.relid = cstate->pcdata->relid;
+
+	memcpy(shmptr, (char *) &shared_cstate, sizeof(SerializedParallelCopyState));
+	copiedsize = sizeof(SerializedParallelCopyState);
+
+	CopyStringToSharedMemory(cstate, cstate->null_print, shmptr + copiedsize,
+							 &copiedsize);
+	CopyStringToSharedMemory(cstate, cstate->delim, shmptr + copiedsize,
+							 &copiedsize);
+	CopyStringToSharedMemory(cstate, cstate->quote, shmptr + copiedsize,
+							 &copiedsize);
+	CopyStringToSharedMemory(cstate, cstate->escape, shmptr + copiedsize,
+							 &copiedsize);
+	CopyStringToSharedMemory(cstate, attnameListStr, shmptr + copiedsize,
+							 &copiedsize);
+	CopyStringToSharedMemory(cstate, notnullListStr, shmptr + copiedsize,
+							 &copiedsize);
+	CopyStringToSharedMemory(cstate, nullListStr, shmptr + copiedsize,
+							 &copiedsize);
+	CopyStringToSharedMemory(cstate, convertListStr, shmptr + copiedsize,
+							 &copiedsize);
+	CopyStringToSharedMemory(cstate, whereClauseStr, shmptr + copiedsize,
+							 &copiedsize);
+	CopyStringToSharedMemory(cstate, rangeTableStr, shmptr + copiedsize,
+							 &copiedsize);
+
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_CSTATE, shmptr);
+}
+
+/*
+ * CopyNodeFromSharedMemory - Copy the shared memory & return the ptr.
+ */
+static char *
+CopyStringFromSharedMemory(char *srcPtr, uint32 *copiedsize)
+{
+	char	   *destptr = NULL;
+	uint16		len = 0;
+
+	memcpy((uint16 *) (&len), srcPtr, sizeof(uint16));
+	*copiedsize += sizeof(uint16);
+	if (len)
+	{
+		destptr = (char *) palloc0(len);
+		memcpy(destptr, srcPtr + sizeof(uint16), len);
+		*copiedsize += len;
+	}
+
+	return destptr;
+}
+
+/*
+ * CopyNodeFromSharedMemory - Copy the shared memory & convert it into node
+ * type.
+ */
+static void *
+CopyNodeFromSharedMemory(char *srcPtr, uint32 *copiedsize)
+{
+	char	   *destptr = NULL;
+	List	   *destList = NIL;
+	uint16		len = 0;
+
+	memcpy((uint16 *) (&len), srcPtr, sizeof(uint16));
+	*copiedsize += sizeof(uint16);
+	if (len)
+	{
+		destptr = (char *) palloc0(len);
+		memcpy(destptr, srcPtr + sizeof(uint16), len);
+		*copiedsize += len;
+		destList = (List *) stringToNode(destptr);
+		pfree(destptr);
+	}
+
+	return destList;
+}
+
+/*
+ * RestoreParallelCopyState - Retrieve the cstate from shared memory.
+ */
+static void
+RestoreParallelCopyState(shm_toc *toc, CopyState cstate, List **attlist)
+{
+	char	   *shared_str_val = (char *) shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE, true);
+	SerializedParallelCopyState shared_cstate = {0};
+	uint32		copiedsize = 0;
+
+	memcpy(&shared_cstate, (char *) shared_str_val, sizeof(SerializedParallelCopyState));
+	copiedsize = sizeof(SerializedParallelCopyState);
+
+	cstate->file_encoding = shared_cstate.file_encoding;
+	cstate->need_transcoding = shared_cstate.need_transcoding;
+	cstate->encoding_embeds_ascii = shared_cstate.encoding_embeds_ascii;
+	cstate->csv_mode = shared_cstate.csv_mode;
+	cstate->header_line = shared_cstate.header_line;
+	cstate->null_print_len = shared_cstate.null_print_len;
+	cstate->force_quote_all = shared_cstate.force_quote_all;
+	cstate->convert_selectively = shared_cstate.convert_selectively;
+	cstate->num_defaults = shared_cstate.num_defaults;
+	cstate->pcdata->relid = shared_cstate.relid;
+
+	cstate->null_print = CopyStringFromSharedMemory(shared_str_val + copiedsize,
+													&copiedsize);
+	cstate->delim = CopyStringFromSharedMemory(shared_str_val + copiedsize,
+											   &copiedsize);
+	cstate->quote = CopyStringFromSharedMemory(shared_str_val + copiedsize,
+											   &copiedsize);
+	cstate->escape = CopyStringFromSharedMemory(shared_str_val + copiedsize,
+												&copiedsize);
+
+	*attlist = (List *) CopyNodeFromSharedMemory(shared_str_val + copiedsize,
+												 &copiedsize);
+	cstate->force_notnull = (List *) CopyNodeFromSharedMemory(shared_str_val + copiedsize,
+															  &copiedsize);
+	cstate->force_null = (List *) CopyNodeFromSharedMemory(shared_str_val + copiedsize,
+														   &copiedsize);
+	cstate->convert_select = (List *) CopyNodeFromSharedMemory(shared_str_val + copiedsize,
+															   &copiedsize);
+	cstate->whereClause = (Node *) CopyNodeFromSharedMemory(shared_str_val + copiedsize,
+															&copiedsize);
+	cstate->range_table = (List *) CopyNodeFromSharedMemory(shared_str_val + copiedsize,
+															&copiedsize);
+}
+
+/*
+ * EstimateStringSize - Estimate the size required for the string in shared
+ * memory.
+ */
+static uint32
+EstimateStringSize(char *str)
+{
+	uint32		strsize = sizeof(uint16);
+
+	if (str)
+		strsize += strlen(str) + 1;
+
+	return strsize;
+}
+
+/*
+ * EstimateNodeSize - Convert the list to string & estimate the size required
+ * in shared memory.
+ */
+static uint32
+EstimateNodeSize(void *list, char **listStr)
+{
+	uint32		strsize = sizeof(uint16);
+
+	if (list != NIL)
+	{
+		*listStr = nodeToString(list);
+		strsize += strlen(*listStr) + 1;
+	}
+
+	return strsize;
+}
+
+/*
+ * EstimateCstateSize - Estimate the size required in shared memory for cstate
+ * variables.
+ */
+static uint32
+EstimateCstateSize(ParallelContext *pcxt, CopyState cstate, List *attnamelist,
+				   char **whereClauseStr, char **rangeTableStr,
+				   char **attnameListStr, char **notnullListStr,
+				   char **nullListStr, char **convertListStr)
+{
+	uint32		strsize = MAXALIGN(sizeof(SerializedParallelCopyState));
+
+	strsize += EstimateStringSize(cstate->null_print);
+	strsize += EstimateStringSize(cstate->delim);
+	strsize += EstimateStringSize(cstate->quote);
+	strsize += EstimateStringSize(cstate->escape);
+	strsize += EstimateNodeSize(attnamelist, attnameListStr);
+	strsize += EstimateNodeSize(cstate->force_notnull, notnullListStr);
+	strsize += EstimateNodeSize(cstate->force_null, nullListStr);
+	strsize += EstimateNodeSize(cstate->convert_select, convertListStr);
+	strsize += EstimateNodeSize(cstate->whereClause, whereClauseStr);
+	strsize += EstimateNodeSize(cstate->range_table, rangeTableStr);
+
+	strsize++;
+	shm_toc_estimate_chunk(&pcxt->estimator, strsize);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+	return strsize;
+}
+
+/*
+ * PopulateParallelCopyShmInfo - Set ParallelCopyShmInfo.
+ */
+static void
+PopulateParallelCopyShmInfo(ParallelCopyShmInfo *shared_info_ptr)
+{
+	uint32		count;
+
+	MemSet(shared_info_ptr, 0, sizeof(ParallelCopyShmInfo));
+	shared_info_ptr->is_read_in_progress = true;
+	shared_info_ptr->cur_block_pos = -1;
+	for (count = 0; count < RINGSIZE; count++)
+	{
+		ParallelCopyLineBoundary *lineInfo = &shared_info_ptr->line_boundaries.ring[count];
+
+		pg_atomic_init_u32(&(lineInfo->line_size), -1);
+	}
+}
+
+/*
+ * CheckTrigFunParallelSafety - For all triggers, check if the associated
+ * trigger functions are parallel safe. If at least one trigger function is
+ * parallel unsafe, we do not allow parallelism.
+ */
+static pg_attribute_always_inline bool
+CheckTrigFunParallelSafety(TriggerDesc *trigdesc)
+{
+	int			i;
+
+	for (i = 0; i < trigdesc->numtriggers; i++)
+	{
+		Trigger    *trigger = &trigdesc->triggers[i];
+		int			trigtype = RI_TRIGGER_NONE;
+
+		if (func_parallel(trigger->tgfoid) != PROPARALLEL_SAFE)
+			return false;
+
+		/* If the trigger is parallel safe, also look for RI_TRIGGER. */
+		trigtype = RI_FKey_trigger_type(trigger->tgfoid);
+
+		/*
+		 * No parallelism if foreign key check trigger is present. This is
+		 * because, while performing foreign key checks, we take KEY SHARE
+		 * lock on primary key table rows which inturn will increment the
+		 * command counter and updates the snapshot.  Since we share the
+		 * snapshots at the beginning of the command, we can't allow it to be
+		 * changed later. So, unless we do something special for it, we can't
+		 * allow parallelism in such cases.
+		 */
+		if (trigtype == RI_TRIGGER_FK)
+			return false;
+	}
+
+	return true;
+}
+
+/*
+ * CheckExprParallelSafety - Determine parallel safety of volatile expressions
+ * in default clause of column definition or in where clause and return true if
+ * they are parallel safe.
+ */
+static pg_attribute_always_inline bool
+CheckExprParallelSafety(CopyState cstate)
+{
+	if (contain_volatile_functions(cstate->whereClause))
+	{
+		if (max_parallel_hazard((Query *) cstate->whereClause) != PROPARALLEL_SAFE)
+			return false;
+	}
+
+	/*
+	 * Check if any of the column has volatile default expression. if yes, and
+	 * they are not parallel safe, then parallelism is not allowed. For
+	 * instance, if there are any serial/bigserial columns for which nextval()
+	 * default expression which is parallel unsafe is associated, parallelism
+	 * should not be allowed.
+	 */
+	if (cstate->defexprs != NULL && cstate->num_defaults != 0)
+	{
+		int			i;
+
+		for (i = 0; i < cstate->num_defaults; i++)
+		{
+			bool		volatile_expr = contain_volatile_functions((Node *) cstate->defexprs[i]->expr);
+
+			if (volatile_expr &&
+				(max_parallel_hazard((Query *) cstate->defexprs[i]->expr)) !=
+				PROPARALLEL_SAFE)
+				return false;
+		}
+	}
+
+	return true;
+}
+
+/*
+ * IsParallelCopyAllowed - Check for the cases where parallel copy is not
+ * applicable.
+ */
+static pg_attribute_always_inline bool
+IsParallelCopyAllowed(CopyState cstate)
+{
+	/* Parallel copy not allowed for frontend (2.0 protocol) & binary option. */
+	if ((cstate->copy_dest == COPY_OLD_FE) || cstate->binary)
+		return false;
+
+	/*
+	 * Check if copy is into foreign table. We can not allow parallelism in
+	 * this case because each worker needs to establish FDW connection and
+	 * operate in a separate transaction. Unless we have a capability to
+	 * provide two-phase commit protocol, we can not allow parallelism.
+	 *
+	 * Also check if copy is into temporary table. Since parallel workers can
+	 * not access temporary table, parallelism is not allowed.
+	 */
+	if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
+		RelationUsesLocalBuffers(cstate->rel))
+		return false;
+
+	/*
+	 * If there are volatile default expressions or where clause contain
+	 * volatile expressions, allow parallelism if they are parallel safe,
+	 * otherwise not.
+	 */
+	if (!CheckExprParallelSafety(cstate))
+		return false;
+
+	/* Check parallel safety of the trigger functions. */
+	if (cstate->rel->trigdesc != NULL &&
+		!CheckTrigFunParallelSafety(cstate->rel->trigdesc))
+		return false;
+
+	/*
+	 * When transition tables are involved (if after statement triggers are
+	 * present), we collect minimal tuples in the tuple store after processing
+	 * them so that later after statement triggers can access them.  Now, if
+	 * we want to enable parallelism for such cases, we instead need to store
+	 * and access tuples from shared tuple store.  However, it does not have
+	 * the facility to store tuples in-memory, so we always need to store and
+	 * access from a file which could be costly unless we also have an
+	 * additional way to store minimal tuples in shared memory till work_mem
+	 * and then in shared tuple store. It is possible to do all this to enable
+	 * parallel copy for such cases. Currently, we can disallow parallelism
+	 * for such cases and later allow if required.
+	 *
+	 * When there are BEFORE/AFTER/INSTEAD OF row triggers on the table. We do
+	 * not allow parallelism in such cases because such triggers might query
+	 * the table we are inserting into and act differently if the tuples that
+	 * have already been processed and prepared for insertion are not there.
+	 * Now, if we allow parallelism with such triggers the behaviour would
+	 * depend on if the parallel worker has already inserted or not that
+	 * particular tuples.
+	 */
+	if (cstate->rel->trigdesc != NULL &&
+		(cstate->rel->trigdesc->trig_insert_after_statement ||
+		 cstate->rel->trigdesc->trig_insert_new_table ||
+		 cstate->rel->trigdesc->trig_insert_before_row ||
+		 cstate->rel->trigdesc->trig_insert_after_row ||
+		 cstate->rel->trigdesc->trig_insert_instead_row))
+		return false;
+
+	return true;
+}
+
+/*
+ * BeginParallelCopy - Start parallel copy tasks.
+ *
+ * Get the number of workers required to perform the parallel copy. The data
+ * structures that are required by the parallel workers will be initialized, the
+ * size required in DSM will be calculated and the necessary keys will be loaded
+ * in the DSM. The specified number of workers will then be launched.
+ */
+ParallelContext *
+BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
+{
+	ParallelContext *pcxt;
+	ParallelCopyShmInfo *shared_info_ptr;
+	Size		est_cstateshared;
+	char	   *whereClauseStr = NULL;
+	char	   *rangeTableStr = NULL;
+	char	   *attnameListStr = NULL;
+	char	   *notnullListStr = NULL;
+	char	   *nullListStr = NULL;
+	char	   *convertListStr = NULL;
+	int			parallel_workers = 0;
+	WalUsage   *walusage;
+	BufferUsage *bufferusage;
+	ParallelCopyData *pcdata;
+	MemoryContext oldcontext;
+	uint32		strsize;
+
+	CheckTargetRelValidity(cstate);
+	parallel_workers = Min(nworkers, max_worker_processes);
+
+	/* Can't perform copy in parallel */
+	if (parallel_workers <= 0)
+		return NULL;
+
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	MemoryContextSwitchTo(oldcontext);
+	cstate->pcdata = pcdata;
+
+	/*
+	 * User chosen parallel copy. Determine if the parallel copy is actually
+	 * allowed. If not, go with the non-parallel mode.
+	 */
+	if (!IsParallelCopyAllowed(cstate))
+		return NULL;
+
+	(void) GetCurrentFullTransactionId();
+	(void) GetCurrentCommandId(true);
+
+	EnterParallelMode();
+	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
+								 parallel_workers);
+	Assert(pcxt->nworkers > 0);
+
+	/*
+	 * Estimate size for shared information for PARALLEL_COPY_KEY_SHARED_INFO
+	 */
+	shm_toc_estimate_chunk(&pcxt->estimator, sizeof(ParallelCopyShmInfo));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_CSTATE */
+	est_cstateshared = MAXALIGN(sizeof(SerializedParallelCopyState));
+	shm_toc_estimate_chunk(&pcxt->estimator, est_cstateshared);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	strsize = EstimateCstateSize(pcxt, cstate, attnamelist, &whereClauseStr,
+								 &rangeTableStr, &attnameListStr,
+								 &notnullListStr, &nullListStr,
+								 &convertListStr);
+
+	/*
+	 * Estimate space for WalUsage and BufferUsage -- PARALLEL_COPY_WAL_USAGE
+	 * and PARALLEL_COPY_BUFFER_USAGE.
+	 */
+	shm_toc_estimate_chunk(&pcxt->estimator,
+						   mul_size(sizeof(WalUsage), pcxt->nworkers));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+	shm_toc_estimate_chunk(&pcxt->estimator,
+						   mul_size(sizeof(BufferUsage), pcxt->nworkers));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	InitializeParallelDSM(pcxt);
+
+	/* If no DSM segment was available, back out (do serial copy) */
+	if (pcxt->seg == NULL)
+	{
+		EndParallelCopy(pcxt);
+		return NULL;
+	}
+
+	/* Allocate shared memory for PARALLEL_COPY_KEY_SHARED_INFO */
+	shared_info_ptr = (ParallelCopyShmInfo *) shm_toc_allocate(pcxt->toc, sizeof(ParallelCopyShmInfo));
+	PopulateParallelCopyShmInfo(shared_info_ptr);
+
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_SHARED_INFO, shared_info_ptr);
+	pcdata->pcshared_info = shared_info_ptr;
+	pcdata->relid = relid;
+
+	SerializeParallelCopyState(pcxt, cstate, strsize, whereClauseStr,
+							   rangeTableStr, attnameListStr, notnullListStr,
+							   nullListStr, convertListStr);
+
+	/*
+	 * Allocate space for each worker's WalUsage and BufferUsage; no need to
+	 * initialize.
+	 */
+	walusage = shm_toc_allocate(pcxt->toc,
+								mul_size(sizeof(WalUsage), pcxt->nworkers));
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_WAL_USAGE, walusage);
+	pcdata->walusage = walusage;
+	bufferusage = shm_toc_allocate(pcxt->toc,
+								   mul_size(sizeof(BufferUsage), pcxt->nworkers));
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_BUFFER_USAGE, bufferusage);
+	pcdata->bufferusage = bufferusage;
+
+	LaunchParallelWorkers(pcxt);
+	if (pcxt->nworkers_launched == 0)
+	{
+		EndParallelCopy(pcxt);
+		return NULL;
+	}
+
+	/*
+	 * Caller needs to wait for all launched workers when we return.  Make
+	 * sure that the failure-to-start case will not hang forever.
+	 */
+	WaitForParallelWorkersToAttach(pcxt);
+
+	pcdata->is_leader = true;
+	cstate->is_parallel = true;
+	return pcxt;
+}
+
+/*
+ * EndParallelCopy - End the parallel copy tasks.
+ */
+pg_attribute_always_inline void
+EndParallelCopy(ParallelContext *pcxt)
+{
+	Assert(!IsParallelWorker());
+
+	DestroyParallelContext(pcxt);
+	ExitParallelMode();
+}
+
+/*
+ * InitializeParallelCopyInfo - Initialize parallel worker.
+ */
+static void
+InitializeParallelCopyInfo(CopyState cstate, List *attnamelist)
+{
+	uint32		count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	PopulateCommonCstateInfo(cstate, tup_desc, attnamelist);
+
+	/* Initialize state variables. */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/* Set up variables to avoid per-attribute overhead. */
+	initStringInfo(&cstate->attribute_buf);
+
+	initStringInfo(&cstate->line_buf);
+	for (count = 0; count < WORKER_CHUNK_COUNT; count++)
+		initStringInfo(&pcdata->worker_line_buf[count].line_buf);
+
+	cstate->line_buf_converted = false;
+	cstate->raw_buf = NULL;
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+
+	PopulateCstateCatalogInfo(cstate);
+
+	/* Create workspace for CopyReadAttributes results. */
+	if (!cstate->binary)
+	{
+		AttrNumber	attr_count = list_length(cstate->attnumlist);
+
+		cstate->max_fields = attr_count;
+		cstate->raw_fields = (char **) palloc(attr_count * sizeof(char *));
+	}
+}
+
+/*
+ * CacheLineInfo - Cache the line information to local memory.
+ */
+static bool
+CacheLineInfo(CopyState cstate, uint32 buff_count)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	uint32		write_pos;
+	ParallelCopyDataBlock *data_blk_ptr;
+	ParallelCopyLineBoundary *lineInfo;
+	uint32		offset;
+	int			dataSize;
+	int			copiedSize = 0;
+
+	resetStringInfo(&pcdata->worker_line_buf[buff_count].line_buf);
+	write_pos = GetLinePosition(cstate);
+	if (-1 == write_pos)
+		return true;
+
+	/* Get the current line information. */
+	lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+	if (pg_atomic_read_u32(&lineInfo->line_size) == 0)
+		goto empty_data_line_update;
+
+	/* Get the block information. */
+	data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+	/* Get the offset information from where the data must be copied. */
+	offset = lineInfo->start_offset;
+	pcdata->worker_line_buf[buff_count].cur_lineno = lineInfo->cur_lineno;
+
+	elog(DEBUG1, "[Worker] Processing - line position:%d, block:%d, unprocessed lines:%d, offset:%d, line size:%d",
+		 write_pos, lineInfo->first_block,
+		 pg_atomic_read_u32(&data_blk_ptr->unprocessed_line_parts),
+		 offset, pg_atomic_read_u32(&lineInfo->line_size));
+
+	for (;;)
+	{
+		uint8		skip_bytes = data_blk_ptr->skip_bytes;
+
+		/*
+		 * There is a possibility that the loop embedded at the bottom of the
+		 * current loop has come out because data_blk_ptr->curr_blk_completed
+		 * is set, but dataSize read might be an old value, if
+		 * data_blk_ptr->curr_blk_completed and the line is completed,
+		 * line_size will be set. Read the line_size again to be sure if it is
+		 * completed or partial block.
+		 */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+		if (dataSize)
+		{
+			int			remainingSize = dataSize - copiedSize;
+
+			if (!remainingSize)
+				break;
+
+			/* Whole line is in current block. */
+			if (remainingSize + offset + skip_bytes < DATA_BLOCK_SIZE)
+			{
+				appendBinaryStringInfo(&pcdata->worker_line_buf[buff_count].line_buf,
+									   &data_blk_ptr->data[offset],
+									   remainingSize);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts,
+										1);
+				break;
+			}
+			else
+			{
+				/* Line is spread across the blocks. */
+				uint32		lineInCurrentBlock = (DATA_BLOCK_SIZE - skip_bytes) - offset;
+
+				appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+										 &data_blk_ptr->data[offset],
+										 lineInCurrentBlock);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+				copiedSize += lineInCurrentBlock;
+				while (copiedSize < dataSize)
+				{
+					uint32		currentBlockCopySize;
+					ParallelCopyDataBlock *currBlkPtr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+
+					skip_bytes = currBlkPtr->skip_bytes;
+
+					/*
+					 * If complete data is present in current block use
+					 * dataSize - copiedSize, or copy the whole block from
+					 * current block.
+					 */
+					currentBlockCopySize = Min(dataSize - copiedSize, DATA_BLOCK_SIZE - skip_bytes);
+					appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+											 &currBlkPtr->data[0],
+											 currentBlockCopySize);
+					pg_atomic_sub_fetch_u32(&currBlkPtr->unprocessed_line_parts, 1);
+					copiedSize += currentBlockCopySize;
+					data_blk_ptr = currBlkPtr;
+				}
+
+				break;
+			}
+		}
+		else
+		{
+			/* Copy this complete block from the current offset. */
+			uint32		lineInCurrentBlock = (DATA_BLOCK_SIZE - skip_bytes) - offset;
+
+			appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+									 &data_blk_ptr->data[offset],
+									 lineInCurrentBlock);
+			pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+			copiedSize += lineInCurrentBlock;
+
+			/*
+			 * Reset the offset. For the first copy, copy from the offset. For
+			 * the subsequent copy the complete block.
+			 */
+			offset = 0;
+
+			/* Set data_blk_ptr to the following block. */
+			data_blk_ptr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+		}
+
+		for (;;)
+		{
+			/* Get the size of this line */
+			dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+			/*
+			 * If the data is present in current block lineInfo->line_size
+			 * will be updated. If the data is spread across the blocks either
+			 * of lineInfo->line_size or data_blk_ptr->curr_blk_completed can
+			 * be updated. lineInfo->line_size will be updated if the complete
+			 * read is finished. data_blk_ptr->curr_blk_completed will be
+			 * updated if processing of current block is finished and data
+			 * processing is not finished.
+			 */
+			if (data_blk_ptr->curr_blk_completed || (dataSize != -1))
+				break;
+
+			COPY_WAIT_TO_PROCESS()
+		}
+	}
+
+empty_data_line_update:
+	elog(DEBUG1, "[Worker] Completed processing line:%d", write_pos);
+	pg_atomic_write_u32(&lineInfo->line_state, LINE_WORKER_PROCESSED);
+	pg_atomic_write_u32(&lineInfo->line_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+	return false;
+}
+
+/*
+ * GetWorkerLine - Returns a line for worker to process.
+ */
+bool
+GetWorkerLine(CopyState cstate)
+{
+	uint32		buff_count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+
+	/*
+	 * Copy the line data to line_buf and release the line position so that
+	 * the worker can continue loading data.
+	 */
+	if (pcdata->worker_line_buf_pos < pcdata->worker_line_buf_count)
+		goto return_line;
+
+	pcdata->worker_line_buf_pos = 0;
+	pcdata->worker_line_buf_count = 0;
+
+	for (buff_count = 0; buff_count < WORKER_CHUNK_COUNT; buff_count++)
+	{
+		bool		result = CacheLineInfo(cstate, buff_count);
+		if (result)
+			break;
+
+		pcdata->worker_line_buf_count++;
+	}
+
+	if (pcdata->worker_line_buf_count)
+		goto return_line;
+	else
+		resetStringInfo(&cstate->line_buf);
+
+	return true;
+
+return_line:
+	cstate->line_buf = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].line_buf;
+	cstate->cur_lineno = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].cur_lineno;
+	cstate->line_buf_valid = true;
+
+	/* Mark that encoding conversion hasn't occurred yet. */
+	cstate->line_buf_converted = false;
+	ConvertToServerEncoding(cstate);
+	pcdata->worker_line_buf_pos++;
+	return false;
+}
+
+/*
+ * ParallelCopyMain - Parallel copy worker's code.
+ *
+ * Where clause handling, convert tuple to columns, add default null values for
+ * the missing columns that are not present in that record. Find the partition
+ * if it is partitioned table, invoke before row insert Triggers, handle
+ * constraints and insert the tuples.
+ */
+void
+ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
+{
+	CopyState	cstate;
+	ParallelCopyData *pcdata;
+	ParallelCopyShmInfo *pcshared_info;
+	Relation	rel = NULL;
+	MemoryContext oldcontext;
+	List	   *attlist = NIL;
+	WalUsage   *walusage;
+	BufferUsage *bufferusage;
+
+	/* Allocate workspace and zero all fields. */
+	cstate = (CopyStateData *) palloc0(sizeof(CopyStateData));
+
+	/*
+	 * We allocate everything used by a cstate in a new memory context. This
+	 * avoids memory leaks during repeated use of COPY in a query.
+	 */
+	cstate->copycontext = AllocSetContextCreate(CurrentMemoryContext,
+												"COPY",
+												ALLOCSET_DEFAULT_SIZES);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	cstate->pcdata = pcdata;
+	pcdata->is_leader = false;
+	pcdata->worker_processed_pos = -1;
+	cstate->is_parallel = true;
+	pcshared_info = (ParallelCopyShmInfo *) shm_toc_lookup(toc, PARALLEL_COPY_KEY_SHARED_INFO, false);
+
+	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
+
+	pcdata->pcshared_info = pcshared_info;
+	RestoreParallelCopyState(toc, cstate, &attlist);
+
+	/* Open and lock the relation, using the appropriate lock type. */
+	rel = table_open(cstate->pcdata->relid, RowExclusiveLock);
+	cstate->rel = rel;
+	InitializeParallelCopyInfo(cstate, attlist);
+
+	/* Prepare to track buffer usage during parallel execution */
+	InstrStartParallelQuery();
+
+	CopyFrom(cstate);
+
+	if (rel != NULL)
+		table_close(rel, RowExclusiveLock);
+
+	/* Report WAL/buffer usage during parallel execution */
+	bufferusage = shm_toc_lookup(toc, PARALLEL_COPY_BUFFER_USAGE, false);
+	walusage = shm_toc_lookup(toc, PARALLEL_COPY_WAL_USAGE, false);
+	InstrEndParallelQuery(&bufferusage[ParallelWorkerNumber],
+						  &walusage[ParallelWorkerNumber]);
+
+	MemoryContextSwitchTo(oldcontext);
+	pfree(cstate);
+	return;
+}
+
+/*
+ * UpdateSharedLineInfo - Update the line information.
+ */
+uint32
+UpdateSharedLineInfo(CopyState cstate, uint32 blk_pos, uint32 offset,
+					 uint32 line_size, uint32 line_state, uint32 blk_line_pos)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyLineBoundaries *lineBoundaryPtr = &pcshared_info->line_boundaries;
+	ParallelCopyLineBoundary *lineInfo;
+	uint32		line_pos;
+
+	/* blk_line_pos will be valid in case line_pos was blocked earlier. */
+	if (blk_line_pos == -1)
+	{
+		line_pos = lineBoundaryPtr->pos;
+
+		/* Update the line information for the worker to pick and process. */
+		lineInfo = &lineBoundaryPtr->ring[line_pos];
+		while (pg_atomic_read_u32(&lineInfo->line_size) != -1)
+			COPY_WAIT_TO_PROCESS()
+
+				lineInfo->first_block = blk_pos;
+		lineInfo->start_offset = offset;
+		lineInfo->cur_lineno = cstate->cur_lineno;
+		lineBoundaryPtr->pos = (lineBoundaryPtr->pos + 1) % RINGSIZE;
+	}
+	else
+	{
+		line_pos = blk_line_pos;
+		lineInfo = &lineBoundaryPtr->ring[line_pos];
+	}
+
+	if (line_state == LINE_LEADER_POPULATED)
+	{
+		elog(DEBUG1, "[Leader] Added line with block:%d, offset:%d, line position:%d, line size:%d",
+			 lineInfo->first_block, lineInfo->start_offset, line_pos,
+			 pg_atomic_read_u32(&lineInfo->line_size));
+		pcshared_info->populated++;
+	}
+	else
+		elog(DEBUG1, "[Leader] Adding - block:%d, offset:%d, line position:%d",
+			 lineInfo->first_block, lineInfo->start_offset, line_pos);
+
+	pg_atomic_write_u32(&lineInfo->line_size, line_size);
+	pg_atomic_write_u32(&lineInfo->line_state, line_state);
+
+	return line_pos;
+}
+
+/*
+ * ParallelCopyFrom - parallel copy leader's functionality.
+ *
+ * Leader executes the before statement for before statement trigger, if before
+ * statement trigger is present. It will read the table data from the file and
+ * copy the contents to DSM data blocks. It will then read the input contents
+ * from the DSM data block and identify the records based on line breaks. This
+ * information is called line or a record that need to be inserted into a
+ * relation. The line information will be stored in ParallelCopyLineBoundary DSM
+ * data structure. Workers will then process this information and insert the
+ * data in to table. It will repeat this process until the all data is read from
+ * the file and all the DSM data blocks are processed. While processing if
+ * leader identifies that DSM Data blocks or DSM ParallelCopyLineBoundary data
+ * structures is full, leader will wait till the worker frees up some entries
+ * and repeat the process. It will wait till all the lines populated are
+ * processed by the workers and exits.
+ */
+void
+ParallelCopyFrom(CopyState cstate)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
+
+	/* raw_buf is not used in parallel copy, instead data blocks are used. */
+	pfree(cstate->raw_buf);
+	cstate->raw_buf = NULL;
+
+	/* Execute the before statement triggers from the leader */
+	ExecBeforeStmtTrigger(cstate);
+
+	/* On input just throw the header line away. */
+	if (cstate->cur_lineno == 0 && cstate->header_line)
+	{
+		cstate->cur_lineno++;
+		if (CopyReadLine(cstate))
+		{
+			pcshared_info->is_read_in_progress = false;
+			return;				/* done */
+		}
+	}
+
+	for (;;)
+	{
+		bool		done;
+
+		cstate->cur_lineno++;
+
+		/* Actually read the line into memory here. */
+		done = CopyReadLine(cstate);
+
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			break;
+	}
+
+	pcshared_info->is_read_in_progress = false;
+	cstate->cur_lineno = 0;
+}
+
+/*
+ * GetLinePosition - Return the line position once the leader has populated the
+ * data.
+ */
+uint32
+GetLinePosition(CopyState cstate)
+{
+	ParallelCopyData *pcdata = cstate->pcdata;
+	ParallelCopyShmInfo *pcshared_info = pcdata->pcshared_info;
+	uint32  previous_pos = pcdata->worker_processed_pos;
+	uint32 write_pos = (previous_pos == -1) ? 0 : (previous_pos + 1) % RINGSIZE;
+
+	for (;;)
+	{
+		int			dataSize;
+		bool		is_read_in_progress = pcshared_info->is_read_in_progress;
+		ParallelCopyLineBoundary *lineInfo;
+		ParallelCopyDataBlock *data_blk_ptr;
+		uint32		line_state = LINE_LEADER_POPULATED;
+		ParallelCopyLineState curr_line_state;
+
+		CHECK_FOR_INTERRUPTS();
+
+		/* File read completed & no elements to process. */
+		if (!is_read_in_progress &&
+			(pcshared_info->populated ==
+			 pg_atomic_read_u64(&pcshared_info->total_worker_processed)))
+		{
+			write_pos = -1;
+			break;
+		}
+
+		/* Get the current line information. */
+		lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+		curr_line_state = pg_atomic_read_u32(&lineInfo->line_state);
+		if ((write_pos % WORKER_CHUNK_COUNT == 0) &&
+			(curr_line_state == LINE_WORKER_PROCESSED ||
+			 curr_line_state == LINE_WORKER_PROCESSING))
+		{
+			pcdata->worker_processed_pos = write_pos;
+			write_pos = (write_pos + WORKER_CHUNK_COUNT) %  RINGSIZE;
+			continue;
+		}
+
+		/* Get the size of this line. */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+		if (dataSize != 0)		/* If not an empty line. */
+		{
+			/* Get the block information. */
+			data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+			if (!data_blk_ptr->curr_blk_completed && (dataSize == -1))
+			{
+				/* Wait till the current line or block is added. */
+				COPY_WAIT_TO_PROCESS()
+					continue;
+			}
+		}
+
+		/* Make sure that no worker has consumed this element. */
+		if (pg_atomic_compare_exchange_u32(&lineInfo->line_state,
+										   &line_state, LINE_WORKER_PROCESSING))
+			break;
+	}
+
+	pcdata->worker_processed_pos = write_pos;
+	return write_pos;
+}
+
+/*
+ * GetFreeCopyBlock - Get a free block for data to be copied.
+ */
+static pg_attribute_always_inline uint32
+GetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	int			count = 0;
+	uint32		last_free_block = pcshared_info->cur_block_pos;
+	uint32		block_pos = (last_free_block != -1) ? ((last_free_block + 1) % MAX_BLOCKS_COUNT) : 0;
+
+	/*
+	 * Get a new block for copying data, don't check current block, current
+	 * block will have some unprocessed data.
+	 */
+	while (count < (MAX_BLOCKS_COUNT - 1))
+	{
+		ParallelCopyDataBlock *dataBlkPtr = &pcshared_info->data_blocks[block_pos];
+		uint32		unprocessed_line_parts = pg_atomic_read_u32(&dataBlkPtr->unprocessed_line_parts);
+
+		if (unprocessed_line_parts == 0)
+		{
+			dataBlkPtr->curr_blk_completed = false;
+			dataBlkPtr->skip_bytes = 0;
+			dataBlkPtr->following_block = -1;
+			pcshared_info->cur_block_pos = block_pos;
+			MemSet(&dataBlkPtr->data[0], 0, DATA_BLOCK_SIZE);
+			return block_pos;
+		}
+
+		block_pos = (block_pos + 1) % MAX_BLOCKS_COUNT;
+		count++;
+	}
+
+	return -1;
+}
+
+/*
+ * WaitGetFreeCopyBlock - If there are no blocks available, wait and get a block
+ * for copying data.
+ */
+uint32
+WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	uint32		new_free_pos = -1;
+
+	for (;;)
+	{
+		new_free_pos = GetFreeCopyBlock(pcshared_info);
+		if (new_free_pos != -1) /* We have got one block, break now. */
+			break;
+
+		COPY_WAIT_TO_PROCESS()
+	}
+
+	return new_free_pos;
+}
+
+/*
+ * SetRawBufForLoad - Set raw_buf to the shared memory where the file data must
+ * be read.
+ */
+void
+SetRawBufForLoad(CopyState cstate, uint32 line_size, uint32 copy_buf_len,
+				 uint32 raw_buf_ptr, char **copy_raw_buf)
+{
+	ParallelCopyShmInfo *pcshared_info;
+	uint32		cur_block_pos;
+	uint32		next_block_pos;
+	ParallelCopyDataBlock *cur_data_blk_ptr = NULL;
+	ParallelCopyDataBlock *next_data_blk_ptr = NULL;
+
+	if (!IsParallelCopy())
+		return;
+
+	pcshared_info = cstate->pcdata->pcshared_info;
+	cur_block_pos = pcshared_info->cur_block_pos;
+	cur_data_blk_ptr = (cstate->raw_buf) ? &pcshared_info->data_blocks[cur_block_pos] : NULL;
+	next_block_pos = WaitGetFreeCopyBlock(pcshared_info);
+	next_data_blk_ptr = &pcshared_info->data_blocks[next_block_pos];
+
+	/* set raw_buf to the data block in shared memory */
+	cstate->raw_buf = next_data_blk_ptr->data;
+	*copy_raw_buf = cstate->raw_buf;
+	if (cur_data_blk_ptr && line_size)
+	{
+		/*
+		 * Mark the previous block as completed, worker can start copying this
+		 * data.
+		 */
+		cur_data_blk_ptr->following_block = next_block_pos;
+		pg_atomic_add_fetch_u32(&cur_data_blk_ptr->unprocessed_line_parts, 1);
+		cur_data_blk_ptr->skip_bytes = copy_buf_len - raw_buf_ptr;
+		cur_data_blk_ptr->curr_blk_completed = true;
+	}
+}
+
+/*
+ * EndLineParallelCopy - Update the line information in shared memory.
+ */
+void
+EndLineParallelCopy(CopyState cstate, uint32 line_pos, uint32 line_size,
+					uint32 raw_buf_ptr)
+{
+	uint8		new_line_size;
+
+	if (!IsParallelCopy())
+		return;
+
+	if (!IsHeaderLine())
+	{
+		ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+		SET_NEWLINE_SIZE()
+			if (line_size)
+		{
+			/*
+			 * If the new_line_size > raw_buf_ptr, then the new block has only
+			 * new line char content. The unprocessed count should not be
+			 * increased in this case.
+			 */
+			if (raw_buf_ptr > new_line_size)
+			{
+				uint32		cur_block_pos = pcshared_info->cur_block_pos;
+				ParallelCopyDataBlock *curr_data_blk_ptr = &pcshared_info->data_blocks[cur_block_pos];
+
+				pg_atomic_add_fetch_u32(&curr_data_blk_ptr->unprocessed_line_parts, 1);
+			}
+
+			/*
+			 * Update line size & line state, other members are already
+			 * updated.
+			 */
+			(void) UpdateSharedLineInfo(cstate, -1, -1, line_size,
+										LINE_LEADER_POPULATED, line_pos);
+		}
+		else if (new_line_size)
+			/* This means only new line char, empty record should be inserted. */
+			(void) UpdateSharedLineInfo(cstate, -1, -1, 0,
+										LINE_LEADER_POPULATED, -1);
+	}
+}
+
+/*
+ * ExecBeforeStmtTrigger - Execute the before statement trigger, this will be
+ * executed for parallel copy by the leader process.
+ */
+void
+ExecBeforeStmtTrigger(CopyState cstate)
+{
+	EState	   *estate = CreateExecutorState();
+	ResultRelInfo *resultRelInfo;
+
+	Assert(IsLeader());
+
+	/*
+	 * We need a ResultRelInfo so we can use the regular executor's
+	 * index-entry-making machinery.  (There used to be a huge amount of code
+	 * here that basically duplicated execUtils.c ...)
+	 */
+	resultRelInfo = makeNode(ResultRelInfo);
+	InitResultRelInfo(resultRelInfo,
+					  cstate->rel,
+					  1,		/* must match rel's position in range_table */
+					  NULL,
+					  0);
+
+	/* Verify the named relation is a valid target for INSERT */
+	CheckValidResultRel(resultRelInfo, CMD_INSERT);
+
+	estate->es_result_relations = resultRelInfo;
+	estate->es_num_result_relations = 1;
+	estate->es_result_relation_info = resultRelInfo;
+
+	ExecInitRangeTable(estate, cstate->range_table);
+
+	/*
+	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
+	 * should do this for COPY, since it's not really an "INSERT" statement as
+	 * such. However, executing these triggers maintains consistency with the
+	 * EACH ROW triggers that we already fire on COPY.
+	 */
+	ExecBSInsertTriggers(estate, resultRelInfo);
+
+	/* Close any trigger target relations */
+	ExecCleanUpTriggerState(estate);
+
+	FreeExecutorState(estate);
+}
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index 24c7b41..cf00256 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -2353,7 +2353,7 @@ psql_completion(const char *text, int start, int end)
 	/* Complete COPY <sth> FROM|TO filename WITH ( */
 	else if (Matches("COPY|\\copy", MatchAny, "FROM|TO", MatchAny, "WITH", "("))
 		COMPLETE_WITH("FORMAT", "FREEZE", "DELIMITER", "NULL",
-					  "HEADER", "QUOTE", "ESCAPE", "FORCE_QUOTE",
+					  "HEADER", "PARALLEL", "QUOTE", "ESCAPE", "FORCE_QUOTE",
 					  "FORCE_NOT_NULL", "FORCE_NULL", "ENCODING");
 
 	/* Complete COPY <sth> FROM|TO filename WITH (FORMAT */
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index df1b43a..96295bc 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -385,6 +385,7 @@ extern FullTransactionId GetTopFullTransactionId(void);
 extern FullTransactionId GetTopFullTransactionIdIfAny(void);
 extern FullTransactionId GetCurrentFullTransactionId(void);
 extern FullTransactionId GetCurrentFullTransactionIdIfAny(void);
+extern void SetCurrentCommandIdUsedForWorker(void);
 extern void MarkCurrentTransactionIdLoggedIfAny(void);
 extern bool SubTransactionIsActive(SubTransactionId subxid);
 extern CommandId GetCurrentCommandId(bool used);
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index cd2d56e..a9fe950 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -51,6 +51,31 @@
  */
 #define WORKER_CHUNK_COUNT 64
 
+#define IsParallelCopy()		(cstate->is_parallel)
+#define IsLeader()				(cstate->pcdata->is_leader)
+#define IsWorker()				(IsParallelCopy() && !IsLeader())
+#define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
+
+/*
+ * Increment the lines processed.
+ */
+#define INCREMENTPROCESSED(processed) \
+{ \
+	if (!IsParallelCopy()) \
+		processed++; \
+	else \
+		pg_atomic_add_fetch_u64(&cstate->pcdata->pcshared_info->processed, 1); \
+}
+
+/*
+ * Get the lines processed.
+ */
+#define RETURNPROCESSED(processed) \
+if (!IsParallelCopy()) \
+	return processed; \
+else \
+	return pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
+
 /*
  * Represents the different source/dest cases we need to worry about at
  * the bottom level
@@ -75,6 +100,28 @@ typedef enum EolType
 } EolType;
 
 /*
+ * State of the line.
+ */
+typedef enum ParallelCopyLineState
+{
+	LINE_INIT,					/* initial state of line */
+	LINE_LEADER_POPULATING,		/* leader processing line */
+	LINE_LEADER_POPULATED,		/* leader completed populating line */
+	LINE_WORKER_PROCESSING,		/* worker processing line */
+	LINE_WORKER_PROCESSED		/* worker completed processing line */
+} ParallelCopyLineState;
+
+/*
+ * Represents the heap insert method to be used during COPY FROM.
+ */
+typedef enum CopyInsertMethod
+{
+	CIM_SINGLE,					/* use table_tuple_insert or fdw routine */
+	CIM_MULTI,					/* always use table_multi_insert */
+	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
+} CopyInsertMethod;
+
+/*
  * Copy data block information.
  *
  * These data blocks are created in DSM. Data read from file will be copied in
@@ -194,8 +241,6 @@ typedef struct ParallelCopyShmInfo
 	uint64		populated;		/* lines populated by leader */
 	uint32		cur_block_pos;	/* current data block */
 	ParallelCopyDataBlock data_blocks[MAX_BLOCKS_COUNT];	/* data block array */
-	FullTransactionId full_transaction_id;	/* xid for copy from statement */
-	CommandId	mycid;			/* command id */
 	ParallelCopyLineBoundaries line_boundaries; /* line array */
 } ParallelCopyShmInfo;
 
@@ -242,12 +287,12 @@ typedef struct ParallelCopyData
 	ParallelCopyShmInfo *pcshared_info; /* common info in shared memory */
 	bool		is_leader;
 
+	/* line position which worker is processing */
+	uint32				worker_processed_pos;
+
 	WalUsage   *walusage;
 	BufferUsage *bufferusage;
 
-	/* line position which worker is processing */
-	uint32		worker_processed_pos;
-
 	/*
 	 * Local line_buf array, workers will copy it here and release the lines
 	 * for the leader to continue.
@@ -423,9 +468,23 @@ extern DestReceiver *CreateCopyDestReceiver(void);
 
 extern void PopulateCommonCstateInfo(CopyState cstate, TupleDesc tup_desc,
 									 List *attnamelist);
+extern void ConvertToServerEncoding(CopyState cstate);
 
 extern void ParallelCopyMain(dsm_segment *seg, shm_toc *toc);
 extern ParallelContext *BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid);
 extern void ParallelCopyFrom(CopyState cstate);
 extern void EndParallelCopy(ParallelContext *pcxt);
+extern void ExecBeforeStmtTrigger(CopyState cstate);
+extern void CheckTargetRelValidity(CopyState cstate);
+extern void PopulateCstateCatalogInfo(CopyState cstate);
+extern uint32 GetLinePosition(CopyState cstate);
+extern bool GetWorkerLine(CopyState cstate);
+extern bool CopyReadLine(CopyState cstate);
+extern uint32 WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info);
+extern void SetRawBufForLoad(CopyState cstate, uint32 line_size, uint32 copy_buf_len,
+							 uint32 raw_buf_ptr, char **copy_raw_buf);
+extern uint32 UpdateSharedLineInfo(CopyState cstate, uint32 blk_pos, uint32 offset,
+								   uint32 line_size, uint32 line_state, uint32 blk_line_pos);
+extern void EndLineParallelCopy(CopyState cstate, uint32 line_pos, uint32 line_size,
+								uint32 raw_buf_ptr);
 #endif							/* COPY_H */
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index f5b818b..a198bf0 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1707,6 +1707,7 @@ ParallelCopyLineBoundary
 ParallelCopyData
 ParallelCopyDataBlock
 ParallelCopyLineBuf
+ParallelCopyLineState
 ParallelCopyShmInfo
 ParallelExecutorInfo
 ParallelHashGrowth
-- 
1.8.3.1

v6-0004-Documentation-for-parallel-copy.patchapplication/octet-stream; name=v6-0004-Documentation-for-parallel-copy.patchDownload
From 0dd69daa6794de67ca6398d4f72869ae3c17dcdb Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Sat, 1 Aug 2020 09:00:36 +0530
Subject: [PATCH v6 4/6] Documentation for parallel copy.

This patch has the documentation changes for parallel copy.
---
 doc/src/sgml/ref/copy.sgml | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/doc/src/sgml/ref/copy.sgml b/doc/src/sgml/ref/copy.sgml
index 18189ab..19b1979 100644
--- a/doc/src/sgml/ref/copy.sgml
+++ b/doc/src/sgml/ref/copy.sgml
@@ -37,6 +37,7 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
     DELIMITER '<replaceable class="parameter">delimiter_character</replaceable>'
     NULL '<replaceable class="parameter">null_string</replaceable>'
     HEADER [ <replaceable class="parameter">boolean</replaceable> ]
+    PARALLEL <replaceable class="parameter">integer</replaceable>
     QUOTE '<replaceable class="parameter">quote_character</replaceable>'
     ESCAPE '<replaceable class="parameter">escape_character</replaceable>'
     FORCE_QUOTE { ( <replaceable class="parameter">column_name</replaceable> [, ...] ) | * }
@@ -275,6 +276,22 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
    </varlistentry>
 
    <varlistentry>
+    <term><literal>PARALLEL</literal></term>
+    <listitem>
+     <para>
+      Perform <command>COPY FROM</command> in parallel using <replaceable
+      class="parameter">integer</replaceable> background workers.  Please
+      note that it is not guaranteed that the number of parallel workers
+      specified in <replaceable class="parameter">integer</replaceable> will
+      be used during execution.  It is possible for a copy to run with fewer
+      workers than specified, or even with no workers at all (for example,
+      due to the setting of max_worker_processes). This option is allowed
+      only in <command>COPY FROM</command>.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><literal>QUOTE</literal></term>
     <listitem>
      <para>
@@ -951,6 +968,20 @@ COPY country FROM '/usr1/proj/bray/sql/country_data';
   </para>
 
   <para>
+   To copy data parallelly from a file into the <literal>country</literal> table:
+<programlisting>
+COPY country FROM '/usr1/proj/bray/sql/country_data' WITH (PARALLEL 1);
+</programlisting>
+  </para>
+
+  <para>
+   To copy data parallelly from STDIN into the <literal>country</literal> table:
+<programlisting>
+COPY country FROM STDIN WITH (PARALLEL 1);
+</programlisting>
+  </para>
+
+  <para>
    To copy into a file just the countries whose names start with 'A':
 <programlisting>
 COPY (SELECT * FROM country WHERE country_name LIKE 'A%') TO '/usr1/proj/bray/sql/a_list_countries.copy';
-- 
1.8.3.1

v6-0005-Tests-for-parallel-copy.patchapplication/octet-stream; name=v6-0005-Tests-for-parallel-copy.patchDownload
From 1f07a8f5128a2e295e6dda1ab667f8ca8fcffaff Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Sat, 1 Aug 2020 09:19:39 +0530
Subject: [PATCH v6 5/6] Tests for parallel copy.

This patch has the tests for parallel copy.
---
 src/test/regress/expected/copy2.out | 205 ++++++++++++++++++++++++++++++++++-
 src/test/regress/input/copy.source  |  12 +++
 src/test/regress/output/copy.source |  12 +++
 src/test/regress/sql/copy2.sql      | 208 +++++++++++++++++++++++++++++++++++-
 4 files changed, 429 insertions(+), 8 deletions(-)

diff --git a/src/test/regress/expected/copy2.out b/src/test/regress/expected/copy2.out
index e40287d..7ae5d44 100644
--- a/src/test/regress/expected/copy2.out
+++ b/src/test/regress/expected/copy2.out
@@ -254,18 +254,32 @@ It is "perfect".|
 "It is ""perfect"".","	"
 "",
 --test that we read consecutive LFs properly
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 COPY testnl FROM stdin CSV;
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+SELECT * FROM testnl;
+ a |          b           | c 
+---+----------------------+---
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+(2 rows)
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 COPY testeoc FROM stdin CSV;
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
 COPY testeoc TO stdout CSV;
 a\.
 \.b
 c\.d
 "\."
 -- test handling of nonstandard null marker that violates escaping rules
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 COPY testnull TO stdout WITH NULL AS E'\\0';
 1	\\0
@@ -280,6 +294,15 @@ SELECT * FROM testnull;
     | 
 (4 rows)
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 1);
+SELECT * FROM testnull;
+ a  | b  
+----+----
+ 42 | \0
+    | 
+(2 rows)
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -349,6 +372,34 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+SELECT * FROM vistest;
+ a  
+----
+ a2
+ b
+(2 rows)
+
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+COMMIT;
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 SELECT * FROM vistest;
  a 
@@ -409,7 +460,7 @@ SELECT * FROM vistest;
 (2 rows)
 
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -420,6 +471,8 @@ CREATE TEMP TABLE forcetest (
 -- should succeed with no effect ("b" remains an empty string, "c" remains NULL)
 BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 1);
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
  b |  c   
@@ -430,6 +483,8 @@ SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
 BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 1);
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
  c |  d   
@@ -486,6 +541,31 @@ select * from check_con_tbl;
    
 (2 rows)
 
+\d+ check_con_tbl
+                               Table "public.check_con_tbl"
+ Column |  Type   | Collation | Nullable | Default | Storage | Stats target | Description 
+--------+---------+-----------+----------+---------+---------+--------------+-------------
+ f1     | integer |           |          |         | plain   |              | 
+Check constraints:
+    "check_con_tbl_check" CHECK (check_con_function(check_con_tbl.*))
+
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 1);
+NOTICE:  input = {"f1":1}
+NOTICE:  input = {"f1":null}
+copy check_con_tbl from stdin with (parallel 1);
+NOTICE:  input = {"f1":0}
+ERROR:  new row for relation "check_con_tbl" violates check constraint "check_con_tbl_check"
+DETAIL:  Failing row contains (0).
+CONTEXT:  COPY check_con_tbl, line 1: "0"
+parallel worker
+select * from check_con_tbl;
+ f1 
+----
+  1
+   
+(2 rows)
+
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
 CREATE ROLE regress_rls_copy_user_colperms;
@@ -600,8 +680,125 @@ SELECT * FROM instead_of_insert_tbl;
 (2 rows)
 
 COMMIT;
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+COPY test_parallel_copy (a, b, c, d, e) from stdin with (PARALLEL 1);
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1, FORMAT 'csv', HEADER);
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0');
+ERROR:  value 0 out of bounds for option "parallel"
+DETAIL:  Valid values are between "1" and "1024".
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri from stdin with (FORMAT csv, DELIMITER ',', PARALLEL 1);
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1) WHERE height > random() * 65;
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+-- temporary table copy: should perform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+COPY temp_test (a) from stdin with (PARALLEL 1);
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) from stdin with (PARALLEL 1);
+ERROR:  column "xyz" of relation "test_parallel_copy" does not exist
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) from stdin with (PARALLEL 1);
+ERROR:  column "d" specified more than once
+-- missing data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  invalid input syntax for type integer: ""
+CONTEXT:  COPY test_parallel_copy, line 0, column a: ""
+parallel worker
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2000	230	23	23"
+parallel worker
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2001	231	\N	\N"
+parallel worker
+-- extra data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+ERROR:  extra data after last expected column
+CONTEXT:  COPY test_parallel_copy, line 1: "2002	232	40	50	60	70	80"
+parallel worker
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) from stdin with (delimiter ',', null 'x', PARALLEL 1) ;
+COPY test_parallel_copy from stdin WITH (DELIMITER ';', NULL '', PARALLEL 1);
+COPY test_parallel_copy from stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL 1);
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = 50004;
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a > 60003;
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE f > 60003;
+ERROR:  column "f" does not exist
+LINE 1: ..._parallel_copy from stdin WITH (PARALLEL 1) WHERE f > 60003;
+                                                             ^
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+ERROR:  missing FROM-clause entry for table "x"
+LINE 1: ...rallel_copy from stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+                                                                  ^
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (SELECT 1 FROM x);
+ERROR:  cannot use subquery in COPY FROM WHERE condition
+LINE 1: ...arallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (SELECT...
+                                                             ^
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (generate_series(1,5));
+ERROR:  set-returning functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...lel_copy from stdin WITH (PARALLEL 1) WHERE a IN (generate_s...
+                                                             ^
+COPY test_parallel_copy from stdin WITH(PARALLEL 1) WHERE a = row_number() over(b);
+ERROR:  window functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...rallel_copy from stdin WITH(PARALLEL 1) WHERE a = row_number...
+                                                             ^
+-- check results of copy in
+SELECT * FROM test_parallel_copy;
+   a   | b  |     c      |    d    |    e    
+-------+----+------------+---------+---------
+     1 | 11 | test_c1    | test_d1 | test_e1
+     2 | 12 | test_c2    | test_d2 | test_e2
+       |  3 | stuff      | test_d3 | 
+       |  4 | stuff      | test_d4 | 
+       |  5 | stuff      | test_d5 | 
+       |    | 45         | 80      | 90
+       |    | x          | \x      | \x
+       |    | ,          | \,      | \
+  3000 |    | c          |         | 
+  4000 |    | C          |         | 
+  4001 |  1 | empty      |         | 
+  4002 |  2 | null       |         | 
+  4003 |  3 | Backslash  | \       | \
+  4004 |  4 | BackslashX | \X      | \X
+  4005 |  5 | N          | N       | N
+  4006 |  6 | BackslashN | \N      | \N
+  4007 |  7 | XX         | XX      | XX
+  4008 |  8 | Delimiter  | :       | :
+ 50004 | 25 | 35         | 45      | 55
+ 60004 | 25 | 35         | 45      | 55
+ 60005 | 26 | 36         | 46      | 56
+(21 rows)
+
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
 DROP TABLE x, y;
diff --git a/src/test/regress/input/copy.source b/src/test/regress/input/copy.source
index a1d529a..159c058 100644
--- a/src/test/regress/input/copy.source
+++ b/src/test/regress/input/copy.source
@@ -15,6 +15,13 @@ DELETE FROM onek;
 
 COPY onek FROM '@abs_builddir@/results/onek.data';
 
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+
+SELECT COUNT(*) FROM tenk1;
+
+TRUNCATE tenk1;
+
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
@@ -159,6 +166,11 @@ truncate parted_copytest;
 
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
 
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
+
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/output/copy.source b/src/test/regress/output/copy.source
index 938d355..c3003fe 100644
--- a/src/test/regress/output/copy.source
+++ b/src/test/regress/output/copy.source
@@ -9,6 +9,15 @@ COPY onek FROM '@abs_srcdir@/data/onek.data';
 COPY onek TO '@abs_builddir@/results/onek.data';
 DELETE FROM onek;
 COPY onek FROM '@abs_builddir@/results/onek.data';
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+SELECT COUNT(*) FROM tenk1;
+ count 
+-------
+ 10000
+(1 row)
+
+TRUNCATE tenk1;
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
 COPY person FROM '@abs_srcdir@/data/person.data';
@@ -113,6 +122,9 @@ insert into parted_copytest select x,1,'One' from generate_series(1011,1020) x;
 copy (select * from parted_copytest order by a) to '@abs_builddir@/results/parted_copytest.csv';
 truncate parted_copytest;
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/sql/copy2.sql b/src/test/regress/sql/copy2.sql
index 902f4fa..7015698 100644
--- a/src/test/regress/sql/copy2.sql
+++ b/src/test/regress/sql/copy2.sql
@@ -157,7 +157,7 @@ COPY y TO stdout (FORMAT CSV, FORCE_QUOTE *);
 
 --test that we read consecutive LFs properly
 
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 
 COPY testnl FROM stdin CSV;
 1,"a field with two LFs
@@ -165,8 +165,16 @@ COPY testnl FROM stdin CSV;
 inside",2
 \.
 
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+1,"a field with two LFs
+
+inside",2
+\.
+
+SELECT * FROM testnl;
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 
 COPY testeoc FROM stdin CSV;
 a\.
@@ -175,11 +183,19 @@ c\.d
 "\."
 \.
 
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+a\.
+\.b
+c\.d
+"\."
+\.
+
 COPY testeoc TO stdout CSV;
 
 -- test handling of nonstandard null marker that violates escaping rules
 
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 
 COPY testnull TO stdout WITH NULL AS E'\\0';
@@ -191,6 +207,14 @@ COPY testnull FROM stdin WITH NULL AS E'\\0';
 
 SELECT * FROM testnull;
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 1);
+42	\\0
+\0	\0
+\.
+
+SELECT * FROM testnull;
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -235,6 +259,23 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+a2
+b
+\.
+SELECT * FROM vistest;
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+d2
+e
+\.
+SELECT * FROM vistest;
+COMMIT;
+SELECT * FROM vistest;
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 x
 y
@@ -284,7 +325,7 @@ SELECT * FROM vistest;
 COMMIT;
 SELECT * FROM vistest;
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -297,6 +338,10 @@ BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
 1,,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 1);
+1,,""
+\.
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
@@ -304,6 +349,10 @@ BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
 2,'a',,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 1);
+2,'a',,""
+\.
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
 -- should fail with not-null constraint violation
@@ -339,6 +388,16 @@ copy check_con_tbl from stdin;
 0
 \.
 select * from check_con_tbl;
+\d+ check_con_tbl
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 1);
+1
+\N
+\.
+copy check_con_tbl from stdin with (parallel 1);
+0
+\.
+select * from check_con_tbl;
 
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
@@ -440,8 +499,149 @@ test1
 SELECT * FROM instead_of_insert_tbl;
 COMMIT;
 
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+
+COPY test_parallel_copy (a, b, c, d, e) from stdin with (PARALLEL 1);
+1	11	test_c1	test_d1	test_e1
+2	12	test_c2	test_d2	test_e2
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+3	test_d3
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1);
+4	test_d4
+5	test_d5
+\.
+
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL 1, FORMAT 'csv', HEADER);
+b	d
+\.
+
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) from stdin with (PARALLEL '0');
+
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri from stdin with (FORMAT csv, DELIMITER ',', PARALLEL 1);
+10
+\.
+
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1) WHERE height > random() * 65;
+60,60,60
+\.
+
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+60
+\.
+
+-- temporary table copy: should perform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+
+COPY temp_test (a) from stdin with (PARALLEL 1);
+10
+\.
+
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) from stdin with (PARALLEL 1);
+
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) from stdin with (PARALLEL 1);
+
+-- missing data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+
+\.
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+2000	230	23	23
+\.
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+2001	231	\N	\N
+\.
+
+-- extra data: should fail
+COPY test_parallel_copy from stdin with (PARALLEL 1);
+2002	232	40	50	60	70	80
+\.
+
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) from stdin with (delimiter ',', null 'x', PARALLEL 1) ;
+x,45,80,90
+x,\x,\\x,\\\x
+x,\,,\\\,,\\
+\.
+
+COPY test_parallel_copy from stdin WITH (DELIMITER ';', NULL '', PARALLEL 1);
+3000;;c;;
+\.
+
+COPY test_parallel_copy from stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL 1);
+4000:\X:C:\X:\X
+4001:1:empty::
+4002:2:null:\X:\X
+4003:3:Backslash:\\:\\
+4004:4:BackslashX:\\X:\\X
+4005:5:N:\N:\N
+4006:6:BackslashN:\\N:\\N
+4007:7:XX:\XX:\XX
+4008:8:Delimiter:\::\:
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = 50004;
+50003	24	34	44	54
+50004	25	35	45 	55
+50005	26	36	46	56
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a > 60003;
+60001	22	32	42	52
+60002	23	33	43	53
+60003	24	34	44	54
+60004	25	35	45	55
+60005	26	36	46	56
+\.
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE f > 60003;
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (SELECT 1 FROM x);
+
+COPY test_parallel_copy from stdin WITH (PARALLEL 1) WHERE a IN (generate_series(1,5));
+
+COPY test_parallel_copy from stdin WITH(PARALLEL 1) WHERE a = row_number() over(b);
+
+-- check results of copy in
+SELECT * FROM test_parallel_copy;
+
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
 DROP TABLE x, y;
-- 
1.8.3.1

v6-0006-Parallel-Copy-For-Binary-Format-Files.patchapplication/octet-stream; name=v6-0006-Parallel-Copy-For-Binary-Format-Files.patchDownload
From fd470b5454555af0f633371f3e7ab99104e36f2c Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddy@enterprisedb.com>
Date: Fri, 9 Oct 2020 12:58:20 +0530
Subject: [PATCH v6 6/6] Parallel Copy For Binary Format Files

Leader reads data from the file into the DSM data blocks each of 64K size.
It also identifies each tuple data block id, start offset, end offset,
tuple size and updates this information in the ring data structure.
Workers parallelly read the tuple information from the ring data structure,
the actual tuple data from the data blocks and parallelly insert the tuples
into the table.
---
 src/backend/commands/copy.c         | 134 +++++----
 src/backend/commands/copyparallel.c | 426 ++++++++++++++++++++++++++--
 src/include/commands/copy.h         | 126 ++++++++
 3 files changed, 599 insertions(+), 87 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 5bed12896f..69119d8513 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -223,19 +223,14 @@ static void CopySendData(CopyState cstate, const void *databuf, int datasize);
 static void CopySendString(CopyState cstate, const char *str);
 static void CopySendChar(CopyState cstate, char c);
 static void CopySendEndOfRow(CopyState cstate);
-static int	CopyGetData(CopyState cstate, void *databuf,
-						int minread, int maxread);
 static void CopySendInt32(CopyState cstate, int32 val);
 static bool CopyGetInt32(CopyState cstate, int32 *val);
 static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 static bool CopyLoadRawBuf(CopyState cstate);
-static int	CopyReadBinaryData(CopyState cstate, char *dest, int nbytes);
-
 static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
 								   int copy_line_pos, int *copy_line_size);
 
-
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
  * in past protocol redesigns.
@@ -449,7 +444,7 @@ CopySendEndOfRow(CopyState cstate)
  *
  * NB: no data conversion is applied here.
  */
-static int
+int
 CopyGetData(CopyState cstate, void *databuf, int minread, int maxread)
 {
 	int			bytesread = 0;
@@ -582,10 +577,25 @@ CopyGetInt32(CopyState cstate, int32 *val)
 {
 	uint32		buf;
 
-	if (CopyReadBinaryData(cstate, (char *) &buf, sizeof(buf)) != sizeof(buf))
+	/*
+	 * For parallel copy, avoid reading data to raw buf, read directly from
+	 * file, later the data will be read to parallel copy data buffers.
+	 */
+	if (cstate->nworkers > 0)
 	{
-		*val = 0;				/* suppress compiler warning */
-		return false;
+		if (CopyGetData(cstate, &buf, sizeof(buf), sizeof(buf)) != sizeof(buf))
+		{
+			*val = 0;			/* suppress compiler warning */
+			return false;
+		}
+	}
+	else
+	{
+		if (CopyReadBinaryData(cstate, (char *) &buf, sizeof(buf)) != sizeof(buf))
+		{
+			*val = 0;			/* suppress compiler warning */
+			return false;
+		}
 	}
 	*val = (int32) pg_ntoh32(buf);
 	return true;
@@ -661,7 +671,7 @@ CopyLoadRawBuf(CopyState cstate)
  * and writes them to 'dest'.  Returns the number of bytes read (which
  * would be less than 'nbytes' only if we reach EOF).
  */
-static int
+int
 CopyReadBinaryData(CopyState cstate, char *dest, int nbytes)
 {
 	int			copied_bytes = 0;
@@ -986,7 +996,15 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 			EndParallelCopy(pcxt);
 		}
 		else
+		{
+			/*
+			 * Reset nworkers to -1 here. This is useful in cases where user
+			 * specifies parallel workers, but, no worker is picked up, so go
+			 * back to non parallel mode value of nworkers.
+			 */
+			cstate->nworkers = -1;
 			*processed = CopyFrom(cstate);	/* copy from file to database */
+		}
 
 		EndCopyFrom(cstate);
 	}
@@ -3556,7 +3574,7 @@ BeginCopyFrom(ParseState *pstate,
 		int32		tmp;
 
 		/* Signature */
-		if (CopyReadBinaryData(cstate, readSig, 11) != 11 ||
+		if (CopyGetData(cstate, readSig, 11, 11) != 11 ||
 			memcmp(readSig, BinarySignature, 11) != 0)
 			ereport(ERROR,
 					(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
@@ -3584,7 +3602,7 @@ BeginCopyFrom(ParseState *pstate,
 		/* Skip extension header, if present */
 		while (tmp-- > 0)
 		{
-			if (CopyReadBinaryData(cstate, readSig, 1) != 1)
+			if (CopyGetData(cstate, readSig, 1, 1) != 1)
 				ereport(ERROR,
 						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
 						 errmsg("invalid COPY file header (wrong length)")));
@@ -3781,60 +3799,45 @@ NextCopyFrom(CopyState cstate, ExprContext *econtext,
 	else
 	{
 		/* binary */
-		int16		fld_count;
-		ListCell   *cur;
-
 		cstate->cur_lineno++;
+		cstate->max_fields = list_length(cstate->attnumlist);
 
-		if (!CopyGetInt16(cstate, &fld_count))
+		if (!IsParallelCopy())
 		{
-			/* EOF detected (end of file, or protocol-level EOF) */
-			return false;
-		}
+			int16		fld_count;
+			ListCell   *cur;
 
-		if (fld_count == -1)
-		{
-			/*
-			 * Received EOF marker.  In a V3-protocol copy, wait for the
-			 * protocol-level EOF, and complain if it doesn't come
-			 * immediately.  This ensures that we correctly handle CopyFail,
-			 * if client chooses to send that now.
-			 *
-			 * Note that we MUST NOT try to read more data in an old-protocol
-			 * copy, since there is no protocol-level EOF marker then.  We
-			 * could go either way for copy from file, but choose to throw
-			 * error if there's data after the EOF marker, for consistency
-			 * with the new-protocol case.
-			 */
-			char		dummy;
-
-			if (cstate->copy_dest != COPY_OLD_FE &&
-				CopyReadBinaryData(cstate, &dummy, 1) > 0)
-				ereport(ERROR,
-						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-						 errmsg("received copy data after EOF marker")));
-			return false;
-		}
+			if (!CopyGetInt16(cstate, &fld_count))
+			{
+				/* EOF detected (end of file, or protocol-level EOF) */
+				return false;
+			}
 
-		if (fld_count != attr_count)
-			ereport(ERROR,
-					(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-					 errmsg("row field count is %d, expected %d",
-							(int) fld_count, attr_count)));
+			CHECK_FIELD_COUNT;
 
-		foreach(cur, cstate->attnumlist)
+			foreach(cur, cstate->attnumlist)
+			{
+				int			attnum = lfirst_int(cur);
+				int			m = attnum - 1;
+				Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+
+				cstate->cur_attname = NameStr(att->attname);
+				values[m] = CopyReadBinaryAttribute(cstate,
+													&in_functions[m],
+													typioparams[m],
+													att->atttypmod,
+													&nulls[m]);
+				cstate->cur_attname = NULL;
+			}
+		}
+		else
 		{
-			int			attnum = lfirst_int(cur);
-			int			m = attnum - 1;
-			Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+			bool		eof = false;
 
-			cstate->cur_attname = NameStr(att->attname);
-			values[m] = CopyReadBinaryAttribute(cstate,
-												&in_functions[m],
-												typioparams[m],
-												att->atttypmod,
-												&nulls[m]);
-			cstate->cur_attname = NULL;
+			eof = CopyReadBinaryTupleWorker(cstate, values, nulls);
+
+			if (eof)
+				return false;
 		}
 	}
 
@@ -4846,18 +4849,15 @@ CopyReadBinaryAttribute(CopyState cstate, FmgrInfo *flinfo,
 	Datum		result;
 
 	if (!CopyGetInt32(cstate, &fld_size))
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("unexpected EOF in COPY data")));
+		EOF_ERROR;
+
 	if (fld_size == -1)
 	{
 		*isnull = true;
 		return ReceiveFunctionCall(flinfo, NULL, typioparam, typmod);
 	}
-	if (fld_size < 0)
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("invalid field size")));
+
+	CHECK_FIELD_SIZE(fld_size);
 
 	/* reset attribute_buf to empty, and load raw data in it */
 	resetStringInfo(&cstate->attribute_buf);
@@ -4865,9 +4865,7 @@ CopyReadBinaryAttribute(CopyState cstate, FmgrInfo *flinfo,
 	enlargeStringInfo(&cstate->attribute_buf, fld_size);
 	if (CopyReadBinaryData(cstate, cstate->attribute_buf.data,
 						   fld_size) != fld_size)
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("unexpected EOF in COPY data")));
+		EOF_ERROR;
 
 	cstate->attribute_buf.len = fld_size;
 	cstate->attribute_buf.data[fld_size] = '\0';
diff --git a/src/backend/commands/copyparallel.c b/src/backend/commands/copyparallel.c
index 6a44a01e47..ccfe38363c 100644
--- a/src/backend/commands/copyparallel.c
+++ b/src/backend/commands/copyparallel.c
@@ -94,6 +94,7 @@ SerializeParallelCopyState(ParallelContext *pcxt, CopyState cstate,
 	shared_cstate.convert_selectively = cstate->convert_selectively;
 	shared_cstate.num_defaults = cstate->num_defaults;
 	shared_cstate.relid = cstate->pcdata->relid;
+	shared_cstate.binary = cstate->binary;
 
 	memcpy(shmptr, (char *) &shared_cstate, sizeof(SerializedParallelCopyState));
 	copiedsize = sizeof(SerializedParallelCopyState);
@@ -191,6 +192,7 @@ RestoreParallelCopyState(shm_toc *toc, CopyState cstate, List **attlist)
 	cstate->convert_selectively = shared_cstate.convert_selectively;
 	cstate->num_defaults = shared_cstate.num_defaults;
 	cstate->pcdata->relid = shared_cstate.relid;
+	cstate->binary = shared_cstate.binary;
 
 	cstate->null_print = CopyStringFromSharedMemory(shared_str_val + copiedsize,
 													&copiedsize);
@@ -380,7 +382,7 @@ static pg_attribute_always_inline bool
 IsParallelCopyAllowed(CopyState cstate)
 {
 	/* Parallel copy not allowed for frontend (2.0 protocol) & binary option. */
-	if ((cstate->copy_dest == COPY_OLD_FE) || cstate->binary)
+	if (cstate->copy_dest == COPY_OLD_FE)
 		return false;
 
 	/*
@@ -976,39 +978,425 @@ ParallelCopyFrom(CopyState cstate)
 	/* Execute the before statement triggers from the leader */
 	ExecBeforeStmtTrigger(cstate);
 
-	/* On input just throw the header line away. */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (!cstate->binary)
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
+		/* On input just throw the header line away. */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
 		{
-			pcshared_info->is_read_in_progress = false;
-			return;				/* done */
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+			{
+				pcshared_info->is_read_in_progress = false;
+				return;			/* done */
+			}
 		}
-	}
 
-	for (;;)
-	{
-		bool		done;
+		for (;;)
+		{
+			bool		done;
 
-		cstate->cur_lineno++;
+			cstate->cur_lineno++;
 
-		/* Actually read the line into memory here. */
-		done = CopyReadLine(cstate);
+			/* Actually read the line into memory here. */
+			done = CopyReadLine(cstate);
 
+			/*
+			 * EOF at start of line means we're done.  If we see EOF after
+			 * some characters, we act as though it was newline followed by
+			 * EOF, ie, process the line and then exit loop on next iteration.
+			 */
+			if (done && cstate->line_buf.len == 0)
+				break;
+		}
+	}
+	else
+	{
 		/*
-		 * EOF at start of line means we're done.  If we see EOF after some
-		 * characters, we act as though it was newline followed by EOF, ie,
-		 * process the line and then exit loop on next iteration.
+		 * Binary Format Files. For parallel copy leader, fill in the error
+		 * context information here, in case any failures while determining
+		 * tuple offsets, leader would throw the errors with proper context.
 		 */
-		if (done && cstate->line_buf.len == 0)
-			break;
+		ErrorContextCallback errcallback;
+
+		errcallback.callback = CopyFromErrorCallback;
+		errcallback.arg = (void *) cstate;
+		errcallback.previous = error_context_stack;
+		error_context_stack = &errcallback;
+		cstate->pcdata->curr_data_block = NULL;
+		cstate->raw_buf_index = 0;
+		pcshared_info->populated = 0;
+		cstate->cur_lineno = 0;
+		cstate->max_fields = list_length(cstate->attnumlist);
+
+		for (;;)
+		{
+			bool		eof = false;
+
+			cstate->cur_lineno++;
+
+			eof = CopyReadBinaryTupleLeader(cstate);
+
+			if (eof)
+				break;
+		}
+
+		/* Done, clean up */
+		error_context_stack = errcallback.previous;
 	}
 
 	pcshared_info->is_read_in_progress = false;
 	cstate->cur_lineno = 0;
 }
 
+/*
+ * CopyReadBinaryGetDataBlock
+ *
+ * Gets a new block, updates the current offset, calculates the skip bytes.
+ */
+void
+CopyReadBinaryGetDataBlock(CopyState cstate, FieldInfoType field_info)
+{
+	ParallelCopyDataBlock *data_block = NULL;
+	ParallelCopyDataBlock *curr_data_block = cstate->pcdata->curr_data_block;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	uint8		move_bytes = 0;
+	uint32		block_pos;
+	uint32		prev_block_pos;
+	int			read_bytes = 0;
+
+	prev_block_pos = pcshared_info->cur_block_pos;
+
+	block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+	if (field_info == FIELD_SIZE || field_info == FIELD_COUNT)
+		move_bytes = (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+
+	if (curr_data_block != NULL)
+		curr_data_block->skip_bytes = move_bytes;
+
+	data_block = &pcshared_info->data_blocks[block_pos];
+
+	if (move_bytes > 0 && curr_data_block != NULL)
+		memmove(&data_block->data[0], &curr_data_block->data[cstate->raw_buf_index], move_bytes);
+
+	elog(DEBUG1, "LEADER - field info %d is spread across data blocks - moved %d bytes from current block %u to %u block",
+		 field_info, move_bytes, prev_block_pos, block_pos);
+
+	read_bytes = CopyGetData(cstate, &data_block->data[move_bytes], 1, (DATA_BLOCK_SIZE - move_bytes));
+
+	if (field_info == FIELD_NONE && cstate->reached_eof)
+		return;
+
+	if (cstate->reached_eof)
+		EOF_ERROR;
+
+	elog(DEBUG1, "LEADER - bytes read from file %d", read_bytes);
+
+	if (field_info == FIELD_SIZE || field_info == FIELD_DATA)
+	{
+		ParallelCopyDataBlock *prev_data_block = NULL;
+
+		prev_data_block = curr_data_block;
+		prev_data_block->following_block = block_pos;
+
+		if (prev_data_block->curr_blk_completed == false)
+			prev_data_block->curr_blk_completed = true;
+
+		pg_atomic_add_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+	}
+
+	cstate->pcdata->curr_data_block = data_block;
+	cstate->raw_buf_index = 0;
+}
+
+/*
+ * CopyReadBinaryTupleLeader
+ *
+ * Leader reads data from binary formatted file to data blocks and identifies
+ * tuple boundaries/offsets so that workers can work on the data blocks data.
+ */
+bool
+CopyReadBinaryTupleLeader(CopyState cstate)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	int16		fld_count;
+	uint32		line_size = 0;
+	uint32		start_block_pos;
+	uint32		start_offset;
+
+	if (cstate->pcdata->curr_data_block == NULL)
+	{
+		CopyReadBinaryGetDataBlock(cstate, FIELD_NONE);
+
+		/*
+		 * no data is read from file here. one possibility to be here could be
+		 * that the binary file just has a valid signature but nothing else.
+		 */
+		if (cstate->reached_eof)
+			return true;
+	}
+
+	if ((cstate->raw_buf_index + sizeof(fld_count)) >= DATA_BLOCK_SIZE)
+		CopyReadBinaryGetDataBlock(cstate, FIELD_COUNT);
+
+	memcpy(&fld_count, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_count));
+	fld_count = (int16) pg_ntoh16(fld_count);
+	CHECK_FIELD_COUNT;
+	start_offset = cstate->raw_buf_index;
+	cstate->raw_buf_index += sizeof(fld_count);
+	line_size += sizeof(fld_count);
+	start_block_pos = pcshared_info->cur_block_pos;
+
+	CopyReadBinaryFindTupleSize(cstate, &line_size);
+
+	pg_atomic_add_fetch_u32(&cstate->pcdata->curr_data_block->unprocessed_line_parts, 1);
+
+	if (line_size > 0)
+		(void) UpdateSharedLineInfo(cstate, start_block_pos, start_offset,
+									line_size, LINE_LEADER_POPULATED, -1);
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryFindTupleSize
+ *
+ * Leader identifies boundaries/offsets for each attribute/column and finally
+ * results in the tuple/row size. It moves on to next data block if the
+ * attribute/column is spread across data blocks.
+ */
+void
+CopyReadBinaryFindTupleSize(CopyState cstate, uint32 *line_size)
+{
+	int32		fld_size;
+	ListCell   *cur;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			att_num = lfirst_int(cur);
+		Form_pg_attribute att = TupleDescAttr(tup_desc, (att_num - 1));
+
+		cstate->cur_attname = NameStr(att->attname);
+		fld_size = 0;
+
+		if ((cstate->raw_buf_index + sizeof(fld_size)) >= DATA_BLOCK_SIZE)
+			CopyReadBinaryGetDataBlock(cstate, FIELD_SIZE);
+
+		memcpy(&fld_size, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_size));
+		cstate->raw_buf_index += sizeof(fld_size);
+		*line_size += sizeof(fld_size);
+		fld_size = (int32) pg_ntoh32(fld_size);
+
+		CHECK_FIELD_SIZE(fld_size);
+
+		*line_size += fld_size;
+
+		if ((DATA_BLOCK_SIZE - cstate->raw_buf_index) >= fld_size)
+		{
+			cstate->raw_buf_index += fld_size;
+			elog(DEBUG1, "LEADER - tuple lies in he same data block");
+		}
+		else
+		{
+			int32		required_blks = 0;
+			int32		curr_blk_bytes = (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+			int			i = 0;
+
+			GET_REQUIRED_BLOCKS(required_blks, fld_size, curr_blk_bytes);
+
+			i = required_blks;
+
+			while (i > 0)
+			{
+				CopyReadBinaryGetDataBlock(cstate, FIELD_DATA);
+				i--;
+			}
+
+			GET_RAW_BUF_INDEX(cstate->raw_buf_index, fld_size, required_blks, curr_blk_bytes);
+
+			/*
+			 * raw_buf_index should never cross data block size, as the
+			 * required number of data blocks would have been obtained in the
+			 * above while loop.
+			 */
+			Assert(cstate->raw_buf_index <= DATA_BLOCK_SIZE);
+		}
+		cstate->cur_attname = NULL;
+	}
+}
+
+/*
+ * CopyReadBinaryTupleWorker
+ *
+ * Each worker reads data from data blocks after getting leader-identified tuple
+ * offsets from ring data structure.
+ */
+bool
+CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls)
+{
+	uint32		line_pos;
+	ParallelCopyLineBoundary *line_info;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	int16		fld_count;
+	ListCell   *cur;
+	FmgrInfo   *in_functions = cstate->in_functions;
+	Oid		   *typioparams = cstate->typioparams;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+
+	line_pos = GetLinePosition(cstate);
+	if (line_pos == -1)
+		return true;
+
+	line_info = &pcshared_info->line_boundaries.ring[line_pos];
+	cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[line_info->first_block];
+	cstate->raw_buf_index = line_info->start_offset;
+
+	if (cstate->raw_buf_index + sizeof(fld_count) >= DATA_BLOCK_SIZE)
+	{
+		/*
+		 * The case where field count spread across datablocks should never
+		 * occur, as the leader would have moved it to next block. this code
+		 * exists for debugging purposes only.
+		 */
+		elog(DEBUG1, "WORKER - field count spread across datablocks should never occur");
+	}
+
+	memcpy(&fld_count, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_count));
+	fld_count = (int16) pg_ntoh16(fld_count);
+
+	CHECK_FIELD_COUNT;
+
+	cstate->raw_buf_index += sizeof(fld_count);
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			att_num = lfirst_int(cur);
+		int			m = att_num - 1;
+		Form_pg_attribute att = TupleDescAttr(tup_desc, m);
+
+		cstate->cur_attname = NameStr(att->attname);
+
+		values[m] = CopyReadBinaryAttributeWorker(cstate,
+												  &in_functions[m],
+												  typioparams[m],
+												  att->atttypmod,
+												  &nulls[m]);
+		cstate->cur_attname = NULL;
+	}
+
+	pg_atomic_sub_fetch_u32(&cstate->pcdata->curr_data_block->unprocessed_line_parts, 1);
+	line_info->start_offset = -1;
+	pg_atomic_write_u32(&line_info->line_state, LINE_WORKER_PROCESSED);
+	pg_atomic_write_u32(&line_info->line_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryAttributeWorker
+ *
+ * Leader identifies boundaries/offsets for each attribute/column, it moves on
+ * to next data block if the attribute/column is spread across data blocks.
+ */
+Datum
+CopyReadBinaryAttributeWorker(CopyState cstate, FmgrInfo *flinfo,
+							  Oid typioparam, int32 typmod, bool *isnull)
+{
+	int32		fld_size;
+	Datum		result;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+	if ((cstate->raw_buf_index + sizeof(fld_size)) >= DATA_BLOCK_SIZE)
+	{
+		ParallelCopyDataBlock *prev_data_block = cstate->pcdata->curr_data_block;
+
+		elog(DEBUG1, "WORKER - field size is spread across data blocks");
+		cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[prev_data_block->following_block];
+		pg_atomic_sub_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+		cstate->raw_buf_index = 0;
+	}
+
+	memcpy(&fld_size, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_size));
+	fld_size = (int32) pg_ntoh32(fld_size);
+
+	CHECK_FIELD_SIZE(fld_size);
+
+	cstate->raw_buf_index += sizeof(fld_size);
+
+	/* reset attribute_buf to empty, and load raw data in it */
+	resetStringInfo(&cstate->attribute_buf);
+
+	enlargeStringInfo(&cstate->attribute_buf, fld_size);
+
+	if ((DATA_BLOCK_SIZE - cstate->raw_buf_index) >= fld_size)
+	{
+		elog(DEBUG1, "WORKER - tuple lies in single data block");
+		memcpy(&cstate->attribute_buf.data[0], &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], fld_size);
+		cstate->raw_buf_index += fld_size;
+	}
+	else
+	{
+		uint32		att_buf_idx = 0;
+		uint32		copy_bytes = 0;
+		int32		required_blks = 0;
+		int32		curr_blk_bytes = (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+		ParallelCopyDataBlock *prev_data_block = NULL;
+		int			i = 0;
+
+		GET_REQUIRED_BLOCKS(required_blks, fld_size, curr_blk_bytes);
+
+		i = required_blks;
+		prev_data_block = cstate->pcdata->curr_data_block;
+		elog(DEBUG1, "WORKER - tuple is spread across data blocks");
+		memcpy(&cstate->attribute_buf.data[0], &prev_data_block->data[cstate->raw_buf_index],
+			   curr_blk_bytes);
+		copy_bytes = curr_blk_bytes;
+		att_buf_idx = curr_blk_bytes;
+
+		while (i > 0)
+		{
+			cstate->pcdata->curr_data_block = &pcshared_info->data_blocks[prev_data_block->following_block];
+			pg_atomic_sub_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+			cstate->raw_buf_index = 0;
+			copy_bytes = fld_size - att_buf_idx;
+
+			/*
+			 * The bytes that are yet to be taken into att buff are more than
+			 * the entire data block size, but only take the data block size
+			 * elements.
+			 */
+			if (copy_bytes >= DATA_BLOCK_SIZE)
+				copy_bytes = DATA_BLOCK_SIZE;
+
+			memcpy(&cstate->attribute_buf.data[att_buf_idx],
+				   &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], copy_bytes);
+			att_buf_idx += copy_bytes;
+			prev_data_block = cstate->pcdata->curr_data_block;
+			i--;
+		}
+		GET_RAW_BUF_INDEX(cstate->raw_buf_index, fld_size, required_blks, curr_blk_bytes);
+	}
+
+	cstate->attribute_buf.len = fld_size;
+	cstate->attribute_buf.data[fld_size] = '\0';
+
+	/* Call the column type's binary input converter */
+	result = ReceiveFunctionCall(flinfo, &cstate->attribute_buf,
+								 typioparam, typmod);
+
+	/* Trouble if it didn't eat the whole buffer */
+	if (cstate->attribute_buf.cursor != cstate->attribute_buf.len)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+				 errmsg("incorrect binary data format")));
+
+	*isnull = false;
+	return result;
+}
+
 /*
  * GetLinePosition - Return the line position once the leader has populated the
  * data.
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index a9fe950e75..746c139e94 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -76,6 +76,109 @@ if (!IsParallelCopy()) \
 else \
 	return pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
 
+/*
+ * CHECK_FIELD_COUNT - Handles the error cases for field count
+ * for binary format files.
+ */
+#define CHECK_FIELD_COUNT \
+{\
+	if (fld_count == -1) \
+	{ \
+		if (IsParallelCopy() && \
+			!IsLeader()) \
+			return true; \
+		else if (IsParallelCopy() && \
+			IsLeader()) \
+		{ \
+			if (cstate->pcdata->curr_data_block->data[cstate->raw_buf_index + sizeof(fld_count)] != 0) \
+				ereport(ERROR, \
+						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+						errmsg("received copy data after EOF marker"))); \
+			return true; \
+		} \
+		else \
+		{ \
+			/* \
+			 * Received EOF marker.  In a V3-protocol copy, wait for the \
+			 * protocol-level EOF, and complain if it doesn't come \
+			 * immediately.  This ensures that we correctly handle CopyFail, \
+			 * if client chooses to send that now. \
+			 * \
+			 * Note that we MUST NOT try to read more data in an old-protocol \
+			 * copy, since there is no protocol-level EOF marker then.  We \
+			 * could go either way for copy from file, but choose to throw \
+			 * error if there's data after the EOF marker, for consistency \
+			 * with the new-protocol case. \
+			 */ \
+			char		dummy; \
+			if (cstate->copy_dest != COPY_OLD_FE && \
+				CopyReadBinaryData(cstate, &dummy, 1) > 0) \
+				ereport(ERROR, \
+						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+						errmsg("received copy data after EOF marker"))); \
+				return false; \
+		} \
+	} \
+	if (fld_count != cstate->max_fields) \
+		ereport(ERROR, \
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+				errmsg("row field count is %d, expected %d", \
+				(int) fld_count, cstate->max_fields))); \
+}
+
+/*
+ * CHECK_FIELD_SIZE - Handles the error case for field size
+ * for binary format files.
+ */
+#define CHECK_FIELD_SIZE(fld_size) \
+{ \
+	if (fld_size < -1) \
+		ereport(ERROR, \
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+				errmsg("invalid field size")));\
+}
+
+/*
+ * EOF_ERROR - Error statement for EOF for binary format
+ * files.
+ */
+#define EOF_ERROR \
+{ \
+	ereport(ERROR, \
+		(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+		errmsg("unexpected EOF in COPY data")));\
+}
+
+/*
+ * GET_RAW_BUF_INDEX - Calculates the raw buf index for the cases
+ * where the data spread is across multiple data blocks.
+ */
+#define GET_RAW_BUF_INDEX(raw_buf_index, fld_size, required_blks, curr_blk_bytes) \
+{ \
+	raw_buf_index = fld_size - (((required_blks - 1) * DATA_BLOCK_SIZE) + curr_blk_bytes); \
+}
+
+/*
+ * GET_REQUIRED_BLOCKS - Calculates the number of data
+ * blocks required for the cases where the data spread
+ * is across multiple data blocks.
+ */
+#define GET_REQUIRED_BLOCKS(required_blks, fld_size, curr_blk_bytes) \
+{ \
+	/* \
+	 * field size can spread across multiple data blocks, \
+	 * calculate the number of required data blocks and try to get \
+	 * those many data blocks. \
+	 */ \
+	required_blks = (int32)(fld_size - curr_blk_bytes)/(int32)DATA_BLOCK_SIZE; \
+	/* \
+	 * check if we need the data block for the field data \
+	 * bytes that are not modulus of data block size. \
+	 */ \
+	if ((fld_size - curr_blk_bytes)%DATA_BLOCK_SIZE != 0) \
+		required_blks++; \
+}
+
 /*
  * Represents the different source/dest cases we need to worry about at
  * the bottom level
@@ -253,6 +356,17 @@ typedef struct ParallelCopyLineBuf
 	uint64		cur_lineno;		/* line number for error messages */
 } ParallelCopyLineBuf;
 
+/*
+ * Represents the usage mode for CopyReadBinaryGetDataBlock.
+ */
+typedef enum FieldInfoType
+{
+	FIELD_NONE = 0,
+	FIELD_COUNT,
+	FIELD_SIZE,
+	FIELD_DATA
+}			FieldInfoType;
+
 /*
  * This structure helps in storing the common data from CopyStateData that are
  * required by the workers. This information will then be allocated and stored
@@ -276,6 +390,7 @@ typedef struct SerializedParallelCopyState
 	/* Working state for COPY FROM */
 	AttrNumber	num_defaults;
 	Oid			relid;
+	bool		binary;
 } SerializedParallelCopyState;
 
 /*
@@ -302,6 +417,9 @@ typedef struct ParallelCopyData
 
 	/* Current position in worker_line_buf */
 	uint32		worker_line_buf_pos;
+
+	/* For binary formatted files */
+	ParallelCopyDataBlock *curr_data_block;
 } ParallelCopyData;
 
 typedef int (*copy_data_source_cb) (void *outbuf, int minread, int maxread);
@@ -487,4 +605,12 @@ extern uint32 UpdateSharedLineInfo(CopyState cstate, uint32 blk_pos, uint32 offs
 								   uint32 line_size, uint32 line_state, uint32 blk_line_pos);
 extern void EndLineParallelCopy(CopyState cstate, uint32 line_pos, uint32 line_size,
 								uint32 raw_buf_ptr);
+extern int	CopyGetData(CopyState cstate, void *databuf, int minread, int maxread);
+extern int	CopyReadBinaryData(CopyState cstate, char *dest, int nbytes);
+extern bool CopyReadBinaryTupleLeader(CopyState cstate);
+extern bool CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls);
+extern void CopyReadBinaryFindTupleSize(CopyState cstate, uint32 *line_size);
+extern Datum CopyReadBinaryAttributeWorker(CopyState cstate, FmgrInfo *flinfo,
+										   Oid typioparam, int32 typmod, bool *isnull);
+extern void CopyReadBinaryGetDataBlock(CopyState cstate, FieldInfoType field_info);
 #endif							/* COPY_H */
-- 
2.25.1

#170Amit Kapila
amit.kapila16@gmail.com
In reply to: Bharath Rupireddy (#169)
Re: Parallel copy

On Fri, Oct 9, 2020 at 2:52 PM Bharath Rupireddy
<bharath.rupireddyforpostgres@gmail.com> wrote:

On Tue, Sep 29, 2020 at 6:30 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

From the testing perspective,
1. Test by having something force_parallel_mode = regress which means
that all existing Copy tests in the regression will be executed via
new worker code. You can have this as a test-only patch for now and
make sure all existing tests passed with this.

I don't think all the existing copy test cases(except the new test cases added in the parallel copy patch set) would run inside the parallel worker if force_parallel_mode is on. This is because, the parallelism will be picked up for parallel copy only if parallel option is specified unlike parallelism for select queries.

Sure, you need to change the code such that when force_parallel_mode =
'regress' is specified then it always uses one worker. This is
primarily for testing purposes and will help during the development of
this patch as it will make all exiting Copy tests to use quite a good
portion of the parallel infrastructure.

All the above tests are performed on the latest v6 patch set (attached here in this thread) with custom postgresql.conf[1]. The results are of the triplet form (exec time in sec, number of workers, gain)

Okay, so I am assuming the performance is the same as we have seen
with the earlier versions of patches.

Overall, we have below test cases to cover the code and for performance measurements. We plan to run these tests whenever a new set of patches is posted.

1. csv
2. binary

Don't we need the tests for plain text files as well?

3. force parallel mode = regress
4. toast data csv and binary
5. foreign key check, before row, after row, before statement, after statement, instead of triggers
6. partition case
7. foreign partitions and partitions having trigger cases
8. where clause having parallel unsafe and safe expression, default parallel unsafe and safe expression
9. temp, global, local, unlogged, inherited tables cases, foreign tables

Sounds like good coverage. So, are you doing all this testing
manually? How are you maintaining these tests?

--
With Regards,
Amit Kapila.

#171Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Amit Kapila (#170)
Re: Parallel copy

On Fri, Oct 9, 2020 at 3:26 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Fri, Oct 9, 2020 at 2:52 PM Bharath Rupireddy
<bharath.rupireddyforpostgres@gmail.com> wrote:

On Tue, Sep 29, 2020 at 6:30 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

From the testing perspective,
1. Test by having something force_parallel_mode = regress which means
that all existing Copy tests in the regression will be executed via
new worker code. You can have this as a test-only patch for now and
make sure all existing tests passed with this.

I don't think all the existing copy test cases(except the new test cases added in the parallel copy patch set) would run inside the parallel worker if force_parallel_mode is on. This is because, the parallelism will be picked up for parallel copy only if parallel option is specified unlike parallelism for select queries.

Sure, you need to change the code such that when force_parallel_mode =
'regress' is specified then it always uses one worker. This is
primarily for testing purposes and will help during the development of
this patch as it will make all exiting Copy tests to use quite a good
portion of the parallel infrastructure.

IIUC, firstly, I will set force_parallel_mode = FORCE_PARALLEL_REGRESS
as default value in guc.c, and then adjust the parallelism related
code in copy.c such that it always picks 1 worker and spawns it. This
way, all the existing copy test cases would be run in parallel worker.
Please let me know if this is okay. If yes, I will do this and update
here.

All the above tests are performed on the latest v6 patch set (attached here in this thread) with custom postgresql.conf[1]. The results are of the triplet form (exec time in sec, number of workers, gain)

Okay, so I am assuming the performance is the same as we have seen
with the earlier versions of patches.

Yes. Most recent run on v5 patch set [1]/messages/by-id/CALj2ACW=jm5ri+7rXiQaFT_c5h2rVS=cJOQVFR5R+bowt3QDkw@mail.gmail.com

Overall, we have below test cases to cover the code and for performance measurements. We plan to run these tests whenever a new set of patches is posted.

1. csv
2. binary

Don't we need the tests for plain text files as well?

Will add one.

3. force parallel mode = regress
4. toast data csv and binary
5. foreign key check, before row, after row, before statement, after statement, instead of triggers
6. partition case
7. foreign partitions and partitions having trigger cases
8. where clause having parallel unsafe and safe expression, default parallel unsafe and safe expression
9. temp, global, local, unlogged, inherited tables cases, foreign tables

Sounds like good coverage. So, are you doing all this testing
manually? How are you maintaining these tests?

Yes, running them manually. Few of the tests(1,2,4) require huge
datasets for performance measurements and other test cases are to
ensure we don't choose parallelism. We will try to add test cases that
are not meant for performance, to the patch test.

[1]: /messages/by-id/CALj2ACW=jm5ri+7rXiQaFT_c5h2rVS=cJOQVFR5R+bowt3QDkw@mail.gmail.com

With Regards,
Bharath Rupireddy.
EnterpriseDB: http://www.enterprisedb.com

#172Amit Kapila
amit.kapila16@gmail.com
In reply to: Bharath Rupireddy (#171)
Re: Parallel copy

On Fri, Oct 9, 2020 at 3:50 PM Bharath Rupireddy
<bharath.rupireddyforpostgres@gmail.com> wrote:

On Fri, Oct 9, 2020 at 3:26 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Fri, Oct 9, 2020 at 2:52 PM Bharath Rupireddy
<bharath.rupireddyforpostgres@gmail.com> wrote:

On Tue, Sep 29, 2020 at 6:30 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

From the testing perspective,
1. Test by having something force_parallel_mode = regress which means
that all existing Copy tests in the regression will be executed via
new worker code. You can have this as a test-only patch for now and
make sure all existing tests passed with this.

I don't think all the existing copy test cases(except the new test cases added in the parallel copy patch set) would run inside the parallel worker if force_parallel_mode is on. This is because, the parallelism will be picked up for parallel copy only if parallel option is specified unlike parallelism for select queries.

Sure, you need to change the code such that when force_parallel_mode =
'regress' is specified then it always uses one worker. This is
primarily for testing purposes and will help during the development of
this patch as it will make all exiting Copy tests to use quite a good
portion of the parallel infrastructure.

IIUC, firstly, I will set force_parallel_mode = FORCE_PARALLEL_REGRESS
as default value in guc.c,

No need to set this as the default value. You can change it in
postgresql.conf before running tests.

and then adjust the parallelism related
code in copy.c such that it always picks 1 worker and spawns it. This
way, all the existing copy test cases would be run in parallel worker.
Please let me know if this is okay.

Yeah, this sounds fine.

If yes, I will do this and update
here.

Okay, thanks, but ensure the difference in test execution before and
after your change. After your change, all the 'copy' tests should
invoke the worker to perform a copy.

All the above tests are performed on the latest v6 patch set (attached here in this thread) with custom postgresql.conf[1]. The results are of the triplet form (exec time in sec, number of workers, gain)

Okay, so I am assuming the performance is the same as we have seen
with the earlier versions of patches.

Yes. Most recent run on v5 patch set [1]

Okay, good to know that.

--
With Regards,
Amit Kapila.

#173vignesh C
vignesh21@gmail.com
In reply to: Amit Kapila (#167)
6 attachment(s)
Re: Parallel copy

On Fri, Oct 9, 2020 at 12:10 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

While looking at the latest code, I observed below issue in patch
v6-0003-Allow-copy-from-command-to-process-data-from-file:

+ /* Estimate the size for shared information for PARALLEL_COPY_KEY_CSTATE */
+ est_cstateshared = MAXALIGN(sizeof(SerializedParallelCopyState));
+ shm_toc_estimate_chunk(&pcxt->estimator, est_cstateshared);
+ shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+ strsize = EstimateCstateSize(pcxt, cstate, attnamelist, &whereClauseStr,
+ &rangeTableStr, &attnameListStr,
+ &notnullListStr, &nullListStr,
+ &convertListStr);

Here, do we need to separately estimate the size of
SerializedParallelCopyState when it is also done in
EstimateCstateSize?

This is not required, this has been removed in the attached patches.

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

Attachments:

v7-0001-Copy-code-readjustment-to-support-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=v7-0001-Copy-code-readjustment-to-support-parallel-copy.patchDownload
From ff510b2589e251523b12e3914cc7fe89ba0ac1d0 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Tue, 13 Oct 2020 18:29:58 +0530
Subject: [PATCH v7 1/6] Copy code readjustment to support parallel copy.

This patch has the copy code slightly readjusted so that the common code is
separated to functions/macros, these functions/macros will be used by the
workers in the parallel copy code of the upcoming patches. EOL removal is moved
from CopyReadLine to CopyReadLineText, this change was required because in case
of parallel copy the record identification and record updation is done in
CopyReadLineText, before record information is updated in shared memory the new
line characters should be removed.
---
 src/backend/commands/copy.c | 335 ++++++++++++++++++++++++++------------------
 1 file changed, 199 insertions(+), 136 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 71d48d4..a01e438 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -95,6 +95,9 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
+#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+#define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
+
 /*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
@@ -224,7 +227,6 @@ typedef struct CopyStateData
 	 * appropriate amounts of data from this buffer.  In both modes, we
 	 * guarantee that there is a \0 at raw_buf[raw_buf_len].
 	 */
-#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
@@ -288,7 +290,6 @@ typedef struct CopyMultiInsertInfo
 	int			ti_options;		/* table insert options */
 } CopyMultiInsertInfo;
 
-
 /*
  * These macros centralize code used to process line_buf and raw_buf buffers.
  * They are macros because they often do continue/break control and to avoid
@@ -401,6 +402,12 @@ static bool CopyGetInt16(CopyState cstate, int16 *val);
 static bool CopyLoadRawBuf(CopyState cstate);
 static int	CopyReadBinaryData(CopyState cstate, char *dest, int nbytes);
 
+static void PopulateCommonCstateInfo(CopyState cstate, TupleDesc tup_desc,
+									 List *attnamelist);
+static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
+								   int copy_line_pos, int *copy_line_size);
+static void ConvertToServerEncoding(CopyState cstate);
+
 
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
@@ -1518,7 +1525,6 @@ BeginCopy(ParseState *pstate,
 {
 	CopyState	cstate;
 	TupleDesc	tupDesc;
-	int			num_phys_attrs;
 	MemoryContext oldcontext;
 
 	/* Allocate workspace and zero all fields */
@@ -1684,6 +1690,25 @@ BeginCopy(ParseState *pstate,
 		tupDesc = cstate->queryDesc->tupDesc;
 	}
 
+	PopulateCommonCstateInfo(cstate, tupDesc, attnamelist);
+	cstate->copy_dest = COPY_FILE;	/* default */
+
+	MemoryContextSwitchTo(oldcontext);
+
+	return cstate;
+}
+
+/*
+ * PopulateCommonCstateInfo
+ *
+ * Populates the common variables required for copy from operation. This is a
+ * helper function for BeginCopy function.
+ */
+static void
+PopulateCommonCstateInfo(CopyState cstate, TupleDesc tupDesc, List *attnamelist)
+{
+	int			num_phys_attrs;
+
 	/* Generate or convert list of attributes to process */
 	cstate->attnumlist = CopyGetAttnums(tupDesc, cstate->rel, attnamelist);
 
@@ -1803,12 +1828,6 @@ BeginCopy(ParseState *pstate,
 		 pg_database_encoding_max_length() > 1);
 	/* See Multibyte encoding comment above */
 	cstate->encoding_embeds_ascii = PG_ENCODING_IS_CLIENT_ONLY(cstate->file_encoding);
-
-	cstate->copy_dest = COPY_FILE;	/* default */
-
-	MemoryContextSwitchTo(oldcontext);
-
-	return cstate;
 }
 
 /*
@@ -2700,32 +2719,13 @@ CopyMultiInsertInfoStore(CopyMultiInsertInfo *miinfo, ResultRelInfo *rri,
 }
 
 /*
- * Copy FROM file to relation.
+ * CheckTargetRelValidity
+ *
+ * Check if the relation specified in copy from is valid.
  */
-uint64
-CopyFrom(CopyState cstate)
+static void
+CheckTargetRelValidity(CopyState cstate)
 {
-	ResultRelInfo *resultRelInfo;
-	ResultRelInfo *target_resultRelInfo;
-	ResultRelInfo *prevResultRelInfo = NULL;
-	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
-	ModifyTableState *mtstate;
-	ExprContext *econtext;
-	TupleTableSlot *singleslot = NULL;
-	MemoryContext oldcontext = CurrentMemoryContext;
-
-	PartitionTupleRouting *proute = NULL;
-	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
-	int			ti_options = 0; /* start with default options for insert */
-	BulkInsertState bistate = NULL;
-	CopyInsertMethod insertMethod;
-	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
-	uint64		processed = 0;
-	bool		has_before_insert_row_trig;
-	bool		has_instead_insert_row_trig;
-	bool		leafpart_use_multi_insert = false;
-
 	Assert(cstate->rel);
 	Assert(list_length(cstate->range_table) == 1);
 
@@ -2763,27 +2763,6 @@ CopyFrom(CopyState cstate)
 							RelationGetRelationName(cstate->rel))));
 	}
 
-	/*
-	 * If the target file is new-in-transaction, we assume that checking FSM
-	 * for free space is a waste of time.  This could possibly be wrong, but
-	 * it's unlikely.
-	 */
-	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
-		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
-		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
-		ti_options |= TABLE_INSERT_SKIP_FSM;
-
-	/*
-	 * Optimize if new relfilenode was created in this subxact or one of its
-	 * committed children and we won't see those rows later as part of an
-	 * earlier scan or command. The subxact test ensures that if this subxact
-	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
-	 * that the stronger test of exactly which subtransaction created it is
-	 * crucial for correctness of this optimization. The test for an earlier
-	 * scan or command tolerates false negatives. FREEZE causes other sessions
-	 * to see rows they would not see under MVCC, and a false negative merely
-	 * spreads that anomaly to the current session.
-	 */
 	if (cstate->freeze)
 	{
 		/*
@@ -2821,9 +2800,61 @@ CopyFrom(CopyState cstate)
 			ereport(ERROR,
 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 					 errmsg("cannot perform COPY FREEZE because the table was not created or truncated in the current subtransaction")));
+	}
+}
+
+/*
+ * Copy FROM file to relation.
+ */
+uint64
+CopyFrom(CopyState cstate)
+{
+	ResultRelInfo *resultRelInfo;
+	ResultRelInfo *target_resultRelInfo;
+	ResultRelInfo *prevResultRelInfo = NULL;
+	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
+	ModifyTableState *mtstate;
+	ExprContext *econtext;
+	TupleTableSlot *singleslot = NULL;
+	MemoryContext oldcontext = CurrentMemoryContext;
+
+	PartitionTupleRouting *proute = NULL;
+	ErrorContextCallback errcallback;
+	CommandId	mycid = GetCurrentCommandId(true);
+	int			ti_options = 0; /* start with default options for insert */
+	BulkInsertState bistate = NULL;
+	CopyInsertMethod insertMethod;
+	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
+	uint64		processed = 0;
+	bool		has_before_insert_row_trig;
+	bool		has_instead_insert_row_trig;
+	bool		leafpart_use_multi_insert = false;
+
+	CheckTargetRelValidity(cstate);
+
+	/*
+	 * If the target file is new-in-transaction, we assume that checking FSM
+	 * for free space is a waste of time.  This could possibly be wrong, but
+	 * it's unlikely.
+	 */
+	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
+		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
+		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
+		ti_options |= TABLE_INSERT_SKIP_FSM;
 
+	/*
+	 * Optimize if new relfilenode was created in this subxact or one of its
+	 * committed children and we won't see those rows later as part of an
+	 * earlier scan or command. The subxact test ensures that if this subxact
+	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
+	 * that the stronger test of exactly which subtransaction created it is
+	 * crucial for correctness of this optimization. The test for an earlier
+	 * scan or command tolerates false negatives. FREEZE causes other sessions
+	 * to see rows they would not see under MVCC, and a false negative merely
+	 * spreads that anomaly to the current session.
+	 */
+	if (cstate->freeze)
 		ti_options |= TABLE_INSERT_FROZEN;
-	}
 
 	/*
 	 * We need a ResultRelInfo so we can use the regular executor's
@@ -3366,26 +3397,13 @@ CopyFrom(CopyState cstate)
 }
 
 /*
- * Setup to read tuples from a file for COPY FROM.
+ * PopulateCstateCatalogInfo
  *
- * 'rel': Used as a template for the tuples
- * 'filename': Name of server-local file to read
- * 'attnamelist': List of char *, columns to include. NIL selects all cols.
- * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
- *
- * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ * Populate the cstate catalog information.
  */
-CopyState
-BeginCopyFrom(ParseState *pstate,
-			  Relation rel,
-			  const char *filename,
-			  bool is_program,
-			  copy_data_source_cb data_source_cb,
-			  List *attnamelist,
-			  List *options)
+static void
+PopulateCstateCatalogInfo(CopyState cstate)
 {
-	CopyState	cstate;
-	bool		pipe = (filename == NULL);
 	TupleDesc	tupDesc;
 	AttrNumber	num_phys_attrs,
 				num_defaults;
@@ -3395,38 +3413,8 @@ BeginCopyFrom(ParseState *pstate,
 	Oid			in_func_oid;
 	int		   *defmap;
 	ExprState **defexprs;
-	MemoryContext oldcontext;
 	bool		volatile_defexprs;
 
-	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
-	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
-
-	/* Initialize state variables */
-	cstate->reached_eof = false;
-	cstate->eol_type = EOL_UNKNOWN;
-	cstate->cur_relname = RelationGetRelationName(cstate->rel);
-	cstate->cur_lineno = 0;
-	cstate->cur_attname = NULL;
-	cstate->cur_attval = NULL;
-
-	/*
-	 * Set up variables to avoid per-attribute overhead.  attribute_buf and
-	 * raw_buf are used in both text and binary modes, but we use line_buf
-	 * only in text mode.
-	 */
-	initStringInfo(&cstate->attribute_buf);
-	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
-	cstate->raw_buf_index = cstate->raw_buf_len = 0;
-	if (!cstate->binary)
-	{
-		initStringInfo(&cstate->line_buf);
-		cstate->line_buf_converted = false;
-	}
-
-	/* Assign range table, we'll need it in CopyFrom. */
-	if (pstate)
-		cstate->range_table = pstate->p_rtable;
-
 	tupDesc = RelationGetDescr(cstate->rel);
 	num_phys_attrs = tupDesc->natts;
 	num_defaults = 0;
@@ -3504,6 +3492,61 @@ BeginCopyFrom(ParseState *pstate,
 	cstate->defexprs = defexprs;
 	cstate->volatile_defexprs = volatile_defexprs;
 	cstate->num_defaults = num_defaults;
+}
+
+/*
+ * Setup to read tuples from a file for COPY FROM.
+ *
+ * 'rel': Used as a template for the tuples
+ * 'filename': Name of server-local file to read
+ * 'attnamelist': List of char *, columns to include. NIL selects all cols.
+ * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
+ *
+ * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ */
+CopyState
+BeginCopyFrom(ParseState *pstate,
+			  Relation rel,
+			  const char *filename,
+			  bool is_program,
+			  copy_data_source_cb data_source_cb,
+			  List *attnamelist,
+			  List *options)
+{
+	CopyState	cstate;
+	bool		pipe = (filename == NULL);
+	MemoryContext oldcontext;
+
+	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	/* Initialize state variables */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/*
+	 * Set up variables to avoid per-attribute overhead.  attribute_buf is
+	 * used in both text and binary modes, but we use line_buf and raw_buf
+	 * only in text mode.
+	 */
+	initStringInfo(&cstate->attribute_buf);
+	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+	if (!cstate->binary)
+	{
+		initStringInfo(&cstate->line_buf);
+		cstate->line_buf_converted = false;
+	}
+
+	/* Assign range table, we'll need it in CopyFrom. */
+	if (pstate)
+		cstate->range_table = pstate->p_rtable;
+
+	PopulateCstateCatalogInfo(cstate);
 	cstate->is_program = is_program;
 
 	if (data_source_cb)
@@ -3913,40 +3956,60 @@ CopyReadLine(CopyState cstate)
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
-	else
+
+	ConvertToServerEncoding(cstate);
+	return result;
+}
+
+/*
+ * ClearEOLFromCopiedData
+ *
+ * Clear EOL from the copied data.
+ */
+static void
+ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
+					   int copy_line_pos, int *copy_line_size)
+{
+	/*
+	 * If we didn't hit EOF, then we must have transferred the EOL marker to
+	 * line_buf along with the data.  Get rid of it.
+	 */
+	switch (cstate->eol_type)
 	{
-		/*
-		 * If we didn't hit EOF, then we must have transferred the EOL marker
-		 * to line_buf along with the data.  Get rid of it.
-		 */
-		switch (cstate->eol_type)
-		{
-			case EOL_NL:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CR:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\r');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CRNL:
-				Assert(cstate->line_buf.len >= 2);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 2] == '\r');
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len -= 2;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_UNKNOWN:
-				/* shouldn't get here */
-				Assert(false);
-				break;
-		}
+		case EOL_NL:
+			Assert(*copy_line_size >= 1);
+			Assert(copy_line_data[copy_line_pos - 1] == '\n');
+			copy_line_data[copy_line_pos - 1] = '\0';
+			(*copy_line_size)--;
+			break;
+		case EOL_CR:
+			Assert(*copy_line_size >= 1);
+			Assert(copy_line_data[copy_line_pos - 1] == '\r');
+			copy_line_data[copy_line_pos - 1] = '\0';
+			(*copy_line_size)--;
+			break;
+		case EOL_CRNL:
+			Assert(*copy_line_size >= 2);
+			Assert(copy_line_data[copy_line_pos - 2] == '\r');
+			Assert(copy_line_data[copy_line_pos - 1] == '\n');
+			copy_line_data[copy_line_pos - 2] = '\0';
+			*copy_line_size -= 2;
+			break;
+		case EOL_UNKNOWN:
+			/* shouldn't get here */
+			Assert(false);
+			break;
 	}
+}
 
+/*
+ * ConvertToServerEncoding
+ *
+ * Convert contents to server encoding.
+ */
+static void
+ConvertToServerEncoding(CopyState cstate)
+{
 	/* Done reading the line.  Convert it to server encoding. */
 	if (cstate->need_transcoding)
 	{
@@ -3963,11 +4026,8 @@ CopyReadLine(CopyState cstate)
 			pfree(cvt);
 		}
 	}
-
 	/* Now it's safe to use the buffer in error messages */
 	cstate->line_buf_converted = true;
-
-	return result;
 }
 
 /*
@@ -4330,6 +4390,9 @@ not_end_of_copy:
 	 * Transfer any still-uncopied data to line_buf.
 	 */
 	REFILL_LINEBUF;
+	if (!result && !IsHeaderLine())
+		ClearEOLFromCopiedData(cstate, cstate->line_buf.data,
+							   cstate->line_buf.len, &cstate->line_buf.len);
 
 	return result;
 }
-- 
1.8.3.1

v7-0002-Framework-for-leader-worker-in-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=v7-0002-Framework-for-leader-worker-in-parallel-copy.patchDownload
From 8f95ef5928693a38f444a94143adeb7d74e85ddd Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 7 Oct 2020 17:18:17 +0530
Subject: [PATCH v7 2/6] Framework for leader/worker in parallel copy

This patch has the framework for data structures in parallel copy, leader
initialization, worker initialization, shared memory updation, starting workers,
wait for workers and workers exiting.
---
 src/backend/access/transam/parallel.c |   4 +
 src/backend/commands/copy.c           | 235 ++++++--------------
 src/include/commands/copy.h           | 389 +++++++++++++++++++++++++++++++++-
 src/tools/pgindent/typedefs.list      |   7 +
 4 files changed, 468 insertions(+), 167 deletions(-)

diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index b042696..a3cff4b 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -25,6 +25,7 @@
 #include "catalog/pg_enum.h"
 #include "catalog/storage.h"
 #include "commands/async.h"
+#include "commands/copy.h"
 #include "executor/execParallel.h"
 #include "libpq/libpq.h"
 #include "libpq/pqformat.h"
@@ -145,6 +146,9 @@ static const struct
 	},
 	{
 		"parallel_vacuum_main", parallel_vacuum_main
+	},
+	{
+		"ParallelCopyMain", ParallelCopyMain
 	}
 };
 
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index a01e438..6c5dc2a 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -29,7 +29,6 @@
 #include "catalog/pg_type.h"
 #include "commands/copy.h"
 #include "commands/defrem.h"
-#include "commands/trigger.h"
 #include "executor/execPartition.h"
 #include "executor/executor.h"
 #include "executor/nodeModifyTable.h"
@@ -63,29 +62,6 @@
 #define OCTVALUE(c) ((c) - '0')
 
 /*
- * Represents the different source/dest cases we need to worry about at
- * the bottom level
- */
-typedef enum CopyDest
-{
-	COPY_FILE,					/* to/from file (or a piped program) */
-	COPY_OLD_FE,				/* to/from frontend (2.0 protocol) */
-	COPY_NEW_FE,				/* to/from frontend (3.0 protocol) */
-	COPY_CALLBACK				/* to/from callback function */
-} CopyDest;
-
-/*
- *	Represents the end-of-line terminator type of the input
- */
-typedef enum EolType
-{
-	EOL_UNKNOWN,
-	EOL_NL,
-	EOL_CR,
-	EOL_CRNL
-} EolType;
-
-/*
  * Represents the heap insert method to be used during COPY FROM.
  */
 typedef enum CopyInsertMethod
@@ -95,145 +71,10 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
-#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+#define IsParallelCopy()		(cstate->is_parallel)
+#define IsLeader()				(cstate->pcdata->is_leader)
 #define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
 
-/*
- * This struct contains all the state variables used throughout a COPY
- * operation. For simplicity, we use the same struct for all variants of COPY,
- * even though some fields are used in only some cases.
- *
- * Multi-byte encodings: all supported client-side encodings encode multi-byte
- * characters by having the first byte's high bit set. Subsequent bytes of the
- * character can have the high bit not set. When scanning data in such an
- * encoding to look for a match to a single-byte (ie ASCII) character, we must
- * use the full pg_encoding_mblen() machinery to skip over multibyte
- * characters, else we might find a false match to a trailing byte. In
- * supported server encodings, there is no possibility of a false match, and
- * it's faster to make useless comparisons to trailing bytes than it is to
- * invoke pg_encoding_mblen() to skip over them. encoding_embeds_ascii is true
- * when we have to do it the hard way.
- */
-typedef struct CopyStateData
-{
-	/* low-level state data */
-	CopyDest	copy_dest;		/* type of copy source/destination */
-	FILE	   *copy_file;		/* used if copy_dest == COPY_FILE */
-	StringInfo	fe_msgbuf;		/* used for all dests during COPY TO, only for
-								 * dest == COPY_NEW_FE in COPY FROM */
-	bool		is_copy_from;	/* COPY TO, or COPY FROM? */
-	bool		reached_eof;	/* true if we read to end of copy data (not
-								 * all copy_dest types maintain this) */
-	EolType		eol_type;		/* EOL type of input */
-	int			file_encoding;	/* file or remote side's character encoding */
-	bool		need_transcoding;	/* file encoding diff from server? */
-	bool		encoding_embeds_ascii;	/* ASCII can be non-first byte? */
-
-	/* parameters from the COPY command */
-	Relation	rel;			/* relation to copy to or from */
-	QueryDesc  *queryDesc;		/* executable query to copy from */
-	List	   *attnumlist;		/* integer list of attnums to copy */
-	char	   *filename;		/* filename, or NULL for STDIN/STDOUT */
-	bool		is_program;		/* is 'filename' a program to popen? */
-	copy_data_source_cb data_source_cb; /* function for reading data */
-	bool		binary;			/* binary format? */
-	bool		freeze;			/* freeze rows on loading? */
-	bool		csv_mode;		/* Comma Separated Value format? */
-	bool		header_line;	/* CSV header line? */
-	char	   *null_print;		/* NULL marker string (server encoding!) */
-	int			null_print_len; /* length of same */
-	char	   *null_print_client;	/* same converted to file encoding */
-	char	   *delim;			/* column delimiter (must be 1 byte) */
-	char	   *quote;			/* CSV quote char (must be 1 byte) */
-	char	   *escape;			/* CSV escape char (must be 1 byte) */
-	List	   *force_quote;	/* list of column names */
-	bool		force_quote_all;	/* FORCE_QUOTE *? */
-	bool	   *force_quote_flags;	/* per-column CSV FQ flags */
-	List	   *force_notnull;	/* list of column names */
-	bool	   *force_notnull_flags;	/* per-column CSV FNN flags */
-	List	   *force_null;		/* list of column names */
-	bool	   *force_null_flags;	/* per-column CSV FN flags */
-	bool		convert_selectively;	/* do selective binary conversion? */
-	List	   *convert_select; /* list of column names (can be NIL) */
-	bool	   *convert_select_flags;	/* per-column CSV/TEXT CS flags */
-	Node	   *whereClause;	/* WHERE condition (or NULL) */
-
-	/* these are just for error messages, see CopyFromErrorCallback */
-	const char *cur_relname;	/* table name for error messages */
-	uint64		cur_lineno;		/* line number for error messages */
-	const char *cur_attname;	/* current att for error messages */
-	const char *cur_attval;		/* current att value for error messages */
-
-	/*
-	 * Working state for COPY TO/FROM
-	 */
-	MemoryContext copycontext;	/* per-copy execution context */
-
-	/*
-	 * Working state for COPY TO
-	 */
-	FmgrInfo   *out_functions;	/* lookup info for output functions */
-	MemoryContext rowcontext;	/* per-row evaluation context */
-
-	/*
-	 * Working state for COPY FROM
-	 */
-	AttrNumber	num_defaults;
-	FmgrInfo   *in_functions;	/* array of input functions for each attrs */
-	Oid		   *typioparams;	/* array of element types for in_functions */
-	int		   *defmap;			/* array of default att numbers */
-	ExprState **defexprs;		/* array of default att expressions */
-	bool		volatile_defexprs;	/* is any of defexprs volatile? */
-	List	   *range_table;
-	ExprState  *qualexpr;
-
-	TransitionCaptureState *transition_capture;
-
-	/*
-	 * These variables are used to reduce overhead in COPY FROM.
-	 *
-	 * attribute_buf holds the separated, de-escaped text for each field of
-	 * the current line.  The CopyReadAttributes functions return arrays of
-	 * pointers into this buffer.  We avoid palloc/pfree overhead by re-using
-	 * the buffer on each cycle.
-	 *
-	 * In binary COPY FROM, attribute_buf holds the binary data for the
-	 * current field, but the usage is otherwise similar.
-	 */
-	StringInfoData attribute_buf;
-
-	/* field raw data pointers found by COPY FROM */
-
-	int			max_fields;
-	char	  **raw_fields;
-
-	/*
-	 * Similarly, line_buf holds the whole input line being processed. The
-	 * input cycle is first to read the whole line into line_buf, convert it
-	 * to server encoding there, and then extract the individual attribute
-	 * fields into attribute_buf.  line_buf is preserved unmodified so that we
-	 * can display it in error messages if appropriate.  (In binary mode,
-	 * line_buf is not used.)
-	 */
-	StringInfoData line_buf;
-	bool		line_buf_converted; /* converted to server encoding? */
-	bool		line_buf_valid; /* contains the row being processed? */
-
-	/*
-	 * Finally, raw_buf holds raw data read from the data source (file or
-	 * client connection).  In text mode, CopyReadLine parses this data
-	 * sufficiently to locate line boundaries, then transfers the data to
-	 * line_buf and converts it.  In binary mode, CopyReadBinaryData fetches
-	 * appropriate amounts of data from this buffer.  In both modes, we
-	 * guarantee that there is a \0 at raw_buf[raw_buf_len].
-	 */
-	char	   *raw_buf;
-	int			raw_buf_index;	/* next byte to process */
-	int			raw_buf_len;	/* total # of bytes stored */
-	/* Shorthand for number of unconsumed bytes available in raw_buf */
-#define RAW_BUF_BYTES(cstate) ((cstate)->raw_buf_len - (cstate)->raw_buf_index)
-} CopyStateData;
-
 /* DestReceiver for COPY (query) TO */
 typedef struct
 {
@@ -402,8 +243,6 @@ static bool CopyGetInt16(CopyState cstate, int16 *val);
 static bool CopyLoadRawBuf(CopyState cstate);
 static int	CopyReadBinaryData(CopyState cstate, char *dest, int nbytes);
 
-static void PopulateCommonCstateInfo(CopyState cstate, TupleDesc tup_desc,
-									 List *attnamelist);
 static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
 								   int copy_line_pos, int *copy_line_size);
 static void ConvertToServerEncoding(CopyState cstate);
@@ -1117,6 +956,8 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 
 	if (is_from)
 	{
+		ParallelContext *pcxt = NULL;
+
 		Assert(rel);
 
 		/* check read-only transaction and parallel mode */
@@ -1126,7 +967,35 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 		cstate = BeginCopyFrom(pstate, rel, stmt->filename, stmt->is_program,
 							   NULL, stmt->attlist, stmt->options);
 		cstate->whereClause = whereClause;
-		*processed = CopyFrom(cstate);	/* copy from file to database */
+		cstate->is_parallel = false;
+
+		if (cstate->nworkers > 0)
+			pcxt = BeginParallelCopy(cstate->nworkers, cstate, stmt->attlist,
+									 relid);
+
+		if (pcxt)
+		{
+			int			i;
+
+			ParallelCopyFrom(cstate);
+
+			/* Wait for all copy workers to finish */
+			WaitForParallelWorkersToFinish(pcxt);
+
+			/*
+			 * Next, accumulate WAL usage.  (This must wait for the workers to
+			 * finish, or we might get incomplete data.)
+			 */
+			for (i = 0; i < pcxt->nworkers_launched; i++)
+				InstrAccumParallelQuery(&cstate->pcdata->bufferusage[i],
+										&cstate->pcdata->walusage[i]);
+
+			*processed = pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
+			EndParallelCopy(pcxt);
+		}
+		else
+			*processed = CopyFrom(cstate);	/* copy from file to database */
+
 		EndCopyFrom(cstate);
 	}
 	else
@@ -1177,6 +1046,7 @@ ProcessCopyOptions(ParseState *pstate,
 	cstate->is_copy_from = is_from;
 
 	cstate->file_encoding = -1;
+	cstate->nworkers = -1;
 
 	/* Extract options from the statement node tree */
 	foreach(option, options)
@@ -1347,6 +1217,39 @@ ProcessCopyOptions(ParseState *pstate,
 								defel->defname),
 						 parser_errposition(pstate, defel->location)));
 		}
+		else if (strcmp(defel->defname, "parallel") == 0)
+		{
+			int			val;
+			bool		parsed;
+			char	   *strval;
+
+			if (!cstate->is_copy_from)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("parallel option is supported only for copy from"),
+						 parser_errposition(pstate, defel->location)));
+			if (cstate->nworkers >= 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options"),
+						 parser_errposition(pstate, defel->location)));
+
+			strval = defGetString(defel);
+			parsed = parse_int(strval, &val, 0, NULL);
+			if (!parsed)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("invalid value for integer option \"%s\": %s",
+								defel->defname, strval)));
+			if (val < 1 || val > 1024)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("value %s out of bounds for option \"%s\"",
+								strval, defel->defname),
+						 errdetail("Valid values are between \"%d\" and \"%d\".",
+								   1, 1024)));
+			cstate->nworkers = val;
+		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_SYNTAX_ERROR),
@@ -1702,9 +1605,9 @@ BeginCopy(ParseState *pstate,
  * PopulateCommonCstateInfo
  *
  * Populates the common variables required for copy from operation. This is a
- * helper function for BeginCopy function.
+ * helper function for BeginCopy & InitializeParallelCopyInfo function.
  */
-static void
+void
 PopulateCommonCstateInfo(CopyState cstate, TupleDesc tupDesc, List *attnamelist)
 {
 	int			num_phys_attrs;
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index c639833..cd2d56e 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -14,14 +14,394 @@
 #ifndef COPY_H
 #define COPY_H
 
+#include "access/parallel.h"
+#include "commands/trigger.h"
+#include "executor/executor.h"
 #include "nodes/execnodes.h"
 #include "nodes/parsenodes.h"
 #include "parser/parse_node.h"
 #include "tcop/dest.h"
 
+#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+
+/*
+ * The macros DATA_BLOCK_SIZE, RINGSIZE & MAX_BLOCKS_COUNT stores the records
+ * read from the file that need to be inserted into the relation. These values
+ * help in the handover of multiple records with the significant size of data to
+ * be processed by each of the workers. This also ensures there is no context
+ * switch and the work is fairly distributed among the workers. This number
+ * showed best results in the performance tests.
+ */
+#define DATA_BLOCK_SIZE RAW_BUF_SIZE
+
+/* It can hold 1023 blocks of 64K data in DSM to be processed by the worker. */
+#define MAX_BLOCKS_COUNT 1024
+
+/*
+ * It can hold upto 10240 record information for worker to process. RINGSIZE
+ * should be a multiple of WORKER_CHUNK_COUNT, as wrap around cases is currently
+ * not handled while selecting the WORKER_CHUNK_COUNT by the worker.
+ */
+#define RINGSIZE (10 * 1024)
+
+/*
+ * Each worker will be allocated WORKER_CHUNK_COUNT of records from DSM data
+ * block to process to avoid lock contention. Read RINGSIZE comments before
+ * changing this value.
+ */
+#define WORKER_CHUNK_COUNT 64
+
+/*
+ * Represents the different source/dest cases we need to worry about at
+ * the bottom level
+ */
+typedef enum CopyDest
+{
+	COPY_FILE,					/* to/from file (or a piped program) */
+	COPY_OLD_FE,				/* to/from frontend (2.0 protocol) */
+	COPY_NEW_FE,				/* to/from frontend (3.0 protocol) */
+	COPY_CALLBACK				/* to/from callback function */
+} CopyDest;
+
+/*
+ *	Represents the end-of-line terminator type of the input
+ */
+typedef enum EolType
+{
+	EOL_UNKNOWN,
+	EOL_NL,
+	EOL_CR,
+	EOL_CRNL
+} EolType;
+
+/*
+ * Copy data block information.
+ *
+ * These data blocks are created in DSM. Data read from file will be copied in
+ * these DSM data blocks. The leader process identifies the records and the
+ * record information will be shared to the workers. The workers will insert the
+ * records into the table. There can be one or more number of records in each of
+ * the data block based on the record size.
+ */
+typedef struct ParallelCopyDataBlock
+{
+	/* The number of unprocessed lines in the current block. */
+	pg_atomic_uint32 unprocessed_line_parts;
+
+	/*
+	 * If the current line data is continued into another block,
+	 * following_block will have the position where the remaining data need to
+	 * be read.
+	 */
+	uint32		following_block;
+
+	/*
+	 * This flag will be set, when the leader finds out this block can be read
+	 * safely by the worker. This helps the worker to start processing the
+	 * line early where the line will be spread across many blocks and the
+	 * worker need not wait for the complete line to be processed.
+	 */
+	bool		curr_blk_completed;
+
+	/*
+	 * Few bytes need to be skipped from this block, this will be set when a
+	 * sequence of characters like \r\n is expected, but end of our block
+	 * contained only \r. In this case we copy the data from \r into the new
+	 * block as they have to be processed together to identify end of line.
+	 * Worker will use skip_bytes to know that this data must be skipped from
+	 * this data block.
+	 */
+	uint8		skip_bytes;
+	char		data[DATA_BLOCK_SIZE];	/* data read from file */
+} ParallelCopyDataBlock;
+
+/*
+ * Individual line information.
+ *
+ * ParallelCopyLineBoundary is common data structure between leader & worker.
+ * Leader process will be populating data block, data block offset & the size of
+ * the record in DSM for the workers to copy the data into the relation.
+ * The leader & worker process access the shared line information by following
+ * the below steps to avoid any data corruption or hang:
+ * Leader should operate in the following order:
+ * 1) check if line_size is -1, if line_size is not -1 wait until line_size is
+ * set to -1 by the worker. If line_size is -1 it means worker is still
+ * processing.
+ * 2) set line_state to LINE_LEADER_POPULATING, so that the worker knows that
+ * leader is populating this line.
+ * 3) update first_block, start_offset & cur_lineno in any order.
+ * 4) update line_size.
+ * 5) update line_state to LINE_LEADER_POPULATED.
+ * Worker should operate in the following order:
+ * 1) check line_state is LINE_LEADER_POPULATED, if not it means leader is still
+ * populating the data.
+ * 2) read line_size to know the size of the data.
+ * 3) only one worker should choose one line for processing, this is handled by
+ *    using pg_atomic_compare_exchange_u32, worker will change the state to
+ *    LINE_WORKER_PROCESSING only if line_state is LINE_LEADER_POPULATED.
+ * 4) read first_block, start_offset & cur_lineno in any order.
+ * 5) process line_size data.
+ * 6) update line_size to -1.
+ */
+typedef struct ParallelCopyLineBoundary
+{
+	/* Position of the first block in data_blocks array. */
+	uint32		first_block;
+	uint32		start_offset;	/* start offset of the line */
+
+	/*
+	 * Size of the current line -1 means line is yet to be filled completely,
+	 * 0 means empty line, >0 means line filled with line size data.
+	 */
+	pg_atomic_uint32 line_size;
+	pg_atomic_uint32 line_state;	/* line state */
+	uint64		cur_lineno;		/* line number for error messages */
+} ParallelCopyLineBoundary;
+
+/*
+ * Circular queue used to store the line information.
+ */
+typedef struct ParallelCopyLineBoundaries
+{
+	/* Position for the leader to populate a line. */
+	uint32		pos;
+
+	/* Data read from the file/stdin by the leader process. */
+	ParallelCopyLineBoundary ring[RINGSIZE];
+} ParallelCopyLineBoundaries;
+
+/*
+ * Shared information among parallel copy workers. This will be allocated in the
+ * DSM segment.
+ */
+typedef struct ParallelCopyShmInfo
+{
+	bool		is_read_in_progress;	/* file read status */
+
+	/*
+	 * Actual lines inserted by worker, will not be same as
+	 * total_worker_processed if where condition is specified along with copy.
+	 * This will be the actual records inserted into the relation.
+	 */
+	pg_atomic_uint64 processed;
+
+	/*
+	 * The number of records currently processed by the worker, this will also
+	 * include the number of records that was filtered because of where
+	 * clause.
+	 */
+	pg_atomic_uint64 total_worker_processed;
+	uint64		populated;		/* lines populated by leader */
+	uint32		cur_block_pos;	/* current data block */
+	ParallelCopyDataBlock data_blocks[MAX_BLOCKS_COUNT];	/* data block array */
+	FullTransactionId full_transaction_id;	/* xid for copy from statement */
+	CommandId	mycid;			/* command id */
+	ParallelCopyLineBoundaries line_boundaries; /* line array */
+} ParallelCopyShmInfo;
+
+/*
+ * Parallel copy line buffer information.
+ */
+typedef struct ParallelCopyLineBuf
+{
+	StringInfoData line_buf;
+	uint64		cur_lineno;		/* line number for error messages */
+} ParallelCopyLineBuf;
+
+/*
+ * This structure helps in storing the common data from CopyStateData that are
+ * required by the workers. This information will then be allocated and stored
+ * into the DSM for the worker to retrieve and copy it to CopyStateData.
+ */
+typedef struct SerializedParallelCopyState
+{
+	/* low-level state data */
+	CopyDest	copy_dest;		/* type of copy source/destination */
+	int			file_encoding;	/* file or remote side's character encoding */
+	bool		need_transcoding;	/* file encoding diff from server? */
+	bool		encoding_embeds_ascii;	/* ASCII can be non-first byte? */
+
+	/* parameters from the COPY command */
+	bool		csv_mode;		/* Comma Separated Value format? */
+	bool		header_line;	/* CSV header line? */
+	int			null_print_len; /* length of same */
+	bool		force_quote_all;	/* FORCE_QUOTE *? */
+	bool		convert_selectively;	/* do selective binary conversion? */
+
+	/* Working state for COPY FROM */
+	AttrNumber	num_defaults;
+	Oid			relid;
+} SerializedParallelCopyState;
+
+/*
+ * Parallel copy data information.
+ */
+typedef struct ParallelCopyData
+{
+	Oid			relid;			/* relation id of the table */
+	ParallelCopyShmInfo *pcshared_info; /* common info in shared memory */
+	bool		is_leader;
+
+	WalUsage   *walusage;
+	BufferUsage *bufferusage;
+
+	/* line position which worker is processing */
+	uint32		worker_processed_pos;
+
+	/*
+	 * Local line_buf array, workers will copy it here and release the lines
+	 * for the leader to continue.
+	 */
+	ParallelCopyLineBuf worker_line_buf[WORKER_CHUNK_COUNT];
+	uint32		worker_line_buf_count;	/* Number of lines */
+
+	/* Current position in worker_line_buf */
+	uint32		worker_line_buf_pos;
+} ParallelCopyData;
+
+typedef int (*copy_data_source_cb) (void *outbuf, int minread, int maxread);
+
+/*
+ * This struct contains all the state variables used throughout a COPY
+ * operation. For simplicity, we use the same struct for all variants of COPY,
+ * even though some fields are used in only some cases.
+ *
+ * Multi-byte encodings: all supported client-side encodings encode multi-byte
+ * characters by having the first byte's high bit set. Subsequent bytes of the
+ * character can have the high bit not set. When scanning data in such an
+ * encoding to look for a match to a single-byte (ie ASCII) character, we must
+ * use the full pg_encoding_mblen() machinery to skip over multibyte
+ * characters, else we might find a false match to a trailing byte. In
+ * supported server encodings, there is no possibility of a false match, and
+ * it's faster to make useless comparisons to trailing bytes than it is to
+ * invoke pg_encoding_mblen() to skip over them. encoding_embeds_ascii is true
+ * when we have to do it the hard way.
+ */
+typedef struct CopyStateData
+{
+	/* low-level state data */
+	CopyDest	copy_dest;		/* type of copy source/destination */
+	FILE	   *copy_file;		/* used if copy_dest == COPY_FILE */
+	StringInfo	fe_msgbuf;		/* used for all dests during COPY TO, only for
+								 * dest == COPY_NEW_FE in COPY FROM */
+	bool		is_copy_from;	/* COPY TO, or COPY FROM? */
+	bool		reached_eof;	/* true if we read to end of copy data (not
+								 * all copy_dest types maintain this) */
+	EolType		eol_type;		/* EOL type of input */
+	int			file_encoding;	/* file or remote side's character encoding */
+	bool		need_transcoding;	/* file encoding diff from server? */
+	bool		encoding_embeds_ascii;	/* ASCII can be non-first byte? */
+
+	/* parameters from the COPY command */
+	Relation	rel;			/* relation to copy to or from */
+	QueryDesc  *queryDesc;		/* executable query to copy from */
+	List	   *attnumlist;		/* integer list of attnums to copy */
+	char	   *filename;		/* filename, or NULL for STDIN/STDOUT */
+	bool		is_program;		/* is 'filename' a program to popen? */
+	copy_data_source_cb data_source_cb; /* function for reading data */
+	bool		binary;			/* binary format? */
+	bool		freeze;			/* freeze rows on loading? */
+	bool		csv_mode;		/* Comma Separated Value format? */
+	bool		header_line;	/* CSV header line? */
+	char	   *null_print;		/* NULL marker string (server encoding!) */
+	int			null_print_len; /* length of same */
+	char	   *null_print_client;	/* same converted to file encoding */
+	char	   *delim;			/* column delimiter (must be 1 byte) */
+	char	   *quote;			/* CSV quote char (must be 1 byte) */
+	char	   *escape;			/* CSV escape char (must be 1 byte) */
+	List	   *force_quote;	/* list of column names */
+	bool		force_quote_all;	/* FORCE_QUOTE *? */
+	bool	   *force_quote_flags;	/* per-column CSV FQ flags */
+	List	   *force_notnull;	/* list of column names */
+	bool	   *force_notnull_flags;	/* per-column CSV FNN flags */
+	List	   *force_null;		/* list of column names */
+	bool	   *force_null_flags;	/* per-column CSV FN flags */
+	bool		convert_selectively;	/* do selective binary conversion? */
+	List	   *convert_select; /* list of column names (can be NIL) */
+	bool	   *convert_select_flags;	/* per-column CSV/TEXT CS flags */
+	Node	   *whereClause;	/* WHERE condition (or NULL) */
+
+	/* these are just for error messages, see CopyFromErrorCallback */
+	const char *cur_relname;	/* table name for error messages */
+	uint64		cur_lineno;		/* line number for error messages */
+	const char *cur_attname;	/* current att for error messages */
+	const char *cur_attval;		/* current att value for error messages */
+
+	/*
+	 * Working state for COPY TO/FROM
+	 */
+	MemoryContext copycontext;	/* per-copy execution context */
+
+	/*
+	 * Working state for COPY TO
+	 */
+	FmgrInfo   *out_functions;	/* lookup info for output functions */
+	MemoryContext rowcontext;	/* per-row evaluation context */
+
+	/*
+	 * Working state for COPY FROM
+	 */
+	AttrNumber	num_defaults;
+	FmgrInfo   *in_functions;	/* array of input functions for each attrs */
+	Oid		   *typioparams;	/* array of element types for in_functions */
+	int		   *defmap;			/* array of default att numbers */
+	ExprState **defexprs;		/* array of default att expressions */
+	bool		volatile_defexprs;	/* is any of defexprs volatile? */
+	List	   *range_table;
+	ExprState  *qualexpr;
+
+	TransitionCaptureState *transition_capture;
+
+	/*
+	 * These variables are used to reduce overhead in COPY FROM.
+	 *
+	 * attribute_buf holds the separated, de-escaped text for each field of
+	 * the current line.  The CopyReadAttributes functions return arrays of
+	 * pointers into this buffer.  We avoid palloc/pfree overhead by re-using
+	 * the buffer on each cycle.
+	 *
+	 * In binary COPY FROM, attribute_buf holds the binary data for the
+	 * current field, but the usage is otherwise similar.
+	 */
+	StringInfoData attribute_buf;
+
+	/* field raw data pointers found by COPY FROM */
+
+	int			max_fields;
+	char	  **raw_fields;
+
+	/*
+	 * Similarly, line_buf holds the whole input line being processed. The
+	 * input cycle is first to read the whole line into line_buf, convert it
+	 * to server encoding there, and then extract the individual attribute
+	 * fields into attribute_buf.  line_buf is preserved unmodified so that we
+	 * can display it in error messages if appropriate.  (In binary mode,
+	 * line_buf is not used.)
+	 */
+	StringInfoData line_buf;
+	bool		line_buf_converted; /* converted to server encoding? */
+	bool		line_buf_valid; /* contains the row being processed? */
+
+	/*
+	 * Finally, raw_buf holds raw data read from the data source (file or
+	 * client connection).  In text mode, CopyReadLine parses this data
+	 * sufficiently to locate line boundaries, then transfers the data to
+	 * line_buf and converts it.  In binary mode, CopyReadBinaryData fetches
+	 * appropriate amounts of data from this buffer.  In both modes, we
+	 * guarantee that there is a \0 at raw_buf[raw_buf_len].
+	 */
+	char	   *raw_buf;
+	int			raw_buf_index;	/* next byte to process */
+	int			raw_buf_len;	/* total # of bytes stored */
+	int			nworkers;
+	bool		is_parallel;
+	ParallelCopyData *pcdata;
+	/* Shorthand for number of unconsumed bytes available in raw_buf */
+#define RAW_BUF_BYTES(cstate) ((cstate)->raw_buf_len - (cstate)->raw_buf_index)
+} CopyStateData;
+
 /* CopyStateData is private in commands/copy.c */
 typedef struct CopyStateData *CopyState;
-typedef int (*copy_data_source_cb) (void *outbuf, int minread, int maxread);
 
 extern void DoCopy(ParseState *state, const CopyStmt *stmt,
 				   int stmt_location, int stmt_len,
@@ -41,4 +421,11 @@ extern uint64 CopyFrom(CopyState cstate);
 
 extern DestReceiver *CreateCopyDestReceiver(void);
 
+extern void PopulateCommonCstateInfo(CopyState cstate, TupleDesc tup_desc,
+									 List *attnamelist);
+
+extern void ParallelCopyMain(dsm_segment *seg, shm_toc *toc);
+extern ParallelContext *BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid);
+extern void ParallelCopyFrom(CopyState cstate);
+extern void EndParallelCopy(ParallelContext *pcxt);
 #endif							/* COPY_H */
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index c52f20d..5ce8296 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1702,6 +1702,12 @@ ParallelBitmapHeapState
 ParallelBlockTableScanDesc
 ParallelCompletionPtr
 ParallelContext
+ParallelCopyLineBoundaries
+ParallelCopyLineBoundary
+ParallelCopyData
+ParallelCopyDataBlock
+ParallelCopyLineBuf
+ParallelCopyShmInfo
 ParallelExecutorInfo
 ParallelHashGrowth
 ParallelHashJoinBatch
@@ -2224,6 +2230,7 @@ SerCommitSeqNo
 SerialControl
 SerializableXactHandle
 SerializedActiveRelMaps
+SerializedParallelCopyState
 SerializedReindexState
 SerializedSnapshotData
 SerializedTransactionState
-- 
1.8.3.1

v7-0003-Allow-copy-from-command-to-process-data-from-file.patchtext/x-patch; charset=US-ASCII; name=v7-0003-Allow-copy-from-command-to-process-data-from-file.patchDownload
From c0a0e8e583a67b1a6090c3cd0b521cbff31a2d2f Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 14 Oct 2020 12:48:22 +0530
Subject: [PATCH v7 3/6] Allow copy from command to process data from
 file/STDIN contents to a table in parallel.

This feature allows the copy from to leverage multiple CPUs in order to copy
data from file/STDIN to a table. This adds a PARALLEL option to COPY FROM
command where the user can specify the number of workers that can be used
to perform the COPY FROM command.
The backend, to which the "COPY FROM" query is submitted acts as leader with
the responsibility of reading data from the file/stdin, launching at most n
number of workers as specified with PARALLEL 'n' option in the "COPY FROM"
query. The leader populates the common data required for the workers execution
in the DSM and shares it with the workers. The leader then executes before
statement triggers if there exists any. Leader populates DSM lines which
includes the start offset and line size, while populating the lines it reads
as many blocks as required into the DSM data blocks from the file. Each block
is of 64K size. The leader parses the data to identify a line, the existing
logic from CopyReadLineText which identifies the lines with some changes was
used for this. Leader checks if a free line is available to copy the
information, if there is no free line it waits till the required line is
freed up by the worker and then copies the identified lines information
(offset & line size) into the DSM lines. This process is repeated till the
complete file is processed. Simultaneously, the workers cache the lines(50)
locally into the local memory and release the lines to the leader for further
populating. Each worker processes the lines that it cached and inserts it into
the table.
The leader does not participate in the insertion of data, leaders only
responsibility will be to identify the lines as fast as possible for the
workers to do the actual copy operation. The leader waits till all the lines
populated are processed by the workers and exits. We have chosen this design
based on the reason "that everything stalls if the leader doesn't accept further
input data, as well as when there are no available splitted chunks so it doesn't
seem like a good idea to have the leader do other work.  This is backed by the
performance data where we have seen that with 1 worker there is just a 5-10%
performance difference".
---
 src/backend/access/common/toast_internals.c |   12 +-
 src/backend/access/heap/heapam.c            |   11 -
 src/backend/access/transam/xact.c           |   15 +
 src/backend/commands/Makefile               |    1 +
 src/backend/commands/copy.c                 |  243 +++--
 src/backend/commands/copyparallel.c         | 1301 +++++++++++++++++++++++++++
 src/bin/psql/tab-complete.c                 |    2 +-
 src/include/access/xact.h                   |    1 +
 src/include/commands/copy.h                 |   54 +-
 src/tools/pgindent/typedefs.list            |    1 +
 10 files changed, 1558 insertions(+), 83 deletions(-)
 create mode 100644 src/backend/commands/copyparallel.c

diff --git a/src/backend/access/common/toast_internals.c b/src/backend/access/common/toast_internals.c
index 25a81e5..70c070e 100644
--- a/src/backend/access/common/toast_internals.c
+++ b/src/backend/access/common/toast_internals.c
@@ -17,6 +17,7 @@
 #include "access/genam.h"
 #include "access/heapam.h"
 #include "access/heaptoast.h"
+#include "access/parallel.h"
 #include "access/table.h"
 #include "access/toast_internals.h"
 #include "access/xact.h"
@@ -116,7 +117,16 @@ toast_save_datum(Relation rel, Datum value,
 	TupleDesc	toasttupDesc;
 	Datum		t_values[3];
 	bool		t_isnull[3];
-	CommandId	mycid = GetCurrentCommandId(true);
+
+	/*
+	 * Parallel copy can insert toast tuples, in case of parallel copy the
+	 * command would have been set already by calling
+	 * AssignCommandIdForWorker. For parallel copy call GetCurrentCommandId to
+	 * get currentCommandId by passing used as false, as this is taken care
+	 * earlier.
+	 */
+	CommandId	mycid = IsParallelWorker() ? GetCurrentCommandId(false) :
+	GetCurrentCommandId(true);
 	struct varlena *result;
 	struct varatt_external toast_pointer;
 	union
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 1585861..1602525 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2043,17 +2043,6 @@ static HeapTuple
 heap_prepare_insert(Relation relation, HeapTuple tup, TransactionId xid,
 					CommandId cid, int options)
 {
-	/*
-	 * To allow parallel inserts, we need to ensure that they are safe to be
-	 * performed in workers. We have the infrastructure to allow parallel
-	 * inserts in general except for the cases where inserts generate a new
-	 * CommandId (eg. inserts into a table having a foreign key column).
-	 */
-	if (IsParallelWorker())
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_TRANSACTION_STATE),
-				 errmsg("cannot insert tuples in a parallel worker")));
-
 	tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
 	tup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK);
 	tup->t_data->t_infomask |= HEAP_XMAX_INVALID;
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index af6afce..0b3337c 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -776,6 +776,21 @@ GetCurrentCommandId(bool used)
 }
 
 /*
+ *	SetCurrentCommandIdUsedForWorker
+ *
+ * For a parallel worker, record that the currentCommandId has been used.
+ * This must only be called at the start of a parallel operation.
+ */
+void
+SetCurrentCommandIdUsedForWorker(void)
+{
+	Assert(IsParallelWorker() && !currentCommandIdUsed &&
+		   (currentCommandId != InvalidCommandId));
+
+	currentCommandIdUsed = true;
+}
+
+/*
  *	SetParallelStartTimestamps
  *
  * In a parallel worker, we should inherit the parent transaction's
diff --git a/src/backend/commands/Makefile b/src/backend/commands/Makefile
index d4815d3..a224aac 100644
--- a/src/backend/commands/Makefile
+++ b/src/backend/commands/Makefile
@@ -24,6 +24,7 @@ OBJS = \
 	constraint.o \
 	conversioncmds.o \
 	copy.o \
+	copyparallel.o \
 	createas.o \
 	dbcommands.o \
 	define.o \
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 6c5dc2a..9a026be 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -61,20 +61,6 @@
 #define ISOCTAL(c) (((c) >= '0') && ((c) <= '7'))
 #define OCTVALUE(c) ((c) - '0')
 
-/*
- * Represents the heap insert method to be used during COPY FROM.
- */
-typedef enum CopyInsertMethod
-{
-	CIM_SINGLE,					/* use table_tuple_insert or fdw routine */
-	CIM_MULTI,					/* always use table_multi_insert */
-	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
-} CopyInsertMethod;
-
-#define IsParallelCopy()		(cstate->is_parallel)
-#define IsLeader()				(cstate->pcdata->is_leader)
-#define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
-
 /* DestReceiver for COPY (query) TO */
 typedef struct
 {
@@ -83,7 +69,6 @@ typedef struct
 	uint64		processed;		/* # of tuples processed */
 } DR_copy;
 
-
 /*
  * No more than this many tuples per CopyMultiInsertBuffer
  *
@@ -181,9 +166,13 @@ if (1) \
 { \
 	if (raw_buf_ptr > cstate->raw_buf_index) \
 	{ \
-		appendBinaryStringInfo(&cstate->line_buf, \
-							 cstate->raw_buf + cstate->raw_buf_index, \
-							   raw_buf_ptr - cstate->raw_buf_index); \
+		if (!IsParallelCopy()) \
+			appendBinaryStringInfo(&cstate->line_buf, \
+								   cstate->raw_buf + cstate->raw_buf_index, \
+								   raw_buf_ptr - cstate->raw_buf_index); \
+		else \
+			line_size +=  raw_buf_ptr - cstate->raw_buf_index; \
+		\
 		cstate->raw_buf_index = raw_buf_ptr; \
 	} \
 } else ((void) 0)
@@ -212,7 +201,6 @@ static void EndCopyTo(CopyState cstate);
 static uint64 DoCopyTo(CopyState cstate);
 static uint64 CopyTo(CopyState cstate);
 static void CopyOneRowTo(CopyState cstate, TupleTableSlot *slot);
-static bool CopyReadLine(CopyState cstate);
 static bool CopyReadLineText(CopyState cstate);
 static int	CopyReadAttributesText(CopyState cstate);
 static int	CopyReadAttributesCSV(CopyState cstate);
@@ -245,7 +233,6 @@ static int	CopyReadBinaryData(CopyState cstate, char *dest, int nbytes);
 
 static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
 								   int copy_line_pos, int *copy_line_size);
-static void ConvertToServerEncoding(CopyState cstate);
 
 
 /*
@@ -645,11 +632,11 @@ CopyGetInt16(CopyState cstate, int16 *val)
 static bool
 CopyLoadRawBuf(CopyState cstate)
 {
-	int			nbytes = RAW_BUF_BYTES(cstate);
+	int			nbytes = (!IsParallelCopy()) ? RAW_BUF_BYTES(cstate) : cstate->raw_buf_index;
 	int			inbytes;
 
 	/* Copy down the unprocessed data if any. */
-	if (nbytes > 0)
+	if (nbytes > 0 && !IsParallelCopy())
 		memmove(cstate->raw_buf, cstate->raw_buf + cstate->raw_buf_index,
 				nbytes);
 
@@ -657,7 +644,9 @@ CopyLoadRawBuf(CopyState cstate)
 						  1, RAW_BUF_SIZE - nbytes);
 	nbytes += inbytes;
 	cstate->raw_buf[nbytes] = '\0';
-	cstate->raw_buf_index = 0;
+	if (!IsParallelCopy())
+		cstate->raw_buf_index = 0;
+
 	cstate->raw_buf_len = nbytes;
 	return (inbytes > 0);
 }
@@ -969,7 +958,11 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 		cstate->whereClause = whereClause;
 		cstate->is_parallel = false;
 
-		if (cstate->nworkers > 0)
+		/*
+		 * User chosen parallel copy. Determine if the parallel copy is
+		 * actually allowed. If not, go with the non-parallel mode.
+		 */
+		if (cstate->nworkers > 0 && IsParallelCopyAllowed(cstate))
 			pcxt = BeginParallelCopy(cstate->nworkers, cstate, stmt->attlist,
 									 relid);
 
@@ -994,7 +987,15 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 			EndParallelCopy(pcxt);
 		}
 		else
+		{
+			/*
+			 * Reset nworkers to -1 here. This is useful in cases where user
+			 * specifies parallel workers, but, no worker is picked up, so go
+			 * back to non parallel mode value of nworkers.
+			 */
+			cstate->nworkers = -1;
 			*processed = CopyFrom(cstate);	/* copy from file to database */
+		}
 
 		EndCopyFrom(cstate);
 	}
@@ -2626,7 +2627,7 @@ CopyMultiInsertInfoStore(CopyMultiInsertInfo *miinfo, ResultRelInfo *rri,
  *
  * Check if the relation specified in copy from is valid.
  */
-static void
+void
 CheckTargetRelValidity(CopyState cstate)
 {
 	Assert(cstate->rel);
@@ -2723,7 +2724,7 @@ CopyFrom(CopyState cstate)
 
 	PartitionTupleRouting *proute = NULL;
 	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
+	CommandId	mycid;
 	int			ti_options = 0; /* start with default options for insert */
 	BulkInsertState bistate = NULL;
 	CopyInsertMethod insertMethod;
@@ -2733,7 +2734,18 @@ CopyFrom(CopyState cstate)
 	bool		has_instead_insert_row_trig;
 	bool		leafpart_use_multi_insert = false;
 
-	CheckTargetRelValidity(cstate);
+	/*
+	 * Perform this check if it is not parallel copy. In case of parallel
+	 * copy, this check is done by the leader, so that if any invalid case
+	 * exist the copy from command will error out from the leader itself,
+	 * avoiding launching workers, just to throw error.
+	 */
+	if (!IsParallelCopy())
+		CheckTargetRelValidity(cstate);
+	else
+		SetCurrentCommandIdUsedForWorker();
+
+	mycid = GetCurrentCommandId(!IsParallelCopy());
 
 	/*
 	 * If the target file is new-in-transaction, we assume that checking FSM
@@ -2769,7 +2781,8 @@ CopyFrom(CopyState cstate)
 	ExecInitResultRelation(estate, resultRelInfo, 1);
 
 	/* Verify the named relation is a valid target for INSERT */
-	CheckValidResultRel(resultRelInfo, CMD_INSERT);
+	if (!IsParallelCopy())
+		CheckValidResultRel(resultRelInfo, CMD_INSERT);
 
 	ExecOpenIndices(resultRelInfo, false);
 
@@ -2914,13 +2927,17 @@ CopyFrom(CopyState cstate)
 	has_instead_insert_row_trig = (resultRelInfo->ri_TrigDesc &&
 								   resultRelInfo->ri_TrigDesc->trig_insert_instead_row);
 
-	/*
-	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
-	 * should do this for COPY, since it's not really an "INSERT" statement as
-	 * such. However, executing these triggers maintains consistency with the
-	 * EACH ROW triggers that we already fire on COPY.
-	 */
-	ExecBSInsertTriggers(estate, resultRelInfo);
+	if (!IsParallelCopy())
+	{
+		/*
+		 * Check BEFORE STATEMENT insertion triggers. It's debatable whether
+		 * we should do this for COPY, since it's not really an "INSERT"
+		 * statement as such. However, executing these triggers maintains
+		 * consistency with the EACH ROW triggers that we already fire on
+		 * COPY.
+		 */
+		ExecBSInsertTriggers(estate, resultRelInfo);
+	}
 
 	econtext = GetPerTupleExprContext(estate);
 
@@ -3020,6 +3037,29 @@ CopyFrom(CopyState cstate)
 					!has_instead_insert_row_trig &&
 					resultRelInfo->ri_FdwRoutine == NULL;
 
+				/*
+				 * We may still be able to perform parallel inserts for
+				 * partitioned tables. However, the possibility of this
+				 * depends on which types of triggers exist on the partition.
+				 * We must not do parallel inserts if the partition is a
+				 * foreign table or it has any BEFORE/INSTEAD OF row triggers.
+				 * Since the partition's resultRelInfo are initialized only
+				 * when we actually insert the first tuple into them, we may
+				 * not know this info easily in the leader while deciding for
+				 * the parallelism. We would have gone ahead and allowed
+				 * parallelism. Now it's the time to throw an error and also
+				 * provide a hint to the user to not use parallelism. Throwing
+				 * an error seemed a simple approach than to look for all the
+				 * partitions in the leader while deciding for the
+				 * parallelism. Note that this error is thrown early, exactly
+				 * on the first tuple being inserted into the partition, so
+				 * not much work, that has been done so far, is wasted.
+				 */
+				if (!leafpart_use_multi_insert && IsParallelWorker())
+					ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+									errmsg("cannot perform PARALLEL COPY if partition has BEFORE/INSTEAD OF triggers, or if the partition is foreign partition"),
+									errhint("Try COPY without PARALLEL option")));
+
 				/* Set the multi-insert buffer to use for this partition. */
 				if (leafpart_use_multi_insert)
 				{
@@ -3242,7 +3282,10 @@ CopyFrom(CopyState cstate)
 			 * or FDW; this is the same definition used by nodeModifyTable.c
 			 * for counting tuples inserted by an INSERT command.
 			 */
-			processed++;
+			if (!IsParallelCopy())
+				processed++;
+			else
+				pg_atomic_add_fetch_u64(&cstate->pcdata->pcshared_info->processed, 1);
 		}
 	}
 
@@ -3296,7 +3339,10 @@ CopyFrom(CopyState cstate)
 
 	FreeExecutorState(estate);
 
-	return processed;
+	if (!IsParallelCopy())
+		return processed;
+	else
+		return pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
 }
 
 /*
@@ -3304,7 +3350,7 @@ CopyFrom(CopyState cstate)
  *
  * Populate the cstate catalog information.
  */
-static void
+void
 PopulateCstateCatalogInfo(CopyState cstate)
 {
 	TupleDesc	tupDesc;
@@ -3586,26 +3632,35 @@ NextCopyFromRawFields(CopyState cstate, char ***fields, int *nfields)
 	/* only available for text or csv input */
 	Assert(!cstate->binary);
 
-	/* on input just throw the header line away */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (IsParallelCopy())
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
-			return false;		/* done */
+		done = GetWorkerLine(cstate);
+		if (done && cstate->line_buf.len == 0)
+			return false;
 	}
+	else
+	{
+		/* on input just throw the header line away */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
+		{
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+				return false;	/* done */
+		}
 
-	cstate->cur_lineno++;
+		cstate->cur_lineno++;
 
-	/* Actually read the line into memory here */
-	done = CopyReadLine(cstate);
+		/* Actually read the line into memory here */
+		done = CopyReadLine(cstate);
 
-	/*
-	 * EOF at start of line means we're done.  If we see EOF after some
-	 * characters, we act as though it was newline followed by EOF, ie,
-	 * process the line and then exit loop on next iteration.
-	 */
-	if (done && cstate->line_buf.len == 0)
-		return false;
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			return false;
+	}
 
 	/* Parse the line into de-escaped field values */
 	if (cstate->csv_mode)
@@ -3830,7 +3885,7 @@ EndCopyFrom(CopyState cstate)
  * by newline.  The terminating newline or EOF marker is not included
  * in the final value of line_buf.
  */
-static bool
+bool
 CopyReadLine(CopyState cstate)
 {
 	bool		result;
@@ -3853,9 +3908,31 @@ CopyReadLine(CopyState cstate)
 		 */
 		if (cstate->copy_dest == COPY_NEW_FE)
 		{
+			bool		bIsFirst = true;
+
 			do
 			{
-				cstate->raw_buf_index = cstate->raw_buf_len;
+				if (!IsParallelCopy())
+					cstate->raw_buf_index = cstate->raw_buf_len;
+				else
+				{
+					/*
+					 * Get a new block if it is the first time, From the
+					 * subsequent time, reset the index and re-use the same
+					 * block.
+					 */
+					if (bIsFirst)
+					{
+						ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+						uint32		block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+						cstate->raw_buf = pcshared_info->data_blocks[block_pos].data;
+						bIsFirst = false;
+					}
+
+					cstate->raw_buf_index = cstate->raw_buf_len = 0;
+				}
+
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
@@ -3910,11 +3987,11 @@ ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
  *
  * Convert contents to server encoding.
  */
-static void
+void
 ConvertToServerEncoding(CopyState cstate)
 {
 	/* Done reading the line.  Convert it to server encoding. */
-	if (cstate->need_transcoding)
+	if (cstate->need_transcoding && (!IsParallelCopy() || IsWorker()))
 	{
 		char	   *cvt;
 
@@ -3954,6 +4031,11 @@ CopyReadLineText(CopyState cstate)
 	char		quotec = '\0';
 	char		escapec = '\0';
 
+	/* For parallel copy */
+	int			line_size = 0;
+	uint32		line_pos = 0;
+
+	cstate->eol_type = EOL_UNKNOWN;
 	if (cstate->csv_mode)
 	{
 		quotec = cstate->quote[0];
@@ -4008,6 +4090,10 @@ CopyReadLineText(CopyState cstate)
 		if (raw_buf_ptr >= copy_buf_len || need_data)
 		{
 			REFILL_LINEBUF;
+			if ((copy_buf_len == DATA_BLOCK_SIZE || copy_buf_len == 0) &&
+				IsParallelCopy())
+				SetRawBufForLoad(cstate, line_size, copy_buf_len, raw_buf_ptr,
+								 &copy_raw_buf);
 
 			/*
 			 * Try to read some more data.  This will certainly reset
@@ -4015,14 +4101,14 @@ CopyReadLineText(CopyState cstate)
 			 */
 			if (!CopyLoadRawBuf(cstate))
 				hit_eof = true;
-			raw_buf_ptr = 0;
+			raw_buf_ptr = (IsParallelCopy()) ? cstate->raw_buf_index : 0;
 			copy_buf_len = cstate->raw_buf_len;
 
 			/*
 			 * If we are completely out of data, break out of the loop,
 			 * reporting EOF.
 			 */
-			if (copy_buf_len <= 0)
+			if (RAW_BUF_BYTES(cstate) <= 0)
 			{
 				result = true;
 				break;
@@ -4232,9 +4318,15 @@ CopyReadLineText(CopyState cstate)
 				 * discard the data and the \. sequence.
 				 */
 				if (prev_raw_ptr > cstate->raw_buf_index)
-					appendBinaryStringInfo(&cstate->line_buf,
-										   cstate->raw_buf + cstate->raw_buf_index,
-										   prev_raw_ptr - cstate->raw_buf_index);
+				{
+					if (!IsParallelCopy())
+						appendBinaryStringInfo(&cstate->line_buf,
+											   cstate->raw_buf + cstate->raw_buf_index,
+											   prev_raw_ptr - cstate->raw_buf_index);
+					else
+						line_size += prev_raw_ptr - cstate->raw_buf_index;
+				}
+
 				cstate->raw_buf_index = raw_buf_ptr;
 				result = true;	/* report EOF */
 				break;
@@ -4286,6 +4378,22 @@ not_end_of_copy:
 			IF_NEED_REFILL_AND_EOF_BREAK(mblen - 1);
 			raw_buf_ptr += mblen - 1;
 		}
+
+		/*
+		 * Skip the header line. Update the line here, this cannot be done at
+		 * the beginning, as there is a possibility that file contains empty
+		 * lines.
+		 */
+		if (IsParallelCopy() && first_char_in_line && !IsHeaderLine())
+		{
+			ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+			line_pos = UpdateSharedLineInfo(cstate,
+											pcshared_info->cur_block_pos,
+											cstate->raw_buf_index, -1,
+											LINE_LEADER_POPULATING, -1);
+		}
+
 		first_char_in_line = false;
 	}							/* end of outer loop */
 
@@ -4294,9 +4402,16 @@ not_end_of_copy:
 	 */
 	REFILL_LINEBUF;
 	if (!result && !IsHeaderLine())
-		ClearEOLFromCopiedData(cstate, cstate->line_buf.data,
-							   cstate->line_buf.len, &cstate->line_buf.len);
+	{
+		if (IsParallelCopy())
+			ClearEOLFromCopiedData(cstate, cstate->raw_buf, raw_buf_ptr,
+								   &line_size);
+		else
+			ClearEOLFromCopiedData(cstate, cstate->line_buf.data,
+								   cstate->line_buf.len, &cstate->line_buf.len);
+	}
 
+	EndLineParallelCopy(cstate, line_pos, line_size, raw_buf_ptr);
 	return result;
 }
 
diff --git a/src/backend/commands/copyparallel.c b/src/backend/commands/copyparallel.c
new file mode 100644
index 0000000..9cae112
--- /dev/null
+++ b/src/backend/commands/copyparallel.c
@@ -0,0 +1,1301 @@
+/*-------------------------------------------------------------------------
+ *
+ * copyparallel.c
+ *              Implements the Parallel COPY utility command
+ *
+ * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *        src/backend/commands/copyparallel.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/heapam.h"
+#include "catalog/pg_proc_d.h"
+#include "commands/copy.h"
+#include "optimizer/clauses.h"
+#include "optimizer/optimizer.h"
+#include "pgstat.h"
+#include "utils/lsyscache.h"
+
+/* DSM keys for parallel copy.  */
+#define PARALLEL_COPY_KEY_SHARED_INFO				1
+#define PARALLEL_COPY_KEY_CSTATE					2
+#define PARALLEL_COPY_WAL_USAGE						3
+#define PARALLEL_COPY_BUFFER_USAGE					4
+
+/* Begin parallel copy Macros */
+#define SET_NEWLINE_SIZE() \
+{ \
+	if (cstate->eol_type == EOL_NL || cstate->eol_type == EOL_CR) \
+		new_line_size = 1; \
+	else if (cstate->eol_type == EOL_CRNL) \
+		new_line_size = 2; \
+	else \
+		new_line_size = 0; \
+}
+
+/*
+ * COPY_WAIT_TO_PROCESS - Wait before continuing to process.
+ */
+#define COPY_WAIT_TO_PROCESS() \
+{ \
+	CHECK_FOR_INTERRUPTS(); \
+	(void) WaitLatch(MyLatch, \
+					 WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH, \
+					 1L, WAIT_EVENT_PG_SLEEP); \
+	ResetLatch(MyLatch); \
+}
+
+/*
+ * CopyStringToSharedMemory
+ *
+ * Copy the string to shared memory.
+ */
+static uint32
+CopyStringToSharedMemory(CopyState cstate, char *srcPtr, char *destptr)
+{
+	uint32		len = srcPtr ? strlen(srcPtr) + 1 : 0;
+	uint32		copiedsize;
+
+	memcpy(destptr, (uint32 *) &len, sizeof(uint32));
+	copiedsize = sizeof(uint32);
+	if (len)
+	{
+		memcpy(destptr + sizeof(uint32), srcPtr, len);
+		copiedsize += len;
+	}
+
+	return copiedsize;
+}
+
+/*
+ * SerializeParallelCopyState
+ *
+ * Serialize the cstate members required by the workers into shared memory.
+ */
+static void
+SerializeParallelCopyState(ParallelContext *pcxt, CopyState cstate,
+						   uint32 estimatedSize, char *whereClauseStr,
+						   char *rangeTableStr, char *attnameListStr,
+						   char *notnullListStr, char *nullListStr,
+						   char *convertListStr)
+{
+	SerializedParallelCopyState shared_cstate;
+	char	   *shmptr = (char *) shm_toc_allocate(pcxt->toc, estimatedSize + 1);
+	uint32		copiedsize = 0;
+
+	shared_cstate.copy_dest = cstate->copy_dest;
+	shared_cstate.file_encoding = cstate->file_encoding;
+	shared_cstate.need_transcoding = cstate->need_transcoding;
+	shared_cstate.encoding_embeds_ascii = cstate->encoding_embeds_ascii;
+	shared_cstate.csv_mode = cstate->csv_mode;
+	shared_cstate.header_line = cstate->header_line;
+	shared_cstate.null_print_len = cstate->null_print_len;
+	shared_cstate.force_quote_all = cstate->force_quote_all;
+	shared_cstate.convert_selectively = cstate->convert_selectively;
+	shared_cstate.num_defaults = cstate->num_defaults;
+	shared_cstate.relid = cstate->pcdata->relid;
+
+	memcpy(shmptr, (char *) &shared_cstate, sizeof(SerializedParallelCopyState));
+	copiedsize = sizeof(SerializedParallelCopyState);
+
+	copiedsize += CopyStringToSharedMemory(cstate, cstate->null_print,
+										   shmptr + copiedsize);
+	copiedsize += CopyStringToSharedMemory(cstate, cstate->delim,
+										   shmptr + copiedsize);
+	copiedsize += CopyStringToSharedMemory(cstate, cstate->quote,
+										   shmptr + copiedsize);
+	copiedsize += CopyStringToSharedMemory(cstate, cstate->escape,
+										   shmptr + copiedsize);
+	copiedsize += CopyStringToSharedMemory(cstate, attnameListStr,
+										   shmptr + copiedsize);
+	copiedsize += CopyStringToSharedMemory(cstate, notnullListStr,
+										   shmptr + copiedsize);
+	copiedsize += CopyStringToSharedMemory(cstate, nullListStr,
+										   shmptr + copiedsize);
+	copiedsize += CopyStringToSharedMemory(cstate, convertListStr,
+										   shmptr + copiedsize);
+	copiedsize += CopyStringToSharedMemory(cstate, whereClauseStr,
+										   shmptr + copiedsize);
+	copiedsize += CopyStringToSharedMemory(cstate, rangeTableStr,
+										   shmptr + copiedsize);
+
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_CSTATE, shmptr);
+}
+
+/*
+ * CopyStringFromSharedMemory
+ *
+ * Copy the string contents from shared memory & return the ptr.
+ */
+static char *
+CopyStringFromSharedMemory(char *srcPtr, uint32 *copiedsize)
+{
+	char	   *destptr = NULL;
+	uint32		len;
+
+	memcpy((uint32 *) (&len), srcPtr, sizeof(uint32));
+	*copiedsize += sizeof(uint32);
+	if (len)
+	{
+		destptr = (char *) palloc(len);
+		memcpy(destptr, srcPtr + sizeof(uint32), len);
+		*copiedsize += len;
+	}
+
+	return destptr;
+}
+
+/*
+ * CopyNodeFromSharedMemory
+ *
+ * Copy the node contents which was stored as string format in shared memory &
+ * convert it into node type.
+ */
+static void *
+CopyNodeFromSharedMemory(char *srcPtr, uint32 *copiedsize)
+{
+	char	   *destptr = NULL;
+	List	   *destList = NIL;
+	uint32		len;
+
+	memcpy((uint32 *) (&len), srcPtr, sizeof(uint32));
+	*copiedsize += sizeof(uint32);
+	if (len)
+	{
+		destptr = (char *) palloc(len);
+		memcpy(destptr, srcPtr + sizeof(uint32), len);
+		*copiedsize += len;
+		destList = (List *) stringToNode(destptr);
+		pfree(destptr);
+	}
+
+	return destList;
+}
+
+/*
+ * RestoreParallelCopyState
+ *
+ * Retrieve the cstate members which was populated by the leader in the shared
+ * memory.
+ */
+static void
+RestoreParallelCopyState(shm_toc *toc, CopyState cstate, List **attlist)
+{
+	char	   *shared_str_val = (char *) shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE, true);
+	SerializedParallelCopyState shared_cstate = {0};
+	uint32		copiedsize = 0;
+
+	memcpy(&shared_cstate, (char *) shared_str_val, sizeof(SerializedParallelCopyState));
+	copiedsize = sizeof(SerializedParallelCopyState);
+
+	cstate->file_encoding = shared_cstate.file_encoding;
+	cstate->need_transcoding = shared_cstate.need_transcoding;
+	cstate->encoding_embeds_ascii = shared_cstate.encoding_embeds_ascii;
+	cstate->csv_mode = shared_cstate.csv_mode;
+	cstate->header_line = shared_cstate.header_line;
+	cstate->null_print_len = shared_cstate.null_print_len;
+	cstate->force_quote_all = shared_cstate.force_quote_all;
+	cstate->convert_selectively = shared_cstate.convert_selectively;
+	cstate->num_defaults = shared_cstate.num_defaults;
+	cstate->pcdata->relid = shared_cstate.relid;
+
+	cstate->null_print = CopyStringFromSharedMemory(shared_str_val + copiedsize,
+													&copiedsize);
+	cstate->delim = CopyStringFromSharedMemory(shared_str_val + copiedsize,
+											   &copiedsize);
+	cstate->quote = CopyStringFromSharedMemory(shared_str_val + copiedsize,
+											   &copiedsize);
+	cstate->escape = CopyStringFromSharedMemory(shared_str_val + copiedsize,
+												&copiedsize);
+
+	*attlist = (List *) CopyNodeFromSharedMemory(shared_str_val + copiedsize,
+												 &copiedsize);
+	cstate->force_notnull = (List *) CopyNodeFromSharedMemory(shared_str_val + copiedsize,
+															  &copiedsize);
+	cstate->force_null = (List *) CopyNodeFromSharedMemory(shared_str_val + copiedsize,
+														   &copiedsize);
+	cstate->convert_select = (List *) CopyNodeFromSharedMemory(shared_str_val + copiedsize,
+															   &copiedsize);
+	cstate->whereClause = (Node *) CopyNodeFromSharedMemory(shared_str_val + copiedsize,
+															&copiedsize);
+	cstate->range_table = (List *) CopyNodeFromSharedMemory(shared_str_val + copiedsize,
+															&copiedsize);
+}
+
+/*
+ * EstimateStringSize
+ *
+ * Estimate the size required for the string in shared memory.
+ */
+static uint32
+EstimateStringSize(char *str)
+{
+	uint32		strsize = sizeof(uint32);
+
+	if (str)
+		strsize += strlen(str) + 1;
+
+	return strsize;
+}
+
+/*
+ * EstimateNodeSize
+ *
+ * Convert the input list/node to string & estimate the size required in shared
+ * memory.
+ */
+static uint32
+EstimateNodeSize(void *list, char **listStr)
+{
+	uint32		strsize = sizeof(uint32);
+
+	if (list != NIL)
+	{
+		*listStr = nodeToString(list);
+		strsize += strlen(*listStr) + 1;
+	}
+
+	return strsize;
+}
+
+/*
+ * EstimateCstateSize
+ *
+ * Estimate the size of the required cstate variables in the shared memory.
+ */
+static uint32
+EstimateCstateSize(ParallelContext *pcxt, CopyState cstate, List *attnamelist,
+				   char **whereClauseStr, char **rangeTableStr,
+				   char **attnameListStr, char **notnullListStr,
+				   char **nullListStr, char **convertListStr)
+{
+	uint32		strsize = MAXALIGN(sizeof(SerializedParallelCopyState));
+
+	strsize += EstimateStringSize(cstate->null_print);
+	strsize += EstimateStringSize(cstate->delim);
+	strsize += EstimateStringSize(cstate->quote);
+	strsize += EstimateStringSize(cstate->escape);
+	strsize += EstimateNodeSize(attnamelist, attnameListStr);
+	strsize += EstimateNodeSize(cstate->force_notnull, notnullListStr);
+	strsize += EstimateNodeSize(cstate->force_null, nullListStr);
+	strsize += EstimateNodeSize(cstate->convert_select, convertListStr);
+	strsize += EstimateNodeSize(cstate->whereClause, whereClauseStr);
+	strsize += EstimateNodeSize(cstate->range_table, rangeTableStr);
+
+	strsize++;
+	shm_toc_estimate_chunk(&pcxt->estimator, strsize);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+	return strsize;
+}
+
+/*
+ * PopulateParallelCopyShmInfo
+ *
+ * Sets ParallelCopyShmInfo structure members.
+ */
+static void
+PopulateParallelCopyShmInfo(ParallelCopyShmInfo *shared_info_ptr)
+{
+	uint32		count;
+
+	MemSet(shared_info_ptr, 0, sizeof(ParallelCopyShmInfo));
+	shared_info_ptr->is_read_in_progress = true;
+	shared_info_ptr->cur_block_pos = -1;
+	for (count = 0; count < RINGSIZE; count++)
+	{
+		ParallelCopyLineBoundary *lineInfo = &shared_info_ptr->line_boundaries.ring[count];
+
+		pg_atomic_init_u32(&(lineInfo->line_size), -1);
+	}
+}
+
+/*
+ * CheckRelTrigFunParallelSafety
+ *
+ * Check if the relation's associated trigger functions are parallel safe. If
+ * any of the trigger function is parallel unsafe or if trigger is on foreign
+ * key relation, we do not allow parallel copy.
+ */
+static pg_attribute_always_inline bool
+CheckRelTrigFunParallelSafety(TriggerDesc *trigdesc)
+{
+	int			i;
+
+	for (i = 0; i < trigdesc->numtriggers; i++)
+	{
+		Trigger    *trigger = &trigdesc->triggers[i];
+		int			trigtype = RI_TRIGGER_NONE;
+
+		if (func_parallel(trigger->tgfoid) != PROPARALLEL_SAFE)
+			return false;
+
+		/* If the trigger is parallel safe, also look for RI_TRIGGER. */
+		trigtype = RI_FKey_trigger_type(trigger->tgfoid);
+
+		/*
+		 * No parallelism if foreign key check trigger is present. This is
+		 * because, while performing foreign key checks, we take KEY SHARE
+		 * lock on primary key table rows which inturn will increment the
+		 * command counter and updates the snapshot.  Since we share the
+		 * snapshots at the beginning of the command, we can't allow it to be
+		 * changed later. So, unless we do something special for it, we can't
+		 * allow parallelism in such cases.
+		 */
+		if (trigtype == RI_TRIGGER_FK)
+			return false;
+	}
+
+	return true;
+}
+
+/*
+ * CheckExprParallelSafety
+ *
+ * Determine parallel safety of volatile expressions in default clause of column
+ * definition or in where clause and return true if they are parallel safe.
+ */
+static pg_attribute_always_inline bool
+CheckExprParallelSafety(CopyState cstate)
+{
+	if (contain_volatile_functions(cstate->whereClause))
+	{
+		if (max_parallel_hazard((Query *) cstate->whereClause) != PROPARALLEL_SAFE)
+			return false;
+	}
+
+	/*
+	 * Check if any of the column has volatile default expression. if yes, and
+	 * they are not parallel safe, then parallelism is not allowed. For
+	 * instance, if there are any serial/bigserial columns for which nextval()
+	 * default expression which is parallel unsafe is associated, parallelism
+	 * should not be allowed.
+	 */
+	if (cstate->defexprs != NULL && cstate->num_defaults != 0)
+	{
+		int			i;
+
+		for (i = 0; i < cstate->num_defaults; i++)
+		{
+			bool		volatile_expr = contain_volatile_functions((Node *) cstate->defexprs[i]->expr);
+
+			if (volatile_expr &&
+				(max_parallel_hazard((Query *) cstate->defexprs[i]->expr)) !=
+				PROPARALLEL_SAFE)
+				return false;
+		}
+	}
+
+	return true;
+}
+
+/*
+ * IsParallelCopyAllowed
+ *
+ * Check if parallel copy can be allowed.
+ */
+bool
+IsParallelCopyAllowed(CopyState cstate)
+{
+	/* Parallel copy not allowed for frontend (2.0 protocol) & binary option. */
+	if ((cstate->copy_dest == COPY_OLD_FE) || cstate->binary)
+		return false;
+
+	/*
+	 * Check if copy is into foreign table. We can not allow parallelism in
+	 * this case because each worker needs to establish FDW connection and
+	 * operate in a separate transaction. Unless we have a capability to
+	 * provide two-phase commit protocol, we can not allow parallelism.
+	 *
+	 * Also check if copy is into temporary table. Since parallel workers can
+	 * not access temporary table, parallelism is not allowed.
+	 */
+	if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
+		RelationUsesLocalBuffers(cstate->rel))
+		return false;
+
+	/*
+	 * If there are volatile default expressions or where clause contain
+	 * volatile expressions, allow parallelism if they are parallel safe,
+	 * otherwise not.
+	 */
+	if (!CheckExprParallelSafety(cstate))
+		return false;
+
+	/* Check parallel safety of the trigger functions. */
+	if (cstate->rel->trigdesc != NULL &&
+		!CheckRelTrigFunParallelSafety(cstate->rel->trigdesc))
+		return false;
+
+	/*
+	 * When transition tables are involved (if after statement triggers are
+	 * present), we collect minimal tuples in the tuple store after processing
+	 * them so that later after statement triggers can access them.  Now, if
+	 * we want to enable parallelism for such cases, we instead need to store
+	 * and access tuples from shared tuple store.  However, it does not have
+	 * the facility to store tuples in-memory, so we always need to store and
+	 * access from a file which could be costly unless we also have an
+	 * additional way to store minimal tuples in shared memory till work_mem
+	 * and then in shared tuple store. It is possible to do all this to enable
+	 * parallel copy for such cases. Currently, we can disallow parallelism
+	 * for such cases and later allow if required.
+	 *
+	 * When there are BEFORE/AFTER/INSTEAD OF row triggers on the table. We do
+	 * not allow parallelism in such cases because such triggers might query
+	 * the table we are inserting into and act differently if the tuples that
+	 * have already been processed and prepared for insertion are not there.
+	 * Now, if we allow parallelism with such triggers the behaviour would
+	 * depend on if the parallel worker has already inserted or not that
+	 * particular tuples.
+	 */
+	if (cstate->rel->trigdesc != NULL &&
+		(cstate->rel->trigdesc->trig_insert_after_statement ||
+		 cstate->rel->trigdesc->trig_insert_new_table ||
+		 cstate->rel->trigdesc->trig_insert_before_row ||
+		 cstate->rel->trigdesc->trig_insert_after_row ||
+		 cstate->rel->trigdesc->trig_insert_instead_row))
+		return false;
+
+	return true;
+}
+
+/*
+ * BeginParallelCopy - Start parallel copy tasks.
+ *
+ * Get the number of workers required to perform the parallel copy. The data
+ * structures that are required by the parallel workers will be initialized, the
+ * size required in DSM will be calculated and the necessary keys will be loaded
+ * in the DSM. The specified number of workers will then be launched.
+ */
+ParallelContext *
+BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
+{
+	ParallelContext *pcxt;
+	ParallelCopyShmInfo *shared_info_ptr;
+	char	   *whereClauseStr = NULL;
+	char	   *rangeTableStr = NULL;
+	char	   *attnameListStr = NULL;
+	char	   *notnullListStr = NULL;
+	char	   *nullListStr = NULL;
+	char	   *convertListStr = NULL;
+	int			parallel_workers = 0;
+	WalUsage   *walusage;
+	BufferUsage *bufferusage;
+	ParallelCopyData *pcdata;
+	MemoryContext oldcontext;
+	uint32		strsize;
+
+	CheckTargetRelValidity(cstate);
+	parallel_workers = Min(nworkers, max_worker_processes);
+
+	/* Can't perform copy in parallel */
+	if (parallel_workers <= 0)
+		return NULL;
+
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	MemoryContextSwitchTo(oldcontext);
+	cstate->pcdata = pcdata;
+
+	(void) GetCurrentFullTransactionId();
+	(void) GetCurrentCommandId(true);
+
+	EnterParallelMode();
+	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
+								 parallel_workers);
+	Assert(pcxt->nworkers > 0);
+
+	/*
+	 * Estimate size for shared information for PARALLEL_COPY_KEY_SHARED_INFO
+	 */
+	shm_toc_estimate_chunk(&pcxt->estimator, sizeof(ParallelCopyShmInfo));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_CSTATE */
+	strsize = EstimateCstateSize(pcxt, cstate, attnamelist, &whereClauseStr,
+								 &rangeTableStr, &attnameListStr,
+								 &notnullListStr, &nullListStr,
+								 &convertListStr);
+
+	/*
+	 * Estimate space for WalUsage and BufferUsage -- PARALLEL_COPY_WAL_USAGE
+	 * and PARALLEL_COPY_BUFFER_USAGE.
+	 */
+	shm_toc_estimate_chunk(&pcxt->estimator,
+						   mul_size(sizeof(WalUsage), pcxt->nworkers));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+	shm_toc_estimate_chunk(&pcxt->estimator,
+						   mul_size(sizeof(BufferUsage), pcxt->nworkers));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	InitializeParallelDSM(pcxt);
+
+	/* If no DSM segment was available, back out (do serial copy) */
+	if (pcxt->seg == NULL)
+	{
+		EndParallelCopy(pcxt);
+		return NULL;
+	}
+
+	/* Allocate shared memory for PARALLEL_COPY_KEY_SHARED_INFO */
+	shared_info_ptr = (ParallelCopyShmInfo *) shm_toc_allocate(pcxt->toc, sizeof(ParallelCopyShmInfo));
+	PopulateParallelCopyShmInfo(shared_info_ptr);
+
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_SHARED_INFO, shared_info_ptr);
+	pcdata->pcshared_info = shared_info_ptr;
+	pcdata->relid = relid;
+
+	SerializeParallelCopyState(pcxt, cstate, strsize, whereClauseStr,
+							   rangeTableStr, attnameListStr, notnullListStr,
+							   nullListStr, convertListStr);
+
+	/*
+	 * Allocate space for each worker's WalUsage and BufferUsage; no need to
+	 * initialize.
+	 */
+	walusage = shm_toc_allocate(pcxt->toc,
+								mul_size(sizeof(WalUsage), pcxt->nworkers));
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_WAL_USAGE, walusage);
+	pcdata->walusage = walusage;
+	bufferusage = shm_toc_allocate(pcxt->toc,
+								   mul_size(sizeof(BufferUsage), pcxt->nworkers));
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_BUFFER_USAGE, bufferusage);
+	pcdata->bufferusage = bufferusage;
+
+	LaunchParallelWorkers(pcxt);
+	if (pcxt->nworkers_launched == 0)
+	{
+		EndParallelCopy(pcxt);
+		return NULL;
+	}
+
+	/*
+	 * Caller needs to wait for all launched workers when we return.  Make
+	 * sure that the failure-to-start case will not hang forever.
+	 */
+	WaitForParallelWorkersToAttach(pcxt);
+
+	pcdata->is_leader = true;
+	cstate->is_parallel = true;
+	return pcxt;
+}
+
+/*
+ * EndParallelCopy
+ *
+ * End the parallel copy tasks.
+ */
+pg_attribute_always_inline void
+EndParallelCopy(ParallelContext *pcxt)
+{
+	Assert(!IsParallelWorker());
+
+	DestroyParallelContext(pcxt);
+	ExitParallelMode();
+}
+
+/*
+ * InitializeParallelCopyInfo
+ *
+ * Initialize parallel worker.
+ */
+static void
+InitializeParallelCopyInfo(CopyState cstate, List *attnamelist)
+{
+	uint32		count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	PopulateCommonCstateInfo(cstate, tup_desc, attnamelist);
+
+	/* Initialize state variables. */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/* Set up variables to avoid per-attribute overhead. */
+	initStringInfo(&cstate->attribute_buf);
+
+	initStringInfo(&cstate->line_buf);
+	for (count = 0; count < WORKER_CHUNK_COUNT; count++)
+		initStringInfo(&pcdata->worker_line_buf[count].line_buf);
+
+	cstate->line_buf_converted = false;
+	cstate->raw_buf = NULL;
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+
+	PopulateCstateCatalogInfo(cstate);
+
+	/* Create workspace for CopyReadAttributes results. */
+	if (!cstate->binary)
+	{
+		AttrNumber	attr_count = list_length(cstate->attnumlist);
+
+		cstate->max_fields = attr_count;
+		cstate->raw_fields = (char **) palloc(attr_count * sizeof(char *));
+	}
+}
+
+/*
+ * CacheLineInfo
+ *
+ * Cache the line information to local memory.
+ */
+static bool
+CacheLineInfo(CopyState cstate, uint32 buff_count)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	uint32		write_pos;
+	ParallelCopyDataBlock *data_blk_ptr;
+	ParallelCopyLineBoundary *lineInfo;
+	uint32		offset;
+	int			dataSize;
+	int			copiedSize = 0;
+
+	resetStringInfo(&pcdata->worker_line_buf[buff_count].line_buf);
+	write_pos = GetLinePosition(cstate);
+	if (-1 == write_pos)
+		return true;
+
+	/* Get the current line information. */
+	lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+	if (pg_atomic_read_u32(&lineInfo->line_size) == 0)
+		goto empty_data_line_update;
+
+	/* Get the block information. */
+	data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+	/* Get the offset information from where the data must be copied. */
+	offset = lineInfo->start_offset;
+	pcdata->worker_line_buf[buff_count].cur_lineno = lineInfo->cur_lineno;
+
+	elog(DEBUG1, "[Worker] Processing - line position:%d, block:%d, unprocessed lines:%d, offset:%d, line size:%d",
+		 write_pos, lineInfo->first_block,
+		 pg_atomic_read_u32(&data_blk_ptr->unprocessed_line_parts),
+		 offset, pg_atomic_read_u32(&lineInfo->line_size));
+
+	for (;;)
+	{
+		uint8		skip_bytes = data_blk_ptr->skip_bytes;
+
+		/*
+		 * There is a possibility that the loop embedded at the bottom of the
+		 * current loop has come out because data_blk_ptr->curr_blk_completed
+		 * is set, but dataSize read might be an old value, if
+		 * data_blk_ptr->curr_blk_completed and the line is completed,
+		 * line_size will be set. Read the line_size again to be sure if it is
+		 * completed or partial block.
+		 */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+		if (dataSize)
+		{
+			int			remainingSize = dataSize - copiedSize;
+
+			if (!remainingSize)
+				break;
+
+			/* Whole line is in current block. */
+			if (remainingSize + offset + skip_bytes < DATA_BLOCK_SIZE)
+			{
+				appendBinaryStringInfo(&pcdata->worker_line_buf[buff_count].line_buf,
+									   &data_blk_ptr->data[offset],
+									   remainingSize);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts,
+										1);
+				break;
+			}
+			else
+			{
+				/* Line is spread across the blocks. */
+				uint32		lineInCurrentBlock = (DATA_BLOCK_SIZE - skip_bytes) - offset;
+
+				appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+										 &data_blk_ptr->data[offset],
+										 lineInCurrentBlock);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+				copiedSize += lineInCurrentBlock;
+				while (copiedSize < dataSize)
+				{
+					uint32		currentBlockCopySize;
+					ParallelCopyDataBlock *currBlkPtr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+
+					skip_bytes = currBlkPtr->skip_bytes;
+
+					/*
+					 * If complete data is present in current block use
+					 * dataSize - copiedSize, or copy the whole block from
+					 * current block.
+					 */
+					currentBlockCopySize = Min(dataSize - copiedSize, DATA_BLOCK_SIZE - skip_bytes);
+					appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+											 &currBlkPtr->data[0],
+											 currentBlockCopySize);
+					pg_atomic_sub_fetch_u32(&currBlkPtr->unprocessed_line_parts, 1);
+					copiedSize += currentBlockCopySize;
+					data_blk_ptr = currBlkPtr;
+				}
+
+				break;
+			}
+		}
+		else
+		{
+			/* Copy this complete block from the current offset. */
+			uint32		lineInCurrentBlock = (DATA_BLOCK_SIZE - skip_bytes) - offset;
+
+			appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+									 &data_blk_ptr->data[offset],
+									 lineInCurrentBlock);
+			pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+			copiedSize += lineInCurrentBlock;
+
+			/*
+			 * Reset the offset. For the first copy, copy from the offset. For
+			 * the subsequent copy the complete block.
+			 */
+			offset = 0;
+
+			/* Set data_blk_ptr to the following block. */
+			data_blk_ptr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+		}
+
+		for (;;)
+		{
+			/* Get the size of this line */
+			dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+			/*
+			 * If the data is present in current block lineInfo->line_size
+			 * will be updated. If the data is spread across the blocks either
+			 * of lineInfo->line_size or data_blk_ptr->curr_blk_completed can
+			 * be updated. lineInfo->line_size will be updated if the complete
+			 * read is finished. data_blk_ptr->curr_blk_completed will be
+			 * updated if processing of current block is finished and data
+			 * processing is not finished.
+			 */
+			if (data_blk_ptr->curr_blk_completed || (dataSize != -1))
+				break;
+
+			COPY_WAIT_TO_PROCESS()
+		}
+	}
+
+empty_data_line_update:
+	elog(DEBUG1, "[Worker] Completed processing line:%d", write_pos);
+	pg_atomic_write_u32(&lineInfo->line_state, LINE_WORKER_PROCESSED);
+	pg_atomic_write_u32(&lineInfo->line_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+	return false;
+}
+
+/*
+ * GetWorkerLine
+ *
+ * Returns a line for worker to process.
+ */
+bool
+GetWorkerLine(CopyState cstate)
+{
+	uint32		buff_count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+
+	/*
+	 * Copy the line data to line_buf and release the line position so that
+	 * the worker can continue loading data.
+	 */
+	if (pcdata->worker_line_buf_pos < pcdata->worker_line_buf_count)
+		goto return_line;
+
+	pcdata->worker_line_buf_pos = 0;
+	pcdata->worker_line_buf_count = 0;
+
+	for (buff_count = 0; buff_count < WORKER_CHUNK_COUNT; buff_count++)
+	{
+		bool		result = CacheLineInfo(cstate, buff_count);
+
+		if (result)
+			break;
+
+		pcdata->worker_line_buf_count++;
+	}
+
+	if (pcdata->worker_line_buf_count)
+		goto return_line;
+	else
+		resetStringInfo(&cstate->line_buf);
+
+	return true;
+
+return_line:
+	cstate->line_buf = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].line_buf;
+	cstate->cur_lineno = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].cur_lineno;
+	cstate->line_buf_valid = true;
+
+	/* Mark that encoding conversion hasn't occurred yet. */
+	cstate->line_buf_converted = false;
+	ConvertToServerEncoding(cstate);
+	pcdata->worker_line_buf_pos++;
+	return false;
+}
+
+/*
+ * ParallelCopyMain - Parallel copy worker's code.
+ *
+ * Where clause handling, convert tuple to columns, add default null values for
+ * the missing columns that are not present in that record. Find the partition
+ * if it is partitioned table, invoke before row insert Triggers, handle
+ * constraints and insert the tuples.
+ */
+void
+ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
+{
+	CopyState	cstate;
+	ParallelCopyData *pcdata;
+	ParallelCopyShmInfo *pcshared_info;
+	Relation	rel = NULL;
+	MemoryContext oldcontext;
+	List	   *attlist = NIL;
+	WalUsage   *walusage;
+	BufferUsage *bufferusage;
+
+	/* Allocate workspace and zero all fields. */
+	cstate = (CopyStateData *) palloc0(sizeof(CopyStateData));
+
+	/*
+	 * We allocate everything used by a cstate in a new memory context. This
+	 * avoids memory leaks during repeated use of COPY in a query.
+	 */
+	cstate->copycontext = AllocSetContextCreate(CurrentMemoryContext,
+												"COPY",
+												ALLOCSET_DEFAULT_SIZES);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	cstate->pcdata = pcdata;
+	pcdata->is_leader = false;
+	pcdata->worker_processed_pos = -1;
+	cstate->is_parallel = true;
+	pcshared_info = (ParallelCopyShmInfo *) shm_toc_lookup(toc, PARALLEL_COPY_KEY_SHARED_INFO, false);
+
+	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
+
+	pcdata->pcshared_info = pcshared_info;
+	RestoreParallelCopyState(toc, cstate, &attlist);
+
+	/* Open and lock the relation, using the appropriate lock type. */
+	rel = table_open(cstate->pcdata->relid, RowExclusiveLock);
+	cstate->rel = rel;
+	InitializeParallelCopyInfo(cstate, attlist);
+
+	/* Prepare to track buffer usage during parallel execution */
+	InstrStartParallelQuery();
+
+	CopyFrom(cstate);
+
+	if (rel != NULL)
+		table_close(rel, RowExclusiveLock);
+
+	/* Report WAL/buffer usage during parallel execution */
+	bufferusage = shm_toc_lookup(toc, PARALLEL_COPY_BUFFER_USAGE, false);
+	walusage = shm_toc_lookup(toc, PARALLEL_COPY_WAL_USAGE, false);
+	InstrEndParallelQuery(&bufferusage[ParallelWorkerNumber],
+						  &walusage[ParallelWorkerNumber]);
+
+	MemoryContextSwitchTo(oldcontext);
+	pfree(cstate);
+	return;
+}
+
+/*
+ * UpdateSharedLineInfo
+ *
+ * Update the line information.
+ */
+uint32
+UpdateSharedLineInfo(CopyState cstate, uint32 blk_pos, uint32 offset,
+					 uint32 line_size, uint32 line_state, uint32 blk_line_pos)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyLineBoundaries *lineBoundaryPtr = &pcshared_info->line_boundaries;
+	ParallelCopyLineBoundary *lineInfo;
+	uint32		line_pos;
+
+	/* blk_line_pos will be valid in case line_pos was blocked earlier. */
+	if (blk_line_pos == -1)
+	{
+		line_pos = lineBoundaryPtr->pos;
+
+		/* Update the line information for the worker to pick and process. */
+		lineInfo = &lineBoundaryPtr->ring[line_pos];
+		while (pg_atomic_read_u32(&lineInfo->line_size) != -1)
+			COPY_WAIT_TO_PROCESS()
+
+				lineInfo->first_block = blk_pos;
+		lineInfo->start_offset = offset;
+		lineInfo->cur_lineno = cstate->cur_lineno;
+		lineBoundaryPtr->pos = (lineBoundaryPtr->pos + 1) % RINGSIZE;
+	}
+	else
+	{
+		line_pos = blk_line_pos;
+		lineInfo = &lineBoundaryPtr->ring[line_pos];
+	}
+
+	if (line_state == LINE_LEADER_POPULATED)
+	{
+		elog(DEBUG1, "[Leader] Added line with block:%d, offset:%d, line position:%d, line size:%d",
+			 lineInfo->first_block, lineInfo->start_offset, line_pos,
+			 pg_atomic_read_u32(&lineInfo->line_size));
+		pcshared_info->populated++;
+	}
+	else
+		elog(DEBUG1, "[Leader] Adding - block:%d, offset:%d, line position:%d",
+			 lineInfo->first_block, lineInfo->start_offset, line_pos);
+
+	pg_atomic_write_u32(&lineInfo->line_size, line_size);
+	pg_atomic_write_u32(&lineInfo->line_state, line_state);
+
+	return line_pos;
+}
+
+/*
+ * ParallelCopyFrom - parallel copy leader's functionality.
+ *
+ * Leader executes the before statement for before statement trigger, if before
+ * statement trigger is present. It will read the table data from the file and
+ * copy the contents to DSM data blocks. It will then read the input contents
+ * from the DSM data block and identify the records based on line breaks. This
+ * information is called line or a record that need to be inserted into a
+ * relation. The line information will be stored in ParallelCopyLineBoundary DSM
+ * data structure. Workers will then process this information and insert the
+ * data in to table. It will repeat this process until the all data is read from
+ * the file and all the DSM data blocks are processed. While processing if
+ * leader identifies that DSM Data blocks or DSM ParallelCopyLineBoundary data
+ * structures is full, leader will wait till the worker frees up some entries
+ * and repeat the process. It will wait till all the lines populated are
+ * processed by the workers and exits.
+ */
+void
+ParallelCopyFrom(CopyState cstate)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
+
+	/* raw_buf is not used in parallel copy, instead data blocks are used. */
+	pfree(cstate->raw_buf);
+	cstate->raw_buf = NULL;
+
+	/* Execute the before statement triggers from the leader */
+	ExecBeforeStmtTrigger(cstate);
+
+	/* On input just throw the header line away. */
+	if (cstate->cur_lineno == 0 && cstate->header_line)
+	{
+		cstate->cur_lineno++;
+		if (CopyReadLine(cstate))
+		{
+			pcshared_info->is_read_in_progress = false;
+			return;				/* done */
+		}
+	}
+
+	for (;;)
+	{
+		bool		done;
+
+		cstate->cur_lineno++;
+
+		/* Actually read the line into memory here. */
+		done = CopyReadLine(cstate);
+
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			break;
+	}
+
+	pcshared_info->is_read_in_progress = false;
+	cstate->cur_lineno = 0;
+}
+
+/*
+ * GetLinePosition
+ *
+ * Return the line position once the leader has populated the data.
+ */
+uint32
+GetLinePosition(CopyState cstate)
+{
+	ParallelCopyData *pcdata = cstate->pcdata;
+	ParallelCopyShmInfo *pcshared_info = pcdata->pcshared_info;
+	uint32		previous_pos = pcdata->worker_processed_pos;
+	uint32		write_pos = (previous_pos == -1) ? 0 : (previous_pos + 1) % RINGSIZE;
+
+	for (;;)
+	{
+		int			dataSize;
+		bool		is_read_in_progress = pcshared_info->is_read_in_progress;
+		ParallelCopyLineBoundary *lineInfo;
+		ParallelCopyDataBlock *data_blk_ptr;
+		uint32		line_state = LINE_LEADER_POPULATED;
+		ParallelCopyLineState curr_line_state;
+
+		CHECK_FOR_INTERRUPTS();
+
+		/* File read completed & no elements to process. */
+		if (!is_read_in_progress &&
+			(pcshared_info->populated ==
+			 pg_atomic_read_u64(&pcshared_info->total_worker_processed)))
+		{
+			write_pos = -1;
+			break;
+		}
+
+		/* Get the current line information. */
+		lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+		curr_line_state = pg_atomic_read_u32(&lineInfo->line_state);
+		if ((write_pos % WORKER_CHUNK_COUNT == 0) &&
+			(curr_line_state == LINE_WORKER_PROCESSED ||
+			 curr_line_state == LINE_WORKER_PROCESSING))
+		{
+			pcdata->worker_processed_pos = write_pos;
+			write_pos = (write_pos + WORKER_CHUNK_COUNT) % RINGSIZE;
+			continue;
+		}
+
+		/* Get the size of this line. */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+		if (dataSize != 0)		/* If not an empty line. */
+		{
+			/* Get the block information. */
+			data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+			if (!data_blk_ptr->curr_blk_completed && (dataSize == -1))
+			{
+				/* Wait till the current line or block is added. */
+				COPY_WAIT_TO_PROCESS()
+					continue;
+			}
+		}
+
+		/* Make sure that no worker has consumed this element. */
+		if (pg_atomic_compare_exchange_u32(&lineInfo->line_state,
+										   &line_state, LINE_WORKER_PROCESSING))
+			break;
+	}
+
+	pcdata->worker_processed_pos = write_pos;
+	return write_pos;
+}
+
+/*
+ * GetFreeCopyBlock
+ *
+ * Get a free block for data to be copied.
+ */
+static pg_attribute_always_inline uint32
+GetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	int			count = 0;
+	uint32		last_free_block = pcshared_info->cur_block_pos;
+	uint32		block_pos = (last_free_block != -1) ? ((last_free_block + 1) % MAX_BLOCKS_COUNT) : 0;
+
+	/*
+	 * Get a new block for copying data, don't check current block, current
+	 * block will have some unprocessed data.
+	 */
+	while (count < (MAX_BLOCKS_COUNT - 1))
+	{
+		ParallelCopyDataBlock *dataBlkPtr = &pcshared_info->data_blocks[block_pos];
+		uint32		unprocessed_line_parts = pg_atomic_read_u32(&dataBlkPtr->unprocessed_line_parts);
+
+		if (unprocessed_line_parts == 0)
+		{
+			dataBlkPtr->curr_blk_completed = false;
+			dataBlkPtr->skip_bytes = 0;
+			dataBlkPtr->following_block = -1;
+			pcshared_info->cur_block_pos = block_pos;
+			MemSet(&dataBlkPtr->data[0], 0, DATA_BLOCK_SIZE);
+			return block_pos;
+		}
+
+		block_pos = (block_pos + 1) % MAX_BLOCKS_COUNT;
+		count++;
+	}
+
+	return -1;
+}
+
+/*
+ * WaitGetFreeCopyBlock
+ *
+ * If there are no blocks available, wait and get a block for copying data.
+ */
+uint32
+WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	uint32		new_free_pos = -1;
+
+	for (;;)
+	{
+		new_free_pos = GetFreeCopyBlock(pcshared_info);
+		if (new_free_pos != -1) /* We have got one block, break now. */
+			break;
+
+		COPY_WAIT_TO_PROCESS()
+	}
+
+	return new_free_pos;
+}
+
+/*
+ * SetRawBufForLoad
+ *
+ * Set raw_buf to the shared memory where the file data must be read.
+ */
+void
+SetRawBufForLoad(CopyState cstate, uint32 line_size, uint32 copy_buf_len,
+				 uint32 raw_buf_ptr, char **copy_raw_buf)
+{
+	ParallelCopyShmInfo *pcshared_info;
+	uint32		cur_block_pos;
+	uint32		next_block_pos;
+	ParallelCopyDataBlock *cur_data_blk_ptr = NULL;
+	ParallelCopyDataBlock *next_data_blk_ptr = NULL;
+
+	Assert(IsParallelCopy());
+
+	pcshared_info = cstate->pcdata->pcshared_info;
+	cur_block_pos = pcshared_info->cur_block_pos;
+	cur_data_blk_ptr = (cstate->raw_buf) ? &pcshared_info->data_blocks[cur_block_pos] : NULL;
+	next_block_pos = WaitGetFreeCopyBlock(pcshared_info);
+	next_data_blk_ptr = &pcshared_info->data_blocks[next_block_pos];
+
+	/* set raw_buf to the data block in shared memory */
+	cstate->raw_buf = next_data_blk_ptr->data;
+	*copy_raw_buf = cstate->raw_buf;
+	if (cur_data_blk_ptr && line_size)
+	{
+		/*
+		 * Mark the previous block as completed, worker can start copying this
+		 * data.
+		 */
+		cur_data_blk_ptr->following_block = next_block_pos;
+		pg_atomic_add_fetch_u32(&cur_data_blk_ptr->unprocessed_line_parts, 1);
+		cur_data_blk_ptr->skip_bytes = copy_buf_len - raw_buf_ptr;
+		cur_data_blk_ptr->curr_blk_completed = true;
+	}
+
+	cstate->raw_buf_index = 0;
+}
+
+/*
+ * EndLineParallelCopy
+ *
+ * Update the line information in shared memory.
+ */
+void
+EndLineParallelCopy(CopyState cstate, uint32 line_pos, uint32 line_size,
+					uint32 raw_buf_ptr)
+{
+	uint8		new_line_size;
+
+	if (!IsParallelCopy())
+		return;
+
+	if (!IsHeaderLine())
+	{
+		ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+		SET_NEWLINE_SIZE()
+			if (line_size)
+		{
+			/*
+			 * If the new_line_size > raw_buf_ptr, then the new block has only
+			 * new line char content. The unprocessed count should not be
+			 * increased in this case.
+			 */
+			if (raw_buf_ptr > new_line_size)
+			{
+				uint32		cur_block_pos = pcshared_info->cur_block_pos;
+				ParallelCopyDataBlock *curr_data_blk_ptr = &pcshared_info->data_blocks[cur_block_pos];
+
+				pg_atomic_add_fetch_u32(&curr_data_blk_ptr->unprocessed_line_parts, 1);
+			}
+
+			/*
+			 * Update line size & line state, other members are already
+			 * updated.
+			 */
+			(void) UpdateSharedLineInfo(cstate, -1, -1, line_size,
+										LINE_LEADER_POPULATED, line_pos);
+		}
+		else if (new_line_size)
+			/* This means only new line char, empty record should be inserted. */
+			(void) UpdateSharedLineInfo(cstate, -1, -1, 0,
+										LINE_LEADER_POPULATED, -1);
+	}
+}
+
+/*
+ * ExecBeforeStmtTrigger
+ *
+ * Execute the before statement trigger, this will be executed for parallel copy
+ * by the leader process.
+ */
+void
+ExecBeforeStmtTrigger(CopyState cstate)
+{
+	EState	   *estate = CreateExecutorState();
+	ResultRelInfo *resultRelInfo;
+
+	Assert(IsLeader());
+
+	/*
+	 * We need a ResultRelInfo so we can use the regular executor's
+	 * index-entry-making machinery.  (There used to be a huge amount of code
+	 * here that basically duplicated execUtils.c ...)
+	 */
+	ExecInitRangeTable(estate, cstate->range_table);
+	resultRelInfo = makeNode(ResultRelInfo);
+	ExecInitResultRelation(estate, resultRelInfo, 1);
+
+	/* Verify the named relation is a valid target for INSERT */
+	CheckValidResultRel(resultRelInfo, CMD_INSERT);
+
+	estate->es_result_relation_info = resultRelInfo;
+
+	/* Prepare to catch AFTER triggers. */
+	AfterTriggerBeginQuery();
+
+	/*
+	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
+	 * should do this for COPY, since it's not really an "INSERT" statement as
+	 * such. However, executing these triggers maintains consistency with the
+	 * EACH ROW triggers that we already fire on COPY.
+	 */
+	ExecBSInsertTriggers(estate, resultRelInfo);
+
+	/* Handle queued AFTER triggers */
+	AfterTriggerEndQuery(estate);
+
+	/* Close the result relations, including any trigger target relations */
+	ExecCloseResultRelations(estate);
+	ExecCloseRangeTableRelations(estate);
+
+	FreeExecutorState(estate);
+}
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index 24c7b41..cf00256 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -2353,7 +2353,7 @@ psql_completion(const char *text, int start, int end)
 	/* Complete COPY <sth> FROM|TO filename WITH ( */
 	else if (Matches("COPY|\\copy", MatchAny, "FROM|TO", MatchAny, "WITH", "("))
 		COMPLETE_WITH("FORMAT", "FREEZE", "DELIMITER", "NULL",
-					  "HEADER", "QUOTE", "ESCAPE", "FORCE_QUOTE",
+					  "HEADER", "PARALLEL", "QUOTE", "ESCAPE", "FORCE_QUOTE",
 					  "FORCE_NOT_NULL", "FORCE_NULL", "ENCODING");
 
 	/* Complete COPY <sth> FROM|TO filename WITH (FORMAT */
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index df1b43a..96295bc 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -385,6 +385,7 @@ extern FullTransactionId GetTopFullTransactionId(void);
 extern FullTransactionId GetTopFullTransactionIdIfAny(void);
 extern FullTransactionId GetCurrentFullTransactionId(void);
 extern FullTransactionId GetCurrentFullTransactionIdIfAny(void);
+extern void SetCurrentCommandIdUsedForWorker(void);
 extern void MarkCurrentTransactionIdLoggedIfAny(void);
 extern bool SubTransactionIsActive(SubTransactionId subxid);
 extern CommandId GetCurrentCommandId(bool used);
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index cd2d56e..9b19dcb 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -34,7 +34,7 @@
  */
 #define DATA_BLOCK_SIZE RAW_BUF_SIZE
 
-/* It can hold 1023 blocks of 64K data in DSM to be processed by the worker. */
+/* It can hold 1024 blocks of 64K data in DSM to be processed by the worker. */
 #define MAX_BLOCKS_COUNT 1024
 
 /*
@@ -51,6 +51,13 @@
  */
 #define WORKER_CHUNK_COUNT 64
 
+#define IsParallelCopy()		(cstate->is_parallel)
+#define IsLeader()				(cstate->pcdata->is_leader)
+#define IsWorker()				(IsParallelCopy() && !IsLeader())
+#define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
+
+
+
 /*
  * Represents the different source/dest cases we need to worry about at
  * the bottom level
@@ -75,6 +82,28 @@ typedef enum EolType
 } EolType;
 
 /*
+ * State of the line.
+ */
+typedef enum ParallelCopyLineState
+{
+	LINE_INIT,					/* initial state of line */
+	LINE_LEADER_POPULATING,		/* leader processing line */
+	LINE_LEADER_POPULATED,		/* leader completed populating line */
+	LINE_WORKER_PROCESSING,		/* worker processing line */
+	LINE_WORKER_PROCESSED		/* worker completed processing line */
+} ParallelCopyLineState;
+
+/*
+ * Represents the heap insert method to be used during COPY FROM.
+ */
+typedef enum CopyInsertMethod
+{
+	CIM_SINGLE,					/* use table_tuple_insert or fdw routine */
+	CIM_MULTI,					/* always use table_multi_insert */
+	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
+} CopyInsertMethod;
+
+/*
  * Copy data block information.
  *
  * These data blocks are created in DSM. Data read from file will be copied in
@@ -194,8 +223,6 @@ typedef struct ParallelCopyShmInfo
 	uint64		populated;		/* lines populated by leader */
 	uint32		cur_block_pos;	/* current data block */
 	ParallelCopyDataBlock data_blocks[MAX_BLOCKS_COUNT];	/* data block array */
-	FullTransactionId full_transaction_id;	/* xid for copy from statement */
-	CommandId	mycid;			/* command id */
 	ParallelCopyLineBoundaries line_boundaries; /* line array */
 } ParallelCopyShmInfo;
 
@@ -242,12 +269,12 @@ typedef struct ParallelCopyData
 	ParallelCopyShmInfo *pcshared_info; /* common info in shared memory */
 	bool		is_leader;
 
+	/* line position which worker is processing */
+	uint32				worker_processed_pos;
+
 	WalUsage   *walusage;
 	BufferUsage *bufferusage;
 
-	/* line position which worker is processing */
-	uint32		worker_processed_pos;
-
 	/*
 	 * Local line_buf array, workers will copy it here and release the lines
 	 * for the leader to continue.
@@ -423,9 +450,24 @@ extern DestReceiver *CreateCopyDestReceiver(void);
 
 extern void PopulateCommonCstateInfo(CopyState cstate, TupleDesc tup_desc,
 									 List *attnamelist);
+extern void ConvertToServerEncoding(CopyState cstate);
 
 extern void ParallelCopyMain(dsm_segment *seg, shm_toc *toc);
 extern ParallelContext *BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid);
 extern void ParallelCopyFrom(CopyState cstate);
 extern void EndParallelCopy(ParallelContext *pcxt);
+extern bool IsParallelCopyAllowed(CopyState cstate);
+extern void ExecBeforeStmtTrigger(CopyState cstate);
+extern void CheckTargetRelValidity(CopyState cstate);
+extern void PopulateCstateCatalogInfo(CopyState cstate);
+extern uint32 GetLinePosition(CopyState cstate);
+extern bool GetWorkerLine(CopyState cstate);
+extern bool CopyReadLine(CopyState cstate);
+extern uint32 WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info);
+extern void SetRawBufForLoad(CopyState cstate, uint32 line_size, uint32 copy_buf_len,
+							 uint32 raw_buf_ptr, char **copy_raw_buf);
+extern uint32 UpdateSharedLineInfo(CopyState cstate, uint32 blk_pos, uint32 offset,
+								   uint32 line_size, uint32 line_state, uint32 blk_line_pos);
+extern void EndLineParallelCopy(CopyState cstate, uint32 line_pos, uint32 line_size,
+								uint32 raw_buf_ptr);
 #endif							/* COPY_H */
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 5ce8296..8dfb944 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1707,6 +1707,7 @@ ParallelCopyLineBoundary
 ParallelCopyData
 ParallelCopyDataBlock
 ParallelCopyLineBuf
+ParallelCopyLineState
 ParallelCopyShmInfo
 ParallelExecutorInfo
 ParallelHashGrowth
-- 
1.8.3.1

v7-0004-Documentation-for-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=v7-0004-Documentation-for-parallel-copy.patchDownload
From 778be67172b1f9eb3070ea64f64215e36e11c062 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Sat, 1 Aug 2020 09:00:36 +0530
Subject: [PATCH v7 4/6] Documentation for parallel copy.

This patch has the documentation changes for parallel copy.
---
 doc/src/sgml/ref/copy.sgml | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/doc/src/sgml/ref/copy.sgml b/doc/src/sgml/ref/copy.sgml
index 369342b..328a5f1 100644
--- a/doc/src/sgml/ref/copy.sgml
+++ b/doc/src/sgml/ref/copy.sgml
@@ -37,6 +37,7 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
     DELIMITER '<replaceable class="parameter">delimiter_character</replaceable>'
     NULL '<replaceable class="parameter">null_string</replaceable>'
     HEADER [ <replaceable class="parameter">boolean</replaceable> ]
+    PARALLEL <replaceable class="parameter">integer</replaceable>
     QUOTE '<replaceable class="parameter">quote_character</replaceable>'
     ESCAPE '<replaceable class="parameter">escape_character</replaceable>'
     FORCE_QUOTE { ( <replaceable class="parameter">column_name</replaceable> [, ...] ) | * }
@@ -277,6 +278,22 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
    </varlistentry>
 
    <varlistentry>
+    <term><literal>PARALLEL</literal></term>
+    <listitem>
+     <para>
+      Perform <command>COPY FROM</command> in parallel using <replaceable
+      class="parameter">integer</replaceable> background workers.  Please
+      note that it is not guaranteed that the number of parallel workers
+      specified in <replaceable class="parameter">integer</replaceable> will
+      be used during execution.  It is possible for a copy to run with fewer
+      workers than specified, or even with no workers at all (for example,
+      due to the setting of max_worker_processes). This option is allowed
+      only in <command>COPY FROM</command>.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><literal>QUOTE</literal></term>
     <listitem>
      <para>
@@ -953,6 +970,20 @@ COPY country FROM '/usr1/proj/bray/sql/country_data';
   </para>
 
   <para>
+   To copy data parallelly from a file into the <literal>country</literal> table:
+<programlisting>
+COPY country FROM '/usr1/proj/bray/sql/country_data' WITH (PARALLEL 1);
+</programlisting>
+  </para>
+
+  <para>
+   To copy data parallelly from STDIN into the <literal>country</literal> table:
+<programlisting>
+COPY country FROM STDIN WITH (PARALLEL 1);
+</programlisting>
+  </para>
+
+  <para>
    To copy into a file just the countries whose names start with 'A':
 <programlisting>
 COPY (SELECT * FROM country WHERE country_name LIKE 'A%') TO '/usr1/proj/bray/sql/a_list_countries.copy';
-- 
1.8.3.1

v7-0005-Tests-for-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=v7-0005-Tests-for-parallel-copy.patchDownload
From 66846373b9cd3a508ba1b0dd622f834783855e99 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddy@enterprisedb.com>
Date: Tue, 13 Oct 2020 14:23:10 +0530
Subject: [PATCH v7 5/6] Tests for parallel copy.

This patch has the tests for parallel copy:
---
 contrib/postgres_fdw/expected/postgres_fdw.out |  49 ++++
 contrib/postgres_fdw/sql/postgres_fdw.sql      |  52 ++++
 src/test/regress/expected/copy2.out            | 326 +++++++++++++++++++++-
 src/test/regress/input/copy.source             |  31 +++
 src/test/regress/output/copy.source            |  27 ++
 src/test/regress/sql/copy2.sql                 | 368 ++++++++++++++++++++++++-
 6 files changed, 845 insertions(+), 8 deletions(-)

diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index 2d88d06..474c5e7 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -9033,5 +9033,54 @@ SELECT 1 FROM ft1 LIMIT 1;    -- should fail
 ERROR:  08006
 \set VERBOSITY default
 COMMIT;
+-- parallel copy related tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+CREATE FOREIGN TABLE test_parallel_copy_ft (
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+) SERVER loopback OPTIONS (table_name 'test_parallel_copy') ;
+-- parallel copy into foreign table, parallelism must not be picked up.
+COPY test_parallel_copy_ft FROM stdin WITH (PARALLEL 1);
+SELECT count(*) FROM test_parallel_copy_ft;
+ count 
+-------
+     2
+(1 row)
+
+-- parallel copy into a table with foreign partition.
+CREATE TABLE part_test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+) PARTITION BY LIST (b);
+CREATE FOREIGN TABLE part_test_parallel_copy_a1 (c TEXT, b INT, a INT, e TEXT, d TEXT) SERVER loopback;
+CREATE TABLE part_test_parallel_copy_a2 (a INT, c TEXT, b INT, d TEXT, e TEXT);
+ALTER TABLE part_test_parallel_copy ATTACH PARTITION part_test_parallel_copy_a1 FOR VALUES IN(1);
+ALTER TABLE part_test_parallel_copy ATTACH PARTITION part_test_parallel_copy_a2 FOR VALUES IN(2);
+COPY part_test_parallel_copy FROM stdin WITH (PARALLEL 1);
+ERROR:  cannot perform PARALLEL COPY if partition has BEFORE/INSTEAD OF triggers, or if the partition is foreign partition
+HINT:  Try COPY without PARALLEL option
+CONTEXT:  COPY part_test_parallel_copy, line 1: "1	1	test_c1	test_d1	test_e1"
+parallel worker
+SELECT count(*) FROM part_test_parallel_copy WHERE b = 2;
+ count 
+-------
+     0
+(1 row)
+
 -- Clean up
 DROP PROCEDURE terminate_backend_and_wait(text);
+DROP FOREIGN TABLE test_parallel_copy_ft;
+DROP TABLE test_parallel_copy;
+DROP TABLE part_test_parallel_copy;
diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql
index 7581c54..635fcc2 100644
--- a/contrib/postgres_fdw/sql/postgres_fdw.sql
+++ b/contrib/postgres_fdw/sql/postgres_fdw.sql
@@ -2695,5 +2695,57 @@ SELECT 1 FROM ft1 LIMIT 1;    -- should fail
 \set VERBOSITY default
 COMMIT;
 
+-- parallel copy related tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+
+CREATE FOREIGN TABLE test_parallel_copy_ft (
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+) SERVER loopback OPTIONS (table_name 'test_parallel_copy') ;
+
+-- parallel copy into foreign table, parallelism must not be picked up.
+COPY test_parallel_copy_ft FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+SELECT count(*) FROM test_parallel_copy_ft;
+
+-- parallel copy into a table with foreign partition.
+CREATE TABLE part_test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+) PARTITION BY LIST (b);
+
+CREATE FOREIGN TABLE part_test_parallel_copy_a1 (c TEXT, b INT, a INT, e TEXT, d TEXT) SERVER loopback;
+
+CREATE TABLE part_test_parallel_copy_a2 (a INT, c TEXT, b INT, d TEXT, e TEXT);
+
+ALTER TABLE part_test_parallel_copy ATTACH PARTITION part_test_parallel_copy_a1 FOR VALUES IN(1);
+
+ALTER TABLE part_test_parallel_copy ATTACH PARTITION part_test_parallel_copy_a2 FOR VALUES IN(2);
+
+COPY part_test_parallel_copy FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+SELECT count(*) FROM part_test_parallel_copy WHERE b = 2;
+
 -- Clean up
 DROP PROCEDURE terminate_backend_and_wait(text);
+DROP FOREIGN TABLE test_parallel_copy_ft;
+DROP TABLE test_parallel_copy;
+DROP TABLE part_test_parallel_copy;
diff --git a/src/test/regress/expected/copy2.out b/src/test/regress/expected/copy2.out
index c64f071..08ce743 100644
--- a/src/test/regress/expected/copy2.out
+++ b/src/test/regress/expected/copy2.out
@@ -301,18 +301,32 @@ It is "perfect".|
 "It is ""perfect"".","	"
 "",
 --test that we read consecutive LFs properly
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 COPY testnl FROM stdin CSV;
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+SELECT * FROM testnl;
+ a |          b           | c 
+---+----------------------+---
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+(2 rows)
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 COPY testeoc FROM stdin CSV;
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
 COPY testeoc TO stdout CSV;
 a\.
 \.b
 c\.d
 "\."
 -- test handling of nonstandard null marker that violates escaping rules
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 COPY testnull TO stdout WITH NULL AS E'\\0';
 1	\\0
@@ -327,6 +341,15 @@ SELECT * FROM testnull;
     | 
 (4 rows)
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 1);
+SELECT * FROM testnull;
+ a  | b  
+----+----
+ 42 | \0
+    | 
+(2 rows)
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -396,6 +419,34 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+SELECT * FROM vistest;
+ a  
+----
+ a2
+ b
+(2 rows)
+
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+COMMIT;
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 SELECT * FROM vistest;
  a 
@@ -456,7 +507,7 @@ SELECT * FROM vistest;
 (2 rows)
 
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -467,6 +518,8 @@ CREATE TEMP TABLE forcetest (
 -- should succeed with no effect ("b" remains an empty string, "c" remains NULL)
 BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 1);
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
  b |  c   
@@ -477,6 +530,8 @@ SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
 BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 1);
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
  c |  d   
@@ -533,6 +588,31 @@ select * from check_con_tbl;
    
 (2 rows)
 
+\d+ check_con_tbl
+                               Table "public.check_con_tbl"
+ Column |  Type   | Collation | Nullable | Default | Storage | Stats target | Description 
+--------+---------+-----------+----------+---------+---------+--------------+-------------
+ f1     | integer |           |          |         | plain   |              | 
+Check constraints:
+    "check_con_tbl_check" CHECK (check_con_function(check_con_tbl.*))
+
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 1);
+NOTICE:  input = {"f1":1}
+NOTICE:  input = {"f1":null}
+copy check_con_tbl from stdin with (parallel 1);
+NOTICE:  input = {"f1":0}
+ERROR:  new row for relation "check_con_tbl" violates check constraint "check_con_tbl_check"
+DETAIL:  Failing row contains (0).
+CONTEXT:  COPY check_con_tbl, line 1: "0"
+parallel worker
+select * from check_con_tbl;
+ f1 
+----
+  1
+   
+(2 rows)
+
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
 CREATE ROLE regress_rls_copy_user_colperms;
@@ -647,10 +727,248 @@ SELECT * FROM instead_of_insert_tbl;
 (2 rows)
 
 COMMIT;
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+COPY test_parallel_copy (a, b, c, d, e) FROM stdin WITH (PARALLEL 1);
+COPY test_parallel_copy (b, d) FROM stdin WITH (PARALLEL 1);
+COPY test_parallel_copy (b, d) FROM stdin WITH (PARALLEL 1);
+COPY test_parallel_copy (b, d) FROM stdin WITH (PARALLEL 1, FORMAT 'csv', HEADER);
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) FROM stdin WITH (PARALLEL '0');
+ERROR:  value 0 out of bounds for option "parallel"
+DETAIL:  Valid values are between "1" and "1024".
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri FROM stdin WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1) WHERE height > random() * 65;
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+-- temporary table copy: should perform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+COPY temp_test (a) FROM stdin WITH (PARALLEL 1);
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) FROM stdin WITH (PARALLEL 1);
+ERROR:  column "xyz" of relation "test_parallel_copy" does not exist
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) FROM stdin WITH (PARALLEL 1);
+ERROR:  column "d" specified more than once
+-- missing data: should fail
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+ERROR:  invalid input syntax for type integer: ""
+CONTEXT:  COPY test_parallel_copy, line 0, column a: ""
+parallel worker
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2000	230	23	23"
+parallel worker
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2001	231	\N	\N"
+parallel worker
+-- extra data: should fail
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+ERROR:  extra data after last expected column
+CONTEXT:  COPY test_parallel_copy, line 1: "2002	232	40	50	60	70	80"
+parallel worker
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) FROM stdin WITH (DELIMITER ',', null 'x', PARALLEL 1) ;
+COPY test_parallel_copy FROM stdin WITH (DELIMITER ';', NULL '', PARALLEL 1);
+COPY test_parallel_copy FROM stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL 1);
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a = 50004;
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a > 60003;
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE f > 60003;
+ERROR:  column "f" does not exist
+LINE 1: ..._parallel_copy FROM stdin WITH (PARALLEL 1) WHERE f > 60003;
+                                                             ^
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+ERROR:  missing FROM-clause entry for table "x"
+LINE 1: ...rallel_copy FROM stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+                                                                  ^
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a IN (SELECT 1 FROM x);
+ERROR:  cannot use subquery in COPY FROM WHERE condition
+LINE 1: ...arallel_copy FROM stdin WITH (PARALLEL 1) WHERE a IN (SELECT...
+                                                             ^
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a IN (generate_series(1,5));
+ERROR:  set-returning functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...lel_copy FROM stdin WITH (PARALLEL 1) WHERE a IN (generate_s...
+                                                             ^
+COPY test_parallel_copy FROM stdin WITH(PARALLEL 1) WHERE a = row_number() over(b);
+ERROR:  window functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...rallel_copy FROM stdin WITH(PARALLEL 1) WHERE a = row_number...
+                                                             ^
+-- check results of copy in
+SELECT * FROM test_parallel_copy ORDER BY 1;
+   a   | b  |     c      |    d    |    e    
+-------+----+------------+---------+---------
+     1 | 11 | test_c1    | test_d1 | test_e1
+     2 | 12 | test_c2    | test_d2 | test_e2
+  3000 |    | c          |         | 
+  4000 |    | C          |         | 
+  4001 |  1 | empty      |         | 
+  4002 |  2 | null       |         | 
+  4003 |  3 | Backslash  | \       | \
+  4004 |  4 | BackslashX | \X      | \X
+  4005 |  5 | N          | N       | N
+  4006 |  6 | BackslashN | \N      | \N
+  4007 |  7 | XX         | XX      | XX
+  4008 |  8 | Delimiter  | :       | :
+ 50004 | 25 | 35         | 45      | 55
+ 60004 | 25 | 35         | 45      | 55
+ 60005 | 26 | 36         | 46      | 56
+       |  3 | stuff      | test_d3 | 
+       |  4 | stuff      | test_d4 | 
+       |  5 | stuff      | test_d5 | 
+       |    | ,          | \,      | \
+       |    | x          | \x      | \x
+       |    | 45         | 80      | 90
+(21 rows)
+
+-- parallel copy test for unlogged tables. should execute in parallel worker
+CREATE UNLOGGED TABLE test_parallel_copy_unlogged(
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+);
+COPY test_parallel_copy_unlogged FROM stdin WITH (PARALLEL 1);
+SELECT count(*) FROM test_parallel_copy_unlogged;
+ count 
+-------
+     2
+(1 row)
+
+-- parallel copy test for various trigger types
+TRUNCATE test_parallel_copy;
+-- parallel safe trigger function
+CREATE OR REPLACE FUNCTION parallel_copy_trig_func() RETURNS TRIGGER
+LANGUAGE plpgsql PARALLEL SAFE AS $$
+BEGIN
+  RETURN NEW;
+END;
+$$;
+-- before insert row trigger
+CREATE TRIGGER parallel_copy_trig
+BEFORE INSERT ON test_parallel_copy
+FOR EACH ROW
+EXECUTE PROCEDURE parallel_copy_trig_func();
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+-- after insert row trigger
+CREATE TRIGGER parallel_copy_trig
+AFTER INSERT ON test_parallel_copy
+FOR EACH ROW
+EXECUTE PROCEDURE parallel_copy_trig_func();
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+-- before insert statement trigger
+CREATE TRIGGER parallel_copy_trig
+BEFORE INSERT ON test_parallel_copy
+FOR EACH STATEMENT
+EXECUTE PROCEDURE parallel_copy_trig_func();
+-- parallelism should be picked, since the trigger function is parallel safe
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+-- after insert statement trigger
+CREATE TRIGGER parallel_copy_trig
+AFTER INSERT ON test_parallel_copy
+FOR EACH STATEMENT
+EXECUTE PROCEDURE parallel_copy_trig_func();
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+-- transition table is involved
+CREATE TRIGGER parallel_copy_trig
+AFTER INSERT ON test_parallel_copy REFERENCING NEW TABLE AS new_table
+FOR EACH STATEMENT
+EXECUTE PROCEDURE parallel_copy_trig_func();
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+-- make trigger function parallel unsafe
+ALTER FUNCTION parallel_copy_trig_func PARALLEL UNSAFE;
+-- before statement trigger has a parallel unsafe function
+CREATE TRIGGER parallel_copy_trig
+BEFORE INSERT ON test_parallel_copy
+FOR EACH STATEMENT
+EXECUTE PROCEDURE parallel_copy_trig_func();
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+SELECT count(*) FROM test_parallel_copy;
+ count 
+-------
+    12
+(1 row)
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+-- instead of insert trigger, no parallelism should be picked
+COPY instead_of_insert_tbl_view FROM stdin WITH(PARALLEL 1);;
+SELECT count(*) FROM instead_of_insert_tbl_view;
+ count 
+-------
+     1
+(1 row)
+
+-- parallel copy test for a partitioned table with a before insert trigger on
+-- one of the partition
+ALTER FUNCTION parallel_copy_trig_func PARALLEL SAFE;
+CREATE TABLE test_parallel_copy_part (
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+) PARTITION BY LIST (b);
+CREATE TABLE test_parallel_copy_part_a1 (c TEXT, b INT, a INT, e TEXT, d TEXT);
+CREATE TABLE test_parallel_copy_part_a2 (a INT, c TEXT, b INT, d TEXT, e TEXT);
+ALTER TABLE test_parallel_copy_part ATTACH PARTITION test_parallel_copy_part_a1 FOR VALUES IN(1);
+ALTER TABLE test_parallel_copy_part ATTACH PARTITION test_parallel_copy_part_a2 FOR VALUES IN(2);
+CREATE TRIGGER parallel_copy_trig
+BEFORE INSERT ON test_parallel_copy_part_a2
+FOR EACH ROW
+EXECUTE PROCEDURE parallel_copy_trig_func();
+COPY test_parallel_copy_part FROM stdin WITH (PARALLEL 1);
+ERROR:  cannot perform PARALLEL COPY if partition has BEFORE/INSTEAD OF triggers, or if the partition is foreign partition
+HINT:  Try COPY without PARALLEL option
+CONTEXT:  COPY test_parallel_copy_part, line 2: "2	2	test_c2	test_d2	test_e2"
+parallel worker
+SELECT count(*) FROM test_parallel_copy_part;
+ count 
+-------
+     0
+(1 row)
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy_part_a2;
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE test_parallel_copy_unlogged;
+DROP TABLE test_parallel_copy_part;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
+DROP FUNCTION parallel_copy_trig_func();
 DROP TABLE x, y;
 DROP TABLE rls_t1 CASCADE;
 DROP ROLE regress_rls_copy_user;
diff --git a/src/test/regress/input/copy.source b/src/test/regress/input/copy.source
index a1d529a..cb39c66 100644
--- a/src/test/regress/input/copy.source
+++ b/src/test/regress/input/copy.source
@@ -15,6 +15,13 @@ DELETE FROM onek;
 
 COPY onek FROM '@abs_builddir@/results/onek.data';
 
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+
+SELECT COUNT(*) FROM tenk1;
+
+TRUNCATE tenk1;
+
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
@@ -159,6 +166,30 @@ truncate parted_copytest;
 
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
 
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
+
+-- Test parallel copy from for toast table with csv and binary format file
+create table test_parallel_copy_toast(a1 int, b1 text, c1 text default null);
+
+insert into test_parallel_copy_toast select i, (repeat(md5(i::text), 100000)) FROM generate_series(1,2) AS i;
+
+copy test_parallel_copy_toast to '@abs_builddir@/results/parallelcopytoast.csv' with(format csv);
+
+copy test_parallel_copy_toast to '@abs_builddir@/results/parallelcopytoast.dat' with(format binary);
+
+truncate test_parallel_copy_toast;
+
+copy test_parallel_copy_toast from '@abs_builddir@/results/parallelcopytoast.csv' with(format csv, parallel 2);
+
+copy test_parallel_copy_toast from '@abs_builddir@/results/parallelcopytoast.dat' with(format binary, parallel 2);
+
+select count(*) from test_parallel_copy_toast;
+
+drop table test_parallel_copy_toast;
+
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/output/copy.source b/src/test/regress/output/copy.source
index 938d355..a5dca79 100644
--- a/src/test/regress/output/copy.source
+++ b/src/test/regress/output/copy.source
@@ -9,6 +9,15 @@ COPY onek FROM '@abs_srcdir@/data/onek.data';
 COPY onek TO '@abs_builddir@/results/onek.data';
 DELETE FROM onek;
 COPY onek FROM '@abs_builddir@/results/onek.data';
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+SELECT COUNT(*) FROM tenk1;
+ count 
+-------
+ 10000
+(1 row)
+
+TRUNCATE tenk1;
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
 COPY person FROM '@abs_srcdir@/data/person.data';
@@ -113,6 +122,24 @@ insert into parted_copytest select x,1,'One' from generate_series(1011,1020) x;
 copy (select * from parted_copytest order by a) to '@abs_builddir@/results/parted_copytest.csv';
 truncate parted_copytest;
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
+-- Test parallel copy from for toast table with csv and binary format file
+create table test_parallel_copy_toast(a1 int, b1 text, c1 text default null);
+insert into test_parallel_copy_toast select i, (repeat(md5(i::text), 100000)) FROM generate_series(1,2) AS i;
+copy test_parallel_copy_toast to '@abs_builddir@/results/parallelcopytoast.csv' with(format csv);
+copy test_parallel_copy_toast to '@abs_builddir@/results/parallelcopytoast.dat' with(format binary);
+truncate test_parallel_copy_toast;
+copy test_parallel_copy_toast from '@abs_builddir@/results/parallelcopytoast.csv' with(format csv, parallel 2);
+copy test_parallel_copy_toast from '@abs_builddir@/results/parallelcopytoast.dat' with(format binary, parallel 2);
+select count(*) from test_parallel_copy_toast;
+ count 
+-------
+     4
+(1 row)
+
+drop table test_parallel_copy_toast;
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/sql/copy2.sql b/src/test/regress/sql/copy2.sql
index b3c16af..b3c9af3 100644
--- a/src/test/regress/sql/copy2.sql
+++ b/src/test/regress/sql/copy2.sql
@@ -171,7 +171,7 @@ COPY y TO stdout (FORMAT CSV, FORCE_QUOTE *);
 
 --test that we read consecutive LFs properly
 
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 
 COPY testnl FROM stdin CSV;
 1,"a field with two LFs
@@ -179,8 +179,16 @@ COPY testnl FROM stdin CSV;
 inside",2
 \.
 
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+1,"a field with two LFs
+
+inside",2
+\.
+
+SELECT * FROM testnl;
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 
 COPY testeoc FROM stdin CSV;
 a\.
@@ -189,11 +197,19 @@ c\.d
 "\."
 \.
 
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+a\.
+\.b
+c\.d
+"\."
+\.
+
 COPY testeoc TO stdout CSV;
 
 -- test handling of nonstandard null marker that violates escaping rules
 
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 
 COPY testnull TO stdout WITH NULL AS E'\\0';
@@ -205,6 +221,14 @@ COPY testnull FROM stdin WITH NULL AS E'\\0';
 
 SELECT * FROM testnull;
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 1);
+42	\\0
+\0	\0
+\.
+
+SELECT * FROM testnull;
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -249,6 +273,23 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+a2
+b
+\.
+SELECT * FROM vistest;
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+d2
+e
+\.
+SELECT * FROM vistest;
+COMMIT;
+SELECT * FROM vistest;
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 x
 y
@@ -298,7 +339,7 @@ SELECT * FROM vistest;
 COMMIT;
 SELECT * FROM vistest;
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -311,6 +352,10 @@ BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
 1,,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 1);
+1,,""
+\.
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
@@ -318,6 +363,10 @@ BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
 2,'a',,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 1);
+2,'a',,""
+\.
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
 -- should fail with not-null constraint violation
@@ -353,6 +402,16 @@ copy check_con_tbl from stdin;
 0
 \.
 select * from check_con_tbl;
+\d+ check_con_tbl
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 1);
+1
+\N
+\.
+copy check_con_tbl from stdin with (parallel 1);
+0
+\.
+select * from check_con_tbl;
 
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
@@ -454,10 +513,311 @@ test1
 SELECT * FROM instead_of_insert_tbl;
 COMMIT;
 
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+
+COPY test_parallel_copy (a, b, c, d, e) FROM stdin WITH (PARALLEL 1);
+1	11	test_c1	test_d1	test_e1
+2	12	test_c2	test_d2	test_e2
+\.
+
+COPY test_parallel_copy (b, d) FROM stdin WITH (PARALLEL 1);
+3	test_d3
+\.
+
+COPY test_parallel_copy (b, d) FROM stdin WITH (PARALLEL 1);
+4	test_d4
+5	test_d5
+\.
+
+COPY test_parallel_copy (b, d) FROM stdin WITH (PARALLEL 1, FORMAT 'csv', HEADER);
+b	d
+\.
+
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) FROM stdin WITH (PARALLEL '0');
+
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri FROM stdin WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+10
+\.
+
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1) WHERE height > random() * 65;
+60,60,60
+\.
+
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+60
+\.
+
+-- temporary table copy: should perform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+
+COPY temp_test (a) FROM stdin WITH (PARALLEL 1);
+10
+\.
+
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) FROM stdin WITH (PARALLEL 1);
+
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) FROM stdin WITH (PARALLEL 1);
+
+-- missing data: should fail
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+
+\.
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+2000	230	23	23
+\.
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+2001	231	\N	\N
+\.
+
+-- extra data: should fail
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+2002	232	40	50	60	70	80
+\.
+
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) FROM stdin WITH (DELIMITER ',', null 'x', PARALLEL 1) ;
+x,45,80,90
+x,\x,\\x,\\\x
+x,\,,\\\,,\\
+\.
+
+COPY test_parallel_copy FROM stdin WITH (DELIMITER ';', NULL '', PARALLEL 1);
+3000;;c;;
+\.
+
+COPY test_parallel_copy FROM stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL 1);
+4000:\X:C:\X:\X
+4001:1:empty::
+4002:2:null:\X:\X
+4003:3:Backslash:\\:\\
+4004:4:BackslashX:\\X:\\X
+4005:5:N:\N:\N
+4006:6:BackslashN:\\N:\\N
+4007:7:XX:\XX:\XX
+4008:8:Delimiter:\::\:
+\.
+
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a = 50004;
+50003	24	34	44	54
+50004	25	35	45 	55
+50005	26	36	46	56
+\.
+
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a > 60003;
+60001	22	32	42	52
+60002	23	33	43	53
+60003	24	34	44	54
+60004	25	35	45	55
+60005	26	36	46	56
+\.
+
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE f > 60003;
+
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a IN (SELECT 1 FROM x);
+
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a IN (generate_series(1,5));
+
+COPY test_parallel_copy FROM stdin WITH(PARALLEL 1) WHERE a = row_number() over(b);
+
+-- check results of copy in
+SELECT * FROM test_parallel_copy ORDER BY 1;
+
+-- parallel copy test for unlogged tables. should execute in parallel worker
+CREATE UNLOGGED TABLE test_parallel_copy_unlogged(
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+);
+
+COPY test_parallel_copy_unlogged FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+SELECT count(*) FROM test_parallel_copy_unlogged;
+
+-- parallel copy test for various trigger types
+TRUNCATE test_parallel_copy;
+
+-- parallel safe trigger function
+CREATE OR REPLACE FUNCTION parallel_copy_trig_func() RETURNS TRIGGER
+LANGUAGE plpgsql PARALLEL SAFE AS $$
+BEGIN
+  RETURN NEW;
+END;
+$$;
+
+-- before insert row trigger
+CREATE TRIGGER parallel_copy_trig
+BEFORE INSERT ON test_parallel_copy
+FOR EACH ROW
+EXECUTE PROCEDURE parallel_copy_trig_func();
+
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+
+-- after insert row trigger
+CREATE TRIGGER parallel_copy_trig
+AFTER INSERT ON test_parallel_copy
+FOR EACH ROW
+EXECUTE PROCEDURE parallel_copy_trig_func();
+
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+
+-- before insert statement trigger
+CREATE TRIGGER parallel_copy_trig
+BEFORE INSERT ON test_parallel_copy
+FOR EACH STATEMENT
+EXECUTE PROCEDURE parallel_copy_trig_func();
+
+-- parallelism should be picked, since the trigger function is parallel safe
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+
+-- after insert statement trigger
+CREATE TRIGGER parallel_copy_trig
+AFTER INSERT ON test_parallel_copy
+FOR EACH STATEMENT
+EXECUTE PROCEDURE parallel_copy_trig_func();
+
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+
+-- transition table is involved
+CREATE TRIGGER parallel_copy_trig
+AFTER INSERT ON test_parallel_copy REFERENCING NEW TABLE AS new_table
+FOR EACH STATEMENT
+EXECUTE PROCEDURE parallel_copy_trig_func();
+
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+
+-- make trigger function parallel unsafe
+ALTER FUNCTION parallel_copy_trig_func PARALLEL UNSAFE;
+
+-- before statement trigger has a parallel unsafe function
+CREATE TRIGGER parallel_copy_trig
+BEFORE INSERT ON test_parallel_copy
+FOR EACH STATEMENT
+EXECUTE PROCEDURE parallel_copy_trig_func();
+
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+SELECT count(*) FROM test_parallel_copy;
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+
+-- instead of insert trigger, no parallelism should be picked
+COPY instead_of_insert_tbl_view FROM stdin WITH(PARALLEL 1);;
+test1
+\.
+
+SELECT count(*) FROM instead_of_insert_tbl_view;
+
+-- parallel copy test for a partitioned table with a before insert trigger on
+-- one of the partition
+ALTER FUNCTION parallel_copy_trig_func PARALLEL SAFE;
+
+CREATE TABLE test_parallel_copy_part (
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+) PARTITION BY LIST (b);
+
+CREATE TABLE test_parallel_copy_part_a1 (c TEXT, b INT, a INT, e TEXT, d TEXT);
+
+CREATE TABLE test_parallel_copy_part_a2 (a INT, c TEXT, b INT, d TEXT, e TEXT);
+
+ALTER TABLE test_parallel_copy_part ATTACH PARTITION test_parallel_copy_part_a1 FOR VALUES IN(1);
+
+ALTER TABLE test_parallel_copy_part ATTACH PARTITION test_parallel_copy_part_a2 FOR VALUES IN(2);
+
+CREATE TRIGGER parallel_copy_trig
+BEFORE INSERT ON test_parallel_copy_part_a2
+FOR EACH ROW
+EXECUTE PROCEDURE parallel_copy_trig_func();
+
+COPY test_parallel_copy_part FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+SELECT count(*) FROM test_parallel_copy_part;
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy_part_a2;
+
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE test_parallel_copy_unlogged;
+DROP TABLE test_parallel_copy_part;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
+DROP FUNCTION parallel_copy_trig_func();
 DROP TABLE x, y;
 DROP TABLE rls_t1 CASCADE;
 DROP ROLE regress_rls_copy_user;
-- 
1.8.3.1

v7-0006-Parallel-Copy-For-Binary-Format-Files.patchtext/x-patch; charset=US-ASCII; name=v7-0006-Parallel-Copy-For-Binary-Format-Files.patchDownload
From f2f82a6018937a594eea9b3f3d9b9c23be9b4b66 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 14 Oct 2020 12:49:48 +0530
Subject: [PATCH v7 6/6] Parallel Copy For Binary Format Files

Leader reads data from the file into the DSM data blocks each of 64K size.
It also identifies each tuple data block id, start offset, end offset,
tuple size and updates this information in the ring data structure.
Workers parallelly read the tuple information from the ring data structure,
the actual tuple data from the data blocks and parallelly insert the tuples
into the table.
---
 src/backend/commands/copy.c         | 126 ++++++-------
 src/backend/commands/copyparallel.c | 367 ++++++++++++++++++++++++++++++++++--
 src/include/commands/copy.h         | 126 +++++++++++++
 3 files changed, 531 insertions(+), 88 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 9a026be..44e0aa4 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -222,19 +222,14 @@ static void CopySendData(CopyState cstate, const void *databuf, int datasize);
 static void CopySendString(CopyState cstate, const char *str);
 static void CopySendChar(CopyState cstate, char c);
 static void CopySendEndOfRow(CopyState cstate);
-static int	CopyGetData(CopyState cstate, void *databuf,
-						int minread, int maxread);
 static void CopySendInt32(CopyState cstate, int32 val);
 static bool CopyGetInt32(CopyState cstate, int32 *val);
 static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 static bool CopyLoadRawBuf(CopyState cstate);
-static int	CopyReadBinaryData(CopyState cstate, char *dest, int nbytes);
-
 static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
 								   int copy_line_pos, int *copy_line_size);
 
-
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
  * in past protocol redesigns.
@@ -448,7 +443,7 @@ CopySendEndOfRow(CopyState cstate)
  *
  * NB: no data conversion is applied here.
  */
-static int
+int
 CopyGetData(CopyState cstate, void *databuf, int minread, int maxread)
 {
 	int			bytesread = 0;
@@ -581,10 +576,25 @@ CopyGetInt32(CopyState cstate, int32 *val)
 {
 	uint32		buf;
 
-	if (CopyReadBinaryData(cstate, (char *) &buf, sizeof(buf)) != sizeof(buf))
+	/*
+	 * For parallel copy, avoid reading data to raw buf, read directly from
+	 * file, later the data will be read to parallel copy data buffers.
+	 */
+	if (cstate->nworkers > 0)
 	{
-		*val = 0;				/* suppress compiler warning */
-		return false;
+		if (CopyGetData(cstate, &buf, sizeof(buf), sizeof(buf)) != sizeof(buf))
+		{
+			*val = 0;			/* suppress compiler warning */
+			return false;
+		}
+	}
+	else
+	{
+		if (CopyReadBinaryData(cstate, (char *) &buf, sizeof(buf)) != sizeof(buf))
+		{
+			*val = 0;			/* suppress compiler warning */
+			return false;
+		}
 	}
 	*val = (int32) pg_ntoh32(buf);
 	return true;
@@ -658,7 +668,7 @@ CopyLoadRawBuf(CopyState cstate)
  * and writes them to 'dest'.  Returns the number of bytes read (which
  * would be less than 'nbytes' only if we reach EOF).
  */
-static int
+int
 CopyReadBinaryData(CopyState cstate, char *dest, int nbytes)
 {
 	int			copied_bytes = 0;
@@ -3563,7 +3573,7 @@ BeginCopyFrom(ParseState *pstate,
 		int32		tmp;
 
 		/* Signature */
-		if (CopyReadBinaryData(cstate, readSig, 11) != 11 ||
+		if (CopyGetData(cstate, readSig, 11, 11) != 11 ||
 			memcmp(readSig, BinarySignature, 11) != 0)
 			ereport(ERROR,
 					(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
@@ -3591,7 +3601,7 @@ BeginCopyFrom(ParseState *pstate,
 		/* Skip extension header, if present */
 		while (tmp-- > 0)
 		{
-			if (CopyReadBinaryData(cstate, readSig, 1) != 1)
+			if (CopyGetData(cstate, readSig, 1, 1) != 1)
 				ereport(ERROR,
 						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
 						 errmsg("invalid COPY file header (wrong length)")));
@@ -3788,60 +3798,45 @@ NextCopyFrom(CopyState cstate, ExprContext *econtext,
 	else
 	{
 		/* binary */
-		int16		fld_count;
-		ListCell   *cur;
-
 		cstate->cur_lineno++;
+		cstate->max_fields = list_length(cstate->attnumlist);
 
-		if (!CopyGetInt16(cstate, &fld_count))
+		if (!IsParallelCopy())
 		{
-			/* EOF detected (end of file, or protocol-level EOF) */
-			return false;
-		}
-
-		if (fld_count == -1)
-		{
-			/*
-			 * Received EOF marker.  In a V3-protocol copy, wait for the
-			 * protocol-level EOF, and complain if it doesn't come
-			 * immediately.  This ensures that we correctly handle CopyFail,
-			 * if client chooses to send that now.
-			 *
-			 * Note that we MUST NOT try to read more data in an old-protocol
-			 * copy, since there is no protocol-level EOF marker then.  We
-			 * could go either way for copy from file, but choose to throw
-			 * error if there's data after the EOF marker, for consistency
-			 * with the new-protocol case.
-			 */
-			char		dummy;
+			int16		fld_count;
+			ListCell   *cur;
 
-			if (cstate->copy_dest != COPY_OLD_FE &&
-				CopyReadBinaryData(cstate, &dummy, 1) > 0)
-				ereport(ERROR,
-						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-						 errmsg("received copy data after EOF marker")));
-			return false;
-		}
+			if (!CopyGetInt16(cstate, &fld_count))
+			{
+				/* EOF detected (end of file, or protocol-level EOF) */
+				return false;
+			}
 
-		if (fld_count != attr_count)
-			ereport(ERROR,
-					(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-					 errmsg("row field count is %d, expected %d",
-							(int) fld_count, attr_count)));
+			CHECK_FIELD_COUNT;
 
-		foreach(cur, cstate->attnumlist)
+			foreach(cur, cstate->attnumlist)
+			{
+				int			attnum = lfirst_int(cur);
+				int			m = attnum - 1;
+				Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+
+				cstate->cur_attname = NameStr(att->attname);
+				values[m] = CopyReadBinaryAttribute(cstate,
+													&in_functions[m],
+													typioparams[m],
+													att->atttypmod,
+													&nulls[m]);
+				cstate->cur_attname = NULL;
+			}
+		}
+		else
 		{
-			int			attnum = lfirst_int(cur);
-			int			m = attnum - 1;
-			Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+			bool		eof = false;
 
-			cstate->cur_attname = NameStr(att->attname);
-			values[m] = CopyReadBinaryAttribute(cstate,
-												&in_functions[m],
-												typioparams[m],
-												att->atttypmod,
-												&nulls[m]);
-			cstate->cur_attname = NULL;
+			eof = CopyReadBinaryTupleWorker(cstate, values, nulls);
+
+			if (eof)
+				return false;
 		}
 	}
 
@@ -4852,18 +4847,15 @@ CopyReadBinaryAttribute(CopyState cstate, FmgrInfo *flinfo,
 	Datum		result;
 
 	if (!CopyGetInt32(cstate, &fld_size))
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("unexpected EOF in COPY data")));
+		EOF_ERROR;
+
 	if (fld_size == -1)
 	{
 		*isnull = true;
 		return ReceiveFunctionCall(flinfo, NULL, typioparam, typmod);
 	}
-	if (fld_size < 0)
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("invalid field size")));
+
+	CHECK_FIELD_SIZE(fld_size);
 
 	/* reset attribute_buf to empty, and load raw data in it */
 	resetStringInfo(&cstate->attribute_buf);
@@ -4871,9 +4863,7 @@ CopyReadBinaryAttribute(CopyState cstate, FmgrInfo *flinfo,
 	enlargeStringInfo(&cstate->attribute_buf, fld_size);
 	if (CopyReadBinaryData(cstate, cstate->attribute_buf.data,
 						   fld_size) != fld_size)
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("unexpected EOF in COPY data")));
+		EOF_ERROR;
 
 	cstate->attribute_buf.len = fld_size;
 	cstate->attribute_buf.data[fld_size] = '\0';
diff --git a/src/backend/commands/copyparallel.c b/src/backend/commands/copyparallel.c
index 9cae112..3e17e82 100644
--- a/src/backend/commands/copyparallel.c
+++ b/src/backend/commands/copyparallel.c
@@ -100,6 +100,7 @@ SerializeParallelCopyState(ParallelContext *pcxt, CopyState cstate,
 	shared_cstate.convert_selectively = cstate->convert_selectively;
 	shared_cstate.num_defaults = cstate->num_defaults;
 	shared_cstate.relid = cstate->pcdata->relid;
+	shared_cstate.binary = cstate->binary;
 
 	memcpy(shmptr, (char *) &shared_cstate, sizeof(SerializedParallelCopyState));
 	copiedsize = sizeof(SerializedParallelCopyState);
@@ -204,6 +205,7 @@ RestoreParallelCopyState(shm_toc *toc, CopyState cstate, List **attlist)
 	cstate->convert_selectively = shared_cstate.convert_selectively;
 	cstate->num_defaults = shared_cstate.num_defaults;
 	cstate->pcdata->relid = shared_cstate.relid;
+	cstate->binary = shared_cstate.binary;
 
 	cstate->null_print = CopyStringFromSharedMemory(shared_str_val + copiedsize,
 													&copiedsize);
@@ -403,7 +405,7 @@ bool
 IsParallelCopyAllowed(CopyState cstate)
 {
 	/* Parallel copy not allowed for frontend (2.0 protocol) & binary option. */
-	if ((cstate->copy_dest == COPY_OLD_FE) || cstate->binary)
+	if (cstate->copy_dest == COPY_OLD_FE)
 		return false;
 
 	/*
@@ -620,6 +622,7 @@ InitializeParallelCopyInfo(CopyState cstate, List *attnamelist)
 	cstate->cur_lineno = 0;
 	cstate->cur_attname = NULL;
 	cstate->cur_attval = NULL;
+	cstate->pcdata->curr_data_block = NULL;
 
 	/* Set up variables to avoid per-attribute overhead. */
 	initStringInfo(&cstate->attribute_buf);
@@ -842,7 +845,11 @@ return_line:
 
 	/* Mark that encoding conversion hasn't occurred yet. */
 	cstate->line_buf_converted = false;
-	ConvertToServerEncoding(cstate);
+
+	/* For binary format data, we don't need conversion. */
+	if (!cstate->binary)
+		ConvertToServerEncoding(cstate);
+
 	pcdata->worker_line_buf_pos++;
 	return false;
 }
@@ -998,33 +1005,70 @@ ParallelCopyFrom(CopyState cstate)
 	/* Execute the before statement triggers from the leader */
 	ExecBeforeStmtTrigger(cstate);
 
-	/* On input just throw the header line away. */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (!cstate->binary)
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
+		/* On input just throw the header line away. */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
 		{
-			pcshared_info->is_read_in_progress = false;
-			return;				/* done */
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+			{
+				pcshared_info->is_read_in_progress = false;
+				return;			/* done */
+			}
 		}
-	}
 
-	for (;;)
-	{
-		bool		done;
+		for (;;)
+		{
+			bool		done;
 
-		cstate->cur_lineno++;
+			cstate->cur_lineno++;
 
-		/* Actually read the line into memory here. */
-		done = CopyReadLine(cstate);
+			/* Actually read the line into memory here. */
+			done = CopyReadLine(cstate);
 
+			/*
+			 * EOF at start of line means we're done.  If we see EOF after
+			 * some characters, we act as though it was newline followed by
+			 * EOF, ie, process the line and then exit loop on next iteration.
+			 */
+			if (done && cstate->line_buf.len == 0)
+				break;
+		}
+	}
+	else
+	{
 		/*
-		 * EOF at start of line means we're done.  If we see EOF after some
-		 * characters, we act as though it was newline followed by EOF, ie,
-		 * process the line and then exit loop on next iteration.
+		 * Binary Format Files. In parallel copy leader, fill in the error
+		 * context information here, in case any failures while determining
+		 * tuple offsets, leader would throw the errors with proper context.
 		 */
-		if (done && cstate->line_buf.len == 0)
-			break;
+		ErrorContextCallback errcallback;
+
+		errcallback.callback = CopyFromErrorCallback;
+		errcallback.arg = (void *) cstate;
+		errcallback.previous = error_context_stack;
+		error_context_stack = &errcallback;
+		cstate->pcdata->curr_data_block = NULL;
+		cstate->raw_buf_index = 0;
+		pcshared_info->populated = 0;
+		cstate->cur_lineno = 0;
+		cstate->max_fields = list_length(cstate->attnumlist);
+
+		for (;;)
+		{
+			bool		eof = false;
+
+			cstate->cur_lineno++;
+
+			eof = CopyReadBinaryTupleLeader(cstate);
+
+			if (eof)
+				break;
+		}
+
+		/* Reset the error context. */
+		error_context_stack = errcallback.previous;
 	}
 
 	pcshared_info->is_read_in_progress = false;
@@ -1032,6 +1076,289 @@ ParallelCopyFrom(CopyState cstate)
 }
 
 /*
+ * CopyReadBinaryGetDataBlock
+ *
+ * Gets a new block, updates the current offset, calculates the skip bytes.
+ */
+void
+CopyReadBinaryGetDataBlock(CopyState cstate, FieldInfoType field_info)
+{
+	ParallelCopyDataBlock *data_block = NULL;
+	ParallelCopyDataBlock *curr_data_block = cstate->pcdata->curr_data_block;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	uint8		move_bytes = 0;
+	uint32		block_pos;
+	uint32		prev_block_pos;
+	int			read_bytes = 0;
+
+	prev_block_pos = pcshared_info->cur_block_pos;
+
+	block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+	if (field_info == FIELD_SIZE || field_info == FIELD_COUNT)
+		move_bytes = (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+
+	if (curr_data_block != NULL)
+		curr_data_block->skip_bytes = move_bytes;
+
+	data_block = &pcshared_info->data_blocks[block_pos];
+
+	if (move_bytes > 0 && curr_data_block != NULL)
+		memmove(&data_block->data[0], &curr_data_block->data[cstate->raw_buf_index], move_bytes);
+
+	elog(DEBUG1, "LEADER - field info %d is spread across data blocks - moved %d bytes from current block %u to %u block",
+		 field_info, move_bytes, prev_block_pos, block_pos);
+
+	read_bytes = CopyGetData(cstate, &data_block->data[move_bytes], 1, (DATA_BLOCK_SIZE - move_bytes));
+
+	if (field_info == FIELD_NONE && cstate->reached_eof)
+		return;
+
+	if (cstate->reached_eof)
+		EOF_ERROR;
+
+	elog(DEBUG1, "LEADER - bytes read from file %d", read_bytes);
+
+	if (field_info == FIELD_SIZE || field_info == FIELD_DATA)
+	{
+		ParallelCopyDataBlock *prev_data_block = NULL;
+
+		prev_data_block = curr_data_block;
+		prev_data_block->following_block = block_pos;
+
+		if (prev_data_block->curr_blk_completed == false)
+			prev_data_block->curr_blk_completed = true;
+
+		pg_atomic_add_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+	}
+
+	cstate->pcdata->curr_data_block = data_block;
+	cstate->raw_buf_index = 0;
+}
+
+/*
+ * CopyReadBinaryTupleLeader
+ *
+ * Leader reads data from binary formatted file to data blocks and identifies
+ * tuple boundaries/offsets so that workers can work on the data blocks data.
+ */
+bool
+CopyReadBinaryTupleLeader(CopyState cstate)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	int16		fld_count;
+	uint32		line_size = 0;
+	uint32		start_block_pos;
+	uint32		start_offset;
+
+	if (cstate->pcdata->curr_data_block == NULL)
+	{
+		CopyReadBinaryGetDataBlock(cstate, FIELD_NONE);
+
+		/*
+		 * no data is read from file here. one possibility to be here could be
+		 * that the binary file just has a valid signature but nothing else.
+		 */
+		if (cstate->reached_eof)
+			return true;
+	}
+
+	if ((cstate->raw_buf_index + sizeof(fld_count)) >= DATA_BLOCK_SIZE)
+		CopyReadBinaryGetDataBlock(cstate, FIELD_COUNT);
+
+	memcpy(&fld_count, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_count));
+	fld_count = (int16) pg_ntoh16(fld_count);
+
+	CHECK_FIELD_COUNT;
+
+	start_offset = cstate->raw_buf_index;
+	cstate->raw_buf_index += sizeof(fld_count);
+	line_size += sizeof(fld_count);
+	start_block_pos = pcshared_info->cur_block_pos;
+
+	CopyReadBinaryFindTupleSize(cstate, &line_size);
+
+	pg_atomic_add_fetch_u32(&cstate->pcdata->curr_data_block->unprocessed_line_parts, 1);
+
+	if (line_size > 0)
+		(void) UpdateSharedLineInfo(cstate, start_block_pos, start_offset,
+									line_size, LINE_LEADER_POPULATED, -1);
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryFindTupleSize
+ *
+ * Leader identifies boundaries/offsets for each attribute/column and finally
+ * results in the tuple/row size. It moves on to next data block if the
+ * attribute/column is spread across data blocks.
+ */
+void
+CopyReadBinaryFindTupleSize(CopyState cstate, uint32 *line_size)
+{
+	int32		fld_size;
+	ListCell   *cur;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			att_num = lfirst_int(cur);
+		Form_pg_attribute att = TupleDescAttr(tup_desc, (att_num - 1));
+
+		cstate->cur_attname = NameStr(att->attname);
+		fld_size = 0;
+
+		if ((cstate->raw_buf_index + sizeof(fld_size)) >= DATA_BLOCK_SIZE)
+			CopyReadBinaryGetDataBlock(cstate, FIELD_SIZE);
+
+		memcpy(&fld_size, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_size));
+		cstate->raw_buf_index += sizeof(fld_size);
+		*line_size += sizeof(fld_size);
+		fld_size = (int32) pg_ntoh32(fld_size);
+
+		/* fld_size -1 represents the null value for the field. */
+		if (fld_size == -1)
+			continue;
+
+		CHECK_FIELD_SIZE(fld_size);
+
+		*line_size += fld_size;
+
+		if ((DATA_BLOCK_SIZE - cstate->raw_buf_index) >= fld_size)
+		{
+			cstate->raw_buf_index += fld_size;
+			elog(DEBUG1, "LEADER - tuple lies in he same data block");
+		}
+		else
+		{
+			int32		required_blks = 0;
+			int32		curr_blk_bytes = (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+			int			i = 0;
+
+			GET_REQUIRED_BLOCKS(required_blks, fld_size, curr_blk_bytes);
+
+			i = required_blks;
+
+			while (i > 0)
+			{
+				CopyReadBinaryGetDataBlock(cstate, FIELD_DATA);
+				i--;
+			}
+
+			GET_RAW_BUF_INDEX(cstate->raw_buf_index, fld_size, required_blks, curr_blk_bytes);
+
+			/*
+			 * raw_buf_index should never cross data block size, as the
+			 * required number of data blocks would have been obtained in the
+			 * above while loop.
+			 */
+			Assert(cstate->raw_buf_index <= DATA_BLOCK_SIZE);
+		}
+		cstate->cur_attname = NULL;
+	}
+}
+
+/*
+ * CopyReadBinaryTupleWorker
+ *
+ * Each worker reads data from data blocks caches the tuple data into local
+ * memory.
+ */
+bool
+CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls)
+{
+	int16		fld_count;
+	ListCell   *cur;
+	FmgrInfo   *in_functions = cstate->in_functions;
+	Oid		   *typioparams = cstate->typioparams;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+	bool 		done = false;
+
+	done = GetWorkerLine(cstate);
+	cstate->raw_buf_index = 0;
+
+	if (done && cstate->line_buf.len == 0)
+		return true;
+
+	memcpy(&fld_count, &cstate->line_buf.data[cstate->raw_buf_index], sizeof(fld_count));
+	fld_count = (int16) pg_ntoh16(fld_count);
+
+	CHECK_FIELD_COUNT;
+
+	cstate->raw_buf_index += sizeof(fld_count);
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			att_num = lfirst_int(cur);
+		int			m = att_num - 1;
+		Form_pg_attribute att = TupleDescAttr(tup_desc, m);
+
+		cstate->cur_attname = NameStr(att->attname);
+
+		values[m] = CopyReadBinaryAttributeWorker(cstate,
+												  &in_functions[m],
+												  typioparams[m],
+												  att->atttypmod,
+												  &nulls[m]);
+		cstate->cur_attname = NULL;
+	}
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryAttributeWorker
+ *
+ * Worker identifies and converts each attribute/column data from binary to
+ * the data type of attribute/column.
+ */
+Datum
+CopyReadBinaryAttributeWorker(CopyState cstate, FmgrInfo *flinfo,
+							  Oid typioparam, int32 typmod, bool *isnull)
+{
+	int32		fld_size;
+	Datum		result;
+
+	memcpy(&fld_size, &cstate->line_buf.data[cstate->raw_buf_index], sizeof(fld_size));
+	cstate->raw_buf_index += sizeof(fld_size);
+	fld_size = (int32) pg_ntoh32(fld_size);
+
+	/* fld_size -1 represents the null value for the field. */
+	if (fld_size == -1)
+	{
+		*isnull = true;
+		return ReceiveFunctionCall(flinfo, NULL, typioparam, typmod);
+	}
+
+	CHECK_FIELD_SIZE(fld_size);
+
+	/* Reset attribute_buf to empty, and load raw data in it */
+	resetStringInfo(&cstate->attribute_buf);
+
+	enlargeStringInfo(&cstate->attribute_buf, fld_size);
+
+	memcpy(&cstate->attribute_buf.data[0], &cstate->line_buf.data[cstate->raw_buf_index], fld_size);
+	cstate->raw_buf_index += fld_size;
+
+	cstate->attribute_buf.len = fld_size;
+	cstate->attribute_buf.data[fld_size] = '\0';
+
+	/* Call the column type's binary input converter */
+	result = ReceiveFunctionCall(flinfo, &cstate->attribute_buf,
+								 typioparam, typmod);
+
+	/* Trouble if it didn't eat the whole buffer */
+	if (cstate->attribute_buf.cursor != cstate->attribute_buf.len)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+				 errmsg("incorrect binary data format")));
+
+	*isnull = false;
+	return result;
+}
+
+/*
  * GetLinePosition
  *
  * Return the line position once the leader has populated the data.
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index 9b19dcb..49f438f 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -59,6 +59,109 @@
 
 
 /*
+ * CHECK_FIELD_COUNT - Handles the error cases for field count
+ * for binary format files.
+ */
+#define CHECK_FIELD_COUNT \
+{\
+	if (fld_count == -1) \
+	{ \
+		if (IsParallelCopy() && \
+			!IsLeader()) \
+			return true; \
+		else if (IsParallelCopy() && \
+			IsLeader()) \
+		{ \
+			if (cstate->pcdata->curr_data_block->data[cstate->raw_buf_index + sizeof(fld_count)] != 0) \
+				ereport(ERROR, \
+						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+						errmsg("received copy data after EOF marker"))); \
+			return true; \
+		} \
+		else \
+		{ \
+			/* \
+			 * Received EOF marker.  In a V3-protocol copy, wait for the \
+			 * protocol-level EOF, and complain if it doesn't come \
+			 * immediately.  This ensures that we correctly handle CopyFail, \
+			 * if client chooses to send that now. \
+			 * \
+			 * Note that we MUST NOT try to read more data in an old-protocol \
+			 * copy, since there is no protocol-level EOF marker then.  We \
+			 * could go either way for copy from file, but choose to throw \
+			 * error if there's data after the EOF marker, for consistency \
+			 * with the new-protocol case. \
+			 */ \
+			char		dummy; \
+			if (cstate->copy_dest != COPY_OLD_FE && \
+				CopyReadBinaryData(cstate, &dummy, 1) > 0) \
+				ereport(ERROR, \
+						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+						errmsg("received copy data after EOF marker"))); \
+				return false; \
+		} \
+	} \
+	if (fld_count != cstate->max_fields) \
+		ereport(ERROR, \
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+				errmsg("row field count is %d, expected %d", \
+				(int) fld_count, cstate->max_fields))); \
+}
+
+/*
+ * CHECK_FIELD_SIZE - Handles the error case for field size
+ * for binary format files.
+ */
+#define CHECK_FIELD_SIZE(fld_size) \
+{ \
+	if (fld_size < -1) \
+		ereport(ERROR, \
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+				errmsg("invalid field size")));\
+}
+
+/*
+ * EOF_ERROR - Error statement for EOF for binary format
+ * files.
+ */
+#define EOF_ERROR \
+{ \
+	ereport(ERROR, \
+		(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+		errmsg("unexpected EOF in COPY data")));\
+}
+
+/*
+ * GET_RAW_BUF_INDEX - Calculates the raw buf index for the cases
+ * where the data spread is across multiple data blocks.
+ */
+#define GET_RAW_BUF_INDEX(raw_buf_index, fld_size, required_blks, curr_blk_bytes) \
+{ \
+	raw_buf_index = fld_size - (((required_blks - 1) * DATA_BLOCK_SIZE) + curr_blk_bytes); \
+}
+
+/*
+ * GET_REQUIRED_BLOCKS - Calculates the number of data
+ * blocks required for the cases where the data spread
+ * is across multiple data blocks.
+ */
+#define GET_REQUIRED_BLOCKS(required_blks, fld_size, curr_blk_bytes) \
+{ \
+	/* \
+	 * field size can spread across multiple data blocks, \
+	 * calculate the number of required data blocks and try to get \
+	 * those many data blocks. \
+	 */ \
+	required_blks = (int32)(fld_size - curr_blk_bytes)/(int32)DATA_BLOCK_SIZE; \
+	/* \
+	 * check if we need the data block for the field data \
+	 * bytes that are not modulus of data block size. \
+	 */ \
+	if ((fld_size - curr_blk_bytes)%DATA_BLOCK_SIZE != 0) \
+		required_blks++; \
+}
+
+/*
  * Represents the different source/dest cases we need to worry about at
  * the bottom level
  */
@@ -236,6 +339,17 @@ typedef struct ParallelCopyLineBuf
 } ParallelCopyLineBuf;
 
 /*
+ * Represents the usage mode for CopyReadBinaryGetDataBlock.
+ */
+typedef enum FieldInfoType
+{
+	FIELD_NONE = 0,
+	FIELD_COUNT,
+	FIELD_SIZE,
+	FIELD_DATA
+}			FieldInfoType;
+
+/*
  * This structure helps in storing the common data from CopyStateData that are
  * required by the workers. This information will then be allocated and stored
  * into the DSM for the worker to retrieve and copy it to CopyStateData.
@@ -258,6 +372,7 @@ typedef struct SerializedParallelCopyState
 	/* Working state for COPY FROM */
 	AttrNumber	num_defaults;
 	Oid			relid;
+	bool		binary;
 } SerializedParallelCopyState;
 
 /*
@@ -284,6 +399,9 @@ typedef struct ParallelCopyData
 
 	/* Current position in worker_line_buf */
 	uint32		worker_line_buf_pos;
+
+	/* For binary formatted files */
+	ParallelCopyDataBlock *curr_data_block;
 } ParallelCopyData;
 
 typedef int (*copy_data_source_cb) (void *outbuf, int minread, int maxread);
@@ -470,4 +588,12 @@ extern uint32 UpdateSharedLineInfo(CopyState cstate, uint32 blk_pos, uint32 offs
 								   uint32 line_size, uint32 line_state, uint32 blk_line_pos);
 extern void EndLineParallelCopy(CopyState cstate, uint32 line_pos, uint32 line_size,
 								uint32 raw_buf_ptr);
+extern int	CopyGetData(CopyState cstate, void *databuf, int minread, int maxread);
+extern int	CopyReadBinaryData(CopyState cstate, char *dest, int nbytes);
+extern bool CopyReadBinaryTupleLeader(CopyState cstate);
+extern bool CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls);
+extern void CopyReadBinaryFindTupleSize(CopyState cstate, uint32 *line_size);
+extern Datum CopyReadBinaryAttributeWorker(CopyState cstate, FmgrInfo *flinfo,
+										   Oid typioparam, int32 typmod, bool *isnull);
+extern void CopyReadBinaryGetDataBlock(CopyState cstate, FieldInfoType field_info);
 #endif							/* COPY_H */
-- 
1.8.3.1

#174Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Amit Kapila (#170)
Re: Parallel copy

I did performance testing on v7 patch set[1]/messages/by-id/CALDaNm1n1xW43neXSGs=c7zt-mj+JHHbubWBVDYT9NfCoF8TuQ@mail.gmail.com with custom
postgresql.conf[2]shared_buffers = 40GB max_worker_processes = 32 max_parallel_maintenance_workers = 24 max_parallel_workers = 32 synchronous_commit = off checkpoint_timeout = 1d max_wal_size = 24GB min_wal_size = 15GB autovacuum = off. The results are of the triplet form (exec time in
sec, number of workers, gain)

Use case 1: 10million rows, 5.2GB data, 2 indexes on integer columns,
1 index on text column, binary file
(1104.898, 0, 1X), (1112.221, 1, 1X), (640.236, 2, 1.72X), (335.090,
4, 3.3X), (200.492, 8, 5.51X), (131.448, 16, 8.4X), (121.832, 20,
9.1X), (124.287, 30, 8.9X)

Use case 2: 10million rows, 5.2GB data,2 indexes on integer columns, 1
index on text column, copy from stdin, csv format
(1203.282, 0, 1X), (1135.517, 1, 1.06X), (655.140, 2, 1.84X),
(343.688, 4, 3.5X), (203.742, 8, 5.9X), (144.793, 16, 8.31X),
(133.339, 20, 9.02X), (136.672, 30, 8.8X)

Use case 3: 10million rows, 5.2GB data,2 indexes on integer columns, 1
index on text column, text file
(1165.991, 0, 1X), (1128.599, 1, 1.03X), (644.793, 2, 1.81X),
(342.813, 4, 3.4X), (204.279, 8, 5.71X), (139.986, 16, 8.33X),
(128.259, 20, 9.1X), (132.764, 30, 8.78X)

Above results are similar to the results with earlier versions of the patch set.

On Fri, Oct 9, 2020 at 3:26 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

Sure, you need to change the code such that when force_parallel_mode =
'regress' is specified then it always uses one worker. This is
primarily for testing purposes and will help during the development of
this patch as it will make all exiting Copy tests to use quite a good
portion of the parallel infrastructure.

I performed force_parallel_mode = regress testing and found 2 issues,
the fixes for the same are available in v7 patch set[1]/messages/by-id/CALDaNm1n1xW43neXSGs=c7zt-mj+JHHbubWBVDYT9NfCoF8TuQ@mail.gmail.com.

Overall, we have below test cases to cover the code and for performance measurements. We plan to run these tests whenever a new set of patches is posted.

1. csv
2. binary

Don't we need the tests for plain text files as well?

I added a text use case and above mentioned are perf results on v7 patch set[1]/messages/by-id/CALDaNm1n1xW43neXSGs=c7zt-mj+JHHbubWBVDYT9NfCoF8TuQ@mail.gmail.com.

3. force parallel mode = regress
4. toast data csv and binary
5. foreign key check, before row, after row, before statement, after statement, instead of triggers
6. partition case
7. foreign partitions and partitions having trigger cases
8. where clause having parallel unsafe and safe expression, default parallel unsafe and safe expression
9. temp, global, local, unlogged, inherited tables cases, foreign tables

Sounds like good coverage. So, are you doing all this testing
manually? How are you maintaining these tests?

All test cases listed above, except for the cases that are meant to
measure perf gain with huge data, are present in v7-0005 patch in v7
patch set[1]/messages/by-id/CALDaNm1n1xW43neXSGs=c7zt-mj+JHHbubWBVDYT9NfCoF8TuQ@mail.gmail.com.

[1]: /messages/by-id/CALDaNm1n1xW43neXSGs=c7zt-mj+JHHbubWBVDYT9NfCoF8TuQ@mail.gmail.com

[2]: shared_buffers = 40GB max_worker_processes = 32 max_parallel_maintenance_workers = 24 max_parallel_workers = 32 synchronous_commit = off checkpoint_timeout = 1d max_wal_size = 24GB min_wal_size = 15GB autovacuum = off
shared_buffers = 40GB
max_worker_processes = 32
max_parallel_maintenance_workers = 24
max_parallel_workers = 32
synchronous_commit = off
checkpoint_timeout = 1d
max_wal_size = 24GB
min_wal_size = 15GB
autovacuum = off

With Regards,
Bharath Rupireddy.
EnterpriseDB: http://www.enterprisedb.com

#175vignesh C
vignesh21@gmail.com
In reply to: Amit Kapila (#165)
Re: Parallel copy

On Fri, Oct 9, 2020 at 10:42 AM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Thu, Oct 8, 2020 at 12:14 AM vignesh C <vignesh21@gmail.com> wrote:

On Mon, Sep 28, 2020 at 12:19 PM Amit Kapila <amit.kapila16@gmail.com>

wrote:

I am convinced by the reason given by Kyotaro-San in that another
thread [1] and performance data shown by Peter that this can't be an
independent improvement and rather in some cases it can do harm. Now,
if you need it for a parallel-copy path then we can change it
specifically to the parallel-copy code path but I don't understand
your reason completely.

Whenever we need data to be populated, we will get a new data block &
pass it to CopyGetData to populate the data. In case of file copy, the
server will completely fill the data block. We expect the data to be
filled completely. If data is available it will completely load the
complete data block in case of file copy. There is no scenario where
even if data is present a partial data block will be returned except
for EOF or no data available. But in case of STDIN data copy, even
though there is 8K data available in data block & 8K data available in
STDIN, CopyGetData will return as soon as libpq buffer data is more
than the minread. We will pass new data block every time to load data.
Every time we pass an 8K data block but CopyGetData loads a few bytes
in the new data block & returns. I wanted to keep the same data
population logic for both file copy & STDIN copy i.e copy full 8K data
blocks & then the populated data can be required. There is an
alternative solution I can have some special handling in case of STDIN
wherein the existing data block can be passed with the index from
where the data should be copied. Thoughts?

What you are proposing as an alternative solution, isn't that what we
are doing without the patch? IIUC, you require this because of your
corresponding changes to handle COPY_NEW_FE in CopyReadLine(), is that
right? If so, what is the difficulty in making it behave similar to
the non-parallel case?

The alternate solution is similar to how existing copy handles STDIN
copies, I have made changes in the v7 patch attached in [1]/messages/by-id/CALDaNm1n1xW43neXSGs=c7zt-mj+JHHbubWBVDYT9NfCoF8TuQ@mail.gmail.com to have
parallel copy handle STDIN data similar to non parallel copy, so the
original comment on why this change is required has been removed from 001
patch:

+ if (cstate->copy_dest == COPY_NEW_FE)
+ minread = RAW_BUF_SIZE - nbytes;
+
inbytes = CopyGetData(cstate, cstate->raw_buf + nbytes,
-   1, RAW_BUF_SIZE - nbytes);
+   minread, RAW_BUF_SIZE - nbytes);

No comment to explain why this change is done?

[1]: /messages/by-id/CALDaNm1n1xW43neXSGs=c7zt-mj+JHHbubWBVDYT9NfCoF8TuQ@mail.gmail.com
/messages/by-id/CALDaNm1n1xW43neXSGs=c7zt-mj+JHHbubWBVDYT9NfCoF8TuQ@mail.gmail.com

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

#176vignesh C
vignesh21@gmail.com
In reply to: Amit Kapila (#166)
Re: Parallel copy

On Fri, Oct 9, 2020 at 11:01 AM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Thu, Oct 8, 2020 at 12:14 AM vignesh C <vignesh21@gmail.com> wrote:

On Mon, Sep 28, 2020 at 12:19 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

+ */
+typedef struct ParallelCopyLineBoundary

Are we doing all this state management to avoid using locks while
processing lines? If so, I think we can use either spinlock or LWLock
to keep the main patch simple and then provide a later patch to make
it lock-less. This will allow us to first focus on the main design of
the patch rather than trying to make this datastructure processing
lock-less in the best possible way.

The steps will be more or less same if we use spinlock too. step 1, step 3 & step 4 will be common we have to use lock & unlock instead of step 2 & step 5. I feel we can retain the current implementation.

I'll study this in detail and let you know my opinion on the same but
in the meantime, I don't follow one part of this comment: "If they
don't follow this order the worker might process wrong line_size and
leader might populate the information which worker has not yet
processed or in the process of processing."

Do you want to say that leader might overwrite some information which
worker hasn't read yet? If so, it is not clear from the comment.
Another minor point about this comment:

Here leader and worker must follow these steps to avoid any corruption
or hang issue. Changed it to:
* The leader & worker process access the shared line information by following
* the below steps to avoid any data corruption or hang:

Actually, I wanted more on the lines why such corruption or hang can
happen? It might help reviewers to understand why you have followed
such a sequence.

There are 3 variables which the leader & worker are working on:
line_size, line_state & data. Leader will update line_state & populate
data, update line_size & line_state. Workers will wait for line_state
to be updated, once the updated leader will read the data based on the
line_size. If the worker is not synchronized wrong line_size will be
set & read wrong amount of data, anything can happen.There are 3
variables which leader & worker are working on: line_size, line_state
& data. Leader will update line_state & populate data, update
line_size & line_state. Workers will wait for line_state to be
updated, once the updated leader will read the data based on the
line_size. If the worker is not synchronized wrong line_size will be
set & read wrong amount of data, anything can happen. This is the
usual concurrency case with reader/writers. I felt that much details
need not be mentioned.

How did you ensure that this is fixed? Have you tested it, if so
please share the test? I see a basic problem with your fix.

+ /* Report WAL/buffer usage during parallel execution */
+ bufferusage = shm_toc_lookup(toc, PARALLEL_COPY_BUFFER_USAGE, false);
+ walusage = shm_toc_lookup(toc, PARALLEL_COPY_WAL_USAGE, false);
+ InstrEndParallelQuery(&bufferusage[ParallelWorkerNumber],
+   &walusage[ParallelWorkerNumber]);

You need to call InstrStartParallelQuery() before the actual operation
starts, without that stats won't be accurate? Also, after calling
WaitForParallelWorkersToFinish(), you need to accumulate the stats
collected from workers which neither you have done nor is possible
with the current code in your patch because you haven't made any
provision to capture them in BeginParallelCopy.

I suggest you look into lazy_parallel_vacuum_indexes() and
begin_parallel_vacuum() to understand how the buffer/wal usage stats
are accumulated. Also, please test this functionality using
pg_stat_statements.

Made changes accordingly.
I have verified it using:
postgres=# select * from pg_stat_statements where query like '%copy%';
userid | dbid | queryid |
query
| plans | total_plan_time |
min_plan_time | max_plan_time | mean_plan_time | stddev_plan_time |
calls | total_exec_time | min_exec_time | max_exec_time |
mean_exec_time | stddev_exec_time | rows | shared_blks_hi
t | shared_blks_read | shared_blks_dirtied | shared_blks_written |
local_blks_hit | local_blks_read | local_blks_dirtied |
local_blks_written | temp_blks_read | temp_blks_written | blk_
read_time | blk_write_time | wal_records | wal_fpi | wal_bytes
--------+-------+----------------------+---------------------------------------------------------------------------------------------------------------------+-------+-----------------+-
--------------+---------------+----------------+------------------+-------+-----------------+---------------+---------------+----------------+------------------+--------+---------------
--+------------------+---------------------+---------------------+----------------+-----------------+--------------------+--------------------+----------------+-------------------+-----
----------+----------------+-------------+---------+-----------
10 | 13743 | -6947756673093447609 | copy hw from
'/home/vignesh/postgres/postgres/inst/bin/hw_175000.csv' with(format
csv, delimiter ',') | 0 | 0 |
0 | 0 | 0 | 0 |
1 | 265.195105 | 265.195105 | 265.195105 | 265.195105
| 0 | 175000 | 191
6 | 0 | 946 | 946 |
0 | 0 | 0 | 0
| 0 | 0 |
0 | 0 | 1116 | 0 | 3587203
10 | 13743 | 8570215596364326047 | copy hw from
'/home/vignesh/postgres/postgres/inst/bin/hw_175000.csv' with(format
csv, delimiter ',', parallel '2') | 0 | 0 |
0 | 0 | 0 | 0 |
1 | 35668.402482 | 35668.402482 | 35668.402482 | 35668.402482
| 0 | 175000 | 310
1 | 36 | 952 | 919 |
0 | 0 | 0 | 0
| 0 | 0 |
0 | 0 | 1119 | 6 | 3624405
(2 rows)

I am not able to properly parse the data but If understand the wal
data for non-parallel (1116 | 0 | 3587203) and parallel (1119
| 6 | 3624405) case doesn't seem to be the same. Is that
right? If so, why? Please ensure that no checkpoint happens for both
cases.

I have disabled checkpoint, the results with the checkpoint disabled
are given below:
| wal_records | wal_fpi | wal_bytes
Sequential Copy | 1116 | 0 | 3587669
Parallel Copy(1 worker) | 1116 | 0 | 3587669
Parallel Copy(4 worker) | 1121 | 0 | 3587668
I noticed that for 1 worker wal_records & wal_bytes are same as
sequential copy, but with different worker count I had noticed that
there is difference in wal_records & wal_bytes, I think the difference
should be ok because with more than 1 worker the order of records
processed will be different based on which worker picks which records
to process from input file. In the case of sequential copy/1 worker
the order in which the records will be processed is always in the same
order hence wal_bytes are the same.

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

#177vignesh C
vignesh21@gmail.com
In reply to: Tomas Vondra (#157)
Re: Parallel copy

On Sat, Oct 3, 2020 at 6:20 AM Tomas Vondra <tomas.vondra@2ndquadrant.com>
wrote:

Hello Vignesh,

I've done some basic benchmarking on the v4 version of the patches (but
AFAIKC the v5 should perform about the same), and some initial review.

For the benchmarking, I used the lineitem table from TPC-H - for 75GB
data set, this largest table is about 64GB once loaded, with another
54GB in 5 indexes. This is on a server with 32 cores, 64GB of RAM and
NVME storage.

The COPY duration with varying number of workers (specified using the
parallel COPY option) looks like this:

workers duration
---------------------
0 1366
1 1255
2 704
3 526
4 434
5 385
6 347
7 322
8 327

So this seems to work pretty well - initially we get almost linear
speedup, then it slows down (likely due to contention for locks, I/O
etc.). Not bad.

Thanks for testing with different workers & posting the results.

I've only done a quick review, but overall the patch looks in fairly
good shape.

1) I don't quite understand why we need INCREMENTPROCESSED and
RETURNPROCESSED, considering it just does ++ or return. It just
obfuscated the code, I think.

I have removed the macros.

2) I find it somewhat strange that BeginParallelCopy can just decide not
to do parallel copy after all. Why not to do this decisions in the
caller? Or maybe it's fine this way, not sure.

I have moved the check IsParallelCopyAllowed to the caller.

3) AFAIK we don't modify typedefs.list in patches, so these changes
should be removed.

I had seen that in many of the commits typedefs.list is getting changed,
also it helps in running pgindent. So I'm retaining this change.

4) IsTriggerFunctionParallelSafe actually checks all triggers, not just
one, so the comment needs minor rewording.

Modified the comments.

Thanks for the comments & sharing the test results Tomas, These changes are
fixed in one of my earlier mail [1]/messages/by-id/CALDaNm1n1xW43neXSGs=c7zt-mj+JHHbubWBVDYT9NfCoF8TuQ@mail.gmail.com that I sent.

[1]: /messages/by-id/CALDaNm1n1xW43neXSGs=c7zt-mj+JHHbubWBVDYT9NfCoF8TuQ@mail.gmail.com
/messages/by-id/CALDaNm1n1xW43neXSGs=c7zt-mj+JHHbubWBVDYT9NfCoF8TuQ@mail.gmail.com

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

#178vignesh C
vignesh21@gmail.com
In reply to: Greg Nancarrow (#162)
Re: Parallel copy

On Thu, Oct 8, 2020 at 8:43 AM Greg Nancarrow <gregn4422@gmail.com> wrote:

On Thu, Oct 8, 2020 at 5:44 AM vignesh C <vignesh21@gmail.com> wrote:

Attached v6 patch with the fixes.

Hi Vignesh,

I noticed a couple of issues when scanning the code in the following

patch:

v6-0003-Allow-copy-from-command-to-process-data-from-file.patch

In the following code, it will put a junk uint16 value into *destptr
(and thus may well cause a crash) on a Big Endian architecture
(Solaris Sparc, s390x, etc.):
You're storing a (uint16) string length in a uint32 and then pulling
out the lower two bytes of the uint32 and copying them into the
location pointed to by destptr.

static void
+CopyStringToSharedMemory(CopyState cstate, char *srcPtr, char *destptr,
+ uint32 *copiedsize)
+{
+ uint32 len = srcPtr ? strlen(srcPtr) + 1 : 0;
+
+ memcpy(destptr, (uint16 *) &len, sizeof(uint16));
+ *copiedsize += sizeof(uint16);
+ if (len)
+ {
+ memcpy(destptr + sizeof(uint16), srcPtr, len);
+ *copiedsize += len;
+ }
+}

I suggest you change the code to:

uint16 len = srcPtr ? (uint16)strlen(srcPtr) + 1 : 0;
memcpy(destptr, &len, sizeof(uint16));

[I assume string length here can't ever exceed (65535 - 1), right?]

Looking a bit deeper into this, I'm wondering if in fact your
EstimateStringSize() and EstimateNodeSize() functions should be using
BUFFERALIGN() for EACH stored string/node (rather than just calling
shm_toc_estimate_chunk() once at the end, after the length of packed
strings and nodes has been estimated), to ensure alignment of start of
each string/node. Other Postgres code appears to be aligning each
stored chunk using shm_toc_estimate_chunk(). See the definition of
that macro and its current usages.

I'm not handling this, this is similar to how it is handled in other places.

Then you could safely use:

uint16 len = srcPtr ? (uint16)strlen(srcPtr) + 1 : 0;
*(uint16 *)destptr = len;
*copiedsize += sizeof(uint16);
if (len)
{
memcpy(destptr + sizeof(uint16), srcPtr, len);
*copiedsize += len;
}

and in the CopyStringFromSharedMemory() function, then could safely use:

len = *(uint16 *)srcPtr;

The compiler may be smart enough to optimize-away the memcpy() in this
case anyway, but there are issues in doing this for architectures that
take a performance hit for unaligned access, or don't support
unaligned access.

Changed it to uin32, so that there are no issues in case if length exceeds
65535 & also to avoid problems in Big Endian architecture.

Also, in CopyXXXXFromSharedMemory() functions, you should use palloc()
instead of palloc0(), as you're filling the entire palloc'd buffer
anyway, so no need to ask for additional MemSet() of all buffer bytes
to 0 prior to memcpy().

I have changed palloc0 to palloc.

Thanks Greg for reviewing & providing your comments. These changes are
fixed in one of my earlier mail [1]/messages/by-id/CALDaNm1n1xW43neXSGs=c7zt-mj+JHHbubWBVDYT9NfCoF8TuQ@mail.gmail.com that I sent.
[1]: /messages/by-id/CALDaNm1n1xW43neXSGs=c7zt-mj+JHHbubWBVDYT9NfCoF8TuQ@mail.gmail.com
/messages/by-id/CALDaNm1n1xW43neXSGs=c7zt-mj+JHHbubWBVDYT9NfCoF8TuQ@mail.gmail.com

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

#179Amit Kapila
amit.kapila16@gmail.com
In reply to: vignesh C (#176)
Re: Parallel copy

On Wed, Oct 14, 2020 at 6:51 PM vignesh C <vignesh21@gmail.com> wrote:

On Fri, Oct 9, 2020 at 11:01 AM Amit Kapila <amit.kapila16@gmail.com> wrote:

I am not able to properly parse the data but If understand the wal
data for non-parallel (1116 | 0 | 3587203) and parallel (1119
| 6 | 3624405) case doesn't seem to be the same. Is that
right? If so, why? Please ensure that no checkpoint happens for both
cases.

I have disabled checkpoint, the results with the checkpoint disabled
are given below:
| wal_records | wal_fpi | wal_bytes
Sequential Copy | 1116 | 0 | 3587669
Parallel Copy(1 worker) | 1116 | 0 | 3587669
Parallel Copy(4 worker) | 1121 | 0 | 3587668
I noticed that for 1 worker wal_records & wal_bytes are same as
sequential copy, but with different worker count I had noticed that
there is difference in wal_records & wal_bytes, I think the difference
should be ok because with more than 1 worker the order of records
processed will be different based on which worker picks which records
to process from input file. In the case of sequential copy/1 worker
the order in which the records will be processed is always in the same
order hence wal_bytes are the same.

Are all records of the same size in your test? If so, then why the
order should matter? Also, even the number of wal_records has
increased but wal_bytes are not increased, rather it is one-byte less.
Can we identify what is going on here? I don't intend to say that it
is a problem but we should know the reason clearly.

--
With Regards,
Amit Kapila.

#180Hou, Zhijie
houzj.fnst@cn.fujitsu.com
In reply to: Amit Kapila (#179)
RE: Parallel copy

Hi Vignesh,

After having a look over the patch,
I have some suggestions for
0003-Allow-copy-from-command-to-process-data-from-file.patch.

1.

+static uint32
+EstimateCstateSize(ParallelContext *pcxt, CopyState cstate, List *attnamelist,
+				   char **whereClauseStr, char **rangeTableStr,
+				   char **attnameListStr, char **notnullListStr,
+				   char **nullListStr, char **convertListStr)
+{
+	uint32		strsize = MAXALIGN(sizeof(SerializedParallelCopyState));
+
+	strsize += EstimateStringSize(cstate->null_print);
+	strsize += EstimateStringSize(cstate->delim);
+	strsize += EstimateStringSize(cstate->quote);
+	strsize += EstimateStringSize(cstate->escape);

It use function EstimateStringSize to get the strlen of null_print, delim, quote and escape.
But the length of null_print seems has been stored in null_print_len.
And delim/quote/escape must be 1 byte, so I think call strlen again seems unnecessary.

How about " strsize += sizeof(uint32) + cstate->null_print_len + 1"

2.
+ strsize += EstimateNodeSize(cstate->whereClause, whereClauseStr);

+	copiedsize += CopyStringToSharedMemory(cstate, whereClauseStr,
+										   shmptr + copiedsize);

Some string length is counted for two times.
The ' whereClauseStr ' has call strlen in EstimateNodeSize once and call strlen in CopyStringToSharedMemory again.
I don't know wheather it's worth to refacor the code to avoid duplicate strlen . what do you think ?

Best regards,
houzj

#181Amit Kapila
amit.kapila16@gmail.com
In reply to: Hou, Zhijie (#180)
Re: Parallel copy

On Sun, Oct 18, 2020 at 7:47 AM Hou, Zhijie <houzj.fnst@cn.fujitsu.com> wrote:

Hi Vignesh,

After having a look over the patch,
I have some suggestions for
0003-Allow-copy-from-command-to-process-data-from-file.patch.

1.

+static uint32
+EstimateCstateSize(ParallelContext *pcxt, CopyState cstate, List *attnamelist,
+                                  char **whereClauseStr, char **rangeTableStr,
+                                  char **attnameListStr, char **notnullListStr,
+                                  char **nullListStr, char **convertListStr)
+{
+       uint32          strsize = MAXALIGN(sizeof(SerializedParallelCopyState));
+
+       strsize += EstimateStringSize(cstate->null_print);
+       strsize += EstimateStringSize(cstate->delim);
+       strsize += EstimateStringSize(cstate->quote);
+       strsize += EstimateStringSize(cstate->escape);

It use function EstimateStringSize to get the strlen of null_print, delim, quote and escape.
But the length of null_print seems has been stored in null_print_len.
And delim/quote/escape must be 1 byte, so I think call strlen again seems unnecessary.

How about " strsize += sizeof(uint32) + cstate->null_print_len + 1"

+1. This seems like a good suggestion but add comments for
delim/quote/escape to indicate that we are considering one-byte for
each. I think this will obviate the need of function
EstimateStringSize. Another thing in this regard is that we normally
use add_size function to compute the size but I don't see that being
used in this and nearby computation. That helps us to detect overflow
of addition if any.

EstimateCstateSize()
{
..
+
+ strsize++;
..
}

Why do we need this additional one-byte increment? Does it make sense
to add a small comment for the same?

2.
+ strsize += EstimateNodeSize(cstate->whereClause, whereClauseStr);

+       copiedsize += CopyStringToSharedMemory(cstate, whereClauseStr,
+                                                                                  shmptr + copiedsize);

Some string length is counted for two times.
The ' whereClauseStr ' has call strlen in EstimateNodeSize once and call strlen in CopyStringToSharedMemory again.
I don't know wheather it's worth to refacor the code to avoid duplicate strlen . what do you think ?

It doesn't seem worth to me. We probably need to use additional
variables to save those lengths. I think it will add more
code/complexity than we will save. See EstimateParamListSpace and
SerializeParamList where we get the typeLen each time, that way code
looks neat to me and we are don't going to save much by not following
a similar thing here.

--
With Regards,
Amit Kapila.

#182vignesh C
vignesh21@gmail.com
In reply to: Amit Kapila (#179)
1 attachment(s)
Re: Parallel copy

On Thu, Oct 15, 2020 at 2:39 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Wed, Oct 14, 2020 at 6:51 PM vignesh C <vignesh21@gmail.com> wrote:

On Fri, Oct 9, 2020 at 11:01 AM Amit Kapila <amit.kapila16@gmail.com> wrote:

I am not able to properly parse the data but If understand the wal
data for non-parallel (1116 | 0 | 3587203) and parallel (1119
| 6 | 3624405) case doesn't seem to be the same. Is that
right? If so, why? Please ensure that no checkpoint happens for both
cases.

I have disabled checkpoint, the results with the checkpoint disabled
are given below:
| wal_records | wal_fpi | wal_bytes
Sequential Copy | 1116 | 0 | 3587669
Parallel Copy(1 worker) | 1116 | 0 | 3587669
Parallel Copy(4 worker) | 1121 | 0 | 3587668
I noticed that for 1 worker wal_records & wal_bytes are same as
sequential copy, but with different worker count I had noticed that
there is difference in wal_records & wal_bytes, I think the difference
should be ok because with more than 1 worker the order of records
processed will be different based on which worker picks which records
to process from input file. In the case of sequential copy/1 worker
the order in which the records will be processed is always in the same
order hence wal_bytes are the same.

Are all records of the same size in your test? If so, then why the
order should matter? Also, even the number of wal_records has
increased but wal_bytes are not increased, rather it is one-byte less.
Can we identify what is going on here? I don't intend to say that it
is a problem but we should know the reason clearly.

The earlier run that I executed was with varying record size. The
below results are by modifying the records to keep it of same size:
| wal_records | wal_fpi
| wal_bytes
Sequential Copy | 1307 | 0 | 4198526
Parallel Copy(1 worker) | 1307 | 0 | 4198526
Parallel Copy(2 worker) | 1308 | 0 | 4198836
Parallel Copy(4 worker) | 1307 | 0 | 4199147
Parallel Copy(8 worker) | 1312 | 0 | 4199735
Parallel Copy(16 worker) | 1313 | 0 | 4200311

Still I noticed that there is some difference in wal_records &
wal_bytes. I feel the difference in wal_records & wal_bytes is because
of the following reasons:
Each worker prepares 1000 tuples and then tries to do
heap_multi_insert for 1000 tuples, In our case approximately 185
tuples is stored in 1 page, 925 tuples are stored in 5 WAL records and
the remaining 75 tuples are stored in next WAL record. The wal dump is
like below:
rmgr: Heap2 len (rec/tot): 3750/ 3750, tx: 510, lsn:
0/0160EC80, prev 0/0160DDB0, desc: MULTI_INSERT+INIT 185 tuples flags
0x00, blkref #0: rel 1663/13751/16384 blk 0
rmgr: Heap2 len (rec/tot): 3750/ 3750, tx: 510, lsn:
0/0160FB28, prev 0/0160EC80, desc: MULTI_INSERT+INIT 185 tuples flags
0x00, blkref #0: rel 1663/13751/16384 blk 1
rmgr: Heap2 len (rec/tot): 3750/ 3750, tx: 510, lsn:
0/016109E8, prev 0/0160FB28, desc: MULTI_INSERT+INIT 185 tuples flags
0x00, blkref #0: rel 1663/13751/16384 blk 2
rmgr: Heap2 len (rec/tot): 3750/ 3750, tx: 510, lsn:
0/01611890, prev 0/016109E8, desc: MULTI_INSERT+INIT 185 tuples flags
0x00, blkref #0: rel 1663/13751/16384 blk 3
rmgr: Heap2 len (rec/tot): 3750/ 3750, tx: 510, lsn:
0/01612750, prev 0/01611890, desc: MULTI_INSERT+INIT 185 tuples flags
0x00, blkref #0: rel 1663/13751/16384 blk 4
rmgr: Heap2 len (rec/tot): 1550/ 1550, tx: 510, lsn:
0/016135F8, prev 0/01612750, desc: MULTI_INSERT+INIT 75 tuples flags
0x02, blkref #0: rel 1663/13751/16384 blk 5

After the 1st 1000 tuples are inserted and when the worker tries to
insert another 1000 tuples, it will use the last page which had free
space to insert where we can insert 110 more tuples:
rmgr: Heap2 len (rec/tot): 2470/ 2470, tx: 510, lsn:
0/01613C08, prev 0/016135F8, desc: MULTI_INSERT 110 tuples flags 0x00,
blkref #0: rel 1663/13751/16384 blk 5
rmgr: Heap2 len (rec/tot): 3750/ 3750, tx: 510, lsn:
0/016145C8, prev 0/01613C08, desc: MULTI_INSERT+INIT 185 tuples flags
0x00, blkref #0: rel 1663/13751/16384 blk 6
rmgr: Heap2 len (rec/tot): 3750/ 3750, tx: 510, lsn:
0/01615470, prev 0/016145C8, desc: MULTI_INSERT+INIT 185 tuples flags
0x00, blkref #0: rel 1663/13751/16384 blk 7
rmgr: Heap2 len (rec/tot): 3750/ 3750, tx: 510, lsn:
0/01616330, prev 0/01615470, desc: MULTI_INSERT+INIT 185 tuples flags
0x00, blkref #0: rel 1663/13751/16384 blk 8
rmgr: Heap2 len (rec/tot): 3750/ 3750, tx: 510, lsn:
0/016171D8, prev 0/01616330, desc: MULTI_INSERT+INIT 185 tuples flags
0x00, blkref #0: rel 1663/13751/16384 blk 9
rmgr: Heap2 len (rec/tot): 3050/ 3050, tx: 510, lsn:
0/01618098, prev 0/016171D8, desc: MULTI_INSERT+INIT 150 tuples flags
0x02, blkref #0: rel 1663/13751/16384 blk 10

This behavior will be the same for sequential copy and copy with 1
worker as the sequence of insert & the pages used to insert is in same
order. There 2 reasons together result in the varying wal_size &
wal_records with multiple worker: 1) When more than 1 worker is
involved the sequence in which the pages that will be selected is not
guaranteed, the MULTI_INSERT tuple count varies &
MULTI_INSERT/MULTI_INSERT+INIT description varies. 2) wal_records will
increase with more number of workers because when the tuples are split
across the workers, one of the worker will have few more WAL record
because the last heap_multi_insert gets split across the workers and
generates new wal records like:
rmgr: Heap2 len (rec/tot): 600/ 600, tx: 510, lsn:
0/019F8B08, prev 0/019F7C48, desc: MULTI_INSERT 25 tuples flags 0x00,
blkref #0: rel 1663/13751/16384 blk 1065

Attached the tar of wal file dump which was used for analysis.

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

Attachments:

wal_dump.tarapplication/x-tar; name=wal_dump.tarDownload
�
��_��]�$�������4��S�����t�N�Z-�$�������(�v$RF��:��D���.v�G9����Y*��2W`�;�,{��w��������Y����������������_�����r�?�������0O����d�7����!L>���,�O���t���?�����������?|�����������|��?|��w������������}��������w���?��on}A��������w��g��w����������m��w����}�����������]�o%���~��/~��_���������w�����~�����w����;�3�����������������o����S��w������������_�����}�������w����n���?��}���}���������~����������y���7���w���?�������_����o�@b~���?������o����;7}A��(�u�q�9�4��(��o~������$�����G�\x��f�[�zW�������_�?��������Oo����Y���b1&|�O������K%�%�����I�(I$}���$?H�
(�<k�$�M ����$�Q�Hr���� I������i��
$}��X�s��Q�=J��{�n��Q�v��Q�S�F������9��GI� ����$�8��)��BDI�9I�����|���J��������$}����)��z������F�*�	$}���%��4j�]H�����R���,JJO��M��%�����>5J��zSf���'��-�����'�I��A��%�OI2a�i�����g�B�QQ}J��G�V
(�(��1�&uE%>3F�39T�>9F�����E��"��X�
��K�$g~��^PR>'������I7���I�xB�����f��H�	Ig�Ks�Fi�(����&��Ys�6�xB��w����/�]"�OL�a	�F�@�EOHz��/���\�u����y�x�4��t����r�	�	����e�]��GIO���t~��#I8J��Q�]���$�'$]�]���)I��Qr8J�9�����KG�==J��������xB��QZ,���=L(��)Ii�(%����I�?qG)<9J��(�����v_��y��E���w)�I.i<!�r��@i|B�_FIZJz2����*J� �%�O���~� �%�OI������I�GIK.�h�4>�w���'�9��Iz5�|�3��8�/N>F�K��,�q������� ��+Y �OIM�\�xB��_�e���4>��v����-��g�,�A���--O�[�()
3�--O�[�Q��������sK������H�[Z�8����3v���--O�[�K�8Y�������y����--O�[�}�F����'�-�%�����q�[Z�8�t�d^��n��L �������)���N��D��TAi<!����"���v�E%�'$�WK�W�v�H�	I�i�$'5���������p���$�xBR<o;J�A�xBR:-)�����
���3�������~�eM$����/����:yF���%��k�������3����?��L�o�w�"�h:�
�i�c'w�g4�~�{>D55�=�qyF���8����T�"�h:����-oz�E��t�5�H�m��f��"�h��=n�y;�E�Y�������4��3�����cv���.�����q��d3�-w�g4������o/5�E��t�R���@o�#�g4����9S��<�E����b�'����]�Mg����������w�g4�}��� �wK};�E��t�!B������������7�]�S��W�^R2�e"�'$]�wky���k<!��e����t����������5��t�e�K���v1w�xB��5�I��
y�OH:��} ��Q������x���������3����dv�� r��~�MW�(~Y�n��5��tv���\��"��<wn��y��F�������?$�%��0�W�|1�y��F��Gc�OH:�:1����������g�������b�
��I�	I/�N����{�xB������~���w�'$�]������?y����.{��-��5��t5�}�Q���_;��PR
$���]��'�~u2���[I�����O����{6����]�	IW�o�V������F��\��V���
����h��;HZ�~U�v�����,,t���4�����P��������%��n��5>%i�B�&	�8�xB��/��rv������1����=����/0�-��'q 
:�7�<���IX��'�=q9���lt�����n����;��OI�G��������iBy�0��Q*3Jz���2���MRI��<.���0�P��e��+����d���O/t_����`	���'R����\v�=��k<!��Q����O��c���s�9�4��t��{^a�#��\*r�V�
si|F��%4I�,Jzn��Izu�����$x	��'n��A���9�(m��������G�p�����������]�	I�����8������o�>�������OH��H���]�xB��'�R`�MOH:���KZ���N�]�	I�7wH�P�������I�����]�����������0��3��~Y.���E��t��rI��Q���3���>���-�%���3�N������7��"Oh�:�_2\�k<!������r�]�S��,�o�Hz�r�]��p~���@�w���Wcr��$��	
#���5�n,Jzz���^7Io�	�OH:��g��n-Jzv�0�v���(e��H�	I�w����(;��I�3��1!�RO��o������B�%�W�x�����LK�$=����t����n���'$���h�$�]0�O!=�1Is��GI���^.��P�����=���]P��;���U��	�&��$�����m�lIt�xB��Q�_�[�g[9����I�A��-�����y��a�{iw��TAtv8��_�'���S��E��m��Vi|�%�Z�oHr�
����%�R����X�^�������&�m����.���(��(����v�}�xB�i��;
7I��&�OI��a�os����.�%��aw����1h�f@Rz�m�?$]��G��<	!;������W�n�$e��wON�l����(������tz����z�4>%i�A�*��H�	IW�iq�'�>�^�_�E�@R�aB�O������8���;�w�'$]}�9�������N�"��Ku~[����������Z?��v[�������5����OH��*��5>%���M��E4��������.6=�J�{K(w�'$�	���8C�����^(t���=��OH:�X_!*��m|z�xB���0�,�+W�v��������Kq�o������^{�u6 �?��������$����<f	����''a~
����1�$-��r�Kz!���K9���4��t������o������������'����{��,�H�	IW���+�xB������"����OH�����yI����x�$YkA��t��e�w�ALq�xB���%=8�OH�������k|�����CI3���k<!��wi$��6��k<!���)MoC����.�z'���OH�����CIO��k���2�����t�xB��_������k<!���7?�8s�xB��_�n�OH:�a�`�-�����)Ic6Ro����w�'$]?J>�����1�	k!�5��t��n|���$=]
y����1`����{�F�M�������N�7/��y$�:��8��Ks��&)�$�8��(iz���cI���5>�E����&	^�����n���[����>���8Ji����_w������7I	$=��u�4�%�X��\�|�4�%�l iyn��&i��;x�����M��	%�B�4>1�97���Jz���w���p ���I~�qp ���	��5J+����b�<���M���'��FI�p��>���=q����\��,� I�K�s�`n�F�q�K���&������v\/�����A{��\/����M�(�
�����t�4�������z�����$\/�g�K�hw���$=�^�c��7Ioc����$��z����k|jBs�z��IO������'�&iI����8��:9�����M(c^7I$�'w����:�%=�a�6Jg�K�x���A��
H�?���������/���o~��������?qS����~�����w����;�3�����������������o����S��w������������������������������������7����������������������?����������~���|�S>~������o���$�g�~��_���w��>��7�M_�/�(�o�x�a�Q���_����/����?|�n����������{�_�h"<q���{��q?�e�����?��������w�������?��������]�?�����{�?c�z�O`�����v��	~\c��W�����/��o�����w�q��|�9~���M���
�����0�_��gL���?������f|r����\�S���O��/~]~�������>F:ui������e�����?uC�������i����p���o����?�������-�)~A��
�w�|��������Nv�������m��i��4�W��q��_��g�������_�^v�w����������������/�w�������������~�����{���^���}���3v���c7�/��}�lo���������?|�<~�<�5����/��tFJI��(�Y�Q��~u�~�����������S��~w�7������_���o������6X�}�������(O�u����R�~��p��Z�"����|#]x�?Q�����W?_s����7�?������������:�,��Y|�g�c��/��Y��m>�������������O������gMT���}�ZChZ#�a���F8����L����������(Zs�T��j$ eg�*�}�,������0M���~%,���0D��^	7���")����U
����?] ���6�,��/�)�����~A�<�@�'�~Q���~��������W���f?y����D>*���@�����G�����tT-�����gG�?U?`T�n����U�fT�y���j�7���=����;z������p������p������uz��	n���B� g�g�����z�{p�+:[Pa����qv��lyI�gg\9������������B���]&pv���s�F8�����������
���ue���]����p68��r6�9`��$�G��*r6dp6����p6��r6�9PMw������8[q����I���Qa����6���<��K�F8��gS�g��g��@��@k�����D�2Y�Q������ki��������i�>���"���!�n}��~p7���	�F1���W���V:����[k��'#��&��,*#�f&���v��[i��
e{�V1���l�>��8jG���h+�L.��{m�bU�mK�m�t UnKn�	c��x����U��*�m���������}A�spkp�^*���O�F8��z�w�/,�'�2>�����z�T4%�����	'So����b�
L���q?@���5('��z����Aj_7�\S�=���"�J�k��h���hn}M�s����h�^8�����T��sw�/�F��!�cQ4�t*�
%b8�����T�"�w����3��q�X�M/��PC���c�p<g�E�'����\(utW{4W/��������]Lb��(�}A�s��#��(���b�%����b@�
�
M�1741��T1"��>�Z��*F����\����sc�s�b@��sc�s�t@��sS�sYq#�M������UB�M�JT+rn�s��jyE�]����P���+���	����2�+�)7�����N1���s�>���W27#�n�J�d����\��Pe����\'�Pe����\�}�1771�)T;b���\'P���;���SnA��������[�������[���)�4)�)�S)��)�I�S)��)W�F���	�N/�JBn�C������,�W�	7MM�uz�T�*J�3n��� o�Go��+�g� .�=z�N%��A�;�
�S	Ku$�G\V�s- n:T� ]z�T�JdW8�J�E���q#�u����W/�J�s���3~��Tr����W���G���^/�J����S\B8�J7�>��?������h�^8��r�������4�������!��&�z�t*-%�!��Si�%�/�+#�]�rI��\�t*��������rC�r�I( ��&�z�t*����\/�N���>��H��I�^1��H��O�^:�JH����>_�RnjR�W��Rn�S����V���P�4�H�k�r�b>�"��}���2e.R��P�4mH�k�r��
)wc(W:���r�>���F���r�6�*�S)73�+�Oe������������;+�S;Bn�C�,O��{r��!woB��O�����t<UrKr���sRniR��O�����Y:��H��O���V�����Y1��������p<�N8g�>����s�	�R{4W/�Z�%������j`� �/�W�0���Aj���T��Pb��,P��R���0�z9�3h����BIJ��1W8�Z-������{�����z���&���n����A4Jj?�;B+�m!�Gs���P�L��Y8�Z=D�����d�
1���a4J���uv(��t+P������ n����e�1�c�z	������N���QR��<�������K����D���pB�����Q�?�������K�>~�}�]��eA\�s���s���=���P�9�i��H'T97�9W����\H��\��*!�2�\��*!��>����F���\H��\��jE�e�,�	�����9W�����\H��\��jC�e�,�	����1
��sW��Bj��*&T9����H'T97�9�]��07#��6�*&T;rnf8W:���s�>�J��[���=���P���LO�E:�*��{�s���#��v.��`nPL�
r.��%H'T9��9W|��v.��h�bBU�s��.A:��������s�6!��&���j��sIs�\��j��sI��qc3G���A/��p.i��+�Pm8��~G[7;��597�%T��%�s�������!��&���js%�97'T��%�/$,#�u����h�^B�y�����������z�\R{4W/��|E�L�R��j����\6aa��Kj���%T���D�s��m�%�/$,#�]�sI��\��j[6��p�pB�-������e�����597�%T[@�
}���	��sC�s��e��97497�%T[D��}���	��sc�s��e��	97697*&T	97�97J'T	97�9�MX��������97�97J'T+r���\6aa����697*&Tr����(�Pm��[�s��e��r������Pm��[�s�tB��s�>��	�s3rnnrnTL�2rn�sn�N�v����\6aa����797*&T;r����(�P���;���	UA������P���p�tBU�sK�s���s+rnis�bBU�s+���	UE��}�eW{�������Mz	U��:ef�$��*O0g��V{C��8r8g���%T�x����N���9�����a.6u!�Gs��l-J�WJ�	U�0g��V{#���.��h�^B����Eo�pB�d������s���=���PeWPb��mN��wh���F��M]H��\��*���Eo�pB�g�FI��QA.cSR{4W/�����Eo�pB�g�FIm�\i��.��h�^B�(O���.I8��d���c�4
aSR{4W/��9�k�"�P�����+}�$cWR{4W/��9���"�P�������a.�u!�s��Q%]���tF��t��A:���.��a�bH�"�2�]nB��]�uW��t���]Hm�^��jE�e:���
��!��Li{���m��Tm��L���Pa{3���4b�N����m��Ue^���$�Ue$���b�~z���m��V���L���Pa{wd��i� ��b�R��W1�*�L���Pa{Ro�S�������m��XU�^���M��������H'V����6�����	��i�b&��j��{I�+����/�m���Z�fB��
�V��%����F�k�|I��_��[���F�|���#�����/�����%�
����f�����v�Kr_Y���������z���V���/��e����$�������k�����v�K�{�
GW��%����F�;�6���j��~It�_��j��~I�+��!�V�6���j_<jd��%��.��$�����_���W/���E����j����_v�7������k���="���p|�G�����t��="���*�W�7r�+�_%�����J?�	�7u�W1�J����_��jE�M������"��m��������2�k����we�Wzwa��~�6�Z��jC����������1����F���~�6�Z��*#�f�~�tz��~s�~gi8���
�V1��~3�V:��~�>��/�vd����V1�*��;��V:�*�����+moA�-m����UE�-�Z���"�V�~����"��6�Z���"�V�|�prU&�:*������[�5�m���\����~E��Pa
�$�����;�m���\�Qc���G���Z�<H�+K��b����W/�*vE����7�����Ar_Y���{�����N/�*j]�U�q��Uq����:�V�������z�U�P��0�bnB����������6
��!�
{���2{��/�{*l��)���+|l�`�R��W/�*�E��B�7���.����}_�`�`�R��W/�*aB��R�7���`_���W}�[�m���\����4��	�7"��>�J��*�/��6��K�JD�e����
���|c�|�k��Cj?��/����3_<���L������}S�}��\lCj�������"�2�c#�]|�>�����m�=�{j�|��m��L����s7���������!�sO-��������1,x�07#��>�����m�=�{j�|�����L��b�swD��A^��V����������_A�ez�vU:����[����m�=�{j����C�ez�v�2����[�����m�=�{j����C�ez�v�2��:!�Vv���:�������x/�2���Y���Kr?����8�����k��������9U5�$���t�58t�^���Z ]��sW8��H��~�n������RU�Q"���!Uu��$�3�v�.�ml!���-J�XW8��X��~&���%�Gw�b�:O(��]vG�;�����u�yw�%�Gw�r�:���.{og���Ew��+���.@�����^PU���e�D�p7�������n@�
�C�zIU
�����Y8��y70�+|��F����]���F�����,UE����]�b5!��6�*fU	y71�;KgU	y7�y�}�qy75y�\%�k�oE�M���Y�����y�}��pwE�]��{������!����M(F��!�n}�eKl�pwC����{�������w7�w����������XF���ws�w���x��w3���Y������+������{�w����x��ww�w��� ��}��nnS�ni�����naxw���
�naxWz�"���9f���"�V�w���#����������zw�	������jY�M����w�=we�������]n�]��j��i�]��]���&q�\��E6���Y�]��k)�k�������A��eU�dJd�-�Y�M]wm���p����Cgq��+&jY�69���1�lVuS�����i)KD7-+�����U��n�*Jd��.�Y�6y�����p���-�.�h�ZXuS��D�h�"Vm�l�^�j;��B������ji�M����1�lZ�M����v3a/����=��W�%��4�	�q�ML{�~IKv��.t���=��W�$"�r�b�l\u����~5GD��D�se3�����5�	�q�M"od�W��ycy�b\�y�V1&H�U	�7q���M������q����t�1A:�ZyWy'i{Wd�����y����u�	�y�������]�pwC�������
������������]�p7#��&�z��*#�2]b{(|��;o�/�*�����7��+�U;/�$��:�������7IoA������������1A:�*�����o����4��+�U��i�����������]�
q��6����UfB��:��
��k&^��qW���M/�=��VcP"�l��^��Y��i�%�Gw��*c*Jdx7
�U�zt��]���X�]R{tW/�2vG��F���8�]��qW8h6x��������P"��Q8�2x��v�+�����������U�P"��Q8�2x��v�&"3[�&��zY���wIs�]������$�������
�����^Ve�]��sW8�2�.���+��`��C���Y/�2��D�w��*�wC�w����� ��&��zY�������$�U�&zp7�yW|U�wc�wg��*"�F�w�tV��w#s��]���7!��&���aUB�M�&��jE�M}��^3���k�wg��jE�]�M�Y�����yWx�l��[w��
qwcp7IGU�����t�w�6�*FUq73����������k�t�#��&�.�Y����3�����yw��._�}���{x��� �����[F�[xs�Y��-H��I��bZU�xG��iUE����f+��[yky���"�Vy��*;��Q���fi��������^\e�����,�n��f��9)��`�+�]��]����%�K�I8��&��[XI�ma�r����U�n(�_+���u�����+�Qd�/�]��^������0v������v����B_�����z���$2�a�$�XYa)���+�
h�/�]��]����3Hd����������������������
z��]J����p`u�S���)g���f�a�r���V6����k��P#�
��$�g�4�d��d��X�������lm��Fd��j��F������X�������lm��&���j��&�������X%�^�A��N���"�&�����+BojBoP��V�^�C�5������r=�_�R�����YmH�L��a����qM������5�7(FV���c�td�{3��P�2rons�bf�#�2Mb����v���k[(
F;r���^��� �2]b���
roa����?����[��S�������F:������^���{+romroTL�*r/�'�����&����^�|�w��Kj����Vn�P"������{In�]�g��C�����Y9�K�{�
gV������Y�\kq����+g�yIs�\+�X9�Kr;���u�\�x�^^�/i��+�W9�Kr?s�\�w�^Z��C��Z���y�]��Y�th�������lP"C�V8�r3�.�m�>��f`]{4W/�rsE��Z���-������������z9�[v������\�%��'�1������I/�rQ70�k�s*uCu��\D�
M�Mz)��H��!]�>�s#�nd5���tc�t�bH��tG��!UB�M��.�&a�������S�Yw�XW:�Z�uWfwW���[�v�&�&��jC�]�u�9����1���������5y7)&Uywcx�I'Uy7s���/�{3onoR��2of��IgU;ofvw�/�{wd����I1���yw�y�tZU�yw�T���� ��6�*�U��0�������[�S�N�\��H��M���UE���:���"�VfW�����0$�`���"+?AmK�t��N8���$�����C�m���Zy�-=�'��/���<H�+k�!�V;�<���W�z��/#d�7�-�$�3)���K�m���\ygQc�t�e�����AlJr_Q7�_�Cr��EW�O��_=��O�=��$�u#��N1$���^v�}A�����%4����������b����W/��sF�����W~������n���-��6��K�����~
]���+�@tJr_Q7�_�Cr���W> �2]c���|@�
���F��cHn�_���G�_�o����������_V��c��b~����1��q>������^�O�����������|�mK��|A�<���~������?��������fn�����i��4�W|0��������7���wz�����O���������{���������V(�����1���d����md>���P��� ��m�?������L�P#r������O�Pr��xW����!c$36����}d>uwx�����s����>j��C��@���d�wd�����'l�xgN	���c����]�|
5"��|���|
�a��V7|u�����?����+���F��C�O����:�Cr?�y���C������jD�=��������C����C���<y���!c$�5��K�{�O�P�/�U���������d���wIt������%����;�	G���V2UC���$����T
��������LQ[��k�����f�P#��l���:�]��V7��.j�%�
w��������pV5{�]��t	������zY��+j�xW8��g��2m�����wIl�]��j�w����"�U��.��dU���8^R��W/���
52���b//���+�E���������Us@�
����G��xsWF8��#"oh#��������]���9"�Ff�Wz���yc�y������e�t��7!�&�F�������������e�t��wE�]��w���H�k�z�bb�!���.������1���q�������)FVb��`�"Ye����|'loF��m�u��UF���JgV;rof�W:p��{�6�:��jG��9���v����^��UA�����S���[�
��UA�-�JG������)�V��2��S���[�.�s���cHm�^��j����rh!��������cHno����������/����3�K��x����	����dHnO����@f94�!]z�Z�
�A8�Z������|l ����>=s��
��A8�Z��������{l ����>Es*dJC��j�2$��Nx�w�2�����3�gT�������dHnG��V��
d�C:��g���B�(D��� Cr;��7zl ����>=s����|j�pX�`����%l.6�Y
d�\���a��D����pT�`�����*m.���}��37"���|j�pP�`����U�>f9������s7!���|��tN�
dH�g�Sa����?�~�O��I��D�Sw�3*�Cr?��
��,��1��7��"�z�|��tH��cH�gRa����=��������{h!���I�T�=��v�I�T�<f94���	�s7#�:�|��tL��cHn���tL��c�C���� =ww��C�O�����w���+�Sa����:�~"H����{�����A��!�w��*��:����[�w�c>uW:���1$�������c�C���y 5w���{����E8�
�.���+�C�	x��������P"��I8�
x��v�&�`�wI��L�����������+(�G���W?��7����O��M�M����������?������_����_�����]�����|����A��'L�'����a��~�?,��������?��_����e���.�P�'�m����g�>~A���
w��C#�5���O��P|�I�C����~�?k����M�g}�}<|��������3"�n^0��u������%�3������������"�m#^��u���J�G����&|�S?�D�A�Hj�����a5(��0�HF���� R�1WxO9��-����z�gX+J������n��'��G�8�I��\��3l;J����	��f�Dj;�
o)��"�=��~��)@fN�<��k��P������oG��C�Hj���e�aG����4���bqP��~&��bq���=0�3���7i~��sT� ��lLz�����`�E=s+rne��<>�s�8����\��s�sk�s��a�t����q����'�3Hm��,��'�3H��\��*�������3Hm��>�
���h�^B�A�\%as-��������R{4W/����D�|�pB�Cs����
D�(�=���PE��D�x�pB=d���3�
����QR{4W/��~C�L�$��*z�FI�g���=�\�r���+���G�H��WG�;C6Jj;�
������k�Mrz	U\��i~���s�FI���P�0��5�&9��*�\���������p���* ��6��%T1"��>��gG��sc�s�n�#�������^1�J�����N:�J�����l3��&����\��P%����\6�a�����f������k�s�bB�"��}�e���n��k�s�F�#���s�&�z��jC�������C�E������9wkr�WL�2rnf8W:������\�rqG��M���	����3�+�P���;���������^1�*�����l|;����[�>�rnir�WL�*rn�s.��0�"��>�J�~�9��9W/�Jrn�s.�07M��������Kj���%Ti�(�����t�����}�����%�sg��*�%�9�]��0wNn��~��Y�\R������'�!?�,����`tn^�����it�8��_}U~E��W\���YX����s|��5U���}�.�������~�����R{4W/�[�%�o��K��n@������
n�����z���m(���zk�&�����5��R{4W/�[sB���7��}��@���c�p���G�y�f�����4��~a��Mj;�
g>k�p���of�@o-@�����#�-@���#N8�YK��k������:���}�.HG�[��ImG����B�	R{4W/���� i~aA:��m��&��p��M����h�^��a'A����t������
z��%�s�@o�&�����s-p���\��n8����K�6l"H�_X��0��nL�@�9ws����h�^B�aiC����t�����?P|��G����^B�aA����1�\��1����y��kr���Pm�D�4��p�0w������s�\p�����%T6$�/<#�]�s7��"�+�-����h�^B�aA����1������\�w��������%T6$�/<#����L��ExWh�������	6$�/<#�M��L��ExWhK������	�$�/<#�]�s��������"��M�
�	�$�/<C�E�e�.��B����697(&T�A�4��p�0wC�ez.�	UF����*l H�_x8F���s����tB��ss�s�bB��I��sw�\�s�"�P���{�s�bB��I��sr.�80H'T9�497(&T�=�4��p�0�"�2}�tBU�sk�s�bB��I��s��s�60'T����o�=���P�iG���7��1�\s���N���9����K���Pb���p1�R�'�Pe�q��U&�^B�-T� �/<#��0g���8��*;�#��2�����i~��a��l��v�	'T�O8r�*Q/���L����z�FImG�pB�}��kV��z	U�J�W�`��������8��*�������z	U^J�W�`��.�����8��*/������z	U^*J�W�`������LD��*c+eR{4W/��9�����c��97�97
'T9"��&�F��*G����\��b.rn�sn�N�rnlrnTL�rn�s.�p�07!��>�F��jE�Mm�UL�V�������1��9w�sn�N�6������	�����9�}8F��!�n}���	����597)&T9w�s.�p�07#��>�F��*#��&�&��jG��}�e�����{�s�tB�#��M�M�	�����9�}8F�[�sw�s����[������[���>#������\���"��&�&���"�V�s����[�����}B��M�Mz	�>������p.���+�P����597�%T��%�/<#�5����#N8����#�����P�8�4��p�0�����8��j�G���z	��J�s.�p�0�����8��jw����h�^B�{����>#������#N8��=p.�=�k&��j�5�A�}:F�;;t��I8��g]R�pW/���5�I�}<F������8��j_�tIm�]��j_6��G]���.�.������q���k&��j�������1�����N������k&��j����]��j������!�&����]3)U	q71�+T%�������E�^����]3)FU+o�/����wE�]��{[���"��M�5�bZ�!��}�����n�[zoKa7���C����������BF��{�>��1��f����^��*#��>��O�w����*F���wo��QL�v$��O��2�_D�����e����wo��Q��
�o��/����� ��>���1��V����_��\U����_�	�oE���
gW������z�U��xeaz��O������N�
�}!�
���b<j�������=HnG���
�~!�
���b-j�W����Z�=Hn�_���`����W/�*nB�����2�_�)�����
6�!�
����
j�������z���kX��1��b���W/�*>��~�\�	���)�����
��!�
���2���_%�B���)�����
v�!�G�^~U�hY��0�2���S��S'�_lCr���W% �2=a�'d���70�k�����`Hn�_���D�_�-����7"�F���+l	Cr�*�W	����?!#�M����_��
������������4��������+��V:���0$���b~�"�2�a�'d�����������7�m���_m��L��	�oF��������!�
�����t����!�"�f��t~�bHn�_��jG�e��O�w����_+�_a����W1�*��L��	�oA�-�Z��
������N1����L��	�oE���Z��
[�����z�U����1�2��:����:���N��$���^~U���e����_��S'�_U�Kr���W����/�����:���_���Z�_���W/��6�F������InG�����%�
����V����p~U�/���+�_U�p��������z4z��'d�������	�Wu68v��?��_�M>c��tg@`���C2������	GXu�8vM>�������B��Gd��0�����Lr��Z>_�n����_���n@�
�:��������S��k�����_���nD���:���F�����SK���E����O�w�od��IGW	�75�����Zw�ob��}:F��"�&|����wm���m�k�]{W{��c����+��������6�������n��������1���C����57}Om�^�nF���JGVy73���#�����[��v|��wG������{w��^/�X��{������wg��}>F�[�xC�^:�*H��s�Y����[�e���VD�� ����*"o���*���[�e�������SGe����U7uo������j��MQA�L�!��a�y;u�����V7u����A�������rC��1�^;���)��e�������A��"���%2�v��c����L%L/Y�	����U��n#Hd�����{]{S��fVy��2w�G{�B���$2
f��c��~{=Ss�
�nb*��$L-����Q"Sj�}>F�;G�wf�`����M�c7cbJ�4�R�<-%2�v��c����.L�Y6����`��L�^��*OaB�L�]��ao�`o���0�lju����{�����"�2Mf��c���70�;��V7u�������l\koD�������{rod�w�N�rojr������{�.3��1�^���p�,�Z�������Jl\k����5�a������+���tj�!��M�=Wa�Z{7�^���|��wC��8��N�6������
l\koF��Z����{3ro��W:�������������u�a������;���tj�#��m�UL�
r/�`�}>F�[�{���������s�5.����/��{+roa�w�%+romr�����[�{��2���L�����E8�4p/�=���Z�iE���8�^�^��S'J�p���{������^����������:�P�X�c���s�5������Wp�������	���V�&��+�q����D�{�a��%�=u���q��$�h�^je�E���8�^�Kr{Wd��/u������z���'��`�"Z��������;�����z���J��W8��-��]�����@/�=��Y�%�Dz�#+zIn/Pv7 ��&�z���d��0oN�L@�
�
o�������+�y#��A:�����c^��@��yc�y�bb��y��A:�J���c^��@��yS�y�bb�"�&�y�tb�"����S�{Wd����^1���yW�y�tb�!�n��S�{7���	�^1����A:�����^v�aoF��M����UF�����jG����S�{w�����^1��{w{�tdU{w{��c������W1�*����^��� ��{��c������W1������^���"�V�{��c��v���6�w�K������]sg�pje'�:H�+S�{���]��^����$rmd�pje
L$���c�����W/����D��PN�������2u��������K��3(����S+� 2%��L#���1w�G{�R+�*Jd��F���z��2�.��c���=�.�h�^je���j�Q8��3D�$���c���9�.�h�^je�
%2�t�pju��`��T�d���B������z��]Jd��F���.���W���B������z��
��\�(�Z����e���F����^���F�^��LN�lD����S�{�{c�{��*!�r-d�tj��{����1��������(�V+r/�C&I�V+r��q�tj�"��M�]S���k"��S�
�w��W:���{�&�.������u�I��UF���e���f�����E1����\�$�Z�����^v�a����7�wQL�v�^��L�N�v����^v�aoA�����(�V��k#��S���[�e�-#��������bjU�{�62I:������^��2�^����^���M��\�$�Z�	�����n`���{I��^����9�N���%���[F�k�{I�����Z9SQb�{-�n����������Z�^�{�W/�rvG�}���pj�p/�}��2�^�Kr����V�m(���vN���%���[F���{I��^�������k'���y�^����e�����kro�K���K�{(�Z������na�2��5�7��Vn�%��N���Kr_y�����5�7��V.8���^;	�V. ��>������������Z�����k'���E����^��2��������ZE���q�tj��{c�{�w�{rojs�bj��{������������[F��"��M��������2�k�S�
�w��W:���{�&�F��jC���5������q�+�Ze�����Q1������^#�Ze���p/�na������S��wg����;���wg��}���woroTL�
r��p/[ru����0���[F�[�{K�{�bjU�{��l���V���p������"��&�F���"�V�{�pj�'�:*��O�s��^�dH��^���O%�KY#�ZyS�}��2�^� Cr����V��(�_Z����[�:H�+���b�{�W/��vC������V���Ar_y���;�����I/���^z�������w���W�-#��2$�h�^j�=���Lk�S+�!2%���[F��-dH��^����P��3}d�N���)�}��2���c��)���Z����~I]k�S+�@dJr_y���������z��%�K�Z+�Z��Kr_y���������z����L+k�S+�{����e���E����K�|D�eZ�X+�Z%���p/�na/v�!�G{S�������V:�J����^��2�^�"Cr��*�V+r/�J�Z��jE�]�e�-#��.2$�h�bj�!�2�d��N�6����^��2�^�"Cr��I1���L/��c����9�������m���[�H�L3��s��w��W�_�#Cr�*W���&c�tpU}����$6�!�
��������N:�����a_v��/v�!�
��������N8��'����/;{�w�~In�_��j�6�������	����2{���x�&��I/��
�/����px5�_����1�_kq���k&��j���$�7����l�I�+����c��_��jv��$�7������I�+���]�����;����p~5{�_��Q'���%�Gw�^z5�52�����y�%���[F�;�����z��<W����N������
���Kr���W���F�~�pz5�_����e���7�����Ws@�
�z��jH���_��2������k���9"�F�~�tz�~#C���e��	�7���(�W	�71���������e�.#�]�~S�~�bz�"���z��jE�]�}�z���������(�W�������6������wC��:���]e����_��*#�f�~��������UF���JGW;�of���:FL�;����_�^��;��txU~w~�����[��k����[�������[�e�}#����
�V1������Y:�����_��7��������z���}�qa���Y8�Z&�=H�+���bc���W/�Z��\��2v���}����[q�p����^-��F���,^-f��
���[�����z���,jd
������ :%����y��2$���^z��	52�vg��j�����d��`s���W/�Z|A�L��Y8�Zf��2�0����]��6�����9�F���,�_-��$�sY?c{�{����W���F���"�_-��$�z�/��!�
���% �r]f��j	����_���6�!�
���%"�rmf��j�����_����������������Y�������e�m���b��6�U��V�_���"�_���+��,���{�����������u�Y���
�w����b/��_���m��_m��\��E:��������$6�!���������n�������u�Y��	8�	�����>��g����S��k���^3�t|�#������������������[~�V3�txU~K~�(�|���MfH���S+�k��H�\�� �\U$��������!�wO��/u7L��\�� �[�	���v�=�6���
`/�=�{j�|����Bz�ph@/�}%���Kr������];�By�pd, /��<���Kj��������
�
�yUp�e������:^�{p��n�����
�
�iU���$���k<�.�m�Q�s��(��� V�Kr_I�G<����k���Ua�%�={���0���W6*G����Qg={�]���W8�
�.�}e�r�������go�(�^��*����=�xC{�W/�
�70�����x#G��SoD���m^��*!�Fy�tZ�y�������M������W%d��0o���Vd��g^�v�wWD��}�Y1�Z�yW�y�t\�!���Jo�
�wkC�b`�!�n�F��jC��8�>@2B���^��*#�fz�tb�zsz���~��yG��M�=W]�Zwwd��a�(�X���{�y���~����{y���������3�����[���DU�k�-������*k\�nE�-�J�U����������[�xk�x������8Y?�x���8��Ar?&��M��������P"SW(	�U���Ar;�
�Z��K����K��)(��*����h-���w�D��k��N2���������������(�����_������W�?�o7���o��������������������&�o�_����7������x��	���'��1��������z��~�U�}[�w�_�]��=���|���G��Aj��u��.�PA02�9�c��X$O��-����[q�0x�/���]<J�'5���bq�;������#v� �Gs�r�,J�W&eo�07 >�b�t���=�����bD~`�r���F�"S/_:s���������bD~`Zr��F��"S.���9�]��Ar����v1!?p
9���V8hAj_��7�]��Ar��*�v��_l�1�]8hAj_��;�]l�Ar��*�vT���v������1���OG��Ar��*�vi��f#��H��)��^��.�nn���R"�������vwG���2�����b�{tW1�*��\'��� ��w���#��$���bTU�w�>�QUE������G��
8H��]���"�r]8���4!�V�w���i�%��2"zYU�2JdxW8�Jx���r�z��x�������YQ"���YU2�������#������^/�Jx�4w�O���d�wI�+��G��]�w�^V��.i��+�U%�Kj_�W0���C��]��U%�Qb�w���#���������#����$���^V�f���������Kj_�J?��x�������2��>��g�O�{{�~8�����wI�S���l���pc��p��s��~��e���\�������G��?wDn���z�3�<��A/�[��i~�.��w�:���;"��?_��xFr���e{+��#�/�%����]�����\��xFr���e{+�#�/�%�n��+wH�?f�k�
�g$�������xT�4�p�`��pCs��������F�C�l�=�e{+�#�/���n��+wH�������,]�u�����xT�4�p|~��	nh��!9yw�	�/g��z���G�H���G��BM��9$g�h�{������z���G�Hs�]�lo��W������!�nM����������������w�Cr���t����ws�wg�lo��r�����9�uG�e����w������bV�G�Hs�]��� �2������u� ��6�*fUxT�4w����
�.sH��)
Qw+�ni��bV�G�Hs�]���"�2�����/uw�r5$�����UmxTncj�x��j��w7�������],WCr���eU����5��e��xwc����7,WCr���eU����5��6�]��1���WU��!�Gw���
��m�"3?�+�Umxwc��'z�^���%�Gw���
�������Y������,���y�]�{tW/����i��+�Um3����3Ot��],�Dr���eU���K,sqxwc��VW"�Gw���m���K�pV�-�����DJ?�X^����������Yb�c��y7p�+MDX^����������Y����-"�F�w��wt�������A1�J��L�%�9F���w��O���],�Dr��*fU+�.Sd�m]?��ywex���|�����H��]��jE�e�,��1��
ywex��J�����H��]��jC�e�,�
�G���w�>�&�0�+�����QUF�ej,��������}����bu%�{tW1��w�Kl�����;���/f��Dr��*FUq����"�w�nap��B�����H��]���"�25��E�w+�n��w��*��Dr���EUy�8�}�eFp7O0m����+|�9O0o����zQU6%����G�k`� ����}60o����Q/��vB��FelI��Z�6Hm������y�������-(������F������-���AJJj���%U�e�����Va�����v�(D�CJJr���%U��(����M���!)��L����p��}��^T�g(�E�;�
GUy����������f_��U�
h�����QU^ %%��I���C������<J���fk��p7 �w���q74q7�EU9"��>��Q�w#�ndpW:������qW1�J�����l���&���������wSw��������F}#�]wSw���ywm�nR��V����]��jC�]�}�f���n��[�w�bT�!�n�JGU�����x��w�&�&��*#��>�F��*#�f�wYu#���ws�w�bV�#��}�e������;���I����7y7)fUyw��n���
�nax�U7����[�������[�������[�e��p�"��&�&��j��wk�w�.��'�]R�sW8��'�]�{tW/����������8t��]V�w
�.�=���U�&��>�F��j�������pV�[�]�{tW/����������������Y��]�w��V���Dw��v�Kj{�
�U�78tM�5�^Z�{ ^��W8��=/���+�V����5��Lzq�>{��G�$W�3 /�����a��Kr���U�bQc�y�p^�/����g�p^�/��$�a�^`��	5��7	V{@�
���F�zCz���X��7���=7<������>��G����^3)FV�7��7IGV	�72���aoB�MM�5�bf��{S�{�tf��{�������������������7I�V+r��p/�n��r���^��jC������S�
�wc��U7�^�����F1��������UF���J�V�7���(�V;rof�W:���{�>�~��E���{�6���� ��}�5��!���_;I�oA�-m�5��UA�-}�5�tnU�|K�|�$M������(�V������O����G�������`{���W/�*SF�L!�	�����������
bHn�_����52��&����=Hn�_���`����W/�*�[�S�������~.�glCr��eW�A�����a��#�u�������mbHn�_���x�����pzU<$�$���pzU�Q�=�k���2[��������2CtJr{�
�W[�����z�UY&���������@vJr{�
��*�,��6�����RP#SD�MG�,���ri�����b�R��W/�*��kc�������s�~1$���^|U"�/�6�H�W�7��W|��`����W1�J��\�#_%����/�n���3��6�U��V�_�u����V����_V��6�Z��jC������jC���e�����������UF�e��#_e����/�n���:��6�U��v�_��K #��w���k���1$���S��v�_������
����_���/��!�
�����u�1��UE�-�Zi��2$���b|U��>2����2��V�ZY��k��^~u����H�{�
�Wu�%�=���Ucp�������j�It�_����_���W8����������W�z���/;�#����$���p�Q-�/�m���_UgQ#�������������Fu��$�Su?��_�M>c�|� �	e2���= 0��Y,qTLr������T�0;~#��-���8�Lr��Z>_���Q!�����pw�%�=w������������������_���.�$�syv���k�������D����ptU�o��~�������{j�|���72�����|#����jD��M�=��{��	�72���c�����m_iwbojb��M�k�]z�N:�ZzWz���wW�����{j��Zw7����]'Ym�����[FuC���[��v|/��wc��I'V�wc������7#����_={3of��I�U;of��K�;��9��g����3������wg��}���� ����^={2oa��I�U��0��8j��6J��������WUd��1�t^U�y+���w�jE����^��j����c^�������q��Y�{��v���=���W��q(����e������~L�����xob2���y�~�Q�^kP"Sc��V7u�k�0-��a/t���=���X�U��������>9���+`Zv�7�^�*s�{�W-��)�Q"Sc��FV��-���0-��a/t���=�P��n�6���������}`��W����o���U�.�h�ZduS�P"Sc�
���[���_����BW�����j��Mb�\o/Y��d�w����z���]��^���&q�\o/Y�� ��>����!�"��&��+�q�����-�e3��:����^~]?������{�����&�^�����ro�s/��aoB�MM�=W^�b{�{��2�tj�"��>��������k�{�U�������-3K�Vr���^~]?��
�wks�bj�!�n����UF���e~#���������UF��z����UF���J�V;ronr������#�2�e�,�Z���;����`���wor�����[�{��2f�N�
roa�{���{�{K�{��������t�1�tjU�{+����������[��{������	���+cf���L��$��p�u�L@�����^fe��9������.C����Zw
@/�=��Y��Dz�#+czIng�}�j��]�Kj���%V�n(�a�E8�2����r>w���8`^�{�W/�2.�D�y���8`^�����z�c�f^���x`^���W8�2���~&�Ef�p�����X�0$��.�����yI�+[�C�-8vM��z���1��0�"�X�����r�i��@/�=���X�`P"��pbeBo�C/�j�p��	�^/�2�70��V&"��>��o��F����^�XE���@�"X%�����Jo&�����������8��N�V���P��9
�"��M��������r�+Y�H�+��+��l7R���^��YmH�C�A:���z7f��m�7�����5��+fV�73��3�������D��kWV�7��W1��z3�A:��z�>����F��#��m�UL�
2��0o�N�
2o�3����u� ��&����UA�-����"��Z/�n��[zkzg���"�Vz�p`e'�8*����`���1w�G{�+;�(�_N�����9Hn�^���B������z��5J��2A8�����Q'����5�����^bem�L��+ka� �=�vz������� �ic�p`e��$����[����b�j����U�� ����T����R�����i���:�J�]����%�K��(W��R��y�U���������bPb�����q�] *%��yWzU�b�j����Uv�(�_@�D������+\>�
�Zwoh��W������1Q8���70�+|D�F�����E/��y��c�tZ�wc�w��x��	y76ywQ��.�3�����9����@�n��w���������������������|O	����������?��������|���}b}��O��O|2���J����h:����W�W��?�{�/}<V��s|��=���<Sn�D�h��f=sA�-�0�],4Lj���E{o�y�����u��4��bO�����C��,���y�$��b�&
G{��4���aO\���],3Lj���E{��y���I����+{�z[ln��Xe������<^�L�a���=?C����aO��],2Lj���E{o�y���I���_��?'g���s�~��"�$�h�^�����g*
�$�����g.��'n�\k/&�{�^������*
'�p�`b���������z���;b��4���=y��a���9�^,2Lr����{��y��p>��2/s=�����������+�#��J�I:�Zz��a���7�^,2Lr��*&VxG�s���tb�!�2��,{�o��Xd���U�����g*
�$Ye�^�z�eo����������^�\�aN�{w�^�~�e�S�����������\��I:�*���1���a/&�G{S+�&��J��tjU�{�b�=P5�^,2Lr��*�VxM�3���$�ZU�^���eOT
�w�*�$�`o�K��	�wfJ
�I8��'�^���W8����0�=���Z���D�
�$�Z�������5f�3Lr����V��(���:	�V��%�={�oP�Xh����K�f7�D���tUj���~y����~z��W�3��?9t���>u���WU�P�'��9ux��}���O�������S��>������o%2�'��o��
�+���\.u7�B*�B�����8���u;	�|s��T�_�|�����F\GE\G��z�J�.dg|s�uT�_����k�M��J��"w�"�9e��������������2����k�]q������������-[+c���{@r_�P|�������rW/��7�7I�{�
|��$���w���
�|�����&Is�]�|/���}�����V:�: w����D�B6�Kl��;���2�g����#��M�M��^A���5��^A�-}�u���k�-�����I1������]#|$m����)$MDy�6y7)fUy�r�+�U-�������{�M��o�z����^V�L;Jd����c���
��y3'���i��������Df��
gU��y��v�N"��=���U-6�Df���
9�]�7H�g�fv����#�eU��������pV�8�IIn�]����p���8�^V�x8I�{�
gU�����v���k���f'3��U��P#s��-A6���R��yx���rRR��W/�Z����V8�ZHJIn�^�}�e����6�������F�����n������O�~�������k&��j	���a^���{#2o�3�%���7"��&��I/�Z"Bo��W:�J���O4���������k&��*!�&�z������S�{��+RojR��#��we��=�2���w�Oa���n��k{���Ym�����!��n��[�{�t��!�n�U�2r��p/{�e���73�+8g����^��jG�����\F��#���J�V;r���^��Z���;���9�������Oe�����[��kS���[�e����"��>�>Q��Z{+roms�QL�*roe���'=��0!��>����U��{Im�^��*L	52���b/p/���+�Zcq���k�R�`�{It�^��*�^���W8�
v��ks��K���%�={�S�`�{In�^��*��C��^��Z�P#�����{p/���+�Z�Kj���V���p/��:�^�Kr;�
�V������z�U�52��n���w�h/����U��{Im�^��*�;jd���Ra��Kr_^Z]z�.,����h��K����F�{�-���^�����Z{rohs��K�B@�
��[�C�E�
�
��
�7�����V!"�F�{�-��F���p�p����{c�{�bj��{�����{rob��q(y�������V1�Z�{��������2�+�!V�����V1���{W�{�S�
�w�s�"�!6�����V1���{7�{�-��f��������`������V1������^v�2���7��w����{��*�V;r��p/�zaoA���N'��h�����[:���Z���p/��:�^���t�|�9_koE�-m�u��UE������{+roe:|>��/�7N8s�6�:��*NP��D��N��S�}�&����	�g���z�U4P��D��N������~+�h
�w{�R�hjd���[�#��0u�����g������6��K��3��_F��[�#�u�������5�����6��K�����_G����{�C{��.�h�{��SR��W/��~G��B����F�;CdJr;�
���3$���Sq?��_�=>��r�n(�_L���!CjJr;�*����ahJ��g�%/Ir�\��*.������':�^k.��!�sO-��57 �r�c���sbo�c��~/����5���=�l������u�Y�#�zcz�4�b�R{0����Zs"/�8f��"obZ;<Q	���c������������"�2�c,�#�]�x�>�����=cH���S���������,R�0wC�]����J1�b�R{0��.���nH�L���s3����� Eb�R{0�����f]�k�eYr�����O���>��0��6�����#�2]c,�#���t�>�Jm��0��6���[u��1���D��G]��������=w+�.�5��k��Vd��g�'�-\�.�n�l����&�]�k�e�-�M�.��<n�	X�������1(��� �S%�Kr?�%s2�����^P�LE����*Y���i����p������zAU�;Jdp7U�������uR��%�Gw����6���nN���%�w��$�q����U%�K�{�
GU��������n�lq�����U�x�4������Kr;�
�I��C���sE4�uw�%�w�pV��]��qW��MZ
]�w�������P"��Q8�Jy7�y����p7 ��&��+�q��y70�����wc�w���w#�nl���
������YUB��}�e�z#�M������
h\�nB�M�F��jE�M}�e�z#�]�w�&����q��+����n���V������Wo�����>���Um����Q:���w�>��_��f�������g\�nF���F��*#�f�w�wo�]�w��yw�xW:���w�>��/�������yW1�*��;���YUA�-�J'�y�4y�\��k�������$�UU�����tY�wk�w�U���]����n���	�����p�b�R{tw@V���������������~��o~�����������������|��M�o���7���3����������~�����O��O<yS9F�#���8T�����*���]�������[x������kv�w;n���w]/�[�\���1�_z�~u<���������6H��\��n�P!pe�n���F��!w"�s�S��m����z��:{��/=�V�a�����+���k����������~�Q���sH�Hm�\�Lv�N��h�^j��	%2eG�����R�1W8�]���=������i�a����F���K�'��n�.��h�^f����%G�c��������+���c��+��EvkZQb���}|B�bs�sS�~N�V��Aj���%v���������\k����2�+�a
R{4W�p��!�2M6���Zs7�������1�"�nM���UF�ezlX��*#��>��I:���$���bF�#�2-6�tF�#��}�5�tH��5H��]��� �26�tHUuKu�$�Rao
�{tW1�*��L�
+�RUd��g]3I�T�Z���U��*�.�_�
�T���[��k&a��&�]�{tW/���%�i�	�T��Kj{�
��f]w�����D��]'Tmp��������&��zI�f�wIs�]��j����������V�&��zQ��<J�����6�Kj{�
����wI��]��j�%�y�	gU��%�=w�yw���$���^V��J��.[�}��3�.���+����Kr���eU�\Pb�w�2�#�]����pE�m�%�Gs���m�(���l%���]R��DC�k�
H��I��^R������pR�������#7��vCvg��j����]��*"�Fv�'������T%����]/T%�����p��%����]��jE�M}���A����2���g�Ywm����Sm��k�u�tN�!�nLs�����n��[u��*#�n}���1UF���
c�2�nn���SeD��G]/S����A]�b�wwd�����bL�#��}���1UA������;�x1d��d�E1�*�����^:�*��������s+�ni����RUd��g]/�RUd��������
5H��]����Hy+13]5�pL�'�4Hm�]�Cj����z9U6P03]5�pN�
���������
5H��]��*[��UWf��*[�6Hm�]�Z�w���=���SegQb��(��n��"RR�sW�PF��$��n����Pb��(��n��"RR�sW�PF��$���^R�}A�LI��*����4����bC
�{tW/��sF�LI��*/������9d��$���^R��%2]$����@HJj{�
��j����zQU��LW�Y8��y7�yW��e�~��h�^T�#�.�Tc��rD���>��{����4H��]��*!�2M5f��*!��>�J�b��N���UL�V�]���,�T�H�+G���b;
�{tW1���v���tR�!�n�>�Ct���N���UL�6�]���"�Te����]�b�w���=��������X���i73��^L�.�� �Gw��i����H'U;����.{1q���N���UL�
�.�Sc�N�
�navw���#��v$���bRUw���tRUw+�����!�"��&�F��j�w���pRu����Kj{�
����Kr���EU��(��������]R�sW8��
�.�=��U�vB��
GU��%�=w�OU�x������v[P"���Y��,���]�j��=�������zQ��2JdZH
GU��%�mq��].�������zA��W���� T�`���^��!�>;�&�&��j�vIs�]��j�vIm�V�p��/��	�I/���]��qW8���]R�sW8d���C����T����>���j���]�V�w�nh�n����������="�Fv�k�#����	�I1�J���A:�J���]�Z�w�nj�nR��n��n��V���l����G��"��M�M�A����2�+TmH�+����+�����5y7)U�����tP�!�n���G���w�6�*&Uy7�y7J'Uy7s�+2�������Y�����y7JgU;�����tV�#��M�5�bXUx�>�F��� �x���#�-��	�fRL�*o�o�N�*oe���Z<����[��k&���LG���Q8�*���S�H��`�&0����^\U�����p\U�Gw����E6�!�
w���bv��/���ba� ��W�p�\��m���W���~}�(�WQ)���+�5lCr��V�%��/���� +%�={����}`Hn�^���x�dY�v0Q8�*�RR��W8m.���6������,�&	GVe��������v�!�
{�2��8������3��@\Jj{�
��{�����F/�*���~��$�Y�����k��#��n0$�a�^fUb/�&	gV%"�{�C
lCj�*FV���
��#�����+j`;R�pW1�JH�LW�$Y�H���^�����`Hn�^��jE�e��$��jE�]�e�{��;�����������4�I������1����a/��!�
{3������I��UF�����=�������k3����
��3��wg��-�1�^�
Cr�*fV��ic8uC�-����^����1�m��Z�^�?���S���[��k�"#���0$���UL�*�/�"f�����[�
_�����Kr���Vu�P#�u����%�=�S�j�}In�_�������k&����_���W8v��������EW��������U�@�$������p���k����~It�^���:�_��y���6�Z���z�����pvU=�/���������~In�_����5r�+^����v���zF�;�����z�U�+j��W8���G�e+���w�%�
�������k�*�^��Kr{�
��5 �����W5 ��~�pzU#�o`����3�����������~#C�F:��H���_�n��ol��SL��ob��H�W	�71{�l���������N1�ZW�tz�"����/[�g����k��bz�!�����jC���e����wC����������1�k������9��N�3�on��S��2�of��H�W;�o��W:����6�:��jG��9����
����/[�g���� ����_|y7�����AD.KGX��X|�"�&�Z?_knE���Z���"�V��*M�?�e�2$�����������y��sW6���y;w��v�=��|t�
d�j��Z:_k�	���"ce����
�5������5���2w�wO-��u�����"ce������~�K���n���i���S��k�u2�u�lluS�]��|i��[#��2w�wOm�^��7��)�keC�����L���/�k�]h!sW{0������VT������U�f����^����GZ����=��{����
���,O�pw1���/{i��j#��2w��*z�.Jd
����[���_�����F�=d�r����
��\'+U�� ��w��=#����	��jl\koD��Z�8���&�72����aoB��M�=Wd�Z{"/�K�I�U	�71����b/"oj"��"���"�r�d�t^�"����|F��"��M�=Wd�Z{7�^�����6�������3��
�wkR��"������q��UF��^l�0"��H��I��jl\�nF����8��jG������F<�;b���^��jG����8��jG���e�3��� ��m�U�
b/�O�I�V��p�+{��L��4��\��k����\?'ZU���`���b&�����s�5.u�L@�����pfe&�^��{xeOH����&��+�q����D���pfeP/������%�Gw�"+c
J�Z�
GV������H�����������z���%r=T�#+����^�VVa��%�G{�"+�v��5Q��n������������=@/�=���X��D���pbe<@/�m�c�:F�;{�&��+�q��30/i��+�X����v�]i(Z,]y�+���������YyIno���5a��k3�^`e2o`���M?������k���C�E�
M�=WT�Z{#2o��W8�2�7����/G�zcz��������9��N�Bo��Wx��$�����s%5.��71��v�a������l�����kz�U�����we���N?��
�w�C�e�]��wC����{�����nH�C�l��!�"�n}���OoF����{�����f���`/��z���7�����.G��#��&��+�q��;r��p/��z��;r���^�P� ��M�u��UA�-����G�[�zK�z?����[����XUd��0/��z����2�����Zw+"om#�^`e'��� /��z���u��$�=u��Z�sW{,���WY3�D���p^e
L$������k���1w�Gw��*k
Jd���qG�k���^TY�sW{tW/��6�D�}�pZeD�$�w�W�]hsW{tW/��nE�\�T���:HJIn�p����9�����^Ve}�l����zJIn/�v�����������D�y�w��3��$�����]c�j���%Uv�(�k�*�T�bR��qW�\���1w�Gw��*,J���
GU6 ��>����F��wC�w��*�w��1lS��F����]�4�w#�nl��bV�w��1lK��&�����'VU��������;+fU	y�k�6������������ZwW������bV�"�r
c���C�E�]������Zw7������bV�!���b���
ywcxW������[�wg��*#���b�������>�j3�nn����U���l���jG�����.�G��#��M�������5�ai�p� ��>���������Y1����L����w+�n��.�b�nE��M�������5�a/�p�M����]��]7�����zY��2J�Z�
gU���������������zY�3+J��
gU����������:�&�.zY��������pV�,�.������u���5yw�����%�=w��*��wI��Q_���C���E/�r��D�w���#����$�������������^V�f�����Y���wI��qZ��������^V��	%2���C���Kr�����#�]�wI��]���-%rMQ��*���]���w�nh����U����e{��p7"��>���OG��wc�w���E����.��m�����������&����]��*!�&�w��l#�M����������������Y����2��vg������y��~:�]�����A1���wW�w���
yw��.{�t���������Ue����]��*#��>��U�G���ws�w�bV�#�f�w�tV�#��}�e��pwG������ywgx�m�9������y�m�4����[������[�e�f�p�"��>��}�F�[�wk�w�bVU�w+��l��!�"��>��m����/�=���U�	�Yz�9�pV�'�7Hn�]��������zY�7P��s�a���#�50o����w=��!�Gw��*o���gz��=G�ka� ���z�
Cj���eU�y��T�e[*�p�ANJr;�J���)�=���*�-J���
gU�CNJr;����9�MaH��]����J���
gU~����v��Ss������zY��J�J�
gU~��n��%��n�����������Q"�F8��rR��y��{�����zY���lc�������]���cKR{tW/��y��#�U������6��.v�!�Gw�����������n��.��n�������Q1�Z�w��0|������k�w�fv#��~0����bV�!��Ma���
yw��.��n������U��2�.�F:������]��
������I1����lK��jG���JgU����U��v�]�#��g��yw��.��n���
���U��
�.���������������<��!�Gw��������F:����������	y�6y7�eU��K�{�
gU��Kr���KNC��8tM�MzY�l<Jdx�gU��%�w���������zY�l-Jdx��=�]�Kr?�;���%�Gw����M(��]�]�w�.��<��x������fWP"��l���z���yW����wI��]��j�%2�������Kr?�3���Kj��I/���5r�+V�3/��<E����k�����y�%�={���y�%�����9�&��I/��"o`���-1������k�����74��Lz��z�lw��F���j�J�#BolB������e�K��7!��>��mFG���zS�z��Y�����^���{W�����l������k{���Y���+����6��
�w�s/�z@��yC����k&��jC������UF�����6���f$��!_��*#�f�|�tl��|s�|�N�#���|s�|s��wg��mC0���w��/�Jv���wo��Q��
�o��W:�*H��O�l/�!�"��6����"�|�s���[���D��k����
�F/�Z&���/��`�����vIn�^��y��0��a�^l���1l+���:Hn[��r�����6����SQ#�$��E0�^���~YK�[�{�?�m��[-vG�\WT��jq����������
bHm�^��jqjd��:��j���������bHm�^��j�	5���Z�<�{!3%�{�C�[�����z��2C}��ic���#��!2%�{�C�{�����z���@����c��#�] 2%��
}����F���z������FeK4��7 ���{�b���'��6��������t��l)��F$���������bHm�^��*"�2�b,[l��	�7�����=�^�Cj�*�V	���c�b`#�]�|S�|���#��V1��a�bn�"�2
c,[
l������������bHm�^��jC�e:�X��{�|7�|�7�Y�m���[e$_�e�e����7#�f�|�Sg�Cj�*�V;�/�3���F��#��}�e��w���bnU|��1��6����[���v�a/��!�
{s����t��lI��V����^�}�{�a�=��c�������lM���	����W��B��{Im�^��*L;j��W8�
���v��`�{Im�^��*�
52��Va��%�{��(X�^R��W/�
6�F�{��`C��%�{��(8�C��^��Z�K�{�
�V�������`��C��^��Z�K�{�
�V�����:���{]�{�^jf��e���w�%�{�����Kj?��/����3�K�p1(�A_����@_��qXxG?,������Z:_lnE����F�<��_���s�oh����������`/[^h���7����4;������{j�|���7r�+Y%����^���sBojB��E���&D��!�t`�ySy�>�#�]ySyO-��5wE�]�e��0wE�]�����a����6���6���n����l���n�����a����5q��&���f����]�(�s3�nf6y�������{j��Zsw���p.[�d��;r���\�D��k��t����-���E���eK���� ��}�5l���D�����goA�-��%IF�[�u����Vd��9���nE����I�'�9jv
�fv�������.���q�Pb���e+��f���W8���7��������b��ic��#�50s�����YU��1$�h�^X-���L����a�������N�"v�!�G{������ed��X�d�{$�$�g�p^�u�=��XE�P"SG�-Y1�^Y)���+jD�Cr���EVq6(�_F��%+F�;CZJr{�
���;������\Qb���e����wqho���a����{�������*.;J���������^����K��;�����b@�e�X���{�{����R"��!�G{�R��{��1���>�����e���[�������UB�e��X���{rob���8;�^lCr��*�V+r/�?��W�G��"����-g�����6��\5�k���{��1����n����l���b��{�W1����L��^yaoF����MgG���cH��^��*#�2�cl�N�v���q�tj��cH��^��jG�e���(�Z����^��
;�������UA�e��X�`�{�{��l���b��{�v��ZU�^�}����UE����=g��&�����s�4.�7M����g�pj�&�^���W8�Jf��kr��j��k�{Is�^��*�^���W8�J���5��\5�k��%2���#a��%�={�S�d�{I��^��*9�9�N���%�={�S���{I��^��*��9�N��wh/��l���z�^�{�W/�J~G����HF�;�������U��{I��^��*�Jd���0�^�^���W8�J���ks���������\�{I3I��W?��7����O��M��_����x��7����0|����y����������~x������'���by��#��������|[�������*�C����k��9���7l�_�����������?��r>+1"1����nB�HM��z^Z#R#�����H+Cl����Hk�"�b��"E�}�`wG��!D�D��wG��!DlM�������!��|�nF���`���p7#C�&Cx��.#C�>C�{�C�E��B��wG����57�+�w;"��l�=��k��a������N����k��y�����Yav������8+���yw��7�Js��+�w7�*�q������V�������w����[������u�8�����#+���N0m���������7H��]�g��(�_���v���i������V��Ar���eU��Pb�@��8�]��������.6� �wg��j�%������#�u���4l���b�
�{tW/�Z]F��z����w=������pV�b�
�{tW/�Z���I�-�!�BLJj{�
gU+v� �Gw���u���+�~��c��1)���+�U��u���������L�
v�m��������pV�b�
�{tW/�Z�G������w�n`x���;�]��Ar���eUkD�e�o�{l#������]���w���=���U%�]����6�����8�������=���U%�]����6��y7q�+�Ua�
�{tW1�Z�w����w7����]���w���=��(fU�.����c�.����.�hw���|���U��2�.����c�nF����}vG���7H��]��jG�eZp�{l#���ww�w�6�C�E�����(fUy�������p� ��w�.�#���$���bVU�w���w+�nex���;�]��Ar���eU����4�`����M������pV�M��$���^V�M%�y��c��q�.��l����]�{tW/��LF�}�e��F�k�wIm�]��j���$���^V��%�y��c�.�.���+�Um����yW/���.i��+�Umx�����	gU�78tM�
zY���wIs�]��j�������pV���C�����Um�G�}�e��F�;������Y�6�����zY��X����pV�-������pV�-��$���^V��	%2�+�Umy70��6��n@�
M�
zY��wC�w�=��F����.�gw��y76y7(fUy7�y��c�nB����}vG���wS�w�bV��wS�w�=�!�"�&�w�6�#�]�wS�w�bV�"��}�e��F��"���JgU����]��jC��������pwC��8����6������YUF��������p7#�f�w��#�������Q1���ws�w�=�����;��l������{�w�bVU�w�>��{l#�-����]���w�ni�nT��
�naxW:������]���w+�nm�nT��*�nexW8��N��]���w36� �Gw���<e��/����p���Aj{�
gU�l����zYU6+J�
b��������+�Uel�Ar���eU�B)����`��F�ka� �=w����]6H��]��*;(e��V��w������pV����=���Ue�Qb�H.��6�]1)���+�Ue��Ar���eUy�(�_$��c��1)����v��.�� �w�^V��	%����{l#�] &%�=w����6H��]��*/%����{l#�
�e�6�}uG��wC�w�^V��n`xW8��y7p��������������w#���YUD����M�G���`H��]��*!�2Ma�=��&���5m�N"��=���U���LSv�m��+����.�2y����k�w�bV�!�2Ma�=��n����l���b;�{tW1����LSv�m��y7s�+�Db;�{tW1���w��0��ww����]�$�������Y����4�a��F�[�ww�w��HlCr��I1�*�LWv�m����0�l���b?���W1��H�L[v�m��H��!^�]�{�	��6��Lzq�>������q�>������a�n]y���W���Dw��(������_��%�$��a��]��I�M7���������O�I�O|�m���������p���~�$���=�q���0}������yB��c������]��������=�1a���W/��sA��s����{w��2���p���pN��6������{��0�59������9(��#����X���W/��.J�f,�{5�^H�Im�^��o���y3�Lz!�^!'�{�C��BNj{�
�|A��6��K�
�da@���`oA�,,H
�|A�t@���|A�0 �n`��A�������n�����yj�^�W�G���Svk��fR��W8�+����W/�+�����)��5�^����g�p�Wl�����z)_�j����{X#���Jj{�
�J+�OIn�^���������{g��2]�'����������z�U�3j�o��{X#�] 1%�={�S��@dJr���VeYQc���b/$���g�pjU���ko���������$�Z�����k'���D����^���D����^vOf���7r�+�ZE����^��*!��>��{2#�M����^��*!��6�Z��jE�M}�e�dF��"�����jE�]��kS�
�w�s/�'3��
�wc��H�Vr���^��Zm������UF���5��UF��m����UF���J�V;rof��H�V;r���^��Z���{�{
�)3�_��_#[��
�V1�*�������oA�-����"��6�Z���"��>�v[f����2�k�����[��k���:!��>�v_f��u�%�mul�G�f�.��N����a�^pU�E�}�5���{
�/����x���^�Kj��W�N�������a��%����p�\-�/�=�����jj���a7fF��,����p�\�/�m��]U�Qc~
�33�_�Kr{�
'�������z�U�+j��W8�����v����s��]�~�^xUg�_��W8��3�/���+�=���������Wu�%�����.@�$���p�\��c��_��^��Q#C�����o`v~�p�\�oh���K�jD�
���3#���������FD��H�?��_�->cp�tpd���apBN}����kN������V������ewgF��"�&�f����uwE�]��{j�|��+����/�73��
�w��/�:���/5wC����{j�|������/�13�\��_�m��|�&��Z6_�nF������w3bo��Wx�������������#���J�V;B���^'=����{�yO��^knA��9��N�
oa�{o]knA�-��@z�V����.��0�"�V���>�Q+omH�r�N���cX��s�w�����q��sWv��&���q�����hoE�Lm!6�a��hoe�������0v�����g��Q"S[�
sG�k-��Qn�^���������q6={��q���^���Nn{m���}b�|�����9�I�;	z���1,��^���&����_��:���:y�c�A)
�Z\u�@����S{e������~�K�d�y�4O8v������U7�3H������t���
�������n���;�Ji���:-%25u���{��.�������71�n����M-��S0(�����MG��{��N6m��A�
m�U�n��{����t���70��dC�N`�b�{S����e��#�M����^'�Z%�����s�5��7!�&�{���{W���q�tj�"��M�=W[�Z{W����^vm:�^����^��jC�]��{�����n������t��r��p��N�2r����s�5��7#�r�d���{3rof��K�V�77��\m�k���{�^2��t��;r��p��N�v������Jk\koA��z��k����������iA�-M�=WX�bw{�V2��t����p�+�nE��M�=WV�Zw+R/�I�]�p�LH���^��7q�����^de�
%2��.LG�kzIn�������`^R{tW/�2&�D�y�u�w�yIn�]�;E�X�C�D�s%5�u������������$�����j��C�$�s5�u�������y�q@�$����4�bw]x�����]�P"�l���z^��q�qy��x����K��lP"��^8�23�.�����Oi������K��\Q"��m��.�e���Zt��������zi�Yv��/{wg�������>�a"oh"��J��y���q�������O��v�������N/�2�7r�+WED��G�'��]�nB��m�U��"ob�w���"ob���&����������q����2�;K�U+"�� ��=���E�]�����
�we�w���6D��A^�M@�!�nM���qUF���������������f$��$^�We$���,W�H��#^���fG��������wg�w���
�����fS�xK�x�b^U�xC��t^U�x�����{+"om"�W��*"oe�w���*"oevy��?w��v���6����Uvz[����g�p^e'�:Hn�����fMc�r���V���t�1�p`e
L$�S�Jv�l�e�]��\����$2}c�"�WY�m�>]e�_�]��\���:�����p\eD�$��b��`�]�]���Y/�����~�\��U�CVJr{�
�I��-�.�h�^`e}E����f�����~qK��i#��f1w�G{�+;�(�_:�,���] -%�={��hX�s�{�W/������s�"�X��R��Q�D��p���*�.�h�^be2/�/��D����8�>�c#2oh2���X������1�pbe#2o�3�e���&�����Y1�JH�L����hE�MH��O���K�������;+&V+r/�.f�N�V����^���"��m�U��6�^�_��4P��
�w��Wz;aC������Zm��L��S����1���#��������bj��{��1&H�V;rof���LG��#��M�]S����c�tj�#��}��ld:�����7�wQL�
r/�5���� ��{��t����4�wQL�*r/�7����"�V�{��t��nB��M�]�R+7����������{Ing+�1]�I����5�w���q(��� Z9�Kr;�>��k�5@�����^f��A��
gV�����I��Tt�����������(��^���9�����������yI��]����%2��+��yIn���Lt����������P"��Q8�r���v�}�D��;{�&�����@�����p^�f ^��q�1]��bq�����*�������q�[xIn�������&�&��������nN�\@�
�������������*�w��Q8�ry7�y��M�k�������A1�J�����(�U%�����tV��wS�w�bV��w��Q:�Z�w���Y����6y7(fU+�����tV�!��}�}b�Zw7�����A1���w7�w���
yw��������w�6�*fUy73�����������������������Y����3�����yw�������[�w�&�F��� ��w�tVU�wK�w�����]�������UU����n���*�n��.��p�"��&�F���O����$�U�	�
��qWx���#��������P"S57	gU���Ar���;axlCb���EU�������uh.��P�]lCj���EU�f��/�k�pT���$��N���1����^T����Es?>���BLJr����w�E�=��Uy�-=�'�$���{�IIn�]�y[�����zQ��������p���;CLJr;^��q{�Cj���EU~�(�)�;	GU~����v�.���A�=����*,Jdj�N�Q�����]as�=�=���T��������pR�#�n������u�������IUD�ez��I:�J�����Ot���]lCj��*&U	q��#�T������O���]lCj��*FU+�.�#f���V�����O����]lCj��*FU�.�#f���6����]as�;�=���Te�]�E�$�Te����px|��bw�vs�v�bR�#�r-b&��jG������'3<v�!�G{�������a������t->���9�=��UU�]�C����*�n�������!�s��UU�]�A����	y�2�+��<�����zY�<e���.�?>�]�Kr;7��5��$���^V5�5r=Q�����������l�\w���U�x�D����f�Kr_>�qi����&��I/��/���+V����v�9q+�]y��W���F�y�.#����$��Nz������a�^`5�5r�+X�30/������:��$���^d5/j��W8���^���W���������z�����p�������>�Z+�o@�
��K����������|C�|�����7�����VsD����O��}c�}-� k��	�7���(&W	�71�k��������k�Y#�]S�bv�"���Z��jE�]�e[d
��wm��QL�6����_�0G��!�n������yC����k�����1�k�������=_�sF��m�5�����������������H��w�����F1���w�������3��vb1�����_��_�����t~U�s����4����[;���_U��������*�o�������}bHl�]��j�����t��N8�Z&�;Hn��,L�v�!�G�^z�(s�0�b�N�s�����o.�*��6���u.�a�u���ba� �/�����C�3��^��jq52mR��#�u����������,��6����oQ#�&�	GW�������R���bHm�^��j�'���Iu���2CnJr{����~1$���^r��52}R�pr�,�����l�kg�Cr��%W��Q#�(�	'W7-����t���#_lCj��WK@�e�X'\-�70��D��k_lCr��WKD�eZ�X/\-�7��W�j��]cHm�^��*!�2�c,[l��	�71�+]�l��1$���SL�Vd_�{�ek���wE�]������Cr�*FW�/�?����G��!�n}�}��K���1��a�bt�~�2��6�������+�F�:��6�UL�2�/�@����F��#�f}����<��6�U��vD_���e+���� ���
_ZX�}�m��]d_���ek�
���p���M^�/6�!�
��������^:�������������[~��/���|�b3]9�a&�=����0�����S�Tq��|j�|����D�g��*�_�����	����=����^kQ"��l�;�^�Kr?���`�I���S����uJd�wN���%�={���^Lr��Z>_moA�����U��������k����$�`�������������0������8��������=��{���������0�������UX�]�~O��^l��K�{�
�Wa�%�={����]s����������p�|Qv�n����:���#���������������������?����?��=���~����y���?���9�/�����o����O���	���O&{��D^bV�w���������'/������!.@i�yh����G�Ht�y���W�#s��<��"]�o�p������'��_<KG�{�
�|1�����3l�<���c��G�>����Y:�+"��W�#s���)�#��m��(����Ht�_��/&���ct���G����H��_��/�a:��W8���C����s����������Y_��t$���p�7(��ct�
�G��������a_��t$���p�7(��st�M�G��=��"a�i_��t$���p�3rdN�6j���������E<OG�{�
�}qG�eN�6k�oA�������E<OG�{�
�U���9Ig��y��������*�\�/��#�=��������3l�<����[��{�D���&<OG�{�
�Wi�M�):����MX����U����Kl�&��*��r�+�_%,�Dr��*�W	�%�H�b���71�������3������U��t�������/�ob��'�\�/h"�G�����W���M1�_����t��3����H��_��*�y���iboS����&�(�a���b�&�{�W1�Jx�.1����#���s��<�`�b�]����'�[�I8�J�ob��'�\�/�h"�G���G�[�I8�J��9M']�&a�&R{���_����jb�R��7"���/s���%�H��_��*"�2����#�M�������eVh"�Gw5������i��Rq�7��W��H��L$���ft�"�2U���#�]}�>�F���	�3����������i��R��wC�����������H��^��*#�2E�l��2�o��o.���>�=���[���\��(�[���{�{�p}����H��^��� �rE��tlU{���������H��_��� �rE��tlU�{��������3������UE���4E��j�p��L��'�"_��:��Ar�Js�u������s����Ar;�������<H��^��j5+jd���t9�^�<HnG������Z�C����s��B�-�@�.G�ka� �u�c�k�u�����+W���[$�g�pp�:MIn��������������8��=@�Q�����"����O���
��!�-1�!|E�uFC<�����cN�J@���/�B���]���/B����]1�[���
�����/���p��q���1"�1B1�[bD�c�y�t_�nD�E<y�u7"E�6E(�xkD��}�0�3���E��}�0������"b�"3�5!E�>E���G��"R"�$����H�M���"E�}�`�/��wE�X�a������E����Y3���"Vfe����w����c�}�_k�G/H��^�/[��'0��@G�����}}��Z{3� �G{5�}B�x��t��;B��E|�m�]k����7�w�L�v���O�l:���������W�G�[{K{g��gkA�-�����+��[{K{
{#{����6�w���*roev��3���[�}�����nromr��Zmp/�~!�`�6������G�6cp���;+�V��%�/�~#�5����g�pj���C��^��j�52�+�Zm�����N�6�Kr��*�V�����^��js����g�pj�9�^�{�wQL�6?��>����G���{Im���������{I��^��j�5���	�V���^�{�hkw��3p/�=���ZmsF�}�u���������������������������N8���^R��W8�����kr���Zm�7���	�V[@�
�>���Z{#rohr���Zm�7���	�V[D���>���b{�{c�{��*!��>�:��*!�&�{�hkw��	�75�w�L�V����^'�Z���k�{��`N�m+b���^��jC�]���6������U��nH�[�z53�
�wc�W:��H�G�������zsz�fd�zsz�td�#�fz�e�{w���	�A3��z�>�z��jG�����D�k_��wo2o�L�
2o�3��N�
2o�3�Ed�u�"��&����"��>�z���"��>�>QC�bw�xk�x�b^���O�^8��L�����%��M9H��]��*��5Z�p\�
L�������-9H��]��*[��Z�pZ�-L��������
9H��]���i���L*VeA)�� ���Ef��Ar��*�U���/M�6ua��ho�p�a}#��v$�h�b\�}F����lO���������Y�J~�f���nT������~eR���w!)%�w�72�� �Gw���@���4�`���pw����v��H������UL�r��L;���wo`�������E�
M���iU�H�L7���w#o����n����������"/���m�>������b�����b�{�W3�Z�y�nl'����������������Vd^���}��2��0�c�].u�p����������t�`���p7#�nL�|�F��j��p������UF�e�q�]�������R�l���b�{�W3��z�nl����;S)��V���}8H�����X�^���}����0-��:[C�E�-M�M��UE�e�q�-�G�[{+�#����k��.$�h�bf�O��L/���{�	������qhu����Kr��*�V��Pc{��#�5������
��w�Kr��*�V�)����l���Z��2=����#����$�h�bh�������oa��%�={�V����{I��^��jw+j�s/�k������3YZ����5�7)�V��%�{�S�����^5i{g�C��^��j��{It�^��j��{Im�R�����+���#��^��j_<jd�W8���^R�'\g_zI����R_��`Qd�z��#�
H������	��zCz���Y��7�����:������R�G����^3ifV�7�����:������~9'����^3ifV	�7�����:���7q����]z�&��I3�Z�z�>��5V��������=~=��
�wmB��43�
�w�S/[cu��R���^���{3B���^3ifV�7�����:���������b/RonR��43��7�����:���w�c/{{��;r���^��� ���JgV�����=�=����[:��ZU���p�thU�{k�{��#�������F3�������l����	g���^��{��!�
{S�2�(�_O���:�^3���a��[�i�m��[���~E!���-L����0��Cr�*�V�&����s�ba� �����mcHn�_���8�vY��1������������}cHn�_���x(wY��1Q8�*RSR��Wx_�`����W1�*�C��R�Q8�*3�����/{�b���9��6�U���bPd��.[�|��������
olCr�*�We�(�_M�-t>�����~�K��r�/��!�
����2Q8�*�70�+�~��1$���U��JD�e�����G���#���Y��b����W3�J��L������a��b����W3�Z��62lE�����+���i��b���W3����F2lM��n�����q�!�"�nm����UF�eZ��U�G���3����gl"Cr�j�W;�/�L���=���wg���#0�_�"Cr�j�W;�/�MF:�*��;��l!��b���W3�*��\?���"�������G��6��L�*�/�OF8���o������:�������U��d�W8���/���v�X�6�:��� _R������#�5��$�sUU�^;�����)W��������U�@�$�u�M�\p��������d��N��Uu��$�����1�	v��$�a�btU�A�L�I8�����~����%�
{���+��������:{�����6��Kr+FWu�Qd}�$�]����v6���]�}Il�^���.��������~In���������/���|�cs�("�>�I8��80�������|n}��	8r,_E$��l�
g�5!�&�[>_�nBNK�W	81��C�ENM>�|����71�k����we���8F��"��M�=�x���
�we����F��!�n���t���!�nM�=�x��^����_vvaoF������g����d�s������|3C���pwG����gi2�}�&��������wg������_awroin���������[�ep�����;�,�nE�-�m�s����[�y+������"�V�yEW�f����m�7�����7�0�!�g�h`�A����r{���}�U�jGr�53hd��vG�k�k�E0����-�g��r^�^�P#�S������~�'��]k���2�P{�W-��Ir5���vG��f����`Z���ZV:�q�}A�ioE��2����z����`>���Z{�v������j��I;j���5V4����
���E0Yq#�}�U�j���eV$m��_f�X�����
���"��y�M���2�P{�W-���1�F�������1;����`Z�����2�P{�W-�����i/c��2#�
�����Nz��{C�{OV���������1l��F����^'��������'�l\koB�e�����{ro�s��^Z%������56��wE�e�����#�]�{�>�:���Z�{�&��,�q����L{��^F��!��}�u����!�nM�=Ya�Z{7�^���aW/#����[�{��v�q�����'l\koF�e��v�2�^����^'��{��#��&����q��;r/�^��������{�{��~oA����{������^���aW/#�-����^���"��6�j�V��i/c���{+roe�W:������������{��2�]���L��$��-��J{��Kj�PS+cjd��]������������Z{
p/�=���ZSQ#����e������~�p�l,p/�=���Z��F�{�S�����������w�kr������6��q�pjep/���+�9�q���{�����z�^���!�Z�Kr;�
g�f�8tM�=Y[�Z{g�^��W8�23p/���+�9�e��kr��������������Y�{In�^���,����N1�2��F�{���{ro�s���M@�
m�UL�LD�
�����F����^/�9�������ZE���p/��aoB���
g�&!��&�z��*!�&�{���{W�����Ezi�"��M��������2���������2�+��`6�����^3���{7�{�S�
�w�s�me#�oF�����5c����9����2�o�O]��vOaG��M��������3�;K�V;������{���{|�flU|w|���#�-����wo��� ��&�z���"�|g���"��>��Vt����6��k�V��2�;�Vv���2��xO���
���Aj��*�Vv*���-��La�����v�^�Ak`� �G{c+k2jdj�����0u�����;����Aj������+jd
������0u�������u�g���@�^A#�Of�������v������adz�4��hd��|<
(j�����v������adz�4��=j����Vv����v����)�=���Z���F���"�Z��T�w���d���w�����UL�l�P#SR�ms=���Kr������{C�{g����^����z���70�+�cd#rolr���Z������Y�S����>�arojs�fj��{�F2���!�"�&�{��V+rojs�fj�"�r�d��jE�]��+����{�&�.������5�Y�S�
�w�s/��b/r����E3����\#�E:���������`���77�w�L�v�^����|��;r��p�t��#��M�]4S������Y�S���[���.F�[�{K�{��� �r�d�tjU�{��0I����6�w���*�/�LF8�r�o��/��`��|I��^���M+jd�7�Vn�%�{�c+g]|���_��W8�r���v����58tm�U����%�={�c+g|In�^�����C�_���9��eweF��|Ing�H8�r����
����52��c+�|In�.�c2��������h�bl��	52��^�a��Kr{���cI7���������j��W8�r�C��k�������U���Q#G����@�$���t#A}C}�br��o`�7
'W. ��>�Z�N�."��&����Ed���o�N�"�o�����5��ol�o����ob�7^]�&r���@�o�~�����������������������?�'�����������?��������|����e��O��O�O����/q�c�a�7n��W_�_����'t?���7����*�$\1��X��D����c1b(F�i[f��6o
��J%�>���It�_���c5b�F���-����1����y,FL�{�
�}��C5b���;X��C����b���1���+��y�F�����z�a%�e��^���c1b��W8��X����e�~���?�!&{�>���It�^���c5b�F����Y�_`�����Y��b�$�g�p����?T#��^����C����^���c1b�;&�y�F���?�W�����2�d�b���1���+��y�F���?�W������2�d�b���1���+|F�c5b�F�������{e��^��
�������V#��j�z����{(CL�j�VX��D���N���?T#�d�1��K���{e��^��
�������#��b��bz������{U�?�J���"&��\�a/#��b�������wG�=T!&{5S+�EL�{�J�VX���b��������Cb�W3��Z�$�g�tj������'�>������{�BL�j�VX��D���N���?#�Q{�f���"�������<!�V�''o����Kr;�
����Kj��*�V�1��9�9	�V��%���F�����������l*jdNpN���l=���-b��G�k�|I��_��j�;jdNpN�����|I�+��#�u��$���bp5�
5���N����}I�+�#����$���br5����k'��j���$�������	�fR�����T�������v���5���.]�~��^��/���+^��/�m�{��^�o��k�����98���pzu{Z��������9 ��&��I1��#p�X8��#p�0{�~���76��L��UD�F�p��x���S�o�A����6�����,��+����_3iX+�����6������!�nM�5�f��!o�kC��,���w���f���3��F:����������������������3���������3�+��;���{��f~U�w���t~U�K��C�#�-�����F3������_#�_U����_�T�+�om�����*�o��W8�Z�:1���+�o,L��,��_��j������k#������<�'�
����c9�%����_-X��T�Rbm��X�x9�'��_�����c9&�G�E�>1�~���a�X�?�W8�Z��������b~�`�bR�J���b���P������[:O��*�WV(&�=���K/����+�_-��C����_��j������p~�`���P���:���!;LO�+X�(&�=���k/���,�`-����:1	��	��E�Iu�`�k�"���H��GXK@>�'��a-X��T����R���n�f��|�O|7X1�Z�L1��,�aa���P��S��!)!
�
���N1��,b%��c��O^��)��"�6[�kE
^
fk �0xE
^�l���!�m��1���1�vra����1���hF����6[�+#g���2#�����`/td����`�d�����`'d���;���;I;r���`�$� �;�$� ���1� �k&Y9�0�v�apE.KG�9��9�i&Y9�2��"`p���k���/��	8��6VL����H���jDC&��'X8�����9�)&Y������IV0��$��K������9�)&Y������IV���$�g�p���c��`��dL�;{�$+8�`��{E�\p�������d8�'Y������IV���$�a�b�f�"��IV���In��x
��dC���I���~��/���|�c{�(V���������>
�f���x&�����2�Z{�%2 �����In�^�S�! �&�[D_ko@{� +���m�5���|n	}��!82��c���lgi{BplB�����&D�� 0��>�������*���+"pj"��������+�����2�Hg�+���s�����!���JX���l������5���&���f����_vn���7���=�?~3�onn����^���p/�E3���73[��7/�wG���[��v���wG����������3'���/�� ���u`E�oa��������[�
�E:��H��sZ����[�e���VD����J������66������L?;'Wq������>D�
�=��]E%3#�����5�_���LN`ElECr��*fW�z��tbe�r�����Ar?�h2b+�{�W1�����~=^;�W�ArJr_	�G���hH��_��*�	5����O�=D�$��~fk���[�������U�5������g���ke���;�������U�3j�������.�����+���
�=��P������~=^�\�_�����~y��S�K�~������ou���v�q���������|��k��~��o��gz�o��_����7������x������}���"�K�J3N��!�����*��]���=���>	k7��9>��_�u���d��/�0�&��y�8���b�&�{�W1�Kx�.1��"�������3l���b�&�{�W1�Kx�.1���"����mbN����+��������x�.q����/E��s����F��3�w���H�&�W�>{����=W�;P�#d�y�x��R`RY�����dQ���4�Q��i4�P��^���;�yH7��M�����Kx�.I��6e����$��s�P���
��`��Dy�*��W��0�I>�Qp����tN�0�`��Dy�:�����0��o��/�����8�aH�8���^6�~	��%az��/���#'�F��2)�6Q�k���/���$Lo�A���X�S���C
��M���>���Kx�.	���8X`D�B�p���C��s�(��`K��w��0����F\���[uN�a6��pl���ki��n]��7m�u"����#g�0�m����
5V��uI������|~d�Z�
K��bq�����^�5�X/�Qh�_e��||d�Z����||P�k��+��:
������_�_�Z����������kh�2^���\��+� Q�p���KG�;�D���~
%V��u��WYb�j���}^o���*���k��2^������+/�P�p�N��?�����k���
V��u��WYa�j��������	�]s��bh�2^���\��+o P�p�N\�0��w����{�C�����5�QY`���x��1������74�w1X9"���WG��#���[�C�������������Q�_����&��(���_�}N��	����J�I`���g����?:���s�K�����Q[`������-��	����*�E`m�U���k�C���K�K��#�k�x�������=��6[
��8i�����P���"m�X�8i��\y�1��s��6x!����'���<���������y��w}���m|�e^��g?��#"��Y.'�������H����m/h����K�#����Cq��
u^q3
�p>�7�v��&(-S��;G�P�k��6���y���
�X��2�j���p(��^C�Wf`�"��o��w���L������{��P��P�Hcp>7}�]�$(-S���+8���^�54ye�1�0�s���@������<]JN����v
=^�f�>'���np�Fi����)�}Ci��Z����Q8F�\�m7,��p��}K�8D���z
%^	f�>��������K����KD��m�5tx%"�F���;,}�MH�����H:���zS�z7�;h%!�&���+,��E�M<��D���������Y:�����4mg��z�p�T�
�R�zs�z7KgU�z�p����
Ro��W��R�zK�z7Kg�#���L�Y�H���������#��M��,�����K�G��={��I�F�{ �M��,����{����*r�!p��m#���������������^�������U�^�F�{"��M��,����{��+��P�>�'�)p��m��'�����z
��>���o����>�'����|���|t��h�������L���jw��Ai�z�G����k�D��j�0a�B3�*[���'���U<��>��6�`h���Rh�^ek��`L)-W���������
��Z�������p��.`L)-W����P��Z����W�����h���`L)-w �l�v\�Aq��Z�}=1#?�Tl9��m�z���w^��[/�����z
�����\:+[�=�RZ�^ek����{���Z��WX��([�= ��{ol&�[/n����z
���{��������Q��{	���K;(��^Kk��{�����J��I��[	���+;(��^Kk��{��������Y��;	:������-�UA��v,��� ��{ol$�[/�����z-����+,�X������K��m�pY���ki�v�^ae��G}D�r�.q����U�Z���:�{�����������"���uP�k����"�
�:mkU�{���"����tP�k����D��u,���D�=��m@����{6�7Z�c�����%ekuL�����W�Zn�G���hh��K��z�����{)-W���:\�G��^Cku�3���*[���RZ�^ekux�^�{���Z���<�������{)-W���:f�^�{�7Z�c>1#������.3�+p��m#�]�{)��^Cku,f��W>�����r�*[�c����z
�����s�8DzH������W�Z��������Zp/�f�U�V��Ki������<>�&�&Cku�� p���:ro�W���F�����dh�����U�VGD�����6�^�����di�ro��W =�������mD�	�75�7YZ����x��G��7#�f�{o�w�[oF��m���V�7��+LQoA�����������[��ki�
ro��W�<�����{c�O�zw�����n��V;�����81yH����7v����@�����&Kou �<��#�G�{ ��j{���{4��M���"�V}���#����UB_mqu"��&����\���'�����:�}O�}o����/���d_7��:-��UVWu�J��������������cH~�������J�����*.����~
����C�#�����><(-������I��6�5�W�W���
����3�+�{7/��W�P�F�����;����e}UP����W�oT�%Cq����d�O�
���.�N)-������L��^�u����0�
Ke����+�SJ����7*�����~
�U�`f��eU7�����W�oT\(Cq�����
����� ���xyD��Q��6�5�W5"�
�e�����7��{��s��sW�P�F���*!�
�e���J�������;��;e(n�_K����2A�_e������_�����2���������r����
�o��7i����U��6���W�W�.��UA�-<����s�~q��m�k��v�_a�L��W;����o���^q��m�k���_a�L��W����o�^�^q�����-�UE��DmU�+���������f�����_�������fD�'����o�^�^q��m�k���	�WX1#������)-����}�='�_�����_�S��<��'4#�u3�+����:�/�m�k��N�cH������)-����:=�/�m�k��N�1�����������9_�������]����:g`J��Q�Li���
��8|vm���\��)�pD�0��
�VX�r��c�Pa���!y-���W@`J�������6
6tX��1$���Q�Li���%��S�k����zp9��!X��#
�A�=i[�3 �6���H���`Q�(8"������#bplc�l��"bp�1X4�#
N��Q�-��:�����<[z���xU���������[�C
������������Y�`m��������k�C
.��������*��E�`m�U������=�1#�6��&kG.<�6pD�;��.��xSlH�;��� ���������J��>�Yx�YX6�#J>����bCJ>��&��E�o�Q��QX�#����U`a����~+�pm��k��;��$\y�}��~OD�*����r���� |6A��/�}�=�O�e����G>~v��9z������g�K��}����#���qD�	����'�3.7,I�]X=�L{i����}�u#
��&]��S�]���t�������g�K����m�G�(���t�#��z~J����~�z|
q��������;oQZ@3���G������;G=_~�9���>%)dX��`Da��k��"���C2�0��V�<�6����z�(L�u����n�~W~H���������g��{H��nf&�:]m�H�@�?$���B�~a��3n���e�3
�x���z|���/?$��S2G��|C�|_������+-����~#�o�W��9�����������F�_i������������7!��&��8��o�	�WZC#���&��$,�P������������f�_i���F����$B�p��77���1}�-���"���
�o�wV�.��
���jG�V�8m�#�<������;����_Ku �J�h���:���)�#�_��G�_���_�_i���W���W�B>����[�������V�_i���W'�o��wQ~��������M�}qG�~O�_i���W'���������/g1�����������\~��Bs�*������x�]��O�5�k���c8����)4����r���2�*����N|vM�}qG�~�������y�_���}R������
��=f��+,7�R�w����g `�{-��`�e��{e�� `���~R�Ly�,�T�(!���r������W``�{-��a�u��+;��7*(x���M\����)���C����������)�����7���������d� 0�h�G����p�������#BphB��C8�������r!8
w��/�c
F
�M
~qG��Rp(x��X	)8I���_}�A
NM
~qG��3Rp(x��X)8�|CCw=v87��}�-��Y`�Y�bd��3��|��
pi��8:��\����\W����#�M�-���<k+�x�X���h���:�	��
��|H����!t�h�����U`m�U����������������:�O�m�u"����������{6�w1X~Z�	
�+~C�����������_���a�3��_C�����C����>=(n;��������g�k����{���C���{����L����~��������������^Q��w^�_~<�
<���kh�q���+?�Q��+�S��������2�t���<�^�5�W~)�Q�+�S��
��������~a	�3��_C���������+�S���+�#��4���~
���O�U4�����S������+h�q���+����fQ�W> ��]���/�oh��j��|D����
aD��7��{gD�~#�ol��j������f��W	�7	�{c@�~�oj��j������f��W�7	�!n����oF��M�]-�UF�������� �f����!~� ��&����� ��Wm�#���g���wo��j��v�_i����v����_�pzH��������_�����U�_��������~+�������_U�_i�����*�o��������"��6�Z���W�>�j�����W�|?���l����'`i��,��	���s�~D��Ly/o�k�N�(-bU6X�[�`�����C
v����Z�������E��
k������C
�����Z����}���/q�(x�����R�Ly�J�yN�Q��MYb�3@0�}�
�����I������`
��l��(����P��N����j�y��\��k^�)n;�W�4�^��7C�5o3f8X\74��
8��rk��y����
E�f8X�74���$V/8 �6��9 ���M�������9���#rpls������Q�`m��������A���rpjrp�4Y	98	,��QpFN<��J������,EVF��#�����y�q��s�)87)8Xz��\
_��oA
.�]h���yG
.M
�kG
�
��Q������?�;B����`����]�`q���~����`�&��~d������bUd�C``q���~+2p�X�e��"�&K�U������������G`�&��~O$��I���a�H��@�"��w�����	X��?����P�k��
k��(�#RVX��O�����C
�u4��Z���Z\���<"e��8�����(�!�>�{)8*�����E�J#��5�`��E>�`�GCy�:�e������F|�kD�3T��|k�/����^�5tX�33i)���`D�T���4�1W|x�P�`C���3f|w$���WP���.����m4�����Z6����Q�a-T��
<���l��/n����~
����Q�I����0c���L/�<�����h(��_C��d`i'MTvXKD;�`�FCy�J�%"K;i������Q``�n�p
��li�2���F�3�����1��s�����^��XX�I�������Y���B���h(���di�
B����%m�U���2B]S�F�{-��b���^��m�v��]��N�;R����d����]�������CZ��}�c��4��Z���:���4I[cU��C��}�c��4��Z�������jq4���O��*��s0n�����-E��,��I�"�D>���(x����&'C��N����;��u��\���:������d�8�Bs+���S\�`�7�V?��ks���Z=p0��
V6Y���\��o�����ks���Z�3J�l��8��rk��u�����d����aH��oH��0��V�T��0�m4l������<	�I�e���
�$|������Q���Z�C�$�'e��n@����+]O��
@��6
6tY�V0$O�~RvY�$Lq�+�3�����k���]���O�~RvYk@<	������	�n2tYkD�<	�I�e�I8�$|�U�-8!�&���e%$������]VBN<	�q��FNMv����H��'a?i���$�y�^y����3��.� g	��]VA.<�0[�~bpa0�Re��"a������p ��b��#�mv�*kG�v�*�@�y�s���3�@>��,M��|,^.R0r�!��o������G��������U�`�r���+rpN��7�F|"�6;K�u"����G|"�����j���7\TCq��m�1�����;e��M�Bq�y7nH�'>;�ylh�6�`H~H�w�&ks�Bq�y9nD�����6
64Y����R�����<|�P�w^�Q0.�����
M�6O���+��(x�Jq�������(��dms����^��M���X�0CS|9nD�����6
6TY��cH~R���bD�+�T����q#
�E5�Z�74Y��1����+��m�Jq��
8�Un����66TY��47ia�xibD��T��N'.T�*7�TCq��- k�WVY[@<����� � �
U����5�$�G�(�����a�TCq[��� ,,��^[e%�$���v���qS
�ml��2�����{m�����7&��-W�P�F��*+#k�[1#
.�Ya�������(�Reaae���*kG.k�,�UCq[��AXXY��	�-Ax�I�o��(��P�F��*�@v�x�������`�V���q[
��<[���,,����������`�V�����k��gK�u"[k��m�N����`�V���q_
�mlh���,������
p0�}�Z����Lq���&)p��l�������Q�����
MVpC
<+���g,��`�V���=p0�mlh���1������
3p0�}�V���g�`��(��d�9cH�����C
�����Q�2��C��w����K/]��(L����eVX�)�;{Gt�:|vM~�kt�zWa�������
 Lq�������]�_����m��+���S�w.���w���z_�
����1������� @�x!pD�!84!��/�}����A@`q��z#"pX�8����������"G��#�M�Q`e	pj�k��}�M��I�_����f��$�����77���C���f��,��8�wH��Y�_������������� ��{�1�#�-��E�^��������_;�������+���������=�0��;�J�a���.��8�wD���!�����p ��Eh�~+��!�������U@_����~+�oe�
�=�}������D�=%��6W'���>��TW'��)�������������F\QCq����8U���%�����>=(�;7xG��j(��_Cy����D~U�W����}���~qA
���kh�������We{=|zP�w������P�k���*�0;3
[j���������s}wD�����^�5�Wq���Q�Q�We������C�=���<}^�5�w]0#?�����*�`O)�;�wG���i(��_C7��5�����S�������f�{���_�0aFa?����b����\��/.����~
�U���z�*�����������^�{���_���+l�����J��Q�_����q/
��l)�����������$������^��XXZN�i���%������^��XX�M�7m�U�������P�k��kGv��M[`����7���w�P�k���@6�xq��~�C��	���+i(���K�U���4~�X��������+i(��`K�U����4���\��\y���~��u�P�k���D���MY`�	������]�M�/���k����1�����*M�����������]�~_���^�K��z���J���2�~~z��^���5����}�����WY^%�Kq�z??<�\������/��[��`F�}���J3�/�}���l�f`_�{���]��cF�}���J�/�}����.�������J���
��*�����7G���R�k���*�3
���U�<�+���6��w�������*m;f�7(���})�;�6��7 ��&�.��*�� ��h�������_����F�������]���%��vW�7
g����#�M��������J��I��N������J��I:�����������_��#�����_~���O_~��������_����������?����/?���?�8H���p�Q�"���f������tV�������.���O��}"*���?��'���U��R�a4Q����;�
�h��AG�{�0�{��R���;���Dm�w�S;�i4���������9�f14~�c�t��_���,��/����cr�<f14~�c�t��_���,���/���dr�@f14~d�t ��_��,��/����g�<�Y�_��,��De���D&K'2���#����>�Y
�_��,��De���D&K'2���#����>�Y
�_��,��De���D&K'2���#����>�Y
�_��,��De���D&K'2���#����>�Y
�_��,��D��jOd�t"#�:�_<������_e<����LR�WOd�t"#�:�_<������_e<����LR�WOd�t"#�:�_<����u��Z�_��2��D&8��3�?�g�<��}�1z�A�F���%F*$�X|=2�N�v���w
�<c����4!�9�m�
�Di������&
O�����v�
�0�0qc7i�W���4��i����H;O��������#~|���
�2�@�8x�7����"KK��=���"K�&Kl�.�"KT�%��'C�E��J�X������,Q�,�Y��Y��YB\}2��Q��.w}����[&��z6Yb3tye�����~�Gi��.}n��������'i���+n���I��"�o��(��/&v��up�Fq�����=f�>����^�Ki����_�Ky����2O�Q8H��K�~g@_J��������������E�2W�(�}~��o���~����~�7t�w����z
�UYv�(�uP�w����p7n9��k�+�/���k(���1�4�C�^@_J�wc$^�z�]�|
�U��|)4���r��/�e~z??#�:���O�����[����;������s��y��x�oh�o0�V%"�|��U��Q_�z#�ol�o��V	�7��+n,QoB�M<��82�\oB�MM�
��*#�&�{��E#����Y�����3�f�����`��2ro��W\X4�����y��A
��-������R[���s���hD�;ro���|����7�7XZ��w��W\W4�^��]�=��vN9�{�&�Kku �<����F�{ ���Q��sJE�=��ki�*�o��W<�QoE��������!�"��6�ZZ�����+����D�=�W'�1�#�=|�&�FCm�O3>A|������� ��F�w�����^�5�V�s����"Z��:�����k+��^�Z��������-��Q�_���47����=|vP�k���j�f�O��*{�}gJi�p���g���Z������Q�~x���j_��RZ&��Z�s�HS�{��P[�K��hNo����)�e����������CgJ�j�}���������L)��R�6��CgJ�j�}�����'8��
�)�e�H��w�*>:t�T��������~�WY[��7��+����9 ��6�j�="�|�)�#����_q���z#�ol�o��V�7
�����o��W|�q��H������R[%��$p�����������:���{s�{��������^Q��� �f�{���[�{K�{���*����^q���z�{����C���{K�{�����{w�{�q�#���{w�{��C�Z��{�{���:�{�{�i�#�=�{�o�{�������ZU����^q���z+ro|o�r�[/�����z-����+,�gI���D�=y��s��og\�Ay��Zj��WX�!�e9��cB�=y�U�V����?:�{��P[��y�GI����RZ�n������~�d(�W0������������������~
�����W�\���2�j��<f�����n2TW��K����������=!�X&|vM�u���:�_J���(x������R��5��M���Xg���8>yD�+�/�e��i��<V�_����P_���<�w�G��SZ�lA��
��6
6X�vbH����-G,�'��b�
�# �&���`8�,�o9���x��*�s�	82lh���y_��oB�<o��&$�����JH��'`���	8���������,
VF�k���y��������,
VA.k��\x6P�	��	�Y*�	��,�Q�����������#�mv�
�@�y�
�@>��~����[��|��Y:���X�(5���|���tE�mv��"W�������U:���D>��,��|�,~�
��N��q��n���+t��2������S����!�#nH���Ai��b2�_\0Cq�*��`$f�e�U|xP�oDAW�0Cq�*��a&f6�e�U=|xP���.���[q�����
V�a(f6���HF�;�?���%�/XW�P�F���.3�F�*;���@�����%��;f(n�_C�UW�!���QYa�*��f~�q��ml���zbH~�nTVXu��`~$��s���W,�3Cy*������V
�������C��M3������X�8�V
���G`����~q��m�k��jDV��N
�m�/O����$"p�
�����}������������/?����/?��+} ?�q�����������������?���w�����8�_����w�O]8����������?�����8�G���=���������;���e����	e�wN(^N^��X���w�9�����~
��9�k����N����?���������m�k��N�0$sM|}uH��](-����jH����k_]�
�����P�7�oQ��Bi�L���y�G���6j�s�B��x=jD�3xJ���������k�\�
�������&�5����}�A�~��Fq�Z�su���������v��o�{�v�w�kk��Q���;�C������;������;}n���Q���;�C������)-S����]��8�x6�~g@<'�{kgD<������#����w��_�x����#��I�aEd��3����}+N������}���nBN<'m����w.�m7#�&����o��7��+���nF����[7�s�vs_�����������W���m��������[����W������E@_mu�#�����vwd�����}q��.�����|chD���.,j��~H�G�|_;��[���{���&mqU||�����"����F�z+bo���M���D������7���{"���}�����'��n��V'2�)��*k+?��g���Hc��#����=Cs��j�G��v<�2�*k+?���g���Z���/s�?����a
������+��&>?�6����W�x����_]k���_/���l�a*>���Zv��O�����������;�okyeo�����L|~�g��8�����&]s�H�B�������z����.���Y�����W�M���O0����nVvW�t��e���0��������Z���+?���g\�_ey�H����|~g����������z�9���WkV�W~�y����~���##��e���~u��#�o��wV�W~����y��#-�~#��e���~u��#�o��wV�W	��2��y�e�oB��L}�����J�����;W;���{���<�2�7#�^�>�W�_e��������2��e���X�����{����_mU������*���y��s-�~�/C�?����v��"������/���[�����������W��.����:�/���[����������W��������*��e���`�����{����mU�+�����:�/���[�����������W'�����������{��<����M����W�_�	���2�j�+7U|vm�5�W���Q�_���~�/���_}��k����^�J1�W�
�������R�v:q]���_�Kq���+�O�(��x�mD������{g�_�����)��_C��3
�+^a���Kq�??�9v�����^�5�Wn)�Q�_�
��~�)���
n]�]|tM�}q�F�zW�_
������
�Kq������n�����������n����WY_�
���2�j�0��k���C7������
���� �������������r�7�+�`�oD��<�.�xc-�UB����7�F��������K�������*!�&E�oF�M<�.���.#��&�.��*#�f�l#�-�����U�x�������R_��"��x�mH���E���}<�v������R_�������
��������Q�x�@�����X�����W��6������wU?���G�KU�������"�V�WuU�k�Ku"�V������{��������l��b�����	
�+�`�������2�j�+g�q���+�&�(��o�������e���W6�<�^�5�W����Q�+�`����_~*��m�}���3���~
���;f���7�F�;�=��������^���p����j����1�0xW<b�/�S��N'�	��g�q���+�D�(��q���~����~u��s��W�<�^�5�W~� ��w��G�#�]��R��_��z�����g�k����of���p#����R\&���G]�_y�7�L{��P_��1��vFY_�����>��74�w5�W>"�Jkg���F����o��o��������Z����+��OXG��#��wn?��7!��&����*!�J[g���f�������W}���������*#�J{g��!�"�f�L���oA��m���W�W�<#����� ��L������[���Y���W�=�����������o���wo��f���_a��OXG�{ �<���������h��f��*���}��'�#�������;����[�k�7K}u"�
�g�x�:���������������g�7Ku"�
�g�x�:��yB�=��q=�k���Kq����y�1�����jv����������:�_�{���_�.cF�7e5;�_����������������Rh�_e5{�_�����yv����k�����Bs�*��y�����������g��_C5/f�wS�W��Kq�~�_?��_�{�7��y��Q��M�_�+�/�e��~�h^�)��_C5of�wS�W��Kq�~�����/���k����bF�7e5����W��2���������������F�������eH��76�7��9"�F���UD��<�������ol�o��W	�7I�����o����x���f�����`��2�o�7h�����y��3�s��������_��,�o��W����{g<R�~�oi���������A�_���;��w�#��wG����k����]�������Cx�W��w>��&�FKu ��mU���W���"��&�FKU����A�_������;����{"��M�����D�=�
���D�=��������{���_-��\��3N\p0��e�O����}c��3�����Z��\��3N|�zD�>=(.�����7�P�k���j�0"s��8���z����L���7�<Cq����e^0#?����~g���9_�����{���_-����^�����=��L�����<Cq����e�0��F�_-+�S���{�O��W�P�k���jY+f��:q��~7����1���!����{�7��e�1#?��Ee�������}r��3�����Z�����Ee������x�5�_\=Cq����%"�
h\T�WKD���r���:������-VB6���-�p�C����`$��$�di�2����Em������Q��a��3��Z���*����VA.�~D�3\?Cy�[:�XXB�������waA�W?d��3��Z������-4.iK�!x6Dx�S\@Cy�[Z�)XXC�����H���"��3��{-�RcU�`a�K��"WaG������
�{)�M�"�D6���-�N�Sa�}�}���&��Pe��0��VVY�$Lq���������I�n2�Y�[0���IYf�P��r
k���
S�F��6k�C
,��m����).����Z=�0�m4l���y��+��u��������,Lq��u�R�ae��.�aX|�bH��0�ml���e��<{)���W�a�������S�F��:k]3��a�O�:k]�).S����u���1,l���
X�Rs+��u��L��������1(l����(x����Z�pP��g���`$��&agh���$x����Z#�p�IX�S4�'8"�6;K���#�~��Y	A8� ,^*RpBNmv�.+#'������2rp�9X�s2������,UVF�<�I[e���s�x�dH�9��9�Y���\$�6Y;rp�9X�s2��9xos��4Y;r�.q������w�P����o�r���`gi���C�`�m�����`�(d�OpE>��,MVE�;m�U��+���I�����+���&�D�;m�u"�<�'!C
>��O��
M�6��e�����?B��|�G!#�p9
��6�
U����gy�����|�P\�a�W�6\OCy
������R�������
4���!
����h�Pfm�����^��e�6�K��\����������
m�6�O��N�fm�T��5�=��%5���������!�Y�^|wH�`S).���w�
��P�F��>k[a��&l�����#^A�R\�Ua�������66Z�57a_�����>��r
���U5������z�!���^|wD�y8<,��!
����h�PimyX�Y���qG4��#��7����_\VCi�Z��4,������#�MH����;����j(�����g%daag����oFN��|��74������-}VF��x�u�
d�,������
����h��gdaao�_��0�pXX��C��5�����������5^|wD�;��.����
��P�F��>�@v�x�u�
�����7dG�/Z����6
��YQXX^���qG\�+��7��m]���5������:���5~��Y'�������h}���5��c�?|����%�T���!"�k��l���,|�,|c0Z���,Li/?��}���n��(���l�����w,����	S�K��}����+Q��Y�dLq�~��WLy/���
�o�>aD��ge�<P0�e.W*���G�d���>�mw��\��+�@������P��k�����	��}{�[��K��z�VX)��������R��5��������3F�wVXa����L�+�/�����1p�~7�%�U�Wa������}���)������;�{bD	}��U�+]�V�z~C� ��s���� ���|yD��7H���:"���9���
�7
�+n_QpB������N����mXpB�M���������S�����������3`�z3pX��<�����3����*H��}l��
"pX\�<���\�3��s����}l��vd�"0����vd�]`�;���#��3`K�u �/��@>�3��o�B���
mi���C��E�bU��C��;���\��k��-5VE
�kk�)�
,^1R��|�)��c�H��D��+N�r
,^0Qp��5��z���c��`F~J�_�=V����rk�qqc
��l����i�Q�[�We�|�P\�`�V".�����
=V�0M3
kk�����������J�}5��Z����3L�����*��8�F��\��&+���{-��d�e����^�*����H��\��&+���{-��d��aF~Z�_�MV\A�R\�`m�q_
��lh��zbF~Z�_�MV�f,XX�(^6R0������
MV���O������8��rk����j(��`C�r������&+�� p�x�dH�����^64Y1"[k��m�"rp8X�m2�`�WCy���X���,l�����J��I�`�����q_
��li�2r����o�&+#g����&c
F�M~q.G��r����o�&� ����&C
�}5��Z��������5~�6Y;r�.p�x�dH�����^�4Y;r����o�&�@���)��P�k��&�@���M�dU��C�`�����q_
��li�*r����o�&�"W���M������-M��,l�y<'��O��S�`m��&������&+M���+X�d�	8��2��M��&|xm64Y�Sh�`e��p0��
�6Y�U|xM^MV�3f88(�����)n;�
v]��@���Z���J���e��f�`��Nw����;S�k��+�'f8([���X/��7�o�0���k���r`F�����J+0�m����}�]�)��^C�����
�+���������w[��5�w1�Wi���\���*m@����g}�
]�}C{��o�7(���}����_�!Gd��d���^����
��*Ed�(����oL��������*!�F�}��UB�M����oH�	�7����^e��$�����H�Y8��
)8#��&����*#�f����#
.��Y8��
)� �&���� ���������p|c�l��wd����������w��������w�X��7��)xoR�j����C�������C8��
)�"M^--VE�Gm�U������_�!���������:��O�����:��O����~c
F>����<-���&+O�Bq���MV��4��Z�����cF~8���&+;���\��&+�n�{-��de?aF~8���&+{������>�`\NCy����+f�G����d��k�������mz���������>r<������_��������?��?�|��������?������h��_q����c�3���������������?�<^�?�#����&�t����_3�co}R�9�������?��8��C7I��a*%��
V�9�������?���������G��e��.�'�0�TJ
��s�O���/�����/�Q7?7�����o����O���H�D�O[��t�oy�3a��3a����_����Vj0��{�����5}3t�y���E�!��H����n:���_���C
��k�����������]����H�\��_�w~�������{�}�{��P��c���*��=J�~+B������Ny�~+"Em#��	��U����F��/"E����+�}�=�(j�(,E��Dq
�4>�
����������]�-8��^�5��e�(�)���|�}�-8���2�jc����2���5���-��_��?�������W�
�?/��������+�cF�����@�������O�{�
?/���T���+���c���u�g�S\����~^.���`��|e��Q8���*P��q�9��
���Vp�y�?��

VYv����JrH�8���r� �����r~N��f�(�i����).�N�
C��_�}^.���_C�U6 �r�����~q�9��~�����}^.���`C�U"�e���"���s���=s����r�}N:���/�?��k���).w��=�����r�}N[J��|���#7I)G�S\�`�_�8��\f�S��+#_�(X�b��s���!�����/�>/����/��"_���W�b��s��~�s�~q�y�L>�~-5VA��?���������[yg����r�|N[j�!�2��C���S�o�������e�9l��������k,|Nq��wN>/���T����H����
V�X8���2�o������2�����X'B�e���~�5�=���1��I?>/���T��������k�����~+'I� ��Z���������q����|~P\��=�����^6�X��0#?;E\#9�` ��	�>J�=|�P�k��k�3��S�5�C
�=�5p��!��Q)���d���y����q�������+��-x�Jy���}�����"��S0hT�������zT*�Pd�+����o��3��<*��f�Eo�T*�Pd�����o��3��
<*��V�c���E*l(���`F~�������rp�8X���������d�98�,��3���V���G�����di�rp8X�d%��$q�
U�������,MVBN�����$V7Y98�9��de���s��FrH�98,n�RpA.m�4Y9��,��S0rp�9��k�S�~w����`7Y��9x�9xU7Y;r��s���F�| �Mv���:��a����:�����-�C~E��G���d��*��������*�p@X\�9��� \� �&K�u"	W���)�C>��O���]�C>���&	��Pf������n����Nq���u��s����g��6��*��YX|9dH�8��r+�Q��A��e��aC�u�C
0����Nq����6�����$�g��>��C
4�����Nq��o�w�Zy�$��34l���h��'������:f�a�������8|v
��c��L��>�X��)�Cb�|��k��3�Y��`H���OC
^�)�Cb��S�F��>��<��YX��4��
X��r���o��0�m4l���0aH����OC��A`�I��# �6;C�ud����x�iH�Y8K��\���pD�mv�>+"G����OCN��Q�~~��l���pj����Y	Y8�,,^�0�p�Y8}�Ek��oFNmv�6+#
g��mVF�<
��oW��� 	�6	;K�U���@��.� 	���'�A�0 l��v����x�iH�;��������}����w��-M����,^����|�|�fV���R���`o)�*R��S�xmbH�)��|�bV�~+2pm3���X��,^����\y������	�l���X'���xebD�u�O��'`����~+�����~
V�
��'m�U|zP�7�m��w�P�F�����!�IEA�`U���k�#��]5��������iVaeM��W����}����~qY
�m�k����4���&h��:�=��o���o�G����������!�a�A�_=��]�1�������J����_��aH~X�x!uH�+�S���}����J����_������mU����h����_�TCi������n��G�������)�w�G���j(m�_CU����F��<����x��1����B�=5��������WXW��UD��<��x��o�����6���W	�W�V��UB�M<����TqO
�m4li�2���&����yvb�1
#�6��� k���*���g�;cf����U5�Q�������5Q]b��;�w���-W�P�������{��R���SD��Du�u �<��)��c�VCq/?��}��[��,��I��"<��3��^�UCq/���5�o�1XXX��5��\y�~����J{i����}�=��u5I]b���p���9!�M~��s�v�	�23�j+�s��o_�������5����}�u����iW[`�����-(;�[��5��������#��+��3�]�Kq���}��@�����k��}��F��W|�gH�3p/�e�i�;�R�K���vn���<�&mmu.�������OxvK��������.f�W�Z�+ /��F���+ /�m�{d��Z0��������y).�������Kqws��f���I��Ky�x�/�����c
��_7i[�3 ���W[[��7��~
���}#����!G��(��������G���*!�F�)DC
N����_�.�pj�Z����xvS/}�=>�����x���7������#�����G�����_~���O_~���_�>����������������_~����T��+��W>������t�kv~d�����|�}��M'0�G��#1���j�?��G�N�=2��q�>����#��?��y�M���a*>��������6cF�CMY�=�E(x>����#�ok�������5e����A����^��=�dxx�)v_Z���3�f���8�����j�+��G�/�/3���G�3�j�M��ov�C��w�^��=�m��R���8��o��`F��:��cH�y��/w���{�[�����}qnI��s�����?�\����]���+^S��8��o�%@�"�]�dH�e��/w�G��nG.M~qrI��w��]�`�dH�;r��s�Wv�0��{��_]���9x8X<R��|�����=� M~qvI��+r�!p�x2���\V7Y9��9��dU��*p�x2��9�
�n�N������&�D>v�&�O�	r�<k�,?�����ch��t`Fi�����>A(/S����>@(��`C��]����qQ��)>A(���
=',��/����
64Y�'�������R��O���aC��g�?@�`C���ga�����<�I���6�-x����H��
M�_V����D�?��L*�}���s��T*��d�u����qQ�)x�Jy�?l�[�
"��^64Y~s�QX:.��!o`R)���
}�@�R�k��&�o'fv��:H�a���%Hw���C��
M���A�`Q�)8"���6�-8"�6�,�������S0rp�9��aC��rplr�bi�rp�8X�d%��$p�����g�������de��,q������Y�`u�U��s��K�U�������RpA.<�9l�\0rpir�bi�v��"p�����#�<�9l�[���79x�4Yr�.p��n�����`1�����������:����gu�U������4�[pE�M^,MVE�����������x'rp���?{���}L�����	����Vys������y�o��2��L,��-����3a(�����Lh��F�?��?�o�e����<�`C����gh�`m����g����-xw����'l(�����=Am����g���t.�����<
�����?Csk����?��?�o�|�[.���`C����gh�`m����g����-����r�N��F�?Cs����C��y�x��3�	g�e~;l(������-�V������X����}���T���[a��34W���[a��3�7r�xu���e�;l(�V�����-�V�������4^��������[a��34W��5��?�~#7�����kr�jh�V�����m�V�������4^�^��
M�
C������M�
S��y������^��S��&k�����\��&k�������M�u^/�
�����?Csk����?�~#7��
8x�Lt��
M�
c������M�
s��y����k@�Lt��
M���������Z#r�e���M�5"_&�S��&k���Q��U�dE���\w���kB�Lt��-MVBN��&+!_���4^3r�e�;li�2rp8xU7Y9�:e�������s��7K�U��������*����`���kA.M�,M��\^�M�����~�x����6[��9x8xU7Yr��s�xzH�r���`K�u ��&�"<����\��k��������U�`u�u"W���K�C
>���&K�u"����9��9X��;��m�������dm��H��[m�&k����2k���y|x����dm�x��\��&ks�	By���M��'|x����dm�x��\��&k��	By���M��+>���`h��y����M�dm3�T���'^�R�"��^64Y��0�0C}�6Y�&��2k��m�Jq���m91�0C}�6Y��`��u�R���W��Z�����3
3�7m��m`R)/S����6��Z�������]b�����T���m��Uxx��K,��- ���M��������!G�����hh���%�6Y[D�<��z����c�����J��I���n�rp�9X��;�`�����hi�2rp88�����V7Y98798Z�����&� ���MVA.M��&� �������������!���{��������w�����:��w���K�C
>���&GK�u u�U�����K�C
�������&�"W����������`�R���O����`K�u"�u�u"�<��zG&�������d�	8�Bsk��0S^�`m��������d7cF���MVp����)X�dLq����f88j�����)/S���
8��^64Y���Q���m���`�k��0S�k��&+�f88j���S^�`m��`�{-��d��`F�����
+p0�m�/�)x����
MVXf88j���S^�`m�6������d�
8�Bsk���S^�`m�������&+�� pp�6Y! ���K�c
Fm64Y!"�����
98�|c�������&K��������&+!'��oB�[pBNMv���J��I�`u���������!��3rpnr��,UVF�'u�U�3����!
��a7Y���$\N�.kG.<	�;S������{��di�vd�]`��n�vd��gawg������	�n��Y��!�pR�Y�������>�o�q�h���,�VE�'u�U��+������#�&���i�H�U ����N$��'b�%�!��ND��AbC�����I[j�	>F(/����p��5�������aHi�����>E(/����p��5���3�Z��RX����V�36������0������
�V����&m�g����O|QnH�����66�Zq.RXc#��0�U��4�}<q�
�m4l����5���f��Zq�Jy��n|w=|�����6
6�Zq���Q�c3i[���W���x7>���l(m�`C�7���=6����XU��|I��)�������aC���!�E6����i8;&n|
�mw�P�F��F+F�ai���m�bD�������6�Kl(n�aK����U6���JH�Q�2q��V��q�
�m4li�����fR7Zi8I���56����4ZiXXf��tZ������gB�a�cCq
[��4,l�����*H�EX4q�d�o�����6�4Z;������<�J�[��_�>��8��������{�{������?����~����������?����������������_~����CV��+��W>|jy�_Yz��~j��{M������p1�g��C�|�����Ca(s(R�`���_{9�����*���q���|�Z����Rs
k[�����r'I�
'���`3��9������9����Yi7�'|xm��
5`� z)5����D/����7\���E�7����R�"�
i�����L<m
��^��h�P��aHA��7��D/�}�e��
� z)n�aC
��C
�W|cH���
�����|�>@�R�k������!�+����+ 3�e�ik�\��k��gC
�+�p�xX[��<\y��0���������'��)���#C>��O�����].�������i�	x�Rs
k;�2S^&���*n�������i<L�����Vq�������������<<:��g)���#C�����o�vZ�S�F��N��C
<,����g�a��4����<Lq?���w��Y�K%��O����H2��e��y$���VY�)�����/�}�]�(�$C�]�)/����*+1�����W����#
8,���~�)/����*������}����0L��~��V��)/����*���k��k_��������:�D�������JDM~�Kt�~#�p@X�!�F�����.�"�pl��k��}�M��Q�`C��������*+!�&�v(�����	dH�!8�.�2Bpn
�v$��_��,��H C�-�����E]c���>~�D�o��,"���w����n�v���aX���,2�����w��u�u ��i��D�C@`B�| </�
�"�y�a��
,R���+2p���,�]>�k�<��b�H��D���D
>���;�0:7�|���
=�>-�%��X��!���iTs���	>B(��`C��;��9�^D�!;���L�7~G�-��G��lh�v?aF~L�QdH�>B(/�5K�$i��	Bq����W����"�)x��`~r��}��� R)��`C���;f�G�{E���J��L��gI�&��^�r��}���P��_�c
�Jy�'�t-x����J}�3`X�
�(4W����Wp����	�>-�7�U�����
�)Qh�`m��o�R)/S��q�����P�>�����`F~a�F�������y���C��_������$�VY{D�<���{D�M~qXG��rp�8X�d%���s��}`�'�����gut.98	,��)8#'������E�9879��Q}���Y�`�gdH�98��_��6\�K�-UVA.��*� ��������
��*kG�^�U�� �� ,�U3��Ixo����:�6| 		��.�@>x����0���D�'u�m�"

��2�"
W��\��k++�pm����:�|"
W�Wu�u"
�<
�����N$��I�/�����1!	�	�_TG�{L@����}��|���	P��^6�Y�T1����2�p36,,�����|8@a�{-�Pfn��
k���
S^������[�����
e��3fHx��Y������
]�u��1����(<��c��\��6���)/�#�y�}���M��2�X��)�;����	S^���mV��O|xm6�Y��`F����C
^�)/�;�����;z���!�2��<fHx��Y�$Ly�x7�utU�(Lq���#L�Q@�M�eQ8�(|g�a���ph��b����$��]����@�����I86Ix��YI8
$�����$���(8!	�&	/�.+!	'���]VBN<	�x��o�9859x�TY98K���2rp�9X�@�(��������*��E���n�
bp0X�
bpib�b)�v��"`�����w��]�����-xG
��l)���]�`����������;[��| m
�Y)�(8����\�a��+RpmR�j��*Rp(8�{�)���}%�8��&���D>��N�r�|CSv����J{���b�i������m�������w�R��W�P�k������AEA[bU��c$�YW�P�k���z�Y��5�.��m�������o�����^6�Xu���U�[��KmC�A�R^��&�s�'>=����������=����!
/ R)/�����}��5�����������W�����WP���k��7��
���{m��e�m���W�����7p���k��w��
���{m�Pf��bFa�k��Y5xl����l0��0������7C�U�����Gm�U#�p�i���`��a�\Cy�
������5>����<����*������-�VB����.��p�Kh�������^�4ZiXX`�����H�YX.�}�����{-�Rh�aa��������f�W��O�!��`�����w�t���?A������_��������?����������������_~���������f��+�����n���	�����������Ow�����{�L,����o�?��g�N>2&��
M��|���]�g��_�[����57�lv��1@�M�h��
�#M��/o\���@��������N>2��1M��|�IP�����M�|R�-���k�3�F��e��	.�'O^�x�����O�����/���f�_�O���������k�/�#�qVry�������c��x����1�o����s��{��N��|�#�����*��_�����3.���H�G�
����:�I����H3
�7LJ�~O��r��C����iG��\]�~�\�##B�.��)}���).����Q��c�~d���u��N�>2"S���
������r}�����?�}��H�{�T��}dD�����
%����@q���a��z����rk������t"OTa?�
B�[/�]�}������;<���u������aF�,���]�u��_�~�}��������g����z
}��N�(�����^7c�����|}�u����Z���s����1���@}�������b����|)��^��|�H3
��7�u������RL�z�]|
���|)��0��;�R\n��v���g��h(���K����1������?�o�����I��P\���Bs/�h���R���Bt����k�o4Wn�1������m�������Q�~7`_�{���\��0������d������o@�
M����������x�`H��7��{g�K�~#�ol�o�tW�7��+��7!�F�~�u��oB�MM����*!�&���1�"�&�c�!�f�����hi�2�o��W<:�oF�����W=�2-� �6[���\x���UA.������R`��;������w������78Y
�x�&���^�S��hp�X��xVX�
o����\��,VE����
,���?9���lp�X'�)����~z�����s��#|zP�k���O;f��^.��;���������G:�����~
�w3��m��|zP\�xZ���^s�C24X�G��������>>(�x>�����5W?$C���
2���qS��~g�����c�=��57?$C���3��m������{���k��S�{��P`=>�0#��a�X~}Jq����'~}Jq/����`��������E�`�
�)���������66tX~�����h;,fl�_� �Rp@Mv����!8�-�|Dk����&C��#Rp(X�bE��(P��~s��pB
�M
~|z6�������J����`q����3bpjb��,EVF�<��D������?��C��q�'��~A�q~��F�}�������WJeT�\=>����3s>�ZzcT^�����_7�5~&��/!$o_D{:���|�������[�	���6
6���0$�_Vm�7�p����q68B-����f����+x���Qj�`m��L��(���C
v�]�z�����@�Qj�`m��8���o�)�O�����3���F������/����47�W;\��5/(:gh��y���
�U��-3�5����u���vh���"�m4l���W0$Gq������r
+/_��K�������[�C��Wm���36,�R�sK�o�+\S����
�������i��e�Fq��o\T���o�Q�F��p�
��_����i��P\����N]>���z���% ��7m��d� ��'���pDmv�:k�����M[g-a8�0�_pB�[���0�x��uVBN��z7>�;7�4���YiX�%�����4�y�Z)8#�6{K�U�3����*�E��;���6\�K����*���a�����w��������Yxo����Y;��.����:��w���\�����,|�Y�[��Y�XX�g�����7.��-�"m��:�"W���������ga��Q��Q�[��Q��Q8���Q�P���������Faoh��	P�R3k��u����p���T���Q������G��m�V(Lq��r��`(Lq���;��p��Y������6)�P��66�Y�?1$��A�f���
�(,.JR�(Lq���6k���p��Y�(Lq�a�/��(Ly
��u)�G��m��P����o����������ZW@aJ��m��P��r?����6�������Z7`aJ�4�m��
X��2?��7;�0��k��lh���,x��6k
���ga}��������Z#�p�Q8j��5"
G������c�gK���#�����!'D����>	'$��$���������:N}�"�p�aX��4���0��>TZ3�pn��k������3�����!�D����>	$��$���D��� ���{c�E.�(�������}��[����,���wG
�y
���!xoB�k_���{ <�'�C�=�a������[���&����o�	�
�.�*pN�'uMY�k�_;����\VWX'�)�$<�;�	�l/���w�<>A�����n|zP\�_m��M��Ay/��v��_7a�7g
�����e���ks��Ay�X,����U$Z�!��g�:�m�6����f�a�~���W��)xJq�����6�@����:��3�3\E�?�`���+X[`m���=���`m�p��oX�!/�O).W����V��=���am+����o(�!� P).W�����^s���#:��-���e"J�!o�P).7�E�bm8T�{-�Pcm�cF~�������������bpho31�X[Dk{�-"G�����[pD�m�Y98�,��!
'�(���aw}N��
��*+!'�e�?���$��3��o�I87I��}�H��'aY��iQ8(|g�]���pn���#:�6\������pA.��6kG.M~qFG��wd��gay/���w��]��Y]g��{�_�����ax�a�M�>�@>$V�Y������t�m�"
<
�I]hU��*���wi\^Cy�
[
�qXXa�&u�u"�����5������:���6����6&�����;�J]w(�	p��^64Za�1����J+8�a�����0��6l�����Q�a������\��_������q�Pi8L�����V�����[y<��^�_�����p�Bs
k+�0S^�cX�|�O|zM~qNG���3
8,n��8Ly�����8Ly�
*��z�(���VZa��o�a�v�w���~
�V�&�(���Za��o�b���
P��^�5�Ya��Q@a���B��_�o|���o@M~qHG�~�pH�i�����@�7�c�-8"�&�8��o�A8J ���"�p�A�/]�M��������J��I�`u�����7 �o�!8�!�Rde��,@�WY!8g�7�s�������� g�����*��E8���}.�������������^]c���;��w^B�[���7x��X2�.0�W�X2��3������G�K�u ��Z)�"�y�����\��XZ��\
_�R��\y
���C��O���I����:��O���O�1#�<�������[k(��`C�'����5������� ��)��������{-��cE�4���F~�zH�>A(/S�����Kk(��`C�=������U�!{���L����#������
MV�����_�R�"��2k������^64Yq��Q�\#�j=��L*�e
�v�W�P�K�������������C
^��R�v�E�EG\YCq����V�(,��R���`~�����#n�����
MV�v�(�IsH�L*�eL���h�XCq�������5�{�c
F</���qc
��lh�bD����Y)8"G���W��
O]��5������J����5�!
'�����
�����S��WK������5�k�C�H��'a��!
���{m�RfDaas�asH�Q��(,��<�a\[Cy�
[��YXX^�D����,��,,��<�a�\Cy�
[��aX�_�D����0��0,��:�a\^Cy/
o�>�@�V�,�>�"
<
��?i��P�k��B�"KKlu�U�+�����C�6������:���56���:��O���N������Pi�	x�Bs
k+�4S�w�p���O������Jn��/�N+9�a���;�Cv��������J�cF��E�;�a<Ly�y�uH�x��^6tZi�0����N+�������\�4<S�k��N+�3J<������a����GZ��)��aC���3
<�j;��S^����W����i����
�VZ3fpx�VZi��L�����6��k�p04Zi��\��F+m@����������^�����Ji84�j����@�w�hu���ph�p04Z)"
��Wm��"�phX��C�H��I���h%��(���n��ph����
'�����`i�2�phxU7Zi84|��V��3�pn�p�4Zi84����4������pi�p�4Zi�H4�n�v��"���|H�;�����`i�v��]�au��#�������}>���6[�y�xxS7Z��!��(��4\���6[*��<\���VE�k��Oy�6y8Z:�y�
<��;�y��yx�~�?���g�������OP��M[i�	>C(�;�"#~�3������
�Vv3
c|7m��|�P�w�E�4��l(��aC������6����~���!������q�
��6l���?0���F����N��2�7����`\eCq��<�(�����V^@�R�v��^0n�����
�V^fF�n�B+/`T)/s���E:�"�{-��g�Fmfa����}V^A�R�o�����l(��`C��7���u6.h����O��L��#�2������
mV3f�G���m�r@<
��Y}�]6�Rp2�Y9"	Km����I8�$|Gu�-w�P�k��2+"m��=uH�	A8� |�t�-��P�k��.+!m\PwY98�|Gt�-��P�k��*+#K+m���*����`�����q�
��li�
r���&����\x�)��P�k��&kGV���n�v����`�����q�
��li��`a���&�@>x/�)9�hrp�4Y9XXi���������`�����q�
��li�N�`a����t>��O���Mn�����-M��,��qQ�d�	9��9X��0�4�L���R��UV�)�p�VY�S^.��
o]v����Q���*�`H����*@��2�>��}�����Q���*>aH����*@������DF<{|vMv���*3�0��
�VYe��L�����/>�&��Pe�@�Rsk���S^���]e��+>�&��Pe�u��Gm�UVa���8Q��PVa��h��e��aH���]V���)/gb����)n�aC�U�CJ(�-�JX�a�n�
�����(6�Y% 
����*Q8(�=u�Dd������*Y8
,��uVB�<��v�6��S����J�I������p�a��������4��4�,}VF�
'u����3O�^{�)������Rh��"�pRZq��8��g���<\�<�,���<\N�FkG�y������<��y�Y*�yxx8�+�y��y�������y�h���tZ��!�pRwZy��y��;��<\�<�,�VE��;�y��<�����<|�y�Y:�y��xX�i�~��<��F\��q�
�m4l����`H~r���
j>D(/O�Z�����66tZ��1�����O�Nkw�!By�x��r��6���7tZ��1�����O�Nk��!By��amk��F��h��i�3�����6~�vZ�R���}��w�:�g��Nk_f�O�����������;<���6������W�!�I�~�vZ�
R���}��s�����66tZ�zbH~���������0?as���;������
�������'m���a��4�m-w�iCq
:�= �m������<x�����;m(n�aC��G�aa�����VD�<���r��6�����J���f���VBN<�s	�4�;m(n�aK������6��;��<�y�iy8�yx�tZyX�l����*����a��q�
�m4l��v�aa��w�NkG�ygOiw�P�F��NkG6�x�������a��q�
�m4l���aa��w�N�"<��	�4�;m(n�aK�U����6^|�kL�����aq����q�
�m4l��N�aa�������<|�<,����1!�m�
��1Sj�am�uL����iX�Kn���<��������WJ�S����)8W���: 1�eJ�V������H�������#
@,��5�_@Ly�~�/y���^�}��t�~g�_���8Ly�����8Lq/���E�w�'F`X|�kH�����0��5k���~_�������
��}
�w��L���;�P��^�}�Kt�~��_��/�0��V�Do>�&�t,���
0�2s�j��c���������51��C����� @�����~Bp X�P����y(���p�~#�o�W|�kH��7��+��>�_���>~�D�s�	8J�n�pX�D�H��}"li�2p�X�`e$�,��q����3sA��`D�, ��&���"p�X�S4�m�� �<����\_R��\�>,<vd��}l)�v��]�`�=�1#�<�w����{�4��bH��@��k@C
>�����+cC
�H�G�0�RcU��*`�����+bp�1X��1���F[z�9�8X|	hH�'r��s��A��F>�l(����8X|hD�u�O��|��\q�
��lh����Q�[$�4�`� ������l(��&����~����Y�dU� ��Q��W9*n�����
MV�3
S|gm�U���k�C����l(��`C�U�3
C|m�U0����-���0������
UV]2f��.�*�.�R)/���yR�}6�������+����R�h����K���/i�����l(��`C�U7��Y��6~�vYu�Jy���mt�m6�Z����a����E�e��$Gki��P�k��2�FDaa��_�eV���Q@aq����q�
��6li�����fQ�Y	Y8	�&���C�m6������J��J�E]ge��$���g%�fCy�o�X���4,��Y�}VA�
��n�����-�VA�V�,�B� 
����V�fCy�
[�iXZi���ix�i���+}p�
��l)��aq����:��a��8w��0.�����-�VE�6���B�"W	��_q�����^�4Z'����fU7Z'��)������l(��aC�uN���F�j+�s��L��v��8Ly�
*�s��Q��U[i�n��g�i�S�k��J�t;fpx�VZ����x��g��k�h��^64Z���Q�a�������)�;���
��
�3>�&
/�F����)4����:g�a�����!
/�^�C�u.���kX�h��0�}�����O|zM^���.�QZ��m��p��r�*i�;�+�0��6l����cF�7m�un����kX�����)��aC��t�(�������8gz
i8 �&/�J���A��M[i�q8H���'KgD�M^,�VD�o�J+!G�tX�����S��K���������1
#'�tX]ie����aK���������������aw����
����aK�U��������*��E8�3��s����������������NkG������w��������:��w������<|H/����<|4yx�tZy�x8�;��<\�
i�"�&��N�"W�����:���t<�}��<���&��N�D>�Nk�&�9y��R�[�~�~��L{���h="���a�C/��-����?r<����g^�������G����� ��������?}��o_�E���_~��~������?��?~����~���������7>�-�����,�x���������;�f��������k~���?v��bF~h��pu�����y��4�;m�x�+��^���H;f�~�)����+�	�f�_y�[����;����H3�c����|L�6�:q������~k����#c��?���+��4|����i��g�:|z����d��|d� c��{q����k���M�?������H���\��}��V��x6�:q���������H���\�4�#�G�{q�����"��kX� ��>D(��a;�z�0��_�M�Cv�!By��Km�4�!By�
�	�G�3
���]�C�6��:qQ���=|�P�k��
��3
������4<{h��������������qD=5l���\0�p?_��8��e��g�������4��u����
��_f��#xq����A�R^�amZ�����R�6tZ~
�q��#xq����W����iX��5��m���R�6tZ~[!���G��R�!
o U)/��87kL��J�_�C������^��7���<$V���H�<�<��q1����N���
G����->� �&K���������!
'��(����H�������i%��$���qbH�y8I<�|m�y87y8�pZ���#\��!�p����V���[E�D|�V���{E���A�u��Wn^��*��w�Tr����>�-]�W~G����)�%��p�7�"XJ����fa}�����6 [[�[���lq�����Ud�C��|C�-�"ZT-�L��[pE��m��T|'�E^��a�|"Y�Y�[��|"Y�m��4|'��)��{Ct-x�,N,�Lq�Z�<XP�k���o�u����#�����+fa���3��o���R�K���������!����`�l�����K�������^6�{3��|�f
�a:�l�����;��<{|x�S�hh�fX���|��K��g��YX���qC
^&|xM��ro�m���L�7���-x��=�N� 6�����������<����o\u�[�
<k<��@lH�+p0��lh�fX����m��
8x�x:q���7�`�{-��d������]pX�`����A<���M��&k��A8`�6YsD�x:q{���#rpls����#rp���j����%���N��'����`K��������&+!;<��<lH�98598Y����yos)8#+<��;lH�98798Y���\x��MVA6x:qu�����K������������������N�6��9xorp�4Yr��s��n��`a���J
)�@>��,M��|�<����,��T_����\��,MVE�<��&�D�w:q����O�������d���'�����/~��;��TjD��� ��Z���Z���)0���1����j���-����
64Y�����)X�d->@(.W���X����� T���Z<,��L��&k��Bq���E�2O�����M�*k�a`!�n?C�Z���g0��kX�t,s���*�����Z�C�3Q�{mC^@�R\�am��,�R)o�aC���C�3Q��mC^��R\�a�[;�
2��66�Y�zbH~&�x�mH���
��
��QjH��T��h�Pg-��!������Z�0����YK@Mv���Z�p�iX��8�a��������%"�&��Pg-a8�0,�]�oD�����ue�~�pl���,mVBN<�W������0��s[����$���YI8$�.�2�p�I�����"g��-]VAv����[���������NJ{��Y��)X�"�[�����,^8�/n���~-=��,��-��@�y������P�F���@������[������&#��m ����������N����~��t���p�m4l��N$`a'�xkqH�'�)k;�uB>����;;)5����Z'`�U������Cv>�6;C��:�`J�4�m�VLq��Q4�Sxu]�����Z��!y
����S�7.���S�F��k��(X�b��������Y����u����
=�:�R��^k���_��t��
������v�|Z��?����}�W������kt�k��p��~W�����f}�����������8�
�����6ax�x�w���
��m����}u��q[{x����o��q�0=N��;�a��	����U|q�pv��������px�&�������o������������8�
�����6av�x�wH�8;nf��������=9�yC�����M'���/�����q7&�w����k�0�����pr�&L�o��'�m��8�~qn��������pp�&��?�����6ap���pl�������pn�&��O?���s�6an����pj��������pl�&���>���c�6al����}���q[{h����o��q�05N4�C���q�05N��3����3��li�ph�&����m��������#����87[�+��	3�D8�_��I3���������3��li�ph�&����qh�&
���Ro84nk�s�����q�05N|�C��q�05�����u�g�m��qn�tX84n��u��C�6ih����
��m��qn��X85n��u��S�6ij����
��m��qn��X86n��u��c�6il����
��m��q����=k~���+o7�	�����
��4:N}�E��)�������]�
S��k��0S\���os�����g�����G���Sf�^m��0�e���kV�z�������}��[�����UV�������X��������w����3F�)8j��0S\����`u�w���z_�����aD����
@0�}�=���.���R�k����=1"O�Q�a�u�z�s`�zW`�{���c����F��7j+���R�o��
���^�}��o�[��<�Fm�/��V�
���}��)p�~�o��7j��|�w������������*D$���oTW�7��{GN��7!�F��a�	�7	��.��o���[X�?'D�����}�����*#�f�}�x��?��7���-�UA��<�&uuU~�wf���� ������*H�������v������	5}���~�������w���:w��������{��A[������7�����{��{g�E�~+�om�������������*�o��W��=��������_���'��I�_���'��w�4t�7��8�{��a��"��������"�����;�������b{>��S8������0.i������0�����V|v��p/N���/����x����"����x8�~��~q>\l��{q
G�~q<\��%mq<\����/D����^�����3����oL�8.���t�	�q{/���_C�3�C���-��
���2��j���>����
V\f����I�`��)�e
�6�q[��5���8��o�I��\��
+n P)/S�������kIqG��"p��M�+d��3���jH�8���a��yv����!8�|CB�=��!86!��Q}N���`7�[���x
]
�	NH��I�/���[pF
N<�I]ce��,`�6%e�����'qt�)8K���
Rp�)X��
bpib���8�\�����kG.<�����#xG����$��������N��S0b��-a���71��A}>������| <�����'�"M~qG��+bp0X|�zH�1�
��9N������Rd���������C
>�O�,X�K��|�)��c�	)�(X|�zD�i
��o��[p���)��`C�����;m��P0�}{G��`0����0�X���Q�`������`��Mt����Z���J�������<S�7.���f�`�{-�Pd��`F	��EV��)�����,�������Sh�`m���`���u�!
��^��C��V�`
�}��6Yi���\(��6��k��b��� L����UV��)�;7��4\��5Qx1tY)��Q@a���R@
�W��4��C��C��"�pX�k����������!
G����aK����^]g%�����|�hH�	i8�i��g%��$��W�Yi8�4|����k�i87ix��Yi84��}VF�<
�����������Rh��"��WZq�H8�},�v�������h�������FkG�%Vw�������Ri������J�@>$V��������RiU��C��Y]iU��*��K��8\�8�Z*�q�
8<�+�q�pX���D>�4�Z�i�hX�;��<�g�)������4�Z����S�����Y[he!����]0������
}Vv;f����>+{���L<�=g7�P�k��:+���=5�:+{���L�/��-w�P�K�����3������Y[g�t*��V
�-5�Z��������7k����N��L<��3������
eV^�(�k��eV^��R^&�����j(��`C��7��u������T����1o�o�����^6TY9L�QX��h����)��ww��������^6TY9 ;k����rD�����a�WCy�
������5nQwY	I8
$|��N��qc
��6l)�����fQ�Y	Q8�(,����W�P�k��2+#
�k��.�2�pP�����?�����^��YYXX]���'C.���ga�������7i�ZCq/K��#�k�8cH�;��.����Y��qo
��6l���aa{�g&i�@>�q9�s�����^��YiX�_��Wr�4\����\Q]X���{-��gU�aa��[�}��0\y������qw
��l��Ndaa���C�(�L����^Q��l��)��`C�U��^�uV��)�7��q3>�&
C���"��^�mVq����y��x��I��Pf$L����eV�@���[y����^�
mV��(���m��(Ly��W��(Ly�
���x�(���m��(Ly��W��(Ly/
GC�U�	3
(�j���
S�o����S�k��:��3
,�j������t0�����)��aC�U�3J0���J������9��k�a84a8������:�������1d�o�a84a8������������ac�e���pl�p��Y	a8	0�����0��caq,��,��,-uVFNo�:+#g����*���3�pn�p��YQ8(,.�RpA.
k�U*Q��Q�Rg���E@�M]g���������eG��(l��vD�]@�M]g�������������(|4Q8Y��Q�PX\I5���(|Ho�x��o�Y�6Y8Y���,\W�iY�
��W��4|"�&'K�u"����a�.I�w�G4��:�{m��g=���>�.��w��hx��C���s�{H�����^6Z��1����&h�����e�d��g�}�e�}6�Z��������EA[h�>C(�;�����B�{m��h�����_���>�Q������0n�����
���L�Q������R������0������
���T�(��qix���0`S��?�a\iCy�
*�}�1�0�7h+�}�Jy���?�a\iCy/
���i�[���$�����
�*�m��K}�K�J��h��i�yXZl��������:�/
�����66tZ{D��m��G�������`L������n�tZ	�XZl��VB N<���4�+m(n�aK�����6.�;��@�y �iw�P�F��R� K�m���*���wx:7�;m(n�aK�U���6Q]j���bq���q�
�m4l)�vbi�MT�Z�����`H�����6��Z����&�K�y��yX\H0�a�iCq
[J��<,m���R�"W����C��6����tZ'����F�q3��y�����i�R��h��i����&j;���������7�c����
���<��xX�ix��2
k;��S�F��N����xX�ix���st�����)o�bC�u��! N�R��=V,��wA�T<S�F��V��w)q��Z�DLy��:�����6*6�Z��1���I[k 1�}�6�����^�����:V`bJ�U��������stH�����@���:6�bJ�U�-��
����s!tL�'>=��
��)Pq�6[G@*��i�F���bqhc�7T[GD,��}�T�����[Z��X�X�-�VB,���}�4���pL|�B^��RqjS��T[	�8IT���2Rq���w<�8���[���P�%(VW[�8���;��L\�L�-�VA&.<{q�������pL|Cl�mxG$.m$��bkG$�y$����!
����pL|�k�m�@"��D�-���D|�D���C>�������cF >�@�-�VE >x ����!
W�*\����sT�������:��+��^�;��y��M���(���d���j���3������FT\'���\����W�P�k�������!�����!�+��ozq���q�
�mTl���;0�0�W\,8�b�#���X����������kU_0�0�w�������_��x3�U�K�����}����?=���|y�{�����������}��?��?�|����-��������_����/�|�P���1_�>���;|��N����~W�_�����9"��?������������O���0��'^�;�qP~�������S��w��>��bEy��/���@(��m����������q��b�Ey��/���D(��u�9�g�)]��s��o�8��6*6��'^�;��P�i��s���t
���}�+���p�����w��_j��c��x�0�;m'x�0��n��y��o�8��^~�_���Oo���T(/~�R�c�O��������(�����Pw~�'F�7���g��`���+2��qP��R�k_�;?�#
#���<#`�)���qC�s�8
��^
~��t�'�H,M�r�2������;o��-�AQ�K��}�����)
�r�W���@,���q?�s�8��^
~�d���kx�4��K��8,]��q=�s�8
��^
~�`���[x�0�������p������`���0�k�����>A��w
���WZ;r�p������� (���tc�0^�;�iP����AX�~wg]U��q�m��e�0��0
J��:���$,\��q��w���s�(n���a�x��Ay���N$a����XzH�8��6�x�0�{u�u"	w����
��	?A������zd����gh�`e��H��O�g^����}v3>��B���}�p���+X�e=�P�p�N\,=�`���5�	�8�����w��\��.���@���;q����O|x��|����y����^�������N���o����<�U�s��a������^������/�J����1����[P�>_c6,x�0#���+��G�
^������P���5��[Q�>��Z\1#���+��m�f,_h�P�:&m��*�yLcX��cF��V6Y�����
V�����hR��]��A�`���������7FSu.8"�&�8������Q�`�����#rp�9X�U:���������O0!'���kOC
N����`qU�����S��_�x��	f��$p�x�iH�98�,.*RpF�M~q�I�'X������&� ���=�C
.�����/�;��w��"q������w���M����9��d���������!������&�@>�li���C�`�����+r��s���tH�9�69��Q'�� rp8X��4�`���s���tH�'rpmr���N�>�9�8xQ7Y'r��s���tD�nB>������O�M��N��h�,7S^�`m��`��3��`C����^�M�s����)X�d9����{-��d9�1������r8��2k�,S��q��,7O�Q��E�d�8��2k�,7S�k��&��3J�m��2c�<��I��S�k��&�-;f�8X�d�8��2������Va�{m�Pe�5cF�Wm��Va���k�J����� l��� L����U���)/S���t���k��b��\@��cm���p�AX�=;�`����Pe�� ����*�E�����yvH�A86Ax�TY	A8JS��UVBN<�{g���S�K�����������aq����3�pn��b��2�p@X\01��� �yw�)� �&/�*� ���C
������!���{��K��#����9x�9X�7;��9xor�b����C�`u�u <��f�\���6[���\�`)�"W���MVE�m�4Y'rp8X�1��9�8X�d���g��WC����������	>A(/s� .�������^6TY�y�(�	�`i��G�}�f���l�q��,�'�(l	�`)��G��~��e��6����
]��3�C{�������aa���.����G:P��Z���������~�vY~�Jy��a�^��{m�Pf�%cF~j��9�72��r
k����5����
m�_#d��xqZ���W����kX�H����g�k��:���2
�k�8�hH��T��5��;<��y��6l��|X0#?������4���D��������aC��#��������4��#O�N\�9���8�8�Y��8,������!
'��$���MsH�	q85qx�4Z	qX�a���EC�����a'�Y�pF�M�,�VF��xqf����px�����
������Ri�aa����iy��<,��!������������-6^Z4��qx�qX�1C
>���&
o�F�@��xqh�������a����@>�0�Y
��0,��������+�p�aX}�����������:���6^Z4��Y�XX\�6��Y�l�����'daa����hx���)/�����'`a�{m��g�S���c��4�<6,����iH�X��^�>kv;fXX�[4�a,Ly���Qi����������}������4,Ly���O�y�����`���`�Bs
k��y��L����!
/�^�������a
�5����h��r
k;�y9��5q8
�y]0������!
�����kX�I�+�0��6lh���cF����EC���)/#<�ai����
��&�(������p�qX}���C�������p�hX�h�i8�4�9)��k�Y8�Y��gEd�(��8�fH�	Y8�,���R�~�pj����JH�I aq���~��O�7^U��oFNM�#\�2���������o�����������_��#�����_~���O_~����>��������_�N�?�����������������8�_���}��*���������/������:��O0���~G��??�����{)���;)v)�
+p����tH�p��~�:�G)���������[pE����>3VD��D�h)�*"E����p}>�(�p����'2��d�h��Nd��g
w�	t-x�������w.���^6�z�T0#?��p}v�Bq���O��By�j��%��O��78�s��Bq�����By�j�����EX"^R�����}�x�� ��Z���[f�V�kA�{`C
��JQ\�`�k�By���e�1#?
U2�����
�����F�{)8�R[V��i������p;��r���/�,���^64Y�zbF~�x�sH����s
�����P�k��&k���OC�q)8S\�`m���B�{-��d-9X�
��M��#
�o�\p!��lh���,l��&+"G����w.���^�4Y	9X�
"^�RpBN����p�} ���������R���~3bp0��O���"�&'K�U���� ���*H�E��c<����@(��_K��#+Afu��#�����_\Bq��ZZ�X�"�D1��x�������.�{��M��@6���P)�"<������k��
��6���XXX2�K���,��/n���~-��,�����|�|csv�~�	��l����:Sj�_m��N����s@������5��M�ku����W�`���2�~H��������&C���C
�-�VLq���W�����~
�:;���-����~������6�5X�|bH�m��.�+��-�u����

����E�`�+0�e�i��������Z��!y���~7`�����P��w���~���Z��!y���~�)������]�����Zp�	x�6Xk@��v�[XkDmv�
k����G�E[a�8
+��oa�8��Y:��y^�VBN~���#8!�6;K��������+#g���_/#���������aed�,0���*���g`����~"pi#��tX��,Z�!����E�����#�mv�kG�y���| �<�X����!�` �Rb���9�������A�!�` ��bU���C�x7���\�~�=�k����:�O�Wu�u"��Eh����|�)�z�mZ���j{�m�O���=��J�����(��cmn���d�U�cm>A(.S��(�
W~P�F��k�C���Vm���z�����<~q����q��ml(�6bH~���-�~�Q��q��f :6��Ai���m>0$��c�Y���~��6��Ai���m)����i��m�Jq���X�����~
=�����M���i{�m�JqH��E���>(o�aC��m0>s6~l�"k���R\�am������h��dm0xV~�?$C�������7��<��-"K;?�U���#��N}����>(o�aK����������p�A��o��p��m4l������C�!�pFN<	��s��0������-eVF�n���au�U����Eb�~�a+H��M����*H�E�au�U����F"h_��v�������g�������>kG��=���.�����-���<,��H�4| �/[�pS
�������g�/���1VDbag��s2���H\$V_�����{�1~��t�'x"+k���!�������V6\VCy/���U������F��o��).����
�0�������O���<�? C�u3�+�������)�����Fw~�F�QX�����\��:+x@a�{���/���`��<�? c���\��2+�>�&�v,��	������W[e�0��r�j���x|xM~�P��\�)3����
@0�e�U���	^�P��#��Op���L��+�����W[c����k	�v"��n3f�X�	R�Lq���-V��)o��$�����<�?"C
H�A `�E+! �j�e����G`�GdH�8��h%DD�����#�������2p8�;�������+!'���1#'�������}li�2Rp�)X�RpF
�Ko��I� ��a���*����`�GdH�1�<i/K
;bpi����X;r��spT�X;r�.p���-)���{��-E����.���C��I{]R8���6[���|�n�*rp8x�~�?T������tt~�������n�N��*p����8���&�8���#D>yN�&+N�r
<}~�����j(��`C��3�������>@(.W�����j(��`C�]������m�����
��>
�����^64Y��L�(,�I�&+z����,4�����j(��`C�g����5�,�!� R)��1�%��J{���c�e����^q��z������qY
���kh���1#?�7i[���D�������j(��^C��	3��z����(T�����p4��J{���`��bF~Vo�6X1�X�0C��3�����J{}S��_���+�����������F#�����~
�U����7�����y������P�k���*!�
�j�S�!�&��$l�����o�����^���W�WXV#��7#�fa���.��kj(��_KwU�}�e5���~�o�H(�������^��TW;����F>b���������pK
���k���_aW�|�:�����W[^��J{��R^������uH�����Wp<�_�QCi��Z����+l���W��{"�V���#��5������:��E5���:�O�����M�������_�	��B3�:m�&�_�������s���������)4����J���2�*���N|vM�]�U�f��i����)/����J���^�5�Wi��Q�_�����Ky�~��U��)��_C��	3
����UZ�)/����J�/���k���R1���N�_�u�~�U�Wi����~
�UZw�(����Wi���L���*m��������J[����Vm�6�_��L�Q�W)�����k��R@�
�j�����7&~��7"��6���������*E������y���E��M�]-�UB���zu����7F}��7!��&����*#�&����������������s�WKU����^�_������Q�}�-��������*��E�_���v������Q�}����&����jG�������@��y��1��o��������_�����^�_��������"�M�]-�UE���zuU�������D��M�]-����{
�������{��{c�w�~��6���<m�%���Wy��������2�����~
�Uvf&ym�||P^�_e�q

�������=f���*{����L���*�J{���_�y����Y�_��)�e�U�W��P�k���*�3
cxgm���
2��U�54����������)�����+�S������2�����~
�U^3f�����*��O)/���������^�5�Wy��Y�E3k����>��L���*�J{���_����U4�����7����2�����~
�U����&�Y�_���y����W�P�k���*!�J�hfu���������J{���_e�_i�8�uH��7��+/�/.����~��������E�_�����8�xD����^���W�W�B��������+�.�/�����~-����+-�Y�������!��n����~-����+��Y�����{�!��.����~-�UE��V�,���"�V����C�E��M�
���D��6�,���D�=���W�z��^�5�WeB���,���L�����W�_�	���^�5�W�M�Q��E�_�Ky��>��8`�{-�P`W1����x��,�/Q�����

V�;f�X�`���r++�2S�K��Pa�9cF��c
��\���,3>�&GC�U``
�����Ly���%VY>�&GC�UV�`
��-��
Ly���-VYO|xM
���lf(X�c1��
(��r+k��S�k����Y)8 �����[p@M���D�� p���bH�98J�,�JD�M��"+"G���UC
N��Q�`m����S�����J��I�`q����3rp8Xd<�����li�2rp�8X�de��,p�8�xD�98�9��d��"q���*��E�`q����w�����di�v��]�`q����w��]�`q�������&'K�u ���,�| ���G| MN�&�"�-�\������4�W�����di�N��*p���bH�'r�)p�8�xD�'r����di�N��S�`q�����	?AN���y�
�q
��lh������H"'��R��O���l�v\GCq�������$r�R�!{���\��&k�}4�Z����}���P^'n�S0|�P^n�����q!
��lh��g��V'��R�&��r+��7�P�k��&k_`r�.��q�^�!/`R)/W����q%
���&C���3���:q����WP���kXYe�����66tY��0$?����-�4��K��\��.k��4�������C��y���bH�a������2k��4�������������-�4����<B�f�����66�Y{D�8q�����p��Gh�,\NCq
[���4,��q���1
#
'���}������-�VF��8q����3�p�pX[h����h��h�aaM��\i� ���!�CF.[*�yXXT��MC���w���1�#�%5�����:���U5N�u1��y�x�s�S��qM
��6�,���<,,�q���!
W��C���q�s�����6�tZyXXW��}C>��+�����!
����h��i�����'n���1!�<�@G4|L�������:��!w^�ix��2
�E�s����k��3tZ���\��N�p����i�����
�	^�����:<�0���vZ���L���n���k��3tZ�<cH����C���)/��6-3�0�m4l����aH����C^��)/��6-�0�m4l������k;�c]�a���k�C^��)n�aC�u���xX�i�0�e����s��0��6�
���)���cH�x��2
~x����<�<�
���������W^�_���|����o<������G����� ��������������������_����������?����/?���?��#��+��W>|{������������������?�Z��������?M~eL�7��M~�L��7d�o��&�
&_�;;�a4��1���V4�U2����!
��������s��Q�WF�{C	XQ�WI���CF|�����W.�D�2�:�=�)y|qw����{�)x�;����b�'#���<Q�������E�)��;#�:W�&�dL�7��'��S2���!��?�g&���=�&�dL�7��'��S2���!
��?�c�X����������D�J&_�"2�a4��`�o���0���1���<��������!
��?�c�X��������
-��&�L���iM�)��{�:7�&�dL�l��N4��`���HdH�h�O����4��a4�'c�gC�u��?���M"cF"��;W��/f�Y���:#q�����D�T��#O����!
'����Rk%�����i8!'��u�cF Nm �-�VF N<{q����3q�X�l����y�����g�/u�t}��8�H���"C:.��E@b��qi�k��;��<\$VwZ;�p���>>w������}�����4�K4�n���]�a�z���	��}��[��(|(,����"
<
���|��������}���oE���D��� \y�E��D�M~�t�~O��S�`q���~O����`�~���)�����{�����uY��\��"������o7���&XH�L{�������"
K��8kbH�.A����u������_?�������/���n������p��o���������?-�/����8�N��9M����.�)�_�����?����_���?��������?~��?���/���g������������[��b�/��?�=��0�U{�c����]�va+�3lc��a��
/��?�;��a����I�q��o����a����*n:R/,��}�w�za#�3l�V�a�����A���V�?�2�v���}����S�zO�(Tq���za!�3���������a���6�x`FA��;N�����y�����]����zUfD�l��X�x��"2p�r�����Z��_��H��}����02p����k���{/{��^U���{/��?�;^�a<��$�Vs�Q�~3��e
�s��a������c����C�����W�����{�B�|������{�E��_uoU�|��;I����{YB�<�7�wG����������}waR�����}/;��Hi�/��e��~�������������{YA�|l����E��UWW���&i����{�@O���]U�����������
;������{Y@O��R^����5����������Q�WnB������fh���K��~�����)/����rn�g���������Rh�_m}��/��^������k���3C���g�(�����������q�~=�/���k����0������r3�/���.����)��_C��3
�;k�+�,�/��7����w�����g��[�(������
�Ky�x�����������rk�������m����������Ki���+�%�(����r�/�e�)�+<>�&��8'�o��7H����\@�
��ge�"�oh���CB��������!�F��(����������/���oB����C8���������*!��&��8 �o��7	������������������������Y��E�_��,����oA�-m���W��������������#��m���W;��.�������]�_�����h��b����C��E�_�������G��h��b��*�o�wQ�W����+�>����[���X������W�_������������{6�w1�W~Z�J����<,�y�e�U>?�����������n���wS�_y�J�����|~�a'�3��_C��������_m�a%�3/�������4���~
���'f�����j�+i�y�~����u4���~
������c�����:�g^�_e�a�3��_C�����~�W�_yXF�������<��y���k���� �e!��~����U4���yXD�L{�w5�W�?9d����������������kh�i���+��e��~��������;K@����{YBC��+��;�?����|D��<��Y�����{�@C�Z����{�C��_u��������&�������_%��������*#�&���#������3��������%4�U�W�7��+�>�oA��l��~-�UA��,������*����_����~w�������_����4�U�W;�����x�`D���e��k���������������W�}0����{�=C�Z����{�@��_uU�������|E�����5�f��N������������W���?�/�g�_C5O���
4���W��Ky������'�_J{���_���%���W���_���#�u�����������%���W����L���j����������}���m5{�_�������y�g�����_�3�/�����W��Ky�~����x|vM������Rh�_m5/�����W�_�����������W�_
���������2�*��y�����k���m���m5o�����W��
���^�5�Wsp�Q���������U��s@�
M�
��j��A��������x�O�G��c�������Q������o��W�������,�UB�M��������U>_�3�oj�o��W�7K����2�o�W��UA��M�
��� �����*����_�v��~w�����`��v��]�����v����_�v��~��&�Ku ���Fuu �<���{ �M�
���"��FuU�+������V����_KU����Q�_���U�_m?y"��m���W'��)�o��W�������j��3���o4�W��cFao��W��������������~
���2f����������w�P�k���j�0#s��Dm�x�����x����~q����k���fd.�������)�e~?k����J{���_-����I�_-�S����*�/,�{��^�5�W��1�0�7i��e}Jy�~���.�{��^���������<�m���9�?�o�����O���?A����O?�������
?��?�|����������?������������+7�:�H�D�����2n�/�_��k1�Bp�w���/|D���d����������^��
�%"PH=n�����'"��m���.J{����-	yBX�!.�RoB�H�N�*J{��P�-qB��!��RoF��<Mh�vXp�����,m^A��y�����[&
��yP�k��2oG��y������#K�<K���{<(��^K�w KH�<n�A�tp��~W
\�Ai��Z���bFa��
�7]��^~��8�hD�����^��4yO��U�*�!����U8H��^\�Ai��Z���W��!n�S/r��s��=�uB�=������p/�f��q��s:�^��p��5��9|tM�M��ju����W�Z����2?��Zcu'>�6�Z��/���5�C�������d�z�^J{���Z����on�R��Kq��;���Ki/���P[���!��b9�����~w�����6�5�V�R1��[,�����/O���
�
�Ki���u�1��[,����R�o�����R�F���j�2�|s���~�})���G�f|tM�u���z��B������rH��7|;��kD�
M�u���Z#�o��W�b9�������?��76��M��*!�F�-�C�M����_�
��&����_7Y�����x��X�7#�f�������3���� g��5iC
.���h*\��C��� ���=�C
���O��T.xG���,������D��G�j*| mv��@>VwX2��3����"mv��"W���M�C�����g`�=n��\��,��|�,n����|����m=���6;C��M>A�����#��&����L:e�p��m�k��6�`�77Y�����e�)�o����6�5tX����M�C����Aq��~q��m�k���y��on�����2���m����6�5TX�\1���,���x��3���o���������C���rH�+T���S~�h�����7X��1���,�����2��)1l����6�5�W��7a���2��
�)�e�U�W�����~
���7i������o��W{��;<(m�_C�E�_a������#���?�����6���W	�W��!>�!�&�������
wxP�F���*#�J�<��UF��<�j�a�p��m�k��2����C�_��,���������6���W�W��!n�����[�5s���J����_����&q���~�wi��r�����6���W����C�t8������k�+��Ai������"�
�<��aC����UX3����;<(m�_Ku"�
�<��RC�=�Oa����g��Ai���0!�J�<��U��)�o8�7L��������
n��<��������)��1?'8�_J����_W1$�����!�z�����=a%x�_J����_�cHa����
3�/��6F�����6�5�Wa�R�d�����Kq��+a���!����?~�,�����q��o���x��L:e�V������}����
L�����
Lq�x�bH�'>�&����o����E���������x���6�_J{i��/�}�
#
��-�~y`�Ox��^��oh��k_���}�����*DD�(\}��j}c}_����]�����"mH�	�7
��v�oj��k��}�M����^qx��v3bo��7hcoF��M�}���o��7��+n�.Bo��W{�s(��y����o�v�n�yW\6����[x��~e?����}����o�zw��^q.��zw�]^���wg��5��@��y�?���{ �<�m[u ���g�z+"��#���6����[����"�V���������+�|��D�=��^m_u"����^Kau"���j�8�G��CoT����i��^�54Vq:0�0rW�XE��W��7��J{��PYEW0#?m(j+������~#?��i��^�5tV�'�(��vV��G�m�K���F�4Ci��J�8�<�(����������+��'�@�R\J������G����� ���������������������_������������?�������S���
��7>�����kY��'�|1�����'�>���p��O���!�T&��\5_��sI���5_��Y��{sIY�'�Di��Z5_��sI��5_���6	�������3�(��^C����\&3������gm��%e��p$���k��^�K�`�����
���pg.)_O8���^�5�|	o�%a.��jC��f��?BP{�p"���k����K�\&Q��7���$\�s���g��Dq��������0�)j��`�t.�9w�����(��_C����\�2%m��"�q��9���Nd���~
U_�tI��$��!�&d_���s�w\Nd���~
]_�;tI����/����+\�s�c9Nd���~-���K�\����
��p��9���8���^����Wx�.	s�D�����+�������L�������tI��$��!����:�}	1�D&�{��R_�M�$�eJ���"�
w��W�!�p"���k���*]�2��~L����%:�=v&�D&�{���_�]�$�eJ���D�n�9qk��~���g�_�J������(��3#��|zd���F���9|v��}/N%��/�������X���G.�9�������{�fC���>��
�6X���G��9�������{-��`e�QG����V�A�f�2�����g��Z����������!���0���+X�����^g�:��T��_�u�����������#
^A�R�k��+�;f�w��I�b�
*��,�����C����
-V�2f�w��I[c�
$*�e�iO��a����^�j����n��X9 ��������z�������"+G��(p��~���c��K��������&+!'����7#
N�����������I�`�.���3rp8X��2������X����/�
)� ���#
.������&� ����lC
������������{��-M���,^wR������&a>��&��"�@>v�"�@>�n�(�"M^-EVE�;u�U��������������:�O����:�O���C
F>����2!�;m�U&�`���\pj��l(����Q�`m�U`0��
VY�6Q�k��"��	3J�-�����J�8���^6Y�W�(`��Ye��`���#
��M�Z���*����"�,����[)x����
EVY2f8�k���S^�`e]�^��
EVY��)4W���*+p0��V
�>�&o�&�l���+X�d�
8��r+�����������(p�x�iH�98H�]p@M�MV���A���?so�k�m]k���M\d}�t�X, ��l�:Gn �
u������R�E�^�S�S@�9:��{����Z��{C
����p��)�{D�M�,MVB������J���p�z�	9859x�4Y	981V7Y98�GK�(8#�&o�&+#g���&kG��������&o�&kG�	��W�)9x'���/��{��7K�U����Y�d��B8X��9��9��d����Y�d���`����9�hs��������Y�dU��J8X���\�,M��\	��&�D>k��9�lrp04Ye�x	��&�L�	"y%�	>@$��`C�U���!E�&�8����x�01�` �Z���*�bFvJ���*�c��#4��q�{-��d_0#9��C5��L����,:
��H�k��&��3�sz�9Tc
�*y-�@���lh��Gi2S���R�&U��
V'j$��`C�UV8K����h����I�����O�x���`h���`FvT���*�T��+XYt\�����
MV	3��zm�Urp�s�~�8S#q/GC�U"r0��'�
)8"G����wj$��`K����Z��n�rpd�]0�H�k��&+!��zT���3rp"���Tp�F�^�4Y9���,�&+#g����T���li�v�`6X����9x'���Sp�F�^�4Y9�-��E�!��B8X�`�����hi��`6YC'��| ���	#
���{-��dU�`�YC��RpE�������{-��d���l�fU7Y'r�I8��01�`������-M���Vk�a�#
>&���p�v��,q/'C�uL3^�M����%o�`e�q8�`�{-��d.cF���m�,y-�/^�����:<p����m�,y;�&F<;�xMN�&����%t�`m�u�����WS�������d��k��c�����E��K�k��&�X=fd�m��8X��Z
^��%��`C�ulf$�i��c�����E��K�k��&��*f$L�Rp�X0�`��rphs���:rp �i��#"�����G����`C�uD��H8xS7Y98V/8!�&��Re%�D@xSWY	A81�6A85A�M�.+#	gB�����H����z�H��I�n��Y;�p&(L��4�#
�}�>������&	��RfD�����.�
�p!(L��pA.Mv���:��cau�u ���)#>���&��Rg��au�U���
W����a7Y���4\	
u�u"
WB����
�H�g���d)�N����pPZ'��IpX����5��������Y�~M�6Zu�����-<*N�H�F��J�:8X�����������f7�#���{m�*���d��l����>D$o�wX���?C
*�:�����V���J���0=lbD��^#q
*��8I��
�J�.�T%o�a��w*��H�F��N�.'�dc��N��6�?WS�a������
�V]��\��V�@�J�^��������m4l����cHr|/���p�*y-
����m4l��j@�;6�N�����aOO��0N�H�F��N�F�a6dC{�4��#�a��q�F�6�tZ	y�-�Du����S��==sbH�������N+#�)��;���<�k7�+6����tZ;�0����NkG�+��Sq�F�6�tZ;�0����C.��;�a��q�F�6�tZy���Du�u �����
����m4l���a6gCw{�4\�����
����m4l��*�0����N�"W�����
����m4l��N�a6hC�{�4|"����>'�������i�����4����9K�^�����*^�6{C�u�C�iWm�u:�a��ki�K�F��N��C�mWm�uz�a��kX�x�xX�66tZ�?1$w�vZ��`�������%�����i���!�����:�a��kX�x����m4l���e��l�U�i�+�����4�K�F��N�\�d���N�\��%o�az���7�������:7�aI�kX�i������4&�xm�
�����am�u��@x��A1�a�������i�y80�vZgD�������������J��������pBN���#N��	y�7_���G�/���{�S������3"q"H�^rF$�M$~�f��~3q�������@�	�S(F��#�M ~�V��~w�����|�wH�qx'8��oA.M~�F��~�p������VA.��u��0\�0��m�����G�����~D����v�Q�h��k7���[�k���.�*�p% LO��/�pm��k�����D�}��C�=�O�������g�_{(|g�q�f����E�[�_~|<�����oa~����{���G����F$'��!���u��6���I�G���,������([�8���s6G�6���o*����]�
V�f��9���:1�`��y�m��cX��cF��������P��?f��C'F�6���'
�/	2�]:�;�������)�����#��`;���1@F�k��%�[�
^��lzz����a���Z���z��BF�kC|��%(x���iPp����q�gXp�1#�wU�Xo���`z����bphb��Gv�[pDf�6t�wH�98V/8"�6[����vm���J������71�����li�r0����C
����p�z�9879���:�-8#�Uu����3�`z����w����������9�����!���;�`��r����O������Fm���*���p0=jbD�rpir���u�[���6m��������p�~���G��_<����+r0����&�"W�����"�&�xT�����l���)�D>k|"�M~����Ff�6^�d�	9�$���1�M���Z���r�����m&+�����K^����~����������y�_�������������S��/����_����������w�}��f���i���p�����|�_��'~�{&�B��������I
��q����_�����s��0tn�����M�a�����M��m�{b���wO�+�SI�k�����3��������7�������������������V�m�������J�J������/����Q�����I_8��i��4��2���/�?�o_�������{����}���o�������e��~��+I~�:�����'fd{��%%�3v���z�'��~�]���������o���@������E��
��O,���o����������;f$�o��~�!��������~���������W��7�3	��w���x��A�v���#�{���]������o�G���xA�������������w���5�0�x�����H�;y�@C���#
��'��0��o�k�|����+��[��w������� ���'�������I{�W�NB�Q����7dH�����0�������G�UUfD�=��Wm�"�}�}bE��~+�om���i�������x��N�����'f���D�=���X����$�KC����{��wQ�W~����������/�e{��������������0��H{���_y!#�A��!C�u��!y;�*�+���~
���dd+�7dH�>>$o�_e�a������������&���z���~��ql����0~�H{���_��������7dH��S���W�_y�>x���k���:aFr�#�
��
�T�v�U�W�i���+�V�H^%��!C��f���*���������~
���
f$o���!�����oU�WFi���+����
�/�o���k����C�WC�#�/�=��!C����������J��������J��l�����7!��>�>�${s������������l�����7#��>����*#��&����jG�e��7dH�;�����'Vd��wG�����Z������o��~�o������
�oi��j��
�/<��!C�=�K��X������h��j���_6x@C��[������"��&�����"����2�_��J�W�_���������D�e��7dH�'�����M�_�����_C5O��������'�_���W�_���������������������������f�+i�����{��������%o�_e5{�_I{���_���������g�_���W�_�3�����k����bF6�����e�~����\���.�����������������W�_���W�_�+�����k���5cF���7dL������������]�7C5o��������7�_���W�_����k��f������������o ���������k������j��9"��>�m�c�-�UB�����UB�M}�}b.��~�oj�o��W�7���!C�������A�_e�����`��2�o&�KC���#��>�>1{o�;�����`��v����/�
�oA������UA�-M�
��� �6x���
�o��o��W�oi�o��W���������{����1�{����G���������/�
�oE��}�}b*��~�k����:�+�_�2����$����N�������_-����/�
��2���������\6���~
���<fds���jq��!y�����Z|xH�k���j�fdk���j���!y;�*���������
���+fd#��j�=��?3*��ey*i����e.��m�i��e}*y;�*���j$��_C�,3��?m�����������Y.;4��;�~W8#s���<;�<�_����~����34�e���sg��gd.���W��T�v�U�Wn�H�k���j	fd;���j	�����O���/n�H�k���j���d�����!�F��H�W�_-�=#i��Z����Kh����~�o"����p{F�^���W	���x�2����������n�H�k���*#��>�<���7��7i�+�����~���������!c�E�������n�H�k���� ��OC��[�K������I{�w��Z�/�2���
�|j���
�9�������e<��������(�D��=�����?�_�O�>[��"P�}_����yH�����['
�����O�|>�xB�v�U�y�<!i����u�����	po��c�'�u��'$��^C�����8�������&$n�^e��z�	I{�����>c�>M�'d���LH�N��2o�g�tm�0�y�0!�;�>���w����z�]��8�tm�0ty�,!�;���[���$n���]�1��x�������[�3�giO��{�]�Q����������I�K�o?x�oC��iO��ro������,��
�W�6
6�yk�0$y����,�~C~��l���������gY0�o ���x����#�o��������c��~����<OS�W	8��M��*!�&�����y��.�"p�#���
VFNM~��3,8#g�DM]ae����`7i;�)87)��'���1xg��j�#���-���71��'�����V�X9�0��X9�t8�Rd��������:����N[d��G��-MVE>�<����\	;m�U��k��������������:��+�`�m�N�������d���g��gm��M�rv�&k�M��(��dm��!�'���&ks�"q{+��
G=$n�`C����!�G���&ks�"q{+��
W=$n�`C��y8~p#�����<|�H�^��&k�Y��(��dm3�?��q�Y�dm3�T��+X�dm��!q��m�1d�t�Y�dm�T��+X�dm8�!q��mu����m��D����l�6\�����
M�������m��m����:�����q�C�6
64Y�v`�������p����l�6����������r0Y�X�M����`�����q�C�6
64Y[D&�������p0}elD���!q[���L6>u�����`�����q�C�6
�4Y9��|,�&+#g�����!#�6{K��#���E�d���;�`�����q�C�6
�4Y9��|,�&� ���������mli�
r0��X�M��\k�,������-M��L�>u�U�����&7>$n�`K�U������n�N��J8��26�`�����-M��L�>Vu�u"����+c
r������d�	8XRw
�6Ya�����MVp^�6��&+8�`I�)X�d,q{+���*^�6��&+�C�9x�6Y�K�^��&+x�`��(��d��a�>��&+����W���
3p��mlh��|b�>��&+,L8��26��8X�6
64Ya90d��Wm�V�`��+X�d�8X�6
64Ya�1$�`m�6�`��+X�d�
8X�~��7_���G�/u���	s��Ya�����eV�]�_������ � �i���a����z#�ph��k7����c�7m�"bp$L�R/bplb�k������c�7u����`����zBpjB�k7�����S�7u���3A`����z3"pn"�k��7������+�8�����wG����c�{���>�n�� ����b#�-������=�����[���������������@�=��_{|o�r����M]^���^����z+r��~���{���������������:|k�����H�'!_uou"���|�����{v^���7N+^�>�mq'�����~�+b��8L#q�u3f��K��Ut��!q{�*����4�������a���DA[]E�������8M#q�����O��?�7h��8��o��LG��/n�H�k���*�f����U\��J�^���*�8����kh�~�����y�����S���W�^E����~
����2#��	��*��N%n�_e}q�F�^�5�Wq��3#Y�	����o^B:��H�
�/N�H��{��*��Hj�����a*�c����".�H�k������3���Woi����W�_E����~-�UB�%�4Q�_%��D���6�_�����~-�UB�%�4Q�_e��D���6�_�����~-�UF�%�4Q�_�����/}3lD��J#q��Z����l�Du�#�����a#��Q�{���_�_2M��UA�-���a#��M�{���_��d�&����� �K_�/N�H�k����"��a����*�o%�K��/�om����:��.MT�W'��I���6�_����/���4!��Y������+q{�*��4�J�k���*M'f$�������_����*9�_�{���_%w`�>�&m�<�����K_������~
�U�;f��o��W��J�^���*�^�&��x������������J3������������5����7��w����~��UZ�%n�_e��	�]�_<{��~W�_	��W�_��W���U�Wi�x���;��������I�_�
�W���U�Wi����~
�U
3��7i����_�z��~�oh����J�7��7i����_�z��~#�ol��b��"�o$�����od�����oj��b���o"�����ob����2�oj��b��2�o���c����3`�~���w����R`��{���n�v$��0}AlD�	xo�bi�
p����VA.��bC
F.M^,��\��&u�u ���+b#
>���&/��"}v������@0}GlD�!�6!x��X!��!�M��D
����Kb#
>���6[Z�)��S���5V���$L�Pp��{-�Pc��`Fr������O��+X�ce�����WC��]���$�I[de� ��W����8B#q���������h&m��=|�H�^��&+����lh��gef6E��MV�A�J�N<�����O�x(R�`C���3��x�����T��+X�de�����
MV^=f$g�:m��W0���W����8B#q����M������MV���J�^��&+����lh��V1#9��i��f,�X��o��(7h$��`C��r0[�q�&+G��@8��.6�`\�����
MV���l������	���F�;4�Z���J��l���������F�K4�R�fi�2r0��q�&+#g���&�h$��`K��#�E�n�v���q����5�{-��d�`�I��MVA.}��������li��`�J��M��|�9��W�F��4�Z���:���.�W7Y9��s�����('i$��`K�U���0�W7Y'rp�s�����(7i$��`K�u"�e�n�N�������26��}B>����}�����M�>K�^��&kw/^��
M����%t�`m��;�`��+X�d������`C���3��&k�����W����=p���M�>{��8X�d�3p����l��8X�^64Y�2aF���&k_��%o�`e��/���Z������	��&k_g,�p0}elD�+p���lh���`F������7�`��+X�d�p���lh��-cF������7�`��+X�d�a�����`h�����&k���p0}elD�98498��="G������#rp$L_R0rplrp�4Y	98��MVBN���+c#
N������&+#'���������p0}elD�98�9��d����p��n�v���p0}elD�;r����hi�v���q���*��;�`m�U��K�����*���q���:���`m�u M��&�@>/�&�@>�W�F\���&GK�U��+��E�dU��J8��26��9�698Z��9�$����9�$L_R0r����hh����$�h��2�'����l�
��H�k��&��3�s�m�U|�H�^��&��P���lh������S�h����D��
V6Y�j$��`C��n�����h��2�I�����MV���{-��d��bFr^��m������Q���26�`���������*K�����E�d�L����l�
��H�k��&��3��zm�UV0���W���*�V#q�����y��m���&�l`R%o�`�����q�F�^64Y%6Z�j�����`�������C�����*9�����&�D��H8��26�`�����-MVBf�5���J���p0}elD��X#q�[����vkVu����3�`�����q�F�^�4Y9�����&kG����+c#
���{-��d���l�fU7Y9x'L_Q0N�H�k��&� ���U�d��B8��26�`�������d��a6\����A�` ���p�F�6�tYI�-���.�"	WF��.Gk$n�aK�u"
���M]f���'Aa�����q�F�66�Y��,��k6m�uL��������:&`a��h�Pgn���7m�u8�a��kXYg`X�66�Y����������aB����
{�a��h�Ph�`H�����z����=�a�����g�a��h��hs����7m�u���������:�/^��
���K�^��J�X��%o�ae�u�/^��
���K�^��N�X��%o�ae�u�'^�6;C�ul�d<����
xX��VvZ�<,q
:�#x�xX�iy80VvZG@mv�N������p�vZGD�����c#��������iE��Hx8�;��<	��F4���S�����J����pPwZy8�o��h8#�6;K����3�����2�p&<L_!���<��<�,���<��NkG�	�w�F4\���6;K�U�������
�p!<L_"�e�_��w�������]+���V���t���g.������C�qo���p�w���i��e^��_������/�}��o����������x��7�x��������o?���A�/c������E�d|��'�x����r�}����l ]ux���O8�*�0$�q%�O���
�!Wr�}�mH�'^������7y"WrE/�0��Ib����h���%n�aU����uB�z���x����CD��.�0|������aU�!���D����
������4L�w�0n������aU�!��!�^�������kx�|�t�R/�6��U������8^�A<��������7Lz�^Vm
��7Y0$��q�|�x�k#y{
�o��j���<V�o2cH�W�x���@�J�^�����]�z��y4�*�0$��z�������
��^������P�p��^�m
:���^��}���vZ�m$o�ae�Uq��^�m
:�I^7��N������5���*N�����\���i��<|Y���am�Uq�F��VvZ�m�e������J������VwZ�n#y{
k;-���q�G��N+!_6n>j8�;-��������n#�u�zY�y4l��2��e��������H�^��N�m�e���������/+77���p�F���vZ�oS/�6��-�VA���|��������kX�i��M��<�tZ��e������N�H�^��Nn�e��7_���G�/�o�����u�q��Zgn$o�dm��+7��r#��=�/S7��.�p�F�����Z8rS/#7?{�V��~�	q��t�q��J���%o�_e�uN�����k7�7�[1"�am�u:��2VZ����~_����_W0"Cam����1��
+���
K�K���D���������/����������w���5A������;K�^��*���%o�_e�u./^�_{(|o�@�d���-�� X���UY�r��k���.���~��X�
�+y{�*k�s����Sd�<f����-��K�^�����%n��J��	3�	�O��H��0}olD�	8t^��,8��O�
����� 0}mlD�8v���c������2p$L�QpBN����+!'��+!'��+#���`K����3�`u����3�`m��#���`K��#�������w�����!#��w�-=VA�	;u�U���`�����rpis���:���`w��J[���������9��_������Oo���|�����w������o������/����_�&�������x���?��'~��7\���n,#MxH���Q���U�������������������]����[��	6:e��&8�������������G���-vf�-R�����K����)��{�{�C�q�����H3lt�f�-M������%�[0����{-����e��������{KS�`r��3[I�G�?�^�3{o7�HN��N�����P09������>��5����K�-����l���E(����R����������^����G�^��f�-�����J��`8���Z���K���)�+���xL��f'���#rp���.��`�`rz���f/M	9�����L��'�����/�[ro�	9�����+ji������gV��-8#�����{�����~��MVF&g�?3�to�;rp���O-���9�������������l$�[pAn����%�\��������!�`rr�3I7�\����%�| _���`u�u }~f!������i�R�������3�?.X�dU�����g��-�"_���-M��|9�����M��|�9��}�{>��/g�K��&�D����q��&�M��g����G��`7K�k��&�M3��M�s����S���r8X�^64Y�e�H8x�6Y�K�N��&��/^��
M�����W���r8X�v
�6Ynvx��lh��,�{k�,7K�N��&��'^�&/�&�-f$<k�,�K�N��&�-���Z���r�����gm��V�`������������Z���r��	��&�m����S���rp���lh��V1#��Y�d����>?�6to�9849x14Y. ���&�E�����g���-8"�&/�&�E���8X�dE�����g���-8!�&/�&+!'�����!'�����g���-8#�&/�&+#g�����!g�����g��n.98�9��d����p0}�|H�;r����g���-xG��li�
r�N8��Z>���\����\��Z��9����)�@>���9�hr�ji����p0}�|H�9��s�3+C�\��k�deK�U��+�`�j���O�����gF��-�D>��Z��9�$L_-S0r����g6�n-�O�r69x54Y~J���/��\����p6�#o�`m���h�G�k��&��/�\����p8�#o�`m���l�G�k��&��2^N���`�j����t�G�N��&��������
M��g��#�m�<����)X�dy8���Z��������S?.X�dy8����S����p<�#��`C���3�N��`m�����G�N��&��������7C���3�N��`m�����G�N��&��������
M��v�x9M����M���y������`8���Z����9�rJ��k�,��C��������|9�����a�9�rJ��k�,��c�������|9�����a�	9�rJ�������������#_���jbXpF����q��&+#�>?�2to�9�r>��U��w���)�L_-R����9����{���/��?^5�,9�rJ��������9����{.�������\��/��\���:��K���Y���9�hs���:�����T�������`u�U��k���������p0}�|L����p���:��k�����:��O�����!���g���Y���yB>�M�<K�^��&k���%o�`m�5O/^��������	�W�����%o�`m�5;�`�{-��d��aF���&k�����S����=p���lh�fbF���&k�,���I�d�3p���lh����������C
^��%o�`m�5/���Z�����3���)x�����M��K�k��&k^f$L_-S0p����m�����ks����7�`	�+X�d�p����m��0��krp44Ys@�����C
���p����rphrp44YsD�����C
�������]�1
G���h���p$ L�-�pBN}v���JH��I���e%$�DH��\>���$��$�&u���s��������������s���n�vd������f���;cau�U���>�I]g�����h��
�p!0L�/�0�p�����}��4\�4-}��4|�/�i�@>�4�&u�U��6[
��8\	�7��4\�k���n�*�pm����:��+�a�����O�������:���&'C��L3^B����
/|�H�^��Nk���{m��i-�a���E��d>�a"�����vZ��H�k��Nkq'f�Y��[�C�36�?U�9m���|���6l��`������f>������5���������
��2���x�����i����5��������
������Y���E�!
/ U%o�am�������6l�����\����o�ix�*y{
k;�'l$��aC��lp��Bvl<}�|H�HU��kX�i-�a#y�
�pZ���%\�O\�0c���������_�����������_�����w�����>���/����_�&?o�������}�����_�����W��~bb�J"��F�$\�������I~d>
�������'���?p�9m���&�����J�%!\�a�'~��	}2]F�H�-���� ��R��,%_F� � �caL��������Q��h�R��d��-8���b'l����H�F���� \�m������E!l����H�F����@� � ���!
�a���pD�6��|�������4\�Y[%������a��h�R����������4|����<k����A$o�aK�w��6�B���:!��Y��v|�8,y
J�u:0$y���;/�6���%n�am��:�a��h�������<l{�������������x6tZ�����������%n���������o��������m���x����3����?|����������Oz��i��4��2�%m_�����x��?���/���������w����_����6���G1AP�*�$��(:U��!w������ c���Q/�0|�A�6V�o2aH��~����%n��y�|�x�����*�s��
CK����
�@������3?N �6�������I
��q���"(8I��Q�����C��������� q{?��-!���������%��DH�>���kH���p�/5H�^��-!��/~�������������C��%��kx�%��;�����z���������58��_������[�K<p	�����<�
g�d�^
�kpH��8����pKx��.#��>�a�;�1y/��58���x'O�������L���<�
#��R�_�C.H�;y�Q�oi|!E�^��������B����d\�O�
���R$o�aM�v	�<L�K�
�iy� <��o_H����5��%$�0y/e.�.���+��e��o_H����-���<L�K�����<|^����"y
:�
DV�^
�kpD��ld@�-�Nk���� �����pBd#"���!
���FD��7���"�:�
7D6�!B/���qBd#"���!��7D�7tZ��ldD�^�!
���F6D����7��#"�:�
WD6�"B/���qDd##"n�6��l��
���3"���pH��"���h�
gD�����
���;"���pL��T72#�m/������q����pHd#C"�iwD6�#������x8$���D�l��6\�����C�!����U�im�$���D�l��6��������6\����7�a\��K"n�tZ8%��)�U�i�����Dh�!
����^q����)��L����4�K"[��[�D�����-�N�ldJdUwZ�$��%oH�;��eI�7_���G�/�������{�Wu��c"�����c"[{L����{��-��l���R�D66%B�
��D����k�����K"YY���llH���/�l�!��n���wD6�#��-�����7�_�����k�����+"YY�u��llD���/��l���n�o�7L�dCd��Ya���~�ue��%��������	k�����a���
0X�^�}������#�!x�Y�K�N�4��~=@������#�{��;F��������+q{�jk�0�J��q7��	3�x��Xa�����-VX<^���/@��S���
����m��:��k?6TXa�����VX�%���7x�x�:��
�f��g�M�a�
X��j~�7``�{-�Pb��0c�7m�Bp ��Cp@����+�����M�b��o���c�a�������`���J���`pP������F[z����{���������l)�2rp�spPY98�7Y;rpns�������>����#�������P���&�x^������`�w���rp!����\���q�| �>���| ������p M~���{���G�����C
����q�z�9�69���:n.9��9��8��9�2�~��
����M~���{>���>��Gq�F��ZLV����^�y���[�8p��M�6Yn"�Qnb{����:�-�m"��	�&+��Md�6��#��Ml���xP����M$�6A�dE���l�F]tD����9���9�<�����l��%��&+����������6��i#�������2l�Q��&+������<M�8i/�6��C��3�O���&+��������`���6��h#���9��?�7j����H�����h\�����
MV�N��?�7j��f,�,���E�����lh�b@&S6Q�d����E�����lh�bD&K6Q�dE���8X�.'l$��`K������MT7Y	981�~\q�F�^�4Y9���Du����3�`��Il$��`K��#���n�v���p0U�c
F��li�
r0Y�I�&� ���O�
rpis���:��K�����:�����&�k$��tK�u �
��n�*r�A8���!�x���li�*r0��I�&�D����*R0n�H�k��&�D&6I�d���'�`��G�&��������Jp����m��,q{k���<^�&/�&+9�`	�)X�d%,q{k���'�xM^MV����S���J8X��
�6Y�W�xM^MV�g�H8X�d�8X��
�6Yi����
MVZf$�m��,q{k���K�k��&+-'f$[�,����f ����
 ,y�
���!#�r��]��������J����4�������l�N�2���=!Aaj��4�zM^
eV
�����n��Y?|e���|H�Y84Yx5�Y)"�>�I[g��0	S_>���0�0�Z���0��0�&u�����a*��4�4��4�Z���4��4�&u���3�aj��4��s�WK��#�>�I�h���;�a���4�#�M^-���<�3VWZyx'<L�����pi��j��
�pa<�����Bx�J�!
��G��-���<|v�N�@>�;��<|�y��iU��Jx��;��<\�;�y�6yx�tZ'��Ix��;�y������|D��k$��aC��'8\3�	����"�������8_#y�
:���H�-r�N+;�������V��{m��ie�1#9��i;���CD���vZ'l$��aC���	3�|����3HU��kX�ie������
�V�+f$'�:m��������6�0��H�k��N+/3�#|����+HU��kX�ie\�����
�V^3f$g�:m��W���������8c#y�
:�������xm��7����������c#y�
:�������vZ9 ���N+�����4�V���l��k;���#�a���4�K6������J��l���;��<��<�����S6���������l���;��<�	Sm>�a������-�VFf�6^�i�����0��C�1�{m��i���l���;��<���|H��f#y�
[:��<�6m���*����0��C�9�{m��i��l���;�y� <L����q�F�^�tZy���xu�U��+�a���4�<\�<l��N�a6k3�;�y�d<���p�F�^6tZ��<�vmfm��O���������'�a�{i8:��M�������v<,y;
Sm>�a<,y�
:��U�Hxx�vZ���a��T�i�K�k��Nk�3����>K�^��Nk���%��aC���3����>K�^��Nk_f�zM��Nk_��%t�am��/���������W�W�����i�+����5����xX���vZ�z��k�p4tZ��`F���Nk���%o�am��o��������������������a���4��C��
������E�i�y82�vZ{D�m�tZy8^��VB�����VBNMN�N+!'����������0��C��������ie��LxxQwZy8��|H�;�pn�p�tZ;��NxxQwZ;��Nx�j�!
�������i��BxxQwZy���|L��������i������������0��C>���&'K�U������������0��C��������i��������:��O��T�i�D>�<�,���<|2�vZe����0��#.8r#y�
:�2U�H�3Z��Vq�!"y{
k;��+7������*�`Fr���������kX�i�������d(�������jK���SD�v*��|H�8t#yZ�2��������V���U%o�bm�Up�F�6*6�Ze��7[�Y��VY��J�^��Z�����mTl����`Hr������
bU��*��Z�n$o�bC�U6�!�����*�U���X[l������
�V	�$����f��b���X�l������
�V	��l�f�V[%"�����o$o�bC�U"r1��Y��VB.����>R1.�H�F��r+!���M]n%����X]n����mTli�2r1����VF.�����n�H�k���n���l�fS�[;r�N���1#�m.v�v� ���M�n��B��*�!����mTli��b�}������ \L���q�F�6*��[����l�v�"W��T��wo$o�bK�U������n�N��J��*�!����mTli�N�b2�6m�uL��'�b��GT|L����Q���:��!k��c.��������f�zm.v�v�p����W���:p���U�m����u���n�XRw*�v������W���:��W����v��I�8h��c.�������1K�k���n��������:�b����*�!/����Q���:�	C.�v�X��%o�bm�u�����Q���:��!	m�ul+&\L���7�b�����n[�������:p���U�m���\�\�
�������m���\S�>���\�\�
����#���n�"rq$\L���rqls���[	�81.V�[	�8.�
}L��������ne����X�ne��L��*�!g����bK��#g��Q�n���;�bu��#�.��[�x'\L'��T\���bu�U��K��gK�U�����n���B��*�!��G��gK�u ���������b���T\��k��gK�U��+���n�*rq%\L���O�������n���'���n�N���p1U�#*���#y��:����,���m���#��W����8�#y����|�J&q\��[������U�m�*��H�F��v��C��<rQ�nU�#��W����8�#y?���/�����WZ��[/��0g�`o\�/��|"(V�+��������?������� o���������}����x�����������5��������o���@������+��668�M���h��������>�'�?����~�?��o������0c�>�����j�����}�g8��o�{���N?{	0n�7:���p��e_�x��C�'t���F�q�x��c�����~O���p��M_Mx���'\���&�kJx��c�����~��������o�R�q�3[�����~)�y�?{�+n�7���X�%m��������~�/�f�c��������$s�_m�Ww8�\�v~�P���[<^<<���`/=/�����$s�_u�W�<s���>�v���O2�1�K�o���E������;���#�g6@o���h��k���\pE>����\M\�k�_;����O$��X���z"�}V��l�k'���/�IC�xC�='$��WD��,q�^�
>�3������: �����VX�����
��v�H^�������%���q�~���d���6��`,�{WP[b� X���=3�yo��������N6���(XB�
��X�,y;��x����	/^��_;�����`	�+X[c�`����kk�s�x��l���u�����I�c�+`����x�s����
E��9�H^���E��K�N�'^4���
8X�^_�0Y�vbF���"�3��`uSy�������3����k��3"����
�����i&7��#�`�n�"rp$��,�L�������ers�	98v�&+!'�0X�Y����S��_;����3rp&��MVF����U������9&7�#���������w�8X�a����_��4Y9x'��MVA.}�W�9�49��3Ln.�@.���+mC
>���>����@>�li����p0}�iH�9��s����������&�"W�����!���������:���&�vz�����'�`u�u"�}��MV�&�9����%�����g�=B�
V6Yoi~�	���)X�d���x�����aX������#�w&��(��Il�l���^<�y|v�7���c����M�[�
�x�G+���0'^<�y|v</�?F>.X�d��KP�������9�{��x3���g�a�����S?.X�d��P��?5��1�{^v�x���g�a���Q�~\���z��B�k���g���-xMp�V�����+fD��q��&+O���O�yfH����oC�*����H3�����!o��r��Q������(R�`;��	98�O\��������G�������d�eD����M�[�����g&��-8!�&/�&+!'���&+!�>?3�~s�������������p0}�:�������|��g�������d����p0}�:��9x�s�3����#�M^,MVA�	�'�C
.������L��[pA.M^,MVA.����!��������[��|49x�4Yr�A8�>qRpE>���l��W�������dU��J8�>qS0rp�s�3���|"�6[��9�$L��)�D>	k�,7!�m64Yn�����M����%o�`m���/^��WC����k�,���%o;�3s�����%��`C��������M������S���r8X�^64Yn�0#��E�d�8X�v
�6Yn����
M��+f$�h�,��Xp���J���8X�^64Yn)��p��m��
,y;k�,�K�k��&��3^�M�[��%o�`m���/^��WC��6�`	�+X�d�
8X�v
�6Y.8�xM^
M����p0}oqH�98�9�����Fm64Y."�����!G��H8X�dE����`K����#�`�����rp"�n�rpjr�fi�2rpb�n�2rp�s�3������s��7K����3�`u��#�>?3�~o�;r������d���;�`�����r�����~�U��K��7K�U���`�������K����M��\��Y��9� L�[R��|�98��dU������������p0}oqH�9��98��dU�������d����p0}oqH�'r�����~�u"�M�M�������{�#
�|�H�N���=L�<�^64Y�y�����6Y��'��������d�#��`C�����y����!{������z��y��M��3��z�{�C
�=�?J3��
�5����
M��f$�������I����������G�k��&�/3��z�{�c
�*y;��
�5����
M�������������I��������0Y��{-��d�m��l����8��
L�����F����G�k��&��3�������rp�s�����C������9��������c���6���,MVB��5�&+!�>�?l�	98�9��d%�`�[C�[RpFN}V��3rpns������l����8��98�9X�a�����&GK��#����������>�?l(��{�����*��d�����\��K���6�������d��d�����| }��p M��&�"��O�[RpE��y�����������d���d����5C
>��O�<X�d���g������'�`�[�����p����m��	8X�^64Y�T1#�o�6Y��X0�`m�5;�`�{-��d��`F���y���=p����m�f,q����g�H8�>�S0p��m�K�&k�g�xm64Y�,�{k��y�����M��8�xMN�&k^��%t�`m�5/����S��]���x���M��.��q����W�`��)X�&k����
M��y�H8�>�R�,y;��dm���Z������	��5C
������]�1
���d���� �6C����nR���H��I���eE$�HH�>��pB�}v���9!
�&
'K���Aa��fL������n�~d8gd��d�di�2�p&,L��i8#�>�I����#�6[��ax'0L�ixG��0�&�����4��i��g����0}j3���4\�4�&u�Q�K����
+>���au�u }v��s���h��m�a���`D���*qeD�.�*qm��}�e���� 1}v3����2$V�Z'"��D��}��Od��01}z3��e����0���Z.�H�F�#��2�x
��S�p��?�������������oA��?�������������"����������O��������w�}��~�W���u�����L��I�\��rT���U��4�i~�?���g������z?���o�I����7T}�.d�=a	��}6h*��kX��-�	"y
��e�1d�D�'~�onxM%q{
k��GA$o�aC���C��DuOX�{^ASI�^���o�U��h�P�-��!�g��'$��
o6�?����!
�,��m4l�������CQ���������������"y�
;C��������{� �$n�a��a����
E������077�J�����.�H�F���oIp~�B�A�o���pBN�������N�H�F���o���d �?����
g��Lx�k���A$o�a����y�,��[�!
���;�a�������-�VA&!�VfH�y���M=��H�F��N� ��z+3��y����4��H�F��N�@&#!�VfH�y� <<�{i�����-�VE&+!�VfH�'�p%<<�{i����-���<LfB�������O�����Z'�������i����n_Cz+3��u��������&�xm��Nku��������Z����5���VW���y�:�������VfH�xX�v���C���������Zg�!�<Loe�4<K�^����3���m4l������}��2C^l�����^�a��h��i���!�<Loe�4�K�^��^z]��%o�aC���;���0����<,q{
k{�u����
���%��a�������%n�sX�K���������Z�p <�����</�^z�������Nk��������Z#�p$<L���4�<�<<[:��<�<L��pBN���N�����������������!
g���xX������s��gK����s���/���w��Lx��ixG��<<[:�yx��0�%�pA�	/���
�pi��l��
�p��0��C>���a}/} m�-���<|�y�^�1
#����tE>�<<[:��<\�<L/���+�pe<���O���<��/������Jv�^����#1��CJ>�O�����>��&�v3}k����$@�-��	>D$����
WC$����n������:����6!������
GC$����n����;��?f�Z��O���a��n�H�K���F���������:k�g�������p2D�^�}�&��~�#��J�pH��T���W[Wn�"y/���X��~�#�J�pL��R%n�_m���`������C�{�]������8��D������
�B$����	����nd3�^�!�n�Q%n�_m���\��m�bXp��f��C
����m�6\���o*���d��C
�H����n8p,D�6^�1,8!��z���C`u��[!������`d`2B����32p"��;�
����-%VF&{!�
)xG��7�7+7\
����--��L�B�S0R�N(xS�X8"y�[j��L�B�RpA.�7u��3!��Z���:���V��C
>����������{-�RdU�`�B����+rp%���,�����-M��LvB�R��|��M�H����&+L��d%�^��	8X��
�6Ya����
MV�N���`z��f,�q���
8X�^64Y���p���
8X��
�6Y�K�k��&+�3�6Y�K�N�A�d�y����������8XB�/!��C
���%n�`m�����/�qo�p����m��,q{k���Nx����I��K�N��&+����W���
k���������m��}�WpH�p����m��,y���f�s0��C
���pp�6Y! �6����C���RpD�����
9869��S:�-8"�>�+8���	u����S��_<����rp�s0��c
FN���MVFNM~���{����p�������q������s��_<����w���p������w��Q�d�����/��qo�9��9�^�!��B88����\�_�4Yrp�s0��C
>����Q�d��G��_<����+r���`z�\��+���n�*rpmr�li�*rp�s0��C
>��+���n�N������&�D>�L������ '���m�"��H�k��&+N3�)�WpH�>@$n�`m�q�F�^O�04Y�e��?��^�1�����m�"��H�k��&+z8O3�	z���D��
�6Y�k$��`C�g8N3�z�<�H��������5��Z��������Fm����rq�F�^64Yq���^o�6Yq�*q5w�8\#y����M��\o�6Yq�*q5w��[#y����U��?�7i��f,����]4��H�k��&+�`2^��MV����q��]4��H�k��&+F�`�]��MVD�����G�����-MVB&�5I�d%��D8��)7k$�����de�`�\��MVF����=�����s��WK��#����n�v���p0�R0.�H�k��&� ����n�
rp!L����5��Z���:���lMR7Yr�A8��)�j$��`K�u ��oL�A�  Lo�4�{5��������l�fRwY'�p%$L��4�c5������:���d��.�ND���0�
�p���&
��2+M�������J����5�m��sx��,lh�������uVr�������J�����aC��������������x��i�
K�K����J���d�u�Zi������V��%��aC���	3��I�h�xX���6Zi����
�VZ*fd<����:c�}��FpH�+����6l���Z0#�am��6�a��kX�i�
xX�^6tZi������vZi������V
3^�&o�N+��@x�i;���C��=��pDM��V�������vZ)"�>{z#8�a�������i%��Hx��;��<��;��<��<l��2�p"<���VF�����VF�m�tZ;�p&<�����<��7�C����&K��#������*��;�az#8���<\�<,�VA.�����:���az#8��y�h�p�tZ���xX�i���az#8���<|4y8X:��<\�;��<\	��!
��������i���'�a���N����0��0�����`�����%$<���V��CD���vZ�l$��aC������E^�ie"��������d#y�
:��=f$�ym��=|�H�^��N+�����6l���<aFr���vZy�*y{
k;��[6�������s���$_�����������i�l$���h���R0#9��k;���T������V�5�{m��i�5cFr���vZy�*y{
k;��s6��������������vZy�*y{
k;��{6�������x8�U���r@���������C������y�����N+G��Hx��im$��aK�����������p"<Lo�4��6���������l�fVwZy8�7�C�M�{m��ie�a�l3�;�y83VwZ8j#y�
[:�y�M���N� �������H�k��N� �m�Y�i��Bx��igm$���d���a6n3�;�y� <Lo�4��6���������l�fVwZy��7�cF�MN�N�Df�6���:��O���FpH��l#y�
:�}Bf�6����'�a��kX�i�����6l��v7aF����������5���v<,y�
:��U�Hxx�vZ���0�az#8�a<,y�
:���Hxx�vZ�<,y{
k;�}����
��>g�Hxx�vZ�<,y{
k;�}����y��i�����5����xX���vZ�����y��i�+����5����xX�v�7�c>��5y������m���m��o���W����7b�����j��cHB�����q DLo�T��C���d����Hkk�="G���^pH��86��M�^+"G���^+!G���fpH�	�85��M�b+!'�������@1�RqF(�M(v����H��P��n�2Rq&TL��T�#�&��Rm���;��U]m���;�bz78���X�7��M�n� �����*���q���*������r�@..��Wu�u ������\|t���nU���p��n�*rq%\L��T\��k�����:��+��U�n���'�bz78����ls���['r�I�x��[e����p1�Qq�������n����d�f��[������U�m�
��H�F��v��C���U�n�#��W���*�{#y����$[����*>G$o�bm�Up�F�6*6�[e��8��q���*3�U���X�n\�����
�VY�0�B�o��m��~U��*��[�o$o�bC�U�C�A�M�n�����U�m�
n�H�F��v�lC�E�M�n�
����U�m�
��H�F��v�l'�$�����*a���Gqzz78�b\��������*��l��E��8"���npH�8#y���������VB.����:����mTli�r1Y����(W�\��W�8��Q������d�m�v+#g��A]}���mTli�v�b���������w����T�\����[���\L�p\P�[��.V��Z�
�����n��d	����V��o����\|������_~�z�o��[�����}��������������/����_�&�����?���������??CX?�+����;�8&�3:.�1��W_�?=>�>�'�?���g����I�D��yC�w�C��P�����N����E������mTl���0d��mG���T���I���=���=�9I�F�����'������������L�^�[��M��Z�l���������]�V}��M���������]��ml(��e���w�]�}�O$o;�hqo�����%<
6�|�
/SJ�^����X�Y��m�{�&���7���$<
6�|�_1�����%����������{^;|��(�P��`(�;Gm�w�e�������0�ph��lh���(
Gm�wDD�H�Y����{�H��M����;�p$$�__;�p"_,|����pBN������_>j~�d�UDN������H���A�]rF�M~�V��~3�p&0�u��0��y;���H�{��_�����Yx',�m��,��/j�[��&�v#}o�Q���2� 
��Bu�u �&�v}o���AH8���I� ������(|4Q����{����������������/�pm��kO����D���M��|�'����'b�������o�<^@�I[d�	>>$o�]5�~�����kO����M��V�K��:������M��u��!qG�X\1c��l��-V�3�Q����{���!q��2,���#�%m�Ug����S����:�D���7v�3f��������3T�����X��/3^<�wjX�_ �����V]@�J�N���������A}�S��W������-��
U�v
�~�T�/*��=5,x[0c��.i[���D������"�
���l��j������o�u�������[p@M~� �{����q����98�9����{�������"+"G��doL�	98�9����{N������&+!'���I�de�����g�qyo�9879��#L�-8#g���I�de��L8X�d������/`ro�;r�N��<���9x'�n�
r�����/����\�Y]���*������L�\0rpir�����[��\�I]���:���>?3xo�r�����.����|�s�&u�U��k��������\����%�|"WrJ��n�N��������[��|69��cKn.9�d�m��	9��s�3���|N���Z���:��k���K�N��&�t���Z���:]��������,y;k����x��lh�N,�{k���K�N��&��^�&�xB������W���:g�`��9��8F��O�zM~���{^�H@�~qoH�������a�4�	K�k��.�\=f$$L��7��HX�~�_1C^�%��aC�unf$(L��7��
PX�~�_1C���%��aC�un3�_��p��a�n�3�����0�0��)�6��a��!
G��@^�~����6��c��_<����#�pd4���"�p���3c���RB�M�-}VBN���}VBN}~f
���3�pj�����H����W�Yi8�i��!��F�m��Y;�p&0��}��0��a��_
)xG��,�X���,���>� �>���!D��D��Rg�����W�Y���Ga:|5��I�h��bi�$���0=cH�I���0��RpE�M^,eVE���IC
>�k������O��������:��O���(�1#�}��W
��	?@�&/v*�-�/O�|������������S������5�����L�[��z
=cH��@���&��R0��<�^�3Yo7�H�k<=cH�>C���&�vS��?@�`;��O�����zz�������4��/<mxKs�����J�v*k�����zz����
^��i��_i�ky/
�v.k�����{==
cH��
���4�0�4�5�����d�[���g�zz���7�
�O�����0L�<�^��Yo�
f�����yC4�����_��0l�<�^��Yo������b�ia8�a�cH�i84ix��Yo������'bi8"
G�+���X�m8!�&��B+!�>B>���8����3_d��a�������he�a�^����4���3��x��,�6���s��WK��#��O����<��u�E�NkG��<l��
�0Y���T�!
����a�V>DZ����aK�U������b)�@.}^��������I����:�������b)�"
}^�V������RhU�a:b�.�*�p�������D�M�,}��,�Vl��C
>���>����(|6Qx3�Yn�����u���%���K,oaN�xM�m�sf$$Le�������u|��-����l(������0u	C
������%��0���Z���r��k�,7K���,�oH������
U��+fd�������>�tC
^��%��`C����	S�0��8X��JD�[��%��`C����	S�0�`�`��+n���598�,�K�^��&�m����W":\px��M����p0U	C
���p����������d��S�0���	�cRD�M�&+!G��T%)8!'����~���,MVFN�������3rp�s����98798X����	���!����<V��9xorp�4Y;r��8X�d������:�����`i�
rpa�n�
rp�s����rpis���:�����wdH�r����M��+r���`K�U��+�`�;2���\���spE�M��&�D��������O��������9�lrp44Y~��
��##
�|�H�_��woa�D�^64Y�9�H����#C
v�	"yg�����{-��dywb���E���)�/Xp�PM�3�������lh��?0c��^OG�<�I�����<�*o����
�G�k��*��;f$C6��dH��T����v�&lq��,�$�Hvl�%S0�T��)X�UzX�y��l��� #����pH�+�T��������0`��{-�Pe��8AF�bC/���7P���S�����_��{-�Pe�0cF2bC/����p������> �&'C��#�0����pH�A8�AX�TC�c������d���K8��� � ��
p��S����J�d���K8��� �� �]eF�MN�*+#�	O/���w�������*w������Re���d���K8�`�����A�U�������d�`2a��%RpA.���M��\��,M��L&l<��C
>�����&�@>��,MVE&6�^�!W������n�*rpms���:�������pH�'r�����n�N������&�D&6�^��r�����m��	8X�^
v�����C��pH�@X�v�VY�����
]��vIH�^�!
{ a��iX�e�HX�66�Y�O��0��c�����e�<{�xMv����g`aI�kX�f�3����4�m��e���da7��y�����u��K�N��:k^*^�&���g���!	
�k8��hX�v��Y�
4,q

�ys������7�a��iX[h����m4lh����������l���I�h����6TZs@���5�pD}N�Jk�������Nk�����0��CN�����I�i%����a7�i-���p�?u	����<���~����������y���_�����w�����>���/����_�&?o�������}�����_�����W�s?11J'��q�i������_}U�$�|��r�������<�O��oG���p�,%_A���p���O��>�����"�;��lQ�l�,��lQ�l����| Z}�H���@�8�h�,��hq������o.�"Y�,�
_E��m�p���"Y�>Y�'���������;,�6X8K�w"X�}�pO��[^&�9	Wh���@$n�`C��L;����� �����)X[�-�"q����Y���O��{v�"q;���7�a�����
����������'�v��a� �����[pD�66�{��.d�?����
���$n�am��� ���6�
_Y[�C��C�O��ro���!q{
k��A$o�aC���C��C��6kY�U
��kX[g-8	"y
��e=1d�@T����m���G�I�g-�	"y
��e;0d�DT����4,q{
k�GA$o�aC���a2
�����C���m�\����
�����6�W7Zy82VWZ8"y
[*��<L�Afu�����au��� ���������ddVwZy8v�N�A$o�aK��#�y�Y�i���;�a���pD�6�tZy�����N� ��N�i�4���6<[:��<LBfu�u ��N�i�6��m4l���a�2�;��<|v�N�A$o�aK�U���D����*�p%<L_�0��H�F��N�D&!���:��O����
��������i�����4����	xX���vZ�����yx6tZ�����������%n�am����������Z��!�<�h;��K�^��Nk������x����_>j~�����8;��G�E[k�3 ����L_R�H,y/����L�����@�hK�u��_��M�!�.�����k�����������ZW�a���W[i�+������������;F����-��`X����Z����k��k�����
K�N��:k��%n�_m��������D��o@}^�e��a����~#�ph��k����7"�>/�*k����`0}?pL�������=����	�����������S���k����7#�&���+#�f���+#���#����\0p���n�v��X�b��{���������>��� ������C
.H�����a���xUWX��/)�@.������G��Wu�u ���{�C
���G�q�������������@0}-pH�'Bpm?
��X'R����U�b�H�'�`�V��������`C��M^�>��k��D��
��Xn�H�k��ks3��-Z�=���D��
��XN�H�k��"k�f��[�j��������-�6\����
M��+f�����&k�g,��I�R0�H����&k�f���l�&k[@�J�^��&k�]�{-��dmK���q�M�dm�T��)��8�`�����
M��������M���H�����M��� ��Z����68_s#� ����6��W����pD�^64Yor��?�w�6Y[@�����C
�M�{-��dm9��l�&k����p0}pH�8	"y�[���LvA6u�����`�>���qD�^�4Y	9�:��s��&+#'�����!g����`K����3�`u��#g�����!���{��-M���V7Y;r��8X�d�����~g��d�`�c�MVA.���M.�H�k��&�@&;6A�d���`�N������&�xF��W�`�c�MVE����;�C
��{-��d���d�&���9�$L�	R0.�H�k��&+L��d�&h��0K�^��&+L����Z���
S��}�&+�fC��&+8�`�{-��dW0c�����
8X��
�6Y�K�k��&+����MV����W���
������&+����S���
3p����m������9��d�8XBw
�6Ya�����MVXN�xM^MVX�����m��
,q{k���K�k��&+l3�98j���K�N����!o����Z���
a��}��&+��@8��8���������C�����
98��)8"�&/�&+"�>Gu����#�`�N���rpjr�bi�rp�spT7Y	98��)8#�&/�&+#�>Gu����3�`�N���w�������d���{��������w�����1#�m�4Y9x'�n�
rp!L�	RpA.m�4Yrp!�n����q���:���&��&�"}N�&�"W���&�"�&��&�"�>'u�u"W�����!���g��WK�u"�}N�&+N�r���(8�`���lh��T0c����m�����+X�dE������
MVt3�*J�&+:������MV���{-��dE�iF2Z��MV��"q{k���S5��Z����3���`M�6Yq�*q{k���[5��Z��������&m���W����8V#y����z��?�7i����H�����MV���{-��d�m���{�����T��+X�dE������7C������,�������Gi:�R���q�F�^6TY1 ���I�e��$	���4��5�������I�
�L�2+"
G�����!
�h���6l)��0����mVBN���{�C���{m��feda6^3����0�	��4�0��0�Y��a���L�>kG�	
�7�4��5������*H�l�fRZq���i�k$��aK�u ���I�h���a�n���q�F�^�4Z�0����VE>���4��5���������l�fRwZ'�pe<���p�F�^�N�Df6N�i���'�am��&�������i�	xXB��vZi���x���!
;�W�����i%<,�{
k;����%o�am����W�����i%�`F��N�i%<,y{
k;����%��aC��f�	;m��f�a��kX�i�xX�^6tZi�0#�a����<,y{
k;��K�k��N+-3v�N+�&<L_��
<,y�
:���Hx�i;��K�^��N+m��������J[������V���%o�am����W����N+���xX�i��<k;���C�����Jy8��N+E���xX�iE�����h���p$<���VBN}��E�!
'�����h��2�p"<���VF�}��E�!
g�����h��v��Lx��;�yx����/
ixG��<-���<���N� �}��E�!
�����h��
�p!<�����<\�<����C>���&GK�u �����:���>{�����+�����h��*�p%<���VE�}������O����aK�u"�������<|�y��G_cF>�<l�����%d<����"�������m$���d����1#9�h�vZ������5���!�����6l���w���c4k;���CD���~��q�F�^6tZ�����;k;�</�p��MO����q�F�^6tZy>0#9�w�vZy�*y{
k�Kg�����
�V^v�H�����V^A�J�^����Wm$��aC�����������+HU��kX�^gm$��aC��78s3�q�Y�i�
����5�~/��6�������x8�u�Y�i��<S�6�a����aC��#�0�����V�����0UnC�e�{m��i%�a�o3�;��<�S�6�a�������d)�1[�Y��VF N��sR1��H�F��V+#���E�j�H��1�nC*����&��Rk���;A�E]kD�� 1�nC*�������kdb�s��{��L\S�6�b������-���P��nu�u ��wR1��H�F��f�"���E�lU��J����1#�&��Rm���l�fQW['b�I����!����mTl���	����,�nk���%o�bm��O����Q�����C2.��[�[�b���rkw����Q������!k���K�^��vk�����Z�3�[��1$��U�n�3p���TL����g�b�����n�s����Wm�������W�����W�����n�p���U�m���X��*��[�:��ks�3�[�
\,�{k��}.��������V�zm.v�vk�fI�x��[�\,y{k��}.����
���$\�j��= ��T�
�8 �6;C����@�x��[{D.��)�
�8"�6;K���#��U�n%��H��2���rq�p���J���q�������p1e�!g����bK����3�bu����3�b�tC*���s��������w��������w�����T\���6{K�U����M�n��B��2�����K�����:����M�n���b�tC*>���6{K�U�����������p����^��k���������p��n�N��J�X}[|?���6{K�u"���7m�U&�9	���������
�V�IN����Vq�9"y{k�Q�����
�Vq;�$G�n�v�8����������H�F��v�x8���-�M�n�#��W��u������n�N�,lg��[e�*y-w�wp$�����n���,l
'h����_����;��C8��Q���*��!�N��[e�*y5w���#y���9I�p���*�U���8j?L,8�#y������P*y������?x�0c�?����~����������y�_�����������c�?�����?�>��o���w�?���������??������:�J����wF��k������?��������3���)���O'{�����?�v���������lD�Y�G���w�u�������,�����QJ�p�[�������"�m���S�;��N�2l��>�(�
i��;��h��A��6|����7N����_>j~������1g�	���6�d�w:����9+���+�:x��3����#���W��U|�P����9)��~O|�P�y���^��{�=�uJ���W]���4���H��9�7��N|��c��n�o�����0�(������Q���) �~�	�$H�K���F������T�Em�w8�e���?��:@a�{�����{��F$ �����%o��'�ro�@X�^�}�q���V�H08j��v�3����g�����0X�^�}�Y����#��"�X�%o�_m�u,����k���w���o��X��+y;�jk�c���5���#N�-x�����-��K�N����^�&�x���o@��W���:6 `��)X�`���I�/oro�a������C��9���"ph"�����[pD������c���9���#2pl?��X	!8N�+!�>?s��'���~li�Rp"��-VF
N}
~��{�H���0�Rce��L08�k�18V��;b����5���9x'��=���V��9xos���*���ppRY9��9X���9��9��d�����n���������ys���G��_<����+r�A88����\���)��\��k��_<����O��J88���9�$�����#��>N��	�/�erk�u�x	k��:�G���5����:�G���6l����0c���.i����3D���>��:�����
eVu3��'�xc��gP�����CD�^6�Y��H��<i��:�M�����O�3�T�{m�Pg�9cF���I[g�t���5�}�c]f�z�S�{6��q:�������T��kX���:�z�So|6��i:������+U��kX���z��C��x����m���U?nX�h�
����5�NKU�{�������cFr`����j@����C�����/aro�y8���&m�U#�p$<L���pD�M~���F�����VB����	�CN�����/`ro�	y81VwZy8�y����[<��8��8��i���3�a���2�p��0�R��4��4��a��#
����������>
?�`��������������0\;u�U�K��y�ts���������:��aa���d�����<V���Q�h�������Aa���*�p���3O��-�"	�6	[��I�v�6�D>�$��C�{>��&/�2�D>	;m�uN�g��y�tk��,q���s*��p��vY�������Jz:�`�{-�Pe�.cF���*�t����S��WIO?��kr�bh�N,�{k���K�N��&��^�&/�&����%t�`�m��8X�v
�6Y�|��kr�bh��e�������C
^��%o�`m�u.���Z���:W�	��{��K�N��&�\��%��`C�unf$L�R�,y;k��s����
M��U�H8��;�����>?�����rphs���:rp LO�RpD}~����G�������d�98����)98�9�B)8!�&��&+!'�����!'����`:=������Z����������L�������Z��983V7Y;r���`:=��9xor�ji�
r�N8��;���\�L���\��K��WK�u �����!��G��������������:�������!W���p����������������p0=�wH�'rp%�n�N������&�D>	��{��|��	?�w~��L8]#y�
������<\������zK����G��i"���L�]��{)x�SYodd6���!�������q��0��<�^�sYoW��&l���C���`Me���������E5,x�1#�r���)x�P��?X�?#�����G�k�v2�L���l�UYf���������}L�<�^��Yo�N��v\�mV��������0l�<�^��Yo��H�\��C�<4�����t�~H�0b��{m��g�E�1#�r�'�i8L���?[��A�!
���#��a;��	i�L��EYh��A}�t�~H�q8�q��h�eD&[6~Q6Zoi�#�a�F?���8�8li��0���8�!
'����aO���4�<��<,�VF&k6���1���<�	�E�!
g�����`��v�a2g�OZ���<����C����&K��#�=~������Nx���i� �&K�U����
?i}H��p!<Lw��4| M�N�@&�6���!
W����0]��pE�M�N�"�I~������+�a�]>��y�6y8X:�y�m��S1�4|"����x�����<|6y8:-7K�^��N�M����W����*^�6*-�f�Hp���R��/��|"����x���_~�z�o��[�����}����������}��������������?���������??CV?�+���|������=�-p�$�����W_�?=�V��r�������V���?����P�u��+9���%2�����$oO}�G`����o�~
-��f��v��-����J���=�@����
��$��`C	����l�I[���U��
�g���T������o������J�m��|"�V��o���������]��_�������M����_����}�������w��������o������}������6���%��Vh�aEUY	#�av�5^Vb<���d��~
������p����������aF����z2��$o��'�����$��aUY�O�H8�cO�4�l�l[��ai8��{mXUVb�3����!
���A��~Be���$��aUY��w�����<���X��qk�E�!
x� y�
��J��X\��u�1
#�u4�M�!
�^��CT����� ��E�4| ��~cH�u���|�U�fD0���=�dH������cF�MN��
2�����0=�dH�'��Ix�~cH�'��������~��O(WO�����
�	>D$o��'�������G�k��N�;��]���i������5���<%<�^6tZ��������������n����R�#��aC������D�����RU��~�������G�k��N��;f�������3HU��kX�iy�Jx��6l���� #L�A�i�����5���<�%<�^6tZ~
��,&���ix�*y-��<�%<�^6tZ~�w�<�L�����RU��~�������G�k��N���3����w��4����g�I�m8 �&��Pj��@LV����T�#�g�I��8"�&���jE$b����]?���D	?�Pzo�	�85��M�Z+!�����!gD�D�����{+������n��Z��l'������8&��Z;2qn2��,���PL����T�#����)����P�7��M�f� ���
�!����X���@*.M*v���:�����������`�3[�7W�X|4��M�n�"�
��!W��J�X��<_��k��-���\LV|T�['r���X]n���g��-���\�v�9
#*�'���p�3���V<O����Z�3�[�t`H��� �!;�b���X�n��X�6*6�[��1$��x����+��D<�b���9����~x���s~������Ot���~�z��[����;?�����O�p��E��
�5~-��|.�EFm#8���*����O4�?7��R�s�Fp�I��X�.x��\n>�X�	�2�������Q��\�ARw*N�Fp���r��q��Fpq�I�\n
�o$u�bm#��+&��}f����=|�H�F�#��2�x
��S����?�|�,���||Tz����r��W�<�)F����.����W~��s���`7xC~�p��'���k��e��;J�����"]Vp���'�>�S�<��������o�.����}��O[��7P����[���R���i�e�x���wt�P�.a���/<�'���
�����Q��������.�"����O����������#�El��7��KD��}�pO8�{NH���������6]xC��$��Dz��m8�[9�����[2��#y
[���cHr�����wx)G��V�|;��#y
[z�=aHr����0��N��yfb�������ao��
�pa���
��BxX�t��@.m����-�����>�����L,��0����ao��*�����n�"W���L,��pE��tZ'�pei7|"�������<|vx��i���'y�����	y�$<�~��:K�k����Z�C�vZ���=��������
���vIxX�i�xX���vZ�����
��������pdL��������Zg�������Zg�aI�iX�i�3����5����e�������i�����4����xX���vZ�R���yx6tZ�:c�>�/�ix������\[W�a��h��i����}��d
ix��=ZR�����%���~���|��R�������}$��Q)9,X2Ab�E�!%D��D��n���7 �>��!�F�@�X���5"�&�v+}o�q8�q�~�{H�	q8^�o��pj��k7������au����a�����0��0��m���fD�LPX]geD�LP8��d��������D���� ��A�>[��� �N���;�����7�� �}��l��[������[�K{&���!��!�R��~���@pR��=���C��	��/����_
 C���������*�om?~����W��`J C
>�+���f�z"��'���D>�LdD����'!��m��	>@$o�����i���C~������D��
�~/ks^�����ksp�������6 �����7����O�5�X���o%t�`m��y����������	/^��[C���p�����m������m�����k�zk���e���Co��������W��������Z����V��G����!�`Q%n�`m����Q%��`C���'f�xK�V���X09�p�Y�U�^64Y�v`��q�tfeH�8X��
�6Y[@M~���{���������rp�s���M���C��_<����#rp�s0�XRpD����MVB�M~���{N��������J���q���������/�qo�98�9���)8#g��N�de����������98V7Y;r�N8����9xor��Gu�[pA�	����\;u�U��K��_<������K���������B8����9�hr��u�[��|�9���)�"������������&�"�>o�&�"W�����!�4���li�N�`�B�A�|"������#
r����O����0K�N��&+L���W���
n��������`,�;k�����%n�`m�\���������`?c�>�a�!{�`��+X�d,y���0;���`��1��8X�v
��)x����
MV�O�H8X�d�e��	�c���K�k��&+,f$�m��
,q{k���K�k��&+�;f�sp�6Ya�����MV��xM�
MV���%t�`m�6�`��+X�d�����9��d���L0����`z����#rphs���
98�9��_)8"G��O�1�]0rplr�bi�rp�s0��RpBN�����C
N��������������t�bH�983V7Y9879x�4Y98�98���983V7Y;r������d���{�������r�N8��v<���\��X���\����\����| �&/�&�@>���9� L�:RpE>��X���\��MVE����Q�C
>��k��K�u"�}��C
>��O�����1#�m64YqZ��9��^�(8N�"q{k����5��Z�����c��AEt�bH�>@$n�`m�q�F�^
^
MV�f�TDG/���D��
�6Y'k$��`C�}����z������&�����!�b���lh��\0c��^:y1��D����m�"�H�k��&+.3�O���&+. R%n�`���{5��Z����+���j
]�R�
"U��
�6Y�j$��`C�78O3����m��"U��
�6Y�j$��`C�����&m�rp �>�q�F�^64Y1"����m�bD�����V"��H�k��&+!���x1������D\�����-MVB&�5t�bH�98��)�j$�����de�`2ZC7/��#g�����!�^���li�v�`�ZCG/���3V7Y8X#y�[���Lfk�����rpa�n�p�F�^�4Yr0����C
>�������1#M�,MVE&�5t�bH�9���)'k$��`K�u"���z1��9�$LO;R0N�H�k��&+M��l���^�h8M�������J����6l���T1#o��Cv36LH��w<�a$,y�
���
f$��t�bH�PX����Y�
K�k��2+����+]��0����5�m��<��k�p0�Yi�����uV��%o�am���W�	��Pg�`XB���Yi�����}VZN�zM�>+�f$3�t�bH�+����5�-��
8,y�

��y�Hv\�����7�a��i��z<��
xX�^64Z)L������Jy8��i8 �&C���p`<���RD������������o��������m��|"�p�����������m��_����/�����n��uY���_�����x��?���/���������w����_���������G�CP8uB�_U�dLH�����K��(b<$��?v�~�����n-8���Z��{������s��������*���3�:!q���7��\���N8��1���8����/x�S'$��`U�������.u�)�x�;A�+2�����k�:U�fD*.�S']�RpA*.�c'�wE�|x�x�S'��w���G��	G�:�| �c'�wE�\'�x�S'��v��������KC
����������+^���Q��A����O�pt�cH�'"��?~�~WdH�'r�����*�~�1O�UO������O���Qp��|��y�a�n�������!��������)wl�e���o�W�H�*]�R0��H�������q�&_vl�fX�/���cD�:��;6��3�J0�`������<g�H^1�Kc
�*y?��C
��|��y��a��a�/c6�m�2��H���*���q�&_vl�fX�
/�����k���;6��3�J0��/^���dh���`F�~]�R0��H���*���q�&_�lg�p����_D�:�4�C6��s�J0�a\���%��6��/s67���2.�H�_��0N������,F���|�����)�����-�|��y|�����,|���au��[6��s�4�a���1��6��/�6]B:�1�a����a�u�!
��M���<0���i�2i�q��>�l$��|hH�8g�/s6N7l� _6m>nX]h��������iy��g�u��������
�-������u�!
��M���t�oXqE ���|\����E��9�R1N�����O����H��a��+V�Z�i#y5��8j�/�6?��[V�H|����bm��O��'Cb���}$����
��>I��.w��K�_M��X�6*6[���A����@����on���x��P�v�oX�*����������%��|usH�����������g�bI���t�cH�3`�����D�������������C.�C*^��%��|gnH�p��mTl(���cH��t�cH�+p����o�
�x.����
���M�p1]�R�\,y?���C*���%��bgh���bH��t�cH�a��	��E��C������rq \L�<�T���b���#rqls�3�[{D.����������#�b��!'����bgi�rq"\L�<�T����b�
�!g����bgi�2rqf\�n�2rqf\�.03rqns���[;rqf\�n�v���q�������6;K�U��w��t�cH���0.V������Y����.��C*>�������C*>���[���� \Lw=�T\�������C*�������v�"W��t�cH�'rq%\L�
;����ls���['r�I��.{����$\L�;����7��Q���*��Y.�7W�m�
N�H���F���q��\�o~����b�p����k����7��s�;�b��)�����~1���9�����q��v�������/��������#?��bX��`��I���{��o$���b\�)�����~1�x������C*����9o���o�e���>���	C�O�ut�cH��#y?�M�!��M������{��+����������qG�~��C*��r���k��oC�O�ut�cH���#y?���!�N�,����{��r�e�����V�	��9�'p�e��/�V��#��M�n��\	��T��7��Q���J��d��m�v+!'����1#�6��v+#������\�	�3�T��7��Q�������������\�3.V��7��Q���*��d�m�v� ����p$o�bK�U���������\\�\�~�t�	��h�Rn��d�u�U�����!����8�o������_jy��2"�5��VE2����w����K8�����������d
�u�u"������1!�M.~�~����	�X2�
�v[�T,y?���c
>��5�����{vF$L������%��|/vH��X�^
~�^�����������:<������
)�K�K���J�[�<aD��A�j3�����o�
)x����_{J|s�#�N�X<L��/Z
)x����_{F|o�K�������K�������W�a�{)��'���f��8X�g+p����/Y
)x�����������7a	���Q�g������X
i88�z���.�H���p�vYG@���W��4�$:�M6�A��-���(	
���i8"
���a���p$,�mVBN����o�4���S���������pT�Ya8�_��pF�����>+#
gB�Q�g�H��������4��[
�qx'8��VA�����8\��L[��<\Gu�U���a���!
������J�@>�+�y� <L�x3���<|�y��iU���xX�iU��Jx�~�fL������/�qo�'�p%<�����<|�_����<|6y��=nm�N3^B��I�i�	>D$��|�fD�Wp$��aC�U����h��������9_��0��H�k��N��3�������~���1��;7C�
�{m��iU`Fr�o�vZu�*y?�+7C�	�{m��i�y���������RU�~�7n�4�8�������K����_���1
�T������!
����6l���
qV�����V]A�J�������q�F�^6tZu�s8+�I�N�n U%��|�fL��JUi��i�0cFr�o�vZ5 ����6C���{�:����y�L�xoL�y8�_��0��H�k��N+"�?�;��<	���i�o$��aK���������VFN���n�4��7���������d��O�NkG����7n�4��7�����������������<��_��0�H�k��N� ��?�;��<\�;-������-���<L�o���������~���G��gK�U��������VE�����%��H�k��N�D&�7~RwZ'���xX�a�����-���<L�o�����	y�$<L�87��s���<��9�����vZ�������!
;�a�{m��i�n�������:=�����/�
i�K�k��N��	3v�N������s�87�����k��b���xXB��vZ�<,y?��sC^&�zM^���K�^��N�\��%��|�jL��^��C�u�3f$<�����K���j���W�a�{m��i���������:7�a��9_���<,y�
:�s;1#�a�����`�����n�4��C��
�����am�uF��@x�~����o�{��~x���Z������O�C�?�p����_��P}���?�������w�������������}���~��_�����������������?���Q�!(G!��?���
2&$��?�����
�!��q��Q��o��($���UU�aF���?����Mu������3S����(
I{�WU�aF���?�����
��H���3�����A�����v����{� 
��k7��L���xf���~����y��*�0#q�C��x�����K������n��px���P���
3"�C(���0���?���}�{�=��5��XU�d�H�G�
��7��4\�GP���g���($� �mn
r�/��;(������1#R1y���^�!�������~��������E�c�����������~�������������~�������������0s���w��x�%37����/��<�^�Um�Vn�{��mo�~���3+F��7���~7U�a����/]8�/��<�v�.�0\�k����TEf����T:o>�_��y���;\�a����p���6�X0#�t�|H�0q����w�h�p+\�����*�0c��D��GIc���/Y�yf���~a�������h��2�}O%
��my;�m�mi����6��AF�n����!��_�n������"���m6;uL��l�x�(iH���l�<�0wk����l�Y����K�m<}�4����K�m�����������,�UF�%�6�>j�oF�%�6�����oF�m��l��*#��UO�����#��U�g��n�wG�mo�K�#��MO���� ��M�U�_����M��W��,�x��fL���d�����[�=��{6��_��d���'4C�=����3����[��k6��_U�_�f���!�V�_�f��l���"���l���:�����Oh��{"��-�U�_����%�`�����K�l<}B3�_7�J�N����M��������rn�����!�:�_�����`���:�_I{���_9W1#�_��fH��c�}�}f.��~=�����k���/������r3����������+i���+7g���W�_��W�v�U�Wn���5�7���O����Oh����J�N������]����r+���������
�+y;�*�+��x���
����H��>����+y;�*�+��J�k�����	��'4C�
������L��o@�
M�����E��@��>�y��u����?>�7������_��{�o��[�����������}���X�����������O�����w����`���
��7>~��w�Knm�H��r����U����O��O�o���pW�@��C��k�����H�i���W^���O���s�k�<M1?���$�)�gZC�=x%o;�3s���[��5�R���o���G�^���o���G�N���o���G�k���o���G�^���o���G�N���o���G�k���o���G�^���o���G�N���o���G�K������:����>��/��?�v�U6~3l�?�^�54~3l�?B���6~3l�?�v�U6~3,�?�^�54~3,�?B���6~3,�?�v�U6~3��?�^�54~3��?B���6~3��?�v�U6~3��?�^�54~3��?B���~cm���G�N��o���5�H{���_��5���W�_���l�?3�vk����4������<}�5����K����]��������O��*"���y�LkH�	����?3�vk�	���2�,�UB�e+�������de����[�������d��2�/���Oh���#����g�n�wG�m/���R`��lb�>�S00��fo���p{`�M�� ��y��fH�	�,�?3�uk�pi��,�����C�!��d`��=�{Fn�����aUd`�/O��)�"�}����*2p{]�M��Df���1���O�`r��3kz�|"����di�N�`�.O���(x�����-�2����ml��<�[R�
��X��O������Z��;������
=���{K�^��k��	�����K��`���Q���Z�xoI�+X[d->Ar�wRY�������G��&k���%u�`m��� Rr�wR6Y�����F�����Z��oI�)�>�R�&u!g{'e���^;����
M��'|K�^��&kY��.�p��l�����C��(��d-x�����m��
L�BN�N�&k���J�F��&k�3�%u�`m��������M���C�����Z��oI�+X�d-9�����M���c�����Z��oI�+X�d%�`r�w�6Y	98�9�Y�,<�[R�
V7Y	9�������pFNmv�*������UVF&g|�I�e�H��C��.�������]��$LN�v���*��{�-e�-�{
����(L��v���*�������f�q����0}f3��Y����&m�u m��:������uVE&g}�I�gU����a?�g-���p�?u	����4,����w���O >:����P��~�q �������~bb�N"����'����>��}�C���3�G~�.V��M��o�qn����74|+�����n�i=��O����-Vr~���
�����Q���[���lt�O�����+9@�M��o�yn��(����x��JF�������@+9A�M��o�}n��(����x��JV������/+9B�9e���@��ml(�V<Iy%3�O���\�
\��3��S�{+.tK�F��~o���W���?M
7��Xp�!�s�zo��n��(�P��x��J�������x���S��S�{+ntK�k����[�0��,u�O��rw����e�����#��Q���[#r0����~����#rp$L1}D���-q���&�`���?����'��D8�b���q�[�6
�4Y9��u�������3�`��C
F�m�-M��L��������w���&��%n�`K�U���\�W7Y9�0�6Y��-q[���L�����:���`��#
��n��q��|��/-��q��*"
��n�.�*��AP�����q�[�^~�_������ L&�gu�U�+a��#���n�{�����{�=��b��.�N���`0���n8�!q/��v}k�o��������Y[cm|tH�^��k���{����{�up@�F�?fm��9�����z�%����R�k�������?�e�VX������WYam��!q/�����zg��g���k���J�^��k���{��������L���������������6\����z_{|s�#�>������Xo�HBG�|D�8�!q������?�t�vW��T�v��\>�_�����h��e��?�t��V��T���U�V�~H��;:��D_���h��- �����G�����p�����K�?ms�Ed�H�����~�}c�}_<���~�/Y�X��UB�M~)���G?$��_Kw��~������2�o&�K�|D�8�!q��Z����,,��jG��	�R:�/n~H�k���jG�%����*��;�_��#����{��R_�_��������0���W��!q��Z�����~,���@�=�j�+�����6,�UE�%���������/���������k��N�_2�������$�K�|H���g�_<���~���K6?Vm&�_���W�_�	�W�^�5�W�y����U�_�+q{�*����%��_C�����j����%n�_e<�����k�����������
�����x>���W�^�5�Wa.�������
����������+q�����d����U�_��W���U�Wa�������_��WBw���Wa����~��U�^�6�����J�N���*l�������
������/��qo�a�����U����/���������������j���#�_��#�������/��qo�	�7��wS�W	�7��x>����������7��������������R<�oF��M�}���{������������3�_��#����&��x�������{�7u�#���)���� ��M�}���{�-��������*����/�����������:��>�n���@�=�R<�/����_KU��>�n���"�V�����"��6�Z������wS�W'����W�_���g�C'�W������|zH�N���'�����~
�Utf�=�i�����C���U�WGh$��_C]����������c�d#����~q�F�^�5�W���?�7h��8�=���~��U�	�{���_�9c���A�_���������".�H�k���*.p>f$;4A�_���������"�H�k���*�p6f$34A�_���������"��H�k���*nf�����U���J�^���*������k��b����n��W1 �����*������k��bD�%4A�_����*����3���j��"�/��	��*!�F���G���3�����J��d�&�������R<�/N�H�k���*#������2�o&�K�|D��<#q��Z������Du�#���)����g$��_KU���LT�W����x>�_�������_��d}&����� �K�|D��9#q��Z����K�g��������/���������k��N�_2=�����{��x>�_\����~-����K�g���J����W�_�	�W�^�5�Wi*����Q�_%�+q{�*����%�����_%�1#�_m������K�|D�~�k�����_%�+�;�j����%n�_e�f��������J3���n_������+q{�*��4�x�������,����I�_��W���U�Wi����~
�UZ=f��o��Wi����~��UZ�%��_C��	3��7i����J�^���*m�������J[��}�M��*����x>����������C����J�7��x>������k��RD��}�M��*"�F����*!��6�Z����������UB�M���UF�MM�
��*#�f����*#�f����������,�����	�����w'�K�|D�;�����`��
����_���)� ���G\�K����:�K���n�$��0�H�G�����:���>�I]aUD�� 0%�WD��D�`��*"p�#�����\	SDQ��|68X:���3���%��|��>���4�Z���������m��� ��W�����@#q�Z������vh&m��|�H�^��+����l�����23���=V��	"y{+{��4�Rp4�Xy�1#9�w�Yy�*y��<������l(���0#9�w�6Yy�*y{+���+4�Z�������Y�N�d�u���ez��#
��{-��d�����0^�m��&U��
V6Ywh$��`C���3��x����L����l�2�H�k��&+�`6G��MV������b���q�F�^64Y9"�=�m�rD�}��G�S4�Z���J��l���������)�)98�9��de�`�H��MVF����M��H�k��&kGf�4N�d���;�`m��k4�Rp�4Y;r0��q�&� ���)��(�h$��`K�U���(�S7Yrp!L1}D��G#q�[��9���xu�U�����G��4�Z������l������\	SLQ0.�H�k��&�Df�4^�d���'�`��
�'�������d�p����m��	8X��
V6Y�T��598������p��6Y������M����%��`C��{�	{m��{�`��+X�d�8X�^64Y�?1#�`�m��y��+��}����
M�>��p��6Y�,y{+��}�����d���e����U��K�N���G4�K�F��.k_�d$����HX��VvY����5I�M�2k��%u��Y[f�����5�,��0��k���m���a�Y�f�Y8��>�ad��da7��="�����#�p$0LY}D�a86a�M�>+!
GB����JH���0��
'����a7Y
��8���B+#'����G4��s��di�2�p&<<��y8��>��yx��������w�����*��;�am�U��K��-�VA.��gu�U���am�u �6;K�u ������<|��>���<|�y�Y:��<\�;��<\	S\�0�pm���tZ'�p%<��;�y�$<Lq}D�'����ag���4�%$<�h;�2�����5���
n�H�F��N�8�!��E���*>D$o�ae�Up�F�66tZ����[�h;��gl�����>�a������
�V��$��.�N�� U%o�ae�Up�F�66tZe�1$9�w�vZe�*y{
+;���5�����*�Y�������RU��VvZ�k$n�aC�UV8c���E�i�����5���
��H�k���i�
�,l�f�vZe�*y;
S\�p���N���6fIN�]��V	����0��
����m4l��JDfS6���*y8��>�a\�����-�VDfc6���J����0��
����m4l���0��Y��VFN��)��h�l$n�aK����������2�p&<Lq}D��e#q
[:�y�M���NkG�	S\�0��H�F��N� �M�U�i��Bx�����q�F�6�tZ�0�Y����<|0�vZ�g#q
[:��<�VmVu�U��+�am���6���l��N�a6k��;�y�$<Lq}D��h#q
[:�y�����N����O���4|L�������:�C�������%o�ae�u8�a��h��in����7m�u8�a��kX�i~�������ixXR��vZ��������1{�xm�
��1K�^��N����%o�ae�u,^�6��N�X��%u�am�u,��������:��y�7_���G�/�o����9	o�Z�X�%o�de�u�����k������n# �����K�^��R���%����n�o�����7m�u��e8�����8�8���������`X[ha8��>���0�0��m���FD��PX]gED�HP����~�pl��k7�������.��p" L9}D�A85A��������3�����2bp&L)}D�;bpnb�k���wG�	u��#��)��!xo>~���������oP�X����x>����[���_{"|o�p!�-��|�|>����|c��`$��pP7X	� L}D�	�v^�6,�"W��A]a����!���:����`��Od��0pPwX'2��X�aU������
%V����J�m\��Xu�O��)�2���q�F�^6�X��I�����m���O��+X�bU������
5V�p�f%�6?����D��
V�X7m$��`C�U�3�O�uQ�c�4������*n�H�k��"�.3��uQ[d�<����,�*N�H�k��&��f��������+�T��+X�dU\����79MV]+f��������������G��6�Z����[���S|]�6Y5�I�����MV�=�{-��d��LFm\�6Y5 ���&������lh�jD&�6.j����#�`m��k6�Z���J��d��G��[pBN��)�)9859���:�-8#�E�MVF���)��(�l$��`K��#�A��M�����>�`������-MVA&{6.����\SLQ0.�H�k��&� �9��M��\SLQ0�H�k��&�@&k6.����|��>�`�������X���L�l\R7Y9���>�`������-M��L�l\R7Y'r�I8�b����	9�lr��gt�Z�9K�^��&����%o�`e�uN'^�&�xD���3N�&�t����W���:p���lh�N�1#�`m�uz�`��)�b���=p���lh��y�����M�9K�^��&����%��`C�u�3�YW����_~+��������������?������� o���������}����M����?�>��o��������x���?��'~��7\���x_�w�k_����wy������������{'�T����	C�w�	3�w�'m�wF����o>1�9����*�M�3�g���|ay��g�����:��7���*�M�3�g*��|cy��g�����:��7���*�M�hb(���1#����-���wU��u�'�=o.x�����`C�w���B	�+X[��;<]����?-wo.�8�x�pA
���S(�{���O$o��O���>����)�R�f$�Y����O$o��O���>�����l)�����;�����H������7\��k��K�w"W�����D>���������g��K�w"�����klu����s�������� �����L�[�3�g�N�d�������S���zK���s�"��L�[�3�g�N�d��OP��?>zb���������3Yo�f$�����zKS�`�|������/~��l�3Yod��3j�l���(x��F�����/^<�R���z��B��<�v�&�-M����k�O�z�]p���"U
�3YuZg�H��v�&��S��������7��x+�T)��d�is������M�[�
���Q>1�ys�[����H���L�[�3�w�����SX���k�O,z�\p@M^�L�[$���8X�d�)"�>?1�ys�9869x�3Yo���#�`�n�rp�s�{�7���S��WK�����`�n�rp�s�s�7���S��-MVF������������O�y�\����li�v���p�W7Y;r����'�<�.9xor�fi�
r�N8�����\�������������d���p0}�|H�r����'�<o.�@>��Y��9� ��MVE>������W�������dU��J8����9�V7Y'r������d���'�`m��&���p���rp���lh���0#�`m��&�`��������;�������r8XBw
��M�s����S���r~�������d9,�{k�,���%o�`m��|����`C���3�_�R�,y;k�,7K�k��&�-3�_�R�,y;k�,�K�K���d�������4��.Xp��������8X�^64Yn=0#�`��!o����S���z�o���598�,����p0�����p����m�\@M�&���@8�~AsL����p���r98498�,��#�`u���#�`u����c�����J���q���J�����O�y�]0rpjrp�4Y98�_�RpF�}~b����3rpnrp�4Y;rp&L��9��9x�s�s�7�#�m�4Y;r�N8�~AsH�9x�s�s�7\��K��-MVA.���4�| �>?1�ys�r����hi����p0�����+r����'�<o.�"�&GK�U��+�`��1#�>?1�ys�'rpmrp�4Y'r�I8�~AsH�'r����'�<�-�O�r698�,?��<�G�^��&�O�	"y;k�,�&�x�"�,�V����y��!;������M�w/~�H��&��3��)���C
��	"y�������` �Z���������z=�����g0���S����3�T�{-��d������z=�������������/ R%��`C���3������C
^��J�N��&�� R%��`C���3������c
�*y;k�,�-x�P��,�,�%��������C
���J�N��&��E�lh�|@���4���C�����������M����d���/h)8"�>?1�yw��������d%�`�[��4������������]W��_9�BU���|�kw��T���YO�*E�$��4U�����>����n�}]\��pD����s��Zc��������:x<��cN'k�{k*�����:x:8��5QO�:x��dM��boM%4�<SO����30�3u�|����N�L,��T�A3
�u�����<�P/�:x��d-��boM%4�L��:xL�d�������d���boM%4��R���;Yu�z��s:Yu��[S��(o�������N�N������ie��bqM%;4�0�S���[Y;��~*��"��UT�bsM%[4c0\P���a8��UP�����fV]�)������p	)lx�S�Yu	)lpO��f��N�B�&�(W5Z8��UW������vV]���pj;��!�
��pj;��!�
�	�����	R���~V]C
�sx��^����;��e�����aC�P,5�P�@^����V�V��� .���V�Bj����V�B^��������s$qFW�� �
�GqjW�� �
�Gqj[��6F���}���	Rhb��������5���55�=Eq.����V=P�B���(��/����)���sU\�t���A�b������x�U���55�#e�x.�����HY<
Y,�6�P<Q��,~����x�.��uq������'��e�f���'����[3u�t������L]<+]������g����[u�|������B]�(]���Z��������J]����2���R�B���(������erwk�.^�uq������W��e�f�7��M��2���Qo�.��n��������3
�;u�.tq������wG�t�v��]�b������9�]\�v�n�1�G����VSl��2�dg�K�#���8���p���=�8����A���*����
����(N�n5�lcxO(��n5�D��\�J6r������(N�n5�mcxO(��n55&o6b�M%[9�P\�_5�������m�	�������F���d3g������8���p���=�8����
A��}+�������u(�R�[
7���3�[MW�?���
�Q(���^����V�7������V��O��dKg�{�b��Q���j�����P��j��6�[1�.~����?������7���=y��o?���������KV��?���_��g{����/?���?>��+���_)��R^{d��8���t�?����{�����? �3?Rb����p�O��sm��=y�3�}�D�!��H���G�*:*�I(�*����!���p�����0��i�Dax��������}\bxO�i�-b}�tZ�0�P_,J_$���9���0���[�/��i�Dax��X��Hn�qu��=a8���Q^�"�g���Fu�)u������{�pN�o��D.��3�3����[������{�pN�og�M��.K���9�]����>_[ �fxO�����D�"�v��%0����c8����5�G=������w�<
c	Il��/��%��$6������*�SI|�e:,��av��P���
���z��6��jg�N�}W����
!�|[jK��!�
��ojK��!�
����.�a�m*B����V�@\����V�@���]�����(2m�����6�������6�~��D�w#DU~����&�B������6�~������[Q���VV�C\���VV�S��2��4yX~{�����G��/Ep�Dpj#�(�����})�������������w��Inc����yJ���pX�G
����A�B�H<
�$w�F
��<#������G_K!
��$p������'��4#�3%��K`�!D!x���n�[X3%����3�P���&B�j�Eh�&���P/����&�B��"X�Q^)�!���&�J��g�s�X+U���`i#D!x�
^�
n��XU�v��icm������m��2x2�Inc����ymtNk���N�c�������}���C����F����5�Nl�NB�����Nmdu�bx�gt��#;�<D:	Q.q�\��"���qm��=Vrdt���!F�t�\�1������[C����NVWW���H�NB�k��#8���qi��=�������	��I�Bp#��z�v�:�1�G�3:Y]��?U:	Qn+��,,��NV��!��HpF'�kb���J'!
��T�������.��	��du�D��lT�$�!F���N�du\bx�gt���:Xl�NB�{��^��6���qU��=�����`�/D:	Q�����;Y\bx��t�F�`�-D:	Q��G���;Y\bx��t�&�`�+D:	Q���'����N���c�JN'k��B�����:x:�K�dqE��=���������$D!x�����;Y\bx��t��`�%D:	Q^������N���#�9���:X��NB���W����N���#�9���:Xl�NB�7��M��.���� ��HpN'k��A�����:x:�K�dq1��=�����`�D:	1��`�������`�{$8����1
����K�`������K�`�{$8���W1�:X:	Q���
�Gpj'����
����NV_m���`�$D!��H���}j'����
�q:GF'��b�u�t��@\���NV�@�#����������I�C0t���N�d�m�����&�������!8�������#8���w%�w����NV�Ah���NV�A\���NV����n2:Y}���������:�:�O�d�=up����NV?P���NB���A��>�������nr:Y#u� tpr'k����;Y#u�x����N�H<
������G���;Yu�t��s:Yu���`�$D!x���N�d�������d���������`��Y��!���P��:���d-����������:x:xH�d�����ns:Y+u���`�$D!x�^��;Y+u�z����N�F��:X:	Q���7����N�F����6���So��NB�w��]��!���S��:���d
E��:X:	1
 �#8��5p]��=������AE�I�Bp��`�ZqH�d
\Ucx�gt��r%FP�t�\�1�������j����N�P�����NB�k��#8��5pY��=���������I�C0�T���������	��d

�ibg�t���H5��cj'k���{ ���d
-�ibi�t���H5�������j����N�������NB�;��#8��5pa��=���������I�BpO�<�v�n�1�G�3:YCO,��H'!
�up/t��������	��d
��bq�t�<RB���,��1�G�s:Y#u�X\#��(O�����cr'�+k����N�D,�H'!������cr'�+k����N�L,�H'!
�3u��tpr'�+k����N�B,�H'!
�u��tpr'�+k����N�J,�H'!
�+u����J/�\Ycx�9���:X,��NB�7�����U������{$8���Q��5�I�B�N��:�*�;Y\Ycx��t�v�`��F:	1�����U����`�{$8��531�:X:	Q.��
�Gpj'k,��
����N�X����`�$�!:��z�v���b�Nup���+�`����+�`��������;��}F'k���
�Cpj'k���
�Gpj'k�7�T������Q���N��@\���N��@�#����-�Q,p�VB�[a��1���[a�{d8��5�;1�
��K��p��a����^��A	��CF/k�Vb+\����R��z�6���R�?��CF3k�)�{_
��M���@-�-\�v���Zx8��CF7k��_��N��0�� �p���)��S1<���F�������0<R
�B
�����jx<U�CN?k��|5\JC!
���$�p����(��S9<�4�f������t�0<S�B����zx>��CNGk���Nni-�����erKk�^N�����Z�����{Z+����prOk�^��pNOk�^���B�7��U�����F=�������F=�	=,-�(������UrOk��O��������w�����a��]��*��5q��=2����
���i)�`x*p�^������6���pFOk*1]sRkl��������N�iM�`cx�g���
�5'��FZ
Q�p�^������6���pFOk�kb|��������N�iM�acx�g����$F1�WZ
Qn`�^������%6���pFOkjvb#|�����&��p��J�iM�bcx�g���v%F1�WZ
Q�`�^������56���pFOk�fbC|���a����c8��5q���=2����z�a��FZ
Q���{�������E6���pYd4����X����B�
�A�:���U6�������HE�6�HS!
�#�(q����2�{BqN[k�$V;m������x��Nnkq���=�8��5S��6�V�B�LM<M\'�������P����)��^�+D�x�(��(��[\icxO(��l-T�j��4�P�R/B���-.�1�'���V�b��F:q(�,^�,��[[\kcxO(��mm��j����P�QoJ'�������P�������~�-D�x�.��.Nmn�u�������\@j�����\@^��&��5�w������\�)t���P\B^�����\B��3�[sU����[�Bq]lx=�S�[s]lxO(��n��N�BKo!
�uM��.nR�[s
]lxO(��n��J�BKo!
�
t���(N�n�
t��=�8��573A
],��8C^������6���..3�[s]l�=�S�[s]lx=�S�[sW1z�����n�t���(N�n�t���(N�n�}�����2��5�����������.��.N�n�=uq������<P�BKo!
�u��tqrwk�.]�������������x��M�n�����.�r�[#u�(t���P<Q�B������x:��UNwk�.��.��B�g��I��6��5S������n�������[�C1u�,tq���Z���s]\�t���E�b�-D�x�.^�.n��[+u�r������J]�
],��(������mrwk�.^�uq������7��������x��M�nm����.�r�[;u��tqrwk�.��.n��[;u�~������RT���������9bx=�S�[���3�[KY��+��(�8G�Gqjwk�
�{BqFwk)7�a�����&��P��K�n-\�cx�����ZR����B�k�����8���p
��=�8����A����[�C1�U��Q���Z����P���Z�\�>�RzQ(n��^������U8��������b:�"���[�Bq��z�v���1�'gt���!Hp)��(w�W
�Gqjwk�2�{BqFwk�+��G��[�BqO]�]��v�n�1�'gt����X��)������x��K�n-\�cx_��������{Xn��a�4{qJi/Day�4�4Nnpq%��=��w]�<R��8�4�<Q�J'�������B����Xl�)���`��I��>����8��@�]�����b)N)��(����}rk��p����.��	^(��N�R�
Q^(�!��������w]��R��8�4��R�B��m-n�1���J&x�qJi)D!x������Z\�cx��$L�N1,���P�B�N1�1�'������+E�`�`���vB���:x:�Omh�t��=������X�Q	��~�ZB^���~�ZB��.���1*%���ZK(a��1���Z���;Og4��
R�@;K3!
�����Nmf�u��9�������c8��������axH�f�������3�Yk����N��p1lx=�S�Yk1lx�g����"F������j��z����j���hh�]A�BKC!
�����Nmh����=2���Z�����B���=<�v���z�?��-�������B���^��!���������i��� ����0L=<=<$��F���T�7�#0�#����prOk���{Z��x�������zxRz8��5QOJ'��&���T�7�#0�3��$����0<S�J'��f���T�7�#0���,����0�P/B��=��zx9�������J=�=,-�(������crOk�^O��}�<B3L=�
=,-����;�C�����g=��~���~������<�����?������_�~�������!����������������_y!�+��T!	�Jl��"���a��������o�Vl%�����[�����}�^J&�wo�0�������+�	Jpynp�g��j'F_�����Bp��`��|eShX�k�s�{$8���+1���&L�Ls3��l��7��HpFpkfb�z)=�(���fx�/��a	n��
���'���#1���L�1���:_���%��<�p3`-��C2�@{���s��C��7,�}��q��������$�,
�(��nnx�/X��	�<�5���2<���g�K��D!x�T6���������o�I`�G��A��1�����������
K�H<�������&�:x:xL]��M������l
K�D<������&x����;Y3u����+{A�<S��:���d������cr'k��}|e+hX����\�t���E��1���P/���4,�+u�r��s:Y+u�*t����Z��W__����:x=��MN'k���N�dm�������
L0u�v����N�N�)������w__����:x?��MF'k/��wQ���E!x/��
�Cpj'k/��
����N�^��(j���N�^6$X���N�^B�#����\�Q�l�����6�����
Kplp�gt��j&FQ�]�v��:��:�v��:��	��d��H��`�H�d�5t��uN�d�M�����&���7���#8���7����!8�����w��3:Y{l�=�S;Y{lx�S;Y{�1x�:8���w51���"���w����!8���w���@p�������N�d�=up���+�?��S��:���d�=up�tpj'k��{__�����:x8��mN'k��.�;Y#u� tpr'k�Oup�����G����N�D<
�������S��t�&��I��2��5QO����3,�3u�t����N�L<\&w�f�����W6~�%x��Oup���Z������N�B��:�����S/�:���d������er'k�^}|e�gX�W���\�t�6��U��2���Qo����3,�u�v��s:Yu�&tp������7__�����:x?��]N'k���N�d�E�d�u��=�!	~@����=���z��#���'v����o<�h{Apb'�]���<@n����31�yAp���z@����#�^������a�x��n	�F`�x��$8����f�'�� 8���u������2\��X�N}Ipb'���kh{�we�gX������z��e$�i��������N��7������N������z��e$����v�K�;Y�z�f�=���z� x-����/#�]I��S_���z�������_���z3!x����/'�;1�N}Ipb'k/��sX��;Y����s���z�D�\%v��b��}|e�gX����T����H���������:x�u���a	���S��t�F��Q���N�H<�:��~��O�����s:Yu�$tp������'���;Y3u�t����N�L<\'w�f��Y���N�L<���>���P�B���Q^��__Y����:x9��}N'k�^�����R�����3,�+u�z����N�J�
,'2G!x�^}|e�gX�7���T�9���:x:XNd�B�N��:��f���������d������r"s���w__Y�������upF'�,��
�Gpj'�,��
�Cpj'�,+�T����6�������6������*�S<dt��
:�@{�v��
:��:�v��jc�Nu����*������\C^���NVYC�#����)�Q�`9�9
�
t��uN�d�
t��=���*��������$���WVz�%��6�G�3:Ye����r"s�;�`�����z��#x��2:Ye7���r"s���
�Cpj'���T����������S���%�<P��:8��U�����r"s������r�D�G���\�t�F��Q�`9�9
�#u���`�Q"�����s:Yu��tpr'k��|,7JD!x��Nu�������'���;Y3u���`�Q"
�3u�|����N�L<,'2G!x���N�d-����s:Yu�"t������:x:8���R��:x��d������r"s���W_�r�D�7
��T�9���BxBX�d���F!��B��;%�0�S	o�Jx��e�T��P�r&s�w*��W��\*������J�1��U�Gj�@{�6������N�fUX[s�{d8��U�
1���*9�9
�%��1����������pF;��*b��Ur,s�+"��c8��Uaq�
����;`F��� �����������(N�hUX]s�{BqFK��7���Vr4s�����r�D����������V�,�����p�(�0U
�GqjW������3�ZU;�?������P[��z���*,���=�8��Uu@�56�������u(�&�P�67�'gt����X,�����(�T��P�r�D����SU�p�H�@Y,V�TrHs���A�b�e"
�e�p*�.�)���2�J�i�B�H]<
],�LD�x�.]�������:�Jj�B�D]<	]\&7�&�����9����X,�����(������r�D�g���\�9����X������(/�����r�D����\�9����X,�����8S/B�}Q(^���s]\�t�V�b������P�R�J'w�6���\�9����X,�����(o����������x;��eNwk�.�m*9�9
�;u�.t��:����x?��eFw�.���r�J�m�Aq]@^����V]@��3�[uY���rps�K�b��Q����K�b�{BqFw�.7��X�n�BqU�b�����(W��������V]-)t�������z�v������P������ �.����P]lx=�S�[uS3z�����n�
t���(N�n�
t���(N�n�m�����*��U������8��U������8��U�;�w�����V�5)t�������z�v������P������ �.�c��P�S�J�v�����?��UFw���{��� �(�����rE����\W9����x�X�r�B�H]<],wQD�x�.�uq�����G���0�(O�����rE�'���\W9����x�X�s�C1u�$t��G����xrtqNwk�.��.���P<S�B��Q(^��gG�t���E�b9�9
�u�"t��I�b���\�9����xQ�8���R�B��Q(^���s]\�t�6��U�����F]�	],�RD�x�.��uq������7���`�(�����������x?��uNwk�.��.���cP�<Gv��S�[
����c�[M���~+�A>�&���W�����y�������o?���������KV��?���_��g{����/?���?>��+���_)��R]{d��8�����|��?l��G��'�~��}�+�����g^�����s���=y�3�}M�Y���)"�/�{D���Sep=�S�}
����3�}M�a��X*"�/�0���2�������D�Kx�������|�a?�mC��@U���V���HNm�5�)bx��}#,�]E��<U�|��>����M��5\)bx���.����(��^����C\\���F_��"����}�"0��b��l����P�_�)7vD��E������a�B�G�^�R��aO\���_�}"����}�����!�;Ed�E~)�G�)�uD���D������a��(��J�m���2xR28���m"����}������b��l����L<,�u���"x�~Bv_�<,���X("�,���P�.B��eQ��.�{2�&#�+�X("�,��R�B�eQ�.�{������
X,�=Q���7�����(s���=�f�I0%��'";,��SoB�UQ�&�{�i�H�N
,������5�.4�������6�G�3�Xm1�/�ewE�!�
�Gpj�-k�<���jK�`����jK�`�����j���;Og���
2�@;����
2��z����jg�Ne��SM�\7���`�W��:��z����:��	�hd�ME���]Qn��
�Wk���j�`�{$8����1�:X�TD!��6�������6��J��NV�n���`�Q���"�B��Q���
����NV�-���`�O��:��z�v���:�?��w�2	KpO����j{��^�`��#
�up����d���:x:8��5PB��Q���S|���������e�@�G��Q�`��#������s�IX�'������o 
�u�$t������:x:����d������e�@�g��Y���N�L<���;'��%x��},[��P/J'w����\�t�������g 
�+u�"t������:x=��9���:x�u�l�B�F�
,wqD!x��Nu���K��Qo��]q�����8��So�:���%a	���w_���(������rG�;�	1�G�3:Y]�q���"�b�8@�Gpj'����{$8����V��M!�q 
�%�������"��	��duUM����9��
���N�du\bx�gt���$F�l�Bp
#��z�v�:�1�G�3:Y]��?U�D!�iH�?����7��� ��HpF'�kVb�'����(�0R
�Gpj'��j�{$8����31�sPe�@�;���������	��du�H��T�:�`��#8���q-��=N���du=u��
"[��S�B��Q�R�{$8���
��b3�l�B�@<,wn�!�:x8��MN'k�{Ad�@�G��Q�`�q#
�\bx��t�&�`�D�D!x�����6��u ��HpN'k�;Ad�@�g��I�`�m#
�\bx��t�f�`�D�D!x�����6��U ��HpN'k��@d�@�W��E���N��#�9���:Xl��q�^�N�dq
��=�������.�:���:x:Xn��B0���#�9���:Xl��Q���w�����8S��:���d�u��"[b����#8�������HpF'�/Kb�u�l�Bp	lp=�S;Y}	lx�gt��r'F��S;Y}��`����NV_A�#����Z�Q���NV_C\���NV_C�#����������u 
�
t���N�d�
t��=������},[�lp=�S;Y}[1x�:���d�-t��vN�d�-t���N�d�]�����6���w���!8���w���#8���w�w��3:Y}_���e�@�{��^�nW��CpO�����NV?P����Q�����H�d�u�p����N�@<�:X�D!x����"��5R��:���d������e�@�'��Qlm/�;Yu�t����N�D<	������'���H�d������r:Y3u�,tpr'k�����"���P��:���d-�����e�@������U���Z���S��t�V������u 
�+u�����H�d������r:Yu���`�:���:xS:8���Qo�:���d������e�@�w��]���N�N�����N�N��:X�� x(x��B�����+k����N�P���*��Q.q�\���N���5��@p������AE�u 
����������	��d
�L���^�:�` �#8��5pe��=���j�����:��F���N�d
\Ycx�gt���4��F�D!���jp=�S;YW��#�����<�A,���Qna�\���N���5��HpF'k�jb�����(w0R
�Gpj'k���{$8��5�%1�{e�@�{�`���������	��d
=u�X\#[�<P�J�v���1�G�3:Y�@,����(������Ur'�+k����N�H,����8S�BW��,��1����N�D,����(O�����Ur'�+k����N�L,����(������Ur'�+k����N�B,����(/�����Ur'�+k����N�J,����(������Ur'�+k����N�F�����(o���Ur+�;k����V�F!�6����(�T��P�Ur/�Kk����^�N%�V���������pj3k, �
����f�X��(v����8C^���n�X6�����f�%����Nmg�%���u�S�YcU1z�b8��5V��c8��5VP���c8��5��w����~�XC
h�����XC^�����Xo���3ZcS���*[�0�@^������@�#���-�Q������B^������B�#�-����Q�������dX��:��5v�����pFOk�VbzXvDa��6���=����O�����{��^�a�F�a��^��:��5����3zZ�@=<=,��0<PJ'��F���T�9=��zxzX6Dax��N�iM������iM������� 
���$�ps�������O?������_~:��u��o�������O���~���Q@��Q>���KY�c��cQ��M��E�e�����������/���?��������O������=��k�s�8�����o�He<��'J���Q$<*�Y��h��o��������H��$����(e�C�J�EL�h��o��1z��'�"���+�����(e�C�Wj�U��h��o���������@n��?����Q(�(�71�����&P���pIu��#(J������x3(���a��=�8�G����?����1(�����z�w���t�k�-I����X	R����!
�\lcx=��[p��sd:l���%�Hq9�pYeD�q�^����q��t�m�-M���
6�t�p����&��1���M8��v�����[�8#�5|�����%��]8���jx����e���6�a���DqF���a��K�S�[�^������
7�a���LqF��� E��l��B1W�^������7�a���TqF��� E�����B1��^������-7�a���\qN�w��G�"
�\scx=�S�[��L�=7���)����n^R��������z�v�&n���n�e�3R<P����X6C����x��M�nq��t�u�-���������%���-.�1����-n���n�ea3R<Qv���8���u7���8���}7�a���,lF�g������'w�����z'w���f:l�����H�B]|�{�����W�^��.���Pv�|��f�x�.^�.�Q(����Q����������[6'�����7/)N�nq����(N�nq��t�{�-���������%���-.�1����-n���o�ea3R�S����8����7���8��5����7����(��bC�Q�����b��Q�������;��UFwk.��
�C�l��Bq	]lx=�S�[sU0z�����n�t���(N�n�t���(N�n�������*��5�5A
],�
�P\C^�����\C��3�[sS����� 
�
t���(N�n�
t��=�8��57;A
],�
�P���X��>��5������������)t�l7�Bq]lx=�S�[s]lx������	R�b�n�b�b��Q�������;��uFwk���{��e�A�{��^��>��5����.�3�[�@]<(]������A��>��5R�����n�����������x��O�n�����.�s�[u�(t�l7�B�D]<	]�'w�&���\�9����x�X�D�x�.��.���[3u�|������L]<],�
�P�P�J'w����������7��b9p)�!�e�A�WJ�EI���Ji��J�����#Ha�
a,�
�La�
a<$��6
��T�w����x�XvD!x�,��,��[;e�v*���N���NQ�Q,{
��S�B�����q����.�A#��k��a;�K�S[�^�������8�a1�����a#�dU����;*e�A����z�����Y{q����&��"D�Q)����8��#8���p-�rX�����$q��!�yA��1�B0��^�������8�a+���R��#�"����6�.�1���
��Kq��R����71��K�`�a.�1������Kq��R�[SF��������/��0U��1���Z�g9,��U�dd��`����%�����Kq������Z�g9,���22�S6��d8���p)���N�f-\�������(��q^2����;��
x��������w������o@�����������?���/=k?��?~���?������_���������WJ���x�+���%l��������a��-	���|�7�}+^�f^�n�<�[� �d���"���j��Y�+kM���f��fu�[F����|u)�1���f��Y�+[M���b��beq��n1���R�bD!x��j��HW���%x��j�������b�S�����B��{��V^�i������9�[Np���OU��#�k�$���U^Yi���@���Ka2Z�k����.eF�K$�C��{vX�K������ZN��Wo��#�H2^��oX����c���h��*
�Gpjp� �
�C��7,�u�����;����`
l�=�S�k
lx��]Yg����;��w�>	��!F��e�E��`��|��
Kplp�gt���"F��e�E�[�`�����Z[�`�{$8���v1*���Z;�`�����Z;�`�{$8���v1*���Z���:��z���������d�=up/t�l��B�@��:��r��������d�u� t�l��C0u����+�A�<R�:��q'a#8R�B���(�������,
K�D<���;�����D<	,�.�<QOB'w�&���T�9�$lg��I�`�t���:x:8��5S��:��A'a#�P�B���(/�������
K�B����;�����J�,�.��R����4,�+u�z���r8��������"
�u����+�@��Qo�:��'�#H�)������7__Y���:x?��uN'k���N�d��������
J�V���upF'k+�Yh��e�E��'��uN�dme����%�3\���@{�v��'��uN�dmU����%�3\���@{�v��
'��uN�dm�����%�3\����.�cj'k���^���N�V�H5�G�3:Y[S���\�������jx�S;Y[#��	��dm�N�~�r9�v���!�~C����a	na��#����]���[.��N���I5��������jp�gt��n&F�m�S;Y['��:�v��:��	��dm=up�tpj'k���{__Y����:�?��MF'k����S;Y�@<�:������������d��������!x�}|e�g`����s������G1��H�dM��������K�D<���6��5SOb�W������g__Y����:x>��mN'k����"���P�B'w����T�9���:x����N�J����Z���S��t�V��U��*�;Yu����+�>��Qo�:���dm���e]$w�6�����W}�%x��Nup������w1��H�d���������J�^P��:���d�t���N�d�t��uN�d�������6����51*����K�`������K�`�{$8���W%1
\�v��
:��:�v��
:��	��d��N�B�����nH������Kp
lpw���^�Q��2���7����!8���7���HpF'kofb:�L�d�-t��uN�d�-t��=�������.S;Y{lx�S;Y{W1x�:���d�t���N�d�t��=�we�gX����;��]F'k���{����N��S�����30������2:Y�@�\�v���:x�u����a	���S��t�F��A���N�H<�:��V��������r:Y#u��tpr'k�}|e�gX�'���\�t�&��I��*��5SO����3,�3u�|��s:Y3u�,tp���Z��g__�����:x9��}N'k�^���;Yu����+[=��R/�:���d������Ur'k�^�N�dm�����s:Yu�&tp������7���;Yu�v����N�N�	\%w�v�����WVz�%x��Oup�������A����N�#�W'�7��i��G0��op�gs� �%1�s�*� 2
�e�K��0���+k��=���z���?����:Yh����4���(�^Y�
���lN�#���y�U���z@S� ��Gi�Q~����#����GH31��z�V*%&x��?JS��B���5��	��d=b�Q�����N�#�7�(M9`"
��W�|�{ x��d=b��Q����
�(�3n�Q�r�D�_����Hp6'�c�boM%W0G!�Ap����&��1x4Ro����51��z+��9
�=up/tpZ'�up���lN���:X����
�(���X)!'LDax�N�����(����J�`���H!<��r�D�G*��T	9���JXl����(OT��X*!gLDax��N������(����Jna��0��$�J�!Q����S-<�t�fja����k��0<S�b���2���bx>�9���bX,����(/���+!�LDax�^��pN?k��k*��9
�+��*K�9q�^O������(����Jnb���F9��
�r�D�7���T�9��zX����*�(�������-��zx?��cNKk�l*��9��c2��pjO���z=�{d8��U+1
=,�1Ga��6��r�D�K�a�{d8��U�31
=,�1�az��z�����a�N�����*+�a�1���*+�a��1���*���;��cFO����
��pjO����
��pjO�l
F�T�=���6���=���6���=����s=���*������0�B^����V�B�#�=��+�Q�a��9
�����N�i����=0\M���	Rb��9
�}M�� �3'�P�S����,2�ZeOE�E,�2G�x�"��"N�j��p���"��U�����r1s�)�%���Z#%�p*��"��5R�B���Q(��G�����(O����&.����DQ<	Q,�3G�x�(��(��'�P<SO���,r:[3U�,T�\�����x�XN��C1U�|���"���P�J'����E�b9"
�e�r*��"���R/J'��V��U�b9�"
�+u�������J]�
],�4G�x�.^�.�3(�P�Qo�.��nm�����rMs�w��M�b9�"
�;u�~������N]�],5����x�X���AqU���uq������5�J������W���Q��������9�-����rH�������P\�1������*=�#���)�:�;n*��9
����P,�Q��xg�x�|�cg��n���[���Q(���^����VU�_5�'gt���"H�o%W6G����jx=�S�[U���P������ �	��\�������(N�nU-�U�{BqFw�j7��g�Vrms�����7K9�"
��U�{BqFw������Vrqs�{�����8��U���������V�S�}7�\��b��^�b9�"
�uq�����V5P��7U������A�b9�"
�#u�p������H],v�Tr}s�G��Q�����H]<���*��5Q��7�\�����xR�8��5QO�����n���b�M%W8G�x�.��.��)�P<S������n-��b�M%�8G�x�.^�.��)�P�P/�����n-��b�M%�8G�x�.^�.��)�P�R������n���b�M%9G�x�.^�.��)�P�Qo�����nm��b�M%W9����x�X��B�N]�9�8���S�
8�\�����x�XN��Aq]P��.��n�t���(N�n�t���(N�n�������:��U�
A
],:G���.6�������.6�'gt���"H���J�(W�����8��UW��������V])t�\������z�v������P������ �.�k��P���X�b9�"
�
t��=�8��U7A
],;G���.6�������.6�'gt��v"H���j�8C^����V�����.�3�[u]l�=�S�[u]lx=�S�[u_2z���������|�u�0�������
���4��4��*��Li��J����a	(�{!����(���rPE�
��T�w�K�HY<Y,7<G!x�,�,�c*�<R�������5���)�M�F'���Y���_}��������� ���������?��O_II��������l�?�o��_~���O|��W^���R:���<���.���_=0����o��~�����a����B$�K9�#��P_,���>u���P],��(/X��Q\,J\$7�V���T\�'-�Fp��X}i!'1F�w��X��H��mT�i����y�n�/*��(�n���rXG~�)�SMq_�<lwj���rc~wJ�]H
9�#
�;%�~*)����`S4��/)���6N������k�R���L��HpY�?-F�_�Bp����z���n1�'
]	�
b�g����Q�p~\����^��"����)'�1�T/����	���r@G��O����_2\/���O������2���]���D������N��OO�c��2
�����j�M��	��b5-�6b�����E�#8���p���=���j:5l�F9r1
�LT�����j�J��	��c5}C���T9p1
�=up/t���`.1�G�3Y�@,���q�Q�����P�(s���=������.9l1
�#u�(t���`.1�����N�H,6��Q�Q���G���@�(s���=�������9h1
�3u�$t���`.1�G�s:Y3u��""�,�!�:x:X��B0���#�9���:X��C��P/B�QQ���{$8���R�
"r�b�W��U�`9�#������s�I�n��b�����:xS:8����!��HpN'k��C�x�(��������,�
1�G�3:YmA,v����1n�`����v��:��	��d��F�B�v���"�B�Q.��
����NV[.�(tpj'����
�Gpj'����
���'���V1�:X�U�C0t���N�d�u�����;���
a
l��S;Ym
lp=�S;YmS2x�:���%aC�@h���NV�@\���NV�����svI��
1�:XT�Bplp=�S;Ymlx�gt���"F_�q�Q���
�Gpj'����
����NV����`9L1
�=up�tpj'�����S|����!��},G)F!x���N�d�u�p����N�@<�:XR�B�H<,�mD!x��upN'k��N�d������r�F�'���\�t�&��I���N�D<	<&w�f���T79���:x�u�����:x:xL�d�����nr:Yu���`9@1
�u�"t����Z���S��t�V�����r|b�W��U��1���R��:���dm��������(o�����cr'k��Nup������7_���Q���7����N�N����&���S���sc�<@v��S;Y��#�������S$�&F!��bp=�S;Y���#�������S$��!���F��v�:.1�G�3:Y]�a���"�F!��bp=�S;YW��#�����(�N����\�H5�������@���6���551��@���(70R
�Gpj'���{$8����%1��@���(�0R
�Gpj'���{$8����;1��z���(w
	����NV� ��HpF'��Vb����Y�Q���
�Gpj'����{$8������b�����:����NV����HpF'����
9+0��������,n�0�G�s:Y#u�X"gF!x��N�dq���=�������+;�	N�dM�����er'k���upN'k���N�d������er'k���upN'k���N�d-�����er'��j���.���P��5rV`�W��E��2���}5��HpN'k�[k���(o�����er'�k����N�F,���Y�Q���7����N7��#�9���:X�����L�,�v� �/���S�et��:�@;�v��:��z�v���`�Nup����K�`�����K�`���������;��]F'��jb�u����
:��z�v��
:��	��d�uI�����\C\�`��+
�5t��=�������N�d�MC���{���@�#����Y�Q���NV�B\���NV�B��}F'�ogb�u����:��z�v��:��	��d��H�����lp=�S;Y}_1x�:���d�=up��`9+0
�=up/t������:�?��}F'���_�Y�Q�������8S�:���d���������(������roW�G���T�9���:x�u�����:xR:8��5QO�:���dM��������(����������:x>��}N'k��},gF!x����{���P/�:8���P/B'w�V��E�`��+
�+u�z��s:Y+u�*tpr'k�^��{���Q��:x��dm��������(o�����roW�w���T9���:x�u�����:x:X���C0u�~����N�P����������������	��d
eM���"9+0
�%���������	��d
UI���"9+0
����������	��d
�N���^9+0
�uM��I�����`��1�G�3:YC��?�W�
�Bp#��z�v���1�G�3:YC3�?�W�
�C0�T��,�vE!�+k����N��b�� ��Y�Qna�\���N���5��HpF'k�0Os�k���(w0R
�Gpj'k���{ x��d
=t����a�Q�)�{!����8S��Bx�he
���\#�Fax������0��5���pN/k�V�k���(������ruW������if���jw�����ZxZX����0���#�9���ZX-���0<SOB��]Q���{d8��5S��5rb`���g����Y\\cx�����a��F����B9�(9������{d8���R��5rf`�W��U�a��+
�\]cx��t�6�a��F
���F=�	=,x�a�zx;��9-��zXm��S�0�S�B�
^Q���{`�,2�ZcAA�v����1(b��Q���b�{BqFWk,v��XN�BqY�b����(�P��������X�)$����
���z����
����P����� �&���PMlx=�S�Zc�0z���,2[c
Ql�=�S
Qlx=�SS1z���,2:[cUl�=�S;[cUlx=�S;[c[0z���,2Z[cYl�=�S[[cYlx=�S[[c�1z���,2z[cW���r�`�;�b��P,7zE���.6�'g4���$H��S�[cO]�],wzE���.�]���{��^�����8P�B��^Q(���s]\�t���A�b9K0
�#u� t�������x<��eNwk�.�.���PL]<
],7{E�x�.�uq������'���<�(O�����r�W�g���\�9����x�XN�B�L]<],�{E�x�.��uq���Z�����L�(/�����r�W����s]\�t�V��E�b9U0
�+u��tqrwk�.^�uq������W���\�(o����������x;��eNwk�.��.���P�SoB�-_Q(���wG�t�v��]�����T���.�{�bP<q���=�8��5A���J9]0
�%���Q��������)�2�[S9�?�����P�s��z�v�&��1�'gt��
C8'�����P\�1�������n�	������I��)���(��W
�Gqjwk���{BqFwkj��'��r�`������8��5q���=�8��5�A��~K9g0
�-�U��Q���������P������ �i���4������(N�nM\xcxO(��nM�F����R��Bq_�bg%�~E��+o�	�����.�oJ9m0
�uq/t����b.�1�'gt����X��)���8SB��_Q(���{BqNwk�.�oJ9q0
�#u�(t����b.�1�G�����D],���r�`�'��I�b��+�����.�s�[3u���S���Q(���g����(s���=�8���P�8��;����x�X��B1����s�[+u���S���Q(^��W����(s��=�8���R�=8��<����x�X��B1W���s�[u���S���Q(���7����[\�cxO(��n���bN)g����xW�8��5��;u�?|���o<��r2�sil�=�S\silx��B�(,�%�w*���R�%��06�������06��������Sa|��:,�UC�J3������xd��5x���W�����y�����������������?}�����?���_��g��!�����������������_yqrU�_�����d!zE�?����������|�7�}):���^��$H���C3�av^
9�1�W���������(������j��>����!D���������V��=�W�����������	�}�#,�CE�~Mw)�5F�w��j���	
���;��;�����a�B��K9�1
�#�T��}xeKhX~G^�Ff����T��F�~�s)�4F�w����zxeIhX~'�����2�a��B�[�K9�1
�3���������9�{2�&#��D�~�s)'4�!)��|AB�%x�<fn-_	^�yh�=��E���^����
x9U�w�A	K�J	�*	���[)�W__��`J��T�9%,�5��4p����O�|
|eGhX�7j��T�9%,�;E�&D������"x�E���a	�)��S|���/�G�P�r.c��'��uN�b-�{$8���;1�I�RNe�Bp��`?uteChX�K �HpFk)Wb��������
'��uN�c-�{$8���T31���RNd�Bp
��:�6��6��=���Z�����R�c�C0�T�����Z�����jI��N�����@{�v��N��uN�d-m���H5�3:YK�jJ����ZZ8���!8�����G#���d-]M�~�v)'1F!���jx��]�
��F��=���Z���r�R�a�BpO��:��j��������s�I`���{����(������l
K�@<���;���%x���3�<R���4,�#u�x����u���:x:XN`�B�D<�:��V��O�����s�IX�'��I�`91��������
K�L<����N�L<,�/F!x��}|e#hX����\�t���E�`9{1
�u����+�@L����;g��%x�^�����R�B'w�V���T�9�$,�u�*t������:x:8���Qo�:���&�	���N�d�������l
K�N����;���%x���N�d�u����+{@�����HpF'k-fb:XN\�Bp	lx�S;Yk	lp�gt��r$F�����8C^���N�ZU���s�IX�+�`����Z+�`�����Z���;��uF'k���
�Gpj'k���
�Cpj'k�7�\gt���&F�����(7����!8���6���HpF'kmKb:X�Y�Bplx�S;Yklp��92:Yk����r�b������Z;�`�{$8���v+1
,g,F!��6��������Oup���Z{��^���N�:P�����3,�u�p����N�:PJ'w������Wv~�%x�Nup�����G���h�(�������l�K�D<���&��5QOB���Q���'__���`���T79���:x:xL�d�������l�K�L<���&���P�B�����:x�u��]�a	^���s���Z������N�J��:������������d������cr'k�^}|e�gX�7���T�9���:x:xL�d����������:x?��mN'k����;Y;u�.tpj'k+x���:���dm�ih���N�V�1����l�KpY1x<@n=5	.1N�@{�v��'��uN�d=���[OMF�+��4����8W8A�Cpj'k�6����&#�uM�����H�dm5�T������j��HpF'kkJb���VEj'kk��^���N���H5�G�3:Y[��?��*R;Y[[�`�����a	na��#����]����[������jx�S;Y���#���������[������jx�S;Y����]F'k�������H�dm=up/tpj'k���{$8���
��biMU�v���:x:8����5�HpN'k�[k�"��5R�����30������r:Yu�X[S����:x�u��U�a	���{$8��5S��5U������g_�z�(se��=����������L�d-�����e�I�����	��d-��boMU&w�V�������$
�\Ycp��t�V�`���*�;Y+u���`Yo�`��1�G�s:Yu��[S�����:x�u��7�B0W��#�9���:X�����N�N��:X��� x/���S�gt��:�@{�v��:��:�v��bc�Nup�������.S;Y{	lx�S;Y{	lp�gt���$F��S;Y{lx��"Yp��
B���he��N�J�����&�b���8��p
%lx�g���z%F����^��@	^���f��@
�#������QH�*���7����c8����
�w����n��Bh���n��B^���v��U����3�Y{1l�=�S�Y{1lx=�S�Y���;W��������R�Y{O5��j��e'q����pFCk(�{!�����>P�.e�I����T9��zxz�J�h�������-��zx<��CNKk����[Z����prOk��N��������'���{Z3��$��,=���L=<���!��5S�J'��f��Y�aY{���zx>��CNOk�^���{Z��"��,>���J=����!���R�B��=��zxzXV�Dax�^O��������7������F=�	=,�O�0L=����!���SoB��=��zxzX��Dax����p>O�,��!z�N�i=�{}���z'����>Dnx������,��\T��=�x-.�lMY��a,���=0<��� m��O.����VYT5�5e	J�������p>O��B����N�i�E]��JL��%(Q���#��<�H1�3|�:����f���)KP�0�=67�G��yZ`�l�:����f����)KP�0�E67�G��yZ;`�l�&����f���)KP�0�3z4Uo�6�b���VMbO���;1aS��Da�lnx�����������[5�=�x������%
�=�p���|�����m�&����zxzX��Dax���pNOk�m�&��5RB��(�������i���b�M�$��&��Q�aY����zx:��e����(��R��InjM����M���x:�e�������Z��I�j�T��R��]���x>U�e���Z(��b��Ink-������
%�����$.����JM,V�TMr_k�&^�&�e(Q(^���SM\9����X,�y������x�X��D�x�(�NEqY�t�v�b���j�;[;U�.T�,D�B�NU������im���b�M����1R,d��D�AqY@��3z[g/A
]��������z��������P���*�� �.nS�[e	]lx=�S�[eU3z�.��n�t���(N�n�t���(N�n=���s]\ft��|���.nS�[e
]lx=�S�[e�3z�����n�MC�B������.6�������.6�'gt���"H��S�[e]lx�e=J�[�b�{BqFw��
�T�8��Uv�����8��Uv��������V�m)tq���*��],+R�P�S������n�=uq/tq���*��^�bY�����x8��eFw���������@]<],kR�P<R�����n������]rwk�.�.�E)Q(���GG�t�&��I��.��5QOB���8SO�.��n������]rwk�.��.�E)Q(����s]\�t���Y��.���P/J'w����\W9����x��K�n�����������x=��UNwk�.^�.N�nm������(%
�u�v������F]�)]������7��eQJ�w���\W9����x��O�n�������(%�U�sd?��UFw�*^O����(N�n=n�< g)�R�P�87�'gt��rH���S�[U�s��z�v�*,���=�8��UU@�U8U����*�#���8��Ua�
�	����n���[�������jx=�S�[�����P������ ���U���������8��Ua�
���:��U�A���>��U��W
�Gqjw��"���3�[U��?���S�[UW�b,g)�R�P�M87�'gt��n!H��������W
�C�,J�B1V����P����z�b���S�[UO]�],�R�P<P������nUu���S
���j�.�.�E)Q(���s]\�t�F�b����[#u�(t�,J�C1u�x������D],v�TCrwk�.��.�E)Q(���'�������x���6hgJc���;�����x�X��Day�4�O��}W��/�b-N5$��
�EcY�����x9��]�LY,��TCrsk�,^�,�5)Q^)��SY|�u:,�+E�X�S
�����xU�8���Qo�����tX�7Jb���[%��$qrck�$�N%�}W����b%�S�vZ�w
�]bY����� �O�}i�����a�Nmj�����Nmj����������a	.BbxLmi�%����Nmi�%���=|_�8,�UE�B��
���6���
���6�'\"0��O!l�7BX��,����������o�������~���_�������<�O�������<�o��_~���O|��W����R:��}7F��.����_=1����o��~�����>�-tE-2�������������+�G���Q,���5�����z�����f����w��f�	��+�Gpjo��K�I�e$����}a!�0F!������H���=uE�f�h���E���1
�u��tEjo��+������^=RX���[�<RW�JW��������\Wd4����b	�J!,��k���$��&����������H�]p�<W$X��d%N�g����������H�](t	K�B<������B�B�������B������S/B��(������s�IX�W��U$�.���%x�^��%8Q����S|�d��o���H�%w�6��M�`Y��`���T�9�$,�;u�&l����:x:X��D!x��Ou��SM��5C�z0�8@�Gpj'��
�{$8����%1�sa���(�8@�Gpj'���{$8����;1�Sa���(W
	�'��'
�\bx�gt��j%FV�����F������NV��!��HpF'��gb�'����Qn`�\���NV��!��HpF'�iFb������q��jp=�S;Y
��#������Fl����H5������kC���'���t_���!r�b�;��#8���pi��=���j���	�r�b�{��^��1���pe��=���j�`�7D�Z�B�@<<�v�.1�G�s:Yu��"7-F!x���;Y\bx��t�F�`�3D�Y�B�D<*������{$8��5Q��!r�b�g��I���NW��#�9���:X��;�L<��*xq���{$8���P�m!r�b���EL�/�;Y\bx��t�V�`�+D�W�B�J�����N����/?��/������^�}g��:x}���?������Q�G����/e��E��E�>��z�2��w����?��_���?��������?�������|}\�9|�I�^�����.�v�|�����3����r#:*�M�IG������������,�vg$x�$>lyAp|�����wQ[$A��O
��������y�1?5�+�-�O���!MRo�!�[Q�"wU�y�UF���o5~�I<���+O��vQ��@��i�(�[M�'�gb��:r�f�'�����|O"���}Q�"���i�^�F����(�I���J��WGn��$�RZY��������`���E)MR��gb��8��3
�,JieQ��vz`�Y����4I�Vb�Q�q��V�����������(�=/Ji����3�E)r�g�Y���������^�E)���}Y�>�e���x�~��2�v'|'b���j� O�l��P�������D��ko�vm�.��zl�~����t�o���>`\�����
�a�D�`���F�.�����=��>`���O���q�-���+u\�	k���kS�����o����Qi���g	�M4���f�0�e���P�q���{:����������.�'���t&���������~�O�������'Q��z����S���k���g>	����F4�3�����������D���'��
��^�"+�6�����cE����3��~q�Y�"}����,g����Ea�^�aR����1�a%��6rz)���J�"��(l1�]i���+v���,��d�EL�,w���#���`v�����`32�����W;U*��i�n��Da������~:Z�-g8"�;�*���9�(���
�Kw�{��E`�+p?1�f�rZ�1�q��A>��iR,&��>��:�k�b0[��vj|��\Fd�D��A>��i6,"�%T���[f���NU�[�eDf+~U*��r���l�c`?�5~��El�]���^yY�4����_���K<��=�5�/�8]]�����������~}@Z���*�������*J���GK����������0��q�������W!T"���g�����a��:�=G�d�h,�������J|�Z����8���_�������}�������������??�-R\��{`�=6���=z-���}���{��G���
�����q�l25�x���;�r<��R1����8�;<�vlh?�;�VS�Y����(�L�4f�_��^b}��3�f
�;_�v�'�����(�_=[�����;�E~9���:95����#s1vt���X�+�c��m�d��|����p�_X�/?2v3,�������,�������'R
�S��Z �Z��w���~����A�����2w�^{a���!�B(����0��H���[���/l�f��W����+Qop�o��/t��Bpxq
��	�Ht���(O�����
�}+yU_n���L3��&t��a��F�(/,������+��!J��������|���*C�YN�z!:�
�Z����l�2�^��1B�>����u�	.�S�'�S5�=N�V�
�
\���<��p�-l4�{�V����w�*��-N�`���;���Ep\]mh?�S��K�UkB����������?\cO]��S���|�����������}\��������TeY~�b�UE�(��x/HS�e�����'������R��b��
���9��~�7>X=
�;/�b��������o[6�w������w��w�~1zkQ��yBE����:zk���~������JC�p���t�h�x�7��_2��m������&b�?�������`i�W��\�j%�ca���+��)�k��{�G}X���H�%	W�Ai���yh�g���i�����9�����:4_h��V���N����b��/m��������u��v�b�?����������_������u�<��{�������S�x�' �c���z����x21������/��O���/�����n����o_��������y�?�������U����d������~j^?^=Fz��vw�[��'"��2�^��oe�Y����.��_�j������O���������X���Z	�3��mEKt��#B��[�
����^��R� G�/�K1����Q�R�Hpx/��1k�0���1�;\�>�������"F�Cn����%U��5_1�R	�0E�D�"F��8j%h�"F�kpW0���@E�U���+�����#3�,_��3'*z�yDI��
75K)z�-�wV����	},��1TQB7�l�� ��O���m��6�>'t+���;u�F	�6\'t���.�n�#���Q.y�P{gp�����G!���D�]�v�u��y�����[xXD�]������:�Vu5t;�����l]���!����.z�������������UP�,�8N�2�,�i^��tKy�R��������d��fr�j����g�|�]����`0�����W�q9z���8.��]�?{_�/�� E�����~Jo�(o�G.���s�����_�O�f���OT;B����@�.��v��IQ;�J�w��/v�����4�Em����y�	m��O�W���K/�
��<�c���������8��J�������Q�\�>��G�z��Y�|���O��q����?����7]y��F>����w���n;�������F��L����0����@�[��ept��AR���/�Sg�����������N@t��3�����b��/���^�+{�"��;_�������;�Z��\G�����pU|/�����X_���w��k�op�_C����++��t����o��/�q���>X�.�0�@W�D�����p����<|����m���_|i��T���"	n!���uz�E�Q�~C�e8�7+Cy(i�fm��p\[�
]���5 �������+7�����kW����
&Pr�����er�{����y?.a���xC���k����7�p���	�;�Al|�Q�;�Al|���G����W��_u���]�H���NU�Io�����h6�n����I�Qh�ZDr����p�0�
����93S�����yzcm
���Sf��'��	�v�8��v��������+�>�W����,�����kZ:�!�T��X�S��H C��:�S:�����X�����^'�oh?�I��Ts�����ZDRl�Q�&��Mp�
����x>�;\�-�����F��
���SD�*$:�e���
�#o�?�K�����y�(���6���]s�U������60�|S��H5`�>W������I���NL?����P]E-|��E���P��W�6����`��z�c�^�t]�P��3/�������B}�0�A���
�8��N�)%�PY}�{��/J�z��^�$9�;J� ����-^������n�I���EtMpH�������	�>z����~��aS�
���ksn$8�~#gIG	tF5�U�}��;�M�9�jlI�o������:������oN�s}�s���;n�����1'���x-�xA�<'T��5��@~�#D�?L���p����[�D]����.TMO���%��B�4�k1�L��;��'�>��&���{�k���E3����}�Cs�,|��]�����}�:���X;tGA p����DV��H�[:�rwGaJpm����;u}����F������#8b�P��&qB�S���;��a�����:��_IFt��������@ p��Z't�����/��m���R��:��?_����3�N��/ng��4�jN�:����;U�$LM ��u�~�w�&p����5�e�l�?:�s��,
�r��^��[Q{��������c0�N1��~G9D��& �i�L����8PQ�-��
��#�5�{��I�$b�a��v�j�
tO�E����N��K���\N���lo���d�����^��h�&�]�F�y�����O�������x�{"V^�����D���r�+bo�����J_�l
�7������a��gHS�c�p��{���ap�mb��.����Q��&��w��Wf�Q��-
N��F��Ot��7����aR��':��`���p��]�8�Nt�'��"6�t���/	N�[J����~1N�F��Ku+��!J�P�kp�w��EpCEp~�n��n�wmp��E��Op��1�r�E���������t�X�h?���c�nD9��uB}j?���\��\\7�.�/N������N��f�md��zq]�����%u������]S��F�� #�����������=!*��	�j���yaBX�]����6���^Z|%z]��+���<a���� 6$4�!zW������M��g/Pm,�AD������
��S��]�S����F�A�
���uX�^����`��_��Fs
�h���W)�����z��;k(nc������(�[��QT��(���[[���kj�����*�x�sw���(�K��~,�:�&�U���7G&�
���:5��P����K*:a��~�@�V���fp?��C�;#)R��n���{���S�e�z	���������lo1;o���X��b��v��v�>����������l/�T3�~�F��xB�����C���D�4��=��WF(�����o�����"&L��Q����J�������IC7twn(h�����g��Q�-��Lmr�K,K�����>*����w�hL��0���+�9D� F�v�c\'t�7�Dp~5V��n��y�����U:��=����>']_�^`p��]��yg��f�{�<��W9���`�6b8MB���;���c��
�S|(6<���?4���� �?4zC��
����`�����we�^���� ��>�#6|�����$��
���~Ja;0Yg��?"�����;���*n
�#8\������:������H���=>�#88��<V�`��k���~��o���?��@�	�������7Q�p�T��C���%1�bL��bqb�k��R�}!,�:^:5��M��cG�o���	+��x�F}D�ob��\"Ou���a~�������1E$�K<�������QUD7��4|�J�V������#5����W��},Qu@�1v��Z�+5��U9�UE��*
��:��]ep����m�H���(
����(Ou�ZC�I�T��^3��r��"��Mt�aap��A2p��b�E%�RD	������;,�V������K#t;�����uX^��k�.��$aw^v�Z0\��|_������|+�%OU��T�u��(��.�;����#�x
�9�>���[�����x�x����[+l�&�����Wh�0��8�T���+�qe��p�J3��fJ�d��p�4��c��:`�����x�W���1���uPDQ���x�.���4/�t3�����$
�s��@F�y-I����"[u����=�V����'[���V~���|���nx����e�T[U�����|M��r7c��Y��5���3������@F7���4�^!w�l�A��OrD��@���P7��k�����l�g���?���p���=y�{���_�������O`~���������������?���?^�5<����o���]9�I��fB��+�������L�7c��o�`~��Q�?�l��v`����CG�~m~���<�@7����[�����S~���a ��^6�����\'�w�f������p>l������.�����S
���#:dH
�s}Q��A���n����z�������^_0�Gp�����+��2�,a~O�m��H>���n�����5��~WF2��������a�=:H��5���g{��Leh��
@C��.��:$��v��������z����u@�����c�~����D���%t0�
�����WU'Z]��*(���.v���Dp��5����YD��{�:��5��V�������	]����	�/oM�����El?����������-/�?W_���/�v	0��p:���.���2��0+����m�O�x�
������o=��_0X�_�@��7`=���tw��"�����+]��*/��-���S� ����$�)����f���G1W.�1��-z������]9��]9���)�U��Q��H4o��H��7���T^\_3t�+/�[�E�T^��~.��.T^�UY��Yy����Q���������0��	xoR$Lj'�X��Im��� �M���ep��w��;Pn���c�Or��\3������@g���8��3���_}��{{=�c};W������;�[�,>���Y�z4��8�K�V�~��x�k��k����+����[l��0
@���_{���
�e��e	@�t���)�J���O 8dFV1�r#wg}��=}���/ ���/������9����n5�2b&h%�Y1��_��<��;A�)�?����A�����P���]�$l�Hp�4�Jn������p�Gy����D�Z���;N�2�^��W��Dt*i���m��6�^����]W��Z�~g9���z��^gBt3���u�����op��]/4yg�����3��[W����@=10/����C.��)���;p_���c������6�4|{7�H^Z3�'�	���=����
����A�wfE��5�AH���I^����~JSjgs�����)�)�x�w��F��I^���=����f�b�����84�0�w��MNf��&8�GC{��o���<y]����=��[�*����z3y�eS�O^���V���_S�c�a��=�x�!�8e_���ZTJSsH��r��*�EtP*�����+/e�/WT-w�S��C�9���:���	��!w�����|O6��#�[�������%�y��2H�_��(*b�.��?�{M�
����P���45������_��*M
��@�>��Z&MMt��~�Pm�������'VBUn�B��\pUq��9��'HSl�HV��Z.`b�]����s�e����F��V9�;J�V0��dk�~C��J�CD�?w]f;1��>d��&��]*9�;J�60+: J1�)N������L��!v���.��q����E�9aX�J�mt%��N�5w5�~0��X}��
 
������oh?��4|��:+}����?���o����HW_g�bX��qn��Z�|5�Z��~,]6|H(� ;������}��~�C��F���}��oy��� ;��c�����=��W��P�~B����Bt���L��w���'8\��O��?@[H���z�(�^��%V&�}�,?�3L������Ks%�zY{�g�u�p���&�p{��=�uH�W�-�_;)�*x��z:q�x�G�%�_u!���m��S���������`�y������j?�{1u&�t�
��T��������=����m$���\�>��w����;��tu�H�5���6H�� �
����1#���"�a�,�0��np�2��#n#��������k"z����-���?H���>��':($�{|��X�����DiE�j+��%�/��r���[Q%A��@�\���r1a��e���?�������;>3���@���7�N(��� i-���Ux��5�+%8�OkW��kW�n&��B����/�&�
�������.�o�~��t��E*��h����)<(��%�y������/������iz����&�i
�	}���T��\�b�f���1t�	kY�����Ft~�@�vt���8����}�D����:O��������B}�>��D�;������kj����RT�	]�s��~������z�V�v��h��+X���e���]��7��N�]�>&Xu���KQ<'t��lT�e�����QE��p R�xuE��OX�\6����.��Y7t����������u��G�R������������+\/��*pA��e��+�;�.���b��3a��{����	�vC������qQ7�^n��-��=��+�.=~�*�q���n��+�v��}� �[7��1��2����P�w4%EI��3_��W�jZ��-��7p�D�Z�����
Tqx����w���"8Xy��k��[�V�Tn5�+���)�����2�b��B���>���7�����(SC`��i_?2;_�C����u������z�s������ :�v�S�����D����$���M1�����AO\]�5Y_������+fA����kR�J#�K\��6����Wi������s��5\G�Y��zc$}����p�b�X�������;�*������dK��_��!��CC���z��/+!:�}��l���cC�T?6�L��Np��h49���v�7���n=IpH�Z�N}���D�g���?�!�gh��E/�!:$e�'y�6��q��^�Ct���7�S�	�7�^�����NL(T����mwH��]����23	S?uR������%t}�Z)�{���8���4�^���x�R@������d��������b�����$A��m'j�d9R��U���X�c�� �������������f�Cafh��Eo:����-�(��Q���j_�.�����������k�5;-KY?#t
���
lC��.�5����y�y���W���G�"C[��g�}��W~�Z_s	-����x5_O��U4|C/�_���@���ohq�3�jC/~�.�p�	S�w�>��6���jC��o�0�� ;�4���C�x~=��8�4��}��o����k;Pi-�����Kk/=~�Jk	��Q����g��Z��
��;.Hi-���0��2�=n(1�^��;#�=n|�7��@Ns�P�4�5c��6�9���c D�w4���p/x�o���)�}
n��mh�Kk�[im���v�Kk���G��[?N���
W��eS��GKk��I�^p��8�S��k�K{���C��~�j����q��/oN���i.�9�����hF���.5��.�7oNe��/����~����n�����?���������{�^?����.~��������>��om�j�������������������,��d�����0����s��+��R���I��TUy�Bp���0k[y�����e��{�����^
R�MpHR��K��{����h��/q����b�}�*o�J��D����d�;J���_��?J�j��U�D�3v�m�U��� �H�X�	�fJ(�M�+�����F�*o��T��3d��*��y�����B�������_�:G��k�s9�[P��a���4������+���@��R�H��U8?fY
n��S\@t���G���U��z��^�HtH���_\�>t#�1��2t�+�n%:��m���6t�2�^���:#:T��(�1��k���d�H��mD�N����54�^���QJZg�k���e��,Z
KY��[�^��=����u
�	u!�c����0�N����8t+���]jAG�{]_�?L4y��I��z��&.>u��=���$y�^�+�_�.���~h��YB�=�C��u5��Re���dxV������R���a�� ~4����`��k�K�[����\��D	�5C��6h�b�|�d�H1��0���
��\��]����o��C��Z���������`��	���~�4|[�+�Av�h
���mwC��"�M+a�N�����Z�)����R_��wC��`���L���/P��_-Op�x��Z��0P�< �8
���5���	���}� �������S�
���]lZ�+���
���^��A��T����=����g,���e�?+���jF��^	R-Op8��i �������������J��^������_�v�o�(��>�������]
���
����m��max�xu����r�'_���x�����_�k�����������l�}�����z�j���
0~�����=���wq{����_�������)�O|�}?q�O��I���Y�D��ix/� �cD��y�{w��P@��������y^������Q7������xxNXCuO�f��k@� �
��}�����k�E#:��4�����D�����$Wj`��A��� *!����j�A��c��Mr\�������#D��"�[�P/~=����8/�������/����������+��??X���l�(j{���M��C{n���m�����U'��0�^�C�����~�-���v�!�_v�'��k�x�=���%�_���������+��vMh�e��s�K������4��`-�t�w��*���)��q�	��w�kd�u8oh==�l�b���q���N��:�y���Ch�	�Dt�����\��v���<��e������&�g���2k|U��t�$1t�P������#,�sO��0!��/]���Jf�	n��%O��u�
v�� ;�4��O�\p�U ��Z��:!����,\��:����l"G��I�\r�����]T>@[�]�B(��\{
�Aa1�~����A���#��~J��������xV�	Qx���^����x���:�5����H����n�yR�.C'������[�c>`�#��~�y������[��@���@6�J~l�xIA��� �ef�Y��8J��]�ja�]S�T�{=��|@�;�����+�����F/�;��I��R�B$��m������(oq���������]t�������/q�c�s��O�w;�[��_��f$}��|�0	����O�`�W��%�r��"F�U�J����t#�
���1���O���C��z��UEQ|ghpcIp�#�����l��pze%�p����*��P����
D'j���w}C��.��d�C��
����8��p��D�e��^�|@7��O:�C
��������������gA�!jh�1�2N�&����j[H����lh����q>�������r����M��z�62��S�,D�_����m�W���m���:^�Z���������z��]�q@��S+6��~a����i�j�r�o]��S'�D���8�a��yw���Ut��}\�G\_���W��Q^��W��_���[��h7�^�R���W'1-��j�*�@��jb@!���,���i��u5��A��{�:�R"��K�
o{�i=
�iY�~��k�Ho�v�HW�E�;�k���G.�:��i�����H������t�k]�����\���wu�{w�W�"�8$����o�=�UT�Kg�a�����E�;/�:��qfh���*+�j
�H��'�y*��R�����qL�H�i�*����o�<SRz5%������G���������V�������������� e.@�������JTV�s!:��Or,+��u��s'��Ht;#��2C���W�b���"�{�\�����C%N���~np���Do���8��Y?��%6���������)V�0����jD���A��F�&-V��o���I�����*q���)���I��W�����^0�O	��f��fj�i=�]�Z5��x������	���r���+B�:%��&��]�u9��]�"�C#���$O]XC��.z��Z���s��5�]
��`E^&��p�5�v�=��n%8Q\*sb��,����$�J�t���E�L��Dt�I���\�*17��su�}g���Wy���K��D�Cf��;1Gp|�D5�$1Gp��h^TC|2Q���h���*��m�?��B�as��p3|�N;b�HQ�^)�/
�c�P����B���s��aC{��kn���I���sM���4�v`�q��x.3���������b����^��<]�|������j3��3>;�������?���7��3�=��2>^�	����lz@\&B���k�	3d��]E�K�E���n��y�>�QG��)�w���tD���*����\}����;]4w����s��a���o�w��F��n���n���W�?�{�������o?��������j����	?~����M�����������}�����7����"eQ����^vg3;^�^G�]���C��?���������/�������r����O��k7��V�;L��k1}���C�#P�����;��s��	��|
�+`�j/A�V��~@O��:��'(	����96����	�������q>��=��49�[�M����Qy�A�g�CF��z�s�.��'�����B��5%���~��0�:��3�N��7"�Dp��Rv�IP�Ft~�2�S���lh��E��":07�LU�SE��TQ�=�����a"�)�s���tQ�v	��/��0�"��;eh�.H��V~x�<)���V����V����1�3�
�����1��������UJv�����V�����o�P��H�."8����������.��tQ|����#���������Luc����.Y�^���Y��+b������~^i�e�b��@_�C�������h-�6����p0�wW����~����&�Ot Vhm��LF�#��Hs%�v�}W_��d�����m���8��gy����D��$g@p|1���\��ig�Y^��47�0K57P��� ���-��X9T� �� }IT����r���U7W����nt�dF}�}9���
��iQ��W�Td�9r;�0���������w�YY���������e����~���B����v��Wr%�V~���� ���[�]^����3���F3�^��OV�� :?�6*^c������	����j�h����O�K
���{�n������:v�Z/t�'��Dt~{i��������Z�#tC�CL���>av�Z/t����L-�Bt���9�\�J-�����8>�P���a'U�����&��%1 �?���&�'��=���d�PIy"��� {�@��<�m�>m���7�y2����&\�
�����F���O�u}�o��y�lC�9y�Q`;��0�_����������!�_8')Op<����s&��[R�v��c��|�<���y�G,
��i(��CS4�k&�?K���L���e����K���c��O�=D�Sfo��m����)&&:������� 5D���y�����H1��(�
s"^�Qt�(y�������fc��#��O��%�����)F ���$�Ot�$V�&���H�W|O*�(Q;^�]]0v|E��HZ@�8Q�W�����
^{������7e�) :x������;��5���n"�����e7���H
����s����ep=7*�j���6��_��n��NTP���A�D���z���� :�&��]�
���N��K;N
���R�
�;�<GM�wvD�(���������������&^��k�^��G������#6�����u���������������8x�w6�~K��!��B���v.O��y_��-�$Z[h�6����/}'|-�|�
��$8����0�I�8����_�0�O��j�g�$�Ip8���t/����{Y��c���;�	����J�����~N�{�@�h�0���P0�����I�_8'�IpH���gS����y�3�����i�7�N[�^�������j��S�S�!�?�Xz�}M���t8�-��.����0�^zC�'2��P�=�j��IJ��]fp?���?����<���m^�<5u�IR*���R����(o��;�����-^���\IJ�CQ����/1;W�gy��m�+b�f�$%���v:,F����&�PIJ��g��{�+��+�pS����#<~��5��k���e�w&)��)I9vLR�H������HRl����U([<�iOt8�
�gEo�#���D�\�����T���.X��WAtpS����5v�)'5�X]���N$������N$���%�;K���~��]�$���]�S���������z\�
��`-Wc������?w�Ft�$�S7����P��M�9��L@W�����x�?��>]'���H��������*.L��6X���������nj�8s���=^����]�@�C��Of1�l�W0��x��q�o���=���:���'������e�U�N�j���������M�=�|�n���{�,o9��<�T�����6o<�K�k��b��J�eY��;%�$o
�~,������1��kR�I5b
s�0{�_���":�l��S��i��)Cl+�
�����Y�]�a��k��������D�np�/����H/q�#������-T�����(P�����BN'���2���-���c��0+���B����������9��$����mTuBV�ij��$:��R%L����ep����s���}�;��
p�u�w�!G�`��
��G��t\�mp=3zs��-ug�?���=Do.:.�2���G���BI��R�W��Q(m"��z/���7���@���&ot{It�Y?��^�C-���b}F/�MD':��Y�EL���}>F�VZ��������0AeU����9~���NL�O���Bkp��E�teMt����\k�:��~���p[7P�����
�lu7��6
�����7�ql=t�_OUG	�V"qd�����V��mLC���,�q�mk�� �D� N8 ��z���o�B�O��?���o� ���>���7���+��?�����n��c����k�'�.������p������^[�q��E�;*q�8/7S���#4~%��7�N�����y�)��~�#6~K��o,���q��t���k��#4~<n�����r5~�;nhC|/z���l��{TmZ5�Vkp�����_�����7i�u5J�j,]����G0l��<����_Z%�n����w|���A?�
����Q��t8��C;�{?�u� n5pv�%)*�q�u��~�#4~m7���$G��x��}��
p�I�~��o{]n|���/��g������K��u�!�9� ;��Hd��^!���>G	.��:��������������-L�(UjmWx;�U��t��6����I�x�h50
�e�P*�����E�s:W�G��=�\�o�+������U>UF����~���G<��s�i�a�{�J�~�V�������	��B���"�0������X�#wj������G��v�k����'g}������~���X�)��[
B=D���hx�S����:np�/��$�K��5�_b�^����D�PY�Z�:��~�������5��_��/��wvI���C��s�U\��Zr��"6�<�@�bx_C�E�Q�u�������jwb���)���������
�Lnh�y��w����v��{�����F�]tX�w����mt1v5�t/������X���6�^����"������*zK�aS�
����TD���T���mF0��qL����n%:1���^"tmEf��U%����]�]����;�����r�����n#:�>�<v�Qt���.z;�����$�Z��;������TD���*�f�8��y���tDUFo�":����=oP�&��`#S/�n(���A����� FJ��u�0����n<�5�>n%��c�n,�N��H~7y�U=Ej]1ND��Eo�%:��F��,!���T�h[�|��M�AM�mYB����D��Z�'v�A�����fL��5������,��������-�D���6�����U�wY\��u�y��?���������.a��k�CE?gwt���)P$8\F�;�)P�n��b��'K:�{4�^�G����uj�}��X�D@�E�k
�<���np5�N$E�T$��x��#��5�_:�@��v���c��m���q^���.P���u(�xZ��?��RC(vE�|�@1VY��^�������6����nk��������6���6�mm�m�p�O�v����;_��6�"a��w[��
��P�Z	.�m��V�>�!���!i7��!
��n���R�������_�<��':$l�S�^]�'S�n�=��/B!<���a`�K��'����7�^�����d�D�D%��h�CK������
����V��q��J�R����2�����_�c���"���M;���#~T�X��
�w�
MV�GYE+1����y�.�����F���H�*a.�7�^chs]	���$_Db�e��{_�����������qoC����~N�^f������^�R�_�}D� xkq�	���������G�<Z��~�>���{Z�7��-~y`�W�d�������j���"u�*"^�|����|��~�!�I�m<
�?H�{G��5T��`���
��MQ�=�[�`��#���W�}�4G�Ny�<�� '��W��Y�|i>���aF�}��_^���U&��I��H�*O���06���������k���&�������M��1	[C�<�tm���+r�M��� �g6��^��AV���Jz}f��Ri>���/��7Q���e��"�T+�m�\���#���`�C$��0��J����~���*�b���X�(�U���nD��z���^s@��me���������~c���T�(�M�	iA���.v{��Bt"-(���������D�d�O���p��gy�f4N\/v��k�V������'a�W�����%����^X��$���u�������G���a ���������p.y�\�FQ��
R�OpX/vC�p!r{p���;�>�+0cE�
���Im�u�P�������8�54����D����;����������~_O����T�����{�rg^l���J�T�k�im�zZ9��.�����?�}������^��>mv�d�+j���r��q}�|����:��>D�������}�C�������c~1���Zfg�?�����W���������/�_~����.~��tM�e���]�
�yu���{���ox��	/R>����%��D���_\�K��^�Z��~x�����3�-k'�_B����<\��b��$C��_i�I��������4����5��C���x�U�B��c��|_*^��]���;���/�R���."����/{�����l���7�c	��^_2nX�%�B�b��Y��|\����r�@�@����(�
TVAt-���X�o��:�%i�m���ss��E
�Scy��U]W3x|I�����v�g��5���}��{�-��yBp#�5�GS+_�^��L�|Oz�0i/4�}����o8���^��
US�#��A��������F��Sd�^SAp��
?�s_M��>���
n�n;�+�9j*v��Oj�������^#��h��b�;���n�^�(�8��V���W9P5J�v�����
kop���3|@�kLU�.���m�����z��^teEt��,�sWv`����U���&�S����]����b�
��������gEU�`��O���^Et3����uP@��/7�^���A]tj�K�w�_np��]��zg-�-Dw2v��_��T�����k���70��p:v��^�@�<@H�h�������V�BQ�R�pS	n��\(���*f���J<���9���&3�y�ajy�n�1=������{DGQs�7!���>j�z�Z�����J��|[����U������h�7~�R�G\L�c��Z��u?�cY]�����4������<{�|�o�j�8u?u����?����y/d��Q_(^Be�;�9�v^���k�z��.���17������}�i~�d�k���j���Z�BJ���I^7���Ve��\z�����?`E���{����[��{R���j+J��	��x��c�5�[\���+�?<�[l3��:l_���_��� :X�u��N��}-�/$�����;�����5D����=���N�P5��)v��Qw�MNy�L�k���W��M����?���7��_�����?����������������f��?�R�~�����S�At;��	��}�����b�����N���|�E�Z�Z���Z+L�XJV�R�J��
�@!:��R�����0&:�t\/v�d�n,�N�t'���RU���N�J>�@t�������u����|���-"��a&�i_����O@����j
�|"8`�;�I>]%C�9��;\�Z�cyjL{��)/wQ��o�I>�F�$zw�Q���n3��J"� �ai[#��Rm	
�|:n���6����n��S:�� -��?���n5/�8iv��M����O"����1?�{M�2��p�_�����zB�����DU���u�}�#����!�������������4 <�'�:
��� �<��<
�2mj�����A�,o1
���E�I W������g{�;�'�?�+�k��E�&���0�<��R6�GW��i�����J/Z�zQ3v�+_��#��?�@����5t���W�����y�������o?���������Kc����������_����_�����Yh�o��7>����"����j��������h����N�����[o���q|��?2����89�����E�33��O�S�D���mhO>�M���N�[�r����0-���6��C�
�X�����c��7�^�����@t�\v�G�����mx@��D'v�u�[z�������6�wfU�n$������J�:�2\�[<���[z�a!����R��*�v%����zT��dU���jh�.HV��p�4��R�u�G
�W����,��z��}��>Nt�N��3��+�Q�#:�nv�k
�R����0Y����{�U��A�9Y�w��|�iuJL�#&���a>��&���?�3<���7����^� ���~x]��g|��
�~�A�_��,kN�]�K�A���f��`u��/�� {�5�Cc��=G7����@K����������f �M��_�Ax�P�w~�/�-f�`w��0�[���L�s�@'&��#��@�	�g� @��dtj�@���:1A@���:z��t:]�I�"H�*�r���������6��m����d4�Y'\�`KB��)�Q��h�Hp���Q��h������]�_����U,/k��":>�����E�E������=!��Lt�=��gg��,���z�j����v~�6�2���{��+z���f�v�"a�e�k`;�w�b/\GC�)�{=�Mx�u�_�xm�P*���5'��&��$�]���7��H#�3�b��j�	c/�������^����������i��7�VV#����om]�����}��� W��c#�����q������
�\�w��������G�b�~������8���
���w����mc�*����
#���u�/�JIx����W�����E
�p�H���S�*o�m��a�5l,� 8�C�;��a+���a{��Ko��|�Ze��1���7�5������=t>�L�l���2 ��0{����2����3�E���[�>x�$60���A��'���(j����PwO���mx�����?A�b����[|mKR��x�o�O�O��3���4%��n��ap?�{<�{8�5D���^��u�C��?���`�he�F�%M$
��R����vv�M^K��KZ���_�j�	��Sd�my?g����f�{>D����������%v��5����gp���m���L���cK���D'=��NAk@W�D�Z6��+��3�^��
���n$:1�?�;[nD'F0��	,HR�����G�?'%��I��bRr�!b�VK���:�`��=T>�cm��!���G��E�VKpA����~J��-):��%�2�37��U%���#�V����D�5#)�i��/
�#��
�O��a��DK�������������Gz-%�,��_u�xo���
6"=����r�����p{����O�������ewa��r��P��B�eF��
���eW|<w�����ec�QC��a[�
./�M_�P�^�./�����l�k����`U�o������{M�_r�e����,���?$���#f��W�J^]����7t(������]������V����fH������/#�������5�����(#s����0;zD�0�J��}�A��B���Ag��q�>`�=��{��� ��d(�	ej���x��ap�������^��"D�y$�'��\'������!hh?�k<�{�fT��g�^'�za�����t(l6�����V(�J�KO�~y�����y�:��
���z�4���Cd�/�~?�}y���la�<��JC{��3�U_����&X��� !r4t�_�\/G{���Ltbi]�����op���#x@�]-���
�8��l��/����H�[�N���_Qb��dV����E��B��z���d|@7����W��)H>��n%:������c�op��]o2����������v�[��%��\3%v;������;���z��]�t@��Z �+tQb���N�5�?H
���Au����
���)���4��`���2�C
=�I�tN�"\V"�����R�Cp+/#������9�k�nzB1���'�*j�����v�R�}}>N�F��~������nbu��f�F!�Znx=���-�E�;��!��w��]��}K���58�;:�u��m�~D���#xe�/.�k���_�'���<�.�?�X�O��1(�	o��|7��|{V�����Pmro��]N���Q���_����V�S��������>wm���������c����W�>M�j��i���/lZ�B���b��z�Oe�47�5���5��G
�T�t������������>??n&��/C���3�WV����b����T�=��:|�
�W�yR��Np���>���\���S�����Ei�B�:����1=c�{|������c
�
�gy��
��4Q���h~���w|Q���=���t�i�]�����b����n@I+j��J�W�W���������e7�Ni��5�Tp7�X��7��WQS��#��?���pz[��U�����oss8��j��&�Bt��4�S���"`�Y][�����������z��^�Dt��[���2cp��E�I��"�M<w�k�����_AP�B�����Nt��P��1�kp��E�I":���C�7�Y����z��^�Dt��Z�����'Y/j����������!z]
��$��9�(J�6��O��g���LR�����Q��������'�(j���3��v������'�(j�d�c��n��5�����x�M�J�JV9���\�h�L�U���]0]q���G�=6���3O�Yx}j]�q7���{�P��Q��&���.<���R��J�����b��N�K���l�Sr$o���$[�&K���l�L��F��FM��%��m�	M&�	�����&R�c�^���E�|w��.O������~j�eW���t����������][��bp���Wc7��+H����FtbF����������;��������z��R����"6|O,{����S������l�\�k�r"~5n��z��z����>`X�r����w��i���o�
�=�p�s)�/AZ��U��������X�OA|��
pH��Cxi�v���x
�?���+~_�����xBC���8P$�w:1�Z���i�$8tg�w��	p#�X�b�'��������e�1�;$�a#��*`��9B�w7��K����p_6��BE�!zBZ��zD�����@�4@���=�E�4vkJ�����K������1��/�����{PV�G ?[3b������Y�F�?����~uv\��]:�{t	�=t���{�9�@�S_�{��t���O���"8��'9��iM�u{�Q�c���^�gu���Et�����������UC�b�R���B��������/?������s��u�H�f���q
������k���8cp���=@)����2����0s��J/Ze���0][�������
5�yJ�<��8�y�/F������	���3�3j���ID?3��,K���Lt"=[D/p�����b�H��x�Y|�)C�x�_D���H�j�����U} -�q����b�H��P2��bup{9��Dtb�r��<w+��*���/�h�Pv��n��`m���wO�M��`EZ��m':q�������l���O����n�"��I���`����b���5���;q��~��_���.z��MD�tE��n(v�;������Ed@W�D��Ey."k^��,"#>]�iF���P�;�8���?bb�G�"2���jh?X�4~c�������?�6�u<�a8Nx4�!��.�������a^�� ��@Ed���}��Ed@��c+����p�"2�C#�(�{HpA��G��b��'Kf�}�@��2u����{���hT�U�S����Cu��I�P3�"����q���7��-dn�"2��y<���"��V$�b�`�)�]��z�J}�Y�:��s,�����O��4�S�����h_?23��C����4a� .<�f������@�r��d���x��x|-����+��
�Wt����������W�0�SD��k�;r;����\�3�����F��v��/�:��1���=��=�b�V�����(\o5Y0P��ktSA���
X��)���5����3��h�N����^<Ep�m�����)��#����=��������Lu������S��XO��u�Nt�]&�]N��t�����]y��31�o?�yo�2�0i�c
R)�1z��!%2�~=Ht0+'����,�Ntb�U��qF���b}^-�!�5�5U�d��Pk=�5c��R���EAt��Z�c�n.`+\/v�J��=ws1�(FK}V�����b}���%��y������}���`����q~�,���j}�;�d�]S�K�����N�d�����Ifp��E��At3���,�sW�$3�^����%:A�����<�j����|1��z%:q�%��d��kU�B���]��ib�r�Y,��e�A�w���N��'��<�������E����,��v!:Q�T��O�Vi���l�����]j]�
D�o��;j��oL��`��b�z�d�]�9c�S��B�����bGM�+M��{�a���]�V�cQ�,%Vja��
�����Z�<Qb��huM�A��mD=�tyb�n��X�n�;~QFq7�_�(���N��R�w�(�?S��_� �KDG�gz��<�/��������&>]�i��}��?�9��RQ�O�#&����9RUO��hp5��
��������o��A������x����7D��� ;����yp-?1�G��yCp8W
����[ZTx�!#�1��;�����j��ty�^����t]��=�������L�����cZ
H����^z��1�:�^3�������`t��O���gjf t|�'��*�8���O������@� �
�<��'x�%�b��sa�-%��_*u���;P���5��D2�^��7������vw\
��c���}�(�8�c��";�R���Z�Bga�	�F�!���F��<n�4��J)xHy/bUf�\�����	v���^3x��W6���B_���ctb��!���B���
'x+�e.�Y�3D	��J�Ul�,��
c���UU"�z�H��<���$V+W.�b�B�
��;������K�0�5��X�P���8��
�/
-��
c�PJcp���Vk��P��/��X����z�K�0��b����&Vk
?���#�)x�����
ceb���#�'xM��	?Ol���~��}G�Y����3�^�+��-<�����8�k��^/x�F?�����;R�vO�yb�w��u5�����+�~�����Zat�����
�/<���qa���<�{:��koS�Zg�_�lu,�=���'���u����_����jul������Wg�
=������c��yL���M�O�@;'��U�1��;��C���Z��k������75-�1Nx4��n�����k��J��_�U�5���ULWJ�sB�*&��u4��vZ�/&}��x�q�f��xG��:u�^�N?|�n+H�����:��C��tC�M?�u���DE���2b�H�������uF3���ZKp;�y;��:���������L��=�@7 5fp�����&���b}����6�^��� ���DOh���%�U=��W)�����B%v��\'vU��D��_�Q�r�(��*�����s��	Y��Y�
�Wl������ :�
DE���+���+����M�WT��#N�x���"U��d@�D'��&?+����z��>���F������'�"�*�\2�[�n1�'�s��$[������x���������&�{>��\�~��������Ah<���D��X���X�k[m��{������U������+�N���������W�����-���t�w���Opx��&����9dnW�&�����;�^��2Wv�ku4���4[�8[��pz�3������aa(�a���q�q�3�����w<��/~%*�����]Q�>���1x��P�8��_ax��E/�%:t����P7�H���nx��E/���`�|��RW�8��y����~O!A t<{g����W�_Qt�� ��b��i�:��/����r�.pA
�����������.z� ��
������u#<d���>z� ��+��z�K.������R�>z� ��:��z�K�06z�(���7
M�M�yU�����v�����+�w�.�+���tl]�o����0�n]�l�_w���o��e��u�/����/�V�?���Z���#3m��t8nue�p�Z_@D{�
���v�yh�9�u@'��/��~�d��f�{>���������n��@���@���e#���-�aJ��nD��#�c?�k�l�
s���)�%�	�D:�S�����~���kI�t(�{�Me�M_�|>X�Ot���6&-�HK�P{%����d����:7���;�d����|k��s_�~�pT}g�n��9��<#J�_�-�'�tZ�ySZCt�y\��&z�9��D'�0���(�k_;7�^����]t�Xa�>v�m����2������R�KT3����,7�^����#���D2M�x������D�.�s�u�7�����a!�j]�r��<w�DtbS��]����;pkezGy����Dm�%vO�A��W5�qb7�Xa���y�
�%S6�����(Z2�?w#O�Q�d�&���q!:�+�?wO�Q�d�f������~��n�I6�5��#J�6�����n����"Fc��3���Y��3O�Yxj�K���D'*��j��7�j��%�;��$[�&K��.+�(��dj�K��n-�N�M���l���j�K���$[�&K;j�Uh2��%J�6j�C�\���6�&4���'vt71W��G���/�����tyb�nG���,��/�.�l��%v��9k�cW����nLW\�]U��R�k����X�N�Q���u����
tNw��>��U�wW_������$���70���#�����\_�cK��#&:��[__�O��OS$8�F�C���������Fq����}jQ~�$��3���
	�����A�*�b� 8������ 8��OYWV-
)�����ue�����^o��D��0:�V@��
x]��dg�.:�R8r�y���=��c:z���3���8'xe��e�`Otx�
�;�"F
�b���D�|��d��������pK0�^�R����
���m���3xj�}�	@W��*���6Jx�����C��{��/~�(�5%��6��>0(_��/�`���0�N����%���S�^��4�����`-,��x�����<d
jQ��`�)�u�'���G%J�:�
���FC���#�)x�'6���/	t}���
���%x}���b�����<��w���	�t��z�K}`���Vk:�q'x#�7�9���ae��{��<J��������#:�y�^r�1����������'��G	�D?o~^�a\DG?o~��H�	��Cj-�<)����M���[���Y?��/��1��i�J�B��~�,��>������U�^r����[����>0�y���K�0X�kx?>G':�y���R#�~�*��;R����Gt��^��r��x���������g��Q�� ��������>�~��:���������?��F�o{����~�cQ���}��y!����.�1����T��c���W�NS^��7�2�|4@���f�P�����FtPR����sHp�|
�')c��f ���KTw[��\���� �k��nkp����b�H�q;�*FM���1
�7���7��C���q5���=�8�i���R#��\�4?8��8������L:�� !g1���Fl���7y����NP����9$8�"��F�SM��9,�����94D�Bp����������������o���3/�����_}���������$�����������?���/e�������~J�����?�����|����o��c��jK\����zn�����X�����7�=��O����-��r��
�S����E�/����1�^���y ���������Qoh��E�ZtuIt"��v�n����{
���S�n$:���#d��n#81�]���<uMEt�YL�#t
�����3�n&:Ud�8t-�01��V9�(O]�b��e�R��gX+����t��-D'���>&:�a��tT>:J�X-lp?�S�b�V��q�u�Z��Z��OK�[1��V�h���yR�CQ_��R��y�wN� �������v��v��v��y����OV��'����55w��d���~��	��.C�pA�&���m�z��+JbK!eYu��+�����M�����b3<�>i�>!:mp����3]��b:~�0���hx=�/d$����A����vq�W��������k�����P��vO,�/���a���m�������:����&:X��^�Ba�kKO,���<��go+�^��'x<|[�l{T�Y����8m��(��jO,�S���^�VD��ex���>0������J�Q��)����R\fdp��%�C,9��6��"����6�N��T}r��uF�XgT�V�tj�������`�Dq��B��@�t�,n�{�Y�������,���,����`�3�#����p����P~�}��-���?V�<�~d����:��KX�L��uVM-�@��@�R�-b0�/��m[�
?�:C{����_�N3���!A���~i@�j�a���f���qu��4����b��b|;����{E�bAZ�wy�	���Dz�>�":�����e��q�����,�q��P/�B����@t�������3����B�^%��s��.�x��NZ�$��.\�S��:����w��z��+!dhO�2��+��.��>��"��oD��?������j��`��W����A����T)U�y�[�N�.z�q>Z/����[*J�F�wb>Z��������%�D���%a���|��VQB7��0�I���[N
C�^"tsAt�8z�(�AgZ/t�� �YH�����dVg������":�s"7!�����"zZ�h�:
����$������Z�aD	���L��YB�����e��
#N�x%^��I��m��������xgw���3�y������`|�]�W�	J|�����+i�`;-_Czt�f�����vZ^��������g���zW/~A.�;�
��S\�qG��pXm�b���,�1�w;�Q�7��Z6�}���1~�N���2q3�+~��S��z���&��6�����9h�&:����-�'����`v����������dRm�B���S#8�>Lb#��O����`h?eJr��n���������Yx�Uj��U��$����=���X�$�G!zDi�����>a��`���:��V9:u�M�:H�����xvOed[5���4u��V����O��G����������P�3�-�>e���q	�/�Q��0e]t��3�^�M����������q���%�D}��f�d=������$r`n��L��K�)=ve`G��x�-o��R��sQ��k~���cR���)��)��������x.K��oj����c��t��1����k�UgdU�X6��� ��t0\�c�*p!�3�p�Z�:��F
4Y�����G��o������v�w����eg7�+3�_�Zu9��;�C���uB���IC��.X����mD��8'�T�W�S�� �tH��O��N3��C�j��'t;��56�C77�{�u�b����:U%t+����jg��-<�f?u�<t�&���*�'t���9�>J��5YD���aD	�Z��9I��_�UT��+���.V�s�<t�&���V�_���������_���V9!t��(<�����s�KEa_��(�/�+����?4��������\a�@�p�������U�:�8h.C�p!�@��|�Oi~.��4��5}����EdVj�H�y�tpt����W��qf(�b ����	����c:�4�:HF��9R��q6���B�2xb�}���'fQ���	����z�K��Zfd�����;����~���6x�Ya�U2Q����]��+�x�	�E���i��� 4���U�6J�V\��U��V������z��>��og����*�������
c`�j��M�������l��H\[`�K���
W�~�+������o��E��
[yz<��6�������/r���B�GXt(N0��W���s����b{�5�q�*&[]�+
;n^����^y��6_������	ES��������u��u���ZWB_8]]���������
����]����O����������#����y�\$�)�7[�|���@5�D���:�5�&�5��T�/����:��}q�u)�ta����;�����P����/��&x{=��HGz��J�����l�4�^k��->��ov/:>?�{�q�����S�P��;�+Lk����[�
`���\��C���@t�`WQ��2�i
 8�"��u��P��P����'h
x�v;8���i�i^�M�J��o'����W��^�Ip�QZ/t���/��.���Q$]��6C��.z};��D��%a����XU�2���":���<t
�,��]��v���������<F�����XU�.����X�7���&�����qB���9��c����Dj*U%t�w�g	�&�� ����Nt��$y�z~M:�A��G	�f
�g	�&��������P���$��4^���������U��P^�Zx�����d
��^��k�� ;-�\������2{�$� ]�o������^��cs^eV����I�U\M)
��te��yy�M[�{l��������U��#:T!�et�5\'v�(�ng�Te��{�kj����_�N�FE�]��s7[�8�����:���Q6vm������+���<����B�V����m}�3A�*���m�cW-X����n+-��[|O��4$�.���]���/;1�5~�/�a����b���`����L����;U'���`��.����g��
���E�T��n����4��+�8��N4�MfQb7�(�z�&��`y���bw���/�S�Ot+c�\P����V�_:��C��|�N��_u�4,�����������c5���Gf�[y�x��	kz�-���������jz���Qz����?�����
������;;�k��%���e�W{��������ip����P��x��)�`�|���^��G���gY��*����G�i�D-6��z��
�'y���._��uJ�/��?X�te���~��]���4 � K5D+w��_9���@W�N�*�
S�Op���J�z>w���Si~1���������2`�
�q��,��+P-
���d/�U����D�/����>t�>�������_�P�__�v�D	�0��A����_
�Bt~�1y���"U0F//'��F?U �wG
�Hp�F:Xy�����
�'��M^�Q��W{Q������}K��M<�&�vi����D���%�L�1�FK��c�B_��!6?�������l~>��}������B�����o`��5���sW����u�����MA��C&d�P���� �
�C{P��f�G���������8�C����}��q�W�#������l�+~��';���W5�8��#�>��G�h���������S�t��R�����z�u;!�1n��O���v ��T+����F����SZ���!��o5�j�0D�Wx����*�x�7p|~�?�S�H��&~�4�A�\���3/����=/�o�5�ya�P�.�i������G�5����
k��h���*�i�?��
}|�^��q�'��*�����z@;,��5!$L�"J9n��T�*�	R�Ct���J����*vn%8osQ�cXw~EEGy�)���~��������"=T���L2��������H��"�k�T���^7�^���	T�t%���S��u	������.!W
��VX���c1��=�������*v��Z���uKa*v�c�op�l�pr�T�J9��= CU��Lp��W&K������;�q���7 %P����68�b�X�ap?K��}�M})�������>z��X�EaGSD�#���|c)}� �j1�)��!��$:_��gilkC��.z��MD�����uC�n������5po�p��������ti���8?�
n@����9��4[uh'���j��C�y���oX�e��������;����$��v�����"�W#7����>r��U}��%��"��2����8xm^4�<�	�������<��~}��{�j��`�����[�,�q5���~�9GI2o�~�+�����ex�'��;����d���?5g��Y5��dV��?�{����2.#"��4%��U!�d�	����N��A����N�B�� sHh�2�����;xF���&!:`���0&���q�B���������"�=��zF&3�g���������o����� ��
o����Qv���Ut�e&�����xBtPilg�Q�����
(��&Hr?��n��c����_�E���xBt�r,��vi�G��(;����4����Ap9�e-�� �������� Lp9�e��6���3�"2��6H\FvR,���o��2����Dt�N���k�f���H�;�t�&Cp�T��{^�b�����������w�����_?]�qf?�{�q��>?i����s4�;�������i�)����*�w0i���\�\��r�����N��/�e��Y��s�}5�2���]g�K��7��������w}#��5r]��pd��	�u}ArB/�x%N�PS"���!:a|)qd^���'�j$@+0�<��K��\�����(y����e@��qU��q���,f���/c�7��E��qdy�*qd����v<���K\��v�+�{��Y�#���b�
Q�{�����@��G��J��V}���Gt��%���/��:�?�������j6j���"8^	��Pd�
��Nh����.T�����9�J��6���BPq�m�o�em�H/��O����sH�[��|�6��vHu����=��l����!�!8|�v�9%�s��
^%�����U�\���Gh�����J-#�c6����M�������3�@h�Sm�%��P^r������Cp�"�����}����T�����<Z�5��B��^�-�W���"8�����PA�e	�[fPz�C��?�J%d@7�(I>~�������2��M���u�wv*�����|v���9;5
��K�N{~*(�[Qv�S[���V|k>C+r���n�4��F�Ct�w"�g���d�/��x*@+t�B�I�Ev8���^�F)��<@��o��y�"���M� KY�,����Lp���2�(��zaY	����)�}~*�3�P�M|���d� d�D��#;� \Nv�o���0�1(�/
2��we���N�(�q�����oJ��um��Q�Z\�V��k$��Y�<W:!	g,H��-\���#�Ht5���=�e������t<0B�&$��d5�qp����l�!`�=�Y�\���Ct�a�jdi�%��q?"D\�P��{�,z��i�`E�K��~���c$����cd�
[-i�����
��T�(��C��($��NjUQ��:,7\&�N����#"�����9.�w��T���f�����KFzK�K'�5����p�fl3���v�Z|@�{/��3��c/��T����
]�����bN*#�o"�
�;a�� �#9t7�����Dn�R"�=��"�����]$������������'�������$76x����)5�Cr#�u#��q������nRb8����7
����C��(���t���6��;����=s���[O������S���W���2!�����MP| �/uae��G�$af������[�|�8����S]�MB�������[O?��?�A�Hh_�\���t�0�n�]u����C�tWA"/ D*�bDi����A��L�
���K��7j���EA
r~"/�C���4�Zg�)��;�a����yjP�;��z��3����>��E��=�(���=�8���&z�tT���:a�D��@����;��4�c��Z-�V��yySo��l
�����$a�j��y+��0�	.s�������	��M��
>-�gJ�m�b)�A���r���0��;�����q���,f�C��0����Dp9J���T�����������x!�|s_;Z%������H�@tP�!�/u��Q:��!F�fc������"���W8}:�����/+�kq')������"�;��C
��EJ�g�8R%]���pp�$�7�pY�X����0	s��K�;�������D�m�|I�4R)=��6�`6�r�>�BIt��m|7s�A�n�z�M\����	Tw)��Et�zHp��1�RE�n��yX����CB{�Q�!��/��wXZr3���eHg4���@p��*�|q$�G���E�is~��W������:���V#L��'�q�&��Mq:5B����Tj�n��'B�������.�R��A�u6��Q�V���>�z�2:oPvL+��������	�y�3���q2���}�����,�M$4��p��,lV<��VB��,lV����B�Y��x�~�A��ga������nV�����m7+��fE��$;t���v�����&�f!A6�����c2dv�>����"lV�]t�Yq6+Zi*q��f�Y��(���#;�����V����cBt��+ S�1�q�P��������~Q�1��5��yL'yLi
�/� �'�.U���M�z�b@�@� �Bp������������f$�o��@�;
R�?$87���(J!������s74����Lf�v�����q������%t*<&DQ	�}O;��B(uU���^L�{�?N����`��
�8mP��	0�b���X��\������&��Cd�C�=���cBp�/3!�
�	�bn��s�����>�BnU:�:�� 8a
[q�-�!���4YD�@_��D'1^��}�����4yD�/��S8��7,��i`���A>�F��e����|~��[ga�A����a����f6{/B�w���N���S_�28�.��/.���eR�Lq�28[k	���J�hL��mS��
�K���z ������P�	�[�����Y�JG�n0(Ia?���\������'�oBc�#t������C������� eFp_�I��������q�2f���������������7 �������������FO�������~��������������N0���0��x�nm�_Q=������%n������j>��;�F���yp
����NYLu��;!����� �X�H���==�*��&���^�m�y�7��Fx��DR_�Ab��r�;��hoG���m���Ex�C�	eq�f���^Fx��s�R����$&e�aNvr�"�/��(,oRRV\��{������Ax��������/_�����7��E��_f�����_�����#��j��'>'m�q �L��G�3*�D��M���0��"�������o�B�Db����x#	$����}���{e��#��L�������w��x76�7���:D��&a����/���}OC����m�9%��Izz��� �Op;6is%�`�m$��������=����Cp�����6�:������`��u�1��]
��A���fL�8�'
���iiB.����]-`L��K�%�|�0��v'J����3�I8)E�Et�6�������3�|�0����	���nBw`���RzP���������/.����1���%�0#|�_���������N|�\�y��nii�M��p��9��}���I~���wI��Wi�
��\%�%�^R"�!������\	B��-���F�
!�
�����{���
��������b���{��e��B�4�uEo0��
=� ��o��2�Q���yq��N���-
�+	UC����c�lx�f������i���3z���+�/�
��=���
�r�My�_^�!�guMLb��"��:�E/`�
���yR��J���n�9�M`����@�xA��<�F��2�[����z�8N���F��qj������,�<��f�z@�V���v8|����^�B�[;��G&�����XDt+o���0iv�U�@���������SDt�U:�B<�3
�"�0��e�����3{G�.�@����������<�&�������. ��	!L�������=�F�":XyG�6�'��!��[����B]q�*�.#��[�\�D�Cq��;@p�I�T��nCp_��W9�?�������������7�}�"���_����j�Tb������Tb�
�)B����Y�Y�T��<(%�^#�\#�?U���;���v��E��������
���+F$.���=����s�Ix�E���LR�m��������9��p�(����
!�8�$���A�	���fk
��	/#�����
1����m�m(<��"m��#<�Px|����(tJ�o���,��{��3�{W�t��w�������v���K���Q��K�����Q]-�H/����}����,A��}|��S���'���Y�;y:U��x��=bJ����,7Rt�S������+pMB����}R6����d��G�|'By3V@7���#]��=����;����/D�E������gS�C^��#:���}�M�+U�����Z/��T���n��N���(U��"_�YpJU��������U{���;�n^s�JV���U�	�������	=�C-����Ep�����nDp|J������x:����"���M0Y�`wL�C���VyD��D)-.:tv��!-uR��8��7�y�T����jo�kU�P}T���XR��#�^~�����J�j�:?�}�F���^�;��������T�d�:��\#�K��l�;_�Gx����pS�j�Xa��<�����:H8i�GB~�����e�����M�'�N��x�F^Fx��A:���j�����j���6�nv(<�v���@Wx3�/#��d��.'�3@u�-
����d����6<�|'��W�x�V=,O��}KU��a��]��}�x�<,Y��}c��W��a�����}�Y]�{H�{)��*��(�.�?|,�I��s�����z�@�={;�#�/?�zL���mP����Cr�u�}�����5N�Q1��M����jf����-n���J����r�����Bp���-��3������7�T��s(��*�f�ZU{���O���������Y2�������T��Gp�\p�9W�����>~�[3����f����v������J��gt]��������N�A���r���1���x',a����D�
nAp��'�
r��4����JI�,����Lh�Ft��)�<�[��)u� ���A��|)a�Et���mD��{>]zNti�T���h����:w�:����9h���:5�X���d���J<wnGt!��C����d������y�$�f��c��!��3�t���'��b�8p�f�?��tH��C&�1����&Ep9�����p�'��7N�=s���w������6���Nx�\ieh�0��Q�*e��C���W�~+���8���dQ��.�N��+.�#�Ax���]#�C�Q
�J���/�(P�L��b��l^������lb2������=���KV�7��y~���y�����K1Yi�n���1���.�����Lp��f'|�&ihqz\�b�
��1&��^�����u�^[�`��5���Li�@�^m�0���;Nm}K�_��@h_�(�K~��V�����
�6��B�Z�W&�mp���&a�����0��K�(��9@�=���,�t��pz�gT��5�������BXD��/V,���lx�&Q�#ZU����><L�|7M��z���JM�/�i�	Tl������A��6��A�m�}2�n?��@B)}UB��5��6������m����
�$��������p!�`1�Lc�
��!��:>p��%~:��e��=��s����Ap��8a����d�\���t��v2Hm&j��f<�(�h��X���
m&�f���t��Qj3���1@a(�-j�����k%�N���J���_��_���������������?���Y�<���������O?���?~�wJO����W*�6�W�,�q@��������w��q<�����7��v���IL��DY�1X�~�����H�I:|�J\\��@��O����/BT�������#�86�qr�f7|J��$�\����f�`�����?��~�`���sr����s�9qlE��=.x�o�������?���1;}
�yD�b�g��a$�������� :���RN	.'���5D7!:!T*n�������3���	�]��b��!A�h���a*�����4"@��/���L�=w4O�W�/yd�/� �d�N_Ct+�^��6;ZD'5O���e7�K6
��6;��N�!�F_K��_�Q �w��Cv8���r������%�&����J	.'��q�� :!W����&|�&i�B��b���u�f��_�IhV$��RN�$�d]�v,Di*�QS�����#:�y�/���@#��4x�����,��������
�=��&D'4OHS���=�����'9|�s��A��X����9�ng"�����St���L�t\������w8�K��\��D���L������/�����`
x>%t�7��	�*��hJ$�LY�V�zc<��6�*�����(���@�\oG�|B���0�@B{�7KW~3��'a�@�W��Ap���&�jH�ej��B�,Af�O�I�7�����N�7�9d����oF�������0U)�jv`�s���O�%����v��������0����/Cx���%6���R�7�A
c~����1��7�2�1^�7��|t|s��t?�+�!����1f�����.�*]0^��k�y�|�G�V�o���B����;�NX_�D�Gt�ny�p��"J]0������-�
1�,l�Ox�{]p�T�'�,)�PV��xs������w�g���%��b��At�1���b���`�!�}O3^�>\�����x��s����L�vDuT�&���X��@nA��T+�?���f���?OM���s 8|D6>b�����v���,�}����a�|~���t�t9{#��x1���s�g�Y:^���4�9L�x��A7d�q!:��\Nv�9L�nCtB����p���d�������Y���ea�"��f�������;���5+�O�A�*uiDl
��ui�T�vi���n���3b@N������V�{��H�!L�V-uB����2��T�Z���!y�f����U;����V;�2� ���j9��������<��izFgj
G���L��Q��7%m$T�k�������P����T�r���5�u��~��Z�u-�H��W%���G�b]��S��/�8i&��8��}V��.����{
�`" b��0s�\i^��P2D�����C �r���}/�b�����	/��<�3��A3��HWZ��T�AxP�"���P(�X���O	��X�j��Z������r�[��>. `�`)���,n����O�0�]��� N"�a9&����1�y�GKNJ(�L�Bt�@p������c\k�T����c���3�9wd�	m���5�1w,z���ST������c���&��fD'$����k8�1q�\�M�	�����K��]�6AD����ci����0	�JI�6��,D����e2C���#:�yn��At�<K
��m�Wq�b��=�C�@jx��d�	.'���{D�!:!�<f������r��^�Gt�AI
��e�{���.�t�b����~������s�yL+?��g0��$a@��z��W����psP
Z�^'<�:�g��q���T��P�[&�����G
/�R=���[��e�%x:�g���������I�p�-�y4�7(J�O�O���N��T���7^y���s�T��v��k??�k�>��G|�!b������Ty�P����V���.��s��R�ah�����&l�q����������|]b�T�px���M�$�
�8d��t����mj��q����6����7�������')n���V���M��(��V�h#:"�7��"V�>�(n�+�B���*��#��g�+�f�Zm�8B�U���L*
��Ra��~��t*������6�*���l0��!����"��a�&���2��R��;n����R���#:�c&�����x��!�:qg�Ji�m�N��S\v�Ct�<��S�����]��6�[�P�����Y��K[`���yd�!!�{��-����nDtB���[���]P���mv2�N��?w8���� Uv��M�b��o��#:�%����]�����M�������F���L�������na�r��('���N��?Qv���������Cp9���+���Ki[�!�g�(<����C
�.Qx�����D���p������jqi�nkQ�	Z���Cv]�����0#�������c�3f�C���:�=Q�Z�F�G�������A���cO����~�i�Rx�CCp�����T�c�9~��}���
�����F�������(�KX���DCx#Hox��s���(!�h$Qf��hQ�|
�J��u�
 ��������N��X�M���%C�CK�#��/wP���c����w�Y
���������>�0B�~6C�KW����q��_��Q����f@'�5�N���`�������A�����*^�� ���3��D�P��!<���J1���bE�����!�����U�� �N��F3�+��;_�)m��iP��^�����5D�\��
�kiV�E_�� H�����C_Ct�� �}M�G���<"�����o��@�#8f�]��,��Q�BuSb��d]������� :H��R9yd�3��^����nAtB����D'81}��_�Q`�?w���S�����VD��H�����N�8��_2����Lp��f=�^�8��^TXD��i<Vq�Mx�x�7n�8w�d����<�[�����h&��dL<�_L�d���*���.���bU�M��+U�UU����}RU��v���t)�O���a���m��D�6������F��`���G�������"�}M~J�D%,���7]������d�
+���Eh�2�g;`Px.-*�uj�oCQ��	+IO���z�����w�t�
��4-8�h����r�>�4�;�Jx��x�g%�wVB���bm�#���m�"+�w��}�MVF����j���1�i1�s����D�mKw����\���D��Bt�h�mK�������o`�[��q��$]�%":|1g>Sm�5s:���/f��t?���xAC�����s9D<M�[��V�-��m�xEK�zs�������������	tz�+�]0if��	@���l|B�I��9N@��wL�l�3������LhNk��8�K��
4GW�>#�!�������f�����k0|���D<��bP}�\�}�Ad��Et��\.��6�"]g�����2�� @!����3@�;ax��:P��'$���-9d�[D�?&�m�����r���At3����+�8���]��np���O���a��*�A��*���]��e��-���N��;dm9��e�
P�yD'M��>�����_eM���Y[��]:�E�C�����b�X�I�
06U��<b@?�*�����x�NH�K#�t��TB��sUxG���Wi
��	--��D�HyG�p��pI4���S�Ex-^��=���r������.���g��s��j�Y4m�Ox9M��"���)�<gPz_$x,���R����}�R<~�~�U	���w��K�9K�7'C��k5���tP8�s��|�@�@����I�[Tjx��^������6��.H�7	�b��g��$],�!:��iLL,)��T��k�����B�J���xD�r�J�|:]���Cto�["V�/�����GCFy�|�R<���.Z�wif�U�G���LR)^�v�k�O3��0��%�A�)�#8�3Dh�R<k'K���)�n8���������(lXGC���g���n�RJ+
���&����p�K)d���&M�������V��c�m���n�����D�]����������.��b��]��g��R���s��K+V��������;I��U�����	����:�
7@����H��2�� �Bh�2�� yt��1!V��^#�E��<D��R���-J/^�zMc���s��J>Y4�I�N���s�u��[��W������c�N��v����q�q����W%�)����S��N��k)G���:�ISa��L9"Dtf~Y+d*�����7���rl�=����M�	�
�;���rtk����w"�M�t�� f$���zv�Y�����x�J:�������$��{����&�,n�;FH;?<|<���VT�nX9H�b���3���A�E6'1�t�":H<\���T��+��2��<9�w���$����6v�d-�r?��V�M�������KCf��t�!:�G���<�	.'���5�nAt��f���	�T���.{
���3�}�s7Aa��p�7�#��������9������_������9��JE�,����r�����m�N�W��-5�ww��|s��/��]����=()�"n��"��	���D�V��i��Z���� :���w�QV��V������
=�U�����Di>���N-�H<wzP�@
��w\#:|�6i7B��b���&�)q���_����9��>!:a>N��b�\�����wr�P���

�d�W.�����)I>q
|�����q�N�z�u�~J��(���b�&�q@��9�s�����>����F@h�
PE�a�O����Ne�>��������-���3<����n9^���1�}�
/��Ah��~6,
Rx.$~�[
��
/<��C:uxq\P�����P��C*���i�Kx_�J���Cx�?�E^����<��s��������9��?����xq�i����9j����������y�+�q�<����0Hq���r\!�h��	3��A�6������g7��`���s#�rs�t`'�{�v�����Qx��i6e�W&3vB������O����K���� �Kp���[���O����
���6���Ct�C������f�J�?�����%'��R������2��P���<��i%���s�?;|J���[3Z���e�8��~W/l{uR�U#���,<'���=���4\Nv�90:H�\Nv�90��	K]��0��A��
k�7�";n�w<��J��<�����r�S����k���N�Lu����w\Nv��T�����������W��]nL�nGt�����a����8W6��v�����l]�:|�:>s%o��q�0� ��"�_2!��7	�8w�Gt�K&�!g�������Y#��,��Wmn�d�_������5��nBt�KV�f|�>�#V���nt�Nx����v"�/���nFt�KV�����Nb� ��<���(/;�x! 
��#;��������	s^l�W$�(zP��(}��:v���`�s���������>��y�c�I���
P�s�{	����3�(�����Hs�n��l�b��y�:;	.'��q��������mq�����E��S�/���=����/�7O}	}{�/!������<R������JB��9J�h?u8ZY�S>�d���QQ~#�������$ 8\Ah/��|�K��b;�	�$����;X�/��D�I��Ep}	8�`���o���&H�L�{l$7E���CC��L�4NX�/���Lx�S�3��'�]6�S�G�3TE	�1�N_�[,J��,�}	-����K�����$��~|����J�Kp��Y���O��1Q�c���Ky�jm��a��
d!�:e��I���}�����l~X��O?�������n���p������������?��y������9?���?�����O?���?~�7�O�����
��4:�q��q�q��"1���>�7����������~�<�p�C�����Fs-���BO�,�j�,�Rs	�������X;��xn�BvR:����}!���\�� Nx�/eM�Vs	@���g�����*��{ x��]�J�%�n������x����f���{:���[��v�]�E��Y�Vo	��� ��IS�'����Op������[���
�{���D�������r��<������Fk	�]I
��.{���k�
�$q��J��m�N(Mw����n�:�}e�Jy������������~9���#:�dU\v;��.'��#Bt0d������+����g�1=�[�Qv~�u�s�4P&��0�"��	d���n1
�n�Ncz�������"%�<S"�F5�������x�LtJ^��A�j4 ,"�OX/���F#8x�	��T��r��������*�g5yI�F����Ox_�C*U��f��M5��(���H�OM�.�%��$�7������a�V��{5�0��A���qm���_�#��A�������=6keU�E�_�Eg�U;�?���&�I��Ug���f��p���b�����r�t�j!�C/�}�g��cp}���eD9�E��!������f����zV�e`6g��� 8���`��D�V���f��}��u��f�6%����mUJ�BD5�V��X�Z �E�|)�ISt����{����W<"�����'����&H8��Fh�.�)�j����`?�S�`�k]m|6'�gt��7�DVY����N������D��+�Cyv��-.�Q�3!��I����
��Pg"�����@":�?���x�knMo������o�!K��&Qz?��(��&�D��E�,1��o�j�; �y��?l�#��?O��s�f|�&�����0�/��'
�c+LU}�� �Bp9�e�4������Ky�-5+���S4^,Y":��\,Y����-������	Z�q��?Kv!?C�p~:af�B^����;��������Z�,����T��(?|)	3#?>�������l�[���9"Af�����S2p�Ep<O�R2Gp���L�m��&�\�Q�>�R�G���8��9��������=<'�����&��w���/&iuJ�or(���>���{��2%s�^2�>s��.5}UB�����
���K�|��f�_^+��g%���_�F|��@��8�e��O�jZ�6��+��J�q�B�&
`�
RJnd��!:�[�:<����wo��7��+��9���W���R7��k��b��n��.�}K3��V���[����LpO'A����nG�!���#������,��9i��Nq��fR����%p*�q��.�"�
�����>�����Ep�c|��F��v������W��������������=�I��-;��{i�C��E�nGt|KHy�
5�������Jp��f�\\Nv����At|�2a!���F�>\Nv��5�nDt|��������r�K���X[t� �������{���k��x�QB''�R �t��y���S�����kK�#p���;��zj3���13��/�+��=�w�ahV���=h��/a�|�S`Ep+��,Ep*V�Y�m���^������f#M�P*�!<�ai�����)�<X�x�����{��
R�������J'��Q*�"�����@��m�V/���|���_�R2FN�,���G|�s�M�������V����P������������_��;�y�j�>+�{8_&K�e��U#�8�-��A�-Y���2����&��(�~������u�un�6���U�Sw�h���Lf>� N
S��"<���]d�)�]&+^�Y�����V�ln��N�`��@�:D��Op�X�PVabq3^�NV�)�Z�_@�a��������"H|S6��$d@N�~�yw��E�$�N���n����i�1����Y���(��~��l\ I��JMp:�|D�����e�@q���hL@�D���d��%���d����*�	���~���N�-��!��!:�j./�n���Nmu��D��(	~�e����	-5���<��;@��7J������Ex*usD�!:��{�^Yv0����]:����9�������y�T7�z���%��<b��|�z��J��pm�P�]��%����}�J��A�Mh�2+`�
���F�T�x�&+��-��W*Y"<(���������W�4�>��a�/������1%K�����D,Y�{��eJ���e��?�+H������u����Q�/v�vO��&Pm�;�����3D�a�[x�{;Juq�en��KW�3���1��k���	���2�3!�/�T�"����&c&+n��w���bB�U�/]Et���h�bEC	���4��������U-t0��7��Y�V�@��s9���:�BD�A�{>���"�	��������j�i?%������8f��[F�\hW��Xa���=�Jc":�fVaN��eUI���!:�%./�mt�@7�����������������nBp9��MtN��B���n���]pP����7�.�*-;���N�$�e/�#:�Q.#�����nEt���%~@g��9��T�";h����d�����&D�������������V8�����Y�:���.��iD�"���+2��YD'���>����Bp������Fq���}�4������E����C"=�s���C�����o��q%z ���#�L�B�vu��%��p*�
B��iP7�������:Es�%57	���G��� �&������I(�����]�Y�N*-*R�G <(�8=���#:��i�#z������?bi�#��
=����Q�G��b��Z��>2���s]��
l��O����B^�d�����-S����*��B�&��3��q�U`�'�^����Lp��Km�C��
(���V�n����x���W���L��L�e|�3�o:k��>^(bEC���W���$GpO���]:����S���X�v� �L@�9�����7t�v!�L����.��Z!�2�o��&mg>��O�nBp��n[�u`;<�B;j�?+�`@�.�Uc$����}�A�J�Ex*�eD�#���+��?e��I�,������/a��p��V0�g��d&y+�t2�n�h���N%��� Jh���[�6�J>�V���h&�p	K��2�o����n"V��Wa���f���n�*d���J�e�L`��,���r�d�������������w�}1����m��'���]o������9���w�_��.3��R�x�l�3���"a>M�RZ����� ����='�\�����?b���b���D�x'��=HJ9Y���1�Z�X��1��	���V����	�&�`�=uD"�}O3��L�.f��(I> ��c��dp�	n��M�b��,���LB�)X�6SY������	����`��,��G�������l��?s�4-L�;�3Ab��l�(1yA�=����� ���t��n��IY@�6���a���U\Nvjm5���+z��j����d�e���N��&Qv���<�6��6|����Ru���lEOk��$; )\Nv�'g:l%����o:Et�D�T$�#��������o��s�e��V�&��������������%���Gv���-�eg�-�z��i�3@�"�o���fAt�^�^�]?Mv�At|cCy�Y�Q,����^�~R��[����G�-���]z\�"��9�����/���L��.n'F@#Pa��b]�8���w���[��n���W"�a�����fC��(0��RZL����6�_J�S�l��I��{�:d#�#8�)�S!8����m%r�w��s���CAAx`������;��k�Y������q���4-�y�h���<H���y��	����
L�7N6�d��!y�6�������qE�����I$���{�[��������F��R�!��E��/H���/�@�����P0�/�@���3%"��HEh��QC���#�L�>�M���@t�\�MS�\�j�����D���g�����X��[B�����b���HEp���'�'�HU��g��&�H%$���T���7��.����Tr��D���:D*D�A�"$s�7�"8|D�H����Lq�:����O���R>���?i������(�	-��#:��� ;��#����Z6��R�|~2����(t�[^�M�����I��QZ�<d_�:���X�Ev��.'���D7#:�T^v}��2�������a&�o#;|���6V�e�Gv+��_2Q�Yd�3.'���D�/�0ATl���2����@�d�#:�F�Ev#�(��e�}�����eB4I�yd�7�(T��V-2���}�(_d����6�E2b���1��JI2�3D������A��y�4�_��p����������$DsJ�NU�8e�K�Ex*� @7@.�������(A�j��|��%��
���8J��%�o���XS�BM����:D��F,����W)A�j~�2��5����kFdWe������4}r��w<��&�����%�k���1N	�L��������J�u~��N	z���G,��5��>28���PHH���h��zaF�0'T�6�� g������?n�P������X�lK���r��u�5������>�Vp���?o�(�hBk�Y1�D%��a�S�������Hp���'��Ih-n����=�x�"� :��	n��J�b-���=���xg
���	n-���+��2�e6?9��P��io��K&
KO	r�J��+�q��>K���J�'3Q�/q�=x������++d����":��P^vu\Nv�)7�nFt<�a�_�Gtx%N�A��Cv3��Wx�_�GtP�$�����fFt����mv����d�F�I���n���"�?w��?I���)7�nEt�Z�������.;���o���Q�yd�/�*Pn|v�
�C�t�_2Q�Yd��@���.;���K&�����
o�M��x5*��v������v�Qv�
������l�.��?����tt�W�H�zF7�&Z��T/�L��:�	1����}�$��,%�8�?b��/�s\�������<����,]�-B��U#���h^�^.����kj���!.h���|JT�����<ac�N����`��}���b
�Ba��;:��-�������~]������Q��[`�9Y4������l{r��w<������~y��</{�yy�����~��X�#��E��h���<�w�S��%�~�����g��� u�@��
y#)�o$���]3�!���I���E?���",s��]���
���m����EhELy�.�FBt��A���j�SS������S��f���]aFZq+���r��c3���<�����ob�p����{��vqKq�
�+�7a������43��� �K�9��g��%Z�l��0G(�h��Bph�P]c���_���T��\-/�[��8}y2�]q�"��}�92!:Hv�����������VAvp�\Nv�I-��":�~�����]��f;a!�/��&D���.w�<D�6���N���(;���/��������M����"���k���w�K\���|�,� �Kp_��3	�J��	/3�%D� :!�,/�� <~���B�,���y����1y'�5�y-!�
���Yy7�*\Nv�w����1�(�.0�Ap9��-p��d0j�n�&�U�����#*Ct�	�Z��>�}/'����}V!�SAx3fB����r�������x��������&3e>@��c6�����������������f���������H"5��� �|-�������8�q�N�t�xo�2U��� ����@�����S���~�Y&)�_w�E�aw���e��mi���"�u*T�\u7��&A*nq;&���ST���.����)PqCp��l�oV���;,F�i�A���^��"M������ "�o��
E)��gf��q(J>�b���v��E��!<���8�%���/��v�\��s\�����X�+�22�5}{y
�uN����58�F��h.Mx�l"{<�-�@����M�@t-v @����03����S�
�����3�1�C�����k�X�e��\D�cy�����bV��Vmey�����z���%_M8!N�Q���=S���nD�HX<�}�c��ctok�Xa$��b��,T��k-�/�C��G����(�@�>�]�4���1�1D��}�g����C�a��<�\��s�O��wc@�pX*�'�c������v�pfL�	!<�[7>����(�����m��3��`f�������lwa\u
�����:����vD'#(-����1�0�[�_�Ax7t���.'��,��#<�V�?�^�_�6����}��g������)�r<�[]�o����f:� vMW�I����
����������:��������4���\�J��d2�B2��
��l�=AP���'���wa8�B2��_��������6+qB��Z,�ka��3:�E��V��a�m�no�B2�[
Jo��o�i�&��s��VY4�� �����i���SHx[���
7���+$��<h���3+x�q�|��������o?�I��J����J�I�7���l��Of��Uh"<���I�����b+�8c���[���}����l��OyP.h�5(Ia~��6��a���K1h.+v!
c�J[�w��2�L�_����h.`m�P?����h'��i6�V��A�Lx�:�X��
 ;|TZ���H��su�4K���'����ouV]��
������:+��4�-]gM4d?"X!!'B��9�Cg������Sgt0���m�7u�[qb�Z�i��<��)�,��@�?����r�w���l��m�w�������#<���ga�g.�A��Hm��ns���mN��N��9w�nU��������z����:����� 0
���D�q�2�3D����H4N��:�;���0���:���@�)$�\���O�9���R���������T�W��"D������N��m�g���T��n�D.�}�$�]F�"p���%:�7��V��;��Sgx�A���|r�
)��4-
���i�q��i�����xL���(���Xg��Y-Sg�����0���Y	u��&���Y�R���ZmZS��\��8�������t�}|�����wO���������������n���_���������%-;�}����'t
��M�	�d����`H7�J7���1��\s��
|"}3W����FpP� �������������,� �-���y"Y{$Y#��}��
����c�\
?���������?�/������b��������.������iM�w�Q�h��2���=~���)}��[o*������?n���?o�EZ����R���,�N���jUj����,�&��Di�n`��=O��V�n�����m��>bE#i��B)^��*5�C=/l���2���
��a|r".�c�0��w�tBXv��5p=ZF��Op�X���y;)o�=��������5x�)��7����������N�� �t�w!:H�\�4p@����q�|*}d]��\�n�e�C��8�}������J�C��V�t���tHx9Q��N��3��� ���Y�f#��!���E�fc�7#< a^Nx�w; ��IKR��]0��Qx���n�'t�>mu��,���E2B��m�z���3!������_���@���,?C��2W�k5��N)�A����N����h��7��X1�B����4Y�@���v����\D~]�-d$	��jzCQ
�����Y4�9�0��;9��;S
Fx�%�h)������K��`R�������8���"qvs7��f)X��Jm����|*��k����Y1�K��������W��>/�}��:~4��g%��q�t���W�����������`}���ou�^��~�����/��]�5�_��L���Qd�B|�����BVT��������r��|#G@t+��{;�4�Q'��&4=��������t1|�o��t7�"�������[�Og�X��Y��=�8Aa��*��9�����+����|�5G>r��}5s���e��Q�'o�x�:�.s�%7�~u��$�	�<��	2�t�z�5O��!�I_�r{t��W�T;���������L%w��`�4�s�''U��i��9��}O��<}Qx���	�����MI_����vE�����i�{�O��t�`a\<�����k�E�	o�N��t�z'|PKBFNb�f9�+��9��q3��	�xOx��'|s����w�'�;:���p��y�j��/��=�0���;��M��'6����	WIE�9�;�8�����'�(�wNU;�s�������,�> 	\��'D��'|6��&�x���=�3N��/
O�xp�����z'��%�3��SO�~��N���$�nwD7�wx���	����E�	o��nj������3gqz�1�K��������A'fz�O�AE���`0�����"����k���vkp���f�����+�r��S����5��/>sO��|k�K��pG �
���<G�7�(��������������:C���A~��z�����D�h��;��>�;Z���C�[B�!Op,��zn�����l���O�����:����	��t/O�����0�ca������O���c��G��O�yKd�6 Sy
�IB��$)�����8�(�i�6����L�_��	�����5�� �'�	��.���>	��$d�����8(��D��q1�X�V����$�������XgO��?X�
���Q*�����#�mQ�{��oic�p�H��s�Z���0�#a��#6�c��B�����1��,a����U�y}��KT	����q�f�L����G���-��.�����CfJ��ps�Ft��]��=6���6b������#7��r����������\���
�M`����r97q*\I�������<�@.��E��a��r���=\�'�+����;<�B&G�O}�2�Lt�uf8@7�N�v������# ����9��\�+�s�����W���}��Zr���%r���c������7��������6a�|��g>�Q�i~]kL������oZ�����1���UNM{���i*��k)��bb�a�V{���o���N��c�0u2��������px.��?�k�>��}������d?#�����;d�99����~a?#�-�~9�8?�rk\��}����!za�Y��H���u���3��.�����i\��=8>8����(�y�vit�K�$�5�����'v?Q >K�J��i!�FBt=��J����q��@t������������i�g��!���O�7�����w?�6=Wc?��z����7�0M��Q!M��U25ts\CO�����-����
3��4r�n���|�p������r�oV������nE�C�e���;������7D�q�2��wp����#�`�k��F�o�Z3��.��&6SsG�alA�}�e��X>������n���8����s�����#��v#`���v�:">�����G�}���7p�h<��!���#�0{��#�8{P��NRo��G�������\���d���n@?w�)�E��%��c�C��,oZ���mq.���_20�y@����|���a��x$��m�x�H�p$v�)�H�m������t�����h��C���r��38��(�6�U�0�%���6�����o�4sUK��U�jDg��Pw�:�Fx���Kv�{r��b������ow���U�Q���UM{�[�;m�36gQ�;wU���o
sW'����x�L�G�+|���w�o^:�w�m!���2l���c��Cr��t���>~��v#|D���/��/m<�)��?������5���������B��+���0���Op������.�ga��[�������K���}<� ?�
���4�o����a�L��^%�����?b��U��
in�&YfiXz�{l���������t����z��9R�
��x�;X�-�S�g���0�\�J�5��'5�T��7D=)ix���Rd�}����F���nV�7����\�<s���Fg*|+o�����Ez����x�D���V�����m	L�3@�\����	��}���qw�	�E�6>OF���H�:������%��_q�Q�����G�
�"��7�b�/!=:;������	?�>W������%r'�=KfjG��.;���3���o�9\w��ndr�y�u����>���}��Li������y� �%�����T�����>��#^<��^��+{��z�,�
�o;<��
�3q\���
�
���F��_�6C1��-qi�>�p�"������x�g9��wk�y.����0�t�-w�L��������s��7���X�	��C�n�rL��z]��
l���o���k"��pt]�[��'}QX���0��&����.�{��(l�;���u���9>;!6@e��a�x]���Vd�.��hw|�����������6�l����,��M�����'|����R�D7�S1�<�S��C���"k=!�m�m�<!�N�����P}���2~���6�:Gz�}�'?q���.����z*�_}��EtP"���=���V|�����Gn��0���.xr��ua^�1���oUK�0���u��u����oK��H���]<~��[<?�t]�y��u��������2�I��xf@x����5\��O5�o��/��r\t9�}�f�a���b�,�r&�.�����M�c��5��E����y1��o�����W��F����5d;�Kb����j���C;F��ob��^�����!���C	�i2���N����
|��g��������u��j�oG�.���N{q-`A�c�������^��?`���������������|��PI�(��5�s��/:u�0A�I(�_�0�dN�.�����r��XZ�(WD�	��}Nj�@Wv`��a�*�������u����5��s�Glxd��G�4�:w2���0��8�51�G���7�-����fN9�A�y��9w�hp{tt������O����<�1�W�����V������1V��2:e	.���~�����w��?o8n��?����������gy����~���'�&����O?���?~�wB���t�5n�A]��W�t�Z�A���%�P��������a����t���#�����������o_�r��V�����lZ;���g��]u��Al�v�&=�y�R����g���}u�m�����I���e�����o�J����;���E�>a� �T���V}A�o���"�7D���cD
��68���gl��CI�;_Uu��:�S�G�o��
�15���tj�������W����<��B�k�:�y��~����xc(�Wg�$4�^����<g������''@s�t���ef���mZ'}������.��m;���h����X|d�����;:��
`�"�7:8����,��>\����]���`����;0���@��f{���C\D|���EB��;���T����7����=n����e��K8HC�����^���D9���C�K��%n>��:a$G��}m$���>�-���A$,;�=�-��n]w���|�;�	.7{��!�t�����>���m���w�'^�|�h�����IpTT��~t=o}}�����M�[�a�
��H����Mn�N<�����G�~��	Ov�SNx�y��%4?���;�A&��i7�g@7���?����[���p���^�DU=��nxOn8�.����m�w�^�xO=~a'�c�����&@7���f����2���6]�t
]�HhA�%��������e]�t/h���(��9���x�����'���P����^|x�U����;)O�W���nB<J&7�?��r�����{�\��;�A�@��=���-�=�m��=�����������m�wr�b��r2���o~�p����� ����H ���
hi>y�����nJ����}����LWW��R�Z���^�6�V���M_l��/���_
��5k�L;u2�(�r�6l����}2��e�l� �/TVT������Mp��I�|':�����~*�>z�������*����'s��Da�p,t��%�\q����t���P�t�t�������{88��mF�����=
9����5�PO�N�q��|�'<��A/]�������~<�S�twG�[���{�g(9�7sCj�K���73�!@1��������]����8�ty�#���..v�����Zq�=�+P����m��������9��)]���u�.��+��<����� aN�R����Zn�=�;�n��Rl�2�?�S	/s�O0*���m��������c�����Z�����o�d�-�����@��d��OZ�	\&}���GJ2�e��
����>�%����t�l�u`�m��O�P�ofL��x�@.���6g'�X\��Xz��t�c�#��4��	O|�(T�U~�s��S����,�+��O����cWN�t�x�[�t'�/uOw���������f��~<�]�t�G�[�<�|�{��(���8\�t���Ch_�[v�LK�}[t�{�-:rc�>�?�����>�0}�����4|��u�3��k�|���GH��[��,�����.�v�@������r[a5iCZF����=�l��qS�����Cn�e�9	��1<t�l"�x��
�{����~|�2��=�v<:���x���t�$~<�]�t���� :<B��!�������E�X_��:�%����'Z���Y�W>������������x��0�����	�v�S��R�7>����:193m��5��7�t�oX���]u���W&L_
�|z>�?��0��4��"yX��<%�xJ"��=r��y�S�`�G��3��>�Z���>�4�G����VR�6�����
���.F��
��o�m���d�4����>�9>�s�����\�P���yo�7�q[�%W�2g(����|�cS
�}Dr�4�#XO>X����V�_��
�S��������tp����_����o�����������Gs=?�I����5���@�O�b/�����p�h��M��{�3�������
�-w��I$�K�{�64�mao�_.������#+���F;�����)���0p��}C��7�o��6���oH����
h�,in�<����/(�#���������KoYO���'���(x����u����W����O�<�H ����I�C�Dt+��$>^
�b���x�L���q��2��|�]�|����IXV>�z�3?Ip<.�)����EZ�x<�V�|���,{x��
���?��kt5�pt�5�������9��!_��n�U}������}X�r�o�>���H������T��T���X�#�H0i�(��f��x�`��=����"�W�����@_����|��4��������]	��e�+�6#~"?�e�+X�=yjGw�������K�qI<����.2���O�t��<3;�_�9���$.+p���?���t:M:�2(V���#��p-�����N�e���X����pM��������f��x���]��^��cr��
�n���m���x�#�b���(<�����'R,|#.�4s����|��E:|\��%�xm���	'w�	�����
����k���l�}�����WY
�3�	�:�7��I!96�JR�o@�w2�o�K�Ja?l"������0����]2>����U��]�(�'������{�b[�"L�H���v�CD_s �#���s)����NPH�:�|�P��o����������� 6���K�x`.��Z�# oO_����#���T�%w��#0�~\E.��cqv���~��{�
���oUO%Gb�ew���
���+�F��/15��%���p
����`<���G��(���;��0r��.1^�_?����������/z�_����1T��k���3^��i{���w��W��AtP�$���%e@����}�C���\58�Eaz���t�D��
�7����#����`1�.7W��-�%����:v��9zN��\^my����	��Jq���y�S��E����]y	�m}���m{�����_57��t�R��.�/�9�q�_O�o���o���E�H}���EKv�F<���K����5��h�g��R]�xZ���T�R��K�r^���TuL
v���>b�?����,=H�9a�_�����L��#6>�&a��Y��>F4��i�C�� 3NDa�����	��f_l�lz�+=&z���6�����f^������F�4�p�����m�nB��a�`K��5i�:2�NNo������]��%���,~7�t�B3a}uR�KTi�7c�>��qc�����R:n��q�7�61��y��-�L�-x��-��?nc�:]h��%�1��c���V��
�Sn���}�_�]l�`?l�������{����-g
���`t���m�^,~��6�*�[��z��t��R_���+�6z����eO�����V �����gJr5�j�>�C�>�\C�����n�y`�������<��;*D|�������mH��70g!M��'�"��L�O!��P�vP
l ����&���8]�AW�
��W���!D~��6I��_�����;�@~CE��%�	�f����E~�op=���+�X�����,����h��z/p���n�[�T�����'8I�F���W�������a��,�Um��j�+�P����V#�'�+���#�*���B
���<�/� �����5�{a��m(�����W� ,����_�k�"~q(�h)�T�E<��	4�����3����/@F�+���1
C���|���
�u���F�(�
1
M�B�zn`�>���K�	�j}�'3��v��K�%��w�yNg'4�e��TB
0KD�*@��w�j]����w���
w�&�	���`BH�+@���&�L������;t\�}�pn�m�w���D#i��d����u�	^L����S8�F�i�%"I;���4�,|�;�n(�����8� ���H�9yi�-&��+�#������
�P�Q�VH!1��$x\ Q�����EpC	V�H�"F>&6�f�,g�BPLpC	VI��A�9	�e�� ��Xl4?m+�$�C+v|~���y�������A���;���iV���Q+v���E+n%+��,�I�C+n�V�*I�c�I��G�t�ku���U�I��E�|d,��2�A��}�J�fL�Ch��~&	xK��~��1��-��+I���X�����l��1	�5!�L~�tH2������Q�YB�����-s�)G$�v�x�12f���D%iB�zP4�f�8%*i��hs�s(�z��m�g���cB�U��~������
��b��
1
Y.�c�K��,L�t4�� �Nn=����c�o�;/��S�� �.Z8n�E'����;�p��;]	�h�}���E'7Hh��0�=�1�5�����q�����x��X��I�h�C���E'�x�E	�Vl$xy�xA�c4���On�6��'����,���M�w���ULn��=�Yq�j�m��m�^��6����%@tMxB��&\���	MxL�8���	 ��T<E�����\.��5������w��+%�j�����@��%M��X5��.�4�,
0�Ow#�w5�f^�A/��va)�n(����JPHo
��A;�=G���bDbg4�����P��a��V<��8C@���Q����9��V�|Y������K�G������~��o�b�o���7��_yd����\�'���������t��T����s������W1��`q���j4��D,}��iT�dP��j�f��.�n�A�����5E� F~�Y�P��
hx�:�+s�<��`_���t��p�A�3���*�pAC��A�I$L].h�K����]��!/�!'�0u
yEC^��\1��V4�U2��:������!W�����%CN(����>��y7a�������f
g����~7���s������	m��e	��q+����C	
V,mw�r�
�W	o(���I�@j�@3}��M��E	FS3}����n�;hF�����bg�A�/�����;hF�������pC	V�Kzh���f$����I���pC	VKz7�����!���b6�
%X1*��%�7��IZl����bP�w�
&��"��	v�I�C���� L���3	�:e	�(��,��bP��=J��j��-�7tH��Cj%�����^sX��$8`�I���"$����x�~lP���P3&�utw��f�+KR}����X3&�%(����Jk�7�`�����
�5_,��P�5c�	�=}P��*A���P�5c��������4�4	�������fL��-�I����#u��S���1	R��E�Kl������[: Q�k�$+Z��05��4	�h�k��k�$+f�W��K�$X�%��k�$ZqP���lh�[��k�$;f�7����$;�Z����fL�cXK]<&�KpC	V�I���CP�}�`�A�70�k�P�c�S�As,����j�C|2���0����`��d�Z�K�+�$��,�Td%��$Jj�7�`��dpJPX��B�Q� �b	n(��1��Bx*��g���KpC	V�I���CP�}�`��n�Z,�
%X1&:��
AE����<j������������:_1&z��ku	�zTg�=^�}�Tg��1��C��Psg��G=�-�Gku���P�#��w�^�C�Xg��Q�h�D.������1��c��a���<
}9��S���G��k�%
�K�\�'�h��1����dQ��!.y��	nD�5#�A�9��3���0���7���xF��Q�"�� �������P{���5TQ�X�%���
p��:(�~;� k�x�����&;�h�AM�h���Y��	����aE+(�K���.K�/�\P ��L�lM�5-��&M\P}��Gv�����*pGZdK/���A�/�<�"���'��/L[���'�p�aMnQZ?Y8K=b���5�2��4������+�n`��"��+�"�u�Q`�(��J���;������vE��Mq�U��Y7�`�hdtxU;�����D��8Z7�`�pdl�����'Q�`�V����b<2���I�0�h�9c|G�����#gw�HF\�3�W������(Aa�FJ���{�����
S3$��E�9	����C	FgU��1��(�I�tL2K������1��"Fa�l��U	�xK�Q����h���D�tL�����B��1�.:�f$���Ip��
%X3&�%9c�~�Q��+$#.^�Krl��������20EU���;�7���1��wu���(��5�qF�z�z��fL��]=uW��5.��X�)j[3&Y��^�uW�J2�/�����IV��W!.�J�IV�Q�����lxW�B��+�l�����-W3&������VW:&�1G�Es��fL�=���`��d�u��K�����]�Q���o��EpC	V�I|�"F��5>��k�����xw5��$X���87�`���[���X8&�x[7�`����1
���g�q�����x�w��[Ca��;�� ��+�$����	���`=M7�`����xW�BKSq	v��DpCu���wxWwBG�X8G�q�3�
%X1&��a�����,�Qc�����5c��j��x,�Q0'�����xW����gp�97�`��g>�w���>|0��$X3&���i�0w��0������x��Q�������i������I&|�=o�V����'|���[\3&��-������`���O���fL2�G=oq_���g����2��1��V<uB���JpA+^�V���I��E��q(�^��W4�%j�]��dE#^#NH���D	��q#��l��Z#>�u������mu5#l-&�/O.������;���	n��RkqXY�xE���v�	>{i�nX��p��_��UH&l.�����%���S�����L8�y���H��V<���)�|���L�!F�~�'����d��Cp�!����@s��c���C	FI�}��dr�
A�9�89�,A��]����Lm��[!z�%�il��n�
M}��dj!L��L8���Z�`t,_1$�p�3�f����D	B���z&`c�	����`�3�C��b��KE	��g�����$�/���)��|7�����@soqi	�
J0��k�$#d	4c�	u:]+�B,�
%X3&�%�g��/	b	n87�fL�!=8��	&��t%��X�J�fL2a�((��\W�*�����F���fP2[�(���8-���X�J�fP2C7��cyG�������&j%��"t�(>��D+^�V\3(Y����S��Z1�b	n(��A	��NAA���;��w?��7L�	&��P� :[[��s����J��R�� �y&��k�$;�r�a�G0����+ln����+�+�$sC4s����o�������!F~�B_x���m��6`��d6P�����sU�h-
0Zn+�#�E�|�=%��z-����p�pdv�����=��W$���g�J�b82c5vF=?J����}�[4��K���X�%���be	��5uX�`�pd�j,�f�
	��Ty[s��tP�%	VGf��h�?���`��tP�%	V�G�83�]�`��t�����������	��T������������V<C������x�Z������ �����igpf#�
%X3$�h�#?��&����A�V��V\3&��|#��K��8������Lh����G	��q�3�
%X3&�;��d����}�9Q$��1��V<��� AE�`�\������I��hF�	�i�R�����D���fL��/<�&$�u���V�F��45��
����K�
��
��w��J6��
}�������c��K�E(ri������G�����,
�*u�<u��8�7"�����,R�����@�.z
oD�C��?�Ps2,��,���7"����b
��U��6�������FdX1<Y�� ��3)�
te���"�������|�)1U1:���[b�*��*</���s���[���0.��DW�-P7�9�FY�xc�|�M��,@���p\Evx]���<���
�����#+*
����<������!D&�a]M�5��x\2Q �7$W ��.���Gfq-�������5��� d�6��
p�d5�
S��uc�`q�A�i�W���4����j�Uc=\���f��k��f���j���]�M�� ���j�!����(�M��"���jF!3^���*����$���2!�w���q������O?�����n��������������~���~&�����������gj���K��������L���~�0���#o���i�u2(��9��~�~�x���/T=q�Y!����U��VX@��-�d�3d��`R	�b�����b��4�c���k0��>���q\�*
�o���4	.h���������Fg�A�6�4	�%�*c*�m�
]��u����u�;z����#�u�(A~E�~]�3��Tq�J�b����q���(��^q��_4n+Fo��*-o
��}�7�`��mkZ� ���9�Z
����P��H[�#F����%�����
%X1"��`4'���DY���!��+�$�m��Aw���� + ��+�$������zu%������x[1&�������/�_�����l-��N�f/���0�������1���]�
 ��$DL7�`��d��:�K��lx�[0��$X1&�pf�f$����+��8�V@�����������|���[�j�$�<!�o#A���	I�fL2�(A��N���JpD_k����fL���	t~	���#�`�7I�fL��[D�9+Nh%N���(B��}�^�j%����E����f<���fP2azk���gt��hz������IP��������
H�5���x���\�����5���E����<�V��c�D��fP��c�
��bz+���������lJPz���8�`�mxKoQ�~[3(����@sV\x����-�Gn��A��(����{Pup���-����*%;, ���G�/��@G�L* 	V�IvW@�����
��{0��$X1&�qX���bM� X�L) �r��d�Q���qL�+A���( 	V�IvT@���X�$��-���$��1��C
4�Q����� ���	H�c��E+v|��1z�Kil����W�I���V�bE	�Yq�oq}���1���[�Ioqi�S�����!����	4w
 ���������/��j�p����	m(����q0������G��P�5��M8p� ��-u;N( ������G&<��+�#
m(����GF<P/��f�8������Lh���������6`�X;w�`�����q�����k�"�����&y�UG��t��K��,h��h�.q���7���������pW:�[�^��p�Hd�Wx�_��t(��+��_�,�H�n�����0b��@�:������EQ���H�=^%��E#7��\�;�WG��3�3{��6*X/�a��q���	�G4���e�L`�h���!F��)a������F; �z��
��������hC��FnG��8�zDY�+hw�v1
��gv��7����l����GW����$��w~�}BBA��
��{t��P/�a|f��A��3l��	m(�z����E�<m��3l
���6`���
����&a���6Dg-���7a�`�Z��	47g�8��{
Z��	n ��b4b�C��T�^�)NIM���7MpC	VG�C3v�7�$���l��]������m�)n+N��*K��6����(A�-Nh��;���h�X1"������l~��o�.��8VIl�V�~8�L2��8��{4�>n�5#������%���6�xH�5#X7r��p���#�K�u#c���<w��%�vG���G����P�Bb�}�7txG�h����H<Z�����Ag'�b_T3"�&��$Yq�������p_3"������y���Nsv�
Zq��!	��H�$~���W���vt��(����H��`����vm�/q3���h���������v��v����fP����k����+�

y�r��d�A��d���������K_���������S=h3�Z$��P�C�o�V����������W�������nr��f���yIwa���6���=tE�v�{N�����3n����CWS�h����Ra�)���7��+F'�y.B��0�E�=�;��nD����AC��DW�S��j�;��+�']�W'�vI({����=7"���Ig�������FO���E�Lp#"��t�E��!'>�E���������w9�������8y[N(�(KY>78���]:������ @�'9�=q�[�@��|]�h��R�X��h�m|�mM�	��	k
0�vh�m����3���1�xN���|;|���c|���`�&��O�S|��N`�&�GM��/�,@��{����)��=�>��(�Mx�i�
Wip@�|.��+��C�	�t�M�7p�b��z�9�bU Z�������q\����k]L�@f��A3<�a��@�.V|V���Lh�������8�	Oq���P2&���vgt��h���Df4�Y('��%�6<�m�f$��
��#�BW��7�������"�>�����JS3Y���V��� ����.�f0���NX���G�z�a��cj�5���tB�8a������V��a���RL�	��nuX)���b[1 �a��4#��B������7�`����\:���_�R^��y7�`���7H� =�A�����6(�%*��1Io{�hq��cGDq	���������"��A��D�4	:�b���1I�f��[q�3�B�������-���m$�oq�+�$}�wu���m�����.w��+�$}�V,�tI��|{��.j��bL��h�=o�	!�%�V�G����I��^�����V<D����I��A���������IF��G��c�D	�G=F=jW3&�%x�����|���'�P�5C��=^�,�����K�hC��H&K�_n��=�&=&�K������SE�8 ��<�F53&	43gAmfT�\,�/:���FK�����C��Fy��4]3��]���*r.�� ����������b{a�I)t������#D�����
�6�p�����f<��(B�3��)���NxC�Hv(��� T����(�h����X�%�/7@�����oCP��g;*
�t��'�
�mx0pK�P�#��B��@3,=�b�f]�J�bH2X4��e�A��;9l�%��+%c��]�A������J��a��bT2`1�@3T��v�Uw��$��A��Bxv�H0��;J0:����Zq�-����u	n(��!����!h��)A���2�}�ZM	�[��>H0���,A|��2,I�fH��X��X������$��1	c	4#����V�aI�5c��x��x,�Q�h�c��k�$��Q���/��������1��V���x,�QOh�S|{��dB�z���G=�G=E=��fL2�O�G=�q4�h�s����1	��'��?x��V� ���c���1	���������g<���}�����T��)V�<����5��/ki*�qP�J6(4�P�5c�
��Mh�..@��P�B��~��1b��@�������w��������?���������3���}�_��_?���?��������~��/����W�!�1����>Y�6�r����CP�������w�.=�Bw���'n\�EF����!��9��o*NXy����m(�����
�~��kT@��C	���W��F��hF�	�s�����F�OH�#8�$�z���
�A}@?!	V��|�!F���k#���+&��+Fp�����`�{VLpC	V���mQ��'p��h�6n�8�,�H0!��+A�������G������[:����%�v(A~0��[�&��07�`���w�M%����4	v��P�c�AM�@��[��(�hMd��x@���-F���k�$4�za@��d���
%X3&���@���%�5��IFh5%��j��Lj�#{ ��k�$��q����n��0������x�6%��%��Y�J�L�����q��L��
{������1��V,�J/p�3Z����1�� F��5;��$���5G�z�5c������IOH{I|���[�k�$+Z����.������h�k��}��dE+^y+N�����lh�k��}��d��x��8eH���-��o����%���6%A���p�kz�N��5�,�h.0N��TE85����$��Q��@��@s�0�*T!$�	o(��a��C��(�x
�
��J�L���bX2�P�I
`�c;�� ��C|��d�	��0�J��HpG	F��bX2�%�'��p�U�J0)�:9H��@����L-��������B�y�S�~�a��dj�q%�����p:;����bd2u��N���Gz9�xv�a��d�-��O0�����"�!�@p#"��L=d�	u~&�h�����~��MH1jF���O�,B���h��45C�
9��>�_M(�NA�pF;����fp2�%���,�L!i'�������|��)):U)z����y��'��!!Lx��x������P����t7M�X�%���y5��)�SP�}��O����	n88��g`�O���G.��d�Y��7�QQ�K����Fq�A�qX;�
��j
��S0���&�>u� Nk���{*kW� �������G�tx�������s�V]n���fW�qT;�
s�%�c�?�^���{��Jj���aC�������v�J�b@2���)���xK��3�j����M��d�����8����X���8{�/�6C�g�����t��������lS1&�-d�gaqvW�_{���'��+�$�3�QH��	����.KxCV�Jf�fTg�j�S������W�I����!���J�qR;�
X1&�;��`^{�w$�vh�]��+�$s�&��&�������������=������4�������I�*K�	��5����{'��� �q4#����y�xi���m��d�:�f$�����o�1Zt�5#oQ�|��W|I����[�Gi��fD���C�	*�$i�,J0���5�	*9��`��dF�
%X3$�J������ 5��� ��k�$3�rt~	����C	F'���1��v�H�xT��-�D���fL��X��%I� .�����]��d��0�6a��j[�����FI3�fL��o<k�&�4H�`������g�I\�|x\�3O a����/+�a�����><
C���i�:7
��8h�����Z����t����{w���U�vY!����t�*q���z�5�v� CxCV����'��w@$�0���R]��{a�0n�|��0���{
w��.A�=��b�6h��P�l\����$��B!��+rk� F���i"4`��7a�Hn5�bhN�	����E&�!�<K(�������$�� F�ENI'����E�E��7H�C)V�6�
no0���4�����-�l+�s{�!F�7�)��3��8�J�b�i�{f�<H0��V=�;Ns����$X1:������.L��u��+����>��m��8���=���7�`��dwh��'������C+vq+������V�2JTY�h�.n�#�G�hF�	���[|��Y.$�����+6t\�	��U�;n���6���7l��������3*v\���lt#��Gl(
0��h�}������q/�p�A3����}������&<��p��{�8�	q����L�	'��u8�/=F}��f4�!�E�{��C�v����������5�fx����	/hMPw5c�	*M�`����u&B
�f(��54#������=�X����@
%������Qud�"�N��+�H����a�c+O�HR�����������L���4'�cS�����=��w���E$7H3b�����NW�s�
n�;���0���x��qP�,�	�;G]��^L���A�����%9�\:��
��zA�
�����sxY	���%������xW/���c�&U�)^�
��]����^X��
�8���R'+x��n���oq#��� �SL{��h����K��_�za�
c��U<�;^�{��5�+���q�Q`R>��y���hCV�Gl���s��9vdTO�5m�*�#�x��p���<7,+�D�o�����1JSk��]	��k�]tC�h�Z�a�w����`�S���uh�6n���[�t�
�z�p�	th�.n�c��
;��G�g8��h�m��+�"��@��`��%&��9`��}���M�������M���p�P��-
P0��'�A�}tv�X3���{~x|�HW��p5��f(2�	�	��4�!j�c�Pd�WxLX/�K����}�����������	T#]zt���#=f�D\�����F����,�_����Y
����P+�F)<�yf���y��0�8�'�k��9���Y
�G���B�
�\���=��k~-�9��������I��3��t��BhCV��N��/����vC�LPN�.UENh�^���2�Bs��
��7������'a_FW\�3�5d_1�s3�,���yFC����+qnAC�C��]e.h�K��}�0�c|`|+CF�	�
EX1�s��y�`[8��6����W�+����f��^u{��U q0���IPQ�;��o��1�WW�;�����{'AM�[��oq��<�����%�������'N%���
���_w��+�$-�O�`������i40���+F$-�Ot\�]�tjk-
0:h�4��'��M�1�]@���.��I��B���pU�uh���[���W�����
�5�`��3M���m�1&���8Z�"����������^���fx��	mD�c��C;��&��Qq��w�WJ������tX��h�=c�5�����XO�iV<�h����o�����5G��`�!�!�%��8�!QC>�����(��M�xD�: �P3FE�!�03��a
^U�}���s�����/��K`�Oh�>j��\]Nh�o�)+�tO��&<EM��'�+�MxL8a���g4�9j��e�	��	'L��5�M8>P�\zUW���0O&eP������	�K��
pu(@��XG�&�b��F�_�����1A����)s�u������P��D6 ��������������`M�XdG+��U�)��t%���q+���h�;o�)��U��k����WG���@3,�t
X1�
%X1��C	
V\:��Z7�`���3b�{o��X���B�DxCVI:�fl�6v�(�$�"D;�q;��t�!F��M������sLxCVK:�W@�9*�%i�I�q�*��t���k��[����L�
�����t>��`�	�w������E_d[12�:|�;�E6�C��������bh�����P16I!r0��DX36����bp�&�_�`h��fp��4'B��$�9�E��kF'#�(1��D�!�qC��x|�G���G'_d�kF'_d/�����	_d�kF'�$����&���<E
���Nf|�'����4��"�����Nf|�g�EN`T+?'��s�Ev5��
y^�F������!��NV|���m��d�y����ft����
/�-�l�"�����N��L�9��`
����]��k��PC6�x���]���jF'XD��"��������:^Ev�������@s",��8����"����E�x_?��tt���	o�����fC��V�INO�{W5�
EX1:�-������_���{���bt�;4�`�}&��B�����\1:��"t�!�v�{yOxCV�N�
9�|�(�����ECn��\1:��E(r���c�	o(���I����>�~� �����"L�����{���bt��0����?�0a2��)����q��}�PE������C����X�H`C��Mp4�f�w�V��u�G���!��!C5�4#�c�P��xG���f]������@�cP�z4a5��fP2�LB����8u �):����Lh���_��{'4�)n�5�<N��0����>�x������^Z<^��q�x�;��Fp�x/�/-@4�����f(���{i��q�$U�i�n��[����n����	�mS%��r����}|�xW3�����v<a���q�x�������^�;��t�G?����}�`dhJPX<����I��n(�������
�z�N��cP�8\�>���
�*��E&e	�8B�J�b<2`W/�~�@�k�� 
A?�}<SM	o�@�^Qu�gQ�Q�L_1"�	4�P��F������v�If#��u(@~RBH�*�����	m(�����
��xl��'�>�P���:�L>��@��Lh�Yz���G�?g`�	����6`�p�*��~~�qD�{���(}��h��Bw�O �{&��k#�||�>?�8��{q��_>>��Ep�� ,wz&�vq��_>>�E<p��`����iF�'�����E��Lh�]�,L;�8������L�=����82�'�v	m(�����&���Z��{�i�����,-
�7�����	��]Bp��,h�A����L8���gB
�f$��|�>?�8'�{�]�����lh�A�n��@l�%��kF"����c�A����;�X[�md���h�;�6�PV�=�;��7�����_w��:�TO���m��$����h�����r�'p4@�!��+F"���f���O;��AF2c�H���C�?0�	h��O?�����n����������O?���?��g����/��������?����?������u������H ��y�|�QY���a��y��4w���6������#W1v���O��-�A��������b���������m�z����;�}���c��:���t��� 6��x����yl��B�w��R>�����}��b�����}���c�|������}���c����5%�v������}��c����"`�3�M�>���+Fp�C+��"8�3��wq+���zY��!���������$X�����=�S+:����V<���fH2@C�~9$Q>�#�ZCtr�ij%#������a�!������fT�;�`��>u�)��myL��EX3,�h���/���eNh��1��q���<��<*z4�"DC�C���� �wi�|Bp#"����W$�*�4i"\����~�ij�&^��X��/rR��_0<^���ij�&+����^�EN�����!������.�SR�t����*����#Qop��5�����:����Z���z���;���Jp�P��X��[Z�;:]{|2^=	N���0sT���$850�a
v{S-�����0sTt��$hJ;[(��(A\�M�9	*z���.�)��M�����,a�$��X�I�B�f�]�)Ap\	3#��Fve	:��v0����J���J�9	�.�L����F"��"l[���t����I�p�7�
X1&�ZpY�`�����XW��������Lx�S���A��6�,@��P�#���P�|�Pu\|�{��P�5C��������,��uY���fL2L����m>��o�!�X05c��C	�����Y�bY�����x4��8���I������I<Z����8��k������fL2��2V�&A���0E]3$���i
*��<&U�Z����mf�5c�yF�|3����#wF7.���CxC��J�E�O�6C�S�Z7����hO����h����z
�D��!�qC���h��`�cB\�k�X�%��k�%rP��d�i"��,�
EX30�a��TeOa��X]C��,�
EX32�g��~��K��pn0p��
��bh2��������� ��`+�&3	��!)I.]	���9>%�UMf3#F�=�	���9&��+�&�����	��h>�������"�����J�pNa��N�C;vq;�����	~u�nIm�!��!WM�
�I���m\��[4�6n�C��CCn%CNp
uE��!wqC������a��q]C�a��vC��G����jk���S���	o(����`P����&��)�M��7a��d@C6z?���]���	oH����@\�����"T�E�>�]R���N�A�K�l�^
eC�xU�����ft���o������|
q�7�
EX3:�`��l�~\p��%���	7��kF'�E�}�(��l��g���h�I[3:����@3"������^�s�����,��@�&�ER>�^�Kt�d[3:Y-��_8iF+����5�q����h�+�q�&��R>��7�����b�aq�z�v1��,��Nv�"�N&�R6���=�/���N�1
;�F#����q/�x���,
��	4'��~��@�	�
EX1:Y�NK��~aR��b��d	J�$�������	t\�C�[�ZFN;�x���<I�bp�XH&h��������bp��E��l
DW����7a����������!cl!�O�	#�<��w����i������Zz`N5����W,��X�C�Z�HDO��a����r��@���:����U�V~ ��[nJ0bU%�,J0�V��V�N�	&�"�L�EV�t'`���u�QX@���Y��im!�#��+Fs+�u'���Z���`gQ���}�`n���;~��M��,A��.n�c��G+�$+>�u��G+��V\1�[{��^���*����>n�C���hN�������
���������!��;UI�#^��@wa�2�:Bg9��@KW�[�CF���5��U}���,BH��P�5���C
�|Rh���<Aj���S	k�%3�V	�Z��q�;�
EX30��k0��$-]�Wq��k|z�P32Y:�(4G$��VN�,xU/����fh��4'B�,W�)��k|z�P36���4= a���)��k|z�P38���4= a���qz��0��Npz�*MH���l�8=`�OjF'8=`��$,��=�[c^�9b��l
0�4w
S��"�
EX1:��C
��?'��l!�
D8V�N6�B�.����[���bt�YHnA�6�s�(B��P���
WnoA���s���-�s{��l�s{vn�>!��+B\����n���
;�7a��Ii�P!���9�DX1:��C�@s"LHv����|�4��+F'v�hN�����|��C�p��I�����4�.p&x[���i��ft���aiB�6�U4����U!v�hN���I�G4��9�>v��'�(r�k��7a����!��s�.��k��7a��;���P{���|
�F���$���	v�oA��d���)��4��kF'����������k�[��O"��`��j���w�v
q��4��kF'���1����Ksj���1#L"����^������l+�` ��kF'��W~�95i��-;�7a��d[#���2������7��`���������i�0��xS���i*F'{������e��"��c�a��d�����a�U�j�;n�����MS1:�q��.��NX��-B0�=�z�4���o���m����!������MS1:�q��.l�N	�u�B\����o��bt�c�v�o������h�x�i*F';jw��6�gBW�-��A������w9��b�+E��pF��~M�;���*-e�*
+���`q����:���-]Q�X�%�L��S�2�='=����DK��)�!"q�Q�����ue���ht%8�<���&�}@�6|������f�*�=����F���h�y3�D�hmJ��7	��o���������_������ v���������y�dlc���������l�l��O?�����?�����������?����?����������������g������~P@��
Zi��]��zh��;��3�+��~P��x
,�f�+����9���|�l���<>�����8���h.�o�II�C��|����������o��O�!�����i�d"d�1�_���S|����o��[���d0�:��:���G������Y��@�jv�Z�}������e�+y,E��f��L�9��d��U���}Fl�&��?�f����	��������������$�fo�z�d����L��T�r\z,�+�m|�66!��'y4��)Rw�/�K�4�O����c���l��[8�4�>��Yh{��})����nF����G����W��<��[������
���#%OM�D��
��<�x�*�V�Q���[�B1���qG�B/�����B�������G��m���
�)wB�2-���\��
�&>s/\*y����hC��H�%*wq1X�8o���.�[���p��Q����Dh����R>w�������5.��$]+y��un�6��j���1����<���On�Co�Z�����=��g�%��A���E-+�v-�\���=}�dQ�1���P���R�NQ�Y�Si�k��xG{�Z��\�\��X/5eZ��	3#?��T���������G�-x+& ��q�Sn�"Da�d�����X@hO_+y����BhC���O�a@���i��T�r�6��k%�r��E�^��x4�QXk_8Ce`p���k%�r=z+��
�^��L3B��6��	������G�3z+S�j`�e��e��
C(����EvQ8Cet��h����P��c�h����
��U��SX�z+[�����P�}D�������c��t��*���z����)�x93#���)]�w����<�5+�����^��b�03�+L����������G��\,w����\�Oz����0{���Zi1i����sm���$afX��3T��8�I��k%�r�	����z*�I �|v
M�ky���
�@I�J����XO����\q�
Z�R��d�\q.�=}��Q�Go�G�\W/Ce1	D��N�����
$����<������q������"�gg
e���6�$P���G�+z+K� ��e�,��c>;�(��nm����<���[�0�x����*A����Z�*�z]��44�p��5���k����u�G���R8I�����%�n����hNe�uu�]j�_a��-Ww��/�<�u�E�y�J.�������x����
'��	�J�v���k]������ ����n{�����J������>�Z����"B�]�'
f����=}�����<������[��1�e~�a�;�C�AhO_*yt;����e�S�e]���OO��NO����o�.�<���S��������]fD��+ma��[0�Xxr�p�����N�%�����U�����E��0�mgl|�-�*y�����E��zsu��o�wX�����A�����Z������Gh/���*���af�W85����;���J����;��������O,!x�_a�T�������k%�r����bo��r�!
Ana�T�A�KhO_+y��A�Kh/���*@����W8;����A(�Z����Ap�&�z��3@��Qna�T;9�
2@I�J�����Qr���\]��!�>KW�?�z�s	��k%�r'�V|<����j1D��NP�3FA(�Z���]�9���P��"���
����� 	�t��Q����o���j�!
#����
���o��<���[��M`�2T���cf�W8C�5mt�J��k%�r�fFp���zsu��(����A�Y�6:a	�p��Q�o��^���U�����fO}���9�'\+y��ve�����Un� D�g)���:�6��k%�r;�����s������8:�p��e����
B{�Z����B{�7WW�#��3����n�h����V�(wDoe�������*����Y���n�h����V�(wBW~�����*wF����A���J��g�6fa�L�U���2����e���q���_aU�b��
��
g����5��;�����mF�����PuF_8��<��������s������$�����}}#'� 	�t�dQn���#�{su�k����}aUo�8��k%�r�Gph/��:Uc"�p32,�����}�J�Z�(�u.���-��2#��=~}�>�%�,yt�A�Kh������_!��YT��.�=}�����
������[�dF��ST��nd��.�<��
����r����$Aft���J��' ��A(�R���	=�)J�;�Z���<#B�]
S����Y��Z8A�/����0�TfYW��"���
���c� �t�����N����J,��3@�_��~�0#�%]*yt����G�q���������P�?54f���J�� �(9�\o��r-��	3#�����B�AhO�*y�k�U!�{su���(8,z���e�CyQB{�Z����xB{�7WW���F���O

�CM�V�(��\|�j����}j�9.��0j`�� t�	�J����������>5��(�prj!��5�Z��\�\���^vj�>5��(�pvj��b0j���G���S���^zj�W�������a�hc�K���G�z+K���^~j�>5����p���B�`:��k%�r7t��xW}���9�03�+��v�����J�����Qr���\U��Ah�}��p�j4���A(�Z����@�Kh/���*�@���_a��h!��$PE���E��s����m�8���P�-�������G�8}��^���Un7#D�Z.L�;�X���J���qB{�7WW���!��0{j�d5I��k%�rq�8�������qC�|(���=����k%�r�����������$af����J��	JVc�J�V�('�������]`��(�!��;���9���J�.��/8����\]�b�03�+��W�6�$P���G�z+k|�j���c(��>�/L�w�v>��<���dEh/���*�c�af�W8C�
T����&\+Y��
x+��bo��r�O�03�+���V�z�;M�V�(�Y_�Z/C��G�03�S�P�]���h��i���G�-x+��bo��r�I�03�+���=�F���&\+y����Bhzs[Uc���������!�����%��pY���\]���~�i
��"�=}��Q�G��GG���/�*{�2���D*?A���>5�^���2��Z��v(pdN~��T~&�=�����N�"w*����uE���b��T*�O����Y�hw�)����������|k��\*�C�����Y�hwj���Xu>��������A�9�F5��	���%�v
�=�{�OWW�vA�<��4�sU������Y�h�K��^����n�#B�����W�v��Dp��,y���a
�J/������3'����	9K���&]-y��Ca
�J/t���;�3#@S�R5
PG���5�n����"�h!�\���z�w�0s�-�����4	mk����m	(K/t���wB����b�hUIT�	�K����G�3z�i���]]�bJ�0s�-���(�MAJ(������At���z�	sB��`����A�m
rBiwK�n��o����RV&�3'��)�i�J�$����,��������Y�"s��	�p�j6����wK����������B��p�jv�0%����<�u��������mG�(9/zM�i�m��Fp��-y��D_�Z/k5�h����Z�=�����G�=�-�b��z�!
��-���G�(��wK���������^]��!
��-�
8{=���%�z=�->���^�j�v�(8/V/k�f�3����%�zg�[�hI�\��z����Z������-y�����`��B'��z7��Up^l����a��	,:�n���
��-���^�j�W�(8/�p�ji�>v�� �-Y��4p���n^U�.fD�B�k7.�^��.������zY��B���^�*� �8�{� /��t�Q/.'�;zu���Q��g��������G���bO��z�!
��-��Z0/Dp��-y��CP�)��zu�;6Q�,]���2��
�{�n����#����s}����B"KW�k�`^����[��wr�SB/v�v�*��F&!�tj���sC����G�3�.AZ�|k��v�

��+��ZV`����K�����H4=�����mD����
�Z03Dp��,y����� )t��WU�k��!L3��u��ym � ��o�,�]p\���^]��
��+��Z
�����G��t�Zo��v��� s�+L�Z0�V��M�Y�h�m�.��;�q��n�#B�o)��Z;h�!��o�<���g!��z{u���ut��R8e��s��7K�PO ��z{u�;B9� 3�kg���	����G�#�,c|U��|��z����-��Z'H��w1�	��)���\o��zg�:&�si���ht�]�wF�e�w��KW�k���-��ZW;V~���Q��n�Ew��WW���F�9��Y��Rs�p��Q��~�_�Z/a�5�~�����Ym
��=�dQ��l�.�>V/c��!
Qo[8c�Y�z	���%�z-�����^]��!
4��p�js����wK���Eit�z{u����A�9�Ym������G�����qo�����}tR�[8i�
���wK���������{�(8/�Z�*Q�#������G�����^���U����>��Ym�d"����<���o	L/����w�Qp^��Y�m��1�{�n�����9�>V/k��h���t��V����*���%�zW�[�x�X�����}�����Zm;��0�E�[��wG�e�Na?���������t�iV{
����E�{~������^� D�y�
g�v�k�{�n��^\�Gp/�����MQ()t��V;R����%�zq%���^���Uo%�]X�g��Y��L�]����yL/�����G�����Noq`Ro�>���:��w���^���U�8"D����Z�#�����G�� �hI�\o��z'�	3���\�}���=��Q��~�-)����U�� Da"]_8k�/@"����<�]��@p/����w��PR�g����U����w���/����*��FV������W;���@���<*�!gOp���jj�o��w!o���[��y>{w��_�����������k{D(]�e�V7t����\6ou�\��������]�#B����M[�M��r����G�0���Zo��v;����/����[]'�e�}c��p����jw@��F��e�V7t��r�p���.L9��������qE���2��Y��7�n����G�}�Gw*����i@���2�%Z����n����;�G������jwA����r��X���7ts,�<�����e�w#H������uF�����l���]�U``G�n-���L9��������0�m(����C�~��|iwK���-A.���^U��fG�B5u(��2��q�{�n��^cF@g��c��U�Bw���Na����H4���u���n�KX���	����S�o���7MHx:��V���^���U/��L���Q��3V�7�.�	�=y����p/�����B&��(��)+3�_o$��p���V���^���U/f�L���A��Z�*Q��^d��_�z��	���^]�NB�c������Fp��<���ww�{{u��@hn��w�T�Z%Z��6�{���Q��~���^/ke�
!
)�Q-k���
C�U�����G��V[��\/kevt�6����`��C�j\+��eQ�m���Q��\o��z-���4�|,�xCq�
�Bi�/�za�����^]��!
I��p����Y!*_�:��������m{�($�G��U��������/�za�����^]��
B���Z�*Q�}�z)*/���=���bo��z�����v9�2%��_����;��������[i��/����z�{���Q�G�������Z�	�C�u��v�v���=�������^���U����4���q���w&�=���wE�e�/v������4���Z�
J
�]�c��p/����wG��f�����7tz�B��p�dQ�k _Op/������	3'��\+g��'����<�5�C�����AU�vG�B�/��������bt:�{��WW��G����t-T�����G��EtQ6�����v{(*dN~��V�����?{y��CQ��^������ B�����n�����p�������������v}�y��
��h�CI���?{y���g��������vg�a��m
'����=��hwF�e�N=�q���2!B�o�M���[�(Dp���<�]�gY��BO%�u��A�� s�+��r�?+T:{y���G�Eg���7�j;�2'����m�����&��,�m8{�bo��z[�"���p��5`�����^k]�}�^��u�zfN��yV������?|y��Do���j1!D�9�Y���� !�v��������^���U/v�fN����b�Vhn�_��;�����z{u��)!��	�p��!�m��P������#�h�{��WW��"���Z�*�r�Pnk��P�����	�o���jg{	3���������,���������9�����U/f�3'��9�v��#�
��<�]��_��c�z{u��i!��	�p���0��Bi�/�zw��7�:^��UUo�n��`��U��������E�]~������^�p#��g�:�G'4�I�/�za�����^]�b�[��{`��U� ����6���Q��]t"���^]��h���YS8k�uPR ��_����;�������=B����Y�������?|y����p/����w�����=
�p��!� ����qAt���zY���}�BI�����:�	B�{�n��^X}w�{��WW������-���f��g~l�t��Q�� ����zY�n��J���W-k��Z������J���Q/����������mF�U��Zu�����/�za�����^U��
����G�Z��"��_��8��RB/�����6��bm��Uo�>����G�8���^���U���Y������z�=������)�bo��z1/D�9n
�E��.���<��D�~��������a�=Z��\��������|�{��WW�#�� �/����#�������]���
}Oe�u���!��������lw��)}�J;{y�;��2E��J:�jw������i�~��c_��������
|O��u���u,B��
g��C���.��<�]�gY1�8�����mC����
'��#�M(Fg/�vq�9�������������s���{��e��`��x�|o��v-XA��Wx�`!� ���^�Z�Y���^]�b�A��W�g5�sRs�p��h����^���Uo�#D�q)��::����G����0�x��WW��G'�\�l�0@�Ap��<�<��������wD��r�+��F('���/�z=�-c��p��WW��3#��p�j� � ��_�N��O�)��z{u�;�Q(%��V����,���������%���^�jX�>����X
+�����G��-k|�k����n��`����c�!5�	�/�zw�[��b�z9�1�
�����Y�h�c�J;|Y�;8|�bo��zm�����JZ�d���������������_w������������~��o?��O?�By���������_��������?�;����
�
�����<-�=8-�������l������������?�6���%���>>@�^�of�(]t�|�9���;�XU��-�������F\�N�9���=�X�`������v=�g��b��vq�;a��[8�7��a���������&'B{�ZW���}�:���]����w�B��g��.�8��-�����:�F�N-��x3�vw��h��3��.�8��^�:�u��/Q�[���=�@z��2�=N�j�7����
�����G��������k � ��v�s��5;��M��?�j�5Q(�vj�����;:.��c>��v�,��b���v[��WW���[:.��c>��v;��������|%S��i�p���!� ��v��,����[]/W�q�;a��[�}��t�`���v����.�-���}�������
s������2�-����,>���^�����'��v����A���K�,�������K����<.u'��v3���AG���]�EW�+�,�/6>{U
o0�p3���������M`��jxC�e���|���r�

���p�jj0���BB�EU�S5,B{��YU���2���D��Kx
B�-�������^�z�U.ns�����0
mr�N�6��NVMnAp���T�YW��
"��r�����)H=(�p�j��&B{��YW���}���������~
v�?(�p�j��&B{��YW�#D�����fUM#D��Qn�L��MM��Z���r14I�M}aR��!���\��r'�&li"���u����'���/���f�s�`���r��&lh"���u��lQ
ts�����tJP�b?������]�MRS�P�S5moi���QM��Dh/v;�jw��]���4NR���kv	��,����E�u�kv���Y���/���q.3�}�Zp��`,�����uhV`�
zi���!3�e&��v� g���`*�������(��
s��<z��h�pr�<��/�����q�;a��[x����G?K��[8Q5���^lt��.6�fN��3U���f�M�����"����z���oQX�5�T�x���n�T�<A~��^����.np'��v�rU�7��}���A��sU3.�"�{wu��Ml���k(���qQ�,��	t�<�]�ea�t��U������ca>��a�����>P����o����rUK���.���rUi7��� ��h�p6ci��-A"���]]��!
��X8W���v��h�p6c��E��s����uB���0�j�����n�l��:�w����j�A���naN��Ak	�A�-��Z:�w	���]]��B���0�j�����n�\�2���K�_����.f�3�����7�/A:�A��sU�7.���U-�
"��v���	*XK�z�n�\�2��2E���zwu��{�	3�����e��#��������eA�e����zwu��� ��i�p�jY1��A_�ZP�����n�����]�fn�[a^��c����[8W�����n������;�3��������c��ZP���"87^��5���-��	8���	��B�ApNX�vAps�o�U��C��,_x`��B�Ap�NX�-�-��Z���v�!������Uk��e�[8a�v;����|���v�!
�_8a�y\F��V��\��p*�����cJ	����u����2�-��Z=�,c��p*����	�s���nar�:A�Ap�NX��,S�:w*����yC�B)�NX�F3_J�Ay���C�DK	�r���]�:����ZW:V>$�Ay�����FK	�r�����:G��qn�<��c����9��G�;�,{�:w��WW�[��y��5�3V���w�B�-���pt9������^�m���p�j���[�zPo�l�����`]�m������&M0o
��6\��������[����>^e�bFh�F�7��U[1����[8���rB{��WY�����M���6nrB�-���p|9������^�	m���p�j���[�zPo�|�����`]��������&M1o
���	��-�
=��pBr����b/��z1+�Ic���9�m��#H=��pFr�	���b3��z1-�	s�]S8i����-�=��pJr���[����n^e�b^h��;S8k��{��/t,�zq�9��������6a��3��V���cz�X���zB{��WY���F�9��e��.��B��MmE(�z�-��bC��z[�GhN����b����pZco��U�Z���F�9��Z�=����&��������^l�UV/6�hN���V���.��	,�<����������@s�-���=�v��M�	�Q�G��GK
��z����m�So���>A���mO(�zgt��xG~�����m�So����`�!��W��n�o��������@s���
L���oPR���6��G���	���^e��1�I����������|����C�C�����_�Bg��~��<��w��~�������og#p����<��;�������b�cKg����RCw��~�&�n�@$�^��U�o;"F��k���n�@�����By����p5�{�����Na���e�W7t��y��(Cyt���p/6���w���w�e'�����n�g��2�G�0���b���z!?t�����X�:����z���n`�{���������iG���l������M����zgt^f�k�������Cs��^�*%�qC��"��e�WC��p/6���ws1X{������n�@����ay���p/v���w_"�b�9��U�ke��w>uj�P�Xyw�{��WU��Q��������>47e(�za����>_]�:��w��-�������r�-��2���{�{��WW������+��2��Z>,7g(�~;p�	��N_]���hN���V�����r�-��2������*&���!F������3Bm��r�-��2#�.c|�X����h!�P[peyW7tP[ ��~�6���{��WW�3���o������@p9��m�}�9>H�b��,3b
�,���
�]����.ZX8�����
-d:�\Y��
F �QfbX�n��'�W�}U�k1?D���e�W7tp�l�z�����_�L�.~?WL_Y3#F�~ns������r�-���bK�{��WW��!"��~s�����
2D��-���nCt�����_]��;bJ�m����b���r�-�����6�
������-�j�m�e�7t�!"��~�����
rC�4���w��4���[8e���|i���<��wq3�+]����b�=�f^Y�\N���WvB�>�
������-d�#L��])xC�����0s(�~g�]���+}���]�(��j��D����|u��~W��!�Wu��"���0��n��A��Q���WvG�e�U���r��v���+��r
�����V\��Y]�\w��WW�fE�����_%������2��y�S��p��������Q��v��W�A���r�-��t0��j���~;`H8a��
��\�S����p~���;�������g�(������1>��z�� �������^�����1�����p������w�/LB�������:�h%�L��T�����'�������{�{��WW����$��
S�,�����[8������B���z1GD�9��`��� G������p�%���_]�b��0s�-��r;�A��A�}(�zwH��`M�����m|?v>��z��U����&��So���5p��`M�������B%��zw����r�-L�j������s�g]��!
��^-{�h�-T	.���������^���U/���`Y��z�����6H=��p��v;�C����_]�
Bj�}a�U;�_Op9��{[X�w�{��WW��j�my��-��jGp�� ;�����o��q����������P��{�oa�U;A��
2C5�;��2Ek�'{u�;��LB���%��������,����u��_�{��WW��"��~���*���oa�U�D������j���o�e�7t���B�W`����_�{��WU�]��.�~��������r�-���p&z,�{��WW�j��0�
�{;��w����p�����]�-���_]��1
�eCa�U���p9��^u8����������#F��l(���`_�.��������.Z[8�����-�J��W,�����[8��@�.X��J���~�1
���������Q�.��<�����j���~�1
���p�����@p9��ot8��^������ F��0&^u����g�������]�B���n��_%�'�#�U �	��<�����j���~w�����n(���v��\F�s(�~w����Z����>����;�_�,�2D��-���qk������_�����G�&_��[}�!��_g�F���~[�'�G��U����P�%��~�'��g�{��WW������p�`�"����p��������Wzu�;����y,�;�c���r�-�����an���_]�z`HhN���W����}��	�Eg������������X�o����'��~�'����j���~�OhN���W������p��_vD���W{����q
9��p�`�A���r:.�=�oo�eE��oR\8����<���W eQ������{��WU���
0af��g�\�Gp9��pfAt�
����z���������W�\N����~V��������G��lQ_�5��<����0�jhwD�-z.�����A�|�����������[8}u%�^���U�����%}a��0��!����pvc�o��%�%�u��!� ��z'�\�Gp9�Nn��`m������6�(�|��������[8�1��������r���]�(�|���n�#���_��>[�^����/��
�d����E��
�����ffX�n��������1��5���v��\N����#n�#�W{U�;xC�`w��[^��y4��\F�s(�~
�>�{��WW��A�|]�m
s�F�=���[8u5��<�{��WW���y�s���������r�-��;����������[G�9�N^�=x���o����/�.>[�b�jV��wo�M���8s��r�-��G�E�������b��mS8}5z��	.�����qB���w�J���~g�	4�����#��.�����������_]�.h!�X��)����Dp9��o�8}8M�����w�>1�F��s����_�����_��������������?���������~��&�<���������N��~��#�Hh��a���!|�7�����o���o������8t���
��F�U��=�X�
����g��^m�V����b�f���H#��v�y��e�+0������.:%�d���z�1�oE��s]�v��ZN��}��G��^m��Uo���$������M��{��-���y>�G��^���U��#F~7T�zs]�!IEh9�N�����j���z�G�<?<a����z�QZN���|~B��ktH��w��f�{\$���RT��So�$���m���*&���"F�{I�m���C�E���<�]�mY����������@V�{IXm���
C�MH�
�<������)�������(hF�����wj��Ah9���M
>�{�;ZW��_D���U���8�����<������������f����J�^q�����YAvy�� �%����������3*.���:�}'���
�<*� �%�[�u��-F����Z�*Q�=����\dzU��)tF�jSC����Z�*�z��4��G��[M#:.c��t.���]l0"��v��V��;A�;	�EV�V��.�&���u����I�<���\W�3�A^�Q���V��&���u��y�I�;���\�f^1��B��-���VtY�(q�\�YW���y�%a����nxl|S�HUy�����)4E�jwn`haf�[8e57sZN��SVs.�����]�!D�qIXf�j���r���[8c5[pY���h]��1��K�2s]�utZF��p�jna�������z&4��������TB���p�j�&D�z�!ZW���y�%a���z{��ZN���U��"�������yDx�%a����<B�Ah9��W�#�-c|�f����w��{/	��u�;K����z'H��������1���y.	��u/�:-�����yA�e�v(�l��U�
����0�j^��Ah9�NH�+�-k��q�ZW���{/	k�u/�C��o���pFr�!_Jp��B��wi��y�F�sU�]�B���pJr1
��O���Z,< �Qo���b��'���^;!�h�{�ZW�
��qo��T�&�Y����So������Lp��A����r4�f�[8k�t@�#��z���nGt+�u�;4��-6���V�m���Q�-��Z�)	���^]�bb�@3�-�����[����z�5o]�}�b�j��"M���Z-�"��z�5�	�YK�z��WW���y]��r]�]�&Dh9�Nk,���^���U�: F�{I�^���ht��So����[����^]��h �n������3��-���q/nE[���+����]����h	��U�wm�HGh9��{W�]�Hw��WW�j��Qo���j!� ��z���]]�Iw��WW���F���i��z�B_�u��Vk~=������^lo#��zg���Y���f]a���D������U/��hF���V���U�l��p�jfD���W{{;U�h$��OX]��be7B���p�j�P�"�{{u�;��x�����\W�x����n���:��.�\�\�YW������'�,W�|���/G[W8o�.�Z��^�����:!D~�H��r]�]�kJh9�N[��Ct��"�r������F��LXX���:d-���Y�u_]t������v���O�'�+W��7LZN���V����	�z{u�k=B�{������f�:-���9�
g�������m����I�	��um��Z�e��NYm-��bo��v1)D���Xm=8�[�z�n����C�Kp������B�Q�V�j$�G ��rB�N>I��Nl{���v��r�~��#1w�F	�p1}��&�����Q}�_x����x���M�t:�v��M���^8w��j�MX���khU���E�l�����6(hF��Ig��o�&����;�������j���vq��&��NX��k���{�z����i\|�w���n��C������WB�h�8���]��Ch�v9�j����ob7	;�U���A�Jp��H
��u����]���mG��{.&ae�����\F��!��zq��������H
�0��$ll��������������B{��YW������	�U%���Q�qT��^��Ch�v9����}#xL��v���C�����z�������]�����(l�KX��k�3p.��c���zq�7������^�����M��v���y��6�N��zW����2��)�}C�Xy2�IX��{9o��o<�?�����mEpQ2��.g]��b���F,�C�7W�B�Q�1�AS�7p�9�;��]���3!F�9`���9.��
���H�5���>��w�W��u��`��&;a�p����n]�AW�nAp�&�zY��iW��s�0Y8�z!1t����l���pAF��.g]��hYa�p���2��2�-����sG{��YW����#���c�c�F���-���aA�e�7���Z�����
�g�X/e��e�[6�16�-�P�W��u�y�;hN�e%o�F@$��[��q��nK0���.g]�.b�^a�l�]1�X���-�����j	�2������mD��wa6i��@���m�������lX�z����T�i,���a>i��y��.����++��h/v9�j6��1s�-��2�b���n�����;w���u��:���/��[�����]�����;w���u�����9��m�
,���e�[8me:�[L|������v{�y������n���/xt��Vf�.�)y.��������[�0X8���z�7�����b���v���NI#��c�S�<_�(n��,S�S�\�YW���v��i�p����:���)+3��2Gyt�����]�:f�F't����W:����p������Q��.g]�B��4���+�S��m]�����g��L��}����
>;��a�p��
D��Qo�l�m��������5;b�����Y��Z0����p��Zy	���^]�:���Wh���^1/������lk\4�=��������^�/���A�Kp�zmA/�������~A�B�+4�����z����p�kp[���^]��=b�^�C+�zG{	.���<+;�.�����U/f�4���<+;A�k����z����n��{+&�,���As�-���3�Bs[_8iet[�x�[1ke�0.B�+4����c������Z���5:�do��z����So�����C�
�m}�����m��
�V���As�-��r�_��Qo���3@r���'{{u�k��G�9��Z9
�Qo������w(T�Z97#F�CAh���^)S�G7�Z��Ep����Y+��}���b��<�s��e�[8k�:p[���^]��b:��<�k��p��Z���{��WW�����tB^��bw��zg��G�%X!�Jo��z'({hN���Vn������p��M��L����Y+7/�QhO���w��c����Y+����D�N����wE�Xx��
xy.�c�
�A���VnE�%�"�Jo��z�1

B^���A��2�-��r;�-{�A�do��z[lo#��zw�
�����6�Z��Ep����Y��B�So������2�-��ja���Fo���blrk��Fh��c��c�7�n,��ja�����^]����;fN��W-l��e�[8q����������&7��i�p����o������,�q��*�^��<��<Z��"i$d����)�����y����6V��^�U����i3��{���ww���K����p�����sX�v��o�8lU�x�
�I�n����X���,rf����V��*���oK�v^Yo����sX���M�5�Zm\����Q��%ZU�BB�bmoX���M�5��x�C�Be��u�cV��+�`�qX���M�5��x�C�BeT�u�CV�
����X���u�7�jT(xQ�n�C�-��wG��W�}��7�{���F��Q���*Wqo��U]���W(��+����P0
����u�g�����������Eh_��
��z �Q�`��Y�5*Wqo�'o����W(��[�<Zso�xU���!��{�y�v&��BagmoX�v\-����M��{�<Wqob�U�������LmoX�-�
�/����\���uV��k���P�Y���*xjc:_n��q�����������������gj{��w���x��uo������:�=f�U���TB�jmoX��H�	����A�z��~�et}��U��|W�Wk{����s��'xQ6�&�\����V
��	����a�[�d4����8�- �\����VMY�_>v`����>JCFg�E���W�3�����8!�g�{���^�hh��
�8����Np5�&�[5��'��V���o���P�%xq�o����j�M�j8�Op_-�
�_��c@_n���Y�=�����o��U��|��j}oX�
%�Q�g��P�	��������������ep�1F��F^��;AK�8��[�&n4��'��V���/�C�1�/7�����j��	��7����x>�}��7�W�@�!}�Q�g��H�	��������������ms��[cB_n�EY�mE��j�M�js����"���-&2�:�/��mK$�W�o��U��|��j�oX�V
��Q�g�V��	�B�'�_�����j�oX�6���Q�g�6��
�������3�7D�o���@N�c���Y�-�C���8q��A�}����#D�5�&a�=�����7q���>�}��7�{�����K�jGH�Wso�V;"~*�/���u��'���#r�"/����\���X���������a�� "��{���7	�Y��a}�#lz��7�{W�cb_n��E���+ �����'������o��>uo���0k�M���r||��uo��dWd��n����a�[bsf���{\u%6g����8x��Hm	����a����0+4�����
������L����t��=S���
����7q��k������IG��3�a��r�4���(��r��\���c�����z��7����F������~{�~W�o��d�����j�oX����vF���(��s�y��Y��#W������Z����DF#�k�n�Y�3r����7ql�����W�~��wi�h�~����n��~1r�E������e�A��g\!F������?�n����7qt��pw�W�~����o��7\�j����������"���/���W����
)��ob�U_��+�����r&���{`��g�H��,�8�s��o�D�n�Z&�o�5n���j�oX�6��}aT��Y�
*gW�o��F���c��3��a����.������7����8��w������a���d�#��Q�g��x�������~����6V�Y���#����7q����\����W������-;0~�O+��p�Q���3�����7q���!��Wk��w�d�k��:/��� z*�����5'��v������:@�5�&�2��W�o�������6�Y����	������C����D�n��8~5����Z���eKF=�_�yq�o����j�M��
]p_��
��g�`�D/���8����^p�V��W������a���d�#��Q�g�6������������������ @����Q���2p���7q�j`Ct�}��7�{��-za������W�o�������������#��6�����o`��|�8�5�-���X���3�p���0
��,������L����������'j��w����a
��+��]Q�#��{G��������n_:�{GV�	�����1�d������1�8Bp_��
��|%���(����#N���7q�j,pom���a��
8a����zp��i��������B�tt�MO���uo���0+�5����^��Wqo�8z5�������a���D�//�Q�g�R�$�gY�-B��#lz��7�{����:�0����^���,������5=S���CFF��R�cW#�M���7q�j9]�3��a�;��1���Q�g�R�$������7G��L�oX�������������j�M�g^]f�@�#W��2�
�:/��������:q�j\ywY�a]M�h����W�M�U�V']MyA:�������"��k���_����8v5P	����a�[Nd��
�:/����Ip5�&~�N����kz��7�����������~k�W�o���;��E����a��fd���Q�g�R�$��k���'o������o7��x��yq�Ku��j�M���z�]]�3��a�;p���������?x�
������i��e��.������
�0����_*�W�o���4��������
�_��	������i���|K������_�p`�jb��@k�
����;gZ�1*��&q|rbSt�}��7��l"���3�����9��^p5�&�O�9�u��j�oX�

i�Q���n����7q�j.V�y�u;k����
)��ob��\�v/�g�om���Z���uOFC\gT��Y�5n����7q|rn
�y�u;k�����T�5�&�_�-n�����M����t��e;k����
i���Q�g�q�\����Ws��K�}����
���%�~�)���8�w�Dp5�&�_�#�.�w2������� @h����W���d��i�7�����;gg�oX���M�5�&�_�3_ F�[�&�o�o�3�O��YP�N�5'�`�+�p�Q����c+�/��~����	�F{`�>/�{��dq�D�w����j����h��G���Cp5�&V�-eA:�xW:�{+<��Ysob�R�,��{��j"���+����	��^��'������8������K�����V���mKD��['_--.����7��j�2�y����������+��{G���z����8z����������s`���Ka���Y�:[������e��e���{��	�����7q��e��c2��t�cW����}��7����Fm�Q�g�.��\���cW������-;0n����8Fu^���B9$��6V���k��w���X��~�Q�e��9�u���7qdc��y�u�j���o��7q��Z���jT�������D�Tp_��
��
����.t�I�V�+�������3���������B��~�Q�gn�������^p_��
���'��Y0������S�U��'�M�j��������y�tFm�Q����q�\����Wk�����X���WHo����8�����`�����uDm���X���SKF�������~'��'���O�Zg$������]�]h����W����bd����uH��.���
�_��	������u��n5*��>m���2~}�w.���������>?}����6~u�@��e}���f%������U����2�z+����U�+
a]��[����/���o���z���^]�f�U��7�����k���_�"DWh��F�V�����s"D�S/��7.0v��_[v\������F��6�����t�5�6���B��K�m����7������������~]od�����>xw����}����;r��������?�5�F��[di�W�]F�����U�M
y�Q�������Ngi�W}6���&��n_�o`�.|��F~�����?/����,m�������/���
��u!�q�1J����<+@�SkS��yv�_���X���y����/�[Q�o������������H������yP�98Ccgp��qY��4������r �������HJ���mu�[AW�����>�q}�k����D��yqVo������&�`��B:��n_:�{���������^H����{�����7=Q���=�G�WF}^����Dp5�&�_��-�w6���sX��H������� ����S?�F�[i���a�;MD4./F}^��;��1��<��h��e�N��|���!�qy1����^�����{S?��[a���A�[d<?��bT�Eq��){O'��{k7�l ���l_�9�h��i�^]���-����k7�_�}��7�K� ��7q��(q�\��ik/0���e��j%���M��*j<}W�o��UQ��+������/cC�X�����?7x�Nl�v�e��U���"������o���@k�
�����_����8tUtP	����a��Od4���yq�g��W�o��U1��������
���!�q�1����w��Wp5�&^#�.������7�g������yq���/���H�*f�.����a���d4j���8�wA���j�M�*V�]�����2C��@k�M��*3(�W�o��U��~W�Wk��7��h�`���(��,��\����W%f�]q_��
���%�q����%^ ���7q��,=�Wk������w*������@W��"q���L�+����a��d�o0����
j�,��L�+����a��q���J�:/F��^ ����L�,;��������W2�������s��/������r��~��v������2���Q�g�\����W������gj��w�]�5�&�_�3����7q���y��������a����nL�+���8�wE�Tp5�&�_���w�}��7�+'BdL�+����*�z�r"D��M����t��u;k����"������:����8~U�n	����a���@k�M���J��+'Bt�������H��]���7�k�!��7q��������^HG���������
WIm�����(1���Xp5'�aU-����b�oX�v=�Gfi���Y�R�����J����t���tX���
������1"����8�U
x]VNt������g"�O������z'$�Wso�V5!,�/���u��Q���F}�>�v�����!\���o~��7������o���������~��?���\����������x�������������������CnUu�k�j����f��l	����A?�:�9 ���J��{] �&����8�W��	���=���A�[���������z�\���(�b�(���MNp�>����n�S@h_���]	��������E����R{�A�Vh_,��]�	����a��E�����Gi�z��
:�{�����4��,�:>��j<������A�u/�jcDZi�)�Y����YB����B�5�a��:"�����������
��q	eX�b4�������eQmH+�"�8�w�D�6
�6(���w��e�*�vV@�u/��Z3`����
�Rm�m��u/�]i_-���&����V%�QVo�c��B�8���M�oOh_����%����4�BQVoS�^/�
]��U��hB�j�sX�V�_4�p���Y������%�j4�@8�d����a�[�d4�IF� ���q�\�.qX��P4�}��9�{[�c4ZiD��^JCW�K�h��p����VM�������8��4Dp��a������<S����Go\^���8���\?�YRX��������V���1�^#0�������wo�8j�L��L����V�<������8�w��c�USTga���Z���r�Z5kCF�.��Y�+������:������?����U��d4./F`(��m)e\����Vm�kK�����z���'��7CQVoK-��*�M�jK�l�3E�a�[!�&��{G�Z��Wqo��U[M����������g2�o#0g�6�
����Q���RHh_-y���!#C��M�j)g\����Vm��:�g*�������_^J#0g���
����Q�����������2�-�K#0g�R�$�~�:q��ymqtL��;�u���@k�M\,�Na����Q�v��e���r�2��g��I���Fp(����1�b�:q��]xuY����-���]["�
#6g�l������.��������.�"��w���r�|W�n��U�IhB�b�sX��B���EY�]����*�M��J<|���R����"�^#0������x7q���V�y���B�a��"7a���8h�5x�vF}[�8h�q���X����@D���8f��������1�������z���z�5n��y7����������:q���g����DmoX�2&$��H<X�j��<����mM��U7��2z��;k{���%n��7q�����0�����n��e�W(��X�&��{G�������I��^Ze�����%n��7q��[Q���mM�pU�����+�W�9�~��7���������7_���?0`�+��|#&�sj_��!��{�#?���+���F���'�!�3�BQ�����Np�&�X�5��B�jmoX�6\��L0�Bq�� � ��{5��z�}��7�{���F6��9{;�=Wqo��F��Z/�����uo���H'q�8��G:Ap�tm��F��gB�jmoX����BF`(����\������k���K���7�{���FB��q���������a�~��e�&v���u���1#0gs^�Q\������-�7����7�{W>=��R��(�w��@V�o@���;d���������h���UVC�����n��X�3p����Z���%*�c�Y�$�Y
%�����7qXc(G��+��Z
�DF��k�����^�U��X�3p����Z���MCF�2�	���z��Wqo����AgB�jmoX�v�wo�������^/��{G��)�}��7�{���FJ����Y�=������G������_�`�j��B���~��V�������#�-�w��������>F��k����{��o�I�v����	����a����03n��_��wA���	��7q�jXy�_�3nv��u��q}������E���97�U��8j5f��l{���
�b�	������1G�h��u�#Wc�����X���%����y7q�j,5\���Wc�����u��j%�!�3"q�n����*�M�k\��������m:"�~��_�����!��w��F��k{�z���|4&��F�/�w;��$��l>�}��7�w{�c@_i���<{�O�U��8&9������a�;�D4F�a�8kwD�������1�q����'j{�zwF�Fa����
�8�F?�n��B�qF�^h_��
�����Y��]���������*�M���pl��LmoP�NO��pc���,�)C�Wp�&�XM�=�}��7�{h�����drB7�M��
<'�������-{2�^#�g���e	�������B����Z����	����������		��7q�j�'����XM�LF�����z[\�Wqo����"�%�����u/cB��7q�j�p������{�4�����_>v`�jbPH�5�&�YM��MNT��.7����-���������@��k�����#������R�i��e��|[M3����7q}�4C($������7��[A���7����FS:#���+���������i��~�wa?0r5��M�5�&�\���Q��g�CWs�����Z����sh���CWs��lT��Y���\�����Y���,th���cWs��l���Y���\��"������/+�Z�o���\CJ75ny�8z5���Z��5�a��R7����8z5�x��F�������-�t��j�oX���M�5�&_�C�Q��g��Ws��K������
�_�	������y@�t6���<q�jxw�E���fV�	�������_ F�[�'�_�o���J����<s�Lzz�2"�q���/�YO/�y���<��2{�;}��w����`*#g��|����/��������[����7���g��7��`�.�����7q�j�+�y��;K}���"����8~���-N������WK�����gj}���"�����Tp� �[������
oK�
Q�[�q�UR�����F�c-5�u���8qki����}���A"a����bpi��[� ��{���v"�W`�/���m��������Y�����_���^���v����}�������O?�5���������,�������O����������o��c�q�q3���Iw��o~��V���|��cg<@~���'��-�,�x��p|������
<��������<~K�A}�X�������-C�
x���[F+���+/��@��8|P�����q�|����5�Sh�p��(|P��9n�B�b�sX��a
��������-p�Z���W�Z <&�/>�un9���<~=�un���*�}�x��
��}��9�s����@d�8����Q+�J��qr%�sk��������mV2�������m�Z���Cwa��Bv+��V=��n��Q�nG���J����^���N�������pe5�+����.u+��[1.|q�;��������y�]��Z����wX���jD���%�w'$EW��3%�a�;�d���f���.�����=4C�:}x��x��e%�.	�0�<�wW>�=�f�j����`�}��9�w���xZ1`�@��~y\i�p�4������r�}��9�w���
�x7m������s�������O�����Y����LF���6T5dU�R���0�8�w��^��4r\�j������%m��7�6�T��U]XV|z�_|\�j������%m��W�5�u��U]X:|z�\�q��!�z2���
C��z�����R����^�����c���6� �������6���]�X]i_-q�]�X]�w?:�x��+���+��j���)V����ln��g7L ��y�lt�M�v������z\�j����zp����]�_����1a��v������T7uo��d�S��uo��5.��guo������7�uo���@��qo����*�-�6�uo1��+������r"���0�<�{+���Vs�c�zX�V>����Y���uMF=�ayX����J���WF�u/:]q_�l�^t�B+�M��Q�u����z��1�������Ec�+��p}��/��Vq����������hg]sX��	����!������{S������s�lYs���HN����!��\\6o�����w���\h7Um���o�6��w�MU�?j�����1Q����E�C1�D�P�{]���^�eIn��{^���q&�~��0�=��WL81�v�P���7�sQ{�}�<�sQ{e��}��\��^iw+��8u�W�k��:u�Wf����|�b��O�I�:u�W����:�D]��Yqn�_���+��r���-Q{�}��9�sQ{eV��8�W�.�J�;<�������X������2���q.�b��O���:u�W����:u�Wf�~��{%�b��O���:u�W����:e�WfE�8�W�,�J���^�(����Z���(��B+L�+Q{��$�#9a����+��U�a����+�n�f��.�J���%�{Q{�}��9�{Q{�V��8LU�0�J�)ZR?�P{�}��9�{Q{��}��q/*c��������W�W�����Wh���CU����Q�oh��������Z���U���Q�aP{P�V������|C�����X[)����*�VFq��A�a�����(����9�����R{`��buleT�n���������|C'���eyl�����X[����u/�c+�<6/So�������;��������Q�aN{X��>�2�c�2��e�l����X [����u/d+�@��s���e}l�����X[��f��u.�c+�>vCL#�wY[)����*��VF}��	�a������@�8���������#V�c+�>v�|���e}le���K��z����R{`��b}le��n����������
����eyl�����Y[��f��n����(�-��5�ck�:��pU�������0�=�wY[��z���.�ck�8��hU����(��0�=�wY[��z���.kck�6��`U�������0�=�wY[��U�s�fil�/��Y���,����XK��������Xc�T��4�VJc�U�,�����|�L���emlm��#M������R{`��film���F��u/kck�6�N}�bil���>S���,�����|�D���e]l=���
����wB��v�T��|n��xF\M�����x��\p��*
����}��7�w����x�z7q��^�*_��s��F+rB�b)oP�6,f����V
+�"�����
+E��xsX��"�1*�
���z�%��Qh���.KI��xsX��$�1J�,q��aM`c�eOq�����_�/����	l���<K�jX�E����z�E���(p_�9�wY�E�y�8f��*���?�V6���}����eQ`c�y��U�����
4�Aq�����_�/����	l��@�.+�wY�E�����.k�&p_�9�{Y�5�y�8b��(���7����/��(��pU����(
������U��U���7�Y�(U��V6FU`�'X5,l��@����,l���CVm����"�(�m3<�������ms$������-Wh����Vm�g��>_���2���jYoX��#��`�8l��x��V��z�VH	
��u�a�[#�&����Os����X���Hx����a��,d4��P|_���x�t�~~�Zt-��+t������v�.�v����F�7�U��76~�]����4GW#�#��s�{�������������]@~����A�CG��@��Q��w]�$[�(�n�?�6�{[\���J�����O��_���G��s~7t��T�uo�����Z	���	������n@��s~7U;:\������a�K��@�o����l�;�����W��<���Z���	������n���s�}7u;�W��D���Z
��T�	������nE��s�}7���Tq��"�&���Cuo�Md42mE�H_�#�&�JeG����H�	����a�[�d4mF��8�-�h\E��8����lB�jAtX��+�<�q{���
�r�U���a�[!�&��VD�uo���H���j}�W��*���go� �&���D�uo���@k�M��[��W ���[$���������F2I6�#D�vx���
�����c�Wk���w@dM�5�&�Z�^����b;���������296��i�Nx�����8�����W����w��h�����V��w��>�a
��)�
Q������k>N��W>�W+����+���b]tP��	������!�"����[�9�/��batX�R�'�����cpt~���uo�����X����	�f�����B^ppd~���uo�����X��T�	�b@��Z�R�58*�=
����mpk���}������O�5�&]
-������Y����"+(�/VF��n7�H
V�#WC����>��
��IA�}�2:�w���FN����������*z��q�����+��zw\�h��f�q�;!%(�O���zwBJPh_�����#���G��r�U�8�a�� %(��F�u����@k�M�V>�W=%�A���+R�B�j]tP���HF#%X%X������qB?�{�)A�}�,:�{��Zso���X�A.���J?9���@FPh_����r!�����
Or�U�V�Cc�����Z��uGF#!X'X�5������_����}�&:�{[D�Zso�����Q.�J<�q�(�{[�:��������F2��:q�j��*���ta��#�!��V��u����@k�M���W��^�RB�j�oX���a�u���8�U.���*��;!�!�����������n<>��w��\p������|���Z���+bk��7q�j\�._�vV��a��"�!������2A����8p5�Lp2�-�}�N���:�#W�'�N��������:�-Z���e���
��X(8Y��u����B��(�r�q��J�I�<0v5�Rp�*��������Q)h�������R*x`�jb��d�
6��WK'�T0�0�+�Y+8)��F�&�
NV��a�8�e��d�
����/�'���R���e��d6��W�'�Xp�(���e���/�Y���,��bA��A��Xp��7�	�_NJ���������U,�$�_M,��b�>��e���>S���,��BAc�e��Pp�
���������Ppg�oP���HF#;�$�_�^��{��9��������q6�|�8�5x���|6f���q����X����BD#E�
a�m����_l�
t�:�y��Oj������L������DWZ��|������9k[����~+��s�{�����=��.��DBA~����A��R!j%���<q�o�pW��2��O�.�{+�g����a�[D4nm��������%T����m�NX���OG�uo���0k�M�[8�Up�oL��-�	�3��������f"�?������]Wso���#��8�]������%����M�[8�Up�����:w@&aq�>Q��SFD��G�8��p���j������GX���O�G���<Q��a���x��]���a�� ��8C]�)����*����8��p���*1���nX��H",�L�g����w�f2B�6q�o�dW�U��xo^s�Vg��3��a�[4d4t~mb��������G?N��uo���Lt}�<:�{������(r��^�u\���7��B�`u�>S��uOFC��%Y��*�J�{j�r����s}�<:�{9cs�flv�CV+gl����
������U��y`�j�������%Y����36
yF�r�������<:�{9cs�fl�8����������=�{9cs����Y�����Z36��A��36Wc�f�X~������gl�,��^��\��F��8��������op����*C6[���ZC6��a��C6Wc����������U��y\�j�2>>�)��;��,�_!W\-���_H�^��o.W�W�����h�h$�������H&�;_`V|}~��������229A��K�V�*#'�a�yX�V=�����Y���@F���
]]���������1k
|}�7-��<:����q�1���o���5������o;��k�y����a���d�F�
^�Y���3���2����~�����������CW�uQ%y@W��������������6*���_�_9?~�5�����]H�����o����?���������/>�����������h���?����?����?����?����?����?����?����?����?����?����?����?����?����?����?����?����?����?����?����?����?����?����?����?����?����?����?����?����?����?����?����?����?����?����?����?����?����?����?����?����?����?����?������q�}%A�����m;��|�9�o�x�t���ZZw�k��8��2k37��>E�goxy�
�./xmU�6f_y�Lm�}�����O�o�eC[����I���M��	�c#��I�f[���k��qU���b�gY���� W@�w�
�g��Q~�����hL���V�{?��x[�y��M<,l��>K���g��'	�SB��5m~�m^X����$���J���:st�?|������4�o�=�7~�o����s�{s�a�Y�woiN��lF���Z�[|k�E���gk�������X7������|��x���_~�����O�����?����]m��Y'��������:^Y�����iKEP����-��0�N�IQ��K�8�+u�X,����!������w_�_�a��n����������->�������������+h�n�������������y9&C&ln��/l������/��l\�Z�I��O@�?y��<��<�y����p6Y��<���90����y�O3j�����9���I�W`?�>���������������~�����!Y1j���'8�Ws��8����:<�}O�7��y��%���4�p'�
{zW�����7����������?e�s2��?����;i|�,�`;<���F[W�����n��������A4�'n�����YP��7����"�Q��GQ���(�BE��x��E����d��|<��l����ycmP��n6nB��������/���t
������W4��Y�y��B���L�����lC�B��\�_�H����c����w�r�.����9��>����z���u;N��+����&TV�C��� +&�v��.��f�']�9��|3�����g�y���3����C$�-9����Ln��&�u��in$�
0��(/�GX,��4��3���q���4���OO0�1�������o\���c�le��8��YN�1V�9(�|c�	����O}0�2�1B�T�!���O���M?���������R$�1)3I��Om?�d��;�<����h�"�����[�A�W '����{x�"r���O���~��(�u��q�+����o?>�@GQw�y��!�.���?���{}����g������\z��y��3W��Sn{���'W�Lx���FD��5w����qO��'��R��������|�	����O0���\���G'�V�/�0�������*x���`&^��z�������'D��/�c��_�.���""�)�G����������q�����^{�CSh]���6q����9v������+����{s^~�|�H��6���/���~�����o����������|�����J��$�y)�=(��(�A	��'Qo�{ui��s�J�Q��{�lD�RUn5�JB�:��wU@(�9d���?+*�����Q�.8��g��.���
���1Xx�.��[4�-�j�A�%�.�y����{5��K��w/�/����q�&�����CI�F^�g������ �'��-��
��F`6��|#%	�#I�s`��^j�&!ss�.a����8������g������n�i.��2:�,?���j�j.��<cWi��q�m<d��
@�x�6�{�)�����E~��cj.�B*����2gLD\��YY���������kt�8���H	��~U��	��UZ�~)s�D\i?]�ZE���h?�X�H�3&"���|���(���R&?�X���.W��+������K��$"����/���p+����)��@�J�O�&�_������K�E""B����/��puN�y�E�,�f�~�%����Xh]���"q������I�d����������G}�0����@%���|���kV+�cQ��PF	�k��-�Q��������p��ot���:��2����3��qOn���&�~v@��3wzo�����'����+������{]�����{r����)�mD��<���j���D�p����=��44Y��t�j^[��0ih��|^F=��h��$�c����O$?�����a(�Q$��Om������O�G�	�P��P��/e���hN�f5�kp3C��7�]��6��Y�s���]���pe����[�ey����|�����J�.<�f��O�f*����I�0�y{PZx;5��h.��&����l����2�3�pe"ty��s �%��]`�m;���l�5��Y�����������w��j%�.����x���w�e��O��3i.E���S���6���q�M%���O`d���O�9F�D<������
�mSs������vz�9�Bh.IX4�QvYs���0��V���6����	VYkJ���\�����sf����T�j�q���N���c����8x��	���>���\�@W����kP=�+��uE[���:v��CFh��	s�"�0���/v��pMN�y�0U�����(�0�����:p<^�l��9cq�������kK������8�����b���7��u��0�I�.���PK[���AP&���&?D����,�[h?
��Z���G��l����#���/^�f�D�fC���������/^�f�DA�B[���1�1x������HC����1��7HX����D���/v�n��u�w��cb8��M���xNs����Th�:���r
�e0�e{�`��'O�R�:������gc�k�m�p��go{�:��
�%>����qO^�e�u�g�3/z��f���?
M��{�r�4���'�j��kcxx�4�����jt���Fs��������(<)�����������z+����"��'�GE����'���RF����0��#�B��/e��������`�.EsI8�ZWs���t��<Yn�^~P�7��Jk�o��xeFS���"���}����V�/A�u#9��\���A��k��t�h=C�`��Ch.��l�i�0��/��p�	`�5����55<�����\:xx.��u���~�>��}�������M�3�I���6i�5�����0�'��E��n��.�W������\|i���.m��DsIB�;y��DsI6�:v��Hs	��$���,/�j�>�md���7�i�L����t�3��v����a6�q��m���+���(=K��U���aV^����c���i��g?6�_���7���<!"�������;�~����j�G7�x�Q�&e����
�Y�������L~qb�w��Du�5o�c�w���jR&?��@��'����_�1F0y��M��'g�C'=N��~3��7y���"���YOw�5G�[���������p���#���U�1�x�3M�,Y�>�]t��V>o��9�����|��������� �;���6	��|��tn�*���'�=���f�������K���Oh7:�<�;�-��7X��>���)�m@,�3�Q���'�k���6"bg���-�[i?o�u��������R�n���D�p�����[tX��xMJ�^����W4�����H~�%����-\�?YTNs��9~�c��_�.���"�%��W(F�V;pe
�k���Ma>��G�&�����6a��AD@S�������\:pe
�����\:�|4����J��<�}�T^G�K���$ju�M��7���K���<�"�)�n&4����
�.Z�.�!4�_��Z�v��K�m%��c�lk�G�x����	��;x������A4���F�\������5��H�J��W�:8�����-��P�'��o�A����u�>o��}X�=����|C�4�]P��Go���V�%	'��y��Bs��AU$�{�0�K�������	6>��k��L6��%�y��u��<X�����r�l���+��C<H��w���*�l��(�0��OT�0gL��Q�Y����E �0�?
�0g� 2
��Q�>v��p+�0�?
�0g� 2
�Q��Q@��xY���]��������W'���1�.���&?�����Y9�L�(��]q]&�~1�i@=����:p
��{��w	�����z�wz�����){�2��������^���E���.e��X�U7����d�2��e7]�Dk������e�,�u7�ao��B�u7�� SV������;�
rAla�J����H},N0`�-��{�LY���z���3�9��CW����yB}�?9����������p[����>�������]���p��o��O�xb�����W	�.����z�W}���7�z�*��}�O��A�q[n������d�K���X��B0X:�x|ev�+��J{�����
����#.�����1}C[{���)�Da�^���Zn��z�d�Ot�P�~����O>�1�9x��}����z,���/A72�9��4o��wa���K��0�:?*���h���s}6W���x<�F��T�Y�����^�[��71�9zO����S�Bp2F��V_�m��m(�s/���l���)5rXg|��4���Q��R��zIc�[��0�K�����5Z��2++�U���K�����7�J�,�b�|KL0���=�n�~I&�"W��M�[fM�)W���+����^���/I�� �?���/���T`�X���`�K�m�}Xf}mN�7e��������c,���m<d��s�����	���	�<�����eT�e�����{���D��s+����#������{���D$yr+�����2 �;�?��'�;�
����<v(�tL����{�0w� "��[���D�'�'��,a�����V�]�E� ��y��{�g	��c:��[�V;t-��x�&B��W��X�iaAg��i��a�Fo~��EH�k3Z���2�&��
l���El%�C�p��z,�0��0���Q0[�����+hA�qv�����gy��w��c�_$�J�M0�"vo��-����g>Iz�hz�$g�I����C�Zp��?���H����f�5��>�y��)����g�l~���<z;a�y���A���(��t��G��(�S>��8q�
eQ�����v��5O�IQ;�|vNF��F|IQo����PdV�?�"����s��
����)������a���p]�)#`\�41$�d��QN'�<O� #c�F+��?���r�{1\�q\�4�1�E�(���t��\�=1�ji��2b�����k����=1k�k���x�yF��B�Re:x�t�o��1.B�IB*
�O���
��t��8,�����Pe����6�v
��	�����%R���a=�J�I�2����W��0��U���0�S2q�&G�C���8�:���<���C��/<��p���(}�H��$a]�����+�*�a�aZ��"�2��l��W�C����^�O���
��-��`��F��^���x��6[�^�A����������}����%���LFs�r���#	��\]p=L�G&�J�����*���������G�`��@k�$����/R��,��� O�#-�C�,��L���e��,]G���6��7sD��P��FT���&�����`��(���Xp�hAT��5��@�V�I�CT�p�|Qh����,�Utm+�&�DFo���H�Y"#�"�>�*��CH�`����IfF''#���M2C�,��&��`h����X�9�����|���Ba�U�s�<��$r���
e�>9����2���@�rkVz1)�rd���%�7�{�2�����K��O92b����0���,����O92���Q\R���HS�./h�����g��kRk�]�45���^�y����^��z��c�*�����~����<?e���u�V����l��IC�o���)#dD����4���Q����!/SF ����F��*XLSf��m��6
����8e&��V(o�6~\���Qe�4V��0�%����4�7��
p�2�UW������a��&��r64������Qf���k��|���d����O��9LA�5ef|u5�8H�4)z�Y0e&��`���`_y��������q��\+;���� ��rC	&�"#9�	��s �@�x����o��/k.�2�M+v���hf2e�K�*_A�`Pf�l��-��[� �L�m(��n����	����e�����g�����)�h�q��A?[����8xcEn�z���
��|3�(�B�y��#����
��{T�H�C7���_�Z��#����
�f�����V��X0]�e\iAC�ZG�:t3g����q���>��uf|<g��Q������Uq.���_�Z�K�����.�����v�/X���*]B�a\�(]mkr���~mk�.��22���V}RV� ���,����W������mu��P\��e�\��4��m�"Y0�hA����7I��
}�7I���T9��<�MR���@k�������r�*\-x���*�n��O����.�Jn�Z6E���(3����@Urk.�O�*�S�7���W�#�����R>���
���F������\�CZU���A�FHKo]F���qk�������k���Fh�Qs;���.D���IM�5�+3]<$K�w�1��Os���Ev�F�j3��_�R��@���>,�M:$��c��2.��Q���������u�Q>#���ya��.
g�Qf��Q�L��o��������=��N�&�7V3�0�%�x�z�c�[���L5�������L���A��~��t�h=C�����f:p#_
�i��\Vn��S	�X�x�>ZM3�+yi��7��0nl���]��P�Yd5@�L���[���R`������o���
)�1�3o,�n�.�DaU���������xb�f�p)i�g�����d��C`w�X������m����wP�y_Z�<d�6������>_����l���R����.�<�����
�:�iG�g�2�LF�~ZY�m�X���\�Sf�����F�g=��������:e&��P��f��A������_�R�Y���������"���/�N�%#���Y0�.�t-���]�L���,hAcw]L:�c��)Q2�U*�g�`�����IM���h���5I�CdRp=L�["�L�.��tuA��q7)sKdD`D�5F������X��7I�����5����hA���9�M���Y�*��bA�����nm|�p�E�L�x�$yR�I:����Yv�n�~�����5[��Y���|���tg4�����[s�����|��������W�qk����&�S����{C������S�n����o������g�`��[��J�<5����<unE��h3�7��9l�Sw}m��Sh3?���~�����z�0�02�9���c�������m����X�d�[���:F9'���M�p��uk,
�h3I73�9�G9o���a�L��o��=�y�q���<���8����$���h6$9���{��m���������l�C�3D&Kc��B�I8�F�����B����&������
�FmM~�[�DZ�M�=��e�,�rG�����<-�n�}e�D9^�Y�F�����59�#q5R[b�4R#r9�i��O<�F��CGx�|Cmd��������������gVy���ZPa~��
��t�Py�F��~f��g�,	�n�
�,����g����=�K #<'���{�D���=d��K=<�������*i��^/}����3�
���
��5�0��0�*%������@W���_��&�&;�P�
�f��	�
W��X0a6�a\hAC��G�
���!S��m�l�����@�����
���	��ddg��,[��!��8=
�L�u�m�����v�Z��pm�E�������H��A��4�"V9����6��c��H�g��_����/�1^��,[���1*�4/���:���8n_O��!�q�|Q]g�2*�>��d��Jp=<�M���Y0v'p�q�E3����o��h����$��3:����v�������}O�f������R>����}��G:n�3����W__����EX#r�vz2$��������A.��o�=�Wcl[ ��C��yy��OU�����������R��[��\�'g�[�� M�o�u[�����8\����0������������'l3�:WC�?�M:9����Kc`�!�)��=�@�g��W�����~9�����1L(i&��\W��'�$�L{�=?(�Z��U_�E<�D�����:�4�x|
����x'"�bYQ���� �L�!M*�
�u��fn!�p��.X)�xM�i](�,cJ2ZG�q+�W��I3�5F[mk=V�ms����4���Z[;��
>�-9�`�(2�/��-�:
����G�B{�W0��"���V��@y�wD��� �L �����ra��D�I8���v��H�I��p��^TE�o��H3{ ��m�m#�-��`{;��F�&S����!?+�[������p��"(2B��z� ���0	������)Kp��\�~��H���� k���Gq�V����%F
k�������$�a������r�K��~����>��8�Ap�.��a�u��1�����(���/�Q���z��1�%�'
F���YP�����7 c��b���$"�9
h��A�H���Y�!L�Pr������,��Y�q
�g����Y�h��f�pad�G@|�p�0���2���v��Y��\������e@�4W��"+�2���g�!��t]�g���1#e�+F=��2�������c���.����e	�a;���ro�H��"[/tN�����!��9]�`!,aVX���g���|a��&kY��F���J��J;x8��w�VJ�����-g\U�
�R�0���!]U�����E������B����Op]��;�.i�C_}���Op]��;�>a�N�`�/E�I�&��_}7B�<��+1�B�2|���<�eq�aIV:����K��SCgtj0�{X��U�i��i�C4���ati0���:�N�_]��W
�M���y����������cAC�h��B�X8�������C�X	��[���/�"�#���5���xH���c��� :V�
9�7m|1��Y�|���-Y�0�3xsK���B(-���Fv.�N� Z2�+p,�}CU�x^��t�EP�z�'b7�Y!t�D��a~��
�cu�x�:C6�Yat���������^���J�&�=��f���_����=[��`{��YoXgG���=��5t������b��/�^�f4+e
����f-�=C:�	�k��)x �
hL�(�'�H�L��
���z,2���<�,��Y����)�{�>c&o52y�
�g��	�s5c��L�0k��$$�Jz���
_"0�h@C�^FWS�jt�}�������YX�4�W����������0���t���k��I9"�4�!G/���AW�4�W�^�L�a���e@DA�5�q/���i@#���%�S� ���{��&��0���$��[h@�0�<�%�S��[�����ZV�A�����G]�Ov[�o�e�o��7����|w)pD������;�Z�����G��GDn��>�%���t��[���*�����[}�KQ����L������(3MV>6;c��>:Xf�x|hv�C�7�R����K��7�qM��e��c��_����q""��[���A�i�B�2�@DF7�a	^}�c`�?�Jw "���,��
������,��f�������2�	�y�o;�<�F��Wg�:,�7�4r�������W��x�yN��ek�� jL ���(x��$d7B��YL��1	���\�v����kj���t���@ou��|w��a/�:����Vc�2��-]��?N����`�(2�
�Z�(�
��"W�:l����3j;����n@��"�\��3+��A��D��8�B�1	��J"����0jLa8���������1�{��=�@�I~�s��P{Y�/��{���{<<���R}��mVz�	��1����S�/���Idq�-��p�p����N�&�D�_�Y3`�T�C�����0�&��X��)�7o;"����+��&�Dh}��4\i@�|��	��D�K�Z�[���9tH'�k���P�����P�����i@o:�N�
uy�m�trz�)*������4��ul%�����A��i%1!a�[�������L�V"b���F
�@<�;D��5��/�Q���D���6��|����0k_`����������H��?a~�yN�I�!��m���j<��.��1�����}y��#�)pD��<-���|���<z[�)pD��<-��_^@7q_�5�u��9OFM��O
��t��/O�����i�r���k����<>4����Rc:x|i��7����|�{v85fy�*dX���ChR�����b1�^�����[����;����(b��������-blR�����j16�"_���c`s}l��1����1�3a}�v~X����k�e��N#����������-������N��Dd#a~B�B���!7:-r��B�I�"'�|�;/Y��x���[�:xPa����*��wo������+��x5��{y�\m,�xE�:SD��"��Q��)�"�x����F\�A���j������Va��D�	D����`a��D�I8��FgV��3+��p#���_a�gif�����#���k�l�!#}n��/2��C<�f�w������W}
��=�0:��5�2�LDdFcX�����	�C&`tf�S&�����F&���J]W���L@�2�LDd�Y3`�� �x�t���M�$2��4��&7`�j�u
�2JD�!
�b�6��t3
��������MF�������I�`���@�2JD>H�&�����X�2�D61�;k]�D:%Gow�6eZ��M�F��6��t�R0:]
��)�JDd@��Tpk����1
�4)��V�Hl&��%
�Ml��Df$6�Y�c��v���\���D�ff�;��C�I5&���\��2v����X�)�����m�����-%iS>����y5����|����z�����{�)ck5���_^H� ���L��#"�X��p��DftyA���L����k��S<����	L,�K5&��A��g\�e��s�?���~^}�#R�u�0�� ��'�G�IW�4����%�;8��]�Q�>��u
�0�� �4�����E�5&���|�X��1��s����AF:E~�9K���Q����I�����yU��uq�Vc������A(���e��:DoL"R� �OC�18����!���jLn ���}�e� ?0���P��Y�mES�����Qc:x�&�����[����x5��?]u�\m�����1j���P�(�	:��Q��)�"���
��)z�,��`M�Y���O=}�y��[��jL���^w�yf�Pcn���c��3+���CNh7|�y����������%��B���M����=`���x"�N�����q���"H_^�5\�W���	�&����4�Ju��	��J��T�K�Dv�\f���S)����0a��sFM��'y$r����L�Dv�����R�
�D��m*�%��qa�g6�J���p�k���T�0� B�,��[L�5���/]�lh��]�/y���0��~������o/���p\�������?���?������?|�������������������~����o��c���KI�����n�����W������������X�\>$���(��F�[������Z���f-���EP����N��L��na�6���C�Hh]����q���2��gEX�U��������
�[aV��x�l?������q���i?���oX���	�k���ks��0�|~<'Yu�V��=re�����>�45�d����03�&vt?���\ 2�6[9�����'��r�>�#������W�k�:���Ww��|��;s���6�t����{�qO�N��+��^I(���`�{��)>;����p�{E�����yS9lpUv�,�����<d�����O�Sw�f-{�$"��?����6q����������������2"�+������n�5�*��Z�Z�<N�Jd���h��G%X'�E�^e���|�0G%�xMF�Nj����@��=]���� jU �-�6� 4�Z�p�%	�g=���U���0���������!r��s�e�����|�l�`jU�q�^��tz_��3�U������s3�ug��r�-/�b��q� ������k��j
�#�Y���
���RS��z!��
�Vb^���^�<���U	�+���>��U	7���V�'p�I��}y�R������\���l�!#^���=�54��C<���w�����	�V���B���.��p�������@+�����a��0a���UF����i�GK����g	��#O�J?a��An��O�,a���uA�o���!�Z�fBFh|Z1`���V�4��sc�%L����h@=�\���Hl�JZ��BF^d=����mNz���g�qlh���5H�
B�1`�������z�A/��d�������
��k�@+�-q�yZ�|��9
���&����Z�|��(�h�|�A/��?w.?�%2�4�>xn�!����c�u�q�����b��m�������n��##w�Q�����my��|5`��;Oz����q[��5���Drw����
�_�bn��<�o�Gg�V>6gc�Zo����v����
�����$����3��e�j1�?�qMgL�u���;����E/]�������-]���q22������_}�c\s��.�y���\���:X�KQcn��\���wj��05���g�����d�i�:������Q��^���F]�^���wh+2��B�������K�I�D,h�\����jL��+���.r��t������a�.��~��������4�k�JD����� �����h����r�g�������bW�%4J�0"��Z-r��D��!y�V�u�{��pj����|�K�����xf�Pc:��
�gV5&����v��F���Al$�[��������e���2�����k�=��FN _����^�l�!�9�v����3�,��(T��y^�L"�q�1���:z8pD����E�$2!g]�I�u�T
� g]����"e�l&����9��V�y^�L"�a���D���3
���)��`�$���D��&#���W� ��H�
%#���1�\/��e@����"e6��D�������W� ��H�V"#��$�&�	pD����E���4&�7����c0�?�</R������1�|�8��� ��?�</|�p�jL"O�a#��?�</|�p�jL"o"k@"_���<�%�06�L�~�yR�I��|��Q��;1���8j���+��=�]����q�jL"����>�u��0����A�+�Q��a���c��82�0�1�|�D����a��=�uxf��E~��&���0�i��0�3]�V`b�1
��$����}�u�����1���A��_�Y�)�dl`pcy��5�����6���e��<��8"��z�2�@���W_,���1	7������N����r����i����4��>�yousX���1��(-��>5fW~%y���z��e������cA���<Qc�[�5��:���1���[�s�%k��5*���H��aJkjBm]���1�����n�@j����ST�U�=@�8S�mpR*���	�WhMe���(����oT��M�7���(}�{��[��jL"������3+�����:�W��
��t��6F��]~�Qc���M~�<����Pm�m��{F�|�_HEa]C��=���F�wy_�Tc6�=��+�y��	s��������$�6v8���`@� �|S'�H�$�+�b���������M�'��t�1���t�x���������0�cL"On��y� �|�e;���1&�w��p�[^�"�7�"�����c���\��/y�0�0�4���"�����=*��i%��^�|�V[��������&L+9�+
����b�Y	�W4�w�v^%L+9����b���Q�����H�F
W�s�Dr4R�����{����y�w��b��v�V�i���{��eI�����sjLik���h�'g��wTc6���*n��_F]�|����s�����|���-W�R�:�����k]T��B8n��_TT�|����s����}_���4�n��y2�+���K�&*A2�����	L��	R���kZo�v��Y~����c��_�Y�)�dDx37z1�^�����;��������G8�5s�C�2�F�b�B�
��|)jLq��������EZ5���g�Mk��K��4������tXo�id4i(J�u�N5�([yz`�Si��1�B�I��;����<�Pc:p�|���Scvb9��	��{|�|O�_]��_����
�n1��p�=�3q�Sr�D9�3130����aB)E<&����}�/��S+E�S������o�aS�0�Z���Y�������"W�Rl��:_�2�R�(}���t�� JQ ���,����4�R�p�y��jP�\ �(�&�u���&��K2E��/M-���������l�!#����=��f�!������UD�����K2����J�:e����/��R�� ���z�2�
�"�u��^{����B��I��&#"��0z��p
�W�6)�`,PW�&7`�P��z�2SKF<�Z���t1,Xe��_*��L��!U�V>��be�!{'��L��q��^r�
���6)s^d��T��5]'E:�B�c��I/2�������mA�T��_,���z��$��,]�B:���c�_#mN�j����z$�����HY�@k�`���J���������u�����I�(���-����;����76(��@����R>������i�r������fp5`�g�?�X���qg���6�3����]0�g���'2��c��=I���|sZ�,�@j���9Z�Q��L1
���q�b��\s�b�s����0�9�=m�����0��+F��	73�9��m�����0�����?�:8g�d�M~ ��0�lt<������C���hF��4�2�
�y4�+�����Fo�G����biFw��{�)���]�>�c�s��0[�C������%]
I�B3���U��*pV��<��p�Y�q���P�r}�I�e\�%M��v
s�{]���
[x��z��;�.�m�=�}���ro�fSC�P�(��x���Q�'D��q���7E�xq�t��}�{�������uf��e:�P��S��0�L�U8P�v��F�����,�[���>O]��g����@�����6��	������+k��u

��b3������	W��@y��������d�q�1��T=������L�\�����@k��Pq��\�&���f������I�C���T�&�F��4�iA�L�.aV��]A�������a����X0aZ�a��L�5��;t+-����%L���S�,�����c����%2B�P��\�=��7����K�`"#�
�%n��AcY�QG��_������kDFG,}�^����7��?$r��FF(
UC�G��){���o�A�~�� ����'�C�4��UAB ��A��[��yN���-������r����f�����������u�����p��<������)/����vI;�����Opw��My��,�������y5���9�@�L����z�5Y��\��.�
�����!��?4��dD��������>����.�,��wH���We�����/.{��'���I�'��:���l���;��:��
:��^�5`��Eeh�"X�K�d��
��H2��$�@.3�<C�V�E��V�9�QI<�E�5T]�6wK2�^�\������.��`XI&�x�'T�A$����mJbK2W��;O!������k�����Fb@x5If�B$M�	����z�P��������L�������?T}�5/�,
�mEFk���j
#�"W`�m�zS}�V�mP���6��zf�d����5\m�YA$�����W��
$�$�B�����)���g$���=D���z��:��l�p�`{�����[��0{�x
��z��=%�$��}�C5�J��[e&L;���)��MJ(���A�.��f��8f4�.Y����H�^\��	��"t���0v@���	3*C��3�T��z���� X\��	3�"T���0��t3�k��)�8�-�f���`�re����4�L��K��S��$<����P-F��*����X�zm\C�4��'���e%��`�������2�WDV�Mf[��1
���`�:cTr�� �_"u�����<�%Rg�]��ZtQ����.��q/���j����C�9!�C��u���B]GB���w@]`_�����8"bs��v>�����5`��9���(���t��K���H��#"7��U�����i�U����d�V<6^�X�� �i����P���)ZL�q&C]ml�Y���b#��+�c����
b��q""�Y[���A�~��C�2�@DD7k�C�W�������q �Cmuc��E�5�C��f}���V�Y����y����:���Vi�YpX����[�A�5R8�aI<z�3�����=,�����m8����c=^5:��au?
�e%^��F�
jo
����:��`����ZV�
<�{�{ld-��t�����@Vh^��ZB�(������7�����eu� p�������4_g��v������q��'���'s!2hMOf}CA�dW��n���,��eM������3}=y�lo=�BhYD^Jf����B����@5��\-+��Y������iY��|�.��X��{����>_tqOQZ��0{����^6z��� ���XBP^������)x"BfQ���:z0�t+
��	W�L��#6����J�����"T�M�J1`�<�Lo���[F���./i@��L��'"n��|��(��S���Xd4�!G��+	I�����L�K&"�6��0���t
����)s�@,���'7`�+���L��#"�6������@We4�W�^�L�q{a�]L:���L�2eR��3
h����B�H�@Sy#��q/���c�qR��D��$�u
x�K�^i@C�^�n�N����r����H��0�~�<�e%���%�Qg��'������7]h8��qzB�w��DN6h���w>�q_�O6�R>�����l��B:����U�9����4���'2����|3����4Y��4��b�0�i�Q� ��<'���x|i�h�3������~��WIX��;qdts�;�%^������M1`����L��u��0e����n2�+](-+�����wZ����;�|&L����K��<�&��W�a�O�Y��P=��x�y�~����M5&)vf��������m�,� jL��/�y��dE
\��=<~���_�n|m�;���$�����l]��q���1�[���Fa��}���SD�1�h��)�a��"V��n��./��j��9�;P�Z��>�B�1�X���j�X��t�p�
�n�0jLn$\��+��Dj���x�-�B����=[������>/-y�u~�{<\C�r������^��}�C�,|���o�`�5� "�ZYx��(���!��������2�LY�6v*�t����,����Hd����m���C�����$��e��4���
�,|���o�kG2 �����ock�:�����n��!���4�������	�k���P����4\i@oS�:aZ��]IM���J$���5`������f����-g%]�`H���Z'L+9������.�"��c��FA�_"���FUN���D��!��/�h�!��e@�>Z�������(������sjL�y�vk��s���F����
h'����M��9Oz�(��G:���w�d������d���_^H�}y�����8"rs�
QQ�����&��}y>Of�a�cs1B�y�)�����,�����_�����k���d��1��V!-{1��s�}����z1�^���M/�&e���c/������G:\,:/�&e����]tV/�.X�KQc�����^wj����;��u�����d��C���2��h��KCgti(��(	���}�l����4l���K����+�6
���C�1	W"f,�O��Rcn���Ah�7���.����U�}i��/��[L��q�H0n����;x�?���>������7�����3�KQk�0�}���v��
~l�Sk���hm��K�h �Zx
O�������*�*E��<m^:O�(E���0?qdQ��-h?���H)J8�e�v�W�.�
��d�A)K����#
��v�����Z�{�xR���x|u[�^eA��������' /��	n"���!3���:@�~��O@�2�MD���������<����s����)�@r���������	3xefm�7�������+3kSfj�82d02�>�N�t��	�k���Z"Bf&���k�A71X0zefm�L-� ��Yz2^�(��)S^Dd���3�0�J
tT2t��A�2�EDF&9���KmI�`��d�Ly�r�n6�
&].��81��/�=R��,/�e�����_"kA������:T�
�c��������j4�q�<������|��Q��~r>�K��}K�>��,vt���8"bs��v>�a_\��)pD\h@c�r����Bp]�|��so����}�Od�I�}���qxf�eNK���H��LM���/�6'�R�xxi
��3�(r33�@)Z~^��?��iko��Kwp�����.���0]��E\i@F7������Z�.]��EDtS�5�|���.���*E��3����An2�=�y�a���4j�!�yl�����1$8�5:D�No����K�q{���Al�%\���#�R�����
�,�};��$���}�e�!.�Z���f���;���WScZW�jL��5�{��w��0�������,��z'�-��@�(�q��ht�.-EoE���8T�����s�z����e��@�� ������c!�����:W.���cn����-�>M��2�/M�'��FolnS�`{���x"�V�&��C<^C��^�;O�&�����zf�{�K�Dv����,|�G'�Y������%�Df�{+�GN��tL����]�$���l���7�N�2 O�O�Dv����,|z2����}�l���l���/��Z8�
_k���s�.�""�/��#��]:��5`�l�����FP?�������i%""�/��#+�\:��5`�����dyS9����5`���f����X\h@o��?�%2�%
hD�S�D�Q\����D�������]P"��h@�D�����P��$��"O�1]:��wC����'�*�
��ev�6`��/W�\��|����sm��o}�k�1��(V��|����sc���__H�������,��-����c���'�������o��'����fk�
k�^��4���t�0�jL�%���L���}�U���BbAf��v�`C���=���C�6���a��c����2">
<�H���o��g)�`dG��;��_��#7�O���to�td���W��Z������%��7�����qzQ"��������`y��^T���,'���q��,9������S%�����w|���gy�,FBV���y�]��#�0U���u��������������}����C.�O���������W������lk�k[����P�_�z��������l�/n7��������/��O��5���o�z ���������!;��#�7�/\�g���|3���n?����^�'.���xz}u7�Tk���p|�-��*��Z#�ECT��7��v���/<j
��<��[yY���,����kN����
��O|�A���C3B���y^�rx�
����Q��4��b�Ug]xc^���o�U����F��W �#�Y+�K��
����g�(�q����B�,<=�g���&w���]x��/��Yx�����w�U��mWF�:���`Z�86Ja�,�
�5�U�t�H+��I7�+�9����Y��o�5�V^����d�����N������`4
�M�+���B��<=�g�����T"������<6���������k������O����/�L
�r�K���3��������z^�nr�?����+��g�����=Zy�yW���'�������8a\h��0"�<����F�4��y]��-����O����\~��������U��`��X}e��7����^Mf������7Ze�%n��|�����A���9w_��v���,��w�����W�w�1-%�Y{���m\z�K����>ub�U���k�M}��������}���]{+?����k��e�[{�i���Mt��u�������B����"�����'�Yt�8�7�=��3��+��2���������H�R�w�3��q����S�;��*�B���T"'��uA��g��u��r��V�2��,o�%���GB���+�Z����J��j������^��W#'���K|����t�g��V�2��Q~���*Y�����?Q��+C7e�����u'�-L-�pB���i���:��;��ej�]��w�=������^z=�R��u'������u���#�������$���Mp��N+f�~�7Un�k���e��,���������S��,R�����t���v�$N�M#ouF�]k(p��7���h����Y�����+��	Zv(�R/����I����,��d�
�v�%��fF��F��_�H{�
.��i-��"������{$i�w��R/��Q�EoPK�o\|+�u�^�8�v�����h�����[<��i%-s�+�� w�=���W�2�
�qqjK����W;���&��|%��y6q�sf9���D�����SN��+�,%���jZ.�8�F]��$����)�O�/�]{l�9;-1o���-3+�����,N���+~����_�h��W�2�=��y7�u�s�p��*k��_[��\�@��jk/��zfM��r��6�77�.���x�����j�9iR~�&H��6�:[��fc�d�x�}��5)�ZW���{3����������)������r�v�=J���������?[�`���k���������g���X{�u���7��Y{+)�\{�M����o�M���G)�����y���(A3�u1.����|����&^�&�e��:���z����w����1�A��{�����m�g^��
�.X~}��[,\��K,��F��B�t���"-������,����f���r���y�-���7��wc��"\:�����C�����:�'��j�u��g�-�L����N��[r\y��K�a��������"?Zy�kO�q�(��'����	�7��8/��+V�yTe�ik���2�An/��5��U�,������;������T��	�r�L��\*D�V[{���:#��)gy�����wY{�r��j���J[���o4��&~�]^(�k�k]cac�������&n����5����i�-K������,	[��
[���o�����tv|Su������X|�B8�3g��V���z^�:Og�������{����,)[��*[���o4�-����7��K��7U�h��{��7�,�}+��Q �\|���/�%?�]|����y�-����hLW��m�ql��*p��-;.���F&DZ{���:����/���;�����y�-[.V����fy�C`��;������)�@U������C`y�������C`�(�^�W��rx�b���l���rx����:3�a��yE8#�X'N��9J�k����5��Q~���%���*[�b�o�E����.��+Q�#�O�M#�2�%�uB�]�|k���#++O�^_K�����Qz�8��e��Fc���,�����\e�=���]|�(���K�__�)p�u
�N�__�)p�w
�����mY�*p5ZfW�O���W�W��'_���^���+�H�\�+p��
�N�`_�+p��
�6�?��ee���h����n���-p��/���y�3���v�3�<�����u�B@~���e����[���AWu�
��4��*�/q���f�B��N��GZ|l���V����l���V�2��y�-+��F��<u9��v���.�K�~e����Xd�u�+���n��i�G�����V��G�������Z���]�-p5��=���X���%����iYuVu���~��� w�=R���U�,Y��7�����<��w�������JA�_{KV���� wC�7���X{����]
��]�2]�~ua���u�g�}�������"�J���~G��
����7��-�sWVq7�k{�<��V��	���!o����nle������kA�CaWg���4��mZ����]����������������E��R�������.���e���S�6��������i�3�<`?�-w���F�B\=�Iv��>�F��U�
�#-��]�Q�����]~-����J�P�~����B���������~�O\��d=���~����H^�xl��zH�z�e����{�����;bX���0���.�h�B�+�`���FZycI��t@����=PCJ��.��w�����R}G+���F�BkjC����t�.�5���k���M��#�j�s�&���zH�z��7����B�G:�A��+o�}n�d����k�E��m�m�]y+/t�.f*��g��������T��]y���c�����wg%^yy��j�>��c�Yyy���*�����<�}Nh����W^����M��Q����>#}�A���i�wg�^{����K��6\�eSl3/K�FK��U�8��V{���p��I��R�v�a����k��D}GmV��W#H�WFu�.x������\��K|��kD�r+%��
�f!��Y{!�a�^��^�k��B}GiV�������u����!�(���{��)P��������"/0�������O+g�1A������p��������G�.����k�K�s�G�NhO�	��� ��j:�����w��7���z�|�w9���?���W���5��y��-#�T�1�>q�!y���h��>�&��F�<���Y�����?���p���Y�����x���^|�����*�������o��n6�d�����@��g��6��/�#/�q���	k�U��+/v����0��b,�u�j����2�"�sy�'C�z�8�!E�mUp=�![>���!E�@��z�C</����n��tw+��_S'��l���w�"��-^-�
����[Qp����L�s�B����*��������`B��egr
&���s��
��J\.��{�x8@2�x(���:�H�vQf��D��
����jq��*��F�����E�X�W��/��"������YW���#�����`��W��xn�����UW\E�����R����.��F��_��[��	�L
��Z~���`�a:u�������K���������[�=G�r��UWZe�%�+=��g�A��N��������u�j��?��������H�oXAg���S?�F��}�A����U�B���\2���e���]�*&��1O��&>�Fc8������f��RI�v���O�9��_��N1w��<������_��y���!#a%E�����l�(R`V4Y\-��XVT��Kp��&��Y�U����3`X�U�K��������.��e\�Q�U�0%sX�Q��%��v9Y�Q���_G��k<���2��)?�]�!���_���_i�I,G`��f���v<����]�W��j	��%e9������`���f9zW�������W`��W�S����f���m{�
Z�=�t]��m�`=��SMY���_�_�_� �*?�]�',�YS��$���`� �e�]k�q-�j,[~����no��W`��n���#�0[W`�o��6*.�a���){~�����E�f���@�O	����CN:�{b!L9 H$�X�e���/���7_>�)�g�y�8��F"�<e"��(YD%�Jis�8!X�F����I��7����AK�/�	�@�I�|T��g�y��|��lm���,|�y�������E��Yb-L��r�xr���+!����������YS2�"?[[���0��J#Q�a�kP�U��Uf���q`����t�+��Y�]�U��r������r������W�J��\i�G��V�y���=c�5'J	���a�b&�oXT�n��`�@��$w>j��g�y�X!� ?[[���0���v(��@+�U���
l��pze�;U������
:�<������,�����/��6���'n���AI�����jf|��U��X
S�XJp�O���Z���n*�v�a>����J��T�8_�ZJp�7��+h�����&�$�T=��nu������,����.��W�3�a����4�I�}B#-�����-�XS�|��,�\�e��G�h��`N�\�������:�0��pb$a4*��&����H�d����VsA:�^C�i�����{�g��(������Ga�=c����e����O��7c.E/z���~�	�Wic2����W^nVO.�9sfe*ee.�}xw��5��UX�^�u6���x��w�PL�#/��O�8��f�<���+b��'��4�9qm|��$?�9����3/�b��4*�p��M�`]��'���F��<Op��XS�#�<������u�K��$w>Re���_�L���`�dD]��WW��7�sM���$���bj&��������5�jaR��8~G(&�d������x��-��VO���H�Hg��Sw��[���^A�?����v�]A�Go�����I#���L,H�{^�z��<����ES���%��:U��N�'���;U��N����;���/@�����Se�:��S�1w*7[g�X�#�c���=DZ�SA�������N���.�GA�UI���3f�'e��,��H��3�,����1�A~���t�fJp���Y���o>�}��Q��~�<c#����dJpO����xE2J�r��\�xy���	.`w� L�A
%?�Y��� �������'�H]UU�C"a�g��*���Y��@�Hh���Oc�k�t�#���{���3*�o��b���8�)f��g�0��w�n\�#���Gl��J���{���~��
���+����
8U}������9�M5�G��������#���������~��������>�D��������������m�U*.��Y�Ze(nDM��n���`Q��z���/���\���o~����������������O�����g��������g�%������������~�>����mv^����|�c��?��u���_~��_������\�C������odA���
���r�xk����_�J9m��5d����~����v����K�W�.������o�[��Z�����5����o�]n3=z3e�r��K]n��V���,�����F~�I"�
���F�X����&w�
�:�UQS,���3=�����NSi��?��X�=[����f��$����������k}Z�0hoF�����=]~-�������<��.�������'�#-?N�n�)�����%����m$�"-�1h������?
��8�@~����G�O��Z����S���z�.������H��	S
���9����\.�G!��j�I�|����2�^�h����hi��$y����E�z��H�E�Sp�O�j[�9�'��a�*��.��x��z����zc,�yN��`b�O�����Dg�X��r���r�8��H��7S�o��L`�]�8������F��7	
�zM�U��o��v-����H�o��1z���g���c�Or���L`�]���i����hoc�������Ig�������������t�9lg��PJ,?�Y���L`�]��B;�.F�c��]��SA���]������W�7�T���c0������p�1R�m_Q������r�p1�M'`���Zm&��v-��L���+
�y����c0������p�!���_Q��W�����>�	����
�I���
�w��`bLW��\.��`�
ol�I�|8���2����+�4`�X����
�v&��t
���
�&��t
B���x� L� 
(?�]���0���0����V`� ��l��t�q�d��]�n%]k��I����@pYt� L����Z�|<��B���+�o�
������Nh�p}�'�P��H��]��������Bz�����$w�=���Y��3����J����p�^Q���w7���F����2�n��15��w�����-�z<��2�n^�+�R�*\f�����7�)�>��c?�U��~u���X$��4R�58��[x��)��5��*�>��+�[T�8��JJh�����F�A��[URUbL�*)���;q��s:�����3�`�B/����K\���LJhO���1�U'���#-@�I	.`u�L_��/�������U0}�3��+q7�_�Wv�����<�CAh7u4x��q�@���`cG��j5���q�-�/@�g?�6�|(y���Y����,������D���L��hVb��������V'�X
����i�(bU�Y540g:9�
������L#g�'��549����l���Hn�������dL~���Nl=�hhh�J]zfec���>�=G�j`�Th���X340c:�2���#V3��?cZ=��zf�����`dL�`�m��������-��/�A-���1��}����x�0x
��G��������G�����a���{_'�X
��B�I�R_@9�Bp��X24L��L������aB���$�����Uyf��0/��z�r��nkX���h��LW[��5Cs��/gZ�9�������#0g����F��I��3��i����I��L�&
�L����i}������$M���_}����<*_���������H�6��0�#���8M}
��D:#q���"-�2#�gVd}�8��&����S��r������#���&�ph��Zm�%���.�����������ZyFE�'����A)?�]�0g^M����l����Z�}��0hX����A�z�Y~����~��?}��\��m���/�xx��i�����O��[����/�������_d����"��O�������������?|������?���}������|�����?���+�������?�����I�����?W�������������������������|����������������ew��Uq�����������{�?���5���-�������]{���=F�Qe�����������������/������l�������������lo�ryv��������G�y~�����a������u�-f�����w?��oBU�����?��n���x]�~mM���]s�ww�V��y1��>���������}L��7����������'�����G�����G���������q~���q��o�~oq������w��,�`���{�_��{������g��������|v����������R����?�~����Es��^����nn�/������^����?��o���[n?��n��������vC�����no)�{����n���F~Ovo����������c������|���,�;�6����o�IR6~���9z��8�t�6r7����\?GH�mh��Gm+mA|t��!�m���� ���d����[��MhN�7������Jo���y?����-��O��L������9G�R~��Pe�y�|Uz��es���M����+��{ ���������?��5�#����_3:~A��0�������F�2Jydd��7 ��%��g!J���R��\��~��Z�o�TU|I*]N�WE���R�Rj�?��������*�,�2#�%�86�U>i6�/��m4]U�N/n)�����J�>����t8
w���].:���=�?��6��:Q�t�y�������=���)Y�������jz���}w�o6���t�=8��
�,`����?�����������76��W�jH� a;�
u����/](6�-���*�	������X��a�6���}�z;�z�(�J��]�3�8�<q:9d��o����'���9�c%���r�k;��Y9�C-����y�t,���A�^�������������b�CdQ�Y��k9��6n�����C���Yo��1�J��.��7B+������2UAV�y��7��7�����>�zl{+�J������r�(��*��3���|��2��f���5_�G�f���7���<�m~���&g��/?�1��E�0+�v��x���Sh]��ZK�Oo��7�����|q���w-+<�||r���c�k���oa�����;���dX �U=�������
�k��^K�(�0+�K�|��R�u�w��c�\Ga�����|�d[n&6������R�Y�u�����,h>>��|��<&����G��mqrs���q���O�L��~�c�
���5�q/����W�m�R�}5������=<��{_��}��.��p���{_q��ci��5��,l��|����w��ci��5����|Ff���~�<`�����}�Y�|�hf��g�o�OuqFP�o|u5�gtUM��]:�����~>�zD$�Y�%�_���{C������a>��7���S��eF�a��H�s\�n�7�Z�*��
����b5r���_y��h��7
����R�5���"v]&c�K�����9�B���>�~37�Y���S����o��~���������~��������|���}�+R�$Wn��;���r�[��/���f��V��w��c���	�V4��~������qo�5�i?��"XBk��r�B������Z`��s�}������;�������r��,h?��W��XK����%����7Z�~�=?����Qt������U���:������*k"cb�������;�������&��9��p�����q��������_��K����o�=?���_c\�Ro�(���|~t���i��#�k�����~�>:�~���%��=7������`�0�B���l�W�U�=n~F	Y���:p���_}��c��7��_���1r���_}��c��7��_�:v5q���_}��c��7��_��o��7y��������o��������o���=����U�c�������X��-��W��������;���r�[��o�����o����>�,k�h������b�+�k���k�����2+�7m����~9�k��{\�V�/g������~EI��>�5��?.�#�W�\����e��
V���{~�Y��|��*��Jn�w�k{~�Y������*m������n�a�������R����W�����Dn���%~~\X����������5��jc�K}�k��9���~�=?������_�����_���|~����]�:���;���q����_����������=��N������������>?����5�������������A���#�������?F����5i����w�k|L��F}�Kn�������|���&c�K�~������������o���&�vm����;���p�[��/��c�������+�����R�?V���;���g��Vc�K|�3�B�����G�a�fE����|����w���{�9�?aV��8~��������q���hi?}�k��'/p������q�����'����_���_�������O �_��G^q�+���q�����W�_��G^q�����q�����W�_��G^s�����q�����W�_��G�p�k���q�������_��G�r�k��������_k���-����������������?w��:��������u�����?�����ZO���8�t�
�����^������z��5��-p���.�f�8x��]/�������3r�;��HX�M��Q[7��Ro�7���>�|��&}��S�f�}�_�r��f�}������3�����8�|��Y�������{���g��{�b�}�O��{����v�=��{�j�}�O�"�	����
Aj�"���weV��8vP��S������{wy����>����g������q���h�Y�_n��0`����w���1�a
Xf0`� �������(���{|%w�R��,�������-����eI���1�4K|�.*���<�R��+kL|�.j���<�	R4�kkL|�.���<�R4�kL}�n�6�=��gH�rl�=0�=���z��}#����Z{`��t�=������"�5`�=�3���M8��{`����El@����&��������������� ��p�{��/��{�`���1��{���|�L�GkL���N�=�����=p����/��{���|���gkL�����=�����=p����/��{���|���kL�Y���=p�����Z{`��H�q\�{��A�A
Xf��Y1`�QR�������H�W4���_"e�=Pp]�)����0�K�,�
�k��^"e�=P�5&~��eN����^"e�=�����/���X����^"e�=�����/���X����^"e�=�����/���X����^"e�=�����/���X����^"e�=�����/����x��}#	����X{`��H�=�����f�5`�=�5��2�K$����<���y��}C	�Ya�p���_����o������WV_�_l�>�������������S����/���,�_d�/��v]�^���w��x�0L����;�O�2�0����b�_],�����_-��&�������l�h����|�q��(���p�����0�1���|f�~�B[�����{�7�1�����4roM���F����4(��|�q�����l������_��{���2��Cq����?�k�����yW6Fp�����~3��������FD��	�b�`����[*��%fR����F��{cV��=X��M�p(��
7���|��7�'�Y���9M����7P�Eo����o1&jl�S+�Z�_�w�=b�q7v��1:�o�_�a7Z�~)_CD�n,�G���W��7N�""vca�����j?��B��/�k�EM�q������F	7�~��i��Y�'�G����c����7P2��w�������2���b���!"6�_��g�c�I�u���5�:���u#�@�������$�7P2��pEf��H��1uZ�S��&J���NVF�4\G����`?���5Jz�������c���u�w���E6F����Q~������fc�M�k��aV�=C8dc�����������lL����CpHh]����?��lL]8�����?�7Q2���?#���������}%��o��c���&rn������o�dX�M|8C�n&��~�N|L�������������?�M$�h?�1V�2�}%���C�*��1q�����p��]�z���?f���<����B��������������H�~W�?��c�D���[��X��G�������}��(�~u�����?R�?���u�w������s|u^�~^5����a��C
&���?�9�`B�����G����|��}��������������Am4Mn�������}%�����@���G���������q����i?]n��F�U��k���5�?��(5,��?�����&J���U�]
�&�����}%���A�O������h�Z�~�?������z�l�_������;���"�'�~���H��~]N�y��&J��_���0+�K�;���������
��~���h@����r�}#%��(M�~Y
Z��A�M�k>V��F5h���b��_���`1hm��6kAk-h������U�z��������>XZ���f2m���Z����kAk�4�L���c-h���|}��6jA������������F-hz�1��x�������?�@4�H��\�[������G��������l2�������EX#��*���<�yE���q��qQ��5\�4�M�������3_Q�|z	���a�W�})�nC���W"H.���}(�pAZ��@�!�&����`�lg�*����kV;�>��j{;��h��<WN���$�}T�#��Zo�����]�����y]���h���C.Kh7,�2���K�h�����
�������h�z���~����#2-��&&��C�t�����7���/o�&���EV�__��=�f�G7�0��_����<|�\��_���>�W���"����~��?��������M�W��l��z��)!4�M��o��?}������O���?���������O�}�����k��79�����/�)
~
o�N��}k./j�x�qmd�jhrp��;�%�>��h�L>�l��k���4�F������������/��-��_L��#(�X���������v�����?�������?��}c����M#�)�ZE��r�7A�z�[p�

���{p��o��-�g�!/�6��b4c�����\|���o���?���O�?�M�R������h��&�_�T|"����&��&0&e������3�_(����wo
����q7�e7�
pSF������=�W6"5�l#"����mD^���x���a�F�wY������[t�ow�f���������y��mD�3�FD<�1;�O�����b<�=�FDV�OU���H����j��f#��������k������1c��`��/z*fl#"G�	��	���mD�CF����Y/� �����lDd���w�7[��mD���Ap������,h�e�F��e�����&�T�3��?��B��\��W��%�j#"b������1�0�����>,zi#"\S�<7"�7"����*�F���F�;�o7"/�FD�6��6�����z#jd#j��(��*o������8@f���I��7�"���m�A1"����=�q�F���������o���t\(#O����������e#����Q�%�����O<2GoE�B����|��mD��.�F��g�bd��Pz���pP"
�I6"�"��;�]n6"��h#���Ip������n:#�QW�M��Y)Y3$y�?�����$��)7" r4��tO�4�>�FD<�6g8��V��p%*������Y!{xe#2�mD��\p�����o���m7��������������UC����RnD@lpfm#�?abD��Y��1V3�d#"�J��s����-���lD��7�FD:SW��,�0�p��
Q_�Q�fu�f��_����C�U���oi�l'��o���z^X�0W"�!#���	7ru�I�9�����7�@;��v��O�im��x��0��]�w����^���U^U\�
~_NW��@'�N���3�9��NLd����G.G>�����d'"+��+3'7;Qtm�C�z3��v���j���u�4�>�����$�Z�_B�Uq��3���7��%U+jc����3GRE��f=(�f��t�$?9�G�!�!�J�Y�d��|��k{�F�5����Z �%�G�y8tX+���E;��a�2g��Y���$����%��K8�*fPh�p[�B6�	�	q��ebN���q{t:n��b����X���}�u��#��+do�s��qn�}gr��X�q0�_`�Z������7������u��:y�7
����8s����C~�������Z�@��c���X������}#���9�ck����j���]w~�MS?�j���N,?e�U�4>�j�� ���[mZu���u��pH~�~�61�:��������F��������Vm#��^;��nO��A�����)H7��6^�6�c�M���k�+��<n������ec�v�����~�/���#s�_�dj�w'\�1sG����7�-5�
��,k�h
�x=���lUdElv4j����:t\&3���Fkv���Y�KI�q��(�������������H[�\�p
�z��gw���������)�~��'6u��}�(EQ�_���������u���������)��N~������'"��fe{��U��	pEI8���G����'�AO(�'���
���V�	������v���Y�^��U�qVqUQW_'_�j�������/�Mdk�s�k�eR�a����]yW�clx)�x� ������}V�E��F�;��z��.}����R�0�Y/����'w�NJz���hrj�7�
�lO�@��<���!"$�GJ:tts���S�'~.��b6��'�����!���L��{�Vq�c��k��
\�p���������et�`�N6���N�����|���x�����{Gdm�e���;�4E�e<B19}6�����;��[
�����v��'U�;�C�c��MC���:��&o����/���C�^{��I��,�0�r�]JPw��j��LiUn\�q�H����Ha�F��j�*-��a<#?��Hy��l3#��t4[�NF����^�0���f�Q��������_
����{�����������_?�_}���s��PY��-��{���/ ���/��/��7�N@a�w��j�T��'l��ff#�`��;�	���������]hHC�eN@�+iJ�"]����w�BX�<�"�����z<]��n%���sK�<��{�<^���C����p+����L�,����`����y�����f�$�?�� ��PTx�����>�_�Js;;�|0;�����E/q��r~�6�M�Q3�q�AX��Mm������:��������K>���}��X�p���n��m4g�;{?�����~+��W��4��j��	Z�y��o��i4fst��	/��/x|�
�dFwt�
��Q?�Z�&�34������Ch�p�c��k"�-x2
�I��d������}�:��WO/�0"�Q+���������u6��������auz�$>A������S.�%�}T�O���<�%���y����k2I`��p�����N�����a6�/}��T��	��HF#ugIU��O��^h�����=t%���{�
���M
�Q��:��W�g��8fW������<pW\*���(�:�K��.=���A8$�������mR����9�Jp�o���r����B������������������e�"fWA�+U��E�V����1<����i$���7�Q��e��i�����H6CE���f��lL�nc��ll%��T��m[��-Y���7�o|�#���LF�$���������:��7��W��`�C[C�~$w��3���){C���%�Vj���1L���P���7cJc�+$�V��7����*���#_�W�;t\'�q2���)� _Y����?n��DF���z�9B�B�,��%d�[`O����D�O���|�%��$�f'*�����-B�T��S�Vcz�u��WR�q��������%d��k�s}����������#�-�S4�e�j����F�xu����ACe���x�e�G�K�����"��\�x�i�c<�Vc({i�v��6n0�@:c�������e�����tmI����
9���n2���j��7z����^�-�=����Ps��
�8�f?����QH�qt�WSw�����~��]���=��?���Er�J�
�]�CES�d�o��(��3`C.���<��d��xS�W�U�]�v�;��������!Fn+��;+����_�[U��H	��c�+��FJ���/@���_p�K+G2`�Qo]no���RQ�$�t�j�Ln[^>Lm(��a}A����
%\��:a�
%��6���G�6�!���v1w��7�q�L!��F��m�
�[Y�Vj�3�������#��������?S��������*�n?;_�
%��M�l�f�������v;�F�k`=k��y1�c�����[0
�^YK���{�,�|��R>Y�+k����������r������L�K���+k���^h[V�?|�
��w�����u�������*�6Y.~��@���������2�p7zAUS4�=�2l=e/{2�����b]�.�Zk;���5j���(�-�N�"+�����7zl��n^	q�8:��(�x+����,��������S/�<������(�ae�)Wq��X�u�|�yFK����d���Q�p+^go�J�"'��0�Ra���\a�gb������L��}t��c�DQ�[I7�o
���[���F���pt i
�h�J�^�5��+�]]��2�!�c��R�/���,�E�n"�^q����x�-��"�"]
�&?�=��}_�w�rG��4+-i�����qt�-�9Q� Y��-�[�k�8n��v��_wtW�x'R��9��P�59���`��o���H��3�D�7���l���o�=K�f��
#�"O����(��E������[���~����8��ks�tj�	���M@��Q����K�L� j��qtS�y�����>5&X��x���j1��y��j�^�;���O�������'�����tXO8~�W���C�U5
�������h�C�Sx�n�-���y-�<�������e��$^�z�gQ�����Z�Ojy�We��{�"�����ky�dZ��>�{��atme�B�o���������wA���z�a��_>������db�*��Wm���,���ls������/��8��h0���]��7��������w������<��}�=��	���V�O�7�01��B�Y���,����BY�I�F��e�>�2f�����	$���S�?Qn�����YV���H1��"~�#�����=��C�y��2>�`��g����.F]0h�7���l�&F�Q���O�Seo2��y@�������Q'Fo�s9
�5Ty�>
$� ���j�
�C#��\�N_$yiD��o�:^�x�o�o$��uMo�����g��B���B����v���w�{��5�L:�����[��������oE���F~����^�x���m��VgN��[�Y�"����&�~��
�Ii�*��"��1�D��/��X&~~r&~�.�IgT��7^��d���eNy��x#���1���x�PWF�����<c��5���6w�8�C�^x5�{al5�B:=b��;r��%}�G"/���W����Gp�c��x����0���J�w���9��*T�	�f��/���Ig���;r�-�3:GW�_U]�N�y��j�*�.z)�6Yq�7������"���*�U�:OE9m^U��b��8��U�1�*V��(_^���!.0���1^[���X}��������:$U���Pi�����Hg5.L��Q�!�����06�QC�q������JK���`���PbU�yU1z����9��xU��P��v@=��j�K������#������*�5�.�����U�tm�����U%�c�Ue������W����X�c��0&^UF����x@�qU�TgQ���1�_p�(	�d<&��9��U��x3@��2_�Q��>��3 ��x�^Zo+�
�3�����j��
�T���Du[-�T��%+�-�����8��ja�v1�-�U��Q�V�[����^y���-��P5��+J��9:���{�:�Y��+�N��:�uU�Go(�
���-;Ws��f�a���u�t&<��sdk��������&��X��}I����S�����EES�����dG8Xjcpu�%���,�{NG����+����t<X��Y����M���9��iJ=��O�8���Dp�Z����x��hMN�����0}������bu��O���'K]�vE��������QA��`�f�g�o�
O��8��n bx����Z�����"��gt���=QSf�B/���SG�j���[��fo=����x����8����C�G�������N�[G���=O�A�������+�N�y��F��"�;���=����jC+�'��
<X#�V$��
<Y��v~�����0}�����e4�����#O��?���J�R���#c����2�2Fr���e�N������0�CcTm�i"&3�����<M
��k�L�B����xz�����]��*�����V�-���<�?
�x<\���kz�"P�5O���5=������_�t����{JO7l�!���S�����)-O�~L79��{NOsZ��k�Nk��1�U��NG<\#���Z�����1FW�J�8�^iJc���,���Dx���5���(��F�t���������5��D����H�&!�������8��y�T'�DHV�)�gBQ<]�p��Q�VW�H���R�]���!���&�x���bt���.Tq<��pi���i���gBQ<��p1�x���4l�!���t����3&u���x�tzQI�������5�]�}FS>;N=��{.��h�jF��=��:������y�Q<=�p���sV��8�x��i���"�?Im3�l��{�l�)����2��-7S���)�U�i
xqy�%y�}e��D���L���~A)zo����v�����NV	i����DpV����y����@�:����_}}�����w�mV�X�Z���S-�;6���F�o`�����hFk55�c�	���@��F��=���yr/��y��)�zb#k�w|a�_���3��7�Ft��PCl%��+�wY�S���?*z����������5`�{�`�1���>�����9f�t8���u��b�������.6*�Z#�w�����p�sM�����o����RhO��:�-��z_�/��z.�N\����xc��u�6����d���^����]�G��k���������x�^�vW�����^�zV#�8�����'Z�1������!�o����5�(�����3:)X�0�X�Wj����e=q�M����z�������B�G�b���f����p��j+�����t�C/F6���n
k<�&VmBr��4aX�8B�A0�x�{�j������3*��
���3<��4�C.Dp5��~��B�Y��R//i<#~j���/��\xOc<��W�kS�2F�C�V9Dr��b�F���c���h@�7�B�y�6�cd������xv4�S�]��-������������3�,�+��������&9�j�O�������Z�/�������W>��D�����?���~��/?������f}���_�������������TdE�?����/�}���_d���/G`���?~����}���������?|��������T�7�9{��U�������|���Z�������t���������������0�eY�?������
I?L?��K��VY��
���a�?oX���U��>}�e�����l6��]�
�-�����?�'�Pd�W���_�90v����ab�~C0/�V��1��$�84d��F��6�^��)sx8>�=�c��i3�T/%��p�iO��
��rK��5��C�u2�U?��.��__��]�N�J���1�a���J���]�����e�Z>�psI���qX�Pf=h�~�\'�!26����k���Ko)h<.���i;��0��9�V�/�K�)"�c�������h�e9a�|�h��2���U]o�d��MQ��/���^�6z��M�r�\��j�����;�G��?��	3���C�w2��V�-��f�n$���R3q�W#s$����M����L5b��{�
�35�x1�<����,�����#QZi� ��:n*����� ����Cx5���r���k3�Fz�Q�-���L�(��Ig����V$��B*����M��f<*�'C)~��:h��N���V�-��a�n"�y������T����y�N=���E8�ws� ��szz�hJC�k�M�xz�u0d������x�������h��4�0a==��j���*z�1�=��Ax���{Q���U�a��"y���t���+*V)H��f.��R��ws�x�������"�$���S'#����l���w("���e>O�_�Y'��<�E����e1�N{���xz���������(�j<c���Q<�,�����*������z���+d?�����p^����^k;���������v�����u��#�T���v�f����9��oG��<�?{1�cf�A�-�/v�	k�!:a��p
���t�%���tmNBd�fcWk����9q���	;.D���P�
�93j?^�D�w����Z���\���DS�o���U��[������<�^����`��Gga�Y�rB�����lY��u�Xx_��m�je`�����*�kUE�)e`u���:3��-f^����}��U}u9_,��*=2�}:��T�yV������/����_>�\)jR9���F�g�]V>Y�bAq�8H~�[E��-e�*2"��s�:=(����o�hl��;W�gi��}�b �!r&�'�.�-�CL��m��������jw����W�������o�Yli�kS%�'Y��.���2b*"�F����V��.F���������}���$L1� �_����,i1 ����X�z��+���>����!6S��Kc0��z��}�@�.�W��t�s�g�i�)%�e>�"�HaK<��\�|�u[S�:���'.q��r1z���o���jt�Ln�5�=���W�x�����j��_IE��xz�Ci�x�c��t�v��J���a����W���a<��[�(����gTR�xAJ2@�|k��b��^������/�'�����X
f������z�M���)��Q_�O<��ww�,O��
�9=]�4���/�������bG��o�}�Z�gh4Y���4��e|�>�x�����g��5��<C���d4�q�-������1�F�����.�y�F;�|�4���/�^����z��/�!��<��V�)�4w���KkM��p�~Q�M<.�ojtU�����F;�X:���M��P��;�<��$���|���e����_���~����
X�+����k���I7���.u���AX�pq�_R�XM�6�z���M.�|�p|[�'���YU��F�+H�J<.�Jh��8�|�x�W)���o����j�e��uO�=<][}��_�oo��j�8�v�8�k
Z����X���|�x
���+H��m��`E�����V2����W����xK[\6���������k�����O�����O���)��$�O&����3�����1?�"����������/���3�$[���`ZN0�������������_���$����h8Q4�#�NC��e�����q��zwa^��H��7�x�DM��5v���'n����.�2����\��� �l��9�N�U��\(���:�2��NfK��3{j-cE�M<��f.�=cVBI���P���������5���"��F�M6��VC-�'twJ����rU��r������P:��u�P�� ���]������5����������z��xC�q���3�����wF�9�&�x�6sC�V����o4^O:�Ax��5��
�M��0&�^qOc������J/��F�Y������R�L:�2F�K:��������WxM8�!����W�b�����I����KZ�D��������,�G�7���Q�����<� �����MS6����/�&����lg�/G�4F�\y�����Wc�M^�m���5��l���<\���kW���m6�9��py�}��E��x�������U���W���Y���� ��7����(���,r>���������k[�X��
�+<��}KDk�~��1 �_\q�k��%*5����Xk�i��������a
8��Z���v���r�}A|��:�Z7�F����h��"�u}���@^���\�3���&����pEV���3���p
���&\
/��v=Q��=k�q�Y��	�
/j�?WF;��������2�����X���������>�*^��_��;��3p�1L���h+|�OD��|���T���qV�U�1����3$�V�"����^-����?b����Peo�����9�-�dxeI���;��-�/:��/�.��:��{���<��������m�.���d�PZ[���;c���AG�����W�����2��H&��������l^M�=)�~Q����X N�GL��6�~��DF�No)�w�7�mpLV�"�~��|Q�M8���������W��d�q��y�&~r�t<�[��.�7V6�:��NrB����Z���WF�����Gv�2B����@2l������.�~�!�������to�;w����2l�A7 ��E��ar�Rt����'������QO���02l�1�`Mb��-��a�����n)8��������5�����q�����l�r2������I7�NW
��`�������4}�x+���5������3����x+���r�3�=^�qWY�����;�-��p�S���@��dq���y��N��.��k`�+C*N�i�P^���Ba=�Jm�P���y��L��7)��y�@	km�S����[iJ��;�0�7�����[O���]M�5O�����Ki�_��~�<]�p)N��i�W������VW��yK��E���y���T�57w��fk/���J���K�,�r�e|@�K"���17���t�m��KK�(���B3����02>���$�O���]���o�e�!��V�(�^x+������k���ne?�WH��wS���n2�r�j�7����&�)�W�������8�A ���p�X/�h=c��������Dx5��o�K<<=�[�Q�JG���{zP�T~�-5�*�J����(J����)[�.Ho���jN������w�~����W���jU\�L�_����Mo�����9U�F?�r��Z��i;~������n��+�z}��'���7��_�!V(�G���NB{�GY�e�����!�+��DaJ�����Gmf�x��[����1�	]�O����p�,���8����%���U�y�|��Vz�{���7���b����. �������?���?���/��r���w���������?~��
%S7�k��+7��"�5��-#Z����r������M���,���;_���Q��P���(�}VJHHJiZC�d��n��Z���&������
���0��B��|����M:�Up=�rs����@X�SHg8:�"�xHj��H�>nt|�	�f<�wk�ULu�����m�M�3$R����W^�x���J��c��t��t�������_�U�g��d��t�R&�����W^�x��������L�3o&������4��t-7��]�}��K�"�"��pC�����V:D^W�2�o�	�.�������gI�G`����:�C(Zp5Go������g`G��S�Go���u4�<��Imh���="X�M]���*O�W�A ��,���"�F����'�My��=�4�^O�E���#������g@`G�<YFe���8��';�0HGO<XF+���x<Y�� +6�[���e2���AZ������2��,7z��^����v-�y�)���������n���������k��D�N:\��1`�P��U#��,R#@F�N8�C��	� zt���{�M���a���E�V��X;J
�o���W��<����V�x+��o��i+���]KV=�jF��x���Dx5O?���G�Z	��8��N��a���*���
��K^�/��NQT��%������_������v����Y^����h �����y�'i���'�Ms0~���O�W��]2�5~��7���-���"����5��gi��/��0���m���m�q��h���zK�b���'��*�k�8��v�x1���1 +k[^���F8p\&F��bC/���2��S�*f�6R>�*���7Z�\�~���8���3���_n�j���v�8�U<d�l�&��;�V�_HL������s�M��Z�}I��C��`M�0�DI��
�3�mu��T�����*]L��t�U�>@IL��1��0*y	�<\��W��nIJ��$����w�t��^�x�Z�n<B�����c�{0&$�&^�qD�`E��/������PW�8�����{�/�+�����~{�D�+t�����
���+�
e�a�0#����Y�������LaqXy�����,k�����4�r~�=����Q<@$������,�U��
���so>������
"9z��2u{�����'�x�:�!9�W]����`��i���<�,�i���������_�f,�Q��O�	��t�x���'��F���4������h$�Q��������y��I �
c��!)��l�F�����/�T\��[�V�2 ���f@}	#2u�p���h^��T�D��c�Ug=���L8�e��	�*S���F�t��l��I���u\Q�9x\��3��pmyQe��!�+��P���s^�t�i��-�19�0��AT��-��L��(��rZO��b� *S�V��K�������*�2�2��^=Z���_��5�}EYO*S]2�Z�|����~�s��k��\�����|S������S�I�_�����p�?��6����t�T%Zq�V<�����*��'�th�MoI6��I	��nS�W�U�����	��'D��j�W=pC8lWB�]��%xUOJ<��]�[�Z�EKF�'w�U��I	����*��3>����+!�����vXq����b6�ZMO�"��I���v�����8����DH]�f�s�'\����*/-�FOJ8���V����N=i����o��']��d�#���e�S���F��c#Zg] a�������c<=�^�
��o�H"I�[��<�x���=�2�b|y�J:��_Xw�8�+�����,vsU�1X���g���o&���L��X��
�i���4�:����b<g�~m>���<e������ �y��-�4�H�HV�rL������6�)��>��%�J
x�W�tZG/Z.V����rXO/��,�����!<^c���cV�����u�����x���CO�|*��Y����4�Qci�E����l�g1<=g8\������R?�[��8��q��3j�(��q��9=]d4�1������4���W�t��#��p�%�yO�4�>�-�RgN���)���5G���R��]�%%�G�\�l)
��>>/X��x�T�g�M�Bq_�����V�@�+�'���������������y�i�)��=�S��������t���=�@����F1��;�]�pO�P%�n���O0P��,^q�U��LpyF8=Yl�)S rB{�m��H�����_o�)�|��h��e
�+JZO	Q�@V����k`O�-��/nC4��2���g���T!��^���>��L�x8����/�(��L�^� �z�h_��Z~��x�4��S�B���Ev�Z���}�o]� X���M���_>�R)i���4�Wph�c:��_��s%
/��+��Rg��$C�����1�)��=PM�8�Tp�tF��@5
�C�q�Nt3&+^��7d��l�Ig�P���y��x}I�q�|�)�[����Hj%_�����/��z���������,��+e�i����u2�GI��ld-c���x������#	W���g���\�0E
��2_h�M�Xa���P�7�&���!�������n�k�f&��&��,j���W���^��Z�l��,����������P����n%�5* ��
l���/z�b�����j���U�o"�1�o{��0�cu��j���n�7������\^o
2��_~���{�o����;�������_����~z;���*���������,���_�����?~��
�#��F��7^����6
��H�������njW��!~�M����[l�Oi�:l^^e>>����������`�Ul�x��h��[�QB{�����������:������n ��x�W�nK}n���B�5�+�Q��z��������DY�0	���+\"y5X���4���T�8�x�,y��&�{z�f8���#���!���E�����e���������������
������e��������e:�����W�����1�cDRx����3��Ds���W�lT����c���p��WKaV^F����e�N����^�t����pY�Dz^���������vM��u	��i���+�U�v��������^������������e_}��|���{O_y7���Jin��o�����.���_�67)���r�{��YE�97����QM�3����j��������?���W��8�F���ots���8�Z�I���+��d�@�2D�v��]sF-��gT��U�9��n�D��S#32##����UW�c���m1�vq��]O@�&"������z
6`���cv���@q
x���W�1{��X����7F�b����@F��Y��s��b?���5�����,���B���GIX��:g�7��D"����?�<�����~���0�k@��?�F6�DD!W)�(���3�q}�ol;���:�zfv�E�#N�,�f��9U	�p��x��P9�0��^t.�A}�e������<�������U���uq*�G�B�q��&\n�U(f��Pr}6�s*�������E��M���lU�NB����QM�]g�g�;�t�y�u���i�*���IW�>[�!&��C��^B�]�Hx
�'J���\����x�������z�&;��".�R�z�?`���xHW��v��k;q���7�����������_��g��w�v�*;���~�8]�����8���rx�-XU���6_?����ow�����q�����V��]��~p�g�dq�'=�w�}�h<C{o@��3R�,��u�B�Q(�E��\Y�@�[���a���a�']�q�9����V���=�2�r���s�i+��e\a�7��,�� �_�-�3"u��1F{�e\s���������:�E^�`��Z�N<�j����e�����1��t�}$tU�y�.x��*n��cL�.x����������G��t���B��~�y��R����P�~*�Mx42^����p�{ 	����z�S�il��������7G�����/����o��T�9N$�j���r�5;�����	?��xx��:����R�?=����]�O����	�c([�s�VE��P��Y������L��������V&4������Y�U�7�����x
J����Q��	���Mv��7���M�<���x�Zu�}B�#����u�=��sT�4B�+/�w�S������w����8P�Y��P���Y����BBV	���4�V�y���uDM)���Zk"O�.��|��ZI<]1���}k*�{6�(*���I<]1�T��^!�O�x�fp�����U�L�QO�.�_�_H��4�fp�������)�����������T��o�eV�\4V2���cli>b�t���	�/�����7���\[�#�\t�6�]��N$2�F�g/��.,k�`���k��w�H-g��w��������l���b�f���
X������������]�|�1{�5��m9#���m9�`��3 �8_�S �qZ��0k�O�Ei9#�l�h�YR]�r�/��3��^Q�������'F67��b���l$�JVq�Sxi<���g^����^m�"^����;l�X-�]����_ma^��z=�����4N�n�#�0`�*��������{U���������k�t���}~�<���*���N�n����<��x�S��Ao��/�r��'mo��%�`�x*��y���K��0@:�;�X����(�*����;����<w�[:�:�z��;u*�_+�j�
�x*�o^nk�����+��O��������O����H�*�c�������!R>s���~���f�zU���E����~�V0���e���y�U%��,%�D)������8�w��<��M��V��xoUy��O�������WE��H���������}�mf�=�g���k�0�{����C�t���ON5�)�^��l�N�o�1Y���c���T#A������:����=q�s�����m�J
�ul'����n �������4�c�h-q�k�[����kpg�v�Dk���H8�t��w�f����B�#��m�Z?%S���D�CR�x�%��L8�8���:����\6�Z�:KwL�JF{�5�A��x�Ek���J8�W�����t~���1�(V�<��l�N�il��q����x����n������:}&���t��:�K>~�p�P�\�(���5�1a��v������A���<=��xF���f�{��3���(��w�?7��x������m�w����2���6��FX��xF��e����3���Q�xRa��yF��%����b�����+����
E��|���b�����+m�
E��|B�]yFY�-���^A�=L�XyFY�3J��{��3��V�����[�*�(;�+�g�������c6O�Qb�+��������������P��yOI]�)O����?�S���������7K��W������xbL����&6�w�6��!�f�����sG�j��������D�g��F.x��!��������:����f��	U����t|�4\�t;���
�%FUa���8_:I�%9t4�����9����H������$�k!�f���v|�4���V�,�.'���74
�1��7���	���<��!�����{_�z�0����������n�w��	�Zz�6���N�f�}�`���e������~�W���F��n�s�X��b}r}t�1�4
���������x�sI}ryt��H<�G��M�����n����#����^7q;��#q��m�M2F{�;s;���lF[0����������&�'1g-���L3�k�������p�x���pB�|��ne�x����$_����g�����u ��V���� /���J�Y�l�fq�V~N�=e��)=0�<����6�cz:�hJ������UX��y���WdO�8��1=]4��9���I<]�(�x=O���B<������.s��O���%��K��<�~��\���k�
��y:��U.�A?���l�7�cz�c�'������@�fps��G'*��iN�6�cz���'19;/���ggOjv�<0&�4ggO��	���fy�$Fh�R�)��\D�I����x�&�{LO�x��D�I^��1��[����UF,��9I�x�����I�(��I������O�D���=�K7vM�(]4x��x�Y�������E/��\���kz�iJq��jyz`p��G�!&����2��]�cIS�k������#����>�~�\���k�=��yz����"�����$�f�����sFS�kL�{��"����u?��gG���^iJq��v��-.�bC�gN�i�l�1=�@�iR��9���eyR�)��W��@����Z��<�w�l�\V1�~���!��!==g(�1x��{��f��������5�%�w���dE���{��;G6�.�w���\�������Q�x��;G6.�w0�:������}z}Y�o�|��+��
�R������� ����&���g��`|�G.F��#/�[����������C�C)*����G����X����P�I�:���x�.ENS�����;��X���yz�*�����x���2�)�c�F���%ZZ�����U�K������M)Z\�0�$��J�R���=��T.�3������{��;��PVj�RO�{�����\K��5��1<G�;K�������YF���
�K�vM7��6x��{������b��(��[�f9��nQ�m�����+.T{2^OPi�����5�����<���{�lr5\,��;�N(;�2�$��\���k�G���{zP{���������(��\����.CES*���k��6^�M��	e�����^8�{Qc����4���E���eDI<�9��x���e�iJ����������2��Ty`L����e:l�2�4��OU#��xzfp����B�x�#h�����<�E������4�^\�D������Hc�����*�E���x�4�^\U���}�J�{LO���^��R��9&�4���
���O���z���5C���{��;G�f.��L[NO��w���5G���{��;G��.��L[NO9�w����@���{*�{�����x���<0���J��?u-k�R���!�i<]2����{���Z2����O]�����v��Z1�T��{�5]1�T��O]����5�5��k�ZL<��$��\�����MFS�k��Z�k������E�e�����~���?]et�=:���#�������?�������?�����@e��_.��/�����n������z�n���#�������E����W6L��1�+M9�j@J^��~����_����?d�2����S�P�V�-�Ot�������O4 & ����Mc@�@>�nX~�s(u��o�Mb���>��q_�����k���w�&1`�]���qcl�UT+b�����4V�f�mF�=�F5`	��3����IX"�y�}q#�k����c�~�#�1����F��U~]Fpf~�%-��q�pcl��M��V�Wr���h�Jc��]O��'6����
������br����p_��c ���7'=d�<�����:����'6��\["�#���y��o1��������CV���,8*��M��O`���}qe������>Wn��j����S`s�AAe�AAgx'�����T[8�����AA�s���U���z�tU��4�yoyz�j���j
��4��>�oa�V>�m�]��+�h�.������f�c�������7�z��K�
��Z��h=��*+V�$xH(�g��"��x\����ZH��4��i=�r
���5�'�4Rg2����k�+lP�gW����(����z����vj_��<p5�9!�.0�J����hR�5G����������M�g\�xe<q���B��>���0�u�����->I���>ntw����Zi�}6�cJs�����Gu��]��J]�����2rq�����(���~��Kq�>6�}l����}lmg������Mj���0s�E�F@�Zd�q���T!�n�1�J�	!�Q�������3���h��y�.���7�xB=���J�������K����_����;t5�w���?��-����w�������|/?��k�/�v9�y�p���Rt~S��u��o�~��������~�Y�i�~��w~��������~��S(.������?q�]��]����n���2��w����������/?�������o�����������>�s�����?6?�������j}������/������������_�N���
+�V3�y�����O��F�6������n�u�>�;~������������_�����W �f?+`;o��U������������oG��_��&�nrqVh�<��E���_��w�
#^k
�9��w�6;���:��N�aH��6���i���K�8���.���k��V<I�jDn��+��-�
G�_j���__��{����d�������Yb�u<�t�p�������_+X��!e��\�#7DU���:����q�*L��@��qi�������v�]v�����'�Bf��:r��Hj��xB��U�[��h���Xnf�D���O-��~`���������{c�i�w�S09�U`}���5l�3��4�jy����cY\�F��J���
��D:����4����3�g;�����HW ���=�`;���g;q6Hc��t�,��k�,�Y�S���K�5[��o�G����t�l/�il���?��Y�ilWU�2B��6��*F��/d�����=UC�E��u5#Ysdh�k[W�b��"��&���q��E���E��x�t�=���`1��
x�����G�Fq�(�������;��,e�1��M.:��chQ����=�Z���9�!���
����wi�}=�1�t"��^���������}NS�!]r��
�K��8$|��1�\L:��yk���.��dYwoG��?4����\[��7^=����e=�{�1���g!���/l�~��[S�a�;Zd;���d<@���O��8���~�!G�!�d���������R���)����}�xl���t�d���b�9M�g�F������C86\�t6��Ng��N��������BM�d�i�3����q4q6th���Z��
�5����PE2i8"<���BQ
8BQ���0����2/�,��z������Bq
��3����D�HWg����-h�MTh���1;�"�F��-��oD.�������g��A]��{m����:�6x\���V��D��������3���|O���[���M�I<����x��#I������Y/�`�5�U�w���������y�xo7yt�&�&���W���<*���{�:�����&�&kN��������P������.�7�K�x�/������������j�.$���������?��z�)�n�B�_��6�I��EHr Z�'�G��&�"u/��'c1�Y�{������F{��1Yy^�E�n�q�:�fu\�/�j��f�l���R��i4�>�:^K�	}
��p���1���
q}�
$�:�0�����\p��n���i3����k �����;����p�b�����B"�@�������]H]�^p�����(I���e���B,�f���)��k��h�M�E�����SY:���c;�n��v��x�}�����t=�����`;S
���oI�;j^�Q�l�����.�:n�
���|�����tB;O��&�]W������v,�2\�v���Q�S7��@��`�T��{�i����
f#r����Q/�S�G���9B:�����#����4��f����!���xG�����W�A\����4�ZQx�W��#�
����yvE�AP����(t�d�#{zbp�	�xz��x=�}�N��.�=��D����2g�]���6x���:i��\��w��������4;	�xza^D	���^\?1R��
y�Yt+c��[.���f�:+_l �����g��>?�mCN������*���=�P�:�0��V0������(�'�T�M:Y
w[���X�
�yLcv���.N�6��:g�O�E)�&W�p�.`��4��L
9�,N	*��Tc����X���CVs����(����U�NK>�w���l�����7�Z�M<d����^��R���	������jo.h���V��_+a����e�T�~�[�j}v�gh8��
��-:���G��[w�v�W�������+#���u�O���v�w�.�.�����+�\���)���SE��~p�9��_��F�~���3�_6Z1'stb-�B����G�9�_�!b�S�}�����l�
�;��Yq6xO"yRtEEK�#�}	�W����#��n�qH�v�u\�d�����GK�u�v���T�M��p�q��`��RJ�G��:����>.��(�xh�Z6R���d��e��F��}T��cE�a�����P�_��l�q"�R�����XQv��o�{������i��>�(����)�S��q
�@7"�c�^�K.3O:���c;U���v���/F���e�I7�����o�� ��Q-QIl���u�J�r7�����R����v�M���R�il7sG���H��8����o�w�O��|��EkB	��f_f�����il����p���Lc;�|�'�n%�8)�*�8��c���� ���_V�A0��DO�;��
F�I�7�8�g�xk��z�Q=�f�"�����k�#��z�N�H�<��4@���V����m�ChYU�y��*XO/�������}��<����x.�&�����\�CpY�5������)Q�~i<]2�����I�i��3�cz��iJ��\���i<]1�T��R�o�"�Ku��I��4�(�Txi<]3�T"1R���k��@�@�����<�~�(
����G��^�4w��@�@�
!�U����^)
�6b�����
>�clioN��|^�B�+-�'O�a�����=EVD�:?��c�Xu�[��d����O3`�q��1?^��t���w��"o�������3�SG!F���-�c\����"w�=b0;�v0���2S�g�xLY
)�& e��S���eac��"w������=]�`��Bfj�x7�3��������=��M���Y/ ��z�)�y��A�;��>������($�^��zBX�|�zOvF�����g��4_�Q*�3����R��{e���+�?��s�lG�O$?wFE���-N��.����i}�n�������EUEo�s���+���b���lO��'��^m��� �S��19�����h����%������:0H��k��>��"uRS/���q��������L�%�����eT����/vRo���F�EUR-����(�w_���P���j���:�3�1����"�V�_�3����}|�R��i��R�x\#v�	����2�,~���1��HE8��WE��4R�'�����gcM� /�k���t�E�B�Kf�VQ����)�g�}B 3Nc�z��gu�Id;���R�������
�������j��J�+)�8��H��*��f�h6�'�����.I�������f6�'*����z"��e��v
"��>Q���t5��������"&j�T��G��4��`�����k��4j]"+��y:}��f�R���,�<��s1:�h��Z�R��/���4��&��k��~P;�uO��7vM�x�4x��j�XO�.�����������]�CES�I�jZO.��`H�G����28i�xz,iJ���P���xzdpEt@MtdO�.c{�5=�4�?������w@��_�^-~'c��[.������<t�E�c����2�zb�@{�n_#/�����w�H����q�2�m�v�c�6�8g��
�����&�B8�mN�E������������E#j�e�b��J�a�o�/�e����7<�s���j���m�RJ�i�A
��Q�j���<H����L�$�^���B�>��C�����C����,����e�������m.~E��W|T��2�6�y.��(��\������F������b��Sl�����2�W@����B>�����(��[���pK�h���F�B����(���L��U���O:��
�6�_��p3�7����d�}��U29y6�t����u`������x73�Me���.�YM�{�B�p�l���RLL8���
��-�����O�������T�����2v��������n���X��������)&V���9��QL\J5�����C���z_��8,&��^-����n"]���
&,&��e��������EG?�N�X?\�\�s`r����n�
�I1�8�5��&�5�*I(M�8������p��"�4�I'�JQ N-%�V�����m����p�P(Lb����{�5��Hm�O�<�f-9��-�*2��G��mW���p�(�Lc��t~���k���R�~��Ob��$������!�g@�}��0��&��u��j
Hb;v�T���W}I�(�(���l�3J��!�l"w!���������$��q��`T��il7�N��'�$�c'O%�������F�������H��(��q��;���.����8�����;J�{�hyFi���w���Z�Q����
��v]N:qF���+�l�����E�]����H'{�x��@�-����_�73\�v���I�<�F��Sm��y�j�{�����Q��sw������}��ce�w�~��n@���z��v��������f����F�Z�g���`I�H6���`;��G���f�$��&��G�l���e5��z�K>�t|�h�w3o���" �������{�1���R�{�����<���d�&$����t�	���^�0�-~�����e$�V_��+�T�U�J�
z���es������
f�J6F��&��s���:�]|�O�E����x8����$��3�����������J�4��s��}"����9�$������/��<�^��x.��2�����8�f=����+M��e�B-�$�.K�R��/a��iN!3�cz����#����j���%�i<M������h������m���x�:$����a�8]3�\h���52��y:��f�1��*��^gx
�K} EQ�BI��=O+y�$�n\���d�x�epi�(JV���i%����-�K���qOw.�a���o�yz�Y��}��;��\�)����hJ�(2�6��{�^(����4��\�)��u(iJ��2o7���A<�J�$����e8��(X�����!���zzdp��G�j����1�czz�hJ��W����������#{zbp�����i�)�kL�^a\O�.�({
����3��\vM���1���zzap��d����;���%?��fM��{��=GF-�zR�X"{�jL�q��j�1�J�I��H�i%�T����dO/G]�MO����sdMO���I��M^�z��4U�����9�&�1������J���.rZo>���-LY��B�I'�t�c��>Q
���eF��6���a��<�w��)\��aY����.�p�5]U4�a-d�eOW.��(Tmi<]1�T���{�.hJ��Z���$��\j��@6E��t��R��]�T1x��{�����E����D�|�������+M�_c
Y����-�K����f�4k��"�{LO��7i�����:M����-&�:�N�#cK�[.��u������x�����w ��t���8��bxhD����9[����h�K{hD^�[����X[�h@j��l�_���������OXId��mB����M����.�]t	]0D?������WLM{l�e������C�C������V�r
�����iV(����3��g�������*��8�B	��P��I�(�B�b��.z�v2���m�/���8�x\��5��\<:+���=]U��}V�z�T��wu�#�i�/<�Fuu_���x=W��^J<��O�����N��.��
��+3ZOs�<3��^��4����@1g$<l�����]d���S
�����xUA�	�����xHo��|	�O*���h�/�0�5^��x�90�47��j����6����a�u����bo��D�p�;H\�5�'Q���A�p_xZ�l<d)�����x+�'�Yd�m��]��2R}����K�7��:<���2���/��������'��_���������O���R����������mO�������w������l��H~�����o	�D��k��s�}���_�z���}�������� ��E�� �Si_����;t��kt�^}���to�����������o��;�������j�{[f��.���� ���s�����j�_�/�su���l�����o?���?~yO�����
{�U3,G_X��`���^�#����Z������|$��������|���p�����Z��B6���-�����~��8����/@��~�����q=���"w)�;G�ho�p�5��t"��u}��e���p3��t���
+�@�K������q��j}@�Vu/%�ws}�������|�e�g�a��I���2~��s��8�xV.�Uu�������d��PJ-���qy�`��-�i�����e!�yEH�5�I�����G��������v!��f���;������]&7���L�~;�}m�9��GX��6����d
w���e�J��P
�c�����-l�{�p2�Hf������^I�I���~6;D���2~����x���
I�Q��}��+���s@�_��b?���f�,�o��2��*����-Y����+�>�s��������g�N�K J�%�8�o|r�_���
=��8�V�k��+�o��g��xSFS

�6�Vw��f7x��2��.>���������c������I����Ad<(a�g������v��W*�~x��F7x+���J�'�����f��h����}�o�	���b�q�h��N�����/���j~_)z���w�!r�F��R�}���m�GH�}�tS�����w�K����ev���v_�����[���~��q�Z?z�o��������&����~��������b�������i����C>�pnT����� �q�6lX��m���;�"�������?�m�9���7��9��5b��O\�l"0��,cN��D�2���F8tL���a�BQ��/������PXR-c���x�^��k8D?!�� ��R�[Q�����>^;���p#�DN�v�������x3]�>|R���s��oo�~fzmR�E*���
x��^So2Qf�o��]3�'2V��7O$�T�%��x��D��������'"\��<���+�9���]e����xKF:��d�E?���*���z�3^��o�I�����i�E�lT<Ka�5'��-��]��3^�xjKN�l9U�p���+����82?f<�i��nf���z�S���3�*��X��x*�E)�"�L����#k�[��{y����qs����>q��TdE<�,����.r�Rt�J��$�.��1�'��i<] ��A=���B�X��'�tY��J�8�D�
������fr��=O�o��f�����4�f~�P:�����e~?��0�1�?���
��4��E��h��Q�>�<!���x���e������
�K}��w�����=O�/{'�K#���%+��[����|O�(�0x���g�m�\ZQe!58��!^���N�]�B
���}Q����\:�*�B�x��������ra�gNz��O�K��8MK�cl�?b�E�Rq����6{�����X�cS3^S�����z�8�����3�aC��u�����q
8tD��~����
N�#��w�x
w�����R��q��8�H7�~�p�K8hbF��C""Gl�N��8E��;$�J81�A�E�;����r$	#�"�������U<�y�(a}�E��Ou�C�-���������S��?�����+R]��y:�%2�Q�����D�[h=�*�|��V>�/J�(��1�k��F�z����,����l�Eyv?�zyF��:����:\w
�3���Fl�!����{�_�t��J�������v���,��������+8I�~V@�e[�����Zr�����.�V���Z������	c��������z�w8-��n=�������1���=�a~p���_P�zd?is�
u�����n���,4�l>�b����uqg��DL:F���}'���/YWZ��^���@����(fm
�^l"&�w�}���j!w\*��p�����po����H]��c��T
��'�N_�}��^�bT�����"&��=��g��]��9p���%S
�}��8��
���q�����"��f�}�)��.��~�"~����'��m#V��m������l�����3�3�-��<?]��|n^k'�t�x�
�a1��0�j�M�P%.��b��'��������Ou&o�\�NTQ�o<��y=�%o'�H:�Z���]�����6y�8�*����������"�M������	f&��T����[|�����m�t5�Tk�'o�o�+f�F�e�2��G�<���5^�G�3��5mI���}��.Wo���yyv]Mt�}����/������[I��}����y�}��-��r��\=a��n������gJ�<�� �y�����E�Ae���/�
#�x�Dvw����:g^�x;�0r��9��x��Qe�F^rS)a��:#��J��]E�%1^�����Q�X�T����J���0�Wg�S������R�r�n�F^��������x�UjQ����
��
�*��T���y
�*B�5���0����G�F=D�~�ks���J��f����Vi���U���x��������DVe�=�+�'�*��oy��J'�*�`<�*���t�n�)�>#��T�����B<��+A��j��t�����z����x=�����g�x$��x��;Z��N��
<$���{�xH�!Y
Hb����A�������(���*���H0�����c)��z����1��;W�4�
-���J0�Go����xg��f�sKir5��������g�����j&g~��Qf}�YIw � �.<1�~CB!5��Y����,�����"	�o��������[�P�/��^O�<��JG�����=��Z�~�c���U-�yZ��$�.���}��0�����y���<�)���������@^��#������.2���.��������|������=���Rt��1��������J�{�.ey�5]��j������D�t��R���@��t��Rymf���
Y0��<�MO�.����1��k�:;����p\���B��'�4�K�D���.�ap��G9��������C���������~����������[T����sdE������}����\Zg��<����=O��#+:�N<��c��q�4OK��
�K7�\��V�g�S��.�����2��#I�n����}i�e�).�E^_�q==4��-��^�xz`�TON��U�c�b�����1�)�lI�����##��4��Y"��GFG
��^iJ1[R
�'�4�7����4��\���%�z��(�yz�D����TQ�1"����b�����F�Bh�R1���YtjU��t��������-��Jx����*K�i�E��T��tdO�.K�y$q=�����=O��(�D��z����z��\���%�z����g����N�����z���#{:�i���%�z:o`�\��T��i<�#���g���^i���q=]�4��-�:!�x�@p1^oM�]xR.�{LO�%M�_c
�����%�K)$&d
/�-�,\���k�*hJ�S��4��\*�| SxI<]1�T�a�4�E����9��fpQ�"!��z��"�{PO�4��{��w�x�ap�����K�J*��1=�����#���L�������L�F���t����]�-Z�����L�����U
3{�O��K�vMwhE(���B5q'�4�K'���������[w_�]�.��UZr����`����_����������~9�s����~��o����?����������N��������}�����|�#������
��U"����������_�z���:���,��������z��	�$� �������|�+���y��c�J���R=�\L#o�|�+���W���T�����Y����[�g�����������UFW����_y�����������o�__��/'O��uY|����x&*�������;�T6�z���F;]�]�)�HD����*}z?s���1N1
X����%�����=b�*p�u�1���x��!+����C��|�6S�m�<�-v�Z<��������MP�9A�tX$��5`���,x>4 �$��J�0����+�E	5�$k�&)���s_>��v���u�u����Q���z$\��x\�����udA�.�wO�k7H<���
O7���a$��	t�R�����m..�����z���)�l�e������^i#��g�x=�\<�Zo�i=�r/��XoB���z���G������k�O��Hx+�������l�����]���f���g���)������:xeHe�)�K���kW�E����[~u~�XV������?�_�M�������(�p�������������������������w�]��\�����8������{~����������,�}w���������������������������/uy�����\����������������������?|�����������RpZ��7,���fX���dE�dE}�4,���6�u�:�;~����m����}������/����JA���U�����	?Y����_�����~�&i���-��j����L/k��$�(�y���fF�
^"d��6�8��Yu�d��p�$�A�F`�+��
'��M�����V��F����A������o�u�vdy���q�c��z�EW�����C)��s!w�;��{����L�������\�B�c"����c%��y����9��Y�=^<��y*�_S$X�CN8��Su95�2e�����q�ad���Y��/�����E���mH�Xy:^�g��S��O\����OD�*Z�Y6��a��`��t��>L�+��O���q�nm�������)��m��g`�Sm�,?Ui��X���j�|7��R5�'D�o���U)�>�<n�M�O5�o��'j{q"�3��tx�6�'Z�O������x�����Ni�����o��U���x+7�UL���1����ow���e���{/�.�o����n�Q���H�������]&���h�����Y������8��g<�e��f�H��EIG��2���
�!d�^�4�h"��2�c:��iJ�;������o���9:�f"�p�5�c:����8���CdGW8�v���KG��m!�1����^hJ2������5K�C�Wm!#Ks0T\G�����9�#�����KM�$�nY��s��:���4T��ut����^��LG��,m��Pq��?����(M�h�VtdH����<6��1�1E"���lpGw,�H�t1Evt����
��=�d
�qtz��1����9��)��F�>�L�����b�GI�,��� S��T�X���r!U�\K�/Jb��2��/���F�KT1���K��
H�r_��V}����J��?��1����pch=D��%���s`+T�5���p�IuP���|����,���F��c���sK������F���LD����ki�7����f��n��0j���)���3T$��!�L����-�H�-@���l�N��84��l!r�F�\���-y�H��j41�o�^Ov���=���*����4[���e��o��d������4���y:��1��<�N"������Y/��..^[�zB�A
��Q!����Y/�2�Pvf����]���<G�x]N����O��m��:��3]W������_����~���yU��ga)�����@{�x]�������[=�;n��n�#���g�|�e'uL�@�������I����H��a0r��A{�������a���tj���&Bn$���;�,+�R|}��.�g�N ����^ 3	��s��'���{���^�O������.�*�2^s�����\(����2^�N��x!�����_��YF�q���'L�#V�?!T�����d����A�xfs��:�Xl����[.��gV�9������Y������L7��)��R���-��FA��{2��w2N��$T��ksR��Qz�H�=�p�c<l��F���x��H��Nc�����c1��z�K�@:�gQ>���w2��f���b�y�b�v9��+���cj�x=�E�5�['^���:����g���O�l��t�%h�/�����z�K�@:���o��
��xV(%�8��c84����b�����t�aqb�3h�4o��y8PoYy�EoH��l��~�Fc��I���x�����$�d�I
I=1��K%����sF��7���
1x��uq=3��Je+���Y���+z�hJ�$[���&��?&�j
]G/�,o$Gs��+��'��u/���Jb�����i��e=���k���C�������wd��^������W�7�G�1���w��#�t8A,�m�]Yx���q�x�����o�������%������K:� w���]5�Va3���y�Fy��w��7�������8W���j��C�����m!Z81\U�E�m���k���M��Wvp|���x�;2����z[����Uu��#������,w4z���G�oF�k�Az[���~g������%Z������d�[i=�T������Dk�<='���Mz�A�64���I/j(�
�q�Vn��aP��K<^�V�-������c�*��E��W�-���t{��<
�����(
(�7����Yo���fh6^�zq��������'��Z���Y/}C)��u�
���t���[h���^���h-
ZO�����#�!�k�����k�L�������mf^��z���4�s�������{�U��<�Zr�)?^�U�g_dy�s3s���J�-�����m[��^�$k_��������N�r�[�2���g�|�e����@?x��o���_� o?i��X���H��2�~�Z��qC�����d�0N��n ��2������U���.��}^�w$]������j2d���
^��w���O\�=�|%���:�y�����}�����7l��3M��J��1�_��K1\��@>�Gi[����e�D���#�-rdP��UZ�my����G��m�p�5Z���
"�-�����w�x��y@�'�-_�6Y���j�UN(N3���'�3���z����]!^(?�x�;���3^�l�[�	f!�xGhD�/����x�&S��:��W��+�3B�:�o"���W��I����g���g^�x�;�7t=��#������"FJ5����t�����WsW��)�DMc��t������*��O\'12�g��,����HN�R.��f����'�����C�*���1��k@�~l*�����F�[��OE��']��J?!�����7x��gl���W���F�5Li���J!�P#��{^���H#lX;���/J��*��{�^I#< ����/�q�6�<�~.FV�%q���2(	9q�H����e8�4���I��?��"�$�XF�s����l�Y��H#�u��e���d�]GO,Bg�P�K����e:�4Y��~��mJu�J����E(���L�����e>N�<Y����/0*�����":���b'<F��8�����/0Mri��,�(B
������e���W��W��$V�<c`Y���(H��sh��y��<��8<�$3�C����h`�_�?i`����g;���!�r�=�7��~u����`���eH�	tl����_�|tt��@G$���?�@,������'��_�(��D��3@�tRr��1�c���`��1{�s���>>�c����[=�n�����"��8Q�gv��n�;�sK8��	k��)��(�:�p��N�p1�u6p�F{��J�4��(���l�����"�i'ptt�^9�.�*�p0���>��mKS�y@�|dO���3��v��u���"�2���Ep��]���G��q�Uper��
�B��G9�)��0����Y/�����B��������
2��{���>7���o7{���������x�C���������['��{���k�������������_LY�'��>�;n��W�^}��_�78�Y!�x��O�������-��\b�n^��MV{���q�F2+�6�D��t(�3���k'O1Ku����:�"�f�NC����
��[�P_�0�����v�1��r��3�����{�*4
#�c��;���C���~R_;�P�c��\�e^����}�e\�xz5\g������N<(�w��[�������R���I"q��	��q)�N����-��h9�[�t���I�[qY���.���@�������Qpk�^�N��v�q��U�����.��f��}���H'j�[qLc<���g��}���#q)���6}�'����n%���x<B�}��%���_����o�k��f���UF�5�P��I�7e����yw�I<&)]�4��I'��?�x�U&����(����{�e;sWQ��3��xH�����cf���*����N:dv��8��7���/~�s����t�aD�@�=�
���W^���;��W��/�l��;���+�-������UFG�jw&+]�9"M�vg�����9:������;��s���qt�vg��a������h������w����t8ATRK2}+��@}�`-+�����CwG�,�H������R���UAS�/a�^���K%��yz�1�T�kk����E�M��L:�Z��+
�4��Y����u�)��j���t�x4���b�����9P_;YQ'`�����;��e`iD_{�{�nY�����*��X�1�����~#�O}�O�������,���U�x����]��
����*�������H}� \����=��/N��5\�!�n�O�E�;%JB���I��4��y�|��o�)��� ]���Sor%����[��A������=W�����7�Z��C��"��_��>�L>$�xUN�	1�G*�#�AM�x�U���x�+_@��m&wA!���s���+�E����F��z��sD��9���� ���xMN���*�\�p�7��#�!Kd�����o��T	C@�}\����D���H&��<�����xP����G�^�xT����GPUEd<^���G^�~1��G-�<�J"�-����v�kP��JA���������G��]�Ju/���F"[o�h=1o����1��x�w����<G��x�6��U�U���-�Rg����Wp�>z���E�6��2-���������������k��D�}����2-�b/��
�,.j��'�eM��LK�\y���PW�~�V���S����H��~.�H�w�b	���t�9��3�dZ�H�=�3YyWZ){��p������5]�����*�^�i!m��u\d������A�q�#����?�I��pXF{�u�9
�����q�W�u�������B<�(�w���fW�@�\*���VR(��:����h���8:-���x���&���c:-_��������I:�N7�3����2*�P�E��Y���Q)����n���_��t��CnC���i��?$rW���~��\O�����d6��o�>X%���xxz��Fb����4I��'�j�W�i��O��'��Z�N���n�1�x=�%�!�H:������Y:h���������>�N�y}����/�;��f��W����������Ha��x��^u���o$��/T�]���Sg������J�����.��
T~�a�m�]����.��!���t���	�+��0^�x"_��x����\]��d����\nt�6\�x�yl�U��*�Kc��t��b�1�U���BU�%1�
�0����(8.T�������'�D:!X�����Z�u���$�c���&�r^/��Uv��x+����N�B���!�m��.��Z�[qH��z��N�x����$7�� ������:U:�fQ'��$7�NU�)4���Io�����0�GM�^i�������OM��
��g��G2��]�=���o�����F��m�*�h����a�E��G�AU������ �*��o#�*�8����T�c>oTG���0&�F���]�M|%�D>���
cH'�����M��LB����
�S3
�0���������k�o"������pW����f�+i��&�D���"Ji�f�+i�0����^����7V���	���)���]E����7��m	����)I�7d�����K����1d#������Q�x=��|���a�G����:�v�B�9Hc��tB�j�s���}�I"��(w?��\)&2�@<uT���1P�~��G����"�9W*����b�G�J�*������R��H'T��7^�]��J�=��z��Me�e[qW�D+��7Ob�� �����N5w�ZTI)��4�I'6����x
w�Z������#��z_�������V�6�
#�z����J�������x=��\%5�xz4�'����J+�e\�����V�^m*I�G]<����s�����a�x�a<U:����p)�GU<�=L��QV;U�Bq����D:!���r����.�
#����B����b`�U�����Kb<n*�����0���YY���x#7�Q�}��x����62^g{^wo�c��pQ���_��'�����O���~��~��w���v�;J���|����S���������Oo�=$������?(���pJ���}��_�z��=���x���kZQ�=�A�j�Z�+���D�=���H��Q='������s|F�o��n�s����H��0�G��(�������zN���$��H'���/�#�G��(��?F>'�JNM�Md<)��9Q�A'1�J:Q�������E��:��8n�p=��}�KUF1n���&�o��?4]U�N���]b�p�1^�x��\���H�2%{������D�D�S,��u�=J�i����z����}��Q���o���o�1��v�\�
R���o������3^�F��8�jT��������U���>��mg�	��o��&�{��W�_^��E'^MvO��o����e�)��g������cO��~�G����,��)�^�����e�����ax5���b���q��?������UY��I~��/���n��K��{���/�%�Wu�w����x��",�>
<�����.���~���E������o����@C��e\�
�S�5��,�x�|���X�q�7m|��zJ5�4E��&�z�3^@��l<�_�g��K��9'��Z��x3��3����iI'd��_�a������}�o���	_�������<.$1�����c��$����Y*E�e��$:��<@_&��0D�{)��|ys��������x3;���3^��,�����E������9��,��Uo������P:<�/h�������=�{PG�4�����h�8�(iI�l���$�.p�0�c:�S�q����qtY����KE�4�.�h6�c:�Dy��;���4�f#��>�����#�E#��]�}��o�R�R%r4K%*^��eGs�����5^�g1OA�}�qt��R��i�I���������M
�q��K�����s
U���E��-#K3vE�A��G�K~G�,�?\��������������/0��/���-n�O���qt��r�-~4G�%M�_`T�bG�,��oSu<i��q�=������/0��0��9��p��9J�h6��C��hV\���\�v�8�fQqQ��@GF���s�BS�������(���S�#�TvEO��6x���g�X�a�O���^��,�Gs��j?��mJ������,����4�fi�������E��j�M�hU��*�q���r1��h�����;��=3�2�(]�b���%�����+z��h�w�wfl��h��������4�q��V��G��[r� �s���WK��x�Q����8z���R��(��r��������.+�������4�����z���Qc)Y.�>�����)���j�O�����
�e�G��]��cd�nW���_��Oz;��6��uN{��U�+���5�K�+��j�z�;�R3��u�e��+M�_W�BG7�.B$W3��8�axi���:�����cJ%����-�K#t0�@�4�n_���K�����{��;A�t-��JT�����������;4�����3dK����y���+#{�gp������%�yz�Y����
%y}�!���~9���^b���w��
.��1,�.*ZF�a:���_b���wO��.�P2*��*ZF�q<���j�R\c�IOO.�9,�.+Z&��?���K�R\c�nJO�.�U/��+Zf��;��^
�R\c��KO/.���-w�^\���kz�hJq�Q�4y:��7���?��1��m%������K����+H������D���\8��o_��UL�����g�o�.B�-��X9=�~�!�Z#��b�n���l�k��b���t������a�+k��b����N+�
"��zo����Yi��^W���)�uEi9��t����zi��Ki���x�����)�uE	O��t���	�.�:�����6�cz�/hJq]Q*Yi<MQo�uvo�:���=�K���:d4���H��$���[��<����:0�1e�"{z�)����J����e:^�u2��9�x��iN�]�D\�_�����������Q=1�L1u��:zBS��{��;����-�����I����2�����]��yz���ufl��������Kzah�c
y�u���x�w-���8zahY����7H��W��%��W\OSe��=O��![[��t@�|�%�f�n�Gt�����gx��;'�N4��>�zI����Q�t�Af��{LO�
L)D�s������S���AH1V�%
��3�1]T��Y���RG=LY���Xq
��3�1]����sz����R
�6Y*�d�.Z���mq=]�4�Y���ROW-�Pm�vnB>�0�T1U��z��hJ���K)�$��[j!�V���|�al�c��E��BS���\jq$�t��R��*����
�KS�-����T��R�#��[�F��(��{ k[���mq��������AGw�-��	����cd�b����s7��Bw:�)�4~fd��F���s����Tm�����!��t.��I��3��~| ����JS�+��������>%q���2�m�!��q=2�1���:z�aI5�[f��8zd`�����J�2X��j^q=���gx���'�&�1�;$cwIO�,SL5����ZR�N�F�$��Zf�UR���g��9�P���^r�RO�F�$�^[%��s1����e9���	m�)���<�&������]%E��r�	��e=���	m�)��t.��)<�g.��URT;+G��\��������3��iy�I��<�)�����Y9����b���t>�������Di<���~WIQ����EE�U�����������DI<] ������#��,h��6��X;���y�I�����Z^3i"{�bp)��bm`�J\c��'��+�J���;7��h\��6��y]���9^y�x�fp�E[I�s#�����>js|�7%M)����'���F��4;7��h\��6��y[���9^y�x�epiE�A�s#�����=js|�wM)����'��;�N4�K��$��\��6���V�R4��9|I<�3�t������������9������������o8(BF�e
.�Q��Oh�>0x�����F�At��������e<jw�	
��yz����2�
E�\����\�����X�}`���w��M.�h��K��3��t���+�����9���e����4�=�0�����������sd���w�Jb{��e9l�t�V4���H��$�^\V�s��~�^\���M=���iY����EO�����D(2x�x�����)}O�{/�"�)�p���ue�����~���?]et�=:"��~������������������w����/��DE��M�}���J�C�������]i�X8M����?4��Q����M�����p@5��^����w����R��X59E%I�g��X��f��n>��
8D�����Kc�����1`�y�J�J��1`���*qf1���O4 {���3��Iz��'Ot��w���SmZ���'��Y�.Q*d����CV|K1c���6m��}�Mn���=j�|�~Jg�/����WW���4	Wn|�����PLn��<��J2����,*^�����\
���pY�������?��a�6��n>����s���$��1����y:��<2��F��<I��k+Z��@Q�
�������p_��G6�t��6^���v]N������y\�uH���c{�$����B.:��VZO���E��cAR�
�B��q�����W����"�z�����huQ��?��m��<�n��[��?����g�������
�������E}��d��W��o�~��������~����f������3���WL���p��Y�������������,�Y�e]�e������w�������_~���������o��?�N7�9���U���������W��?���������_�/�su���5��?|����������=�p:8����F�7����e=f=���DS����������z$�x�,��D]�#��/}���q�W `?+�HT�Ht�A?��"k��?���_���f?i������53���%��fd�����k9���5\'�������{2M8hQ�A�`�r���
��)��tH��������������]�!����q��"Dt�_���{�u����Q�q�@�����{�?�:��3���}P�U-���1kH���f3��N<}�2��z����+E�u�b'l����7F{N����x.�rl�iFU��z��NG��������?���L�LN[g���b��#��0Sv�����2|?�]�P�fx�2\gT���%h��5�R7�p����4��l\+d�J�����������9Pl~�l7���n�:�>f����rs�n!�����J��z��IlW����p�w��3\�v"�>�f-M�1M�� ����v�g�����$��I'��z�4���)`�����������;Ju�<d���������C<n0����|��xuA�Hw���$����"pI<]�pZ������nx:��;IVz�3"pI<�B�Vz�N���J�6�v�
iJ�;)E��x�epi�kI�;��-�K{ �I�v%M)z��4XOw.���(t'#{�cp��;	����N�NJy�$��\z��R�NF�4�s����2�R����$�����zO�������2Hw��+M)Z��e�.��> ���|�G��1���e:q����Pp���G�'���2~D�m��J������>o��?�@��:2d�k;D�%�&���>UE���t��1�g��t���B��r����j��F ��b�����D�k�r��u��uk=�����3Z���Z~��k<9�!-��k4�����W�I�������������	����F���������k�6�����z����F<����v
v������V��k�+������r���-��<+������6*�}'����Z�@{��U4���������p�����+x�������m��&�@?���~s��� Dk*Zq1����|W���T\L:\]
�)�TpQ���k7()
���!��h��W��I����>�_m r���]�!ZS�����2�\����2�����nE��#���}g��S��m�2~�I�t+mG���}�{6	r�J���H��i���3�WV�b&t)#5	��F��I�t;~���+D$]G�I��M���.�63i�Jw�q�zt-����SxQ*�I����:t"���v#�����PxIl��N���n��;L+:�
QY���t�a:_�v�5����p=�h�=��]���������q�3\�v�:{�.�
��}����v�Qz���M)���$��Q�w���;� ���h�=���0�N�(�u&��F�(���+�u��}w�Zh�G��F�(bNaYF��	��B:���n��$�����G)�������v<O~.��G����H6����m7�l<�H&]���t�d�w���_?s����7�g�o��{M���^�_&w��@����"����b���^y�Y���u���^�,e�����$��<��~�x-��xT4h�G���m<�uM<m����H
O<m��K��>�W{��W��q=����=O��%���m9��tdO�w��o��m��=O��%����$��1�=��K����b��N�%J<�����4�fp)��
���)ECM��K�x.���V�%i<MY��:P�7X�����m�.Q�1����[=���4eE���E�CS����{�!��cpiT���q��"Cs��o��CdP����sd;D�Vt~���4���������+M)�1��9���"���c�yE�P�*2t�2����l����$q4UE��q���S���]��ch����������.z08!�������i}�8��Hk�>6�,����?J:���������k����=���H3�I�B)����Q����"��� ��qt@�h6�GME��t�f�q���h6�h�2|��x�f��f!��N'��x�>}*8X���*'�~�5��Ob�����������bm��p�3^��P��gq�E�\��Yd�-4��x�xUxSA�)E������B����q��P+7�Z���Z\��������$�c����P��zPg�J��R��]���l5���30���+��wN�65��fj~���g�T�sW���M�~;�q���*:��Q�]��8���P����|M�����������t���u)����h�k%�R4�(�����R���)A���}��?z�����7#]����'��o�7���?�������>���3z�o���#?K��(��a�}
�m./�����N�?���tB�?������!-c��H�lXqt0�'�k��g���B)UV&�5�5�
��]�!��T���}�u���������Y�&������):�:f��$*=�_�,��D��,"�"���C���c������dp�2���^��}H'p����'��Qdp�q�F���=,�$���x�r7tH�N����tVn�:�h������o���
�b�����F�F��t~L�\�`C���OM�Rx!����t�#{�|������Y���3��I��w�QilG�A��l�Z�dC�����w���(�HJ�"g��v�Y.����w�rGY�b�K��
���yy�w���,{w
��7�!Q�
6tL\�����L�F�X�1V���^s�o0��N�S����c���t^���~�w�{c7x8�����E1�=��~i���t������K���CE��z����������{LO�M���KO'����!������Z�=�n�{PO/4���%��%^��R��q�,M����bl��6We5x���[c�W3�T�*k��4i�t��R��]�5�"�y:yk,������*�������r���r?7�-Mv{M?P��*k=s���$�:��r.�:%�Z�n�I��8ur��
2��{������8��b�YL���vcA:��N����C~�pc;��F??��w7"?g�G���
���v�����T�]��; �����qM�C��y��f?�U��5�>��N���r��{�R�e�Q(�\���qm�P#����������OOTo ~^�����6j9��@2�`��L�'�3���5j��Z���L����y��_@=S`�T����V����W���r3]~�t\~�����W��j�2k��?$�BmZ�����_�������l�\BX`X�����z�W����ib�|�Op�[
4��c;U.��v8=�g�h���[I�����������y��sq`�la?��FK���`���~)o#�rGS��p������.B��Q�f��n�{��������������v�]����:��;I�t8��al���^��w���^����Jd����N�.=���!z�vQ2K���� ���1S$�P��#���H�2H14M��c�6M���*M������{0Mq{������x�����"M�������{�m�4E�>}�K���:�g��v����������(]�4�,�_��g�h�/���g(�_�*S�-(�XT���Wo/�_\������d��������&!�=���o����;����E��kU[}������OL�u�!E>Y��;i[G�����Z���k�a���.���gx��.@+,���	��`s��D+4_�2�����������d�[h=��0��'���������%~�����Rn�]������_���{6x?@�eX�>Sn��\OL#���a���0-w������h��=��@�������l,�v�K!��������h^]4/����+:���8�V.��P����-�O�������x;C��q����@����p���������F��gM�t�J6���mq�_K�_�o���W��}���
��.�klTJ�W�W��w��������������V�l���-�+��y�Y[m������-�W���OZ�?��.�)��Y���#����l!��S���>b\���xT����n�x����P$uK�U\�����8��3��?�G�t���w����%����cn���O\���Z�������t~�@��7��[����8�sX�
7��B�g�c%�qu����2v�YI�td�)J��V��t�wV@v!�;�z����J�t�K��q���Q�S�����;k��g���Y6���s�Y�����~7�����A71����0��[��&n3B|S��Id����������y�h�-��["��5h��K���~Y"��v�>8�e������R�G�����������f�(B|��e�Q�]I���8#�7��_!_���"=�o-iJ�)�l$U�q�Y�_DV��W�_���I<}��O����.2x�x��"��
��tz�9��9M)R�L���9nt�{LO��������s�+2�R(U)5�4�.*X�p����b�)�C+c�Ryz�)�V���&��Y3���Gi�l�������w��
��F�"�K5��n%�����5z@�V�l#z�w���qr�+Z\�1Gh����p������Qv�	��I�'������������y��|��6}��x���7�Gl����H�HO���k���?MSl������W5�H�Bh���I�[.�&�������������zQ���������	�|�.�����v��~�#t1�@����g"�G�tSI:��|O�f_�q�M�+L�����G��z7]U�3�������@y�����$N�����r'ty�KqRZyB_|�)Q�4�[yB_�	]^����'t!+��w�����z��%�Tf<����
����D���;�D=��ptY��n��`�r!�DW����)�p�b�
��{���B����v+��~5(������E���]�W]�=�wW���p�b;��9�:��;�Yb
��u�E�o�MG�J����	��8s/�����E��7H��/�e���_|�gbkMQy^�HI�s�Wp	.�%_������kc)|����s
�>E��=���x�P�i�Y�:�z����G������l���P,��:���f�Qm�Voq�@�a�����R�g���c���4]E�����hb��"+�<���hzN��UN������_�������a���^���i��I�(��3zU��x���GR����-��^`Z������P�r�L�D���"�i�7��Z��E�j���;�1���zq��V���z���������?�����/��;������h��(�������{�E*��S>47�����e���P��T.��|��W����~z�����W�#�`�O?�F=TV9��F���5����������Q%�����?vT��1���I�wo�3���x�����J����Y��h�gM��u�N��p����m��I���}�n�0u=�"bU�r��(K�3��5����J���h����c�������k"��\��kcp~�Q��,������M�rS)����������u4�
b��7DFB ���hu��h�����=p%��X�����8�����R �����U���AE{����&�KD<iU{|����[��[df��6�
b4��aO[�4�����)6��%7y�|#�DF^���&.��QS-��Z��
���BW[]��.��KB����+����G,�B�O����J��x �fQO���a�oh-��~�S��?-���V�o�I^mD�a���j�o�.��Yah�
�c�Z���_�v����A]K/+A:�iV�_�)"���[�������'���>-~�IM(��kI:&�V�|*�����OK<&���:�e�"�:�3������}�^K�iI�O�7*�=�:�s���A�q��Ve���G��]��v7/Tv�.������L�����@��9����"��;`��p�����K��t��������~n6���O���m�CJ�p�B7�|E&�t����Z��vmI:!��E�	
�]�����@�)��v�D���Ha;j��B3F���]�kf�4cd?[��^�������;�����R�dE�=�#��9�G;=��_6��,JY$N
�x|��
��T�o�C�
�a���!+O0����W�!�0��P)M�4�^i���7���)���B������ �u.�^�_w�����vIO%-�_>U����c���l���������2��]�3���\�N�4��[f�h�C������ev2
�"r
��my��r�#�n�LC��:����O��H:�R�QlW���U�w��5n��{����e���v�-�QlW���a���J��al7���Q���l�;���n�(���*I����T�k�8I���i*��l��Z��c�Sz,��s�#�]����z,�������C�����
E����D��
��!��^���7�%���P��s������!�L8������
����qJI>E��lv0z�+���E1�f��pP��0�a��]���9����r�����2�x<�+�������o���|K�"K:����s���QF���YO�<�����{��C�,�V������Ik����`��t������"�i�G1���3�}�1��xB]��R�`��t��b�/�����������g�O\��O�}�xQ��-����2������xh)��^T�����|Q�(ol7Z:����.�-��
���E3����hE�zTJq�o9��cK���Yc���n!��F�):���r�Y�������
o������p� U�;����|��k[��x=�=6���K�M���X���K	���R1d����4����1����5�CJ��j�p)4��&h�9O��VQ�r�����IU��xmj��a�^k����W�`����Vtl����z���b�oQ���}Ux]N�}\����vf�r�dbl�./`�������9�����M�=L�b���h/f�B���*��qi.�>���>�T��J�G����gs���f���?�������&��te��.e[u?ki��������f/D.���������$�4�D��t���<S4W����H[��	VZ�	�4��.DN��n3�!���{��{��D��xS�,T��1D�v��yI��j�����!���;���27��+SX��c�1?-X���HD������!v�/�Yq&"���L�-r"m�0yH�2��X�Q����}L����I�E0r��A� ���/��H�u���q��W���df������|�icI������O����<�4�� k����?�'������1�c_����Q���c+5�(�4��6\�N|�i�U�?�q��d�mG���+���b�_�-��?X2�_�#I�����h���;^�:����:�PVg����(^�$�������w�)9Z��PzU['G�t��j�O7�����"w����� ��������~g�Q���w:U�_m���y(n�[���v����F������]��� 
:��S�l�R�B:�fe���p��9{���v�#�����YL���RoajhQ�R��pq��e ����.(�0^�x��"J�6�V����m�q��,�7x�Q�����GY��������}���3]��|�1�Cz���M�y��<��o�'�(����R�I�$%�4%������q���R�
]�x��i��[��3���z1����tQ���0�POO����x�5}����k�Cp1�X=�q/R}�������9����"�7=���#F��2zP��(�k����hw����7��<\����~��_��w�������O �����������������@s�s���|�����m���?����z��*�D~��x�?v(�c7����������]��.~�Oi�����SR�I�!+T����%���1#������gj�x�b��p*�&"�l�DZ?���l�<<���9h+�y��;
�(��~�w��������"t��y��>�����u/x��!�;3*�,(lj|�;dO�h�y�.�;dOu�~VM��G��t\B\F����C'�D8�a����X"t��������{Xc�+��b����#d
�������g���9��l��E~`vn�9%���v�����]Q��b^��_z���X�n���v
�@X��X�Q#��� KJ���]z0���t5���n$������kqH0�����c��z��;�:�x�0���n"�x������� �T�n�����s��I��c*��e�E�n�L8�=���7}�����s�7t/j�	u�z��,���G�~B�*����=7���j�G�;�0�63(�97&���#�3CL���Gr�����
���i�C�n�_���$DM�'��S�"�l���ul����.��k�y��n*��4��R�#!����vS��(��na������{Hy�������mp��<�)�sd���8�2M��4P��x�f����q�+�!�-���Y)�AT����WE���FV���D�l1D�#�t�UE����{��':��!�p��}�':2��
���\�Ut��-:w�e{���G`��T����,�4��l�c����S�C�����������S��h�4]���:w�����\��\W)U����v�����$�f����>7}"���u���g�%}��6�P�0��$V_.
"O=��Q���rI�Y5�g��� ��v;��/�q"�Me�@}�� �� D��3�g���Xq��o�yD_�1����ls������#�rI�8�no�O���aD������_����t��	?qQ3�m�[�4&�q"#�gA�O��\���[���g2�!����i�L �BFv��[u0����>�P1.�g>N�%����J{&��8�q��?~f�Y��x������O+���>��5�?3�0�l�[�O��L�Z�M���8��f-q�2���SW��B��O�9���W���2�������j..��Eu/y��N��������
���P�o�Nj?��o������[����o���5������~�*�W��wWD�I?���#z�G��~D�Y?�W��n�����(�>,��D��M�6�2��Aas�U�Dy�G��'�.�w��B���}Y?wo�����A����^y�w�6i~������������W�
�v�����	NO�"8�X�SF�~�?���htb����al2
�Qo�������-w�F4��!�Q��7tmI����������+�S�x_��5��-W���(���W�	�o���>�7�~eP�.�B���E��r_��W^�"Q���p���1�1��
�(�x�B��m�2~I8K���}�5#R��rdP�b���b(Vl�xo�b�(�������)|�+��5�O�+A���c������t|K3�[�L��}%��s�l��yU�l�H-���C���:�`4��P�����	s)P��v��5^�v��qlG����!�`��x��B�z���n%�������4�++��
��|Lb��#��l����-��/H��������r���������xo�5�.�wW
�S�����j%���iTk
��%��r���]�b�ulw_�8��&��y���������.q{�O�����l��
Mby�-��v��r-3����B�^�-�V�H��S�e[�Z�C=�r�i��z�	^��<�L���O0"�[4y���f������9oz=.=�Z�x��;���Y������=
X����^hJ_%��g_O.��E0�+����<���&b���Sp���.��Y���#���vM�L���m�P��i<���z���4��\.r�G�4%����2eO3�	����_����X��B�h���y����tj��-���g^�,VQK�fN�5�c:��f1��P��i�0��yU�m:��9��p������wP(E�4�^ZV!��`�JG3�����I�%�8Z���;A�dp��>�qe~���6\��I����u�����Y�V�������zN-�+�#�?��t����E
�����[A��
Ha��g��cJ1V|It��k��SL��[I���������M*R���=�{�C����
��?45����&!��8�Io���P�~��ym=35{fH�7=�}J�h���W�P�!^��!�}qe�(�v]
��oIWn����j���py�Zn4��������%]�
��e���-����;>gA������w�p$5���>��}��dc��cOO����W����^("�]��3�g���\�<���u� �kDB�j/%,�M"��OL�+Z�D"=�B���D��Ob������\6	�HNx���w�ZX��H��=�����qw�u.c�'��������_���B(Y�'�e����2@P�gaZ��
��^���:�������_|l������x�t��������_��W�AB�����\�K�P����_�b����kq��]��]06�Hj1pD�A����6]�c��.R>�x�i�����:b5�Of��t���+�����a?�H��|�u��Eb9H�1�B���w����r_���O��.R>�x���������+���v_�J�G�.���b>�:�n����cu�rdP��[_v����']��#�"R>�x1E�s����������;��
�9UQ���#	�g-�$���
���~�;�:MF��Cm�N���o;h��y�%o�'��y�N1�Gko�f��Y�&y>���pJL-}3/���P��%Y��@8��	�Cd3^�v����� �x|���H���
���pd��<�	��2���L=r%�]U�%��+��z��=��+N#4�f���Z8�{���c���E-�*,��vC�	���
�&�)E#t��=�x<�4���
�����5j�k�����L�K<��V5B����t��1�=��ytmE#t��=x��f������X���;P#4Yy9�D#t��=x=�K����X���?P#4Yyk�E#���L�����������W�c���2������Z	b&�4�� ^�jD���#c�p�>h��m,��E��=�x�-�P�������e<P4Y��c���MO-���S�A~�kt3#��Y.�&�����z�k��V��#g��|��������U����Z���H�������l�Zq���g�����z��M��{
�����,��Y���B����G:�u���N�������Z)�;�L���4�����>C���t89�!�%����^GI�)?j1JYV4�_�P���HM����x��V�;<�{�8���4�����2.��XM�[`�J���$��Z�s�Ry���t�x�g��������x�O�h������Ee2O��z
rZ�����{�6�&�{�#���U:Mw�P?�����!��nC(n?��S���j�����/N#��6���k�|���1U����l���m�4��;���"E�����Y]=�������/@����Y�O�>K��02S_����P���C:n]"Q�'��8���� W5���!��j�\���q��4}��#���y�r�=I7$��jO��E~~�u<��1)���}|�C���s�\)�����:^�Pf?�tE1/�����F�����k W�EM���8}|��e|��H����p��$]�t�������kcu&�~J`1}�L����
�85���W%�*%�8=A�[���~��Xo�����E�_*&�*Q��|P"�M��w�Ob;��*Q���4����3�c�h���k���JL�����j�bh�O���9�� ���l�4��:���?j;�V\��V���L�>'�]WNHP���Il�!�b��Q9�4����&�uG��V}�����jpm��C�qy�����#�����<
=�3����5���	Fh�]��x�C����+M)J����ZF{�+����
@�=��G]G�P+�'����2�&������\���kz��x���Zy=��g�I4�w������2H������Zv3��\6��EE����}|�[\���kza^dQ��wl��e��"�~��t+c�2vI�x5�g*h�8�O;����g
G�C�������3���Qn�u��b�O;��>>��4�Gd����������m�V�����B�rb�P;����CF���j�����!���(�?�C=��s/�VZR�������)U�O��RX�OU�{���x�G��xoy��+�� �����#�����:@x)2����Y/��/�1	R�$�#������'Nd�5���a�e���m&7��O�u�T���IOj��}����g!,-��i��rP���Pq������e�-��XZo
B/� ��w!U
��o%/C�J�t>��[KZ���U�j��x�1^�z�����Y/}��5^��5!�N��P�h�����5���1zcIb�<�������M����zI��~xN�2�p2����������Y�w�Y��X�+{������?�,?������/m�^.\U~�r���mn�,���^=������B>������g����-~n�����!��h��`�2�k�8y>�����q��EVT��#5-�����p�_&+���<�?����H:�
�;�>������������O\�-�J��v�!w�|]��_���	�H��2��x�7����>�%��0�1�i�t�3��\f��h��e@\)�h��E�����@H���`q���L8$������M�E���\��!O��G��j��7��
&lZ���Z���*��r�������[>�fX���0]�97�U�����*N��'2^��)�7���Y�F5X%�]QO���eGl�j�ql�;��:�K���2'��|6��IlW���x�Ek��K�4w�z��c�?a�+���~W�z�|p���R�����p��uw�UH;�c�x��m�
��7r�w�Q���,�R��v5�(��������wK�}\r*��(��*I��m�0VI�J��|�0V4���B<?V�7�$g��J#���?��x7��3.I��v$�x�����������WDIJ������I�������}�l3N#��Rt����8������t�}Fj{<#�3%�I<���x=O�p�����n���t4O<���W��&����2�JqY������a��X���l<���\F�!���j:�\���kzb�c����8��'�I���b�$kzbp�������)UQoz�1���E��_�yM�.������d4�����I<�0�,�G>�$ ��^\�	}�u�)�5Fxz��UY���<6��M"���/��������'��_���������O��h����������N�[���~���?�����������"��z�()������/��~���7V<v_���O��8�9�.?l
���e�3BE)���/���e���eTG��5�uvl��:��������4�D�X����;l��+q0�g��I]�6`�Ob&qt��x��4ul�0�g���8�bd�tq<V����U�,�a3M]]�����$�t��R������U�,�1����B0���j�2H0������?4D�}�f�Z�B�N;�m}M�W�nA�����L���<�F5 uw�J�y����~�{����l��{Ig5��'����
h�e"����������\�����V\M
w�
�yXAh�����C|+K����t,!6%�������J�A������AW�����.�t ���0�C���;��{������*A�����t��7����xME�9����=�"�o�������{��<�^�x8��g���m�[h=�9
X&Q���������O/�F<�Y������F�C���z�K���>�������*��E�9*<�C�����3)��r&�m���-g��Dm����������)9��l��g�#�UW��-����k�>���D�Y��n/���r�u�r7u�
��B�r9�V���O�\Q���p���m&'LM �(!�<���,�!�DA@GIS���������B:d��E����u��-���V0.RvV{�K����~Qz��_+/�*�����q�����8��k{L�49�E�C������
����,T�Q$A$��{�6��m��&����#�5�{���xe���J����G���9��1Y�z<	�+�sH���7�����G�t+m����)vWA$@r���fS��}A$�Q�j�s�G�t��M�� u����])���e�{�9��]J}�@G�(m��)[�i��x|���YZ�6��PG�i��}i��:/��n�$�Uj3�����>�vkI����*���?'O����Y���h�������n�2�	�����9Cd3^�v�t^m�N�4}�������������h�GY�3eg1�Q	`&����p�m#o�k3o%�e��GptEI�5A��L�&��o�&����}���]@Wr�)4K���%m����8��	�x������2�@����+��{�N��M<F�JH+T�Dv�J�9��pt]���,�Bi��qt��R����q]3���aWtS��bl�];������E@_~\G7,M{�����S.�����cdi�d���~q�2���aW4�
�st��c�1�t�aB�7I�1�t�aWt������PZ�i�3�t~�5�����T�1���a�t��?�Ez`h��&����W;RI��2|D������#�{�#��W6C_��H}���q)P-c�����N"5T�Y9�}�#5�����o<��A�����#5j!��q�Y���$���y�f���q
8D\�,�p���p_�cp��Jb���S��7����I����F��SCD������4DM�7�F�bc�5gE�3�g��
��Nf�q_��p��(r�yr��U��y~b#�j��`���c�C4�{]��`����sg�7������gf����!H��nbn�\���8��tf���E�#�8�*���%IE�t=�;5�uB[hI����"�o�:���P>{>&Q���e��	���'����T�^s���xU���+������gq�1����[�2���J��xw_J�U}�k�2+i<�<����$�+�k%�3���t�������{�������;�u���:�*�\o�e��W|4����:���g}�H:���/���%C.�2����%���b��n�m��|.����:����J��mS����o�:,��8�x����n�����@I�n�3�3�@Q��7x����^s[�a]�i2T���GY�
B���?�8���__s��Edm�#6~������m�p��������`������g37!Qt��B���>�����t��'������t=�H'S�1��5s�>��������!�]^L��f����N�ag��W�R�o����B�P}�Q��6t#�T��j�Jb<D;�z�S��)�� �]�yh�a��x~�H.��5^����(#&�}��]yzY����|O���<��f�������/��S����R��]���
���>�^��x�D�������x�-9\K ����K��-y�����{���G��^�7x��{�n� ]Q�x�iK����j������o�K������eF��-y��W[�w,����$�.YJ1�(����n�����L���%EI��]I���������6t,�q���Z���hKV�Di]3���-9�������>N[2Y���m�m���
#K�_Y�n"G7,�q����f���
j���o�YZ�-Y<�%rt�����s�����-y��U������Sd^lV��1�t���Y5���U���n ��t��<�!SV���D�l$�*�������]�>>J�!ac��u�D6 [(�Lt��w�8�	:l$��{����k�B����0�'2sQ�6t8��?^��hR f�q�jH�������,�k��<.�Vd��O�&�
�J�9i�OhR +�?��t�Y�<\�k)��"���#El����������x���JS����[��5�<��x���1�,��ag^������8��G�9�(\����Qhc�(T�{1q��3|�i���m��{�F��T�����o����p��/4v���_?�����T�n����_�M`������'�"��-&/����������{���M����{m��`:����������BH�����Z�5�%�J��W��IW���?�L���
!�\�����b<��-���C3�b.�/��������8Rg�r��&;���
+������[4b��l���B�����(�����+%Wc���A�1�c���>QT�3�tP.kD�N���{�3�(�;C�b�B��t����SZC@;q�)E�?21Z�*�p�2^�C�$N�/���L���oQJe<�
5�����ROo���$������7�?��B�1��0K��{�e�pWYD��n��WC��t�@�/oE�K�F`
��4_�����>|���w�{�s����x3�T�M��u��f�D��P�Hb�6C��p�����H<�f��D�[I'�[�7^^Oi�$��"
3�({^����Je ����t��w��U
?�"/�i�7�N���Sh�qW)D6R
�Kq�k��tbS�?���������1�D:q���x�*��o�F[qS��Qe�e[!�����jHZ���SY������oEVE
�2O|C����z_^���<dU�Z\���k��s�������LV������h�m��q�i|}�2�t>����p�����h(*�����nyBm�p~����#9z��>�Gst�;�h(z��������P}L/'A:�����+��v�P�+��SG��,�/�2���y�<F���%Y���G�e%���C���>���!�cd��.��w�A��R�Yi=2����L/B:F��:��!�m���zR�:zbh}��2�p�Y&G4�������.���fF�I����E� =3���a��������]zA	�1����]��~dO/-����
�W��<��0I<�0��������^[���kz���*�0��;��W���
i����.����V�w�ve����N�u���2���F���fODw����=���(T!AO�)�Mez)7��4�x���+jZR����4�.p�0��x���$qt�C����eIK�IQ��<��K����w�"J���h����@�p�������]G5'K6:Q�Q�{�����E�lT*��dYW�.UqY�9�/l6N����:�%?b�o��_���s����	���������������4��v��������N����?~�����{������?rqI.����n��o�C*�Lt�m�������������qG�wT�E���
����u~F���5d�\��{�9�?�E�H�WT�u4-��a_�����v�������e���%!�TgT����1������&�P%��1�����p��)�h�a �H��U��h��mwo���^l�/�Y�d���h��=w�(��#���%���U	�S�������q�@�����Uw����J:�2�{�3���,�����^��G2
�7����r����x��+
j����b
������t�;� :�
5�-��\2���t@�@d<����Y/�Q'.^Y�z��`���.�����]�3Id���1�n���r�8tUN���M����F���]���*���mT(�D�c������'r�����s�h�W3�V��J��W����m��V�����X��9���~�� -�>��m^��M%�_U��U(�v�o�]=������x �?����u�w���-��dv�+�������~Rf7��:g�_���&k|Y�&�	��G�^�����tH�<�#��Ie�t<�1'G�x����� J�e�VeN�q��~m��TGe�x(N0��������-_T����'V'�
,��#	�n�x�8�m�\(���\'�&rBP�]�-��5rVx�Ua��*�_*�iS�
\�+�u�����G�]������OB��1��/}c�%�]�M�sz}�
��-�q�x[E��rt$A�!�6*��"�j]����t*����*<��g�h�u���I'���cC"�!��g�h�u������T����x5n���Od��o ��=���p�7�@/��\tMI:53p�e�!���OM2Oc��tO>��1^�x��C�s5<�����0�C��F)5�'
��Q��;L��0UzQ$�u%mw�{��	����A?s��(�V�5�@���cS�.��{4�0��u��cX�9������r@7d�]���q�<�V���h�K�g>��C�^'�t�*�}&����O��w.��GF����������Qe���'�VF���K�g��5����^��'������9z�iJ��"+��8�sx
�y�	h����=�+x���%�%������ae��p���b�6���ae�+
j�U�ZQ���Fn*�$��-�:���f��������@��u�p_���k@��g@y�����o��;t����������������"��z�@�#��s_`��4"�L����kq����F��tb���������py��4��Za.�/���x�6�P&�7-��eNh�����\���.�
��t��=��+\4���t�?2b��z��G����x�ss�����i��`��z��\�5'��[������n��P�1��?����x�'��v�W������G�;<����^U�����DQ�;Q4�}������h���^m�����w����o���T_��Cf�|}�-�~����T����_�]������=���Z����.4���G��~�S��h�@�>�1;�����@:K����>y����5��A�#2��F���,w?C�j���NF5�,���b�x�������'.��;�(f$���'H��V���p��L1���]�3�������g��Y�Uy��x���79��u�	��������q:�H�|������	p|�0ZO&�5]�$����:�S���t
���^�����TM<�/��+��t�N���SJ�������/�,j�� �Em�Md<l�����F��1�B:{�9�4��K�Vl�jl��4g��1F��g�h}�a��^I'����l��x�sZU(%1^�v_�=�������)�4 ���Iw���r�i�t�l��S'G:�0������/8���h���~���4�'Z?����%��s�5�~��;l:f�+Z�?����$~���u��T��g��XzG��~
Z�����I�<0�~ag��n?�*C{��<�����EI�<2���rH��A�t�*�a_�������L$O:I�<1��b�a@���
H�cX���.�	%��Q'��g�����	��j�V���z�����b�0����W@���
H�cXY>��ERs��6!+o���Dmq�c[��,�x���p����!-"
���q�H�3tQ�H���Z��������l\�y+����6���
�a�U�^��%���{������y��\�~8�p�^E���2�j����Y�|�"O?xT�_Er����Hx�X�PO5p1�����
�����8x��Y{���~>�P?�
��OX��'���dM��G���S�Yq�F!�):�Yo�aT����x< ��UM��'����z�H�>0�0.!��xz*���x=�����z3�':��mo��ZOTfu�{3��������������U�"���A��4���[���-Y��3���3�_A)�Y-Ye���3�x��[V�8���t��et��?����:=��n=�������
�@����<�3�����������O�dB�=���Xd@����P��lD�
t�DR�)"5
��'��^���`1	�)���t%J!�;������q��x�����'���"����W�*���:�4
n&��4�Zs�T��b�e\s����\����4H�	���F�2��6
�aP�������4H�t��MV��5�� ����������w�u���
����q���3*��kP���i8f�p�0��d�������O�9�("������V���M�6�Pv�&�i�"��I���o��U�jl@����l=�V=��$��K��V=����x3���T�W���$�,��J�>��]2�����o���,��i�D���'�E���o�#��F���x��������g��*���x��'VU�i��p������u%����z��4�^������nq��z�a�1�'�y��2�;��:t��Z�./h�5�����'��s�=��K?�
tEF�hzYqM2�'�����@X1\�.�`#��W��@���ZV����&w�$~.UJ?�^?�G��%�Jy��e`������1��+F�)0�(��+F��@���Z����T�;c?��*�Y	�n�I�x+�������hJ��"��$�nV��{��;�����_h��M)���}��e\����h�Z����+my�������r��WZ��1`������c\�>��E7pw�
\/�#$7����`��h����l��wUJi!���3�K:{�}��=d��Y����)�.D�^+b|�w�>63���&�h�(�[g��u��w[<���"�^�����1`���>'����Uq-nqf������*��h�16�������S�+���4Vda����F5`]�D�<��K`��yL�}q#�k@L�93{L>_�t(��7b����)�|l��������{���um^S"�n����j��$�������,��`�}�bK��
�q�)X��[qd�H�xl���E�)"���{�$G����:����^�u��p�=�����e�u�^�Lc��!�`�p
5���(�<�d��z�N��A<<-62Q���/h=���@�K$:�i��kI*���o�O+�:d�t+��C��$�����S2��w�W�,��{������9�	����w�L�YW���l�>�G��t2��N����q?�,_��-�u�[T�����c�Q��m^��jq4�B���4�k����p{M�_�T[�!�v�x������������4��������`�����n����8��D\y�\�lF.�����o��s��5���q$6p��s�������iS)5�7t'������= ee��(��Y���-�����|�e��}���^��'�x��-��H�l���1��,�����$SW�(<��f�!�3�$Y�2��0����n]���N�	�(<��F��*���������?���������������������H�o���5!F�h���t��[�7wi1..WS����n�&���Oc�!'��T���aI�7�8�f�Od��x���q%Y����x���x#�� �:���$��F1�@����L���jFf�e�1ug��KrZ�g^�x��:�71�))����������:��}g���8}�Vn1��d?E�n�
w1�.����~L�-<0����a�!f���rZb?/��o�=6�1��y�Y�3T��+�I��}pI��2���-)�K/��W��������cr����|I�����n���.'���~����9/hI����:��	�$~�qz0�c���@�X2�.����n���L���7x8>�A���~��	(������%UY����%�Jy��V���������W��N����������r��x������+���~�f��^���q��5=���������[!��w ���7��Cf�jK"���P����#�����C!��>C�-iC��;���sMK���r�q��7x�82^�����w��W6_�����w�j��j�9��
��\�"��������PWG��3������i��g�t5����� $h����Or%^��zb<y�I�<l���Y/�$�
6i�=���ZOt���:o��Fe���/
Z�c[��������oN��?�����~��~��w�����o�����������qO����?~������85�d��$w����X8g����}��j3�������^~c�/�dy�7���j���/�����<�e��^�C���tMA���e��
Zl���f�l<\��3^��
�J��-�;�����w!5�*��Zd
��1^@�td����p=��}������|�3
e<�NT|�T�����~#��Vt�������z��[i���O�����M��n���M�6Y����������d�.���;Vww+��K��o����#��������<�;���'�����
<F��
�lO�|��;�n[hq�&dv�'m���=�B�8������P��/�t��f��/�����I���|�'\�"	j�Nc��$�����[�Rf?*�P8��Y�S����=����=j��cK�m:q���M8f-�T+y�:dt���0v_�'��zp
���xp��Yxn�����@H1�[�F���M:���:���-N�7���t��my�����%����C�0b�7���O����������v������3z7xx�3^�m*���0�����z�Lc<���g������������!)d����i�,I���w7�^��3^rm�M������*'��P��tx���J%2��`<)�wAg�$_^��NM�H/	���J%�s��n��()5���G�Z�����$�C/
����4�k��������Nc<UuTI/	B<U�h%���x�s9������c�2��na{^���|W�,���*n���#�U:n*�Q|��J��J��*{�0:U:uT��x}I���J�FWYMfug���nXM���eM���-�&�'K���_��kw�s'}�M���2������4_���m�E��O�-l)�x
0\/�~��xm������,^�x7�@�q��mL5z����]L���J�7�����{��h��B�x��0���Q%���V��V����4��ukU����n!��m�9:)l7Qegmf��n���$Tvr����v3�D_C�9,����t�Y	]���S�d�ul��e����z��w�
����tB�s�8;���g��[��Y����n��tB�M.
�2'��AQpIl�����yv��������|�O�w1U9���+�bEU���Q��@�U<�T����|��*�Q*��"�v5�(���
�WD��j�Q��3��*@��'��?�L�yU�	t|M4�'$���(��'�������A���?��E��BK
���f��~������|f��3c@Ewd?��v��*����|e�.zo���E*�xs�C��������i�{p$�L�q���H���H�Nb����M���a���
�Q;���a�?�<=X96��?���&�� d�bq�<0��m�������.rgL�g�U2\o�����7�*M��t��:�4�w��L���aeR������=1�L�-'+�`��u�^�t�y��p���'9r��+��y�X�a��-���i��0��y�O���qe9�l9YQ�a���wO��+��C^�����{L?����D����'�3���K�r�I�g��!=g���E5�z,H��9CX1\���#tdGs����������b�R�wRl�W����4���%�=�����b�R�wRl.X��
�D�^i��}kY����E��'qt��R���2	��,6s�����,����%�k�����(���#��c���~f��,�.Iu�$~�Vj��4`�����a�n������o/��9��aTi�������~f����+-�_^��sbs��"Z�3"��eTi���E���;~�;'6w�*��1��|h�U����:l
����9��gT�D���e%s���g�]�=��
�q��9��a�u��?C��J�vE(37x��������/3��+i=2��aW��.j�w�{Nld`E���#�8vEOh/0x�����&��o(����,�p�M=�w�{R��
f��������r1��h����w�{V���f^A`�K�����r!�q4?�9-��_���b+�������~^W����y��������T�d���:���_������������/�������G?��������?�������?�����@eS�_.>�/����y������t��_&;]y�����.�BD5~�wcW��C�������t=�Fwc��
� -g����C���6t���5�q,L���b�&?7a[4��0c���D�/�g�[�]7�g���{_�f��7[�=d4[�����l�* W���O�a��T�h6
�(�g~g~����{��u2G�u�f��?4k�����w�D���K5�*XM������L??�#j��yPTe�uEF�Lt�m]Lxx���.J��/rG�KwT=�uE��*$�B2Y1���%����(A��l(�u�����Pd�]wd�q����]2]��v~fH�%�� qw�u��,�@b-��	���$Fd��4�R����]e%�<g8�0R��kx��|���g)\3�F�m�Y�����W��q�Wp��='g)w}��:�hC�������F�e�{����[�����zF��|{j�nB�����e��@w����B�HnB}�W�
t��;����!-�d���{�&�F�3��_D
:�����)�4��t-��5=����h�Gd�^�
��+���j�S������}�9����G���P��}Cv��{��R���t'�D����u�B�������2�`��UD�N<�l7�K�����X�93�L��[��N�t�(���Ng�;���t�$S���?6��K����o��n�@�8��m�y�A���r���B�-���K�k�3���6;%l�1�����.��;����g\�v�f���,H�'���f	�q=�����f1K��{�5�Yg\�v�g��
�g��|w���%�\�b��A��{��9v����^�$��k������k�f$����\=U���@��t�kS��bFN��f�x�u�Zqj�I�����mNK�V����-������VG�<��*k����<��o�%n�����VGw=��U�]�|"1x���[l��3��7)����|#1�c:�o$�x#���-���#I.I��VG��$�x$9��d1s�X��o����2�i�����X�M�"�K���5K�bK<F��W��*ZI=1���EV&H&���	����e�3$�����-y��X���r��W]��5/�����|���������������B��<���uoU
o��C���nX�!�sf��o��Z�@7`�+z�1�F�gK�i5�'�����n�H'2��.JK��i5�C��bD���p�|�b>���G?�����������J�Q�*>��n"���%��g�D����
��L�#����j���W!�m>W��/���T!�L�}d�P$^�_�����*e�H��M����c*��g�/���}�S��j'�hT���.����e�w��b�?���Z��b���b���&`?+�-��~��!�n�s�_��
�I�����Y��g0b��������H���c-]��s��2���@:�������d���u�U_-&WJ�_o����@WV���}�!	�T����o�GY�n��������b(
��3�
��=U����W�xr-7QWK��R���������%x?���x�w�6[�����������y!l���t�m3\��(�qZH��NTi�r��2t���������t��P���P�m��������X� ��-N
q��I�MZ<E���D��S��>�����t�����'�O����N��%��&G��e�5�>G��l��(�v<	
����;��ql�l7���%������n�JP-N9>�&�����{�XP�`�O�"�����Wi�q\q
�H��I�=�����T"�/�q����OXrWG�L^�1��#;��UTi��+����l�h�J[��J�����{HGW]m�#.���xyIS
G�o�!��
����qC1x���l�W�4�M�`C:� ���.�1�gdc�8��hJ?"U��8�D`1�c:������r��JF����6��j�6�*��#�\Ti7WU����S�m��
����=�P�q�Cq�M��Zr�)u����J����j{�^�����y�yl�L\���*���j�R�k���A��1`�g�6qI�3�#T�qJ�I��N]�]�Rm��]g1;����:G���U�Q�)��"T�a���H0�X�
:����3����qMU����!m�qMY�Z�z�!>qJ�AW4�/��Z��u���VtN�6�p?2����U����]�]�K�������WT��5JV�VUV�\���]�JZ�~QZ��vb�pR}��S�i�E�e��e�W4(����)�������@?���~���
bg��=�9���d�5�V�=G)�$J�
�+��f��l�qt���LVO1B����y���t\)�����|��E���3��k��<>qS�������t�R�O�D��'�eF{�e�B�Z�������S�B�<���X�M<d���k����Z�
H��N!l��t�������S�M:��&Q-��=X�}��|c��c:�bh��>Sn�NX�}�|7eU�1��W ��:U��!��0��l2�p�a�V%�q�I��;��>�h��aw�g��+�jU���v9�m��l���#��a��p.lDj9W�B�T����I���_�,�0\�yM=^���@:�(��wW���w�Bi�$Y�eI:��|����2\�v�3Q�K
��{��R�V��|�B���x8M7�WY���S�D:n0U}\G���hX��k�����hT����8�}��E���]��Q���Z3I�4�zBU�I<���d���t����{�N_�����z1R.��[����I��C�
�Ky�o�!c�fBt��]Ow�-�z�5��<��=O���!�K'�d�XOs�����=�`����8y�.}�~���Z�W��A��2��T�w�U��j}���������Y�|��5���������Mm�
���3��s�'�b������#������Xz��YA���V���}.N9�p�3�g��T���i�=d<k)�d���  ��XK<.�'��"U��)C�=H9X���"e2�&��;����q��H�����p=�dg���9�����}xN	9�pg7��u������)!�w+!���+>n��n��JY��}	��������NO��Z~���O�wJ����%��x����)���f%���z�=�]��[���q7y���X��d�y4RUW���>Xz���:K�WB��b��o�x�������d�������^�=��!`���(�;���
���]�!�������������x��b�%X+�5(N	���fuJ;?wYCV��e�e��#�p�y��RB�����MK�y�������DH��y!l�X	y�����pQJ�7t����u�����e�V������t�\�	��m��3|��N�<G��#]W���3z�z��R����.m���T�s����=*���sC�M������G��p=���V�����p��QU���v�|��Be���n�H��������]��P��������a!�5*T^;����t��������~�Pz���R�]w�n$����
.��8a�p��v�$���r����O�o��?��P��4���2��n�����g��P��Q:P6tx5�cf[8�����h�\�x/A�y���R���CJ�x����Y�E��*�$o��tQ�4�+$o�K��N�z��h��<�������B6TV���t���{�>��{�\0�'�8�t�Voa���;x.�����������?���o����/��w����}��?�h/��X���������(�6��������}����.��������/��)����GZd�8l�����^~c�����������8Fzt��8&4Q��I��~���x�w�������p\0�czz�iJqv(���zzF��xQ��[����qZ0�c:z�hIqt(��\n��8g���Z.�:za�Y�3�i����b>S��LG�-��b���2������a���{�N�q	�!��73".�p��CG�!=dp��{�N>q�xyNS
GT��ut�����9^,�(���=��$��Q1Jg��'����������:k��3m �����'�C�8tD�b$�C���P`��t��
\�aV���~A@!�}<�^��oz�s�]�-�p7��c���� �1{��F��d�U�(�sN.����aD�0�'�i��'o�V�)}6E�?�tT���(�lXQ?3�BY%dj�k��<.�Z>�*�O�K�	u<��5���J���n��36JX%����-^w���6�H��:T������s��:��������c��x�{:d�w\�u�o4�gz���	j���Y/��
�B�)��LLt��Z������GB����������.v?r��������X����#�Y����	-������6��-�z�q���/$���w_?��i���j�����`������o����@?���~z[�'m��!�S�Zu��
�Q~�[�.��iONm+���=���^�������Y�y�}���KY��a�N���#�����cja�z��g�;�A�f����mEHr&�2���AdOo��mN<]�/�f��h��'���A�����*�z�iN�c���x(7��cIX8��q��$���w����-d�7����m�L��{�$^��p�g���{k]���(�2'�|��PF�=`9����������k�����^e��P�����u"�����y�~{����o#����Id��<Z�}��Z��"#�jW�79��l���t]F:�,y���CG��z����s~�z�������M��~�*�����������5N����\$���iN1���G^�������B\��&�4��1=�A��d��������'9�<�t�
����$��yz������������2�������mb�c������F'�qW�o#���Ft��]�l�3�czz���$:�>�D63����Ds�@V����HM�&;�=?���~u��������F&��y����,�/��_=����d�����L�F�F5�@W��+U&��{�7o�d|�����1�c���p����=��H����b�������X��`���<�3��qJ�I�5<o�C���v�Or�r ������9���$�������RX�G���4�.�Wd0���Y�>��K���J; ���K��b�����q�J�+�g���6x82��������I(��>����zUF�	!L988��*�c���`��z����Y/`�F��L���~������ZO��>�-#��j��W{��!�xx�6^�z������z��6d"y\�5��
�h������g=����2~K#2~r�M��9�'��B��Z�E*�x=��5Z�j�3u�i���zBJKV}&����g���s��1�'����^�E��
��k=��]��[U��z�s���S3D82����]z�� a�z�',C��Zo(i=Q
#��Xo@��x_P8�l=�����$�3ZO$�Bd�ZoDF�x��Kc=����-���czo�?CZ��>�.�{������������t9�/6�����#����:��]\�n������G���H�W�����s�]����U
��k]���Z��kw-����1>������q���hwki������������������W�<�'�s�w�^�k�5csU���s����N���l0\��]�Eii'�J�M�k�#��;���������p�����-����p��8�.*�2.F2�S����@R�p��v�o��peE�
�!+J�'��_��
5�g��qZ��W4�M��������*����L��-�a�.I���j���px3Z���}�x�����7���s�%�D���i��?����v�*<���+��H=��Ci���U�s��X�5��j�B"���S=������J:�����������D1Y�5-�������n�g���bG����k3��������g[����=�|wmO:��n�5�.�l+f��j�$�]�H��������;J�G�B�z���H:G���C1���]4��@��5�D-����v<�����#����%F�����g�yU���l<t���'�n&�__T�"�$���b�Wz����3�;J�il7������h*���#�
U@��v�B8��vw�~P���4���g����f�(��)TmG�8;��2�;���Md;�QfqF)��*��g1Q���|�0�2�3���Hb���������f��t"������n�H����_�+�(�_�X(��4�ce��(�`;�(�P�PzR)l�C4��{��h|��l�^�����t����n��Y��l��{E���m������y�����.���+�|"��&������UCdw�W����{�5[�gc1�8����������$�h�v�\���8��v�dBMC�-N���+��H���g�AK�����Z�U�dBJc��l%�3���j�4�AW����8V�����K-����%��%����J�G5���2^��r=��
���y:�+/��a576��5��Z��s4O��#5�5Y��x�ehi���0K��o��{LOwM)�U��5��;�N��x�E�q�1�t�a�4�[rQ����vO�.J�B��%Y�=������<�[���P��4�f�������kz`p��w9���E!��n1i<=2���-@�������e<�dT�2�:�kL�~6�&�Q�(��~OO.S~�5���gx����)��\�@u)��$N�.�z�5=����=O(,�����2+�������0���a����7�wL)'�'�4T���`UxI<�2�\T���kS��#E��xzepY�����������G]�E�����H���.2x�:,Zp8��(��y��i(���=O��#+ �r��<��]OC���{LO%M).���9���1�x�[��������1�x�����)����;GV�.��y�~�;��K��9���2�R\X��sdE��R	%��~64��+��@��������Z��#+j�J�w�3'�=]3�\h���5�w����9��ap����Y\O7.Mq�5M
��<�w��h\�I����E^�-�K�vMcJ��1e�w��h\����lh\Ow.�Q%O�=L)G���#+:�NY��r���{�����E�.*��<�{��gp����+�������hI����sd���F`�]1X.�Qu��b�hJq�iv���.��v�G&%����2h�6X�"b���w��M.BF$h~R\OSG�x���9�)�5F�K����e-&!���z��"�{LO/M)�1r�]O/.�h1��W"D�O/.Ku�5�,4�����|I<�2�,��$dY�5�2�\�9��W���Q:����e"x�]~m�����~���?]et�=:��5�_�������wx�����9���l�������3Q�5os�������0��-���G�0[v����]y���j�E�{I��~��_����8o#��U�+��{V�7�$V�rD_��|�!��R�mB���?
�1`���j3���|��| ����IX�8�����'��U����^?d�/u���X��c��w�z�\��Fsh�\O�j����z��ym�k�c$z�w��A���
�3r-8����x���+F9�����3t���/��k������k��kucW������Y��e���A�����}�X���'�������	N��d\���^$��:�a���:�x+�L���F��+��D�[i<���q�q�(���w%���x�Dl�&�#[L$:d_���+��4�+r�����l�3^@�22�	��/��82�J���A@m\\�����C���g�7�]����id����x_�����U9�'�'B���Z�B��x�w���^�zH���Z����zB@&�%���i{��5]]�x	���������<�n�D[��?����������������a�@o���~nL
�������o��w�~�+��{��{����~������~��/�����������wY�wY�?����������������o�������������������<�/�s������?������&������������_���o���?���/����R��a�r�o�e�����w��Ds���M���	}����PUD���|�m^O�l1����.����,��&t�A?��"k��?���_�	k�p���y1���53�4�L-�8��9ky�����}��xgf���t��d��q�����%�0�� �Z�20�e������g�@:���m:�]s#O��2�sA���;�}�2^x��E
���x����:j;�b��1W���P���}S^�p_�c(�qi���-�c~#/d��e�9�DY�m���*T�aS�_�m��q�}t��x�Q7�r9b��zY7[[Vu��.S��'�u�%r>�{c���w�S,9����G��=aE(S����� ����x�_��6��
�	�B���&m���%2�@:�R���G�}��/�P�1��*
�����b[�C����3��tm������0��"����85���}�x����������[L�qS���o�k��k�	1�vfh�"H �E�������<Vy:}}ch�)�v���D1sTv,�7f��~iH�*R��4��]N�U3��"%#z������q�HAW�=I���t8��!�YW �������xeFS��V*�<TE��2J�{LG����9:})�V��?�KA����ni�����8��U�����5�K�.��^�^Z����_�zI�Y�zm������[�����+G{�����f���T�=_9��A�+�K�c���t-� ��_�9^����$L�O2��~�������PZ�F�I�y�$���]��'.�� ��/���{��{uoK�ZI��p��������/��e�$D����J��
�x��!}��^+�!uF�D����ay��o�����:�s%���p�Co�'�c=W�MW��\��	�+��Qf�7����+���Zsy��k�E3��\����V�h|��Rs��gLx����T"=s��K���'�L�'�Q���<��n&�C���r\����G�4����e��Y�TO1��o!�h���+J�V)�(����
��3�*yIc��x�I�P��q��AWf�;�T5Yq+1x�i?��<�p+1^�H�~p�����a=]U4���l���yz�}F�%��+�3����y�.hJ��!o���������KO��+�1=�7��<�^~�x.��D��$�t�����]��JS�.�����k\�gEs�x�epiogl���o��y:��<�:�VU!T��(JN<��8�����h��9{�.���(��q�jI����������������������;�WnK��AZ�����n�~�l��F�q
���E)j��2nv�t��d`'��{�n�E��G��OJzL3��I�����s�qt���.p�2x���
����xG���#����/�@!�������1I������^��xx�0����Ht+�'�#T/_���w(�f���m��V	}B����xn�n��1AW3�UB�P=��1^����z���F�C��x=���'$�B���P�BR����&�5%������&��vA]��K�����������m���l"��p�)���E������x���?������V�;9n/�:�
�����G}�yV�s*u�~p+���_�sK��������b���
��������H���?��W�#���� 9��L>��iR9N�8�F��p��Y��6~��1q����q���x��(�^w_����'�������@���:s;�����W��|�,
[B&s���A<&���m�u�fl��@.�����E���Q�#^l
��T���2�,b���tl����2��a�)��hk����o�3����,����"l9�E�\��t#�e�
�}���'6�$�c����x�p�(�<E�X���0�[�t��hH����x,�Er�PZ�����Fo��j5s����x�0^�x�����pSQ�y�/[Vg�g�h�c����I'��y��'�������6N
���t��s������`�����_|�!���z\�^�l^W�z�a=�����v�6�<��;�NQ��=]���E}�3Z�vW�u�?������G���/��f��=�E����H��]��J�
v\OM)�������c���g@U��%��c�b�Z�zz,iJ�_����3��v��-N�:�`��sQ��_���a%�}��r{������ �|�l=j�rb1��?Q��l�tx�T1���R��
�t�h�=��21yd�^yUz-^��yd��m�����~��k�;�9�7���;�}��9:�/����D+m@���%���	k��\N�Oc<����;K��nN���wx9�>����:��yP��b	'���.�\Y7W}���������;1��|b���S����HO'���D�;������K-`W�v��c��E}E�����w��>\uZ���R��[��������7�e�c�\L&yW��I9/����"T���\o���2�c��7��G?���?j�X(E:*������7t<�M<��:��M��9������g�7N���tb�J�z�
��S&�BY��e�GY���(���g���7x(%4��dC���H���\[B*�k%%�P�c�B�`c����<n��8�@��=-D����� �pol3���
����y.z���I�*��R������x��0���S�C��$�8S��(.��J�]��3^4���2���*�*�Kb�
{��z���}N�wC�=�R8y��o ��zi������j!]LE��'��F���{�.���
b��%��k�n���D���MAS
�����
2���y:�v��U�=�����|�����-cK+j��@�$�nQ4l��4�����!�5�<�1����"@����
�K�t����
�0q�gp���G�!�hjC��������*�.��u>������}�g��Ww��""[)���"�(�R:�Wg�;)�b�K�n�r��G�L��A��j�n��h�}z3	��:]��?4]��x����wt�$��{�(����i~�u�\/pC�$��z�K.���[h<?���Sg:�.
�1�jIMc<6�/"u�����jtW-�i�We4�_L���e��p=�%�Z����������R���[h=q���I��N�E�+��a�2�
V��(s��s�c��.s,����e��+������s1�HV�m����$�~���/�O�U9_:�E��r!�����s�w8����P=����@��~V��U��nO�O�����*�A��M{S}���G��c�kJ��'����
�h����/?�b=&������/^�����B~�~���B.�
%-)�'��^��$���]��'�����A%~�^�#�{���T��Q�1	��x��h�N�G�?��2�P�c�^-������$,�w�?�o=& g��&�?)rQ�'7t���BRd���cna���k��1���V��X+E:������z�k�5�)�����v'/��
�T�h�zL���{�},��
\K��3^4
�@����a���R��6@U.�teF:Q��*)���C��z��������TJ���z�o%��T�q�YA��^�{�C�Z�6��	_���H�x���C���.h��2�q=]��e�����n��A7^���#�������-xO7��6x��}�Cr\O7��2^��j�I����;� Y����c���%���P����cGn���Jm�C�x������5���MY#����L���X�@xd826GC�YVV��Z��~!�����p/W�������/�i�]��,���&0��eW{�.���������]������EQ�n��"������L��i�������wi�*I[�����[��Nmx����]
����i�q����W2i��Wq��(�I[Fth ,��@���u)���2�I/]���1�b�j��eD�.t��I���jki��w*\��`�U>y���Z&���*���A�u�7���A�$�:�Px���TX^Gx���t>��.�0���7]�����^�,��v���`>W��^�j��Ax��\{y��M ��|����*�����vV�����uU���_��U�9��N+�(9�[%�"<}���UL+5����4��|�0Jx,�Y������8�q���M�3���e�������X�t�
��\f�:ds ����{g�#��7�W(0�0�B�Y�
`od�m�@
����? ���zD���Y V��B>	-l�G� ]���Z���L.3�C�G!=6'���g~_0��8������i"�[�"6��������������k����Rc���LeFxhP�!�'�4�@N�Q]��Le�������\�R�[�Lf���l.�Y��l���G��z�t�L�P3��'�V�u\�d.�����CximQ������9[�0�>��]Gx�a ��	�z[^D\[�0����Q#�������N�D��f���
�&N�-o.��9@gJ�)/�yfBx�z~[^��-�+Ea_���j���\�Om!�1�}�l�$���m>Uz�����Ft��]����KDx3�+e.�*��5��3�+X[�?UT)@�z�����c����A��&��#&�oP
����T����w0��A��~��x��B,F���J/(��`f����]�o����m�{�ZV6�W�~�j��6��[�3geVzP(�OT��X!vD�s+����]�/��-2���*+=��2|��,�
�">���s�^.c�"����`����e�D	��u�@�X���_e���r�>���������*���a���:�T�Qg��a���N���a^.�'���K��,�1����\�BE�v��f��4z�m5z��������~|~B��W�'���,w�<w�b]Z.�X�b������G�j�9Y��P/8N���QD_���[�0g�:��>��7����m�P�b�C�]'�)�!��x��+�>^��o���.(D�O��(U���� �Ot��)Xt}��
7D�H�"�C����jU�^b	|�,�~��z���b��j��B������Qx�c�J����Q��B3�.�6��,t��'D&��	����6�*���q�B��^!X]eREz�F�B��O��'�YZ��q�������'��
���0�<~��l�b�W���T�tBI�+����n�� h_�Kxm��JR���RH�(��*t-��	n��'o	�%@tpQ�Ob�"�$��oMF��h��7c�K����������D=�-b,�6/�c�G�>FWh�)T����PY����lj�����3��j��"����Z�ez5�������<�XY�i�w����/��	5��L1��x��B��T1�e���f�V���>��>8f���<�u�Q���P(���S�.L_W���+��
���������!����)4YT���2�P�O��X�{���
@x���\D��*�x;�����)��W^��J��*����������'�<b�BA^	�P��C�x(
��1TWf�<c�iWzD�f(5�h��Jcs��[��3������n�ge>��0U��JOx���	����)i��s�4����J����rY����Fv��<N�����~Z��1�:���'��^.s>���_z��:���e��[���}�k���i�%���
x�,��I�/�;�f�R��Q��e�����t"�K�F�D���0�`�N�K-�����U�F���[Gt
��[��A�7��u]e�1a��f�~�uD&�J��^���oB����=O�2��B�B����U���K�{��B�])tYl�]Gx
��v�r��n�]��g[�QEx���[����~9���|��G��:yg`T��+	o��d�l�:DxhX
���_{_��Y��/�Y���Xh������p=�����2�0��wuK�����V���`�-������{.�����}Ykud���.5���T������V��C6���f4n&�vP�ebD7e.�m���B����]�1i���P>&��8��$�<bE7`)DE
M��2�Rx�AUY�~@�!�LB&�7��������"�V#���gUQd�BT��f2��������>Q�>`U�(����BMQ�����s0#���JxW�l�K32$v�&�O�s�tWGt^7�����:2��k\)M%+�����Dw��[D����9�����E�J^�owXXh��.���/t�-Mc���Ct=�+\�]�n�oAx��B�>��&��.�%������Y��7'�R��H�\D7!�B:��w&����nUz����=�W7�|��+%��^�}��z�9���DW��[J��"<�=Exs���i*��S'�y8~��SE�����������"Vx�!��-T�-��:�7��T��5��Z���iWz��d*��b��V���7�����-��3�&w�����3^-s�ji��IEx�����V�~�k�7���O��K��,�okI�+�����l�&�/��V��
��R��2DW�B:]i���2L��#<Xi��9W�U(��J�O�Gx`F�'*���4�y!��s�U���W��~i�3���N��M����������w�|��eqt)����l��q�\��}��n��\
M����\�k7"�����F��5:�W��o����
��4>��3�+kt"��"��*����� :����PEt"5:�b��s�tP���z[�L"���� ��"���O�jt����h]���P'������������.*u���B���'�dD�������E���^�=�����m��o��J�a_;��c�jF���T��,�)���.��O'+��"<�������!<��
��=I�B�f^a�z��{�aj�-�R�XB��nY
����:�C��P�����5
�4b�~i����f�������gk�d���;��x���6�#��p�\3#����b��j.b�wYV��������|��jB��8���e>S]�_V],4�#�_��F7h������� �N�VA��yeQ
`�<b�G�K����R��7WKQ�*������gD�+<R��$��G�R��)�������<�#Mx������O}[���rMv-��������;��������d��c�SDx�u8X]���O�[�)"��3zR��@b�pWjWT�w-S]�� ��
����Lqb�[>�SH��*.Ct�q�L��S����e��k�X*��a�)�����u�g
o��WH7m�RR�ac����RLY���M��T�r�-
���J1e�Y	��.	n�:�~�
���n���\M(Omq<;��,g�o�L]
n��XM(Om}O-����o�W�7+��k�<�jDWx�}��k!HDxs������o���O��yl��AT[��;����������eV����� �m�u���_&�e���4F�	on���cAx`������[i�Zt�������:��,�-��<��A��s�t�	���t��Q�g�r�
����<����Q�V�qD�/M�l��<�Q�M!�22$dW���b?�l�
�.�YiU�`���b�����/�x/��; V(i ����vx����b���%G��o�����}�-Pr�=n�J�DF���($%Gm�*9R���-]?6@�����y5@�e)�b4�I�0��b���G�|s�
�k���)��
���?Q��G�sA��{w�[Cy_��
P?/@��7��A�.a�����7D���t"Eo�������wm0�JL�s�(��O <�cSh���U�e8����4\Q�������P\j<Vg�-�	��B�D|�u��7'��5��u(�B��+9G����L&>��w	��8��{Ot�g�#�	Y|�_�;g�d��������?�]����L���v�=�K �r^��]�\J�h=ZCH���k�.����)�:w:����)��m��"���BS9��'+tx/�'�u��d(]�����I�olP��hk�O�Hr�
D[	�Z����<)�Xh'�rM� ~Dp��������N�d?�"c�zX��:U��Z=���9=��e����W��V'K�3Y\,;A.A��u!N�3;����`Hp���IOp=��
���B�����i(��l��C�o2�����t��-d��sV� �Ix3����6\�]!�i��@x8"�/����-�<�:����p�� ���
-]2D��W�fDW�<
P��g �����'WU��y�?Cps���a����J!eF7��+�7��<�'��g|.%�z��<���3����~�>�Jc����t�~�+x���2fZW�[�
$������?C�s+��o(��8�����W���
�u��<���54(�����������
���z��
^.w}�?�J/(�B���^���z�\B!��4�Vf.�
^.��I�_a�'Z�i,�/�>����_����>���B�w��(;�4iv��5�7�5U����������/��+���G�3�������0��U���H��
<��g�I$�!:7/���'�� �J�sb��]��AU������-|sK��E������V*�V�S��p
�WY�Ng���W�&� ���?��������^!oOj�<���
�{�6�U�g ��
�2B� ����OZ�$=���
�G��\�7�-t�,5��$=��l��+��#=��
u�d���.[�����B���J�~�'�J�����
ft���#����qZ5��-J�#V�i�&�U�&�Vm�������"�<��Cm1����������������C���]�d�T�\9���.�]C	�c}����DH���W�S_��C��h+Z�w��s��[���MtU)��d�u�+�{�P�+`!��@���e�0���?0�&�P�:����8=~�X�D��?SW&��
�&T��P�W�u ���� ?���5���ZG�g<��|���5yF�y�7�.��JYGp��<�+N�
�\OPds5��\q��LYGx� �sEV�i�z
rl��/M��
��HC�:�In&o��y!���Z������R)�����~��u�}�}.}��DU&}���5v���.�����#�	��-[P�:���a���\_k�	���c)q��
��8,�����0qx\��9Um1Wx,�
��T��g�P)�
�~�a�0��	�v_kD���?�;<:��]�Y�:'	%H!<0S	o���z\����'J\A�V'�����ul�q���~����]�[Pz���O���CQ�Mh���J�[BaL�c<���t����+�kea��f<���t��K_��0Z�
�t��K�>�N-�2
Q��:+=��2rF���+=��2|�V������F�\
/Q~;��`��:�[��������b�v��������|z���^>������b��5b��v�+S�S�S���Tx�,�/2���NA8��>�N$��A���'����"���:��v0��a���{��5��m���Xi
��Ig����W�G��JW������Tj]$�R
�DoNz�KND2	�y��
�oNz��8���+��� ��Y��+4:(6��"=M�oNz��wax�BBxs��_��\��+<��I6����I�~�_��
�ox�dp�����XL~������dp`����o�\J~�V���=��J&�O\\Z�s��u
�������3���e�����Y�=�X��M!��x�D�����4��o��sg��W��J#t��������>�P)��~���y���B�2��}��#Ex�.c�P��iL&!�MJ��N������0E��{.�����u��Z����3�I�����xA=�KQcF��`:8����{�R�j�0�x�<7��/����.�I	Gtp����,�������g%�3#<t���@�Ap�G
m��a�����<��Q��H��d�<S��"��dB��4����^�f�oNxb��������!����*���#�9���pD�]!j�z���f���\'s��0�y.�=>Am1�y.$3��S,�S��DWxe|��b.3��	O���y�y<T
���-�K���oNx�:"?n���D)��5(\�|E����m#<�?o.��~}��gLp�v�1 O�s+]��6�������RvR���!6Cx?�J����c3�X_e��=���������b>Qw�����7_U1�Ue�G�\�������Gxx�������c����^.c�}�qx�����n�>���L�.�W��	�{��^?6@��2������^��&�]0���gvZ�����
\f�����4���:H�YV�{�|�J�Rs��`��{�
�e��@t�:-�Rs��^Y�\K���-���$ :H'���)H@t�$Bp?���`���^��w>Fx���Hq����l���s��>Xi�Z��F�Jo`�]�n���"����������VX����db���S���C`x)"���Y2���������d_GzxF���_���-(���q�2-����R��C�
DF�2���
u�������tT����P���s�o��w��K9bD��A�;��I�~��[Pz�:��}�'�V��)�x�F�}4Q�t��=[�{\=�������F�Y9����>��N�������	�B��x,���K�@�pYE�^�X�mqir��e�{�n3��.�V"����P~��U��fD�����|�5�m��,��a�G3o^Q����b7,�z�7��Z�-QG�f
F��E���T������d�;�|j��z��D��������A��P(���t0��u
��O�;.d��y����)�
pg�<O�!c9���S������^#���BD��:��]&�������y�B��(�])�Z&�������K�`dRp]�s���Rvu�k[���m)OS$����0������2�"����m�e.���RB���9���|��}~n��^��z4����R��YGx�*}����_�"cE�
�yQ�V��G�Phu����x�7 ��E]�7TGxx��6�]�����X�4���Jc�_��P�Mh����?�JOh�N��Tt\g�'�[�Bz�gx��+=+���iuzv ���(P��������\(!�d
������,9Cv��\
�0
q�J+�����a����V/�Er��J�
�O,�q����.��I���_9�����n!��Lu�f������mz'�a�k�	�s.�:o"���v���V�����U� ����G
j������$uD���x��+����JR(�iKBd����t"I���������4�$���*���I�x3��T�OG�JR���L���U�>�}�����F#�-X������J�b5m��*��P�#��x0��I����<g�����#-E^�Pz������:�k�>&������R�Jou���^����5W��@xs��_����X �9���8@xJ�`�����D�9��(b�OMJ������@xH�0H�-�L�#��W(*V(V�^���
F�q��F�.�H�+�
���Hr�o.{�!=�r����(�l�^�alt��i�O��)lh������l�,|�yQ�\��M��A����-��o9�x����r�����(�����J0W!�A��^:�a�ye=@�#B,��(�yiA�D	n�&��	�� :�]�O�C�h����qd2)�5%fIp������p��=Q�<���,�W+�9��)���	s���Nr����(Ca����xDEJ�$z|���3����c�R�8��2����
���@t�^�fc3�)�At3����=-v��\��o���n����)��g���_�B���	���
$i�\Zx�V����nNx�B�:��x	��	O��?���m��JEX�B�*�k!=�����o�/b���Gt���2�[������x�CQ�b���#<�e��\i�	���t�6�O+e��r��P���2���+�!�D�s+]��6���n����'��Jw`�����D���9�����$/o?�M^t����w��.I^��6���WK���6/��s�<��9�i��Q��C�a~"�A&u���?�o!�:��������6���������"<�����dGJ�F��pk�.�"<H�"�V��v��u�(��lU?u���2�0*e�X���Kax�*���$=�]�����	h��B�R�kIoF�b�/H�x�?�����\Ez�?�g,���������MBxP ��R�!#��gd��I@N:#�bU}Ce�>wU���sqY������;��]U���f{|��d��<�F�}���=�e�=���]�fy���K��L?�R���!����p�tw1��r�������\��%w'^^���M%�}���}���[��[{���we����&+�8(�"wu�-b���E8�m���������V��D���5���?E�"?�_���G`o��
�M�c�(����zb��jBg���"b���Jr���y2+��Xs�lM���w�!�}
2��2�\���GrX ����P�����d�sk�#)����G����>V
�o]�E�#���Ax/[^nB����,�Y����}p`�HP�
��!0/����vpC�e�w�P��@�H��Wq�}u��k��#���G���(��P�4������~��_�������}��������O����+�j%*�n��TG��wK���j[A�\z��_��� ���[��%l��Cw���j�x�Ky\��gi�l)�`�t���G:����������yZ����B��W��i�:��_�j���L-1���<B�wy������L���/?��������������8Q���?|��y��&�Q����������<�g)��=�.�B� �����R��	|.���d�
xys��1l?r��;z��[�#�
�{�����<P����.�.U�;z����J��"�o�8�|7g�7��������W������������_���r{������������t���Z��o_~����_��W����������������W���d��4�GSp\=2��W��o�M�z���x%����3���ZH��s��/=��<H2���3���lL����f�����Z��
�R?"�B�u�Uo���2e.h������]���4/�����a]
�T�t=YMN/�w�9M������\��<�[�9{��vWB��D �s)����������;��w�o�Q�ys�p�x��'��3.��y�����s~��/f%nA��z�����xU2-%2�E���fA�f^���J�Z�����,��c[v�U��,��s��2�_����>F��S*-:0	�g]����f�v������w��E'����KN�� ����b�D�A��	,�8�b���=�n>�re�D)��>����Nw.��]~���9���v��}�W�T�����WCo�f���Rq����{�xy��<����g���g��h_��3 �
l
������|�-a����
�b����h��s�7�ins�d�wm��
}l`����,g�w�#��#�|�x)>�Oz
I����=a1���5�7��)��'j��,�=����	����dOy^
�-3"�?����{��V���n�L^0p�n�SGz���&A���������B��_G`W�s�IO�����>��[�P��p�
�\���?Oz�#���[������v%�p��:�
J]JO����iU���"�~sj��b�����}B��v-�
�W~��R����[��v�pBz�R��7�$��8�s.�CJ~�����@p�����J�=B,=�x���s���o����t�"c!\ �uXE�S�[�2X0�,��&?({���%{�������l�u������y�G�������w���<���I��v���Ah��;������pH�������8���$\�9]��0g�'�}�Y�r��`�u�N�O���L�>����|�H� ��b���C� gb�b.���
��L���	�����t�4m����Se�� *�M���?�,+�/�R'�'
 �������e���������
��q�N �,*>�@n�)��K�����-�*����=�������B�m��wi�>��@�e��(���zh��2�d���9#>�g����p������gY�u`������=x����p!�c���3��]�r��=Zm��@9Q���������,T<�������,8���`�YV~; ��t
)��+?��L��<��xx47��Ai�������r��xx5'���~��~�#����`
X��P�|w4��
�+.����8�U"�g��;p�TTK�u-��Ep.i���T����RQ������������C�N��?���k%���*�������������������k=x�����m���7n����O����5't���Z�����0��vO��7����h�L�N��������_��7o��%�R�-s�k.N�SR��G,>4�,S��s��-�~T��e�����*x2vU���C����
b�x���H�	���e�cg���&����w��X��)�-���FY��!�-J�����@��=��(+?�	sF~b�&��,<4��'�����#��K����=AB�~d|e�	!���� ?��n��B��6�S�6!D<bBa�b�D[�+��K|�;O~=1}�ifij�L��
�������O��9#?�`S6X���� �k����x��y����?������'�T���8��$p��F�v����\`E�L�Lq�g�0C4�CA
.�?��z0���}f�&w�"DC3vAy����f:n�5��]��������Y�������k�J&���w�qCaLy�I-�������[��AX_+o�6������8\?�����U����ze� zx�!�uC���W�����9	��_���y�m�01��p�i������_�`�7 ��@($8�����Y���[C�a�bC����!&���<�s	s���!pf$��Uy��	���L�!_����=��� 8x�!���e��"�������!�Z5�Gp�1��K���_!��1"����q�x�
��X������/A�xf*/����������oD�
�+��!�Cp��C��e���o����>�;3�7��Jh�%����?�\=��i���������]����[ A��?��s6��A�4�=� /*��=_	r��s�4
���V=_�H���v/%��c�"�Z����o�	���S�fN�3�����4�U��`����4��	sF~�s^\�"������<�"��U�ypF!��o��r&e����sF~�s^��������IY�9<bl���z�����������#��}��z���������_�#������9/|_B{0gRV~X�C�3��k��)0Ep����q������K���_S������=�3)+?��B�3���?�9C����Y��L��o���Ph�b����&p�	���IY��x�N��rF����Ck��`���� -,�lw��?r�ni��D,�]��*�*��U>�����}m�fW���������G���B`������'��S/���>��������R�m;�������w�������5u�M���q�������	�9�t���q@
���.�hmww��E����T�}iVL�
8!� gZ�%+i�|C� ?�f�<��.���aA��#���y�p#x���`����&�IsF~�_�t�$���d�7CL�0?�_>�[*`���]�]����������V��M�[���������O
ql �B�3��
�����\>6��k�]g��2���;a��O�����#vsws���D
W�X���/����h��^M@p�%����i�Lb�B�����$�L��xQW-�'��[A�����98���7�]!3Y�a'���\�k&��9��>9�re��!
D�3��s@x��:#����e���9#>9��'>|0?��r�d����c�����7��|/�����d���"��s��������WS"�'��o����{m��� 8�K�c�����V18y'>9��b/�{��#�=�,,+?|��|��	�m�����Q��}�j:������4����O��h�m���c��	��daY�a�����'?!��
7�����
��ub���E�7�!�(y�����Q��0%���NT��M�32r?TcI�vC�����K�����h�=j�^��Mz��
l`���|�:��![� g��e���{KA5+�e�`��f�(�)"���7�
������|1qR� �=�x.+=h!g�B�3d����6�!4�=8��;�fn`}
B�P��i�]�un~���"����c�y��K6W�A�9�=8�$�D��	�^Z��7��nFpK=wY.�G_�rFy���"W�F������y�����O��9����57��~l�K�j�������G�����^&��Fg���
;������rF|bU���8nX}������t��3�����I�Gp`��y�]&=c��$���Z�������N`��'��0=n�.{k1j-v�p.j��-���Fu��s�>C����_���J��/M���	1W`�=9��0(���:��<t��� $����M��"�c>�����9#��w������.+>��!g�'��c;���j���<��g����e��rF|��D�����]^����b��X|A.;�'>����2e��#����7�@pp�j�N����q���Tv�����#���LQ�u-^s�D�kE��,Cppu�c�M��S��� V������8�}��`r���4���9#?� �7p:l���*%���d�g�y�0g�'V��{;���`r���,<�����H���B����`r���<���U��;�U�@p"'�;!��/���1�P�0�A<����(+�~�%^
���RB'S��@�?�.>�����>�]�6r�G��3������^����[����Xm��+�m\!�Bt���5C� �H�9'@�	���4.��g��?z���a�`����C+�Y@�<�����M�g����6��a��@�j�D?DY������':�"��n���������9'���f��L��y~��`i�B��ms�T��Ft�;$�����L����6�{b#:x!�[t�
��)c�� ���W����&�=��KV��!b�	P�a�@�����yVT��L�sB�k��
|
6���w]����'������V6���aL�.<���u�����Z��k�n�qm(?����p��"��o�x�)J������h�.G���\Y�a��Y���'��8w��m�?�0�+v]�����C��KX����#:���c�����t��������Ftp:��=�.k{��87k;���)���Ch�;c�����m��,%�Oel�&l�W�g�v29���5���,&�k�M�������GR����}Rz���������;c���ooM����\��N��q��T������?���n�-��-������������~��_��-�B���6��t�c������c�r�v@�DXpm�T|B��r�6���������g*Y�
",��zh���8���r��%�0�(�P�	��	������W���T�9'��s�L��VV�����E��VV7g��\����L���TsN��J$3�����W��b�b�X��r}�Y��k��%��d��X%�9J(�V�S�$��d�Q�*?������
P?�+Cd��SF�U�Ct��Fp&��
�@��0�(���'@1Z�{0aNV�z���<�-l����L���C%�XP~/�{"�A�&�=�0'+@? �B�f�bO�yp4	���9Y�!R6�{"�������'z"=�2}�p���W���Et�;V�����I�s���	�F���l������I�s�DrO����	���9YNx�j��(��p��6���������*�v'@#���8"���6��Z�
#n�9'@)O�+���U��x�'�g-����D��
���:��<O�7p������t�Ft/�}�-e��%B�s�/��[������D����y"��!M�s����y0�	�����y ���\[�>�����
��p=���g�yql��g�ql������7���O�w�k��r�-��u�[
�f��-#_���������V������O��w��K����[����������z���Z��S;k���-B�s�Pn\{����bV&YA�'�^}�����$N���W�q���+P��D���$�9!Vo����$����d���{9'?����0�5�����B)��T�F���S
�{��p�K�{V.��'?��
�1����d�7��hX�����z8��WQ�{�xOV~� V)��������A <~�� +�B9��`��5:L�%��*$d��@�EX%����zVC��o Kp�UH����NO9'��I
��U��'*$d���sN������������NO�9'��I
��:�a������0,��V`��������NO�9'@�q�4.�]�KGt�1���<=Q!!+���XH�����D�7t�o����{�BBV�#*I($58����M��vK�G����0�K�s��K#9�j$����a5j��
	Y*h�O�s����� ��������P��jXy/@�.TLjs���D3�0�X=���	=$f������`R@3������)s���YTc�g����6M��Q�pQ��V��]��
�b�O���w����%���[8��}���6������'@�H;a���R�@���]�fC���3���O>�zI!��;����U��Ftp�����]�Y�u���+\,��_~ �=�*+?5�9'�����B���c���,8�9#?_�1�AF�=�*+?�+&�9��Uy���y��{��+
!+?n���Q^l0��%�X�� �.(D��>oWBV~!rN~RA��oc�a�%�=�*+?�K;�*0��'����j�j����v{<�vWBT~S��Ka0�����������{�1TV���jn���C��P�Gp>��
'z���<����
�D���D�}���DW}*M��R.���+X��<a�i��?�*+�C�U�{J� �����w���
���PYN
B,<��Ry*G�V�(.���QSy��������y�Pd���#�����c� �
���9���:CA����PGp�-�
P!�[T�P���.l����
�V��-8�s�X'���fB�+t��Fp��Ve���S/A��On�*O~�.�{,�*+?�+A������o�V7�<�!?U�q+��7������Mi<9����]���mx&������#��x6�=1������/fmco�������k^e�����oi�Z\��z���
\��X�XV~
�E�\���'?�"�=1����k� �~1s��9a��
\��X�XV~��D�k��Bg6�A��bg����
��s�'���#��'��������������73����7�����j��D�XV�hd���f�A����jEt`�,wV�3PZ��cV�"�n��{1�8'���Gq��j,��fuY��zC�����sI�[?���J�9;��.�K#���^Y���H��`�Z�������_��Db��z����������B7:�W������X`H�T O r;Xup/D���W�5���p��B��ntF� JV��������w���C��A��W���mD�8v���5������
8�8����]�������4;K,!��{�2�������s�Y++�ve�,����������I��'a��C�3�>�v����G����]�<����`���g0 :���x�.a�����yRa_F4�[�U��� ,����0�w���'cD��i��p:�w�{m�R1-�d����]&��}'+5
�f����&�~l��svz����"+@�.��S!�!6��X�'��t*ma�|o�`[�@�$(��1%��$�\�%h��&�9	�U	�)�6NA������^��F��IP�'��@%���?.y�SG�u";��m$����v,�Y@7��J���U3Hx
u�#�7��p���)G7	`��������r��&���� ���p>�KpA	�����K�nP��c	���D��hA�s�����-��K�u��[09xN�ri���S
�=�z�5�
a�	�z� ���~<l�Dv�):�%�J���3��{X���2���(a�	Pln)����B�{0
,+@�5a�	����:���6���bY:<m���j��C2
W��t��fM�����PCD�Qs���=-����.�V$�v����4_P�|A�����(���������\oCu����7^�P��<�a�P\�����NbX���\���AG���`��<X@���*������?@\P�R6�\k/����
�t��BYv
^�K�RF.;�r�*7��I����Y�V%���Sm{S����	��P}��FV��!;�>�������n����@A������Q#��G���:
�f�C :H9�V5��<��J�CD�@���TE�:�D:���}���`���."�b�\	�x���O�/
��2]=���V��h�A(��}�������P�	$����.�[w1��u���w�k�JpF=)��I%uf����]<?��O�H�-��p�eu��4Rt���?�{��BV����@WO����:hm��%x�Ob0���\<��)�L'3���������w!SL'��K�� ���p�<�'1���U��)�����@7�y���}c!���:����*��U�5��d(�����>�������O.�Q���.�P��c->�'1�����X,C��j�*��A|���%x�Ob���)�[�$`�[��Z%�k	����aD������p���0G���!�k	����	�~����OB]"��K$���i�����>	��:'A�OR~���[d�������� ��q�.�_�����mt��4K��M�i�������������������{�v@
T��RK�Py��5\�:��$v�u��V_@���Ap%����
}	xN�b
�2�YV� Cp&�
��M�s������Gp&�
0@��]=���z�*D�
�`���!�[�)#mc
��x4�=�D,+���>������\��3p�M��$bY�x�1�P*����t�����x���\9q�������I��;�;{���a�yDh�ch����x6���LB�8�O�V����Z�����e�^o[�w��-�z��I"v��h���`�P\��&k	�ru����%S���^[��
f�G������	���e�X-^�Y{,^�����`���+ :����5��^T��E��k�=��-+@G1�/7�{":�����B;S�e%��
��\o�{=3����}���]� ��W��!��.��|���T�s�]=G#6P`���[GzX�����{o��Z�{�(c3`Y��e���G�)t�b������l!�,�l�B�GhS�����6����1�
?C���n�A��)����n��I�����!�����V�T�ch�����;'y������v�-������:�� �����u/A����7�4U�AX6�2���:�� �O �9	J�����*��� �,8�\y��DV��s?����KP.���Ft�i?�:�?Su"+�A!F��_e\)S�TW��U'��y
:'A~l�����Z��y
e%��:9K���A���J�3�4z���\���x�i�uv�H
|by����R"��	t��+*�5�\�C�iy\L���`�[H
%�9	��*f<�:H�&�RZT�
.�~��^�bqOk��|���W�{0CJV�zD���JnVL&p��:�?	���'��b��4�� �O��:����,x>��)p��mehz��ep�~8>E��}V�1��j�t��o��D�M���8"�L/<x���o_
�J�8%�Lp]����x|�q�
p6�p|7r��+���$�=�^(+��m���\��'����BQ
8��9'@1O�R�?�����yCp��
G�����q���>���Ee����b�H��k
�o��k�{0yDV��3���|�L��
���h���}��������t7��VZUD���ap��b��X��S����N�������fg����{����o���E�B�FW��z��p;�E%86(��`����>��[��!:� �=��,+A�cI�R���f�a���Gp�>6�J�h�X0����u�x4'�G�e%8�;��IP��*uX��B��W""��Jq��������"cNmh�'5�=���a�	�v��
�rw�UY��E��R�3A������&l?.��mp�_��P�A��ZX���|�@W��/7��B�MR��t��c�~������'�j$������@��b�9��"6��+@�;t5L��P�����0�X{��
d1M����}�����0�(�p�U��*�}�pYp��B����'D�0��/.+@l�I�s����P*1�Zn>
� �'�9����B���j���paB�a�	P���
�����pY	z4�<��k�z`KpAt��������@�$(���`�j�i����x���0�@g$(6���$A�!�b���$��x���`����P��c	���`���I����-L�c	���`k�i5��������������#a	��_j��c��F���in��"�k��
&�����,��4��p�]4xO�/������0�*��(Xfp��M0��Rp�	��"���[����R�q�=�
��}���R�0b��<��N�l8�g^��=S�$+?
~����!��71`�4b{���$+?,�'���W=0�������K}b�h�'���O��n������<���GL`vL�JvD�US*�4����x���K}���E ���������@p�|��=D�	t��'W�"�w-��:���H���l�4���Sd���{�����5��J�	�kO��-���=&v�7qu����$lD�2�@��c��l��XB���������E}�SlBR{x����;�4���A�_;/��!����)�Nu��-
������bD�a����U7RlF��Z~/�I���ew�tL�#?�NB`��{iL0*0]�U�N��:���$v�p���`���e������z$�u&[��fy�p�_���-~)e���������]��K�w�hb,�+��esv?���{B�������a&a}&��s�3���r�%�A����p�}Tc���h��N3�[�v���J�1=�\09�\�(w'�������c��N�����z�=��-�?���_����:'���-�j}�Z�/�yF��M�s�?���������$�M�����c�5��f0��
U�����������`�F������6��zao��~��a����%���C�Q7��B�F��D��h�Z�/�@F��tN��c8�nt�a�y��`tV�������At�s��^����UvX�u/���?�nt����s���~��h0�8b}�������v^xv����
Hs��n�E�g�u��O����B~���J���ck����F�:���QR���[\����q8g��WWw�����jsC��:T�/�'�g�
�m:P�����������u��F�lS�6b�	P��f�q��~���d�sN�R��Y��y@�3
\����E�:���m�bwt
gj.t��h9��7�Sgn�_�:�EE�������]��z��1�E�w��?�����
�n������������ :(W�p����I!.�D��!�:�
���l��������
�"�`
Y*8�	s��H���x�WD/�{����J]����+t�%]P��������f�����!%����Yp�o�R���b�����S�h�*��OR�^j�o]���o�{�
m*�����Zv�u9x,���=2����i+t������;��K�_�vh�+A�����"+�	^[��������%8#����_]B�0�3��I�v-�
��j5����.�\�C�>j�.+t�!df����O1�STav����o����h?
a	��7tN����!��At�ovv��� L���s������Y��]`����<�����������RW��E�8�N�����M��<�T���7	�vC�::������"�4+���6��]��B�)�q���-Ed%h�T��f���E��Zl!�Op�v����#���%(W���#����!+A���/d���P�.����&����cr�J������!�md�9�p�o}�,��p��qQ���h]��?A�R*:�l�|��7w�����'x��E8����Q��:��b���;_�xN�����5��]���+���	����\0r0����{��2������0}�@�~}gJ�����q������tW�_��}��
�a�����l�&!�����\����:��Q�MB�O{)Dtp����9d%�9�]a���Ka��Btp�t��<09�
�ap�t�Hp��u�q������
}��Y\T������m`O���|�M���Awy�9x�!�?���v�����x<�������aO:�#�b���;@�J��M����&�2��!�BX_+��ky��1��X>����C2�B�Yy������BP�g3���!4��P_�gm�4���P�L����=-�lj^.n�x��v7i�m�.�4�N�����Z{�Oq�r�x�j<e���2��%�`A���a��p�,)�-oC�����,�����
�\;�,��q��h���ZYB����v���h�v 4��p�5�
�B:�)����6�F#����>�5w��O��������7�6�T�?�2�|'��(ej��{}v}������g�v����s�FQ���3"[��D�3��?n��qee8B�I������������[��Zm�����5�o��5���x�m�@4�[�����k��D�����c�T�-7o&�;	���=X�-+@Wa�%���N2���'�k�e��0�X�u�
	��oY	��%!?�@����J���*�{�UV�hX���3�
8����A���xid0b��F����7��t���+_�v���Ffv���J�u�fJ�s������ ���J�X���gxN�rM(���@�n�=b����[����At`����]X�� �;D�x4"#��x�`[��#�O����Gm<��|�e����>C���m��������o���sf�c5)-�z/q�@��`��+�'��/��h�|Hn�Qa���MIix�#����b0��v+W��Ftc0���dh���0�V����b#���dh���0�/_��@�	�`UV��%�0W�^���J�@t`"x�0�/�*+@���B0r�����Y����
08�Xx6R3������v��������2���i[-�Y����G �k����Q���k������S��m�'s�v������Zx���R�n�������_���	��/����C���Qi�����g����Y�!o��dA�]w�m�d.��;4��3����P�:��v�(-�|.���������3���������_{���XU.E��m#�������A�3f���UsK��~��y8���G�5�"()����=�~,���s��y\U
�*bx�A�1�}�I���0�J�3�������v�J��G����>�ao_~���0�=��)���~�n�.������F�/}U��du��KP�u_5�C�PA�����y��{�-��'�2�^U��'B{4�Dt�B�sP�n%���� �7�^@�I/��`���`��L������K�i����@�$(���;z����`��"�k	���0H#�9	���rKjHx\gn9%��{n�B�O���t/o�����=8���RP!3��/}Y�#<?����z���-���������Jd�yQ)b4��g��xs���\��p���d��B�:�P����"��!:x^#��\D8b�>a�	Pl1��w�{@�������}����S�X*��'��A�������Vx������������i�������w�g$Kav�T:�x��v����� �.���� ������������y]�g"�
k�sN�b�}.e�A�k\��=�|$+@�Q#�9Vw����:���#Y�`����:Ft`����d���9����c�z�B=^���KcR?��h����F��]�\�r��=�rg����.�]���{��=�8����+�3�Q������������
t�ZLp���Jp�W�����+����Su2�M��@�������Y	b�.�����n�@2[��@�7����!+�n�1o!uM��kt�~Ip��Md^P��6x�(C3#B�x�,_P!�6v�_J���T����<��J�����1M" ���������U���������������k�~�����{k�M��
/mm��-�u|$���~��o��'X;{w��,����������0_�>?~�=�L;Km���j�>b���(�Dy?ex+a�7�Q���GD���S+��
<V���5+0����'�*�&2D�Jt���@aL�U��R
�JM�TZ��&�T*3�����0v���u��*�X��k��*����h�Wa�j�]e�E���&��_+M����;��_��W�kDWa�)H��*�Xu�
��*,��A4�����dW��W��(����
<V*P�^PeV��i�ua�s���#��*�:��cu�b(�P<�.�<�R�L�v�D���#�"��*���*�X���X�Mk�q���*��	VA�Y+�.@�d�)�-�f.�m@y��&.C%#�I�r�SFH�AOZ����
��w���s��	w�C�UZ-����o��o���v�
�u����&hP`���W����&KIoXJ�_"���C!�����5�����.���<Z���l�C�Vo��C���;`I'�k�6N��P�q`����.��5{���k%����q��KQB%s�I�����ko���m?��u��OE}��%�'��[�h-������-4"��:�:���4OZ�h��"}u�[��d��4��%����s_��Vi��q���������s���������������_����}��/o�������w~�����_���O������"��h����������6��y�43mp�� NC$����v�^^C���4��v
.���+�w������=��F����%�[-I������-9����Bc�(���Ye.�
p�ka�u�|������
�������>��4��D����;o�pEc�����Fh�u7�bs��(����m�  �|���sAh�w���` �J���I�w/k� ��w���r�y-����s-����e�,�+�����*N���L�8�37���m��E�k�x8c��m�����������#�f��e(k�:���n?��R�C.@��
���$z���I"�jN���9�4*q�!�0!�b��'�x��[�T�?U�$�t�'�����JM1�)�ng��0�5���9h	��8��G���Rw��eA4��x'UZ����"�Hqa���+�����)��E�����
�X/��x��������%j7z5!^[�N5�3�#���|���u��v��'G~�u����d�A��:�Y-���
\��S�P��K��&52��sZN>�3����]h�y����O�a�od�_Sk����n�C�.i�����2�xE� �	���|f:���pw��E9�4No�7]���'���RN���-3,�G<����������2���51f�`lc
;`����#��!��H�����f[�r��cb!=�}w;}���o�]I��h��-������lho�:UA{��b�������ovI����,�]rd+�)B�:A�����r��Th�H'�O%�����D�/9���1FY6�*(0t��T?TL� `��(����ZU�?�YT~.��C�0}+�h�I�����7�E��������-`�=��l�P��WF�:[�Q�����WP�������]�7R\������f..3 �����=��i���58}��h�y�4��*A���UM���{���*/�������W����{2��J��n|���/�k�VR���n
q�������c�3O���!<n+����}Dq�E?"������
�;h�X�j����+4� ���W+�^*"8V.���kF4�ZFU���*X�#��c�:B��19\������8&e�����d����1�v���a��v~�E��J��3^�s�����-��V���X_ZrS�
�
w���Mr������G��bT��1�=fF�����n��Z>�W���m#��`�rd�"7�W8(G�c2��.D��*��B`V����!�QC
3A?�*������qk�g�5�3 ���69���\jD���D����h���9�����'���$�6w3r�O�$Z&3���}m�3�'s�>��������O��)�A}2g��h��lQ���$[71[T({�B�!�5���Q���E��g��lz��P��):%kL`�b�rR���C�r������P��):%{�z�)w�N�^�u���SJ����S��R���G��g����|��?%6!{���p�N�^�u*��S��o@�
����/��N�StJ���Q��StJ���Q��StJ���Q��3tJ�Z�T�NiY�b@�N	��Z��p�NiY�b@�N�)Y�bD�N�)Y�bD�O�)Y�����I�Z#��x�N�Z��x�N�Z��t�Nq�rI�NM����Z��t�Nu���:5��S��E1�N�����E1�N�����E1�N�����E��N�����E��N-����E��N-����E��N-��%�Z&�����(�tji��)#jQ,M����)n�.�I��S���s�����(�u�<+�)Q�biQ��StJ��XZ�����(l�L,_NJ��X������)+kQ(������H�Z
uJ��SV����S���tY�B�N�StJ����S����(�l�X����E�uS�)uSV��������)+kQ`��rJ����(�tj9�t��ZX;��R;�d-
,�Z�)���(�zj9�z��ZX>��R>�d-
��ZN��r��O-��O9Y����S����E��S�)�SN��������)'kQ`��rJ����(�~j9�~��ZX?��R?�e-
��ZN���6B��B�:�~��ZX?��R?�e-
��ZN�����O-��OyY����S����E��S�)�S^��������� kQ`��rJ�T��(�~j9�~*�ZX?��R?d-
��ZN��
��O-��OY����S����E��S�)�SA��������� kQ`��rJ�T��(�~j9�~����+T�S
�>�'�B�:������+,�ZN)�jY�k��Sj��F���"���"����+��j9���md
,�ZN)�jY����S���F���B���B����-��j9�����4�`)�rJ)U+�jr�Z���Z�V�����T�)�T�l�����S��Z�n��i�V����mqa���4_�J������;���mq!� ��V���iZ���SXI�V�W�)z%�H�B��=E�D;i^H�^����h+M�(������ya�z���+Y�B�^�s�J��P�W����-4��:G�dm�z���+Y�B�^�s��g[�V}C�P���^-����w��W�N�]N���h���)��}G,�.�4vlqQgt��
<Z��p
����]YS'��un�j-�w!�h�Q\#d��q��s��]���Z-�BL-�'q��5(�	����4�V;�x���6-����]Q��:�H!���B�hq*�#O��5�[�����Q�����.�U@���!�i�~��c�CU]5����.D�@��Sv!D��v��(d��Z���]�<Y�)���\���M��j-�w!�h-��F�����[�F!���F�z�
�6E��!�6�(��*�d
�.k&-{�'~���e��Q���������p4�|�����1yqU���DDeUB��V�B>��u�VB��VC��F��m*n����_	�k���s�f��V\'D�k�B8�(�W�V[	Q�Z�&�EDeWB����E,R����v:����E��+!�^k��.w	���J������DDeWB���=D��+!�`���^������'	���PSk%D=l=��6�]	Q�k�f��O�:��u0y1W�kB��������A��H!�T��Z	&/�J@��HTv%D}��������vm-+�����^����������B~%T�����0���uB���F���B~%t��I���FH�"��+!�cw���3�;S+(����m%.� y���W������m<O�����N�����������>6x��<����w���������������~���������'e��!u<����|�q���p����o������/~���?����_���/��w������5?{��������������O���eO|G������jn��$��
�� ����I���#����2�B��D���o��LJ)�G^������������Q$��"�/O1�'��%���#_o������/~��~����l�l7���7_������s����N@����C��������~��_���gW<���������?������������|��?�������?�������e����/������A���b�m��s�Wf�l����H��0&�Do���[~#]~z�����u� ���69�:����|5'Qw�ur*�8*qu��i��t'Q��'"�jN���3�O�}5
�A}2g���#���O�}}�p����O���>�3�I����*�=C�D{��P��%���B
U���R��_�C�r������P��):%{�z�)w�N�^�u���S�w�G��������Q��:%����)�N�6}qu*��S�=_\@�
��&d-��:N�)Y��G�
����E��N�����E��N�����E��N�����E1�N�����E1�N
g��l?7�N
g��lo7�N
��e-�uj8C�d{~�uj<E�d-�uj<E�d-�uj<E�d-�	uj<E�d-�	uj:E�d-�	uj:E�d-�	uj:C����T0��Q0�f��iW��B��;^������2�*\d��]�m����
��	���
��W�6\ ��|�����������
�IK�j���
�I��k��8|
����OD]Q�@Z/�|9)QW�7#��g�uE}� ��R���oA����I�^�S����I��S�E�jO�)�{�+�������B�R������P��:ee�)�:���)+{Oi�)u�NY�{J�N�3t���SuJ��S�N���S���]�ms��i�e!%R�������?X�{�O��|d��n@Rgx�vO��f �w����Eq�ye:*Cu�R1o4���=Ym���

T����B���fDR�R���m�T�j�)�mh�\�n\�����7uK5����=��
l�����V
��� Y��<��!���y�z�����}�v��-��=x����������5���n<Zm��N��
Z3���,C���x6�R���������ov��h�-K'���b���9�i�����d��-3SO�Y�}z���#4�H�l�e�g(�3����
�W<p�}cd��M��8F�c���LZ��I���LkB�`S��w����_,��3��yxv��n�t�i��^w����x8
�o�>����)�EH���m5�s�'�'���v����>#�|K�}��m�E8��Y!�9�����H��vC�g�'H���pNG��0��q��@�]@[f�0^C.�`�r��x�!�n�n�!Wd�$e���"Mq��c�+��[��=pH\#����c%�3��L(������2����~^��Dwe���;,4�!�����{�2�z��l#P��k��5�C74#�Y��3��*�f��m���l���ee������@�>������1�$z���Z��B�E���N(�����I3��g��H��mb�������� q+�{�#����J-'����N�H���-p���A�WN`_��%��(��X>+p��q���=��~�sw8�������.�:�����k	�I�y�`�
�|V������?��Pj	�K�w�t��p����	'��g8���1����.;� ����f�&������ne��;��Q��%�(J�6�4w�=��e�#��3��q��I��p�g�=p�;��p��3�p6)���pw`�s�4�G;������xg�C;���e�L�W��;�K���<�R�: p�r�����XJ-�sI���g�?r�����p_<�k	\��9���I�33��G;<�q�'������}B@;<������SJ��2�'�3B[���j�wd3�?�d���u0��l��v�~��i�ndZ��G�;h{4�����n���n�]{�"G�-���q�ew��)�H����|���;��[����������/��D�d�����o��h� ���
���$=&8����9���Y!�b�o%N�!�a�l/"�jN��0�����I4�6��O��$����|�>���=I$_�IvF���B-g(����aA�Z��(�<����%b�rR����@�:�|9)Qcbl$�� %jM�����3H��c�����nR�����N�����A1��S�):%jQ�-�T{�N���T{�N����:C�dO�
uJ��S���F�:�N�)Y�B�N�StJ����S����(4��>E�d-
�:�O�)Y��C������E��Nug����������I�Z�=<vg�������N���&%kQ�)s�N�Zu���S��A�2����EaQ��):%kQX�){�N�Z�!M,_NJ�������S�%��C�I��MJ��p�S�������;C�d�G�:�N�)Y���N�StJ����S����(0�X����E�Y��?E�d-��:UN�EJ���S����H6��p�N�N$�T8C�d'��=�T8C�d'��=�T�N�Z=�T�N�Z=�T�N�Z�W�X����E1�Nm4_�DJ��P��StJ��P��3tJ���8�N
g�����qD���)��q#������(F������(&������(&������(&������(&������(f������(��:�|y���E�������m�2��S�:%�e\P��3tJv����N-����E��N-����E��N-����E1a��|9)Q�b������)��9�OM��O�����~j:�~J�����S�)�S�C�&���N����`6a��tJ���(&���N�������S�)�S^����~j:�~��ZX?5�R?�e-
���N�����OM��OyY����S����E��S�)�SA��������� kQ`��tJ�T��(�~j:�~*�ZX?5�R?d-
���N��
��OM��OY����S����E��S�)�SA����������a}��
��P�	���*N+������������g'=����(bF���gt4@�� 79h#F��ui��;b�M�����v6�&
|���r�F��G�Tnm�WK?y��+1x�5t��g%dm�	:�3V����D�mt���[-��c!d�%L����h+.�W%0�b�v]Y,��y]Y���570�c�w]Y���^���q�+Q�����Z{���7�wVx�f�v���BgZ��fV������0�&���f(�_k�0yu4i�+�03y%�w��w����_,���,�J�������W�|7�u5���>[E�bm�M�Z��N]�@m�6��*P����<�\dh��as.u���
��.i�v��3�>������c��9����A���1��9�<���V� �q�����k�����m	h���a�<�nP�a1������uz���]�
;�|�9��A"�X�Ns����A�L��;�Iav�k�mv��;���}w����+P��q����5��3���m����.��|�$}����$�Y��9�l�u���iT��8=���2#'Y���{T� 1qr�1��������������P6[�x@���\��}Kvi�a�b��|W����E����r�r5�sY��|�*��C������n��E�e���&���,��������8�����Y�eY1'}�#:��<��I�n��"2�q�F�6�A{��� j���&�"����Ok������Y������\��Q'�"��=W��N,�s^'��/���[���A������-�#m�6�r�~s�-#CrS,m��������LG�7�vi�����_c�3m/���V�����]n��Ws^�nX�cbW�$���
R;���v�-�4.�`�n�H�5���j0J=�H�U�LF��-/\�z�{X#m^�F�����@�5���[����d�����`^���k|W�e;�e[���MQ`w����
��`����f����	�����v�����g���z5���e{��$�l��%�=�{���5z���+�������#yZ�����"0#��z-�sA������m��`�l������;���vT�F��m�~�hx��n�QI�w��Y��)n��������`l�8��zs��[=�v?�p�k������s��I���������D���$�.r2'p����
e�4�M�r�H�cD����W���6VC��?����'A2c��
k}�����n�w^�.�n�E�.aqZ�1�e91
�����c�d�3N&'���CH�f%m�����>���T��m�����rR�����>��~g&^t��[jBJ���N;��;���\GP�!V�o���0�MN�&�E�SND���DMH�u��F���DMH�y����I��BaDN���J�D�LkP��3�I�6��	����O�I
�O�}��C�P@}2g��d�������O\�K
���P��!�j�=C�ZYS��J�3T����u�SV,��y���5�.�0�$_�iO����l����}$��s����K����/�}
\`�cFl@����n|TB�l�kF���>	�4x�4�x�����TK��W����O�<>������691k�y������=�
�6���TH���M��|�u������pV�g�����H<TE�O�k�/��\~J.��^�"���|���I/����3�7f��w����;j����ow�.�.��I��"Qa^��D/����")s�jF6R����W"�:N{r��g���YM$�2���E2�	���f�s���Ak	��/��E2`��~��������|����]$����~��*k��	xE�2!������?w��*Fj������,d�����?6�mT�hgr����Y�}���1���OJH{�A;��!�����(��7�^��O\����V�:h�J|�b_z�n��0�MN��=���Ws}�Y����	�D�F�~BN����8���,X5D$_�I4�wP������������lN�(I$_��Bxx\'��@'g���,'�-�@w�H����m3�������n{J�00p��S�I�w�{�5?�����3~�����,���Oi�r�b�|K��Id����e"��Ae�k������u����&�SM��'���I�Dv�M[_G���$i"_89���8I�C](��I]���.82�
y�R��I�������w�^8YX'��L���.]..��c+e;&i\p��K?6R8�$#aNu"�?�1p����i��k�`H���7�]��vW$���d��Rgf8������9���
����D��]��>��� ��~ae�����}�y�w��4p)�������\�k�lR�60�>���${|��6=�iw-z�u�2�����v>y����O+�[�u}
b�[y2]k|��{8���qD��7(���u�E`�0��>DA:�M1��>�
��L�
aO��{B�x���t/vBqw��"A��N���gw�.�@�\��;U#����	w�d�ymr�3���;D�B	�~;�����`�s�LI>8�
S$���<����o�h��.��5p��S��{��I�xQ��A�>��E������y<V�e�b�w��(�����l$'�8��#��l
�+���0�[�)���mF�JT���D�5�B��}��nq�2��X��B���%������D���Nt/;�u��8�;��.SE�O���?��?"8�u�y�LTGY���������>�(�����-�#�|����"�k5��t�X����){!�A��pE"t�������Z��5�}z�� �a�ds���M}�"����
x�.��7��A�R��Y�����p%��]��Kk`+���,��b)xIf_����B�%�3u�������R}��b�^�.�tp/��x���'��G����Y
��dW�\x�	C���:k�#���>Pj�>f$��2PKm�	�dG��I$���7]�U�����iiU�����p��3M�����O�0��<���d�X����|��^�w���@�W���2]X:�5s�b��J'�e���V^��=������ �����
p�?K���&v;k�s��I�7�B�Y�e�[8��@~�J����t��%�)�4�6P��[o�P2��A4e�Wi�
�m�vicHs�8A�1�|'���
�pL$�j.������S�xa��D=�[��1��ny�z�}��Y)C�:����i��fr���Mc_y���
��K��g����]��_�c����&�TpDM����0�b?���V���LC��6�\Q;itpQ���zi�����x��f��H�ua�`���:k�|]�������4��}]��?��x��5���y!��T��z ��0���^x���u���BR����.�=����R��<R�5�������q�$���5��b��:8K��;\����!�Zg
D��q��h>�D����xu����k�#�^<�F��H�Ya��0��Q�E��*0Wa��h�u1VA�U���'�_Y_yn�����*�:�3��s1pTmd��yDV�Q#YwyA�~.���JW3�w�M�U�u����b����03Y��r/T�-jjZd5���|��W��.��@���W�VU�g��	Y	�������B���~D�������\Q�yj�e#�aVr������������o��UP����i�O��s�E/&5"�]^�v��u�'�'�*zm����W4�HZ�DR������@~*�LV\��I�:��m$%�;O$���*�J���D�pou�2��O$%�;O� �b�|x.�b{D}�	fM�I�w��EN��������20�g��d��3����q$�:�������Z����$��<Y�]vWe-Cd�g]��@!����$�>;���>�d�g}8��	��������J�)y(���}����u(�:�w��%Y:��(,C��*��^
�r{%��*�Ac�($#���d]�������HYSw�@a*i�w<�z�CI�����CNX��i�Ci�u(1�A���V���q(U������0B��t�Xfd�h��'',����������2�z���y�(����^��#�]��� �E��fNNXY/z�����5cd��cJs�7���V&-��0cLi������y<D���}��������HJ�^��(�[>�x-��XQ/zn`wOIm���fB��,1�j�
�^���HK8q����W���FIO���z�s;"-���N���JD��e}���
;�<�:Q/zVx(����k{�z�3vZ'��� �E�%]>��-��=k<����$�E�J������+���]�'C<%�A���q6�����T����]�"�]	��e��g)�D����o����0 -'�
�^�l����)��2�z����7�)��^���7"p�2��A��AZ��o���������^���������=�������d�������7�)��Y/���@a*�������yJ�t�����1Oi.�)�[Y/���}yJ�e���{<��yJ����E3��^�P���1O���AU
f0iq����}yJ�e���t��yJ������^t��]�cd��cJC�}��N�I�{7�S�cJF��1�4�cJ����E�F����]1��H��xe��	�1��#�XY/{OIm���gh7<O�v����_Rt���M���H�|e�V�|����"]����]K��f�>�k��{.�5y��B���G��I��Q�K���r?}�$�����u���%���@Wj"(����+*�*_Z8|��k���[��Q|#���a��X���
��1hZxT��f��4G�Cu���7��_�-��3��y�/7��^F������A`�N��M��&��l��W���M�;�*�~��M_�h=<���g��]�^��m�5���~7�y����E��:�= ��KvP�v��A�P'��?�� ����D���8!8(/�d�/y���i�� +�^������?�[����/[6����69I�C^8�!�H���$�|�����9I��]8u���PY���s���GN�^�8I��\(�>�3�I�!��=�S8C�$_.�P��3�I2D������O������}G���<�)YKb@�*�Z�"%kJ�R�*%:{��uj8E�d��uj8E�d��uj<E�d��uj<E�d��uj<E�d
�	u�<6�)Y�bB����)�&��S�:%����uj:%6!kQ��S�:%���B
uj>E�d-�uj>E�d-�uj>E�d-�uj>E�d-�uj9E�XE�o����P���b���M���W�������H!���O,�V�o����2-x��<w,D>�k\��Q�S���j���^��~�F0B�,S�[g#$Wm!X����h-�G�B���&)��,Z�������B����O��"��E�����A\#DM����r�F�hq�k����Sv!D��ZuD
',���n�A�+&]h-@�����M��,�u~F��F���<O����O]>���Z~��j{D}�.��F�U;�VN�;-������q�����Vo98C�}��gD,��n'JK��^��'JH�V���m����n�t�F��u���5��h�
�>|��������{P��<�<j�M2��w��>"����\����zA
��n*"3�p�+�u�5_NvV��E^$�j2��Q`;�=�"I�zR�m^L�I�I���D�u�Z�c�.-�S����l_�%-.[B�T�
pM@`�c`�H�~+�SK_> 4��X_R�r�������61+��;�	w���v���jS!FiYa��*F�#z�1���3�{b��hy|bl�~���y�A����&�4��{�st�� �:�}��o���o���-!���L=^��uB����7��gq;�n������b�as�cf<��e�"�*�z~�p�/��|�<a�������`�[G���������_�K�h�D�6-}�������H_��BH%��(�ic�C�D�AK���)`F�	�����	0FJ�w	����.M����D[Q�%�(�(�U��=v1WMzx�	wS��wc��!i�A#0'�����3������B�nWHt�-��Q1x�A��&'Q�b�������o���Q1`)�|'�&k
3��]%�8�f�Q�f��7��i��N��I����(8h��>��Y������
���1��yF��e}�����A+k�����"�Oi�qb�>��>�'��������at�(�Q��#�������nv�"=��� �i����.�d/�B�NP"*��q���Av!xQ\��E���3ai��r^�M0A4C|���A^���p�"XHi$��� ��L�%�^^j8w&I�E��M�p1L\ixi��E�pJ�|���"Hf��Z�D�^'�"@��HRt$S�C���r��J����]�V���HRt$�C��B����� �+�L�HRt$���L������+�f.�j,���*Y_�M-������+��.�k���WJ�q�$�A�t�H������|!5�}�}X� �4
Vj���e���/��L��f�h����N����<R�e@CU���}
C�4">�R���.C��W��RvD]�.�Q�H��� �;w����J��s���q�9�P��
���RvD�g���9�^��b/����*�@4X�9��m�`5VQ�v�b�����K=#K�eu���/���e������JJ�]X�C��(���M��vh�:y�U�olph��SV)�2����
V�N�����N1Xy������Td)��^��`T���Q/\Q/�Z9�����2�z�~�(Q�.����^�� 5���YQ/:��J^��^t@�5����C@�5�
VWiD���k�`��z��2��h��J� �E�*��Y�.���C;�H!_n�l��{D��>X`u��NjD��ZG
�_Q?z@�u�k,�0)�Gh�e���:0;}s�m�A�f���Y���ZmD=���A�hm���G������A����T#��]QWz F^����8�jp����/=��J�����������v�$o��v�������*���7=��:����]������l�>W��������%����:���3t��^�����4��k'#�����z#�����?=���HSvD����yc,`�u���[y�����[�
���:�X����E�n�$���Q���ZU�����UZdi����?�7!��E
�_I�����oJg$����5Rx�:H��V��i����?��`�F
�_I�o�n�4e�A���q�u��o^Rk$��'^�����I����@\�[m�wQ+�:�.�9�4e�A�����F�"���t�46+j�]nQta5��#j�����]��.�~�������GT#����u;�4�F|WKz����7)�;Vw��1I��BM�)��D�-���>#D
��0��y-�B,pjO����;�v)��U�-�Bt���;dF�1�&p��B~!|�����	<2�)���������B�Z��D]c��KF<eB�56=�dD!���z���b/�v��]Q���`^��B�J��<Z���-8e�Sv!D�c��� 
�����<�B�;��2�)����],l?�&S����2�6>���A��'{!�m�H�6��a�,���p����������N�����]��w����_,���V���;�u���>�
(����|��?���/?\_,�������_�6�����9-������<"�y��.�_S�$f\��5C�Ef�����{&6��m\J{�K��B������a����Q������������?'��#�o�����d�]�/��*��	��,)���)�E����Xl�y��3��;hG��_d)8'��t���#`����i.R��7'��O�C�,�����������ret9_��`��W1R�3����.pb��3f�X��3}p3���Q=Nx�L<�������Nt�`.���������.w~��_�]�'Q=�{P����4@���]��3Y���7@��b7D��n���$������5|��#<8������B�g*,��l��}|De�i����dZ~��>�,XQ?5�x��U�b=Q��Y1�F��?�l��Qi�g��0!����3�d�F��^�<���{L�vO����|�'�"�� 7��������3�s�3��sz�����mw������>����'=#���!�}p�e#.�L�Q��������3�/{�����_{�������E{�����5<���Hq������h&d�]2�I�o["4p]t��\)|��V���0����m���+�=��
�������v��[���(m�)���o�y�`Ex���j���kQ`n@`��k��6x�������&���������"���^��o&	���x/&�7�QP/�$1����������K��0�e ��������P�x�����`�S�s4l������ZF��)����.�T�H��-)O:l�l|��}���`��g3e^|3����
�=}������N�Cfn4����^��\���	�),������a��.(}���{�����Q�S)>����
�IM����^g�������P��B��o���^h:	�\������S	��]�w��*Fp[����$��^��ZwL*�s��y���p8�����L�m��P_�o�ksK��|y�����?��7�7#������I��H _��p��+��
���c�DS�-�nd���LQ���{���(�vOJ�5��*-O�V2N5�0���b;I���	���!0F���7b��������n���������Y����t��;z�13	��4��S�V�r�(�ra����������<-�yJD�8V���Rl.�w��3�h�.�d�����������e�U�������Qf5��C4���l/�d��Z���A���8?��IV�{q�)b-u��������Q9�|�*1�VI�^�����:�th��:�/�J�-��S�y�F�P�A��nv����=t`GQ��77��hD��3�c��� �aV+#VX���+<`6�#�_FI>��L]����aE�����g�2�C$�.<�C����ya{���������I��*p��!�er�����n}�W�����7���������H��e6���A����P'��|���_Z���<��T|/��*��O#��]���*��O#��D��[�p�����)pA�y~��> �^X�KZ��\�9�=\�6���oL��w���(�c'�����?�7s��Q�56�2r?h��+���;/p��j��_�
s�bs$���i5�Z�.	��
j������_�H>=�B`�5j�m5�d���=�f������h������-F��3M���]5���K��IH��L��u>�*g���Go�\\OS|v�5��a����L� U�������l��o*0�i@#R|�ua��X��6��9��d@rT�E`���{�����\�xX���jP~Dh�� ����U�������d?�Q��H/�2v�-�.��^#��m1�(���{WD*e�$[J�j���I��M��|����C�*Bf�&����+4<>�9��-�F5�6��&�]����hB�_�]k�c.�P%����f����m�I�1���;gHg����cR�����|{��>&�$�q��E�
=~��lr�cR7���������kE
��u�����4�rL�Wu\�J�;�QY)� '4"9&�h�[����X+��M���o�7j��6o���F�I��d��`��5�nt�=�&��QJ�_��F�/��]k+�������8zme��M��c�"�vdoDc�i^q#^��mS!U�B`�]n�������mq�7�<Wu����>���������e7�C�p/S���5�D�*������Dt�x��F���"HY#�C����������4�r��Y
D������&������=�������W��d����L��['�?$T��q�
�G���6h��#o�s{��y�(#
"�h1�i��*u��9v
n��<��eeg\���3v1k��n��G��ma3U�JdkG��M��I"PX	��Jl��Y��'{]�_�X�f�>d��|�+�#��b������Ar(�h��L�)��6s>u���N���Lg�=$�0��xbF�6}��h�*�>��������[t[��#��z���0Z((��{'?���f��tD*��aD7���XW��������{�@Aa��`S����#����1�/�������U�B�9�h'������-��������	��!;w��e�:/\�t[��s�]>wO
���I�xD�'E���E��f5��,_%o�:|��U"3���,z�\l�!��?+Pq0�.B?V��f���?�u��w�|h�i��(����r�+N	:��	�QY}�W+��
<V�U��TL4%WA4��m��~x�����_��}]f$[.�������^�
<V�Up�E4%W�Y��\�OD����c�]�6'��\�`G�*P�J^�
<V�U���hJ�ss`�Q$��U����t��4%W�����~�kz��U�������4%W�K�B��������*�X1W������>��m����l"����w4�H��>�Z���\G18�m��{g�]Q��w�=ANXQ��w��B<E�A�����"'������O�uu��^���	� �C��g���:�:�=>{��A���'���w�fB� �F�����A�����O�uu��R���	� �I�O�uu�
�������u�������:�:�����ac�g�u��t����:����������y�:����E�S��M��<<�<�����?=�[D<E�A��z�Bq�Y�u��t����:�����i�����u��t����:����]&�;���� �O�O�u������<���:���c��]QzTp.��A��5�K�StD����s������h�\"��� �O�X�GNXQz�J�����YQz����+vo��<Z�z����c�p�x�S�3�3[�X��{x�"'��h����b�)�B�fej���TN�x?��S�`�[��0`�w""�L�-�Y=��v�����1SL�g��3���4�E������x_��I��\���u�|�d[�XDE{U��
���b�cR|u�������e@`�����}55x�/u��G��S��<��Nt�����j�� 2����W�5
&,�"��:U*�*���tW`�����Q�9P�C����
NZ#�g��RA���|�iqx��S"*��7���n�
�]{a��E?;`����2O��[����eZ�j8��5	����]5�e��5�+��E
'\WA�-��!��b���WqpQ|����	�xO-��M�/Bu��*�_�T��P�JW���J�L�!��
B������R�
��LNb��d������G���2��W.�)�(>����j_p"���^'�)�4�N���
��*F_��B_�eD�3:������:1������:1�R'*�\f��9��"�U����d���|���Z�-���u��]g�j�����b#�g�um�7�5�� �Pv�����-�/H- mwUC�[����u��������:�0b��d���m��!��Q��l�` �e/��?l|,�>�>��E����,^}��<�|�y
-��w�����_K&�O�I��"�3V��������
^i�P$�_�B��+b�4�I���*�������
^3�2���h���W������'D<��,^��nw�������"�+���%S���q�x(�\V\	/�=�5��������Sg�T�H�����j;z������"Q�������SgA#������/{���_x�F��H�9��E���kF�N�M�����y�������}���Y���\(PP�<���%��Cd"V����f��ccC�����0�=q���t;0L��w���qJ���^�0 6��i�G�wf�:�������c��n��������<�-z���$��s3����!-��P��M�!j���������~�{����9Qw�c�NB�b���Yo�-*q���
�a�a����B���u�`�G����n����{���<�,^}����UhG�Z�~�S�������<���I�#����x"��"���Uf_x�����v�#���:�N��~������68�	,���t���<��J��#��)�48�>�����1
�A�FQ��,���D�m�����UH�D-���@���c���9@.��\.�����7���`������|���$�����p���*���!/18�c��Y�,&��
r
���s}TJ�X���o���������/��-���p}�����T|�v��{X��9?����/�%U�Q�k{W����
_�e���A)����O��mm;:&M��57|,����_|����������������]��r>~������t9�����&�����~�����lv}=V/[��-b��?��.���
��c;��@��������_~���~��_���_�y�����?���/��������_������/��~v3��P����/�T�n�������r���j����MA��ZD?��6
��������7?������?��O?~y����.����_��������$�����?����~�r�����?}��2{�������{�{��2�����bK��/���?�5�$o_�������
��B�!���!!�=�al�����������?��"����C��vG_>�r4�����������kG]�����?����M����l����6{E���o������?�����X`!H�	���o�������=�o���n����^������?��Cv�(��������!�E����lc�x:�<�d)����c���[�8�r�7�n;�m�@h�@�.1��P��]�������5{��V`-"%��]PE�t0!�1�5Y�	�;(����������.�Q�Wmyw����V����9��=u����V�9�f�s�[�:��gYn�t���9�}Y��j������������8��8r�m��5DZ����I`�<�=<�D����Z1���d}�d�++J�3���T��C�?��?<�D���jkA��SB��d���Y�=��B<1	OH�RN3L��_�h'�7"��Kd6�3�'r���V�tn:�6&��-��j��8�Ri�ed)'d������2L����_'4h�>k@�&d���[T2N���g?Rra�8,c�el����2��)X{��I����3,�>WX���	Q�=��q�3������
�&���lH���06����}l�']$���=p�4��"9eu''lJ�m��#,���.��n���ru�����E$�#�	��[��5���[������^�����������v������_�S��{R����NW�����_������~bI�M���7��m��������/���T����7_������������[����o���JW�7��������>`�{��g�����h����^��F�V�`V������M� *�P
��ic���mG(�������QR�W/1�������e�]N���[��������W�bbQ��
��C ����$�Lz��V���4lVb��)C�US���]��avx1�;���wn���o8,��f|����4'����0�7������Xo���zhq!?Fhry����;����A:t��]��{����T����
D�i$48��{���8�F+sN������j��S�oS>�=��F�G���f��d�������I�/�����G����v���m�|��v�}���V?��vC�=�/��3�tEQ�����H�o�����r0i�w��3D����r'�m���BF��l��xJ��:@�n�-jB�����-�66j���G�;�/R���0%��yH�%"�� s�k HQ!B�X����=M�"����pj�\s��B,F�bb+�c���F��}1W}���|6�Y��$�� Y!N���V��_G�K9a�DB\{����^�������N,��*	�ZG��I��"5B�T;��li���IB\a�;g'*���~��B��,�BuR��2�S�.0�,����
��1��z5m���8a�/����.:�SYri)��_��}DM ������e���t{Xk#8��7�Sfgo����
 i -"�|�tMh�.<_;s��n��s����/����~<�^U�#���N����V��tHW����������Ly�0�<b������7O&��
zcq�����q����`��1�Bd��+����:�7��>��5z#�~������f�;�����:���pn�`Zc�wu�[�a�{�c�2s+�c��sk�e6�u0t��P�������W���^�w�Tug��+���~m��B<E��O+�`��F�;g0n��sT	<}�(�@�s�� }�z90�Ruc�{E����5��;��xGhp��a?F���zx��K�����eg
�u#�\����{.w�z�B�$�VSv�L��*�z��<��?�� H��;[v������`����!��g<b�R����%?D�����wI%B�?%�ED WUr.�$����)T�\�/�o$��]����������#H��
����x�KV�0C%b��Sf>�2�5h�b��S3�[����.l\���a�G���=c�����@��PZ=�`�W$����3c�1M��s�<��;X���*"�Y��:>�a,#Y�T��1����-�,t��dI���1B��
�P{
�')�B�Q�d���
���$KGF�HQ��JGf�e0�\�v*����'Zh��Q�I��P�o^&��&4��X)���%���S~�z�Df�	U���~�Q�����{�z>YT���2�#�Qn��B�$K�3�z+�D$�N���	q�}��G��*:�"�l"���k�"���9'���q#���s�8j\�BU����-#����P�q�:���G�sB��XE�",�A�
���aU���������e*�{��YI��#�!n�1V�� �|�����"����o�1 �BAmxM�BD+l�Ut�u����"��?���*B\�
[�����f�"�"S'	��%_��;Q����M����|��e���
19q�1��(��p�8!�B�W��d��U�P����"�4��S�����sN��W�",$�l=����b����X�BT��el_���J������na��9�N�B�G��u9�\K�=",�8��D�'�.�8F�ca
1��9'���e#D<q�|�IQ��+��q���DO�n,Q�ca
�@h
=�)&����X���a����A�"�'�)��3<��-E�O�-�8��6�<��� � ����%�\�&�5�	d��-{�k]�,D<~\����*S{�B*��3J��]�y��
mD���Vg��*�w��!��A���?Y�����+M����*����m����.�����~��<r<zU��s���U|�����i�cB!Kt+]#�g�����-%>]P]����(�ME�;@9|$�}�CG��0D�h��(������
�=Jb��z�n���*�M5@��0?Xu�9V}�oaJ���Xg�G�^(Yh�����B��$�9)n��;�H�]�4��h)�N�BT�]���h��+�������<��	_U�r���7�8������=���<��`���j�<��#b���-���b:�Y:���S�Q��S�mn��������^���}lc@�
��MY���^�z��U��wK��e�.P�y�[�w�Q���b� |Y#�Om�y���$rJX���{}z����ljC��l�[
����v�n�6����`��jW��-�<`4�+D�!�nc-L�-�����
;��.F�����J[
�������b���NtD#l����i��������������Dz��>�L��3��H���=z�v�bK���I��l���[S�������rZ�bw�t�����Q���Q�3��\P�
�,��o<]��w����*u��B��"a�x�/W��\����x���[���zy��+B-T��Z�H������EB�y�|D=����A�]��9laj�jxU��~7�A����Cc�n[����{a��pe�!������kW)B0�#4�q��^G���=�;
��+��l������~&�{�
=?4c����	����	z�V.zFI��$�6�J�K�����YYWB���]e�=��xg|�]�#Y?z��J�����D�>��1���rH%I�F���G���I����X�I;���Ew7UB+��P��\����EYO�d�\��j��
��e-��'BGH=���a ��+��e-��TC��zy$���PC��������
��2����P�A���[7(����?���!��x�a�RC:3�X��d7�P����?��g���P�����tw����'�$;��rw�
��?�-�A�X{5����<�����nI��p�31�'�%1�=N�P����t�8�Y�;����{��@�s�H��Vg;�0��������l��~�~�����������c4�����M��v<!]��x��B�����
����e�C6�������������E�u��*f�h���R5�����:s�|��jn�����x1|X,[;c�G��R��m)?���h�x��yn+Ke�k���>��L��TeIV[s4��8Z�����h*Q���
B�y�{F��u���s�Sk.�T����y�)^��TW�XPqV��	���7�BI��.\�����n��7�����������^�\~�����}�����/_���X�?���~����(�u��_���/?��������.���������?�m�D�7��=���������~5��V�E�V��",j��l ���	����|�C24p�����;$yF��h�"|�'��S��8�

m�
���eQ�������R�0om���O���#�g$X�M�1��su��J���T,"�{|��=X���M�O�D!ww��x������BGw���?W@#"��!vpJ��_>������YK��"�9!n\�u�8!�|��$!��\)g7�iU�h � .!�ka�	��>���a��V�g����F���r��>�������v�����{�i{B��5��P
|���.a�	��>������j�=�-~��v	sN�'����B������VE�O��Ih��Y�W@",4=������9'�&������mWm��Wb@����z,\!N���	p�����
������b��v_2�O�X�!�m'��p�� �R����I)�9'�3<���}1
�;q�g(�r/�Uz4b�i�8'	qDc{,�rgx,��� ��x��8�����r/DI����N�zc'Nhl�������l�{�Uj������o�_��Hr{��6�?���2�����x��n�]6`il_���Np��'��2��@��}5�	�'�;a���ZDX�o��s&+C�rN�'8t����#<E����o�r/���p�"����"��PB��	����C�!��]��QSz�'�r���0*�O�.o�j�#7t3",<=��
�2� �dx���` <����)�������	n�`DX�0>C��[xv�'<;
6 ��'|����?��z(����",�5L�VV���rN�'�9
n@�������k��kB�����sy��z����("���G��f��m����&�W�&;x"��2��J�3���w��z��EZ��
��Sv�q�a�%��+�"<`%�p7s�<D�������6�\_1��aU�������k�� >m�XG��Xa��HF�:f��'Mz���C�� "K�W+�	v����'��	wN�e���0Y�l
5�7���	������O�{G[3�Mt*d,�z�e�J)rNr�	���j���SG� �;p�i�D ��p��7�z�����h���Ti=�`����9FZOC�x=#������{��T]������4��T���T���R���1{(f�*�8�iT(������*��'�oN��0Ch�����/���U��bk��D��;s:���^
%��_���o�������Q+k���
��#��p��?���Q�j�����p�^���h�����y�6���?{������������?����/����������u�~_o�����������k�~�m����3����J���3`~�����'zz��v�����7�����,�m�k����������������~�)���(�O<���o����=�|C�q|����3v�$ky/��}{1�1lRv����u4���R�����a���$v�xm `�zIra�>
�D`kI���1���lV�[�41#���H�����:���r`����Q�mt��y�`�5�r������MHc\�Fa{I��k�w;;[��l�Mc��G��F����H��"��E�������H
���d����H�n��rh�t�H�n��r����H
��W���#��Yw�������������K�O�m�,d�{rvi�G�PC������E"5pK^�������H
��7�j�P.����nx����J��#y��7o�+n��2�����%/x�]z�G"5pK^��3iFf$R���L�^��H
����:
OE"5p�.x.n���b"��%�K��4@���-z]�%M��Dj��.���Dj%b��i��H�n�}�4��)x����-{��&-e�j�Z���`s$R��?���H�n���`�6-��D�-X������F6��[��_&�pW�����n�pO�.�^�}z�D"5pK^�ZA�c$R��L�����N$"����d���C0��[�����#��D�����"��y�pC��
����H�Y���}"�k;��P�H
yK�������H
�������H�n�m�tst���HD�����\Q�:�PE5D�����T��������o�������g$�zti�5���#j�L�6�7J��Q2���_�QC��F�<h�=Vz�3�1z��4����:��'`�xp����	(jow-��E5D-iG]�`���Z�}�eGq��Z�X`$"�E$�����j�PC�,����[�>���;�z���Q��-(I����4�8R�!i��NgBJ�Dj��J�Q��)N�H
���\J�Dj��l<� E"5p��(����.���Tp�dp�����=���urO�~L��HD��u��~��(����f�0� ���	(���	N@"R���M7�`���%c;���	HDd�VQ��[���:r� j'y��F�-�H
��F�ia�K$R��>1�I_"��%�;F-�KB$R7���r7zJ_�"���gFqwmF�dK:����/R��7x�y�1:u�#�
��4��Y�k=�!oI3��i�K��4'iF��"��%%��������IB��������I��I��n'"���I�7����C����#{�")��!�V�h=�.�H�-�Df&�&�F"5p�Z&������-�����D"5pK���i�'�H�n����p7�"�����[���v(iR���i�u�3/� w'�pxW$W�����B
IK�I��i�H�nQyw*}��Dj�����i���H�nf��w^�7�?���~�R�,��!n����kg��G�������w��	��kx��us��G�� j��>}��Djl���
!��Dj��Iz��Ti5%u��M�#�*�E�������I������QEL������{�i62�=�eo�yI��"�*��=�eN��#�*�%%��)M?�L��>�vHo���
p�U�4b���8fd"o���d��S��"u�E�*���=R��ExsE�[D/i�82��EDa��4"�*�0%�������D&U�K'�B�FdR�d�Y���L������T���
pf)�P�cZ���8T$�.4i�m$"k�2�J�&	c�$�l���v?8>>����3����$�[t����G&U�KFO�d������>�\�3���I��)���{Q�IdR�����'"U��O��W��7�W-2�o�.�nE{y�fN#��I�KF"|;��adR�d$��!�lF&U�K��^��rF&U�K^���rF&U��JF���q�]��8UD;zz���'�I
��Zz2
ZoPNb"m��(n4�y����M=������
p�h�!}w�L����������52���6� M3��"lQe�<���
p���@-�B������]��.Td��L��O>}��*8<���~�`D$R����fcA�c�`�hU�tp���yMT�[%4*���LjlnU�q�1��F&�����Z�z��C�M"yY�wdR��I��I������+�L��4OB7�^qdR�����z��I���`���$2�\��.���I���}�.}��Ljm���E&U��f�0������I
+E��I�gPNbRE��7�0�r�*�Y7'w��('1��UDo�	{"�*�9g�z��I��7�ct"�*�yY�-�%�2��i���$���e�a�%����kF��4�F�i������3�x����
��pDVt�O�B�h$QCE�~��K���
pI���P9�T.i��]���I��n}o�v42�\�8���&�G&U�K'��<�ke��6����>PE&U�K��������
p���>���*2��9�Sr��^�.Od"oW��Rr��*�#Y�J��~��������������k�.jE�i��K�"�*�E������I��W�����I����{.:}��L*����{.6
��=E����D������M����CL��|r.:�l���p�������T.y��K=���
p^�J�18t:�x"�c����k�k���Q���F!�BV��sPtL�` �IT�#���`UZ;�T.i�"��I��q��-���T.i�~|���x/i����G�5u#�Lr�~p���@Q�$i<��GD���o�P+����>�=�T.j��.��D&U�K���� 1��e�p����|*����U�n�\�j6�Q���Y%����|<p�����3�Pe[KTc��>�*�%
�����T�2��9*��g���FJ>F���fw$QE��&���4R�T.iR��K����p%�t�:=	#�*�%M�����$2�\��}'!1�\2�3�%���L�OB^sXZ��<.�:�Yt����iS�H��a�LG���
���;�J���8B,3�"pQ�jRp��������|n��"&U��(K���D&U��(���"��E;�M��\)��x�A����d���1-�L]=�������4i�$�[�m�]��D&����h��1/�������)��t�CZ��T�'�W���
*x)^�!;���E&��,/��=�O�����	(kN�9�*D���|�zg�I��w�_�����
pI�j
S�	��.��t��4e02�\2�3
C���T�2O���R�>2�p��:�r>5it0�"p��gZ��'&�W��Q5C�w$QE��;�k�,6�7���&L��)���i�$��"l^_6�Q2��s+2�q�H�'s;�G`$RE���������@I�d�!�O�Ljm�5w>�O�L���Ofc�����
p�}��.gi'���u��M(��7B>��SO-��
�<�m;�~�s-O��8�	�C����
pI�~>m	�T.��3�.ux"�*��-My�`��fd"}��Z(��Da�Z(�4�j��
+���F�e�I[����{��
Np"R��-���LBbRc��Z������s+�-_�41,2yp���=L�k�����k�PE����4<�T.i�,�����I�����`�MdR��}r�#N���5�F�va]:c�T.y�/��adR8/��3cl"�w&�+�HY\����I#�����S\�8��SD�,>h��:�E��.��1NL��
��YWKo�gd"k]�Z�KR�!r�"k�]�����������g��w���4~IT6�>a^:S�F�#�*���}2���kdRE����<�|�U����_BD�Ljgv�`�qw�i.udRc�K6buM����3�"qA�5J�x[��_����y��t��;�{^r��iRY�Z�l�d�X�tz�������(�:l7�������?hH�>Nc�V�'"U.x���v3���?���<S�5N�t�aSV�+�`A-�Da�'����c��)�^�	�Jw	1�\t��~N��*�E����}BL��OFkR��D�>=��t*�;�*����frp���XGd�t�����}Cjx:�=z]3�%�51��Ix=z���bB*qbR��l�r�� !"U����6	��Q�6it���#����b�ZJ�m����$�[��j�N���.�����M���T.iR]��K��*�%M��[R�22�\�M��fS��*�%�'�V-)pbR��e��A�[��T.z���M�;�*�%o�6�����T��3��>m����y%�@��{�����%^��2��vpqY���;0-�aL�>���E�4�y�Z;�)3����I��u�d�XUdRec��'�NcU�I������XUdR��}���bR��}��%I^gR��}��9�RzgR��}��dS���
p�d����[��T�L6e]���S�'2�4E�*e�HT��l!��5 lbR8��g���u.�K[,�z��������V�n�Z)�HV����d�� �4��o'�[)G�o�E��#��K�8��#�����k�TQJQ�$��+��Z��S�I�"�*�E���K~"�*�E��Q�9HL����6�|�Lj�l������ZdR��c��%�|�L��t��2��a�I����nF�8�I��.����{u��M�z�3y`���	K�L�P�6=#�!�+�O��O���D�OcZ�����@�$�llIEw`�D&U���
�
(�I\����O�#�*��O��3����dgSw����82���,�y��.W�_~��u6������D����u�A/}5�D����a�*�E%>8�KbR�d4B����T.z�O]���T.���R���
p�d��4��T�R$��^p�4�#�!p�6��k�~42�\2�]��d�D&U�K�>������
pf�P����&�8#a+E�{���Z)�Da�z��l��@����-+�&�u��^v�:=k^�Pf����%1�
YI��@N��s�"k^0B�5�6��t�;�,���W���J����JI������w&5v�d��[���P�%{+��O'��3�\�>��	��L��t�/�Lj�G&U�K:��8�6xdR���3
p��*�Yw=��{���I�s\����
[��T�8�����������������
Mm�"Y��M�������j��6E��
�:���E����AzgR��V���w&U�K���������
p^��9hTz�G&�A^�Mf���x"���hP��6�)�9G6�����3���3�E�7�adR�d���t��;�*�Y{�i����q����%������r�(�;0�����[���A"Qc��v	5#X��I�����^��
5�K(�zIL��en�v���I�����e�p��"YGM4(k��KE�d^���}bxw�L���Ol��I��7�U.u�"�*�%����������t�l��IG��p�gW���.�q��b��anc`��*�D�<�� lbR��yb�U�	p[� �u���`F&U����]e=��I�����{��v��D��f���Iz�t�D�M"j������l��>B6^dR���3�4A,2�����{�����T8Ox�+�~��l�9��w�O}t���v���Q�d�z��5^�6�tM�v��L���{umHm��p�7K�����vI��#�G|���/�������H����m��#�*�%C>�3i�$2�\��vkG&U�K�T�Bc���
p�I��.�����������0�=�� lW���|������I��D��&m�B���T.iS���}#�*�Em�>����
p�����5^dR��e?�����T.z�O}�}=2�\�������L����v_�L����������:<������]��1=#������}�����|�#aO��aV�[=M��$�
�������^)�MD*(d'�Y��6})�L���O.~p��L�����dkF&���N�I�7��G"U.i�x��"�*�%�����L��4O��^��I���X��`VVd"|e2_\��!m�I��hcS����J�r:���~�i����
p��~4i����
p�e����.������y�M���4��T�8o"=����e*2�`��6�����{����n��C����
p�e����L/wK>������6�-n�2��O�����e��'�U0�b�$����JD���x$Qcc�66
za�*�%����4�T.i��S�$2�\2�K#��I���Ip&�F&U�KF#���xdR����NsQ"�*�%
�k��81��e�0nah��UdR!���Go��l�via$��m���x=B�A�0=�v���Qd��a����H����k&
71�\������52�\����e�V!&U���z���,p����G(������������#���!�#�$��Q��O��T.i����)b�I���%}��G���
p���3�zc������a�k���fL#V��l�Gt:Lo8N�C�="�����e32��g�0/�k[�f�l�tD�Pze$QE��6Uz��v[��b��g71�\��������T.j��0'+2�����y�L0'+2�uDw��@�SyB�Y��T����4U�c����|�����I���h/�~	i�U$RC���X���G&U�����=�6���L*���X�vJ���H�K��-�j������Z��I��+��p�lqbR�0�E"us.e�S��D���//y�&��y��m�:X���D&U�K�����;NLjg�0�{���E&U���z�2����L��o��3ymM�/jC�S�!2~Q��=�.���$��Qe�i�idR8�W<���.���LdL��o�y3�CYKvA&���L�5Rt6�0�`yO�RfD����71�\�\ ��������q$��"lICpl!��T��)y���2i�ldR�]����+q���22�!qf�[&��IO���
p����[Rg'2�\����:;�I��Q������T.iZ��;�*��
p��~�}���T.��2����I��7g=6#�*�%}�q�ps��:mv�n��+4��kdR��g�c��d������T�2[��,�q2��DD�g�'�p�8���k$Q#\%��u��$���Z�^�K�1�\�������F&U�K^�S�R�*2�\R9'e�`JdRE9y3�y��I7���G�D��'�Xr$Qe�H(��`��V,Y�hw26=�#�*�%]����:#2��g��L��u���0	y�B/���$��{�F&�Z�=���	�����Z�N���Lq�L�5Pz
�	1�\�@TjF&U�KF#������T�2P������2�LBb���a�km�]�����"����������B.f�&����L$Qa�f#.�9��#�*�E��eJS9"�*�%#(s3��&&���6s���2��"lI�gV`~G&U����z��
����ed��6b
���i��zL�#Y#Vt����������I��S�
�"�Ld��D_�g�A�&3�L@��V�l���j�$�iS!��"a�=��M�DUd-i�������.�Av:M�L����^���I�����%�I���9,i�ndR8��b>4��W1���`xd�� ��T��d�g�mZ��T.Ya</��Ld
+^>W��Y/���YKZ�K=�#�*�%/��5����p�v�����I��{|�0&2�\��_.0S���l#��u10&2�\��g10&2�=�E�.�"�*��u���3,�"�w#�@vq���T8�<a�^.����L�s
�,W������T��U�&��p^1:W5�6�]�L*��h3��W���H����C�z�I������5KL����X�%
F&U��^J����["�
��h_���#�*��_����x��Mmx}M�!�eY�Pd"�g�������>
�}�t������@�^P/���0�j���q���U���X#YF�$V�;�*����9�����l���'�nbR��u��nXR���
pA��7����BL�|t��
6NL�4O|�<���
pA�����)pWk�a�%'S��L��t�;�|���^&�G(�;�M�@9Cy�����E8	��]��&"�	���6�jJw7����%���fL=�w&U��^�S���d���K�]��s*qbR�`��o���gR!g����w�,|�x�����o
�	���I$�����edR��}���}��I�<���p��O�3�M�}*���\�mJ��o�����I
��f����5A����T8�y�X��
��T��}��NL���O�i���I������O����&��<X�3���	.�m{eSa�*�D�@�2�w&U��(�w�P��H6���8�NL�g�q��2Mp��
��y��i��w&���^.:��D5v�d�P��vL��*�%-�6��T��PX�j���L�z�v�^���K��[���WzL�>�I��7z�����71�rzK��b��TdRE����]z_F&U�KZ(�����L�����y���*���I������^��(�� p"�(�������#>=�����,��*�SwdR��}�{8NB��n�o�x��L���G��P~�>�����9�n�����L��m�_�����<B5�!�MDd�E�j�|�����Nf���L��N��D&U�K^���|���pfWS^��n�$��I��^WS�y�UH=��D�<��:��n������&�4Ot��wNdR��y��9�-�L��4O���w���
p�g�'vLs"�*���}�]0�V!&��	sds��6��#�*�D�>�^�#�*��w.���;2���
���K�#�*�5�
'	1��J6b�zTi�;2�\���S���#�*�y�	����J��T�t�dSS���ybRE����^���E��������g��OB��*�k,lo"QE��~C��t{G&U��$��.;��>Zd"{]2���V�\�wUd��t�{g�t������;��gV�t�O�"���k���#�[#�*{D����^�Z��V�����O=���
pI���.-0�L���t�����
pI���]Z`�T.���Nk#�*�E��^����I������CL����t����E&U��&�YJT����+b���w�^��-B}7�DLjH\�E��f���j�E(�wX��3��P����!
�EUd������iz��b��yC\���7��E"U��/�%q��O���D>����r��3���T��Uo���Z3�,�C(�NgL�3�\�I6��W�I���D�	�q�T8�By c�4���D��L
@j�D{;�|��R"���������
p����4t�T.����R�!2�\2���6�"�
6
���{�x�sP���x���AQ�d�'���
p^"����}���x�����f�N$Cf\R'-r�"kQ��F&5�s����/�<�-?e��_��M�ADU�-iRY�A�����&�E���m�!D[�^�t{G&U�K�T{!=�#�*�%�'��-5b#�*�y�<[����I[P��5>���D�\������J����!���p���wiNrdR8���Wm�Ns�#��h��j��Q����
1�H$��������6���6�p��L�H��l�����c� �+�`�'&U�Kvb��������iv�i{�H���%��vV���I�������&&U���'��fYE&U����2P\3�}BLjd����2%�����F&5$���g��N��32�/E;�9
�G�DaK#\�G�I����i�^x�GxdR���ub�
�����D�\�$t�a"�*�Eu�A5LdR8���^=�a"�*W/k�y�{���L�Op���n_-a������i?2�\4��
�LbR����-����
p�e�=P��pbR�@�j��%�
�L��c^zw�����Z9��]M�2����I���o�4@�T.i���#�*�y��yF�W��22�`�3��Z;O.E����L������@�d��k0�"�*�D�@���x5�J�]�7CjF&U�K(���I�T�2P�@�I��BjF&����gc^WSf/��������h/(�kw�xh_9T�#�R^&��GH���D6Ot����B&Ud-jQ���oL��l��H�LdR40�G���DUd-9�S�&BD&U�K����I+F#��D�$�!!,r�"kQ#p�����pf�[�����!2�\�m�����
pI�$�KZ3�T��}�tn�`����%�a�� �?�^�P�9�h�'��6t:�E�L�lI�*�T.�
��G&U�K�'�Bs���
pI�!8hn�T.y���#�
��h'���}dR��e��p��Ls{��I�ai���D>���V`��F#�*�]��p����o|�kj�t��d����D�������&�m#����)��w���D����e���3��84���������>����dI����[�D������TKX�~`f��iq���Mc��4]�s@�.��n����>�:F""��Oe����c$"��U?��_�r�����i��������Bi��Gna�_j}l���g�%�/#��;F"2�-�����S�z��kB/��=����
8/����=Y���y�1HlO�5]f�b������Z�x�b�����k����c$"����q��������\�,N���kEM�nRVK�D`�r�����D�j���H��DM��euH�R�s���U�i� �	]��M��\6{i�����?�l�or#~m��v}p�;��4����V5�VKDc��^ ���O��A��@Z��V����HD���S�6�_d;F""��]�kgn*���I��3�Z���>n�;�c �����A~r�DDx�����C�1�-7(�G%�HD�������_<F""��e
�}�|�DD��R���Q�q���x���=j�3���,?4	�-{����

�)�]<N��\�LC��`��~]��c�c"������1P���O��wR�HJ�����j�&Xmh"s�tG�����H$�_�{Mx�����o���
�64�-�i��.���o��JC���x�DDx�U2����c$"�[�$E����oE�q���s�DDx�("�x�#��x'M�>�9F""������~�}�DB��R����O�{�c$m�����/�N��f���\,{-gK~A7����lM?wMv��@D~�M��h�/�#~��	�R����_
��&�����/��J�����c "�t�_l
i$"�����=>$�F""��J�Y��HD�_Z�����p����[������Ky|��4���b�y�7��	$OR�p��U�{�?�?F""�Z��k?�mX�=H#i�#�V��Z���@�s��m���'������1��G��f����:��B�6����1�-�T�[�o(#���}{�����HD���Rmx����k[�k_7lxy{p�|������&w�i�-B��c$"�[nP�z!#�2����p�DD�������B��c$�����n���N����x����V�������u���|)�Iich\6]���_	
B���t����#�c$"����{�?�>F""�e���
��F""�ZW�k��M���c$m�Zroi�������:�1��;����i�l��+��H$~$M���q�?s8F""��%�tE�����h���������khmg��x�?F"���V!�br�o+��pI����Y`&�!�+i�A�������o�A�m�a����o�AY�������m����@�H$��Z���/�U"��4~�4������$V �i��|�J����o�
�x��HD�7���;��i$"�[F(���N#y�\��\�{�����c��H���o�%�f����1��HZnPvv�H� lZ#t�}fu�DDx�
���{�?F""��o|�oy���j�^����p��I�{m�Z�����9�gm�@���v"��e�A��A�V���p��#�r{��=9F""��O%��W���oyZ�/�=a#~�[����u�'�c$��k=�����p�}�iQ�����k��@r(�t��^G���������c"?���m��=x�DDx�
�����=F"!��W����A�.tC6\��zQ���?�;F""���$�
�@������8������8������8����QD�?�DD��Z"WjU����H��������A�uO�t�����\\��tY������&MH[.n������H��1H����a�*|���+�ZV"������M#~�c�K�fx�H�^ ��T]��h��� U�'����e����HD�7��,��4�M���?o�����IR��	�D =iY 4�q�����7����}��p���k79.���C�+�����m�kB�mq���N#i��l�z�����1H�HZ5�f�/#�a$"�[F��w�iF""��Zo�}�#�r�7c�;T�0��.r\c����~�_�0���6o�u�����*Udoj^��/B������c"?�����?�~�9F""������������k��k�i������&����w74�4� $&�b��KU{o8����F��j��`��d/+��i"�}����v�����%4������e]�h���F"2�M7U���#�tS�����1�-��MH#��|���&��7a�-�;$��r����qk��������	����=~�D"A�V��Z��hG7����/.	����q�����4N~Z����E�a?��3����"�0������`�|Xr��174M�����A�Lv����~�4��$[zZ^x���pI�W�K���Od��^2�Ad���I]�fmL���M#iz������^L��k��\7}�����k������5�_�9F""�e�i�Ax�������h���UF""�����l�J��������lv���
��4N���2\<����?B�t�e5���x������R���;�#�uF�������$
������t�>9F�vr����	�I������	��W��o��1��<Zn����o���������O�~�[�c$�T�:q����������yG�H#��������o	�c�������o�?Y&x��HD�_��\������#i�����oH������o��A�����&�����_�6��I#���<F�M�����}��h$"�[(���h$"�[��nXa���Ho�-zt&�s�1�-W����~�<F""��j�F�����K�������c$1^�{q�]��,����7,m�4�_;F����R�����'�D���Z��������V���=��>�D�D������~�wr���U��,|�?r8F"!��<.n���#~�:������O�K�'�c$%Z{�=x�y.�,�I�o��auX{���e������K�yC�I�,�����W��%�/mO�n��p�������0�����0�	�vTrq��1��JC�_�b����n`�M���K�����>F""��R?
9��]�u�V���p��������F����,|s�����M�r�����d�\�'������o��O��#�r�������I��>�,�z��������������s�DD�5�i�2>�{�9FR���~)-��),�2���Lx��>��<����k%B/~�9-^�4�/1�����L�}��#i{��ih5�%c��4]��@x%Jn ��R�M�A�1�Mw���'��HD�����}�/�p�D ����^c�y��B#i�-��4��-�1��6�&�����Yj�}�x�e��u�1�-W�����HD���S�#|�q�DBx�Z����3���oy+b����c$"���U�p+�������������kM��q���T��74�k:�
��4�oY�t�����1��uM��/�/n��i m7Vm�y����� D~$M�5�o����o���t������I��zx�DDx�\s^�?�?F"��V������9������FR,o�^(�Z8\$5hh�aMI�*_�a�PEdke�����f@�T)���~�7����c$"�[����<F��������\�����1������b���?I������'��D���p<)�r'��J�^} ����N������1��;$�V���p1�1	�+�^ �:F""���;BLu�DDx���/S#�tK�BLu�DDx�-U������K�C����#�
w��Y���~��/$#��K�����>�	������j��l��d����A�Lv��*^(4�-W�`��c�c$�����*�N�/�c$"�[��at���1��V������}�y���&�i�����w�1��n�A	S���z�DD��
��S�0���`����\�{��H��=��'��b��K��]���/��Z���HD�7]�#t�:F""��Z�.[Xp����R��.[���au��#����uMC��S�����p^|n��z��H��	
�~�#���drA�.�_+z�&a���G%�Hj��EB�~�28Vx����1��~��Zk���z`c���\��Y�i����k���a�������%�����#����7����#�r������s�DDxKJ����K�1��jp����@�7�K�1��������������
��4����E@��#����r��7o��w���k7/��1�bO#iZ��m�vc�����%E�I�Mk��u���x�DDx��IZ��c$�����;q��?�H$x�i��������HDf���d����#�2���.�?�?F""�Z����2�������[�V#����w��i�d6
�3��F�1��FZ���u��JD\�zU�8���<F""��Z�8{���HD��\��	��#�~�H�����s�D�=��F�2��+�����M#3�>�D~#�v'n~�=��/�p��1���0�`����a	���1��n�Z�~�4��j�]�`j��|?�4��L5=u]ht}�Ad�[&>������o��nY��c$���%�/�]��da���}�v�#��s�@I����?]6�
�C�E����G�2D� D~M7�y��:x�DDx������M#~{��\p�!��NC�Q�2Z[�z��C�Q�2[[�r��C�Q�r+������(o��^��_z���(o�6_��������k�_[;���x���y��������� df�e���o��������~����K����j����_
�}Ve��%{i'n���e��${��^���(o��.�~�xE��������M�1�M��4�o���(o��oli(2��.������"��e<��6�4�-��4@>qEFy�%4��~�xEFyKtN&��'<�"��i��d��g�A�/S�r
Mc�������khr��7��Pd�_ZC/~���x�Ci���Mx�%4M����1�)oY�"���3{O���7�-�9�pO��P���U�0����������c�o���k����!����I���D^o�t��4���tK���Sy����)��
���Ly��J��v�HD��i}��@O�c(2���]|���������~�+�i����k��Pd��%�����CC�Q�t�������Pd��������������
����c(2�[.������8�"���z������`���[��J_���l��oC���/P~����/�������4�r�*F\���p<qB���<��x6G�|�)o���8
�M������6Cm�c(2�[�����a����k�\��z�=3Ci�5�M�������[��q�1���S7���h����k�E�*_��i(2�[�Ll�p���Pd����m�����(�V�����[�<(������eo�/��WwY[��X��4�e5%�mK��yB�w�T��W��u6������:���(o��!��H8�"��b��KM����F�PJK��M��������t���<���H���(o����u�{�4��?�K����x��{�?F!�oZ5O#<�4��I�
V���G�g��gz����C�Q�2X�~��!
EFy��J[�����i���i(2�[v���zQ�J���/x+^��z$�
'���������C�1��I��J���BC�Q�����9�e�P�~�z��>�Tq?!�T6��d3�r�2�7�����-���/��}�]
��;��U�M��c����h��C�Q�r{��;������������Pd���^��gC�Q�2�G�������Uv���C�Q�r��O�!�1�-��}�����Pd��\�wC�Q�2��x&~E"�V1�����~�x�Dd���L�����zEFy�%t�7\�Pd�_+�~�N����
�1�;���R{%������]�c$5��wW�	���^�`����+WUI���>�����@�"v���p������1�MW�<���<�"��e�}��c(���~	�7����}wBf����0,��b�����jQ,�	w������hY,f�q��i(2s�p�rS��m�>EFyC�_���s�C�Q~��/��Zw�9���T��������-�8����R�(���^��}��K�4hY��������A4-�|u�o{��o��-X{��O�T�(��\�,<
�-�|��|E�������{|0����������E��(:L��hEk�-��,�����y�(d���*_��.�v!��c���_�m:�K��i2���s�a
���MC�Q~�s��#�+M���rJM�4��%�)2�~,4�)7-��.����%����Uk�!��lb'�Z����������Pj��{�gn����H��G�q����&��(ox>���4�+{�?�k��&z'N�;������P�����Ds�f��)�A�n� ����b,�(�Pd�_�����������1�3���r��+�Y��7���~�i$�_�/x��T�����������7�W��D����
w��_?���������;���_�����+�7�������3�<�Y�����U���oI��5��y��������|������j]������_���_���o��|��?�~�������o�����oo��m��p�������������7���1������f����;�_�
5T����~���7��?���w_�����{�������y�_�������<��o��_����������<���������/������_n���������G�����y��o����������?����_������7�o�|�7���~�������?�������o������v���}���7�|�f[�������_��?��������~����o���������������7���}��w!1�}��_�������w���Y|C��7#���������f�������g��%k~
��S]|����S�S�P|���7�7�����{�?�?�J2JJ%�_�$MR�2H2�UINH��()_5n�4 �����������$#$�Y��J�$� ��K��q��������w��II�@���J����B64^0�NAJ��>�P�@���"/����$M�~K��,���������������� ���%����^��y���_�������4^�-E�-�jQR�4K6�R[�uI��4K�J�)����xE��miEU�gI�D!I����K��]�R���m��H
r@E�%E��rm7�(�ks$�&���?H�2GB�?�`� ������N�{E�V��0���O2a�'�n%��$��}��nr����$i|B����4N����'$=�[��{0K�CI����Qf��6����������3?K.�o�m�����^h�2D]��	I/���%�%]��n�f�Y��'H����-=��i�x�4^�4B���8�t1�� ��Y2�$�,���$�[������Y��-Y�xI�$4K#���?Ij�[q������~��,98;!�OHzz�f���'
i�$)
���Yr���?qg�_�%o�2�)�,������9�����.����,EHrI�������x1�u�������I�{uW�P�
I.i��B��B�;�����$�~J%=Nr�K��P�4%�]�x%����
7'���$�
:>��6��l�7'�#�9J�*3pi|B���� ��v��@/I����\�����?�y���4^y{�By����H��+^��4�����������qxoi�po�fI�u�{K��{K������H�[�/�[z��+���{K��{K�$����������&�93�[�/�[������{K��{K����u�5n�{K��{K�$��w��g��(�Z����g�u�m%b%�$��'$�g%���������IISkI�b�g�4>!i~�������H�����%�%`��H�������dF���OH�OK��,�|~h|�����r`�f^A�|F��/�����y}V��oK�x�,����C�3��=���t�����g4=�
�i�k'��g4=�w|�j�t������_��&��;��&������������E�C�3��~�?�t�����!�M���������f���8�~��A�|F���q��]`m9D>����8�~�	��C�3�^x���������hj�o?�{�H�3������������hza3����������g�������8��8� �M����5�c5���|�|BS�K���c�C��Z'�w�o�C�%I���/)�1��'$�~��K������z�;��>�?4>!���2���C���Y���0�o��OHz~��@��C�C�����>�������	I��x�������C�3���/������@���y����+������C����%k����$����Z?�\lt��A����}���,����������O2]����������'.���1��+?�����G1��^���	I/�N���
�{h|B����G��
.6�������7x )�q����?Ij����=�������L(�*����4=��{����{Hz��3���L���^i|B��O�q��{2��@������?���$��b���h��^�2����|���6Y��������;M.��da�{h�$I��i�����	I/\��Kc�?�?4^�$���I�'�4>!���/��r���?q2����]�d�L��Q�E�BW��1
 i��sx����'.E���F'A��i�,����+{?Iz~���o�V��]&��.�=��<������B��n�2H�����'��{�t���yq'�P�,<q����k��8<�����4^��e>v�\�84>!��,m�����=���)�a���e�%I���ki��Q�(��X�H�I/��x$i�(��w������7I� ����>*�����^+������G�p���W�k��P�������������8�/G^���wHZ��{q��'$���8mh�4>!����)g�{��'$=��K����$������wH�P�������3>����������R�w�|�p?M$�M�_����T��hj���c��
s�|F��A����E��������������_"���:��|~h|BR�������C�%I2����.|~Hzu��v�
(��x�{u/�{�$�,m(�NR��5�f,J�<K2��M��9���	I������Y������.|>���i|B��'`q�W�
������Y&d���w��=�2��������wH�	��} ��w'�����{7�����I���M�������,�$�~0%]�/�\����
$���=�J����(�����r$vA�I�A��v2?B��[����,��J�-����D��e��o�6�t�%�y��4
�F��]���J$�����y_�,�'I�������^i��x����$��������R�����w^���	I��&�����	I��8gJ�Ze�AK?��{�C���������&	~����$��s����OHj>Ks��awh�$I-�_
H��6|��|�W0�4^��.�x�F����C����_�$%��w$'2��oJ��4�'IO���o����_"��$�\��~��i|BR�o|�������W�"z )n����=������#2h|BR�o����������WD��{i��������1�����{�?�94>!��Fw������	I��i�3�C�%I�~��X3o(�j�5��a��O	�8����	I����R������	I/:�gi��R��'$=��
_!*��>>=4>!���0o,*����������������������{��L$�������KZ@�t�v'�-\X�%]����5��3�4N i������B����R��7i|BR�'.m$��oo��������������B�y|���+�H��Z����;���������"����OHj�^��4�$w�f�k��I�Z�4].v2���F�)�OHj�[����	I��Kq����K?���J��f���	I���&�@���a���	I�K/�8�����'$5�yG���OHj���fDI�g��S�G�@\�=4��������S�C��^�y�J�k0��'$5�yg�psh|B����n��$���$�����'$��%�Q���T� 5b-�C�����=q��.�B�dR�n7]�{���$�����'M��\��$;���1�!I�s������������{�%Arrh�pD�L�u����Brr'�y+����/�*��R������xe�����I� ����!I�%0[�t-d�I�z	�+H��~�$I���CI��n��]�xa�G�'.�(�b�y7J���B����$'e\�=4^0.8�YZ`��_�;NBM�o�p��\Lt�(%i���r�X'�=q+��.V�}w�WHR���z��M���p����4�W�x,i��R�������=�~i���7IR�e�/]��t�$e����|u��jL�X�����%!�]���IW�KN��}�tS/I��y/��94^ZPd.W/�5 �b���,�<q7IH�O�P7�eG�t�t�����n�H/����2�	%]��s��g�K�8���@��2Hr?��O�=�����?���?�����������7U��������}��o��1����������y��?���������������1������?�����������on���v���}���7�|�f[�������_��?��������~����o���������������7���}��w!1�}��_�������w�,&��q�5�����~�wL+�������/��3���W���p�s���_����N�~P��x2�?��?w�y������n����74��y���}����9���?�����_o��J����?]��[�����N���/��p?�����m�2����?�����������H>�o��~	��gC���p�]���TFz�r}���_3>��?�;]�Q�0J6����������~������h��@�NE��b��CqY�uO}��d'�"�|\��,�?����?|���_���o����0�_�_X�3��;$o������~�v��5��oo���o\�o���}�������o_��_����n��?��w��?�������^�o����/���������/?����}����n������?����?~�X������}7��Y�1�c�7�����<~�\�������/��rFJI���/�?�W��_�����������y�ni��W�������W�����������������o_�fy�o��=. �tDi���yi�����7!�/����"x�>~�����2����?������������:�*�U|�&�s���>�/����}������������������m��U���t������;?������8�{pz`�nP���,Z������h<@4��x%����'���_	~����J�u_	~�$�
^	7r�^	��T���B1�C����7���
t��?�'~�f����<��A�G�>�����������w�?-����/Z��{���<P~�x�������Z4��uWg�=�U'0�P�������f��#e7�U�PD���i�:{#�n����F����fpv�;�i�pv���=9;�s�
�p��^���u�u�K�$�u$�����lF��:{L�"��d����6	g'�9L������	7�S}�0);;�����k�$����H��������
���UE�����K�$��#�[.9��9����$�g��*9�8��K�$�
�-��
��
3(�:{A��	��D��q�����������:{�a���y6���I8�gc�g�����6���\����C�]���B�����v)"�������L�������.�C�]�P�����kjM�$
^Is�[�(*!��u�����X��Xk:fQ	�61��v�!��:�j�(������
�v������6D��������h���t��2�m�����2�m��-�`H��wH�������x����hgRxC��� N�\����_*�	��N�F9��z���������+sln�`*�%�����)'S��!���V9X2��%��@��[kP".�.z�xka� �/��0���Aj��-��SZ��+7���0:4wM���#����ln�p*�Jd��P���;����0�A,��4i����V����G�*�S��j?s'�E���(MZ�x*@
�Cs�\�x*L�����	u_s�����ln�|*���W�1��a���3���q��g�Q��/�
0�4W�O9�
1�3��|59x�\_�\�/�
1��1�*T! ��:�j������k;T97�9�jT97�9�'anD��e��PE���p�v@� ��:����������9wa8W;�Z�s�s������9w��P���k�s��W���sW�s��
rn*r��1�J������vB��sS�s��
6��T���c@�!�nu���
1wc0W{����[s��UF��u���������)7)w��O�H��N��v>�#��u�U��v����c�x*�{rG�x*BA�C�'�yu�q�Pd��_:�%��^uD�[���:�*�D�Kb����"V� �o�����:��#.+N�\�O�8HW�p*�%2��NE�"v�}A���# n���/���s��\�?�p*���q�#����,�\�q]�p*BG�Cs���r80ntu�Ur�q���ln�p*b�8��)�Sq��S�qYq"�f��"��~�T�G�X�\��N� �����H�;���������
J�S�SN��G��u��&!��������S�#��:�:�t*�\��Pn@�
E�u��������������\��51"��"����TD��u�u��������)w)R���O-H�K�r����E�]���)w)Sn�|jE�]����V���N��8	sR�Z����TB�M�j�S	)7}2'�1!��"�N��
!7�!w���6�����	����!w�Oe�����v<�rsr�����)7)w�Oe��\��I;���rs�r���s�"�N��1w�c��O-�{s��L��e�5������O-���E�&�|j1�f����$�5�f��������(�^hR�k�}��%��g���~�b�$%i���P-�R�i`��=[H���~�2BM��i�2)T��(��4�Z�m�=��/�Z�	��to����A4��z9JV���g�Q��/�Z�%2�n���U���I���[�	�Q�&�/�Zf��R��	�2C4Jj?�'��������e�Q"��E9�Z�����Q�?���������P�+���;+'T��(��:���=	s���=��/�Zr.��e�N�rn�s��k����������s��������~�$a.�r!�gs;&Tr.��e�N��������ll�Bj��vL�V�\�����P���+�PP�<w�^.��ln��*!�2]f��*!��:���=	srn*sn��jC�M�j'Tr�V�\��qvs!�gs;&Tr.��e�N�2r�V�\��C	s���=��;&T9�i����97�9W}��v.��ln��jG�e��x��jG��������r�^�\�/�Z�\�\1W9�Z�\R�i��X���+r���P�8�4W�UN�V�Kj?����p�����%T��%�s������s3�\�s}��jG�X�\��P�#p.�}!a�0w�%�gs�%T�3(���^9�Zp.�}!a�0����������(��]��P�����9�MX$���sI���~	�:m(��\��j��sI�	���3p.�=��/�Z�%2���P�3p.�}!a�0�;��"��~	���s}�s�rB�z�\_�\6a�07 ��"��~	��sC�s�rB���P�\6a�07"��"���	UD��u�
�	UD��u�es�sc�sC��jA��u�
�	�����9�MX$�]�s�"���	�����97h'T+r�Z�\6a�0wE�]��:&T+r�Z����P%�����l�"anB�ME�
��������
97�9�MX$���s�"���	�����97h'Tr��p�vB��s�2�vL�2rnf8W;��������nO��97�9�cB�#���j'T;r�^�\v�'`n��.��dn��P��S&��KTN��k�}a�'b��3�kMZ��*�����	U2�f��v{�bSR{6�_B��E��j@Q9�J�R��nO�\l�Bj���K��8��z����P��QR��nO�\l�Bj���K���Qb��mTN�����/H��M]H���~	Ur	%���F��*M����O��\��.��ln��*MJ����	U� %�s�Q��������4Cy���v��	U�!%�s�Q����������s��.�	U���������$��Bj���K�R@��z�('T) ��:��;$���.��d�:FTA�����QE$��t`��1���-��1�Zu��.7���.����A;���.��`o��jA�e:���*��"�.Lm{���-��1�Zw�/7���&���i���Ta{R[��cT�x�./�vV��x��A���/��`o��jC�e���*��!�nL3��{�����������z�	U�7#��:���
���������i�r�l�������h'V������Ymr/������6���W6~�n�/�-��/����9�U��6�Kr_��I�k�|I��_�/��LF���m�%��#�['_~�'���%��W�M��A_�\m#�/�}e�'���Kr��K��qA����_D��%��l�$�u#�]~M��js�$���rt�9�_����O������������	��D��U���	�������w��+���^m�C����)���Kr_��I�;���������[����QN�6����ew�z�__�_�/����g��(�W[@�
�jw���o��o��* ���������_��7"��
�v��"�o��W;�Z#s����.H�K�~m��jA�]��������0��}���H�K�~m��jE�]��������2����$�MH�k�~m��*!�&�~�vz��~S�~'m8J����cx�!�&~�vx�!�nu�U�\m��[�}m��*#�n�Z��*#�f��^m{3�o.���]����A_�]���;�}���yG����k;&W;�����UN���K�����;?3��!��%Wy���^Q�&T�_k�}e�'�/v�!��%W�$�X/*�^�������O�_lCr�����]Pc�~�M����z��W�~�b��{�w��]�j]f�U����<BpJr���[-g�Cj������j��is�l�����V�U����O�-��/���C��2�7���N��������62v�!�{�%Wy���^H�&T��bS�[��W9���+�����\e?��z)��Pe{=�/�������-�����\e���4��	U�7 ��:�j����/�����\�������	U�7"��:�j����1��~,�W�}����37�Cd_�w�a�C�ad�Xg_�2W�����������-�L��������R_��3��!�'s��8������cX��0wE�]���]}0c�R{2��ms��K�L������	�7��W���mcH����6�m�oC�ez�;$��y7y��ZelCjO�>�en;}���c�]����73��6c�R{2�����������1��E��q73��5c�R{2��c��������1��E��}@���U��`����}�����-���\v�"b.p.��4���f��+�>u��v��.i����S�@��~��n
N]���_F�[ ]�\sW9��-�.��4V���8u��~!�>:����rH����$�YvG@]R[8B����(�c]��jw��$�Yw�.�=��/���%2��N����.��\\�^w'�]R{v�_N�O%2��~�#��l��:�j7��g�]R{v�_P��	%2��~-���%�w��]�������%U�G���N�I���w=����n�������/���n`xw����n���v��="��2�v��"�ndxw���"�n��.�bqy7y��Jm�oA���N�Y�����y�}�H�� �.E�}��F��[�w�w�&����k�w�[����k�w����v������vV��wS�w����	y7y��"��y7q���Um�������m�
yw+��s54��������Ue�������m�������\	����������������>E��ws�s��jG���e[�J��#��u�e_,��]lCj��v��n��[�k��fU71���!���nV��4�P{v�[Vu�8�D�s���U��,�����T��}��q�p� w�eU�`G��T�u������zUK�f�7-	����A��t���a4(��3�fU7u3�;25-u���e��1&%w�eU7E;Jd����Y�:8�����P�^�s�=��-��)�P"S4w�
��a�`�{������,��{��[ZuS��D�c���V��<�����%��^1������������1^7����`�\/i���B��C���nq�M""/�.���U71���A^�Ws@��E�}�lF����\��W�� �y����7�w�WED^�U���qUD��\#ew#"o,#o��jA�e:��W-�������2�Rf��y����u���y��������H��"��E�u����������������H���xS�x]��*!�2]b{)\��
�7����H��!�nE�u��
��ic�:D�E������7#�nE�u�������1^;�������O���7��u�v^�E����U��x�:��[>wx�"��~a�x�1l�'w��Kr+���z�i�%�gw��U���/��I�]�Kr?��oZ�wI���~a�1;Jdx7(�U�:t��]���X�]R{v�_Xe���
�a��wIn�]���������n����+Jdx7(gU����Jue�5x������eU�E���nP����%�w���L����S���L������rVe&�]�[qW���m�SW���_Vef�]�\sW9�23�.����|�`��SW���_Ve��9�U���G��u�Un�{������;���L@���F�����������������;u���n`x7jgUy70w��=����7�w�VE��o���X^�=����yw��U-����Q;�Z�w�:�*"�qw-�n��jE�]���Q����2��D&�������������QUB�Mu�5F;���wS�w��Y����1����
yw��._�]�^���s��*#�n���[$���������f$�\$��cZ�#�f�x����wg�4[�#��w/"��1��ywy��*;������������P{v�_\e�%�KYN���V�[��|�`�+����n����
%�K�A9���[�Xi�ma�g{��U��(�^+����������|Pd�/�!�lo����$2�a��X��R�[y7k�}a�gw�%V�y��4���rbe��$����1���0�����+;M �is�*�;AZJr+�*Z�s�=���VvQb�X��������r��r�l�1�!�lo���z���r-[J�^�Krk�j3�G��E���+��y��0��
%ao@���6p��7 ��"��~��
�L�����7"��W;8H�zcz}��*"�2
b�wr���7r-��]zcz}��jA�e:�X�Y-���A���"�.E��#���ic�B��H�+��P��M��k{}��*!�2=b����bo��j�QB�Me���Ym��L�k�3�
�w��j��������ch��{�.1�h�V�73��V���7#��"����UF�e��X��Z�����^�����;r�^���1���{�>1�-X/`�8 ��u�e��
�;�����n��jV��a�rh5��$�����;�SW���/�
P/i����Y����V^���Z�3Wd��/�-0/i��k�������:es�g�H��_^5�@���f�r^5�@�$�17��y7�K�F7�D�w�rZ5:�]��I|8:�]{6�_V5N%2�k���q�%�eu�74�	X������T������I�8�hn�u���H������S������9���tIn���r�������_N5zD]���U��F������|�0$]_$��/��n`H��K�����K���F$�P$��1��H��#]��*"�F�t��H�� ��"���)����p���R-��s���ly\�v�"���9����0�;j�T+�����jwJW������cR��wW�wG��*!�&�V3����7!��"���YUB�M���Y������]��'a�����7vL�6d��a�Q;����w�Y{���ys�y;�U�73�;j�U�73��G�{��������1���zw�zG��jG����]����!�'{��/�r��tL�;*GVn������5��;������R+g���c��X�(��������7�w�������_p��C��2B�}J�ka� ��H��]bHn��~��-j�����7������W�I��}bHn��~��sj�W���"��������N�_�Cr��������^@����$��F��^��W'�/��!���WnJ��^B�:��������W�I���bHn��~����X��k�rz�f�NI�+�$��~1$��o���y�_�k�u��������_V����1�����_�������N9�r�70�����7���t��"�/�9��5�%������ex��/��������|�]I�<����@�o�����_>��]��������o���0������b�o�?~��7�|�_����?������������_�������w8���1��>��j�l�I��F����x��������[�a�w�s�����F��S���O�Pr���[��q��������@cB
>����]��
�!���!�>j��C��@�pW3a�2pbnM�	�C���C��b�w�s�����F$�S�����@6�!�eu��{�W���}���f���OMd>vW<]u�?��~�.v�q��1����jD�=����]�l
�!����C���48����!c4�5��K�k��'k����v����3W�]�\
5���������%����;�g���V3UC���$���x����wInY�x%S��q���k�eU�8�F�w�b�����$��N��.j�%�w�eU�3���]��jr��$��G��
x�����UMnG��*gU�4��L�;ew'�][p�_V5MjdxwV���x��V�*��`(�����VM���e�����V�U�"'�p���k��U�G�����qK���x=���r\5D^_F^�/��"o`�wV������#^�}sD�
���WEd��0/[�[�������"��
�v����@/[�[���w�:�)�� �.e�;&V+R��P���X�H�+s��7���k{�������2�;kGV	�w�:�)���{S�{���UB�M�jgVrob�W;p��{�2��C�
�w��W;���{7�{��V�w+s��1������^��Ze���p�v��#��2��S��wg��k�V;r��tP^{g�Cj��K�����O-d>�W9���{��-���8u�r����?;<~�a�t�C��72^9�������Sv���2������B�@�W��f� Cr+������2t������
��^9����������{gl 3�������fT��������dHnE��a��
d�S����\�P!S�+V3v�!�u�G�36��O
d�f_?s�2E!�r\5c�[Q�|�;c���@�.��3w��������*�U3v�!���[��b���@����3�#����|�U��f�Crk�j���{jC�����sOMd>6W9�����D�*l3�������tO]d>vW;��2$�����|�s\������{j"������!��HF��c�S����MGwuO=d>vW;���1$�	��{�|�s!�swE�=���x��S*�Cr+��S*l3���w����vOd>vW;���1$����vL��c�S���JP?w7��S�������w�����Sa����:�������{�����A��!�w��*�3�:�����#����|��vR��cHn�]�u����1�}�n��y��=��}�rT��]�[qW9���.�=��/��f@��F����]�[qW����%��;Y�����_F�?�����g_������t�����~|��7�������������[2������?������������)��k��M���/�`���FO��<��?���_�,[��t������?1\[p���~lx
�G4�wU#�}������_��=��=���~M����C����U�COc;���|l��������q��oE��>"y��,�"��rY�B��m������~��%�#F�	s#>����7�@q.������O��XO�H$�]�� R[1W�L�/�-������O��(�0���H��:4�����@q-������O�n(��/�7X%�M�m����|��$���ln���'Ls��1V��AER[����0w�`������}�
�scn�<&������Dv����a!�#0�gn�3o���
V	s3T� ��lL{���s3��8�~����;s���E����s�:����E�E�����\����w�����a�5��V^����a�5������P3�D�n����R[yr���k�=��/�
��D������R�i�Gk�=��/�
vG�L�$��*�#�[���}Q ���������0n(�)���P�(���������l������P��D�t�rBd����PMg�X9���+m�o�+R������N����������lq��u��~	U���i~�����3d����H��p��U��~	U���������z�\�p����#��2��K�B@��u�e�6J��sC�s�n����P�\�1��������vB�sc�s�f��F��X�\�1�������l6/a����f���.��K�s]��jA�]���f�����K�s�F�����k�s]��jE�]�����"�"���*�����9�uL�rnb8W;�J����\�raC�ME�u�
9wc8W;���s7�s�����[�s]��*#��:������973��|#d��\�\�1���ss�s��V��9w�s�����#��e���P�9w�s.�
��\R�i��q�%�gs�%Tq�Qb�s�
���fDs���?F�KjO�N��h6�X�\v����S�_�_xq8��^� ��������wm���h2*_6uj���4;wN��_�?��l��&[>K��oh<�g�_���%���a�x/�e�&��F��,��
�=��/�[�
%���a�x��@��������!�gs�z������7N9�[�7��4��Y|}Cj�����Qb��v�.b.�7������,���+~}3���
��4���0w�&�s�3�%8s��o�~�����I��$��@���"N9�Yr��+~}3���}D���o�
���;�7���S�@c����=��/�[�� i~aC*`�:	�L�I9�[�\R{6�_��b'A����T�\��\�s��������s�@o�&����
���8we����	W�Kj���K�Vl"H�_��J�;��L�@�5w�sI���~	���
I�Rs�sW�����,�\�s�~	��MI����8we������3W���_B�bA����!a���2����)��9w��P��D�4��pH�;��L��Y�Th��sI���~	��MI����9��8+�
�9�9w��P��D�4��pH��s��������sC�s;&T�D�4��pH��s��������sc�s;&T�C�4��pH�� �2�g�S�uA�]���;&T�B�4��p�����4��O��9w)r���PaA����!a�����������9�wL��� i~���07!�2�g��*!��"���	�$�/<�n��L��Y;���s�"���	�$�/<�f�\�q��N�2rn.r���Pa�@����!a�����
��	����9�wL��y i~��07
�f0m�rBu�����H���~	U6�X���}8$�5�f���8��*X3H���~	U2+J�W�`sa� �q�	U�g�Xe��K���*����C�\k���SN��hq��U&B��*�Pe�4��pH�;B6Jj+������b���/�J�L��	sd���"N9�J.���L�~	U�F�X�2�>�N�����8��*M��������4�X�2�>�������8��*���������4�(�^e�}8$��#�[�2�����I���~	U������	sr��snPN�R@�
E�
���sC�s��C�\��P����PE��P���1���������!anD��u�
�	������1�Z�s�:�����r�R����P���K�s;&T+r�Z�\���0wE�]����9w-rn��P%�������!anB�Mu�
�	UB�ME���
97�9�}8$���s�:���jC����;&Tr�V�\���07#�n�j'T9797vL�2rn�s.�pH��#�f�s��9w/rn��P���;���	�����97*'T����97�K��8�4��p��
����b�rB��3W���/��p.i~���0�����8��j��\�sc��j�������C�\�Kj+����f��2��K��qD�u�e	sG�\R[��Pm#p.�=��/���A�u�e	sp.���SN�6�KjO���_D��5�A�}:$��Ft��Q9��&]R[p�_F�Mj��.�xH�;����8��j��tIm��~!�6�������!�.�.���S�6�p���k�~)���u}�u��C�]����UN�������k�~1�v��1�vCv
7u"�F��P�]3t�"�ndpW;�����������������f�U-����"����������Q�wA�]��k��i�������B$�]z�:���0���H�k�z;V+R�Z�^�	��7!��u��mb��M�����3�������?!�n����]�����V&_�1���|�:��O�����[}o�e3��Vf_�1��������"�oF��u��mc����~s�~M��jG�����?!����;����U��/$��o��*P�23�_�'D��<��Ark�����}_Hn��~�U65���O���V�[Qg�����_Hn��~�U�5�+�O���V�[�W9���������_�q@�����"���)���S��26�!���Wy���^�B$�u#�[�ay��(��=`Hn��~�Uv	5�K��O�����$��N9��������_�iA��*��"�/��$��N9���	��������<CE��4���	gHOInM�r~���-��/�����	�?!�z�_���Q��2��!���W9 �2ma�'D����8�����%�-��1����Lg�	��7"�F���+�
Cr�v���_�9��H�� �.�Z��
�����������?!������V;���0$��o��jE�eZ��O���	�we��j�W������_%�_�K�����������v�!�;�W�/�(�B$���7��v~�MbHn����UF�ez��O����73�k��+�Cr�������i�?!����;��V;��V1$��o��j���1�"��>����:��j�In��~��n���/��H�k�InM�r~��_�[��_~����e�	���r���_�������_�6�F����}�%�u�r~����$��o��j����r~����$���r~������c�������_�	�������:��j�����>�����g,�N�L�_yH$,��InM�r��O;�]���@�uwv��`��pw&�5u��>����Om����-*d��}:$�������Q9��=��/��S�����_��/�tH�~��rx���P�������E�
��O����70�;jGW�7����s[w#�od��}:$�]|#����������c���.������!�.b��a�vl�"�.E�}�����+B��A�vh�"���:��*!���C���|����w����UB�M�:��*!�����S'�m��x���!a����1����
�w�|�������1��>�f$����N�2o�\x�g�����e�	{wD��A^�W���{�������;�������4�t��:�����~�8����X�e���b�	{���q����
�n�<������uK�n�Jd�
�����v{
S
��&V7u������u��n���T�e�{3�k�J�N7�J4�9�����Y�$������	{���L!L��Y�Z�r��v�ng��4���	{��:���Z���8w���n�U&��R���!a����)�9��V71����)����Z�a�(����>��3�;3U0'���&f���12%{��Vi�Jd
������������L���Mr�/r�sU6����4���	{r�g�w�M�n��{C�{�+�������u�a�	{#ro`�w�N�"ro,r�s56���{�.3��!b/rod�w�N���X���Jl��wA���������r��p���Z���K�{���������1�>����+�����������m�M��\�����7!�&�{�S�������1���{�3��!a����1�;k�Vr�V����UF���������73��noF��E�}��Fc{�{��2�J��#�f�{g�PrG�����\q������\{v�5r��p��J��������Z�aA���(b/p/���S%�q����\i����^���J�k�{InM�r(i���+r�s�5��k�{I�+(a��%�5u����;�]�{�+������D�{�	��w�%�5u����{I���~��q%2��N�������>�y��k���%�gw��VfP"���rhe&�^�[�J����Kj�������Q"G����m���r�����zI���~���J��W9�2����5ew=2�/2���X������������c^��@�y}�y]���d��0��N�2o��W�0�Dd�Pd^�1�����a^��XEd��1��a��������cb� �F�y�vb� �.��K���2�Rd^�1�Z�y�y�vb�"����K���+B�Z�^�1�J�+�^;�J���^v���7!��"����UB�M�z��jC�M��K���b�V�^�1��{7{�vd�{7{��C��������1������^��*#�f�{��C���7���ch�#���j�V;r��p/�t�k\:�"�N�R+;���<4W&0(�Vv������tH�d�g{��V�L �k#�S+k`� ��,"�f�;\:��~���#Jd�
���ZX:H�+K����?��{��_jeG��Z�A9��#D�$���C�^hs�=��/�����b�A9�����L�Kv�����r���K���P"SM7(�Vv������tH��c�g{��VvZQ"SN7(�V�1��S��]:$���1�����R+;G����
����!2%��,�B��C���~�����\���ZY����e�	{r�/so����^��LPN�l@�
��K��������s��*"�r-d�vj�{#����!aoD��E��;�Vr/�C&j�Vr��q�vj� �.E��;�Vr/�D&j�V+r��q�vj�"��E��;�V+r/�E&j�V	�we��]:$�M�����s��*!�rmd�vj�!�&�{��C��
�w+r��1���{�62Q;���{7�{��C������w��Ze�^��L�N�2rof��}�H��#��"��S���k#�S��wg��}���������_j5��\���Z�p/�}��"`�8������R����q�rj5�^����E�^�KrO��~��hv�X�^����:���^��"a��%�g{��V��Pb�{���Z�#p/�}��"a��Kr���K��qE�u���rj5:�^����E�^�Kr���K�FQb�{���Z������n��w�8wE���R�q�%��	TN��	�����n��wp������V��K�k��Z�3p/�}��"bo��+r���Z�~D�u���rj5z�^_�^��"a�G��E���R�1 ��:��A9�ro�s/�n��7 ��2�vL�ro��W;���������E�������1������^��jA��u���-�.��K�{C��jA�]�5������p���Z���k�{C��jE�]�5������r���Z%������cj��{��F;�J����^��"a������:�Vr��p/[OW��
�wc��}�������7tL�2r��p/[rU������e�-�f��\���1���{3��l�U	{w����������#��E�
S��wg��(�Vn��cg��B9���:� Cr���K�����zi!k�S+g`� ���[$��2$�lo����
%�KY��Z9K�}��"a/v�!�g{��V��(�^R����YX:H�+�	{���=���Vn����i#c�rj�F�LI�+�	{���=��/�r�^:�������s���W�-�b�{��_j�&({��>2�*�Vn������n�7��adJ��K��<��zI]k�S+7CdJr_y�H��MdH���~���%�K�Z��Z9�Kr_y�H��]dH���~�����L+k�S+�{=����E�^�"Cr���K�\@�eZ�X��ZE���p/�n��������S�������V;������^��"a/v�!�g{;�Vr/�J�Z��jA�]�e�-�b�{��cj�"�2�d��N�V����^��"a/v�!�'{��1�J�L/;j�V	�7q��[a�[��cn�!�2�d���[mH�G���b�[��cp�}�n2v��2�o��W;��F2$��o��*#�2�d���\����a_v���;����������'cG��j~w~��C��i�%��eW���F�~G��j�~I�+�����������������*�W��%����Z�sW�_3�K�&�K�k3��^M�����zH�;8w��_M#�/����r|5���$���C���sW��~���F����r~59�_�[Q����%�gwM��j�jd��)�W��Kr_y�H�;��������i�Q#C�N9������W9��f�_�[��_z5�jd��)�W��%���]$��H��L��_z5y�_���SN�&����e�.��__�_�/���o`��i�W�70���]$��H��L��cz�~#C�N;��H���_��"������k:�W������N��������g��^�����cx�"�.�:��jE�]��_e{W���B������r���]%�������	�7U��ct�~��������e���wC����k;�W������^e����_�p##��2����UF���N��UF�����>	w��\�_�1��~w~'��jG���e}���W����^����g�������y������������������@)��i/c'��j6�z��W�M���W���~��ljd�
M���la� �������Z����^��E�L��I9��G�NI�'�����-��/�����J��rz5;�NI�'�����-��/��]F�L��I9����e*a������-��/�����Z��r~5����Oe���eH����_~5�jd������<CzJr_�7	���-��/��=�/�efV��f���9�U��<c��[��_~5�_�����_��70�����������c��*"�r}ff��*"�F�Yz��[���������k43k�W����/Ko�b��[��c~�"�r�ff��jE�]��{�^l���{����������43k�W	�w��W;��&3$�cu�����������D$`�����`mH��N�J�}����==�Om����!�r�ff��jC���e��������Om����~�V3�vx�~s~/�{n��b�R{2���s[sw$_����N�v$��#_��#�1CrO�>�on���{�>3^9��p/���{|l����`/�=���������Bz�rh�
@/�}%xt��%�'w�:�m��P!��^9�����~��x�KjO�>u�����
���y�G4�^��C��xI����N{��;&T���WN���%����F����B�~��%2����*�vI�+I���;�8w���~A���vIs�^���O@�$���J	{g�sW�����x�4��U����Kr_9��w��������;���rV�=�g�W�;P�x}���_X��g�7(�U> ��x�������������
�iUD���>v���yc���c\�y#��A;�Z�yc�y����.��K��s��jA�]�
�q����0��}�W������we�7hV+B��A��:�z�2�vL�Bob�7h'V	�7���Be����
�7����m���y7�y�vb�!�nu��P������[y���������1��������{�*{[w3"o."�s�5���#�fy����w�#����m���x�"�>WW���a�8�*�Ua�u��~L���=��/�
f@�L]��W�����|k=`/R{v�_ZLF�LU���Vk��z��������dH��]����������/����?~������n��������������_����s�����7o�����������o���/������?a���O9�#��u'?N�3���/����P��P~�������S��+_���������0A��4�0����8H�HmY������q�0x:�n���J�'5����8��Hm�\�k�;r�����r��-J�W&e�<�0�#>x�b�v���=w�/���i��~�&�n@|L�|��=`7�{v�_n�����pI�����r�����b/�{v�_n"����1���ER��}�b'�{v�cn�,(��v"��ER�����b#�{v�cn�B���j7	wW���)��}8`�{v�cn��v_m�!�nB�ML�|�s\wwSw�+%�v7�]���������g���p�p���������u��N�2�nfx���Z�]l�Ar��v��v�]��vT�#����_[K��
8H����Y����u�P������3���f��.�=���U�!�D�w���h�wI�+�[K�k�wI���~YU4JdxW9��x��������v��+����UE�K�+���YU��������%�
N]�w]��*�������rVG�]R��w"��8uE�u����J��.{7^�]�Kj_��^�]�Kr������dQb�w����N�����O�%���wI���~YU��X�]�n�����������q�����8������}1t���S`n����hg�� M�Z���8}�������]�xxF�9?
���/����%x�-|��pW��c����N�g$��n�lo��r���o	$��Gt��#��?m���H���~���W�H��H������$�3F[w=��=�;����*G�_��@�]�Bs�.����O[w���+6���e{^�#�/���p7��wI�B����F�SWl�=����*G�_�>/�n�/4�������S�g�����������K��@M���$g.��m�n���rD�n�lo��r����r����sIN��]�w�"�N��������������w�Kr�BK���&��T���_���U9�\qW���!�2�������V���cV�W�Hs�]��*#�2����v�m��������*�*G�+�jgUy��$������;�n.�n��
�������Y����\�3Z97uw�r5$����/�Z������q�Y�:���%93=�!��],WCr�����V�*�25k�}���xwe.����W,WCr�����V�*�25k��M�]��2���wU+��!�gw�eU+^�[�Ef~vW9�ZG����$g.��m���Kr�����V�*G�+�*gU��]�w'�������������������Y�:���%9s��`[w���=��/�Z�����Xb�C�]����$�ODX]������U�3����X����u�%��$R����J$��n��j���L�%�9$������]m"��J$��n��j
��L��I9�Z�n`x�B����"��"���YUD�e�,��!�nD���^���],�Dr��v���]����^��ywax�Bm���by%�{v�cV� �2E�X��pwE�]��P����X^������U���L�%����	yw��n�3���=��1�J��L�%�����������(�����H����Q�����Xb;�J��!�n�j�����=��1����L�%9$��������(�����H����Q�����Xb7�����;w��Uau%�{v�_T��X�]�`���i�e����]���i�u�����U%cQb�Q[0Z�]���D���u����
���d�XoT���p���Ajk��rT�,�$��n��*�������O��qDw����q7����������4&�X���V�0�AHJj+�nP�� %%�gw�%U�-(����M�D�����~"g�iq��}�C��*MP@�4W�U���!)������i68u����_T�f(�E�+�*GUi����~"Ad�w��b_��/�J���z_n�����q�s���f�������_T�����.�I�w���A���%��������������p7"�Fw�oU������1�������l�'�������D.��K�wc��jA�]����V�����5S���"��E����ywexW;�Z�wW�w������y7v���n��n����nbx�U'�������;fU��V�]6��pwC���UO"7������cV��w�:���*#�f�wYu�f��\���1���ws�w�vV�#�����$���w�"��~Y�6 ��u�e�p��
������rV�
��$��n��j2J��nP��63�����$�5��$��n��j3	%�y7(gU��%�5w�������������.(���A9��,�.�����Um��SW�]3�����DW�U�������U�6gp���k�~i���xIt�^��js@���f�rZ����H�f�Wm�C�u���q�6������:	{'@^�[��_^��5��7*�U��Kjk�*�U��Kr���6?��:�F��j����^V����������#��:����%�
H���^�[�[@�
E�5C��* ��:�F��*"�{Yu�F��X�^3t��"ro�so���"rod��U'a���+��1�Z�{�:�F��jA�]�e�I��"�.���Z���k�{�vj�"�����D�E�]��k:�V	�we�W;�J����^��*!��2����������N�6�������|U{7������cj��{�:�N����7������|s|M��*#��:��A;���|s�|��M�;��^&_�1���|�:��	�7�x�u���2elCr�����P#SF�}B$�5�z�����p��A�-��/��fA�L!�A9��V�[�W9���"����]e�-3�)�}J�ka� �������������<B�����a�������O���mbHn��~�Uv52�s��*;HNIn�_��*c��{���K��dQ#�/fP����)����_elCr�����<�F�����_��S�[�W��U�f1$��o��*�52Et�P�_o��z�K��������bHm��~�U���\��_��������3��!���W9 �rmc�v|C�O�2v�!�;�W��kc������e�I��=cHn����������1������0�����w)���_���\��_���+���:	�o�-��1�J��L�c�������e�I���cHn��������u�a	D��
�wc����������c��jC��z���*#�nu���:	�}�-��1����\�_�����_����@����_���\vE�E����_��Y�> ��e���W�_��F]�W9���_�[�W�z�n�]��~��n�It�_��j7��$���r�������c��j�52�����������U�7v�Kr�������F����w�%�5���}�%����g�v����S�It�d��D	� 0��Y�q������6������`v�$��,���U8�	����}j����)�B���pw�%�5w���}�%�'w��<�uw^P!����>���O���#�]~��:�u�#�z}����#�z��W��
�����Om���|��rp��������= ��"�>u��������c����c_mw#bo,b�S��m�]z#��vh� �.���=	w���x����o[wW�����Q;�Z�wW�w����yw-�>u���^���Q;�J�+���O�����*���7!�&�xG��jC�M�:�@rC��*����!�n���q����1���[$����[������73�;j�U�73��8jn�5��#���io��jG��9����vd��a^�o���w/��v���a�p�8����n���C�'��M���q�=��-��3�D������n��k�0-��k����$�;����c?{�A�L�]�X���`��W����O�^�*s�=��-��)�Q"Sc��&V�0:��^���>	{���!�lo����hC�L�]�Ym��`�X��i�m����U��{���-��)ZQ"Sc��FV�:����^���>	{���!�lo����(�D��.
������^��?	{���!�lo���&��D������nb�;��_�?��U��{��[du�8�D������nb{}{�}����������hko@��z�8�����7�����K��{C�{�����������q��UD��u�����F��X����k4����-3i�Vro�s/����wA�]���\u���.��\o�I;�Z�{�:���z	{W�����S��we�w�N�r��p/����7!��2�vL�r/�[f�N�ro��W;���{S�{�+����
���-c&��jC���ew�f������U�hkoF�eZ��I;�����9�ew"�"��"�>WX���;r/�Y�L������3����������{{�+���]3 �2}e��Z�����6�����������Y�aG��*gV�8t����T��]�Kj�������P"������$���>�5�u�������+cW��0���X�����r?W`[eF`^�{��_be�����+3���W.�J��,�]�y�%V���������q��$�9-2��sWf�~��
cA��0���X�	����rT)bo��+2���X�C��������yI�+�>I�;������+�
Jd�wVN��G��u�e_-g�������V�#�zzg����^_�^��"�n@�
E�u�����������^���zc�z]��*"�F�z���72��}O�,H�K�z]��jA�]8�������9�U�B���w)R���Y�H�+C�^;�Z�zW���m�'aoB�]���:fV	�71���3������{��Q��UB�Me��Ym���^�Ym�[z�J[�n��[�y;&V�wc��k'V�7���B����fd�\d��c`��y3��^;���y3�Y/�Nb��z�"�N��wg��+Vv��cgNzYu�Zhs�=��/��������WN��������U��-��9����YY���z=!��#+k`� �u�+]c�gw�%V�F����1^9��V�[c^ew�g����n����$2�c�W��i)�-���U`[w�]����n����	$2=c��jRu�AXJr+P�8�l�n�������W�iD���&(�Uv����~q��v1������*;�X��k�r\eg�JIne���UA��C���~q��w�X/�k�r\e����+\^���]�����;����G�ez���W�����U��a�n(���/��y��c�vZ�wC�w/|�������;w�"�.�3��Fa�B�5���:���3�����}vw����M�����7?����o��������|��?�y����������7���������O����h2l�O��V��x
f���/��p|8����J�4����/�s���c�
���9��c>c�*H����I���~�����Sm�����ka�u�bn�7vw���U����9�H�1��MP�����c���	G[w��0�=��/�s���cj
���9��c>c��I��U�I���~���O�Sj�D�h�M+;��������E�I���~���/�Si�D�h��#�[�'g/|���<�a�a�{��_���1�T6Q9�sre�|f/|���^,2LrO��~���O�Wi8*�{�;��0}{��0�=��/�s����*
G�t�D^��0�~�)a/&�g{��{�s\���|�Ed^��0�~�'b/Bo,B��X�7b��4�����<��_�I��E�I�����~#��J�Q;�Z�z���,�����Xd�����Y�7b��4l�vd�{���,�����Xd������Y�Gb��4���wC�e���u*	{��0�=��1����Wix��2r/���e�SI��E�I�����~&��J��vj��{�/�,{�J�^,2Lr��vL��31�T��vj�#�2_�Y�F���V&�'{C��j�{'����S�i�%�5{�c�	������R��8��|�:(�V��%�5{�c�	������R��Z��|�:(�V��%�5{������0�=��/���%2v�V�U�������{I��w�P�s��|��K����n~���\��h:*����g�(��Tn>�h>�u��q�a'E�9?�R��[��\P�S���N��?����2��]�)�)r�_�7�%�/��A9��n�B���e���ppE������Q"�A�r�7E�G��'��q@��������(r�_�7���d�%�$�]p��L^�������<= w�%|���������!�.����?(n��:������/��V�n�4��U��H�������N���;�{	��$�5w���g$���w���q�������m%2d���$������'���l�����V���1������F;���������h���y7y7v�v�����Q��6���;S"H��v������cV�#���*gU����^�]���m��������=��/���
%2����!���u��V���I�l`� �gw�eU�YQ"s�l������Ar+�*'���e������U�6�D����
)�.�$�y3�����#�����C�����Y�<BNJr+�*�.���SW���eU��������rV5;�IIn����g�]��+v�0C��j�F��\�fK�I�;APJr+��1�<ANJj��K����F���UN���R�[�W�a�!(%�{��U���F���U��n������Z?���#��"���_^5{d^�0/{�E�������{�$x[{2o(2��Vs@�
�jV�7���B���F��X�^3tL�"Ro��W;��H��Qo[{��X�^3t������^�����b�������+b�R�^3t��V����^�����+r�Z�^��7���k�{;�V	�we����"aoB�M�j�	�7U��cj�!�&�{�k.�n�������������tL�6����^������w�s����m��������cj��{3���E	{w��\��e����#��e�5S��wg���'-`��{�:�N����{Im��~��"jd���!b/p/�����Zycq���k��V���������7��$�b�rj���SW�^�/����D��UN���%�{�S+o3N]�{M����#jd��=R��w�%�{�S+?������R+�jd��=R�����������w����`o����52���J�;9���^���O����`o���Ojd��=R��w�%�/o�����3p/�=�k��V~^Q#�������������jk�G��e���R+��{=�����������^�{�> ��2��~������^�HU�����U�5�#ro(s���ZE���p/{�*aoD���>%�����k;�Vro��W;�Z�{�{��������vL�V����^��jE�]��;+��w-s���Z���+�������	�w�s��| �ro*s���Z%���p/�{��wC�Mu���7�����S�
�wc����H���{7���c0�����{s�{;�V�73�����������3���������c��jG���es?	{w������8snjop����;�K���.It�^��*�t���k����8u�r��K���Z�$�f�rj,$���9�q�p�8���Z;�F��.{�*a�����V�U�k,���`o��*�5���Z�HU��"S�[�W��F!1%�{��Va�Qc���es?	{����+]^h���^�)�-��/�
nC��B����$�� 2%�{�ok�	SR���_}��g���8<���e���Zv#�0��$�����B�N��4k�����%I���[�2S�[Vw�n[s�m�=���������k��M%�������
�6=�
�5����}j�������u���#�zCz�6�b�R{2��Ms[s#"/�8f��""odZ;\����X��1$���S{���.H�L��B����R'^�|�g�=���9ocs�w��1�EJ	sW������W��.��!�'s�:�mk�������,PJ���v�:�z�(;�����O���57!�2]c,��"�"��:�^Xs�>��0�����swC�e��X&%���t�:�j_m�0��>+��nF�e��X8$��������7�6�!���7����u��1���J��#��u��Pm�����{�����q@�e��Xv�"�nvI���E`�uI���~9U4%2���s�hvI���e�`�����TE��D�v�rP����i���I�k�vI���~AU�Jdp�+Uq�%�w����p������T�qE��z��*���$�������N]�w�EU�������QUt��$������8Y��2������K�k�*gUq�%�w����y��+��sE4��;�����A9��3�.����|�&��������h��Q"��A9��y��y���I���w}�w�+��������
�YU������OO�������\���"��w�vV�wC�w�����y7y��m���������U-������OO��yw)��s�3��� �.���jA�]�����$�]�w��E��Y����2����yw��.���p7!��E�}�zF[w�nbx7hgU	y71��|x[$p����1���w7�w���
yw��.�b�xv7����������q���Ue�����v��ws�w�+����y73����ywgxW;���w�"�>W9�����;��Q9�Z\7v�w���[�����Y�����_F�?/��w�}��?����q�qS��o~�������o:T���~���o���?�����������?_x����'.~��������������a�C��C�m��DO����f%~��q�������e���v�<���_�/#O��b�r,�`�
R{6�_p�8��0M7��v�:��Hm�\�Tv�n��ln��n�J��e��I�;A�Dj+�*���� �gs��v�lQb��([�N��R'R[1W9�]���=��/�[�������������V�U�d��Aj�������4���q���aDs����rf�`�
R{6�_f����%G�c�okn����V�U����Aj��C�EvK\Pb���}|C������^?*'vv� �gs�%v��������/��5wA�]������=���r��"�2M6�����+r�Z�\�M����kt]��*!�2=6�vD�tSt���Qaw
�{v�cF�!�2-6�vF�!�nu�5�vH��5H����!UF�e:lX��*#��:��A;���$��n��*#�2
6�vJ�#��:��A;���$��n��jG�e�kX��jv�:��A�v�h������S�����;*�T��Kjk�*��jF��2���n�MwG��j5������2�����yw��T�x�4W�UN�V�Kj+�e�]��SW���_T��%�ywT���x����U��u�%�gw�eU��(����rV�:�]R[sW�wW�Kr������i@�u�e��K�;��������N��$��n��j�2J��.[&X��yDw�U��������ln��j�J��.[IV�\�Kj��.4djk�G��E���%U�G���*'U�G���>�r��������;���������n``W}�����������������9�U�������1�Zvcv�vP� �.L{s�UwA�]��;w��Vd����N;�Z�uW��������+��ZD��cL�u�:�:��*!�&u��1�	Q7Qw�S%D�TG]�Sm���A]��&	w7d����s��jC������c�����Y�=w�x1gd�\d��cJ��us�u�vJ��us�u�cg	swd�\d��cJ�#��u�u�)����s��|)#aC
�{v�_Lu���KLLW
�S�
R[sW�RF��$��n��*(���N9�JV
R[sW�RF��$��n��*Y��UW&��*YX6Hm�]��D	w���=��/�J�E��*�l':	wG�HIm�]�K	j�����_P����UF�Nt�:�HIm�]�K	j��������2Jd�H*'Ui��n��a?^�pj�������4%��t�TN��!)�����C&l�Ar���K����D���rR�fIIm�]�2aC
�{v�_T�<�.�UcR���G��u��nq����=��/�Jq�i�1)GU) �w/���}t���=��1����LS�I;������������ �gs;&U�.�Sc�N�����]mw���=��1�Z�v���vR�"���^8!j�.�� �gw;&U+�.�Sc�N�����.�a����N����
�����������
i71��~�(�.�� �gw;&U�.�Sc�N�6����]��D	w���=��1��H�LO�Y;��H��9�e?L�p�i������q���1k'U;����.�a�����{wC��jw���rRu[���%�5w�s�m�%�gw�EU��(�����u��]R[sW9���.�=��/�����U��6�Kjk�*���,�.�=��/��lF��*gU�h��:���&
�!l#�.�=��/�������Q��wImY�co���:�]{��_P��%�a�+U��%����r��M#N]vc��j�vIs�]��j�vIm�V�r�������_P�������rP�������r���;N]vc��j�%�a�+U�G����_K��v}vc��j���^9���n``���X������;Ua7�a�kUa72��~V,�nD��E������������a72���g��.H�K�vc��jA�]���V���9�e�+�pwE�]��;U+�����vP�"����K���w�2�vL��n��n�N��n�xW;d��wS�w;fU��V����Um�����Y����y��������7h�U�73��~Y,aoF��E�5C��jG��u�
�i����3��~Z,a���������<��:���*�r��J5#�����������<���^1((�U�8t��M�\D0cR[p�_\����%��r\�-����jV��3v�!�{��U����^7(�Uy������U��3��!�{�Vy���^ 7(Vy������U�3��!�{�%V�A%����	��Uv������is�F0$�`o��*OP�23�`�rd�'HKIm�^��9c'�[��_f��5���F��*�������ys�^0$�l���YeoPc�LnT���G��u�5ly	{��-��/����i
�3�{=������!�w;FV���
�#������j`;R[p�cd�z��0Q;�Z�z#G���E������3���i�3��wa����!a/v�!�{;fV+R/�&jgV+R��P/[�C�^�	Cr�v��R/�&jgV	�71������7���t��6�^�7L���6����^�����������Ye�^�9������{3��l�	�1�-��1����L3h�V;ro�s�a�|H���aH��_�1��|�1�rl�H�;s�����w}In��~��>���i�:(�V��%�5�S�����������D�Xg_3('W��%�5�c��Z��2��~��n~It�_��j�@�$�����q��+���]�#�/�����]�#�/��4��}�8ue���������i�:(gW��%����r��;�_�[��_v�O5r��^��/���c��H�;��������}�Q#G����>;���_�b���3�/�-��/���
5r
R��������������~}�~��W�G�����jH���_�j����7��w��^��70�k������e��H��~C�~���UD�����*"�F�����#������;vL�����_��^-��s������w)���1�Z���vz�"�����{$�]��2�������2�k������8��N��o*���1�J����_��_m����_��jC����;v��6����_��*#�n��5|$������W�}��a�3�����9���vD�\G`��	x/�S�������;��V;���w��*M���<`�{r���sKwo
��_�k���W71�k�!���qx����4�9���}j���\�A!�E��FW71+�k��/
[�K���2����Om���k'P�u�����MLwm���ap���q�p�x/��ms[w�2�u�nluS����^�����$��2����O��u�T������M��:����s�eZ�jO�>u����2uu�nb��iDs�u/
[\M���2����O���uw�P!SW��I	wg�N����-�&�.��9�J���w^Q"SX���(b�������-�&a/��9�>6�g�G��:�X���&y�3������7 ��"�>Wc�����k%3��U71H��!^�~����7���"m����\/�Q;�����A^�~����������hk����5�����wa��-�#a�������"m�]z�n2�v`�"��u�5l	{W���H���hl/b/�Nf�N�b��b��L#!��"�>Wc���	��k'3j'Vbob����$��n��[{;fVb/�Of���6����^�>����w+co��*#�r�dF��*#�f{u/��aG��E�}��F[{w�^����Z���;���p��z�"�>W_���f�%�5w�3+3������{C2�3�����m�5#J�Z�*gV����Z`����^R{v�_de�A�\U���X�^�[���V�xx-@/�=��/�2vG�\U����#�[�^�VV��w�%�g{�EVf�P"�DU9���.���N��
l�nv����n����%rMT�+�zInY{�!���p����\a���N������rbe&`^�[yv��h�8ue��X���4��U���Krk��I���]�y�V�#�z�y����zd^_g^�V��������m�
���c^���d�Pg^����7 ��"�>WS����7p���XE���A��I��������hl/Bod���N/a�����l�<	{�����U�hk����0��v���wE�]��k�z���H�k�z�+�����we���p-b/R�Z�^���&��������hkoB�M���%�M�������v)a�������\9���n����l�k	{7�������FF����;v��2Rof���o-anF��u�}��66�7���cb�#�f�y�������;s��y���#��e��X����1��6�p����@�[S�����1��s!�~y�5J��*�U���Ar+�_~m�.t�9����WY�Q"SD�m�+���]������B��C���~i��	%r�S��*;BTJrk_�*��c�gw��Uv\P"�=U9��#$�$�v9R�]�s�=��/��.�D�}�rVe�$�f(�}c�gw�EUv�A"�<�m�+��9)����|��B��C���~I��J��*'Uv����V�U��l�g����n���z�����Q�������li<	w=��/�n����]�m�W����������p7 ��2�v���.�4�m�+�nD�
u����jzBd#�n,���1����\��!����n����]U[w�����S��jA����
5E�E�]��{aW���yw)���1�Z�w�v1�Y����2��|��&�����S��*!���b�������U��j�n*���1���w�V1�Y�����y���K��!�nE��:fUy�k�6��p7#��:��z	w3�n.���1���w�1|M	ww�������E��yw/���1���w�&1�������������8��������qH(�k���U�x��V�U>�
�.�=��/������Y�h�wIn�]�����8uE���eU��%�5w�������������hp���;����x�4��U���x��~��q��+���/��C����3%�u��$��������wI���~Y�8Y��5FU���	x��~���	x������U����e�!K�;����:��S	wg�]R{v�_V5�%rMQ������n�w��O%�������s��j�����]�����y��y���T������;�������e���������~|*�nD�
e���UE����.��M�������~}*�������1�Z�w�w��l�.��K�w��OE�E�]���;fU+�����vV�"��u�e??�pwE�]���;fU	yw�xW;�J�����l�a	w�n*����Um�������Um��[�w�"��n��[�w}��jC���e�fJ���w�:����$��������cV��w3��l�L	ww��\�]�o���;��^�]�1���ww�w���"�"��u�e�&	���/�=��/�r�tls���
�n�����w3��!�gw�eU�@-K���a[fJ�k`� ���:lCj�������R���
��T�p���Ar?
�u�������U���D�J.�RQ��rR�[qW���MaH����/�r��D��rV���$���*��s�������U�i@�\;T���M����J��|k�aSR{v�_V������Y��-�[�b����p��������*7'��u�Q�������~9���0���n���y�]�1�rV�<�����v���%�=��/�ry����U������6��p;���������������"�n��.��N�]��X���1�Z�w��0|�	w�����l3;	w��=��1�Z�w��0�Y�����y��e'�.��!�gw;fU	y��	��U%�����vV��`H����1�J��lK��jC�M�jgU�������Um��LG�����yw��.��N�]�Cj��v��2�.��������������9lCj��v��v�]�'�5�Y����3���Y�4 ��E�����i�%�5w���i�%�eu�GN"��8uE������8����Q��&�Kr+�*���%�gw�eU��(��]�h	w-�.��4��,�.�=��/���%2�����pw�%���7���Kj������1�D�w�v]�:���yW������������%���.��K��	x��~w"�	x����5C��j����rX5M�$���9�#N]x��/��f ^]�W9��f ^��i������+���U�G�����%$�������F�����y}�y��/��B�g���.!�o@�
��f���) ��"���cb�zC�l{		{#Ro�S/�fT������k�������e�KH�� �.u�e��J�� �.E�5C��jA�]�e�7	{W�������k�"�������S��we��j�V	�w��/�HV��MH��B�c��������UB�Mu�e;�J��!��
�v��6$��!_�
�����V'_������w+����[e$����vn��|s�|�^�"�"��2��������9����v���zO��wG����k��V�0�2��v"��6��$�{�S��������b������a[H�k`� �eulKJ	{�=�-��/�����&1l/	{�C{�e-�n��bR[��_l5�
5r]Q�c�y����V�U�glCj�����qE�L[�Q9��d�$�y9c�R[��_j5���us-[�Q�^�LIn�^��y�1��`o��j�����4��l}F	{'�LIn�^�Pr�1��`o��j�����t��l�F	{g�LIn�@��~B���s���q��_lu�52�Q���z_�ts`�����������r�9 �2�b,[
L�����U>T��Q�-��1�
H�L�����7"��:��=�%��N1��`o��*"�2�b,[L���7���m�-a/��!�{;�V�/�0����$�]�|�|�f�Cj�v��V$_�c�e�������2��}���bHm����UB�eZ�X����	�71���:c�R[��cn�!�2=c,[L��
�w��/��[�^���s����4��lE0	{3�o��/��[�^�Cj�v��v�^�k�eK�I��#��u�e�K��
cH����cl�#�2mc,[L�^? ��u��.���^R[��_j��
5r���Zy�Kr+�*��7����`o����52��V���������`�-p/�-��/��6�F�{��`"�������`�G�SW���_j�G�^]�W9��#p/����F�
8ue���V���������w��$���m3+bo��+s��/�����e�I�;��������~�%����g�vx������e2��V�px�%���O���KjO�S[������_��������u�e[�J��|}|��8�5�#�z{��B��^_�^������7���ms[sBo��W;�����l�Y	s#Bo,B�S����FD��!�v`ycy�>��.�����Om���� �.���g$�]x�:��mf%�]x�"�>u����qwep�-;#a����2��V���kw�:�mknB�]�e��H��vs��mnB�M�C���x���!�&�s��$�n��[�s��rGm��t���SG���E���eK�H���t�:������Q7W���goF����%I$���u3�������{�js?ww����]�"���a��c���a��
��m�-�"t�7+J���lE{a� �5{����}cH���~QU0P�20�c,[�B�^+�����UlCr������Z���c���ZX:Hn�^��*`��{��_\F�u��1�-Y!a�I)�����WlCr�����Q"SG�-Y!a�������U5��!�g{�EVa2(�^F��%+$�� -%�5{��W�Cr��������z]�~�.a�<���*���6+a/��!����B�0o(�^F����K���{I�'R.%`��{��_h<r/�@��������������u�=��/�
���c�O�%�
����^������:������ZE�^��e?y��7"�F�{����b��{��cj� �2�c,�����r��p/�rV�^������U�hk������a?y��wE�]�e{�J���cH�����UB�e��X��w	{rob��m:+a/v�!�g{;�V	��ic�vj�!�&�{�S+�Cr��vL�6�^�}�
��UF��8��N��s�=��1����L�����73��6���;����g'S���ic�vj�#����=g��r�^����i4�7����f�rj�^�[�W9��f��+r�s�4��k�{Is�^��*�^�[�W9��&�����jm��#Jd���G"a��%�5{�S�h�{I���~�U
J��W9��#p/�����Z��������Z�qG��*�V��h/��l�Y	{p/�=��/��nC����H$���{In�^��*N��$�lo��*N+Jd���@�^�^�[�W9�����+s�@j�����8��f���/~��������7������������_��t�������������������7���������'L�O��~-!��,�����~-�����)�C��C�m�9�9�7l^�{@�e���������?>���*1"2����p7"F�"F�~^\#b#��G	w���������R�R��1�[�"�:E�����l�]	wW����c��"D�u�`%�M�+�l�]	w2D*2����%d�Tg��Q�]D�� �{W��
�����c|�!Bl���c(h��'g����vz�-N]���uL�2��e���1��u7��Yf������xp��g�cx������=�����ywg�����"�"��E�u���ep8�����++M�]X6Hm�]��n��$��n�g��(�^��=v�p���Ajk�*gUv� �gw�eU�Pb�@{�(���e��V�e{�J���7H����_V�����H�CG	w����4l�]	w���=��/�Z����H�3G	w������rV�`�
�{v�_V��%���G�"�BLJjk�*gUv� �gw�eU�u��{�&��1)�����U-�u������U-3�
\������3������rV�`�
�{v�_V�x��I�36	w=��gx���+�.�� �gw�eUK@�e�o�gl�����.�lW�]l�Ar��v��"�.�}�=c�p7"�F�w��*��Ar��v��"�.�~�=c�pwA���jgU�z������U-��L�
��M��ywax���+�.�� �'w��Y����4�`��D�E�]�e�J���7H����YUB�e:p�gl�&����.�gW�]��Ar��v��6�]�{�&�����1����qyw+���1����L��M������e��J���7H����Y����4�`��$���ww�w���b�
�{v�_V���L��M��u�%�5w���u�%�gw�eU��Qb�w�36	w���2�����p����������$�X�]��M�]�Kjk�*gU��%�gw�eU�]Pb�w�36w�wIm�]��jG��2�����x�4W�U���x���>aS��Vgp�����eU��%�w����������Y��v��"��~Y�:9�X�]��M��	x����U���	x������U��E��*gU��Kjk�*gU��Kr�����V?�D�w����#�z�w�F��z�]_�]�/�Z=����.{�&�n@����}v%�
������cV�wC�w�36	w#�n`x���+�nD��E����������������e��J�� ��"���Y�����y�=c�pwA�]8����V�������yw��.{�&�����r���U���k�w;fU	yw��.{�&�nB�M��=v%�M������cV�!��:��gl�n����l�]	w7������cV��w�:��gl�f����.�aW�������:fUy73���U�����]�����;��^���1���ww�w���4���3����p7a�
�{v�_V����E��36	w
,����rV����=��/�JfA���A�����l�����YU�6$��n��*Y(e��^�����
R[sW9�J�e������U�JY&��{�&��1)�����U%l�Ar������s(�^$�=c�p�ALJjk�*gU	{l�������4Y�X/����I�;ALJj+���u%��$��n��U�y@��"�����3������rV����=��/�JsF��"��������L������y�y7����G���*gU) �z������wC�wc��*�����vV�w��l�d	w��=��1����LS��M������
�I$��!�gw;fU�.��=c�pwA�]�e[&�����y7v��V�]�){�&�����2��vL�p�����������4�a��$�M����]�$��������
y�i
���I��!�n�j'��������Um��LS��M�����q���Db;�{r������t�a�$��x3s���K������������i��������3���K�w�x�"���_\�
��$�b�r\�
����f�r��SWD^3���6�K�+�6���4�_�_��%�$��a��M����]7����b7������8���?������D�_������7��e�8�_�����-aO�q��mi@��k������.�n����v�����0�-��/��RF��{���������2���r��mpO�����mn��Ea�hR�������(�#�-���$�`o��o����/c��+{!'�5{�3�mq��_���_����������!��CNjk�*�|A������e���${~%`oF��,H*�|A2W@��K�2�df@�=���A2������N����xxjL��/[�����	���VR[�W9����[��_��G��������#������)_��������e7����){�%a���SR[�W�VZvp~Jr��K�����~���aI�;Y���z?(�Vy�L�����Z�)���*{�%a��)�����Z�"S�[��_j��5�P�3,{!1%�5{�S��G������Ze������S���{}�{���Z����+��/���7���=���7 ��{�S���*��1�������������7r���ZE��X�^�1�Z�{c�{�3	{����^��Z-��K�{m��jE�]�����H��"�����jE�]��k;�V+r��p�vj��{W�{�vj��{S�{m��*!�&�{�S�
�71�k�S�
�w+s���Zm��[�{
{(#�/��������2��V_�1������=���7#�f�|�vn�#��2�������������2����;��F;��}�2��~��> ��u�5�������Kr������n��������`o��j75�����2�`_�[������^�Kj���v;��:��\F�^�Krkog��y���$����/��mF�u�5������E9�U�������]�cB�u�5����������UN�w�Kr����v��F�~���������V9z����L�c��j��~It�_��j��~In�_��y�
�]�~�~��>����������3�/����>���sW���_z�{��eOg$��H��9������}�~��=��������7��W;�H���W�}��a�3��S������8��=N'�:�c���=76�72����H�� �F�f������� �.E�}j�����wa��=��pwE�]����N's������k}��8�5wE�]�efD�E�]9�U>����Z����m�M����^6��p7!�&{�}�
�7���Ms[w7����^��jC����;j��2�Vd���{����x7�x���������Fm��������;�nfp�
t%��ww���U�����{�@r/w�a08��qn{wo��W�Cn�]������U��[�����%2���4W�^�����W����.��\7����fC�Lm!6����Z�������G�7u3�������~��%������Y�>��k�/��]s[{Gs7bLz�$��w�(�����
�nb2�;�+^�Q��w��������[\u��A����c{u������z�K;�����4��aRJ��-��I�@����e���N�;�+^�Q���&&��aVJ��-���yD�LM]vo*a����^����a�ML���1,�i�Y��7(�����M%�������Q7m��A��e��Z�!�z�{�������3�;��V�>8��e���Z���p/�7��7"��{G��*"��"�>W[����72���M%�]�{#������������m�]�{�{�������������������m�]�{W�{�����+r��p��N�r�Z���jk��7!�r�d�����	�71���S�������\m���n��\/vo*a����1���S�
�w+r�s�5����{�^2��T�������^��7-�������h�.b/�J���J��#�f{����z�"�>WV���;R/�I���
�k����^��7q����n���+Jd����J�kzIn����d[w
0/�=��/�2&�D�y�}�����$����7E���������h���%�5w�+cyIn�]�����"�>WP���#/i����W����V�}�F6v7�����rm�u#Jd��-%���%�w��m�u�����n���L%2����*3�����Y����xI���~i��v��/�5����C{��P����3/�=��/�2���e������������4�G��E�}��F[{="���W9�2�����B!��Ko@�
E���U& �y�������{�][w#"o(#o��*"�Fy'��*"�Fy��uwA��e��W-�����v\� �.�>>�m�."�RD^�1�Zyy'��jE�]�U>4+"�ZD^�1�J��+���v\�yw�Y��������:�U	�71�;i�Uo��W�f���x�"���y����1�;i�U�w��W�f��H��H��c^��x3C��v^�#�f����q	{wD�����c^�#���N�y����3����5���t�E�u��*;�W�<4��U���K��]�P��l�i�!�lo�����1fR������V�X���-��9�����WY;�D�o����*ka� �eu���,��9����W�qD�L��Y9��#D�$��bV�&�B��C����_^e�A����fV���������U�&�B��C���~��u;J�W�5�r`e�����l�&a/4�9�����X�iC����fVN��i)����|G�B��C���~���W�X��kf����������}S{�U�!�lo���zd^�_�M�����s��|�d^_d��_be2/�.�����
�������K%��H��H�S��*"�2�b���U�7"��:�Z6.��7�w��X-��\��Y;�Z�{�{���������cf�"�2�b��������+����	+r�Z��������t�1^;�J��+��l`*aoB�ME��;�V	��ic�vj�!�&�{��T��
�w+r��1���{��1�k�Vr�V�^�F��f�����s��*#�2]c��N�2rof���L%���{s�{���������1^;���{w�{��T��q@����;�K����4��UN�����V��sQ�Lr2N]{�~��hF��`�W�F�Kr+�>�����^R{v�_f5Z�9�U��F�Kr+75SQ[w-@/�=��/���9�U���qDw��{��F[wG`^R{v�_b5�Jd�7('V��%�w3Q[w /�=��/����
����yIn���H������������	��4��U���	���V�}LDm��-N]x}��j�xIs�]��j�xIn�����m��N]�w}��j��������V�y�3����7vy�y��������
�a��wC�w/��u7 ��"���YUD�
���*"�F�w��������;fUy72����y72���U-��K�w}��jA�]8����V�����N����"��E����yw�xW;�Z�w�:�^8�o�nB�]���1�J�������U%��T����m���wS�w;fU����n���6�����������w�"���YUF���F��*#��:�^8�o�.�n.�n��U��������U���{�w�\��yw/�n��U����1���*7��Ar+�*��{�������*g��T���Y�3�n���:�N[�������*g2J���*GU��h.��P�]lCj������M(�^4�D��������:�8[�������*7.(�^4��c��.��$���}�H��-bH���~Q�sP��1}bLT�������V��^w�E�=��/�rT�t\�N�����$�r�U���1���n����%2Es������������6�!�'wc���y�����rT�<��gpW�\lCb���K�\@�ez��A9�ri7�i�B����b{R{v�cRw�1v�N�"�n�����Sm���0���n��*"��=b���q7�q�B!���b{R{v�cT� �r=b��jA�]��{��~[w�=�=��1�Zw�1�vT�"���*���aH����IUB��Z��IUB�ML����������;&U�.�"f�N�6���kZ�|3�aw�{��cT�w�1��!aoF��L�B�����������y��c���yw�������!�'s��1���w�1F9������]]w�p�����UMCB�������]�[�A�]�Kb����&��F�'�rV5�]��I�����3W�]3���&�K�k�*gU��%�/_�hZ�j
N]x��/��F ^]�W9��F ^�[Q7�����������9��0/��@�_�Kr+���^�Kj������F�y��i�%�u��^�	�����YM��9�U��������U.�:���$��o��j�3jd��*gV���:�Z���G�����ZM��3�k�S�) ��:��{��o(����[M�70��>!"�"��:�Z�A����7���tL�"�od��j'W�7�����$�]cM��jA�]��������0������w)����^�����,aJ��"������wc�������t�����������ob�|�olL	�7���t��6��������6�����F���iC����k:�W�����v~��7��N,�oF��e�5�����9����v���|��~�$�����W��c~�#������������W�ta�>1$��n��j����t���rz5�v����Y�~g�Cr���~��l��������rz5X;Hn��������bHm��~��l����4���rx5[X:H��b������q��/��G��6���	{GHNIn��R�^lCj����fgQ#�&uT��f�)��}K�l/v�!�{�%W�4�F�M���\���$�V�J�_�Cr��K��)�F�O���\��E�u.-��Pb��cHn��~��<'��4J�����w�W�dcS��[���������#�2�c��\���3�{�[`�����������9 �2�c�S�������]�l��1��`o��*"�2�c,[L�������[6c��{�w��\-��L�����wA�]�����f�Cr�v��V�_��e?���wE�]��{����b�R[��ct�~�2��&aoB�Mu��F#lCb�vL��/�@����$��}���{glCr�v��6D_���e+�I��}7}�?Z��}�-��1����L����7s���/M�����������i#c�vt�#��u�U�t�����W�}��a�3���,����<V���Lrk+������O���kJd�wR����%����o�I����6����%2�����Z�_���y�KrO�>�nl�8�D'������$�f���Wm��I���������(���I9������>�x��^�KrO�>�{nl�K(���I9���/��������N��$�d�S����������^�	�����UN��<�����s�������f�rx�g�_�[�W9�����O~�:�ml�G���N����6�_�_�C��?s����g_������t���?���o��/}K��7��}��o�~��{��:�����~��_���o����)���{��D61+LN��������������q3P��P�����*��=�Y_����\�3�Q�����������$����t$���r�<|��[t�M�E��8w�~���'i�/��#�� �A_�	r`n�6e��7����YLG�2�������� ��acf	#��=��1�x��D��U���2���cs�q[@5�{��c��2�������Jp��a�f	W`5�{��c��6������Jp��a�f	�����[$�c��>����������t���%���S�;�}�������q_����t���%����[�;�}�������w�BF�en�6l��7���
%����t$���v~�#�27��6K��#��E�}�DI[#��#�5���8�F��a�S#�g"�g;�W��E�H�r~���r���_E,�Dr��v��"^��L�&�k
	-�od��6=���3���������"S����B�_���\�3���4���������"W����B���727���3m��
M$��o��*�}���ib������F�*�a�S	�D�=��1��x�.2���/)$���#s��\h0����sW����U�u�-���_��72����3m��M$��o��*����jR���G�en�i���X�������_E���jb����7 �z/��i��b�&�{��g|�BM���F��P�_��2+4����=������i���q�7��W��H��L$��n��jA�e�4��RH�� �.u�
���#�g"�g{{&W+�/S����B���w��o|L���3����=�����i�A;�J���Q��_��L��lo��jC���4��jC�������E,�Dj�����2b/W�)h�V�73���hj�/�g"�g{�V��+��c��7s���X���X������[���\���[-.;S>�B_���.,$�\��cn�	52}��rn�X=HnE����oj��������[-fA�L�>�.E�����V�=�]����8u��}�cn�X��E�+�������[Q�8�lk�hp��M�]��j������\-#��$�VyP�������IWn|?�n|0�������E"�1�����D����xg��_Kd_c�����>*���?�R(O��{��!�=��;�x��Qc��y�\�q^��#Hm�#������S��#F�:F��Ow[wR�g(�q�������1�[RD�S�y�4v!"�!����KD�e����-)"�)���,aoD��u�0����� E�2Et���)b�S�Y��!b�C�o������HS�oE�X���c.hk�
W/Hm�^�8�ok�
W/H����	^��o`\�@%�Mp����~~���W/H����	�6�F��q1��wC�����s�gm���z�"�N=�
�w�S/�J���z�:���l	{3bo.b������{3sz���J[{w��\�^�~�-a�����w��Y���;sz��Y���;����5�w�{�"�NC�u�%�/�~��p/����|�l5����S��j5��$���O�^�Kjk�*�V��q����1�Z�C��*�V��%�5{�S�������S�u����^��j�{Im�^��j�{I����cj��5�����-a��%�5{���������S��e�X��Q9�Z��e��B[���N��$�lo��j�j�s���Z�3p/�����Z�3p/�=��1�Z�5��wTN�������UN�V?���w��Z�����wTN�V�������������w��Z��7��wTN����������������s��*"��:����UD���^hk�������;�L���X��Q;�Z�{�:���	��[�����=C��wa�W;�Z{�:����I��"��e���Y�H�+C���UB�]9�}�n��kB�ME��=#��������#�
�71��n$��z�"�����������iGVB�V��Ud���32�Vd^�3�������N;����������uwG��E��=��w�#���vD����j�4v�w/���W�a�	��S����������s�����n��*��5Z�r\�,�����7�	[r������d-j�Whq�iU��l������&l�Aj��v�n������aU!(%�$b�|Yd�~$�lo��*�5�K��M�%�u��4��O�^l�Ar��v���K��^����.a�I)�����?�O������
��4-��^����.�.$������AB�V���n��*�P;01
9�~����������		q��������x�����.��G���>���]$^_$��1�J������r�p7 ��:�n�D��6$�lo��*"�2�8�V��FD���go�J��}8H����y����t�`;�K�� �.��b#�{��g`� �2�8�F���������wn�.�� �gw{V+"/���m�.�nB�]�Z�l�<�j�	�p����=����t�`��������R�l�<	{��=��3��z�nlw	{7�������U[{��=�{&V������p��7#�f�E[gK�^��\���3��{�flw	{w����w�4�����������Ymb/�����.`�6����>����
��$�lo��j3j�c/��]�^�KjkO���y3��$�lo��j35�����.a��h/�#���+a��%�g{;�V�M����l�v	{G�^R[��qh���������Zm�����������~"[���8uE��S������������{Im��������+so��j��{It�^��j��{Im����7`�~W�M;�\{;�V��P#�����6����8�B8��KbO������E�����*��G���>>Ohk�G��E�5C��jH��N�l�U	{Ro`�W�J�zCz��3�
H��N�l�U	{#Ro`�W��zcz��3��H��N�l�U	{���uFW�wA�]��k������������*b/R�R�^�����+B�R�^3���V���N�l�U	{W���N���k	{B�Z�^3���Ro�S/[cU��������^���7��=3��������r���r�>�N2�I���$�!��������,�~�[R���F2�r�&#���W�+�������@�=y�g����B��x�o`���B����tV���W�YU���s�x{F���2�k)�ro�W[Z5���s�x{F�
�����YZ����x�g�N��.���x�o`O����J����Z�����<!q���z|rPZ�����Kc(n�_CmU��!��B����z����\���[qk���k����������U���Ai�~�?~+�����~
�U]a�e���g�3�]A�RZ�_��_�Cq;���`�e��$esUXSJ���|�Pqq���k����bH~�nRVWumJi�~��(f���c(n�_CwUw�!�a�������M)-���|pTqu���k(���0$?MWt>���_~���r��/�����~
�U������l�jB�����~��1���7�W5!�
Kd�i�3����I�_����~q{���k��2���EF��=�_��,��x�~F��>��v���W�WX##N���oA�-����g��d(n�_Ku �
�d���3�=�����S�E�=���-����+���b���D�=%�����Kd(n�_Ku!�
�d���3���/��93��-2��������m2���"�^���f��{d(n�_KU��}2���!�Va��r��G��v���W
�W�'�l�����x�U�y�`_
�i��]�%cH�}��U[�})-s5G�]�����w54W��Rj��M��;�^�Kq�WU���>�>�����y_J���l������'�<�����O����j��!�%����j+�/�e��=f�����S���j�aHa�����Z���_���-�R�N������!y�u���j[�z��_e��6@_��)�P]����<��E�]����2�������S���j��!y�u���j���r?���#������7�-������#O�nQ�W-"G��W�WtB�]~���vp�X[_%$�$�*����S�_��<����%��W8,~zL�8w����c�-��Y�_���
�o�W���QoA�-]�}����z��"����6����~�'�������k_����{�+~����D�=�U>�y��o��]�}��wl�'��)���g�{!����gm2�}�.��v�;�����W|�3�������V���=�}��wl���
�+>�)�"�V���r�
����}_;�[oC�m��OpF�
��	�����-n���������9�ofa�'4W����9�o>9�����\�o���'m�J�a�n���r'>����:~�S=��9K�G���_�
��+fv��OpF�>B����`���z�U�?i���)��H�����]'>������C0��i��Y
<�u��z�zf���:�	��7�X/?�������v�����5SV?G�0#?f�yUe�fsPo��`��f����2�I{���Y������]�U���a���C0u}�[�����O�{�f����2
�e�W�V?���������9�v�����5�V?gD���8q���z#ro��w�����{c�{_��1����+��q�~��&���s����*!��.��8dcl��WX/���23�������U��UF��]�}q���zr��^F>-�QoA�-<�����?gA�-]�}q���z�{��2N��2��������������r��6��{ �
�e���eF�'r��s��z��s8�����/�[���+��q���)�"��<�����oY.�����/��[���+��q����^������yoE������x���V�^a�������"�V�{��UC��}���V
�WX/��o/3�m��M�^mk��{[�{
��[�{��2N��2�^��R�O)�#�up/����bh��s�Q�^����zp/�e���{����{)��^Ck�\�����^f��W�W8�Uv���R�{�����3J��l��H��<�j���.�G�v����c�]�(q���r+p/�e�Uv�.|t]�}q���zp/��^�P�V.�R\�^e��6�����/��[��K��z�����{).S��sv������/��[��K��z�����{).S��sv{�G�����Z��bF�{��3����������]D��}�5�V.!�F�{��3�M��������]B�M}���V	�7	�+���QoF�M�*;g��{s�{������Y�^����zro��w��jU�{K�{���*��E�^����z�{����G
�@�-]�
���@�=$���Vr��s��7�~O����R[�������D�=�W/��=S�|�.�Kmu!�^�n���B���W/������o��V���W��;����[y������\|k|���j�U�M[[5�����D��� ��.�Km�|������~t4|?>S�Q��p��Ai��j+�T�(�G&����G�e~z�O��OJ{��P[ywbFa������������|"�=|rP�[������`Fa�������������������O������	2J�d6em�Wp���W�D��������a�a���6�_�����R\�^�A>:T����n3J�d������R\�^e��7P���^��������D�]�Z��W���y)��Q������5�V>.�Q�+���Qo����tQ��7"��.�n���G�^i����zF�	�7
��|b�ro�r�fh�|B�������*#�&�{��k������ki�2r��HF�1�^��,p��W������ki�
r��Hf��V��������@�-]��-����+-�������{��+~��R/r������Z����"�]�Z���'��������g�{wKku!�J�d�-�3���{/�{�����{u�w��V�WZ%�k[���[y�����"��.�����"�J�d���j��U�o���sC�m]��-�UC���(k�uA�m<��_�&��.���^���Z������j]|).S���Z��������Z�/���U�V����L���j�]|
���|)4W���Z=�/�e�U�V�o����k���5`F|�S�����92R�V�
�Kio�FCm������j
���K�1
}Ma
���^���Z�3
�+��5��
���r�������R�{���j�*f��W�[����������;�/���k(������*��5�R\�_�E�kD��]����j���Q@��l����y���������
����}���I�\%d������5�f�����h��2�o�7
RWo����>H�����?}��o����������������O������Du����������w���������}��??�e���������?��o�C�
8j��o������?���������?����p�BL�
e_�Y����P�}���0�/�2+�W���[�����8��Bs�*������m��QL��]>��S���/�0b
���l�N#�i�v�>��U>����+�����)4W���8�8�������|��!�z
m_�a���W���Fn���\}���|��!�z
e_�a���WY��Fn����W��N��m1�k��#��\���/�4�p�F�E��� D���1Q���/�0b
�]SV}���4�/�U�A��m1�kh�#��\���/�4�p�F�E��7�CB���!�z
E_�a���W��Z�i��6���z��7#���S���
�Sh�^mm����m���P�{oc��^Kk���)4W����i��6���c���7��@���!�z-�#��\���
���0�/.1}��c�=�{oS���-��"���y�bF�8�8��Q��`4����6�����V8��Bs�j[+Fn�������Vc�����)�T����Y���W�Z�0�pF�E�	���!���S���
gSh�^mk����m�����73�97���b���Zmro�pJ�f��-����WYJnp/���kh�6�0�p�sQ�V�����9��������~
���fnp.��j���-��g���|)��_Co��3
78eo��@��3��3�]})��_Cq��f���/��j���3�3�
��������B��<��E�\m���~�DzF���g��_���m���\���j��~).����z�2��}�G��_���m���\���j�)n?��?���������C{��CJ��l��~Z��(�����-"��.���P_m	8J������x/���7!��.����_%�$��M�7#'���FF��]�}��a�oF�;m�U�3���[�K��b)�
p�i����������_�X
���i���X�O����_K�u"���:m�u"��<��W�g�{!���Z
����W|�vF���%�����v!�^}�u���"�^�mU�+������V����_g���o��i�����x�oe���!��>�:K�������j�����W�o�|x���������S���X��/�'�o����W�o�><��\��~
�����)�gF��������_��|c������g��a�8��Rf���~��c�
(��_e��~x��k��vPL�?3bmF�8�x�M(��_e�����{���j�	����W�_�8�x��(��_e�o>:������GSj�_e�����6���:���)W|vhO�6X;�(��\��k���mF��+�}}���S0oh�vRL����
��C�����/VVX{D��'~/�Pa�8��Rs++����)�_���)!���l��vSL�����)�oc��,X�2B�m@�{���Sj�`m����S����l������--VA
.�3f\��O�.h�������Rc������&�����N|�fF�'r���`o��N��S�`q����O��S���-:N������Rd]�����������/���O�.����`K�U��/��Wm�U�������T��+���&�"W���my3
n��U�`mU���[��WK��������,�	�9����2\��)n�`C��C
,N#�R0p0��~��]tt�]��WC�p0��
V6Y�S\�'X{�w��]��WC�=p0��
V6Y�S\�`e���]��WC�W�`J��MV\��).�+Z�����������a��e�p0��
V6Y1S�N��&+nC
�MV���).�+�����#�Lq�L��o���{�/u��>��9�2+�+v���g���!��)�������c��/�(�pPVY1S\�^�[�1"�.��%zl�18
�EV���Q:V>k�	18v1����c�M�I�����Bp�!�o��f�������@��7#g�����fD��#�/�b��[�s�_��<���\$�VX��k;��\���1��z��"����:�8js>�.��v<�����W<��Q���{��+^���'���=~�xp���������z/��S8���pp�r��?~�xl���%�����*��%�������~+�oe^6��"�V�|E?�_$�*��b�!�V�"�a�
��	�+���6D�&��j�M����v��M��L�>�)��������U�D�p
���k������IXH#��5�_��+���p
���k����Q��*��5�_��+Q�	W�P�{���*�3��x��,��
���~F���W�P�{���*�3��x����P����,�"��/�����~
�U
3��xe{?��m�~�Y�N�U���h(��_C��3��xe}?���)��~~�n����{��*�3��x�>�_�o����� �S�K�������������z�������������_~������������������?���O?�������/�_�
���/�F���������M����o�����?���q�OD��M����D��7��0�����/o�y��{t��u�����&�{����e�M��N~W6~y���,\�s������&�{����e�N���M~W6~9��mn�9q���~>;�M������}�,�o���_N���p����f��s�(��_C���B]��7���/g��Y�K�����
9�`��Dy�*��W��0�I>��Qp����tN�0�`��Dy�:�����0�����/���9q(���qn��l(�2^�����_^hU-�F���:'e�R0�m����
�_��uY�������'2�p���C��s�(��}C���j]�7yq����/�`�R��2L)�6Q�{����eaz��(�"�����l%��&�{���b���,
o���!����#g�0�m����
5V��uY�����*|~�Z�K9�bqY������5�X/�Qh�_e�U||�Z��N�]||P�{�����:
�������/���Kg��������5�X/�Qh�_e�UV��E�V��%�3�]A�R�{�����:
���,�J�Z�ku�;��7�C���~
V��u�y�I�a�
������S��<>�����Pa�\G��~�V����Z�@��y_��u��C�U�r���U6Xe�Z�ku���)?�{�g��sV�+f��'e�U"�o�������~�D�����`(�JB�����6��7!�&�������S����J��I�_����f��$���_�c�����R`e�,��n���p������-����R`�"p�Xp��������G����:�	����|�,�:����p�X'�)���:�O��8=���������/������/�u�/��`K�U�/��������S�[�k��+��<��~�p��?x�����/�m��?~���/��������_����E��v"�n<���E
'��8�o���&��^|Iv���g�P���vC�w�3
�p>��v>�&(-S��;�����z
m��3f�aB��7�^`	J���-k��Cq����c�8�98�m�������W��8����5TyG�8�18���� 	J���m��Cq����c[1�0�c0��
@����=�<CJ�~Ci��z�cw�Q8H������9������t��J{o���{���1��`l�1`��)��-�#�!���k(��xaF���K,c�MH�Q�D�}��HH��O���HH�I8C����z3Ro����$���f����������z�p������"�f�z"\oA��]��-�UA�-�	���*H�E�A���q ��.�����@�=�4mgu �<����qH�G�zwKgu"������:�zO��I������{v�w�tVb�)�U��B����'El�Q���{u�w�tVr�%p���������"����"��.�����"�V�{���f���{���"����!��.�����!�6�{����=��h���6��s���{���Z�����-���:����\����z]�G����Z����A
���l�N����Wyt��=>��J�hh�N)4S���:=|rPZ�^��#�����n����\a� �f�U�V�
���r�*[�s������
��V���/�[��7�1��\�����L)��^Ckun3��K���3����RZ�@P�Z�������5�V��0#?�Tl9��}�z���O^�[/�����z
���_��\�*[�3�RZ�^eku���{���Z��WX�����{���6���vP�{����L������m�ro���^������{���Ze�^auG��V�7��`+��zqe���ki�
r���#h[���[�}��`p��������Z������m���C��	����:(��^Kku"�
K;���:�{O�{��.����z-����+�������B�=%���V��������Vr���#h[���{	�+b��zqQ���ki�*r���#h[���[��mF���������V
�W����UC�m���6��kA�m]�M���Z�{)43jI�Z]p/���U�V�[��u�7Z���Rh�^eku9�^J���l�.W������Z]~��<�n���������W�Z]�����5�V��0#������V�^J���l�����������Zf��W�>���b����6���Kq��Z�+\���^qL��z7�^J���l��
�����5�V�v`F�{�!�S����\�����>�.�fCku�����W�Z];p/��^�V�VW������
���{���������Q�^�f���{c�{����ro�W�Z]	�7	�+b��z�{S�{��������^q���z3ro�W���f�����li�
ro��W�=����[�}��il�������Z���s�80yF�ro���v�����G�{-����{��+L�Q���{��`���zO�����n��V'�����81yJ����v����B�=���Kou!�^<��#�g�{!�^�j{���{u��-���"�V}���3����UB_mq�}k}�bi��o��w�6W
��	��`���~�}[�}�b����
��������WY]�>=(n�_CwU������]�]U���W�]U\$Cq;����O[������z����\�����&�����^U_1$?[7*��������A��<�_\%Cq;���������U
�N)-������K��v�5�W5�O�����p����W�oT\&Cq��:CU7�Y��2Q�_�
�)���U���P�N�����0�
ke����;�SJ����7*.����~
�U�C�v�����7
�+.^��/n����~
�UM���f����jB�M<�>��<v�\��2���������j����2�o���������N�����_e�_a�L��W�7�������~q����k��
���\&i��������W�W�*Cq;�Z���W�.������{���?������2�����:���2I�_���'��Y{�z��2���������2I�_]����Y{�z��2�����W�WX0���UE��<�������e(n�_K���
3�	��~�o��7k/\��Z��v�5�WmA�V��'4�m�/�e���xal�m����~
�U[*���W<����[�_���Us�������j����*����)-����j���v�5�W�)����j���2����S������7Xm���p�3
^�)-W���j�����74X-S�OH� `J����Zh��6TXm�G`��(x��\���m����S���j���<�pF�;00��
��Xm����WC������`��(8"G���m�ZD
�}
^
-V�H���`Q�(8!G������bp�c�j��bp�1X4�3
���I�-��:������Zz���yU���������[�S
.��������*��E�`m�U������k�S
>��K��WK�u k��9�8X�'6�`��������:����e8��A�@X�)6��A�D��7�����J^�>�Y��YX6�3J��/���bSJ���.��Ezl�Q��QX�3����U`a����~+�p���k����$\y�}��~�pP�cY�m�!�.��%zl�
1��,�����}��gG8�c�1���p���xO{k��o�#�}KtbDa�hg��~�������.��yO{k����c�u#
��]���B����>6c���3�io��v
<�]� ��f�XoaNh��S2���=�{����?8���a���4���zS��������a���oa>;��$��
#
�x]{��.A������al��z�=ng��a�����$^����������|r�0�_�=����a����I�NW[������|r�0�_X>��sG�����I�NW[�}���/?$��S2g��|c�|_�1����+-����~�o�W��9������������&�_i�������������7#��.��8�cl��WZC#���f��,,�P�������������_i���f�[��$B�p�-�o����c8��{ �J�h���:��W�������:��U4N�_��'�����c����{����_]���&���.��K�_q
���W������p��W�D���UE��������"��.��8�cl��W�D���UC��<��w�~~]�]����c8�����M4^�_5����oP~A���|v]�}q��~v.��H��~�������x�
�����u���1c�u����W�_9�Kq�~�_Oy��>�.��8�cl�>`F����r���~��L)��R�{����3
����[�)�g����W `�{/��`��`F�����r��~F�L)8S�{�����%V6Xn�X������R�Ly�:,���Qb`e����

��3`q���v``�{3��a��`F��We��v``���W���W|v]~q��~#2pX��3����Q��`W��_�	!8v!��!cN�I��UYb����;���9#�.�8�cl�)8	�j[����[��/���A
�]
~q���Rp(x��X)���@C=v�t��c�=��������:������!�;���.�8�cp�H��@����:�����U 3�@��g�WK�u"���
�B>%���B��li�.�K`m�u!_�%h�w]E��l)�*p�X[`U�*���xF�
��v�7X
�����
��!�6��U�S�E�m]�
��/>A�o���|zP�~�M��7�~=��y�{���_y�bFa�PP�W������{p�0�_�C��������aFi�����>=(.���6����=��y�{���^y�0�0�WD3�]����|�G�~a
�{�{�����f����g���R����L��������~
��f����g���<���yEyF����=��_C�����A�_�
�)���+�3��4�q�����?9d�V�e�w����_�!+V�����k��|���&����|D��<���$S�_�������_���+-���~�o��������&�������_e�_i����2�o�������f�������_e�_i
����
�o�C<��?����[���Y����+m�������[x����������f����C��M�_������3V���{v�w��W'����f��W'�����x8=�������f��.�_i�����.����_�pzJ������f��*���}f��W���������~�k�-�UC����l���!�6����S
n����k]��4���Z`�����3
^ `�{+x74X��0���U�`�.`�������)��`C���3J�X����)�g.�O)�S�{��k�fX|�kF�+00���
�)����^���Z����%��S��\��Rp�����Z�5Sh�`e���`���:��m������Pc�`0��
V�X�Lq������u�����z�u_1����������+X[T�;p0��l(���0������G��(q�z�98�9��d�98J�l���������S��-MVBNk���������s��������Y�`q$���rp�9��U��������h)�
bp0X�?�_���c������=��K�����:�������f�{ �]h����D
>�-=��|
,��5��)����O�����Rc]�������^���M�)�^��W���������������Vd��3����kE�]���"W��q3�m���G`�&��~p�p�tX
	�	,2��~����'`�&��~n����~
VX.�(�#RVX��������S
�u4��^���
����<"e�||P��(�)�>�{+8*��adf����/t�(������"�R0������
VXaff����ot�(x�Jq��`�����h(��_C����Rq���~T���ils
���P�R��+l+f��H�o�P)n?]R���h(��_C�v����I�a�*���}|[6���P�{��+�
3J;i�V�+��������	/|�FCq��:�����4I�a��v�������6�X!!K;i���J��I``�n�p
��li�22���F�3����~0�pp��������XX�I����*��E���BR�}4��Vp��XB����em�u ��uM�i(��`K�u"K{i���:�Oig�:�H�g��������O��������/ii��U��;i(��`K�u!K�i��������5B�.G��4��^�������jq4���rp����9��P�{��"�!K�i���j��M�`q/����9�u98��m���q�
��`�����������
M����)4W����p0��
�~�l�>�>���Sh�`e��y�`�������+>�>��m]1����&k[��).W����V�`�{+�-�*kC� ��xS��k�R�a��i��em�aH�������m��y~����7a��)��em��!y�����v a����+CO��@��v
6tY�~`H�������H��rW:�g�o1�����[]���#O�~QvY[D�<	���N���n1tY[BN<	�E�em	I8�$��U�-8#�.���ee$����_�]VF�<	?q��F�]v���*H��'a�h���$\x�^y��V���.�@.k��A��A������{ [��1��0X[e����p ��b�v"�}v�*�D>v�*�B>y~r�4�3�B���,M��|	,^.�R0r�%��o������W��������U�`�r���+rpN��7�f���k�����j��M�`�r���rpN��W�&�����)��d�����}5�)��}����w�������{��&kwC�C��S6Y�������f��j(n�`C��{�!�)E�)��������q3
�E5�S�����C�sz��� R)��Axl�����v
64Y�Z1$?��;e���fh�/��(�P�N��*k'��'���.f��H���y9nF��������&k�
���xe��o`R)�g��p�;n�����
U���4�]ZX#^����&�����g��7�P�N��*k������U��#����9#�>{C��'aaa�<�fF�	A8	 ,��<�C7�P�N��*+#k��VYA8 ,�7�`�TCq;[��� ,,��^[e�"���Ihc�U5�S���*����V����"���v���qW
��l��aae���*�D>$�VY����v
�TY'������[0��)�����Q0.�����-U��,���^[e]����������{/x�TY9XXZ�Wm�U��+�����)#�>��&�![k��m�rp�9X��;�`�WCq;��� kk��l��Lq?s�wB�q����
MVt�8xU6Y�S�����Q�����
MVtC
�*���W,��`�V���=p0��lh��?1�������+p0���������S����k���3{�Lq?s�wF�a�g���o���{�/u�>�(L����eV���3{gt�9|v]~�k��z7a������� Lq?�cp�
�]�_�=��=`D	��EV��)�g.���w���z_�
=���1�����F��(@�x!pF�!8v!��/�c�M��Q@`q��z"pX�8�����������"'��3���I`e	3p��k��c����Y�_������,�������t���C�����"��8�wJ��E�_�����t�_;[���{�+���Q���{����{"��#��N���{"�����kf�{"���jO/�'����l����{
�+�������{	���p4^H�s�����{I��-�*�o�W��=����[��_�~�o��W�\5d�&����j����k���o�wSVWi�O�&��x�wB�	W�P�{���*-3�c�������O����3��
5�����J����T"�)�������~���~qA
���kh��/����7e{�<|zP������/�����~
�UZavf���MY_��)�������v�{���_��3����o��*���3�w������<}��k��0#?��o��*m`O)�g.���W�P�{���*�3
j6e�v���3wwg���i(��_C�����4���J���~����~q1
���k��RD����M�_����o�����P�{���*%�_a;����UF�M���t�0��{i(��`K�����4^75�`�,�����4�����*��r�][`�"�����4�����:���4~�X�!�����4�����:���4~�X'�)����c���4���������4^�8�����v����J�{3�R`U`a1���VE�<����;�J�{/��`U$`a1��sR.�!W����?tu]��4��^���j��Z�+�� 7���?����R�{���*/3J������Kq�z?>>[�[��u����c�u@���7*����~).S���Gc��]~_�1�^�K��z��U����������6|t]�}q���z������*����3�5N`���R�{���*�����*`_���g��})��_Cw��3
���U��})�g�l����Kq�����U�(�oTvWy���p�+��8�������n�����Q`����r����y�qF��7v�7��~������/�o�~�Wg���~c�~����	�7I�����o�~�Wg��S������Y��A������E��A:���+������������o������?������O�sW�o�����������?���O?�������A����c�*� 2��i���*����a����G���q���8�'��,���",}_��)UF��}_��)UF#�:���h(��_K���wJ��$m����5a��2��~��8�u��C�W�8�H�1I��<�)�q��2��~�<���c���+xS����l�
���<F~tF�x S�2���<�)��LR6~d�p #�:�����{"�_��"��$e�W�D�H'2���3����?���_��"��$e�W�D�H'2���3����?���_��"��$e�W�D�H'2���3����?���_��"��$e�W�D�H'2���3����?���_��"��$��jOd�t"#�:�_<�)����_<�)��LV�WOd�t"#�:�_<�)����_<�)��LV�WOd�t"#�:�_<�)��m��
�/O0�<A<�)_������3�g�?>�X?<��#?�����?,�Y�
�=�����t�1�o��4!�9�m����O�6�D�8x������i8��S���I���TN���O�6�D�8y�����B�8�_|���{!L\}���y�������dF�Y�XB|�yF�Y�vYb�tyY��,!n>�R/�DP��������D���n���D�YB\}2���(���]����~um]��
]��KPh��n��Gi��.l���v>��I�nh�0�p�������4J����:8H���z
E��=f�>��2�^�Ki??op������5y��`F� ��{,c�]})����
�w����~
/�k���A���X��<�+���S�qh������54WG81���A��
�����=������n���^���:�������R�~�#��������k(����Bs��(���RZ����3��S����u�7z�#"�F��r��7���`��������
���|�����H�I_�z�o��o��V�7��+n,�QoF��<�>82\oF��]����� �f�{��E3�-��E����h0������h��
ro��W\X4������+�����{ �]�����@�=x�����D�=��#��D�=��-����{��+�+�R/r�)�U~;���{�.�FKku!�^<����f�{!�^��Q��s���{����ZU����x*3����[�w'�1�S�E��}���V
����+����!�6��Iq���z�o��o2�V����WY[�}U����_	��|tP�{����t3��[Dk?�^���������G���k��N�0#?�E��3���m���Ac���������5�V��0#~�|����:Wp���	���yiJq��j�s=0#��/����:8SJ���Xk�7�4���z
��2fDs��dJ��L)-��M���n:S��P[�L�����Q����~-��>:t�T���:w,H�?�g���2��i���{�G����5�Vg\1#��/�U�VgD��<���n�|s�������L��_q
��z�o��Ww3��������-�UB�M�jk����x�_a��52ro�ro��V�7����
ro����z��������l��
ro��WC3�=�{����S�=�{�.�fKku �<��������{��+��8�����ro��V'r��s�8NzF�'r��s�x�`�W����ro��Vr��s�8MzF�r��5q���{u�7[Z���{��+��QoE������_�c��5�^���j����q���zro����m����qM���k������C|�rB�����x�U�Voc�}t�^�����3��+���Q�������6.�Kyo���P\]����*����R���K^���v�54W��R`_esuy`_J���=[�Z=>�.���P]]+�/�����w������	9WX��u��-���
����2���Ki���P��u��-����V���8>yF��/�e��i���6�_����P_]���<�w�g��SZ�lA����v
6X��0$O����3
��	�������H��K�n14XWD�<��[��7!G����oBN�+!'���.g����O��z�	83l��2p�	Xt�S�E�<G���� �>;K�U���@��� �������@.}v��@>�6X�����>���>;K�u"<��g|"�<���������g������O������/���'���|!_}v��B�x'J�(�"_��gu]�k��������G`�CnF�
�J����6D��G`g��"p�X����o]������;�+t��2��������!��C�G��~����~����~q����k������UX4�Vu��Ai�]q����k������U�4�V���Ai?�v�����f(��_o���
C1��iF\D2���)��.qh���b��v
6tX5�R����j�Ji�`�Kw�P�N��
�nC�3w����TJ�������)�Pa��aH~�nRVXu_�`~$�{r�c�W,�3Cy;*��_�����V�����������f(n�_C�U#"��q&)+��#�����)�������Pa��,��I�����O���� "p�������y���_��[������������'�@~��������O���������������N����c��/����N���8�#�M]����G�z�����c�����z���3a������{��gBY���K������c���=���k���r`H^�'e���J���%C~���k�����k.cH�������~��PZ�_q������g����z����P�O��8�`���~~0��~�]���j���
��R������](�'>=�|�]���j��ZX1$sM|=jF�����������Fq;�Z��9�_\����m�](����������5J�������aH��ZVv~mX�pmM����S�N�������8+K��)-S����C�����J��#�Y��ZK��`��^��~pB��7�����*��>Ed��3p�vX	8���j���3"p�"�k_�����3�Y�`e������c�-����}}�nA�-<��7wg�[�����<�]�������=�m�@�-�j����^�zp�il��������:�m�D�=��VW'��)�-�n�D�=�������"��<��7�f�{!����F����B���������z/����^�h����{�����U���[�{
������^�h����[���o����!����
�z"o���-���!�6��WY[�'>S��D�~�2����{h�_]m�����q�~���_`��{���Z���os���W�Y��9�_�����Xal�0��=n�^�a�~�����_��k���d���k)[��0�]�m-;m��u����Zn��Vo�"���okyeo���gw���~�e�op��Y�-���-���m-es�����
|~?����aF�]-���+�������t���zK����>�f��]��U�9]y������WY^������>�g����U�9]{��A�;����l����������Wo�oS���WW_��A��<�����/	��6���H�����{���e����-�o��wU�W��6���P�����{���e���*#�f��,\�/��m�����a���6���~��UA�-<����� ���=�k�{ ���>����:��Wuu ���=��kY���{��e����D�=�U�W'��m�����a�'��m����j�����W�_]���i��[��^�����_����.��������*��m�����a���6���7{��UE��<�u��o�����m�����_�����o��7h�+� ���=�l����_
�������Kq�~���[*>�>��+�V�(��x�mF����r��>�4�_�Kq�o��������W�f���)n?���l�������~
���
3
�+^a����b�<�>��7����t�������r�������7�R������������5�W.�Q�_�
��~�)�������|t]�}q���z7�_
�������Kq������n����������������WY_����2�j��������C7������
��F��(��������������r	�7
�+�`��oB�M<�u<J�������*#�&�l3��������}<�2�o��������Y�_�@f�[3��A�x������`��
�o�W��6�������i�����o��W��!��x�mJ������Q�x����G����:�O��l3�=�Oa[������{v�7X�����W��6������wS?���W�������U�_mU�+�������������_5��*����j�����M�_5�����`�����	
�+�`���_����2�j�+g����5�W�-�Q��+�`����O������<l�y�{���_��>����]���~����S1�l;�/,�y�{���_ybFa��x�mF�+�S��]���x��+g�������_f��G�S�{Jq���=�S~~a��{�{�������3N<b��o{Jq��W~?�~�a��{�{����o;d��8��uF��S������^���q�=��_C�����3�'��~w���I������W������k��|��QZ;���|D���j�������+���3�	��~�o��7>�w��oB�M]��,�UB��v��'�3�������'�����s7K}���3�	��~�o������������_K}U��3�	��~��O�����@�-}���W���yF<a�����{���dz��~O��������:��3N<a�����{
���v�?�.�����B���8��uF��������9c����.�����"�
�g�x�:����[y�}2�yl���v�w��W
�WX?����6��������c�m��������j����'��N�w]�������w]�)��_C�.'f��W�_����2�>�;�_�Kq������(�����V�Kq����]�wC�z�_
�����V�Kq����]�
����Rh�_e������������6|v}�5�Wk�Q��]�_����2�j�~��_�{�7��u��Q��]�_��/�e��~�h��)��_C��f�wW�W��Kq�~����;�/���k����bF�we�����W��2������
���������&�������eJ�	�7u�7��5!�&���UB�M<�>�4��2�o��o��W�7K����2�o����x��������h��
�o�7j����[x�}2ip��������_��E����������'����{ �}���W'��!�o��W'�������Hc�=��>�Z�����7j����^��>�]/�������_]�����Q�_U��K8�U����������_U��*�o��W
�����d���~�o��o��W
��	���UC�m�j���y����5�Wa��A�?���
|zP\�_��7�P�{���*8���3N|�zF�>=(.�������g(��_C<����'��7�_���W��F��3�����
k����_~xT�]��R\�|A{�U��3�����
�cF~�K��*����W{�U��3�����
����3��*l`O).��?9�_\=Cq�����U���u�������c��[S���3��o6�Wa?1#?��%e"�S���g��?p����k��BD������BD��<���[S���3�����
	�WX@����
	�7	�!��H�{����XX�@������Y��`�����s�����*H��
��
VA.�zD�#���g(��`K�u ;h\�VX"�!�GT?c��3��^���:���%4.k;��Dx�C�?Cy�[J�!X�B������OaC�W?e�4��^�������54.k[��|	+"��1n�����-5VE������*bpv$z�{�W�P�[�n�Y
AX�D����j�Ma�}�}[�[��b���H�Rs
+��m��\��w��������[e���P8+���
S\�am��9@a��i��fm�cH������<�0����Y�����
u��.R�ae�����9p�~�[��)n�`C���CJ0������`���-���)n�`C���C�0��xS
��).S��+��,Lq;��m+��a�(��m��L��w��}�g������v`aJ�����X��2k_����g������"�p�Q�/�:k���Q@��������c�������p�I�/�6kKH��'a�N����� �� �,eVFN<�E[fe����x�hJ�98�9�Y����y����*����`�����rp�s��TY9���m�u ���;'S
>���>;K�u k��9��9X�s2��9��s��4Y'r�)q���:��O�P�����o�r���`gi�.��K�`�m�.����`�(d�OpE���,MVE�;m�U��+���I�����+���&�!W�����j����`�$dJ�
9�1lh��e�G(p�(�&��g��#���g�x2����P�{��Pe��aH~F����h��'���~m��4�������]����"��]��6,L�C�4�j(o�aC���C�sz�S�Y�
.��r
k������v6�Y�z`H~R�w�6k S).��� ���P�N��:kC��z��.�����R\�a���;������
}���<�]�V���qg4��N��������qQ
��4l(��&j���/��;��|*��V�.��j(o�aC��V��'�z�u�
G��(���c�4��j(o�aC��'�aag�����pBN<?p���~qY
���ki�����������7#
'��\��/.����~WK������5^|wF�Y8,�����������v��YYX�Z���qg4| ����m�P�N��>�@��x�u�)
#�>uJ�����v��Y'���������h�D>%��`�����i��g]����/��;��Y�X����E��P�N��:�"
�k��6���+�p�Q��\�}h�����v���Y
AXX^�Wm����������P�/����?|�^�K�c"�������6+.���g����V`aJ{�~�[��v�raD��We��0���ci���H����}�;��~��^�MV�����W�ze�������k�����3F(xU6Y�S\�r����z|t]~����vW `����l��
Lq��^q����|v]~����z�/e��UVX1�R���a���P��u�������n+F�wUXq���_M��/�����1��~w�%�U�Wq������c���)��������0�����*���J����^E���?~�xl��7
�+._�QpB������NH��l(�bB�M����g�������3�of�D��������)#�f��c���[�3slXoA.���g�[���Of���Wp�[���X\�<��������#�#`K�u"m�u"�?��>�����[J�!� 8hK�!� �����_�W�6������/������H��@�O���-�"�>[j��\%
��X
)�
,^1�RpC
n}
��X
)�I����� M�`����������K�+-f���M�c�>@(.W��g	7�P�{��+9�����5~S�X����
�~a%���{/��c%�4����o�+y���\����$�WCy�����4�$l�����J+hT���m�������
MV
+f����M�d�"��rk����j(��`C��6��i�~S6Yi�Jq���MV�}5��^���J[����^�)����X��XQ�l2�`�WCy����_�����7e��"p0��
�6Y	��P�{��&+E�`ak���MV���Q�`�����q_
��lh�RB���M�d%��$p�x�dJ������_W�4Y9X�Z�wm��������m�)���{/��d�`ak���MVA.��M��\���\�������k��9�8X�o2�`�WCy�[��9X�Z�wm�u"���M���j(��`K�u"[k��m�.��S�`�����q_
��li�.�`ak���MVE���L)��P�{��&�"[k��m�*rp�8X�d���{/��d5�`ak��sR.�!7���MV^��[��
MV^��)4W����p0�e
��L)�-���lh����\��&+;�`���m������MV�+f88*�����)n?�
vC��@���^�������Ge��W�`��O������S�{��+�
3
�-V+��3�[o���z
Vf8*;��S�~��;��
�����54Xy;0���Q�`�
�����=�����]�~����;�/���U�Wy����z6�����u�7���}���Q�^������M)8!��.�C{��o�7*����}����_�9#��>�Z�����$���W�7g��_�)g����_K{U�~�D���� ��X��7����[���Y����[�g{�(�@�-����oJ���%���_H��@�I�_�H��p�`����Od�������:��O�����:��O�X��7��)��R�f��.��K�����.��K8��M)�"_]�,-VE�'m�U������_�)7�������c5��&pp��X
9�	,���S0rp�r�fh���
��MVY���rk����i(��`C�U����p"��MVq�Bq���MV��4��^���*~���p"��MV��Bq?�J���q9
��lh��������(���/���GN��X���3�����y��_��[�������?����������������O����������������W��|����e�W�H��7}���o������LDp����L���������>+��AMR����?�����C7I���`*%��
V�%�����y�J����C7I��a�����G�a*%���s������������?�~n��m~����?�
>��5��?�����|�g�	���	3���5����C
��}?�k�������r���C�!��Hy���i:��~
_���S
>�k�������r���S����H\��_�O~�������{�}�{��P������*��=��~+B�����N��~+"E�#��	��U����F�/"E����+�c�mH�O�"�!Q4a���_����(OO�(����)��_Cz,�m
�_a>F���8���2�j�������s��P�.`F~���X���S\�_m@:p��qNo�*��{�(T}|hp�8���~��c��������T���;�3
�T_\/�>���iOU;p��q~N��;���c���
.g�S\�`��j??n���`C�u�3�,���R0�>��\�xl�8���
?��

���(�i�g�S\����rl�8����>�~

����_���/�>�����P�g����T���:""�m��7E�����+X{��������s*��a	�6��Sq��q�9������^8����>��-%VF�
@����$����).W���h�}~�f�S��� ��Q�����������{7�_}~�F�����)�6���~�-N>����w�/N>?n���_K�u �����������kyg�����m�9l��N�����/
V�X8���~-�,8���M>��-5��|�E���S�����'����T����H����_���p�9�e#>8�������s��Rc5�����/�U�X8���r���'�8���
>��
5��|�kk�s������$�|�P�{���t3��S�5�S
v��Aq9H������{/�Pc�~����q����=|�P\�'X�(���	By�j��W���N�HN)x�X0?�������F�������:�3��S�5�S
`Q).W�[p�Jy���3���N�H�)4*��Z�c���=*l(��
F�Q�O��3��
<*��j�E��T*�Pd�;�����x�gJ�;xT�����:��E*l(��0#?CT|�gJ�98J�}�F�����lh���y_��RpBN�_�:rp�rp�4Y98	�n�2rp�8���[pF�]��&+#g���MVA�����\�li�
rp�9X\#9��9�,n��R��|�9��d������9#<?ymt���|t1�-�&�D>y��M��|������_��g��bi�.��K�$�n�.��K�`q��_�r���`�X��� |� ����� \qNi�"�.���e5$����8%vJ�
I�	$,����pCn]v����D�����n���/�Nq���u��s������
m��T����r���q:��.Vj������� ���
u��N)�����p:��_\~�0NB�n���6�Y�/R�am�u�$t��4��Gx���'�_��aC�u�@��}8�����}��
S\�`��W����14l���4L����}���)�'���)������3�Y�0$����)o��Cb��S�N��>��=��YX��4��X��r���o�];�0��4l����`H����OS���Q`�E��+"�>;C�uEd����x�iJ�	Y8
K��\��pBN}v�>+!'����OS���I�~������3�p�����YY8�,,^��0�p�Y8�Ek�oA�}v�6� 
��mVA.<
��oW���@.}v�.�@>VwY������$��@>�TY'�����x�iJ�'��������c�=��O��-M��|�,^�����|���f����R���`o)�*R��S�xmbJ�)����b��~+2p�3���X��,^���oC�<?�w�oCn}���!7���+3��~z4�����������v�5tXu90$?�(j;������~����~qW
���kh�����T�
Vu��Aq?qm{F�����v�5�W��8�*������z�������=�_\VCi;�����4�*�������`O)�'�lO����Cy������a�����������
�M����~qU
���k����0$?�W��:��
�)���}����J����_��aHaa����{�~�)�F���7�P�{�������!�Q��(�)�F�_�����3��E5��������W�W#Nb��oB��<�>��1�|���J����_���+��I��*!�&���=�_\SCi;�Z����+l�I��*#�f���G�����v�4X	XXW��
VA.<;1�����K��WK�u k���:��������KW�P�N���D6�$u�u"�<?�';�`\UCq�L��o���{�/u�>EaaiMRY��������c;�m5��C������^��������*r��s��9�c��]5�V�k_���[���5Y]c5���c����7�P�[��}��nC��du����p��n[�[�_��<���Sf�]m��@`���+�c�u>�.���yl���23�j��)����v+>�.��v�;�]�bD}�|���})�����v=�/��������vW�y�_����
�Kq�t���������kG���m�'����Z�.O��ct���������~��.�( ���j /��J���
���v�=2�w;0�����������W�����R����~��y�uR�I�R^&����-z|x���a��7���mk�"�o��UK����k��ZB�M<��c���~�p��n��o��Z�����x���M)8#�f��������ki�
p�	�-�����A�_�?�C.�"�����7o�����z������������_~�%��������w��?���?������������c��/~gx�_	�Z]���r�W��o��|�����#$V���C��t���S~o7��Ij���-�o?���r�t�������jv�ou���5e��/A������������������[]t�Q�PS6o�v(8�^�+���0^�����.�aF���r�[p
X0�v���{K�����e&;�������u���[]�Pp���Wvo�vxx��v_[2��|`F��:��cJ�e��3/w���{K�����}qn���K�����?�\����]���;<>���}qp����A�� S
>N(����������G��_�\2��9�8X<�R��|�����[�����/�.[��|
,�L)�B�x��w��� _]~qv���+r�%p�x2���\V7Y9��9��dU��*p�x2���\V7Y
9��9��d5��&p��6Y~�O��s��m�� ��Z�������]k�&�;���L��&�;�����
M�wf6��:N��	By?�0r���}��� T����>CF/,u���=|�P��6�-x�����
64Y~��qv��:J�+�T��������T*��d��A� �Zu����T������W|x(R�`C���3
[�E�?��
L*���a���7��^���������qQ�O)x�Jy?�0��D*��lh���0��s\��S
�+�/Azr�0����lh�|D��:J�	98����al�	98�9��d���u�������O����S��������Y�`u��������\��s�����*��E�`u�U������&�@.]�&�@>u��������'�
�F>�,M��|,��)���'��O�|"�]�&�B>^�M��|�,��R��|u98X��9�8xU7Y9��9��L��W�����`i�*rp8x�>f�%���#�k���W��}L���1���c~�M��� o��1h@�����?x!s��D(��/��������0��=4�3�-��p���A0c>V|xx��
6�&����
��F����� ���^���
�_�	����'�-��p���A0�n�����/�6C�`|�{h�`m�`~�{���[����mt;l(�p��-�Lp���A0c�p�n���`C�`��{h�w���0��=/O�|&48����T���0��=4W����`��{���5Z�����v�N��
����
���r����4�p�v��N��
f����
��Ls����4����������`��{h�`�klt����4�V��������`��{h�`m���L���_�M�mm���lh�6���+X�dm0��=�Wr�x���m�;lh�6����+X�dm0��=�Wr�x�����@�_���&k��������M�s���~%7��8x�Mt��
M�c��Csk��
�����Jno9�6��
64Y[D�o�&kK������7���|��N��-!'��7u����os�
oo9�6��
�4Y98�����|��nx�x+�����T���*��E��M�d����u���[A.]�-M��\��M��|��~�x;���.��&�D>��M��|��~�x;���>[��9�8xS7Yr��s�xzJ�r���`K�u!_o�&�"_<����\��k��������U�`u����+�����)7�����hi�rp�8X�d5���s�x�wF��� �����d���H��[m�&k_���2k���y|x����d��x��\��&kw�	By���M��|x����d��x��\��&k��	By���M��+>���hh��u����]�d�+�T���'^��R�
"���64Y{p�Q���k��=�I��L��&k R)��`C�������������3��K�S
�@�R�{��&k�.�(�P��M���I��L��&k�A�R�{��&k��(���M���R^�`m���_���������#rp�8X�d�98�,^��RpB�]N�&kO��I�`m��'���s�x�wJ�98u98Y������&+#g���K�s
F�]N�&� g�����*��E�`u�U��K�����:�����Q�d������&�@>��,M��|�M��|�,^��R��|v98Y��9�88���9��9X��;��9��rp�4Yr�%ppT7Y9��9X��;���\�li�*rp88����\y/�N)�!�>[������&�!7���K�3
�rp�rp64Yq��\��&+.����)X�d�����rp64Y���Q�`m�p0�e
�6Y�S�{��&+z�N�&+z�`���m������
MV�
3
��MV\,p����+p0��lh��zaF������8��2k����)��`C���N�&+n����O��;��
8���64Yq��Q���m��Ly���MV�=>�.gC�w�`
��m��Ly���MV�>�>�������I�d��y/��)98�9��d��N�&+&���s��Ah��~bp�b�[,MVFN�����y~0ml�18w1�-�&+#g���MVA�<������.�����n�TYA� ��U�� \x��Oi�@>� �K�u 		gu�u"	<	�'S������g��bi�Nd�S`��n�Nd��ga�d����/����n��Y��%�pV�Y�����{�>il�q����[,�VE�gu�U��+������#�.���i5$�*qVwZ
���D,�$7��VC$nJ����$��R+-�1By�����n�����
�VrCJ;l��Vr�)By��������������J�aHa�k��Z���0?WS|OnJ�����v6�Z�_R�����VZ��R�~<�E�)
���i��k�����)���A�R^�a����l(n�aC����L��E�k�b����=�z��p�
��lh���5���f��Zi�Jy��|
�-7�P�N��N+�0_3I{lm��v��������Sxp�J���
�V�+��,�J+E��(��x�)<�a�aCq;
�����M6���J	i8	K&���0.�����-�VB�V�,�F+#
'a���kZc�-6������H��.�E�h��,�[�n��P�{���h�aa��/�i�F.��	��q�
��4li��aa��_����4|�&�,�m�P�N��F�D��x�G^ix�>������_q�O�����to���y�?���������_~�w`�����w���������������}��?>!�_���+_|jy�_	#�*?�����?�m��S�X?�3��(>��O���0��%R�`���_{%�����*��+)��c>�-`I��F����-`I��Fy��$������|�j�����Rs
kk������r���.>���������kX[����r��������j�r�R�"�Mi��Ky�x�� z)n�aC
XN�!�+"���O����/�
n��Kq;
j�r6)�^�M�)
_+6���o�
n��Kq�
���\�D��#S��������KE�}^
5`���U�am
X*�p�y�kk����k��WC
X�pxX��)
7�����p�|h���<��<�:�c��\��N�X��)/O�in�������ix�Rs
k;��S^&���:\�������i~���<2�a<Ly��Vm�ux�a��i��i����<2��x��2
k;�c��_���7�����JNc�b���H2���b�<��Z�����c�������#
@,��~7b����-��
�����}����~�#
8,���~�)/����:������}���0L��~����S^�_m�uD����}��oD�
k��#"
G�Wm�u$D��E���D��7!'�E��oBN<��2+!�.�v,<����1dJ�18���2bp�b�k��c�-�Y�`�@��[����"� ����kG���E�-��2�������5���{���_;[��|,"���O����n�N���aX��|
,2�����O��������O���a�"�% �!S
��/�������slXpE��2���\���'�0���Bp��[Z���$
V�X
)�	��O6an1����
=��|�k{�s�����iT����>B(��`C�u:��9�^D�);���L�~G�-��G��lh�N�`F~L�QdJ�>B(/�5K�$���	Bq����W����"�L)x]�`~rt�>J:W��^���:�3�#���"S
�R)/S��Y���R��]C�u����^�%8�`p�������������w�`���
�vY�.��2?���������J}?E7,x�}J�+X�e�;�T���}\x�
��w�4,8��/l������#rp�98h��98v9��icN��Q�`m�u&���s��}`x&������u�-8#'���MVF�<o��gF�]~qV�������������rp�9��[�C]�Y��K��_�1���\F�| a����k�������*�@>��U�� |� �DF�-�D>� l��N�S�M]e��'��[5S����.	�8�cl���%�����.$��'a���9
#
_]~qR���+��%���.�*�p�Q�������"
�.
�8�cl�
Q�
(�����(�x~p1k,(5$��%��t��Z���@����^�0���G? %?��k����
e��T�(�������
�������~_P���6�Y�;1����2������)8}�+����)��`C�u����e����)/w$�@W]�~�+>�.
��6�Z�)4�����V@a�����������I�Pf]H�B�~����0��
��f
.�������������O)x������r���
H����t��k��Q �][f];�0�e�=��1Tu\;�0��l����`F�wm�uED�����y�c�H��K���e]I8
$�k��+!	G���5�3>��p��p��Y	I8	$�����$����(8#	�.	K�����D��.+#	g����0�����,UVA.����\x�>������`i���C���n���C�`uH:��.K�u"�/�N)�D>~����O���O��"�B
>
�=M)�B
�x
~�e{l�R���`K�U��/������H�U:�.�"�.o��"W�����jH���`�+YWCn]�,5VCnGm�U�i<?��C��������5�Xu91�0�(j[��������=��c���5��������`FaPQ��X�����I�FV��5�������FjVao�/Kct��By��|��0������
=V]a�f��x�R���W����k����p����64Y5�(�qo�Mi8�H��\��G�m7�P�{��*�n3
{\�KOS�@�R^�����6�;k(��aC�U�3
{\�[OS���R^�����6�[k(��aC�U���=�I[f���a~��{��pl�������
mV�H�����mVMH���a�d����qs
��7l��jB�������p�Kh�r�������ZqX�_�������YX.�}�����{/��h�aa��O�F� 
a�������k(��`K�u l|%���o����� ���+������������ o������?������O$g�����w���������������}��?>�F���f��+_<��]�u�������������O����G�L�e�����?��g�N�e��q6�$e����wM��~�u���^w��ng�2F��M��|Ks@��7.^{]`l�q�����i'�2n�1
M��|K����_�6y�I5������d�������O^�x����?���o�d�����6�����{����A?�����X��
�/?�?�H�S���
��?�7��K�7�$x�����7����E�0�p��@�<��0�`����<R�-���vw�������Hfv����6��v���~�7p��D��]]�~�\�[F��S8�} R��{"S���?��L���^�������
}��Lq	��<��~/D����/~~?��[oE���[�z�D�[F$�*��>Pc�����_��S����n�S�v4,
y�
���z���{�O��:��v���]Z�z
��[f��r�0�^��������~7uh�n���{�{��>�-
3
�.����X/���:��z�/���kh���0�p���&��z=�/���[1c��@���^��]��Hfq\\/�/���K1c�]>�>��+��R�O\��R�
�Kq��.�������P\��K�?qcJ����~~.��~��]�|���r�/��^���w����1��������P\�}���j�+��R\��Gc���})��_Cs�����j�+�}#���?��7v�7�+~#��e�)�&�������.c�MH��K���]%�����xt>�����x�}2�el��7w�7Y�����y�O������y�����[�s����*����_��|J���H���_�����\�l�����U�_������D>�l)�N���U]`�������D>��-��|
w���|	�����|u8[
��|�����\�7��eE�]���"W��VC�����O�K����-VCnk,���Gn>?���=�������k(��rbF~�e�X����e���@���O�{��P`yW0#��!h,�����r��������������>AF��~��{�������)��W�����!,���q�W?�������?�����7�������!
,f�7?m���S����}��:�������5Xo�Z��_����@�R\����	��@�R�[�n14X?�g!$��!h,��?�������A�R�N����C������q�������)Gd��e`�J,�����'��(@��!�O���n1�X>!'���-VB
N��7��g������O��3bp�1xS�X18�,���RpA�]v���*�����m��
9��E��A:���+0*�gd�b"�/�����/~�sc���+�2*o������3s>�Z�`T������_7�u~&���!$o_D{:�����z	����[p�Bq;���e���M[��
��P�O�
��Ca	�o���^�]�a�F�����_X��Q�ON)�y|v���n1���`��L���/8����8�R�_��u�':g����F�����������4�W\��u/(:gh���bH����m��
~��r�p=hx�
+\Q����
������Q���_ �(.������4pI��v6�!4��R���_�VlX��������7��Hy;
���]����k����a��\�.*�mx�7�(o�aC�C����Wy�4WM(.cx|���������s�6+Dd�����m�BD���z�J�)
'����ag��BBN<��:+$�����~�a810l��2�p�axW�Ya8Ko�=��0�pfh��g�aa�����
�p�iX\j9���0\�0�-}��0\x��}��0|0�����������Rh���m�)
������Od������g�������>�B>~rfl����gao��.d�K`au�u!_?�T>���,|�Y�[���,\y��:�"W���?��p�����Y
Q��(�mVCn
?�r<��mAn}��6k[�)5S����@a��|gm��-^�������!y��6ks����W����)n�`C��y�!y��6k������&��
S�N��6k�
C�(�m����0�����)����^�jh�����<
Gm��@a���k���0��4lh��p`H������0�����o�]�WC��m����)X�fm�0��~���g�^��WC�������iX�fm;�0�e~��ovlq�g�g���fmY8�,��m���#���(�c�WC��%D���p��Y[BN<
g�S�-!
�>
��6+#
'���mS
����Ga}�H�I�w������_�8�}����a������p`X�Pi+����}�[oA.<
�wc��{ 
��I�@>�$�������������9�"�(���G��_�
=��)��)X<S�R��|���B������@���B�xO���{!_������"_]~����~+pX]bU$�*�/���"�.�v<���\VWX
�	/	/��!��"O�~�����W<�����������VX�����k�c�uF����)�:����L�^�`�>>(og�e�3���D�?�`�b��W��
������v�L2,������*Z�)��O).W����W���sY����`F~��h�����rk�=����3\

�`�+�����Rp}Jq�����9|x���k�`�&�����R���rkK�}k����L^�1��=`F~��(����B���m����P)��`C��G��e&���RpD���k��������c�	98
������~2�nl�	98�9�Rd%���s����4����O���m8#�>[��� �y�e����pH�����
$��%�Gt�m� 	��e�?�aD�"���awc>�K�_�1��Q��QX�S>����Wu�u"]~qF���Od��gay/���O��S��U]g��g�_��1��a��a�-�>�B�$V�Y������t�m�"
_<
�E]hU��*���wi\^Cy�
[
��8,��q���j��M�a���������4Z
yX�a����j�qAn<?9U�C).���^������%�VZ�S������)��aC�]��;m��0�������O����J+z�a
�5������_�;�qu���8�����
����kX[i�p��2�������uq��9c3
8,n��p��\��g�1S�{��J+n3
8���V��)���0����S�{��B+�f`�i��S�O�b8��P����5�Yq��Q@a���b\�_�|��oD�]~qH��~#�pH�i������@��c�-8!�.�8�cl�	A8I ����p�A����f������Ree��,a���������<�����l)�
Bp �����\�3�<�`d��g`K�u �����:���H��-�@>�,5��|��5��|���%�����g��������O��������/����-�B��,%��|	,�j=���|	���_�+Rp�Rp��X)�
,�j=���\y
~�����Rp�Rp��X
)�	,~��))��������n�����
=VZ`�f�v���r3
N|�P^������Kk(��`C���L���U�);���L����.�����
EV�0N3I�k�W������2k�N�����64Yi
���+�j=��D*�e
���pg
��lh�R��Q�\#�j=��&��2k���+k(�����d�m����^�U�)o`R)o?^�v�	W�P�{��&+m3
�k��C��{,���]t��5�^���J�����"iN)8�I����R��k(��`C��"r���F~�zN��������-7�P�{��&+%�`ao������rp�9X~����eh�������TYAXX\#�f=��� �y�_a��0�p���f��
����F~�zJ�I��$,��<�a�YCy�
[��QX�\�D�����(|�(,��<�a\[Cy�
[��YXX^�D�����,|�,,��<�a�\Cy�
[��aX�_�D�����0|�0,��:�a\^Cyo
��>�B�V�u�U��/�����4��k(��aK�U��%6A]hU����������q�
��7li�����&���<�Vo8/����������0���VZy���y�uN�
�^��wC��]��m���0���;�Sv����������cF��E�;�a<Ly?�����=�0��7l����`F����V^��)�g�s���
<Ly�
:��V�(������c�k���)��aC�������V���)/sx��������S�{��J+o3
8�i+��S^�`�k�y_��ui8��
Sh�`m��w�a����������^������i8
4�i����@�O�h
��#�p��p44Z9!
G��7m���phX��SNH��K���he��$���n�2�ph����
g�����hi�
�phxS7Zi�4�������p��p�4Zi�4���i�4,J�)
H�G�����:��������4|���4����8|vq8Z�q��pX�h����p:������/������F�B������<|	<,J�)
W������J�"W��wu�U������c�sE�]N�N�!W��wu�����������!�.'C�U��������*|�P������.�����6TZ�9�(�����Vq�By?s,2�a�eCy�
*��f���J���
C6�s�)
�.�{o�PiaFa���A7���*�e>�8�uh������64Ze=0�0�w�6Z%�R���xQ�`�dCq�
�2fF���B�0���9���"]p�
��l����6������>�l T)�W���M6�^���*;��,�:�uV���R^�`�ZW�P�{��6��3��|]��Y%"
G������.�{+8�������6Q[f��$�x~�:���l(��`K�����6N��:��� �x~b:���l(��`K������6.�����y~":���l(��`K�U����6Q]e����`�����q�
��li��`i�MT7Yr��s�x�sJ�������4Y'r����Eu�u"�<��?���l(��`K�u!+m\T7Yr��s�x�sN���W���������J�MVE�<�w?���l(��`K������6��R�-�!7���Mn�����-MVCV���m��9��,^H�q�t,���V�[U��\R���� Ly�x6�-�S�N��*�p�@8i���S^&��2zl�8��v
6TY��R���� Ly���u"3
^=>�.��Pe+�0��
�VY�
 Ly��?v�c>�.��Pe@�Rsk��#S^���]���+>�.��Pe��!N�*���)/w�Dy���S�N��.����HX�e;�0��L�v�;�0��4l(���aH	��e�6,��~�:�6�#���6����Q@��m���(���s$d������:�pX8����,�x����m8#�>;K�����Y]ge�����pqgl�i8�i�Y���4\��>� 
�������@.}v�B�@>��B�@>x�����y�����4Z'��!�pV7Z'����������g��������O��������/�����;c����>;K�u!_gu�U��/�������������iU��*����j����a����p����tZ
y�I<����?D���4��;N�hCq;
:�s90$?��K�&5"����m-O�hCq;
:�����S�k�m�u:���L<mky�F�{o�:�����S�k�m�uz��������<q�
��4l����l��^�h;�s�Jy?}�gt�:���
��V�O�����:HU���;<���6�����:7�!�I�~�vZ�R��~����q�
��4l����aH~��_������0?as���'������
���_����m�uF�a��4�m-O�iCq;
:�3"�m������<y^����;m(n�aC�u&�aa��_��VBN<������6���������f���VF�<�s	�4�;m(n�aK�U����6��;��<\x�iy��yx�tZ�����;u�u <�7�;m(n�aK�u"�m�SwZ'�����8{bJ�����v�tZ'�����;u�u!�<�7�;m(n�aK�u!�m�SwZy��yXN0�a�iCq;
[:��<,l����_sF�<�d�4�;m(n�aK������6^|�kJ�
y��<,������ �>��N�Z��)5������a��4���/���C��7����WJ������)8W���� 1�eJ�V������H�������#
@,��5�_@Ly�~�/y\�����}����~W�_����
8Ly�����
8Lqo���Ezt�
#
0,��5���b�<��
����K_��.�(������~7@a����}����)�����D�w;0���K_s���_���=�����K������)3�����v�`���|�^�_:�oD��/|M�7"G��������/	�7!�&�����������+�s�E�M�#��N������+#g��O�����'��� g���
VA.k^	�0�-F.�oM)�@.<�w�f�Mz��slX��|,�4���X���:����q���:�O������|�,���|!���`K�u!_��M)�B
�x
��M)�"_��`K�U�����[@S
�����`��bp�����X
9�	,�4����x~2hxp�������"�.�����;@3
�|�P^���4����l(��`C�U�����"��);���_	&U�fCq�79MV�f����&�z��������Qq�
��lh����Q���j����X0?]Sr=�`�fCq������Q��MV
`R)/�+Z3�a\gCy�
��
f��m�U�T��5�}�Tq�
��7l���#6����m�U7p����%�}�Pq�
��l���6����m�Uwp���)X�FW�fCq���fF�m�U#�pHX�9�a�fCy�
������6>h��������h�)
�6�{o��fedai�MP�YY8�&���S�m6���������J����
�pVM��n����7W,}VA�V�u�u 
���Y	��P�{��B�@�V�u�u 

�/7�������4Z'����fS7Z'�������W�:�2�{/�Rh]H��Fu�u!
_��	q:��a\fCy�
[
��8,m����VE�k��Pq�
��7li�����fS7Z
q�I8�}��2�{o�Pi�qX�h�7m���a��4�i7��a�{o�Pi��bF�7m����
8,�N�������
�Vs'fpx�VZ�S�~<���{�ih�h���64Z��(���[pN�@���3����C^W|z]�F��@��kX�h�h��~�~���������`h�Z��\��F��a���Fsn���8�V�f��j��S^�]%�s��S�{��J��3
8�k+��S^�a�s��S�{��J�
�1������jq8
8,����pD�]�J�E��(�����ZB������RK������Ri%��$�����2�p�N������<��<,�VF��{��4�<���au�U��s��-�VA.��J� ����w��6| �>[:�y�xxWwZ��!?�0�a��������:��������<|
<�����
���g��7K�u!��;�y��^V��y����f��*��%�pTwZy�
<,���pE�]�,�VE�Gu�����t<�}��5�������i5��&�pTvZ����H�yX�J��}�������~���[�3�#�|e�����������~����x������{����-��������?�������(�������?}�����?���O?������cp������_�-���2�,W<
w�������?>W�~�G���o�5����?v�-R����6�������{��}�)�i{���(��a;������<e��~�9a����!o�6xz'�����[����m^\Z>��

�f���lJ���O�5S�v�-c��?���+��4|����i��g�:|z����d��|��C��0����)
�
�f
~�k����H������}�5�,��%hX�4���Sn<���H�������#�G�{q�����"��kX� �-
|�P�{�vp��aF�����4��C��~%��������7l'�"5�(��w-Ni�l�?'t���)
{�����
��f�����Oix�����	��;��u�����zj��i������|q�����
��9�weMi8�u����
��3����qqN� U)/��6-����C�J
:-�E������sqJ�HU��4,n�������C�J
:-�o�q��#xq)���w����iX��5���O��/�����q���}/n���pD�+_[|K�<�<
���bF�������4�$V����y8uy8Z:��<�NLi8#'����GF�]��N+#g����S.��Y�a�k�o���K�����_aX?z����W�[Edo�|������+��_��������PJTI������_qm�������)�O��Sx�B_�]g.����..i����^l���%���%nN��W�-,_E���������+�E������WD��GK��-����;0���d����M)�!Y�>YX��d��7�����E���������l(�VX���y�����p�*,�tO�8�-���X�{+8���y��f��)�-��1�*,�t���){8f����
��
�<�C3?0��S�UX���qS
^=>��)[2�{+��|�������W��UX���qS
>�.'C���6���L����-8��O'n�Sp�����dx_m�e�����\u[��
k<��@lJ�p0��lh�VX���)X�d�;p�*��t���)�����^���Za��{hn0�v�1`��_�x�B/v98��5"G��M�d�	9X�����aS
N������&kM��I�o�]pF�x�';����s��-MVF�����,��t���)�����li�
rp�9X��9���,��t���)�������d�������:���
�N\6�`�������d��������:����N�6��9��rp�4Yr��s��n�.�`a���JM)�B���-M��|������,��T_��9�v98[���\y^�MVC�w:q����rp�rp�4Y
9��,�j�QpX�D�����R3
|�P�{��&+,f������� ���-:�����
64Y���B
��m������-:������
64Y���B
��m������-:�����OJ������BJ�����)
�`R).����k���*��aC���!������)
P��kX[u�.��v6�Yas���*^l���.��r
k��	�T��i��f��aH~&�x�mJ���
��
��QjJ�;�T��i�Pg�����L����B��\��:+D����a�����#O����9
#
G���WE��,�,�C��p�aX��8���0��������fD��Ea�X���,�y�.N�7#gal���rl�I83$l)�
�pHX]f$�����b��E.[��9X�
"^\����|�,�8��/����~���:���� ���)��H�'O������FJ����c����^����~/d��g`����~q���ki�.$`a+�xkqJ�	��	X�n2�_�Bi;�Z:���+�/-����J�����P�N���!;A�[�SnH�M:�vX�������;;)5�����`�M������Sv>�>;C��9�`J�4�m�6Lq?q�h����*>�>;C���C�,�K���
����P4�_Li;�Z�muR�`m�����M�Jg���*�8��v6�X��0����<��l�������
�����v?Z1<��~i)���_��Ra��[cH];N��'����/��g��[���P�8;n���s�P��8<n���wyg���qx�.
���7Qw����9o��v�������S��q�0=N|Ye��g����q��������8�.��~���.�{0�ql�8:n���s�P��8;nf��7y�����vav���/N������7�;�����q�=�)����]�`���~+>������'����8���~qr�.L�S������q�������8��cJ�88n�i�������q��������8��cJ�87n��i�������q��������8��cJ�86n��=�?�_����9o��v��S�Ds:�_��S��?����?3����������n�ph�.�{0;}l�82n���s�����q�03NT�S���q�43.j�J�����?3��������8�Ni��������*��C����8�Z:,��S��G8�a��S�>�
���~qf����VK��C�vah\TwX84n�������qh���VK��S�vaj\T�X85n�������qj����VK��c�val\T�X86n�������ql�~��o���{�/�<t�����vat\��YqA�F��O���0�����Uzh�q�Q�am��a�����m���������4������:`a���������L��\�_��uQ����c����������@��2�~�kt��]��_�=��u��<'m�W�`������������V�k_���F�!8ik��)����\o���z_;\o��<'m����
����n��V�k��c��.���o�VXq���_K�;�/�����)��z�#�����U���k�7"���1�k��c������m�bD��<�>��ah�	�7���
�ULH��'��.��o������oF�M�5h�~3�o�W]\eD�,������~����96�� �f�}��UA�-<�>��c~�o�[������������{���dF��~���l����������N�����'j��{"����_Kyu"��<�fuyu!��<�>�O3�����_���W����oV�W������t���V����_K}U�+��Y]_U�����xG{J�
������_5����oV�W
�����dL��~N����{��*���$����*���$�{r�}l�8.����8�cl�8.	�����J8.	���\q�o�g��������x�$�����*�x�$���gO�����|��p����%a<\��W	��%a<���B��p�?��)��m����xs
��pi���kO�M�i�Mj�~
�U
f����E[`�
�)�e^��i}Jq�
�������m��6����)X�@�=���NIq���w�N����V�A�R^�`m�������� ��GD��#�[�V����g`q����2p�3���J	8��m��Bp�!���{��Bp�B���8����nQ�X)8�,.������s��_��1����y
v���*��E�`mJ*H��K�/N��/Rp�(X]cH���`}J:��.�8�cl�b�!a���:�����|"�]~q���O��S�`'}��)1���0�B>��� ��_������K�S
��/����\��.�8�cl�1�
,�F=���\V�
1�v1x�Y
1�	,�H=������`�/�
)��)��c�)�	,�I=���S�O�[p^��)��`C�����;m��P0�����;�`�{�a���k�Q�`����_�`��Mt����^������������S�O\&��%:����^������%�Yy����M4����u18���)4W����0��~�:���7�O�����d�
8�Bs_c�MV���)�g.Mix_��uA8���Sh�am��wa���Es����(]V�+fP�k���������)
Gd��e�`(�rB�{m���pXX�S4���0��0l���p`�����0�x�/Mi8#
�>
[���4���>� 
g������-� 
�.
o�>� 
�����*H���a�����q�tqx�Z��!��WZ��!����p>��.o�F�D>%V7Z'��)�������.o�J�B�$VWZ��%�������.o�J�"_��J�"W�dX]ZV������Ri5��*������ppX���!
�.
o�F�!
7���Q�3
.~�4�����n�����
�VY*fv���B�8���\<��q?
��l���;1���f��Y��'�e�i�9+�����6�Y��(����Y��'�e�=x�el������
�
uVYa�f�6���:���S)��R0n�����
mV	0P��j��m�J�Jy�x���SCq�����(�k]�eV���R^&�����j(��`C�Uv��u����*;�T���{0ovl������6TY%.�QX��UV������ww���.�����6TY%";k\�VY%!G����0������
]VIH����]VFN	?��3�a�XCy�
[���(,��	�2+#
g�EP�q�����{/�RfDaaq��2� 
�\��#�Kk(��aK�u �k�8�dJ������xu���p�7i�ZCqoGK�u"�k�8cJ�'��)����Y��qo
��7l��.�aa{�g&Li�B�~p9kp��������YiX�_��Wr�4\����\Q]X���{/��gU�aa���>�!W���!3.��]Cq�[���,,l�q�p��p�+j��=@a�{/�PgK��
o�:�X�)�W����V|x]��6�
� �Px��Y���_�+��w���$
e����)4W���:<�0��Z^�?|���GaC�u�3
(�i��c��_�+��
(Ly�
��#x�(���m��(Ly��W��(Lyo
'C�ulfPx��Y�(Ly��W��
X���6�Y�V1������:����_�?v�a�{o�Pg��%��YG������9�qh�a8va8��#"G	��u��#������'�����d����0���uVBN<�#,���S������Y��]]ge��,�c���4�`d��e�d��
�pXxW�YY��,��W�g\�K����:�������)������s��Q������:��wu�u"
�
k�'���GaK�u"
�
��:�B>�p����
_��W������/���TS����������6\��k��������U`aqe���������x�{J�
a�va8[���0�$V�Y
a�	���;�3>q�
��7l������6�)��w��h�\�C��~����q�
��7l(�Nc6Oi�M�Z����������&���l(��`C�u����EQ[h�>C(�gn�O���6������:W��9�.j�s�Jy?sKJ������6TZgX0�0�7j+�3�R�����?�a\iCy�
*�3T�(��qOix���0`S��?�a\iCy�
*�s;1�0�7j+�s�Jy?sOJ������v���:��!�I�Q�i�;HU������~���6�����:#����&j;�3"G���u3^>q�
��4l����<,-���N�L����aq�����S���b��2���&�;��@�y �LiW�P�N��N� �m\RwZ���@,�#��0������-���@,m�I�R�@ >x ~p�gp�����v��Z���&�K�����X\G0�a�iCq;
[J��X�l�����@|�@,�#��0������-���<,m�I�R�B�xLiw�P�N��R�"K�m��������aq#���q�
��7�,�VC�6��3n�4����p>��M��P�N��N�Z����6I�i�}���a���|���a��i��i]�cH��������)/������0��4l��.�`H��������)�g���8\�<1��Tl(�._1��Y[j]����b�.���W b�����j]��!"��V�
@���3�A�T�)o�bC�u��!$��Z�
����3�A�T�����L����Sj�bm�um����3�A�T�;|z��k(��\��b���)�g.������c���l]1`H������"Rq�M�7B�T�c�����bq�X��;���X�,���r%����bo��2bq�X�;���X��c���6���s������H�Y�bu�U���pL����*����Rm��"A���:��pL����:���>{K�u <{q��������������H|���[��������~�4|"��1��5��������Z����Ni�B"�x"���i������Z������~�4\��pmZ�2�U��+���V�!W���8�wJ�
y�	����S�GC nZ��8|�<{q������"���X������{�x5�ZuiR��+N��R�X1?~��#��T��n(o�bC�U��!�)��b�){���\������P�N��^��C
s~�Q^k}�����o�Jy)�����7�������_oA�������?������O�3��o�������+����m�����������P���1_�� ��w�!�5����~S�������}D�����?�������O���0��
/�5a�_�e`s����kxO^��C+�QP��S��
lx�	�������go���=�q>�b�Ey;������0�;m�V��m�5�'W��V���(o�bC��2^FBy��[��M�������W|z8��w������_jy�c��xM���l��n�M�'o��m'BQ���k2�	�m�&L�����)�0�I�����7�`�Eyo���z�l�?��N[��b��-�Wd���(�����N~�FFB9m�`s���=�!3�`�Eyo��ez�D$�&B9m�"�t���}c�aP��V�k_��>A�����PN��[���
��c���(����N��>A����yPN]j�a����1��QP��V�k�c� ��k�8�_#t>���w�����#��${�X}��KxM�����:����wO�U
.AQ������^�Ay���.a����uU��AP�����e�H��4(y����+��p��������
�@Q���'���^�Ay�����p�N\,=�`Eq;���
�&���^�e5$a����XzB����'H��
���������+X�e����'�{^����cv+>��B���}�p��=4W���zKsA���;q���������'�����O�����
VvYoi(X�u'���Sp��� �����(\�o@M)x�P���4Q�W9�������J}�fXp��Q��+��Rp�Pp�W��(X����������
���>����]�[�
����_�=P5��-���P��_M�,�bF��_����e_�`|�����1i���vT���4��'fD��e��&k_���w|�����1)n��"����.�G��(p�x�iN�����������c��_�y2�	&��$p�x�iJ�	98�,�*�RpFN]~q���'���������)g���s���tN������/N<�rp8X��4���\x�N)� �.�8�d�<������&�@>x��N)�@>������O�D>$V7Y'r�)p���:���>[��9�8X��4��9�8X�d]��W��-M��|	,^{�RpE�x��N)�"�.�8�d�D������\yw�N)�!�.�8�d�l��M���n�rp�9X\Q:�`� �.�8�d�tp��>m���`���m�Lzz�{/��d90���A�d9Ly���M��9O�q��,�=f88h�,���)/S���r0��=��`C���3
�M�[��)/S���r+p0��lh��Z1����&���9X�N:��Lq��,N�(q���rp0�e�]��9�m�������r[��o�*�m�����v�n_���A�Pe�@�Bsk�,�S^�`mW������`��\D���cm��"�p�AX�=;�`���`��\B���cm���p�AX�<;��� �� ,UVFN��cu���3����)g���`��
�p@xSWYA�� ,n��RpA.]�*� ��S
>�����)�G����:����S
>�����S
>���.K�u"����9��9X�7;��9��rp�TYr�%q������/���u�S
���W��-MVE��c0�\������&�"�>[���\�`L)�!7���MVCn]�M�_>A���13
�|�P^��A\6;�a��'��7l�����Q�(������������nZ0l�y�{/�Pey�`FaK�8cJ�>B(/�#�-+=,�y�{o��ey_1#?����.���i~�����}K*���6tY~=1#?����.�p�������5�y�
�,
f����='��A�R^�am����=��aC�����5^�V4��
l*���>R����=��aC����2
�k�8�hJ�;�T��5��;<��y�{o��g�0#?������4���D����G����aC����������4���O�N\�9���8��8�[��8,������)
g��,���MsJ�q8wqx�4ZqX�a���ES.����a'�Y��pA.]�-�VA��xqf�����"������>���.��J�@��xqh�������E3��q����n��N�aa���M)�D>yu���/���K��������%6^Z4��i��iX}�����.��B�";l�x47���0\yV�<�+�p���n��������C�����������)
7d��gaC��.���/N-����S^�am'�.��������Z���Mi�ylX`aq�����0��5
}��N�(��8�hJ�X��r
k�����)��aC�����iX��r
k�:���O����g�+�0����Y�
0Ly���-1S�^�����Z�0����Yk��\��Nz

�^����Z��gMix��\��Nz���)��aC���3
<,/���<Ly��K;�0��lh���`F	�����#����X��4�4
�����D��FkMH�����I�-C�M������>+!'����6S�����g��������s��-mVF�	��m���$�y~����~rp�rp�������� �_9�O�������������� o������?������O�s������O��������������������1�����KJTI���xNO���}�����?���������O�
��c�3�/��Hqv�"Y�������=��~>M�Dq	'l�g���Hqu�"Y���Hq�H�H��W$�*��3cE��]�H�b�"RT)�'0���DQ��5}fl������5d��3�{���i�������A(��`C��3�S`�'0�` �+X��<�F�{/�P��1#?�?������
�> ����6�z���� �/�M)����
��Kp#��l���
�
��D�6�����
�~�6�F�{/�P���bF~�8"dJ����
���p#���
o���aF~�p�el������w|�.�P�{��&+l
3��P���S
���)t��;.����
MV�/��OC�qN)8S\�`m�p!��lh�BD��xm����G����w\By�������� ^�d%��$p�����A(��`K������ �E�)g��,p���cO����~-EVA�������[������)�t)8[z�)X�	��{�)�(������6�{��Rc���J�U]c��������P�{���D6��/QL��B>�� ip������u�������� �;S
������b`*x�/����~-%VE����!W����3��M ������jH��>�U�a5$������C������_�*�m��L��
k[�).����4�_������[
���)5�����0�e����[��u��-�k�+�X[`m��~��6�Ki;�
�mu���-����~������v�5X��0$�A[`m!`�k���0��lh��paH�����6`�������)m�_C��m��X|�S���).��cC9������u�k�3��X|�s������=�t�����
���#O�A�`m	8
+��oam	8��*�-!'�����"pV�k���2p�3��tX8��VF�|�4�#8#�>;K�U������� ���_/3�-�������ad�"0���:�����o����G����:��EK4���������g�����:��O���c�)_��'���).�B���XB��C�x7�`��K�`�k�[E���X!��,�M)�"W��_��Bp�C���X
!����k�������+�����
=��l�y
��=���'�e��i_��q���l��v�bH~2����v� �)X{��+?(n�`C��{�!��D����y��o�y~�8�yJ�����v
6Y�o��v�i���wT@:~���&���}P�N��"k_/�o���E�@�R���2���>(m�_C���C�;?vm�����������J����c�L��������7�����][d�����v6Y��3wa���-��<*���6Y;.�����
M��wa���C2���y~Cx����c��WC��'�`i�����rp�9��/��q���4l��2����C�!��pF�<;�M�;n�����-]VF�~�?$S.H��'a������������*���M�6�.�d�"l����l����O����:�����m��4|k$�����D>�<�Z��y�xX�g�����GB��p�E5����������}5����/��K�a�e+;n���_���7�����J�+"���F�9�RrE$��/\�q[
�����ez�l�����dJ�
��	@��oe�e5����k_��>�� k����p��r�j+��S�[��}��F�aX����[�_����D0Lyo���5z��0"�����~=�0�����Y�
S�[��}�������2�_a����-����uA��c��Op��L��*+�����W[e����u1��C��O0Sf�_m�@0�e�U���^�P��#��Op���L��+n����W[c�����	�v"<��+f�X�	�R�Lq���-V��)o��$�����<�?"S
�H�Q `�E+1"G�j�e����G`�GdJ�	8
��h%&D�������������32p8�;�������+#g���9#g����*��li�
Rp�)X��RpA
.Ko��I�@
.��`K�u <�?"S
>���eI�D>�w�-=��|���=��|
�hoK�'r���`K�u!����9�8x�^�/������&�"_����\^�_��9�v9��1�!rp�98����\^�_��
9�u9��)�!rp�98k����H8x��,xl�	��P�{��&+-'f�gem��|�P\�`�)	��P�{��&+���YEY�d% �v�}�p]
��lh�����IXZ��MV��Bq�Yh��
	��P�{��&+�0S3	[k�YTS
^A�R��cK�u5��^���J!`F~`�8�jJ�4*��:��$\VCi��Z��y������+m Q)��1�%��J{���a�}���������
��2�*/M������54Xi�������
V�+�+�����al�������T1�W)"�
�j�c�)�&���������{j(��_C}������-��*!�&�~�)�3��55�������������uJ��7�$>>`�/�����~-�UA������S�-��EX$��K'��J{���]������uJ���!��P���pM
���k��N�_aY�|�:�����W�]��J{���]]H�����uJ���%�����%5��������U5���~+�����8�xF���������W�W�T#��N��!�V���3��5������j�����E�_5�����8�xB�yA�m]�
��*/�����i����R^�_e���g���`������\���*;�_�������k�����U�3
����U������W�_e�Ki�����z�(����Wy���L���*����������a���:m��/�e�U�W9�R�{���*���u��*o+�+������/���k���vbF�����;�/�e�U�Wy����~
�U�f��j����R^f�����q�g��_C�#�o��W�_���y�}0�{l�	�7����_����$���W9!�&����/�o���f��2�o��������y�}0�{l��7w�w��W�7����UA�-<�>�=����[���Y�����������{���`���~��������:�����:��������{v�w��W'��)��W�W������Q�c����.�n���B�������B�����W�����f��*�o�������[���W
��v�w��W
��	����UC�m<�>�=�_����_CU�������,��Ay�~��U�54������*.`Fa���W����e�U�W��P�[����*�cFa�������������
�����~
�UY�(��]��UYA�R^�_eUp

���k���Z1�0�w��W%x�W����
�����~
�U	'f������l�O)/����*������5�We+�Q��j����>��L�����J{���_�Fdi��������2�*���Kh(��_CU"�o�V�����D��(����*������5�W%!�J�hVmU�o��W_<�_\ACi��Z����+-�Y��UF��<����g��h(��_KU��=4�x�)������8�xF����������� �Jkh���:���������J{���_�������N����_qt��~q����k��N�_i	MP�W'��)����W�}������W����&������Ch�+\>Ci��Z����+��	���"�V����S�E��]�����!�Jh���j��M�_m��g(��_Cu,�����������2�*��c����~
����(�o��W�����xe�u8`�{/�P`�bF	����=��<�xF����64X�?1�D���X��)/W���:V@`�{+8*�c-�Q@`q�����)/W���:�������a�Bsk;�#S^�`e�ul^����:6�`
��-��
 ��r+[�ck����-���(P���bJ�;P0��
V�X�Lq�j�#z�(`���bJ�18��dM���#rp�rp2�XGB���,��������"�H������Rd%��$p���bJ�98I�m�2rp�rp�4Y98,���RpA����g\��K��-MVA.����\'�(�@.}�4Yr�!q���:�����Q�3
>���.gK�u"���,�|"������|v98[��9�8X�g1��9�8Xf<��9��rp�4Y9�8X\h1���\��(�"�.gK��������F�)7��&p�8�xF�
9�u98[����WZ�(�\��	,�3�P���h(��`C�u.f�G9q����|�P^�`e�u�:�{/��d�����L"'.��R��O���l�N�GCq����g���u�V�9�'��F�(���P�{��&�\ap�)l�q�Z�)�`R)/W���:q#
��lh���3Oa-��ZL)8�I��\��&���4�V�[U��������S�@�R^�ae�u�R��i��e�����h^'�����.��r
+����P�N��2������:q����c������2���4�����:#�������-�4�����<B�f�����v6�YgB�8q����3�p��Gh�,\NCq;
[���4,��q���9
#
g���}������-�VA��8q�����p�pX[h����i��h����'������<|<,9��0�������:���E5N�t1��y�xXs<�a\RCq;
[:�yXXU��]S���/��?�a�m��P�{���i]����'n���pE���7��j(n�aK�U���u5N�w1���<\y�NiW�P�N��N�!k���bF���<�x/��h�Z��)n�aC�u-C
<,����0�0�e�����������ag��.<L���������)/�������>�>;C�uy�aJ�5���.<Ly��?><�p����ag���u����/�4�S^�amZ�V�a��i��i]�aH����S����iX���<Lq;
:�+4)�������
�<,^���<Lq;
:�k�0����N����)/���������)��ao�������0�4��)/��������������i]y8
<,��x��-�����3D��������7o�����z������������_~����_8���?���_�������?������'v���1����=���l������������������n���q��DE�_��
-`E�_%�/�
��[��������NiM~eL�7��M~�L��9dJ�h��`���:�`����PV�U����7�U��7�������6��M�����9���&x�'�\Z1����|o(��&�|q}���Q�7A�?I5�b4��1���64�M2���)��o�;�����F����
-`C��$�/���0��&���7�&�1&�Z��&�I&_�"2�a4�M0�v�
nM~cL�jh��&�|/���0��&��[�7�&�1&5��
M~L���LiM~L��=c�F����:��&�	&���D�4�&�	&�����
��o��_
�VC�����M"sF"���W���of��bC��q�����D�T���O����)
g����Rke�����Li8#g��u�sF �} ^-�VA �<{q����q�X�l����<��o���{�/u�>����H���"S:>���;>���.��]zp�������N�D>�7������<|vy��o�c�=��O������4|
4�]��0|ua��o�c���/���)�VD��Ga�b���XQ��g��z-������{��E�I�����y[�����eC�p����\�Z����:�9� �����{����Zg�_�����A�$ L�D��� |�A��=��9�lr�kw���{!_������~/���O����	�%n��k����-�����{�*���4���x����
w��&����}������"�QzO��R�KP���d=����~��w?���??����p��[��O�;�����Q���������������������nI���K.|��������������������?|�������~����s��:(�?�W?��=��?�b��u����6�W�j����������*�#l���z�2V���;��a���}����E��{���|E���e��D����!��(�#����}o��H��x�����aFbP����za����s��r��G��x
bY���A�+'C��A�G��}=��za����W��a�3�J7N��s����/P)�[���u���
3"W���;^�A���@U���a�zU�fD���?�w�_�x����O��b���&��j�^�U�k���Z�����z
�!�&���'^"�����[��?�0�7#�Vc��;��a<�LN�~��{�E��V�_c0�wG����?�W�[�H�;�NR�wG��F��
�-�����������[�I���� �V������Z���_usu ������:~�	��e3��@����?�W]]��YM�vW'�o�@/���]�H����������$�I���B�����Y��������_:g2�_���|�F�^�	������fh���+�{�j�+7�J�N�����	�]�_<6��~���������������k�{��k���g�����1#��Y�_9�+y{/�+���%m����r����gm�f�_��{t����+i�~
���/�H�w��WnY��>�>1�~o������<c���r`F�����r+�����S�w���u�����;f$�;k�+��J�N<e�6�_I[�k����0#�_m�6�_������\�x�����9!����_m��o �=+�+�C�_<$��~#�o$�K���oD�����UD��M�}���{�M����/=�cH�	�7���W	�75���B��7#�&�������������oF��M��-�UF���u�#�f�����;����_K�#���uU�w�����������_��B�wQ�W�o!����{ �M�],����{�]�����{��~~t"�M�],����{�]�����{����}0����l��b��.���������/��_��G�������_�i���W�_y�y��������,�#m�����n�����G����<��<�v�U~~�a�������_���T�UF���_m�a��������#�4��u�����3�g���j�+�4���~����9�G��_C��3�C��_m�a���������0F�H[�k����cFt�����<��<�v�U�W�hi�~
��_d�i>�W�_y��y��2����#m��j�����������_m�a������fhi�~
��������_m��o���3# ����[��H����G��z���~����������L���oD��h�_K������U�W	�7����}0����[��H���*!�V+4?@W�W�7����}0����[��H���*#�V#4����v����_����~w��jyF���W;�o5@�q���jG����K�>�oA���g�_KU�����U�W������}0�������~-����[-�|����:��>���F�{"�V�3����:�����U�W'��I�W��+"�V�3?��,����[-�|������/����_������~
��<!�V4�����	�W������;O�������_����j�����o���#�u�������_����������%o�_e5{�_I[�k��f�cF��A�_��W�v�U�W����k��f����WB����W��+y;�*��y�x������y����~�����J�N���j^'�vM������J�^���j^�%o�_e5�'^�6���y�1#������
�W�v�U��y���u���j3�
��j���������oh�o0�Ws@�
�����#�o��/}:=������,�UD������J�������&�����`���ob�����o"���|a��������_e����W�_e��L�W��jG��M�
��jG��	�Fu�#��}��o���� ��M�
��� ���Q�_����_�v��~�K����:���������������G����:���Q�_���g���%#�=��6�Z����$������{��������_Ku!�^����Z&����*���g$m�o4�W�T0#9�7j������������n�H��_C��������������g$m����Z<�����������>��/n�H��_C��pF��h���Zf���������/n�H��_C�,f$�&m�,�O%o��W�����3�����_-����������������~���3���w��Z��/�2�nf������������������E��w?���������7����y��O����o����?��������_�_���W��q�Q*������:n����������Ap�������@�&���F��������
��(���>��t����m��������5�yKB� �tPzH�	q"}A8�S����P�-q��y�=�!�f����	��\���U�����Hd���I�wG���0�.{p�C���Z���0A�<����z�D���z���!i�z-]��,��<���������x�p�I[�k���3�-�'L�������O�9Q/�xH��^K�w��42�A����{!���A�6��������yr/Y��K�c�E��������:!�^M�M����p������k,7�����U~�eu/]�{���Zp�����m�V�+q;���Zcu^�6�Z��/��3g,����{%�������{%m]���Zg�?s�rH�3p���2�1\g�^I[��&Cm�.����!�.���xm]|%m�_Co�.'����!��3��'_��
�
�+i���u-�3W,����J�/��u����~
���e��+�c�����qo?��0��k������o+�}��+�C�
���y��F����_7��5"��>���!�F��H&��#�ol���,�UB��}��+�C�M������D#�M�����n��W�7����X�7#��>�:v����s�-�����Lg���#�}~M��w$��C��kG��Lw,�\���>���r����Y*��\�+����
5�>���6;K�u �����|�X{�m=���6;K�u"�}�K�C�=���>k���2��f`g��.d����t�rH�2��g`���B����6mx�L���6������Sf�
7<$m�_C���C~����~|zH�N:�g�nxH�F��k�C~����~=|zH�/�_�����~
�6O�3�,��;�A���t��m��!i�*�m>1�g.Y�w��o��A���
7<$m�_C��-C~����~W���N��GnxH��_o(��5c��\��/�S���n��#�
7<$m�_C�mp��F�<�o��~7��������p�C�6�5�W[���������o�������������"�/Y��WpH��7��W��7<$m�_K������C�M������;�nxH�F���*#��%u��s��w7�����~-�UF�eK��jG����}m������������]��oA�����r���!i�Z����K�<����~�;f_�_�����~-����K�<����~�������p�C�������D�%K���!����'������
I����_]��d���.5����"3s�����!i���0!��%m&�_���p�o��%m�_C��!��K�������_��9��J�F���*�C���05�_���>�j��<���m�k���/�,Yj��0�J�/���0�J�F���*�C�%Kmf�_��e���/��o����%�T�z�E\�%�g���x���t�
+�/]�_�����X2����vW`��_������	���>����`D2d���~z���t[��H
�����}����v���~���O���B~�G�B@�
M�}����v#�o ����BD����g�[�����������"��>����!�&�H^|���M��	��=���������K�nF�M}�
���{s{_{�{o��7������i�7��W����#���C����������y���
iwG��������P�w��#�����[oA�-}����
�� ������t��kX���[��K?���{ �}�
���@�=:/<�{"�}��nC�=yO�������g�y�a�2��g^��1����"�{�}���{��Z
���"��-���Wz��oo��I[�kh��t`Fr�����>:$n�^����K3����PYE�c��iCQ[YE�����I[�k���O�����������N���
qiF���J�8�y���������������'��0���������o�����������w?��������A�h�~����������������������O���S�_�
��7>~�����[�J?I�����7����>�'�?�'���!��L���5_���9�)jk����6������Ox(���_k1�|	��K�h���������6��oV��$i�z
5_���9����w���D^�K�7��L����P�%|q.������K+�<��;sI����'2I��^C�����D�e��6��m�z����=Ox"����5�|	��K�\&�Z�����D^�s��_�x"����5}	��K�\��-�R���yq��'���~�D&�[�kh��?���LI���p���s�)���'2I��_C���
�D�e�2mH�	���<���;.	Od��u���/�;t�����_PK���>����Lx"�����tW�]"�2%uw�#��������$n��Ky���%r.�!��_����/��$q�~-��H���L����@�%��9����$q�~-��I���LI]_����:���Ox"������W�*]"�2Q}?�_�_���>v&��L����_��t���������K��st5r@�y�O����/�Jrk�_�����|fD�y�O�L^�st4rD����k���x*�����t�gx�Vv�����tN�X��.�x����P`e|�NB�
�6X���G&��9�oie��.��`e|�NB�
�VXy����tN{y3� P%n]������������C
^��J�^����0��>���a�����v��-��:c�d����=�����6�Xy-���]�&m��7p���g9�_��8T�[lh���1c��M�+o Q%o'���~9�x��������18�1�M�+��@8X{�+G�������c��k����#�`�}���c��K����#�`u�����`:3������X�����w�����3�`��2������X��98�/�
)xG�	�����{��-M����o�
)� ��������rpis���*���p0}�iH�rp�s��7	��|41x�Yb�A0����1� LO�Q��|41x�Y'b�I0����1�$�^��|61x�Yb�E0����1�"LO�R0b�����Pd�b�E0�i��}��_H�;��$q��
E��<fd�-�v,y{+���m��u��"k�fd�-�v,y�����&�[l(�vbF��^[d����J�(�n��u��"k�f$��E��K�/��8X����}���p��Y�,y{+��}����9�Pd�+p����-��8X�~)o/^��7C��o���W����7�`��+XYt������������	�w�����`��rphr�fh������
)8"G������9869x�4Y	98��&+!'���'�������d%���8X�de��D8�-1������Y�������98V/xG���Y��9x'L�^=�`���p���� �M�,MVA.��gu�U���`������`K�u ��gu�u ���O��������&�D>��&�D>	�|"�M�&�B>	��&�B�k��9�jrp04Ye�x	��&�L�	"y���� �.��d7aFvH���*>A$o;��L�(�����64Y�����R�m���Xp�M��q�F�����f$���c��<�I�����EG�y�[lh���1#9���C5�`0���K)j$n]���*�Y�L
?�jH��T��+XYt����u��&��p�f!C5n�6Ye�*y���/�x���`h���`FvT���*�T��+XYt\���u��&���Y����*98�9X�`����U���d����j�IrC
����q������[li�"r0[�Y�MVB�������[li�r0���G)8#'���kI�j$n]������l�fQ7Y98V/�j$n]�������`��n�v���p���N���[li�
r0[���&C
.���p�~��������d��l��N
)�@>�&F�k5�.��d���l���9��9�$�^0��H��`K�u!���U�d]���`z����q�F��[��9�����>G|L���`���	8X�V'C�uL3^�M����%o�`e�q8�`�[lh��1#�m�6Y���_J�~�����dh�,�{k���K�N�����/^�����:f�`	�+X�d3p���b
���598��cY0#�`m�u,����W���8�`�[lh���cF���&�X��%��R�
,q��
M��M��p��m��
8X��
V�,q��
M�����p0=p{H��c����������&����p��m����&F��c��
M���#��M�dE��H8X�����&K����M]e%��@X�td��a7Y���$�		o�.+#	gF��
#	�&	��Rf�����0����(��QX��cG��$�&K�U�w�����*����0=dbD�Q�4Q�M�6�@.���m��,|��L�h�@>�,�&K�u ��u��0|Vo�D>�0�&K�u"
���������OB����
_H�W���d)�.����pPZ��EpX���k$n�aC�uNp����k���:'����x�������h�Pi��<��M�VZ�����f7�#���[7�����d��-�m�uz�����a��O�x��h�Pi���!���A[i�38U�����M�h�k$n�aC�u.C��{���:p�������;'��H�F��N�\.��\����.�p�\M��q�F�66tZ�z`H������
����5�l<N�����
������K�z�4@�J�/�a\�����
���������:�p����'N�h'l$n�aC�uF�a6dC{�4��#�a��q�F�6�tZ	y�-�Du����S��==sbH�������N+#�)��;���<�k7�+6�n�[:�y�m�Du��#����_�9q�F�6�tZ;�0����C.��;�a��q�F�6�tZy���Du�u �����
����m4l���a6gCw{�4|"����%��h��i���l�&�;�y�$<LO��0N�H�F��N�Bf�6t�wH���ExX��kB��<�
��5K�N�I�i]����5�l<������ao��.7cH6����.<,y������m4l��.�0$�v�vZ�����������%n�aC�u�C�qWm�u�6LxX��xX��
��N����]����K�^����Z��%n�aC�u-;�d���N�Z��%����
<,q
:�kM���j;�k�����	#�<^�6��N����%u�am�um����Ki8Lx��<<:�+ ���N�
����0=�bH����������"�p`<�����<	�7��c��gK����c��=�7���<��3(F4�����o����5�T�v�UD$N}$�C�CJ���� �z��87�����{�����~R�Z;q&@LO����@�7���[�{����>��!������z�q�4q���{�-���~RZa�0���pi��k����{ 
}�#�C�=��������G�_�����A������e�� |��O�A�l��k�����B>��'|��{!_������&��P��~�4�x+���x���x�����9����������G����F$'��!���u��6���I�G���,�_����([�8���s6G�6���o*����]�
V�f��9���:1�`��y�m��cX��cF�������\P��?f��C'F�6���'
�/	2�]:�;�������)�����#n]���z� #��q��-���C6==rbD�0i��[lg��2�������!o	
��gl|��C����3,8�����*k��x���`0=pbD�1841��#;�-8"�]:�;���	���c��-EVDf�6N]d%����`O��QpBNm�4Y	9�����!g��D8X�������y�������������p0=lbD�;rpnr���u�[��LFm�����w���p�z�9xor���u�[pAf�6^�d��B8�51��9�49���:�-�@f�6t�wH�r�A8X�`�����/��qo�'r0����&�D>k��9�lr��Gu�[���m�����/���q�v�r����O���`�`6h��M����/�<X��,q��
M�����]o3Y�/�����p���x��_���?������� o���z���?������{J?���}��_~������_�x���?�3C��O�/��k����;���?��3��U_���7���O��O����X��J�<�����s���[�tf��y+�TI�v�'�>��kp���=���6tn-����M����M�����������������?��m�o�?>���$��+���������5��{���������-��SsX������|������_������������?���W?���In�$y�u$UI�/����KJ�f��{��O�����
����_����wW��]��%��xw�O�X����$m������;f$�o��~�!��������~���������W��7�3	��w���x��A�v���#�{���]������o�G���xA�������������w���5�0�x�����H�;y�@C���#
��'��0����������CW��� ���
�oA.�O,	��o�����W�NB�Q����7dH�����0�������G�UUfD�=��Wm�D�=�����������g�UMfD�=��7m�B�=��������^��W�Ku!�^��o��~��>�.���O��q5�w1�W~���l���~������C�v�U�W&i�~
��w2��2�_�������0��H[�k���� #[A��!C����!y;�*�+���u�����fd������������-������#m����z�+3��o��~���������0}�H[�k���:aFr�#�
��
�T�v�U�W�i�~
��_O�H^%��!C��f���*��������u����o3�7��o��~�S����*�+���u�����_�|@C������������F�������_����v�o��~#�o�������ol��j���/[=��!C�M�����O,���/�oj��j��2�/<��!C������������������������
����������{����&����� ����2����[���j����[���Z������o��~�����'d���@�=���Z����
���!�����_mu"��M�]-������o��~�O�����B�=��k��.�_6x@C��{!�^}�����<!�^m�5�W��+�{�j��y����~���<]x�������-��
�i����J�N���jv�������_��cF6����f�+y;�*����J��_C5�fd���j��%o�_e5��������_��������������s�����J��_C5/3��?m5����������W�_I[�k���5cF���7dL������������]�7C5o��������7�_���W�_����k��f������������o ���������k������j��9"��>�m�c�-�UB�����UB�M}�}b.��~�oj�o��W�7���!C�������A�_e�����`��2�o&�KC���#��>�>1{o�;�����`��v����/�
�oA������UA�-M�
��� �6x���
�o��o��W�oi�o��W���������{����1�{�=��&�Ku"����o��~O�����OL���/�����`��.����/�
����{���W�����`���i�H������w���C�v�U�W.H��_C�8������Z||H�v���������_-~��l�^�_->>$o�_e�x����U���_-���l�O�_-��~��cFe�� O%m����Z�������Z��������Zp�F�����e���M�i���h$o�_e���R��<~��]����Z�yvFyH�8D#y;�*��gh�j���sg��gd.���W��T�v�U�Wn�H��_C��3��{m������'b���g$m����Z"�/���7dH��7�U�Wn�H��_K���
�P�oB�M���n�H��_K������!C�������I�_��������W�����!�������I�_������M��jG�%4������w��o��W�=#i�~-�UA�%4����� ��>�&m��3���w��Z��/�2���
�|j���
�9����_��j<��������(�D��������_����q��_���(���H�B�<$m�o(��	��,z�'|��?�������z�}�:OH��^C��N'f���{B�[��X/�	e��:�	I[�k��VW0c'�6��z=������l�V4!i�z
m��3f���{B�\/������,��y�K��	C����S�.��zg`	���W�����K�f	C��.����O����.�(M�v~���������,-��u]0#y���
����I�^��.o]�Y����}��3,x��<L{�]�{�}%n�`e��n���Q���[��!���'^f��������&e���������<��y����,�C��l���������gXpD��y���J���n��W		85	��'������5u���S���m�22pj2��O�a�!8�'j�
+#�>�I�a�H��I�o?y����;{�T��1xg�m�v�����o?y����p���*���q���*������"�@.}��E��|v�"�@>:li�N��������:��O��N�d���g�����:���>��&�B>	;m�u!_mv�&�B��<k��m���p�S6YnzH�F��&k�v�?�e�6Y����+X�dm8�!q���%�?�e�6Y����+X�dm��!q����������M���D��
V6Y�zH�F��&k������{��&k�A�J�^��&k�]��(��dm��!�����&k[@�J�^��&k�a��(��dm�����Mgm��� R%n�`e������mlh�������Mm��m�?|��7�F���Q�����C�8]�M���%n�`e���������&k��d�c�6Y[D���+c#
�q��(��dm9�L|,�&+"G���������mli�r0��X�MVBN���+c#
�y��(��de�`2�������	�W������-M��LV>u��#����+c#
����(��d�`2������\�W�F��Q���*��d�cQ7Yrpa�m�p�C�6
�4Yr0�X�M��|0�6Y��!q[��9�,}��&�B>	�W�F�#�Q����������n�.���p0}el@�aB��<��0K�N��&+L���W���
n�k�����d,�;k�����%n�`e����������
~��}^�MV����W���
8X�6
64Yav������
3p����l��,q��0_������
������(x����
MVX���U�d�8X��
V6Ya����
MVXwI8X�d�
8X��
V6Ya������������:�^��9	
k���
K�^��2+�������F�[o@}��UV���0}glD�A84A����{����������
18�o�
�1861��[�{�M������J��@0}_lD�	!85!���{�������������� 0}[lD�87������E�}�����	�w�F��#�M~�1������{7u�Uw���M���������[oA�-}�������[����F�{ �����=������s��.����p/}KlD�'r��~���{�=|O����D�=�j�����|#�����"����.$��������|����v��i�+�G��-�����/}El@��i$n���a�n���s�����>=$n�_esq�F������f�K��U���!q{�*����4����]Ea����A�]�y�~��f:�~��~q�F�����8��8o��Wqs*q{�*����4����^�4��g�m{P�������8N#q�~
��O��:#��	��*��N%n�_e}q�F����������,�m��7/!�N������i$n�������7������~z�
��*����4����_���`F�����-
��*����4����_%�_2O��UB�M��{a#��]�[�k���/Y����*#�&�������,������W����Du�#�f�������*������W;�/�����jG��	��W�F���4����_�_2M��UA�-���a#��M�[�k���_�L�����{��/���'i$n����:��0MT�W'��I���6�_��������B�%�4Q�_]���_�z��~q�F��_L1�WiB�%�4Q�_�	�W���U�Wi���u���*Mf$�������_����*9�_�[�k���;0c����J�W�v��������J��_C��������U��������J������/��qo�3����������+q{�*���x�vM�}���{�]�%t�_m��_���W�_�u�k���������WBw���Wi����~��UZO�vM��
�U�f���������+q{�*����J��_C����}�M��*��@���6������k��R@�
}�M��*E��@���6�������X����	�������j��������X�������������j��������X��������X�1g�L��6��87x�X;��`7��	x'L_QpA���X��\��&u�U�A`������K�K�u �>�I�a��a`�����d�������:���>�I]b��'�`�����O���	����:��>�I�b]H�'�`�����/���M���B
���&m��'������q�F��j�<�H"��=Vv�	"y{+{��#4�*x5�X�e�HN"��EVv�	"y{+���#4�.�Pde'ef6E3i����D��
V6YGh$n]����3������6Yy�*y;���bC
����H��
MV^�HN�u�&+/`R%o�`e��q�F�����z�H��u�&+�`R%o�`e��q�F�����M������MV���J�^��&+����64Yy;1#9��i��f,�X��o��(7h$n]����9�-�8m��#rp L_Q0��H��`C��#r0��q�&+"G���}������4Y	9���8u�����`�����q�F�Vo�&+#�=�n�2rpf�m�p�F��[��9�-�8u��#����M��H��`K�U���&�W7Y9��9��W�F�{4�.��d��l�����9��s�����(i$n]���:���.�W7Y'r���`O_Q0N�H��`K�u"�a�n�.�������26�`����u��&�Bf�4^�d]��W��=}el@���|59x34Y�,�{k��}�����M��^�6���K�^��&kw����W����������&k�f$��M����%o�`e��{�`�[M�>{��8X�d�3p����l��8X����}�0#�`m��/����W�����`�[lh�������gm���3L8��26��8X����}-��p��m��
8X��
V6Y�,q��
M��e�H8x�6Y�,y{+��=�x��M�����Y�d�98����(8"�&C��G��H8x�6Y{D����+cC
F�M�&+!G�����J���p0}elD�	98�9��de��D8xV7Y98����(8#�6[��98��M�������(xG��-M���3V7Y9xg�m�
rpirp�4Y9�0V7Yrpa�m��������d����E�d���`�����O�������d���'��E�d���'�`�����/�������d]����E�d]���`��������&GC�U�
� ��E�d�	>A$o�`e�Up�F������H�)Z�MVq�	"y{+���C5�.��d�1#9�h�6Y��'����l�
.�H��`C��n�����h��2�I�����MV���[lh��|bFr^��m������Q���26�`����U���d��`Fr^��m��
&U��
V6Y�j$n]���*k�����E�d�L����l�
��H��`C�U68O����U�d�
L���L_Q0��H��`C�Uppa�5���*98���
)98498�����j��m�JD����+c#
���[li�r0��Y�MVBN���+c#
���[li�2r0��Y�MVF����+c#
���[li�2r0��Y�M���	�W�F��5�.��d���l�fU7Y9x'L_Q0N�H��`K�U���n��n�
rp!L_Q0N�H��`7Y��A�
���*�@>k�,������-]��$��kVu�u"	����]��H�F��2�Bf�5�����/�����
�j��m4lh��	Y�m�l�6����%o�ae�uL�������:��!	o�:�p�������:���m4l��wbHB����:���	
��F4���%n�aC�u��!	o�B�������c#��%n�aC�u�C����1K�^��F�Xf�x6TZ�<,�{
k+�c��������:�x6tZ�
<,�{
k;�c��������^x��<����-�����:6�a��kX�i���m4l����1$�am�u���xX�iy8�y�:�#"��A�iy8����h8"�6;K���#������p$<L_ �pBNmv�N+!'��A�ie��Dx��A6���<��<�,�VF�����������0}�lD�;�pn���tZ;��Nx8�;�yx'<L�!�pA��<�,�VA.�����*����0}���
��w?���??����t��[��O�C.��p��������2��{���������-��S���_���_�z������������������������������(�_=f����'���h�(bH$��?��7��h|��'��n��e�N��y��s��
C"����0^�a<D���?A�w����y�����
B^H�'9�"��o��"1���F4|�A�����|�u�sB�z���x����CD��.�0|������aU�!���D����
������4L�w�0n������aU�!��!�^�������kx�|�t�rV�6��U��<1$��q�|�x8k#y{
�o���Y��<V�o�`H�W�x��p�F��.�0�����y4�*�0d��D����
��^������7H��6g�k�hXU�aH��g5o�q�����*y{
�����Y
�<6tZ�z���m>nX�i�8m#y{
+;��m�j������:��!��FQ�i��m#y{
+;��m�j�F��l����<\-�|����:q�F��VvZ'n������aK��������VwZ�n#y{
k;-�9�q�G��N+!W75�����H�N��}�
���Y��<�tZy����au���6�������y����y4l��v��j�������H�^��N�m�j������*������
�;-\�������������aK�u W;77���p�F���vZ�psV7�����~��R����x"W[7����p�F��J��Z�rsV+7���������_u��+7������������9�k����{M�������j+�k���~���5K����n�o���������<��`XYh]`X�V��v}o��`D���:��oc��1V�Y���U���D���������/����������w���5A������;K�^��*���%o�_e�u-/^�_{(|o�@�d���-�� X���UY�r��k���.���~��X�
�+y{�*k�k����Sd�<f����-��K�^�����%n��J��	3�	�O��
H��0}olD�	8t^��,8��O�
����� 0}mlD�8v���c������2p$L�QpBN����+!'��+!'��+#���`K����3�`u����3�`m��#���`K��#�������w�����!#��w�-=VA�	;u�U���`�����rpis���:���`w��J[����'�!�p��������?�����-�����������������=���?���������o}�������O����o�����XF���~�������������0�p��[�_c��T������H'f$����^���G�v�g���[�S�q�7[���[��	6:e��&8����S������?������H3lt�f�-�	�3��K��`8���.����e��������{KS�`r��3[I�G�?�������d$'�{�l���d(�����T��_x������%��?B�
V6{o�"L�f)�����G��`;��&8���W���{��A����g���-�����3{i����;{e��o�������$�[pDn����%7�LN��^���)!�����I�����>���sK�-8!����W~E-M9����J��g�����/[ro�9�������������gF��-xGn�����%��#����W7Y;r09�����{.�����_<����r09��S�?���LN�f"�����K��_<����������V7Yr����g��-�@�N���-M��\���q��&�D>���@������a�R�������#�?.X�d]��W����G���9�:�_
�4Yrpub��k�,7!_}~f����,q��
M��
f$<k�,���%o�`m��p���64Y�e�H8x�6Y�K�N��&��/^��
M�����W���r8X�v
�6Ynvx��lh��,�{k�,7K�N��&��^�&/�&�-f$<k�,�K�N��&�-���.��d��cF�����r+p��m�{fo���W�`�[lh��6aF�����rp����m��,q��
M��N�H8x�6Y.x,�����
�[p@M^M����q���r98�9����{���������r982V7Y98�9����{N��������J���p0}�|H�	98�9����{�������������p0}�|H�98�9�����F�m�4Y;rp&L_-R����9����{����6[�������)� ���&� �&��&�@.�����C
>�����&�@>��Z��9� L_-R��|�9����{>�������&�D>	�W��|!�}~fd���/�����������/�����1#_}~fc����� W��WC�������:�����M����y;k�,G�?���,�d����`m���p�G�N��&������u��&��2V'�T0}�|H�p:�#o�`m���p�G��`C���3����k�,��?�v
�6YN���64Y~q�u��k�,��?�v
�6Y����64Y~�0#����6Y����m�<����[��,��u��k�,�?�v
�6Y����64Y~�1cu��Gk�,�?���=31to�p>�#n]����9�:�����M�������l�[pD����jbXpD�N���`m��#rp�s�3#C�������������S�?.X�d%�����gV�n.9�:�����a�9�:�����MVF�}~fe���3rpu>��U��w������
���)xG��������������WM,F�N���`u�U���>?�2to�9�:�����a�9�:�����M��\��������G��-M��\���Q��&�D>���9�lrp�4Y'r�I8��Z>�`���p�������&K�u!_�����C
����>?�2tk���|598��y�����M�<K�N��&k�N�xM�&kv3f$L_-R������M����%n]����������M����%o�`m�5{�`�[lh�faF���&k�,���I�d�3p���64Y�|`F�����!/����S�����`�[lh��e�������C
^��%o�`m�5����.��d�k�������c
�����M��y�xm64Y�,�{k��y�����M�&�xM��&k���p0}�|H�98�6Ys@M��&k����p0}�|H�98�9���7��� � -UVB�����CN���nRwY	I85I8Z���$�	����4���S����.�2�pn�p��YQ83V�Y;�p�����m��,�7Y8Z��Yxg,�n�
���ga7����0\�0-uVA.����cF.}v���:��K�����:��B���!
H�G����.�N������B�D>	�7��4|"�}v���:���6[�y�$<L_1���<|1VWZ�����d���i�KHx��c>��e���kX�i-8^#y��
���f��X��K�Cv�!"y;
;m���z���6tZ��0c��"O�2���������i;��k$o����Z���g�z�����g��������Zp�F��
:�e�1c��^O�3�0HU��kX�i-8`#y��
������Y���E�!
/ U%o�am�������6tZ�
�k.d���7��4��T��������6��n��i-����O_5��RU���vZn�H���Nk������Kf���Y��7������������y�_�����������"~������������������w?|��??�����:����OL�RI����������o�?�����p������p�.;�-���������[�y�G����'�ed���B��-�	"y���d)�2�Y�cF���-���H�F���oG� � �o�!
��;a���pD�6��|��l����4\�-
a���pD�6��|��
i�@�8[xu��� ������;.�:�kpH�'>k;��6���pD�6��|>l#� ���!
_���"������e��h�R�]�������G4�N��y����:K�F���o�I�=����
;�a��kX���xX�66|qmu;�$��x������%n�am���/^��
�����%u�am��z�a��k���������������?��m�o�?x������������������O����'�����nI��������o���w?������/��������������~:`3��~��2H��G���7�cHv���EH�K����x����������|��	C�/��7d,q;
����[=^��W�S�o�XR����nx2����_�o��q��	/�/LL?N�m]G~����

N�7~5-a2cH2�9�V��K
���8�b<|�/y
kZ�*$Br�L��!��zH��� q{
��/:�x�}���d�pDH�}G���p�/�K�^��-a���������M�
'����p���!
'�����5<�V�P�%�~�?^�1l8#$��R�_�C�H��<-��[�*
��L���y���{)���!
�H�;yZ<��U<p;2�?���l����B��pA2�����K�)��n�k��*$�1y/��58�������-�/�H�F����
�<L�K�
�iy� <��o_H����5�[y���2�oU:�����2��7��/�H�F��N�B&����N�B�/�N_H����
���"+y/��58��
D62 �m������^q��im8!��	�����qAd#"���N�l�	�
���"���pH�8!��	��a���"�:�
GD62"B/���qCd#"n�����l��
���+"Y��pH�8"���h�
WD������Nk������K8�a\����[����3"[{F���Nk������K8�ap��q����pGdk�����im8$��!z	�4�;"�q��odc<��C"n6tZ.�ldI�^�!
���F�D����6\��K"n6tZN�ldJd�vZ.�llI���0.�l�%7[:-��������pIdcK"4���qIdk/����i���F�D�_�C�%��-���-�K"[{I���N�D62%��;-\����7��y�Z���������JN�^FD��������1�����xCJ�1��=&���������F�DVu��S"������S"[{J��[�{��%��,���J�D66$B�
��D����k7����;"�Y����llF���/�p{F����{��������:GD66"B�
�GD����k7���&a�!�j��0K�^���2L��������7�{aD���*+��e������U��=��_w`�>o�"+x�`���������U��=��_�c�>�n�+��������
3���mwcX��0c�7m�f`��+X�b�����@aX�,�;k��K�^��+�^��aC�V@`	�)X[a�X�~1������<���m��}��V���%���K��`C����}��%V��@���!8��Z���C��7m�"Rp ��SpD
�����+"G���+!G��A�bpj�m��rp"���2rp"�o�2rpns���������A]de��L88��d�������&kG��L�R����O�CA����y�\��K�����C
.���pp�~�
rpir���u�[��\�L�R��|�����|49���:�-�D>�L�R��|2V/�D>���a7�|�9��8��9�d��6��������Y�|!_}��(8�����RLV����^�y���[�8p��M�6Yn"�Qnb{����:�-�m"��	�&+��Md�6��#��Ml���xP����M$�6A�dE���l�F]tD����9���9�<����Z���Fm�q�F�~)�#��M�6m�`C�8[3V�6�m�".�H�/�iR�I�XM��wVMV\g��?�7j����6�����R0.��j�F
64Yqs��xo�6Yq�*q���h\���u��&+nf����MV3L�^���q�F��������M�6Y1"���w��a#y��
MV���d�&������E������4Y	9��Du�����`���l$o]������d�&�����k?M�8`#y��-M��Lfl������w��T��)9xos���*��d�&����\�?M*������&�@.}N�&�@>��,\������&�@&6I�d����`�����5��.��d���d�&���9�$LU���q�F��[��9�,�$u�u!_���*Qp����&/�&+M���S���Jp����m���x��������%t�`m��p����m�����59x14Y�K�N��&+y�`��+X�d%��kr�bh��<cF���&+����W���J3p���64Yiq��p���Jp����m��,y��
MVZ.�H�\Y�1
�36�@X[e�@X��
����!#�r��]�O�������J����^
]V�v�H�\'m�������0��C^�&
��2+D��Ga7i������S]>���,�,�����c������RD���/�pB�M^-uVBN}v���JH���0�cFNM^-}VFN}v��������05�C�����������s���n�v����0U�C����&��FkG��+��<���|H�y�4yx�TZy�0VwZ�p!<L����������N�@>;u�u ������<|�y��i���'�a���N�����������&o�N�B�;u�u!_}�T��h8�x���6tZy��53��q�N+O�!"y{
k;���5��n��ie�`Frl��vZ������5���2�H��aC�������"�������kX�ie����u��N+�f$�:m��g����������a#y��
�V�O�HN�u�N+/36�?[�Sm>�a���u��N+/3�#|����+HU��kX�ie\���u��N+�3�3|����+HU��kX�ie����u��N+op�ffc6^�i�
����5���2��H��aC���0[���N+���xX�ie���U���i��<��l����y8��|H��d#y��-�VBf{6^�i%����a�of����u��N+#�A���2�p&<L����q�F��
[:��<�m������3�a���4�c6��n��i���l���;��<���|H��f#y��-�VAf�6^�i��Bx�j�!
������tZ�0���N�@>Sm>�a����u��N�Df�6^�i���'�a���4�<|�y��i]��l�fVwZ���xX�i�����6tZ��<�vmfm��O���������'�a�[5
���&�Hxx�vZ������6����u��Nkw'f$<<k;����0�a���4���%o�����}����gm������������g�a�[7l���9cF������g�a��kX�i���W�����i�����5����xX���vZ����5y8:�}��������K�^��Nk_/�zM��Nk���xX�i�����5����
xX��
:�=x��xX�i�y8��|H�y8�y��i�y8^�����#�am��G����aK���#��E�i%���xX�i%�����d���p"<��;��<�Sm>���<��<�,�VF���u����3�a���4�#�&'K��#���u��#����6�pA��<�,�VA.��u�U���a���4�<\�<�,���<\/�N�@>Sm>��y�h�p�tZ'��AxxQwZ'��Ix�j�!
���g��������O���N�B�Sm>��y�j�p�tZ���xX�i�	?D.��T��h������6tZe:1#9�h�vZ������5���
��H��aC�U\���x�U�i"������*8s#y���d(�������jK���SD�v*��|H�8t#yZ�2��������V���U%o�bm�Up�F�6*6�Ze��7[�Y��VY��J�^��Z�����mTl����`Hr������
bU��*��Z�n$o�bC�U6�!�����*�U���X[l������
�V	�$����f��b���X�l������
�V	��l�f�V[%"�����o$o�bC�U"r1��Y��VB.����>R1.�H�F��r+!���M]n%����X]n����mTli�2r1����VF.�����n�H��bgi�v�b�|�����x'\L
������6;K�U������n�
rq!\L���q�F�6*��[r1�������\|.�
}H�8{#y[������l�v�D.>	S�>�b������-���\��o6u�u!����BR1�H�F��v�B.&�7n��[��\|.�
}D��\,y��c��q���:&�b���X�nn����bgh�\,�{k���K�^��v���^��
�����%u���m�\,y{k���_x�:\lh��y�������:f�b���X�n3p���+��v�X<�$\����K�N�T��x.����
���N�pq��[�
\,y{k��c.����
�����pq��[���b��T��x.����
���I�8h��#K�^��v��������n�8.�v����p1U�C*��������n�8.�v+"G��T��8!�6{K�����bu�����b���T�\��\�-�VF.N����VF.����BRqF.�.��[;rq&\����\�3.V�[;r���bK�U��w��t�lH���0.V�[����x��[��.��v�@..���BR��\|��x��[r�A�8����� \L���O��������:��O��Q�n���'�b���T|!�m.�-���\|.��v�B.�S�>���p$o�bC�uNp<�Iq\��[��#��W���:qG�6*6�[���9O2�����:|�H�^��v��5�����n�~���3�\��[������X�n�8�#y?�������G���<O�^��a��9�.�&��_~+���x�X%����7������������y�������?����?����?���}��_�����������w?|��??Y��+����[����6�����������?���?��?�`������^b������(����;�<����?���~�;�w�9�K�qs��a�>���-���wN�<4zB���o���7N?{�.�����}wI���	o�"yb�������wM	��~�Z��o:0b��]��|g���\�����f�_�x����^�����;F�?�vI����_�~3;sG��}��������G�7����"���W[��;�h.y;��O(�{�-/�e�s������o�gE������+p����}I��c���'������7�{��"���W]���G��3�7���{4���cNn.�D>�������D>���!'7|!����_Z;/$��O���t!_M~�����E��choH���|}A|M@�������k:0#y=i+��K�N<m�u9@`�[l��.�cF�j����.,y��q�/^��_;����=@���]Am�uy�`���������/^�_;����g�`	�+X�b]3P����{�]�{^&�xM
~�\��^�%t�`m�u-��������������`C�u�3f$�dO��Z�%��)�0X����ks����=i��k���xO�hzo�p���_�0Y�vaF���"�
3��`uSy�������3����k��+"����
�����i&7��#�`�n�"rp$��,�J�������ers�	98v�&+!'�0X�Y����S��_;����3rp&��MVF����U������9&7�#���������w�8X�a����_��4Y9x'��MVA.}�W�9�49��3Ln.�@.���+mC
>���>����@>�li����p0}�iH�'r���`}Uy"�m�4Y'r�I8��3��9��s��n�.�������^rs�r��8X�d]��W��ge���	?@�&�vv���e��Yl�����M�[�_�<�v
V6Yyr3^<�y|v�"dt������!�
vx�G+��<y�?@���
2z���`e���f��=���Q��&�-��?@���f����V6Yo�<�)l��{fN����.��"���aX��1#���V6Yo���O�yfL����.��"���aX�:aF���l����P��?3��)�{^\�E������3�N��`e���m���'�<3�~o�[����H���L�[����\����������a9����[pX���R���z���'�c
F}~fD���#rphr�bg��2"G���&�-
rp�s�3�����c��K�����`u����S���P��`�������de��D8�>qRpF�}~f>���3rpnr�bi�v��L8�>qR����9����{����&/�&� �����!�����g���-� �&/�&� ������������g���-�@>��X��9� L��)�D>���l�����g��K�u"�����1#�}~f4���/������&�B��'�C
���/���&�M��W��
M����%t�`m��&�`��)X�d���������d9�`F���&�9�`�����\��;�`�[lh�����q���r8X�v
�6Y�K��`C���	3^�M����%o�`m��f�`�[lh��|bF�����r���9����{^��%n]���rK����m��V�`��)X�d�8X���,�f�H8x�6Yn�����M��f�xM^
M����%t�`m��6�`��)X�d����59x54Y. �����!�����g�o.98�9��d�������#�`u���c��-MVB����{�C
N���p���J������������q����������L��[pF�M�,MVF����M������0�����{��7K��#����{�C
.��{����MVA.M�,MVA.���{�c
F.}�7Yrpir�fi����p0}oqH�r�����~�u"M�,M��|��-)�D>��o�N�����������O�����!_��W����M��|59x34Y~Z�
��-�(�O�	"y;k?.�0Y��[lh��������m���O��)X�q����G��`C�����y����!{������z��y��
�&��3��z�{�C
�=�?J3��
�5��u��&��3��z�{�C
^��J�N��E�d�#n]����K����^�������J�N��E�d�#n]���z�[2�������W0���S��&kq��
M��6��vk�{�C
���J�N��otx��y��64Y>,���������C���6���M����l����8��������G�����`i�r0��Q7Y	98�9X�a�O������&+!�������3rp�s������s��-MVFf�5���!����������798Z��9���������9X�aCA��-MVA&�5���8���\�����@.M��&�@&�5���8��9��s����9�hrp�4Y'r0������!���'y�n�N�������d]��d����5C
���/�<X�d]��W������'�`�[�����p����m��	8X����y:1#�o�6Y��X0�`m�5;�`�[lh�fW0#�`��fH�8X�v
�6Y���u��&k�3��k�,y�������/^��
M�<K�^��&k���%o�`m�5//^�������`	�+X�d�p����}=/^�&'C�5�fd�m��8X�v
V��Z��%n]����7�	��5C
���%o�`���
8X����9L��p0}^3��������p@MN�*k���0}`3��� � �&����$�$�,]VD�����!
'$��'a7i?1��pj�p��Y	Q8��l�4�(��(�&�G�sFNMN�6+#g�������3�p�������;�pn������w������w����n�~h8�H�{��-}VA�	
��6C.H��O�nR�q�4q��.���y�0V7Z����a7�?7<��&���V|"������D|2"V�Z'��$���|���O�������/D��!������&���V|!_�����/~�\�����Zp�F�6*!����k�����;����������������������������}����,��?�����������_�x���?��3����+�����~db�N"����������������a�����y���'���k��'A$o�g�P�-3X��a��%x�G��t��$n�am���&��m4l���e���Q��-���4���5�m�����
U��:�?�=a	�mxM%q{
k��WA$o�aC�����������6�-�p��BG?D�4�� ������[�C�EuO8�{@������.���v��o	Hd�?��6ARI�^����8"y
��%&�?�?ann���5�m�\����
=���������'�|����<��'�;�-������
5�����@����{�������v�n�H�F����-;�0Y��2C���w��^[�/8"y
[:��<L&B������p!<<��z\����-�VA&!�VfH��p!<<�{i�����-���<LFB�����O��������qD�6�tZ'�0Y	��2C���O���������h��i]��d&����iy�"<<k;�uB��<�
��:K��5��2#^'�a��kX�i�n����ao��V<,�;
k;��K�^��Nku'^�6{C���C�y���i�K�N�t�{H�xX�66tZ��0d�������g�a��kX�wx����
��:_����VfH���
3����<,y
:�u90d�������W�a��kX�K�+���m4l���u��}��2C���%n�am/�n��������Z��!�<L��0����}k{�5x�x6tZk@���������E�K�y8tx��i�y8�vZkD����������c��gK����c���_�CN�����z�	y8�yx�tZy8�y��58���<�k?yX3�pn��l��2�p��0�%���<�	���!
���{��gK��#�}��$C.��;��E��RA.m�-�VA.}��pH��p!<�����������:���>�K8�a�������>���6��N�D>�<L/���O����������O���|�o_?j~�dw�e���>��8����"H������j"�k7����M+^A��Rk��CD�~)�n�"y�~_����_7c���0����|�H�^��6
��U���H���w�4��-�6�����6���U���F���������:k�g�������p2D�V��v}o����G��8��d������+7\��U��=���e����R��/�T���W[em8"y�~_{(|o�+�`���z����H��_���p/D�V���H��~78�p#�!��w�*q{�jk�
�B$o�p���F6C�Rp@�Wm���Z��m|S����L&C�RpD���Wu��c!�����a�	�,��+8�����+�
���'
�#��z����a�M�q�T�����X!����+8��!8�����p)D��[Z�)����+8�`���P��n�p(D��[j��L�B�RpA.�7u��3!��.��c��d+�^�!����M�c�H����Y'r0Y
�WpH�'r�I8xSY8"y��-M��LvB�R��|��M�H��MC�&�`�B�����,q{k��0K��`C��3�9�^�!�f�m����u��&+�3�6Y�K�^��&+x�`�[lh���1#�`m�<p����MV��xM~���{���%t��+8��8X��
�6Ya�x����Q��K�N��&+,���W���
�����/��qo�+p����m��
,q{k����x����A��������
)x�����MV���%o]���
�a�>�+8���m�rphs���
98�9�^�!G��@88h����c��_<����#rp�s0��C
N���ppP7Y	9859��C:�-8!�>�+8�`���8X�de������������	��������9879��#:�-xG�	���9x'�MVA����	�\��K���RpA.�����*�����`K�u �>�+8��9� �M��|49���9�-�D>�L����O���ppT7Y'r������d���g���R��|��&�B��li�.������
�(8N�r��&+�|���64Yq*��H��C
v�"q{k����5��>���dE�1c��"z� �W����8^#y��
MV�p�f$6�
)������m�"n�H��`C�g8N3�z�<�H��_�]t���[lh���`����Q�d�D���R��#.�H��`C�W����&m�W��������[lh��6a��q�I�d�
D���b��q�F��������Zo�6Y1�Xp�M��h����u��&+�`2^��MV����q��]4��H��`C�#r0��I�&+"G�����#��H��`K�����tMR7Y	98���C
���[�Z���L�k�������p0�S0rpnr�ji�v�`2\��M������C
���[li�
r0��I�&� ���pH�8X#y��-M��Lfk���:�����pH��W#y��-M���VkX�1
��az8�a����u��*�Df�5������OB��.pH�8V#y��-]��$�&k&u�u!
_��m�����(|5Qx5�Yi�����mV���%o�am������faC������5���������uVr^�6����HV\'m��<���m���FpH�hX�V
o�>+�3��I[h�pX���Zi��u��B+-f$+����J����5�m��<,y��
�VZN��xX[i�u���<������W�a�[7l���Z0#�am��6�a��kX�i�
xX��
:��e�Hx�i;��K�^��N+��^��7C���p <���V
�������i8"�&o�N+E��Hx�i;���c��=��0�pl��f���p$<���VBN����VBNm�tZy8v�N+#g���N+#�6[:�y8v�NkG�	��!
���{��������w��N�i����0��pA.M�N� ��N�i����0����<|4y8X:�y�`<�������0����<|4y8X:�y�d<���N����0����<|6y8X:�y�"<�����<|�7�cF��<�V�6��������|�H�^��N+�����6tZ�-��_���Vv�!"y{
k;��K6��n��ie�1#9��k;���CD���vZ�l$o��������A�^�i�����5���2n�H��aC���3��|��������glzz#8�a���U���i��`Fr���vZy�*y{
k;��k6��n��i�5cFr���vZy�*y{
k;��s6��n��i�
���l��k;���T������V�=�[7l��r�l��k;����az#8�a�����h��rDf�6����y8�7�C�E�[7l���0�����VBN�������q�F��
[:��<��mfu����3�az#8�a����u��N+#�e�Y�i���������Q�[7l��v�a6m3�;��<�3VwZ�j#y��-�VAf�6���*����0��0��H���d���a6n3�;�y� <Lo�4��6��n��i���l�fVwZ'��Ix���iy�l�p�tZ�0�������<|�7�C�e�[7l���	y�����Nk���%o�am��O����n��i�n����m��;�a��kX�i�xX��
:����������v��a���FpH�xX��
:���Hxx�vZ�<,y{
k;�}��u��Nk�3f$<�h;�}���������x��<l���xXB��vZ�<,y{
k;�}ux��<l���xXB��vZ�
<,y;
��1
_x��<�v{hX��`H�����7b���X[j���mTlh���1$!�E�j��8"���C*H��I�n2�Z{D$�����#Abz/8���H�H�&K���#cbu����#abz38���L��L�&K�����U]le��D���
�8#�&���le��L�xU7[�8*�w�C*���s���d��v���`����v���`1�RqA,��X�&K�U����U�m����X�m����bK�u �����:�����r�@.>:\li�N���p��n�N���p1�R��\|���Y����$\������"\L��T|!_m.v�v�B.���v�L�9r.�w�#*.�z#y��2�l���v�8�������V�������n�cH2~�j����sD��*��[wo$o�bC�U|��dv��[������U�m�
�H�F��v��pg!�7n��[e�*y{k����7��Q���*�Y������VY��J�^��v�����mTlh��:cH2�i����_������V�������n��aH��i����_������V�������n����dv��[%,Xq�(NO��T��7����������[��#rq \L��T��7��Q���*�����M�n%��H�8�s1��H�F��v+!�����r����p�~�8�#y[���\Lfp��n�2rq&\��.�H�F��vkG.&;8.����x'\L�}L���{�����*��d�u�U���b���������-���\L�p\��nE��V������_��������������������w?�������������������?�����_�x���?��3�����:�J���c�;��z����������������[��	���O���7�}��1d�	����pp�$y��/j��$o�bC�wx�!�on;z?�b�N���	������I�6
6�}��0d��mG���<�Xp�e�'����g�o��u����;�C���vA[��7I�v�'���[�wM��Q���;�C���vA[�<M���xO����^;|��(�P�+�L)�{kk�c�g	������{�<^;|��(�P�|�PR�
��|�O$o;�OT�-8Lx��9��`C�w���������%o'��s���������;"�p (�
��#�f��S�m8"	�6	����HH���p�~}�HH��|��	Ko�	Q8!
�����Q�K%�{�"�p"4��VFN�Z��3�pn��k������3�����v�������wG��4���������;a��n�vd��}�P���0�7a���{�-����pT�YQ��o���Y�4Y����{�=��B�Q�eH�9fG]f���G�_�����A�d ���N�������/����������|2V7Yb�E���^��W�_{|k����N�"����C���US�����C�V���4��~���oe����N�����v�>=$n����O��'�%m�u���(��\��{�����oo�f�������:g����S����s�*qo�<g���%m�u�`P%o;�3c����x�P�>��a�|�PB�
�vX�
U�v
�~�t�/��<5,x��J�^���\��J�N��O������
�aO
������K���@�J�N��O��
���6�Xg�������o�u�������[p@M~� �{����q���:#rp�s�3;����c��-EVD����,���rp�s�33�����S��-MVBN�������������|����3rpnr��G��[pF��{��������p������s��_<����w���|+yR7Y;r�N8X�d�����/_ro�9����&u�U��K������`�����/���9����&u�u }~f ��������/]ro�'r�A����M��|�9��y�{>���&�xp��_��'9�kR7Yr����g��-�B�����%7�|1�6Y��|�9��i�[�&�`�[lh���`F���&�r����S����p���64Y����p0�������%o�`m�u�/^��
M����%t�`m�uy�`��)X�d]������O����8XB�
�6Y�,y?�/��(]��W�	�/�qo���	�/�
ix����7��� a�[7l����cFB���{C^��%���3��PX��
��k�0#Aa���!
o����s����,,y��
m������0�������
�w���v��
�����O�����0�/�
i8"�r�3�����4�4��)�6��#�au���c������pl��l���pb4����p���3S�����S��-}VF�������H��O���\0�pn������3�a���v����t�jH�;���d���gd����W�YY��Y�N_
)� 
�&
/�:�@.����:��>
���!H�G��K�u 	���AC
>���>	���!��g�K�u"���IC
���>���!_��W��K�u!_���Qc
F��L'��O~�\M^�T�[�_����+XYe����'�#o�`�w+�	�kq���L�[��z
=cH��@���&��R0��<�������d$�5���1�`��`�?J�n;�)���� R�����y����z==cH�s����Y����6��9���hR�a;��O�����z==cH��
/��4��/�4�5��U������n�0c��^OO����@�k�<M��!
�r�#o����z�tb������1���c��5�70�4�5��u�v6�-R���S{==cH�a�������+C���G��a;��	a��xz ����C��w0�4��C��W;���i��xz"���#�p$��|�����pl��j)��0��#�CN���,K<�E��FNM^-�VF&�5|�yH�y8�m�g��ro�y87yx�TZ;�0����P�!
���;Y�X���v������N� �OO��pA.}�k�C�eA.m�TZq�L�xz*�����������
)�@>�4�Y�i�l�xz*���O���O�����a�l��f)�N�a:b�.�N��������Y�l��f��.da�bCO�R��,|�Yx�~p�&D�������r��������(,y��/������5Ix3�Y�-���0�	C
v@������[a�[l(������0u	C
�������[�`�[l���<aF���.������s(���oa��%n]���r��k�,�x,���4����`�[lh��R0#�`���K�/Dt�8X���,�f�H8���1K�/Dt�m�����`h��,�{k�,�K�/Dt����598�,���`�����`u���C�����r98�*aH�98V����,MVB����JRpBN����)�98598X�������!g�����U��3rpnrp�4Y98��#C
���3y���;r����`i�v���q���*��{��7u.�������d���8X�d�����M������`K�u �������������:���G��-M��|��#C
>���>o�|"�M��&�B>	���!_��W��7��r����hh��4�$LGF�'���_��woa�D���,�f$G����!;���_��woa�D���,�.��?�����!����}��[:���u��&��3�O���wdH�3�T�����3�����x��y��6TY~�1#���$C^@�J�������0a��[l����0#����pL��R%o�`mW�a���.�Pe�5@F6cC/���WP�����3mW�a���.�Pe��8AF�bC/���7P���S�����_��[l��|�1#���pH�A8�AX�TC�C�����A�m��K8��� � �~�����	��ReEa2a��%RpB�}V��O��	��Re%a2a��%RpFN}��2#�&'K���������pH�;rp�spPw�;r����d��v�`2a��%S0r������*r����di�
r0����)� ���&�@.MN�&�@&6�^�!���`u�u MN�&�D&6�^�!���g�����:���6[��9�L�xz	�|!_}��&�B��li�.�`2a��%Q�<!_}��&k���%nU��U�<��0��Cv�����������m4l��f�cHB��i�	K�N��.k�@�������}����5�0����4�-�����k���m�<K�^��6k���%o�am�5/^�&��Pg�����5����`X�v��Y�r��k���}�����0��C^��%o�am�5�@�������7�!k�y��������K�F��Fk�.�xX�h�a���<�����=\���aC�5��@x�^�!
G����������<;<l����<	�k8���<�<���VBNmv#��2�|	��S�y8�����_���?������� o������?����?���?���}��_��������������������_q�%>��t������W?1���7���O�X�����#�#\�G�I]��{.���+{.�~����g�![�>[$u�W�-J�-���;�-J�-�z���D���I]��G-���;-�>Z<�����H!u�w"Y�m�p���D�8�d����|!X�,���`q���Y
������{�
�Z�2��E�B��-�"q��e�1d��)�\0|�H�N��zo�5��(�P�-�*\�&���[�������]�1
���m4l���.d�?����
{���������{ ������[f8�p!� ���]�mx5%q{
k��A$o��7|emYf�?�?����
/�����5�m�\����
m��:�?�k��e�W5$n�am���$��m4l�������Q���Z��U�&m���&��m4l�������Q���Z����5�-�����
����4��ZK@}v���ZpD�664ZKD&� ^�hE���xX]i�,��m4l���0���VBN������H�F��N+#�u�Y�ie��Lx��;-����-���<L�Afu��#�������e��h��i�a�2�;��<\;u��� ��nx�tZy����N�@.������m��h��i��d!dVwZ'��Ax��;-����-���<L&Bfu�u"����+�C�u��h��i]��d#dVwZ��Ex��#8��uB��<<:�u�������:K�^��Nku^�6��Nku��������Z����5���Vw��k��l��V?c�>/�Nk��������Z=����8�o����5�T�|�e���#������X�vJ��
)y$�����k7�7�{a�>/�Rk]f��1}SpH�����}�V��~�#�qx�VZ�
8,q{�j+�u��U���H����c�>/�Bk]�%n�_m��n^�&�v}o���d������
PX�����Yk�x��(��M������E[f�A8�o�7"�&��X��~#bp�c������	��������C�{�M��@���J��@0};pH�	!85
��H��~3�o"����2�of����2�on?~����#�>��kG���-�����[�	x���n�
�N��8���\:/H\�K�Wu�U�A`�b���D��ylX��|�xUwX2�A��8���h?��X'B����U]b��'�`�Z���/����4��b]H�W��Wu�u!_���[�c
F
���
5�6-x	��jk�m���+X[cm�
"y��
=��<f��[�j{���������6���u��"k�f��[�j��������-�6\��u��&k�'f�����&k�g,��I�R0�H��MC���3��A6m��- R%n�`m���.���64Y��1cd�6Y�"U�v
��)gA$o]����V8_s#� ����V��W����pD����m��572
�i��m�*q{k��
GA$o]���z��c��������rp L�R0n�H��`C��E�`2�i��-"G���u�!�$����4Y	9���l�&+!'���}�!�"����4Y	9�����`u�����`�B���3rpns�������p������3�`�F���w������&kG�	���9xg�n�p�F���Y�4Y9���u�U���`u��6��.��d��d�&���9� L�	S0r���������9���u�u"����;�C
��[li�.�`�c�M��|��)l$o]���
r0��	�&+L���W���
p���64Ya:1c�����
n�������
8X�����
f�sp�6Y�K�^��&+x�`�[lh�������A�d,q{k��0�x��lh��,�;k��0K�^��&+,/^��
MVX��%t�`m��`��+X�d���������d�u��}��&+����W���
+p���64Ya�����Q�d�
8X�v
��)x��u��&+�	3�98j�����`�N���rphr�bh�B@}��&+D��@8��8�����X�����MVB����;�C
N��������J�����Q�d%��D8��8������X������MVF����;�C
���s��K��#�}��&kG�	�w����9��d���p���*���p0}'pH�9��9��d���p���:�����&�@>��Z��9��spR7Y'r��8X�d���g��WK�u"�}N�&�B>	�w�|!_M^-M��|�98i��8��E8��8����5��.��d��`��AEI�dE �W�����W#y��
MVt3�*J�&+:������MV���[lh����4#�I�&+z������MV���[lh���iF2X��MV�A�J�^��&+�V���64YqY0c����m��"U��
�6Y�j$o]��������{����+�T��+X�dE\���u��&+nf����MV�@�J�^��&+�\���
�MV�N�H�e��4<6�?J����4��5��n�Pe�� �fk&m�#�p $L�
�0N�H��aC�#�0���eVD���k�C���[7l)��0����mVBN���{�C���[7li�2�0���uVF�����cF�M�,u��0��k&u��#
������C���[7l��
�0�����VA.����C���[7l)��a�_3��y� <L�
�0N�H��aK�u ��I]i����a�r���q�F��
[*�y�-�L�N�B>�;-���U���i]��l���;�y�b<�����<|5y8:�4K�^��N+M������8�a���5y8:����%t�am������5�������5y8:���Hx�i;����%o�am��<����6tZi������vZi������V���%o����J��	;m���a��kX�i�xX��
:��������vZi��0�a�����W�a�[7l���Z0#�a����<,y{
k;��K��aC����k;��K�^��N+��^��
�V
�������Jy80�vZ)"�&GC��"�p$<���V����������������i%��Hx��;��<��<����CN�������ie��Dx��;��<��<����C��������i������WwZ;����aO_���<�7y8Z:�yx'<���VA��<����C.�������i��Bx��;�y��y���4| M��N�@>{u�u }��E�!
���G�����:��O��^�i���g��=}�5��y�l�������/���N�B��<����1
#_m6tZyZ�2�vZy���kX�o���6��j8:��f�H�1���Vv�!"y{
k?y��h#y��
�V�3�s�fm��=|�H�^��O2N�H��aC�������������
����T�
i7m$o��������������HU��kX�^:�����6tZy�1#9�w�vZy�*y{
k�Kg\���u��N+�	3�3}gm��W��������4��H��aC��78s3�q�Y�i�
����5�~/��6��n��i�<�������r@���r�0�ph�����y�����N+G��Hx�*�!
������tZ	y�����N+!'��T�
i�m$o���,�VB f7������1unC*�q�����je$b�q��[��8"��mH�;��$b7Yj��x'H��k��H�$��mH�8p#y[z��L�vnu�U��ab���T�7��Q���:�����.����@1�nC*�������l�H�l�fQ7['R�I����1#�M*v�����������.���`15oC*�������m�r1��Y���>K�^��nk���%o�bC��O�d\�-�v�`���������%o�bC���C2.��[�.����������%o]�3�[��1$��U�n�3p���TL����g�b�����n�s����Wm�������W�����W�����n�p���U�m���X��*��[�:��ks�3�[�
\,�{k��}.���������x��\������p��m��
�X��*��[�\,y��=8I�x��[{@.���|Rq@.m.v�vk���p��m���\S�RqD.�m.v�v+"G�����J���p1e�!'����bK�����bu�����b�tC*�������v+#g���v+#g�����T�#�6{K��#���7u��#���)�
�� �m.��v� �����*���p1e�1#�6{K�u �����:�������T| m.��v�D.>o�v�D.>	�/��'r���boi�N���p��n�.���p����~!_m.��v�B.�o�v�L�9r.V_/��#y��2����i����sD��*���.8�#y���vI�����Vq�9"y{k�Q\�����
�V�p0ga[8���*>G$o�b�;��38��Q���*3��Y���m��~U�~)w�wp$o]�lh��Gs����VY��J�/������mTlh��:cH2���VY��J�/���p$o�bC�U6�!�N��[e�*y;G����p$o�bC�U�C�AJ%/U��[�/�X�/s����������������������?����?����t���w���	x�;�o}���������<�������nm#��Q�|���������'�������g�w�x�������	C��P;�iC�Z���i�?6��,�#zO�;�:�x�����,>1d����6����N{���3E��p�;��wN�8����R0d�����6����J���3E����7N�8�����Q�K%/�^��9�O���1%����l��Y���|����g�K0�~Oxr$�{����(��gF��yo�>O8�y���^��{���uJ���W]�]�4���H��9�7��.|��s��n�o�����0�(������Q���) �~�	�$H����n����y��*����;������~�����}�&��~��	Gm�wxa������������U��=.���#��������1���!��w��U��=+����`D�Q[d@�����-�� X�V������~��	�Fm�u,��������:�/^�_<����W`	�+X�b+����m�����k����[�,�{k�c�����
��]x�����&���X[a8���#!�-8 �&�x���Gd��X�a8���!�-8"���`K���#���.�Bp�C�3�A�[pBN����+!'B�I�be�����g���������-5VF�������3�`uM�#�M~�P�{���w��I�c���;�`uOY���6[���\'u�U��K�����>��K��-M��|N�&�@>���9�7�|49���L�-�D>'u�u"�}~���{>���&�x���_��'���n�.���<����x/����&�x���
���K�@X[e�|�H�^��_�9'���u��.�tf�?�%m�u:�������<|�H��aC�u�3��'�xc��gP���������6�Y�/��|;y��Y�6U���>�����J��aC�u�3�/'O�:��A�J�^���?���Wu��}O��8NGB���Y�>U���>�\^=���7>
^�4	�kX[h�+U��kX�������B����a���Q�~����:70�����:-m`T%o��C�u���]���:�p <L���p@M~��{������5i;�3"G�����!
G�����O0��a���xX�i%��Hx��=���<��<��&�6����au����S���Y�������s�_<����3�p&8���VF�}���C
���s��_<����w�����S7Z;�����g,�[pA��0��Y�\��a�.�
�p���3��n.Y�4Yx��Y�p!,��}��,|�Y���J�| 
m��Y'��AP����Q����3O��-�D>�$li�.$����S�Y���'�g*�[�� |5Ax��Y��E@�i��kB�� ��3�[�&�`�[l����`F��N�e]8X�v
��*����%n]����\�����U����%o�`���^~�������d]8XB�
�6Y������M�5;�xM^M�5K�N�^�d]3p����m����������d]��	��{��K�N��&�Z��%n]����V�	��{��K�N��&�Z��%n]�����	3��)x�����M��K��`C�um'f$L�Rp�Xp���y�o�98�9��d]98���)8"�>?�����#rplr�jh���	�c{���L�����c��WK�����`zn���rp�s0��RpFNM^-MVF����MVF�}�c�c
F�M^-M������9x�s0��R���79x�4Y9x'L��RpA.}�C�C
.��������:���`zv��������tzH�r������d���`zx���O���p���:���&��&�D>	��{�|!����M��|�9��d]���`zx�����/�5�g@���6�	�k$o����z����5�{
+���4��y���&�l:��5��U����z� #����)�(��������{�a����n��e�e\!#�����i�gh���5�]�[�/~�<,�a�����+=�uH�s��������u��0�<��
���2-3�)We��o�������Y0a��[7lg��"]����*��2�6�?Z���a��y����Yo��H�\��C�<4�����t�~H�0b��[7l���"���l��^�4&hx����� ���a����n�Nh�EB&S6~QZoi��C��=��pDm�3Zo����_���[��Hp���i8!�6[��8L�l<=cH�	q8�q��=�1
#�&K���������ai8#g��t�~H�y87y8X*�y�������4�#����&���w�������i���d����>���<����C.�������i�a2h�OZ���<\�]�!
��G�����:����
?i}H�'��Ax�.�i�D>�<,���<L&m�I�cF>	���!
_��g����������
=cH���Ex����h�M��W�����r����5����<,y��7<�t��k����rn�����/��[��O����������������������w?���������_���O������"��o������������g��������_��������������������>���?�g�������OT�Vj@���q%[��D���������I�O�L�|������EC��3��'m�6�����x�<P��sm��*�[l(]p���<iK@��*��a�����������������?��m�o�?>�o��/�U�����_�����O���������wK������W��������������������z��w{���~�i���Y� (�a��VT���1�V`wX�e%��;�H����0?���
Gx� y��Ue%dL3����!
'x� y{
?����
'x� y��Ue%f�0#y�@�=�p^�a�mM��1��$o������f$��'C������5������8H��aUY��w�����<���X��qk�E�!
x� y��Ue%fD,.���:������:�&����W���!��J��\|���"C>���G��1��s���|�U�fD0>�z����O$��<p����0�������� ��<|���i�B��obi�B��<�T���3�	��Ex��~2�a?�����5��S�[�����[7l���s���Uz����|�H�^��N��P�#o���������tm����
�p����y��
���f������3HU����vZ�y��
���w��?'�m��g�������������[7l���� #L�A�i�����5���<�%<��
:-��H�w��4��T��_��%k	��u��N�o���'�	���C�@�J�������0���[7l���~-1#y��~�~H�y8~f�����ph�������d5��~H��8 ~f����#ql��,�VD"&�	���C*NH���3��V���S���d��"1YN�_�RqF$N���(����H��H�&K�����v�~�����3ab}��#�&��Rl��d=��~H�;B�N�����{+.�{��di�
R1�O���RqA*.��������b7Y����,(�����@,>?�Uzs���G��d��N�b����c?����$\��F�?���[�����(��.�.���q�������[�����(�sFT<O����gKo�x���%o]�3�[�t`H��� �!;�b���X�n��X�6*6�[��1$��x����+���x�����s��w���]������_;�����9�T���vf�"�w~>:��O��8��_�>7�O���04���`H2���|�7�$o�o>m��/����K���o$u�bm#��
�R� |\���e�������Q��\�ARw*N�Fp����A��bm#�8��Y�[�G��Fp�I��X�.~���7t�Y|��b�#��Q�#��?_�e��5<0�/�&�:��'9��������?z�+O��t�oy�������/7x����o���R�D��ym���}G����7T��
RR������g�a:P��K�F��Mx���w|��5lx)�{�%�
o` %n/�� ]�/^����
�%����G��Y����|��?�7��"�����%"_�>_<�I}s��"��_�pD��m���zt�����	Gpo�	�"��_�p�;���oh���t��@O���
gx+G���}K��$o�aK��wIz����/�H�^���o��$o�aK��'Iz����F���?�L,��pA��<�-5_A.l�^���<\�������������@>��v���Ax�����F>�<�-���<|�q�>��O���L,����<|vx��i]��';H��y�b<���.������N�B���6m��N���a�3��	xX��
��Nk�IxX�i�xX����z�xX�66tZ��1$�am��z�a��kX�i�xX�66tZ�O���3��1
K�^��Nk�=^�6��Nk���%u�am����������Z�	/^��gC��.��������Z�a��kX�i���������Z�C�y�~YtH�+����5�����K�F��Nk����0=$kH����������<,y?�������G�/���{/��Gb������%$�_dRr@$M$~�f��~q�1]`�oD ���<^#ql�k�����c��������#��E�V:!�&�v#}o�	a8VZ	a8V?�x���	���F��oF���uVF����M��(��(��M�����{����!���;�����#��)z�~b���`��fH�1�N���1��gR
�=�K�)e��@>'���!�h>~�����"�}��2���� ���5���{�	��D���O����@�|!�����Y��|��[�	��0E�o~~\������&�����v�
��3����+c
���+X����-x��g�:������S����|�H��Wl�_������>��Pbm������%���D��
�~+k�'�x�so
-�6����S����fp��W�����/^��[C��-3f�zK�V���D�����5���E��u��k[f�yK�V���E�����=���F��u��"k[/��?���)x��`rb��-��
<���64Y�v`��q�tfeH�8X��
�6Y[@M~���{���������rp�s���M���C��_<����#rp�s0�XRpD����MVB�M~���{N��������J���q���������/�qo�98�9���)8#g��N�de����������98V7Y;r�N8����9xor��Gu�[pA�	����\;u�U��K��_<������K���������B8����9�hr��u�[��|�9���)�D>;u�u"�m�4Y'r����M�d���'�`z����qD��[��9����y�!_���`z������|59��S:n-8L���S���
p����m�����59��C:�-�K�N��&+8�`��+X�dw��kr��gt�[��1c���0���=p����m����u��&+�3�9��`)x�������C
���%o]���
��	k����X0�`z�����`�[lh��r`F���&+����W���
+p���64Ya�1c�����
+p����m�����kr�lh��,�;k���K�^��&+�����&+����`:�1����#����C��
MV������t�bH�98~b������c��K����c�������rp"L<RpBNM^,MVFN}��C
����q������������������A�d����q�������&/�&kG��L�/�\��w�����!�������d��B8X�d��B8�v<��9�49x�4Yr�A8X�d���`z����O��������:���>Gu�u"����Q�C
����&/�&�B��Lw/�|!_���I�c
F��lh����%�s0��Qp��D��
�6YGk$o]�����c��AEt�bH�>@$n�`m�q�F�V��&+�	3�*��C
��"q{k����5��.��dEb��Y�t�bH����yEz����q�F����8��?��N^)x�*q{k����5��.��d�%c��i�Q�d�D����>#q�F������y�������!� R%n�`m�q�F������y����Dm�7��W����8U#y��
MVf����MV���p���J���[lh�bD&�5I�d��	���D���u��&+!���x1������D\���u��&+!��:y1���������s5��*x�4Y9������!����p0=�xH��W#y��-M��LVk�������w���&k$o]���*��d���^)� ���&k$o]���:���n
]�R��|���)9�hr�fi�N�`2\CW/�|"����i�C
���[li�.�`2\CW/�|!_���i�C
���[lh�����k������ ,y{
k��4K��aC���3��V�{1�a7c����y�Cv@���n��e%W0#�o��C���������JPX��
���3f$�t�bL���������J��W�����f�XXB���Yi�����uVZ^�&C���a	�kX�g�hX����Yi���5i8���.�������!
���������J+����6Zi��������!
o�����0=�xH�����64Z)L������Jy8��i8 �&C���p`<���RD��������?~�������������m����D<����������O���?���I_9��i����9���}��������������������?|��������:���EA��	I^�(��7����c��	G�:��Q�xH����*��'1�Zp�S'$n]��{������s��������*���3�:!q��U�fD.��S']�R��\���N�����.X��aF������Kc
F,���N���)�,x���NDU����K��	G�:�\��K��	�]�!/^������0#B��?u����!�G��	�]�!�^���QU�aFd�����KC
>�������"c
>��5O����
2^��g��	G�:�|!_���wE�|!_M�������Z�b<^�a<�����]�g�������
vf$V�.u)wl$�g|WdH��c����Y|bF"U�R���q�F�~�wE��;6���y��a��`F��]�R0��H���*���q�&W;6~3,x����bD�:�&U�~�W	��;6���y��a��a��1���6Ywl$�g|�`H��c������F����`m��q�F�~�W	�|��k�_�MV��H�/�KC
���9_%�0��j��p�
���Et�cH�8d#y?��C�%�\-�<����$\��|������d#y���a�������,F��l>nX]f�����b~�q�&W[6���6����A��V�Y�e#y?��@C�1�\��<(����0\-�|t	�\����s�����4�k6�Z�y`�a�;�p5i�q��>�l$��|hH�8g��9��6\��M��VZ8g#y?��@cF��l�n���<\��|�����=��9_�0��j��w���������;-\�����}�!��M�&m�q�oX��D\
�|\����M������M�Fm�q�oY1"q5m�q��Zk��/������H,yz�}*�01]�R�&��_L��X�6*6[���A����@����on���x��P�v�oX�*����������%��|usH�����������g�bI���t�cH�3`�����D�������������C.�C*^��%��|gnH�p��mTl(���cH��t�cH�+p����o�
�x.����
���M�p1]�R�\,y?���C*���%o]�3�[�vbH��t�cH�a��	��E��C������rq \L�<�T���b���#rqls�3�[{D.����������#�b��!'����bgi�rq"\L�<�T����b�
�!g����bgi�2rqf\�n�2rqf\�.03rqns���[;rqf\�n�v���q�������6;K�U��w��t�cH���0.V������Y����.��C*>�������C*>���[���� \Lw=�T|"���wa�T|"�.��['r�I��{��B.>	�o���B.��\�-���\|.��c*F.�����������mTlh��gp�j������V����9��R1N��j���V���R
�|\���*�}#y?�;�C*���Rm������=��Y���+��[�o$��|)vL�^=����/������������q�F�~1��M��o����a������~��R1��H��y�H�8S�����V�N�����C*����9o���oJ���o�[V|b��y��|�p$��_0�b�)��?�voX�V0d��_G>�T�8��s�/R1.��j���7�8 W;8W�m�
N�H��9�`H�8�S�	�|�����\	o�v�D��H���`0�b\�����-�VB.&�7nS�[	�8.�G���8��x��[��,��M�ne��L���a0�b\�����-���\L6p��n�v���q��c������-�VA.&+8nS�[��0.VW��#y[���\Lvp��n�����b���N�H�F��r�@,&C8.����� XL�0R1��H����������K-o�^F$c������:��OB��;�CZ�%�[�"�vG}o�r1Y�qA�n]���bm�qL��W��_�����c*�������1K���f���/�zM*~�n�����	m�u8`b��9��R�&��U���K�[���q��Z�"����}�!{ b�[������F$<���1K���6���g�a�[��S��>1"�������c��)1������a�[��3�{^
Fd0�m��`X�~�����K������[��1"�`m�u�����s�d5��m���~B���{��%t�Fm�ul���s�c5��������# 	B�Q�eI8�_��0�p��7m�pD����:"�p$(L�~3���(;��
N����pT�Y	Y8����pBN����:+#'�Q]ge��L`�~�fH�a8�[���4�	
Gu��#
gF����;���~8l)�v����pTZqxg8��;
�pi�2mi�
�p!<��VA.���7o�4| �6[*�y�`<�������0�����O������N�D>�;�y�$<L�w3�a�����/�qo���Ix8�;�y�"<L�v3��y�j���'z���9�x		'm�uN�!"y?�[7#>qG��
:��9�H�6J�N�t�!"y?�K7C��[7l��NwaFr�Q�vZ�_�ar'�����qG��
:���������9�T������!
����6tZ��cFr�o�vZ�RU�~�7n�4�8��n��i�K����_���1
�T������!
����6tZ�
q�l'i;�s�*y?�7C���[7l���
��<�N�vZ�RU�~��m�4|��C�*
:�3������������a�m�!
�������b����<L&p<�7���<	���i�o$o�������d�O�N+!G����6C���[7l���0����������0�����q�F��
[:��<L�o����v��Lx�~�fH��|#y��-���<L�o����v����0�����q�F��
[:��<L�o����
�pa<���p�F��
[:�y����I�i���a�����&��N�D&�7~RwZ'���xX�Z������tZ�0���������/���
������tZ�0Y������&����0������	xX��'x:�k:0#�a���.<,y?��sCv����n��i]n��������<�����/�
i�K��aC�u��	;m�uy�a��9_������5yx1tZ�<,�{
k;�k������!
/^�&/�N�Z��%t�am�u-����s�V5���^��C�u�3f$<�����K���j���W�a�[7l����aF��N�i]������U
ix��u��N��.�Hx�i;�+,�0�a���!
����aC�u���xX�i]y8�_��������������V�m����'�!�_x�������oz�>��{������w���u��iz��&~��������������������?|�������~j����8CP8�B��?���
2&$��?�����
�!��q��Q��o��($m�����0#rq�F������f���?���)�[��p����Uo��8����~�x�x;Rq�E������p����U�n��x�D��x�������A��P��o���5��XU�fD".�c(�/�0q�C1?������]��UU�aF��������C>��P<�/ro�^����p��'���?�����
�!
��#(^��3A����	��k���������$�U� fD*&/�x?�b<d����xyB��/�!X�U����xL�ss��P<�:��[�_�<�v�}B���[�_�<����:A�37���~�;A��_2s���������#m���h���r���w�h�x�KVn�Y1��_��y����TEd���G�N�t�|H�0r����w�h�p	�]{�fSm����D��y�!����#o����
��v���MU�a���H���C����G�N��E�[���n6U��3f$"�>J��	����g6�n��mi�~UEf�����x�(iH��o����w�h�p�n�H[��*�0�������������3s�����������1E�_�m����!�F�_�m������F�����f���/Y���Q��~�/Y�yf`��~�o{�f��W����x��aH�����<3/wk����j�Y����KVm<]�����KVm��������i,����K6m<}B3����K6mVmU���6��_�_�h���1�"��E�g�o��@�m��Ku ��=O����@�%{6�������^�	���D�%k6�>�����K�l��
��_����M��W�/����	��~/�_�e�j�����d��������OhF��&�_���W�_�	�W����+�&�H��>�������x�������u�����3��Oh���=����g�o���J��_C�|��������%o�_e�f�_I[�k����1#�_m�f�_���W�_�e�k���h���>1 �B��>����+y;�*�+�:�vM�������������r+���������z��k�o4�Wn[0#�_��fH�����������+i�~
��3��Oh���C����������
�������/}B�J��:-����D<���������-��������������?����?�����W?���}��_�������~���|���7\����uR��/��- ���4�������>�g�?�g��7������#��?d<�y��������	�+y;�)?Mx���)FC���2^�4E�LkH���m�{fN��~O�v������a{�������a{��������ay���������<���W����<����W����;�H[�kh�f������m�f������l�fX����M��o���G�N�����~au��������as���������9���W����9����W����8�H[�kh�fX�����m�fX�����l�f�����54~3��?B���6~3��?�v�U6~3��?�������{�j��6���#o�_�7�f�����5�W3l�?B����Ws@�%[�����o@�m/�'C5G�_�4O�i
�7"����gf�n�7"��w�������lg�>��oB�%;������oB�m��'K��������2�/Y�fr��~3�o{c>Y�����6���!����dc����[�����n�X;0����h��L&���[������w���*H�la�>�RpA&���q�Z��\��&K�u ��y��fH�"0�fO�������n�tX'20���Oi�|"�}����Nd�����,%������c�!_��T�g��n-�Bn�����b]H�l]�>�Q�2�'9�;*[�e��I�(�Pc-x�������� 9�����[v��!iz�O������=���d!{?3�xk�>?$m�`C�������W���Z<|�,�d��,��y�k����
M���{K�^��&k�A�.�h��l�����C�*;C������S0}X3��L�B��N�&kY'�v�Q��O������M���I]���I�d-���=��`C������W���Z60�9�;)��e�*i���������M���r�wR6YK@mv�&k�C�%u�`m��D�`r�wR6YKD�mv�&k�S�%u�`u������I�d%����`gi���oI�+X�d%�`r��cWoH�A8�A�Y�,<�[R�VWYA����&m��#	�	[�,<�[R�VwY;�09��M�2� 
���Yx����5�.�
�09��M�6� �6{K���}K�N������dar����u��0|�a�[�,<�[R�V�Y'�09��M�>�D>�4�G��e��.��.!���
�y?���������?=�y����8��p�_��s?11J'��q��I}}z�/���O(��|F�����J���I���8�-q?���o�S�W2��>���	}6��J�Ov���[q�[�6
64|+����n�i=ps��b%(�I���8�-q��Q^�H�������b%'(�I�����-q�R^�J�������b%G(;�,�V�����
��')�d������^�+Vr��s�~o��n��(����x��Jv���I�����?dsNY��8�-q���R^�P�������Vr��s�vo��n�[<��S^�R����.w�L�QvNY��8�-q��5"��n��]n.8"G���G�+��Q���jkB&[���/��\pBN��)��(g�%n�`K�����X7=�|H�98��>�`�������d���d�����9xg�m�p�[�6
�4Y9��u{u�U���`m��K��Q���*��d�����9���>�`��������������:�^EDa����e��(|��>�c�����/�k����{"���Y]e��'a��#���n�[���M���^��d�{VYb�E0�R��z7����U���B�Z����#nd�c��X��W����p�C�V��v}o�(�����-�6�W����p�C�V��v�|o�~���c_fm��y�����z������������;{��?�t�X��T���UX�~H�����[�2a�����������W����p�C�V�����zO��?�t��W�:c��#	�������m�Gc��Z0c���Y�]m�S����r��~q�C�6��e���1c���Y�[m�S���W�[m8�!q���}����-�����R2�/�~H����~#�/Y�X����}#a_��C�E��M�}���{�M�d�cQWW	�7��l>�_���u���*#����E�]e��L�����~q�C���Z����,,��jG��	�R:�/n~H��_K{�#����E�^����/�����������W���~,���@�-���.~H��_Ku ����E�_���_m���~o��_���d�cQ�W'��I�����~q�C���Z�����~,���B���R<�/������&���0!����U�_�	�W���U�Wa���u���*8����j����%n�_e�����5�W�O�������
�W���U�W��J��_C�����j��0��/�_��#���%n����
s��}�]��UX�%n�_e�_�[�k����1c�Wm�_���W�_�u�k��_CV�_	��W�_��W���U�Wasx���k����+�;�j����J�^���*l^�&��x����3���W! ����G��C�_<���~#�o ����BD���)���7"��&��x����&�����M�_%��D�����~�oj����o��/�o������2�o"�K�|D��77����7��7#��>�n��jG���)���wG����������#��}����������x>�����7����7��� ��>�n��� ����G�{ ��&�����@�=�������� �K�|H���G�-����{��wS�W'����W�_���g�-����{��wS�W����W�_]��W�C����oM��F�.�W��e�2�n@��]�)9v	/���(��b1E�EJU��<B=+��AW�G@�i���l�r�c���[P����
�-�_��"W�����������=�[1�
�A�z���t~�=D��o��*��{��b~����Cc��*x����-��4"��o��*�5�x���Uh!=�������#hD�����Uh'��7�K�W���T�j���N��G+�W�������K�W���T�j�����G+�W�������K�W���T�j������G+�Wa�P��}w,�_��S���[8�
8~F����_���F���X:�
#�����p~p���=�[1�
����K�W! ��������gD����f~����x~��_������{��f~����x~5!�F���-���3"��o��jB�%hB��jB���R<��'�����5������	����w&�K���_<#r������_2~&������/�s��$��5����L�	����w%�K���_�9#r�����6�_2y&��6����/�sq���=�[3������P<���w���-���3"��o��jG�%�gB��*6��;����Ul�E�����Ul���o(�_E�+r5�W������C��*�	5�-�_E�+r)�[��[\�$�����E��o��*z�_���[8�����K��P1��-���N�`,�_��W�j���b���%�w��_��C�:����U��E��o��*v��"��o��*�5��K�W����������������84�Q��X:�������-�_��W����_�aC�:����U=�K������#������b~G��Q��X:���w$�K��������[1���7����W�70�-�_E�������UD��:����UD���K�W�oL��X3���'�����	�w"�K���_��)��c��jF�����f����/�sg��9��c��jA��u�uL����B���������f��"/:��x��"���)�[�"�Ik&X+���k�GX"�J����"��D��f��!o:��x��#o��)�[�#�IkfX;2��3�k��X;B�N �2�����G�+�XS�2'6��)�bM
�AD�fp�k�	4"�hp�kr�)sbsh��1���
"z5��X���G�+�X��V�D����&o��\8��p��=*�XS��F���)dM-���7-�SL�0���������s����mJ'YS9���.�dM8�F�
��dM��I/^W:���
�ez����{4�b�5�+j$�x]�$k I������	��������i�Q#���J'Y�I���.�dM8�F�
��dM#r0G�J'Y��<��)�[��hD����I����<W:��rp�9�SL�0G�����5�������IVD�:{��&#�4�L�&�`6��O�&���qp�$������5��9���q���9xf\:��i4"�`p��d���l&�+�d-��3�`���8�{4�f�� ��4�x��"/��)�[��hD����I�������I�����na0��G�k&Yr0K��'Yr�F8�b���8�F�
��d���l.�/�d���;�`���
r����X1���`�\:���`��\8���
/���b�5�5������^���I����E����I��j$�K'Y������������������p�/�d�m�3.�d�-p��=\1���5��������������]S1���E2.e�=���U��n�p ,rW���>�HF�����������y��xIvM�0k�E��p[:��@a��9\8���/�����f�#��HX�-�f�#��HX�������c��]S1����H`�-g�a8��n�p@IvM�<+"
B�m�<+"
GB��-�H�1I���hE��Hp�-hM����0�u�'��)�����hM�����x�5#O��)�[8<#�
���f����p[<�Z��g���#�yxQx�f�� /�������<�0.�i���K��]�LkE^��V����0�u�7��5���f��!o���gZ��Fx�������[��]�LkG�w�3�yx'<Lq���yxO����i-M�KHx�+�i-
�DD��p�Lk��5"7�p�LkqE��E]�Lkq�����3�������3���(��-�JgZ�o�a�����n�0���	�+fZ�_Q$i������BU��9\8�Zpr��M8\1�Z�E��]�Lki!T����3�g�����3����a�����BU��9\8�Zpz��M8\1�Zz����!6]�Lk�!T����3��������b���dsacl����2@�*z�)��8���a���PE��E�.�]�Lk��G���-�6"7�p�Lk	��l�M_:�Z�p <Lq��a�b#r����0f���"�p <Lq��a�c#r���"�0g���&��Hx�����8�F�&��iM��l�M_<����'���-�Y6"7�p�LkFf#m�����<<��n�0N��	�kfZ�0�i�������0�u�q���M8\3�Z���P��x��"���KgZ8�F�&��im��l�M_<����7���3-h#r��53�y�����gZ;��Nx�����8�F�&��i���l�M_:�Z����0�u��xX�&��i���"	�3���^��������En������fIxx(�i�xX�j��V����y���i�xXTk���V<,z5�gZk�q��<�V���xXTk����xX�j������K�p[1�Z;�aQ�9\:�Z;�a��9\8�Z�
y������W��29d]��E��������^���������c|�f:���C������:�^�����:�����m�3���D��C�Hk[���p�Hk��$�������0<2.h�ax$0LY����0�0|�6:��Q80.gD�@P�����Q8$Q��Mt^#�p$ <�"�p$ L9���	A8&A��c���N�����x�5!O�)�[�;#OI��P8��3B�L x,d��3�`��&�"��C������� �����1������xn���������;�k�����X+�J�����+����i0�Jx,�`mH�+!`
�oH��R ]��
x#<��vD��!p�kG��������;a��x��#���gX���G�+�X[�672����C���7��U��na0���G�+�X��N�l���)���
"z5��X���G�+�X��F�l�<6���� �W3�p���L�{4�b���j�;��P:��Z�QE�fp�k��6"�hp� k�<j���P:��:�QE�fp� k��6"�hp�$k�����u�t�����^���I��mD����b���j����P:���
��kz���@�{4�b��
j����P:��FHRE�fp�$k�y6"�hp�$k���PJ'Y��<2.�dm8�F�
��dm9���q�t�����8�t���lD����IVD&#m�C��G��H8�b�����1��w���k��L&��P<����'���-�Y6"�hp�$kF&m\,�d���3�`���(�{4�f�� �y6.O����p0�t�q���=\3�Z���8�'Y+r�B8�b���8�F�
��d���d������
9x%L1��`�c#r�wVj&Yr0f�b�$kC�SL�0������5��9���q�x��#���)��7��{������������������������q��|g����5������^���I����E����I��=jd\:��=p��U��na��G�+&Y{��F��������������G�+&Y{��F2��������o�.�k����w���w��������������~���������h?~���|�������_>����>����
�����y����~��g�wy~��w�o�!����}�3�}&F�T����g�b���5�Z��t���U�6���m��������*V1��������t��G�U�:��	��
������a��=.���XnJ������_'<1�3��n�&�TIC����>M��\YnJ�����I�Nxb�gf�g�TMx� W����h�����>����U~;��l��p��pA��-p�PDk�8]���o���
�q��pA���j$w�����
��W1��p7��+.����5����Frg�)�mH���T��l��o��[��������1.�������'F{f6xG�����v���p�+\��5
�Av��OL��j�E���*�hp�$�"iE����N�����A�z�'Yu,�����d]$����Q��I���v�������
�,�����d]$E�H��]�$��f��~|tb�gf�[���/�ga}�$��q�-9�v�����n�2�S=3�5�x��������4v���N�.j&0���(O��m����A�\/����E��V�N���$���^Fyb�gf���� U��dm��P#��v������2�#=3<L�x�bp�$�"iG��V�N��f��`����D�����c���zI�Er��8�p��59x�9��@��������^�u����IVD:����������L�"rp$��'Y98�|b�gf�'������I��<����	9x�9��4�����S��k&Y3r�L8�O�f��Y���<s�<'9x��d-��3�`_<�Z����O���l���$9x��d����`Z{nb����|b�gf�W��5��C�$kE^	��I����|b�gf�7��-��C�$kC���I���.�d���{����I���3.�d�9x'\:�r
p��=\1�rMD���K'Y��iy'&yf6�y\�$�,���E�bp[:�r8X�*�N��op��<TL�������,���E�bp�$��
/���,����p0��ibp,z�K'Y��G�+&Y�s��p0��ibp,z�K'Y�����I��v�H8�^�41���`��O���lp,r�WL�\��F�������p��U.�d]���xC����I�f�H8�^�41x�����,7"�I+&YnD	��6#���K'Y. �I+&Y. ������O�"rpHr�X3�����qp�$+"G��O���m0rpLr�X3����#�`zA���	9x�9��8��O��S����I��<�4M���g��O���l��<�9�f�5#����M���Y���<3� /i��d-���`zA���9x�9��8�����k��C�$kE^	��&o�����'�yf6xC��j&Yr�F8�^��19x�9��8�����[��C�$kG�	��&������'�y�5�7���*&Y����y�\:��
�AD�bp�$��_ bp�$��4:�O��4Mv������,�6\<|����,�[���)������� �7-��8��{x������,�:����������-$��W1�t��[RE����I�ow����������]���4O���lpA��=\1�����~��^�41��$U�*�N�|A��=\1�����~��^��1�T��\:��C���A���X1��C�������&���^���I�=.�bp�$����#�`zA���9x�9��8����1���b��r0�[��M�rp�9��8��#�$��IVD&sk<��ibpD����'Y98&98�L�&�`2����&O�����I��<%98�L�&�`2����&������'�yf6xF��k&Y3r0�[��M���Y���<3� /I�5��9���������������x��"/i��d���dn��4M^��W��c�$kC^�\3������O/h��!o:��I���%9�55��A��������;����p,e��{�]S1�j$a2���+��
���U.�e�
���M8\1�j�C���M����U.f�PX�&��f�nG����%M�}�.�f�XX�&�g�~E��K�Ym0,z�K�Ym0,rW���vF���K�Ym4,z��[=��W/�����h����V,�5M,���E�fq�H��=�^�]S1�j{ bQ�Y\:�j{ b��Y\:������)H\1�j@bQ�Y\:�j@b��Y\:�j�
WOa���V;�(�01��ib��L<�L|����xD(�P�*[m@(	��&���C�e�Z���T�T�j&[�8*�W6M,�H�A��������8������"bq$XL/m�X<!G�/���O��S��]�lkB.��k�6#O����[3r���bW3����g������xf\\<�Z���4�����\�0..�n-���bW<�Z���4�����\�.��7M,^��W���x��"�i.v5��
�x%\L�o�X�!o��]�tkC.�.��n����bz�����x'\���[;r��pq�tkG.�	�+�w
�Gv���t���T�{��WL��fC�z/#O/q�X��="z5�K�[���	�+�[�[P�����k�&{x��^����V��mDo����V�'�����"����������g������������p��UN�[�WE�fq�t���6�7aq�t����fGf�xz�����U��Y\:��p���MX\1���E��}=��ibq���U,����'�������n�(R�����N��WE�fq�t��7�7aq�t��w���J���#p���,.�nu8�F�&,�H���y
���5D.~5����������7���/B.�����������?��T���������"�����������?�����<�/�)����� ��q���g�������W��O����~�#"F�s��F��w�����w�b��M�dx�Z����U��1����>�"z��5��	�L�Q���3�L��pp��M8\3�[0�����8� _,�/�g}89D�&�����d~
ZL^/V���>"z���6�2@��,&oH���I��	�k&}�� rb�����6r���}8<D�&���x�FF��������3������s���37��p�b��7�$gn'�_2;<,r5�K�|�kq������_{��.�c�et��"\1�DL^� ���L.�����%����t^=�hV�=Q���_@,r5K�Z��q��@|�V:��m��y[�H�o�E��o�H�o�E����6�y��<J$�m������������F���oP"9i+g�=�����-g�=���=�{�&:��Jd����Z���p[:��a�{�������J$\:��G�`���[:��G��1������wDu�9����#���AV�����}G�y�
��A�_�"������x��C�H����G��0ML���pW<���1}"\3�����N�4B01xB�w��		xR
N+<#O:����x&���fD�Y9�h��<�LC�d��0pW<�Z����qp�kA^t�)���+B�B �+b��k�4�f��"�:����
)x%�O�6��-}\3���7���c�
1x#���v��-]]3����w���s�9xg\:�pp��=\1���[o5dzM,x��\���A��sCD����I�����@���$��`/��]�(�d
86D�+9*&Y��P��
�&	&{x��\���I��SCD����I��z���H�I���-�"W3�t�5���{4�b�5t
j�;��$����T��\:�pd��=\1��
5��Qi�`bp��`�g��K'Y�G�+&YC��F�;*ML H��������������a�P���&	6C�*r5�K'Y�G�+&Y��L&��$���9x$��N�"z�WL���L���$����O�pP��=\3����dZML����qp�$������5��	9��
�I���r�D8x(�d���{��R3�������$�<#�����I��G�k&Y3r0�B�����p�P<��!��hp�$kA&SBh�`b����'Y8D�
��d���dFMlF^	��,"z��L�6�`2!�&	&o�����x���AD����I��L���$���9x'<O�p0��=\1��`2�&	�
p���.�d�
p��=\1��G���K'Y���������������7�Q�`�$����E�fp�$k�����hp�$k�j�9�&	&�
&<�N��8X��sTL��vA�:�$���8X�j�N��8X�
��d���u�I�����"W3�t�5�-.^����I���h���I���\���I�88\�$w��q������q������q�q���UL���C�:�$���9x$<�N��9xLrpW1�r��s0ML���p�X:�rpHrpW3�����pp�$+"G��c�$+"�$w5���	O�&���8�x�5!Oi��dM�����4I01xF�O�f��9��5��9x�9�&	6#���C�$kA����L���E�`�$�� /��C�$kE^���L�V��U�`�$��"���C�$kE^���L�6��U�`�$��!o��C�$kC����L�v��M�`�$��#���C�$kG���WL�B�p	u�I��������.�dW#z�WL�B��F�QMLvLF+��IV�Q5��hp�$+�5���h�`b�����.�d�U#z�WL���Q����&	&���\���IV�a5��hp�$+�5�
{i�`c0�"W3�t�pZ��=\1�
��df
ML� H����t�p\��=<TL�B�4ZC��{RE�fp�$+���{4�b��5�
{i�`b�A���.�dX#z�WL���P����&	&���#��X:�
8�F�
��d�9����I���9x$K'YG�����5���L��$������I���G�k&Y9���I���rp$�'Y8�F�
��dM��dp
MlF���I���G�k&Y3r0\C��g���qp�$G�����5��9���I���r��8�x��#kD����I��L��$���9x�9����1G�����c�$kC&�kh�`b�������I���G�k&Yr0\C��w��M�`�O�pd��=\3�������$X��]�`��N�b,z�WL�b3�F��i�`b����������E����IVt5�L����E�fp�$+z������b�=p��V.�dE,r5�K'Y�mp��<VL�b,��K'Y��������n�xI+&Y�kQ#���IV���E�fp�$+v����hp�$+�5��4J0q������������������Lp�Y���C�v���8	�����b��5��4L0qx������8"
�I��8"
�:
;�&�8��G���t��pH�p��f��,tv4N�qa8v����0�0j�Ya8�0�h�`�pD���]�<kB�I5��	ix�i��@���	qx"8��Z�����P3���'�ML���g���x�5#�I5�yxf<\<�Z�����x�� /I5#�yxa<\<�Z�����3�yxM�p�LkE^	�H���
yxe<\<�����4���6����0�L���7���x��#�I�53�yx'<L#���w���t�5���{t�b�55�\sbSlh�`����KD�j���&`#z�W��&�5'6��F
&;x��^������lD��������������H��a/��9\:��p���=:\1���5��4R0q��PU�j���&�a#z�W�����F���F
&w��^������ClD�����������������}���5�/�iM8�F���iM��I_)�8<@�*z5�KgZ���G�+fZ�0�F���F
6C�*z5�KgZ���G�+fZ��<����H���yx$<����&d#z��b�5b6��f
&�@��-j�(����f����D*�X��#!��x���lDo������H�f��T���	�x"H���p���MX\3�����T+�X<#��������	�k[3B1�kCs����@q[<���6�7aq�dkA*f�mh�`b��T�*n�'[8�F�&,�m���l�
Ml,F,^	���-k#z���6�b6��F&o��������	�k�[;r1�oC��w���qq�pkn��w��+�[s\,�5�K�[s\,z������l�zi.v����(�p1�L,v���W��t�5;�b����b�5{�"	�l��b\,z5�K�[�.�	�+�[��Q$�b�-�X��h1���t�5����7aq�tknWI��f&w���W��t�5w���7aq�tk�fI��f6�^������w�zi.v���.�������.������y��zi.v��y.������y.������ylp��\�*�[��\<2..�n�#r����t�5��������9 ���i�`bq@.����[�8(\\3�����p1�L,����pq_<����1���f���#�b�-�X<!G��}�tkB.��\�k�[r�D��f&������x�5#�i.�5���x&\L����g��}�tkA.��\�k�[r�B��f&/�����x��"/i.�5���x%\L��W���pq_<�����4�����\�.�����r�F��/�nm��[��}�tkG.�O�v���pq_<�����4�����x\C�����������,.�n-8G�&,��n-�A�d,�L,v�������G��������m(�L�������E����~(�n-8G�-n+�[�_P$�	K��[�WE�fq�tk�18�7aq�tki'I���l��b�WE�fq�tk�A8�7aq�tk��9�B��8�-�X�A�*z5�K�[���	�+�[K�92��l����U��Y\:�Zp��MX\1�Z�E���L, _��������������e�(Ro�h�`b��\<.J�[N��	�+�[K@.&3q�L,���p�P:�Zp��}-������W��q�k�.#�1���h�`�rD4��\8G������
��d,�������qd`\<���8��`�]��O��d*�����������x��qD�������
���PG��g���@�X<��y8��`�]���/��d&������"�B�x,l�8�{0���tf�Wb2��P����x%@<��p��=|�1qf�7�a2��H���
qx#8<�p��=|�!qf�w�a2��@���ax'0<��p��=|�qn����<G���9x'<���8X�&:��sxm��@�t��:a��9\:�Z���M�b����P##��Y����E��p�,k�-�^���b��z@a�8L��=����.f����S��+:��h���i���^��P:�Z�W/}<\1�Z�5�q�������.g����=:\1�Z{�	
�<���hX�j����hX��h�C�	�@���pX�j���pX���h���	�D����E�	����:"�i�i�#��Hx�F
&����p(i�y8�y�b����@x�F
6#���x���C���������<��"�p$<�gZ�pL��}-=2;<!O���gZ���x�x�5!OI���Gf�g����0�L���g���3�yxN��}
=2;� ���i�`���<���3�yxI��}�<2;�"/��i�`���<���3�yxM��}�<r;�<����]�}#py��������W��������~r�{����_~������rQ���������"_��R���?���O�����W��W^!�W���i���a�,��a�����7����?���1�S�9�s�D���b�y�uHw4�����<tt�iygf�vY
���"�hp�p�;j�������C�����I�y
n��E����)����QGtGC�;��&z�O��y
��E����!����Q'tG3�{��&z�O��y
���E���O�p�#j�����`��&z�Ol��<x\<l�&�*F���I"Z3�t�
��M�*��x�<6�x������h�gI"Z1�0&���\�*��x3���a[�������E��i������PY�*�Hx���C����x�������������gf��58"�$���$�����pp,]��M��Q��3�A�<!OI���If�'���pp,�d������g���5xF����L�f���pp,�d-�����g���5xA^�\3�Z�����x�� /:��	���9xIsp�$kE^	��I����|f"h^�7��5��]�$kC�O�6��M��3�@3��%9���d������I����|fh^�w��=��]�$ko��wR�����7���W1�t��7��"�hp�$kov�Hj���I��:4�pp�$kw��"�hp�$kw+j$%�M�$k����7-����{�`�{4�b���5����t������W1�t�����"�hp�$ko#j$�M�$ko��E�bp�$k�<.^����I���h���I���^���I��7�xi��d�=p���.�d�=p��U.�d��������I�>����^nJ'Y�,z�K'Y�,r���}t��qp�$k��G������k��<&9���d�#r��8�t����Q��3�?���C����IV@��]�$+"���������L�"rp$��'Yrp$\<�����$�5��	9x"��'Yr��s����y
����$�5��9x&��'Y3r��s����y
^���$�5��9x!��'Yr��s��y��
F^���L�V���p�+�d������g�}�5xE^�\3����W���x��!o:������
9xKsp�$kC���I����|f�g^�w��=��C�$kG�N����7��s��9�9
���}�\�
��d]$��_#�
.�d���/�<������I�E����r��U4���_#�������v����������.�@�����=�F^\8���Y�`��^\8�����������hp;�����N�.jf0��m/����kp���a�z��U4��Ac�q�k�'Y5��?�+�'Y1.���_E��5b�����I�E���^i/N�.bX���������C���6�p�u����v+ep�$�"f��0H���j��F�S_\8����E��Y�+�'Yu��c���%YI��#�`_8����<�|f�g^�rpHr�X/��HB���'Y98�|f�g^�#rpHr�X3�����qp�$+"G������k���<�L�&���pp[<����'�����9xJr�X3����g��m�$kF�	O�f��9��c�$kA�	���&/�����g�{�5xA^�<�L�V���p0��lb����|f�g^�W��5��c�$kE^	���&o�����gF{�5xC��<�L�6���p0��lb����|f�g^�w��=��5��9x'L;2����|f�gV�]���9�b���`�\:�r
p��U.�d9�q��*&Y��h���I�s���W1�t��|�����P1�r8XDk�N�������,�7\�$��I�k[�H8�vd61������,������,�9�H8�vd61������,������,����p0��lbp���:�����8X�
��d�~E���iGf��`��\:����a��$��I�f�H8�vd�18X�*�N�����%98TL���<��M��G���D	�r�����I����p0��lbp@:��&G������IVD���iGf�#rp�9�N��198&98�L�&���8�x�5!O:��&O��S��c�$kF�O�f��Y�`:Q���9xNrp��d���3�`�����9x&\<�Z���$��I�����M^�������9xMrp��d���+�`����`��U�`GGJ�8�!�I�5��
Ax# L[2�8�!o:;:S���IxK�p��e�H�;!a�����Ix�I�����!{�c�0�7�-5��5�K�Y������.�fy[s�{t�b��]��^E�ve6q��KD�j���<����=:\1����F�Y��m�M�������,�k�z_��-n�����1���-��W��t��at�Uo�����o7�7���5���]���t����0���7aq�P�w��[�z�����BU��Y\:��0���7aq�X������z����b�UE�fq�\��������-?I��x������U��XL'L�X#l�zWL���TL�x������x$TLgL�X�T<&����hq@,&�l<m�lbq@,���	�bqHb�e#X���\L��x������\	�9&G���pq�pkB.&�l<m�lb��\<.v���	�xR��f�5!��6��j6�xF.��Y&���s��]�tkF.&#m<m�lb��\<.��&L,^���4�����\L��x����b���p1�7ab��\�����L�V�b2�����&���+������\�����L�6�b2�����&o��������\�����L�v�b2�����&���;�b:u����xOs���n�
r1n�i�f���X�j�N���X�&,��n��A���i�f�p���,.�n��X�&,��n�nC���i�f�}�.��'L,����7aq�t���$\L�7�X��^����V���������P$�b����b�b��Y\:�j�W/���b��v���Z��t��v���W��t���W/���b������Z��t������W��t���;�^��}�t�:I��6q6�x.������v.�	�+�[��Q$�b������xd\\:�jG��1���b�����p1m�lbq@.���$
�rqHs���n��@���r6�8"��t����8����L�"rq$\L�9�X<!G��t���r���b_3����'����������b:�����xR��f�5#���iCg�g���p1�Hab��\<+\\3�Z���������r�B�������xIsq[3�Z��������x%\L�R�X�"�i.nk�[r����x��!o���\
�7��-��m�tkG.����&���;������\������n���;�b������������t��������"����5����pC�/o��~��o���\����������_~������r*���������o���o����x��g��������}eBO�����������n��|���F�o���y��|"�;O�u�|�q���M|�+�}]�;2S�^���+zV$U"Ws�t���8��p�b��u���#CE���;�D��p����y"��������^m����?�}�:��������=DU"W3�t���L�{x�����%��T����D��o�����"����}t����A������ ��#�����-�u8QD���-2��hA���k&��������a�/���F��7,(Qo�z�2�!�����#��������m���'����.l�E�z�G�u����DD��������;!��"�����b��0�x���DD�������;#��"�����3B�L �N���!xF~Vv�Iy^�_2P���0�wA�]��a&��,���cS�����,L^�W�tX���8KD�&�rU4xC&E��7$��0��ab0���j��#�y"�����;"�F���01'����ICE�wd`2N����0�o��w��tR���},z�W��fB�:��6�\���!V�Z\��ip��w@�"Z1�t��;�`��\:�����KW��z,��K�X�����c����xI���I^��5�L�U���\���9V����������Q�`z����8X�j�&�����G�+&Y}��F����
�{�`��\:��{�`�{����d���u�7*L<L8�N�01x�G�+&Y���F���}
�G�`��\:��G��1��w�2�k��<.�d�#r�H8�N�018 �I���I^�rp \<�
���p0��abpDI���I^�#rp�9�^018"G��t*�����1��wv1�k��u��L���'��t&���r������d�����������3r��8�x�5#�I���I^���Y�`ze���9xa\<�Z���4�L���E�`zg���9x!L�q��"�i��d�����������r�J8���01xC��|g���o�������������`:����9xKr���K��#�:�k&���;�`:��������������v��B�
X<4����������������A���L
�Lv�������G����������Q��Bo���"r5�K'Y�G�+&YC�P��
�^01�� U�j�N�"z�WL��vG�z/Tzu����C�����N�01���������[Q��	�^01�� U�j�N�
"z�WL��~F�zTzu����T���)�d
8D�
��d
CD�zTzu��`RE�fp�$k�� �����b�5���d6�:`b��<�S7L�� ��hp�$k��d2�:`bp@����
���C����IVD&sA���#rp$L'n��AD����I��L����&O���`:o��`"z��L�&�`2�^01xF��i&�0�{4�f�5#�� �����r�L8���01G�����5��9���WL^������,"z��L�V�`2
�^�19xe\<��1 ��hp�$kC&�@���7���p0��ab0�G�k&Y;r0�B���#�����
����$����A&s@����8X�j�N��8X�
��d���F�����p���.�d�8X�
��d�nG���K'Y���`���t�5z�`�{4�b�5�5.�d�-p���.�d�-p��=\1��5�L����\���I�����������Q�`zu��`�`��\:�{������b�5���"Z1�t�5���"W3�t�5
.^����I�8�h���I�8�\���I�8l�xi��d�c�u�WL��G2��-���#r�����I���G�����rp ����I���C����IV@:��&G��@��7�����<�L�"rp�9�^01xB�dj{S<�����$5��	9x"\<����'2��)�d���s����I��<.�d���3���O���9��C�$kA^t�WL^����}S<�Z���$5��9x�9�^01xE^u�M�$kE^�<�L�6��U�`zu���
9xc\<�����$5��9x�9�^01xG�O�v��=��5��9x�9�^�084��	��IV��5��hp�$+4;j���&;x��\���IV��5��`�X1�
nE�z�"zu��`/��\:�
8�F�
��d?�F�a/�:`c0�@D�fp�$+���{4�b�Z����zu����T��\:�
8�F�
��d��i2��^01�� U�j�N����G�+&Y��~����WL�!H�������#kD����IVZ��7��WL H�������#kD����IVj����&���"W3�t�pd��=\1�
#r0\C����G������#kD����IV��dp
�:`bpD��}�$G�����5���L���6#G���x��#kD���P3������zu���	9x"��'Y8�F�
��d���dp
�:`b��<���,Y#z��L��`2��^01xA^��I���G�k&Y+r0\C���"���}�$G�����5��
9�
��wL��7��x��3kD����Q�� �&���&�H�!a_<���5���p�,kGf�k���c�(�3.f�PX��f�fF�d�+�>`�0����.�fE����Y�b�����.gE0,z���qV�W/
�����E��p�<+z�a��9\:��m�����X1��-����.h�pX�j��b���%q8V�b��F2��^!0q�������������;��x�t�{�a��9\:��=���=:\1����������������V��E�����VV�Hx��"0qx����3�8"�I�3�8"����5���G��m�L+��1���b��p <L��8������VDI�53��<	��&G���x�x�5!�4���&����0�I`���<<����~�������������7��o�C�^xx��������S+���r��?9��M��}�7���4��w��������������?��������������*��Bg���l=��o��x�[O8z�!�W�!���Dg������K��pM��
E"/z�	Go=�X� /��Dg����
W/�}�5E�7�"/z�	G�=�X�"���Dg��<�?!z��@��p��
(��`b��p���}������MX\4�C�H�������&�H��A��p(z1����E8�x�����`a��cmD�f�}���=2��|=$�g���(��������8�F�j�Gp(�#�a���S���E��������#�W��>�y8�f:���zL\�b1�t�p��b���{D�j��p ��L��6_��+Z�B�:f����>�Cy���^�������|��0���AqE�;Z������N�&p#z5�K�[N��n��W��oQ$�<�!L,�7�W��t�5����0���QqE��"I��	ab1�������	��L�)7_��kZ��HR{D�B�X�cnD�fq�tk�97�a����������i7�-.�nM8�F�j�N�&�t3&�|=-�hq@.>��ye1�ac1rq \�O�p��t�u�������0������-v#z5���[8�f:L��z
[��	��0������-w#z5���[8�f:���z
[����0������-x#z5���[8�f:L��z
[����0������-y#z������\|�y�����+r�B����0����^����N��So�������0������-{#z5���[8�f:���z
[��
��0������-|#z5���[8�f:L��z
[����0������-}#z5�K�[s�\|�}�����s\,�5�K�[s\,z5�K�[���zi.�����j�bz-��b\,z5�K�[�op��\�+�[�.��������^������7\�4������(�p1�n`bq\,z5�K�[s\,zWL����H�������p���,.�n�p��MX\1���E.��
L,�[��p�X:��{�b����b�5�+�$\L��X<�^�����<����m�tkfI��^7���X�j�N�����Ksq[1��G���p1�n`b��\<.K�[s@.�\�VL���\�N���\�����\�\��L�"rqd\\<�����p�X<����1��m�tkB.����u�'���p�X<�����4�5���x"\L��X<#��������\<�����n���3�bz�����xf\\<�Z��������^}������h�4�7L\^������xM��}[��+�`�0��
lF0^	�����`�&���
u���7�������b�F�8�v��-���m�����P�(�w
L��w��t���d�{0���t�\��V�r����������qD�fp�`k��8�a0������yW�9�����;r�����8G�j��������<+���8�
z��fG��201���^������cq��X�ge��]��A��ye0�c`b0N�����#���,��8���;"���J�`��������^������Cq��P�k��wj���:z���a�#z5�K�Y�YCq���*:�O�Qo�����!P��������,��8�J����s9L�y�p�0k��8�Wq8������\�*:<"&��v�t���P��9\:�Zp(�r�s=W��p@>L�y�p�8+����
y���������~s����"�������������?���������/��E�����_�����������8�����{���5l���q����n�������g��T,���qku��O�'I"Z{*�g�n����X�>����Zpgu]���j�����ab��;�U?E:3�4��+n�V�X����7���jG�b����j�O��5�k����
�U�n53��A��Q��71L�q_����gf��5x�m��g�n53�}C��Q���0,^<d����3#M��6p� r��0#��YP�~T��-�2�^�����;8c�G�+&���P�^������A�*��x��[\<<c�+����J�\:\=���U>���5�u�xI���I�l��E�fp��om��EoZ��q��
�q��|g���+�u��p0�}abp,z�O��y
���E����I��{�H8���01���������G�+&Y���F�����u������u�G�+&Y���F�����u�h���g���5xD�\1�ZG���p0�tabp@u>34��98�9�b����@8�^��198�|f4h^�#rpHr���N��`D������#rp�9��`��O��1��w6;���r�D8�^�01xB�O�&��)��w�:���3r�D8�^�01xF�	O�f��9��w6:���r�L8�^�01xA^t>34��r����;���]�9x!L/]��"�:����9xMr��MN2� r�J8�^�01xC^u>34��r����;[�d^A���qp�$kG�t>34��;r�����f��#����'Y;r��s��Q�Y
�|��i��dm
�,��������[o��\:������������n�h���I���
"z�K'Y�op��r=��h����"Z3�t��yx��^���I��7\<|�\�+���Q���b�$kk!I�������� U�
��dm�C���eK'Y[I��U.�dm�"�hp�$k�v��_\v�t����_(<3�3��=�"�hp�$k�W���[v�t��
���^���I�6@�*r�WL��aF���eK'Y�I��U.�dm#p��=\1��F���qp�$k��G�����kp@��UL����N���t>3�3��98�9�f���#i���������g�~f698�9�f�5!G���)�dM�����gF~�5xB����L�f���t�j�'Y3r��s����y
����$�5��9x&
���I��<.�d-��K����I�����]M�$kE^O�V��5��}�$kE^I���x��!�:�����
9xKrp_3����7���)�dm�����g}�5xG����L�v�����n�'Y;r��s��1�Y
���=��}�$ko��E�fp�$ko��E�bp�$ko6\�$�������qp�$kw���W1�t��;�`�{4�b��{�	��I����E�bp�$k���"�hp�$k�;j$�J'Y{���:�����8X�*&Y{��F���t��w���W1�t��w��"�hp�$k�f�H8��N��8X�*�N��8X�
��d�}D���]�$k���E�bp�$k<.^����I�>�h���I�>����3S=�<6�xI*&Y��<v���}Du>3�3����c����I���G���t�����s����y
��!��C�$+"������u>3�3��98&9x��dE���8�x�5!G���L��k��<�9�f�5!O��}�$kF�t>3�3��3r�����I��<����9x�9��T��/��K����I�������9x�9��T�����K����I�������9x%\<�����$�5��
9x#��'Yr�F8�x��!oIk&Y;r�F8�O�v��]��3#=��#�I�%Y�i�W�p�/�d=��y�|��\6�zs��*�hp�$�"�9���)�t@�������J�6�01�vd�W�G��%YO�v���)��l�uQ�[4Xo�IL�|;���������'I+j���z_6���i��V�������#k��=\-�z�4�F�_��H���`p����
&L�Y�U���jI�������M����`p����
&L�Y�U���P-�z�8�F2����&�3���4i�	�oG�|�{4�Z�����dn��#�M"<��4i�	�7\<R��
[�����t���#r�H8�l��$9xLrp��d]$�`2����&��@FJ�&���P3�
�dp��3�M������-&L�H�1I��f�����O�0�8<!	G2T���0qxB��(j�Y�0]��f��'2U�6�0qxF��,j�Y3�0�]��f�gd�����]&L^��4����a2���9�&/��+A�L�8�"
/i��g�H�dz����M^��W2X����qqxM�p�hm��d|����M��72a�6�0qxC��<k&Z;�0�_��(f�w����p�HkG��<kFZ;�0`��,f�/�ct��p�L����]=�{t�b���5���Mv���Wq���0q�����3-�f�Hx�Nc�qxX�j�����p��<+fZ��h���������Ws�t��Z�����X1�r-����.�i�xX�j���\���%y8V��\<,�5�KgZ�����3-�m�zi��i��E����Df�{�a��9\:�r=���=:\1�r�C����Hf��a��9\:�r���=8�����vI��e6�xl�b������#��b�TL���D<"�c�M,H�##����H�!I���k��H���6#���c��H�H����VD&����hf�#2q$LL;O�X<!�$��f�5!O��pf�'���@1�=ab��P<%��55���x&TL�3�X<#���i�	����$��f�� ���G[b�B����0�xA,^�X������\�0..�m���+�b������xU��f��"�����f�7���p1�Aab��\�)\\3����7��tL���;r�F��v�0�xG.��\�j�[;r�N��j���x'\L�PXX�|��i.v�-�L�"=�o���f�}���Y\:���������S���"��O�5�X��="z5�K�[�;\=|�|=��h�@$�q���f�=�GD�b1�Fac���������-n;�w��t`���-���W��t��[�WEo������<����z:�����U��Y\:�����7aq�t��
��;�z:�����U��Y\:��=���7aq�t����{�z:�����E�����v�0�x�|U�&,��n�aA�z�_O7�X<B�*z5�K�[~.�	�+�[~D.&�n<�lc1r�H��6�0�8 �i.��-����?�N�|@.��ig
�#rqHs���nE�b2�����&G�����x���c��}�tkB.&So<�lb��\<1..�nM��S��}�tkF.&so<�lb��\<.��)L,����4�����\L&�x:�����x!\L�S�X� /i.�5�������t����+r�B����0�xE.^�\�k�[+r1�~�� g�7���p1�Oab��\�����L�6�b2���Q�6#o��i�
�w��M������\L&�x:�����x'\L;TXX�6��������.�������.��������q��\�VL�Z��H��t�����X�j�N�Z\,zWL�Z�Q$�b:���b\,z5�K�[�.�	�+�[m��H��t����-p���,.�n�-p��MX\1�j�
E.�c�M,�Z��p1mSabq\,zWL��nA����`g�{�b��Y\:�j{�b����b����$\LG;�X\,z5�K�[���������n�p���,.�n�p���,.�n����C.��o�����\n�.��h<24.p�#��H�����q�xL��}[�����1��lbp@0�i�
��qH��}��G��@��Nx618"G���M����8&�����9���y���������_}��?���o��E�E��>�����>���/�I���|���_�����������?�����<�/�)���9q$������o�0�����7��~;�k��y���9�w�k��7~A�X�|q]��I[�.�.��� �:����E��oE�X�pqZ�]��b���vb4�wE�XYO�6$�5y�v��y��*6*hF7d��0m�a�/2��d��������L��LA{0���#R�)h�wD�=����g]���pu��
-��x{�\����^�#EDo��ME��G�z��~��`���\:��p���M\��h�oP��+�6_41���C�j�N�:("z5M5
�P��A�$g6��h�����&�<��8�hp��F�*m�hbp����.��u8ND�
���N/����������P�!r5�K�XN�G�+�X]m
;2R�6]41��"
��\:��p���=\1��hj���"�������"W3�t���(�{4�b���j������&���#�`����`$"z�W���L���v�&��@8�6�01������5���Lf��f�&G��H8���01����cuK�$+"�I"�����rp$Lr��#DD����I��L���F�&����`����` "z��L�f�`2E��Y�19x&L�q���CD����I��Lf��&�&/���`����`"z��L�V�`2A��X41xE^	�F6#�I���I�%������`���
9xc\<���!��hp�$kG&�Ch{E�w���qp�$���������A&�ChsE��8X�j�D�����G�+&Y}��F������y4�p0m�ab��G�+&Y�[P#���IV���E�fp�$������x��b���	5�L�*�,r5�K'Y}���%9���%y����������������s�xI��{I�%���E�bp�$����E�fp�$��v\�$���$��j�9�6T41���������G�+&Y��Q��������p���.�d�p��=\1���5�L�)�<"���K'Y��<&9���%��9x�9��R418 ���K'Y}@Ink&Y98�L)����`�m�����\3�����pp�$+"G�������rpLsp�$kB�O�&���pp,�d���S����I��<�L[(�<#���c�$kF����L���Y�`�@���9x!�'Yr�����f��"/:���&���+��X<�Z���$w5��
9x�9�6O41xC���I���%9���dm������o���;r�F88O�v��=��]�$kG�u�}-|����K'Y�G�+&YC3�F�M��hb�����.�d
8D�
��d
.�F�Omhc0�@D��"�t�5�0�{4�b�5xh�?�� �O���^ "W3�t�5�(�{4�b�5��Js �@h�@�[RE�fp�$k�A ��`p_1��5��@h�@�;RE�fp�$k�1 ��hp�$k�j�g��V�&���\���I��C@D����I����Qo�K{�<th0i���N�"z�WL��aE�z�^�+���8X�j�N���!z�WL��9����M��#�X��N���!z�WL���LF��^�6#����,��!z��L�"r0B{���#���IN��G�k&Yr�qd������	9x"��'Yr�����I��<.�d���3�`W<�����4�L����pp�$kA^��I������I��L���^�&����`W<��y5��hp�$kE&Skh�@�7���p�+�d���{4�f��!��5�W���;r�F8�O�pb��=\3�������+��`���p0�ea�� �I*&Yc,��K'Yc,r5�K'Y�kp��<TL�F,��K'Y��������m�xI*&Y�oQ����W���8X�j�N�F,z�WL����F��i�@�[�`��L�v����������Q#���I��uh0�`:����8X�
��d���	�N��8X�j�N��8X�+&Yc?�F��i�@��`��\:��`�{4�b�55�L{�,r5�K'Y��q��<VL��9x�9��
41xD	��]&��1��c�$k��A�`�+������]6#�$�5���t��M����p0��ebpD�Ik&Yrp�9��
41xB�O�&��)��c�$kB�t��M���'�����9xNr�X3����g��i�@����p0��eb����9�f�� /���'Y+r�B8���21xE^�\3�Z��W�����9x%L�v��!�I5��
9x�9��
41xC���]&���[��C�$kG�u��M���w��tn�����{��C�$+4=.����W��������.�dY#z�WL��kQ�����
41��D�j�N����G�+&Y�;��7*��M���������#kD����IV�;j���^�&�-�w��tn���8�F�
��d�vE�z�^�+����T��\:�
8�F�
��d�nF�z�^�+��`RE�b0��eb0���G�+&Y��~�����M�!H�������#kD����IV��f �kh�@�RE�fp�$+���{08VL�����,���Ax$ Lw�8� <&A8V��B@f�kh�@��p $L'w�8�CkD����YVDf�kh�@�#�p$(LGw�8�SkD����aVDf�kh�@�'d�HX���2q������5��	Y�
��
M��'�tx���8�F��g��lz
�h�0���h�x���kD����y��4������&/������N��G�kZ+�0�_C{�8�"�����.�qt��=:\3������4���
yx#<Lx�8�<��y�f��#�	6�k���;��Nx�N�2q��������j������}-,�
���,.j��X�&,��j�fG���i�@�]�"�S�L,v@��7aq�X+�E$��M,����W��t�= ��MX\1��~F���i�@���E�fq�\+��^��]S1��-@���,.l��X�j��b�q��P����V���E�fq�d+v@��W��t��W/I���m��XTk���bX,z5�KG[��p��X����VZI��v4�x.���t����p��MX\1���C���K�[qD.	��^&��������8"���K�[1 ����T/�rqHs���n��@���4�8"��t�����8����L�"rq$\L�	�X�\	��^&O��1���f�5!O��i?A�'���p1��eb��\<����L�f���p1�(hb��\<.���L,^���4�����\�.�=M,^����t������K��]�tkE.^���&���+������\�����L�6���p1�+hb��\�1..�nm��[��]�tkC.����&����b:�����xW��f��#���K�[S����p1��ea��#nDo������,(R�l�hwA��GD�fq�tk�!7��h���nMnB�zo#G��X���Y\:��p���MX\1��<4����G;�X��="z5�K�[��	�+�[Sm8'2����&����^�������nDo������u(R���h�A�;�WE�fq�tk�a7�7aq�tk�=��{�:�g����U��Y\:��p���MX\1���E��~�4hb�����,.�nM8�F�&,��nM��"�~���4�xl�b���s�L,��7�7aq�tk����G�
�X��G��t����8�F�&,��nM����q��������p1��eb1���	�k�[��L�q������8.���L,��7��hq[3������G{�X<!O����/����4�5����L�q�����3r�L��N3�������5������q�����r�B���3�������5����L�q�����+r�J��N3������5������q�����r�J���3�G�����5��
��L�q�����;r����x��CpDo������\Lf�8�{��b���qq�tkn��w������^}���.�2�
���\.p�
���U\��L\vW/���m����E�fp�xkv��W3�t�5�W/	��m���;���8[�|�����<�b�+�~������~s����"�������������?��������/��E��,�������?�����<�/�)����+�g5����,��a�����7�W��������`w%���P�� y�.#�f���
M~��[����3�B�����x��zv��w�P�^��h�FG�U���3sB��;��j�M�����#����D����f�&��T���1�y�
��
��zv��z^c�����vj4�7��*���L	��o�-U���ga��g�wC��-gG�4��;y�W�zxfHh^'8f��;Q�����D����=M����A�*��Hx��;���M���h�<�F����m�#��|�����xx�p��U��n�h���������w���k���$	��>(y
^�W�����x������#�I��J^�7d��1p����O��|fFh^�7d�-��w�@�k�����M��w����k���'!��(Y
^<>�	���/
�AD�bp�ki�"r�W���fG��!��]Mv�����`/�{4�b���5�����d41��D�*���/�{4�b���5����vd41��U�*���bT�{4�b���5�e���c�1�T��\:�Z:���9�bWL���)E�fp�$k� I�������op�0H�+&YK��"Z3�t������^���I��o�x�����ehQ�^��h'F�HREoZ����y
 H�G�+&Y��P�^��hF�G��Q��3�A�<"�I���If���G������9x�9��d�������;���58 ������98�|f.h^�#rpLr���N���#�`�����	98�|f*h^�'��)��wv:�k��<��mF�t>34��3r�����I��<��M���g���L�k��<�9�f�� /��i�E���E��3�@3��$9��'y
^���������+r�J8�x��"�I���I^�7���p0��hb���.�dm��[����o��`���qp�$kG�t>3	4��;r����;���5xG��N��9x�9�����
p��=\1�Z�5�Mv���W1�t��:�`�{4�b����	�~�6�^���I��=.^����k��`,�5�K'Y��������mp���VL��8XDk�N��8X�*�N��v��Ksp�$k�Z�H8�vZ41���������G�+&Yk�P#�`�g���8X�*�N��8X��sTL��~G���i�E��
&\:�Z�`�{4�b��+j$L{,�<�^���I�:"�I�*&Y��<2.�d�9x�9�����������b�����8�x������gf~�58"�$w5���	���&G���s����y
���c����I��<��M���'������l0r�����f�5#O��c�$kF�u>3�3��3r�����f�� ���c�$kA^t>3�3��r�����I�������9x�9��������k��k&Y+r�J88O�6��U��3s>��!oI�k&Yr�F88O�v���pp�$kG����L�v���pp,�d���;���I���dOrp_1����)�5�K'Y[o���wf�g^�������NME�����������D�*�N�.o\\<|�\��T4�C?M�^A�����
"z�K'Y��p��r�SS���E�z�^��N���T��\:��ZRE����I��9�����M�$k� I�������� U�
��dm���~��)�dm}���4����kpA��=\1���5��z}S:��HRE�bp�$k�i5"�hp�$kf�����M�$k I������
������C�$k������N��9x$\:��p^��=\1��r0Z���I������I��G�k&Y9�L��M�$+"G������l0rpLr�P3�������O�&��I��3�<��#kD����I��L��xW<����g��i����8�F�
��d���dn�w���9x�9�����#kD����I��L��xW<�Z����i����8�F�
��d���dn�w���9x�9�����#kD����I��L��xW<����7��i����8�F�
��d���dn�w���9x�9���X�7��{����I���h���I���^���I��l�xI+&Y�kQ#�`W:��p��U.�d�8X�
��d���F�������^�����8��E����Q��w��@�t���-:Lf+���[ a�{t�b���+j$$�KgY{$,z5�K�Y{(,z�W��nF��}�0k��E��p�4k�;\�$�����������������}��zI+�Y�0,�5�K�Y�0,z5�K�Y2��K�p�<k��GB��t���H��N�����8�8<�q�b�������/h�q8�8�h����y8$y8�L�"�p <��'Zy82.iE�����P3�������/iM����p�LkB��<jfZ���x�x�5#O��i����3�����P3����g���3�yx&<LkOL^���$�����<�n�gZ��Bx���8�"/I53�yx%<���V����0�>1qxC^�<jfZ��Fx�-�im���aZ~b�0�����P3����7��m�LkG�	���w��=���2-�4���p[8����}�\�j��.jn_"W�G��eZ�q
j���p�u��������(&�������^�u���F�s�ogZ��-:L�k��a��U���z��E�����-�i��u��'�5i	���0�����p�L�"iB�z_���.jvp�%�5i	���0�����p�L��1�F2����3����HMZ�b�0���=:\/��h@#�f�����E����&-A�qx���P�z����C��6��+�i]�Epx 6i	���0�����p�L�5�G�z_���.���G������yxL�p��i]�y���]�L�"y8�%(&�������V@&m|W<������0-A1q8"�4���"�0i������<	��'��)����jM�d�����Z����x�5#OI vM�TkF"&cm|W<����gF��S��xN�kj�Z"1l������H�$�U(6#/I$vM�\kE&&�m|W<�Z��W�������xM2�kj[B1n������B�F�����X�!oI(vM�dkG*&�m|_<����wB������xOR�kjF[;b1p������%�,��(��X�&,��m]��(�pq_:�r�X�j����.�	�+�[�M(�pq_:�r�X�j���oq�.��n9\,�5�K�[��^�����e����bW1��|�AdK��/�n��X�j�N�\������UL�\��H��}�t�u���W��t��:�b����b��z�"�N�\\,z�i=���=p��MX\1�rC�"�N��\,z5�K�[n.�	�+�[n�P$���t���-&\L+RL,���4������G��C�t����p1-I1�8 �4�������p�P<�
���p1�I1�8"�4���VD.������VD.���iQ���rqT��f�5!O�������\<.�E)6#O
�L�f���p�P<����g���(����xNs���n-��3���x�� /����[r���b_3�Z����C�tkE.^O�V��5���f��"�����[r�J����X�!oi.�5��
�xc\\<����7���(����xOs���n���;���x��#���iQ���������b_1���mW��j�������_��7�t�(��b�s����b��]�d�K�[��{D�j�N�<���MX\1��~�d�K�[��{D�j�N�<L���MX\1��m�"���~,�n��U��Y\:��0��7aq�t�wE���X:�����W��t��a�U����b���E���X:��=���W��t��a�Uo������7����c�t�-��r:Z�bb1L���MX\1����"�������Z<B�*z�iQ���0
��7aq�t����d �K�[~D.	���r�����b��r1���C�t���@����X��C�����VD.&#q|(�nE��H����X�\�\��L�&�b2������\<.�E)&O��r�?}��o�>��r�ugDc2��;^���x&hL�RL\���$����k��`L���P<�Z���*����xI��}��#��8>�V���`1�I11xE,^�X|�v:��+B1��C�hkC(^��6��-	��m���!��8>�6D��!q�`kG$��H|�V:��;1��|o���;�N��V�X�6�{��;&�jp��f����V��^����V���zI���8���C��c�H�u��W3�t��:�a�{0��#��{�	���V���E�fp�@�����7������}^��}c	�5���o�������o.���_�\��?}���/?}���_~9����������������������?<��3���_q�_9�� ��q��^>��7���}��F��o;'>@��|\��}G�rL��=p��M\�����O���<�d
���B�j�������SJP+<X�h
�J<W�\����^;:\<�����#������hb��\12�(���#r��>f����b����a418 W����6 W�t�i�p��A:�����\W������������^;!WDr�v��<�����~_�g{������5��iC����D2�������|�V��<����=\3���H�N��5xA�����11xA^�\3�[��r�v��%�����`Z�cb���$9���&y
^��Wr�v��%��+r�J8�����!�I���I^�7����O�6���p0-��19xKr��}M��#o���x��#���i	���;r����;��d5�kZ\Bv���]/��\:��p���=\1���C�z_:{��`/��\:��p���=\1������0t�����C���������CD����IV�W���J�sMn!H�Z�Z:��px��=\1���5��R��E�;RE�fp�$���!��hp�$��"j������6C�*r5�K'Y�G�+&Y]
;2=�N\41�� U�j�N�:"z��y*&Y��;2;��[41x� U�j�N�:"z�WL���E�z�T:m���9x$K'Y��G�+&Y]@&sC��E�rp K'Y�G�k&Y9�L
��M����pp,�d���{4�f�����:g���	982.�d���{4�f�5!��!t����3r��8�x���BD����I��L����6#���?[<�qP��=\3�Z����:a���9x!���I�	�G�k&Y+r0�B�+��"��sG���������__>�����a�F�xCr�������������T5��������n������]?������������?���~��O?��������~y�>�Mn�����0.��.�MD�����!������C"�HmM���?�S�pXHwr}W4xG$>Lye�}�����wR[DA0��?5(o��{�a�S��H�5��o��X����tE�A�p��*:�2�7�A���}������ �OD��o������B���?��\w5%���qF��������� ����� KQ�W�(���6�7�&F��7����h��W�������y����RzZ��v���71��X����R��i+j�Q�����&cQJO�R���3�E)}�(�+�����Ig���:�zZ��v���`,J��E)]��5B���:���`,J�iQ��q�G7 �R�WE)|��������
��Ce��\��x�8�F��M���xP�\(Oy�f�}�D�7��x��mk����7��P���S|����A���_:A5�7���zR�r@�18@�/z����'�����6C,���3u\�
�-.^2��K����Q���T�#�q�F����M���a\�
��B1��0�;?������)Y~^�����y��5h7��<nz��~���o��_~w���=��Rt��Y��]�O��s��/*(���0���m�YWuF�����j���������'��
����������>R��D��Q���~'�_z��:����<�,�*��k3q��C�9���,6+�����������4)a�,�]1�]Wd�]�Y3"�����8c�?�9����-�6�Dd[�Y�U���jIR1tv��u�O�6gw<������J�
���We��v��b�����t�O�6g��'"���[I���N���K�Y:��p'rN����Em�������Y��"9�z��0CgP���_����AmI�y+�4t�����w)�c0Cg=P������;�,����s�����#Y���W���W���"_�V��-|?���G�_6+�����������m�S_|�����<-��B	��x_��I:���.���a}{�����7Lf�P�^������\�c������c����U�HV���c�>Y��o\/�q=U����F������������O_�����~��qe��Ak��c����ki��E�;�x\���Ot�P�#j����0k�P��LE����N�9��z)����s���`w,j����"�Q����H.������|�[y���.�P7+r���Q���w}�q�e��g=��������r�\����,���9�v�t�C[�3�c��������=�{��
q�������?2�3t�������]lO����k�O)����P2@�z�)��~
�?���e�|�����<�x��Y�J�bm	I���%���,
������]��K7�8rc���/��9(���_��o������+jf�"�#-���|�p.��}���@������,�i��a�����i�"���y���2h��9�,]��:����|4Y��U��Q������-��g���E.Q�-3�b���r��u�����(�D���������\e�,���wXG��k��M��q����'��h��e�Y:��D��7��[���pt��}�o��/12��]������?��o�������[����f�����,��O����=
����������t&�����O��7H]�w��C�8OV��A&���'�����YN�z��o|�z���y'���g���r[��o��7�A�#b��������[�
I��k�zY������M�~������b�"��yt�H�s�����;\`����^�r��M���U%�9n��Ks@����+��V�X������������Jr���Y�A��+��$�90�js����4-z4�[xG�x�f��1u�}���'���+S����\k�q�^6m����~��:�n�n1��_���_O��O�����������?������
�sy���7>��g:Q�/��c=������������?�����y����������{��W�=/�����������}�*�?�b��c�O���k��^�}���[��'T�%���'=�����������0�.��N��������A�~�jE�	j��������O� ��o
�,j���h�o�R"��1>i.���H#�����s��*b����$E���a�	"����1�:8���|�s1������<E���E��,���y�A]{��u��T������{>�����B�&~d�e��I������.��B�,G>�.n���y�[P�~���\�d�&��"r�oCe�t��&�H���n�w��������[Q��co^����M"WY�lUP'�n�Dz��E��K�w"���^�z��8R{W��]p;p�<v.�5��-�XH�]���r��,]�*��K��8�~���K�vh�>1u0��Bq�sZ�����u+4d������zg)���Q�Ky��R��d)�����oh�m��3��09W5���}��g�|o\����A�(b�Ws_!�����I�q�w�C����G��t�f���6x�����vl�-����3	�vl���q�'��d�y���jGP+������`�������v��<d)*q8s~5s�
�kQA�.*�s���G���>d�������m�e���������8�(%��5������Q��H~��_U��9���&����b�F���w�g:�Mv~`���o�;LP�n��,�{�jY����*$�����A%ru�D#���	Pn�_
���'�������*������\eOpb�U��x�|[��3s����M���?�;$�"W���W��a�4�\���>����@W���_���|�����_�:�q�����|�W�w�������b�S�|���pyd���_��_>�g�5���/>u��Q�s�"*nAq!�c�=���P�~U��p�_VFu�����s�F��7(�-�������^��6�W�����Hc����~c{�1��d:qp�qU��C����?w��i�7��:��>�87}=��(\��?��>�@m��_H����j����������{�E�����*�a%W}w�*�o���n}�~��u�<2?i`�ab���Jn�Sx�9c��
7��m/'C
��PxHo���p�?�1���<~�?���o/?����7������+o,p��+��r���b�i���>-��d
�P����?��\,�����_�>��������j�����$Sj��	�Qd�����<o����x�'����U�r��1�U���%���UZ�a�U��<�]��$#�%}0�Fu+�]��U������6h��Ia�#Y���R��;�~<l'Q��H������|+�s��� ��>����b!�s���r��b�'������
��_x�'�Eq�������Fu@�"��@�f�6G�)��Ae�U��?&K7�����hn��P����_�Bq;��������%[>�F�(@E��<�aAu��h~��E����������\e�����������K�d��3|��DG�cw7��)��%��������x����g�(wN�K}����x{v��;;���3��?�����	7H�;��:;�U�6p>�Ir�������@���-��1hspP�jtX?�j1���oILR�C���0c�Ew���s��Q����e�����f;t�����N�[6v�|[�<�`��U���'����%c���A�Il�Z"�������t������<�z�K�o����f�z|k�z��;�=2���;4�_����F�'w�������VY:�J2T����2���$���VY:��,P7:\��M�4Y�PQ�*Kg�_��9��U���0�L�v\:��]N�Y:�;[�w���<5�(�����N�	����1]��b=�3��Nx�aC���<0�y�{�?V�n��)���Q���	��L���%x���	�-�����[�e*jBu������P+�,=�g��2��P�-2���8����/�%Y]|y�T{�7|NV�i.�S�`�:�B��Nm#m�-���ab�j ��!��9!�?����`e"��]����<�gFW�+M��5���_:;t�s���;�kX�1q8��{T������u�M|�Kl"�	�\��^���_�P�.��Pp"��o�y�~T7�E��)b��74(������-�n����?E�Y��������:L�w��&K7:G�-_�juE��)���E���z:��d��VW���"��t'����R�������U���k?��Pi#H'Y�,\A�iu����E������b�"�s�\e��������Ts������x�k��|��8�u�"���/�����Va��#�������������0�?<��o���d�Y��(�OpZ-��8/��~��?��9��=|O
>0Y����+���<yVO���@C�V�L��\����Ai�H�����6�D����e��m
D�C���������-k���_���|��#��m�K��?��-���Wl��RDu�������O�YC��6\��-<�P8w-�J��^D���z�_�C���x���"����E��%"��;i���c��|�{F���$b�6���
k��^�AE�@�6v�1�Q+���M�>������������a��@��Xh��^�a
���_�+��b�y;��?�x�v Wo�y''�3�W7o�!�Z\H��F��x�cV���B��@up�*r�O�����%@��O���[IEL�z	T��?���|�n[/����Kw���~|.�G��@q�~�KcjW�^�b	����$�[%�:H�R4�(:�i��=�#g�t����P�%r��3�P��&�Wc�������j�`^�s+��kCq������
�D��t��t�y���f��-x9C�7g�m��3D�����!�]����[G){��d:�x������$���f]��@��HV�0����=����{��@�E������P������e9Cm<"�!�6�a����a������+n�s��`�$j�f<��wAF6�PM��\�����P$�6}�^��r�e-�?���7>���%@``]�����`�Y�e�����"��
�kc���8��p,K����f+-��#�>�����z��q�q�;��qv����xeGe����w������ w��!_��=���7�."��Y@ ����T������8�N�w��Gy�#2o���3��>vPuP���%���35���P���J$�XQ`����:��D�������t3��D�*d:�:��ZQ� �T(v�}�Ln���9boT�=,D������� Y����t.���!�n���`}�� nEq�)��s),�n�������l7,O.�����L�)����-��mA8��}�Tq��/��_��������w�@Clj��������`#���iu�;n�����
m��p����ZyWo����\�%���� r*Q{X�3�q3�V��(M$�{R�����
v�"�~m9N���[F�6���6����;��(L�6.��d��	��j�7�D�c��@+I��G�B���:\I��$������ 6z�6}Z��iT�(�UC�������C���i�w���i�V�~�ZU�n����M�zoB�'���85�a�Y�u�t�:x<E�V�m}Z���D���"P��Ij�r�����\��p%_���~��o/�.���_�\���>�����>���/�b/�������������|�����xb���7\�o��������4k����>7f������\C�7?c��g�������y�kT__��~��0�D�6������.r�
���f:�CqP`.j�go�.����f��:H�E�r�wbg���=T�
���Oy��d���@��O
����A�9�CupB*r���.����aw*r���t�76��{c��{(�[�&~e���{������+y����p%�1)VR��]'�y��;~37�i�N��r�q�ni�g{���,��s6�� ���Y�A<��C��L�����Q�����Y_�:��\���h}_� .�8r��N�6Y:�E��t��5Q��(�\u-�[��DD��t��5�&G�����@"��������Eq��k����[E��t�5?(nFqzyk��:�~�����|��;�/P$i����/�������-���5$��uK����p	�P?0s�������'>���8(��&�u������N�e�Ty���	X�����`�*�`e=<gnYg��m�Cmz���e��@mP�$b2x\{x����7�&����rD���7���6�������G�y�#����a�w#�7\Ir�w_?�OD�Ry����%�����Zy����P�Q��C�FB>������(�?���|EG��w��o
���7���"y�6A�1�hV�6���,G��r,��5������6Q�X"�A�=�unq%�X�E3��=�g�p&W���O1��^����W�=�>'dw��X,|P����hl���C�z�>�C��c��c��?�+>'�~o�cs �(������#"Oq,Z��"������� ��:���.��_��'�88YIP�����	qx������t}���Gf�q�+vk�W���t�e�@�����U���7AA\��8�=\~�:��w
��t�6	[Q��M��I�&K��:�#�e�&_���:rfM�YZ�v�����W���	��C���l��"W[;�2P7����Z�~f�y�����������[�������\m������������sk{n����aD
x.���'o��4r(�^���}������O�!�E���d]�}�Q!9��4fX?�Fq�r���;C���A��H��gE��k� !b������+D�C�R;^���W8��R{�x'��Xk�<��(n��{y��f������n�#�;��F;3f9�Fq��6}x���>}x������|W����8�M>������?��>�f��6ho��c�a��=�x�.��)��_�oIa�cjP�gH"Wa9=|�u����T������V���:��Z�LoP�gH����[���S�8���gG_� �����M/�(��	���{�h�����N��?�m�x��\Z�!�����*W9�>Q���cjTw��U��)>7[=�15�tE�{6:(�15�[@��O�$�<�� �7��##���r�������&�#s�F_���������������/a�������!������.�&k���=;l5�o���H����ag��1o2��&T�_t������m�,��H�'��=�#�Y�{�aW�����Gu��zu
�r`������6��<������@!��J��9�:�|�A_�~��k��s��T�*YY>��e�|���6�q�I8;��������V�0�H��k�a��U�����.(]%+�����;������.&Z_�~�0��-���U��|�f,���(�B�S�3�^��~����c������AHU�qY�Ql���f�i,$��i=�I��7|�YH�0���!�U�c������������������y�s������]G��]��[���g?���o��o|H��S�}��7}�/u�������y������]�����l�{�� � H��[4k�l�t�{�����������Q[�8�
9��W~��m�<�
P����zM*�D�������3|�1��a�Ev��(�0\#��U��F��
�������r���C��s��/��D����: $�{|��D��A��o���U��i�}��'���E�vo��d9�ux#r���<���{^��?�.��e	w���;��+��"_YJ��=���a-W������#������cWQ���^��$��|R&!y���^��f!}]����s��#����F��_��k����$��9z{�w�i��_��Y�M������oS����~r;;��m��\����\�	��h���f:�Gu��+�����.]/+Q�-��=hTo+��|�����y� ������Gu;�������K�������T�,]�u��(K��V[�l�o'_}���
��K�e��V[:��7TQ)�,������U]��������U]�^:,��X�%)0Z:�:����oX���X��?X��u�����������n���FPw�����>X6
w����K/��h�AEY�����o'��sk��3�$M�2
�'�88j�+|��|6�"Y��k]���`�.j��[��~�*�@����v���[(�tQ�qY*�@����}�3�~�j��KI&�:�����6����r��o��@�Z@+����w\�����_���~p��-Q^���Z|{������.w���� �7==���:Q��>}#�Un=�K
�X���M`����������3�<�'�/��]?nI.��}���N�j$k]>����y{�VHSD��z�o(���'E��.������v\��
�3a��C��1q:i��[�E��s�)-S���U���Oq�������p%���;1p�d�X����W���vxU�Z�U�~D�(��Kc.����:�P%r�����JP�}"����;����\?F<�Cq;���D��Q?jW�M�u����#Q��ZmOh>����N?���~@�~�V[:��T�2"�A�u�z��=o^���6TG^���u����V[:��T��@:�	k6K��p8h{�t�?����$,�����JN_H�X������7L�Y:�IQ�-]���V
�a����8Y|����Y��`�t�����nCq�V��#Y,���N��~M��L�j{r��8�[�gT��Y��0����_ux�V����,]�
��^����F!���7�-�N/p(�t�������Z,]�"�A^�<�V[:�)j�N��������)n>�4�5|�'�+�@��?k��\��37�8����vw��f]��C1�d�a�jg�/����jCO���\�uG�d��y_N��1���Xmh����b���e��y��|z=���8�i����|��
����JkA:��ci���_��Z��������g��Z�5(�l���,��(
Q����q��������q��x���n.�Iqoq�^�G�{���w4���y�K|���������D�)����&��Em�������Ji����vl�?����! I�^����6v��him����5�s��q8�������t�����7�|y;���'��~r��ONs���%������5���~n����s������O����_������������O�=b�_�_�u��_<�B�����Y���g� �������__�������?��Y :�28A���,�S 
���h�
D�c�L�Q$.i<Gz�d��Fq�g�Z��'�~n��/�:|N=V���Y��QR���C<�{���Ik�������\� �3Uy���P���@����Fi��8���WIw��>X���v\���p?���� �\����
�&�+Dr��'�F�*oT��8�����U�c�\�=vo-�^]����ikTy���]D��n�U��9�Eqp�$j�=�y�#��j��T�G�d�<�?fZ
����R\��&T��?�/^U����W>�:8t�[�����E��n��������N�p��g��]:������:CuP
4�j����MX5�4b�t��N�?�x�P�jKg~�
�AI�L�`���L�:Z�j�[�w
�������n�P�Z\h�t���U���~���nEq�e�a������_:��-j���F'�u8I{����KpK|��z�J������t��a>���;O�,UFu�s^��Ty�-U�hV���?���~�R�V��p���9�>W�:Q?k�6C�m���%����Fk��B�~��6���nE��jo�|+�_�����|����,6�7\����f]����X$+�������<��6�`���6�(SO��m����;�\-�9���f������f]����G$+�����^-�� ���j�S�����A����h���&S�<�����}��,�� g+���,�=�Jv2i���2����G�*U
�x O�<��q�^�G��d�2��e�3���G!�^�R-���E��:����Z�;*��!{#���Tmy�������NT�����F������w��z8���S/��w���5n�����s��o������~��y����_��������Wx������^*�������^�����\��Z���;��x���?�;�s�~�����l]B�H���)�W]��1Tw�E������w^�@u�{�<��������v������g���	�P�S����$N���Y�>t����Zy�P���Z��kT�Z"�A���u��I?�
�"����E5���c�c���@qp�%j�Oq��/J$#.�?�r���C��l�E�c>�+���Qp��x�}���fG�w^�hZy�1GGub����z�T����f���~ ��<�^TUW"W��A��<�^P��;d����C���M\�E��/��������SV��a��5�����g7R����-��n����������?=]�<�!��`^#��n���V��le�'��y\�*K��Y,����}h�,����}�`>\���+����/ge�k[T����Tf������M$Q�������:�z8���&d���ip�����Sa7��K������|0�*YY�L��Cu����(���Z�Cu��?!l 9��s��v���!��P��`����{���"m����(g?r�V���p)��c�y���8x������5�ly����L|��W����M��D�)��(���{5�����n1}������m��c�=�1/�#~�������������g�#k�6�k��E�O�!^[������_Of�E���:p�vK�����:�����'���d�u�����:8h����W~o�K��v\Ir\���8Bq}�K��>p.J6y�|Nz�^V��x�A�@�?�=�<�C<�krP��x��R��?�c�+�#�=��X�19�=s+ �������s~`G.9��.���w/��m��V����~���� �4�7��[p�+��Z`�����,J�����y6����9#8�����_:���Zm���%�:�wy�{�.�f�<l�=�r�z�a�u�����K���V[:�a�����N?�{A��y��}G�J���P�~����,l�E��t��|������Eu�V����������.[�����nAu����o���������8���S�����S0�.D��t��u�u��������W�m�u_6��p�4��.�9��w�@���l4qV����<.���(n�(���g��&��[�Q�Z����]�jKW�&F�:��h�i"��+�J�D�B��(K�;�@*?��4��ATT��u��D�knK�5o������X�~�������u�Q�H%�������H� ��;�]c�ri�����87@k��N}'�r����A��E��7��i��A��}L���U��3+�2�����=tc|��}�`?q�"��8x���t���"��Q����sB�����s�C`���j�D��b�F�9����8]RF�%e�X�������"����#�����\@"L.�j��x���,e.�n���%�
=���T�����@�>�k��>��B����VDu;�����\���>�X���p�)s1y�>'�J��O14���M�#�61V���z�<�C6\H=2/�#��\�X�DS���:�x(���h����I�z��Y��X
�A%����=E�b5�I��W�����l^������
���I�5
�C�Z5���f�s��L���A]����lEg����T��.���rD��t�E�.����a
+j��3/B@u�-������u���Zm��!h'��^i�]�����(������s��?'��u�tD��t���y0��&T�r��r0�n�B{�`���o��74����G�@"�C�f����`��7�TCPqY�PTCt��!j;�.:6;�����u$�`o�<s(v�]x��v�u��$E���|&>��R?'��}�`�A���M�u��9�������9��z��tq��Rf��������	�GZ�����~q��
�>������j7�/N|I2�������_����_��=�����2�z:�~=�.���eB�zUqK~�4>��[E"W;l3��A������8�:�
g
"�{�<o:T�;���"��s�)�<.]r������)��n���)n/O�7�W�]��W]�~����������~�q������������?�]����>���������������?���u�����.�7^Y���8�e�#p����j�+��~(���w�m���7?`�i��_���Y�zls(��!��
��'������}�*W9�&aG�JP�w�v��8g�|��"�"Q�P��9���A&#ru��(�+E���P�v�<����0�1�q��B�&~d�� ��'e �*"�v�$�(ND��<g������nAu��B��������af�t��N�*Kg~	�M(�\���i�P��
�����u=l�E��t�w�P40�xT�o���sGE���>>����	5`��;�=.���]"�����9�q��tJ��C\��"�����'�G�a�b%'����1��#Z�*?u'#������QQr@����-[I�7�M$��^iy��P�o��_B<.��E^9.�7���
o|�����^��E�����E��g���cm{c�x�=������\-Ht��iP����;Z���E,�Au��wW����~��|��h/�Z��E�;N2��"P��	k���p�!n.E��6�<�-��D��<��Gu��������������V8v����hs�7�d�q3��:�!�{|��
V�uf"�E�H������N>��V��Zg(��A���������y����A�L��Q�R�k���_&�~h���� A��{��E����P��,�.+�_jBq���Zm��/5����#���V�]^����`�.��������o��88F����wVu[���s��|�X:�]*j���.5�]:�����:�]*j��3���v$Jr����o��Zm��;���	���K�/��vr��F$Y,]h�%F���~��]*j��;*���eT����~9Zno���;w��S���v���*!�r#�Qa8�i������Fq�����|g:�:�G���&��G��P�m(���Y���	�'Q��^�`�.���Z�1z(��I����fa~�g�
#j��
li
��"V+�g(?����5��D�)��(_u�K�9����|������}��!����t�!^���P��M�������l��?���aw�5� �����a,xz�:�h�����M���T��Q�0�=
G�6��������z�j�x#E���+�	�������yjPd������Oq�����A���`_��O�)S
���=����c�����������6�5S
�k\;|D��)Z�"��"��v�~���s�q�P�����<E��k������w^��p?����	�
��B�)� v<�$�{�����p�\-��6����
������.xTG*(h��,��b�����)���D�jkg^B��vTG��_;�I�0������<�Q�CS���p� �f��U~��������?��	�U������������;O�P�"O���������o��m��oh�_�C�~�����w1��l�P3!�����|�w|�7���7�&,���;��Y��|��t�������=�O?Q!��D��G~���~���Eq����e9�Dq����^L����N��������$��
W����d��1}!����������$���u*�D�)��(Em���k���]��3[��������<�E?����J�������o��vMp8N=L/w���C4k��?a����J�'V�aH�� .�����4���}y������Sc��,��(*��t����
��x�=��S�)^!���)QE���|��������M��
�����A��t�&O��I��)A�>�H���gS��47Eu�%�$�?��U7��/�{o�����qx>��R�8�"�e��X���v�%S��g	�Q��E��_�Cu+�#7�Sg�v��\m������ P���!M��v�cI�y[]T��:r8^|�����q�s1yf1����{7�!���]v���{76�N�sV�{7��Y�jk��������l$�����
��7�����(�����_�����9yu�k���O���];�R<��+�F��
�D\��?�A�(j�!����V�M��36��
���+����'3i�:�
f���z������h��:���'�����C�2�{;�7�y���Nfl���<g����� r�g��z���;��P�������m����=�c��+f90|�5�������Z$"^�7��s�[�D�v���H��P�r6���)�<i��[���-<�[�vP�%��qk0�K��c���/�������]��3E�Fq����t'/��@-"��2�L�� n�(.gw��O1["�Q�b�l�'ze|����
�>"������E�+e�{��`U�K��.8T��D(��9/Dup%J��[�gg��~���
q��{�P���.p.,����?/����"W�1�/��:��&��+��D�����r��aR"��&k�!(��Q,��Y;������6k�;�M�@�,E�sn�v���e}���jE��v�=zQ����
��k���4��~�b�Vl4��N����Eu�Aee���3~T7�:�����n�&�"W[;�6�������x���u�=k�?x�5�n]D���e����������w�E������z��~���d�6G"YY>��e�|���G�f�j����8Al+��E�_6�8�B�~��y���}@��[��_a&��{�1Q������7�(Q'�N���^u��
��~}���v'��:=��X�����Um����^��u��E�'*6�8/ nF�}��`��spNy���_�yg��u���U�����Ab��d.���-�[������~.x\5+��������p���6����L��".��3��,��~� n���;~��_�� q�w�d�����0t����?�y���]5+�W�D.�w��������}����/���_7��;\�y��`�u�tz$I*lq�������`�����I�F&q�y��}��
q������~�m��U��~�HD�]���Z������L�W@!�s�JVRqr����
��A��H�e�]��&�v��XEji;.$i�MB�*�~h>��l���\Au`��}H�8�����fmM�v.%3��m��:��
��W��M�\i�7W��J�}v�{������h^�C����������?n�d������R����R����6O)<H�f���-wZ}���������A]���9�����]��y��V�E��W
r�zP�.��K~��,�n<\��3q��C<�cB.:d|��zAP7���T ��t�����|�G|PF2F��c�A!�H\��B����A�Vq��]h��)d��4m
���r�`(���}������ ��4}R�}Z���7��L�j�~�k�w2�;��C���A+�5�]�`��U�V2������k�G2m���k��`Z�jkg>��-���_��W�@L*������:��A�TX���"8��vL���P���H�o^"�z����+O��Y�]?��^���w���*W;��v����m��\-�v0��*W[;��T�*A��t�h�:���������:��Q���rd������������S�:
D���+F�A����l-SO�]hP���*�vwP���p��"DTGZ���A=���2���E��H;��{��;���)JsE�P�f~���*�k�����M��k�$��Y�	wP��L!�������e6��f�pEF�z��7O�P7���tf�������<W���7����kJ/W���+��9�^{����xC~����g(X�x�0x�sf�G'_�<�(6#����(�����j���:��(��S�����1�p��uG��(�����K��<��lAE���������x�W3��1���:�@���x/)(^��^���!w�bh����y���w�!^*5X�bl�>Z�hU�_���Q�,/�!�?�[�_[,���1����vkQvkwk��B�P���l�wk�p���0���������4XAq�2�����[Cq+������I�U������� n��K�c��w�����w����l��.i7F��FCW��x�h�A((�xhX��h��������\m��G	�<�p��	;���4�������9� �x�hVZnc��KIF
�a4��OQ?���:�b�'p�u�q��F�@��M�
�����U��U�aE
X�qg�����\���2I�yT�lA��Q[k��� "����Za3+��_D��� oq��d�z��!��Dd"�1�^p3�����_02zmp)�������:X��9��������p���S${�p������H�9��/_XI��#I��[�b>g�wC`F��|��A�?��7��!�H��x��� J���GC�>&����:�����(v=�����C���:������@�������B���pP�W"W���|f�|P>O���m�y�?VW�21��H������8t"�������]�A���1�d�5&�k��1��H�Aw�Yn�:�5&����7m���(��M���Hr�,����Jz"��F�K��"�A����"i}�}�?��y���b��
����������b�a%��0�L��SBxPy���*�������Q)�e�M�.�9������z�A��")�-����v�����z
��ZTG�~�����"W[;��5u�#��d�����y�����^��X�3��(��.N�\m��������4�*���H~"�������������U$��_�n��s|������74��4v��u��=P8;�v.d�(���R���`��U�;��8�;���l~5S��R�Fd]�kG>�c��mp)������}���V�>��X� ����K��v\J6��;���t�>��Z\��*w<�s1������b�|[�����r�S�8k}��^�����x���y��f�X�o���&�u��y���>}n{Y����o<d���o/>l8�W�O��e��g���~�5z����_��������Wx���HL��O�w�z�3t��u����3�����/^��'��N�����1��@;�����������1�� mY��"h��W>�8�b�I�X	t�>'/���@�c���/�s�]��Z(R�_5I�?�O���w�~�/��S���MQ?|#�~�O
|��"��G�~������?�y�O<�;�mA��&���]���,v*��d&v��XP�7��#�qR��������)���G�<$=��7�wn��Aa
�X[�<u�nhq��!����c<6�p�3�������Q�]�����'(.���q���c2�����������L��>XS��,^HN���UF�����)����0OM���.�o�`^S��6��P��;��T<���F���&����^!�������������,g=�noa)7r��[�;�A�N���V46k����v�����������(���0f�*W[;�6�u���
�Ej~�����Y�jkg^��Gu������
����}k^��&T���J�l�E��v�uP�����L�*���~g��&��y��Q�#j^�`��U��v�uP��ul�K�gF�\�jkw����<�nAu���}{S��O^����[�O��aG
������g����"Y��|�������P����������qM�b�8�Cc��x����E�A�"Xgf��<O-���1��"���G�kF���9��`)g�>��z�ZT������Z��z���Z��g��=��{�C,-~������V�����<y�~<kc�O�k��~����6����d��]�~W�N��is���������t����%�,xg9|�����6�>���c�r��_1����O��C�MI���*lQ���o�U�L�������U���e'�Y6= �y�8M�Z��P�k����[��I��C��(yJ&@����=��{�=D������|���P��B��/\���.�j&PD�m�@NP+��[:|��c�9\J��Z]>X3��`�'r�����q��	��(��N���J�����:ID��[�_m��������?�������������>5���}������>������</#���y����:�����3�N���7��Em�g��Q�b���%%��Uk�9uXJ��R2OzDe:@Au��;���^;�cT5�"W[;�PTGj���]�RU���)��t����{�U}9|�o��s�O~|�"r��

3j�k���<��(�
��+�,���	��l{��,�O S%Q����R���cy�
Xv_�#^��T�
��s�t��k��])G�ot�q����f�dat��m������	�a���*m����f��r���>|���7���[��$���C���?|"g;�����[0-Oo�3�^s�y���A!I���5n�B��hK�*�}�G"S*������6@��6�����R��6@y��t�m�F^eI�A]�o�C�Li�Z�)�|G$?�S�O������$S*����W���=�>'�����c<��B�M�&UyRyT���=������Ry��2��F#��'�o������7�����u���W��������~�q������������?��b�eS����������������?<�g�r_#q�}�/��r���8���C�������vw�v�����~#n�����%o~����~�7G?��3���w�����������8[�&~��' v��Y��:��IhQ��"WKh����:���I��k
p�r��3�������`7���EuPG r��3������L���J���q�����kx�<UAu���������*�d{���JO����������R�NUn���^��:,�9Uq���������8�k������C�����?�;��<,��Z�r������M�����P+l�D�f��lv��5��d�X�9UAu��G��OU�� �S�w��|���������C�4�����.��'>�y�/��
^6��D��gt�����p�s�9P���c	�xk����.9���\�<	2(���7X����w&�������"7�.�}����(_�c|��h
-.$�	4��(2����r��?�c��p��/`���J��S��A���t�����HP+�d��@��;��a���a�8L���]�c ��
�G�Cx����cl6���U��9�@q��
$5�6$�u�'��
Q\�5|�
��������_�'u�`�dxYg�h���pcM^�:��C������2%��nCu/��,�7�r�O�������5���a)�}C���O>���[\�����<�2�� v���%^Fq�:������8nB�k��}���\J�:�7���F��	���F�-����`�H���q)��	v
'O����p���o_��1/������ok����b5�8�����
z�WO^//r�?��(�.��qx{[P�2�����ylM�o|��O�j���4��<���yl�pz[�wrU�1��!b�����u_��	7��Nxpz�x��]���'��"��Q;;7�:��d���6,�@q��V{�q2�����a�U�C����,����q��� 5T���l�}�|����xSe��e��YK�Y�~��?��fRw�����=Q�`�W'����5z\GRG����{�<��E���<��'�S���E��)>7%��)�J�����'����id:u3$"�1��g2���s<C�!z�����?x8����kK���C(
D�v8�zM�7�����:T�����������t+�EV=���r]wAq3�{y����b���W�/Z�8n�-
�~"W;�8?
#�:(���h�b�v+�#��\�,k��9T��l0uk���O�jk����v�ETG:�f���H��]�r(	��Gu/��_%����p�P2J��)c������g��:��x�Z$+�A��9�Dq�~]��j*.�y$��T�>$b,���$
������������G�:�2E�c[\I�O;�R>�#���^E{���G�:�4Dn��K�lD��K��H�J	|,��Ou"x�m���Gf:����Cg�O'2����M��`�v]�=C�>�N�cy���-�XH��P�%����rh>~vy����e'�Q��|�m�lpyUo���&��]���s�������>�f|��n�G�74����5�<�
�{~\��
�1��V�`~���
�?B���
��S�n~��^F���	?D�Q�!�2����}'2OY�ki#$���x"s�2��$��V4+<B�7�����9n`�E9���g����D��>P�k�������p)�������c!�������^��x�(�d��	�KD�r���8W=���@Q��������GU��x�3���������s��:(l���x8W��\E.#�����>�����.\����'��;��Kd�7��}���U/��F�����A\)j�2��������-�eW�)H�3����G�*W;��n#xP7�:2��������r���n#xP����+g�6k��V�_�I���[P)^c��L��s�,iA�w-2Z;h
u�����%����v���g�LY���VTG.h�{�&km��r��;�8���@i�_�]���T�z���cM�nGu������������~��wPl��������2X�,58�n��������\�u
N��������]K1���
#����9�jpP���B}����,58(n���BZ�0q9jp�zx65P�G]��b%�|�|@�A��KI^�}}>n����>����V��ndtS`=]M��f-W������D��kpP��{�M�7|=�w���7���q�=��{�C��a?5��5��u�g����o���������U�����s<i�������������&�V���o�������O�?�Z��sT����������������~�c�����j��V����xT������@o��k}�T���[}���
���kJ����������������������z��'�u��z<�?3�<�I<Hl���\jI��g�A�~�\�,��S�A�����A���op���s�����A��@�6����1f�"�����c�C���Gy��
��&h�$SE
���S�>�s<���������O���M�`���P7z\<|H�;��5(�*�^9�Y�}gE��'�!\�*�qoW�|�S�A\qd�~��������?������-H�\����&�����d4�������oMwx+�zP��,gV��w��L
a�M���]������&	�M������lfD��v�5I�n��n#�;��$T7���^A��!Om��Q�u���L�OrE��v�5I�����o�w��p"W[;��$T��:RW��.��l$�p����.@��24"����:|�24�v-2Y�
��o�����o2�H���Ek��c�5��"��"���{*����:��M�&���V9Z|�&`\��(��	�d�>��*G���TG�m_���E��v����3;GTG�����&�I0��
hwq��(�w2iU��m�gv�7�����3�@������4W�-�#=�����L��G�%�����leLVz�6d��0�vk�v2�W��n�Pa2z��d�0]��Qi4���v�E��t����b���S�>J��/��.�g��sk�7�7�������
���\m��q�������+(������H�`�k|�vo_��k�:�Q��/�m;,r�y8���)��'"�N��w��Sw�|3H#���,�nB
��q-�=qw*��zN���\����}/�x8v���E����.w��e��.Q��]Xq�"��y��xC�����Tm���K(����__w��'��o��7���P���!�t�w���]=�s���LQ�qY.@��(6���`�����6*l�E���/��0�u0��lP�=L
.��C�hFO�_����"m���XT�jF�7��Q�\�Du.���(^�^J����C������?���[�����RM�_�|���9��\��ri����c�=��Gg���<K��C��(N�E�v�C?���?�V�S4PG.��q�nm�88v��G�p�)���lC��5�0����l;������������X�1}��t�����R��}���}�A�BuP�/r�9n[\Ir��s�B�)z��������3"����T�����2��cy� �:PFrU�u(�sk�a�CQ������{>�y��
qP�9�jyx�+s��L�[�v������9�Bu�33�F���,K���Q9�m��@��������H��>f���
k�;��\����������=�o���:�=(r��3/�BuP2;�dtpc=���nBu�2K�M�w+��J�1Wl�)X��`�|�6�l�c���
�d��lEZ'�w������1o^�v|�m�9�s���k�#���MV�]�n"W[;����B�q������.4��"r��3����&T�����.4;�#3��y�xg�s-�{�Ey)"�n�����P~�\�D�T�\�; 1�(Q���f���P�QE�����_tJ�_����}�OQ���CV�Em�"��}<O.b�������"�?����P�����,"���#��	��SD���"Y$�=��,Ed(^a�Uo�;��c�In��m��aF��E���>�>��[�>�����$��lOjc4v{���s���:x�W���������;h�Ep�Go����������cZD6>y��.��R<�?�X�E�����<�_�NV]��_`��S�d�Z�^��N�En��)���%>�>���w�]���<|P��w���|��)T������k��c�C~"�_�1�������)P�3~D�c>�z��t�*�c�I��:f*��U75h�!��
+Z<�"�~E�;n��iy
�0��r3��x
�Am�tHv_O���ly=>���o�[P\H�����{�`��Ml����m�7�A�2��%�����]�^'��s?=��GP�6 ����#���G��%TG";�w��������G��%T��:�����a�����y�ZT�\�Q��y���Z������}�n��M��H�5�	Z���@� r���V�t�{77��b�����Z������u��:�\�������"W�`v&h����539���������l&�k���d	����7Y�w���M&r��3����fTG�d��w-��D��v��jQA��G����&k�"���Y|����7Y��]�o�V�k��B>���1�"�a���g2D���
,��nCu�������7Y�gmS�+z�[���{�/��.5��b�7Y����3;��[���]i�����VX;d�A����l\qr�F|�fy�\��l$LF��2������6K����_�uX7�F��5#4Y���(�&��)���-��\u-�Aa��H=My,�.����n��v������������9Y��n�_����o��q��K�S������Rs}��hl����)y������9r+q�����#sM��9��s-��.��K��������_/}�|w�L7o@\��8|����7oP!|�D��B~����q=~�H�*.���UQ���pKU"^��a�F��3�����tO�r���p��
.��C|[���w:{�z�i� ���	���^�iv3���L��E��x�F�	��I��{�ffR��DbV�`�x3>��|x���L��E��x�J����.a&�d��1�G��p��m�g;,��[`����}�L��D��x��rQ���G����5��o
��w���Y<�)���B���xSh9�:��f�6�rK�uL�����L����DF�G���������p�X��8���xz�����l2��\O���u������B
����f�V���BdV�`�x+V"�dZ��
���2WV����o��#7���������\����f�p��z���z�
���&t%�<�h�Y<����E��/L��R��-^i�X=T��^m�
���*D��x�	cm=.�����������w}-�y�W[��������}�����u.������ ���(23Z<��D��x�	c�.��X]�������^m�JFy��}G9�����x$�#3�mohq������1@�'z��+M�y"W[���1:\<���vy���:��Dn����_���J�����X���3��~���k|��ct�?F�>V������?8:v�}tf��C��5�)�6
$�9�h����o�L3'Q�8���l�3u?Dq�R���C�Z1����D��5��5��0&����k���+���c|�W��c��V�]��c��V�!���!S�CP�c���C��=�;� �$�,��p+z���������4z�#Xvnt��� ���j��!I����Eu@4�.C��d�~���GP�*�Ugs��Eq;��f:�ot�{	��qF�If���	u��D�vG�|�"��[�jkg�{�A�-r��3���TG��_���Yv'�|�"��=������3Y;���\e��y�T��:����r^���<�#���y_2T�"�Q�x�b#�+Zo�?������(�{��+D��v�#�Q�l�z�g�?l��dl��7�K��������8�E�jkg���ETG*��|�-$���}�@��t��>=���mG��8�D_���ws���q
`SJ�����Y@�X��wdZ�����Y���CH]�r���������7���n�K�sz*���A���~�
��n"���l������?�/�IZ<9�����_������X�����}`��ac�*b�c��7��N���{�{������������N��}\��|����o&o���9dn��&��%E�wx�vc�\��sulE7��l�f�l
���%p�}b�F,MEi<f�{G�#|<��i::�����	\Mx�����t�n�+Jc�O$�m�����8�c�B�j��N�%:t��V����#	�w��	/:������S���"����w�s�g��������^��Jx||
.�� ������6u�{_���wymdA�w��u#���3"]�FA�[
������P��������D����	/y8�����R����L��	/y��1g���>z� �1i�s^�I�q���t������#�'[����f1[�k�B��.�[:��9C���{n����UqA�b�����`�������������i��p8n�3]8���}��dj;������:�3��=��/R�	n&��+{X�����"H����"��l��2���0�}�!��6r}���1�AW���X!��tF9�4�,���]���w-$i,�`��Qv:i�'��"e��6
�
lLJ�H����5��qOR��d,���Ul��a(�74��V�1=�(�������xn��9�e.�H��=���{bQ��1oa�5D�K�j����s�����aZS������\�j��N;'��Zc�}z�-�l�O����w���)�u����(���
W�]��uD7�QL�F����Jt��Ds1\�s�u�W���V�H!���D+���������w=_�^�����w�s7�Dgp����Qd7�%��2��f�3V�'+F�d���i6�����h�d&?w#_��h�4��b�w�BtF\���M|�F�%�l��q�&�~�����/�d��4�1��n#:c�r��5k\1Fc���\��}�x�K6�k�K��Dg0��wc�YO�����(6��%[��,��.+n������/Q��Z�1 7��V�d�>\��v���_�������1�j�d���(���9}s9��m������/qd���fL����Qd��F���bmfyb�n�@��Kj���$3�Ev���9k�eW�Qv�7W���*��T�������X���Q���^vO�y��]��������j�>���>(?`����t��iR����%D��\���W�'��sj�	�(A����(��&j�7��9���g���6 �a�����p������,�=g����
�'��3@p�	����UKCA�#sqx^Y�T�������5��G����C*��I�S{�������42�����P{����]@D�t��}b�P��
��u�=����c#	V,x�^����@W����KM��+x	�W^j���?�������N�Y��O�����,�E��Q�CNO�j��>�����\Mx��F�))<k�}��A�+p5��LCx>�"��;u�n����^��4������>�ZX�yK�>��$<T
j���`�)�u�g���K%��:�
�&��F����}��Ix�gl���_����36��7r��=������8��F�>A��#<���������`�Ym��0��8�!�������V
��`on9�"�����
�����yW^�cd>o4�y�'��y���3��G��|�h����":��&#�g:Rq��|�SZK:O
�f��&#�gn9�"<V��&����|�Q��L/4������|^���X���-�^�ca>o1�y}�ca>o�8z�#�~��st�c>���V���H�c>o5�y'J�O��#:��nx���7^g���3�������V}����w����{z��=�o?�<]~<�����u�������_��n��B����s�9�j�/_��6��NS9��t�5]�p> ���f�(������")���<��R���Mhl�����+"���o+x����q�V��f�C��d��H�5���c
\m����@c��C�U���s��;��Zj�y<>9����\���2��C�D8�cy.E�1�~�<TD���}Ma�_�A/#���sc���!�l��(�[����eN\3�����!��C�x��l5��~��?���/��^�\�����O?���?���_h�����������,�������?������7���C�Zm	7]������?l������������m��%��5�E�[tUAt����������*D?�V]�9D7�5{/����ZMt���]]�QEz��Vt5���V]�)D7���5G�F�Fp�8w�.��5��b�^c���J�j��>���f��HV�E��
3�VM:��kA��Z�(�������=�"Gt�S�R?�����X��(�#[X����#Y�5�����8w��W8��#U�5��V-�{�NJt ��7L����ON� ����}_S;�������r�T���x�zl>����#�� �����2�~��	r��}\��	�����V�{�]Q����U�HSw�,x�r��1<SWl���'���'DE�#EW�5]�����Da���(x5M{T$����A���`�8����v�����L�C�(p5��'
�N��������i(<c��Y��"�Q��U�7F�MtH}
\Mx��������l{�_y���x{���8������G�=�"���3^[s�z�u5�g,�S?��W^�VD�C.J�j�K�`�%��'�*s�z��(�^��K�`p������<"��3�}�l�
���:�rR��#�3��uFU��� �����WQ�7�A8�g�S:K�)n�{�Y�����A�,��w�����`�����=�W*�l�h��}�}���`m��������#��*��u�U���L���,����H0�;��l1#������Z��B 8���^����������G����:5�����0�����g\���������F��������"DcAZr[�����D=H/��������q����;�Y��������@t�K��R�g�I{�D��*
F��w��0��7x�VM2L��UxE������'{���w�IX!8B�����[�zL����|ZJ��H��A��7�S�/�P�x�x
>��9��(���RE���Jt��������zc>ZmuKE�������^t|�FkIt�<�mD��s�
v�	N���##��&��^�I/����a�)�@7Dg����F	q���D}"����3��x���fp1��n��N�N�M�1D��6Y��+h�#:�~�$���d����aD���L��.��m��}�����#:���~�$���d��������D�\����]@ht����������^�	J<Y�aw�OY(�N�{�C�N=���x����NK_�
=H�����$>����y�x
�;���).q���p>8+�%��O~#�>��t&9���S�F��#�oF��;!�������J�S�.�������������A�71:��
�$�b_��#29������>�����+I&�
������Z&c#�	.H����A��eIrb�]�k���L~��!���
���W�^��&��n�kJ�X�d������t��):��m�CZT�� �+rTx�M2$>b*�_�S�Ye�+�mx������������p��������zB�gr�-\��t�.B\GB��>V1%��A�>��u��h���,��}����J#�~�5�$�������{I���!��D��Kz�g`G$3��������f<�s�=����B:���[��\�B��b�sYR�zS�������:pi�������I�UM��r���^ag:��p�J�������+"hv��F
4Y�����%n��k�3�x��Fe76���F�2�~��V�s������.6�������D���+��������*�Uwbj��9��A����}��f����Vs��D�sl��nnN�}�}l�����":�Et+����U�QD�����Ur�-�M�
���K�MD�_'�L�(��m��s��EtkMt�u�\t+o��`��{:F�~�$����ho����QD��f��.��mb56[�� ���������_�}q�(�=�����6���k#������K���n�W�s���C�%h�������o��\���Zj,�t3��� dV�b� ��t���#E?5�8�����4Y-�q4=��,x5M��&��C�(p�� G*����Z_ t+�g����b#�����Y�'��@�6
\Mx��S�B��}��w
OE���-��>��A��V�D���w1�^s�w���]�Y�f�6��8M�*�F�lEx+��e5fQ[��������}��o���a?U�y��$���e�)��6�Gl?�����E~l����p��_��{�S�Z��%�������-���QN�Z�&_�������	WA����U>[	\Mv��_��d+^QX�q�jl�j�} t�hVk���Xv+egD4u(n���@t\���,�a�B+]	}�t-t������s����Z��_�7�Q�Bo��k����������������b@���
��oq���k��\k�'�5���^o2���������H[��O��$<���W{�B-�5����/���#�������1[>��������������|7;��C�6v<��^�3wb�i
 :��\�5�o{���$p5���0�D��jp���aZ����l�����[�_�������L��y��$m���lF���
�a��D7�n"mt�'��F!h5���{��.�N�Q$]
~���D��Nt#����[og�U�J�QD�TD�;-�E��g�������n&:�Yi-y���cU�rq��|�Z��.��x���XU�XGt+����9�>��:�&VB�*G]���}��6���1:���v�������y�tF��h<��H���":�&������s���n(���:I<��F�x���|u-�w]C��������<Y�^������k���h���pn/�o�8\�����&h�2/�h���9�&+;��6J��*nM)
��teM�iu�M[�>��k����,J��):�j�W���2��v��"QFg�]SSv�u}#;�Ev
&�	�l�q�CS��Ud��QVvmI�YK��3��N��Ud���Xv|v[=����Jt|v[������]�g�5-��-�yO����N���d���������Kt�.p5��~+H��Z�8��6���I�~+����e!��Ev���A���`7������#�8���h�6�E���D�����q�eW������j>���������J�/j��������>�*j~=����w������qz��#��*�Q��P:!��+�57�b����*5�c�e�������Op���o4�X7�^���)}R;/Rz	����W{n���f�=��5c�P$3���4�`�4c��Kt�Q�z��,u�������q�>�o�bC���G�����/h��W�
5�����teC��� ���o���dUdi�1+'��>�]t������a��7��Vi���Ij~1~R�����6�S��!3`�
v\�I��+���zH�7��ctz9���6vu���^���1��StCMt:����Et���H�1��Wt�������u0Jctz9�5@7��c{w$��gq����=O�zW�or�MLb4��[��(�n��n�{�����o���]�":���v������cLz�����0D_��#6�����l�z�����=���"�VE� ~�x��'k�CurW��Gayf�Y���2#���	t^b���e{�x�$��%D=�6�~���W�������BG��"?��xJ~���3���v:�j�TNG�\���Q0+���s�+�O�t��)Mp�+'F��_�n D?���R|�n�[�j����v��EA����j� �QO5�l�0���	������H���/~7=O-%�_�M|�4�!������$:$��1�f�k�cb�P�&���gy�������G|%�MbM7v����@���������3u�p�������'K�5����,��6!$,�"�W�Z��"�a�}3��Q��A ����m.��,��[�`t�>M1/V�	�������"=c���L������.FB��'�����!��^W�cGw{1v��DyZ����%R��]��.�
����P��#F�:v<�
�
��!H8����1�-�a���_�*�#���Cp�r��3 C1vn&�������X2;�b��W����@m;�"�� O���!p�Et��
bGSDC
tdv���V�G'K�A�h��<1��NO,���������T���gi���V]t��MD�����uC�	n��C�I�
�;�������|^L^;�����7����5��2[���c�����6�=������y�	a�p����9��v�����c����}%7����^r�����1������	����80��f�/�P}G�y�}�������}�A@9Q�Or)T�{d����i�
9�!u(h��BNp�
��L-5�y�2��$����1q��������,����6!�{��1���d�����x":8���d����Pc;�I��px��#��n���M�'�(a���,p���Dt�46��(y�~	���Xd��qd�����=��mv���!t�OD��c1��[�<��n�����5��8�#�C�j��>Z���n������x":d��&��cw�n+);=l�!��nC2@�*���`qd��u���.>��6���������]+�n� �%MF����>�����������������_�m�������p���S��>���
�F��_=GCy�p�6�p8K
g��
c��[L��~�V&7��e���7����C�L�+�;'�W�)�?I���$8��x�E���w��w������u����(�������:B������PD���&:c�|��/��>N��H�+�W^��ydw^��^[Q�:����e@_7�U�������(f�5���1��q�pQ�jY]��8�DG�����{^���uOn�,X	�����8�D��U�r��f�~�A
y�Q�TU���0����Z����F�������`��V��PY�C�*h��"�+JA���k.tB� 8T�����9��������BPr�m|�����q$��y����:��#K����F���tQk���K����g���mr��9���l�h�$��Jv�9{Lgz�����}�{�+p�ZEr���A�\W�_%��\�FA�H�1�6��F����Kn#8�*�J�a��WU��^���6�T���
�	�{��G�b�Q���TP �������x�0TP�C]V�>.��P��o�A�8�G��V���nj(I=~������D����}*(�.|g'��
Jt�������(��K�N{|*(������&�3���v�3�&�-��V��n6J�!�$p�V����/��xJ@+��/��y2�E��	���Q��!�m�[ar���n�_�d+�Ev;(��<(��@A�����);������������o��������2�"��@A������'�a]YRv_d���<��xf}�G�����kG��1��.����K�K���	��Wx
�UN�K��p���)�5�EWB�!:���r%=�,�"�����	�7� +�j^��x�)/rpl��a�����\�KGtX��;D51���Q���kr�qG��3������]����}O;&YM������;l5����t@7��R�H��#F$
����ZU�p����&��0����#8>"F�I�����}7|N�����Lp�����d���\:l������m���`Bz�N\�7����+r&��z<Zd� uv��8W�k���0����2A�&����3��q��-���n��'��DA{>=Er;����]$GWz���Vr8����I��'=Z���
^%�>%�J
�����n��=��������f%��H����`�%��������Or�n$�/v������
/n=%-��������a\�S?eF#��N��P|�OuaE��H��`V�����o�P������������^u5&v��z�AD����GA�T�"�����aw����zJpG��#�y��T����i�a�����h0aLpA���x���X���4<��D^��	���\f�)����0�fz�
�y�/C��C�S=\M��s��$z�,p�����=��D�F�j���N����<�u=6�=NS:�/_�w���0/or�M9�E�Z0 ��K
f���w�Z0���,p��������k�M�o��+|Z������`�C�C�j�L(6���5���������(f��Z-����;4	\��a-8
B� :4�	�����b�7�e����(�
f����C�F�>�����CK�z����a(D�eEW��q��P:����/+�kq')c�Y;�En�	n?N<�9KJ��W�8V%=H�88~2�V��XMp� L�����CuG�*�6��Sr��U/���UJ�!���fT��_��M�f� :��&��0�I+W�^�Au���QD��C���.��Wtt�����W�yG%��fR_&��0��f�����g4=�� �����7_���#Q_"Z�9?E����N|�Nr$��=���z�'����).L���0LJ�>.H���?	����\X/���t�jGD�j�ll��+[qj�O��������%e�����XK���(����q�L��llV����/�9�� �Xh�q��llV<�����llV4������llV<s��A�����Y��A����gc�bz��f����hy��dG���X
�\��c�l6d}��+DG����UC�a?DG�������t��8�+k*q�q��llV4wc���!c�beM�
�c"����
��c��<�����'�1�v^;7�MS[5��<��<������� �;�.%U����H�o�L V @f�a���D�����&+��1nFA�&�b�)H����������(�`�Zl��Dt��k�>�5���i	Q����q����xL�� <&�CT"p���[^��.��������B���c_�c�~��B������Q�RY��axLDw[�������$:A{�3>����/�2!?�	`�[�Zu?��(��sl�V�C�SBp�S���nA"D��O�D���A���b�D}�E���4qD��m�)��E������X�TBp��/�����(jQD7�����w���8{��ul�^��[�/Etl�^�f��[�����S��2���
������s�z_.S/\���Z�����@4�{�kK�4l5��
Cc�D>A�� 4&�]��e:`�`�����tt}II�I���ahLD��_��	�	Xt�'����yD�����AtH�	�'rRgdW���#���:d�����~��?���/��^�\~����O?���?��g=}y�������?����������?�����~�<�������+A��6�T������a�����/�~c����p
����NQLu�;����>>A�g��3�{z�U$�M%�g4�X���o��&x�����8�Cb[�j�{��	-����3�&�/�����3�>���(���
^Ex��sD�������xS`�1'�9Y��Ex
����5W BxO���{��������5&��x�,_�����E�+��4��7��5��p��m����[��8���)�5��5b&q��Po��=��o^����z��v�@��("VT���� ��!<�5
^��yL�|e<�x/+Jo;��6��%�f��&v�W5��Aq��c���/�!#p���9Q���!�5E�sp|���H#:���c���\�P0�l��s����%���@���0���Hc�LQC�����,��3��V����9`�A�^�f��;p�������_�0���r���2��%��D��O��Np�$��F:1����R�QD7�i�\z�1F��OF�T�1A-��&��^����a�8Go`����8��,_��D31��v�RHENE�'u�����{nwK#�og�
������s��H�kK@�u���~��!���CB����@�0"������a	C��"8=l4�!�\�v_�{�.���w�������	wz��4G
��^Wt�Bx}y���������Js*CE���������T
oh(��t$��eq-�e��7�nX}>9M���F|����7��C�W�o��������|��0��k�a�k+B�#��e�\�d���Z������9�<��`���� V^��5��Q�b�^��Q/2g�����-�!N�u	k�+]����������� �n��[�h�n��&�v��G1&����|�Ht+����(��8T9 A���������Ht�*��!���_����2���w����}�r �b>���"7�0)r��s\:����a���1�����dd��4B�aQ����NLi���o"���B]r��
W]��@��I}H.:�W�.H9��6�������}9��k��>�z?~�����K!a%������*S�!����7��������}���\y��z��z%�����1W�4����\������v
��"�St�_�{A�-(���C�@�j����JxH���Y$����
���4dxUQ��F���&:<s7����i��$Q�W��Q)On�U����U��[��P������-����k/���8��j
OO���:�0�{��!��������Z���}��t����S}�a���������k�h��K�����V]
`����}��}D�"?+��r�m�)�9��	�z~����0U{|<A�1%�v����������9�x7w�
���������������d��H�z'Bz3�W���h��#�0U{�CO��{����jKo��c���v����D724_����U��@{g��H����T��?iQ
BT�p|E&�����U�p3�}�!����:��;�.^s�J�����j��n�%�� 8�'�`��Y_�|�*����S�DG'f��V�*��v>m�1`2���L�9C���VqD7�E)M.:��N���:��\]�����_��CqW������P}����X
T�'�/�@V
��s�j���_�>.D��������-#���5R�z��2�0�y���%XN�����C��W&�d��+�y\�+���(��C����yx��/V�xH^Ex��O�n*)<�v�����%x�E'9�P;��j����3j���6D7��U;��]Vx3��W^t������	���0�����3ct��������
O{�����<�U7�Y�o�*?J��MU�w>�w���E�j��0�Z�����_�V�+����C��S!e�r���N��m��*��+��(t���
�p����������1�=����wky���������W�5N�	b�MM^���lf����Mn�M�J�����b��v��o��i�
��3�����TOn0
S�����Wa�~v�j�
||A�U���d����1�
����(L���F�3�������}�J���p+�)=��L��=��3�,?�/��u��-���z��J���J
�V]��q*�����J���/����9�E*�!�� :=�k%M�����}�!��S�qD���)�-RA�U%��1��i�U�#����|�����<����h�����+\����r�j4�����Ol
�I�j����<w�Nt!3�C��B�j��N�"::OF�Q��f������y�,�^a�G��w�Y�i�����KR�|���;e�\v�I	\Mv�x����X���|���\��3�p�`A���v3�/Y��G��3���
O��q(p����o��Z�c�I&�Yv��V�_r�
��z�%+�w�C��
�R����l0�]e��b`L6/Yr�x�K61�QE�s�����K��7������`�9w#c����R�w_������t1�����}����M��b��������M_/�W�My�u���:����5?��,��7@�j^m�1�Y�;Nm}��_W� h��(K~�L�+@�?�m����6�q��}��+��6\q�����-f���#A�7*T��gT +�\��9�g�3zFMpA���p���`�9�����X"�l��&Q�#Z��t�����L�|7M�Ei�VY��8�.�-^M��&P�m�����=n���m����n��O&����$��Wy�A�MW����}!���wj�����F'Ic��k���������k�1J	��@��|}���1.&?�����T�[Vu�6������	#V�Q�&H���/��	�v�[m&�:}���)��6�!�m&�X)t#���j3����A�0T�&�����d�<�$���+*��~��E���?/@.���?����������/f}���������?���_����>=)_�R*�rS	��x��zz��Sl��~�~/}��u���1��7pY�|��$f���Cnp��_/���9���C���*���5�F�	�3����������.?A��S�'j��������F�k�=�������9vQ1��6�y%����lr/O�9���9��O�#<�7ht���M�C��hnx�N_#����l��#;F���.zO��%��.��H9�������n":#TJn��NtQ�����qE��}�s�T�hmH07��8wL��f*&:�������i����G���l�%������L���5�[��x����P��<���)��/�`T����0�5C(}��f�d�Abo-*��8�T�j���Ct|��	��e�\���d�:��
�3r�]��n�K6Y3R��@t�K�Z��";�d��h�H�#;RN��x����XD�4���Q}����n$:�y�K��� �	�g<c�n�5���6��� p�!�G��DtF��5�)���A-:��n<����,���fW��3�;b�;ng�����S���k=S�:��z&��.�����~�:z[��������S����/���N��Y�$�O	��M�e�qMN=��RV���@�1�gU�:U�*�����������h�OCh�&N���f���L:�d�4h��zc��\�|x��zc��B(+����w
�Cp�[�'������|����h�3�S��p��6<;-�7��]��zco������4M2�l����<�����-6���2Po�!�1���eo�p������1xoL������G���_��7�+��no��]0Y�`F�/_������*��x[cB�<����Y�������DGwk4
z(���.~���"V�t��=��	���CRm�����B9P��e����w�g�d�
�w���$:������b�Dt�w(p������>�0��?��o�T	��At��
\7��g���9r�R/�V�|���~v�1f��yjV�(L;������S�'�9�����9G����|3����ic�F���R�11��e�g
t�.���i�s���C��������Us���.:���6�3���e��W�]t���Y���e�0x���`��n':�Ao���"���f���9�3H]������K�wu��o\cYWn���fb '�d]�[]��=�T���N��:!�����A�� u-�����$/�,B[���Z��qS����c.cqr����A��u-�C�h��c���g:S�Q8�vLD��NQ����0P]���������u	���U���2t]��>�ZM��?�s�*��V_�/���;U���Km�$�_�I���k����pMA&L�"�YK�Z���%#:��Vf@��cn$��}�be�����/��y�{pkA3��H�Z��Cx(e	^��}(�q�x��S��&V��x�Vc��5!#P9��V����
�����f\�N*�)1F��*��$���c��8T9 �� �h��
a�kz�R�0B�0��k*���*���rLYU�+?s�&8d���3�(�,w,	z���S��'�������Do$�����sz�!���=w����T��xN.;�X�����	_7k�R����\�$`}{��y6�Le}���Dg8�M��#DG��jxOn�lx_����K�DG��jx�����f���.z���6�3��C�qK@��w���.z����AY
��e�����d�_���Lt������W���/?~����&>��,��	��:zU��n5JA���k��>L����}\��3�!�"h�2�5Hx�i���������W�*[��T�	�����Xq'o� \k�|MwEi����{��3�)�g�C|!x�+�����(��:t��m>?�m}����
C���P����*�*���������c��7r.�Z��8�P�0@�C��
8�q�jM":>���C7���h��R����D���	�cAz�H/��mS�������hP
^��}fG�bNR��)���������h��T�&:��W�������xe��!�1�+TE��A�\�!�����h$)p�Z�h[+��4Ra��~���T�	����g���s���l0��a����fD�0����L!���g����q�\-�}j0���Y�j��^�!:���
:sgE��"�mDg��I.��&:kt���D��Y�j��^�&����2��g&��r�nm�5FB������>�n+Gv���o��5��
F����$:#����Mp��&�`t_��%�������i':�%3��������|�&c�|r���Qf�%3�}�8w�Bt��b�_�#;�r����u�{�n�o�X�q������.u\A
�nQx�!lQdG
�nQx��1dG
�nQx�������Xk���n':�Z����j� A��Rb�nC�E���o�����d�W<I:f�����u����5�u��?R�?`�~w�`��MH�C8��]��[�M���?�W�O�B#�������>h;iD�U
C(���(�K����:Fx���Q�9�neoD�%�(�*�RO�V�e�:Fx=�7|�Hk���V�����c}�9��o8����#��A�:6u�r��4�����c��k����(b���l���6!�A��b��/����Bt3�t����p�}E�&�"�v�3�K�������!�U�)WY��@�5�����+�|V�P���]����6���\���p��7��G��w�h������ ����`^���}�
����Yq(�@�%A����:~a�kD�|��U�kF>"}����Z����!���Np�>�,Y���f��i���d]���-#p��k�D�T��}"�Gv�����O��1|�-Dg�n���� :����( :�n��8M~��V1�.:#��V��{���n����8��_"�n��,p��fG���q27�a�k<Vr�M�QF�07n�8w_�I�Q�Dz��Dg�d�3Iv3��I�����(��������	OV��n"��T�WU����w^U�K��F~<�����l?����U
���*B*��7B�����lC=:��*������\�"��}N~�X	D��@V
�����pmAp:����@px��[&��
��E�bp�Z5�m�N��,�b%^WSz_V�n����xM�V�#��;@�W����9��V��_������]Y	��J��
��G���n�-VB[��3��@����/_�%����b����%�	k�����+����1\���D��":>�f�RlF�����Z��&��P�F�����b-���b�z��2����_L���z���BC���a@3�rD����F	����������7'��4�Uw-���@����Y���`��8'� ��lzB����s�O�L�l�3�@p�3Z��Z�9N������GW�>\�{�Xo	96���?$���[_�c�l"�b1}����|��AD��%:�W�r�I������jS�^�":(W�]t�����+�%�����FR�^�Cv]Et�c��f;�&W�]t��D�wAg�8�W�]�@��D�����l?@���
�����Btztz���%p5��c�xE�5Y[�����
P��DgM��>���V��WAUe��@G����d��y��@t��nX[_,������~����
������'I9a�aS�]�pkU�*<��A�O�;W���^��*M���������h/R�	W�|��D�j�a
���hQ�jo����/�K����B�K�j��3%�5M[��(�������On�������.)�/<K����+��1Y)���O���y��_K�1K��Z�Z
o�?-
'r.������$�����%H
���hv�����x��n<tA��I���1���Iz��Gt��i�L,*�*���5vE������R|j3�\V)^O�*��X����JK�R|r;i(�(o���tSI���k?3U�'H>*�U��������yff0��1�aJ��9C�V)���q�����k�G��	�?v��m��8A�%>���
���(;(�i"O���R2����fM�����8��1��T�6������r):)��F�ku:���QJ����IO+���=�����U����_���| ����rx��r���A��@����d�|S��i��� \��A�C�E��e��� y���1#V��&����Y&o,P�����;.K���Y|�����OM3i�Z�ws�r�:�����5@��QJ�b8�S�e�:E=|~�������*_�Q������Y�0�������{����M�)�2a��������T
t��7��� ����L���M�	b�N�����J9�ZP�:����*bF���q�������1�o���ctc�&>�CRO�����7c�er3�!��������j���P]�n����CU�A^�
E��j��f�/�!�(ptF|�rp%�@A�T���`�AC��"8�������Z:�3�n����M���������!����X��#�\v#h�W�]���[��`5V���@7�K������R��]����Fg��,-� ��V���e�9�W��������u�����BQd�O�j������6�3F�%?wKE�����6��c�E�j��>����AY�s�o��Dg�_��%z�[�A-�^�`%z�Bt���w�QVFh�A
����Fj5�!Utz�!�'p5��+<��Fj3�!U��D��l�v#��+v�6cNI���������F�q������8������]_Ki��BI�G�|���\�%i��$��S�������p�������SB�F�{��4�=q������o�O#��kh�C�@�����c�/����.�(}�CZ�w�I�&����'�7Vq��-�Gp��'���A����~)(H�������R�G^t6Fe���#<����M5�Q��Cj���iN��OL�	��#<>�7�b������Q����yq}��}��#~���m�����_��s���-�?�O
Z�h��K\��[���
_C'�q�2�q���qf�+�?�a��tp�n�iW7���`��(���v��B:�����`�d|���)���i����Hf\/������qO[���K��s�!�+p���ZJ�'~��qCCi����M���][Sv��Q��8�� ;>*�^Q��Y^A�8��
\eZ�aA8���tZ�>�����?%W�%��2Z�:q������]�������!��DW�9Kc����7D}�A��A���.6�A�����d���[��X*X��	��Q��|�(������N��,Bv��r����q`����^���L�c�5�����&��c*t�)�����oE����d�������^%���q�=��F��������:�_�V�\��5b�;F�]d��%3�{�P�s��Dg�dFr$�mDg����1�]_���jb�%t|�z��no��"�����,���|�z=�cV���n���x���d;	�'��qd7���%��F���Y:�"��������s���C��=(c�l��nb.`��+<}���d�R�w\�.p�lxNv�}�:zP����<�23&���E9w�+p�%��y���Kf#�!��1�l�d���:;�&��q�����wvVMr��FY������/��V�d7{��K�����y�/����je�%���z@��t�1T��>G��O������>9�&a~d���Q0+��c�0-	�������o}	���v`���]�q�K 8N�����/��f���f�iB�g2���rS���x4����X����%d������J�w����8��Q�O��a�o�(���(��;�/�
��0����������U}	�%B������k�D�����o��kT���f�m�p��>�OR����V��x�d��Z���������������������~��������Lw���������0�?�������������/����(����Z��gY�����#_/���_~���O���|�U?D~�oT��Q�����5���
Z����\Bp�����1��".����I�D����}"�����������&&Ts	 v=!�q�h�����/A{��;Po	����{�q����F�6c����[����)������C��������-NZ�y�D�J��UzK�B~����#b�{��9��r�>+Gc�����'���%�:�4�!m�R
��5^�B�9H2H���6�3J�m��>�m���g�!)��}�]��N�g��8w�Nt�*��v���&��#Bt�.p��f����!��iL����7���N~��a����(���� ��>wKY�q�T�4�')D�6g�KJDyO���X6���>~<���UN���2�
�}E��	�pa����^�>.H5����Xn��o�XZ������K�j������}��Mx���jz�(����b�8��.����x�7U�	~�r�L����Z�.�jt���qm�q�G|��f5z��������Uk]��,��^�3�����X����Pu@\��"��:����/��;A������G��}�g�X��:\��{<z����#_��&�=P���4C��V<���
����������������
��=�x�}��u��f�%%����mU���D���u��~V�Z�eE�z)���0���{����W	���U��1��ja)���I��	Z�K�zJX-��v�'���&Xx�ku<�S�3�g���'����iq��'(��5#1L���(�����>A�LD��%��k���C�I�j���It�?������5���@������<@G������~v1�Pz?M������Ub���(��P�����?���^����ubo��4����K����g^�N�[���}e����d}������Kz�-%5k���S4�,Y� �%���dy	�^��&>A��3e�=������:<����������;[�����.�����K)�����@]�����<l�S���>��T���+L�����t��	.H������L�m�Yx-�he��Ro�
DksI��9��%��������4m-������4Z��$m��9�M5��U�g�|���+�d>/��������Z��q��+�f��d���/&a��ke��^���7g��������,�n�s}SV{�������ul3j�FH�8Np�w�7yP�u+)H+���Ft�[	�':<�	�;�����|V�
�`�m�c���h��Q�-=���������}K3�D+�S��h�{=��I�P�q��);��:��8Tq �� �ZPm��S:n&�J���8Np�vci�V O������9X�7��+t9J��n�?&c_��]�����������7t��G<d��o����}k��D�����]_S���z�!��W��.6�#s)p5�E�ZtCAtz��c!@`�
�>\Mv��5D7�^y� ;��\Mv���'k�@7�D��:�U[��k����Ub�@@�J����_
�!�� /s7v����v���H����t��s=����E�W�����+P�������
�X�p������a
����`i�R`���n�����J�\��d���Kk�G��������f�'L�������=5�u��
�������J��3G�*��N�}=&(�6���ZX��|��A���dJ;%�}�������twA��,A������rv��o����K[�������F�����g��Z�LX5������o���l�W4Dp�M�h,	T�%8��7����u�:7�M&#q����X4":���'�Ia�j��G���U!V��E�������'��e�E�;K3~18��&��}�b������f��NV�)1��j�@�1]i"�!�Ik��7e��NF�d��������W�J2����p���L/L��Lp�ofa�>F�������v$��B�	.L>�����W��h��2��������>�H��Z�+\Mv��}e7���g��Nt��l^��5��Wsz���Q�&�`#�}e��~�x,�
,��7Jk��C����k���o�������MxA��D��A�}�>��0��
W��?����9�u@w3���n��������?J�?`��������d	�kA�FU��v��,	9)A�� %K�C�-h�2+P�����5,>P!�6�&���m��T�$<|�{jzc������mG���x��i�����xJ������@d����,�dY'�����_A�Yl���������g����):��)����*�v��>C&B��B '��-����@u�C'h��1��U��K�{#f�����=����Xf :���}b�`�j!�����0#Yq���a���[�,�V�F_�Jt-��o4A�Xi(����f��NZ�)1�����@���W�n����CU���b���K#��ZHtH
���}�j!�M�gU����e�)���m�1�N�2���@��{R���I�4&���Y�9Ef�5H�������8����6�nb�;';�����lzcWz����\Mv�&:{�����6�������j��y���*��������I�m�?��F�������Jt���%~�+K��9��U�";4g^�j��^�'�����Az�-w�3|S��������Q��l�B���d}�4��D�TwE$���Y;���� :�(W�����7Jm�(��L�Ft_7�=���G�������?l
���u_�����@8"�'���q���G�%��	pA����}�4h=����Di���	%�z20k�O z�!��������d�LQF��Ly6��Z���#��{L�h���V�G���]������?b)�_U���]�+=�mh����l��#��,�u�NLKX���O����F^�d�V��:A�T��jr���"h������5�L����z-�A�W{��-|�������k�>�F+n��u���b-SAp�TZ�w�0��
��*�[��%VJe�y���$9�{z\(���ew<���C�.eA��.�>� y�c�E�*}�F��vAp��5F�eP���M�u�y~�Mp�)����my�v�6~V�0��
W��cx�t_�����7��n^��2��D�`e�����X�e�������oa��
8c��vK�Y�=��$o��T��2�-�&���d�	�PA�����;���j��������L��62�,o����n+���X�i�Q4��m^����?:Pf���������Y���r:�\W����������63�}Y�}2�z����[�Z6�����u��2���������� )
��t�@K	���U.��9Y�+q�7��_��
����b�����3�Z�1kR��,��9&x]+�Y1N�AKn�5����h*=��EO��� 
��4c6e
�w1���$��l|<6���,���-p�������$�2��`��,��D���5:1;C�ar��G���
���l��>s�2-����+Ab����(������O�$:������M7)tkAtz�^vV%p5�k�����Uo���F�J�W�]��O�a-��y�m�m|����Vu��]s����xG�H�W�]���@�Q���.��S����h��"A��D�o�O.��@�u�8��.X[����7��}�������%��Gv������+k�3-v����dW�%p���������z]�v}?�U���
�eW�F��4U��k�����j$�7�Q�
����d�W<I���&���������=��(c�M"�\��sO�z/���;�X���e��-	���u�w���!���w+�bb�+��ZG~>��Pd#"D%R ������n'8�i�B6�
���|�Jd�wL�k����Bx���z���;�^�t]Qz_V�n���%�i�b�D�t
W��0�'��g�S�F��
L���l4\�F�B6���6���kW����EM&�h,�������\�����(��A������Z�=�	)���}�"�5�7������J��n�J����F�H�	x�@������ :��W{��m��������TM���'����X�������T����(��@���i���� R%7����d��x "��J/p+n��8�
 �� -"�Q4
C�":�������Jp|D�H��F������������m)_ib���':�]��%:���F��=��C����d��tl�����d �CV`0��+^�MD�WA����C <X�����`����N��MpQd���%p5�E'��Lt:(�����2P��Btp�����/�����f����Jt�Kf*6��8#A�j��Nh!:�d�|S�qd��7f;���b�n':�F1Evo����[�E�?At(�	\%D�Gv�Q������"�X����En�@MQ�H"������PR�Y�!��n�JJ7��d�����x/���3�����^�X�bT��24Z�MxA(A@�#�2������!j��|�aJ�
�lV\J��|�[&�G��F��V���a�"�G#6�j����R��E�q�2��5=��6�k������I=��i����x
%���������WJ�pL	j�d���H��W=�����C�3�T��|x��_�F�����ri>�^(� ry�h��3���
r���;6:��6�B��M�/bE�V�+Ee���E����<Z}����"��^Qx�
M����U0��O=zc#j����oi�S�Z�d��&7���K��N��"�<x��f���8� �� u?�.

�!�
�7���p
Z%����''����.��7��5�y������L�v���xiA���L��t%�������x�=t�++�X����Sn�n��N�>���n���.:���f���C��=��J���	/��f��Wx�_�':*�&�����n!:�P��f��&�`�O�-tS�!��[��.�$�j�N�!���t�4�������.:������:��Tl��%[
���rCttIW�%3Ev�
\Mv�)7D������?wo�����������K��o����y��F�,�����1�'�LT����t��?�x��u�n�&Z�K��xO�zu�1�t���YNJ� =!�G�,�������z�x�O��}qpVX�
!��ji�����/��uX��k��y�C\h���|J4���`��1���Ep�:!h�����%��(��;a�?���a���OOn]�%�����)J�-(�9Q4�yiK������F��x
����`���H#�����F��U'���X�_
�&�����W��;��A�2F?]����g��� �p��d��0o����.�Y�t��$od�~#?���b,s���.������/���hE�y�^���������5�v��Z1��	^��}��F�����1#-���������8�F�����o�bE8,����G�y4vq[qz��ob7��I�N?3C�rA�+�5��g��yZ�\��0�(�����h�Q]S���_UY������&����Y�����v���(���������X�<cdR��n$:}>Z��~���"�ZtmEt��bma�#���f[c!�	/��&���s�@��C�M�j�Fj��������&�(����i��`S�Qd7���)�}��_B�*����F�]�d��}�c�$<D��W^dV��n!:#�L/��$<}�Bm��Q�7��t*����
�U�y-.�����,����
W�]���.:>f����SW�]����W'��Sv�<Wc�{]DQ�����R$�������R����F�'��ffF��6��8y3��Y�J�N�#������"2e�A��1������[�!/�k�9�<&��E��l�����^�Ww$���y�.���0�~n��KHB����b2��<����F�����4���=qZT\��<�$�����H6v����a��-m3Z\��.�E��N��T\�#���@�a���|y*�G3����T\|���S����{QP���R�3
C4]x�b���Y���!��.<�A��M5�Q��Zs�aM�5E�'Z������x�T\2-��������<������������b�W|edL.n���\��9���ysp|Kk�c�����&����*'��o|��bb������.�l82_�6��G\����}���X��wF.���|�Ht����U-Ule��sW��}>����_M8'x���%�)k�@���G��yt��>��mm�F�.�<R�F��j�E�%<:��a�z�%%�$�!�V��4
>!�<�����'}Q�9�.8z�����r���8|}��/��T�O������rR�Q8+��:\x�[7=�\���G�� gV��gV����[�E�J��1�:��f��k�u�Dt;��Ro-86f7�}���#����R�����ECx;����9����|���@��
�m�W��-W�OtO�)��Bt�������L'�N���s#�B�wk���^�Z<Y�?�x��]t��	>C`��R�{/
2Y�B2��%�1yM$,$��zfo�SH&������	.H!�>����q���X���4���)/�x���������o-)��8�}M��t�i�JXE��:C�7�V��!L!�����
7XH���K����.$7�gV����W������a�����d�S��J����;%^�
K����f���"�g���N���l�U	~��N�������\Y���@�x��RO��<(/h��*)Ic~l��c���S1h,+�kB4��������U�3~1 ����h.�64�Zt�����1������Jx���[g��Y�����M�U�<Wg������=����]W�^f�������p�6u������`���u��	����gL.B�:+�an���oj�[sb[��S_��D�R(��c�o�n'}Um��!<p9�p���"	m�W���*#Gx���gc�g,���ZZm��nc�it��6'o�Sed�kS�A��DG�j�r�n���]��z��� �Z�<�s��Lx�j��.�S�������0���t��
\G�>$�X�P�����+P��f�����z���Y	\�|>�	Sg%���t&�	.H��$r�[&Y�e� ��g�,	S}#<Z�b�l�2p�:+��%��F������4m
���i�����4}rK�w<��Jx;��5��u��[��R��c�:+�S,���Qg�������u��jj���Z/��������N�u�K�f����i������q!>��_��w��������������O�w�����n?�������|�|��%����
�1��U���������>�K|�|�V����&8/��y'aR�7���V������QH�#I����;`�������������w�����������>,�����q�
�����n����nZim�[F�����o��=���~�E�������-������D}�w�hU��F��b�����J
�5m���D;�(����	����oU��5�������	���F��#�|����DG=/�6�FJ_3n6
�a�w".��
,����[D%�Q6�]��\G�h��	���>G��Iz+����>�x��\����+^7�7�#� DM��/�*��Y�EtH�\�5p HO?��8=�>���I�I��2m�P������������\�U:��o��	�C���H��j_��%�u>V�-tZgc��	/����������Lx a	^Mx�w;�Bt�����c�u�x�
�����8
��:>m7u��,���I2��a[��2BsOF�k�./N�o��A���F�	K������U�Z����Lp���'�)�V]�F����Y������a
����Ug$Z���"��5� #)x�T�Ei�n6�#G�t[S���������xJ)���%��Rp�K�9._�����z�����_��+�f7�0�3K�F�j�������b>�fw�i���_M�������Vw��}��:��f�Y��,/^�q������k��i��t�_0��%��2{�������Vc'~�E�������T�N)�71��OU(�o�o��c#+��Ohh��Z�?X�Q#�JtzoGiMo�p���7r����0�h]����b���@����2���-
��3p*��U����0�0(_��u��vh�_�T�v��C_s$��3�J���)�/����?�x�K�#:t�	\��[n���j���8�`�d��*�Iy��YO�"��W�N��+�N���R�Z�8`����!L�N0������N�4�D����}O��P^��=������	�M)_������aO��9���@�:U.�	_���<������5�"��7�N���f�N��SKFF�b�F9�+�y�����q3s��x�'�}���P������>:���p���~�v�/�{�1��
W;������pl���	���s�w�8�����'�Q.�y�9�����B-)���P����I@�j'�#�y��Io��>��	�9�^��=����>ni�w���Z2x0}�|��	����	<))�	�v���;�)���s��|�s����	/s�p�������9��1�+�	o������������e�\;���n"�//�,�UE��i�{�5��T�fv������r��������5������'�n�5�yRT�����!�������)��5w?��-����_��+�@s[�yP����V�#\��=��n��(�77����za�R����<�C�p,�n�zn�k�r�U�+�?���+������	��t-O6����0��0~q�JB��'��o�ow���o�/���!S5�jP�'�S���]E���&DcL��Q��UtQ����C�P��p�v
"��s;s��3��'!��������}/k
�q��6b�@J �@D�J0k7�E��v�t�8����C�f����Q*#����{G���w7(+������H�rn}���;�?b+9�A��%z}K=��q`������j���}�KT	~bs_��~�B�_��T�����a�#�� �^o���[���{w�
�� ������-����d�\����������\.���
���6�o���8\^�v����x���\���2�o���}7W���S�+C����-����1�S_��<�\hm�?@7]kL��p����G l��u��se�U���h�{O��
�W���}��q��%����c��=d�W��:7�_��F��g��'�>�(`O��������7�,���
ro���V9-��o���|�F�
����]!�v;r��O�:Eo����I���;�Ns�;|a_��~��`������ovE'�������B����vY�~a�#�+�~��8��)�|����{^��/l5���'}��[}�}������8����!N�����>�>��.����(������������h��q%�n
��PK#]t�A)��}�1^�-�o����-��>Hx���>sw��)��}��Q������'����T�My]Ew��VL��~�K�f�J
�|\C�����A[��jZ��t�5r�j���|�p����n��Bk9�7�_����J���e�S�������/�^���W)�q|����f����a{x}����q�U���������7
��y^���}�O�HH�w;�Gb� ���\;5�q�H���l�M�k��#�#���C����������?�8�a<��!��G�c�D�G�8�P�h0����S�HY�w�����O'��������s��s[�2w����~����B�M{@F`� �E���KfT��������l3��X=��.i��I�p$v��A�]}�?�-/���{.�O����#����~8����W�rU{�q���_t�o���o�~�rU[���\�DW���pt��zU/����~H���]�ef��/w���Z���W���n�w�*�����kW�/-�U���co�O�	|D��#�����r�sWW
�������m�o��w������R����>~���>�ej��}�KO������}�Z���9������F��3��0������k���n_��a7���]!�������V%�v
��l��7���mbQ����k�������G��1`d���\����E��4�?�}l��k�=�����t����o��s���a��������g8�z���onZ�����I
�*~��CO�^���\��j������H�����
�������\������!��p������|[�^�o��O�h�I���w��-A):����W��}a�s_�}!������;k������2:�����dJB3���u+!]�����"cy����Tx	���c����������}����Z��"w�aVg�L������#���at�|3��u'��� � �=���������|[��t�o8|�=�L~�a-�y�<��!�����o�����*����x�L�#�
^�+�s+F�*���x�������.^l<{s������x]�����	�/������)y<�3��w��{U�u.Mi
^�ps���X\�*��V�?��Gt�U�+\���� ��xB���@7�	yL�x���
��e=��,�*k�������[���)_���~)(����R�]����'|L�.�uAt-�u:�c�N�u�����l�������"��}E�j�;=���Yh�p�i5� {�q��,N�M4���W=N|S��U>gb����.�y����q&�9�R�Fl���-�Q�t�>!R_�X_�`@������Z�s�w�GB��R�5���S1����l�C
H�*OH��"��|���`��yj;6`^������1����x]�,���.�U-��9^�.�������V�����]�����O��������"���\Dw�E����Ma��+{������
�^x���j������x<��E�����U�Y���~i��+���f	��r�#j�����VM�.^����~1��o8<��.�����6��VV�E\a�xf-:�Z�P���f8|C�1�k������
�'�5ud0K�����;���p��@��U�1:��A�����7��{�<!��^�.��^���s8�.�����h/�u��!���&R}�
���������q��$k����sM�/��N�lL/<��/^�����~��cW�Oi�]KC�jET�|�����t��6��W�>�����U|No���>'>b��]<��y�����1��8D5�`�Hw�m/���;Y}�9UT����JY]?��~8:����X�>�"�#r��eI�z7f�x�����z��|�U�FCY�+�����~�O��������?������������<yQ�E?���?�s�������?������t�5n�F]���4������[�Ro����a���?l����~��������{�����o_�q���s$&�>�>(�U5P��=����o�`6@�
��?��:����T��o|����
�WW��d��Y���|������c��?����'�#���[�OvK��[4+\d���a�T�1����.9����m�����v"�������O��~��o�S�����8�A'O�
N�7�d=�x�SB;~^-����k�}�����3d<]_���OlK�3������''@k�t����Uf�<.eW~�������;��������>+�+Sq|������1L����l{q+������f�=>���[��/��
d�=��������/q
\5����w�r������l�v��vS�6���X
�F}�x�x��_A����CJ�>=]&�%��H�\���s\��\���� ���q��>7�c(R���v\� <��=�
jJ�]���#�!o�\m�L�C^�!�F�-�{3'�hs�v��=�����������Q	��t�u��u��|���na�4��%���C�����������>��S�poW���7!O�8��6�zGu�>�Az��~7�8�@7���?�>��}��y]���#.x����{�����$]�����|p������{����q�S���i�I7��cfX��=#S(p�i�)Ow_��MB�#J�R�Mk����:��^h���(��9���y�TP�����P�e��^F�t���n�<������&�GiB�����{C*W>Y;����9����
:zm����to���"}p�	�s������{;<�M��|{w,&.��	��g�n���	���r����F��7�ONt���s/�8^�P������L�Ws�R�M��/gV����_l��/�
K���N�������U�s9�6l�_�"/ ��<o��&����J��.�u8�W	���oO�R�����GP�t�g�yp��y[��v���|��X����Y]���S�����?���9Nw#��~����t�N��Q��=�xF��q��5����{4N���)���x����N�(u��|���{:<�������t�(9�7kCj��=/oep��1��������R�A���q�����S��G��{t��V�����e�}�pKh}��
���U����n����Dw��2�A<�����!a.�R������x��6}�=�&���^�|�`T�I��6Bc�NkA�n��3'����H2q�Fs?�h-���)��&����z�
�d�e{�
{��@>J%�4�.���uP��-��X�.��0����4�mWM*8���������jT�nG.�i� '����P����s��S���Y�|���Zos��raOw������~�t�<����n2�n�8����nOw��t�,�>���O4N��8<�����#h���m;re#�}:�@��aw��uG�*�����{�W����T���1���%^��ix�+[��t�^���C���Vy7U�fY��%�];�n~�e�E��F�
�F��e��{�8"f��>6�p[��{�&�X����X���A�d����2�������x�L��3[
��w�J|����T��^��r:c��s��Gh1:d���n-��`�A5�8��pFI��@��D���Y�|������������y���h%p���;��n�����=I���:19�o�NU
O�d�������]]�����w�0}iL��d�Pw�b�OYEr���~J��e(��s�������;�
����r�j�����BD��(�#����V2�7l��^����7�O#z1�7T-�a������/��d�2�3��^>�>>�~��-7S�^<B�=���}����/��F9C�U��1�#j5�PV�>��v������+��Ul%�%�`��o?��K>��-��1%��-��2��
��{�#��R�������I����5��@g������7=�u�
-����&���y����(������>�@R�$�{l}Al�z��rI����?9�G��z5��}��������z��G��?�-�7���M����7�O�
�
4����Y^��M�/(�c����j���&KoU���#�,���(���u�������jv�8�P�Ax7_���7��It+�M���b��f^4�An�q��2�8�s{t��G�;$a9��^�u��$��q�-��^|/�"���j���������p�����z�����G�;$c9������7+��q��w������>~��v&coV�<��Q����H������T��Tq��T
G��`>���6�r�!���������G>�)�J(���J�/�ztR>yJ��3�����hWBH�r�+�*~�>�eW��{�*���p������_��������F��e�'O\����3;�_��9�G<$q9�-���O����Ct��T/������hUG����q�uy$����U��=�������c2�����x�I������G/��c�����n?������6���:�|�{������H��F.�~�r�F�~7x���:��P�K��h1����+Z�B��5�_*����/�U#����p�/�}����c��	��z�/�Q���c�WI
���S��6���������Z��k	�|���%��+���?���)
�D�����\��'[�
l�1=�c����_�B�-Hned��p.�{�����}�{��CP������|��=��9�=��c�
b����{�"���C���U��=��8��{�x~���U��������~�8����A��t��?���K4(k3��}��6��W<M��/1����>+a?�.���n����>�:�������@�!_�������������\~<�<��E����Z�rp���Z���3�8%�Yu��Uw�E��Ct(z
\]��2��%������C�������/r�3������H~�1{���O8�a:�����p����:�<_����UW����S�9�����#:8��U�WSw�@���%���s�]�	������y�n,�Hu�o���:9��!���0{G��4�n�����?�����H}���E#vqD����/"����j���������Bl�i����F���|�y��wR
cR��w{���P�&o�!!W���
O�Iol;���4[��5����f�|��*���X��Bl:���v��'���m�g0~��L��-.����_�������K��7s���4�:\�xb��m��D��f��yd�
?l��{k����N�����._�<�&K���tF�Y�>;���T���zf�>w�qS���dK�r���m��mR��>�����zb[x���[����m�BC�W���|,���J=��8U/Z����[��m�8n��ao��O��h���U����`[�K_4��-h��^�b��M:}���/����
��=�z���2�(�0��j���z�D'/�Y�\�(����Cm?�\}�� �U���a�������=��;)D|�B��3���ks���8��hY0�&B|a��.�XG|mN�M���8��8�CW��u��e����>��46I�����b���#�>��xI������b�"����\��������5�S��=��b;��#�1���Q�n���M���<�{��g������������Eo��V���r�~F������
��F�O�++Z�cG�W�~'pE
C��|T_�)@��Z��k0�	���+ZW�#��Wuo,����_��E���K!e�Xd$)[@+���{�s�����(����F��'@�a���������>:����3
p#F�)�hY�"�
&<:��7bi>����{2�������QB�	p��Q�t�F�_�H�
ZW�Q"_�����uj_p*xA����
w�&���o��#�+@\�Sq�LW����;�������m�W���D#~��T����u�^���Q�S8�%:�U�����;�h-3��"�w��+����R��������+b�R�-��3�#ok�eW_�KYS���t�1 YJ��Z���IP+^J�Z��`��d�b�c���L�V��+��!���Z�`�����n��:�OWc����z~�����V\Zq�1(YZqmYq����7�������Q�������e�$����C+�3I�����$���^Z�Z�ad\g�I��!F=26�x�� 6u_����t�ca����$���tw�o�3&����J��5�<�����C�V�3&�Z���R�$]��}%��������	h�X�8"iC������7%*���A�Z�c���,���1gO0�b��|t����
Z�G�5$	��>�u��2���&H1Y.�c�K�!Y�U�V��3�BD�/8�`!���C}+�y���v����q�/:���������#�+��v��q����v���=��f����c3��\0��{���q��$H+���8_tr�7JP�������"]M���i#F=��w�F	O*n"��u��br�H+u����Amx�
��6��^Rmx4��y@���D��M8_W�Mx2L�q�L������C3n3�%��K@?/��v\
���W��3%�j���?V�c:��0cHR�p�tt���TQ���t�1"�xWh�%���Z�� ��^����TsM	��>�7X���������T3�x����O�����V<[q����>F���8�0���/+~�|�s������o�?��G����7����o��M��_�e�>�-�����kS&m�����n��>�����/
y���}�������1�k�8�
�f�h�g��Y�~m��(������>L_z]���A�i��F��"\�Q�c�E {
��u��v�!����|#B�2]�S8����W6@F.4�YT�E�+����r�1�k�b�3�!�4����3�t�JC^-C���!
y=6��1]�U�e����������wf��m!F}7K�8C��%��1�v�Yf�N3�K�&�<f�� �x?����IW���a��v�(aW �*x]fM�����th�$XV��aj���t����V$���(vvN����(A��]A+L��th���u%�1.��^w�H0�7�'A��]����t�	�u>CK�l��J0cT�5-%�7��I�l9�}���k�
��"�����I�}���k�����J]`	����,�>cP�u%�c-��-�t$�C�s%=BO�I0\s����t�s�$=R�Z�`���
J�0C���I���
Z���L��Dj�sV�}r�$cE	����a%����u%�3&A����l���%Y��J0gL2���9u��D�W�����5%h�-�M�������|�r�$�n	hM�i��T�[�1uk�����-F_b�v��oi�D%�����E'`���$����c+��������IX���s�$������I6Z�vl�9c��Y�����1�N_�x,��3&��6�R'�Izc�+��1I_ �;�[	��x_K�����L}�I0���:�b����c����d�+hM��c�����x,��1&�+d�{�"{+�p1��Q���3�$}�R���D�LP	�+p]	f�I�Y��������d-V�����
���S���`���g-V�����-ju�S����p�����MLt����Z��1&����ku�z����;^��a��,2�$}�Z����`j���-����"gP��X'�5&���{^��a��,rF%CI�8���:���a[NY�K�`��T�����<(��3.i��e��}���<*��30�*��2��%�~B�]��0gd���Za�\?��v�i������*�3R���R�X
_�~/���{������diV0�06 �^�NQ���9�i���|k��~�;5Y�)g ��Y`��=�J�)�
K9�Y��/�\*@���J�lN��6Zd�&.}��#������N6ZdS/����	/�<�"+��'��_��R��O^��)����Z?�8K=�?v8��-OeK�sf0�cS������%p]	f�E��&F�9p���+����`�`d�Vb4�oW^�I���%p]	f�F��Wum��|��te����u%�1Zqm�>�I�J��7�V�1�$G@kL�=�#g8��SfH���9���+r��9e��d�J�X����T�}��pVE�3$�����WI���gU�9c��(�I0uL���,p��t��dh��X"�30%����!�������Z"�:&i���B��1�.��V$���I�wA����pI���_��`�
�������*gL�%9��$���T����7�T9c��w���{+��5�a�G=z�U��d�]=u���5,�{,�)�*gL���^�u��J2������������W#.nS�IV����u�3&�xW�F��M�l�nm���:gL������V�:&����s�u���=�Z�`��dg����	f�I��w�n����gp,@���3�$c��������kK�����%�j�I0�73��|\W�c����� }�c��oK������B�q+��A���3�$c���6�[}b�z��!p]	f�I��wum�B$?�
z��+��1����n����l��$p]u��dlyW�FG��8G=r���u%�1&�a<:3�o%���f��x�b���I:��V������1'@�������{cN@�3�cN��u%�3&��g�.0�ct�=�s�$�����1&�n�f2	\W�9c��V<���p�����q���V�3&����W�(V<�-�����1���x2��.���x�[<��9c���l��]b��8�����i��IZ�lx�9�*�Z�rh�m��d�/�~�����J#^�����4��0b�$���� �x=6��!����j��[0���im���6gD��b������ ;�����6g@�����Z�A,A^���w��������}�����|w:^��fH&6O����ds�t�\�fH&|���buP+��|w:^��fH��&F�~N�^i���G��C>2$S���3�I�a%X���!����L5Z!��O?N� o������LMC	��]�%�~lxK7�
M]��dj����8��%�6���X�.cH2q���V�`�5��D����z`c���X�H0���v:9�����Q��,����q3I���G�nr&=_�#�y
h�-N-�����]��d@vP@+V�Q�k�,�
\W�9c�����`��%a!V��s�r�$#���S����G�.�Y���s�$�GN9���:_��&p�+��A�\��Ch�~�-Vb�+��A��n�������R�����|�M��J��bt�|�=%H+^��8gP�����}���b�b�+��A	�w'� �S�,�NN�����(��i`�"{#A�1�%Hgk;���s%;��NI�\j!�5�1���`��dg-��|s=�oAw��/��x�v��d.0dA@+G0����}���`��d.kb�g,t�G�l���3$s�J��4����=�UE������\��+����Vz+�pul�����)@�����'����Ay��3�#3���3��V��=���pC#v��"�����j���$��!,A�Y�S�	fGfVc��T�X���5����:�H0c82�+��3��){v���:�H0c<2w���w9�o���33��G��4��z���{���!gf�������� ,�h����9#��
�I0\���`6
\W�9C��V<���+�V��gp���V�3&�|��S���,p]	��I&Z�3��V���Ay��s�$sK	ZV����k��D�s�$3�x��u#���A�3����c+��,��
hE������y����W��1�J+^t�j���{WZ�zh�e�3(�@p�Z`��nt�6R�"��l���>��S����v��qY�K��"495�h��n��D����,h�:~��K�K��=a��d)�4�7��5z����@�C��?JPk2L��,%����@����*	�V��� �+\���@�����	��9��� �k�]����}�����<%�2�k����[Ry�U������s�y6a�����p�%a� �����5������*��[��,��uG�e`���i���cJzX����;�"�;����Y{�+�!��u��r
��tg����I`"@�.8����8K�o������s-N��r
��tod�<6����d��uS����`>`r����W��si���c�x1���p~�c�x9��9�����Q3~��	+�	���/g2���t�G�(nwK��������'���:�������"!uW��������/��?����/�����yr�����������?�,�/���?���?�����{������?������o�F�$wn�|u�+m���N%��<�����=����=q����|�{�2Fm+h�b?�����L*f��V�+���zM�X98~u\�<d �����"���'��6�*�Ny�)A4:h�l����ZR��Se��q���KR@?�s��e]yG���(�����U��>��g�n�3�a���u%�1v[�h\@k�(3�W._��W��u���Z��������V����mEC	�}�>�#A��[���u%����;1Z�7�_��,����3F$[����$�8$	,Ada�+��!�V5�hu�=�c�� �\W�c����7gf��������xv|�1&�j������/I
_K����l
����fO��4�I!p]JL��dkxW7���/I��I����l�Y ���$^1������i"��1���Z��G�CX	v�bgZ�H0gL��-�+���J��[���u�����6�-��ND�9c���
���jV�}��0.�s�$\�-��K��-19K�E�9c��"�Y�G+��vNO���Eu��d��:�(y�p�h����J&��&���Kp��5����A	�hM����~O����W ��,���x�=V@���B+^����,|���=��������r�79�����j<��[~gp�[���M��dk)A�-g�^�m�-�����A����Yq�����[z?l�ir%;�QZ;�����������~�4�1(�9�@@k���|I�U�3�@$�1&�9�@@��G����wgN�H0cL�sX����b�� �xw�{9cL�sT���$�8&	+�
����(	f�Iv*��S�~����x�`��d���y������^#��;�	D�c����z�kY�k_��`C+n��8cL��|���J���[����[�f�I��oqk������=~�3�$;w�h�L,@���W��9#��/��j<q������`����C�L����N��d�h{A�
0g<2����7L�R�sB��u���GF��3��F��_a�(��sF##M�Up#�p)?��A�
0g02���Y�����`�X����3��F���i��j�;-�"���;wwg���$�p�O��vZvE�9#��&����`������c���|��������Wx=~�sF"+_�U������Wx=~��D"m}��7���%b��4���n��_
�.9Rf?�w����{.���#�����\���W��P�|���������?��/XVh�a���E#u����72y�	+�u�v���>_4r����[7�1����`�h��qFg����#��B��aS�/������w1%��|�C�����>_4r��{z�W�{$�>�U�z?���G.�yW���WnhA�
0_8RWeC�:m:�3\����+�|���������������-x]fF�
�����l=Nk��+\�����1�����]���'5}AoZ����T5��6���#$*��V\Z��1�>��a�����[���C���jJ�x�=�����-o����i��T�N�FS�6�_Wo���q��T����pj��o7��w4����sF$=��3���KV�=m�a��sF$X7r��p�S]
�����9C�y���K�����7�9#����6���`/�xG���1gD2��G�
�KK���V</
��L$8YV�:53����7���HfZ�3��6��8�9;���V�pyD�9#�����_���;�]����1��HZ�3��\C{h���c3���4���`����v�G;^��8gP���W�5�i�+����r��d�!��2����?Z�)�C��������D����S��fn5$�bW�C��7vcL�i��}P���8W���.�ya7��T3���<���!��q��o]F��nz��v��C/�`��sU{�r��v�i��"�;�;
yS9ct���s	jE�/r�S�#�%pD�1<i�n%����]�pD�1<ix^�����������fO���:<�6�G�X�0d�{ ���I[5��G�3����������}��))Va���n����R$�G�:��WV�5|�����0���������#�s>MX6�����q������1�9Hnt)@�����C>���`����M�c�V���1n�s�LXv4�V���O��	�h���	��e�u�������'��G�3@2
��	��?n����i����������R~�3�vS�]����T�K� -x��M]��8u;������9����V�����t��g��9��&l���h�{'��tl�9�%c]�~'p��5�����L����G^0�i���
��D��l?<�!�Jp�/�F�3Y�/�#�\��t)s�"+]ik�Kz	��>^�R�FX+n��.;q�R�Z��[�V�3!��5J�+����V��z�
k%�J��V$�����R�W���I��.W��=
�A���J�+\W�#��s��F}�Kz	���	\W�C��\ ����	������C	f�I����3No;"�K[��J0cL�����<�	$R�I����V�1&���u+N�=�+��1I��-�o#A����[�1&�Z����7�c�+]�p]	f�I��Vl�t���v�������1I���;��=B�� ��;��:gL���;���{�=��?��:gL���{���Kp���V�3&�Q��I<%H�z8����1�XR�/y�!7>_����D�
0gH2.����F�i>���x��+����Q���&��'pb�c��X`��d�(@�>NI�����g�y�&�r
3&�2g!��(��T����:g4�`P�����������.i:g0��]����\��A������79��b;c�S�{
��"<!��G6P*����
�#��a�xdo(B�3;�)�Qn��s$;������g�/
����dHzVc��
A��}�[��a����,[b��o}j�K����`�����:��S����+p]	fI��F����H0u'g�F]��J0cP���;��78[����D�NV:3F%=��Z�`��
~g����S�	fJ�	��i��#A�3�������6cL����FZ6&�b6�
\W�C�����i��)Av��N�:J-��;=�7�(2� �b�+���+��%8$��{z�NV$�3&a1V@+L�Q�b�+����A��!�G=���c+���|�����$#����-��L��Q����D+������I&z��a��=���t�Qw9c��V<���z�Q?���C+�r�$�/��q�:�9��?����I8��7����������O��r�$���[S���X9��?����JV^��T��AIPp���$h]��I6������\��ZW�B���?�����j������o������������?�������������|�_��_?���?��������~��/������M�S*W���T��� �iXQ��������?l��t��/�~a�7�`����'.c7l51���=V��?�
4#A�
0c7�Z�O�}�� ������g��rP�"A��W�~gp�;��`�n$	E@?�������C?	f���b#FrB����`	+��3Fpc	+���A/+KX��u%�1���4��#�+��V\[q�n$E@+����� ���������H�h��O��5oi�r%Nd�`�R��`��o���a�+��!��"�*����~l�\W�c��EMD@��[����aMd��� ���-&�d<0��Iz4���0��/I����u%�3&��i*��E�CA	��r�$ZM�"A�����ZG���+��1�XQ��p#A�[X	�� p]	��IFt�
����,L%%�>�+y'�9@@+���������yC��d����\��V<[q��d^�Q���`~\�k��C=��1���x��z��'��$����-s�$+�x�������%Yi����9c��V��V���9�7����C+s�$��M�b�!y�%��x;|���1�^Q��[\�$��"�yM���y��A	K�Z�=���"�
���j��0cT2��h�z\��E�D��uE�1,�8`r������!WA%����P�1cX2q(�d���vV�
03�%'�O�P���G�;%x��3�%S�Q�z���{���J�N5���`Yd�K�~������Na�y�S�L��=a��dj��
jM��G^N��.pD�12�Z8��3��V���^N�.pD�14���"������"��`�"��L���:��r4S_R��������H1jE��c�&�yS��)����4d�6{;~��tt
�����@�9������j��h�O��.po�������*�SR��JqD���k�=�������uN�9�&���dV8��]?�6+p��jSb'�@{#�2\x�'@�j�������������6�z+��Y�����Q�KC	���2�F?rX��u��r
����~{=j�a� ��ON����3J�{�'gb��LsV�t�7�\�5�7�����nA�j�n�5�w���q�Y}A�����$���w�o�8u�����+�������3������g�j��g�#����gcqvY>~����������e��d����X������8{>^�]f�I�
���X������+d��+��1�\��h$�;&�Y���3F%sM3v��7��`�S������c#���
��Z!��wrR��u�1&�[��3�=�;�w[�p{l�c���	��	�|G��`G#n�����_��x�S�?�;����K\�IX���S��=��)�^I�9%�2��V$���>���C^�3"P���:�~gp�-=����XQ�z����������xH��rF$#
9Z�`���O�SE	������J��V$��%�����s�$sM	�{w����l
��J0gL2��#��K��\jJ�p�^�3&YPo���Guo����^��IX���_?	ry�|�<����1Sm=Vm��7�Z�!i���l��Mg�T+
|%�w7Z�vl�b��+><��3O`a�i����0���C����
��4�]��~S���V����^tw����?��OCj������4�����-R1��&�ri���\��uE�1�[��/�������)��R]��{a�0na���D��v{
w�T��^D�1�[�nT7����K�+Y(��a�@n-b4�8"�O�%Y��"���%^l���#,B������G	�����o>�/cU��"������%����7(�])f�6�7�7����C�������7�d���%F�7R�^gp�8��J0c�i���;3]n$��Z=�;����U-�����wg���=<��g����M}�
�Q�UG	V��X�=�����`��d�i��N��%V�5��>�����^��k��}F�� ��>�������.Z��G`V�
�bg��H0c`�s���>��������6��
m�
��
��a�c�x�;l��6��������w;�pwh�m����C�&�x�������6g<���{��X{��4����s�#��^7a�qX���C_�����m	hE��=��C����x��js##R�Z�cG0�	�xA��	�6g,2��$�&���O�3	ZW�9Cn���S;�3���b�6g$2�*��1[l�2�#������.c�d_���
��~l������r������|ISN����&�����~Aw�_����\ ��h����ta%8��sS_��%8w�83�q+��A]`	N��|�Rw�b��\
b4�Nz,�	+���~������\ ������+��Jp�~������4���z�v�>vi|%��U_�M��z�����%M����q`7N��"��d�Qh�[p4������%H|��i`77����|����8_Xr��A��0��'p�����|��*jb4���O`U�GLW��3�#Uq��s��y��=�UYQ��
8}�p�*G��p<����y.XV�<���3F#UU�5��q4V���V�]t}�h��h���E7<v}��l��6\�p�`��A��n�C�g��������3�"UC�u�=�~'��	7�&�1��
l~\b
{��<�f�3�"UKn�n��'��	��&�1���4L8�	��;�?�E:�p�����`O�Mx���4��0��~`O�Mx��|�{����r~�
����3�H�+�A5
+����p�H"�������yO����Y
��g)tw����(��Z�6J���+������g��y�F)��?��,��G��B�r�\���=�
Zk~M���^����]�Ib����^a8�"h]f�j�N��_�Er��
���C9��TE8��Gc_��,����.�h���g���f<�2��"�i���!�C�z�!��!���!�4��x�}� �^h��a��c�'��rh�c�0�c|0��!�w"x]f��u&F�#�$Nf������3����f��^u���X�4bg���� �w���n��c�oX�|���_�N���[��o�����	�z�K|<Jf��4d���(��$�L���u�1&i�>i��_7�N�`�C��D�1"i�>��l�S�����E���!�DP�	7������\E�1 i�?��WE��f�0O�%.s�p%H���*�!7%\���E���i�jM��8Z�"�k���e�1$iZ^���'fx4-����@�c����zl����h��b�����w�����V�)V�3*�i��a��$�g�=���������*�SB9������.��'�����9�&���E�ob��j��"��G*�`V*�����S/�;�� 
��t�����<Z�9W&�'Z��[��
��'p�	O�&|��	+��&<&�1�<�g��|h�����	��	{L�k�M�x����jX.4ac�������	/�&|.�V�kM&��:
k�+C�����<�^
,A&�W���gNw�#�1TZ�3�9#�
�_},��qf0��xGo��`����N+��U�>���Jp���V�3�i��n�>���Zq[���c+����X@+L���X�����eM	V�:iK�Z��`���-7b�{o��X�a�xI��"���������"`L�)B�qul������Q��������s,x]fKZ�+���%~�I���uFHz:c\�64���}����!7��\eL��rc�G�]`Cn�"��/r�12i[����"��C�������U�������0`l�)B�3�@D�36����0`p�'��/�3�@D�38����0`t���|���"����@C,"f���S�4����sF'#_��2�����y<~�sF'#_��z��G'_���E��L4��z�SWM���<r�3:��"O�!�N�D8�E�_�:gt2�E����Q�9Y�"��/r�3:Yh���"{0�C����r��d����\%�NV�����\��NV����"W����/�z�"�9����&�������r�3:a
�5j�e��v�"r{\D�sF',"�F��RG']�����\g�N.��=F��0ut�q���uE�1:���y_��0ut���������t�F���2$9��/�*\���a����h��>���R����^W�����!;S�#����4����3F']�C��e��]��#��+���I�������"L���rsl����m(B��S'�;����3F']�a9�3��F�s��E������{���0ct�u�x�9��oD�1�:�)�xUwvu�2�Q�}K�����|(��#����+���	gAhE~����c����3�:d(�1�L@+|��=����p�Y�3,i��1���?��4������A�������aO��B���L�6gH2��?A?=7 �	�h���	�H�y\@G��	����x�x�3����Z<����w�;�;��F�w�3��� M�x�x�3����Z;��N�+@�X�[�����m�@�[�;k���d[_	z����v�;^;��E�v����{��
+A�����9c�������|BX+����x�x�1���4����a/	��,��J0c4���!��/����,)A��g�(��
�|�)�1�P���������H�Zq�)H���{��S������#A���(�C�L�1"�k���P?Nk
!�
}�K�>�d�1"����� y�t��;��,h]f�H��6����c{9�Y�����-��3��TL�r���ug�e�G��&��"@������`�p���wf?��qD�����Cz�3�i���B�S�@�{��s#\>�;c�o�8��r�s�|���p�xo,�����	����x�x�3������7|L3
{G�X#IP"����D�jE��	��gA�
0g$2�{�;s�Oqd��@��
ZW�9#��&����Z���iW����,
���G^?�	d���u8��D����{#�p&�w9�Y�����������>�I�=�l���sF"M����"@��f]A�
0g$����;�7L���cm�m#C�Hd�	�z��GY)�	�i���	g�D����&����hn�Swf�D�� F���Q�z�A�
0c$2���hE��R�~'�*(�C��!���C�?`�	h���?�����.��^�\�����O?���?��g�]��/��������?����?������u�Fy��#���_C���)����?���^�������'���@�&���������l�����������l�������"�d��x��?f�Fv��F��8�-A�3���������l�����q+�d��x��?f�F���F���1
|��?������m����R�~g�]��q���1���?]�p�3���������-��h�������V�[q�n���"�������V�.�`�j����;z\�Vt>�=��?���!I��4�tH������e�3(h��>�#���@3��,rF%cKv���;�#������s�%#
y���%��q�&�'��r��d�!O�!=O��'��s&3d��r#��.
�'�@�9#��~�CB�a@��O������.�����{��!�����5.�����,r�&+
y���1���'����������}��))�a��Gy5�Y����D����snMX	n�e��V���Z�%��z;��w��	+�����x6�w:]��d�|���[0k�[{Ip*0�arv{K-"���"�5	t��$X�� ;[$��(A.���z��D�����tF	�:+�5	t��$X�qr
����� W��H���=���<�`:�m
+�~�`�$��h2q���=�L2��i(B����7tL������`��dj��N�n�>6���RoA�
0cH2��X'g����p`"K(h]f�H����$a�q�~"��=��s�$=�Za�q�^Y��uY���0gL�O��O��<>�=�=o��0�P��I���3�����g�eY��J0gL2����l�3�'��V<[q��d���?������V<[q��d��i��O���
\7E�3$���49��[	>&U������|��T��I���f��!�����q��2��uE�3*Y:�P��]�Nu������^{��q�J;^������O�+
y=6��q�JC^
C<�����z��uE�3.�h�NQ6�!���Y���0g`�c���TeoO����������uE�32�gb��u+B���AE8����*ch2sF��VXHv��� �x>PeMf	��!>I������xJ@�14�����x��K���u%�14�������8�e��x�^W�C���W�>�S�+B�SX���c;���5��6�j����EHC��
9ch274��2d�m�a
��!7���14�[rc��SV�-
�=6���������=���5�����:ch2w��;�����w��)�&o���0gh����d����r���uE�36�i��F�[&���[�������������a���S�����%uM��d,)B}I]��W#�!�����-uM��d\�Q�RWU�+��O!Wz^W�9��	k�fg��������yUO�`&"���E���V����"�yU��=&M��dF���VD2S�w.����&�&gt��	A@+"���.������M��d�(B}�d�18�)\yU��'����JC^�����h���p�!����3:��.&�5&w�7��	^�e1gt����t�c�T`C�yU���bm��d_���Y�1)�)\���O����@ZX@k"L�.�M�+�����:��VD������&�S�f�N�s��"�=�B�2��!��S_*��D����B2I@k�0u��T;ExX�k3'K�Q�z�����a����uE!8��_��k>~����`����N�y���<�>�"���7�Z�zp�+���T!�Z!\�����]��k���B@'_����Z������TA%XW����1�[9�]@+��E|%���5���.�2�skS����c�s�6��A4'p]	f��V�u�����������t���������ct`	���c+��������q8��;Zqwl�C���w�{TI�J��w�V�1�[9�]@k|�� }-g���I�(A�u�
	���t��:��v��3������Zz�.�u�)��9>]��dDjU@�@K,B�V�+��a��R��$ZzXC��Z��T��q�����~��V��.x]�L8=`u������U\9=`=����L��������S4����9���pz���D0��w
9=`=����M8=`��x��|
9=`=���N8=`��x,�,BNX���9�NX��>2�������	������aO�V��w��g�N�.����)O��%x]f�N����������D�P�:"2F'[�l��~��dc�V��"��l���S����x��B���0ct�q���Th�>',�n�;����������s��<�]aE�������!ct��C3�n�>��E�|��4��3F';��&B�dWX��nNs��0ct��C_@k"����n�����/"��l�:�]��m�N����	;��&������U�4�_��e!;��&����������S�1Z��<�c�V��"���4d�P{���9a�V��"���Cs
��X]�O!k����/"���Cs
�'����B�h7�9_D�3:a���jOv��=���nNs��0gt���)��<'e��c�S�	����/"��,L;c�o�W���lkI2#,"���L�NG��Ssj�3�+���������`(���?�zC���uE�3:�Vb�[v|&��A�x�M��`(�����
��W�B��������^Yd�N�����<�e�aE��c�{ ��������Z��U��wn���7o�E��d���������3�a���������\����kn\Xr��~�{�,2F';�o���m�9�]�����������,����m�9�)d�~�E[������h����+��7�S������U������"j�\�b@��O�-/k�J+Y��d�V0+L����������:�`V��m�,��s��4�;%ZQmN	��H���S'��uw��9����`O#�uBM�M{O�m��;V~l���	���w��v?n�=��� m����|zv�I����o������?��/G�:9���3�.���8�����\<�����oy��we��E��m��U��U�w�?������������O������/��?���?�!N/UW}���%���rZi��]u�v"P?u����T�����[�Tl�pU�w��r_U>��f������]��{p1���|&%�7���y���n���������o��O� �����'���I� 3�_����ge���76����3����:��������������u �jvC-O�>�dG��Ns��J�J�;���S.`C1Y�>}���>�a����E�mQ�iB KO�LE�l[ �~{�>������L�wPI�H_!KO�rE��/�f`32��}G��=E�
��p)�f1��
�Xzj�<��6-��SH=��8�E���Sa\$��3Lj\��;���<qT�5�v�u�O�=
�c���L�B�H�"��z����qT�ox+����P�"�v����S���Zd^�hO_)qt�l��A�0�r'���i)��1��<�7��{�R��\,���u�#�����Dg�����������A�Z�����r������j�|���q�-w+���x]+q����6���2Rm�3����<���O����q��Q�Noe?��+�%�����>K�����\����+���J��%�A�*7_^��&B4|�`�)?�-AM��=}��Qn]�131_j�l�fE~�rS��N���k%�rx+�C������v%Dc�d��T��X hO_+q���[��r�����'Dc�t����r{D����G�CAp��2_��i���>q�����+���J���V��6T�2T�4�5�!��N(���J���V���A�/CU.(fmBb�.�6c�E�U���_�U�U��8����Z�m��<������l�}nU�U��h�Ol�;����'�PUO��+}��M�U��C0+�K�����{E{�Z���r%��8���������S�*�x��=}��Qn�8�r��^q�S.��^1+�K��������4q��j�;�s�|��I ����g��qn�$����8��&�;�s�e�*&���)4���U��Iy]+q�;�[�YO�����qn�������d�#�\A{�Z������x���2T�@�����H��mTN��Z������|���2T�@���L�H���h�Iy]+q���[Y	ru�U���W�g�E�����3}��Z�������8��F�*������e����.qXC�g����}�7�n��#B�mI���K����%�n���7���.��-���"��,�[��hO_*qt[�w8��Tr9�n��&�����t'77j�E��T�����"h_��
���8����Hv�!7*hO_*qt�-w8��Tj9�n��uwE�(I��
A{�R������}�37�nG����
�9�������=}����DOe<,�J,����~z���/qz��f�zC�q����LOe>��?�W��e&B�]i����a�����K%�nW:��!9�\onX�n��U/4��S��8c��o�V������vX48��V��F����$�O5�c�[��k%�r�'O����T�
�?�Y�_��T�U�W����8����+�{s�*����YBp#�����FE�q�?^�J���q����a����h���SM� W���V�(�E�+h_��
�\&��2q/qv���6N��Z���� ��&�|��� ��(71�@�k����G�����w�77�r��u��M��jF������G����8����j����'��������V�(w�+?���2T
�@�Y�_b�T�2�p�@^�J���V��&�|�f����?�l�66�	��V�(w���7���P���y���/q��-m��JO�k%�r�b&����zs�*�(���%�A�V�6Zc	�q��QnoE����V�uG�����=�Q~�W��8�Z���z'�Cf������mB4|����E�!hO_+q���wX88��V����]�����!�����8�����{s�*w9N0+�ML�jD����G�����w�77�r��u��K��j'D����G�]���pp�77�rg���`*�kyf�1�fg�����|�U�/C����	fE~�9T��hc5V�%�P�+����w�77�r��u��K��j7F�^80��8����o���s��A��9I�]/t����#':'	�u�DQnW��	�{s�*�*Q�s�����q���J�V#��,�����*�� ���0q����vN"��j����&��X7�n������u-8r����Y���E�+h_��
��n%B=��������=}���mE����V��	dE��ST��@�s�@^�J�����r�au�$�@Vt,C�y'O �uN��R������tH�;�Z��y&B�]�S�����llVM���z*�a�{*�V�L	dE|��S��X�Iy]*qt���_�q��au��@V������f8 �K%�nwz*�!;�T^9�n�b B�]����a��=}�D�m_�wH�;��V����Y�_b�T_!���o�8�����{s�*�^�pX�e�����
������G�
�xA�bonX��OM0+�K���[
z�C��V�(��	�x�j��T�>5�|,�!1���Z�7:��k%�r{8��������e��`V��89��5z�C��V�(w�	���>_v�g��`V��8;�O��F��q��Q�DW~:������������8=�/�6f�d`\+q���[Y������z��	fE~�;��5���P3��8������]��T�r�`V���?����
���J���V�Cr�������$���,C��P���$���E�C�8W����V�L	fE~��SC�8wp�@�[�w����
����Qqn��� �����8���qA�bonX��3!�rb����b%hO_+q�����������eh0�����SC����$����8���qA�bonX�!����x�0�d%hO_+q�;��VF�����
�\&����`*O��P��$���G��@.h_��
��{�c����oX0�A���V�(w�+�p����a��$�`V���A5��6�$���G����x�j���3�t�eLL���v=7��8��Q��/��U��>5���/q�j,QU�5�Z������"h_��
�\��	fE~�3Tc������f\+q�[Ww�Z5_�jd��`V�,C�w-�
���hO3��8�m���{s�*�Mj�Y�_b��!7:�i��G��A�7�	�`v�	�c��8��#��.5�n���.��}�97�r��u��,��D �{�n����.�x8B�T~9�r��&�5�&&R�B���S���8���!���������@����I5.`	��K�.tZ��!r�2�a���D�{.e��J5n��	��7K�n��
��zt�jwg����o�"1�j�Qt��o�(��
���U��]�A�;�x;�&��������=���n��'p_��
��j!B��P�sUS
�^���Y�h�KS����V�MG�z�'�/����$p��,q����09d�'zu���}k�Y`bB�D��d��YWK�v(#L]��n���e��`VX&�TM=����f�-q�;TDwXH8��V��]��zg�&��&�m-�zG�-e�������h�����hU^T���%�{������^�CZz�g7�z���z'�����I	�=q��Dw��/c51'$�5&�XM�m����[��w�_��]�������������I
��-Q�;
�/^����KD��Y`���\������8�-���/���Uo����/'��	S�{�n���~��}�{7�z��-�%\��zT����%�z��������Z�������Y��C�!p��-q���o�/v��Uo����T��V�����=��Q�@�e8�(���
���#D�y���#B�{�n����~�x��5_�j�vB4��*\���zg����%�zg�-�aI�\oX�.#!�K�8k5/=����-q���oYu<��V��c5��*q�j�zl���[��w����b������
��J��Z
��n���%�z��O����T�K9��V���q��}�V%�����V�B�Y`���WAp��.N^�����^.�/v��Uo��u9'�Z--�����G�-�J��bOoX�v=!�e�8k�0/$p��-q��!�\���]�a�;�hD�u���2`Z��=��Q�0����s}�a�;N�hD�ub������=��Q�TSBOv��AU<�F&#���e�</h�����%��g�.NZ�|koX�.�K�8q��`�
���K��t]VM������6�����Y-�	��7K�r���$������Z�:�i���N{3�b�{�f������"p_��
��r&B�y�s�����=���n*��}��7�v��&�5�%�Z�5�t���f�,q�[oDw��;�q��f'B�oI��Z[4���7K���Y�k��a���:Z�oI��Z;����G�=�	������PN������u@9A���Y�hw��2�j=�o��q!D�qi���	�R��.�;�i������
���Q�dx.Mb��:�F'p��zgz-�qg~�t���h�.M�t��2�X�It�cG�+���p������e��`����g�n�;��6�n����~�v��5_�j+�~����$�Ym�C���[��w+6�;n���������I���*D����G�ht�������B4htM���V������8�mJ�;�����
����`��8g���{���%�z������|I���}�V��8i���{���%�z{�-������:B4��6X��S��z�{�n��^.��/���U����>�&�Ymd2	��wK�N�[���a�;��h8/m���6�}L���[��w��2����Zm+�c1��6q�j[z����[��w�������Zm�c5��6q�j�zl�P�n����~�~8��\ooP��EO����&�Y�:���%�z�~��}��7�z��
��M���+�����%�z��O����V��D�FI�M���Ie����8��J���1=��V�-Jn����lg�vr�����]��<�'z{����}�F{Bnq�Wo����-p�?q�����/���U�0�QR�s�����=�t�Q�X�aI�\ooX�N�����\�}BIA���[��w�_?�����U���1��K���P����%�z�����a��v�h���Y�}�_�Qyr��;���������6���.\��{����
:��|�Q�����}��7�v�����y�.-��+���w�{����������9�v����9m���n�������.`�+�W������n��Q����������6r���G��s~��ZooX��#�e�6kuA�]k�i�]�1�W������nO��F�wi�Vt=��F���Y�hS��p_��
��a%B�o�����b,�n0���G�#}��p���sX�N=~K��huA7�d{�kw�G���������B���������w/�s,�<�����e��������
��u&DcdJ�6cuAG�~5���G�[Ct�#S����U���f�z����.�������w��Q���nqrAO��UoY��hTS�������B\���[���,�+������Jp���5���~A���hB��[WDw�u;_��lh�1��O;���n}i����#�z���
������eN�t���
0q���J�srB~OG�b������a���P����`��U���/-��q������p_��
�^f�Jg����`9+O���{K'+�w���w�_/p_��
��i"D#a?$NZ��m�����^����}��7�z������V���V�����&p��8�]��/���e��u#D#e?�Zy�wc��Q�q���w�k�s��e�����f�VC��tt�v��2_�V�~�Z���
���y��s>����C�[9y!��G�q~��booX�V!I�!q��������8|q�[#_/p_��
���#D#i?�ZyZo�^��?|q��!�W�/���UoW����e�<��5@�YQyb&N����/���Uo?�A��u�]�=R������^�9��}��7�zG���5�|L���F���������~�x<6%_���h���1mw`W�()���/�z1��
������]zX���p\+?�]����_���[������V���Be�:s��
%��.����+�{{��w�}X������t=v����[���.���/��Uo]"4��s��~��=��Qo���'{{��*�v�4:�����u
�^��?�qT\�N'p_��
��f$B�M7&��T����G�mEt�l�SY����PT���������=��h�CQA����V��B�FMaL����#@�[ay��U=�qk
�r�a�;vD�;/��.�vG����G�#}����p*�V�3��u^��V���C��?{q�;�g�����8���2���TE��U��($p���8�]��,��BO%��jwC�M k�K���7��>+�:{q�����g���7��.;��&����M�x�hn��^�6���}��7�z�r$D=�������y���/�z�������e����`���g���x���G��Bt��c��U
B�Y`b�U����8	!��G�-B^��booX���M0kL��t�y���:|q���Dw����
�^���&��	�f@��8)!��G��Ht�A������eNH0+,�e�</�����	��8�������c�RV���W0k�M���=f#�5_���[����\ooX�2+$�5&�Y5+C'+�w���w�_������
�^���&��I�fc�����_����7FO��Uo�7��	0q��-@3m��6��EQo[�o�/���U/;��&��Y��D���m����^����}��7�z���:��n�8k��=Z���:|q�[oDw8��\ooX�6��Z��Ue��U��� p��8����+�{{���	�r^g�����=������p_��
���y����`��U; �����a!����|Y�v�}FI�
����Ph'����G�X}w��booX��=!I�*q���������n���� ���)��V���J���7X����Z�����J���Q/V�]����V��L�U�J��j7��	���/�z���
�������
����[&�Zu�	���/�z;�9������a�[���M���Y���}���/�z9�\����V��D�FdY%��j�����G�
���{{���y!��	0qk�%
:'/�w����]��~����CPw+a�=ZU�8s������G�=|��ZooX�4���_c������������p���:��.3CY�_.o�g��tNf������D�e:�r*�V��L���R'N[u3c��|��G���0�=�s�����qo�8k��=V}#�u��hw���2�8��V��F���R'NZu;#��(Fg/�v9�\����T�}1���������{��E�n_�D�x�|ooX�V����/���B�!p���8������z{�j�nY�_b�U� ����6����n�E����V�mG����8c��:���G��Nt8���
�������:q���u���/�z����	�z{��w�}�F9�N�������G�#�����p��7�z'��"�&q���w���/�z'z����s��a�;��h���	�~a�1!�q���w�[�/v����W��b����~E-A��?|q���oY���KY��p����������f�8�������]���'+��K��g5���NV���EQ�P��	�{{������{�PI�A�wx`�C���������������y�q����o?��������<��������/g�?����?������P�Fy�������i)���+��_����_~���O���7�~�������j	��������.q�o��c�
���*�v��������{�fM���(�)��Y�~��q� �vG�g���&����~w��i7qzo��a���7���j�MN�������z���tjwQ��Y������V��q�/�@���F����`�=����������YX���ip��?�V��B����&����+W����@P��\A�btP��eG����K�yj�D�!p�>�
��n��a��\�sX��!E�6Xf��fkW��c>KX��pY����a����h����d��A�!p�>����n[����|y��C�T0k�M�?9v:����t�����;�[�/W5r��`����}rt��^��&�U�]���`z��9�v��
�W���6�:������q��2o����g��������qf�1��R.KX��t������rU#��fM���h����Y������V�+]�������cP
o�	*�
w��h���c���z�Y�jx���1�8��V��F�F!�K���
���^H���U�T��%h_k{���� ��)71m*������rg�&�6	�����*���'���KLC�j�����F���US��a�{*�V��	dM��IhS�xwr�A7�M�����$h_�y�\�r����.q�j���O�.��&NUMlk���<�U��hw�Z�����i@�+p�&�TMlj��u<�U.SA����%&UM#�����(7q�jbK��}��9�r��}�����y�iF�;9��o��8O5��I����V��F�V���S5�7=�5(Aq��~&A�b�sX�24YMM}bN��1�p�@7�M�����$h_�v����&���O�����k6v��(������u�kv��r!D����S5s.��}�Vp�gg,���a�[�:*�1��KSy��9�Y�*�M���k������O�:��n[���O���[x�W�n�$���w��:_�j�w��i7�����G?;K�o��8Q5�X�%h_lt�]6�	fM��3U��]v���fP��hwX	�xEu�T�<n�h,��s��	��U��8U5O���{w�j�����`�*��y�G�lp��n�\��E]�������e�l-����f.����5�G�+]eOW�\����h������A����6�@q�������S��U-��XO=�U����AW�n�l�R��-N"�������
B4��!q�j��v��h7q6c�F�;�w�����n=���)U��\E���KS�a�{�w7�v�
��vs����I�h71�ji�
�{w�j����w�����������������8K����
�]f����������'t�����e,	�8����Z�
��v���	��I�h7q�j���L���s��a�����Y�nb^�23�p���h7q�jY�����������e6H0k�M��ZVN:��A������p������e6H0k������A����n�\���e�n<��T�+;��������@���k-(�v��"8�O���EPW�CpM��Vk��C�**N��Z���s�o�
���&R[��������U��8a�6�[�k�����v��;/���\���<����	���	�1�������B4J	c����#���v'��~$��R��\s`����(%��V�"��h7q�j�����S�����@���v���	���U��8a�NtY�C���\s`��!��1q�j]y�z)�����B�~9,%��5��J�X�R��x`��2�X�������F�e=,%��5����`V��������c��s7(�vw�,�!u�\oX�nNNh���H���J����Qo���������.���e>h����Uw�oNB�F���Ug�o���'�x��	���`^$NWm\��9�������Y��Do`�2#�Y#������E��9)��&�Fn�^.h_l�
�^��6k�y�8a����mNN�F�������;y��9��b^$�Xm\��9I��&�Gn�_�9���h�
�^&�6k�y�8e�M{7'+t���	������������f�1/��������Qo����	����f���eZh3���E���������Qo�����������n���e^h3���e����3�pC_�X�r���}��7�zw6�m���L���K����f����w/����y���mZSo������W�=v�����Qo
�E����X�
��ZSo����A�!p�&Nk��Bp���Y���mZSo����!����6�$G��zA�bKo`���M@k�M���{����f����w(��?c�jgw�����8k��()�Fc�A����n�xXR8��X�lo��zg��	��nt�<�8����O���V;������Y�}a�a��%W�B�~9n�������&�5���
����o()�Fo�����
�zA�b_o`��#1�I���)�����w�}�4�C�}Q�v���?��T�}Q���W��~��������o���
��oy��p_��
��j#F=����l��@j�
W�o���]tNR������mb4J�UZ���t��z�[(�~1��
7D��=u���i�8�������:��\��8:�x�+�|����	��;Wi'�_��@���SJ�2G��o~��b�oX�"?t���7�X������z���.`������h�
��i'D���������k����/�zg:/3�ZO���U���g���'9�+O����l����U����"id���a(��������?����~��YY���1���S������|c��2{�����c2[�o^��+���
��&���]+@�����7�d���V=9w�",�{���
��.����B�WlWU4�j���|�o:u��P�:����}��7�{�����Vy5Wt�9=5w�d(�{���
��>���� z��n��WsuA�w�������r�}��
��F����Gb4
�Uf���+��zZ��P�6x��W;}���Er.�5�f��\��C�j���[�v!�����+���h��������-\����+���������\��'�7jU^��jW�ofj���-�W�}��wB�!�5�f������������p�.Sx������'b4
U^��
�]���D,,l�����'d1:�����:f ��Q�aX��������Q�[�������:|}�����P�%�oY�D��'�W������uf�U�������UY"���v���/"��7����P�*=��������Z�.X�=�����F�F����4��d������U� �,=n������myB��[�]&xA�H�j���_��.��
=����=��Z�of���[�����3tCi�����s3�3]�q�;����`�:���$C$p5�f�����{�z��7�'��Q�0�:�J�:f ��;���4���v���g�~��w)�����W;��0Y��t~�.����6���/"��7���\�*=�������r��e
U9�����v�����_U�u������U1]P\w��7��B�����'���?W%2��������/��_������UO�F����_U��W�of�d�1�W������o�DeC��������T�j���OV��~��j�o\��1��&�����{t�Q_0�ai��A�W������o��2��WMf��������_LB�����[F���Sb�D����o�/|���83]�������q�;�����U�Y�UaI�����t5WD�����q�K�H0k���`U��Gt���������D�o\��"��{3X�����n�k����wy_yk������������~�F�����k��p5�f�k������=����%(T���7s�`]�|\����Wu9]��{�}���j&D���Fc�v���_���73�QcM�����q�Kz������7���n���=z������������'z���+������Wu�w�����9���&�
������%;T{��n�����{<�k���o����p�������q�Kf������7���Q��=f�L��|�����������xBF#�m�W�x�zf�1Y�ofm]=��+p_����_rCZ�o������p5�f�^��#���q����+�5��]6xA���f�~
�P�n��
�W{���)��oF�����j�,�
W�of���L��[��L�o\����6�d����;�`[������U�����-�������6b4z��������p5�ff��Do�uy�����o3��[�e�����������j���������q������B�.3�`a������U�����0�������gb4�]�����
t�Q]0TCi����������[b4�]f��Q^��3�
G��W{��w.���/t��W�����}�r&��}��7��c2z����v����d1�u�.,�9]������stc4z�e���
8����P������^+y"�z��;���}f��u8!����73�rk��}��7������[�f_�%�[������$���q�[��TF����_����_���73?����������mVb��s�����������j[H;[�z��7�;����>��{[2DW�of����#7�L�o\�PHh����W�����}�#�g�������'d0��}���v��^�j���O��I��j�o\���'�����U;�}��3�W����g{��>^�48�>s�`������3w�+s�5�Q����)�j���)������^C@���]���:�������*��Yq������:O�j���ptn&�`����B�y��7����<���73��Ux�w���'z���n	��-:d�_u��'p5�f�_u�Ft��������mB�	�j�,��Z�������%�$:����������56K��W]��CWsofv���n���%���q�; ���{3�W��	\�����n���[��D�o\��+!��!���nB�!p5�f�6����)�W����sG�Fma�<����<��.��L�����L�o\����3&�Y��5<�`w;�����4�]G���>�����u�Z5d{�m`w�����d��y�������������a����$>�o{����P�����'p_������ F��P��W}�����������5O�������H����.�qW;�o����������h�����q��B['�5�f&���{���73y��3��g���^��B�z�V]df���!���73{���E�W{��w��QWG�Ef������3�W�������3��q�;!���3��T7	\�������{O��L�o\��<!�X�������n��3�='��������}���/��F2D��\�������?����� �?���������O���������~���,��|Y������O��~G���o����OH��/�����rC8�f�������|������C�7�e��(b>U����X�(d������}�M:j�*;��g;5��"�P��'h�
�4��&�N	;�%���L��]�c�y\�6x�	Z�������%!p_m�������E�;���t������'h5�f���
��j�t\�v1���v�7�{z{�T�Vsof�o�!���H�u�0�����<���Q	Z���Y�a��e��!��tVZq��"y��;����{3�|��g�v"�7�1�������wa�1�pCa����-KP~�?:�{W�E��Xm��+S���p
�U�n|��A
�`{tT����Zq�cj$��;�gZ�������'p_����^�	h����QO��pFg�3�Ui�["���6G�u/�!��7k���V�{G��W�K��
y����]Gu1{�������� �����X�qq��W�����l1��w�W;��"������W��nW]�����%5$��F��v�����c�n����{>\��|����l0��w��V;����w4Z�JCZ���:-p_����]C�1yz�B�����zx���w3�V#GN����z���h�����<nd^�yx���w3�V��'�.c��zw	Q��Xg���L<V�)�4DUi�����Fh���������x73e5�9������T��"p_����]���p���<���J��������T��"p_m�����'F���c�y��[!���{]f�j�1�E�����
z&����l���%U�j���VM�Ht�a�������Q���e��-�RA��73]5u5��wm��WM=H�?^v�2��{��Vsof�j��l���6O$��a#F���c�y\��P		�wq��T���
��S�Q���c�y��<�CA�j���GN3�-S�C�`3t\�.�wh���uV����������>[��R�`/t\��< ��z���<np��z�z�v�23���T���
��s�d��;��G=�s��!h5�f�$gW]x����\���{3�Vs�g��}��#������q�[���z��c��^���12W�{������\#8�W�����A9Z@+���Z�
dt�Vsof�yn6���9�{����r���O��C[��U�[ff��9��}��7�{I	h���������n����������c'�V�����V������	Z���i�yD=k��gz{��wZ�QW��X_����		Z���i��������q��t���^vl/���2:A��73�1s+��}��7�{7c7����q�3y!A��7w���h��=����K������cwy����	Z������UD������5i��73k��H=����y�R.DT�����^��	h���gZ-5R���k+��Z����^������lo��{3�VK�r�b4��Uf���:��{���u/������Z��C�w1:��*3k�t����loo��=I�3�;V��u������\���Z������q�;���`m���������w3W��]p��1�9�wg�Qo}���<j���|��z9��2�V���"������]FB�7���X��.��
Z���i�e��.�X����jn�9l���zwC��������Z����[5�Q�Q���<6�����<jd^I	Z���I����[=B������-B�{�v�+�zv��C�j���Y��q.p_�������jL:���<���Q���w����Z#��/����.I!��x73c��x��'t������"������u/I!��7c���G����7���]'_D�7�N�����k�����������N�p�$t�b&��w�����n��d���O�|�?$os�3��q?v��������[��{5V{��5�Q��0�*��O����x7��l]y����1�����-h_�s��]��^���;���=�\��k�s����	.���D�ns��h������!}��w�;q���;���.���-7b�������QC�V!�at;D
q�[��"h_�r����'F���v�l�{zk$�Wq��1�{9{G������-D
�1���������;��������m�h��v9�uo7���u������[A��U��8+��^����v9�u���a��q;���
���&�6�*v9�u�T���n�����w��A�*�},X��^n���v9�u/�yo�6o�c[{�����7c��MC\�.��n�2�)�m��Xt1����=np^��_u5�QC\���������w[�Q�;c�p
�^�*��������������\�h_�r����p#1��gLN�/�V�s���C����}NyE�j�s\�V0��&;c�p��b�
7�n��!�{����M���V}Q/��k�1Y8�{A]�*���Z]���1B�t9�uo������3&�	��|���7/k���sE�j�s\���<�=����
��z{����`���7���Z��0����g��^e��U��������o(�3]�q�^�
Zso�F���<b���y�,|�xC���r���y%F#�5F��9�s�Y�{����\���
e~��9�{���
��l�4�w��n��
���U_l|��,g=����t�+J�4��8c>i��~�����������+����z���5�f&�V�_�*��L\9����}��9�w�����+3�V������Mf��a����]�q����W��w��J����p�f��\�w���?�9��n;��xq�d�4g�]���Mf��u%�;%�Q�q��W����gNsv{��M�n�T�������L�z��3�
�9�ct�^��~vG>Y�`��1�9�w��v��y73e������&3e�&>Y�������O�d����4�ya�at�5�+����et����
nW��{33Vn�R��mMf��m|��A�������-^��rq�T�$��,��
\��������'h_m���^���>fLNrz�D�*��LW�%R^A�jgo\�V19������r^�F�f����$�`�{��7�{���Hz��4��A�+p�fNz�I��}��7�{�����h�Ksz;������Yo���"h_������%F#�5:����G�+p�f�Y��Fp���`oo\����{3���yo��B7����*G>[�p�{"iU���
Zsof����{�mmf����l��y���U���8y������.�=}�K���*>[��L����q���+h���Y�rC�Bi4���Y�r��ew(��ZUX/��73kUa�������U� �������uo	���������Jt(\���Y��	.��p"kUU1
F^�V�Ln]����������'�VU��Q��g4��	�
r���73kU5x��W{{���]���P0���^���U�����:<[*o��3��q����hL�3���^���U�����>[�b����u��������YiU��N��{3�V��g��N8��������/�{g�����ef�����9��p��7�{��Y�8�/Mp^�{,< 7���ZU�-��gz{��w���hP0����

Wqof����l��
{{���f{������3�.���Fg[����]Mp���Y���������5��"�+\���Y����hc��vQ]�&��X1���4';��p�����U��W�/����.6�_1k��L\��&v��x73qU�H}ke����e��`������;��k�����[��Dp�������L�F��d������}��;@*$h_����]6�	f���Y�zD�Bm��e?�#�,c�K����lr��w��V;�����6�����U=C($h_����]6�	f��yW^��G�6�����U����D�`���q��w����C�Bmt���)�z�LH������M��c3:��$g�qP`\�������"h_������%F�C�h�K��
Wqof��)7�w(��V55�Git(
xIbsS#��atCf����h�����uo3���`4��9�
:����)o�V�P8��j:�<����|U�!���{3��M�\�C�`oo\��<�����LX52���7����l�s<����cG�F��������H=����:�f��ev(�����<����
xi�;3�����Cf�������t<����������{�qV{VC^�1�X��<�{W� ����q����&�5�f&�����M��
�I�{��h_������9��'
xI�s�p@�����U��|�������-'b4����4�-!���{3�VmU\�}�D���y>*CFg4�%	�-�!���3����\��z��3��q����hh���4����N�j���[���'p_������'FCEg���9�*ZW�of���j>��j{o\��j�}���Ks~<�[���of���n>��jo\��31J:�	/�������3SW-��	�W|����Pk��sF^��;CK�z���3�-��	�W;|����Pk��sF^���BM�z���3�Z�����������X���>�4�wC�M�j���^u��'p_�������6��������v�:���73}�9����&���-gb44uF'^���U(�	\����������]�q�[��h�`�6�4��F�M�*�\f���A�
�W�|���-�Q_Z��f�4���+p5�f��:���1�|��>�F�4^1FKO�3�A:$p5g�����}��7�{$!�Ysof
�@�
\���)��������q�;.�h�a��V7A:$p5�ff��	���}��7�{g� ���pFG^��;����{3X����Lr��^���]Q��{3�v�7	�wq/��u����f����x>��}���K"��6& �Q�p����`p����c�sT��������������=~�������,�.����q�[!8f���g\����������+������q�KvH0+4��������c�n�Yf����":���i�����i��73w��P	�w�o��C�t���o��������q����3s�����G
=�����@�F����Ks~�~�����d����������P������h�K�������]����~B�W�������L�F��h�Js~�~�����F���+p_������%F��;d������������
?����F��P��#�����$>^�W�ofvc(�v������/�����x������P����2��j(��
�W����	)��7��j���
\������Z�.����_
d�t���/M|n��Ct��23�14x��W[�����Q��K�;/��m�9#p5�f�7��;g������9�����Yw5�(�	\��������^�������D�:�_�yi���D�j��,�F�]��`����q�;!G��3�W���������&���po����0o����+���4�]��
\�����a��S������+3�E��/���4�y{*p5�f����]�w�D�j,� �5�f���������X,D*z��7��	h���{����c�n����9]������UG�:�_�yi�o���������9
]������
�����^�yi�o����U�[g��F�C������o;����Fw^����u/p5�f��F�C������o�hLE/���4��Q���3�W#��W{��w�	1���Fk^��<"���3�W#'����CTO=q9�����O����������������]P���������/LB�3��La��/��'z��w�	Q��FW�����G�j���`�_/[pz�1:�{'v�	f���XS�d������T@!p_����^����(]����
'���735�x�L��������e�`����{p��i�������T�<�<i���q�� ���{���4���&������^M�Lt���c�s\��!����h�Jsz)o��rz;P��'lz��7�{��uuDito�9�T7	�w9�=�-��������b�_/e�����n��3sW��t�tM��������c�{J�;/����I�j���[M3_.��������]P���3�N�W�of�jZ�tY�aOd���'d1�Fw^���1�X
�F����6�]��F�����oZ�of��Lu�lu�5�����D��?���K�!Z�of��\"���3sWs	���}��7���������Ks~�n��3��s��w�tM�����o�����yi�o��W�*�m3��s]��}��7���uuDit��9�T7	\����Ws7_������o?����yi�Ku�����Y{5|�x��gz��w�	�����K�G��W�of�j�v��'�W�����)���4���&���735�|�x��gz����oZ�of�j^���o����u��{N��f��	h����W�f��3��������C�����Q��31�:�;/��]^�W�of~rqP�	�W{���l�����yi�[�u/p5�f���r#����`�o\��<!���f_-5^��]�[C['p_�����f FC\gt��9�
^�W�of~riK�������o��������Z:�����.3?�t3���������'�3�_�;/M|����3�W��������������)���4�wD"p5�f����o�1��`�o\���
h�����ef2�q����2�u?W�����_6�	h�����eab���.3���|�/�=���-��>f��|�Y��l��-F���rs�/[�������#�6c<��������!Y=��D��)��}��7�{���83���8Wsof��Z�D�����[#��{3��	�������Z����	�!�9�{�	f��F�O���"�]=��v�ef~cm��
��z#����H������q/p5�f�_�}At�������_���73{�x�\�����u��ef������GB�/��������l!p5�f&�����1�����3�/����s�����l���3sW�����b�od�.+1�eFw^�����G�j���]�+.k���D�j�zb4���yi�������������O�������C����J�;/����uW�offcs#��u�z#���oZ�o�����t���|�B�e�o�T������5���7u�K���+\����9w�	�{#���	16��Fw^���"�����{��b�od�v1��;/�����
\��Cfnr��[&p_������wHo���yi���{���73{�
(-�{#�w�	������&>O|��Fma�L_mz�������;w�h���[i�����l��
���mAqA������+�Z�of�j[��_�������������c������7��73�m��mF����WCQ����{q���F��P�����������t��-��W0��{������*���-3��R����*CX���V���������[�h��y�Wt��V����6%��{��������_�{+��m;������y�����
����_
E��1���+���]gm��+�������n?����CG������K��a���Ny����v���c����;���F�kt����St����E^���o�)����_
�<�!�3����w^�n6��E^�j(�
_����������b����4�y����z+��W0|�����������Vb4^0F�V�����6ckm�����������q��\G�F}���Jr~����ks�gWD������.��+����3����j��2�������.<��D��<$������������6��y%:�k�|�/���uo�D0+4�����v��Z[���r�JtA��1:�{���'�������8]�j��L`��{�������������;J�?/Mp��\����+7��2w�����wB	D0k��+���c2��;=��n��MO���u�<��x1��������lh�\��h��e	n�9F>�u����x1����^���p5��N�V�[<a���Q�[�?V��bt�%q�%��G'p5�f�n��Ht���c�s\��������C�[z���3k7����}��7�+� Z�of���������^��D�-;��*����7���l��
\������A�+p_����_rCZ�����&>��}K���z���*;�]����q��#����QW;��#���3SWe���}��7�����8Fw^��Lu�������*G�]<]�3��q�;��h�`���4����
\�����r��e
��{��w�	������&>/�@���23{U.�]�������:���`t��9�+z�����U�����{�O����Z�of�UU@9$p5�f��*����}��7��B�����Ir~��l���73Ua������q�[u�h�`����U�D�j���_U�S��j�o\�61����!3U55�5�����_U��w��j�o\��#1�/������-z���;��p_������'���W�y)f_]�!�����d��� p_�����a#F��P�yi������73U�|�����������xBF�;�2�?���	�!���73U����z��7���Z�of��ZP_��3�W�����/������9����2:?���
������������
�������=����W��Wu�P�1D����_�� �������q�[���3����:���73U��n	�W{��������YUWx��Ct����U]�D�]w��7��!Z�of��n�����f%:������i��>nyJ#6���pu�X�j>��a��K��b�o\��!�Ife���9�=J�Wqo��������%�ct\��`Q����VM�H�j���`�#���c�������i!D=�����4�wFX�j��L`�3
�������]:B������w��}���}���d��������W����/���q�q�����?�������?�,����������x��������}����#��.�o41CUS��SM���������~�~���q�����	�coJ����g&��O9�����\^���Bp�Z�1*>�w���E�����!��x�	\��������q����z��D�Y�nf"�i��k�6���m��
����z��D�Y�nf��@�6V�c�6�w���btA�uo?����>�4����O�j=�����hW��6A�u/�cEZe�)�9�#H��l!���q%�=�q��>"��7se3��m���qe\�b5���-�q��6��X�VM�iN��Rc4�P��u��g�T(����^v	h�����7J��?�C���X�vE�jtT��sc=Ze�(&9����
���VT�����}��9�{�������
%9�m�w��U�e��Z�E���?�uo��Ek,G�� ������
���F[��,r��9�{��
u���9�
��WA���h�M�������	���2��4�������Lk��Bp���Y��_��x��A�R"pt�i�v����<����#��`<^���4���
�0����������9'�V���1y�A��{g������Y�v��e7���Z��L���� ����������v����w��~
����Z�[K�F_�A�9�s�MWM�P��u��g�^Y~"k�1��Jrz;J������U��l�<�3]�q�[�h��1���v�2	\���Y������S1=����5JnZsof����I�*���Zu�Lp�1=�����B���� �������U�����Z(���-�q����H���{3�V�LWqof���6���������
b�/�A�9�(S���73k�q��}��9�{������A�9��3	�0�&3k�M|�x:�g����w��O@k���,��a\���Y�n��e���v�*����Y�T9�&@��?]��df���O�5��������#DC�apCi����U�����~z[x��y�����y7����!���w3�V=7�	�{��z��	Qo�f(���+<������U_!��/�:��n�����P���{�����U_o�{�Q�q��&7��y73i��H{{����LZ���&h_�����n$D+���Y�^�W�nf����d��Y�1�9�w��&�5�fZ�����nk2SV����'z{�z���`�D�����yB���mmf����d���������e���������gfFs[�����Y�p���lU�7��73[��L;���63[��|��������-nZsof�������mmf�j(�j��
'�U���O@k������&�u+��;�O$��r#F�3����LN*dWqof:��2�{pU�3�D�j�b4dt)���j����������Y/h_��������1�	+���-�	WqofRch�������uo7�QM0h�4wo��C�*���j=���������Zb4�	/���('�0�.3�1p���}��7�{����B1���N�=������0�Y?�������y$F��`Ci�;3������Lk�-s��p��7�{W����(�P����� p���{W>[�`E�`oo\�nL=V��R�A��;< �>7������=A�jooT��������*����6z���{3�pF�;�����uo�����zV��eVc�w��U����������'�Vc=����P��� ���{3+qFn;�����uo�����Fc�v���z���73k5r���}��7�{����7k����x�\���Y��GIA�������@�FI�������z�F�gf�����!��"k5N�\!���~�Y�q�TH���{'>[��.����q�;�|LF�k�~I�����c���>3)9r���}��7�{�����������+FW�1t�������Y�w����������)���%	�S����U��������Xl{�����b6�	p��������g2������T�i/h_�����
��`������*��W�nf�j�V������q�[o�h���/��mPT��w3�VS����}��7�w���i������H>��������|����������O�������x�GIA���w��O������O����2h�$i�4"���w3s���^������SG��
r�Jsv'4��0�!3g5���?������]0�Q0k��<�}Z��_�
7Cf������/�������|�	����X�<�+&a\����i��#�����������n�/����z������\�������u/� ��7sw�\���!t���l�\"������uo5�Q�5��4��B-K�*��LW�5������q�KFH@k��<�jn���=J��������	.�>v"a5�1S�
�/�������{3Ss�R��}��7�{�		h�������~�H��f�4����>�>v"e5���{3�����f��@������w��Gw��7�'��H|
^(Mt��|Lz����R�y��e
g�'�V��j������?p^ ��3�V����� ;�����J��P:��K��������]����7>�������mnZ�of�j)�,F��+2SW���E�������s��3SWK�d1:�\���Z����s�v���/�������R!Y�7Wd&��o��j�o\���M@k��L^-
�t����������D������_��	h������C�Mn_.��������6���/{��������C0�]n���_-�.}POw��7���&�5�f�����b��9���ZF�]�p������n7�`m�K�������\f�j�����]�'�W��2����`���3�E//8���Z�]�`}�`�o\�n1�/��`�����������_-_�[�O�`�oT����M2T`���_���73��������V���%C$�5�f�����c�n����Z���X{{��7��	h���[����c�n����Zk��7F�o��
OI�g���&yc�
�uW�qfkmQ��/v��u/I"���7s�����z$��{3SXk7]P`w��������k@�B��r���~��o������������|��~��w��k�������g������~���?}������������hg0����+w���~��^��~�~���|���c������0p����H����q?N���<�%\T��X�\�1*>�oI��8���[2���v���f�8��Gu�V���o��iDT�n���6�|��Gu�����/v>�un��`V��8���LA�87���J�c��������fB4*,����������s'q�[C"h_�{����%D] �cy\�6���J��qq%�s�w�������m7b4����������	Z�������� ���v=��n?�.����<�w�JZ���}v)\�<�������pe3�+;����.u+��[1|i�;b�����y��]�XZ����w\�r�f�TF`I��E�����L�s\�.
1�E����z��x�.w>�@�ysx��x���u#F]�cy\�nL�W�D3v����A��}��9�w���x�b��D������
�3����X�������q��Y<W��w�2Up�y�xn���Uu�2��+�k%6;��n���p�KU�E���;uwl2������W�'���U�E���p��U]���{����.X6|zMX|W5]A���%/WuW\g������`���u�u]�qUc�����v,!���~������U5�������<�j,�
���cy\����z�o�:���E����-�q���+��IG�BQuE������|zJ��y\�X,-1����zwn1&��>���Oo	oA=���u#F��cy\�nL�WC��czL\�n=�=of�3��Q��������Q��
d��������u��x��jss\��`��aB(�{K���Vqo���9�{�	_�]?��r�L�zp�������Z�����q�[����`�`ks\�6
1�U����=_W����qgd\�b2�����q���@W��{3V=_W��{s�^��}��9�{1�
�0]����tE����R�q��J��:����#h5��73e�����Vso��;����=g��5�Q]<M���^���|�����������]�!1���6���o�6��������������&�(��F�&��y#L��������:��r�K^~��]�QOC9-����w�l���7��=,T�����\��^�����h��b>\}N�\��^�VT�q.�b�h_�y��\��^1+��L������}ZM������}��9�s+��^1+��L�U����}Zn���b�h_lz��\��^1+��L�U����=LO�q.�b�h_lz��\��^1��q.�b�h����u.�b�h_lz��\��^1+��L�U����}Z�������}��9�s�{��(�2S{�b�hp�O.�b�h_mz��]��^A+���Uh����$�����E_���]�q����+��b�4�E_�������Ec���m�q����+h���i�
��W���%wB���+�W������W��o�4�Eg�������Ek�����q����+h�����jc6n���c�����W��v>Guo]0�0zcw,j���������v���������{"]U�9�6�cw,j��^6��Fs�+3��jv��Jw���U���������=�{�[��n�$���e{l����HY�l���������������������u�?�`�s\��?�6�cw�i��^���F��r�^6��J����U���h����=�{� [[
��[Fu.�ck�?�D��flm��������������F\��?�V�cO��j���F��
�q������@�����]���J���U���������=�w�[�������el����HX����������z����������]���J{��|U����h����=�w��6F{l�927��m�����������c3{\��;�1�cw�.��]6�6Js��lU����h����=�w����;f���.{c�7�D��aolc���������m���:����5�	���|��]��6Fk��rI�^��6Fo��g*�{��(��'rU
[c�5��������m��Xc�I��5�QZcOd���6Fk����=�{����M��[c�5������e[lc�������}����i;���u��2G�u�>���Eu�^M��!�q���\�>�U��J���N���]WBd�����I�fcV��r�Fj���V���m�(�5�f&�Zv�FG�1S!�w[v����c|s\��#�5:��]�q�����h	4�Q�x�-�m�%����l	l��@Wd&�Z��FO�������	l�=������eO`k��"3i��)�5�w����.��pS�1�9�w��M��e��Zv�VW`���eW`�
<�7��.�[�)����U�����
4�Ai����6�x�o��]��FO������l
l���C��z�=���x�o��^��FO�s���M������7���*M�'�U-�[�)���tU�����
������
l���	��]����\f��e[`k�I[��-�U�O����'F�h�L���+���������s(
�W�z����&�5f&��i��}�k;�KT��m�q�[M�hT]f�����\�?!���Q������onM@k��L\u
Rs���7���kP���6���o��Q4���&]w��I���d�B�!9��N&]����I���I�7�@}s]��c���������p=b�;g}L�~�M<�t�<�-��{^���zz
�����$���l�����7~]T�vx
�W;����?}�A����l����A�xLE\�x	�W;����?��73���(������kG���#���^�����O@����3�l�������O��:��}�:�{)���{3s}���W���n�vr���6A�j7t\�R�'�5�f���
�������W����wC�M�����C1�Qi+33}�C�M�*��O��Ph���C�uo��Qh3�l�qo�B��U���y���-Qg��6D�uo��Qg3^/i�[#+��0�1���5�l�������mzb4�lUf��� +��v8��;���	�W[�����&�5�ff��Y��U���s�"��}�':�{���"�1"�{{d��ib\���	�W{���w�&�5�ff��Y��=�����#jl�������Vb4jl��4������Mci�;��!p_������'F�����[
�r����)�W�<n���>��7l\�qf�j���o�����������)���{3�W��!=����-�{G����}�1:�{����3�Wc��1z:�c������E�������	f������F]p�d~���uo����}�5:�{������ji�KQ�����8��:���e+���q�K��`�����;TG_qwsv3{�CUP������L�FQ���\����i�U\�(

�;��zwl��	U�4�Q���1o��#j���������6B4J����4��Q�O���zwFIP�����KO�FI���Z�r���qq���$(h_m����
%A��73a5nL�7�$�C���J�������������`����
$�Wq���~T�N%AA�j[t\����������T"!���J�9���DEP������J�FE��LXM5Rr����2SS����}�):�{����`������WQ[e~ZM-J����������	h���)��CR.p>�q�(�{;�:��-�q��O�h������#+�O����w@�C������#x5��73i5����"��}zG�:���q�;��h,o2�V���\�jb�����j��}��7����m�F�����r����.�W�;��=�q���[��3�V���|��Y=�j�������}��7�g�	
h������m���&h)���wf����	��\����>AcO��Op6��hq�������(x"u5�Qp������F��h�j�i��N�Y�<����)8[��mf�jf��lt
Z��4�e����
�H^�l��V�63y5�Up6Z��_q��^�Y�<����+8[����������+�v�	��_6��f����q��f��jl3�W3�g�Yp�*���e��n<����l��fAc�A��Yp��w,���_6�J������f��jl3�W3�g�Yp�}~�,8{���4���/g�Q�Xb���l��F�!��yf��n<����K1�Ql3�WK��\����������;D�q	�M�k>��a-%2t��(���i|\�F(p_l����j%D�D�F��������_lt5t�+�d���?�3������1�����]	~��������}3���V�s��������3����BAA~����Q��Z���ZN���[��U�j��7Z��5�	���������mFB4
n]f�o�vW��T����mQNX���O4G�uo�J0k�����\�*p�L���	����������B4Ft�����]�����w@1a�V�>���cG����.3��r���U�=tn��#*	����������B4t�����]�VJ���u��[��D{t\�.#!�s?�RV�r���}z�A\���"��R�g����wW%�5�f��V�v�
������
E�����L{tT�n�B�����L�m��*p�f���C
a�V�>���eK������R���U�*����lq�[���y]�i����� FC�g4��q/��
\�����V�z�y]�i����f FC��g��6�u�J�{n�r����s}�=:�{�cs�vl��)��;67c��b\�r�����<����cs�vl��)��;67c��!�H�^����;6�G�u/wln��MC�������;6wt��u/wln�������;67k�f�����cs3vl���q���[x�������������i�H�^�����n��������MY�y"m�q��f-��3�V�ln���=��q��-���e�<�j*
&��MC����S��O��V|<�/�/��_.W���G��o��Q��Wt��FA03�|���k��G��o]�Q4���o]]m�w�0���z��W���������x�y����k�M^rc*�__,l�������x��������3��;����o7����u����q��/�h��K^M����7���2����~�������������������_��Q��w��o.�QY�w�����e���)�g�]�8�������O�}�����?���~������o�����f~���������������?���_��������������?���_��������������?���_��������������?���_��������������?���_��������������?���_��������������?���_��������������?���_��������������?���_��������������?���_�������������{�����u��F�Vw#o��#����2�w��yW622�w�M4��~����sC]�S�C��+��k����v_�*�
u���������w�5���]�9t��0amDw�	�k\��`�5����\��,�/>���k@�_w�
�g�gP~��g��%�����~���r�]��Mx8��W�,�9���k�$�-�2��i��l\���$/�����r�3�pu����7��n��3���0��Y~	G���C�-�k�.�z@}�{��pzw�v��2R�����������l]�y�>��4���s�L|cQ���^���������������������>\m����a��k����:�r��E�e�U�������������UTt����{�V��2��&�����������:l��{�wW[�������~�����_�����'hW4�������n�@Y��\�!6w��������/�{��46���/���\��>l�>lx�C���}�����y�s��Z���C}�Q[�O���}
|���o�i���}��o��<p3��_�Cw�}H��5Zk�3����0��\u��B]���]1��/!��:J���wGLo�K��cz;����>�����/>�s
��?���&�i|�.�h���V[OD��|�J��>�7����S�� :W����R�@y�� �**c\E���*j��o]E}���z^E�3WQ�J�����*��}�cW����#(u7����$�,�M��/���t%`rF!`j���,������ai������	PE������������v�9�p��G���l�cI{�+�K�|q�n�;z��e1�	��!�*�Z�|��|��+����$2��8������'���?S�>UyHd���|����[Qk���vm�Md��[������2�F��!��Z0��|[E�m���C�m��6����;�|d�6�f��o*�G�l7)��|S�
�Y1��0�2�1��)�!��V�O����K?��X������\)��X����L9��j2�n'w)r���+�O_N�'��j�l����w^�1�`��b?}{z"���Y��Z���W�������>l��lz�<����;���2��������>;wo��1�
��.g�F���5#s��p
cr����)!227��9�-���0&��r�l����02�h��}���2&71�������?M3��Cr)xx���G)0^�h�y��5���	�v�K������c��k DP���,��zG�������_.S0���hLA��/'�@��G2�����uI��'v�P�~<���z�f���m��������?�n�Y�O�/�'/J"f~0|���_����h������n�8%����C8�G��(��Vz��r���e'qHU�������Z<��4�����=����2��������78�����.��%Mi�,x���6��j���K��x�U��WS~[������:��g��l?K��a�#~1hz��"}����E���6���'�l���&J&O�p��:���<M���y��}V��"6V�V�*g���{�=��$�����������Y4�m��c7�4��8�1����
�H���\�������+���P�C�xr��	�(�����,�����#���g?���`��N^<!8hU�o��5cB�h?]�Z'g��i��X��Y3&D����/DA��/g�+G��r�:����@�
Z�~9����W0+�K.�%����U���O@�+�O�f�_���������D��r�b���#�k�T��9�H�2W0+�K.Y%8�����_�*!�������D�k+�/�Y�N�?Z�����-�Q������GW�~�f��'��_e����wb��A%�_�?��\�J�
;����F����2���~2��3&w��^��?;@�{}�B��Gp��c�����"#��kV�?[ndL���*g�F�����Y��}O��	�1y��������)���W]cQ�q���71��~H��IsIxL0�j��J{�O�e�C*�S$����6�LBs��'��j�#�9����d����kV�g{�����e�*'�@�$4���Dc�4�%���\>��[�eu�����,���%����c�O�V*�]����h%�y{QZ�j.[�\��Mx�9����@s��-6���������4���a�V	��5���W�6��^
f
��� �n���7^��$�cW�\�������+S�t��Rtx?��Yi����ev�`G�>#ghM�d�q�O����L0���5I5��(�����,�#V�%V%Mi��&�\z�p�
��V���m$�v�'Xw�t��e)����[;N�^�:�]M�����.��d�k�~������L���z��)5�]	��HA��T��bS���3�I�"x���Z�`���,�`V���xBp����,L��f�A#���kS��8^/mx�V���q��������*����U�x��:p-�Y�_j��L�������I����t��M����AP&h}�e,~z!+��b�������E9�~/,�x�M�9��A����u�*����/��5�G��/��HD� �x�M-�������G}b�1��44�������$asb�1a��`V���3�=p�uZ�~'�3�c7����9�����v�Q�m��xme�ew?`Y��`�k�3m#DF�����<�c�O��L���������Bp��k������"#��O�j�}����1&��S���2����1���)C{��^n��)�zq4�<&�����k��Cs��Yf{[�����6"�=�|[
p�������m D�,�Y���M!h}��dq���l���v)�K���kA�k.��4�bO�����_������.Jk�o�������������c����V�2A��39��\!u
���1����F�z+��������V�������n
Lr��5|����g�9��i��skx_���k.�s.��Yi+���=���gD�>#����������H�#���o�����U5����kW���qi;/�(�K"��C ���h.�
�{�������"�m�'8&)o�e�2��>X���x&Z�!F���~x��q��x\��;���e�Ts�(=�����"d=�Y��������7����g?�_���7�K^<!80��7����;�~+��������7�z�,j��fL� z��������,~�L�w��D��5oG�w��js?	�D������_�#G0��m��' .�Cg�'�n��,�,�9�H�H*w���}r����!�WQ�y�[IG�:�'��	�5(�isV��$�������?n#��������������Vo>������c������
p[Q�~�9��y��V���/�Oj.	
}�v����F����a�[��`�a�3m��Y0��1Y������""�`>��Bp�l��r�m�X����j����(Ccr�>�=�H1�&%Q�����W�4�Q�.,&?�����`
�\��93#���s:~�c@e����}F������;���8P����_F���BS0���\[�~A�j��m� ���a����"i.=p�2���N�\z������%�v��Z}��k��%���&�t�MY�/���K��t<����~%4���{&
�.Z��14�6f��-XQ;������G��ngxY�����C�=x��������Q4�<��N�\��b��5��H�*�~V�6z�	��n�K��ad�>�|��{ ����&����/a��"���\�%�2�����v^X14�D8C\$��_X14�6����+�����g������\�������Sr��c�:��-������[���xR2����m�z<�e_(Y�%8'��X3&��,���0��c�Gf
�0k�D�0�����'���Y�,L����,�f�0�Y@����;���5c"9�M��l��`�]����X�� ��
�����D�������o���OBt����!�����~.����X�� ��������o���C���e$@,+��x��
��X�0`���s��q�K����e�D�
l��s���+=Av:]���#X�n��r�����n2� sQW�_���?-�@�`�Z��q:S���3Xo�����h
Po�9r�<����50`�s�P���To�������{���M0yr&o�����S��>�cTn����3y�������O�cX�����3y#D��Ng�\q�|�
t=�r��O/G+3�^���>B0Z9���e�z�Y�������1����W\���c�o�������.CN��'�{�E(�Yk��`�!(Yr��8����d5}�Gt�4�`�{�I:"������h/M}	t9�����Q_������D�a� :O�*��w����;}7W����xM����������(��L�s
�.;��[�=�4�l�K������P6X�^�%��+^�������+\���V0'9�kIS�-���^�q��������h>wW�������-�}wo���Y���n'ME�0���H�&�"<��m��w�]�����k�/_,���Q}I�x���V�%��2�G/�H�K`s���}8tu�g�x?2R#�
��X�!��b���5�R��D<����s��>E�����
�{��k�C����wg��]j��X{w�����t�AD��Y�w��&�Q�q�����v�A\i@���\j*��X|w�����v�AD��Y���D�������X%FV��U}���Dd��5�����X�0��W���`j��n��/E�B(1b���X��`Ao��O��-8���>����EHD��`p��+2�<�5,�+��JV���`����q����2������'&$��p�.		f'\�,xbF�o��>����x�P���)��81%��FK����95���k����h����7P]&Qc��l#C�������0N��^5�����y
N�t.g*G����+���!:��)(,r.g*�3�d(��c�������y~����i�l�����;J���f������X�(�LS�e�4����7�%~INo1����d �q%�ib��dY��$�r2�H����!���,gx��`�g��\�1����X0E���#��gb����Uez��+l�3X�������Z^�\����Gi�i(u�p,U��.��v�1T�DH�Ci�i��T1T�6$���x��NU&������=�%m^Se��J�W9�:�K�IxUA�M�������Te@�T,@\��Q��%W��8�����<x<�;��osU��2�@�keA@>U&65M�{���b�2=l�LcSSbU��m&�����05�Se���e�U~�x����1���^+-x������z�'��9��>��S�������y01��[@+�L��I :��n��9�������l��]���}E{������,�C�,�5&����LO��OR��,88Z�����\��,�#��Z�`rU���`p@�������cE�~�\Lt`�n��9��V_@����������,��Z�`�\�Dt`�Ko�Oj�-�����eW'���LJd
NYve��1����V�N.!:�!s�>\���,d'g�����,�.��O�I(���
Z��X�5�����O�I8V�4�*�I�Tfr���
C9t��6������Y��P�L���z3�K��{tU�����K���1"@���0D��,p}V9S9b\hA���>�
>Q�:W��oT�&V��^��X{����	����YLe&���7�����?}O�������_8�9b�YYC�s�@�!
UxH��r2�����4����,g���y��y\iAcLC����@�1
����[ef�2���+T7SN�.���Qm4�����8�%�q|Ce�o(�5
��2�UW���*<�agrc[9�4�1����DQf����R+3��IC����2�)3�����*c�B�w�ESf��M
��w�Mf�|e������kUO�x{�5{^(�R��B���R�=G Ex����P]�VDSf~���J�1�43�2�G�._�|����������������(3=lcEl��O�sRY��$�8@v��;v�P�UZ�x|�t�����u�G	<���	�z}pEBe�S���U���|ud#d���;*����-��V���>Fh[�f�����7`�|ud�F��&1��[x�x~�J�gAn:�ocA���n����Yp%����&�*�GG�w
k[�|Q#Y����6���>:�kX�Z�+�z7&���m�n��������*K>F2���m�7!��`��
7`�|�%#x��X�����Ve��`����q��y����Dt5-�WX������ ��$'�2����p��y9I�Z�`�	�>:dL�7U�j��r��D�$�_�I�Rf��6Zp�z����@W�(0S(3��~�@]14��T����c�]�
�?�ch���V�3�#F���S��	t
Cs�����12@7���������147���2���-hI��j��N�2�"f��IM�

+3}x(��=�\_f0dUf�����+h�p?J��� F�S�i\6�� .p��@�J����?��KZ0����d ��3��:/�2�G����)3w�2�G�\��h�9�����Q�o�v�5�,�uIx�����t��,�2�����������L!����1�2��F���I%�4�71k�����>=UOu�'F���i=�cH3=x33�i�������o*�,������=�j4�0.������/YMb������l�n�.����h���%X��ycE�f�Z����#I3�
�{�����$�������0��f�7��/��F�]#7�Eb��7�r�r�$�<��������RN���{�)���lrV������.9�@t����sV��q��.�.y1�\E�q�&g%������3�D�K��&�$�:��/�8cwv�`|e^@��$J��}�f���8�[i��6�&gI��4�qw���D�@�,��$J��J��X�.h����6gm���
h���5IDfR�,���D�-h0�}ru+�5%-�����-#��Y0�4������O�I��4���s����������{/�fA��7�!�j����=1'�����x��M��6�� �jnv]�Ho7%��3�6�~�@�34+K8���12@�����������6�6g*�to�[�?a���y�[���12@���?�
>Q����y�������i�h��;k�J�:5�1��:����8�L���r�;�������f~���~Y�)<m���@x�uNFocr.��f��S�����@x�u���5y���#�9���]F��H�s6��}4L�f�B�s�`9o���i�L1s����<�����>Z��8����$����bHr���{��m�G��J�s
�0;�cq�����X�a����$8�Fh��V�������%����[+���A���c����9�������3=x�������:sV����J4Rp?|�u��X��H��bi�<���hM#e}�Q4R<�q��oh(�AO�����������wVy������;+�>�����4�?�;+�>�������_a5�:�g������+@='���={��h����J���hf���+�p���"��LW(t��<�
g�&{�������	@�8Z0�p�2V�=�P�
h���*:(\n������4�CrV�Z^2MX��e�&{��
��� X_��`��(1r����,�Z����z3
��X�0��m���L�����`X��e,�#'��d�3-���7��'������14��%�P��a�k���D��x�f��
WYox�O��-Hj��`p�=����H>��^����<��Q	�w�IF�n��'�$�~!�5��Nt\~��a�kbN���������9}����f��A��E�Y���F���g
�3C�������#�2����14/������j�#F,��1�����Ct���<y�g��z�%����HMc���O/U+���������J���1�\���t�E���c���*U_�����-~iNO�������/�{�]A�s3*��l��)p=�z4F��N�|Z�t������Co���s�9���0���D�S�����<i&/���y�E	�eI�Z
q�5]���H�j��QG�f�O��g6;��Q���X5���[M�ci&��L*hp��E�Ip+�����V�3�&���I�1%�'���f�kH����5FW�=V�3g��4�~�Z�x�	
>�=5�h�(b�;^@k��*�#�<�����
�m@�Q��(���h���E�	�*v��\�ygE�fJu����I�Ip=��Z{q�
���$���lQ���F�=��{>7��B-KD�=���������h���r��PT���C���ra"J�R���,<���C@�z�;$G�l?��f��u�F�K��Hq�7���Q0S��y���)��H��G�e4D����]������W�+���������5�7Po�16�$2�L�`
���X� 2�
� ���LC���I��8�h��I�D\HH.l�f,(yIK.:-�%�k@!�6�4�y\I�,zE�K6���+�5�����p�`~�4dcI3������l�inFMSWX�2 k�[x`����FZf����D�Sb]_0M�>��h
���e4%fy??�w�����w�3�#DpY����Gt �z$���	 r�B��^��x!:0X�7u�
�D�����c_�����n�?(�����Z5��1���JvQ��<����p��������{��!4p!�
�����
m\]��Y�`>��&:d}�7`N���<5�#:d}�7`N����	f����|)BL�k�#��b��H��t��e,��K�7.�����X����;D�,��zcR�q���2<>5�Q
�;$�����n9�c�E��W�����i�y;�����{b�Y�P8Zu�:V/��nl��:V�J�[�A����XQ����5}�@x(�^M�j��(:V��7����ysk'Z��`�g���=�B,-1N1������h�<x<�S���j�R�Z�J_O�B��;+����5@0?qg���z�x�zKv�Yqt�8���N�����+B���
]S���M������  �g��-�#}���l�+N�!<>C��^��(��U.��a�_��Z�lV�<!�sN0k\Br2���8'p}�,��V���V�*y!��X���K!v
SOe@V�6�����Oe@�0[����q(X���J^n*y����TD%O0kL�$$����w5�$2��i@C�^%WS����l/�!G��b����A9��'k"���f���u\D9���
��(G�
h����b`��*0(G�r���`>���2 X����Ld�
h^�3�������Ld�0a��	U�!���
��2�����&�D����	��0�f=��\����xZ���C����%�����"�sk���G>�������*gG�����%���������:gG��������}�OT���g\���2M�L6{c���:Ze���h�F�Y�[~�iYo`��/������\�,Z�?���:������`mCHO^�!�muN���n�2d}DGb3����;"�McBYGc�4-+�q�p��N�z��w2���}�o{XyM������������������*:�B��9�9x��1E�	�KA�$>w
��1	�A���&�DQcK��������L/I<N�)u���<�u'���C@I�NjL1@A���6��b��:ME���7Ke}CqQ����;��!4�6����n��EM��u�;��jL"%���;+����$����G���
'hw|�m��} ��1�{,�=:@F�$����b��C�����g���=<���M����6����P��k��l8c�����V6��N �������Ed"�W��0u)�C���
�0�3�	��S9o����!���3�=�����1�FR�#�X
%������5`j-���d��0c5���r�hm@hR����u4`���d��z��m�rr~"��3��<�+
h����J$��*0��6�JDpB�Y3`j9��#(�o��e%B��C�7�'2`�Y��<1���.�H����A����)f�L= �C����� <1��'�_�D�Sc�X���>��+��f45fu?6`���`?b�3�#D��	�>���	��L���y2F�����<{���	!28�FO�^O�����1.�q���4�r����&���{��hz;v
������1���o`�qu��W�Y��
W��umN���n�Fcz���Hl��&�6'�@�d7W��1}�t��5��������f41���/E���#��}�wj��v��T0M�>���/Kb�m$���2��wn#��]��C?������z�u;;9�;�	�����jLj��1�Y�~5&������y�+�^3d��<�0&kmB�|��o��>��wh��Vc�w�W������OP��kR@4E0R� �5E��7�QD��S�S�y�HR5f�x�O�V���E�	����<���;+���P���]���HjL�����6����x���?'j�7<7d#Z�!F���_d��Cx��
�=^����1������&oQ�d�9����J�d,��35�@t�L��1`�"2!�4�Q	h��R��/i�`%��YD&DT�f��� ������Y��Ed@
�������a�o���PBD�`V�%���B���9����!�7�������DG���_ �Y
%D&���S
H���_�X����b0��t�.���HJN���]��!�����9]r9+�qJ��M)�,+"	oR���+B��,�7�@xb&2o4�Q����,
,lv'f"
��Y�S������)p}�����fc:��K�I5&��t�~�2&�1T��y�
�xj�������[I��	!28oF;]��Gt��[�������C��X��N���Bt ��o��	!�����}�OT����4��uze�Xq	xM`�|k�����&��%���A�{������C��9���1��fO� �>#��AD�'��"���r4`0��3�D�.�YY����0#��A�h@#���1_������xX��1]�=��e�AF9E~�{\�V�F����E*���$���Qmm�P�a5f'�1��<$���W����c��$D����jLc��rpV���������������(�j�4���iJ�6P[O�(jL���Gq�z���*�|Syx>]}?\m���.81j���X�(#
tZSDYySE��'����u�g{%Tc��-��@_�A���;+����G������b�1	n��:k��;+��N���
g�xF�YJ�!�
��!�Ann���h�'�|4R$���b��:���+��j��P>��`%��XD� ���1T�ON'�\����R}�"��e��0u)�C����
���L�KAC���<���@���XD� ���C�����%8T��X
%�����*5���y�H����R}�j��e��}����D�4`���OP
��/���_@�dY0�������?������?���������O��������������?�l���?~���>�������p�c��u���*��.%��!~�������o���c?=�=W���w������-%���c�o-g����Z������J�/��n�Y�#D����r���������F��g�?�+����i� [4���-5�[����q��l?���o����q��1��q��~
*D����y������/��IV=p���\��P_?����D�j}?[aa=M��v9�\@dMm�jj���1&w�v�!g�K���^�+���z��.��r���������;�o��D�����7��+���RP���h�{�C*�x����x�{E���c�y�9l^pe�z��a*�X���F�!�N���W0k���a����.�Z���m ���3t���=��J�/8��9�b�+��{�q��NjjU��+hj��<�*!3C�>����J`�yMz�����q�J��]4S,�7e�M�<�s�vq;�Q����t����0�Q��Y��U�Y�~�*��|:,�3����a��N����s��� ��[1�Z������N�
�M���V
or����-l�]���=��h��{�k������>���)�b��g��o�r!�sD�j�������(jU@t5m��u�;+�Z���$����HjU�[n�����d�6�����k�iuAb��� E�=��,X@k��z���=��X���z�v�{s��V�u�d���Fd�Z��S�	8d��6`���cb�P�X�.�x�x�������X>�0�����NMz�0�������4���f7`q��
0c%�����V��k��NntE�R(1�5
���k�-Hd��dA0`�Z����V�%g7`�h�����v�g����V�Z���� h�XV�0n4��7�
���W4`��������=�F	h���� 80��6`�3����z_l�Ld@���
��Ld@s��V����"p��{�����X�������sBL�q'�Z��������N�c����<*�wG����>�/}���aybX�0gG����>(������`���[�Hb@F�YoZ����5-&�-��GX>�2�ae����k�_����y�bh�u�X,-&�q����s�5�����i1�?����&�z�s��Hzs�[������\������������.�������]t.'�@��77�y���|)jL��
����y��lOScz��&�ox���Xqm�6����vT��,�9���k�;T���D��=��S���{��c�;!�����p��1��G��:e��"�1=p#��O���!\�k�%^�c\�4����XO�(jL2������9q�|5�<�9���>�qB�X�WD���c)�<���l��g�MQQ<o�z����������n���h�p!g��C��A�`T0?qg�Pc\���=|g�Qcz� 6�{��v(c�1��fH
 ��m�=���s�`����]����b���s��z}���5n��-����9������zsg��N8."����]���L���n�&�&y)�� g����]����&����=��Q[x�+s����fl"�o���Y���P`�&���D�g���E�[x�+sVC���fl"��#S�dAx�+sVC����7cyvr�^D���e%b$�kl"o�+������"rW�,+#�Icy�\�Jp$C���]���D�dD�M�;���5 �o�E��:1�&���D�=� �-���U'f"�D������������5,g�N�DVr3����.�'��������z�u�����4j������]���Rp�fl"O������
0gG��$��Y���"�+��s&p�������_Tc�����4�b��&0��n��L^Sz��o&��8jL�a�������>}2f���,"�������;c������7��U8����3�7��������6`���1�0`�g}]4�KSc��Y��s8O�	�MA{��P=+o�F���k�X����x{���R�Sc��/�/���^�~�y�c��$������h
��1	���Z@n�}Q���U�����X{|�������@"����&4��<��z>��H]�����UyAU��?�V�����(`��+hMe�MqQ��8�T�vm�t����P�z*o��Y1���8�Q2��6��jL/�Q�wV5��,���������|F�V�����)�=���m��=F�|�3�����Qb����i����
�_���myt��*�����)�0v0����KM'x�f0�����$����D~�0u)�����E�nW�I*��cl"�R3�8�0�E�n�z>�W�{�M��
���^D�v=�S��cy�ZGp���"r�������D~�0��7��[���������gT�6�+J0<���XV�0�k����V"y����W�f,+y7P�Q������i���mWg,+y��h���!8� �6`��2�A
W����8R���
������kW��(��#�=p
������e"��h@]w�yN���C�Z��a=��I����j���7[��\�e�M���k�^�>�\��\�[I��	12:7��(������������#�s����c_���4�����T�=�H6�V.���D�L{��g
^M`oN���$�����}w�������1�?��������;#�Mg�bHO^f1\���w F������>�#8��N�����������1_��^���b�Uc�
����� 3M��p�eI���}&|i��#]��7�62�4��5���S�-�<=��T�4��tb�1	qb7�4���jL*��V����1{��}�c��>*���o.��_����yC�%\��g��yH��	NoQNbfVf���z;L,���E���(`��;{���J�����7���'Xx�U:��������Wn��������'p-w}C��H�m��^�U���i�( ndBV���}E)Jp|yn�jP�\$�(�����
�"0�1����5���2 SX&�gO�-�#��Z�=��'����w���2����o�(]E;���M�71��,��L=9�Ap8��6`��n`,PW�����XB)*h}�9��FU@+L�V�J���m�70V%
�+E���*h�Y�%F��Zy���RX�.h��T��Y�%FP�Z����	�;A0`�R-1.4�^��n����R�6g����
h�'�I�P��`��1n�������@���`X,���z#TIZ�`r�
�A�$p<1�-��E�g#�H�6`����$�}��g�{�6Z0,�NLG�����G.�'��D:N���>.�������~�A��b����3�#F�go�A��p#�7��j��i12>��Z���cd���.gG����.u��o��
5�q���}�
5�2���-X�"U�	���d)F��j4�(��L8�}��������?sGw?���V�t�#i�YW�&'�	n!�9��]F���H�s�eG�S?	�%,�2�����\���E4
L��z�Hp��f�9M3�Af����f����h�4��G����h�4�F�=�42����#��o���!chF�*X%�I�.�f��Qm�VgM
�1��7\����*�?T���o>It�+W��:�S�����2=x��w��wh�|�z+�({��pUI�� K�k�F,m��i����Q�'E���	,��S/�2�9��ev�����+�+���C��A������>��e\�U�����2=px-�=_a���2e
z�)�]��<Va���Y4�b06�ym�S���qb�Al&x�x��N��j���	���2��=�+�i<�\rB���T(���d#(�Y0uA�CJF�,���L�]A��KN/�.�R��XL�0� ����-���g��c_��:����������3�E=���	h�������oU�3�E��[��X���j�U�s�������68}�|"R�P)��>g��!n�,q�����dE<q����7�������F$;b����DF������y���P���I��-{�����$��8cA k�_���:�A��
B��h?�4�����5��6�C��~;�R��3����cF�fv����Ayv��{_���pe`^Ip��Gt�+��`������lT�3�]�ncP^�eP�y���7c��^s�$���1(ooT�&Vf�����2�h�{x�'D��D���E�Qd�<x���"��g@g�2�g��I_]��"�_<�D��O �F`R>����}�~�wj�t;\�t8�^�5`��Emh\���$�D�W��
H2��$��\4��,U���.��Ui��\�����������aIf7��kxo����K���"�D*���(�L�c�6��%��T�>�HVT�&��~��&�����I2��#���T��?M�Z�W�u0������y�E�EcW��T�������'���T����L*������"��YQ$����Q�����(�L����O���$�$���v��u�F�d�{����!�A����l�b1���%���qb��:��zS�Qb��
�����'����x�A��L�����������7`��1!N
�K���t������7`����e��05!���
3)K��3�\�������!X��3VB=�P-f����pD��^��I��p�hY0kL-��A�,p��
����������P�g@nn�WcPf�Z����X�~m]Cn4�1'�N�e%��d������2�7"�1&�N-����^bA�)�Jn:�=i
���o��2��@�Z0k_��.�708%�</i8I�1&)�D�bz�P�n�Rh��\p���hB��~v@S".7��e����i��*�e��0gG����)J�x!:��*�)*s&p���\����x�2Mt5�r�>�i+�M�	L,�<Je���D�162�.�� E�Ix����;Gd6}�d�A<-f_����l��
b���!��l�y��k��<�&<����;"�����>�#:�MxC��wDNch�iu4�KQcz�@l67�n���K��t��i�3!3M����	�%��t~g
��V
��,	���
���P��e$x|j����Y��X�O��zjX�O�hY	o�S���{	�ZV"-8����`C�Jp#/����X���C9@��I�@��8xM�j	��c�C��e�}Z-��f�9���Z�{�]����|�f�<�����0���dF����'���(z2O������&�"��e��{������k���Y1��D>J����C�����j��
pq����g]vr�RT����
 3�]�E�f��-�#}������^�qb�q���zW�]R-k�|R���W9K���Ec��wMr2��608��Y�����S�1:�]��EtP��;��9K��ez����09�
t���r�*g	��R�oc@<�o���d@,���7���D�lM���YK&DTm�f��jj�[i����YK���
9zvVx�
\��9�r����`���:.��0(G�r���`��\Lt����N�*gQ�����+��"��2��y�H� Yj�����H� O��O�D��4��M��D��4`P�^�����=
��/�'��D�����z��'-������
Zo&�|w98@�f���l�>��rx�A�3�#Dgk�A���1.��98@�^���k����L���^��+���d��o`�E�T��
���s�kY	���������6g�d����1$6������;�Dvs�'�e �����DbS��w D�����Y�Q� p}�����!s0�������������������4a�`;O�,�u�m4[C��/{���6Zt�z����1	���V���l��1�b��Y0����-��.��6R���>o^bE	\�k1<}�������xo^M�Ix|&n;'�������j���t��Q��k_���h�(`tX
�"��R�h�(��	�{���N���s
�(|-����b�1	�,iK����C�����*h������M���
������1�����B�$���={��X���H�W�<�������]���u%�h��p����
�����&XG��=���wV^�D�<t��w�*��1�����F�K]J!:V��p~W�I"�
�YU�.5#���
�����2�FU��d�W�w���U����w��p:�k]
����������p]j=��s��o���P"�	��1�F��5�J��W4�1�K�D��a����
����A�F3���O-g%��dH���d,+yI����>�"�CGd� ����Et����=���.�$�=1����Z���x*�����D�'f"��YK"\"��1=t�[w{g(��J��������nf\O^hs&p���<���������:�6g���l���?^��qy	����	!28/���?��L�����Oe���ds5�s�|������'��>B6����Lsw�qUQ�f?�s��q��:�������5�!=yMt$6������=���:kC������������!�u�[��h����$:�b�of1��1����AF��of3�~Y+�^�,�/�&<Ni��)
e}`A�%�|�����1
}xL���	���{-��>���w5&�U�����1��C� h�/���\0�����gQ��
1�_��15����`�*E�/���� x5�h��<> �f�{����V�V���`���o}��'H~��FSk#o��PWV�@����E��[���\����Z�}��t�FQ�"�F���++�R����3fM��")E	�����V���-$���e����'
�_v�{����{,>)N�!<&C�^�~�T��
"���	H����M�mi����T�q�@���,p"df�`����e������|��,p��h@Cf6$g+��7���u9���_0��I�A�Y��R�)����
�uzD����
��RK���	f�����@7�,��2�.g�������,��xJ1`��!����n
�\%tT2���A���E�d&=9���Km��d��d�,y"��b�Lt)���b�3�3R��d"�J�?w'f"[I������=t�>���3����f>p�<��G7
�A���GYT����P��S���4������r&p���,�O�|D��,p}�L�q��U��/@�A�7`���kDq�|�2Mt����<��+��Z9Z����Q��T�&<$��W�X��8JQ�C�)x��quq�������1����U�>��C�)�O"�}t 6�o�|��q��nf��<tME��}>���vS0k��|���>:��W���w�+���-h����������5����2.o������v�s;}x+��_���1��Nb�YPo�*���>8����f��0���W�����(�x���P��9�=j��WScZO�jL��gb�Q����C��j�����p0�3�'��!�#)�<�cM�����R��PD��x�z�7T�.�������@��1�G�{gEPcz'>JF����A�����:O\5��4��oqU���hs;���5u��!MAnn��h�����H�*���{���y���*pEScV�}���*�������>DT��
_��t��
?���}�"��U�������=�*|����Cd����{�R�7L�
?�+"{Y��*|~�
?���C�j����
_��Z8�fk[p�����C�/�5&���@�\�����>��4H��t
$���e%B�/�5&V"��@�\��9�J�X:���]U�D,�!\��9�J���I0�,�2�J����Ld�*�`�sg"#�(\���e"c�di���k��D�0��q8/k$K���K�)5��y����z�n��������c��\8W�������1���C���M��rE���[��J�|!:F�6Hc�"g��sk�X��o���4�14w����4�2��B��6��)NsMo���$^q:,���q�x#C�������-�l�c0�a/lpEN��1�a4�1d ������<W�$������!�#:���@W�d��FK�P����G^����7������p7C�2K����]M/Jl|���b������E	���7��]����1��4�E��	����x������]^����bL���w�x��wyS��&�((�'�(�DUW2��O�����x.���~s=\r�>��������?�e��o?}�������N�5v����V�:��J�K1���������$�u��
 ���?��7��>��������G��!��/�����7�/}����|3;��n������+�����b���Ow{H��)�	�)�j-�2�U1Tk�k�����n|�����A��W�����X�������k���M$�������E	����{x����C�+h��=�Hr�&��-^��or%��^����~o�?x%���Zs^��W��-h����)n���[[�*Ogq��� ��?x��<N�������������5��m�g���� ��r�0I^
~M�*�tt�N^��n�O^��'��g����k���}O[��7+'��U$yS��d4$��R�<�#Z���E�4'��k�����������{�=������x���w����&�c��CA���r�<�'k�{�+�����������'���7�������<��'o�����*[$9y�0.h�R�Nw�O�nq�R���M|������
o{�8�\~�����_��WW����w��U�O�<�g�xc�Ir�f�S_�*�/3��������r�,�����o{�~�K��\�����{�X����e,�*z;��R�j���]X`��d���r?9��{��r�8{�m����f����h��^��go.f�H����Go��hAgaKp�f���a�U���������������
����G:��}O^��'�w���>Wx�	Z%,�M��
�����d�4'���.O���X����������H�r@@����+��q������N�>���=y
88����������������w�����J��=y�������Or�:��V��3��$��=�#':z�Lt}�����e��]vs��=�����>zs�N���'zrA�|����Dgo`25B���;�.����Y���M����{�f9 #�}�&fS��y�V>uL�"�|=����������y�����k-Ns�����i��z�yf�1��������,��[����������S��4+h��/s��������^|�����<{o�h�W4��7Sho��#I�; &�}�6���>��VT�y�6��6��qa/���Vb�j����KQ����V��x�����C9���Y��7�6��zq$p���q�!jqoq�Y�g3���.[�����p��R������{_M�����k9��t����������g�#1o$�m���mY���-g������wYS�y�����jZ�f�o�?�6��zi@�	Z��Y/������kAT	Z��e�Q/�	�<{o[�[Z~�mP�Y>*���U�,�4)?Z$F;|;_����X5�=>|QS���&�6U+s������f����{���3����=|�J|�}�-�0�7�iK�����
��nl�9{V/}��7�Y7�c�_������g�mK|{���m��g�Q�����e���3Z��w]�G��y�Va:+����������O�Nt�������{�
���1�A��{T�s��mY>���>Z}}��[A�\���,�^V��k�?:��M���G���������������[�m�o�?��*�%xt��u��)�E%:�7�������!��[������{���������%�����%n��J�m<���W�MG�>!8Mp���Dp�����2��r#����z������L~�?�a���*[�EX���������\k��������\k��V;{���� ��P��m{����e��Y=�Y/�W���5���6s�w�P���u�E��8{-�A�
��<~��fkc9������.8��z$l)�W���
�5u6���gN���7Sv����+���9+}�b��7���&sVo�lY�Cp4g�H�R���e;�F#m�}�F�T�.y3r�Dl��w���������M��<|o[]_�rK~��U������3v��I<^�����U�V�Y��rB�:�ntaB���	�khB`����������Qu�|_e����5"07��*�jLl2O�\9!p5�3�NT%:{���&Vo[]_9!p
O�U���U�l\^�#�
*�w�m\^�����>&8{��	��>6����C+����{�����v����G���}�-[9�7���R�u���Uh��O�M�2l�u�V{�g���j ����z���V�H���G���}�-[��7����`)_����U�c�%����@A������������m��'n�I������j[6�
��Q��9�(A��qV�f�
����=|�����T��Y�[hV`�����������P���l���?;9-p3�������;cX`�g��]@�Y�m�}����G��}�-������:����mB�U�*�/s���a��V1�^�Ot�8,p
�����qX�X?��W�+o�8-p3�����n���>�t���7cZ`Yd�un�����o;<b���-<-�~4<�z_y��i��5-0�����7cZ`����FF�����E�owH��wU�\��������#uK�����p=����I������n�d����#8�
r�Tx��+�����k�k���P��\��`���s�
�=��Y�:V�t���<�vQ�X����7�t������n����y��V9������/�}������Q����ZT�P��Y����z�W:tA7]����������w���K��Q���.o{�~�
Gl�~8n���3����4>�������/�F�k�)����Tq�_W�o�i^�>�9���j�����O�������>�������|�w��>�j�����^�g�O^����^�y[$/�xm�zL�z�c7��?�����8���n�
&��+����n4���k���"����zA����S���M|�L�����(��Go����
y��^�m@7�R^s`H������l>2�>On�%�T�)T�{�~�KP��H�~�d�}�V��K���=�
�[����f����A��b���}�m����L=�J=����-�R$R?���������}���Ls��G'p~%�k�9���6�4��sn"��6����G������yG�=��h��}���?Q���.����tUt�1�>oW�xA�ezy'\�,DZ�S���a����g��D�@oV�����s����^��z�����{�_��C���L�1T0+����S�����0�5x�)��f�>{]����_w���:T�r���b
�/X&�����"/`���&?�so+gq��u�A��{���@kV��7��s7{��rIq�
 ��[L��`I%h5�^�|o��mm�[=��]��m��,�+fqS����ev�ebN5��3��g���E+�����SM�}�o�fq3��9����r���������H[�h������*p���q[d����]�J��BN���Z������Jy
��w7�����m|���l���~Jq���6�eWe�Q���M�Y�c��������
����,�����*��	dtw�!���-jt+Y�_�R'���o����t�����E\�P5��%O��U��tx\\%�>n��X��\6s%�d�,o���������������$���"������_U�Id�Ub_���eV1�
x���_Cf�^���P�&1D>
?��>����.����R���x�Ev@,���U�{y']�e�z_��,=1Jt�:���@�H�bj�������
#��G���?=3��bG37)�=�[��M�%�V]�*�/3�\L+��z��E���o��9<.���E>X]u���������������M��F}���w���|-�_�v���o��y�t���=��<��<����bM�r6�@���-h��J'u�5pL��B?�K;��\8���,�2�>x�.�+)�|�VfX�U��M�l�$p��NfYQ�.�{t6Y����2��U�3��2��U>�uWW�Vl�*�6���L�T�aUF���j\�9$Y����{^G�F�k�����������K���r��4�$������Y�jc;k����B�%p�I���������7�`���f5O�#��f��'�)�+�e��K�Uy��
���� ��j��u��e>��Bt�n���r�B�b��5V�I�|�a��50U&A~�v3�0��
t�1���<�����w�@��3�_?��#�%p��a�����fT\>�a�YS
��{���x�R�]�����	��`R����)���0��H��VQ'
D~��|c��B|�h���M��O�4�W�x��I0��b��UZ�s���j2H�[�f9�3s�9P	���6G>�3*����������������������Q�:I~"t�#i�sTWd��T+7k�X�q'D���\�������w��T,����N`f-L�f��(�����tu�~]�u�x�X�&�UQ�,����L9�I�|�iyd�y�X���R+W���	��u�g��U�=c�57J	Z�fV���Bt�eQQ��F>��P�I�|4P������� ?[;��h�Av�
���J�*����l����>��3v���������<�lP����������6���'o	���EK��}�n��]���V�bf5L�f)���������������wV��}�_i���3��kvK	\%|��{����
;��0������'h��OP�T�O���'�;�a����4�I�sB�����X-�YSO�QF}��{��	���8�7fA/Of��)���\����d&�#^����dfc�\��%�^J�3�5����N����R�W`��4����I�	|D�Y����#��}�2��'p%��S�\����{7�����D��':�7[���3
���������}8�b�)lr�����K�z�9�;�8�����&�)l89O�j�2+b7]�5�}�����$?������w>���it��i�����SO�>?-���<���������.P�o��9�������G��TL�����j�f.F4
^zMmly3'��8�lL�������IM�1�{�����IM�1�{����Y4j��$��Oqr�^���x��Ot����z|���M����'h���`������'h�(<���?�,���`fAZ3��7����6l�������K���������
�N5��S��z������{�c�T��&a�w�1�N9stF�8��1O�!��K�[��I���I�|D��J��1��8���m��B"a1��q?�\y�,:��erS���)����$��z|����#�@SR����Y�r|���a���}��m�'��2���ri�%��G'pq�7&a�j(�I���0�����������2�0$ a�w��Ui��m	�H�j����������G����!���ft�|u����s\[.�Q�������
p��*���7�U�������������+������U}O��9G{����#?��e��z���������������?����y%��������?��r<b���Q�����������E�6��=�Ec�����.y����t��_��������_���?���?���?��/_�w?^>�����?~���>����E���7�}����c]���%�Gv������~����������o�;���QD
���c��|��:@�!���r>
��5d�����2��k��
-�����=n�W��g���K����}�5����o�=n=z�e�q��z�B���E�����F~��0�-��\
]f�O�D7��*��<n���X~��3=
U��vQ��tE�iV�D�Hh�y������g�<���@�j�2k}:�0�nV�|���=F=~��]x
���GYk��q
wg��������pw����O�
�Kg��6�@��_Z������O��?.9����?�h������{k^1���������=��Kt�0�1�X���ez����,d��������4dd�]����i��Gs�n��BK#h����u�cZ��Q����v�s
\�7���uN�I�|HVE���=�=/�N/t�V_o�8��)h��Y��
�c��YeV�t�d-py�����|��-���!Yk���d�t����.�A7A�)h�A�(�]���s��7���{��;S0���������,��{���Z~��
S���o<c����,�\�3�����e!���w�`(%�����!Yj�n�Nt��������kA���$(��t���m��������q����)%�����;h������z�v��0���q0�n����������,Z�j0����,�.P,�����%�����+hN������R����7`_���o�o��x�\�f��5�����L_#������+h�Y�7=�^�2�`����n��2����XmfL����<�oL��-��������)�Y�sn��l�F#a��`�9����;��\��{L+�;���H����@oL��=?�������Y������H�}9���t�6n���5��������|���-��������O���C��u0���W��}��:�~v7���g�3��/h���Y���=�6p�����Iq�����[��Y�/���S��`��+�x�^�r�?�c�����������A*���=+?7�T����
f(
�J�Ugf`vI	Z��e�1�y
V�T�Y3�KJ����138G�������yg�PB�%?[9�;��I	�7)A%��������� ��.`���P�w�����C��U0C�;��;qw�_�������y,���5�����"�;'\O�1@��oys�#�h�J�����7f���~��^.��?�|� `������Vf��������o�X������i�����Y54�f:5����f�#k��Q32��[GpF�T'�����������B2&?�?7���hh�F�J]zf��)�_��O��c5�b*h���Y34�b:�*��3V#+�c�bZ?�����������6��}��������#�?�Q-��U1���D�o�=�����������'���cU��dh���3��7��q�-h5�P�(wX\�f��36s�q�yc�j���,?��r�����Y24.+����f��W����M4{#k�W;��5C#k�c�f��3�����6�w�M���F�����X3���i����E��,�f
M,�N��i�������M��W���7���}y�!l�BN'�p�F�a�*&N'�p���������^�Jt����"�7�a&�������C�|���?Ro^n3��L����_ft����������:�*�ycf�J�I��{�����k;�H}Ud�y|��b>��U�W=�A�Z�+�X�WP����_����o���w��G�tm���t�<��2���������,�����>���E�����u]V��j��o��3�?|����������O����}�O����}����y���������������?���O��G�?k���\_��������������?���_����������������o��������Z�w[�����m����������������]u���0���ww;���`�Eq�������Sw�O�-�n~����U[�wW��]q�w7h���*��k��_(o�P��]9w������r�������[��p�?����f��	us��������	���ty������������-������O�����ms��w����]u�O��zx\s�O�?bw�����u�������������G\����[���������������?�l������������	e����<�{c�?����/����R��O���w��}����e{��^����no�/W�����^�5��?��o)��[n?��.b\��n��p�.������-U������Xv	����-q��w9����wXn�r��;�w���������K�����U�>s�7d��%���������^���!-�A�d?jW��V�������v�j�B�}j*2��=�
��������a���T��w������������&��b��_�8P���vP�U}�_�� �X�7���ex��_�_ydLu��4����g����$Q�0�kF�/(1F~����p��ZE���j��T�~*(�"FA��WPj���i��V���9U?�.7����nGQ�z�4��K����Hg5X�w����J8\6��>i�����i��":������*}�4HA|���m(pwD��h�������N���O�(j������^�E�^������B���{h
=_S���MPP?�������`a|Q
��L^}��'p�0��u�4�����������"oQ�]�]��Z�g�/=(<l�[
�[lW)Ot���T��=�����]�b�Y���2 ���������Cl��-7��Hq�F��3;q���i��!�����`����;�g�59�z��A?���&�_�/�E�g=�����3(�O.#/y��g�����(�.�4��]������h=��
dE���z3�z�K�I�i���[��LX�m=�.�������<�-��������@7,`}�%H�v��O�EW��h����[IM.�'�;1Z1"J0+�����y���S���;1�*�O���H��m�86N����h>���r�&_��V6�
X�|��k��Z�������Q*h}���u�,�`V������RA�����c�^G��8��y|Yd[o66�����c-���F�i��w�J��	�����ceqN0���Q�b[�����u������'��������6�����cm�j}�Z���0�5��W��x�
c_���h��N���}M0����k�����/m��|�}m8���w�c_���c�3*��T���6���#��W����>��^�r���������
�gLU�\�]{�����~'&EI����2�o����dybR4@�#�����j���iG�i�QH������`!�<1+��F=��~XM�~S0�U'fE3��d�l>�K���N��8qt����;�\��A�?��>�~���?}�T*�1�-��W����~��r_+���~'�E���G�27%�1�m��wb��1�mF��|�n����[��'������C������=6��~F�E���N�9�?A�����c+��{��[��'h}���|l%��`~9�V��_0���e[��W�/��oc�����w^����F�Y���f�����>/���������~c*h}���~l
��1�4� g��Z��&���?������_��K������y���1����/w���@A������g�3�ff�����G��������_f�e��p�;1�`�`~9���-�AV��{�~FY���62�������{L~��������7�_sb�11�Mz��ssW3��������7��/��73�������{,�������'�+�����:7��2����wb��2��z��rs0'h}���|l��Q���~���p�;-����#D���7�]��7�\���;-��
w?b��Y9�y����s��!�;-�� �`?�n���#������B�kO�?.'��d��Y����������~lE��|��:��*��*��������*=��y��8��:�����"������0����wZ�q������/s�q�������i��V����r?�Z�?o������c+:����y��8��.�NL?:�����=�_�'�=�_o<�r��������������_��>��c����;1��=�������o�����cd���������`��N�?&��I�m^�����o
�����cf������~3���'���l����������������������]����o	������o5�_��ce�[�����cc�[���;����p�;/�p��f����W �	Z�~���@����/�����i�`����?�C����2���!�	Z�~����h?=�uy��p�����y�����b�������`����?>��h��������p�;/�p5�_m��������p�;/�p
�_m�����k��p�;/�p-�_c�����k��p�;/�p-�_k��������p�;1���:#���?:��.�N�?z��N�}��s�����pb�10��z��s���?o���+%w�<�kC��A��}�3<2�x(�k��!p�C`��	32��x(�k��p4"`���8#��$��f@o������pf�������7��o��,�}sX�r����E�}Cn�`a�[������2�-z�r�+c��~�3�����/���1�m��w(��l>����}�o��h.��-A�j�����w���/3wP��-~W�����;J��~N��7d�;J��~_���;/�(���[T�9]
�X�[���U��bWd~<�"���
x^�QV���]���\��U8��~\�X�L����f��1���lk+f~B�
c`���� e��X10�#�l�p</	)[��������c`����!e��Y10�;�c��1��J���;+�~H���}0[���c`o���C8��1p��ck#�1p0b`�)0[92�xl1b\����3� ��a�1��Ldb������p<1�'+��Df��9O�Df������3��1p��3��1p�b`�Lda\�1��Lde\��;Y�p<1�W+��D6��-��!�l@������3��`��1��"���
�@��0�*��@����L�r5
h��2s&R9�@����L�*�f���HU"
\���e"U�(�5f�D�����x^&RU���3g"U�X�c�y�HU3VV���T5c`���e"U�X[10s&R5��M8���T
c`c����H�26�x^&R����3g"U��c����q
�1�V���t��]0�I��=c`g��*Z&R�_�_�c��1��R���|V0�
x�����~�������|W����������P��������7���,������r@~Y4�l��Y�����������a�BLU�����������b��\,������-��%8������� �����3e#����P;����K�/�����c�M0+��F����p�������������������z��P(�����
�}���/a��~�/���r�k�8�~^�Y��{���~�\�68��������+����[�T^�O���!��L0+������Z�~l1����!��������O��	MR�v�K��;�������l��
vE[(��7	����o)6j�����W��/g�x�.��*e�����W�����_�l���Y�����G���!"����h��^�!Z�~9�!@,��!�&�%�������9�!@dS�`>+"8��u�'��B����X=y��W�;��~9�!Bla��x���q����_�lG�q�F���;����_\H|l�dd���*���#����i.��(�~:Y��x���o���q�W��<�u%�7���:Tc�o������_���;����_�sl�d\����f�~��1�j����wb�1T��^�I?��@	Z�~'���A�����#7�?������q�72�
67��11�������q�71����#�F���c�1��c%��of��-}����;��������F���c�1��G��$;��6�:��xl�d\�q�[m�1f���o������oe����G��v
Z�~'�+�ol������n�?�`�ql�d\�m�?6=����l�?�`�ql�dT�5��M�?r�?������w^��P�	����W�~A5����q������~n�`����y�G�����=���CE��P�c%#��Ac�n����������q�WA ���#w���<A��������O���h��~5�����y�G��O�|����?h����6JF������L������������q��������}����o�����~:�o��N�u���o�����`�/�F��������m��k���`V���iz��������A�r~���i@��6�v�c+%#`c���>��m����6J�5�A�4��e3hnNL?�������^�&�:��}���zAs�^��6�^���������o'�^�����'f�m�^�x;�v����M�t81�`/hc��f�����{A����6F/h~���[���pb�����D����i������������u����l�C������F�;UpkF�L����|����<�9<Tr��}��� ������W�4��B}`�@���/�?��<�U ��r'Jpx�
Z��D��c����`�gpuA�}�k�8��M�����h�P
<_N���D���@NL����F����^�q����R���3	�,A��(TU��?
e���4@�V�=��+[�y7_�����Lf�&	���l�������<��u<���E���|����3K|t�M����7���[�o��������������]�����������?������Z~�
~G��7-���i���|l���w��������?���_~���?���?��?OL�����������/�/�)-~
_����cg���X��F[�T-M�#}o�����P�Q8s]=������hDy��
.x������Cw��	��
JA,��~����������������p���^G�s=�vo0����R��U�]%�z�\�C��W��{p�_N�����������2T]��������?��_~���#������Z��?e�EO��" N
!�ecS����\)w�P����G{�>"��h�H4�
�����`4:%+�{^	D*�-�d��"^�@Dx����/�eQ�De���eO���?`�)����=L_�@�l��Z RS�h����c�F3�.�����x��M��R�+/Z ":P~WD�8���P4�N���='}���@�����S.��)�<Z D����'�on����Z�ge�Q��^#h�$+F�W���^-R��"^�@xUI���QW�6e ��/�j������������*(��S}���a����uG'y��"���E/"�kK�{���/"tNU�@����h��"^�@Dx]A��|uu��D���D?���{�r-���`B46	De!�Am��8"�k��qz ������o��o�@Dt<(o�����'�e��@���O��������(��+s
v��!DD����'��@����"��x�Fu����"��Q��I "V��o��M 2���=��s���,xq�����d$;uu��jVI�E����>zs��33g D���I�6�GD�jc����Qk�
DW��{�a6ND�
���W��.R ":d�WD�8���6o��".IDR����jJ��{]�X��o��*g ���`��������wQ�s�&�%�Fp����X;������o�@Dt S��,xq��9)x���%}5��^��p��{�����g�B�H�#��^?���*�q�D�F��T�'���{|����R�D"��)s��h����F�D������;
�K�$������)o��YxS����W&g�p��HMd����&\�L����}�HD�|�o���D���j�����k�=x|�n��a�E�%�De�I����{M�T��o|m��;9P;���h�E��0��pW\��}�����+>�
A���u&�+��_�E7\�>�XK�Z��>����b�yu���]�Sx���6�4�����%����ap�:����'x��H�C�<&�������'o���(����L��#l����^i<���m�E����w!����[�G������~s�o����9'�F�7v6g�Az8��m��}T���G�������o�����;�}�E��3x����Z�g<����j�6��$�*��O9n�#��Zu(�m>����z$v���O9n�6�Ugb���C�v	�:����r��]����g��w����/`�_�M�~
��������tL����dS���<��P?}dh&��a0���f����?���G�lz�HpN����B������k2v���,R�ps�Y�oTY#�5���R�O�"Vp���k���C�c�p�-[s�5�)^+�G�@g�S�*�`~�S���;eg��B��@p��w;�,a�79�s�x��'vM�=���DQ�_�\���w���t��������q��:;�w�K�l����`V��~�"�'�++�����1�\��zBA�&��X�:���u]�cRZM����b
���]�iNq]����~�k��gKB/f
�6[�>o`mxLj�6��9�W�jo����o�C]r�9��-���������CoX�����=�*':"�����b�����<pH�f��}U'<y�F�{��X{0B��FI������T��������d��}�iN���^��~����������y2��m2+��.�x��GKw�#S��;)��������������8���c�������-�	
�����c��[u����p�Z+`��.������v�1�u_4����#�6�g��F~�N�b�ZZH�,��fk�q���zP��{a�1�2���q=�]�+eY��}�i��WM����#�g�g_)�;�cf�{:��gc�L~Go$(�a���O�2����~��������^�	������o����}�����>��������.�O{0���/��_�`X�^�$_Z36/�����F/�G�	������b
&���3ag8Y(�]��PX���4��{�4Q��M�?���qQ��Q0���#-�x`�o������7b5�z�)�������W��cj��
���W�>S>Kc=L;X}��+v���r�O2j�G
�
^���i��h�/���J{�;�z�;-�����r���������r3u�,nT�Se����4�6�M3����S������}���	���//���4�z?Fs���s���~�4>^Ewk������[��0Ck�L������,m
������/��������f6��|��e D������Aj\�����
�+u_����Q���{�X�!�z�~���jq����F�GDCx��
�g�F�9���j���x-�nX�^-�O�:5��h��<�k�����c�:GK�s���1��5�E`���9Q��5G3����� ���aR��0�1�;K�%>rxA�}����������7	P�����?k�������&��9�uI�����'���G��'e?�MEp��s]���b��}�c��5)���s)��=���r����B�e��	��������98�e�!�W�|T�rl�*�66����KFsd��nl|AN��/��q{}:M�f�#
���m#6�f�a�1��8Jv��T��<�Z�zSco.��G�cT��b��1������0;�?���5�!�K3���#�p���
A�T-	h��J��4|y�@E����1�4FzB������<=V+_A���%yW����d3^@���8-��,��2]+������QO�r������1N�RAlc��<���9�or�7����M�����Z*�[���#b�T#��m��v�Iy��b�)� ����a�[*�m$6]c��[*�Z����,�����RvS�<�
H���=o����*R7�����Wf��}7E�����*�iJc<�a����2}{�x;L;������~k�������������.E���	��CF�c�Xm����,�X}<��3�to$t"V�9���4��<���QH�q����[~acK��?�����/���Y{�9z����=�cMS�d��n�k�Z���bg��f�Y�x��W�u�]�vO\��<��_l���z�������OE��V]JA��5�W���+e�@�� ���?�}�����MK���r�z;f@�HKD�����	����������<�� �����\p�M���Jp3|���,<b�
��������q��mi�q�������Sl�F>�a��
�Q0[�<}?��'���5$�������*�n�������C�l�f�����	�v�	^�YKn��i�M��`0o�4|zg-�m��Ge	���O��u�����>YI��E���g���L�K���
;k����h[��?|���w����&;�g���5�.�.[.~��@����3j��H����UM��8�������qa�6&����`k���o��P�$E�Z�qY����j�M>�CG7����}�N�*�"����kZ�q�a���1]�����+
����3�(��p2�[�bWL=���$�)v��%�f��`1�:��(���*��)�7-:�(
KG�zbl����%��J��I-�"6�o�m��6��E�FtS��p�(
`k��4F�V��#IS���u����>iEQ@�TDg���1�}+�Ox5�Y��"�"�������:�3^1&�(�(�k��uo��i����{��c���4��#�dq�1��o�7H� ���~��`���;S�vP�������{#���F��������=/K�fl:I������H�F�L�-�[��=�b��o���8�(���r�~�E����a�����2%�j�q#��'k����F�
�#��|c��8j�cz��R#\5
�19�i�|�HR-�>�&Z����g��q����{�(2��y��	��O��{��4�������.q�
^���/�W�(���N����Y5N��v	�J�Y����C�����&�CQ&<���W�^����4d��N��Z��Z������I����<C6-�O�Q51E���Y�3���5-Ow���_y�a�
?}F]X���lb�*��W�����u���<����z���KO�.&��4;��V������j�������h]?^7���������(s��1������+Ct|�������8�������P�q����H���~�cL�����D���[fx����6"��������Q)�O8�����qd�|,5A��L��8����`���I����!6T�Jc����S�������<@������UI7F��s5�Dk��*�>�$� <����*�1�������C�*�=Jc��D�j��|��x�U���[��^�x�(Z(���n�Z��c���O����5�Bt��%������O�����x*����;��������m������:�����:)�W
�����:9�W*�}���H�j���<�������@��]�����L�No��x��������cF�$�c��6�
W�~�q��h�����������-��k���t���9��������K����RW���o&<=���F]3�T��zgF�$���m&x5�e�0�z :�����i���19���a�MIt�J���0�4�����d�1�Dt�b��$�kU�U�&O%�m[>UZ��b��4��S�5�*���$_^���!.0���1^W��T��N%1�W3^nJ��f����c'1^_�5�0{��C�j���a�4YC�q��U�a{�%oNrap�^m(1N`U>U�Y{��nNc<>U������-x5���0F�Q_At���T��RY{���Ae4�*�k�o�Se��*�3��O��R_d��&>U&��b
�MR���T���J~��L�f��b���|y�k���DK`"��d���f�$�[X����y'1�L����[�E�0��VD7�18���Q��b����F�m�2��o�W�X�nY�cH���n����j�[���gP�m|����:z�]����~G�l\GoP(	\����4��k
�%��B���x�
x��;|�:���N��9����8�����P&���*��7�����WB.��XX�E����+����}G�5M��{��I]�bi������K�,��=��^qt��pD���~Pd?�~��?x7G�������HM�8�R����ewt���Fk�v��hJ=�r756
/k:o�x�XdG7�Y��mOt�]�+�N��Z^,�n�"�������o{�[�����{������"��wt���{����

��W��k8����������;���r3����^qtnf�����s�::7��Yn!�������������e0�����h�C�{:zDm�1�"Cvfl��2��2�cl��2����fjhJ=��3c/��P���'�,���'z�hJ=��3c3/����2�2&r���e���D/%Mi%0��1�6��0&�����y���2;7��j16�:g}�I<��nY��=��*�5Og'�6�-��P��oC!<^.[��gz�"P�k�����=������_�t[����-=�r����<��k]ISZ���L��������
�y:7?�rHkl��������h�����%D�����Vr���FS{�)fi<�� ��==]�������$��x�T����Y[�r��h!��#R�?SL����K�dKdO7�\�7�DH��S(���&�x�������X�<�����Lsj����H�����1��YS��x����o{�9�C�?CM$�t������9i9�C����{GSZiLn���y��zSI�������o��LM��:�$�x���mkYO�\��m�������SO�����`���D�����e���L�h2�o�E�N�[F����7g8��n�>���-���������$����<��21=�f�=[����?Q���j$D+��g����Ub���&���
��C�������\@�y���W���u��!+��&����;����Z+�D�{�h�+O4 7��0Zk�A�x����'aTl����{I84�^S��0�����&�4\��%pc�����b+~����?����G�`�?Ih
�a\vx��&��S���Y3�p�4���������wn��k?���P��z�P��/J�1����5�U�o_�-����}��r��[
�'&���\�|T��7��zrY��+xw��uO7����Mc_&���R��<]��j&��^s��^\WO���Fz9��]�����U�g
�Lc��/���H=�m���5#x5��(5E���z�Z��Z��zKM���Q�i��'��=��Je=^q�K�����z+����O�L!��W�j���a����C�j'��������^�j\�C��x�M�����ck��<B�C0�x�{�n����
G��n�
fT�M�_��6�C-D�j���M�J�Y��r�U4������$�sH����"����rg�!&�"���
1Y�Q��I�T�x4Y
����xF����cL^9�Q��fs?u�������fx����7���[�o���������"9��j�O���?����_��p��:W�?1��������?~����_q��?�Y����W0������w��o>�EY�w������E�����u�]�������o?}��|�o�����~���?|��������SS�����?����>�c��OO����?�����O�����?��_~�����k�":�����S)��������S�*g?�����s�*�V9`}�4����7��+8l������\#`��O��,�_�_��gb�������ab�aG��u'f�YkS
��8���������>��S��x����:�c���
y�/=p���xb����aC�!I_�z�xN&���4��@��c������Yq�1�0l2
X��1ua��������V�'��"��Y��a�AYt�4�1^xNCdlQM�1��W6����xD���c�=z��c��"}12��Lp���j2*
F������1�	����XSZ�M�?�������_�c��)c���A�r�\��z�����v��A�Di&�?8��KPYe�(��=t��U�Ic��#��/���]fn��
��1�Hx��f^�/�k$�������#QYe�(��=t*�Q��R�D���!x����[�4�q������X�u>x^�q/aj��$c�}e��,X���=���1�?���:�����Q�&`��H�z:�2#32�
�x��\�}ymF:0�7����1��Kb��t�9Z�k%2���/���0��R|���`��sS�JK��e���n"�q��������o�Is��z����H�:��C�����CFS�j]Yo������(C���,D���h2G�y���2��4�0q==��*r�y�\ul�������������ZT�c����?�;S"O��c�����a�EE������73�L��R'W��1���Q�������=O��1�.�xsJ�PD���e>�����N�y:�D���e�N�4�������G�w��,�*�1r``O��x_����9cpY����aE����>=g.��y:�m�5��
�J�}���*���^�#�T��j;Q_����9W���{@�#��7/��:f�u�����N\�H����82'��.����O�dC��YL�jEZ.���n!��`'�b��nE���3������W��=�<.b�KZ����dN�jq�-=�:�y�O���s��{�N������`��Kg!�����//i=�Z��a}��el�/����6�
��������]U������*������u1�R���]vU�]�r���#������R3����K��������m�����f�f�f����An�(�S�mw���'��^�"(���O�v��RF�" #Ri����I����>�F�5��j��F��#5�3�=�q���LZD1Y�l����Q��p�3��t���@�C�l�-�Y����Z���2��,�Y�E�D	A�H�@�������z����E�g����\[6���Z'q����2�e�X;�����#�_���k�5���������q���6ri�Z���}���i#����C�z����4I�����R������D��%�=��W��B�~�Q��p�H��1���Eh����I��
f���o�xN|��K`��|��/}'���M��xOc��t�v�U�JI��4�*4�J���������`��x��J�Ei�%���y�����Z�&�*A�"}�>�����D	��)"�J�gh4Y����Fe�B}��>�xn�O��IU�=�������e�B}�1�T*w����x�O\���&k�����L_�O<�Z�_�8�$��\���&k����4[�/�'�K#�F?������8C�7���4��L_�����Q����o����g������w������g���������]W����S�7�X��S���gcU_!�Y�Gc~�����������;t���3����'���h;3?�#�|�t�
���0R�6�..�C����)�&\�R��TpQ��	���e�cK�U%
)��U28RY*���+?�Y���8����`������m��Y����\��t�����!�_��j�6�fX��X�8i������y�����m�5�^�QA�:��kl��ow��`+�I[q���W������8����o�U����P�6��*���1�4'W~���O�tJ���J��+����<�S,�����@?���~����'��CZh��r�q�����oz�|I��p-��h$46"�d���@�x�����`-d�����q��~w!�qJ��7�x�5#vO��'n���j��2����<��$psN��j��e����_�3���J9|=U��)�&�y3��#cVb�draP�����	��g��n�������d����UT���dW���������[��g�r���P���;�������l��X��������7�zh[� ?�a�(k;�����2G�	$��\T��m<u�@����]z�k�-����)����g����*/�.�R�%1�H:���������b�I'�qJyI�\����������d��\��[��u��~�^�xuI�h�Y;���e����0e-z~��
��������nZ���U��m�1�4B�N�/'�4F��y�����W1�&��m��E
����i<���h�/X�������t�����B#��e�cp��wsQ�W]�����
������������K��9�����X���C�k�V,r$Z
w�+�D�-�$?��1 �/��>&��%:5����\k�Li��M������p�i��
��v���r��A��q�������@+.9������jxI��k���0D�&V
/1����<J�g�^�5�$\�^�
��z�&�k�*�^�*�����������+!�Q���85����������W,gz��WY�W�_��a��n\���g�:0M�{�
��Y�4�&�9U�������Zt�"��D��z�Hc=>���Fz��?r�|�������z"�.���)�^Y�z�����:��v�v����-��_q������S~��e�l���N���%���Z)c�/*c����"��S�?����U�.�.�����+p�.4����W��a�X����X �G3qH+l��M06}	�^U:?T��m���c��:e���7_,�&���������W��de�n�w�&��(��[?Z���x���q��B��S-cf�+!>��2���S������p3}u�e�/4��&�}�@�����6��-�&������Xe���T�z@�s+�t����?���|�2l�1��&��jK�a��{�a���tO��#Y}FQ3`�0`��:N��M<�
W�����������I�W
�M0��V�����^J��0����J�;�����_�K���x+���r�^������~�Q��+cG9�N��{�S`��h�^Y\�)��;��z�8��%�p�sgH�<�'��<  ��|B�����p^�4�P��'��y�@k��S����[iJ��;����eE���]�TW3x���K]���R���P�K������8�;����f�����W�+qc���x5�����EQssU���j��7��n,5_��(�}���sID����He|��ikf^��E;���pAj�������S�G8\���	�(e|���`����,4��TI�H�*�[�������\�������;�����
R����MFS���;@+>����4^���O��V�����N���'�{�P������^��x�z4J�D�>���#�B�}\=X�T~-[j���j��8���������������
���o�'m^'m�C��������y�NU\�[U~5��m�y����SUq�~p�i:��"5��s����4`�[2�I��Q>VN�g�p�?��!Wh��U8*I�A.d�����Lj��������(d�}��8��6�inN))B����1�	������p�,��Uq��5������������Vz�������_��d�����O �������?���?������������_������?��������5w�����"�1��-3Z�F��t��v���$s�G��c���]p�jE�+���
	��k��>[���,�iE�j�{��0p�k���B�����l]V�M4����,$���"���mI���}���BB��a�RH'�"�xx�6^�")��y���g����vk�U(�����R�6��&�������g^�x�ty-��1�@:��tjD�����_�u�'F$2�J:Q)������g^�x�uyI�M�b&��7��UJu.�S�
���J�Q�}��K�"�b��0@= �3�C��p�W�����2/��gdGw�%���	yv����h��0�9��/��gdG����G���u4�<�^I�$Evt�Vw��y4G����G�u4�<�M����^w���r��y4G�9M����2�u���2
}�����YFg���<��?v�4HGO,����o2!#�t �������r��X&�7���V�N<F��#�\��w����"����n�$����X�	u������I�YH��
/J=:�p�6�����A��k���E*4q��	��P�}.J=:�Z�{�M���q����n��?����	�o�����=�_g���,�VZ��T�
Y��=��d�3�2����n$��y�~M���������>�Nc���^
������x��1��%��������nc��V����?�������wG���Yu"�/YQ��Zi�6/j���NQ.���)�_?�����v�����pG���)���������6�J��~����
Z�	8V�&g�&�Y�W�1f�o�p3Z����q��7p<��y1 +{[
�yMM����q���"@�����
^��M;��-l�|�U�"�^H�E\���46p��*?���pCV.�����x�P�c��X�C����z%����*�]HL������~$G*$&$E���)$��I���P�R|PS2��To���v��]�V�����;]$�B:��PB%1a��)������T�����x�������kJ��T�\Us�����z��&IB��D������ &$�/��8"aPY���m�C� �"����f��y�p��u��:�����s���B0�c���7x����w
3?����x�;���?��
+O1������4�^hI�p����O1�q/����q������eP�Q����1�����������@"G�,��cxt ����Y���1lX��3x�����7t,������a���2�Ub��������c3�,��)7�j$7x�,�Gd�������6T�����NVu��2�b�n�j�I �
s��()������j��?��!�j��L�Le@���g@�Sd��C�;�h���U������N]��T�n���1�'�bT�n���:^T#,���3��BR�"J����X\���c��U�<�~��U�d��@��<�|����QL,d�s�*�
�-����T�M9���Zu�x�*�
r��{���?�����*�2�^ej���������#+K�����*S�d�Uj��kj�og�Kw-����n~t_�����v=i��UO��<L,w����,m��I��V���`e��Ty}5���h��%�������(�����������1R=)�F�5�I��5����C&O����z������	D�����AG�Vq��Qhr�[�N=)�pz0Z����O�zR��(���hroXq�4���b
Z�WO� ���o��n67��X����&B��hJ�!N=)�j�����i�[t�zR�!gg�^���d�'��w���=����oo2�g����O��.���7x�"Z�X�0�t��@,����I���k�K��(%���)F�<?�x<��9��x)��a%��/��%����x�TQ��W��!k���T�z����s���m�e����xL�N�_�TI�$�c8��c�'D[��L���,�!����X�t��G���c��\��s���Qx�}F�%N��������^��\T�]��r\O/��,j�Drq�
�1�q�1+oJ��_Tg�4�^1��x��pH���W��?������=�
/�����x��pH��9Cp1�cz:/hJ�H�N�i<�#��3�I<�#��1=]d4��F���i<��}��<����x.s��4�����������/'sY���=}��\���k�D���r��+��R������u(�����-
�u�B�����@�+�'�����\$�H�}512O9��R���cU�m�^vx���6��U��D��+�E3��;K��pM��,�p�m
A�`�6"��x�Q�%9N����p�c�����@8�E�!#���#�����xM)�;�I��)�(i='A�m
d�����9&�t���R���l��m
�++ZO��B���Z����>��M�x��{�b��Z1^8m
e�6���{�:����*��,+�;�)DjiP��k�o����m��Y.�&�@��h��4T��4�Wph>r:�-�������+��R�����>���-�����c{���qB����*�z�����dLV��
��!�Of��q�tBC9�E�����%m�%�u���e<p�������x�r����X���@��p��k�����2�������u2����R��ij R���]�!r$��91����E���@8T���������p�D%~�n2�55�Y�f��?4�����L��M�K����W���W���l��Y��5���*�B�F�t+������W`�6^�x���I!�����U�o"��.�.U�x��4\�x������xmw�x%:������}��_���~{����	��;������������~z���i�������?��l������?}����{@���?���'^����6
�FH���v��������wk��6��S
]�
������� ��[����\����l������������2��|w]N<?U�_�qm�t���v���Cu�5��30�v�$,V���K����"���R�0"��G��@��`
�R�W��Ti<=��3���E,^���3�p��j��<���Z�E�����2����
o�C�x�i�FQ
��hi<=1����:}��\��W����y:}s���4�'�#�xzfp�4w������K4O����e�o-���L����e���<������1�cpY����H?�x+���vM�x�2x������+����v2�$��)\���|�5}b���>�}�������w��=}�
J����\���g���n���_�m.,R8����������\>r����g������1������/���UW�c���m1�vq��]O@�&"������z
6`���cv���@q
x���W�1{��X����7F�b����@F��Y��s��b?���5�����,���B���GIX��:g�7��D"����?�<�����~���0�k@��?�F6�DD!W)�(���3�q}�ol;���:�zfv�E�#N�,�f��9U	�p��x��P9�0��^t.�A}�e������<�������U���uq*�G�B�q��&\n�U(f��Pr}6�s*�������E��M���lU�NB����QM�]g�g�;�t�y�u���i�*���IW�>[�!&��C��^B�]�Hx
�'J���\����x�������z�&;��".�R�z�?`���xHW��v��k;q���7�����������_��g��w�v�:��NNH�����h|��u/���^gV��@9~�����v�������+r\��g�|�]��`�@?���
~���������>F4���7 ���}�t��j!�(��"u��,w��-Yq�0xG�0��.��N�c^�W����gW9mw�����~�2����Q�q]��/�����	���=�2��Rj�Af�e�p����x�VV-c��x5l�p��2�v��d���l��>���<J<�p7Z�1&u<�F��R���db��#�J���Y!�h���<nL)��TF(R?�&<��Ou8��=��CF�h=���4�CF�xo�����#���m���}��f����o*���p5�f�������������v<<�B�v��n)��������������E���1�-���V�"��x(X�,�����P&�V��Zqnm+ku�[��,�*�E�n�k�%�g^��(}����&;P�Y��&S�N��
<L�:�>!����P�:���9*r!����Y���Ug^���;����jS����LY(������[iJ!!����xS�����t�:���PB�5��K�Rt��v�$��\��>�5�=�J�v�$��\*_m���'I<]3�T�a�t�*���(��k��/�/��IO3���a�tS��B�c�[V����E���7���F.+j��1�4�e:q���gk�tw��bOv���	�Y.�F����W'�s�����H��i0���5��;J��3��;[Y��D�^T��BD1~��W��,�o�M����p_���j�.C���=��y����	k����Y0R�s����)��8-g�C�5�'����A��4���
��s��K�����g^�(�~c�UQ�#��\w1��G6�u%���)�4��L�3����
@��O�N�D�6i����TE�������i���t_{��e����x�_�
P�M�K���*jbc�������
^��A��>�~���V��
Vn�
�����@~�o���N��u��������U�{������X�����,q���x,��cq����t�����@�b��X��n��/���y*����~����*�����y�
�qO�����?
����6?M+�"����f������dH��u<24�9�B(���U!��w���][U��R�N��w���V�@��������2N�
�XH��B��v7��ZU���U���;t<�_T�_o2�^L��"i�:{{�z�C��
����{�)�k�������_#%�A��>9�H��x���:e���d���z�S�il7��v�hc������	'�?��+5�����cKc��p�Nc�5[��d�������Yn�F{�����i�q�%.�v#������]��?
}�4k�e k��L�
w�I�}8c��v3��������Z�r�Dk��,�1L8�+�a�l�:�ul�%.�v+��^��������5���@�X��l����:}�����6n��+����J�������v�U���.��]�qC�r��H?~x����&��"�v#j/�.^���D��e�k/���#�(�:����Q��xo��{�+&^����g��[��_��xRa�b�eRg����3�(�Fi�Im��n�eVg�������:��w�[�7��	����:��w��7��	qv�e���v�{u@��0�b�e��(���+�(jZ���3n)�8��|�3�Q��{��;���H<qF�u����~�����c��cC�30�=%u90�<"l`�����G8L��?�bS
~.�,��_��c�j�>��i0i>�
��(�5������	'J��Q�)F>k�S���h���Q<j�;"������n����^'T�"g\��Q�p���z36��U����c�l|�$U8����0p6�rp��k��"��W������P��:��=L�E�p�[M�`��p~��t|�4\�t;����'��������[H't�}���T3����2�c���m�~$�j���tCF:Q���m��F{�;�"&�?��_mF��c���ucA:?�����	�d�(���#��G���%����	�#����7.�c��o��b���{���d������	6��Q"���D�[�w~�9l�h�&fn'b������t��`��W0� ��n'b�����i\&�	������Y���V3��|u+/���%.w����t�
[
��3�p�`�R(�f�����}[�9IO��!l��d��(�(��2x�x�����)����~�rTa�����_�=��\j���tQ��B�@��&�t��,��<�~���F3�cz��iJ?���r�4�.\���t��.�cp)���i6�����s �W1���|O�E�x��i���D�~^�����E��������99�x��iN������L?x��=����������=5�&��{��%���Ki�4�fp&���K�iV��1=���'y���$�n\Z��?W�4��$�=��;$>'5R�T�&��;�N�>�YO�.�t�5��t���Z��sd=�K/�>��D�fp�������)�5F�I����ePc��������vM�%M)�1b�N"O�.�����{dp���i������sd���z�C{�x�]��{LO�M)�1��92���3��$��\��Cxz�)�5��=G�0���
=�9��Y�a������IUpT���V��I��4�^\�M�'+ju����9�9cpY����sds��b������x��=O��#���n�^�{�[�����������yz���#��j���/sQ�z�^OVtF���z��\ ��j�a�����.3Zo���e������;�(37�K�_{2��p/d<��{���������������8n��"K^�"������p�JIV��c��/zB�&��Xr,^�=�>�9M��z���R`������,�'C�=��������zqO�hi5^��{WY.%N��{PO/4�hq����x�*iJ1�b���R1�T�T�x��R�yz���BY�E�J=<!�uOsZ�r!,u4O���^��1�,����/�.dQO7.Mv�5�����=O��W\�FH��2�$�n\���k�E���{��;��P��x=A������,zOG�t�*�E����p�4��\:��,���x�gp�����U���A��W\z�^���2�4�fp����M������[8��x�7��3'�aZ�;�{��E��Vc��x�s�5�[�%�4�p/�a�S�)�)E�������$�S��1��'����������?U��K����e��y`L�i��1�cz��h1�&W�xzapit[NOs"������1�&W��xzepYTa���i
(�1=���{rJ�����.�*���>�f.�a�S�U��yz���!��3m9I<���a�S�U��yz���#��3m9I<]���a�S�U�����#[�u�������+�w�����iJ�������t��R����3'k��R�?u�J�R\c��sdk��R�����t��R�?u��R\c���4��\j1�P�x�fp����6M)�1�k��
�K�������w?}��������*����1�4����0��/������}��>�����������3Q�����;�W^O��S}|d���<���b�2���Ic~<w�I#�Q
H��u�/�w�������CV,#Z��(9�
�k�RX�Dw}������Db������4��3�����0�R����v�$���C����0����F���x�i����7�FXE�"F�����Lc�n�f��aT���?3?����%�g�7���K �<f��<���/n�Q
X��eg��[�����7�F��h�~%�H��v�4VJ��T�yb#�j����8���}/&':�
���0�1���xs�C�����o��������|b#�k��%�8R��������?����[Ymq>d�X�����3���d
����W����:�!��p�����)O,86�T6t�w2�Y@)_L��nN��;�,OYeA���wOW�OcP�������������{N�.�3���`�3�f�E^����V�"(>��mV�0��L�!��Hx#�W���,��/�����M��b�J�����z�(�����\�}��TIc���S+7��,.^S�z"M#u&�X�i`�F��f�\��pv5^�9��r�Hx+���[�k���^�W#�*����t<o��&EPs�x<o����]/���T}���P��x.t���Q�3^W�Oo�����`���FwGi�h����g�>�4w�Ky*l}Tg����������� #�k����b����'�c���v�:L��&��p��k��������o3��Y�k��E6����Lr�V��4����k<h��q=��~o���������x�'����$1:���^�$�x:!������CW�x
|��?��y������?�����_scM����@�w���w�����E����w?�������_~��,�4o?���;?�{�Eg��������P\d�G~������Y��u��y[����w��_����������?���_��������������>�s�����?6���_����j}������/���������?���/���M����g����Z�SG����j#lTH��xs7��[��?o���v^G���|����_z^��+�h�����'"��_�O����o���_�v���-n�&g�}��X^T��9���y��0�����s�x'i���)���o��4���qo�	M�6;�1������y��b�[����a��D�F�&o�"]_���p��������u���g�m�O���x(�(�%v_�JG
������������
�QF{�u<rCTu]��c���q7���[
�j����;x�	h��eg]�:�{�,d�n[�#�����H��'$YZ��Y����,��fF�I�X|�����v�����?��!ok�7v�6|�9��GX��w��Y�v9��H�����K�:��uj���4;/����P�M������Hc;�9�z�����.,�t������	�C���z�g�4�[H��R��f���=%�8�$Y�%N��{���I����L��v+����e��vUE:!#��h���b$��B�O��L:q�S5��]�k[W3�U1G�F��u5.F]-�lmr��
7�ZK�YPQ�o��	Ag�cz��	�C��7���nx�i�������^h���Cq=�R��C����<�U������e���C�z����l}������K'�n���7x.]�!q=��4���%���1��j�Cr��
������y���^q�b�N�u�v�~�C�
.�����������\���'����~�����v����%0%����E�C�>J�$����������rq�RI�-�������)E.)�����������{LO�HV�Q.�����~�:`���:�:�c��Ng�]�tv��tn ����=+*��L&
�F?�?�/GgC�����Y����P\���U$���#����(*��#����#��})����2�����}��?!*���?3?��IT�tu��������D�6�� �S�!�mQ�
�B8�F$�b�
����hy�������.z�i��U�(m��I�@Q!�x�xmN�9�h���t�=���T���-������:�D�(�l����l�P0*Q��~�*,�y-{<����v�Gwn�h��={E����}����c>��g�o�(�L7y����W���F���/u!��P\�v�[�x1����������TT{u!�W����W>���]�dR�����/m������@��0N<���M(fE�^ O�b�����	p3Ju�� 'c���4������7t<.���t_"��.$�-<.�<.�:�Q�Z��h}�u����
.J���5�c�����\H�u<aF���7�����.$����f,��
n�.$@�5!}w��'J�0��h����D8l�F������������{�3]Q�n���4���XV��mS*��H����@'�fs����t��5\�v��"��0����9!R'
�z���}?�v8��g;��|w��0������I�](u�4�H�������+��v��Mb��$������X�e����;�\=�n"��j��J���J��,��F*���S�^2��Ss�t\OM)FHw�;i��#�����B��==��4�GM'L�L��2u�;i�72���*@�8��G��1==��:���>�4"��'�Q�P�zG����29"�����$z����4��\&�z�������e���)�m���cu���1�(�����=M��ivr���������0�,~b����j��V���#�\4��uV��,@�++�'�6D}~����bOO��UW�{���u�anQ�`�/6�5`_Q�76�N�T�t8���T���T�����<���]�Rm��u�h���R�M8���@]�d]iH�rY�T����x_��J�����<:-��Q�
�)#����|����x=O�oo~�T�x�&�g���6x�'Hc_-��\�z)��m�V��K��,z�v�^�R���8��p��P	[�����Q���]����|�(��v���2h]�S���������r��l�
$��g�|�u�>U�������k��'m�9C�e�s�1G'��)T{,���y�%"��:E���9_,�&�@����g`��$ �'u@WT��:���x�(�x8�v��m�Z�eMFQ���:.q�4\'k�/�HE��[��.��+�Tz�{�c*���������&�e#uk`HF*^Q6 )`�N�G�=?V���)�����)�'�-�h	�O�e�Y�f��?����yi����3��;@����B;U���t#�<�����2�����:�S��il�H<�b�y�\f�t3������
������v,1\���*w���;�*Q�<il�����(*��v3w�I\�T���HA:�fG����7�{Q�&���na�e�{����v�
����4��Ay��W}��V�����2��:6I/��
����e��^I�$����`T��|s�Szv��f9�7��k�+��{��;��f8���������3Z�@T��l��{�N��A<��U����E��B�h�
X��7x����>����nR���N��E<��8P�X9�����U����%�����a�D���?�=������o��/����K%�-E�V.�1�T*�$�JS��I����5�K%#��k�fp�4
��x�1x���������z�yT��uO�qgm4
��X���������k#���?z���C:����4������i �����z��������QdED����=��U����L��-��4V���%Q�z{@W\���q��=!�v�z{�x}�:3;u"`���!�B81�A�E��.rg�#�kC�[]!35qz�7����BhR���=uk�X6V.rg��.?���Vq�+d�&��qS:�z�H���<�������q������+T�#�#�������B�59�'�����dg�X��x�a;J���r:����(u��W��������|<7�v��nd;����H]Tb���o��EU_;#��_�������������
}n~E_�W\���m�OvQ�8���/�A�� �cr������CKNQ�!�#u`�����g}?�E���^�ir� k����y�>K�=#��T��3_��"�B�q����Z���Q<X���'^3D�j���"5Ru�g�c.��ET����g��Y)�<������H�����F���c5RrePY��A�c���p���"���i�"\O8qo]���nA:^����a!�t����������[u=�)R&�2���@f�������2�(��vH�����Q})lW������]����PWR>qH7��oU��2�l�O��'�]]���3���1�l�OTp'Y��D:?����D2�}�&:NC�j�5�Q3y��EL*�L�$w��YiJ����U���r�i��DV�
��t�6��0�/dYy���bt��<��0��#_�y]i<�M0e��5��v����3Zo:�����i����t�4��\z�+6/��#�����������,�4�\���������ep�4��X��~�e�&������2�������\���kz�iJ$�'��'����.����Z�N:���#�\�7W��y�t�,�����}e���������F,*^�'U�����j�AW��e����n��m"�q��oP
�S�M��p�����R�
8�I�i�
j��F�n���8U���*6��`_��<�I�yox�3�2�G����2������*"��b�n�y���S��Ib��9�H}���W�����7��Y�Y�_�8����U��\��>������e�m��2����~�p��2�/�eh��80��E����b�T�7�������)v}�\Eq��*���[�F5�6Z"'��F�N$dZ�B��|���o������X����y���L&+����������}�p��VLL�����	xl*C�e�p��j��������d�\�bb�1�\THm��W�~*~�e�.���0}���SL|�Wf%�w��8l�*&$���N1���}��8��e�b�R�)�.&&j��������`1qn�j��^�t���T0a1��-��������-:��v���������^= �Wt��opN�������4A��V1HBi
���$����N����H:q8T�qj)I����?�o�5l���Ba��xn6����Gj�}B���5k��No�U���?R�o����Dig�����=�_�w�B�{�,|��%���M?�t8���il7����oUS@����*E��*�KrF�xF�<�`;�Q*U�|`�����6}���e�O�%�]��P%�Zu�Lc��t�t@=�&�;y*!����U5�'��v���@:G�v��l�1\�v�6����g���Q��cE�3J+�(U�{E�w���"�t�T�4��r��3J�^f�����/���F$�@:��S��W�n!���������z�K�GN:�Q6�e�j;�(���T{�+��t���������}^%�#'�(������w��
��]�{E��F��_7��=7���p=�%K:F�������l<��v5+&�~7�l<�g���,����]�A������F����y���)m�d����0�����l��2���v����t~$S5!il��Mh������l�{���.#����:�^�2�ZV�h�+XW�/��;��6E<n0��`T�1Rg5�xV��St0O����r.�������x�H�&�t��6n���t^�����P��i<�#����4���&i���4�|�����F�Cp�������?7F��4�Y����^iJ�,[j�$�tY���`�~	{dOs
����%n-�IV���P���x�(�M�i*���.G�t��H-tl�P����!1�'
������B��h���y5x����7���V���:��k\�)��J�yZ��%�t���%
� ���-�Ks EQ�����=O+y�$�n\�'���x�cpi�^w�x3x��{��j�����<���HQ�}ES
E���q=�3��BQT=���t���HQ�CIS
���y�q==0��AW�%�e
.��E�:�4�P
�
��#���?�V�4�f�����SFS��� �����\&��w?�����TvMOM�_c��
�zzfp�D�k������\���kzF����������,&������=�0�,�a�4k:����92j1��������Tc����TS��VjLrFO3�(9�z��&�xz9��n2x��=O��#k2x�x�(�Nr�n���;���"e������59�M����T"D�t��z�Qw��ha����RN:��#���R�4�.3Z����
�����sdM��"����D�fp)������)�k!�/�x�bp��D�j3H�����
�(���uAS��B_&�t��R�m�)"��k��=������{��;G�4.RF�~%B�[uD����^iJ�S���$�n\��D6��Y��1�cz�E�I#TF���i:��o1	h�yu:�[���r1�����N�k�������}��������C#�^��v��R=���E��_�C#�B��R=������Dr P�$d�����=�����.x�J"vl2f���n���]�w���K���!�����DU�bj�cS.������:Z7�F�G����k�����H�BA��`�p7�a��8+����NV)g��J8~��UO�E�
��tw��}��i�Fm��������*^���?���Y�U�������������~����M���6����f���: ����P����x_x�l=Tv�wY�m ^��z��3��1��J���g��9#�a�6���"�-��R����E��
ZOh�<�E�Cz�x��K@}R��@�}��)��������!��q�W���p_x��l<T��w?��x3�'j�C�A��)h<�� ��x
�0����Bd�!Ki����[i<��"�m���2�x�����<]J��?���Y��x���������������@N������?���?����K�~��|���l�=����������� ?����?r
����
�����~�����~����>{�wc�nhd�"�@����/mot�:Y�5:���~��7W����������7���_��W|�b5��<]*5��t����������W�j}������?�W�����������=vZ~�7�YW���}a9��9��zI�����k-7�������/�6�&����Ko�az�c�
Hh��
�X�S4�����q�o��_������[I��8z"N#E�R�w<8������<k���D��8�����c	�f���8�%V���I]����:��8��z�,�2^J��8���1{��(������g����e�����'�q��6�\(��B�y���*bI���Z��-�����w[@�����'�B����kX'��M�l�3�����u�B$���
w�+lY���Ln������v���.s
&���z-m��E{�(�z5�%�(��4e����E	'#[����d,��E?[!�����r�)�lv����e��c�����t��g�OWx�7^��x����2~����pY��fWe�ET��W�[����;�W6}j���_�%9�����!�@��K�q�����(u�8<z��q4�7���2xgWV����ZQ�����m�%$���K�n�P�e�7<]|��''1
)�_���3���8����xP�2^�z�b[�$���Tv�"�n��n�VZ����O��	�������'�;�z��F���#����5�������	�=�<��R�����C���6�}�������������0���K�oo��f]1���|����~�����r��7��)���~���F�wO����M��p����y9,�)i��'�?5-S�"%�I�|��>����
pEA���m�������wrE�
�I����s��oo�+s�k�R�����D`�GY���5�!d���p� �4;k�����	v_�5�I%bI����Z������2�m�p�~B��7@6**������)"�}�v:���F���P�n�����E�f��}���[I�( �)���������Tz-���&�3*���d�����!�f�Od�o �H���K��3�*������OD�$��y��EV&Js���,4j�
:����tbS���~�-�U1FE�X?f������Ne��7������x��xkN:1[x�h�"
g������b�r�����[W�)A9qd~�x���5��bI����R)�7g�U�M����T<�RdE��t���G��J�������&��}�X���x�Y�1=]�4��6���I<] c�O��x�@41��zz�)���
O����)��q��<���1=����{�N�r<*�"�/O�i<���|�t4O3�?��~�a�c�V	~uH�i&�����<]��}y�B����4�K-����%����@e�dE���{�N_�N<�F���KVO�.�����nQda�������1����BjpF�=B�������;<������D�=�1�t�)T����4�K7vM�5M)������.��x��q��H����������i�}m�!�+�M����f�����]7�qY�1g���=���1�cS3�p��(��������G��?��!�����
8b����'q�=�nB���n�p���H}�DD�����-q���wH��pb�����w�w��HFdE�5�'*,"�S��xV��Q����������[
Z����������]9��W�����t�;Jd<��������z�U>����|�_��Qv?c�z+5�V�,/�)DX��C��*����~&�����uf���7t���g������C�5����d�0���<���]���~��Y6r�e]�����Wp���������������*��[�7_k!.�?�
'��bb>��������g���W���~V���U�dq���������O��}CFFk>"g���+M����A:�45r]��"5����o��>��K������E��-��%-)�Y���������A��v�hg�Z���z!�}!w(6��t�$!R1�h�U���	���v_�=���)o�q�����e���Y!p�.b@\*��T~�"t���y�u,r�q��7��h~�{����������C�C��	�n��U4a��yn�7[���h���Kk#��������v" O�]��������$�U�2N/�z���L����x�T`��q���D���Co���3^��q������/������i������j-���[��,"��Dk:��`f��Me�/��g^�x���IW�N����V�b�ja�X�+��z����=\��x�<�>^����;����r������g��Dg������,��1�N��t~9�'o�g��k��/G8��f�^��x|��x������g\�xj]$1T6������0�7�Ndw��s�����
#�H�3�q�7OUv�a�%7�r�K�3��$��UT1]�U-�*>��ULe��x��>�
#�xuF:%o���j�*�(��v�a�uO:���Y{���]���]<a��h���R�M�������"�\�.�
#��kxTi�C����6'�8�t�na�ky�i���Y���'.@��oy��NdU�����x"������w��t"��	������J�����3��M��}��+��^�t�n���H'�m���g=^	��3��o��p��G���7������<�${��C����G����A��@�$�yH�!��=`��z�������,�����y�o<���g��o�sUI������x�V-�i��p�*i�?���&WC9��o��y�=L�`)M�fr��7�e�'��t�����7$RC/A��	�[�"���.���fXo9jA}�����Bj�%���c��t�����+����9�`�.X�b���EhI����g�'

�x�@k������s�Ry:�@+�p�0^��_�U�?��=�x���"�)���Bn�I<]�a������.p�0��zz�)E����x�,iJ�
Q��4�w��R��]�%n��y���IdOW.����tOW.��f�����3x��j�$�t��R�,���x�fp���������+T9~"O3��JT,��2���z��y��k��{�N?��x.�x�+�����n\���k�E���{��;GV�.����������u�J��^q
����9��cp��3�<F<�K��T�8�0�t��5}n���1E���hO�.S�>�4�f���>����X�z���^�����CAS�����%��F�A����YE<F�!�l���s�R��T:i<=2��JY�%�xzd�q�P�����%��xO�x�x���L����e�9[2��)�b���wO��.JE#�x��(�{LO�h�*�FJ!��xzap�E�Vu?NG�j-.K���q=�����O���D�fpY�Nu?NG�������G��+��
�����2J�����q:�����e�9[2����z�yz�DY�!�����q:������9[2������lI�\���9���>�������Y ��EMS����2��������'e��b���tY���5�Pm�i<]2��BbB��R��������������1��1M������2�����K�vMSZ��=O��#+k%-20���-b���JS���{7���Z
�����������
�NJ�;R�
�$�n\��$h�I\O�.mq�5����O�
�$��\Z�0���t�1�t�a�t�V�R��)Tw"O3�tB���l��\�u�5�U��[]�%���o��������?���o�����������O��������������?��p�����?}����{�����������*�KT����{f������v���:���,��������z��	�$� �������|�+���y��c�J���R=�\L#o�|�+���W���T�����Y����[�g���������������C���������0��/������}��>y����������3Q�5o��o�����y�{�N0������NQD"����U������<�q�i���-�p/��L���+V�����1�g����Y1?��������h��Bo;���n�+��QT���%�m�r�	���"1���,��f���a�)'YoV���PN_\�/J���&Y5I	Wn������P�[w�������=�j���#A�*��*���_@�#�t��{�]�A��n�xox��|O#Y�L������p�3�nsq�F�������LQd��(+6^�\�=�J	=+��Y/���zSN���{Y@��zZ����^��<���D5��_��G�[i=5`�~%Md��%�'^����7���x=���N�m=$����(C*�N�_����\����/W��?��W����e��/������=�����d_��[����n`�10������������7.{��q6/�gn?������:��������������Y��u��U�7���w��_����������?���_��������������>�s�����?6���C����?W���/�~�����w��O���������oXbQ���dEa������jhXh;��m��.u�w���W�Xy�����;=_�+*"4��z�s��]�O����o����5��6I�<$o�Ukf�ezY#0�%E	����f�7�0:o�� Sf����I���+�'�F��%�h�6+'X�W8��n�t�6����5z}7��v�$S���#�����[�
�Kw(�*F�tJ��������E��/dNe2\��x�|U-��2��g4+����-���'�J���i��S����"�Br�������y`�)��
���;p#�G��j�~�����X/j���hCj�����>��������"�V����6�cw�[/�a��]�|�o��;��wk[�'���O���h�&p]8�@��j�f��Z�H�@����V�T����A����>!"��x3�V�J����q�n"�x���xKN<Q��A�����s��>����xxnE�_����h��tJ�#�$x��}+F��j�$�[���bb�'��wU�x�����.c�XU��{�v|k���v#�$�D:0����x���2�t�E��h��R����//���x=�)�(�H7��@*`-J:������/V��Y ����E��4����eNS���e@WU\G�x�7\���5��k����|O4x���%";��i���^::�l���i�u�BS����4�$��X*5*�j�Y�����:��]��6��I�0��'�\j�$qt�������|�5x��0�>��[��*%e�8�edic�������DGiG3���##@����f���x����)�&e��8�c`�D�$��)��{F�.�P�����&k����+������ML�=0��1gB�u����?J�d``�����W�
H��2|����Z��}Q�#w��f�x�g��5b_�����\�$U@:������
8�DT���Q5�G���C�!j�}(�8f����Xq�j�������N��R���4�pd1�7�������[�p���7�7���f"*MF�@��\K����M7�
�pcl�Q��'N�7����"i���d�����0h!G�lb��dcvj}��9�f���7�'��h�o��E��`W��)��z��_��&V�T��������-c�}3��&��fU~���T7x����q=���vy�����x((4^�z/wq�����RP<���p&4^�z������3�}���*��E�9���rZ��~�~�~hnK?�Y����z��?��
�?]��C_�/K?�", Z�7_h�?��+�]����~���m�:�M�bD���������'���6w��$�O�6��@�5����
�k���6;���cP�|�4r#	n&��fY�����&�p�<�~p��Pf%P�����I�����?q/��g%��:^x�[�u�`�uWQ�����@��d�BY������u"��YL���o�2�K�N<a:���	��b�N�M$cl�Z�3�s��Y�b�~��?�r9.?�����lg���v���g��tN�|���=l!�5
���iT��q���� �j�^��j���#F:���{�a��7jF��K�@��t�S�og�i��3^r-��8����V��i�7O5������I'^i�7S{��/�@���:������1�u~<+��~�e��-A�y=���3^r-�1��~�'o�����B)����&��p���d�3�������3���A�	x#O���zC��S�(zC�wd���s5C��M�h��������%1'CNRH����E�X*!�4��3�@�!dEo��;��������eV*[��4���2�]�KES�'�*}G6�X�11WS��8zad�x#9��W^Y?��{i�W���^L�x�,���
^�.�:o�L.��#�tp���������I<8�x��h>��������	bo;��������;�{PG�4�S���-�'�e�x�F]��a��F���Q�
�)���[5��w ����>�����������U�v��5>No�������.Jo��\�=�n2�@���������U��C��������RU����;�t����f���{�N?Rx32_��p������;����~�.��d��$��J����"�H]�-%�'Z���9��n��h
�����MzQCah@���r�^��"�H]��j��m�N��G<W�]-�7�o��T����Q�����Di@����x(
0^�z{G�5C���z�xx���g�����>����7^�z�J���Uh���cv��B������/FkQ�zb�F���]�����]ce
�x��h�n33�����H���������\Fof�����\�����O��j��?������9N�r���WE�g��-���q��/��g[~�l{�m���m��U���B>�>��k[�����v���
r����������dlq)3���q�7t��Z�N&���-o��},��N/oX�X�
���~���~G�u\(�\�&C�i[�����x�����u�s�WR�����w��O^�Wx�my����8���:p��~c�eL��u���x���
�]��K�N<a�8R�2!G��}Q�uQ��7p���~Q��Q��	G1\��^^� �`���h���q������}B��5m��\*�f[���4��~�<�z�@�g[n�j�����w���y=��������`��w�F����,��o2E�c>�xe�R<#4��0��&���y����x�kx�=�� q|�����c~C��N<"��l+�*b�a�Q��.H'N.�y5w���2P(A�4�I'�*�������D�u�!Cy�=��m����d�*��o&���|��Z�*�8$�B�(��t���r���	m����k�daP�J�u�aZ���<}�{�W�x�q�fnXy5�|iY����-��
5�:����;�4����){��$���8�g`��4��q=0��Ga������bdeXG,���'�4�Y��H#lX�t���,bK����e9�,�����e<�4Y'^YF�	L��%q���"t�e�4��Y��H#�J�g���T��4��X���������Y��t��u�iJ��8i�0�,�c>K.v��cdY��1�a]iJ��$�F �����"���^/j`l�Y���+ze�}�/0M�a���3�U�����+:�����������3�A2c9�X��������=?[~����R,g�s}���7'�?��{��Q���@��*����@G�]t4A���
�B����qr/�����N�8�I7 %g�>6�;���g@?��������7������3����M��k��!���EyqfGo����>�������������K�!�"����W��	C^g��o��<�MAC
��2�j�����K,��vGG�����b��������=��4�_p���G�t�8�}�m'.^��z�(�+�+�l�Pg�����<z$<:QW&W8��-��T����X�;�����+�l�p//������/���!�k���~�s����v�W��>�������?����\���M����U�K�z��v�7_�k�X.?������|�_�����v_{U�����x�����7yU?�������s�E�y�;7Y���������u�~X��(�p?���p<�,����g�������;
��\�6��n�BY|9�����������5r>�|�:.3����4���m/�������I}�dCQ��r�yE;�����q����p�e�/�b_;�p�0�m�:l��k$�NK���&���k'.��h:M��8�����4o]���k'n�ey��v�v�$��5o��f�G���z-;���I�M�W�b���t�������n"���o�Q0��X�o���������������=���'���4s��8����7����~�RfNb��I�{�e;rW���B	3'1���N<����M�U&���t���'��{��qW��[�*�Lb<��a���]E5�g�4��!yO�����R���#N_;���-��L����N����M�vg�q��E��6���^y-_��LV^�V���I��L:��D��{N{WGW�����pt%��4���IG������s�����v3x�����I���z�N/`�"����NV\R�qt�vg��QI-���T�[h������hJ����i]2��"���0 #Ky��v�VM����{}GW,��������R���uNS��6}�3�Xj���4��8�fd���N����o�m�vg�Q��po���N<F��@}�dE���;�N������}���1�edi��NV���A2cU��������?��?�:N:��#�\��W��u�:�w�[7��w ��t7w�:�#���p�'&����8}��pu���>���p(	5�Cn$u���Z��e�������k�t���N�����KZou�����x��\����j��ku�Q����|]���2��d�U9�'������5m�u�Wd�"�q�|����Hx��D.�I�Ws�T��+���Y/ �����H����59�'j���r��a�x_P?���,��z�K/W@���S%
�q����UR�"��zT�0�
@"�A��VJUz��Q��JAU��x�Jy����J�P�*U����zB�����A%�Z(y��G�C&�VJ��w
*y��hR
�l�!�����z����L�����k�"����c�xojXT�W
���LK��&��_��g��-�]Y�"��	2-u.��k2-�����{�Zn+e_?���L����K����9��}��7���}��@?����/�������C�����u�\��<(�������sL�g6"����F{�g����R�B���a�U}�k�&��WqU
92�(�B<8�x7���>o7|�1����&G&�QO3~~7�N��6�����)r�_)���� ���cYG��x8Q�f���:-�,�T
!���P�i	tp����::-��qtZ���F��M�Y��tZ���{Sg����tx�n*gk��eT0�L��m��
�}�R�-MY��	��_��t��CnC���i��C"w���7x�E����}�@f#����U�q�|����Nh$J�;N�4�z���|%��x�T{~r1���T{���[��3^r1���S��{/������/����3������g=����B��o&�xu��xyA�YO-���q�7\�U'���F���B���1�J:u��}�+���~�M�����@���f��U
�
��������I�o*�`�)���'�Ei�7�������=��pH6^�x��6A�>a�������F�^5
���4�I�j(�7�Y��*T�]����pmYp����B�=mIx�M�����a<��[���Kb<��a�-������Pewi���NL���)4��Z���������!�����g-�$��1�*�Kr��
��)����Q���kur�M�qS��QE�B������/�
#�x����&�����x=������0�~&]$�
�Uz�sY�����yjd���v��2���:�FX�xT�Q��=`�<���R���1��2���(KLe<��FuT��
c��g��N�%1��W�I�����0��t��o�|����$�,���085�pc������^����&�)����w�Y��i��a���p�h�Nd<�*���h��a���pc<��E)M��}�`%M��0(���x�UD)M��|����.����xC����iK�4��oC6�NI��o<U��3��7����{����y��h�(���4��H'��v?�
l�0�'�$��r��h����`"�
�SG��o������J�*B���s�R��/�{������"Z_
9.����tB�j�U�U*�J�����'��T�_�w�J�(y�$����*�~���PsW�E���Oc��tbSQ��i��pW�E+�?�<��<����o<�*�h%h��0�g�L:����.��Z\���3��URC��G�}B^+�������QV�%1o��h%�����x��3^�x;WI
�!����Q��
Y��xT�3���e��P�+dW�h�O�2���!'�(����0������ T|��+��Y�A�m�
�$���2��J��
c��[�U�E\)�7rSE�'���Q�*Jj�!�u��u��<���*�����:�����~�8��������������~�c��P����������;
������?����,��?�;�H��J���)�������v��=���x���kZQ�=�A�j�Z�+���D�=���H��Q='������s|F�o��n�s����H��0�G��(�������zN���$��H'���/�#�G��(��?F>'�JNM�Md<)��9Q�A'1�J:Q�������E��:��8n�p=��}�KUF1n���&�o��?4]U�N���]b�p�1^�x��\���H�2%{������D�D�S,��u�=J�i����z����}��Q���o���o�1��v�\�
R���o������3^�F��8�jT��������U���>��mg�	��o��&�{��W�_^��E'^MvO��o����e�)��g������cO��~�G����,��)�^�����e�����ax5���b���q��?������UY��I~��/���n��K��{���/�%�Wu�w����x��",�>
<�����.���~���E������o����@C��e\�
�S�5��,�x�|���X�q�7m|��zJ5�4E��&�z�3^@��l<�_�g��K��9'��Z��x3��3����iI'd��_�a������}�o���	_�������<.$1�����c��$����Y*E�e��$:��<@_&��0D�{)��|ys��������x3;���3^��,�����E������9��,��Uo������P:<�/h�������=�{PG�4�����h�8�(iI�l���$�.p�0�c:�S�q����qtY����KE�4�.�h6�c:�Dy��;���4�f#��>�����#�E#��]�}��o�R�R%r4K%*^��eGs�����5^�g1OA�}�qt��R��i�I���������M
�q��K�����s
U���E��-#K3vE�A��G�K~G�,�?\��������������/0��/���-n�O���qt��r�-~4G�%M�_`T�bG�,��oSu<i��q�=������/0��0��9��p��9J�h6��C��hV\���\�v�8�fQqQ��@GF���s�BS�������(���S�#�TvEO��6x���g�X�a�O���^��,�Gs��j?��mJ������,����4�fi�������E��j�M�hU��*�q���r1��h�����;��=3�2�(]�b���%�����+z��h�w�wfl��h��������4�q��V��G��[r� �s���WK��x�Q����8z���R��(��r��������.+�������4�����z���Qc)Y.�>�����)���j�O�����
�e�G��]��cd�nW����~��'�XTh�:�=����H�������Ss5w=�k�^�:����������J!��F!���i�0�4U�@��
�G�1�lH�����:�j�}O��/mq�%�B]��=O�� [:��VL%��?KG�t�����]��K������cl��<�����=�3�t�a�t����<�{��gp������_����K�vMh/1x������A��{-#��0vM��/1x���'�F�Q(�{W-#��8vMO5M)�1J�$��'�I��{�-���vM�%M)�1J7%��g�Y���{�-3���vM/M)�1J�%���EH����N/.Ks�5�f4���(E��<�W�����w�\����{�h�V����������g�k�}�G.F�����*����c������!��dq���k?���c�QV1J7W�CI���FD1^�b�w
bmrZ�����AD1x��{���x���w������a�+k[��������x��u�x������k��c���tW��������x�cp��l�|�L�i�x�1=�4���(��4�����:��|�L�����?�ue2�R\W�NVOs���z���I\��2^�=�����E
e%����2/�:����k���4'��b"���L����e���C�i����[��:^q=�)��=G��U\g��Iy�g�$Kzfl�c
y�����x��<�w��:3��bPH@�t�%�0��1���:zAW��;��RYI�0�,B�K�$Y�+C�S�+���2m���w����-Je:�D>��n3B7�#:��z��3����d'�kG�y����W��K�� 3}�=��������PJ��|�)s_� �+��������.*Z����RC)����,�l��Z���������.KZR���9=v�ch)�h�,K�w�-eL�����r�����RD)��+��J��U;7!�hZ���mq=]g4�Y��GO��-��m�v�B>�0��1e�"{z�)��j.�8�x�ap��n[p�������������S*�i)����-�K#�_�L�=���-mL����nGXRO��� ��;���������1�t1e����`H�;���r?3�t~#����g\�b����s���Bv:�y�$~�Wz�������a��)���CK
��\f��8z`\�6��z���V��b^q=����-�OI=2��B�K�\%I��,cL5������3�����cC����1���'F�)��W\G�-)t�e#`G�-��*�w_�3C�s�k\O/9M)��e#`O/�-�������D���U������ByZm�xzelY�����Y9�����U������Bz:�g���3���*)���#Nx.�{HO��u�����<�$�t���~WIQ��q�Cp1�cz:a�\hy�G�4�^iJ����vV�h�������ub�a�Bhy�G�$�.\������m^��Q��O�LY�k�<�$�t��R
-���4�=]1��Gm�?�60e%�1������K%�J��iO4.�Q�����iJ�/�<I<]3���������D��R�9������������
�K#�J��iO4.�Q����-hJ�/�<I<�2���������D����9�������������K'���JCOw.�Q��Oh+M)����$��\:�o���I{�cp���BC���{���sd�K�7!#�������'4t����sd#�� ����D����2�;������<�{�ldp���"`.MdOO.�Q��O��>0x�����&�I���������e:j{����yz����2�
E�\���^\��vM������9���e�;��i%�=����m:_+�R\c��@O�.��9hv�O�.�a�����^E��,�K��"����[�{W"<m���t^�������t��a�N
��:��?�����~����]et�=:"��~�����������������������\|l_<Y�6m���;+!x�.��o���v�}cU�4�������CFD7:7���/�j��$�{Ig�z���b�J
�bY���$���Nb���%����O4�0Q��w~n.�<�������*q+1f����K`�����p7�>����2f��~&�!�<�}c����O�i�zv#��f��D���{V�OTY�-����q����>�6���k?���m�)����2_�_]����$\������B1���`_W(�0��O��xuNS�br)\��eA�.�wO�������xox��|OcV����������3����b��x(G�Q$�$��h=�1DM*�fJ�>*�}!��xh�5��x^\�u9m'�rC��qm�!�o�^����HxH������[i=�f,g8 �I�*H
������^U�>8�����
������E
���o�&�������/������=����d_��� N�Z��K@^��kJ�������?~�/?}��n��������WP}�~�������:�����������������:�?��k��������/������?_�����/���O�����������>�s�����?6���_��/�����_�/�W���\����D����?|���������N�����fX����g��g}u�hj<���p<�_�Do������|$������?��
��g���!Y��?�'�Pd�7�~As����'m��B��yQ�f�����������l3�|�x-'r���$��tP�UWpO&�	-*�=H�]NC�ZT�5E�	^�}��~�~}S?�x��8�==�:��R�����S|����;�7�:�h����3|��GY��{�uR�
��e\�2fM�P��l�����Z��SO�u<r����^��M�`���ho�������Z��7��
�\������Z�7�7��:����i�l�7�S,9�Uf�.�Q��baUC����K���\���������m�FZ���c;���v��k�l\���]�w�#���8��/������T���l�7v]n��-����wT�3\�vB�!��
<q�Bn����p���N�����i:�i@W������C�����$V�#��\`QO��v:������]�[[[qG�4�����3"pq{��
������vp�.h��N������R.��kNk�;����
O���t'��BO�F.��Y���B�����^i����N_!M)t'�\O�.�-)t'#{�epi�;	���)EO��K������E��ddOw.��t'�����	�I)O���=�K�_[������s����CFS��Y����|�1^��3�>4�\��N�u�)E+������e��'���O���P:���#�L'��� �l
���(����Y���r���\i;4Y��C���7��YG��pm�H����]��������4���?��]�nR�U(�7�Cnt;_
�����_l!���hv-T���n��n�'\W�tuF�9�_���t�''�!���t��u�}���j7)����3UC�q���6a��!���HxT2�\q��f����U/;�����s��������`7����<v
veQ��[�?�%U��V������_�Q��8y]�����k����1_��@�~���$���$�_������4����&�@?���~s��� Dk*Zq1����|W���T\L:\]
�)�TpQ���k7()
���!��h��W��I����>�_m r���]�!ZS�����2�\����2�����nE��#���}g��S��m�2~�I�t+mG���}�{6	r�J���H��i���3�WV�b&t)#5	��F��I�t;~���+D$]G�I��M���.�63i�Jw�q�zt-����SxQ*�I����:t"���v#�����PxIl��N���n��;L+:�
QY���t�a:_�v�5����p=�h�=��]���������q�3\�v�:{�.�
��}����v�Qz���M)���$��Q�w���;� ���h�=���0�N�(�u&��F�(���+�u��}w�Zh�G��F�(bNaYF��	��B:���n��$�����G)�������v<O~.��G����H6����m7�l<�H&]���t�d�w���_?s����7�g�o��{M���^�_&w��@����"����b���^y�Y���u���^�,e�����$��<��~�x-��xT4h�G���m<�uM<m����H
O<m��K��>�W{��W��q=����=O��%���m9��tdO�w��o��m��=O��%����$��1�=��K����b��N�%J<�����4�fp)��
���)ECM��K�x.���V�%i<MY��:P�7X�����m�.Q�1����[=���4eE���E�CS����{�!��cpiT���q��"Cs��o��CdP����sd;D�Vt~���4���������+M)�1��9���"���c�yE�P�*2t�2����l����$q4UE��q���s���]��ch����������.z08!�������i}�8��Hk�>6�,����?J:���������k����=���H3�I�B)����Q����"��� ��qt@�h6�GME��t�f�q���h6�h�2|��x�f��f!��N'��x�>}*8X���*'�~�5��Ob�����������bm��p�3^��P��gq�E�\��Yd�-4��x�xUxSA�)E������B����q��P+7�Z���Z\��������$�c����P��zPg�J��R��]���l5���30���+��wN�65��fj~���g�T�sW���M�~;�q���*:��Qve��8���P����|M�����������t���u)����h�k%�R4�(������A?'ES�� ���������v������~���������������f���v�
x�=�����������w���0�>��6���a�A����teI:!
������l���1�c�e6�8:��5Q�3HWq��*+������������j�u�b�>�:���I�z����^����M���m��c���czL��CF������c�����X���H28�lTD�G���>$���[�T�����(28��8x�u�H�~��	�d�Y�:$T��i�I:+7pO4e��WU�7N���]1��u\FS#	\#SO:��J�l��[H���K)���vsA:���J>�uC�C����R���������(�4�����z�K�F��CVzR���ww�E$�K�3Oc;�,G���[��,B1M���P�������;��q���������(�:&������u�B��?����s��W�9�7�BI������a�1�cz:/iJ������<a����������q�4�cz��iJQ��%�����"�x=O���D�t�zd�=�����du������n�\�����Z����7�=���R�s�����bp)��8@�&�s�\1�T�}�+����������[*_��PY�4K�fl���.�i��<��5�x
cK��E
�Sz��]�~��J}����&����GO���9����y�{n9S�f�m7���w�:�����=��z�����Y�y@1�,&H�o�� �_�^'�E��!?g����P��������3����j���|w��n�QZ���.����{�������!����l�����e�h�RC9r��Y����(�y����6��t���u���g�'��7?�M�Muq��i^ i0�r����fJ���X-�_�z�yEQ����/��)�U*�t\}�PB������L��.�k:.��c��	�+��5l�5��v�6��oa��W�y�hx�.(�*b,B����U})pzZ�F)����
����N�K��NO���.Z5G��V���������g��u^z�\�,[�b���eq7�f"�_���������3��l0-���P�k���4������v3��'����.�g�8��m���h����N�.���{�-���W����=+�W�n;��c����K���"t��]������8�o3e��2���Hr�)��GMS,��F�MS��#�JS,|�0�'��LS�4���{�"�!z���HS,#�3�����i%MQ�O�Rr������q���>����z��7J�)�>���u��:Z�K���������v�<��"������.��}a&�p/�,1����I�f��4�[$)��N$a.yQ��Z�V�}�e����piH�O�����N�����&��52���~�������$��{��
��vw��>��y=�������6x=�'zxs��.��ZOh$�y��z�������o�_�w����[b��Bv�5���_}q���7�k�g����c��i��5��_�r���h���-�3�
4q�z-�����h:��:�l�]�n����E��j.N�����#�a���oO\�B���}[J�����3��w�ZXo
T l��
�\�����+��6*��h:���W����vl���Z��Z����,��-�S_UHvy^c��P�*����kD4.��vP-�����eS��n�_����
�j��Q�9u����������O���a
�n�������m� [m�T�c����&�3U�s����@'��{?)I�pG����'N���d�O4F�Q�#�m��8���n	�:����4���q=�������&'�_5�+��(���k��5����q�
q�����EIg\G����k���wV�!�o����&6���]AH����2�����]��;k�-�c��;��>���f�Y�6c��t+��w�:�;k����)�;k�a�M�&�z+�'�f�����T�e�n�g')�hro^*�t����6}
���t��_�������GY��D:����%�Qj#@���2�������;��,eYk�fW���;���
+��E��~�H/�[K���`
�I��x�a������U���jO��*�S�E�0����6�Cz���i��<�^|xyNS���:���t�����9n%�y:������JUJ
8���
�+��x�`������X�T�^hJ�U�����m���L�3�Q�,��e�(�����|E�-����R
��[I��8mz���<��^��m�1Bg��\����B���v�;6����il���B���z��	����n�g;�����z��;_;�M��C:�{�����9��<R��'+�Z����O�[����9�UM2���poi�����IF8����������n��^�$#?��#|mk��������6���5���]�4������H���$�T��_~*����p\}��
Sdn|����MWU�L��7},�� P�f���>�S��'���\�	]�R��V���vJ�3��V��WqB���$��	]�
����<������?�FI=�O��|{�9@��,�>`��"Q��)]�8��A6��\H�����4��p�2����B��������`����J:�_A�Jc���g}���mW�U�p����(m6���ch�����Ny��Bs�}�vQ��e�����.f������K8t/*|b!������K�n,����ZST��-R��\�\�K��u.����X
_��}����OQ�l�ku) �2B�}C�����k���r�g(�@)=�D�CGt)Ky����E��tT����@�+�~ftF���TE���q���0#M�_�=)�:*��AD��J?O"�.���<~�/`�E�(�W��*�<�h�g=���z3r��h�(����^�"������'�e�!���f��z3.���,S<Q/���v�
4��qQ������~�4��^�{��������"������������O����>�/(���r�C��*��}�J6������*�r�/$T�p��=!���U�x������5��U��-����Q�U�$���~n
�����t�#��>vTEI7�)���u|�7��Ck���[����?%gu!�#����|@(�M�_4���W��*��^��N��V��������S���("V�-7����4:s_ZCk9��n��z�/>�Ln|?��&2K����6�WE���.?1@�x��dq-7����(Z(��^Gc� VI{Cd$b_���V��V�����WR|�Em	�{�����(b��1=��Ym�� Q�G-��o��D��V5���n-I����Ef&��z`c� �A3���eO�{�\/�r`cL_r�W�7�Jd�Uk��`���5��.�%/�`�`.t��%�+��x�$n1NN�
�:}�(�����X�j��+a��i�V��6��US?�O���2�>m�������F�a6�����6�2�������1��%��5h'-!���������f��5���!�>-��%.O���}�����g����H���c�i���~������c�i��3]�!���:�JY�����q����p=�������q�2�C��:G���d�9nU��x�p$}Z�mw�B�`g``�Q�2.�P
�1(��	{�
�o���/�	(���h7Z�H�]���iI7��iO*O��fcJ���O��F:�d
�)t��wQdBI�����Q��il����]4��@���n�T���l7�N4P�����fL-4cTA�u�f�J3F��E)�%]O:q��}����Z�,eOV���=���Sy��s��e�0qY���E��`�����`�J���8���?�<��3���Yz���3�Q
��TM����{#+��/H.^O�h2^������uG��n��a��T�����PU�i=1�L��fQ��yIO�-S{�%=3�0������L����e�9$*�:-�[f'��)!��M����-79b��&�4���#�Z��j��C)���vEN:_5~�_S��l���]O:q[o�l�����veA:�v����p���v�|��y��v�3����r�k��t�Q�M��V����Y��b`���V��U(?�q?���:��>��K}����(K��j1�����P��`�+�N���PN�RL�E�q^y�^�	5�8W��M)����W_��Y�X���k�����S�_�f�����/_�o6�U�
SFz����#��x(70^�x��*C��3������
�V�[���(���!}(n�1G��0e�O������C�H?���,<��Bk%K/�H<�����	�I��X�y+��{���=3�'��'���-�	��H'Z*v�����OQ)����{����(����4����������(���������";�E��x���`	���v�����������/\�1�����V��G����cK[1�����5�,��9jD���*����/��j����n�N���'	R��JJ�����J���3�c#L��t��tm]��%��m8��`I-Cv�[�J�(J��k�j_[�=���V��B��n�����lu-7H�/�^�T�^����
������	~U�x��mE�F�������X+����:�W�`������U��lg�� K&����������n���q���n��D��d�/f�����b�+�>��Rw��R��y\�#J�@;@��~T�
��{6���a����z�3,��OjiOW� �RU�hi��������f/D.���������$�4�D��t���<S4W����H[��	VZ�	�4��.DN��n3�!���{��{��D��xS�,T��1D�v��yI��j�����!���;���27��+SX��c�1?-X���HD������!v�/�Yq&"���L�-r"m�0yH�2��X�Q����}L����I�E0r��A� �:k.��H�u���q��W���df������|�icI������O����<�4�� k����?�'������1�c_����Q���c+5�(�4��6\�N|�i�U�?�q��d�mG���+���b�_�-��?X2�_�#I�����h���;^�:����:�PVg����(^�$�������w�)9Z��PzU['G�t��j�O7�����"w����� ��������~g�Q���w:U�_m���y(n�[���v����F������]��� 
:��S�l�R�B:�fe���p��9{���v�#�����YL���RoajhQ�R��pq��e ����.(�0^�x��"J�6�V����m�q��,�7x�Q�����GY��������}���3]��|�1�Cz���M�y��<��o�'�(����R�I�$%�4%������q���R�
]�x��i��[��3���z1����tQ���0�POO����x�5}����k�Cp1�X=�q/R}�������9����"�7=���#F��2zP��(�k����hw����7��<\����~�����������'��_������O������a�9�9?��?���������?}����{@���?���'^l��J�������v������/�����<����>%��d�B�x�>��W���3��YQ�_�{�&��(��	�i� ��vH����H{�vq��SN�������9�������'�q'��[����*B��W����{��^��W/���3��������C���6��J��C�T��g��*0qD�H��'�e��l�>t�M����?�%B:J�n,�����5��R�)�>�9B������O�|��3Z�v{_�f���S2�il�NH����]+��*��G�q������F{�l�P���Ez5����x�����h=���#jJQS���F�	�������=��Z<F�g����C���=��&��w���;JbL�����y:!>W��T8��x_�]������S�s]�|��g����=�|C���!�P7��z����p4�'���h���s���|���o3���scR,�9��:3����|$g�����L/�F<$���U�ZIB���pY;�-��v(y1^�v��?|q����������\H�|,�9By��=m75�0���F�Y)�)����
��/�!O:����s�":GV�Y��!�D�K����k��Z7~��x���
(����D�qQ��?}Ut�od��pQi|Ot�C�92!I7^UH����x�s ��
7���x�s c��Po���_E����s�X���6��K%~I��"O�?��=�9M�?U=�i�Q���o��;x8Uo�fH[��/�sG��������u�R�k��k'�k��M�o�)�|�s�'�1��^�-nx��_���l�	�Q
���L2�g��� ����U�/���Uc~V_.
"Oh�����ri'"�TF��{�b=b@��;c~V_.�\�����G��C�;�6w�9��=�/���#������\F$9
z����e���L����53��eLa'2�<q��D_���u�y~&#bz��&�2.ddW��U7c��o���
���q���Y�,����gR��#����g�����w���;I��������z[��3����e���������T�.��3Oj���-��?���,��Y���sxu�H+#y�M�~���2y[T��������!��>���P��
�g�����n����o�;�%�o(
����
_���h?�G���~��qwEt��#��?�wD}�G���#�ye����h������R���G���tos*�O�6�_u�G��~D���x2��G�~7](����g�wo�����A����^y�w�6i~������������W�
�t���������xEpJ����^�����2��Go{��d:9���A�����[:�p�h`C^��o���t[�'��oY�W6x�f����k��[:���Q����^���QY}jo^����]���q����/�� ���&E��o��!1�c�c
��Q����"����e��p��/���kF���
���2(�
���P�����4
�
Q~C9�S��+V��k���W�J�O��7�������f��v�,e�J�����i��v���Zva��.A�u��h����	���R�*��XSk����e����s!�C>�v#�|��Z�l'��J8��=W��ilWV��.j����v%�GF��.u7��[J�_�j%��]oW���#��]�c����kD3\����Zw_��J<?��&���K�	������*�����Jqd�M��2�������]���-�,f!�������4����[8�����Zf�w
�a5�H�P[<��f��}?������*�z������4��yZ�2��;�`Dn�h�jq=��=��9<s��z\z:����w$17�h�a5��{��A=����J�{���\z1�&`TWdO.Cy�5=�M��=O����\��0�)��G�1?���~��r�m�x�)~��<-�-i<=1�\����iJ@��ie�4�fpPE}?N�6�m�������<=3��#p����[<�����Y��� ���k��t4��b�o�D[�8zal����t\Gs�����+$�g1��P��i�2��B���"��fdY3O��K�q����w�l��h�}\�2���-m�F�������Z����-���$��
��F��ZdW�GV~da��������a�+������K�z���b>����&9��%��!*��Xq�{
�)�T���1{������m��Oh:j^���MB:
Rp���*��s�|����zfj���oz���4L���#����C�0d�B����~Qb�������x��C������P�.�h�=$��=�C�K�����x�g[��/�w|��<���5��?���Hj�7<]}���,+�*�l����>�]���y=O�PD��^'g^�zY��xyN���$ AX�����0^.JX��D�
0���W�*'�Dz$���m�2���zEI��k�l����"�z������^���e{r��=���t-�\�nO������;�����P�lO���hO.e���������|����8jn�����O����N�]��h��=~E�$�'^5���/
C��:�~��EZ����A�v�w��p#���15R�.��t��Q��H���1���s�#����>�����K:���Jv����"�;���U4�-� ��D�����[�_�}
��?��j�H���y��o����{��^L��}\(�M��������`����gX<�����Ae�o}��/<��t=�F?��g�H����x���k�;����?���n*H�TEu���$l��X��h���7�������4Ek���J8�V����)z�ul���p����:��������g}��
��+r�)1�����k�W�G@�/�d��D#�'���x�Ek�����p��u�5["�k��*T�|�1��~��'������2����vU�J�t�G�D������7�8����	w�Fh�Bh����o�%�!�P���<N�
�&X�>P#4X�����E��X�����6`�g\O7����mFS�F�2}{,�ZZ��w��-�����������e��X�u.����N/cA<��@��d�����e��X��.�j�N/cA<��@��d�����J�3���^4B��__m�%��p�Fh�2/2�Fh%����.�x
��Z���-��������\H+e��X�1��B�2�> ��'���@}�d�����6=1�L��N}����I���,�Gd���,��&����IBp[�o��}�k��n�k���#v.T��?kE��#2s��k��j�y ���]H�Gz�:�Y�6=k�C�5��&���Sg!��
1�'R����Yn�:�Nf��?�k�x��3q����G:l2��]��?���l��<��n?�{%����(eY��~�B�
*"5�Gg�=H�X1���y:����|3++���c�b5�o��*Q`&�X�.h=�UHq���?���a����Z"�u>�.�e2n�k2ZO��<u�5�i��r������G<<������kGT�4��B�p�_���P��
�l��4O)�#���_��"5��n��o���W];S�_�������VN#�������+ Rt�Y!�m�?�������/@����Y�O�>K��02S_����P���C:n]"Q�'��8���� W5���!��j�\���q��4}��#���y�r�=I7$��jO��E~~�u<��1)���}|�C���s�\)�����:^�Pf?�tE1/�����F�����k W�EM���8}|��e|��H����p��$]�t�������kcu&�~J`1}�L����
�85���W%�*%�8=A�[���~��Xo�����E�_*&�*Q��|P"�M��w�Ob;��*Q���4����3�c�h���k���JL�����j�bh�O���9�� ���l�4��:���?j;�V\��V���L�>'�]WNHP���Il�!�b��Q9�4����&�uG��V}�����jpm��C�qy�����#�����<
=�3����5���	Fh�]��x�C����+M)J����ZF{�+����
@�=��G]G�P+�'����2�&������\���kz��x���Zy=��g�I4�w������2H������Zv3��\6��EE����}|�[\���kza^dQ��wl��e��"�~��t+c�2vI�x5�g*h�8�O;����g
G�C�������3���Qn�u��b�O;��>>��4�Gd����������m�V�����B�rb�P;����CF���j�����!���(�?�C=��s/�VZR�������)U�O��RX�OU�{���x�G��xoy��+�� �����#�����:@x)2����Y/��/�1	R�$�#������'Nd�5���a�e���m&7��O�u�T���IOj��}����g!,-��i��rP���Pq������e�-��XZo
B/� ��w!U
��o%/C�J�t>��[KZ���U�j��x�1^�z�����Y/}��5^��5!�N��P�h�����5���1zcIb�<�������M����zI��~xN�2�p2����������Y�w�Y��X�+{����c~�Y�������/m�^.\U~�r���mn�,���^=�������~�M�e�d����G[��(�'m{C���z�Xd�
q�|�������U����/GjZ]����$�LV��
�y�����t8"�w} sg!�9��#��=f���[.������B�
���H��8"5-���;PeY�zo�GY�}FK��aBc"V�2�Pf�[����xM���Rz�>��<�cM����3\���2�i�pH���)������i�(�cC:������.�ovL��|�A�|7eU�1�:���u�M��|��:��ka�&nsn��x��U�U�&�!Od�NS�1n�[	'�D�j�Jb��"�i>�-���x�2���wP�ul���peN8q�l�g���Du��:�����7�i��������~WrK)��$�Z��~g����%�U%�T������v6^�v��C��J%�o���$��o+�Y��2��j�QZ��+��������T�Q��U����a����2���a�h+��x~�Po�I�(-7�F����k�<n��g\�|w�H8�8��w�qKi�+c~����l;��!��m����+�t�f�F�-4�����Kq�U��s������xF2�gJL�x��;��z������������h�xV���.�M����e���,,��y�������)U�xz�1���C>����t�1���a�����(^ae�qOO.������I����2u�]�sAS����"�cp�E�|}��3���\�	}�u�hJ!�%���xzapYD�|HI@�5�0�,�"�JS�k��������'�;xli/�D~�����������'��_������O�����h����������g�N�[���?}����{�V�����?ra��N�I��e���v�����~������0���QG�#����MAt9�l�F�(�6����x�L�����������������m��\�8��u�x��������]Y�x�M5u%n��1��K����B�$��r�������L�wGW�,�.��j���U����:l���k��Y�$��Zj?��w�*�E:F��#�\f���YMV	fY�VB����h���� YKS�`�i��������-H}����5���B���N��n[I>��}��/�~�����}���p/��&��$��[!��L�y���������?4�����n[!>��+��3����oe�����%���������t Q�7�2�\0�t ���t��W�E�$R�{�S�PcG4xO�!�"�V�R%��U����������h='�Q}��[��
��tz�6��xo����k@�{����^��x�'2G�$j���4��t�������3��zU����Hth�2\�x�����g4����C_e8�<G��xh�2��r&E�U�����S��L��m6���}��>1)gRUm��
���+���fQ�5u���C���}Y��C�u9t��O���tg�!Z��J.W�'��(H�8�~�6��&I��Kf�D����H� �����zR�UA^|B!2u����NW��}�x��+);����W{�v�(�x����_DDY���ra�M�E�L��=&v�����"����o|UH�?��It
��(� ���M��������}S��Q����MT�2��t���H�H���������x=�����9$Y�����Pjy��#�D���cj����  9_yR����>� ��x5����z���D:d����U�:���HY�������2�=����.��P��y�6z��������
<�zO�,�r�qz�	����y���]z��A7l�*���v����`���k��x�������w���YNb4^�v�t^�l7g��������!��c�x:/���	'^�>�v��P�G�y	��f�d4�����2�����0�|w�@8���������O�2uV�#���$��� ��
�Po��lge������.�+���%MV��6�g��I]�c���roGW�w�Y�d���=G�o�&#K%��*{";z��i�8��hI�Z�4O�8�fd�����w����X���+�)iI1	���������w�"�/?����=��nsZ��)M��c�1��b2g�x���nX���+�z��9:}�1�Y:�0���$��X���+�[hI��R(��4��Y:?�Rg�jG*�Y���K�G����"=0��~�L@�����cd>"�EGj������J�+��/Ot����v����1f�L�o'�*I���������cFD�7��� �G�]������b�8���gk�Xq�<�u3������"
��i8��b�/n�1
8dT%1f������Dw��x�}q#�k��!��B��[{����c#|�1��3�����br��]'3��/n�q
8gD9�<�B�*���?�F5`�A0gf����!���.�]0C�]��3��a\N�W�3�g����kA71�z�V�Q��^:3{o�"�G�t�T����"A������:�-��x�WEf�Z���p��D(�=��[[�������z���z`j*O�9Y�[�*�K��GW�}��3�8��V���J�Xo��D��/%����5]��4��UU\���������f�W�
�w��r����]}m��}�:vCw��o�u���2��+>aTCw��E���A$�N���z@��!�G����B�Y�z@7��6KQ>�U�{@}x�U%���)n�q��7ttu�g�
�KV~7m@���M��C7���J�(��<�V�M��-��.�4*mg��,����V��_�f�
����9��"����fn�u��6h���k�i���M�]���y�������:S{!O\Rk�\��:Q��g�����M��a��������O�{�Q�dw���./&�^m3m�fn�Q��3M��F����7x�hf�f���(]f��t��C�q%1��y=�����[��.�<��0^O<�F$���/l^x��>a��<�,B�LH����V�U3��_����h��z�)�We�n�n�.yW���x�x/Kc��t"����U�J<���%��V�%�����a�����DG�#�k��<�����S7H��(h���%oXq@5x�����7x�%������2������a����;�l��YG��,�U�\h`C��x�iK&kU����O���qt��R����B:��8m�d�KZR�%+m�4��Yj���\h`C��R�-��MNK���6y�������,B7����8m�dm3ZR�����7x�,���,�9�e`i�S��a]hI������cdi�Z��)2/6�n�X�������gW�����S7�V:^L����+��R"u6�S��G�X����.%���1��:d"�-u&:V�;g���
6�z�=��g��G!�kE�U���(M
:�����b4)�����l5$j��^cm@�����
s+�R�'J��o���4�'4)����y:���
.��~	H����"6^�z��n��
e��I���Ht���E��k��x<������	�E��3�G�tCE�}�g����{.f__�(��{*�����8p�>�4e�BU��/=
�v#�j*b��T�7q�K�N���;�@������z*b��T����&0}���U�sS�����`�Qn������=�����S������6�d�
�t�E�����H]!�Cf�pr�����~%`�������a��\�E�t�b.��|��c1������}1��s��N�}�H�3p9�G�g���w�?�Znr�-1xC����!�J��V�w�d����1�� ��?��f�p�(*��B:(�5�J'�\�=�R��!E��!]O:g�_�)�!���������X�x8��!�e���t�i&�{��(�2e������x��7m�p�if�{�	����er!���x�%�=��]��,�@_7F��!�@:U��������Q#0�^c�/oEj�p�����������jLd��t*������k��x��V(t$1^�!�f�G���l$�H��DV"����-�/����a�wt���{�=��g����2��xEN:�����
�*��i��4�H�t��)4����"���8��eI:���mK\����S���o"����o�
G�����
����T�������Ui�xK5$-��V�����_^]��"���E�'�����p�//�L�
�*m-.@J�5N�9��C���I&+��[�PT����m���4��E�|:��Cd��tt���V4m��u\G�<��|8�p�R����x��9��X4�w�������N�>��� ��]w�Me�V(�J�)��{F���cR����
#K���v`�������J����e�sez��1��a���;� fl)��4�Z��R�!#�XvE���6x��=)q=1����v�^8�t�,�#�zGO���QE�^Ox3#�$�_R�"I��Y���Kz�����`�.���Zf��.DN?�����@�}d����{�Vw�$�^[��kH�mdO��-�r�5���vw�����+������4���t����a+�;N�2x��{��:vDt��t@�k\O�'�;nOD���N�D�� �������2���Vo<���5-)�d�`G8E�m�J�t�8��!�p�����%��(�L���%CK��;W��Js�ns�X�a�[G[��S�����%�(�(��sd]��"j6*��I��+F�������6��Ek]�����w���W��������~9����o?��������L�����������?����������������>����G..���0���muHe�����������}����o��8:���/��8l�|}m���3�}�F�!{��
�����!�(D:����iy����%�����x7���,�5-�5-	��:��t������x��5�z�(i~H�1��=�����L�DE"N����@��m�{���b�}A��g+��@+�8��cEQ�I�t(�5��J��z�D�����h~��zM7d5
���]=P�a�1�C�	�f�'����T�8�i�Y'���{|O��V_QP��x��S��<]���1��U��oi<]��i����"�a?4^�z�:q�����7��EUt�ld����I"��AtU�����rOl�P��x�62��7�"��W�4=�n�B��$��o%��<�/t_�#E�������T���*}��h�,��g������q���Si���gU��m*Y����G��BI��3��������m�Q������������n��&��_�������W���2�a~p�9+���6Y���z4aN <��bX����0��#@:��AH���H*����~�99���XG�=QJ/+��(s��e�k���8*��Cq��>�<O��'n���~�u<��:�W`Q�I`p3/���Q�h�x�B������x�:�E0���(�o)h<������
��dPY��P�M���n�B^y�[T�\d<�(�������|�)�~��/�(��n"����T`7l)����*����#	r��Q���T��W��S����W���x=�ES�5^O:���1�x=�ES�4^]�N�����4��q�4^�x"#��x�������C���zi�����kJ�����/[)5^�xj�y�M�{��5��Z���R����q��H������6rH��?�h���t�aZ����"��+i����GNP5�'
���TG1@�J��:�O��rvq��c��������&�J�A�~N/��!��b������
�D�\?���p��:9�cT9�3�8V�����sI�<2��~�|�^&�t�*c��<��2��hd�\?sL��>��j�=�V.����sNS�WY������k��sN@�n���qfX���{4?/-�_]��X-+�/���{�A�t+�GX�hP������5BpSYx'	ol��t�85���%����������b�_\����=�{�c�Ue�|c��C��6��Ot�E5���D�/t��������p��c��e2���_��U��4�����$]��4�X��{���\ ���
pa�x�xX������2a�iy�^(s�C����d����t��l�����q=]��i�����������^�E82������m^lNc�3^��2��8�g���|\}Pv�D�2�YL�)���D�[h<���C��^����>�<��Q|������2v�Ge'��������|�T���rU���W�Wm����NWv�7_kA��]�!�e�����_?��iA�vkA���.�}d��Zu�s-H�~p[��_�#�d?��Km�� R���[���Ej] �%��p�]���p�b�y����y��sq����}�u�t\'�Wp�|��x��n^�L�����3w_��
�k�H��D8�}�����.��e�_��_�3��,b������D<�}���e�:�����Ae������8H�c�g���RS���8>p�'���.V�x�Z��Oi@��]Jf/�S���F*�&����D�]:N'�f�)%���GIm����|5�p�Y�����&2��EMAW�k�o!��=��h��%}+6h56��j�3��#L��3^������R��CK�_�ME<�9�*���A����x�g�h�U�q�@���;P�Y���~:K�~���#w���a��g��A�e��xX?wH[��I������9���@?��6��-�hd�G?sl��:~H���3�F,�#�q?-�KJ���$~U���~@7��F��=�zsZ�?����$~UF_9�N� L:F����a�����O&�'�$~�UF1�0�j��$�1�L�a��������3������~��t+sq�=C����r�ZVf_�+����$�1�,a����n@
������|�����-�T��<��^�F\k���Qi�8���
��(���a�{�_Y�i�^6.���a[^���D����*{���2���}������]�<��{�N?�x8R�"QSL�x�}�x���b�g��<*��"9�PQY$<��b�����zh�X�z�C�L<������H?�x��X�b�'�����u��o�#�B�������x#�������7��0�B��Td<F�����Yo�h=q$h\	��}�=��Pj���TPKc�����E��7���'*���������Yo���u�ur}�*~tN� �V�C]�-Y������lv�������������^����gP�-+^[�^�v�2��B��h��m���v��A���D��g�|�]!?P�3�����������O�dB�=���Xd@����P��lD�
t�DR�)"5
��'��^���`1	�)���t%J!�;������q��x�����'���"����W�*���:�4
n&��4�Zs�T��b�e\s����\����4H�	���F�2��6
�aP�������4H�t��MV��5�� ����������w�u���
����q���3*��kP���i8f�p�0��d����7o����_���m|x�	+R��&~�B(;W�4L�����Z��7��*�56 N��x��T��rm��%�D����Ob��g�YL���D�cb�j%p�d�.��p������U��4W��i�����^N�����l��}i�h����v�I��3�x��xk�U��*�4�c8[�|����O�GT=oq�D�����l�x�8�u=�����<qj�I��p��S�@��������C��?�����9������j�"��4����&���I�\ ��CP���+mw��e`-+Z��f�;c?��*��M�������Q�<��2�BT�����������v���Ju��e`�sZ�O���1��kF�����T���$J<���@����d4�u�[cG7+��������|z�/����������A�2�lF�]��D�[�[���<��n��h�G�Aw�+���0V��n`�1�tq�����.����J�KI��v�ap��E6��b��*%�4��t���%����g��b��a�g�R�V/�1���������e^Q4\��3��������-��D�E�Y�_������p��EHc����83{��IIXxM4�a�R�jh����KH+���p_���.F"�J�R�%0`�<�����5 &���=&��L:���	1Ol�Q
��x>6f�������������6�)�7�FXE�b]�S�E	u�HC�I�[��>w1�%S����,_
���82E�C<6�g�����U�=d��iVZR\�k���:nD8�P�xr�2�:X�u��|��e�v����W�D�f��x=O�W� ���	x������h�y��%�4����$��p�7���_�L�����?�J��xCE�)���;��C����?�����}�G�����~�;q����^Wm6w���Op:��7'�?[J���n�����:�-���������f��8��_��h<�����i<����-�/����������C�����_�55���m���i<���
�%.���w3����a=�qz��������\<G��
��q�Z�kd�'	�H<l����a�e���Rj>Jo8�N��%��{@�.�2n3Q�w����[�-��� ����`�y��[O,���[��`9�2n�yc�GY��I!bI���Q$6x(2��2�C^g�I<�)d
T�a��
���#�HDQx ����UtO�)<��E}c��kAW9�u�'�%�C���?!�	�x=�0��kB�6�3�x=7�^i��o<��b\\���Ei��M��22	��xCN<��>W���o�)p�*��x��1P��J�l��"���FF�A(u�WI�72��b����'2��#����$�c������$2�������)uob8SR��H��y=��+u����g�q��7��bf?��~�(�:�0b2]@������[x`��3T{��C������$~^x?��{l�cd?��g�6YW^��'����yeXY�[RH�^\?�Le����k����?Q����s��&��X]NT?w��e��s^�����u16t8=�tI����`���3���dr]�
N�����b/��o�p|0��:z�)�dPP��eEK����+:��K���8�6�x�1x����1HW1��g���;jH�g�=��+��;����
��W*1=����E��
�J}kzz�]�%������B��?�@pS�o�Y�����D����V���G�-iC�Br�}�.F[���w3����W����o�Pqd�^E�#�LO�l�^u��3#������s4��^�zE�����?�����gx�3��]�X����j�J/#�AH�x=�%��J�<���x���\7x�����^�I�<l��{���/����-�u�v�����g_������o�����oO��?�����}�������O��o��������?�qO�����������o�]�6��?�;���j,�3z�����C����a�����o�����,����_\�[�E���x���l�����o(PQ"��)h<1u�L���C���:x��������z�K���[i<��6`aG6^[�x�.�&P�1^����:����l<<q�g��/�=U<{����F��g���O5�*��P��o>��n��}t�[�7t+��Q��6��<���������&�uw�W���~V@�l���/�����[�7_��~���y��]���_����tw?���\w��W�1�~V�g{�D������Z\��	��I�~�l��P0�(�3h�/���F�%���/��E�n��n��66�	��H���z?��jc(�������4N�q�����5r~��u�r�_���������{�NB#�w�Y�#�J^����9�����������\�_��&=lF��@v��d>R��V�Q��w�a�p�~qa���
��$�h��_[k�.�w	��?��!���}��Svxwv��x�������a-���
����k��7�7�xEF:���^%��5���/|Fo$����;h>�xH
�g�h���+K�)������W����\[�t�D�y�=���'����8����R�L�'EJ��]���4��W-�SS+�K����R	�%���x5JJ
�8��Q�5���:I���K�}�� ���*b�e�����G�FU�K��G1@���1�\�j2���������x�F�����"_�U8Kb<������4G����z�����������7��G�NUv7^_�������UV�Y�Y�=r@�V���wY��v{�����~���������G�~�D�(���+��2��4�~�~��5��s[�3^�����>^�����66���6��+�v��fS�^il�p-5��Mr������v<���6�}+�v+w�E	D�m��'�U�(��1��x�Z�>���[H'n[j�N
�MT�E������r<	��\�r���L:��p�k�� ��@VB)�����p��}F���c����]����|%����;�NEE:!�����3q���z���n&�PAh��D���I'jP\�q���z���%g�|�i3_�Sm�ELU��x���XQ���w�#��v�(���t;�+��g��?��HD��]�3J�����Q*@��g����r�
������O,~^�h_
�	I�8*������1�h~n�=3x��}{�����B�/�Y9����h���3�'��P���l���3�J���3_�������C��$����$~�<'�un��I,x��4u��'+R����$�e�8�gX��<}@�u����gX�$OV�M7x�����I��2����X\?+�a[����%�������s�����;:����J�x �r�N9M��]�%�8zbX��n��#wdGO�+��t���$�$f]���{�'!�*/�I��3��q{�'�x�mK�<q?/�+��C^���ya\Y$[NV|����Sb+��(���$~f�����+4�&Q����������t��nR����{HG��|fQ
��8z�V�s�����d��t����%������s��}�()��9g�x���o���������}��*��W�@c�Z�4�{�j�I]2�����L��8���d���3K5f1tI��'�s��"J56��~��%�=��Y�1��KR�6��k���/.
��#��fX�����&�%��K�wNlnU�-!�u2���n���JK���~����2��������~nUZG��~nQ`l��������J+d�.�;F�����s�[�w��wNl�U:�>�{Y��3���at��r�w�{N�gX�E]����������]���
�q��9��qe���e�JG�,�|�=����G��XF�E��s���2N�]���q��9���e�
B���v4#�4vES���G�����Y�q��n53�\L(8��9���G���<���WX���v�0�\�s��kNK���~�������-�9��W���9�z^2�y��/�7�-�l�N-��W��k���~��������UFW����
��~�����������������������\|l_<Y�6����;3!�@;�Lv(����Em�]���j�����<��0/�7����zT�����'pAZ��=����%�m�Z��k��2X����#��M~n��h�%`�����R_\0�.�"�n��������o��{�h�f-���U@�������:6^G� ��6lTQ���,
��$m
����d�.����oh���%?m�����g�j�U����_��?��~~�G��������������������r�7�]���_�,�����z���
�UH��d�b�MK�
�yQ�@)�P����3���������<�>Q[��d�<�����|K\�A�����[YT��Z$��w!I���[i<�Hu����J~x�p�a�����0K�t�=�R��f^�/����O����x������s1zN�R���M���G��_�����~����u��fXn��^^/_�����M���	}�j����n��+F���#�	UY^��
t��;����!-�d���{�&�F�3��_D
:�����)�4��t-��5=����h�Gd�^�
��+���j�S������}�9����G���P��}Cv��{��R���t'�D����u�B�������2�`��UD�N<�l7�K�����X�93�L��[��N�t�(���Ng�;���t�$S���?6��K����o��n�@�8��m�y�A���r���B�-���K�k�3���6;%l�1�����.��;����g\�v�f���,H�'���f	�q=�����f1K��{�5�Yg\�v�g��
�g��|w���%�\�b��A��{��9v����^�$��k������k�f$����\=U���@��t�kS��bFN��f�x�u�Zqj�I�����mNK�V����-������VG�<��*k����<��o�%n�����VGw=��U�]�|"1x���[l��3��7)����|#1�c:�o$�x#���-���#I.I��VG��$�x$9��d1s�X��o����2�i�����X�M�"�K���5K�bK<F��W��*ZI=1���EV&H&���	����e�3$�����-y��X���r��W]��5/�����|���������������B��<���uoU
o��C���nX�!�sf��o��Z�@7`�+z�1�F�gK�i5�'�����n�H'2��.JK��i5�C��bD���p�|�b>���G?�����������J�Q�*>��n"���%��g�D����
��L�#����j���W!�m>W��/���T!�L�}d�P$^�_�����*e�H��M����c*��g�MQ����_��B4*���ZC}��2��mq1R�h���ow1T�u1�W`�����]�dC�����u�����!7�h��`���3�'3������A�Z�2�b�e���t��+�����;n)*����Z�L:�����V[/v1���h;��C��q�=�����+� 
�����=��P�g�w{�����7�zr-7QWK��R���������%x?���x�w�6[�����������y!l���t�m3\��(�qZH��NTi�r��2t���������t��P���P�m��������X� ��-N
q��I�MZ<E���D��S��>�����t�����'�O����N��%��&G��e�5�>G��l��(�v<	
����;��ql�l7���%������n�JP-N9>�&�����{�XP�`�O�"�����Wi�q\q
�H��I�=�����T"�/�q����OXrWG�L^�1��#;��UTi��+����l�h�J[��J�����{HGW]m�#.���xyIS
G�o�!��
����qC1x���l�W�4�M�`C:� ���.�1�gdc�8��hJ?"U��8�D`1�c:������r��JF����6��j�6�*��#�\Ti7WU����S�m��
����=�P�q�Cq�M��Zr�)u����J����j{�^�����y�yl�L\���*���j�R�k���A��1`�g�6qI�3�#T�qJ�I��N]�]�Rm��]g1;����:G���U�Q�)��"T�a���H0�X�
:����3����qMU����!m�qMY�Z�z�!>qJ�AW4�/��Z��u���VtN�6�p?2����U����]�]�K�������WT��5JV��E��R���]�JZ�~QZ��vb�pR}��S�y�E�e��e�W4(����)��"=U������/����A����g1'[��������(���C���zE�~��T�
:�0�������)F���:�r��+��]��\���(t}F�q����'�c���Q����NT
���H���C��h���Y�XQ���15qjQ���Y�����,|=r��7�]�����R�)�
��c���� �yq��I�t�$���W������vUu�vL�]
��g��>��	���������;�\�
d�^���8��<0�}�M���?��D;NU �Pwg���MX;l�n��t~�]�J���.��m�����C"�u��7�O����H-�jRh�J^�9��s��k����<����4�H������t�n\(��$k�,I�W��o��_���.�c&�u�a��py]j�����^H�����F�*��q��H�
�������
+yz
Q��Q���r\wG�O���S>��k��6�]9Wk&�����TO���!��������n��7x������2�4B/F��%�t���6��p���{)���?�cl�L�U�K�����]��;�������?�cp����,K�i�6�cz�Gls1v�'��������_K�j9��\f��*�����U�oBp_x91Y�=�����&���B��������-���z��}n�DR,��=��q�r��\��K��=+��� 7�
�t���� 'nv��]�
r�!7m���g-���;��kc�����|R�
r�!eh�� kW�U�C���ut�s��>�}���t8V�g���L\�>��������/�)!'���{�n��Z��9%��n%����m^���~n�K	���������#�I�Q��O���)�N	yt�y��������>����'K�_��~{�����j���n��y7�JO�8�h���ZW}�����7t�4\��\��(!����37�9�u�hI�������X{��C.�p��Q@w�k%�:$>
w��C��S���+e������c��K�V�kP��
���v~�2����~�����cG��>����|�Gw�����g	9!������B����@�55�'4����o���3���t+!��������;t�<	��*�I�"�g�N��*y�ReG��]�g�
����sC�]�p����4�I'�{T"%Ju����t�T��]���z�K����C���:���9��&��j����'�����O/���
H%�g�h(���I�'�_��B:�jT��v���|5��m7rG�L��������H:G�\�q���:�S��Il7!���	�`;�$'<s��il�e������sE��;J����t�l��j����p�o7��"�>2�^�.F�>&���q��������.��U$H&������i$WH��1��1���4S��y:@'/��y�]�l��`I��>���"�|0O��`�O�q<��������w�\��)�������?���o����/�������}��?�d/��X����������(�6����������G��gq�a���s���?�Z�#-2n��g�����o�t�~]���X�Q�H���a��&j���!�6�O�w���������{LO�9M)�E@Y_\O����#�uc���x�3N�{LG/-)�E���
���qt@�e\G/�=�q�3mXZR�g*��I����e��B�0��WF��8��6�x�5x���;.�7dt�fF���.�:z��h�=����6x���'�/�iJ��������q�0�c::����%�8���x���:*F�����1\��|t���Ugm��|�
���]y�d�cc(�����]�$y�14�������W�K5��c1��/(����k��M�}.��+�%��3|l�U\�d0f��~����L�� �~�����7���D=m���
�J:����b�'���]cue�
+�g�Z(��Lm|��r���\��G�O���}i;��'#U���V�>��
^w�F	����:�����>���?yC���}��<��p�1^����p�rOtO����k�����L�9�=#�AM�x=�%A��[h=%������Z^k<�����H��=�#������G���c��90R�~��~�:�������[�5��ymj�[������_H����~���r���r�_1!�b?+�������@?���~z[�'m��!�S�Zu��
�Q~�[�.��iONm+���=���^�������Y�y�}���KY��a�N���#�����cja�z��g�;�A�f����mEHr&�2���AdOo��mN<]�/�f��h��'���A�����*�z�iN�c���x(7��cIX8��q��$���w����-d�7����m�L��{�$^��p�g���{k]���(�2'�|��PF�=`9����������k�����^e��P�����u"�����y�~{����o#����Id��<Z�}��Z��"#�jW�79��l���t]F:�,y���CG��z����s~�z�������M��~�*�����������5N����\$���iN1���G^�������B\��&�4��1=�A��d��������'9�<�t�
����$��yz������������2�������mb�c������F'�qW�o#���Ft��]�l�3�czz���$:�>�D63����Ds�@V����HM�&;�=?���~s��������F&��y����,�/��_=����d�����L�F�F5�@W��+U&��{�7o�d|�����1�c���p����=��H����b�������X��`���<�3��qJ�I�5<o�C���v�Or�r ������9���$�������RX�G���4�.�Wd0���Y�>��K���J; ���K��b�����q�J�+�g���6x82��������I(�����k�9�C�������BU�>m�)�!���s��ci�%�r$���twb��x�J$Y@K�B�{���OfVV�w��Gx_������@�1�0���Y�WB<�����e����7�=��*s�G�1�}��w]�y��c��(h��������=���� uMxS��T����c*i%�u�W������`��.�p�,�Mq��X�p"~C�D��]7Y�W��N�Lr��^
� ������F
s��+u�y�7"��QZl�g���[���������5�7(�szun��d.�.�p������*c�p�������T��v��tj
F�hso@�1	K�0F]�5��T����p��h�=0�P�{�"�������@�1*��@]��'�����=������������)iWM���Z&�'p����{7�C%8�@��0��}�����_���z�Q_�]R�t���*z����9�]�����@�t��y�����5`�������}9S���zK��Oki*0�FdI����-����@><���=�v�q,0�9r���v��^�D���`�M��s�TZ�����h�4`5`��D/�v��h/,�E!����:�����@#�K5��E�Rc�"F�J;]�-�n�����Wiip�Dpo�����t��|5�������NK;�+-2oun��NmiG�����?�E"v����;D�~F���NK;����M%����}-�.�;��cO8��Cta�Z�������(!�G����5���	��4`��:�\��J,��S�-W����q=�j{�EO�
��������������b�,��j@W1=�\�}�u ���i�������.]:�~�}W{�l���s�Y�]]:qw���H�fv�s�Y�]���N�m����7JH�d��������o���LpS�S�"�]������e�]���y��#�D�.1:��mJ�,�C����b7�5����]���rEYx����0�����At�����r��<�k]��a���x�^3�rYx�&����of����;������Az�}��������vdyg{�Q����U�f��(=c���s�(�F�p�}7`�gln�E�
���8��:;t����p����n,]:n|���G�����~��wG�q�x�7
S(b�yR9xg`h��Mxg`��7�;5�B�3E���7J<�w"�7�������Mp�;��5&�dM������
c:D�n<�w��d�%�'���mLp�Egm����Yc��w�K{���;�7�I���,�����
��%c�ip{���;7"��K8�3�`��w�d�<�+�%cFi�����1��?TMi�8���}�x��V�_<���Y,J.^0���5���2x���}[IW�����]y����������ZVeI��O��$]��T1���5�G�5>-53L�`�E�5�$	�{J:Xd%3Y��]�H:���^Q���Gx����mu�[S�b8K;��#>.��v�^����<��x;I��������<��r�{@��:����T��n�n0.�0c�8/&��[|\��M0���J����}����#�-����w�������y�y$�������i��>�OI��<e�4>.�Buv�k�w�����V�{�����t%����sSn�okx>.���:=@��O����E�X�BxS��,��qy�Py7I��rd�v�I����������>.c��:m���7���C��I[f?p8��-Lb�����a�>%��cdF�LxS��1�NG�0�e�����Y�8�����`F����������3������EV2�?;Ff<.�7%������>.�z[�.d%����cd����d&���h���K|\�7�~�XGd%����cd���R2���v�DY���Y<�&i�;>%��cd����s{�12]IW��T�mug��������f�	�12e���q����i�R2�O��:;Ffk|\�-%�h���>.���D�a��Jve��12�q	��5v]N:����6�F��"�)I�#���Dn�������%vo��
�� �)I�#k�qi�XgW���]�R��-���S�#k�qi�m���,�n�qi�h�6`�)">%��cd>.���$]I������
��qc�%rY$����3-&�]O����"��=%=�J��a�e����������Jez��e(�V��Y��1�r�,��q��2]��qyZ�n������K�+�q�!x��v_Z-���?���O
]I��-t��\B��_t���������������U��x:m)����9�l���Z�"Xsp��:d��Y���N,S��4�^����3��������hvqQ�oC����KO�S\L_�Y�Xx}	��J�_�b �	���`F���������:z� Df(S�������Bp,/d vW����]���1����X]y�h�z�"�\������b����E�i��u��z����"Wf�`!��+�`y�BB*�U�>�.;�}�[���u��c����{��=��sSK���"<Td�cg+&W����1Wo�'������c�S&AW*4��;A`]U�������2etP�Xq�����L��y�"�=�2u��H��+p����a�D����{�%t}���������y� ���������@pS�)����@x�d�����<�2����s��$��1��U�����@�T�{�LAx�dzUx�A�1��Y`��+!LDxSy���g���T�{`��2��3@F���D��G	]��y������_�����e��z�@[��o�����/�}U|������7�B�_H�����_�������~��O?,�0&��0�b_�
�~�g�������O�ao��cn�o�w��;_���+���W�����?������_������o�������n������?���������4�O�������MN;~�����_��O?~<�����_PV��KY��R��b��������S
^B��%������Pi�/���H�z"F��
�o����%K�]B���lQC@A5�7�U�j��J2��5�Yhi�"�����g���)W��K�'v6��"�tJ2�}��(5��0��j+�t��9IY����?������Y��WcLT�
�)t�hw�L
��j<�0;��H����8_�����xr��N�b/Dp�1X�;RcL� <��/���#S������u�����*+���ue�w��>�$u��3���TT%�u��;n_?N<���� �CpWn�R~��������G�"�e"@��Hg=�������SZi�J���1=���y%\��w�_&�5������p���_�����a���fx��<*��1�9�:[m>m���C�
�:�<ul��NM=���&j���Gk�^1����TS_�k���5��G���3� "�������B�A���o��G7B��^t��P��������9��ti�R)�����^NoD��ZU�������if�*R@g-�c=�J)�;����{,��>�q�_E
�\��L?��D�]U�RA;�Dp�S��^�t�*R�7"+��=;fW:YZ�J���4�!�W�/Y�j����Y=�(-�lP��D� ��������f���_�r�s�T�����d�Tgf9#���2	��	���hTi����%�q��@p��!�o�L VH��#�KG��9]@E��Iv��N��A���.���P��E�L|�t5�h9G�o���Dp-�{�����AE�������AEi��D2��`��A.�]N]����e+$.�#�/T���V����o���1�N��u�K'zm:X���Dt�tEpE�J�5�t�FeQ}C<X\`E��`�����`:���9�-���*��'�L�^,0�1�/nn��R��A��������db^Dx�n��N�����YCp>��P�w�!�$����-NO!����7 :�!���g������6��g��"�)�q%/y��!���e�^T��>�s�{�Q����J��?���+!�)�:��>��w�k�V�e��dfL����#<���W&�d�t	��)Z�n��Y��n0u�������eG�d��_�����1�B�S��?~�����O�94Y$]��R����jDVr]���������9Y$]��R�Gl�A�5�	|J�������K�U!	�S%Gx����: �H��������t���u�j�-��my*��ge�A6��xwO��?6@���>���fUk5�q���O8��)jDt����T����/��{����N>��u�?�������]��o4fa(������d^B�����`k����(Dxp�������Ct�����(x� ����Gc":�G���(Dx�� ���%t#2��Gp�|y�����K7����%>n%3������<|�J�q�?�y|�Jf<!�^��<�<�M�v,)T�Q"���^���o@�1�!+��x���n"x�C�%�z����^o"����J�������
��J6��.�1�!�t7�.�R�BP�CR]?���Q�S�n�;kJR�OM�,�a��}
�kS��rHV��9��E\������q��@
�@�*�����x+D�`�N���R������I���M�������:���E��Y.-�x�������INj/T��#F���t5�`��hJbC��{��������KW����=��z��E���`����X����e3c��>��>X�T�pe`:S�dl	�ES���o����L�����X=�Lc�e��&��ca��M2V�����6������eVxX�}J�k�[1�{�����\�Y�����}�/\��n�^-���f��Bt��VCr-Y����-���,��}�������r���k���<� �)��5���W�����;_m�:������8&T�*":&�n��>!��13a�L�N
����������/�����I����
��7�z�����/X�^���h����d�u%�1	���n�)iG���6����2�:I����6B�Q�
�	r����P-BxS�����b���(*����Y�����0
7�SPUu�d���h�Zu%�:de�_������M����7��uD�L���<���y�����G��?6@����SB�C����U����Zt���G:���E�R��J�������n��G>U^�/���H�D����e��?r���9��d^��t���}�>%���xk:��V��t������1��n���<��o��������=��gW�g��q����

��p"<�wO�\�n��R7%�~����XS<����]��O�*�n���
��K����K��.��P ����-�sE]���tw��g��P��=R�,Z��I���
W�X&�pL:��

w�I%2�����a�(�4�9�t�"��ak/����C^q��>X(��pB)�}�y?X��@�X���l>n=����]���|c�Xk���Y��S�����k���U��������b�9��4��z�<(%$���
��J��r�$7��%���Q�������r��\_�rp�C�ZP�s�@�w��ym-��/�����2��W�R����5�MC�����D��clj��ea���+�M1Om���
�]����0\Q\��p�����g_���@�wL�=�������t�T�:e;�/D�9�U���=Ty��S�}��4��TP8���<�cT0�J���Jf����I�D�	oJ��g�.���Jx�S�u��|�|�%������bjf�t
E���M%��k�l�`�5�$�q����@�cESx���D��H:@�����;�q	��#;CZ�hj������|M���h*
�|>��?6@���������"�R��U��� ��s��,:�z)@7���z��	|��!��<4�}�2�K���o��Gg
d^B�����d �)AJmum!�Ox��>/p��7�����d^:��'���C�7�<�%5���}`B�{�%tPK1p��\Kj��2/]Lq��b������}������Gl��9.�
�=�d�g�v�\�����9.��a���e�����b���E���.<�pa�
�~�����e���V2�~���C�'�U�����~hx������7�'����O.���9�%8^�Dv*3}R&�d��S���W�O:�/�V�#�)��>�6�u��-��4�����?y���5�Ot����d�On���r��!'����:������w���B=n��m����z�By�M�cr�1U�1z���4E#�/���?y�wP�CpS���7�S�������.�O�[�	 {'u��I&��2r�����?�D�u�1���H�
�L�ng=f]<j��k����D�_Q�9;d��%Q��]:�],/��*���EU�1]��^���a�������6CQ�<���6'��WJxS W.�R�	�\����-��"�$ro�yj3�w��K�1��7:�F�������:��Ep���K�FFn��+i� <|>Jf��tQ��
�y����+i6�OI:��<�����w�#��t���_����7��'X�d]IW0b���$�]9y$="��g b���OI:��<|\jn�@��"<|\��
v��?kfXM��u%�3fG.u"���+i�1;>��}7IG��d�n�o��xY��r%���eD�o��t���e;+[�NV�\�����nx����S
)Grf�2@+����+��eD�R��xt*e��
��]
��(P[G�@`�s��&!���'����Q�:e��n.�	���-V[ VN��'.�� h�.^`'U��?"������.�������P<
��E�1O	�X��y���t��� ��Z`�c^:.y��y#2/�����<��5�M1/���<f?��B%t=0��������<�<�=0��`�2���{OS�q8���e��Zk���T[.�c�
�}������Vw����Z�[�|�0��<V�����=��������_�K�2��j��
�f���"{�j��k��B9$k �9��E,��{��^�H�
`L���[���#:�"3+�H�JE���Ato4�����Ehq��>Z	�������Y:���
�u���_��-��
c�)�q�@	�E@���D���El�i����k��f���Z�ax��o������
��#d��SK�d������8&����Y�����{����*���
*�'��Jf����R��.r=��t�J����Y�J��9f+���:U}o�[4�MU�������&Lp_Hq�aL�����},/���p�?y0u��b��X^��l`���mN�w�i5�����*�]
�<W�r���=��j��cyu��2�����~�`��7�<����B����9�F����,���r�j�����������%"�	�q�y���J�T����������t�7^*��[���
L@�40WL�?��E�I�R�R��;X��� 
Mx�S�����t�kKzDV2�����KW�
�&O35�M�
>-�	���?��A����$�c����[��{��,�
�#����rJW�->.--�\�AIw���o���X�\���$�������1Y�Y%�7>.�\�]���������L��J������,�:`��gFGpy$��	�����/�Ax��o��XG��d����������.�pBw�V/~,V/":|[����=/�Oo(Z����.���eyj�yj+��b��]��=}�`A���E������7i�j��x�s���i�3����&����E���u<wYp%��.��>���x����]��S�������� �/L��iXtM����E�����P{��]�*�@&�������Gx��M:vt��6�&=�m��y��Q��t9
��`����;��oB��;��|7���+�|��'��
����=&X��2����!����Tj}BxP�Ex��P�N�/�[��6��A�/��������b�P��l����Z�j�/����1�����@6Y�`��`�Rf��R�3�'��V��I�����CIp���E�-p��_MA��h��7a�_K����q������z�bd\�����Np��1�6�zy4*��q����X����	��1�z��0.�� <h(s�Uo_�������B��Ls�D�u� :p�n"���?�fW�+���S�f��qy��"W���?���\3e�f��a����S�T��� �����6p�*���.�[�,_7.�,����h���:�P�o��Z�g���
@x�qL-�
z�P���8D�Ew���,�k�Vi�aY��P:v`�!��~A�����0
y<�����q�-���TWG�-�1m������i9�F���4 �)I������$�=Mx;I��t�3�U+��{|[:f����C�AI�}OIc~���vTrIz��e�~�"�}�8>.�y[�0�:�����#>.C:�*�_zt�:���e�|[�
��s]]X��uo�-���
x����i�/�!���������:�K��j��
:��%@�w&�oy���zg�*-�?���U]2�w��@:�����{�y��5��q����,���]��t�y��L�rQ�����#�^��K[�{R�:��E�1�Kv(w�a����b��A"��B��P�<��yL��t��i�%3����:�0�y��q�����fS��/�(Kn�'�#�0\IxS��f�`�!�C��M\�:���W��(W�����-*��ie��}@����d���M��R���^��5�$�����������+s�hu�B�Si.{�ne��'G�K������h����:�pfbD7e��6�oJ����nt��qL��+�T��� Bp���G���LT�R�U�5��T�1���t
2�w�����Y��_���E����&�Mdn�U��!���Q�>`��(�m����X�9��rVd"<0Y	�B�+{jE&�������r.���������M����p�Ap\�J�u;+2c�`�c;/���	��=S_Q�	`�rQ��<���Ri���&0�r�m,:uq��At�c\�����F����iN
�t-��D��?y��	o�y\����\D�#:��������Y�m�tD�m`��g�EM���a>�
3^�KGd9ym�����\�m���)��b�|N���RavO]p���)��o�t�)R�/����"V�����Z�����M����x�A��o+���i{ab��$��u���t%�m�Jz���)v�n��i����?&��*���t�!�o@�5o��c��d��A����G|\F�h��?����2�w���@I��Z#(pP������	o*F(H�,�Gx i����6Y�I:�<�3�����G�8�������AV���������� ���;��k�f�}SI����d����
W��D�vm�t������-O�Ka�u���r��:���<�����J�������
x�&a)�xf�@�uP�9��h�N������[��S��AtC'��y�a@�b���L�T������b"����]=:�=�z���z*��A���3|+.��MQ�#h�[1C|��O:�����7������y#2/��=�S�a9q�������a����t>6
�feth��L�%W���y�D}���]��yX%�)��o�Cx�1��=E�J�d�h�����yX�]1��=��:�[F��m���<4\���_��(�y�����u\#��`���NVk��
CtP	@p��w���������\�r������,`�wl��?foX��2�/�u���hm���yq'��B�����]T8��g��=��N�k�e29$�R"P�w"i�*�3�Rcc:���VjJAt`��T/E��@�
����WD�+$�|������])U�3�.��3��2��s�	�R����\��_1sO��� �t7-�<z\Cd������(5';_�qN�=0��`w��9E�bN=���z�e�����"n��Nw���O��
g�i��2�� �t��)��j.Ct�q����K��l�`%3����*wxX|JxS��j����z�f�MM�5 �a0�ti��b�:->��Gt\���-�c�������DM�7���K�Aw7�M1O�'T���������
4S������*S�P@�������bDxL�S�q��q��I����o�y��P�-�p����[�� �bM�9����
�vlR��4	O�A�M��@V�ke����:�MI:�>�&jx
�����iqL���_��J��d��*�>��A��=%]�kB�S���0
�<>.%SiZ������q��muWn����0
�pGA�L�F%����t��K�Fk�+�|B�6�(����J�L�������To4��BK������N�`G��l9"�~#x�-���-G��F���Ad��.Z�������#[T����c��y�Qp��f��"F�l����������$�Qtu��n����
����80L���h<�}y��Bt�@�:���b	U��9�V�.:Mo����t*Mo��C�����[=d�	|�%��	��z���+�Z�[���
����{���
�2�bn�XIW2$��+�
��)������D�1=�5��x�D%>����]/t.�:��+������_����
���U�����~�/eO�������>���Y��H1�5�9u���z���51�D%��A�:%��P�J�S�c��[����Et�At�
+f�����:|���)j]`E5i�Gz;2s���u�����s"U��� �Jx���.���"Ff�����C�����+������Ni_��"c�z\���T��[=r����|�����+]t���*�,�V�� �A2M���S��N�i2�ut�Q��t��
���2Shw���EA��b\�M�H��������6���,�A���&�!�U�6\�k���� <\�0-��[��R��@�VS2o��k^��r���R��@7 :��`P�����������U";yX?CpS��^a����
S2�
yW������O��b��O��d�w����
S1c����������J�g|J���/�Amf�T��:���<(�'��)i��!�)I��J��5�)���O�^���	�S��Xc��d�<���l�����[<��qy�;�v���L�������|\"S��m���K����K�>�����%�oc����4�������Z:�Zu��-�Zu�/���^6��R����W)���������)>�r����j
j���X&��R �@�:��
:�9Dg��%�oy����>��>�z�"���������@��c������TrI����y��!�Y$]��Lx���i*rx`���S�rqoD�1�{{Jt�������c��p�C��U�e��A���_���{�A�1�G�kn�/\�L���Fd��p�����p_8���rfj�a����G��1>@	X�-����3q�m������5�����^V���A�}�*���Oe��H�UW�e��DQb��
��g��-�������������_j�J�
:oO���J�S�8�>�4�JX������A��<���y�*��i>�����1/�S7�{)Y�j��0%�HZ����*����	��w[g
��SP���J%��."�Ow���
b�=�J_�N�+��QU:�+��u�S����>��.5YV��G����t����<��<��D3s>�J�\���g"b�-W-3��E�5W-��J�\�`�:����b�Y=����9��@W��vU2���@�:xIn�n����)Yp�!��;b��V�:�� ��R�`q�O�orCTu�7_]��8�uG�d����1�*F��0�	o�yzs�e7w\���kW8�7�Zv��p�[���Tm�V�cj����r�*�T�R��O�
��r��Ft�Et����]�/q��"[nr�R��3�����g�"�P ���p�BX���$�}2����b
������]��{���7�t,����	'HA�J:���5Y� ��+�1����n���i��R]I7��4LD0UY�
>.M��:�de:b��<�n�qi��A%���[|\�7�X1E���"��qa2Qa������:|[��\�l��ObS�v�������S=����GY=�}�������xu���uf)�bo�s��d'g����:�@��
:�RzDT�-o����E�S�:��v�������J������C�������`�c_��%���	|J����.��!�s���E@:%��C���������A$��^W������������
�=�o��rf�WY�3�����{5#�)�	����A����������r�I��)6R���Mq/�_��*��D18�C��i-
��/����bp�"���<��+~����������R��������)wsh
4G��bp�(���#x�4�����<���,!-�������?�H��g�!Nf��R)��:mMpS�]i�@�������{�=����L�_q_t�H�K�4*���t
�^_"�PK���\����	��(���33�:mC�Qc�kM`�S��n���j<��\�Xb:X���+��y���?��4�2:�#��_2���pDo	����J������k������XV���:����j����T�U��D��T�d�I��C�j`&�8n���<iD	��b^�a��7�<�I�B�U���q�h=�*���CA�,�D�D��W[�l&�)��M2�1+�f��j���S���X�������2���X�LxS�S�#�y/�z�T\�D�AX����'�#R����#�7*i�����Y�������� ��B��3��1�~[Ic@���$��6����0�bW��E�
�f��J]�&��l/|I��{2�~���Gxh��o4]������W����H����e����>�����o��������=>.]:?&���NVGt����o�S%x9��NT	n����l��{��������M'M5�;bO�4��;��\&��a��������l�E����>���0'�4s�d����u�\�q�jN^��
	��gcd��
�f����������N�!�AJ�����6b���2��'#<�c.�������,�BxpO�I����FIo`�Si�Ne4�u}����+GS8
K({�J&
v�s�u4�L#�awg�T#<�"f�[d��{xG6���������<.q��M���>2�{������[���mP��<�����.����o���s��<�������J�Bex��NxS������F�^��������|0���w���!*P.n�T����V^,����h� +���r��'������&*�oj��i�����cu�~.�B��"("����ng��� a������6Q������7e���_*o�1���/�	���|�5��DN2+e����[����)�a�a��#��g0�D�/Td�)8a~E���i;�L�J��+����m�����������
�J�4�Kv/��x�E�ajq���U<�G�X2���9�;��e����;���u�y��a*��(��@uD�#�D��k����BA�+���5W]�S����A	�pan�N	.��x�fAL�UWga^ [�>��NS��u����Ws��Y�q���c�u��:� ��_9���|i�s~��N=y
��
c�p{7�0��[�I����^t���t�f]�����2��\�1��LxSQ����1��t%��[�1����D�$�!$6���:���������{4X{������H����g����3���`�{����P+�P����Hz��e`Z�$����q4�a�Jz���#���f��������`���M�
���e�\��*iS`~b��a�m����(���_9Z����m!��Ju?�T+��)z'�a�k���T�u�D�Wc]Sif�(�Dt�-��I�\��AL�cm��D���]
�����g����i�1���"uD�0�}�J�:��;�/��9��d�����Y��.�7��L|�]I��H���4��7�4�	������F#�0��e�����- Vc��Ui��G��`��������m���w����3���}�Ry�g�=&�
����g��7.��{�@�1s���\��Mq/��c����������=�>���5l��������M	���������@x-p�Y�c��)y�7"��V!�C1����TE���	�]#����b���pj�o�zL�=/r��
��^r�������6J������o��a6�����6�>����,*��x�����^���z��/G�Z�(���\r����L-[(�xc�K%�RHV��@>:�j�?�� �!r�$�1�*#�]��!�M���}=�VD�k��&�9����������#<������$�������K��P�[��n�����BD��&Za�w�l�Ap
��\&���-*J�,�8_�;T��[&!����0���d�k���_��sf	���@t�^�f.3�i�At�K����;[an��7���0r�'Z���0v�,������3���\E��7U�}�?��\�M1�k���<�����F���g�����F�,�3P�GxS����W�e�i]����3`��T�c�1����J.&��:�[�����-<&>%��c����Jf�r�?P�AJ�������|J���l����$3�t%]��Ox�S�%D�����8Q��&�����G������i��S�r=+^v�1����%c��Yx��UoX�V+�
\�*tJG>����:�����&����]�>�`�_:��PSZn<���������z<D,<(�"�+��b\0`�����c���"<�_:f�P�S��z�_����
��{�t=3���4���1��L:1���?��
�a��c��-[��{X?�l�y����\�BL!<h�uO%�P�Q}������j����U�
}�4�x�<u���5���"�t�����:�t�daO�����L���1����^�N+�0�[>un���n��T���~zE!�j���3iF�5�S���2?���$.��=�WVutsS��G�)��m�4q���uFnw]����8�a��
��S{Dn���GD"n���}����@��Moi_�N��[Dn����,���}����?��pM	)�a��^�X���X�o��E\�V��bS�@���? W��p����l^�,��|�w#���B�#��B\%��24 �,rn}U�k��m�G4�!��}�><��?X���D��Y�d�	��G��������ra�(P�
�>�B `^�/D]�;x!>��3���>�4P3,���6���?��d����X������ixZ	�����/~����_���+BA���o����!O��!�J�$��m��\�[��U��U���5��D�~���A�V��X����R5*x����%�U1���J8{������~^��Q�H7����4�E��H���\��ey#���T�?���z���I�,��������g������?~�����?��_�����9~�����w����~���`�+��]Hf�H��c�`��\��{-/�@7"�uS���b��#�O�C�B���/o���q;�m����$��$��{���#�<���i��f�sF����(n�b�"���:��O{�~����������iqr�����/��/���?��H�����������K���wY���?~��?��2��W�����+.i�|�W�����!��0��	h
v�$�o~����w�P�I��x'`���B�^�7hq0�>�=������,���3���m�q�{G����*4#[����Aj:��T[sY�}������i�����Kt]W��u!_���&��J��R	��t5y��}�������BMNMY\��������5�
�<�-�#p�K80�����?�>�q�����6���$�>}P���^`mA�CZ���U7#��;ncXY���B���74#Z5��.��x��<o��~�������m��d����I��j���<$����kJ�Y�!�}���K���E������}A{�u
��;x����d�^��!�BLo`���J�Y��=[?|[�>���k?�ln�t7~���S}�{�9+��lw����+B)�k�d�����_�v������_�{�xUINL���AQ���U|��oL����=��j����?
��P��.���v�]��o���K����X�o�c[����\��!����E�\|d�
�^��
5��f�=�	rpo��}Zs'j�*:{���z�6�0�=�y9�7�0�<a���g��O����+�N1p-���{�@h� ��N�q�R��������#����q��|	�ne��#Zha8�o.�]p/\�=a����-rh��@5�]p/^���n��2������6�e����}�E���
���z�<��	��%)�*T��(�7P�Ub���Zp��By�Y&���#�`N�|h�/����.�^4��]@�\��������l����3�o,AE:&\��uT��g7�7�e0bM��!������L�>����W9��+1v��+���������\�����yx����{������.�w��Q� z����=|���n�jW��I�u��QF��s�j�G��U�cVe��\L"1X.������\�&�� B�PFAh���u��&AN���\K-�L�r���e���xJ������dyp������e����Qg]�
�s�T�R@0��������t��ag��BMh�����s�wVe�/�6�3qgn~�>�Q��]Z8�����]��.�,"4����*�}�s�*�y��[���]��v���b��`�Z�C����5�Xb�?������`�Z�Cf��B{0���?�.�E��0���P�{x�����.�*�x �	�i�R�U�X���g]�a��0'�5�)�0v����< i����]{��K��;������_����������P�Bl����zw+W�%�Wm���8�U"�W��'p|)jE�u+���Zi��\)�)�����������������S������I������D������T������|�������m_�=��=���X�~�S	oG�G��]����������i���x���vM������g?��_��?���qmI
�t�����$nNf���������b��9~��{^U��X�����
�L�h�y!���?������W	4!8p�*��l�i�eD�ig��E���+����L4���71]h����?�f��`�Q�����bMB�U�h�������5^1U:��M6��?�	�2�xf�	!�3��j�n!��Ap������&��WLdV-f/�p�Epx�L���������fr[ktb��u/�)�w�:H�����M�`����.�w���������R��������[��.�?z�N��u:�&p��F�vj���\�E������8�CG*��zp1�Q
��s��g`&�0yZ���F4��g-8)4SJ����]����i���*��O�����x�	���6�4&���H�����������z.�+S��9�|�8�?��-�(��������@��!�yC�����~��yNB{��7�{f�'bL,d$�{b�rc����8X�
��������H��|��%V�!6T�������'`w.a�w��o�����h�}�@��\S�YAx(0=�z���X�B{�@^�}�E���z��3
�����&��c����87&C���w��xWB���=V ��>��K�s����%!�]U�]q]�u��-��z�q?����*�.�U�}=��a1�)G�Y��lWB{�@^�}h���Q��x�_X��v%-u�7B�|`�?��s���A�4�=V ����3_	r��s�5
���3__(���N/%��c�*�
x�q1���y]�Y�������8v�=X ��?�r���_��W��L�:�#��'���_���-�[��������"�	�e�yp�Cp�9�}5���������y����=X3����WL�����5/L{B{�fR����n���� 8�}	���I]�a7aN�Oo�C����������E���_�}�����=X3��?��B����?�5C����,�j&u��CYXdF�x-�C���sB{�fR���}z����?�����=X3��?(�������T�.�
�[/����])T�t���W���h��f�&2'��5���0��x4
�)v�m���������o����B}n����+A�u�������N���y9U�f�����o<;�<���X���e��\�8��=c�+�,LU���?6�AS2�}��a_���}-n�!���&J�J�*���
l�o�q^(RW=}m;"�t���%��z��7KhVJ�����0'��=���`�'�=X,���b��y���o����qI�v��3>qD�����D����A�]�����bW@L�0'���q����}l��l�]V����8��0'���p��o�����i����@t��u�4�t���G��b����-�U(n����6�%���CF�[�,�_,��>A����sp�Ep�9�]!3]��$��`�^�k��������w����"�	��9 2���c������)AN�O������z�t����>��vL����7����v���]��.�pUD��K������n�%b��.�:p�v>j�ls�M�A\��+�e_�@���'���{�|���q���`��.�0�����i��{����������n����baU���Et#������w���%p��qqB{�XX��'�/��?�O��0����?6�A�a��'��XX��"�DY����������*�JUb�p'x��~��"V<l������#�%�6:���J�������6���k�o�5P-G���:��������U��qp���),��D�M������}�o&��>��K��rF�N��%�y2`<o��&�N`�N5�S��Z+�^���
\	�����,�3w� ��/h�^������c�S]�Aq�9�>����u��>6�
n��s���z�(�� '�Wk��#re6"W7l���m�
;�>k�&����5 �x���c�<�6�=v�e_a:n��I ��U�m��������y�	r�}j]�-q���l\}|F�.�`��9�>���"V��
z�����U����
���
���W]�
{�\�����Up;�pU��U�S�\�Bm>��\���aq��{�����?���mO��?7�b�M8	1�P����VB����.�9LW��30��V�<��83������u�W��O����q���Oh������������s���;.)#�����]>�.� �0AN�/{w���[�.��2u��'����z�92��$�	�1/S�}0	q��`_�a�_�0	Q�}
�����s�w�>�=�e���4�t�QQo]�����Ah�7���V�0�tD�����n������M��s�����.>�������,n�����aN�O�+@������`q�.�*H����I������	���&]����aoO����� DNhNB��_�+:�c�1{c��x �=8	Q�M"^,�|Z����i�Bt#�k�����>�u�IW�B��H�rt�r�{p�.;|�+"����\�Ro<!�Et��M��!�2}$��b��xrA�
d�;p��0
Q���^p��b�Z�U���#�WWp����@_�8�Wp�"�<l@g���a�/�C�e�/�0���9�Y��V��}u����O�tX!����!��������<���Ct���sD��[�LOH2E����� ���.]Vx��t���<���0	��]��!��<�	�k@���bB��D���Fc��S�~=��!��_D=aR���u+{r��b#����R��a]�5(����2Fm4v|��L��q��&��Jt��B<�3�R��%DEM�,"��jt���~0z���'R���W��;�z���GX�UQ#B��rD�5�����X5�.�0�N�S�S�CRU��n�j�O���2.��N�?h�FhaZ��X�?�b�90K	�K�������l^\L.��*����P���e]�s���E�[Q�{���(}6����o���+�?r�~|�������r�&���[�W?~�������.��p������l��o~�����O��_}�T(��VE)��#��X�^Rpm��J��O; l<"d\��p&R����_���JS����!����	@���@p���2��LaN1P/Q�����n}m���1�8@=aN10��`D���>����@
BL��z8s�2p�~c�{�\N��5,��0��=Q�����.�7g���!�t��qzs�E�Hm��%��th�X%�)j(�V`m!�Ip��2�!mzw�q���2��3��@,��q���b������9]z�����9��!FKp��2����9�@5OD�
W�JNp��2�F%������'{"u
%��`��.C�����dO��h��s��BdJ6��=��ytq}(���H��L�n�1e��1@�D�>��BO���M��b`��M@�YD�^�y�'�A�&aN1P�I��v���s���\��?3P��2�mw��=���E����^�3�Ct��6��Z�2#n�9�@-OD����E��x�'
g���ky"B��YwYnx�'
xDs���gt:���#�o��.
<"�9�@��2ex��-o�[ ��G�]���i��b`�9��.�!MpWj�����N�Q���B�.^2
s:\�0��pA:G�lQ��C��Pup=d��,�������������j7��Fh�rUQ������-����?.�����z^
W�����V��[�Yq�(�����v����h[����C�q���H!c&YAg�b	Y��5�li���Eq�/��*4���L�
����Et�
�c�{����=����Z���X���t���{��p���Q!:�T�B��.�Z�0��W�U6�����q��x��.�:���E
�3��w�#:���c�{����@\��>�/{]���@\O����o�PN��U��@����X��.�F(����g�e�j��k
��c��kp�AN�/{Q����f1���	]��'��b`��jD�i���B��.q�aN10{Q�����t]bGn�,K7���L,�r�Yyz�CB��8��0����������tD�b�����Lyu:��w!Bx���:(j �;$t���D����Z�j*l��
wh#�;$T�b��0��6�Vr��JD5+�b����0��0�����A�#�=�!��@��v1����jS��t� �;$t�faN10{Q�����1OI%I��`Q@�B�W�m#��x��U��z\%���6���F�V�Z����3J����
���C?'<g��:���c��8?'�tp�G�="F�	s�����c�z���ve14��-�pn�E����������"��+���'\-!�_	~ �=�����G���_�d(��P;�=���_�*AN�/dO�":�!��������b����^���XW�����]Q]�pS��$���bP�(���h�j�� �.�ZB��������������X2T����[t`>�O+Q���r1n������vWB�}�����f�j���b_D��=��e��@g����@�d�������d�.q�aN1P�	�����` n���7z�K��2]�����\O�����~�����e`��~1G���Z>��o���7��]�`2T��}��dh�;!|���:
�XG��P��gE
��Lm
�<���1E�yCG?@���{0�|�<����0����S�)(����8�{0���@�
��|f��W	]�D6?�U�FU&V�|\�NT�sM�� �Fp��Vu�W��^������U�j������.���9�?�k��������_�.�+x���j�W���h�dE�9�j��.c����-d�	r��Y�qDt�&��"�����0��9cf���v,�������EU����*�F���b����:x	����.�,<�9�L�?�"�=1����g� ������9a��<��X�X�X�D�sg�<�����b`����vE�u�)3��;e�J9":L���)�}c]��������=���xl�~^�|}!b��@4������g���L����b=g���x���(RL����?����9��`���9�=>V8W��U�H��
�PHp�5h�H�S�k%�����[:�=��e��'G&�)��%_���YO_���D"�����k�)0��-t=��Q�x?�CnN
�	L�l�:x�o���b�{�b|L���l��Wh��e`D}�L1���1_?,{_�e�`��W!mb
U.v%�lpB��cU�pT8�8�j�s�u���a����vg���y��=�-�V����Z]���32!r��c	��'$Mp�����aN0Pk��)Eq�����,l��9e�p	s���+�����.e�D����p��E�{��g����-�;���#Bt`M\�c���x�Q��(�lh
�d�jy�.���9�}
�j�C�l�x����
tx���!�]�]Z3��{&�����W�O^a�����	��|�2K8�:�A5�L��� �=�pQ�`�7�NqP�K�nA�q���j=eu�O<X:�A-�,R�2.��.���&r�S;��>�{�6������Xt��d{%��T�T26L����C��Dx��������0�l�	�����v������� ����L�(spDr�yc�������q�������:����=�1�Ni.��m:\4`r���18@g-�[_�z!�
aN10{� �+�[_�r!K������,,=�+WS�=����"�)��-��3��WHpF�uX�sM�S���t��t����}O�.k����c[���$,.��X�o?L�O�����,�������0t��"��Z1����|������"�e?���c���W��mh��3�&�*��g,���<@I�rE�4��Y��n�<�������CH�<_����:x��U���q�F{���X���7��2�,���N��T�
���@D7/b��L��2�@X�0��N��C�o�z@g0��J�F��0!{}�<u#�G%���$�����E��Q#��O�suz�!���@tPrZ.z�_I��r0@D�@����%E�J�D:��>�=����`��A���ZE���
�1q=�}j(0�����%����M��B)�h^C���-3H����[���b����m�;��PO���VQgr������[|�GR�hq
�[�W���i���*���]��N���3�[t0�b�����>��r2�p�Z]��W��������[;��Ay!�������q�[Lp���'�������%�7����@/�_����>����s^�ZIcI������A1�]r�B��������W�h�d��
t��a]�/�I|�����UhPY�]��":���%/�I|#`�Q���&���B�*�]r�B���bd��^�F���k4]������>����'�)��$4%�.�D":(�&�K^���_L�S��$|B�,����:�faB:�Qw���?k�����!��R�hS5!]a�(a]OH�[H�����C*w]Q�����.�S�t����%���%�����o���
��QDlU��!�K�S\TP�X��@��{��X���h��b`�Y���?�{��X��j��Ez����T!:hU ���u�41="�z�h���
��	��"b]�x6�2(������x���i�/�2���x1����Z��d6�C���,��e`�w���{f�Z�-U�������|�����^6@:���C�DV����&3	�K����R>��ZQc^���d��XV���2l����"�8+���-tukX,4	j��$-�\�n��"�g[���^W�Pe"�l���01i
ecbY!�:��l������nQy�T��k����=��2�n�QEt��"�K�u��&���������z}���Rm]F�cC�3��������
t0��������!T�_���1=�.}�Bi�D�(]-���
�������^	�(A^�^�����	�������mP����MA��7��|4Dw�]�x��=
��
Bk��m"���
�a����v���^3���')f�����q���#>�:9��s�������Z+�~��7��������:�� �������A�����U�AX6.*�^�:�� �O �)j��k�����;����Xc��+]'����q�%���z��D�0��I�q1i���]�1���,�J�l�����:�� �S �)�c/NDt0� >�S�M���W����==�lV����g��J�.�����u�86�) Q���G��)%b�h�@'�-������:4���f�3#v��1PJ�ST�*&<�:(�&�RN���f1���jq���`��@�+�=X!��@�!��t��+&8At%��w��IJV-p������1^��������N����������Q������L����'����~6��};&
f���1�`y��� 6x}.l���T���u���f�����e��"s}z��	+�AV��,/�e��6aN1P/�!c���{��P��m0aN1P������t`���������9�@-G@�@\a�����>_T��e���B���Q�|��%�X���#��a:aN1P�H��/��
Mp���r0���	�y�y#FY?�Gk���W`p[��Qc��Zl������-��-6;k���
���@�n�T�6�@��S�j��L6�r�+��
c����&��#
T{�!:� �=�l��������#�h��at`����f]z�3.]��G�;q�{4�����L:�A��J��Tb����\��x���J[x��j	gK�����nj�{0"���l9��b`�v�:���2�k�|���4��W��&�����8�%���������"������!���
t�Px1�����[)�~��4��m�����C�����s��Em����O�b���p]b��0��{��T1��j2f����@�A �)j�RbB����/��@�^�4!�m{3�Gt���}�p]��M��b�� e`��b���p]�*q��b`�Yt���K�_�+3��s��Z��������
��r0��0\�c����#�[_Tp�q�+�NqP+#�`�n�~1���x�.�1�@'8�����`��`��~��J<X��-r���k�UR���v��W�#��@�S<�����[�������;s�z�rG����}w6)sM~n���Uu�5�N�7�
�}Z�|�+��z�������N������3�#���b%�H�	F_K@
n;A?�wP����1���z�S�q��f=�}�c���@'�:��<.��k�t+����_<,��|�/�K�J��V���K�t����z����mDl�s�O����x(�>�<.�Q^GK.yX`���n�1���P�c�m���P1���dU����cq��kpt�xg�bGt�"�%Ou�c��1����r0@���.9x��q����LVO#:�8U�H�r�A=��H��AEt�
MpW|�=�J�<*�X�
�Z�l��SQ�v1�.�u�M�	P����c	���U���{jn��\bg��Q�{����k���1���k���b�,X��y�d7�h����Sc���+b?���p�c1�D`��;5&
��"�$����8���.�wjL0Z0]������<���$vYpxjL0b����N�dvi%IS��������A	����G��Pm�d��GpP�4�O}w��������)WR���~���v���?��a%a}�����W�����Y
�.p�x�=�(���������wZio�)��9;�&��R�����1B�;q|y����
^;1��n������h�:�����-��:����-�z}������#��&�)�Sj�5�%�1L���4|���_���/]���O]�x��'�[7O�>��C���M.mc��������7w��S�3���h~3�g�Gp��F��.9xj0V��r��`��k]�:b����u)W��=g�Gq]�j��J�F!ch@�5�u=s0{��
�.<��ON����/�Y
�OX_��*w�	p�'/����*�HS���E�6������~���J~��
;���������7�g�UT.��8�9$�&!h�����#�9���H\=]GN+*����[�P�|�_���@S��\���3�������&��2����	s��Z��P��� ��2����U����%�$�E=���5B{u�K�cj�Psa���V�h��{Wn<?�n�-���m�gV�������c��k<�U:��?(�@�����FP�2pb:0�?&���]i�{p�*�W���.��Y����A��@3O
L����,��+Bp���e��k�0g�S?���?�����)(��>\�\���l
��������Gh��Q��pH	�E���\-�N�Y�b��kP����c����x�N����b���}���R����������e�\���`������r�,���w��Yw�uQ� ��t������'s�{t��.{���>]��sp@t�����.!F��9�Nq0w/���v�����.��C5���:��CO���]���u���-�A��������y��:���s��)�j������
���~�k+o�zD��xU������t��u#��I���"^'r��F�&�N�R+H�����lp�E@�V��(��A���h����OtP���g
�)���
L%�v^-J$��
����
]�b�p�3��d`$���7t9��
L�������At�/�g�-���T���*�md���p���h�5������7��P�O�������7�TjE'���}�f��c�������	����Wb�������w9�9����S��q�����{�rp�jz�{t"�.G�\5}v��A��=:�C��%�/���w!K,_(��vN�P� ��K�~!��}Dg,����+s9t9h�%!����b��n�A�T�0ZxI�e�BD/	�=:�C��X\2���2�I�
��KR&j����+��5���5�A��a
pY���1�K@n��7����P�^��1���+��kyTE=����C��]YC�����A�v����x=���������tjF���S�w���r�7���{�`����ha=���4�����XOFT��{��!~��UI~�b����T���&��V��T�!����{f��(T���"v�^�������/Ngw���]�nW%��������	��6�V�,�9N_@����g�o��Gg ^Bp6��2��Z��g�"���c�-����
��t�PA�s����4.�A
�=�P��@�s9a�]n�����.'��uXA9�g�\�U�%���������;���}@������mp6�������V��W�V����>�{��&�/�}��'���Q�"����F%'�GU'����6�c~$��.;����-��X�7v��������>@�=uuD�����	@�o�|���o���A�����o��������k�����7���t5��=�����OaN���N
��'�{�u!�K�S�=:~����h��.���^^���kK9�@���mG�� :�A�����h�@t��P%V��������n�z��i5%M�)����Q��jdfg;�*�r�:�A�y?2�%��\�k���������*86��M �C������F�3��g�3w�&��dC���W#

������?���y���i�'�-``XA�(����C�I��+������Jv��1����$��Y��V��OT�5{��q^�H.hPa��n5'�AR��<�S:�b D����
�R����`���t����0_�����a#�sJ�� kC�����N`�	�`U��8%�0g�^���(�@t`"�z5�/����i�P3!��U�	�&�����5Bd��^k�)�MSb~�A��4RCQ��o���]���@4/�:�$F]��MP��������Bn-����ZW���. �x:����nKIn�r������Gh������)�T�>����
�0��3�+��{������$]��rI����Z�����ki��5D���������6-"����w'WF�_g�p���&��UU��Zp�����A� ��l��Y��z[<�=�<�7�=��	eA%��Ll
��u&���8�'�jjU�����cB�ZJ&�0�J��K����g�G����g!]�$&����PU���O�SJ���/���c\1M�>����*`��$�����J�}[��
}l�C���=E1�,*���{�-��7������g!�@h������ :u��VR�����"�Jy�.K����OdBt���%OM�FO�NqP�2"��<z,yc��`d�%O���Eb:�A�La�������>�J����q�-�ChX�IX��2���i��8_\��\iQ!���f�c�g�:�Z���?�������.W��/�r��<�����M�'��a����t8�������I�������"Uv��O�ST�DL5�����a�~�����z�e NJ�����{��
wv}��$[DOr{ s"eO�}��9���O|-L#Uf����o:�����q�������K���fRT�q��>6�������}&�.�G�0�����J����E{��G��5��b`v���~,��^(>�e`F:aN10��cD��=�&�e ����{�	
��":.u���}M#w@�!��������W<�B��&���]���g�{�{&v�:����	t�dk���?����:(-&�GsG��1��1C�J�N����!l�D�	�W����]:�A5�����������������`������"��%:�_�k�T��
�>xh�Ch��K����j�9�(�g����Q�8�O2�O����x��a������/�������L��������~��?����~����v!�KG;X_�xk>�����W?m6�ZVO7e��D��_����G�|����ms�2WW4���l�Q-����@�N�/��L>~C<^��$��$�)U���%U`<�O�'���^�*�|9"����#U��[��o������J<ew�NU
]�xk^2IAF�)�]+7����"S,���A��I����M����*G���6.�,v"S�,0��	�W���!^�_HU)��*I�-U�����?�R�(��_	�;"��B�#U6R�^�<U��������#V�J&dO0R�y� �������t�*Uv��d�o��*X�4��B]����*��v�����5�8nQU
��O0Rpy� �J�P$9���F�?�P��Ou��b�d$	��]�TRl��7mU����H����sY�=.�K��$Y6P�.l�! ��w�
9h��e(p0�B��AH�ud)�
K	�KLt����|��A�E���D������� #�����d5~�>p���t���k��4���L���,YX�F�du�}����]�nd�!f2��d�{7������a��6���� ������^z�B�u���Q����+m �1Q��!��$��e�`0�a�E4$���L��=Q���/r�K��y��y���X�d}^�?���m�����o~���?�~��o���?�������~�(~���oo?��������o��?���o��-����	��\<�o3�.������	�4D�+3;�(��+(R(���.��gVE��k�<�(��64�`OHO�"I��oF�0�D�
'��`��rcu��\������4���|���`e����`)sP�2�*D�y�W5��*�<������� 6� ���h?�
."S�2�g.(	a�w��3�(��_�I�w��R��w;�.��g����=�r05�,���sU��]F�Y����Gp��C_W�6�`������1���1_�o�]���T/��'��j�jlY����o�x�e�P!L�*��I���VG�M�g���\�1"Ml�F&�Tc�u��&6v��&�xl����?e�I5�Yc���<�&Y@�Si��(M�1�_��3;\'����O��8�� #J*��QO��u��L�������ozA2��B[ j�U�.�jaJ�yp�����
�X�,�,x�i�������j7�#���I7�+���,O�~�"8�d��Jo���j�o3Q���uu�"Y�K)xx��N�KI�.%�����t8�H�!^���,�`��D��T}��|'
�r��� l��z�Qx�C���f�2_���A�e"��$���J��fh�t=�E9�����o���E��h����O�����EC��V�<�x��S�^10|&���m`�e�e�6�K�����
��*�����U�����v,��������������#Z�O%Z�������6��������iwZI
���25{��x`w���F�P�.u�~��pf����
\�D�K(F�P��	�)�_>�(��WE���b�����`DX������V��VVE����R�B�J���Iy��r��������|�muwL�����;E���������
�S��SV���O��H\������f).�"�q�Z��K*��e��m8}��0����m
�*A}s�������g���U^��#�e{��{�C�T6K�$����n�3��}����T�����V\M��1�K����*B(���c������(��h:�v��[W��z�Zp����N���L�����"q��;�Z��RR�k��H���CC�idT�Ca�2������5��3\��G	��U��5�{�|={�<���IS�F>������D���&|h��C��{[��`�.!�������
�9j��o3���1����O$�EQ�����w�Xy.���z�;�"�t�/�EY�B��j����������,4(v�E�O!�����q�UZeP
wz�	��R�����G�p=��`��L�&M���C	�y6M�exC	e�D��4���
�'"��I�>l(����&�6���>�W���8���>�+�I��f��O�
}R�L<���B�T=�
��_�O�}C�
U]�P�MC�U]�Q��C�*U]�R���C�:U]�S��Nh *O'J���Q��KtJ���Q��KtJ��
�S�%:�����p�NY��7�N�+t��>�u*\�SV����S������Q��%:���F��x�N�>�u*^�S��|�:/�)]��A�j.�)]��A�j.�)]��A�j��)�kQ��S�:�t-�u��$��kQ��S�:�t-�u��D�t-�u��D�t-�u��D�t-
�$*O'J���P��KtJ���Q��KtJ���Q��+tJ:hTJ�TI�W���Q��+t���(���
�*u-�uj�D�t-�uj�D�t-�uj�D�t-�uj�D�t-�uj�D�t-�uj�D�t-�uj��,I���x��<�(U�b,@���
����X4H�:%�!%j@�.�)U�b�=`cq�N�Z�A��w��"J��
���D�T-���N�KtJ��q�3Qy:Q���s�G{�NU��E�����(]���N�+t���(����&]��p�S����(���D�t-
l�"*O'J���������J���������J���������J���������Z���������Z��������)]����K��j]����K��j]����K��j]����K��j]����K��j]����K��j]����K��j]����K����E��S�%�SA����������kQ`��xI��t��(��K����E��S�%�SA����������kQ`��xI�T��(�j��*�Z�?5^�?t-
��/�����O���OE]����K����E��S�%�SQ����������kQ`��xI�T��(�j��*�Z�?5^�?u-
��/�����O���OE]����K��>g�*Q�JuI���%�P�.�����C�P���P�B������*S���D5^�De
]����K��L�kX`�xI�)t-��/��2��i��T�%�T���-��j�����N���j���������j���������j��������j�����N��E�Pu�^i�7���@&2��J����"U�%Ti�7"F����*M���!U�%Ti�7�P��%z�:H�F���D�T'i��@�2����(M_X�+s�^����Q�ze��+]���^�k�J����W����-���F�tm�z���+]���^�k�Jf[��~CT�^�O��a�����l���������Y���Z�/�U�e���
@�����TAF�Tud=�����;8:����!#K*���b����Y���y��DY���,� zdu��F��cG�7�FT��&YBA��Y:u�j���HH����,� ��SW�f�����	iAd{#ddIQY ����i�0������u6���%Dt@��N]A�:G���HH
"�\���%D�,��+U��`p	iA��!#K*����B]#T������ !)��M#T=kS�&:U�:6�[���G2�\������O���AVdy��j2A�z�6��D$�CME.�NH�T%�MD��J�����`���q�e.I����-����~�U��{;@4�HHK��\�Pu����������s�����$�l�P����s��P]I�z���M$�%Qg��T�k��&Bu%��^�L'�O	s!�$T�kW��D��JB��v
D��+$��`��������!$@$0��"�$T=l�Cz������]���l���\�!]BI�E��E��JBu��/a��DB:UW����.�$`��D��$T}���������&�+�K*����J]'T}�2��F$�%a�IB��.ct�Z]'T}�����HHK�e��T}����-"TW�>v98;[�X�\Aq!]�=$q������P�$�D�>�/�>;V'|6��BW��_��.MWU}CtAf���j�����?~��w����~�~����������\�h����gxD�o<N�'�?���m�����o~���?�~��o���?�������~�(~���oo?�������?�����3�[:L�aC0��x��&Q�*�M���$����V��2*�����3�oht]|C<Q�"�?����0����I`�J�E�,!�zz��3QI��st��
�Z$��������>�U���q��~�������I�;�I�'����o~�����O��_}����w������������_�����������(~�����'��������}�#��|��������l��G�3X�q���<��2�������#}�n��Cme�Q�� B����I�	�K`�g�����e�4�!�L4�:F�7HSM�.F�A����iR5�k�����'U����O�
}RM�����B�T�u��T]�O����B}���'��67P��+Ju���k���
�R�r#
U��B�tg��5�T}�N�>�5�T}�N���u��D�t���:.�)��7�N�KtJ��
�S�
����RG��p�N�}�#�T�B�tg��u*^���("�T�D�t-�u*^�S�E�:�\�S�E�:�\�S�E�:�\�S�E�:�\�S�E�:�^�S��`�u��B�tg��-�T{I]���P��+tJw�G��Nu����E��Nu����E��Nu����E��Nu����E��N�����E��N�����E��N�W������?6��u��5�����W��J����xeO�)�7���5a��������#� �r��p�Z3��t�t_��E����\D�����D�U���R}8B����OT]�P@Y/Qy:Q��h(:$*\A��+L�DuW���:ET�N����T��<�(�w*�)s�N��S��N�KtJ�ku�^�S���E��W�T��NY�){�NU���C��W�T��N9�)w�NU���C�r��������D�d��)]?���U�N�]����C�������A�]-[$�
O���z����D}z�*��Z�d���Z��b�;��kz�����z��'No��}
}�D�+��}
��b��s%|
+j�6�
���+��uK5���}\=��
l�U�G�+-��w�x����!^����
�-laC���5��?�{�
���6f" �l�l��~u��e��u�}l�5 Y�1��$�i�}������������l[��n ����KF��i������s[f.�":�f��edy�G�:����PK�N�/��������,���x���.�t��M��]#^
N������1$������m�us��7���O>���DN���y=�E���	���e�yb�`������mL�=��!��t���-��]��$�z�JW��L���'w�H,�6pqI�fP�"�"W�<�<AB����3�p�d����"�:��rP#&�F�]�s�rEYn�����(�E�%*��o��7�}�z��P�F��]��R��o(��#Gc�@�*|d@c��y���	Tx����X@���{�&��;W4 ���c;^��.]�_���hH�����k��@�]�pX��FTS�X�C����}@���hc48�\��Z_�B�T��hzdiL�t�������di�a`f��J�=Z��NT�$6��w�
b�w�e9!�$�]uv@�>=����Nx���2h)Q"�2:p���W�{��p���e��3\z�eo�����p�Lp,��;���b��(����+D��W�R������b��(��R�HT{���V�D,8!����R�d�����p�������2+1QB��HT�:�+]+�����k�US�����Tx��'\�:2Vx�WW��b�dwx�wxu��uOx�'���%cx�'�>p��U�R��^_q��D��������[f�ElW��R�d��1`,%�Wm������Rr1\J��J	x��#w��������v8�$*_d���K�p���w����$Q��>1����<m��
��l������'hgm���l��[�A6��^c��V�?�z�O� C��f��:��>"qy��WC��������u&n|�2�gW[�n�,�Fz��5av�/n�.�!5]$;�n���=fT{��;X���Kk~�U����^"T��M�T��mW>y6M��v�H[���&��d;@�y6M�L;4HSuM���v@}��'U��Q��+�I�����I"�l�tw4�#*�x�B��hjG���
�����
�]"*O'J���
(\'*O'J������� J�����j� J����C�4R,��R�':�:e.�)U��3�S��R�(:�:e��)��S�E�2W�������N�+tJw�TgQ��:��x���S����(���D�t-
�:�.�)]���N�KtJ��p�S����(J�)w�N�Z%�Ty�N�.���z��<�(]�����
��]<�y�)����D�Zu�_�S��G������E�Q��%:�kQT�S����(*������(�B��<�(]�+���
��mq�j�)����D�Z5�T}�N��Fv5�T}�N��v5�T}�N�Zu��D�t-��:.�)]���������(�
�����EQ����\D�Zu*^�S����:��)��d]D��W���F��A��W���F��A�j.�)]��A�j.�)]��A�j.�)]��*���kQ��S��3�kQ��S�%:�kQ��S�:�;���P��+tJww\��NuW�����[�������(:������(z������(z������(z������(z������(������(p�:Qyz���E�����
����
�S�:�;�Q��+tJw�^7�N�����E1�N�����E1�N�����E�c�Qy:Q�E��S�%�S�Csz���/���]�c�TI��������K��t����?�_�?������������jQ��?�_�?T-����K����E�c�TI�T��(����*�Z�?�_�?t-
���/��
��O���OE]����K����E��S�%�SQ����������kQ`�TI�T��(����*�Z�?�_�?u-
���/�����O���OE]����K����E��S�%�S�.}��
fc�B�
T�S�df��F�e�����fc�l_�����;J�X0���%-�+7��5�#�����b�K_��(�N�&���'��B�oaFj���vE�K?etI%���-w��$tm�&	WHBHM�������Z"T.	� t�%,���Q�!�K�XS����,�J������r��
X����,'�\�j�
���HH����\gGH�l��`=����Z��o2]ha�n���zB�z��������?%!�)�U�����a\�J�>������?������"Z�`����}l����O�X��+�����D@�}����T��Ju~P+*\Z1`����,�p!n���h�m7tJ��)�xG?y���S�v�����_o0���uB����O@e��XZb7.`? ���u'�]?-e@
5@+� ��Z���,f�`s=!?O�����e'��&\=HD�3�v����"u������0��g�����]�g�y:�Kz��L���9t4���|�I,�
/7NI4pJD�h��;�;'	k���+�k]
i
�*)l�q@�+'E�*�T���qr�1/;����	@SS�~���l1���~�=����!��l����<<�;��r��������-gc��*�����K�=r��	R�w������r)U2�wh�w�����U:�$u���l,��#I�p����3�=�C|��Y��VTV5}���'h�m�����ak�R�����Y�j��&�����H����R�P'�Ob�{�Z�Q'��N�[_Z�n����~����8���c}|��<+���<�)��y=��V���v����]��I�����j!��KbG3"\>��$�V���e�Y�D��v�-��u�A��hM$�CQU�9(�{��gQ�3P�<�h<QF9��5 #�O������v!��\���	J��.��=��,���qu/�����p�u+VR��
��V��3�v�
��z��UQ��w�mA-B{>dY}��~�i��
�'G���>��o��[=sp*����c���Y��p�7�f��[A����S�� 0����YsCZ������Pg�p���������P��w*�Y�Q�z�k����L���Z���s�k|C��g������b�cl���h��r=��c�tm�����0/j��<�&����&p%���i�L��H�H���&Y��)���o47�H�g�� ���4���l�������#~Q����4+oT�e���|��/7_�:��%n��5��%"��uLI��xY�H��e���6'f��!�/�4m����NHWl�=��-g�(��EiUi[���.���x���osR3�R���V���w�����7�r��D�2]�4���7���DD�M��	Y�%�� �l�TM��HSyM�m�7:��m~�D���Yy���
}����������'���	�O�
}��C�������'�����P���$5��D�BUW(�4p(%
5��B���)Q�JUW��q�vU�NUj|u����Q���W�OD�G�����'��4� ���0}�s���]R�}���E18a����������N��A��Lc�?xf��0
3Y���Dku|����W����o��[����tm�$���]����SxJ�
��
���P��j~����hZv-��Cw5��uX�I�n�	�K���C0��n�s��\IQ��sJ�M���>��o����!���1q���������]�=$m1ob�U�k�&���5PCD�\�NP�����5�!"��iO
���n
��D�KF�����G����p��C�:�ZB�'�K�����'�o���U�����������Pq��/��V1�A�0�k"T'd�����"��=�xEv��+���+�{���|m���j�N_{W��r�B�^�}����;���#���w�ho�����/TK��.
q��Ekw]�K%>l��
X�D�2]�4�f{Fl)!"��I5�36i���Z726=��N�D�j���]CD��4�V��-��^Qm����g���&(�$"��)Cxx�
��Zs����/#JI������&"WL�m�I��{�������e`�:��B
���84�kX�%�� 3~�+	��������4~%F��}��g�	��B��\�(�������=���ok���-�y&B����I�D�������<�&M�FS
4wM��P7Z���z����p�����������h�wM��=�7�*��]7S�Ca�GW��Y��n�lG�4���p�u#E�0I3V��Gd�����<[=A����-,�8v4��+fvE�*��*�Z*�����4�4���U}��j>Pb��CY�&�M!h&�oTU@U�6�u���y����D�Y��}��6(�W���2���f����U�!"�~�d���kW����$�w}��,�fy�9[�.���[u2��!��6
\HM�Q�
*�!���B`�0��9D7F�����;�U[��Y<��0�����No����vCIOE�"A��N���Vf�=�.�B�\�k:U�?���z<�}�O�&M�vf5��&"�
 �v\e��9��^
�4�D���.��y�T�A`~�.Krl����g��Y]��BX/����b���:&5��'^�d�T��@}]���1�WL�
�1�[?E��Z6��b���O�O9�e��^����LmS�D�(���H<���w���3(�DDA�'V��0�h�z���?w;G��O]�N��]��,s\�%�D��"������?!U��]�d�LlIU������	�<��L���,����6RO����w����C�q�s<a�RO���"~�����0	b���CxI�2�\}z�aD��=2H�0}��Z�C�pG�E�U�������Q
�=2H���
W�����D�
'�*�����E� *�"���:6�����D�}�Ye�x �1{�mhN���w��'e$;k_���(����RQ�Sop!�[�&�<2�e��=�v�=h$��e�rc�	���:�d���t��(�HAF��O�Y���=D���H�6M��T<Y����m�su&�HF�!�lx�q�wy��.�)_�j����X�����,2�HB��Y�[mx	#8�D�\
�n��p��)���,�n�����z�M7mS�
]<fU��1p'i1���AH��in\JD����:@�oD����si�j�Rc���������8�9T�	�����h��|x#
���������`����%`��0�<Q�y�&�&���wu�����% ���2�J'��s�-V�N�����&�����\��BS��D��o�E��P���}�	��a��(U�������8t;O��,��6e 4��2��p��2P���*��v�E���2f�2�t�#��B�"�i�<2f�2��(�=�_��f��5�O�@��/�]�7�j *:]=P�.t���?-Q�g�����D
�z��]���	?R�#QbtHT����B�B��?]2�����	D�B�\��B�	)��DS��@�O�:��Z��H5��uxu�]T��;�e #J,��:��H7���xu�e�K���P
=�F���H ]W���8_
���`��]�)�:���8�&]oy��*�����<�w?��*��,�J*���D��t������29�B��������� U�]H�����2������r�PU}����*���tS�P
�GD��RP��{�#"SS
�nso�e#������ ���R��R����@�,8mD��2�� ��e���vH�.�m;zaT]����dY�-dJ�������)�HV�w�q"��B&AH��F*�Fr�n�m����}	�D@R
1�� �Jz#�x��]��7�U��{�/[1_+���������L"S�FR��{e����x�G�d��y^I>w~��0�$U������y���r�I������U���h���\�T:"�)��u)���5>xu�|)����p�A�?/��D�����?�qB�jC��R�u�#���)_J�t����!SdUH��^�-�U�������u;DS���R�u�|���{tJ#u]h,�!1d�!YR1�x)5�������z��@�	���K��u)	���D�(�����2YJB��b������#]/���������������/���C�����lb������5I ]/z��9p�t������<1�z���v6��2�B��~��1�AiZ�W��^4���2%}�dI�a�Ki���T��������d#�^��=p��NMmP����G�l���s�
�^�`��\�Z�z����U"������T���tH�r�j��E.%"�1����Nt*^J��=X��,)�\���^�����NMmP������/�lbP��������T����K����L�bB��b�y2D��T��w�%{)�E��!YR1x�d�*��A��<��25�
���E�jemP���
�oD����/�A��*����b���+���A�z�$K9�V�z�5d������E�-���}��^t@�f�o��T #$K������������N�`��)�'$K�
X�4h�)y]/���N)�t�h�S��)	���E7x)�uJ�� ����R��R�})�z�X�D��`33�dI��uJ��:%�t���7�N�t���B��b@�����	���EwSjy�-�8=!Y�����R�S��^t�1���)e�����z�)u�bJ��_��z�=lc&��xA�^4�$":5�A��`������K�k���Z���*��me���7_��2�~�h=�$zR�vn���Q���#��+y���D+\u?h-�����o��/�����y���R�*gzk���b�U�����H<���v�f�t�H<�"������22qU����W��v@hcqD�?U������A��i���=��������r�12Z���P����?��Z��s(J�_	�)���U�����6�xE��!�o?������������������|������8��<����2\�5���������>O����!BH.�#��K�j�18D�N�bU�t�x3����h������aN��M�4��7��!����i�L�I����i����h*�&>Q��&�t����4��:2����������'�DH0
�S�B�4�
7�P��+�I3D#���B�4��7P��+�IuE0-*�'Q��D��g�s�kJ��R�*��{�F�T{�N��T{�N�Z�Tw�N���Tw�N���Tw�N�=��6)Q�E�:�_�S�C�o4�N�W�����
�S�%�	]�b@����)���7�P��KtJ��P��KtJ��P��KtJ��Q��KtJ��Q��KtJdQ�'|�� 
uj��)A��)���"V5,�4O$�� ��� Dd�(?��dA�w�s� ��_��&��������	BF�X���N�B�,�cGg#$�M"���pEd��G��jJ:?_1�p� Dd��&:u�j��f�n7�p� Dd���@V��k���^%"��YRA���:~�SW�nF	�:&.����|�%[t#k���9��R�O���Q���
�yAB��G����'+Z +{�`�������4" ��S��I�B�F���
�������+�q�M�'�C��gDT���nJk�����'JHW�%;ew���ZwB�v����u�.��o�f;Z(;����@�������Tw
�j�W���F�,k
%����j���q)*k�!��i�����+��*k]���S5X8�*	/~���T�(p5�g�MD����r�a�����h����<�&�-U�A9%�����Zr����%�/����	�����_������4�Y���	�).���>33��kjpm!<Q?����o���T��y[�D�Y�A��H<�"W��c�7�+QF���������"�����8_�#�c���c�(���3~�8<���m�����2�dq�����i'L�d\��]{�p�a'N62��u����2�����������3"=�tV�=���Ul��+�^bU \~�
�Y��������
,"S'��i��R�]���D�Ye��jD%&ml{�*0I<!}	���Db�����0AJ�w����}���>��D���a�����:��=v�TMH���-���������c�X��1RX� 3�b��z�B�����rZ�a��m�jo�>]�4��m7��0�������a�7*Zl%""��I�������ItMu�����������w(��E����u�
FjNh_W���*�vH��������\�<'�+��>�n{�����Z�����	�[�s�u�}�'�g��BT�b��et���h��_�����/��H��'Q������a�E��.� �7(�*����	4� )YT�)Y��Pc��a��4!�j��XA�Qp�d��R!TP�HD�
A�:|�!�K�-Yi�T=��HU!hV����0&�$YY�L7��q��HU!hV��F�L�-Mb!����HU!h��Gc-�~�K&!�h�
��y�v"RU����y#�D��B���u"RU��M�u��l!���B��!�������VsKb��l!����B�����J*q�4���v�����5M��FTD���#���X�	��A�k�f��7SU��E�v���N�%�N�PU�SK�����(�J;�:OT��A�u.�<�5�p�T}�2z *�KI�y.�N�W\J���Gs��������^����2��b@��g0XUh����`U��=�>����BWe@����>tU�='*u���DW-��������EWmD�����:�5�h�	���T��
�Z�`U�k4X�KVQb1��Z����nc�k}��*#J*��&*u���E�
���4<�D1�z����9QU�.U/:�#�b�2�A���D��&�I���EG4X������EG4X����:�9F4X#o������EG4Xc�U��n�G���2�A��n�|B�D��T����M$��M��w�A��nbT=
��������������G�h��Oc��
&U��M��7Ys�A8�[*�Y[}�Uu�wl�fmy�5�T=���V�hU���A��X�\rPu��r��1��+UW�k!F$�/U_�k[�����%U_�G��HH�A���[��t�vk�o��N��=�����j3�A����n���V�)�q("����������N���s"SW���a&����?=��z'�%Uz�I�	��A��`s�D��T����ac-`.9���#�����Z���#������I2��r@�u��[KM�)l��y�5W��?}�j�d<��+M�)�<"6�p�4��U����I���O7��������O�������r���v�D��r���v�D��4��^O$�������?����������?������Ze������������L]9h���m����tz:S���*���(�Q�U�g�f?8.�1�x�]~���u��V~Fl��Xx����]�~�5�����76���X]�r�4��Ypi���H4�����4�DBZ>�=/#K,�nM�SW�~q	��'���3i��,� �
��Rw���c\���	iA�\�P���<2�SW���w��	iA�\��T]c_�KFt�
B�5�
�dDB�%�����%Dv��+U��2`^	iA�L��2����8eD�� T��*�yA$��dKy�B�;�xeD�� T��j�������|��ZF�w��Y��
� �@t�Qn{�^3������3���r��r�U����Cm����Oa�����?�����h�l~M+���!����@�&�6�o~��?���?|��w���O>~��?�������1�
�E���z�S��4R���3��7``�t��u4v{������x�K1�� G�����^"`��B������.���Vb��kt���)Jb�Q�#*��3�WsY"��P[&�}F�G�(���Qx�����Xl�}�M�k���Y�~�������zvF���]~S��ZY�����-��WL�����M&G��0������brP��H<�"��1�
,��r#nL"q����.����&����U=����&����O�Nu�`#
5</]|��3O�j=[w~;�_���'U=n`P���[ x������,��([ x�b7D��i�^�m5����R�g���Z�Pt�p�O���������+����wf��J.��e���Bh�����X�����L��:�������������^��{W`R�C!<�L�8:D�������1����������'BU; 7�9(�}����h�S/��;��m�u�s����;"�����=�����#����aB�r�%#.�L���P;��;"�����>�&��Y�*z���h�N2�C��w�`a"qy���p�S��n
����-zx��8?����B������[D�����t�W�{B}cV��*���_�2E����gQ���7�>���4o���*��E`���l��0��0��	���P�m/�,����B9��g!>Y��d��>x5��%�����7wr��d.�O��@������[���P�x���h[�`��*�h��G�u�i�E�[a"�,����p#`^�1����6kO:��{��T�{�E_�n=mf��/C[���� ����C�����{(����7�G�z`�gJr��J~}>~[����4zN���=�gY��F���r"���F9B��bn�NhW�:Y>�_��������,'��z�i��Yx�v�5O������s�*�����(���=�^�:��E��N�\���J����]v�;�A����U����o��{�e���._p����"�F�f�W��]���s�r" ��UH��������r��+����U��K��}�=�=D�I$�fOI����G)�/��f����`���KUjZ-��XmV�	���:����z�����)�;a�����0)k���OXI����/���F��KW{����iIz���9�'/XP"� �M�Z�bS"��b�,"SU�m�mhG��V4�1����y���}�Tu���r1�b�l�o��G�(`@I��b�,"�Q5�Od�XKe,�-��o.E3O*OD�d�xM�$�,�	��U���D�m��IV���1�&Tl��K����a���B��nK���P��77Z?���`.X���$6���a����Zc������l�y�D�i$�W��(S�h|���T������e�D��-k�C����ye���������7?����
�^��V��%�B/M�|���I��Jj�u59�r�m��cB�R9Z	_�����[�����_a!���V�����E��E2�}k�46?E2�}�*���+�8���$&�}	\�N����v%��i�g�Q�C���W�o���������Bk�������_{o������+�d�y��$����w��������(����4���0��	������E�{x"�,���cn #����Z�m��cFj���u���]���1��h�z����������=����7��r����r�2�p�u��Eyz6�&��*��2����.R������Pd���4&��h�y����6�H|���������4�7`=���z�]�O�
B��^�������<�5�iv6��Fl8)�X����Q����S�2v�wMHU����H���xS7���?xo�{�n�E�g�wr�=�� �v��������l���M7|(��O]6��5�;M#J���17�P%�u��	��U����K���)u�����ZG��5�?F����S>�ea���=Ef�kr�(�������^���c>��1�uM���7�tN�+N���5���q#T�H\9A��J��5�R�k�������3j�����^8_�l	�����e�'�����c�7@z��Y4��A��R�5���;������K��[qtngp�|��c�"�vt_D_R_��"����"C����N��N�h�/��*�2Z,,IW�����s^�'�2oL�=@5�D}�J�&�0kT��Z=�AT�O��y;o��5Dm	�)og�9l�����Sv5A9L��vXt��\����%<�������`um���9MJS.��_�-*D�^�"�Q�z|���N-�(��l{=�<��#�����i��E���]Y�!���FT�q�*���E���~��,e���L��%����W�|����$I��$�)��TG){����MTU�}H��
WsF�
�	?#����B�\J�U0^f"S��'n�|�3�o4��R%&����i�U�"����f��z��*�MP��g>�w�y��p���wD�Y���
]
�����^����`���T'��UEk��T�����5�Tz�@C�D���8���:���Z�,�qR�W�:�$�g�
��,]��9��X���{��9�C�P"��Vu�h�3m]zSN�P�����M1D�7E������f5,���<'J^��:|���Db� ��z��l�90B�a�j@��5u�c���������@QI�|���G3��;*v����_���S�����`�QEs������*���RP��D���KAF�T
�����:R���������u�dTI�PCA��)a��P
RD��R�Q%�B������p��P
-���KAF�T
-d~�LM)�1�[�&����*�`��D��jU)�`����7gJAF�T
0/g"SS
AS
��ic|M.)��J�����h�H��mB)�&����� �J*7R��o$#t��b�p%�m��s��N":U���>75TO�A�nj����rPu���������A7�3D��T]����>Qp�T}������*U'���Qp�T����M��5S�����PKB\ U?�!FCt��A��n
�v�A��n�'":U���J��7�'w�T9���-zED��T���C���X��M��t�n��*Uw���b�}rxN���?��[Dt���T��6@�s[����%�T���"�SU��t�@�H��g����O����rP������'��T9���-�ED��T��v�)����s�T���"�SU��tW��4��J��A����KD��T�����D\ U�sp/��rP����%��9�����{��T���?�a#Qp�T��;��j��d�T��G.w5;�=�dd9���6f�w�5��Le�N�d�'`U�k qE\ ���]U�D�J	}����E�w������7��4��UDI�������W�me����:����f[�N1�N����K,b��6�f�w=8�s����W�+������V������8v������b�����i�������E`����T�}�x���}��G����%���nt"qy(�8r�
��#����iV�W5
zl�"*��U2�*�-�D��`�s�����9P�KE���
��!�Og��VA_��|�mux��S"T��o�����T���FD�F���� ��+���lMB��h�k�����$����O������M�`+x^�'
���Z]�"�,�����*�`#_��l��Sc}�P��U�1�J�S�
���L��DHD������"��X�\'�Z�:�kl��$*O9A�1n�
�DcN�(�_9��0"qE'N�>�F��9_'�O�tNP�:���6�8U�H<��s��u�K������u��D't-�u�?S'2���!���**=A�2AXO?A�����u�xZ��Va�d�7��Q��`���p�)j�t�;��MPv��u�	G���V�����H�7�W�!�G#�}Q9�v��U!�1Xq�q'm���D�����V��ba�tb�+`���6�h�D��0�!����������]���2��P��X��w��Ih"�
I��2�~H���A��Kh"T.	&N��fx�|���6���������A�t�f�$��3��f!x��IBD�q���~��qtA5�D�Im�R��,j@��%�%!�K�N������}'4�����K�&����.SR^nC'J��M��M�m9h��eQ>%�����zQ����B��>5bV%(�����0\s����=x����ek�|����W�S�q�e�57�<(h(��$��{0`���U�`�R3?�����X���0�3q�����0|:����o\���p7��2�����4�#�;C	%lp�(H����'������iK�����3/�69���4��j��7T%m�LD���O�O���w��H�3_���%Qw�k��K����Zf��GT���L	�������!jZ
���]��W����
m��t����[g_ua��:AU:��g�V&�g]u��C�s�y��D��\H<�saC�U�\��)�jJ��C��.rg�c��G�����
na+�x�.�]���p�������a���B[Z��g�����=K�")Uuk�yS��UI�T-��� a?��`q�P�?��Z-�����7T�s!������C�M�va��}�������BY<����m�va�X8���)RIH����{Ri��<������~��~�����x�y��*��m�V
j�1e�a��|��C0{�����j�v5O�72|p�/�Ekxn��[� L������k���Ps�����7?��O�_~�?����������>~{�������x������b�J��_~�����~h~r}�VoG��m��?���������������i!r�_�����?���������?n����n�8��O>~���7t������������_����<����n����O�?���'��?����������� ��ZD���������O���7?|�����?����������}�����w�}����������?|��w�o�����w�3P>|������x�L�ah~}�����������2�$?�i���������!����������������|��_o���O?�Z��7�����ux>���_�����{s��s���a�������w��h���������~'k���le=���������_�����e� z'��������~}0��=�1����7���J��G`y�2PQ�B��k�qp�do�9]��G�9��=8u�Y����mgC�A�dx���U��/�w_o�������0�a"I��PF�2��K�	1��i�B���AF�c�
,dW�������qF�����<���p��9�{}�����f�0��C�2w��{���
�`��X ��m���_�����?��qg�0G��;���HK�4U�������I%L����U��7�z��W��(�K���>��P%RW���_��T
��r5��az��7�9��FD�T��u,O��'4[)��aL$�E��I,u���,���WFYI���c-�(�P�PmLx�m��k��8aD��/'*��������k&T�N���z�F_���>&���WT3N��F�W}���2�zX���e�YX�:����W��������a����2�N�����?vA�P8Rx ��4�n$L��������8�/�H��g�ih�"E����T����z[�������[���\<D3:����)����|��d^�aE�kn�KJ����3�k��_���������������B5�����^�������������� ���#��m��
�n�g�������/~���s"��~��_����R���k��W[�W#�v�'���oL�B)3����������o_��/(m9���qi�vqi�v��!yi�d����*a�;m�*:������E�>�&U��%�~���a�'��[�����p�{r���_�������XT�����wUPe��>X�\��#
���H�����)[�<�)y�e	^�N�,�`N'��a����sJSd�z���Q��0�9�	�A��!�`/o#N&��}�.t��f��{Rxd����U����u�Z6>jt�<:pT���y�q�� �)=g��S��=�J������N��>�_"�F.~���zl
�V�5�O�T	���/1��7��7$as�;��l�����s�+�_6�N��fY�J�w"�{\��e������!��]N�7i:��
-d�m����!2^���<]���k�������U�qv��N�(eW�
�%�>�LM#dh���#S�k�HU&B��9���JM�e"�����5mj8�:��(P @`��+a�n$U��!���w�����&a>x�2�G��[x>�.r��FL{�w:�c�%��VLa��D>v�����z��NL����:�\���M���8"B���$Z�rF��u&��\F[B{Q��*�
�GG�[6����3�\�������]8a����9E]\������ o����'��g�����,���Gb�L�\(?D���zJ�>6��i��T���6Ve���������S����?V��~������g��8Oghk�q���s)B�$�cA<W��a�/��TXl>a�Q���//�-zcvF�o���,�{1E|�������T{����m��6L��m�!�<!;c)�f�%�L�QY��E����-\���M����M������=�f`�y��������n�A<�{�!���\0��COy����r��J�J�S���PY�n�bw�aa[���p��
�t�Z���e�E`�P�^�������j��}�����7b�_��90����=�^G�r�
=,�X���	�b2�u'Rq���<�n��B�8�)�jf.t�}(O����;`d�����-;��T�`�A	w������;^���i�#�� �td\|�k*yKD��>~%o#�ED@*����R�p4�_��[(����_�<H�E�.Q��DFT�y�Go�$�F��~�X ��	�V��0)+��[����n��l��+������E��$�����b���y7B��P������k"�E�mg����\`���X�Y�����VaV�JV���T���tu<P?K�ZD�B��,��e��
�C�q���
nQ{���E
nQ{l����[��/%����b\��9�������������}}a�����j�n�.���*���0�_��c
�cb<���R�,�����(p�v*�b_/EVU�������(7\J�J
��%��J
�UL�R��{D�vLl�f��U����0��� ��xN�B���0��xJ7"!�E\����������[��]
;�=�u� �G�SL�����#"dr�q�"��DXA5aN1qKYr0�����3���a@fb"D�s��[m�Y�8�0=-�"&���	s��[�7Y�!�P�iB�h�
���+�n�L
"d���e�ea��V��n�p�V7K&6���L]�D���t#�+U=Ix�*��������%���;����s������="d:���%����"D��k+d����P��ou��6_0�����H�8"B��g+����D�L�M����h ��el���c9c[�c2�D��p�����q�������� B����$:�qc�xU�E����/�SL<�/!��S�M��z,R&v����)�7�o�<�8e�0Q�c2�{@�������������c�"������Ux�x���_��T5 ����%vb�7N�D��>�E����.����v�'w���_H\?[����l]�x����v�Mm��TA�r����n��[�Q�e�����K��u��v����/v�#@t��Z�����?O��#����~���<��WN@���~N3]���k�:�*L�oLd�D��5�rW���(T\��
e[���~�r���c�P��yox���8���
�5 2��`�ZsZ��>Z�����m!@A�W�n�C���x�-�nb�w���,���#J]	"���9��
?v'���d[#��Z�"Su"d�u����v��<�2����������U�*��`�zxc���(����U:���2���H-�E:��#��qq��vp��r���R�/�_JF���3-�1��AYaR�l�>v0��y�:����@��Zd�v���=�k�2c�\�Wx$d����`�h�af� �t$��b���-QYp���P�6n�2���t�y��r��]�K�����C�s��"DV��g��^0�"k��rC>����4�k1��(-
#i�hhF�#��."KJ��M��#����Ttp���a����+�o�������?��g:�=�I�g���%�{��3Xb����'��%��5U
����,O������k6^� ����!LW����j
����o��v���4u�rS��!�H��F�*���; �����'V->}���y�����V�Q�kM6�Ds��/��y�z��K�0��+��9*fk�-d]��y7��|f����V�al�Fz<�Q�#��A��~��\�L��~�#d�:B�l����]���[������k����@�f�k�w6F�;�z�^���@��f���x+V�Y=���U^gB���Sg�3�S�39j��~����^��R�!������4��N�����p��q���;q�.�g"*�8��r�PC�b��UC3�����^�2jc����_�X�C
�"C-f�5���+$�y������zD^+�0�P[���x�5T�Z�u>��!:���|�{�vT����vr�_�����J>��%�7{ �3K�o�B��]�r���H7 ��Un��������g�o�H��eU?�7<�~�W��"<�c����+�uD�����X�Q�Wb�7{%��^/��o�Jb9F�^��*����b�
2{5���=�+�����_
d�z������AN���_3�������l��06Q���>�����
�+3/p�t#�z�;DtYf	�F�~�r��E3�y��Tw������^+�S����U� '����\�^��N��}��Tw�>d����y��b����:����n�z�wwX���T�e�t.����VS������h@��gF����u5��zcm!~_�Py�O^�Nsk�
���30�����eXKu����gai^���@{cd��h����]���
�����������~���������7,����������?���de�,��������)�u������������e��S9�I����h��%�D�7�����f���/9�IOD��7[D������S��^�O%�N�d,�����tI�� ��^7D��'�.�[��8�
�&m��m����z���h-"L[A}(_�z�r��D��gS}n���@�5w����,���7��9�%�"��h0%H$���+�6j�Lt��o���a`�K�X�-I�SL<}��!"�5+2!PE�SL�x��0�G��@�EL������6�iY���� �!�C�SL�`�v�D�n�����M�"�R��`�vSA�A~��X��W�g����9�M] B��&��]��b�s���>n���b,~��v	s����n�E��p]�e�eab�'�c�:}W�P��a���8w�0��x���&���0�v�V�=#Bd��J�c�2�G�L%�5&N��vdyU����
�
gl_��4-Bd��Z�c�2qD�\����E)�9��+<���
[�r������2����w��ugj��EL�����E^��a!�)&^r'vhl/f�<3Q�c���$Vn�$�hlw���F��a6>�|������8���k�$�#�[n�nF�7&>$��fK0A���s�Zl�m����.]k 9�>��.B���j��5="L''\}�.��D����9�����9����6��J#���#L���r���9D8&��Meb"��Xx�3�b"�e�����.
.p�Zl$�/adb!�4e�8u�G�-D���.9��G�S<� ��z����<]rz�k<�x
�qmU B���
Vx�TL�)\�vj��O��]S1~pP�Pd������k���.k��#�)^�sj�2�e��!��u:��Erm�7�N����0@� �x��EQ�poC�?��oX��F4�Cz1���T�e�l!�D�Sm~[��9v�-�X����Y���^���+u��@�S���zU���	�>�\��W�%����y����hq_��wa���f�u�h��<���5�,���h�M��M��������k���E��t��nf���l��b&�|e��������:z,V��>F�]m-dd��h�T,�52���r�j�	���B����>�#H���
�q�,��Am��Y��
�wLWd��9YVZ�
X��yE�����o�������<R�
����&�L+��L��M�T���d�b�\L��	gX��*�:�������;��,��{�oN����7��T���;|K�����,K���;q;D�`/���/����o����am�C����
��#�����������-�s��x;^W����?;W��d�_��'�������������������w�������C�.����������������s����I����O�R��������M��N���d�<}����ow����7���L��������������!�������*������R�M�)����7�17��Q�'�x���d-/�%�7�/�&�sT�@^G�	{l�Da�����a�b�B����m :2�����6a^����i���<F=���(�i��������0c�#�^���B}E�%�mY�Q�?x��N{"c-�n�W�,B,=%�N$d8�&l_��[`���+7_ 9��v��]C/�DG��g� ���P��_I�~���K�����`���n���
!k��^�5-`�DBKD��C�~�B��[��&����U����s��.n�5"��AU�DH����#x�I6p�q���I�._�e��-�I���vkfT�:�U
�!�{&r�U�d���DH��&�-*xq���5C
����3������=p�?X����8!I��e�L����H~d�����r"d�*�_v�d��'����7����h�$7��
!9pk�$7��H�DH��6��0�b"$n�����
p?
���-z��~U����~��I�~����e����l��SBd��R��P�$��i&rU�$�����UM�6�M��lkl�e�!9p�L��B���&BR�W�Rx�8��n]E`�{�W�Mt��$���V5Izm;������$C5�\���[�$=��DH��&�+`��DH����$n�$q��g�N���/%N����}/��87�&B��/�$2��b���Li2�i�8W������5m���9�#k�i������H��tp���	!9p�|Fr�����;�!���`){��{�o<�q��?���~�B����y4�N��M�B�&Br�V�I"�����[3��z^K7�����%��
�m5pO�$q����R����1��������D��UR��iU�����������M���������M28�����Um���!9pkF�����M���-z�?,�Rv7%!I�/_�^����"���;a�|��*Q)�5m�������'D�&)��6c&[�k�$���o�DH��Q����!9p�l�m�p�fnKM�$#��o�xK������3�D�j����mM�����b�!G���MR��L1���MR�����[�&��N1��,�@*��T�)����$��e���M����-U<���m����	<�sZ�&��	9N��M���]�N�J�&���d"$nU���� !9pkF�a��{d�A�����X�FK9��p!����/�Z��������|a��k���M,B����~��h��S�i�x��G$M����i�x�!'Br����x��!9p�^xK-�v����a��L��#�/�e������7���j����������^����x��?����h�$��/�:�
Xk�$�.�6�DH��6�nn�L����u���m���m���Zjb��hb���7;M����^�����[������"������7�����f^�3������$�8�YM����j�tC�����u�=��DH�2��k�Fc�`��DH
w|�+����a���=:`�����_g��I2��R���D�$����m�R��i�T��O����i�<��f�M�drGY��L�a�T���I&B���m�([,P>�j�,����r"d-���I"C,=!���	9N��Irsw���DH��&����&Br��4I����&Br��:T���8!9p�^xCM,f���
#�8DH2���(������;B��D�j���P�&��<	<������$M��!SsBT�I�n��O���QRhfB���/��(�\��[j����U�I���$��O|=��>�k���k�y�d�6Y����V�K�8O4d9$���{�&J���L��:O�d�i����O�DI������sv�$pY�-u�|lt�����������YL!{���uW���js]'B�����Y������#`�5����=������DI�����I]��DI��1���>!J���'�gk6�l�����(I��_v��l��-�� ,�;��	>��~�IB�����K�'��U�$�s�r�$pU��i���DI���	.a�(�\� ��m�']�;�uj5�|%�-�ODo��TA�w��=��N���'x�j��5�����jTG���x�:�G�s��'c9/I�(�\�<	��'J���Ec�&�DI����P���o�]�������[�l��
�����`!�6�v���"�,=$��9W"��NL
n�G�&J���OB��Z%Y�kfJ���x%Y��{K���
��L����;j�!��,`��yq�D�Z�uGMunj�8$DC�C�:85h`�(�\�>���`�$pU���m%Y�k#B�
&J��5�R���F�K�`_�DI2��=(E��G��������������������&"�U�'#�l����8����B��HFui��H!�l$#Hj�
�n��F���#����&��h)r�/���?19���-M�$hf�h�qHT��F�W<W7���Q����%Y�k�'�l�?1��R#KJ����O����p�$�@��%���4%����U=�'JV�$��kM�$��9d�!�!��Ob�w7Q���}��'J�W�O"��'J��F�B�%9����j�1
0����DI2��=(�Nj�H��|Ll�y��D�j���Pu�j�`��DD�C�j���|�DI���I?��%Y�k&K��|���W6��Rg�����#���(I?��V6��%
z�{s�:'JV.�;oU��6E;�'�M��1����(�\�>il�?�%Y�k�'�����DI���J�����&J��u�R/��F/L��<�3Q�~�F8��������M���X���}�T��ka��W��yi�DI���I��~�$p�`D��~�$p��2�62�ME�%�����lb�	�f��
��Ig�d-����:d�i`��DC�C�j��C^���jdcV��;�:Q������o����V���d��-�dh�-%%i��(���w���`����d�T�uV��'c���	Y���y����ib���Z�7��f�$pM���~�3Q��f,�����2Q���<�^����n���(I?�
#^j}�q�|+L[�y�j"d�O;��:p��v�XNDd9$��I[�P����e#W���b~�O�d��+ik�3Q�������k7Zu��r&J����4��������|�n���(Y������]mc�	������'
���(�\�>i�O�\s5�� �����%Y�k�"������5Y��F�~��-����(I������yG#A�x;�y��D�j��E�j��U�1W��p��xW�yBm�$pM��3n��(�\3�Y;O�M�d.�%"[�93�O�$��� ��&�����{����:�������B��CR@N��T8$��IW��P�DI���I��y=�DI���IWusGm�$p�`DW��6���=�����c��fj�(��q�:���q��0Q���c���6���,�U����9L�d���w��FL�d.{����l4�t����'J����/+�j�G_�-�����M�!�����!f�!`	�DD�C����vE�(�\���3��L�d�����8��L�d.{����m4��f�?�%I��/���!�����������������B��Cb��E8������5�]7��L�d�i��e;�'J���Oz�Q���,�5=��
s�p�$pY�+5�|l4��u=�0Q��z_�	��#�|��q7�p"d��z��D�YxH4�MDd9$��I�����,�U�����'�j|��SB�_'Jr�M	���j7_������3+_�FkeSB���a���}��r%k���5���}o�$�U�d(�a���,�U��a��!&J�W�O�~^�>Q��f0b(�y��DI�����K>6K��#?%)��A�S_�p�v;?(kv��}%B��3b��c9���h�'���l�DI����P���6Q��������l�DI�2���J�F_�P�$������J�lF�u��|[�P�������Jx�i�����&"�M�d0�g�$pM�d�nnN�d�j�40�g�$pY,���e����aw�$�@�
	��
�?�}�C��%k������C;�k��*K��sM�n�����T�On���%9��	�v�`N�d�����$pY�+5�|l4���gL�$�������=��7�M���_�U���&:���6L\�>m
�&J���OFW��%Y�k�J�VN�d.z�-5���������DI��Kj�lH�)u������4�D������Z!d�!�\����sM���k�'Jr��5�P�>Q���}2�`�(�\31F�`�(�\��J�%�%c�J�+�_��3Bc�0�n<�p7	#eu|�����I��!!"�U�����%Y���'}�e�k��U:�]w�$p�}B�����=?*�]���+�*l��?������������=��p��.)y�����Cd�]��q2�+0"�r�}�5�&,o.���K]ZeVX�
 M����I����3q ��>���kj�Nf�AH�$5�����Sb�1��'v���#^q~b��|2�c$"���z.G������,|�����w��eEB���J��_���|��H/��Mj%��$�����Dn���;��|>I��euM���|��HD�W������|�DDx�0�n�g�6S�����&�tF�ga��W}�Uh$��J����5B�j�^�a��i ������Y�����7	
B�&)�kZ(|���b�HD�W��l����HD�W\,��~>-�1�E{Mgu5V�a:��w����.���J����"�����q�Uh$��>��,lj�c�� �A�&�9?Q���	�DDx���R�<?�#^s~��:�O�HD��#�c"p�U�H$��U	}��0o�Y������8�$����{��H��X=~X�f8O��@�	��a�����N���Ij�O��o��m2��+�9?�Tg�,�F""�f�,���HD���O������Z���D>F����ZY�P��{�}�au{�e
���/��U�'���d��=Ruz�8���N��������<��#^uz�M�Y8�DBxa�P�����'����
�$�����	}3�Gu?�������F�
��OOj�5}Ha�Mc�I�NO
�o�����=�,�F""���D����#^3���[c8?�����tF�ga�����G�
���=X�������������?����EXs~����\!r����h�z�Ip�Y���i9�|����f]S��W�Y8�DDx��^�Y]�������jwIV��&�cY]S���~�a�;����$^(�{�J.�I�=��q"7I���?�$�����������q$"���O��n����a���y*G""���.��y���X�0������?
3�5��{���u��~$5���Ts�M�4K��K��
?�}B#�^����G��	�DDx�0b6x��HD���O�������Q���II6�
jcYYS=�������z<O��@R�mN+�\z�<�1g�4�{���d�0�HD�������3�DDx���8Y��i$"������O�'�<�3�$+�~��������hc{T���|��c$���\����O�,�J�xkVb}�7>�0���*��
���u=�DDx�����q$"�kf�r���q$"��>�����'Ga�5���q$9��O��eUM�{?	�������ZH�=x�(L����d�XnRjc�J�v��s�G""���$��X�HD��\+�no������&���p3���|�$�������+�F����q$��>��,�����7I��MR��5�7����9?1����HD����s���1�5�3��!|�DDx�Q]:
���(����>F�
�����N�=����9��I��_�5K�Z5�>!r�������1�5�'j*}�DDx�0�@M����/�%BGu����j*}�$_S�>���5U^Sr����f���d�*}���Y��!�7�1H�$5K�Z���K�o�J��
�f�#^u~�y����:�5����l~r��BwI>�?A)�k����7��	��	f�4�dQ������d��v�8�����dR���#^s~2i���HD����L#D�q$"�k����>�DBxY]SEga���0���>�$�����5��e��auO���kH2��"�Y����8�q"7I���4��F�DDx���d�sG""��b����	�8�E{MGu�����?���IV����cY]S5*����8�G�x��o�[(��&Y<|�����$U�'���<�DDx���f�3O#^u~�O����H�Z�t
�����/;�Kga�������������Q����f~O�?��	�<4���/��5�'�0����j�6�b-��ykA������Y���8�5��Y���8���Dhb�d�~a�}I>�OjeuM�ST�E������HR	�}P�Z�u6P�5�A�&�9?���jq$"�k�O�J���H�Z�t�����#^F��d|2?��;)�#��?A)�k�iE��a��>=4��V��������3�!��#U�'�<�p+T�`,��Z*|5��0q$"��NO��|&�DDx�,b��y�5�DDx������'ga����<q$9�_p���������a>�Uq )N���0U+�~j{y��i"7I���q��F"!��k�p;@i�8�5�J��r9q$"��>�����'Gu��r9q$��>���5}��gu?�������G�
��sZ�J�v\���8��������G""����N��>�#^s~���s��8�5���Px��RU6����o$���pU6�H�������4RuP6���wX��$�/x���Xof�l��X�b-����8�U�'�:�q$"�k�v�jq$"��j���|?�jq$Y�����euM?5Y��~X�����H/��mu%��${8�e��MRu~v��a��b-~l��lq$"�k�O����HD��#���cq$�/~����;��Q[��7U���q>s�#^�c����9������w�9s�#^���<�7F���/������`����tG���o�TLY�Pm���|��u�_$'���B��7��vq"7I�����9E�#^�c���cG""���~�=B�j��H(|�|u�{IV��&���H��{?�����A?�8���~��B��7����p���c��5u�rNQ�HD�W��3B��������S�8�5��3�i$"�������'K�2�
q$9������"������^�;_�8�������R��7���uq"7I�����k�����o���G""�f�'8�G"!��J�������W?���8�|�|�������a�'_�����r'_���-�\z���i"7I����;|th$"�k�O���I8�DDx���_�;��HD��#��������/�������'K����OIN���>�fx�������F�q��U���j.�G6K��=Ruz�[�X�HD�W�����iq$��	��t^��#^6=�s%����e�J�q$9�������z�i>�+Y(\�,������dQ�y]*B�&�9=Y4���#^sz����.G""���d���0�DDxYA�����d1P�?�$�����	}���?��^�	6'��������uM�i?-�Dn����e�&��}-k�O����q$��	]���	�DDx�,b���
q$"��������'K��g��d������j|�?�n� ������5]V�@��{���W��l\l���������8�5�J�-�HD�}�5|�O�.�:����d��oRk���*���.�u9`�>�$�B����Pr�M�
>:��}�����{��H$���5-;��HD�����v�����F�#�`�#^v����=9X������++�~���������^A��LR�����u���:�p�� Dn����u���q$"�k�OV��_�8�5���Aw�8�e���	��ybG�M���ZY���v����g�@�	�}P�Z�t]�dF��MR�������8�U�'���#^u~����8�ea=����2�<�$+�~�ZSV$�m�.�u
���CI��r�Im����$�#%q"7I����ZRGJ���
���\�#�DDx������O����a���sa�8�eMj�,�zrf{��V�#��T��,�:�wP{����sr��X}�Y��uM7���O��MRX��P�d��O������m���O�����%���q$"��>�����'gu77��>�$���'��*������p��nn?o��#I%��A�ja���#H��6�U-l�-�<?�#^u~�0?����:?Y�s�G""�f�m�'4	�eUB��,����0���S�8�������"��}b���u���@�	��a���[�N�q"7I������8����9?�����G""�f�+�����/���Y]�������HIN��jeEB�z�����}����"o�.u���>�$b���������0q$"�kNO���'�q$"�kNO�y<���#�^X$��'����n��,LI>�??)+�i���/����������uMw���`��MRsz���<��#^uz��y�G""���d���C#^3������G""��G-��QO��<�>=4�l�����������^7�i ��^�U�'�r^.���I��O�?/����:?9�y�$�D@�T��i�pN#^���tVW?9�_���G�~�I�TV�T�����~x��y�UI��r�Gm����D�s�� r�����Z�����9?	F���q$"�k�O�-��HD��#�t���q$"�����Y��'ga�f~pS��Ga�����{�?�n�d�@R��gaJ5�$6���J���
K�
w;�Oh$���5
~��	�DDx�0",�yGr�����	��UO�������F�
�o��TV�T�=������:O��@R�mN+�\z�l��q"�H���n��G""���$�g��#^uzrLpw�HD��e4=�LO�a<fIV��&�SYY�OmJ��V��s�q$���\����C����c�IjNO��Y���e�XK����R|������cg��#^3�8���� ��eeM�QO���v�������?	3�U5���$��V��jq �����0��Ko�y��r�ZP��Vb=��%�DDx����<<�4�5�J������/��k��	_��OI>�jeuMW�U���������V����p��$n���X�
�7����:?��B��������5�HD��#��!���/;�KGa���9��G�
�����N�=�0��.�@w�B�Xt���8?q�T���MRq~�~���1��'n��J#^1�p�T�����Z"tTW�Gu�5�>F���t�����*�)�g���a:�?#I�P��Z�,���|>��1���f)V7�^�p��
SY)�R��,�c$"�+�O��fw.�1u*�kJ�������O��V������������r�Q]7,�>_qI����k]u~���,�� r�T���������:?�����HD�W������c$"�+�����c$����*:���0n;��w6��f*+k�gO[M��0n8�q�SB&�O.��U�'�����!r�������4�c$"�k�O�ZN�z?F""��b�S�/g�4�E{MGu5T������c$Y����NeuM�`�{V�)s>��1���~[�B��7����|��MRs~������#^s~��Y�Y8�DDx������3G"!�f]S��>Gmq$"�����Y�7�,�S^���8���/8
SX����	����=�����b�����dQ�>�R����R����36����:?Y���?F""�f��������/�%B+~�������c$��>���5�4���~X�����c$��>��,�������z�L5K�:u,gP�#^s~�w7�DBx���Nj����8�ea�O�'����,�F�~�RV�����7��
�y*G���t�R���hZ��L1
A��9=��(>	�,��*��
��z��i$"�kNO���Y8�DDx�,��6���8�e�:���0����G��Ga�����Q�a�(������8��}�Y���X�|,i"7I�����
��JMe�XK�/��i$"�k���u�7���&�"�E{MGu5T����|������;��5}��gu?���7��V�2�r����-�\z���'4�����$X�|�HD�W��3�O�T���f]S7�*�#^3����G""���.	{&\��l~�$��{��[?N#Ue��1�>���"�����,���Q�<Im�*,�Z(��eg�4�5�'�9�)D����a�8�sG""���HQ;I7��yA-�$+�~_��������u?�������H/��mu%��$v;�e��MRs~2�u��a��b-��y?[��������A-�DDx�0b\���C�+���'U?��|���H��\���ws���HD�W����|�!�DDx�������HD��${3��q$"��>�t�D=9Xb���tG���o�T������+����V���I�����Ps�M��e�?!r������>��5->n��}����{c�s�G""��cO_�'_���?�q$Y�����eEB�����7�|5����H/��=j%��$�?��$n��uM���������9?1n>��HD�W�����-9�DDxM�7�9��HD��|��%oO��U�+�����?W2	��=N~���g��4�������R��7���� Dn���������:?	|zv���s�*��|zh$����j:���|5|�#����I��J��<&�ufx8�����=j%�$�����q"7I������G'�DDx�����sG""���d�y{����a�d�y�L������,y{r�d��s�G�����O��{�}��e[�Qh�y��s%��K����?�q"�H���d���2�DDx��������H$��,�&?�W��HD��MO�\�zr�dZ|2i$9�����e5B�8�|�?V2-P� $YX��u������Rq"7I���u~�HD�W��lP�'�DDx������p�*�?	����lz�%�?F���OP����YE��s�����HR���I�����������<W�k:&�DDx������kG"!�j������>�#^3�x����G""���+,y{r�d6p>#�$���U�{���u��8�d~�EX���<�4��7�Xx������F""���d��������V2�s�����/��k:���|��q^{�#�
���v.+���������2}I��r�Gm�������q"7I����~Hm�(�kZ*|��q$"���O6��G""�f1���=�DDx��W:X���`�p���;���k���}b���u{�2��d���k]u~r8�Ih"7I���,\l�������g��'q$"�k�V���~�DDx�����g���<��#�&��A��Fh�;;.��3q ��>�U�kj
������I��5����#^s~bg8�G""�����p2#�DDxYA��������X��d���R;�	�t.��a���|�!�$�B����Pr�M��sa�8������C��8�U�'�r.�G""���d�B?q$"�k�vs��q$"�����Y��,���s?�8��N�������~���{='�q ������Z������AH�$�uM��9��#^s~�s~�HD��\,q
N���/��k:�����uZ��>�$���'��*������p��:����������V�������F���M�x�MB#^s~�L� ��
~�V	u�~~�HD��#����'q$������Y��'gaS�s�G��cu�=XZ$��O�?���<I�I&��_�U�:��� Dn�����}�HD�W��,�������F���q$"���'tVW=9��6(&G����ZY�P��{�}��uop��LA�7�����d�H��^'U�'��������:=94L�i$"�kNO����{�H$�	����dz��p>G����O��������o�?���{�#I���'U��zuh�,v��j]S�����wY]�R��v�|����9=�f=z�HD���"���K�q$"��z��Y��,�����G�
���=X������������ 
$�������[w^.���Ij�O���Sq$"���O�|^&�#n��5�����i$"��>�����'gu�:�W��H���7��euM�~?��4X���y�UI��r�Gm����d��u�8�����d��dq$"���O�p^��#^u~Lei$"�k���a*K#^vV����=9�Lei$9���������{�?�n($��X�?S���&Y�v~��A��$5�'�^���8	�U��.�?�O�HD��#��;��HD���O���zrVw���}G�
�o��-+k���p�~x���������V(����3��1��#5�'����G""���dq��q$"�kNO?�3�DDxYA��������9��d��oRk������6�Gu��8/�����'_p��NO��5�A�&�:=Y�3���H/��Z*|�B[�m�������>�DDx�,b	�y�l��������0��Q��X`
N#�	���U5���$�v�I���U�8��{��Q�B��7�:,�XRj�j%�U��cG""���d���X�����V������#^���$\?n��OI>�jeuMWW���HR�}P�Z�u��$Fj?��Z�u��|C�������B7�8�5�'��nq$"�k���nq$"�����Q��'GaV��H����`aY�����^�q�M������b]��R��MRu~�5�V��J�j]�k*�b5�l���+�TZ�j*��������'GuW���>��t�����*�)������?k���\���X��7�1H�$UK�n�@���[V��T86K�#^s~�is�7������)�O�'��m��q$��������-��Tw3�<#�#IU��k�O6�����Dn����m�ww������m��>�DDx���6CtG""�f�Y���H$���5UtF=9�9���H�	���`YYS={�j��y�����L�����b��z�!� Dn�����F����:?Y�y_o�����%�f�;�HD�}�5��O��n;���#�
��W���5U��bP�Y�-�i�8���~[�B��7I��'��Dn������g�F""���d�9j�#^s~�+u����H�Z�t�d�3�4�egu�,����0���-�$'����55�{��au��.$����u���>g����Ij�Ov�� ����^���>���8�5��}�M�q$"�k�����
�na�}I>�OjeuM�ST�E��t��#I%��A�j)��A)�8�������3�����:?Y�k����uM�u������ZAxYA�����d3�#%q$y��'(euM?��C?��]�T�F���t�RW�������D������>
�,�e�XK���,L������8�����E�! \��CYYSEga���0Am���8���/8
SV�TO��
�Ga����*$�i_p�j%���4Q��MRsz����#�^V��T���Dq$"�k���	�����/��k:����
3���#���9�����?����n�y
G�
��sZ�J��AO�kMc�Ij�O��*�q$"�k�O��}���l��uM�U6�HD���"���}�HU��euM�H��3��p��G�
���=X�������x����8�d�/����}��y��bUX��Tx8�q$"���O��Ax�
���5
�v��HD���)k'y�yA-�$+�~_][V�T�������u�;�H/��mu%�$�Z�p� r������ |�"��R���G{��G""����0���HD��#�i:Gmq$�/~�����9Gmq$W�U�kzX}���HD����N��S������?�p�G""�&�>��{���/������`�����T��s%��F�6��J>���Wh|���oSO����d�2�q"7I���� \��+�kZ*|_�cO#^�c�9E�#^������������cO#�
�����	}s�_�{�����#I�P���-�\v�<$����c7I����O�t���1��'~�f9����8?���L8�DDxE�����,�F""���+,y����{r=�*4�����J\a�Pm����������&V���j.�I�����A��$�'��;_�Y����Y%��|��c$"�+�~p|z���WWV%T��W�|��?|�I>N�OjeUB���0���~X<�>w��~��B��7���;�� r�T���>:4�U�'��g�4�U�'���[�F""�b��0��p������,y����0�|��Hr���5X��7�{�O?��	nGj^u�\I���{D
>�4�{���D�����#^sz�hU�3�4	�5��z5������/������+y?�������?V��j��q�� {��+s.\�1�da�/��5�'����|B�&�9=Q�����HD������\��c$"�kNO�]��8�eYMO�'��OM���i$�����H��nZ��+��7'�$������k����k���%��uM�Z�Oh$"���O���q$�k	�j��}B#^3�P�9sC����s�t���?X�U8���I6��,��������>o�H2��"�Y���C�����a��k�O�����i$"�k�O4�����8�5�J�:�8�����������?�����7:�����	U���]����#,���$^(�{�J.�I�}8_�Ql��f]S�����]jKDY]�R��y��HD���������c$"�k���w��DDx��W:X��,���%�$_Y��{��F��'V�^��.3II�//��U�'~���!r�T��,\l���������r����j	�z;w�������		W���
&V�]���WV#����C�;o��I&��A�f]S���d�� $n��uM�>�'3>F""����8���������q8�������0�����s9���X��d���R��������e��Q��,�F�x��oR[(��&y|dN7I��MRs~2��5�DDx���h�z>J�q5���q:������a�8��,|��� ��I-��Q�Y?Z��oIv����`a��A���������}Hjb�gaj�5����9�����I
��
(=_l������E���8�5K�N���/��k:������pZ �$���'��*������pd��q��gN��oR[(��&��Oh"7I�������8�U�'a��	�DDx�������8�5�3x���H$��U	}��0oO����)JI~����`i�P�>�z����y��L���k6�F�;B�&�9?1�=�q������c�s~G""�fa&�����/���Y]�������D>F����ZY�P��{�}��u/p��LA�7�������Q��E�uRszb�:���#^szb�p�|����:=��y'u����"�4=�MO���[��~�ZWV$�������
_��kI*�?=�Y��!y?O��Dn����m�@�.5�.�kZ*|_`�M#^uz<|zh$"�kf���C<q$"��z��Y��,�4�����d�/x�m5��gu?����=����EXs~2���\!r����Lz:��HD����L�x^&�#�k�5����#�q$"��>�����'gu�I�W��H���7��euM�~?��4Xw����8���~��B��7�<����Dn����i>�9r��������[�}�DDx������T6�DDx�0b��y*G""���.��y{rfZ��T6�$'��Q_X�tv�����}.$�1�����Y�R��7����d��!�K�
��y�L����uM�����F""�f1���@G""�l~Bgu�����1���F�
�o��/+k���p�~x��9�I��9�Pr�=2��q"�H��������u������Y�3`����9=����q$"������O�'�x����H���7��eeM�FG������K�q$���\������3��1��$5�'���a>�DBxY%�R��v>G""���d����HD���"f��{d�HD�}��QO�������q$9��O�����������?	3{XU�I���)�\z�,K/����Vb��K������m���F""��Z��x,i$"��>����g����#���A���i�J�`WrI*�jUK�����$H�G�UK���7����9?��o�#^s~btC�#^3���!���/;�KGa����#tC�#������eM'��?~x��y7uH2��"�Z��bM�8������bM%+VS�W�kj��������5�XS���T�euM5��O��Z��d��T�OjeuM?U��~x���lQ�/��UK�Z��$n���X�b�yl�����h��1�U�'�>g�V�c�/�kJ�����d��q$��������-��T����<G�,�t�ZW���<�4�����$���F""������>�DDx��� ��#^3�p
��8	�euM��QO��8
�}I6��,+k�gO[M��0NC��8�d~�EX����tb��MRs~��;/7����9?q�|��G""��b������8�E{MGu�����B{�8����}u}Y]�O����^8�f�#I�P���-�\z���|�>�A�&�9?qh>_k������e8Gmq$"���O�>�4	�U���5�Wy�HD������0oO���m;Gmq$9�_p���������z���$�X}���:?��3��A��$U�'al����:?9`�}����a�`�}����Z"4�z�B�l��#�'��I����r���(^��N<q$��>�U-��5�b�c�Ij�O�8�A-�DDx���7P�5�DBx���^=.�HD���4?��O>mV?���������5����
����p������*���5�'��L� r����x{�C�8�5�'�����T�V����p�!�DDx�,�/�y�'�DDx������'ga����^�Hr���(LYUS=9*6��������t�@R��ga�Vb��&���I�NOvo�M�4�/��Z*<@i�8�5�J��r�HD�}�5��O��.���#���9���������+\
�)xI*��iU+�.���'q"7I������f������eT��I�������@��8�5�����T������$����i?��H�������4RuP6_����>$������d��yA-B�&),�Z(�n�<�DDx�����s
G""�f�<�5�[�F""���HY;�eq��8����}u}Y]Se��~�a����3�$�B��V�Pr�M��3\�1��$U�'�U �IfY)�R��t���HD�W��s�8�5����Q[�+���'5?���`bE#��j�Z�tU�9k�C�Q^�s���|�+EFy������BG��k��:n�3_q(2����t�D=9]����~����o�Y��vo���%�~X����#I�����Tt�}2A5�8
����G�T��\�&�Cy���j����"���gu������(/��������O��~JV��~�j(+����~�a�/��'%�Z����Ts�}�L��a��}R��������6
EFy����a~HC�Q^u��+��Pd��D�u?��J������t����Q�5��Pr���4y/��k��0?~X���)9�$5����Xt�}r�a�8
����\e��K��}(�9W���C�Q^3��4t>�CQ^V=T��X��@�6���8�|���VV>TM���?�}��PR9��[����q�Wa��}Rs��M����C�Q^s����9��C�Q^s��=���n���(��Qln<o��C�Q^���s'oO��l^�#�8���/y}����#���{�{���d�?wR*��6Y4|6i2�I������IC�Q^u��
gt�CQ^�����3����(/�����������J�q(9����<����g���O��
�H�����jW��(G!s�T����*EFy���>@A�8�5�*��6k�+�C�Q^Q�Te|2U�5T��C��_0Y)+(�f������#ld�CI�_0W�Zu���!s�����f:@���n�����9Cg����EE�y��

EFy��b��q(2��N��Q��'GQv':�P�������= ���aOYI2 ���a�Z��V��~�r�U�*�8�q(2���U��A�!�W�-���1EFy�w_��Y�������E�8�����m�����8:����wX��CI�V�7�-�\z�<���������D��_@�"����&j��v����(�9W	l�C�Q^3�
�����(/;7K�R���K	&+q(��L�_��5F��>�z���'�3�d����]s�F�	�B�>�9W	�����(�9W	�>7�Pd���(�z�Pd���UH�z�Z���d�/`��J�������0G�L������G
�w�Q��'U���;�Pd�W��x8��"���\e��q(2��2
z8�g�����8����
o���������m>��CI�V�7�-�\z�l�\�#B�>�:W��lP����s�0��|���(�:W9�pP�����1��Y���TCyY�[:R���9�>oj�C�nn���aa��A�����>���8��,�K��T��zh}N��(D���b���i��3�4�5�*�x���8�5�S~�Pd�}�5��O��8�C�'�_oe�G��������=f{����J������L=��<W����Oj�U���8�5�*�[�s�8�U�*���8�53�c�0W���(/+B�FGj���9����0%�/�������e=~x�&,4�dB�����S�
Z%�Q��'U�*�t��"���\%�s��"��fFq8'���(/����_��]�j������/`��R�Z�w����w�K�1��[����8UY����^*�*��i#��Pd�W��,��b�k�#]�qW����"���)MUF~��f���i(����*eI�����O?���|��c(����*5��>4/��y�;C[���2�~���d���j�r������(�8UY���Pd�W�(���
�A4�e]q�H����,�b�DC��_�:,������~������F����}Xu����|�/����s�m�/>
EFy�������BC�P�jVS]�0��r����������?��P~���BC�*������������O?���;P~���}���:W9���>!s�����aA�T7����s����>�"���\E��<��C�Q^�R��F������T��VK�����?��_~����'t����y����~�O���'f������������f������eW�6Z)�h��j��,;��j~��=������}�m�������������������������F��������_�/�������+�3���fc>�~��������Nv�oG������o�����
5d���?������������������g��G�EO���������S���1����d��3����=��#l��/~���~��_�����������??�h������?~��~B������|����������
�q�����F=n��'o��?�������������������������������N�m����������_��?��O�����wz�����/��.������������}���������?����[�U|�yo#�\�������U�Y�_������U���5=�����h��S7�����v�����{��Y)���V�t�����d�>I��$���F�'���$mQR(5n�t�����H����A�g5��HRB��FI�T� %iIFI�I�*���?4<q��NJ��>[�"I�*��C}h,0NONJ��>;��D���</�:�t�I��K��Ur�0�C����HrOYYI�����EI�T����L�����K}v����*M^j
�j��������n]A������Ro�����P��m��6Sv')��$�3J��$}*+ ��E�\�H
�CEG���H�v(P\�5c�cE�*�FB������h)�F�f��������$>W��<sk����_$����&I����g��4�g���Ic�[i���F_����4y��*�%�}��F�9��!`�����$�����d�K����kg+t�D]��I7�M���������Y�*M���I��KO(w � ���A�^��AI��������z&	��*�JR���W%i|AR�{I��"I��U�*�2�������Wi,�J��K����������������d��B�$y��d�*������O���d��UB���*�������gO������%'t�<$��+����r�M�/Lr�,%i�(�0�5wg�O%�����"����\�X$I(��6���'���f/.M�.i,���2�i���VF�IwCA��9��������=�����2���$�~���9�[�����$)h: �%�/H�~{���Q��f�sg��4�1�h��K3�[��-�K�b�����`�]%���-������]�}&	�-���>=qJ����oi.��%	MNf��4�[��v���oi.��������}Ks���(������q��\�o)JR��qI|&�����"��IzuY��yV�?@i|A�yU���)���**i|A�T[����UZ��e��I�_6�IrrX�8���$������2`�a9�C�{�8�*�����I�eI��J&����W�K��+��V�
�H�+�^Y>����H�+�^[���j���r��W4��
��;��s����hz��L��N��W4��7|���sw���hz�%�k��|L�C�+�^���=���^Q�+�^~�?�4�k�}�|ES������]"_������/�h���/�~�=�oc�|[��W4����Oz�oK����q�:��|�!�|ES����������W4�����q^y�"_�tc2�_�q;_�(�M��������q���Q�+�^}�?n���8���4��D8��D�/H��\����Qc���nr�K�
n&�������q	�yo�������q[��|�����o�[��$����%�a>O���$�>�}"I���7j|A��S�'�l��_����W<�\��_y/��IvfgMf"7%��'M��(f��K=Q��^�JZ���CH����j;�ll4�@�-|�>$�z����h�h�Q�b����F�������I��N�b`�:o��Knowoc�����o���������F�/Hzuv��<��acc����Wg'���I��76�MR������5� �6�}�PR)��{{��J:�IK)�FI�>qJ��������H��^~��ao�I���X�������C��|�������s�K:7>��X$If3������W��=M�9�^�0���$����Fw��$�����K�?/�G�E�d&�I����$�8�����O�X���Lt�W���������B�B[��q@�Z��������y���F'N��4�n��l���$�~���I+H��	��f��W)L(����,T��!)��Px�g�2G���(�����9x*����x�{/_�'S83�w�F�%���a���v���I���O�)��ae��L��oi|AR��{Z�GK�B3�i�oi,�t���3I�FIe������8>>}H��i,8�3
*��
��ZVN�o�n���$�U��_����$�W�������'��8`�#�(����'����/.j|AR�-����vI��j�h�B��7i|A������yX�+�Q��^_�}"IC���I/og|&�L��@���{���r~h8_&����/���9�(�M������[a��W4�4�,�W&�(�M/��#����,�"_�T;��785� ���r��px�X$If���AR���(������;Px�Xr^���^Ip��
?I�]�f��FI�WI&�zH:�F�/Hz}��P�]k�T�Nh�m�|~�6����$���'������4�H�eB���<q�o��f��x�����;
��(I&d������'�$����{7�Mc��I���C�y�d?o���*�$�vP%���n��|*iI�t��P�};�%������ ����$����qZ���(j|A��W�UZlIdK[�j�YH�ARiK"u�^�~�k8�5�TA�;l�����X��$�."o�������������>�4�H�����V�����5
^���I��!�\%j|AR�'�h��J��2hi��<��_��2L����$��Ic�$���;�pQ���_���k�E�E�d���U�$_���CR�)�]�8�X�	m<�vQ�s������'���6��=7.&'2���;J*k��7I/_�'g��
0_"�E�d6�Z{�|�4� ����|�����t��I~��+�	�7I��8?���|�����g��n�{���$�|��=y/���I����W����[����5� ��D����+j|ARuh:`�0j,�t�`�`�������k�w���QB7�gB�_���K��������$�(t�_�zJE�/Hz�%0+�B�s�9>�_���^�7����e</~E�/H��^r�9''Q��j���2)�dJ������KZ@�TJ����-���
''v���I}F��H�K[9FI7"/���m��&�/H���m�I[�������~v�0���xrr/d��'����K�4� �����	��$�������K�_�T����iI��f�=���$�5H�����2��1E�������=8��$�~/�zpF�E���%���&��5� ��{i�O$Ys��$�.���p���$U��=D^Q�����^�(��*�[�|�	�%��)j|AR��{[���Q��n���%�6���I�o�n��$��`�����M�X$If!�!��F�/H���EI����B��Z�Q��^����=q���K!O2��P
�����2�I��"j|��d���0�$�%=�)�$��IH��c�wI��}�%Ar5,:#y=$���(HN�q2��������U�~���]��_Qc�U:����AR��W�$��5J*���^�
������$����T����$�A�0�%���q�z����
���Q��
b��IF�8�5���UZ`�tn�'���I8_Z
]7JIZq��.�8�'n��Ra��O{y�$m8_Z���<$I}�6�/me+M������v�/mehi����?���2�|H�2.�|��C�C��q��B�|�nL�\�������.�z]����������1E�X$I��^�5}Pd6W/�V ��w��*�<qIH���N��2�#J*[x|Pd^IHW���{����:�<����%�U]0 iI$������G���_������7���������gU���������������O��������o?���������_�������QZ��_�������?�����������{�������z|����}}�����?���7���??���������o?~�����������>���
������� 1?y��������~���;����/^V��������b�?��_~����
���?~���0����
����'#�s-�s����~�����t��F��tm������~x�k���o~���������~���?����N���G����aG�'�#�����/�������u��������I>�O�w��_V�W���P��_|��i���_�;������e��r�Q��i����W�����O�r�0�K��JZs):|�e����@m^:�Z�
N�Eb����U�}����������������O)���a�P;.J�o����?=nb=��W������?�?N��O�c�9�����O>	����������{��~��?�����������}���O?���$����?������G��=f������o����{G3n�������s�����w�O�����������?O�������
�^~����?���~����_�?}�����/��o���������o��q�~�������{\�����z^@����/��?-�#2���|�x�G�����G�?]�@���o�a����������.��������>���y��g�����>�G���g�z{��{<~�����m����W���t���%T�+�i���F����\�����{������VU�]=T�����^	�}�������;���~%�m_	v�$�^	2e�GJ*5g�P�+J�|������l����{W
��y"����
|�,��_����~���#?���g��w����}W��y��������?W_��j4��
u�W�<��F��B��8����9]�:�����j�"���OS���w�g���tOk���1�,�M���O$�����Y3��5{���%��1��ni�p�\����������c�g'���[�$��p�0���S?g'�,N�����yg'��i�pvB#�g�~��*��W/�(R�pv^ni�p��x�B�Y��Y+�$9}������vg���M�Y���m)g]?g�
��^=��Y	��J�=��-)g}?g�A�G��1�i"�z�Yoni�p�#��$��������*����C�]��� j�j��H�$�V	d��oE�]�L�jEh��j�<��~pW��5	��c���9�m�(jC�]�X�~6��-���c�!�nL��:��l�<���\P&�Wo;�Q;���'[�:��m�<���&D�=���c�mC�mU�@* ��<��	sq����1�:o�<�����P �7�����{$W�K��0����jKa=����t@�\7�'�������/�rjD������5N���!�_�T�)�d8��������Z�D�p�m��V�'���'a��O��n��N9h�5gv44��h����8	sGHEI���~��w����hN9h?���H�k ucQ�h��)gV����g�6N���j�s'�E���(]�~���BQs������ u�U����RGQ���~�������1-;�&b��(��!N�\;���`�t����%����8�r1�2��xk����6���_@�b��c�nP9������z)�9�\��\�1����.���u@��s}�sYq�z�\�����G������\������9wIsn��jA�]�m�P�����������&9w��P���k�s�������sW�s[�l��[�s��	�����9wl�Pm��[�s[����[s�������1wlP���;���?�1wOb��1�
��!��c��* �s[{����;v��������u>u �y�m���Gr�~��r�<����)E����x��q��d��_:��%�7_uD�[e��<�6^3�
��^��Ny��A�3�6�<���*���8	s5 ��T� ]��)�W�� n�p�C����8	sG@\?��_8���x���~��)?��1����\���%���<tD��3�%�S��z�g��O.4n�j����<V@�S�qM�p�O��~�3.+N���W.	��_:��%�!�4N���Kjo�+��@���jn�t�[���k�S�"��<��&!��k��k��S�"��<�����wH����\�����k:�S)��)��N�<R�cr���)�')�t��<R��S�iO-H����� � �.I�5��)w�Sn�����H�C��AhE�]���1�Z�rW�r[�S+R���\V���R����������1��:���r��f%�o�[r��������!wjO��{r�';B�����c<r�<�N����������%�
H�!I�S�x* ��<�N���)7�)���b�����c<u �y���S����#��lv&`�2�7��^���O-���E��������Ajo�WI����Aj�������|��q@�(�f��.a�6x���A�_@�h(II�3�6�
�R�u`��=[H���~�2BM��i�25���QR�u�Z�m����/�Z�	��to�T��ht1�r��8s^9�FIW��j�F��T�mP-�����'a.6oY&�Fi�|��j�JdJ�6N���QR��<�����^���P-���6.����hn�e�'[�������O��Ab�s��	��2� .���lO�\��Bj���K����4s�['T9��9��k�����*����s�['T9��9�=�$a.�r!�Ws;&Tr.��en�P-��K�s[��Y������1�Z�s��.s��jE�]�����s��Bj��vL�6�\����:���s�<���=	s7��-���9wc8�uB�#��y�m�?n�n.��jn��jG�ez��������9�=(a.�s!�sm��* �2M]l���@�
y�m���v.��jn���@�e����	���{�9��7w�s�$��~	�:�������u�%�_�N�Ui�rI����U�������U����ck���rI����U�������U���	����\�sm��jG���\�8�ZG�\R{#a�0w�%�Ws�%T�Q(1���qB��\R{#a�0���������(��]�8�Z���s.��H�;�������u�Q"����u�%�7	sg�\R{5�_B��+Jd8�qB������F�"a�5x�����%T�E��y�u���"��<��	���9�&9��K�V������'T�C�uy�e	s=r�Kr���Py�\��\�:����>��l�"b.r�Or���P-��>���uB� �.y�e	s��%���cB�"�.y�u��9w�s.��H��"��I�u�9w�s�k�Pm��k�s��E��
9wKr���Pm��[�s]��jG�����&,����{�s]��jG�����Z'T;r��pn��* ��i���P���pn��* ��<���=	s������	���{0��:�:�s�<���=s7l�Bj/��~	�6@u��i��'T��R{c�'b��W�t��%T�2(��y�8��|3H����������^���PmZ��|5 �8��4|3H����������^���Pm���Eo}��j!%�7f{�bSR{5�_B��%�����	�fF4�f�	s������/�����Eo}��j� %�_G�
��������mZPb���o�Pmd��6cnk��.��jn��j��<���v���m�l��f�m�B����^���Pm9�k��8��,r��sn��$vu!�Ws�%T�C��z�4N�6��������0������j�Qy]��K���#�z�C������C�Q�������Ywaz0�2���M��1�Zv�/���]�v�
Ck{���M��1�Zw�/�����wW�C��
��������
����2���6$��i�����/�6ao��jG�e�<�6�wG���f��^��Bj�v��B/���!����7��W������M��1�:{�f/���=�{�<�����y!�	{�EV�����{QC��j�{I��������Kr��K�v5�F|�V��%�wf~�* _�{�W���vP#C�l[b	��������I��}In��~���7����j\�#�/��3���w�%�	�%W���F�}��/"����;�?	���.
��_t��_���qt��_�{g�'�������W����	��D��m�]��/��3����k��_�/��g��e	S��������I�;���������j����j�^���2����$����6���_|�;�_���j_���1�������]�;�W��q��:�����Y�m��z�_������G�������_����~z��%M��cz� �.��������0��zua_�~�4��������2��[�W+����/;���wC�]���;�W�����n�^mH�[�~��p�!�ni�����wc�W��v��=��'W;���f_�1�
��;���uv�}s�����7��Ww��D����n]��s�����@�=���;&W�����n�\�?������
���&���\�!��|E�����*�v��;3?	�;�M��/�
jC���B�������Ar�L�$��1$7�o��*�5���>����$���O�_�Cr������0B�����Qc��*���������v�!�	{�EW�@���4�yml�����f�m�o#`�R���_r&��etB�;AnJr3�6���S�M��/�
�F��B�����!6%���������bHm��~�U�j���}ml��%�{[�/v�!�	{�%W�"�2McB��}m}[��
�/��&���\�����yml�G�uy�m]�.`�R�����g�F�_q��5D�ez�(?DF��y�m]�*`�R{y�_�:��|�/�;F��!a���������������/M��^�����X��0wE�]�����`��1��b�K����oC�ez�(<$��z�<�6-c�R{1��Is���#�2�c�����;����ZlCj/��4e�{�/�;F��R	so`��u��mcH����Vz+_>�]�w�b�,�������Q3��!�s_Z��|�v��1����{�����c�%�s_Z��|�T�p.;g18��~�_5��K/����[��)]��s�qNu(]��u|t����Wx�eT��%�9wgT��%�_�W��^��o���
J�P�qHu���$�+������6����]�Q"���S��������k�uI���~1�1
(��]�J�;���������	`��^���SS@����v$��5�����Mz�h��^��T���e�DK�kwIn�����E���M�����"�Z�w��I�a�w-�����y��y�_Tu8�]����:�r��.����-y��y�cV��w=��S���#��<��/w�w}�w_��Q��-������uV� �.y�e_,�.��K�w_��Q�������l
	wW��5��l�-	wW��5���U��{�6������Y�����y�}�H��!�nI�}��F�����q��:���w�<���ns���{�w_��Q��!�����������y�us�# ��$��VB���C�
��������m��p ���>��Y���{0�����p�@�=����X����6��^���U=$��[F�9w�fU1��F��q�mV��4&����-�zH�@"�9fn�U=�,�����l�k��%������-�Z=�D�z��6�z�s���W�l�l��e�K���AGL�eU�0*��t���fUu3�;25-��C��n������U=(���;�����t�n;C	{�[L�{��[X�P��D�h��6�Z�I���n;C	{�YL�{��[Z�P��D�c��6�Z�y{���%��^1Q���nq�C�G�L��6�z�	`��/i�~9$��N1Q���nq�C""/�.����by-���_���&����u��C������q�C"�c�����!��$���*�����Q�u\�y=����������c\� �2�b�mW-����Ck{d�%�������c[�U+2��g^vV �����&��t��VD^�O�m�Wm��ky�Y�����$^�1���x�.1��.���������H��#��I�5����i��"�"��y����7 ��I�5�������Q�uZxCx�9���oH��V�L�����M�=x�<��S>wx�$��~a�x�1l�'w��Kr3�������Kj�����R(�^�����
���~�Z�wI���~a�RJdx�5��6�.����f��wI���~a��;Jdx�5���Kr3�6���Kj��������D�w]��J�]������w��%�w�~Y�2%2��gU��������HM/]�w�~Y���wIs���Y���wIn���;�s(�tI���eUj�%�9wgUj�%�w�"�9��K���/�RvD��6���E��y�m����y�&yw��U)��k��������uy�m>�r��.��S���!�:�w}���#�:fO3;����#��$�N�*���������������yA�]��;u������]�:�Z�w�<�6^DP+������Q����2��[GU+����n� rC�]���1��w7w}��jC�����T�$rG����;w��v����]�:���w�<����E�E����;w���/��E�������������;wL�$��o���@�=�-������{$�w�W������*=����#/��	���+LT{u�_\��%�KiN���
�$7�-��B���0Q���~q�V;J���C��Jk�p��������&����/��zE��Z��=�#b/|8Hn���E��D�W{�Vz� �i�����!+%��wskw�/LT{u�_b���Ls=4N������f�m���/LT{u�_b��	$2�a����N��������5���j/��~���G��/��������
��L9��q���1L�{��_`��B��j���
%a��%�9{[3�E��I���+m�y��0��
%a�C��w8H��z]zm��J;�^�?�fkCI��z���z�^��^�1���L���N�m�E��\���.�>	��cd� �2b�jY-������yE�]��k;FV+R/�"F��$�]�zW�ia��wC�]��k;FVb/�#F�������q][��������cf�#�2Mb�j�Y���;���5���{�{;�V����U��* ��{�J������^�1�
��L��Z�Vro`��-�/a���{$��uL��^�O�f��;��G�{�����`/����/��%r��8��^��q���;*��.I��_f5*�^��s�qf5*�^��y576Wk�rI�u��Q������qb5j`^��Q���q�+�$^�/�G ^��3�q^5�@�$�+17��K����V�fD����i�h�wI�Wqp4@�$�jn��j�JdhW7���	h����5��1N��$�jn��j�����n�T�����Y���;������r�q�Q"C��qN5Z ]��;q�8�-��M����S�Q�2���T�E��y�m��0:$]�$]�/���cH�=�%a�C�u�����z$]�$]�1��H��#��!�G����.;'��wA��I��S�Yw�X�uJ� �.��n�f�����$i�w��V������uN�"����n�N�����&y�wL�6������uR�!�n��f����wC�����;fU����:���x7fu���$���y�$���i����3�;�N�2���jn=s��!�������[�U�70�����"��7���cbu �������`�w[3���^�UC���P��0]b��8�2|;H�������!��&���Z�-
�'F�/@	|<H������^;�xD�WF��/#��7����$�+)�b�K�M��/�2�F�����=3+���)���N�_�Cr�����Pc�z�f�	
��$��:	�S�M��/�2&��|]����w��|�K^����+��&��^�iC����4���)���N�_�Cr��K�����|
]m�Wf�����Q'�/��!�	��W�"�2]c�i_��k�e�I��cHn��~��q��L�m�W�!�:�Yu"�"��4�����G�e:�h�������s�����_���������)q��
�<��������������������������a��I��irN���W����w���o�������?����o��������ON�}8��b�si���9jD�����>��P���l �~��6�c.�c��-S6��|�#����)�C^;��Am�\r��R-36��!_��|��x��������!�>j��C��@&��2a�;2�����6T��3�����c��Lt�e����/]d>wW<_u�@�������Ql2��1����jD��4���]�t
�a���u|w�{��t������P#��������gk����oj����W.�qH���j�%�9w��5T�Kr;dmJ����n�\
5���������%�_�ww�^�4����j�%�9w�S5T�Kr���+����W.���_V5�#jdx�-*���Kr���7��6�]�p�_V5�9�m�UMx��v:����wIl��~Y�d���n��j�Ft�i{���	x��&���UM����gU��Kr3Y��f0�Kj����yE���'AE��%�{g��5x������U�E������%��H��9+�8��"�M#��WM��1�;7��&����%���f���2��1�����a^�J�����35"�����3��1�Zz=�l�n	{����|����wIS��1�Z�z�z�������2������wMc��1�Z{W{�������r����!�ni�;fVr��qo��jG���m8���{�{�������s��:���{w�{[O�r�����cj�{���uj�{���#��7��w��Z�����uju �L����{������R�y�2������6N�f�Crs����x����������+���P��������;������c���@�t�3WkT����c�;����������2�������
���qh5c���Y5^�����|i C{�:�P!S�6��f� Cr3�/���@f�4���}��5*d�B�����dHnF]������2�������
���q\5c��Q�x�w�2���m��g�!�K���mV��A���*n56���2�����a��D���h��j��1$7w������1�����9��D�ssU3��!�_IP��c�K�������A��E�sw[�T�@��~%9���/�c���~�.H��&2���:���1$�+���}�|iw�ttQ��C�sw[�T�>��~%!v��/�c�B?wWd�K���_��
�������)6��/�c���~�n��2���:���1$7sJ�uL��c�K���%���;�����������w����:���1��uL������{������*lCr3����s�|�7�s�@��������Iv�!�w[w�q�|i�us�����1��[GUv�%�w��v�%�Ww�eUV
(��]�8��
x��f�mLDV���������������_@���_������7�|��������������������-)|���������������~���?|������J����>.�7��W�i�4��������������#]�S���=t�OEcs�}C?��p��h�O�F~:�������h��h^�q4��?V�g���>��>^�v���|���p���x� �u��"8�H��C$�<���������j�Ap��ux8(�u�3��(11�GH$�����| �D�A�Hj����?��Pb>ad�H���� R�1����] [$�Ws���v9Pb>`d��H��47����@q-������O��(1�/�;X%���l����xI�n�,������O�a
�1�i�cU]q;T� �iql�[	swI���~���:wf7�s��,�a���d�4^9,��~�X�&�7v�J����dc���rn�21Q�g���{0{i�o��,9��s.�
]�\��#����a�z������5mk���Aj3�����n�o����/�rjD�\����*�f�����x��S�� �Ws�%TN+��Pjl��o��:����o����/�r�@�L���	�G47_=��F7B6Jj���K����D�xR����FIm���x�3�������*gV���Nj�P9�(��J&T��+����Z����o�-R����U	s'�FIm���������%�&��*7�)�|c����3d����H����%�&��*g�sI�����Z�\�pn�	�E��i���P9��k����m�0�!��<���L%�u��.���cB��s]�s��	�G��y�e��J���s}�sM���#��<������r�g���6wA�]��k:&Tr���\6��0wE�]���6��0wE�]��k:&T+r���\6�19we8��b���s�$���	����1��:���s7�so�s;r���\�1���sw�s['T;r��pnksr���\�1�
��!��l|+an@�
�6���rnHr���P��!��l|+a���{�9���Gw �i���P�9��s.�
���\R�u��~�%�Ws�%T~8Pb�s�	���jDs���:~�
8��^���%T^�(1�����s'?���/N������>����|�Y�=�����*������������_�"��Vgk���,,N��x��B�@o�J���a�x/�e�&�_G��,p���^���-����o�)���+�7��:�e��7��jn�@oYW��?}cz��Mj���7��oH���~���y��?}���E��&�sg>����%O�L��e�&�7����@��6cn��g	^�����_�� o�|c�������f�5�|���%O�L���Qb��
;!�0��&�q�h,T� �Ws�z+�$�7&������4�z��Kj����V�$H�oLH%�U�e8�q��*�\R{1w����D�4���J���sW���x?���sI���~	��MI��	���#p���l��]G�\R{5�_B�biC�|cB*b.p���l��5�\�s�~	��MI���C�\��2��s��\�s�~	��MI���C��	8we�6��N�\�s�~	��MI���C��8we���W��8��^���P��D�4�x8$����L������j�sm�s�~	��MI���C�\������
�9��9�cB�MI���C�\������
�9��9�cB�=I���C��9��87^Z��%���cB�-I���C�\�\�y��xUh]�s�$���	v$�7	sW�\�w��:���s�$���	6$�7	s7�\�u��:���s�$���	�$�7	sw�\�s��:���s�$���	�$�7	sr.�8��N�rnHr���Pa�@�|���0�@�e���	���{$9�vL��y i��p��
��`���	�cnr��H���~	�6�(1��}8$�U�� �q��M�7��^���PmjE��*��!b.|3HmF\��j��\�����Pm�L�������6#�qB���\�����Pm#T� �7	sG�FImF\��j3^�d�	�/��T� �7	s
d��6#�qB���W.Ye��K��iD��*��!a��(���k�Pmd���jn��j�J�W�`	sg�FImF\��j�!%�Ws�%T�|��|�	���0��hn���k�Pm�J��^���Pm9������0�!��<���	���s]�s]��js��.����!b.r��s�k�Py�\��\�1����>����!a�G��y�u��9��9�cB� �.y�e	s��%���uB�"�.i���P���k�s��C��9w�s�k�P���k�s}��jC�]���>�n��[�s]��jC�����;&T;r���\���0wG�����Z'T;r���\�1���s�<�����9wg8�uB�sC�s}��* ��<�����rn`8�uBu �I���9�`8�uBu �y����}@�=����%T��K�o<��p.����8����+��\�/��p.i��pH���sImF\��j�^�$��~	���sI���C�\
�Kj3�'T�x����/���%�9�}8$��sImF\��j�sI���~	�nJ�s.�pH�k�sImF\��j7����b��ET�9Pct��C��iDw���GT��Kj�����iG�y�e	wg ]R��8��g ]R�p�_H��+j��.�x���Kj3��T�5x�����~)�n�um�u��C�]��k�m�R�Y�&YW
�b��!�:v�T�C�uy�U����#��$���cP�w=����*����������y�'yW
�������@$�]�x�<�>&0��]y�$���cZ�"�.y���	W��5��)LcW��5C���w�S/��H��!��y�}Lb��!�n���Ym��[�{�'D���w���c����wO����Z�H�{�|�'D�_D�=���iLc���f_�1�
��!���"�o@�
y�}Lc�{ ��4�������{���B$�=gW���������0@����~���_��S�8�
����&���^ePc�\��H����Ar3�T��*`�����_|�F���A�"��������8�
����&���_�q@�����"���)���k�_lCr�����Pc�>.��H�kF�7_��1�i�/��!�	��W�l�1_"�B$�� =%�9u����m`Hn��~�U������?!"�BzJrs��W;������_~f�h��0�"���)���k�_lCr�����E�ez��O�����2���W�������������0�"��C�u�����%�M��1����Lg�	���#�z�[�W���&���_-��Ls�	��wA�]����+lCr�v���_�?��H��"�.������!�	;�W+�/�"�B$���W�u��
��������
����?!"�"�n����v�!�	;�W;�/�(�B$���w�u��
���������������	�o`�W����O���;v���_�]��H�{ �������!�	��W����t���������5������&���_j@���O���
�����5���Kr����P#���"���_��W��%�	��W��P#�����c�%�uc����In��~��1.�������1����������x���;����Q�h�e�	
�/���k�_��k�������h�+�U/�L��<$O��$7��q�uL^�$�4����lP!��#"��Lrs�X�Lr/��4}�������_���p�"�Z����am_�<�u�!�Z~��C�]�����W�C�uI�}i�\�]D_��/�tH��}��c���#��$��4q���G����O��������up� �.I�}i����b��`/�t�����p��:�Z{�$����[���w���uh�"����������&}_Z�������q��:���w7�wM��jC���K�/����wG���e	{w��^�:��x����~�$��!^����7 ��xM��* �����~����A^�����@�=�5��������v���`��}>���
~:�yM��������r��v��Jd�
���������rs��Vu���O	��X=m(�)7�>���UL)L�6�z����i�t��n��C���j���!bo{5S	������D�W{�eV�$2�e��C��q{G��i�Ym���r��v�g��4���	{�����6�z�9��a`J���V�0����e�	{'�NL��mj�����01�]�R�m�5Jd*���������L��mj�����12%{��V�`���e�	{�{m�����V1��6���U��l/r/�d�>$�u������mj�P������Z����:�^���|H���{��S���#��$��Vc������2�>"�"�z�{����������Z����.��\�����wA�]��Z�V+r�����*l��wE��z������+r��qo��jE�]���Z����n��\�����wC��8�m�Zm��[�{;�V;r/�a�}>$���{w�{����������cj�{�3��!ao@�
�6�7 ��$��V]�����\�J�{ ��{������{$����u�=�{��2��W
����s�PR
��$�jo��J
Jd����"���������R#^�$��VZ���
��4����*�^��S�8�TZ��Kr�k�5����{I��(a��%�9u�CI��vI�}��F]{G��e/���#p/���kJ����^���Z)�Q"�����������������^R{u�_h��%2�;7���Krs[I�;������2+5��Qo���1QGw�]����zI���~���7��Ao��JY�^����k�ym�yM��JYd^�0�m�X)��k9�m��2�M2���X)������+���8�m��<2�K2���Xyd^�0�m�Xyd^�1o��@��y}�yM��jA����������0��~:$�]�y�$��������0�k['V+2��0/����wE�]��k:&VB��@�m�Xm����C��
�wKR���XmH�C��ub�#�n���	{w��=���cd�#������U@���e?��������U@�
����ro`���tH�{ ��4�v�����������{0��~:��~:�$�N�R+=��]F����Vz�O������:�D�W{��VZM �k#��VZ������t����������Zi=�D���k�Zi
��{��!a/���r���K���P"SK�5N���)��������D�W{��Vz<P"SL�5N��1h/S���tH��c�����R+mv��T�u�S+=AdJr�|:$���1Q���~���V����u�S�������v�~:$���1Q���~���=Jd�������!2%�w>�B��(�jo��J[�^���k�Zi��k�e?�:�^���~��v��\�8����1��~:D�E�uI��;�V��k!�[�V��3��~:$����>��s��jA��z��������p��:�Z�{�$��S���k"�[�V+r��qo��jE�]��;wL�V�^���o�Zm��+����C��
�wKr��1���{�62�uj�#�n���	{w��=��s��jG�����������3��~:$�
��{�{���U@�������U@�
���	{������cju �rmd|���@�=�e�-"�"�i���Z�r/�F�7N������y��;��$�jo��jT
%r��8�p/���n��W������_j5�%��Ws�D���e��}�H���{I���~���w���^=4N������y�H�;������R�q\Qb�{��8�
p/���n���������R��x���^=4N�F�Kr��[$��4^�$��~��8����l�Z�p/���n��w��%���K����4�.`��j��{I��w����]�{m��j�#J�s��V�E��y���-�Z�^��^�/�r��s��V�C�uy���-�:�^������C�u��N�<r��s/�n���#��4�vL�<r����uj� ��<���	{��%���cj� �.��������p��:�Z�{�$��������2��Z�V+r��qo��jC�]���:�Vr��p�j�Zm������E���wKr���Z���;��l=]	{w����^��"b/r���^�1�
��;��l�U	{ro`��}�H��{C�{]���@�
��5W%�=�{�{ju���@�=���:�Vr��p�j�Z�?������k������/�2������j�Z��{��"a/v�!�W{��VF�(1_ZH������� �w�-�b�{��_je���%u�j�Z
��{��"a/v�!�{}����P��0md�n�Z�"S�{��"a/v�!�W{��V�@�K�����qjeD�$���E�^l!Cr���K��e/
�GF����� 2%�w�-"��v����R+3�(1_RW�����!2%�w�-�b�{��_je�B����Z7N���%�w�-�b�{��_je,r/�JF����q����^��"a/v�!�W{��V�!�2�d�n�Zy�^�p/�n��������S+�������uj��{=����E�^�"Cr��vL��^�����S��wa��}�H��]dH�������������uj�"�����	{����������������c��jC��8�m[a����cn�#�2�d��:���|w�|[��}dHn����U@�e����up}���sIl$Cr�vL��/�NF�����70��~=$��N2$7�o���@�e����qt5
����C��i�%�	�eW���F�~����4���;_	��k��_5��&�K�sW�qx5)�_�{��!���x�����~����It�
6N�&
�Kr�|=$��v��_M#�/��]����4���;_^�����&3�F��W��%�u��5@�$�����^M�B������4���;�	'�_����_z5Mjd��4N��yD9�m�nL3�/�M��/���52�k�W��%�w�.�Z�_��_�/��,��e��4N�&��k�e�.�:�_��_�/����c���N���c��}�H���~]�~U���#�z�~M���#�z�~�������O����^-H�C��uz� �.�>=���"�.i�U���wa����V���[�ml����f��cv�!������6�������n�[~;FW����o��jG���e?��wO���^��;�S��* ����7�oH���^������:�
���_�����@�
i������`�wj^����'���}eHn��~���oz�83�e��8���z��;w����X��&��^�
Ja�L{=5�f_�{��D�=����#��/���A�L���qx5k�z��;�&�/��!�	��W��Q#Shwj^�#D�$�+�?��[��&���^�f@�L���qz5�NI�W2����M��/��M@�L���q|5O#��T�l>��2$7�o��j�6������W��)��Z���^��^���W���F����8��gHOI�z������������"�r]f����l�-����>��`��&���_���k337��f����e�M�_�_����c~���>3s���#�z�Yz��[���������k43�������_��$��3$7�o��jE��:������w��oA�����3��!�	{;�W+�/�ifn_m��+����Il2Cr?W�����h�+��	��63�N�v$�-O�%��>��g��^�����u���^3s��jG���e?�/��!�w_�<�u7 �r�f���U@�
y�-(�\���&3��b�K3���H�\��:�:�|�|[�a��{q��ysUw��������s+;�������FU];�����/�����4*d��6���%�w"q�G�*�^�{q��%����2�kGVV�����<������b�K����
��^�8�����2���vH<�#/�����jo]w�
2�k�U��������5���6QG���fA����a�5�$�N.��N#^��Zo���N@��9go���N@�$��B�����k������x�4��mU�x���Y����k�Y��g�5(���Y�������@�E���u�~a�uH��!^�8����q������x]z��cZ�y���uZ�y=�������zD^�^��Wyd^�0�kW-��>��l�Z	wD�%���c\� �.���q����0��z	���kz;V+B��@�kX��+��7��
�wMCo��jC���u��
�w�CoAe�����wK2�k�5���#��������������.{ewy�$��V[����wg����"o�#oAU���D��D��*k�u�@�
����D�#��5���{ �I�}��FUw����q��8�r|7H���D��������*�������*���Ar3�6���������/�r*�D���o�V9���|���z�u��N2����@Ze���g�g�oC��x��?�������������������������+|���������������~���?|������J���[�9����5?.�3����������������������ov����^��~������c�s���_Y$O�6-���@es�r<��[?sg���I�s��,r'R�1��6B�9H���~���%�+��'%�������:tw����^������C~`�r���$�u�����:sw����^����9�����`.I��S.�=�)�.�� �Ww��v�#?p
9�A]ql� �wN�I���8H�����������8D������i\	w�����1�[�b����C��aweJ���������1���v�6��pwC���B��q\ww�$��VJ���w�^���ww�L>{�O�]l�Ar��vL��.���uR�w���ak	w�����1�:�w�>���y�`x�=m-�.6� �Ww;fU�.���qV�������of?���k�~Y�6���n���+�]R{�����
x��^���Uy��D�wgU^���;��%��#^�$��~Y�����9�~�8��x���9n-�����%y������K�3�6����Kj��+q��K��]�/�����<��{�%�5�����Yz	w
�.����/���F�y�e��K�;���;G�%���wI���~Y�����]vo��>�����}�y"x��m�S�z�}������
p�V`v����l��� U�Z���q9���-r����"'�4,���s}�e{n�#�7����	�h.�9�����������/�[p�i�q�@��yDw�=r�y�S�����^����-�U�4�8K �����I�<g���Z�3�{qw���-�U�4�8K �.��\�Mr�y�S�]g��%�wO���������%�upBs�6�������x�����~���[�H�����z8��0�����x��p&��/�[p�i��^��j-�&9U�����/�#"w�e{n�#�wg{�
@�0���?�+������_���V9��q�q��l���&9U�����������_���V9��q��>�eG�e6��3���{�w��Yn�#�w[gUy��$�
�9�u7 ��4�v��p�i���:�
���&��]M�=�wC�w;fU�U�4g�m�U���&9U�����+��!�w�~Y��[�V�f�i�U����l�S���u��r5$��n��j��r+S����H���wWf�\�9���jH���~Y��[�V�f
�e�pW���&�����������������"3w�qV����+�IN������Kr�����V�*G�3�6��V3���N��wW�Kr�����V�*G�3�6���	xwe6���N�u���J$��n��j��r+Sb�ew�wWf�\{"��J$��n��j��wW����8�Zg�]R�K"[?�X^��^���U�y�)��2���y�r����������/�Z�.Sdij�U�y�1�[�������.���cV��w�"K,sH���w=��5������H����Y����Yb[�K�� �.�����.�W"�Ww;fU�.Sd�e	wW������Ju���J$��n��jE�e�,�
�%���w�<���aVW"�Ws;FU�.Sc�-�%b.����nA!���bu%�{u�cT�#�25�������;���_�X]��^��U�]��������nA!���bu%�{u�cTu �25��I������-����������/���0��l�hw�>�6��6���
�� �Ww�EU��(1���--������J�7�
�{q����6=��|�2�����>�6��6��6
�
�{u�_T��������O��qDw���[��6BJJj���K��qC����lEa	s
���6����@�HII���~I�f��o��&}"�BHJj����m��%�r�~Q�6A-��q�qT�M������qw�^�d_n�/��f(�E�3�6���RRR����|��K��v������������p�"�Zw[��-��M���Umq��q���$�u������A���%�.���*���������p�#�zw���<��O�n���#��<��Q�������n� rA�]���;FU����n��jE�]�-��Z��ywM���U���+�����ywex�y�!��I����
yw���k�Um�����:	ww��-���cV�#��y�e�>	ww������I����'y�w������]�:�
����]V���y7$y�w������]�:�:�w�wYu���G�w}��j�w�<��]8���]R�s�qV���$��n��jJ���k�U�jDw�e�I���wI���~Y��6���]�8��5�.����8��5�.����/�������gU��%�9wgU�8��K����U��K�3�6�������mV�F��K���U��%�{�U��%�9{�U�9��%�W
���}2�1���q\�O���6c/�N��	���&���W��F�y�����}�%�9{�U��Kr���v;��<�����nz-��:	{-B�MB��%V�E��y�e�
K���z-C��w5���%�W
#+������[GV��1������#��$���cf��{}�{}���#�z�{Yu�.��>��C��w�s�oZ-�����:	{W��%��S��w�s�o�Z���+���:{�{�4��������2��:���{7�{[�Vr���^�1���{7�{[�V;r�����8���;r���^�1�
��{�{�N����������|C|U��* ��<���unu ��<���5�H�G�|U���@�=����'D��0�������Q��0$7�o��*jd��O���
�$7�oc8
� ��&���\��F����8�

�$7�o��*`�����_t4��\��
(������Z���$��&���]�J\�W���w����~-�glCr����1����;4N��������m�^lCr���~�U�4jd�����0AtJrs�6����!�	��WaP#SBwh�_��S���������bHn��~�U�jd���	���V���*�����T����������`��1�q|��e��u��_�M��/�
��k�Z�W�������Q��1$7�o���#�r�cT���#�zYu�b�����c|� �r�cT��jA�]�e��������Ww��V�_�y�j_���+���:	�o�M��1����1J���6����_V����:��&��_���\�@$��w�����<��^�;�W;�/�CF�������_���������������u�Q����70��[�/6�!�	;�W�/�G���"�"����n|����4������w�H�s�6��������m���P
�]��~����It�������In�������vi���W�6���_�
J���In�������In��~��1j���/{%��In�����1��������?�6����S��h�� 0{%,6��$7gq���0��$���4���n@���O��I�����1����/M���;m���_��I�;��������c�%�w_�<�uw^P!����c�%�_��kG�vI�}i�\�]��k9�m]��rK���]��k����������1�;6����8�m���p�.	�/-��u�#�:{����G����okw=b�Ob�K��u�]z=�c��jA�]�e�=	w��%�����o]wW������ud�"���6^2:V��5�����oe{xWx�������2���|�n�[��o?{7$��!��uZ�#�n��������g6<��wG���[�U;"�� /�n��7 �����~�d��0��:�
���a��Qs��(�������������u^u ��6>kt��Gz��[^�����c��y�C����~�>���Q���ny�>�%25vM�������*_S�������
����F<���^�P"Sc��
��f�W�+`jv�'a/t��r��vK������5m�}
������Y����U&����-�z(�Q"Sc������h�w�W����O�^�*�^�ht���V����5m#�O��^�����y����U&����-�z(�(�����B"��w�����O�^�*�^��Y=$Z����1m#���
����/�?��U&����-�zH�@"�[����b{m{�y�����6�����k�C��z�����Cr��s/?����!��$��V_������-cZ�V�������K���{}�{_+�Q�^�^����:�Z�{}�{�y���r������k��wA��z�L�S��w�s/?���wE�]���1�Z�{W�{�������2��N�$���{�4�vL�6�^����:���{7�{[�V;r�����Jk��wG�ez���uj�#����3	{r�����*k��7 �2�e��:�
���Y�eg"�"��$��VX���r/�YFM�S���`��9�]�?{�$��VV���j@�e����qh��^���8�uW
@����n��J
J���qf��Aw�}NEu�U����n��J�%r��8�R���f>��g�u�������n��J�%2�;7N���Kr����V����^���X���D�y�����yI��
����.���+e�yIs�����2��$�+Y-R���.��������a��qb�&`^�{g�R����.���_b�p%2�;7N���Kr�}��w�%�W{�%V�*��@��8�R�����}�HL�-B�MB��X)��k��V�!��<��o	wB�KB��X9�^�@��:����Y�m���<R�OR���Xy�^�Qo��jA���������%I��cd� �.�������Y�m��lW+R���^�1�Z�zW�zm��jE�]��^����R���^�1���z7�zm��jC����[P����jC�����1��z7zm��jG�����V��pwG�����1�
��;���ub�yC�y��u7 ��$�N��������70�zYu���HB��1�:zzm��J��8��^V����D�W{�%Vz�Qb�����+���Ars�6��5���r������ZQb�����#+���Ar3�O�4t��j���K��� �i�l��Jk�r���6vz�D�Ww�Vz� �i�l��J��������S�u��v1Q���~y�6Hdz���jj������f��yY�����Rr�_\��%�K�*�8��d�$����4���j�������Pb���r��*=CTJr3����*h�^��W��@����5�����|���n�u���6	�s��J[^�g�r��*�x-���hh�����;�K��C�ez�(�:�r��.�������w]�w��a�G�ez�(W)���s���u�������_��������?:������?���?�����?����~���������~���?|������	���]����Uf��������_�_>��t�U���i<���_�g���a�
+�8�3
>��9 ��U�p
������=���Sm���6uW�g�0�
v�Wv��K�_Yr�_�g���a�
+�8�3#|f
s>��G]w��0����/�3xF�0���o���a�����$��*����n�h��1��V�q�g&��
s:�`x]w��0����/�3xB�0���o��yDw���t������������=�'�SiX������+�p�.8�S�^,2Lr/��~���#b��4��{��tX{{��0����/�3xF�p��}�t�8D^�x�f�vJ��E�I���~���3b��4��E3��9���"�"��$�����3\�a�:�Zz��a�=�'a/&�W{;&VxF�p��}��jE�e��i�����Xd��^��Y�1�TV�ud�!�2��4{�O�^,2Lr��v������*
s�D���{��a��N%a/&�W{;�VxJ�p�����U@�e�iv?���Xd��^���Z�11�UZ�V��9!��
U�b�a�{��cj���SiX�S���9!��U�NXe��^�u�R�i���R�zh�ZMp/����8����0����/���A����qj5)�^����q�1a�a�{��_j5i��#�C��j���$7go��&�W{��V�8�D���P+�r�|C?O�������2���}}��M���K�?{Ue6�}v92����3L���dv>�h>�uX�q�a&E��>�R��j��lP�|���������e���'R'R�n��orJ�oP�C��or8�r�#�e����p�pE����&P"w �q�7y�G���I�<�����i��i��/�������s�.8���#������,j��r�_�7-J���l�wa����>P\��u�K���n��oZ��$i���8��VX< �����uwSx�p��]����mpn�4��m��m�v@ro�������������nP"s ��%&���D���L���������{�w}�t/ ������^@�
y��G�u�
��!���c�w ��wU�-i���{0%�Z���{$y�w��������Y�<�w����y��V=����|��������y�Q"���>�*�n�����q9+�l�������Y�(�Yu����Y�w��f�m�D�>���n��j�%2��lmHw��Ar��7����%[q�~Y�<�~H��s�qV5��������k�f�K�����eU�����9�n��j6���������y6/]����U�4�Ff�5[�L��	�R��yx/#����6ao��j�jd�Z��i�<CRJr3�6^G�gJIm��~q�<���j��U[���N����u����6��j��W���2��np���!��<���k�C�uI�UC��jv�������G�uy�-h@Y�^����������G����N�<R��"��k��������������0���q��wA�]�{���"�.I�UC��jE�]�e7�H��"��y�5����w�po��jC�]�ew�H��!�n���7��-��S��wc����"a����3��:���{�4��������3���s��7 ��y�-(�X�������:�V�70��nt���@�
y�-(�_����Hs���Z����l=i{���{��wj�Z����&���Z���F�{��"�������S+�4^�4��~��U��$:go���*�^����qje���.���_je5p/����8�����f�m�ZY����W�K��8�F�{�%U	{G�^����qjeG�^R���_je�B���K���^����qje
p/�M��/���@���K��N�e��qje'�^R���_je�52��.�J�;����S��;���Kj���~���W��p/��*a��%���Vu����6���_je-r�e��]R���2��x�u��6���_jer�c��]R���!�:�{������WwL�<r�g��]R���#�z�{�����E��i��S���s��:�Z�{�{/��wIs���Z������S��w�s��xA����k�{u��jE�]�e�T%���{�<���������WwL�6����^v�"a������wn� �#�����Z���;����E�����3�N���\����2��1�
����^vIU�^���t�|�9���@�
i�;�Vr��p/��I�{ �L����sU{��_�#��c���
P��D��m�Z�>$�vM����/~9���R+���%����8�r
>$���9;����#��/�rzD�L]vIU�^
������^+���Aj��K���Pc���f�T%�!2%�{��p#$��6ao����j����l�'a���|����u�5�������R+gv��/����O��	"S�����n
7AbJj?�������+�u���2��t5;�qRS��q�����
^:M���3w���$9gn������������u���1��b�K���Z�^�u;7�0�"��<�������k������������37���C�uy����������/M����y��1s���#�z��CA%���6�!�w_�3�uwA�e�h*%�]�x�<���K�{�����/��V6y���Y��0wE�]����J���b�R{1��U����H�L���������]�:���1��b�Kk�u��t��1�eIst�<�|s�>��0��&���swG�e��h&%���t�<������a�M+��n@�e��h8$�
��!���w6;lCj�o��{ �2]c4;'�p�@�=��[Pm�����Gf����~@�e��hv�"��vI��q"������n���+����s*�vI��1e�
`��^��Tyu�D�vm�������.{�I���vI���~A��;Jdp�6���Kr3�6���G�]R{u�_R��%2�k'U~�%�wo�����K�n����]��s�qT�
�.����x���4^�4������K�s�6����Kr3�6�v��/]�w_+�Q��x�4g�u��*?���������9��K��k54��kG����k�Uy��k����z�Z�]����Jh�u�!�Z�w]���;�]��]���p�!��$��VA�������]�:����.����'��G��I�}��F]w=��gx�����]��]���pwA�]���Z����.�����uV� �.y�eo=	wW��%���cV�"�����Y�����y���$���w�$��V=��������k�Um�����W	�ti���U���;�����yw��.�b�xvw��=�������s��:�
������Id@�
I�}�tF]w�����o�U�������y�H��k�3*���{0��gU��������I��-bH��]����������_@��x��?���������e����?������o?�mQ�����w?��Od�����?���w����.x���'T�O�Tv��p�`���Ku���/�/�`�S��S�u�u
O"�'}���Y�{;n�����/�[F��0m7�s��z�~!x"�s���� �Ws�w��
��t��o'a�����f�m��.�m��^����-�A����lu;	s'��Hm�������6H���~��2k��/<����0w����f�m��.�i��^����-v@�L����_�\�@j3�6�d��Aj�������4���q���nDs���}��n�.��jn��nqJ��������"'R�1�qd�`�
R{��/�[����6��*��E���2��qb�`�
R{5�_b�,��L�
�|�J]s��������� �Ws�m.[V�\���~�a�5wE�]����K'�.���]�1��t��uD�!�ny�UC��
�k����3�I�i��[gT;���']5��������1�
��L�
�:�
��!��jh�Rao
�{u�cJ�u��uJu ��<���uL��5H����1��������c�u@�=�������@�$��n��j�����qN�@��6�nc�]���.�������D����qP�*�]R�s�1��Z��K���/�Z5�.i���8�Z5�.��������tI���EU�hPb�w��Q�:������yw�wI���~Y�j4J����8�Z
�.�����wW�Kr������i@�y�e��K�;������yw��wI���~Y�:���]�L������2���"�:��������u�Pbw�J��Z�]R�W�����i�&iw��T�i�2��8�Z-��eh������:�]����_P�:�]��n���!�:v�t=��K�n���#��<���A�G���6�W������1�Zv}vM��jA�]���������d��cN�"�.y�5�s�Ywe��?�����"��I��;�T���G]�:��u7uoc^7D�-��s��jC����kZ�T;����.{�I��YwO���1���u�<���1U@������;K���nH���1�
��!���uJ�uC�u�eg	sd��d��cJu �y�5�S�Y��X����
j�����b��$�,qc�j��1�6�G����m�)c��$��n��jSPpc�j��9����Ajs�6���aC
�{u�_N�i��UW��9����Aj3���%���$��n��j5J�We;�I�;BDJjs�6���aC
�{q���63��|�Q����"RR�s����
j����������t�l�Tm�Fw�e{xM�]l�Ar���K��iC�L��I�6CHJjs�6�!7l�Ar���K��yA�L��I�6CHJjs�6�!7l�Ar�����6���t��GU�E��y�m��r�~��jn��js��LS��qT�9�]��n��n�G�i�����*���4��ZGUq��q�u/�
�i������i���1�N��������b;
�{u�cR�"�2=5��I����2�[�BT�]l�Ar��vL�V�]����:���vW�v����b;
�{q�uL�6�]����:���v7�v����b;
�{u�cR�#�2=5��I����3��L�p�i������������['Ui70����D	w������1�:w��s���@�=�e&����{$q��K��q���17N������6�n�r�wI���~Q��4J��.{�N�]�Kjs�6��v�Kr�����v=�D�wGU��%�9w���5�.����/��u@��6���Q��y�e�&
�!�#�.����/���
%2-$GU��%�iq����zkvI���~A�n���]�8��
�.�������4��K���T��.i���8��'�]R����8d�g��.	��_P����9�n��j�vIm���!�>x�����U�5(1��qP�[�]��.{�X�]��k����U�C��y������!�:v�c��:�]��]�1���.��uP�v=���b	w=��O���Ty�]��]�:�Zv=���+�pwA�]���;U����n��jE�]��]�\���+����]�1�Z�wW�w[U+����.{�X��
ywM�n��jC�����Z'U����n��yG�����1���w�<���Y����s��:���w�$���cXx�<���aU@�
��'�%�
�!	�j��VH�!O��uZu ���G�%�=�x�$���_\�W0���q\�r��L5��56�!�	w��Ua8Pc�b�kWe�]�7a�"�����������v��/��UA�w���^�����]`Hn��~yU�+j���u���0BTJjs�6����!�	{�Va��1_ �5��Y)����8l���&���X�,��5N��������m�6lCr������,��7���i)����8n�	��&���Y�yD��*��qff�KIm���ys�^0$�j���Y�Pc�L�o�Y��k������b7����_f,b/��7���C����5��M��1�r��LW�:����.���C
lCj�v��<R/������^�Qo�����`Hn������������3��wa����!a/v�!�	{;fV+R/�����V����^��������&���YmH�Lk�:���z7�z��"�"�ni�U3����
�[gV;R��P/[�C�^�
Cr�v��R/�Fq�D�
����^��������&��Z�^�?�Z�Vro�s�b�|H���aH��_�1�:|�1C����|f��-�!��1������b�cXQ#�uh�[
�����m�:
���&��\���<���qru(�_����q�|h��.
��_tuh�_���qvuh�_��u���8��K���]#�/����8�:F�_��u������W���3�F�1��8�:�/����'���%�	�eW��P#G����c�%�ul�	'�_����_xuLj���qzu��e����#���Kr��K��yG�\�����a�~In�����a�~m�~��W�E���������~-C�l�	��K���/�:��c�W�N���c����#��G�ui�;�W��3��Z�W��3k�l�	�_����cz� �.��������0��l���4�����wa�W�N�V����_�z���+������c|�!����������q��:}���4����
�wc�W���v�������������w��_���;��������3������7 �����g�F�_��������C������|�@>������������n�_����l����o���������������Qr�����C����f�=�j>�a�2Q������u�Ur]dt���!fsU���b+pI<��@&���������z�\�6�z�����W�Tl.w^;�l�{i�\��qD�La]�6�z������|���[�B�(���K��u�5
2�uu����nw
S������gZ�D�s_Z��l��
����mb�iDs�u/[\M���2Q�����{��;�����������w�|�K�W�pZ�D��*���W���e7$��{��s���b��I�=d���a�~�Z�]���nU=� �Z�w��=�:^���jl���!�r�d��a�C�c����#a�G�uI�}��F]{="/�Kfl�VyD^� /[�G�^D^�D���l��wA���������wa��-�#a����$���"u�]z�n2c��jE�]����
>��H�k�z_+�Q�^�^����:��{���$2�
�wKR�k56���!�r�d�������1���g�xxw��=��3����'3���v����^�>����wOco��* �r�d���U@�
���D��7$���
u�={�~2c���@�=�m�'���HR�k�5����^��s�qf��^��{x����uI�}��F]{�����3+��zIn.0m��*�^R{u�_d��B�\������$7�7�-�&��j�^�{��_d������#+5�hoz5[YM�����^��Y�qG�\�����u��y�-8X��lzI���~��2+J���6N���%�iu�Z�����K�d��
k�uw�%�9w'Vj�%��g�5�/]y�Vj�%�9wVj�%��o��^e�vi��X)��k�e{�K�k�ym�y5[�R�^d^�d���j���!�Z�yV�!��<�j�������%����u���������G���6^�U��'������E������%�]z=���-�'a����$����u�]zz������Kz5[�R���wMR�k5���"�����E�E�]����?�b������i��wC���e;\K��!�ny��l�K	{w��-������k����3��v���wG�����:�H�{�z���U@�
����%�
H�!O������"��4�vL�d��0/��Z����`�y�#o]wD�#���+=h�~�����}��������uWC����ZH�_^�������*���Ar3��o~��.t��j������
(�)"����pW��.S����JC�����n��J�
%r�S�Uz�����N�6vZ�D�Ww��Uz\P"�=�qX�GHJInnsdcw�sLT{u�_V���l���Y�6���\���]��^��U�i�\��5�����$7�n��7��D�Ww�%Uz6(�k��8��3��$7�n�}�z�D�Ww�EU�j���MmUi��k������p�"��4�����C�����Mq%�u��.��li<	w��K�n���!�rMc����z�]����YU�"��w}�w��Y�G��Z��
q%�]�w}�wfUu�]�w�$�N��y�k�6�qyw��n�����+������cV�"���bZgU+����n�]�zC�]��;u��6�]�YL��jC���m��Uo��[�w��Y������i�U���{�w�	���;������cV�w�F1l#M	w�n��.;��p7 ��$�N��y������p�@�=����X$�=�w�$�N��y�k��pw�w�w����.����/��
%r-RgU��%�w���
x��^���U�jA�\���Y���wIn��������%yw��U�x�4��m�U�x��fN�7^�G��.��s��j�wIs���Y�8�������8x���;���FcP"��l�L	w
�.����x}w4�����n��j�4J��6���	x��~���	x��^���U����e�!K�;����:�����3�.����/������������n�w����Z�]����_V5Z�]��.�{O�]��k����>�p�!��$������!�:�w��l"�"��<���O%����.���*����e��I���w}�w����.��>����ywax���&������y�=~*�.����]�1�Z�w�w[gU+����]�����+����]�1���wW�w[gU����]���������]�1���w7�w}��jG������pwG����k;fU;����.�6S������y�m�$�n@�
I�������e�fJ�{ ��<��}�$�=�w�$���Y���{0��6�qy���.�6I�]�}aH���~Y����a��4����
��q����maH���~Y�QP��p�a����*�n����w
��!�Ww�eUFC)K����{*J����Ar��5���^���U���D�J.�RQ��rR��q����������_Ve�F�\?��Y�1�����w���9�MaH���~Y�����Cm�U�	rR��I3��3���^���U�)�D�Dn������W�d��I��MaH���~Y��7��u�i�U9)��:rf�=aH���~Y����lc��Y����6���sf�-aH���~Y�q��l_��Y�q��.��l3;	w�#����1����l[��Y�G��y�e����������:fU�.��o�#������y�mf'�.��!�Ww;fU+�.��uV�"��y�e{�I���`H����Y������i�Um������*�Cj/���Y������i�U�������*lCj��v��v�]�#��G������y�md'�.v�!�Ww;fUy�i	��|��]����������!�Ww;fU�.�F��Y���{0�����i@�=����eU��K�s�6���x�������D�=��%y����&eP"���qV5)�]��q�q�1)�]R{u�_V5i��e@K���wI��qp������n��j���.��K��x��~g�x��^���UMc@�����$�5���n�3���%�Ww�eU��P"��l�.	w'�]��u���&�]R{qW
���iZP#����i�%�_���i��%�W
���i�%�9{�U��Kr��]��Ux�����~q�dy-��lo		{-"��#�j��d���6��j�XM��2��v����!�:fSs����!��$���cb��zC�l{		{=R��S/�fT�^��������������e�KH�� �.y�e��J�� �.I�UC��jA�]�e?o����K�{�]�E���wM��:�V+�����n�ZmH�k�|�F������e��cl�!�n������������$+a����e��cn�#����m$���|�<���d%�
H�{�|U��* ��|[�V�7����%+b/�oH����[��������{�����T]{�#
��_n5#^@|�N�>�|��$7co��y��0�6ao��jV
52=b�V�*�t���:�%������&��[��@�L�����������l�`	{�?�M��/��������c�y����f�m:�� ��&��[������c��j6��������bHm��~��l<j����lyF{!3%�{��3��!�	{��V��-g�Q�f�3J�;AdJr3�6%g�Cj��K��
\�L��h��w����f���"��v����b��-������h���"�Z��{�B�_�Cr����f���t��l)0	��c�������bHm�����C�e��h�����������-a/v�!�	{;�V�����b`�.H�>O�l�o	{�U�M��1�Z�|��1��&a����0��xQa�^1�6ao��jE�e:�h����H�+C���Y�M��1���|��1��&a����1��:u�n1�6ao��jG�ez�h� ���;���'_������{|;�V��i���`���_������/��&���[��L������@�=�����������c���@�e��h�&���v@�=�������{Im��~��v��qo���*�^����1Y�Kj��K��ZQ#��lU0	{5p/�������%�	{��VV{��p/[L�^�^����1�Q��Ks��/��#p/����8��#p/����������w��ZY�K�s�6N���%�iul�Y{^�4���R+;����^�����p/����x=�N����sq����������z
g�2�e+I8<������W���Kj/�KS�����_��������y�e[�J�k|m|_�8�5�"�Z{��B�:�^��^�������%���is]sB����ud�z]z�F��z�^����&�u�����C����G��y�e��J�� ��$��4e�k����0����0wA�]������0wE�]����2o]sW����]�����+����n��jE�]����"o]s7����]�(������,��6wC�����/-��5wG���eK�H��#��y�U�����#���5���x+����3���$��7 ��y�Ul�Y	{�n����go@�
��%I$�=�u����=�u����~���lEw��_�#��m3+`���1$7����^7�(1_NH�ID��/����8�r�7��^��U9�.�<F�%+$�U�� �9{gU�������*����c��h�d���>$7go���a��{��_\�F�u���1�-Y!a�I)����8�r�:��^��X93�D��.[�B�^Y)����8�p�;��^��Y�I��|]�����w������m���a��{��_h��%���j����������\*������;��^wg������|]�y��������\���1$�jo���Y�^���f������k�m]-�a��{��_j�r/�?F�G�%�u����^������:��^���Zy�^��f��K���{=��l�Y	{�u����1�Z�{��1�=�.a����0������wIr�k�4���"�r�c�#�����+��l�Y	{�s����1���{��1�=�.a����1��6���;�����S�
��i�]��jG��8�m�Za��{��cj�#�2�c�k�Z�������v�!�W{;�V��i���"�"��{����b��{=v�1�:�{��1��N�����^�����~@�=���Z5������4��m�Z������m�Zy5��Kr�k�4����{Is�����W��$7go������.���U��k�Q"��l=	{5p/����8�����^���Z�Q�D�{�V~�%�9{�V~�%�W{��V~<P"���S+oF���^��������^���Zy��D�{�z$�N��$7go���O��$�jo���O+Jd��= b/p/����8����k��^�������O.��K�I��~��o��_>����������_�������~��
������~������?�/���������\����O�����������i��������K:J�T��T~���!G0k��m�+q�;����~���.����K7g�8��`�W�]���a�Ex~A��y�`�%�]�"�"����.HK�"L�oA�X���>J��"D,D��w%�]"�$D������!�]|�pwC�X�`��J��!ClI�0��
b�3��(�."�� �{W����[!L��nG������PP��V�Hm����]�x��+g�czp�,0+g�������p�v��p�����\83���f����������n�6�qy�H�����-�����=��R��e������8�[������o���4J�ha�%�U�� �9wgUv� �Ww�eU�Pb�@��(�����������p�o����S��j�%��������#��/�����b�
�{u�_V��J��#e�%�5��������[o��������,(1_��]rqbRR�s�qV�`�
�{u�_V�LP7pa�o�kl�N���������n�������e����z�]c�pw������m�U-�v��^���U-���|ERv�M�]��k�e��J��}7H���~Y���w������y�1��6��po�����*���t�`��$��������Yv� �Ww;fUy�i����I�� �z�w[gU�z��^���U-��L�
v�M��ywax���+�.�� �w��Y����4�`��D�E�]�e�J���7H����Y����t�`��$���w7�w�>��b�
�{u�cV�#�2-8�56	ww����]�������{�w��YU@�e:p�kl�����.�eW�]��Ar��v���]���&����{0��v��p{o�������u@�ep�kl���.����8�Z�]�{u�_V�%�y�]c�pW��.��l�]	w�.����/�Z�������I���wIm���Y���wI���~Y�����]v�M�]�]R�s�qV��#^�4�����x�4g�m�U�#�.��ak�U�F��K����U�x�4g�m�U�x����m�U���K��]�/�Z'������I�;��������u�%�Ww�eU��Q"�����u�%�9wgU��Kr�����V;�D�wgU�E�����v%����6���_V�Z�]��]v�M�]��k�e��J���w]�wm���!��<��kl�z�]��.�gW�]�����k;fUy��y�]cqy�3�����pwA��I����yw��.��&�����p��:�Z�w�4�v��V��5������+����n��jE�]���1���w�<��kl�n����l�]	w7��-���cV�#�ny�e��$���ww�w������{�w]��* ��y�e��$�
����]�����y7$y�u���n`x�uVu ��w�����G�w]���@�=�m�Um~6�w����n�h��^���Um���E��56	w|6Hm���Y��}6H���~Y����/������
R�s�qV�a�
�{u�_V�i(e�1�6�56	w5|6Hm���Y��]6H���~Y�6B)��i����I�;BLJjs�6��6l�Ar�����6cPb�H.��&��������m�Um�c��^���Um�F��"��������6�.�YW�]l�Ar/��~Y�6(1_$�]c�pw������m�Um�a��^���Ums@��"�����V��L������y�&y����6��k�m�Umy�r��Z?�y�%y����6����m�U9�]��.�4Y�]lCr��v��<�.��]c�p�#�z�iC�$��������y�i
���I�� �.��-�E�E�]���;fU+�.��]c�pwE�]�e;&K���`H����Y����4�a��$���w7�w['����^���U���LSv�M��yw�x�u��`H����Y����4�a��$�
��;����HlCr/���cXx��0�"���o`x�v��b?����cZu �2ma�U6{�x�x�v�����$^5������Dg�mW� /����8����K�D^5���v�K�3�V���4�o���8`^RK���O�2���O����sa7�x/��O\�I����n��?Q�n_-zu9|S�/��q��%�v	�x�C��o����&�.LJ��6�
�����q��o�M��&�����[@��}���������2��}��o�a�0�M��/��w����������g;�Q�7���cIn��~�p:�'c��+{!'�9{g|�1��K��UC��o? '�{�|�8����8��$7ao��/ H$��+{�d`A�q�$C$U��/ H$�,	{$��/�j����{��K.�*�/������)��%a��/����8�>$7ao��/�5��O�%,	{GX>%�9{�|a��S����_�����������OIm��������S����_jL@��Tv
K��I��L���qj&�TIn��~�U�6��_@e��$��!1%�9{�Va����&���Z�yA��Tv
K�^HLIm����U�#^�����Z��k����V�"��<���qjr��po��*8�^��^vMF�^���8�m�Z9�^������G�uy�e�d$����������G��i��S������]���wA�]�U�S��wIs���Z���K�{�5	{W����^�:�Z�{�4��������2��:���{W�{U��jC�����;�Vr��po��jG���U�S��wOs���Z��{�[n�Z���y?�I&3I��$ �h������mt��[�j�h%#*w]2��� _��N�S����q!�^<�:�PfJ����N[[U����P[U����Oef�[�|�@�N�[5$��'_o���o�����23�m��M@_�-��o����WmA�m<�:�\fB�m����t�����G7����R�N�v��9�y�u����z�/�e����wl����v��W�/��G_'������R\����wn�����]��U�3�����������WY<����v��SWm=1#�N<���o���\�����_�����]�p`F�~��U@����+��������������Rh�_e{�6�_������������w��Wm���L�����~w�_����,�������w��W-�(��x:3������_�l�[D��}�]��UK��Q�_�xfF�	�7���-7�oB�������w
�CaFN�43
��������pF��]�}����r�~�@�����r��,��z����v���K�o}w����{�+���h� �<������mh���t���/�c�-�E_�`fJ��E_�c�v"��.����yl�'b�)`�(vg�{"���*�����b�[_���{!�^�jK�����w�����y�.��u�;����{I��m�*o�{??0[nE����@v�6��*��(tg��w�p��+_�h
���$[������XW����}�����G\�]���W��j|���N1��aDa��hsg�����zu�z_�<;��hv��#
��D�;�^���_�r��������<~r|<6�z}�����m����-��z~����yl�k�g��&�8I��w�e������W�
����K����%x|v(J�����W���o���U�0'����~�=�m����CSJ���W�"nqf���Mg��P��O����1�+L�g������j��bDa����tF�{�zw~��_ue�+�	�nGYJ��LY�%:�(������7"�F�{W]��
����k&�^��{����w��&��(p��+�~y��]�s���J��I�^����z3ro�w��V�7w����c����Y�^����z��,q���:�{�.��7[cl�r�!p���tJ��������� �]�}o���zro�W�n:����[�
���D�-]�}o���zO�^i����tF�'r�)po��V'r�����fk���B��v���Mg�{!�^�mku!�^]�}o���z+r��KF�n:����[��^���,������
��.b��JF�j:����[%�Un�!��.��7Vcl�
�W�$#~3���[�z�@��s^�z)��];e�������h��R\������v0/���kg���Q`^�{��v�y).���;E�y�������������\����y@^����{��u�G�%��j�mw���\�����@��i�s9����������nX1������^�������n����v�l��Fx7(�*��R\�;��-
��R�{�v��m
#
�+�
=��=`��>�E7���������Un�0�@���;3��@���W����������M�[oD���*�*�y#������M��������r	�7I����"o�������fD��G^C]�y���������Y@��y��{ ��>������w��U"�! ��g���E�=��uUA�=���uUA�-�*���[��u���[���u���{JW���=�x�.�C]u"���n���B�=%�U���.$��K���W]H��@�����H��D��7�]E��]�
���"�V�x7m_��x�p�+���z"o�"o0�U
��	��i������S��������h]�
v��/��n����W�W�>:(.wEC�f���1q���	+�"D6��MYXy�c����������r�|��D���]�Wy��N�v��}1a����*��Q��+�*��*���/f�w<����{�w��U>8����u����\)���U~'�������z���
#��s��,���b��pK/���������z����.����u����;�R����|G�������z����F�g��]�X�t)�e�=X���b>����3V>"�
�b^I�����Qb^�+8>!��.�nv��'d^a]�����O���g^/���f�������Xe�^aY���hU��H���^/��)�"��.�n���@��������@�=$�U>N�r���^CgU�{�}1��@�zro��W�8� ��>�Z���+l�qQ�Z���E�^Q����D�=���Z��WX������{O�{Ee:�����r�nh�.�^ag�����B��x���2�QoE�����Z���+l�qQ�ZU��*p��Lg���{k�{wCk��{��1.j[��������z���u�w��V��K��z�����R\�(�s.�$�����b�n'�V�bD{���Z`/�e�������z)��];g�z�%�UvV�����M���hl�������SV�oQ�^ee��+��C���c�]�y)��];c��F�7)�5�R\����hl�������Vk(Q@��,���Kq�v?G���n]�x���Z7 ^�������
���2�~NDc��=>�.�F;]�����kWYW�;/�e���l�q�G���hg�����M��j���Q����)��v�wc�w���Z�nx7)��5!�&�w��m7!��.�FCW��w���I�Ue��,������������Ue��,�n�vU�nxW�U��G�w���:�w�w�]UA�=x�}p�?����[��
]UA�-�j����[x�}p�?��y��y��U������Y�U���'������{!��}�5tU��%�n�vU����������V�������UU��*�n�vUy������~p��������U5��*�n�vU
y���+J��6�����d������	���]UX�s��2�*��Ci�������(L����*8�����t��0�����r�TUp#JCs�UU�+�+�.TnW�P�{�v�*�#�Cs]VVUaMJq�t�p�����v�TUX������Z�]����N��2�]\Ci�����`�e������BMJq�v�?wqE���k����-��'FJ7��
4)�e.�*���!�����SUaQ��(����&��L����.����v���
�cDaf����BD���*���a(��\;S���#�/��*$�������Sc���0������J�����h�����x�}�}jl������54UqW��m�������A�c���0������:w�1���:ww���.�����v
UUA��v�,��� �w����0�^���:�v�1���:�vOa��������{vi7��iWZ�h��i���*�������5TUqWZ#�|���"�Vak��}���a(��]CU��w�
1N[U5������������r�b����� �)��mA�m����-���������3
�+���h��R\�M�v�.���k��6w`Fi'�����.��.��l~�'��]������Rh�]eW�y�]����C�Um��G�^����m���\���j[�x).�nU�����"�[�t�f�W�B0���Kq�t������v��V��1�����j��y).�N{����R�N�v�j��(Q����v�^����<�u��{)n�_;g��3
�����W���^����H��!_;k�E$�(��W�V[B��<��{��o�����V[B�M��?!S�E�M<�zqA��~3�o���34W�7����UF��<�zqC��~����_g����C�_�����C�_qE��~�>�:C{UE���oA�-����{c[A�-}�u���D�-�zm}u"���������D�=�������{
�������{������.�������_]��������"�^���Xf|�V����_g��*�o��W�_5��*��+��4������5�W
��	��j�����x�U>]�qO���kg���\����*��}�����vV��7�P�{���^��\����*����g�e~;+�!���J���N^��\����*����G�������6|t���Q�������5������`N).wr�\/.����z���<f�����j N).�.�r��-��v��3W��`FaM��l��
�)��Zi���b(n�_;s�o3
{RWes�����\zq������1��v��3W�~bFaQ��l�^Y����t)j�?��2��v��W{D���UY\��7
��`[��_\Cq;����=!�
�c|PW{B�M<�jO-�qk���kh�2���;����f��}����s�v�Cq������@���xq6��~d�C���=�l��1�����*���/�?����[x�}G��zqu���k��N�_a�������D�=y��F#\Ca;����WX ���`3��}O	}��;������P]]���
/N��oE��$�U~ia��1���������/���/�o��}?�49�_\ Cq;�����+���A[]5d�������� �6��?���>J~�b��|�q��\���*.���X����4|v]~����z]���n��*:�_�����������}���z�����~wF����~'�G��R�[�o}\��`D7e{W�_������������V�[_�G�[1��������c��~~�jl������}����z������U�).�.}.'����R�[�o��w;0�@������/���U�Wq_��u���s��������WY^����r�*��>����[�������Q��m��Z_��|��7������?����z����+����o?���?�������tN�
��?��O?��?~
�����������_����?�M������7�^>�RV�.|��s��������~����v�4��t���<$�JG���e��vx9	����myh�q�g��F��|����]:
�����R�W��p����yJ��]w�{�I��w�(47DY��� '��-��~���������(4����K^AN�5:'j��f 5�{��P�%�LG��~�U_:V��?Fp����T���~
]_��t��W���#��p����yF�X����5�}	o�Qh�_e��
��J�=:'�������`��/�}:
���l��	����tNT�3����>������(4����K��p����yF��������Kx��Bs�*�UK�W�I�D�<�_������&����Qh�_m����tN��3�m�������(�o��t��W�_��7���hO'��q<���k��2�����&e����J����2�g���~
�U��tY�$�M1�_���{tN��3���L������x�.S���)������t��������&�{���_e�N��1M��3�]��p��=X03�_��Dq��������4�I|�bF��7W��hOg��#�(��_C��B]5�oR��w���]:�`���~+>�>����7��8�I�_��7����3c��M������x�.�����U����m:�94G4Q��{<��*G�_iP��.��z�o���~��?�8�������W	�W�$�L1�����x�U�.�qB���k)�2��0�I~�bJ����_��#�3Q�{����@��4��R�h�@�=x�M���3�g���z-�UA��4��R��� ��|��brl�8������W'��0��'mqu"��<�f��3Q�{����B���4%mou!�^<�f��~�3Q�{����"�JC�������U8�}�E��~q<���k��*r�4�)ik���[%���Xl�8�������V
�W��������G��<��<��c��{Pb��������������I����8�^��^���:����}"]N�><(.���oWc��+>����`����(4�E��Q�������\K��wu���K����:V��E��z�����4����A�z>����0C\����O`��7w����_�~7$�?��wA������O���D��1�
	8����s�4b�_�,�y������� �(��/���;�����s��/��p8��r��nD��}�0�xGD��<F�������"�@�K���&����C�w$���S���n!"�����##E�>E:�##Ed�"���3�����(RD�S���;����q���z�����|��jp�����R�fi�
R�!|3����[���e�������zAq��Z��cF���P����������gc�=�����ki��3�
��
tF�B��C|�;>[���{u�w�4xR��S��@g�[�z/�z��J��z+bo�b�fx�����U8=�����zbo����od���!��.�n���!�6��L�Y5��&p���vC�-ro�r�f(���K��`�&�[�^J���|��8��������*��BA�����RZ�^ekU\�G��^CkU|���*[���{)-W���*�����5�Ve��Q�^ekUV�^J���l��
�Kqo������3��+n��Qo���\�����7�R�{������y�]��U�V�W��k�����R�{����l'f��wU�Ve���\��������^���*��y�]��U��{)-W���*q�G�����Z���y�]��U���Q��k�����{c�{wCkUro��wU�V%!�&�{��\/ro�r�ni�2ro��w��V�7��`���z3ro�r�ni����s��m�����^�e�	7����{���RZ��C�^miU{����`3�-H��O���� ��z�����[$��������{v�7Z*�����7h+����W�Z0�����Bo�TVB��Co�VVB��C��)2c5Wd������XUd��3o�6V�����`���v"o�"o�V
������UC�m<�>�!3�]$��%�h���e��oP�U���iW�%��rP�{����t3�3Z���:|lPZ�]�w�O\�Ai�����{��Oh	������Ai�v�_�=q!���k(�^��������\A�RZ���|\���8(��^C[u�3��I���3�
��:�K��zq���k���pbF~4���}F��RJ��nV~%��e���n2�U�v`F~2���}J�`J)-���A���8(��]C[u�0;�r���g���)��L��	'.����v
m��xOa���}F��7
�������"��.�&C[u&$^a���}F�	�7����g7�^\�Aq��Z����+,�W���7#�faX�x3wF���������U2���C��>�������qP�{����@��q���g�[�y�y?G�}h��������V�W��!�q�����[�Y����	��O��Aq��Z
��W��!nq�R/2�)�������pP�{����B��q�K�g�{!�^�������{8(���li�*R���C��>����[�q���)�"��.�fKe�{�e�
��6��&��{p�0�^��Aq��:�kA�vq��'�{-����������z������5�V�[0#�����:�^J���*�r�`/���k(�.W1#������z��
;����3�����^������y�����w���\��K�������^�����3��+���R/p/��N�Z]a�G���lh���K��z����{)-7EM������s����6�^
���l��
���2/~~v�{E�������PZ]{���*K�k����p��p������}}�7l7z�S�8cuF��7
���y��z#Bo�B�[����z#O�����&��$P����+!��.����Y%���S�8cuF��7	����9#��.����Ye���S�8cuF�Ro�6�+�{ �]�u���:�z�z��S�E�=x��_��� �]�u���*H���^q���zRo��W�=����t��-���D�=y�g����D�=y�/`O����R�[,����{��+�X�Q���{��+���Q���{1�k��*r�%p��������^���z+roe��RZ5��*p���j����^���zro�s���V
����+�X�Po]�����+���Po��1��S������!�yB����:�����v�	���P�N������!��B����z����\���[qk���k����������U���Ai�~�?~+�����~
�U]a�e���g�3�]A�RZ�_��_�Cq;���`�e��$esUXSJ���|�Pqq���k����bH~�nRVWumJi�~��(f���c(n�_CwUw�!�a�������M)-���|pTqu���k(���0$?MWt>���_~���r��/�����~
�U������l�jB�����~��1���7�W5!�
Kd�i�3����I�_����~q{���k��2���EF��=�_��,��x�~F��>��v���W���FF��=�����W�m?�_\ Cq;�Z����+,�gb��� �����S�E�-}�����D�V��S�g�{"���j�%2��������e2�\��^��������������_]���6mU�/��A3��=2���������>m�����P�]�#Ca;�Z����+��Q�WmA�m<�*��j�/���k����1������-�������������������|)5��&N��Q�����������\|WCq�<�/���U6W��R���o[p�g�'���\�u����EY]����2���3~�W@_��)�P]��0��GuQvW-�R���u��|)l�^Cs�B��<��EY]�-`������h�/��l���vaH}������Kq��i�zw`_
����\��`H�}����Z������6�F���������G�ou��>E$���[��U���Q8������c����=����$��W		8	�����eD��E���>�m7#g	���UF���S�E�]~����z��,����W��!����1�������{_���[~~�����"�jO�i��t���/���E�-���n3�=~��������}�������m�D�=���v/$�S���MF���E��}��{!�^��pF�����W����[������m�"�Vy�8�]D�*�xVn�!�����{��c�m��M`^�	���!�6�yU�5�e��2�����U��d��,����UV����'�?�r�����V���\�1��m�QX.��'8�^��^��t�G��d���������a�~���NU�	���G���C0l�[�����#��^3e���:����u��Q��A�+?���&����G��.��BoYo����]'>������`>�[5���o��G�{�f���Hf���:���^a6�~�nF���*����z���/�
f���:���~	��������_Y~�V�i���I�_2f�(l�q^UZ���zw~�������2�H{���Z���WX/���23�������U��sB��]�}s���zr��^���ef���{����W������������f�^a������7#�f�{W��V�7w���c�=�{��2�i��z�����U����,��G�{��1�^�^a������� �<�������C�-]�}s���zr��^���^f�{"��{W���_�!��]�}s���zO�^a����L�����wU=�}e��{�.��9_cl�r��^���^f�{!�^<��������r���5��[�{��2N��2����[���V
������Z5�^a�������!�6�{��UC�m}�5�VnA���8����z��Kq�|�����-��������r�aF�{�o/3�u�����s�[�����z
��s
3
�+~{�Q�_�^��W�9;�Ki��Z+�/�(q���z���y��>��.�G�v����c�]f��W�Z����2�*;g>�.��9]cl���Bs/y([+�{).S��sv��G���7gk��w���\����m����W�9�}�G���7gk��w���\���������W�9�����r�jh�\\1�������F���soPv�."��>�Z+��{�������&���soPv�.!��>�ZZ��������7#�&�{�����������Ze��,p���oF�ro��w��ju �]�
���@�=��M����W�H��������Z��"q���*������7�~O���`��N�S_mmu"���W/��=S�|�.�Kmu!�^�n���B����^�\/����`��*��%��8UwF�����+������"��.�Km�|�����j��_����dA�m]�
���!�6|7em���h�~~�0p��/�������5�V~��Q�-$�L�Q�������*�z���^��������l�MY[y��W�D�{�����z7Cm����������>:(.S�������?9>���&�(������_��R\�^�A>:T����2
�d~�
�ZogJq�z�O}h��P�~|h���(m�Q�V~gJq�z����@�R�{�����3
uwek��_�zw~��nF�;SJ{���Z��`Fa����zF������E��������Z+�{�52����&��(p����O���������	�W�#�k[�����U���3ro�s�������"�F��z�{����_�����^Kku �J�dvmku �<���*��G�{wKkU�{�E2���*����^�{��z�{K�{wKku"�J�dvmku"��<��_f�{"��]��-����+m������B����v�r������ZU�^i���m�*ro��W�b0����[���[Z���+������!�Va�a���
��u�w��V
�W\&��������+~��P���R�{���j]�(�oT�V��Kq�z����V|t]��
���|)4W���Z�/�e�U�V�w����k��V�K��z����|).S���Z}�G�_Cm��3
�+����w��������ZW_J{�7j�5x�(�oT�Vk����\���h�k
k����z
���-�Q_�5��n��\��%�
�����5�V�V1�D���j�W��'_��Gp��|)��_Cq��'f��WY\����2�j/\#�o��o44WkD���&es�FD������$�&d��e�hh������M��*!�&�}����5#��.�FKu�~��i��z}���|��7�����?��
��_��W���o?���?�������T��������~��������_������_~�����/\��p���x���������������������?������|�M!����/�,b
��@(������m��k����������T����FL��~�m_�i��6���(&x�.nc��^C�p1���U�}���4b;WV�*nc���m_�a���W���Fn���\}�M>��S���/�0b
���l�N#�i�v�>l�E>��S���/�0b
���,�N#�i�����
��X�6���5t}�Sh�^e�pq�M#��^eU��G����^C�p1����)������m�7�*� 	��6���54}�Sh�^e�pq�M#��^��!!���S���/�0b
���|G-�4�p�F�M�����{oc��^Km���)4W����i��6����x8�{oc��^Kk���)4W����i��6���c���7�� ���S���
�Sh�^mk����m�7��>��������)������
gS���@1�^Fn�����s0[���{�BL�ZZ+�EL��z��#�a�����W���V���b���Z�,b
���m�pq�
#����������{oS��^Kk���)4W����a��6���t�����r�m
1�kh����	W8�x3���^����,%������5�V�s�Q���([���R���F����R�{���js
3
78em����
����3��@���������������V _�����������������y�������/������~�/���kh���1#��~Q6W[���_9�������u��-��j��~)5W����6�_��|��^��w_��u��-��j�)5�����v�_��O�����~+>�.����^mq���*���O+��U���E����_���-!G	��������e��&����_�X����vB�)�f��������������~3p�i�8��������_�X
���i��|������t��-�� ����*��`u�=�����D�=�u��D�=y��d���B�=��X��%���F��~/��K�_����B�����,�UE���>���"�V��K�3���������_5��*����W
����+����oC�m}�u���!�6�������).��������oc�?�5�W;N'��_�6�_O��������|x��������S���X��/�'�o����W������c�
&����~q>1�����)����~P�M���j_>:������_�8��Re���~qB�~�P�M���j���~
����)5�����qD�~Q�M���j�|t(O?�5�W;�(��\���j���mD�7t���S
�����~l(�v�QL������3�����oV6X��t�M'�`��`�8��Rs+����!�������|O�Q����qJ1��
VVX;N)�oS��I�i3RB��'�(��a�8��Rsk;,S���[�6$e�������-%�)��\��+#���+Z�B�Rp�S���XR�!P�8aF�R��S��?�1��c���X1�,nr�QpA.<;�-���������c���������������A[t���g��������O��Wm�u!_k�$]�����&�"_��&�"W���1�"W��-MVE����f���������!�>��&�!7���YD
�rp�9X�e��S�N��&+.C
,N#�R0p0��~��]tt�]��WC�p0��
V6Y�S\�'X{�w��]��WC�=p0��
V6Y�S\�`e���]��WC�W�`J��MV\��).�+Z�����������a��e�p0��
V6Y1S�N��&+nC
�MV���).�+�����#�Lq�M�����G�ou��>��9�2+�+v���g���!��)�������c��/�(�pPVY1S\�^�[�1"�.��%zl�18
�EV���Q:V>k�	18v1����c�M�I�����Bp�!�o��f�������@��7#g�����fD��#���b��{ �.���yl��!���:��wmGy ]~�xl�����W[`��"G�o���t���C�����E�_�nF�'�����x
���g���#���"����G43���{O������^��W������^���������p��_������y�����[����~�|�p�k����[�����6D�&����g��}�p��=n4�&��9\��7-023	�h��l�����W�e�U4�����JFf&a!��2��~|zP���V�U4�����J>`Fa��.��~=|zP��DM&\ECq�����z��������J+�S��1>�_\ECq���������Bf�@�R\���8�|F�������5�W)T��������~���ge:�W�n����~
�U�N��������~w�����U>\H������m���������A�j}�a����I:������������������������~�����O����������~����A?����������_����?�e������(��2RW���t�	�����':�����~�G��qv�y�?��/���,Lp�����|�f��{pql�8�����54~o�ea�����_���6���}aF�8�����54~��ea~����_��y���tN��0����gS��a�x�.K��ve����,\�s������&�{����e�P���M����|s��9q(�?�B-�6Q�{���/���,Lo�-g|�p��m:'e�R0�m����
�_�KuY���we�������tN�0�`��Dy�J�����0���ZU>���p���C��s�(��`C���b]�7��l���,��s�P�)��&�{��P�e�Z���M^,0��!X�T���S
��M��^�����uY�����3
�H���:'�0�AI8�������Xx�.K�����jH���:'�����c�(��`C�u���,o�QYc|~����r���c���{��Pcx��Bs�*k�����!\�s��	�������:�r���U�X��/���Kg��������5�X^���\���XA���:'.!���
����5�X^���\����P�Z�����
�P)��_C�u��:
�<�����
���������y|v�=����:�r���UVX����=������]w�}04X^���\����A���:q��������������+f��'e�uD�������c���c����:�o�W|�qF�	�7��+�58�������,�UB�M���6��7#�&����[pF�]�+#g��wg| g���1����p�X�!p�X�����������`)�
p�X[`����Z��~O���`)�N�S`m�u"�<?xqzp���`K�u!_gm�u!_<?�8�_�����"_gm�U�+��:��"�.o3VX}�a��	6���n���
������n��_����wF���.)Q!����v"�n<���E
'��8�o{q@E8�_�������{��n���+�Q����
x���a80Ai�z���(8����5�y�g����x�oJ�����W[���Cq�����Ka�xhF�+��e��v��P�{��*�@�"������7IPZ�^m�Wp�
���kh���bFa
��"`l�����{�y���~Ci��z��;�(�}Nc�������i_S*8�����5�xeo�Q8F�\�m7lW8E���T"�Q�{����3
�h�_b[oB���%R�K�%!��>�:���z�p������f���S��I$���H��K������z�p������"�f�z"\�������[:���N������{7H���(���R�n��
Ro���UA�-<����Q
Ro�R�n��N��"��i;��������]N���������{O���r�b�%�>)b��z/����������{/�{��UE����mF���v�w��V����+��4����[��mF�
��u�w��V
����+���P���'G�W��	��|tP�{����\
f�������\����r�~�c�u]w'�nh�N3)4S���:|rPZ�^��A�����+����:=L��L�������Ai�z��������
<Z�s�����W�Z�+SJ���l������o7�VgX1#?�Tn9�����r�*[�3�2���z
���9��/G[��wcJi�Aeku���{���Z�[����Rq���z���g
>y)vl�������5�V�~aF~p��l���Ki�z����k;(��^CkuF�^ayGP�VgD���>�L0�^��Aq��Z�3!�
�;���J��I��{	���K;(��^Kk��{��A�Ze��,p���c����^���:�{��A�Z�����v����ro��V�WX���UA�-�>�H0�^\�Aq��ZZ��WX������{J��m�pY���ki�N�^ae��G}F�r�)q����U�^�����{��A�ZU��K�^�f���:(��^KkU�{�uA�ZU��*p��m3��=�^���j������m�ro�W��	�^ro�ro2�V��K��QK���Z�{)-W������������Z]��B3�*[���RZ�^eku����������+f��wS�V����\��������^����V�y�������RZ�^eku����Vo6�V��0#���������W����^�{���Z]���<��c�g���RZ�^ekum���^������y��HO����r�*[�k�����
����Rh�^eku�����{}[�Z]����ro6�VWD���*[�+"�F�{El�QoB��]�����J��I�^eku%��$p��mS�E�M]����*#�&�{��3����Y�^�f���{s�{���:�{3������������;���@�=��ki�����^q`��zr�!p���Nc�-�������� ��{���3�=�{���v����D�=���Kmu"��<�������{
��`���~/���n��V�����82yF���%�����H�W�|�b)�*�o��W��<����[%��W
��v��-���!�6�}wms��}���v����u��-���.�����.��Ai�~��U]����v�5tW�y�O���Uu��Ai�~��U�E2�����z}�bH~�PT�W������U�W7�P�N������!���Q�^�u�~�u�����*����P_�����p����juJi�~��F�]2����������t����jwJi�~��F�e2���3�Wu��UX*��U�@�RZ�_e�Qq����k���30��V&*����<��\��~��B�����_�0$?`7*�����������F�����_���+l�����&������_�c�U\)Cq;�Z����+�����*#�f��z�/�����~-�UF�v�Dmu �f��z�/.����~-����+,�I��� �<�f�����P�N���� �
�e���*�������~�/�����~-����+��I���D�=y�����+�����~-����+��I���B��x�����+.����~������������*�o��7~�0�_�,Cq;�Z����+l�Ohf�����Y{�z��2�����j���bF<���o[�)-����c�m�/���k���R1$���	��~���
���������~
�Us'��W�_5�Ki�~��U��������j����*����)-s� =�9�+>�>{C��V`J�8����rk�>�>{C��0����Qp��\��
�����A`C����!y-���7@`J�����Ly;:��{�3��g�SZ�`m��v�`�{/x5�X/.��<�pF�!8
��m��"Rp�S�jh�ZD
�<�"pF�	)8
���wX���S�WK������	�QpFN�5h�%�)g�������ce���s������b�R�����Z��9�8X[d������k�S
.��G��WK�U������&� ���{bs
F.}^-M��\x�m���O�Sa�����O�A�?������*y�/d��ga��(�B���M)�B��0�����VD��GaY���"W����bS��������}��/�p�IX��3�m��U@��e�>��� �� ������6���c�,��������&p���cd��p����H{k��o�#�}%:1�0�H4�3�u������
KRnV�|����������#
��]��
S�]���t����������v�;��OQ�?��
�W������'/z�^�������1�w�!���f��W�0���S2�1�|����C}JR���0�0�w��W�t	�
���'c���3q;sV��<f&�:]w�J�C�?$�����~a��G��{H���f&�:]m�J������xal��|�#n���e�3
�x���z}���/?$��S2g��|c�|��1����+-����~�o�W��9������������&�_i�������������7#��.��9�cl��WZC#���f��,,�P���7w���1c�=�=4������{K"��_a�.��9�cl��WZD���UA�-���?�����_���*���N�����c����D�=��k��.�_i���W��%��8�|���������c8���+m�����"�^��S�g�[�k���1����+m�����!�V���;f�����u���1c�m���&����o��7(����Y>�.��9�ch��8��e��\�����m A:����)���t]�}s��~�/���U�W��R\�_��S^��������c8���f��+�+��)�W����=�/��l(���1���^Y`����~E�L)x����

�f�+,��)�W���� 0��lh�\��QB`e��6�,
�)o����^���r��%VvX�oTP�&����&8�S���)���fxUvXn��_�hl�q�g�e�7�p��7"G��E�?����+�v����c���1����^�%�K�I�-~�S0Rp�R��C8�����@�����H�Y���r�+
Rp�R��C8�| g��Wm�u <?��CO���|t��c�-��������*���g��|��
p���8��\^���\W���}"�]^-��|
�j+���X���������/	��
��|I����!t�������U`m�U�������6�����`)��o�7h�����WO���u�7
,�l����N��/��Aq��6�/������#��_C�����CA�_y��������~a�G�{����{���C���{����L����~����#��_C{�}���^Q��w
�/?�
���54q���+�^�Q��+�S��owJq���2��[h>���5�W>�(��)��wyJq�����~a	�G�{����o3
#x�����S���W�g�;h>���5�W�?9d�V�e�w����_�!+V�|���k��|���&����|D��<���$S�_�������_���+-���~�o��������&�������_e�_i����2�o�������f�������_e�_i
������,��x0�l��������_����M�_����_�pz��(��������*��E��M�_�����_�+�D�=���Y���WZA�i������W<������{v�w��W���}f��W�����x8=����{u�w��W�W�>�i����[y�}p}rt���������!�J�g6m��������)7��`C��.���MY`�0������0����ui�QZ��l�V�`�����S
v����^���Z���E��
k����+�����)��`C����_��Q�
Lq�rJ�+@0��l(��5cF�we�����+W��<>�.��k
@��+X�b�(��~��N)x[��u1x7�X�L����5��S�~:�>*i�*>�.��k�W�(p��nhF�;p0��
���Ly���5:�(p��ohF�98J�^pD�}64YkD�+��5!G���s�)'����`K��������&+#'�����)g�����hi�2rp8X�?��98���*��~������Rd������H�)�"<?�J9���|t)8Zz��\
_���oA
.�]h����D
.]
���D
>
���Q��|
���?�'B����h��.��S�`q���~/����`�&��~/d������bUd�K``q���~+2p�X�e��"�.GK�U��������6D��#�xJ�
	�u	8Z:���dB�a�O���xF���P�{��
+,f��)+������~�U�)�:�{/�PaW0�4�HYa�+�|J������
N�
+x���4�]3
���Aq������h(��`C�V����4�]3
^��R\�#X��?�:�{���a�33���F\y0����~e���+><T�T���
���:�wF�(T��O��A�6�{���a��aFa$oRvXa�Jq��g����C��m4�����
{���Ne������2���t����P�{��+Dd`i'MRvX!!G����0n�����
%VH���N��-�2p��[,�FCy�[Z��,�����(8#g���,\0n�����--��,��qI�b����1B�����h(���li�
B����em�U���2B]S�F�{/��b���^��m�N��S��N�'R����l��.��S�����.��KZ��}�#�N�{/�Rc]���f����*b�%m����p)
��l��*r���F�?���\��`u��4��^���j���n��-�rp8X�2��mAn]��&k[��)�W\����8��rks��<>�.gC��9�`
��l�6Lq����8�������&k����+X�dm8��rk�q�������&k[W�(q����V�`���m��8���
v�������<{)����0��^�Tn@��v6tY[h�'a�(��m[�a�����2��
@��v
6tY�vaH�������H��~}����m����
]�����_�]��	S\�J���-|v]v����"�p�I�/�.k�H��'a�_�	A8vA�-�.kKH��'a�(��-!	'������g��a�X���$�y�����H��'�'�rp����n�tY�p�I�/�.�@>x�^y��v [��� |H ���
�p�A������[����*� 	��U��\�a��9��s��TY'r�)p��VYr��s�������r���`gi�.��K�`�r�����/�DX|3n�gpE���,MVE����g\���p",�7���\��,MVCn���g����p",�7���P�N��&k_`��.���N�d�|�P���7����?@>
64Y��R�����|�P���7�`\TCq;���{�O)�N�d�>@(�W^��Q0.�����
M��.���+��(x�Jq��c�E5�S������!�A��)��=�X�0CS|9nF�����v
6TY{81$?�W�v1��
D*����q3
�E5�^�74Y�v`Ha_�W6Y�&��~�+�W�����i�Pe�;L����5���
�`R)n?��Pq���qS
��l���� ,,��^Ye�A8� ,n��S0�p���7TY{B���lf������3>�qS
��l��2�����{m�������q3
�M5�S���:���5�k��A�@��$������)�Re����V�����!���v���qW
��l��
�����{m�u"	��U������-U�� ,������ |
�$���f��j(n�`K�u!;k��VYr��s�|�wF������^-UVE���U[eU���s�|�wJ���������j�����j����x�o��(��P�N��&+.�����*���S��\��Pp\��)n�`C���!^�MVt���+�zg���)n�`C�]����&+��9X��;�`Lq;���O)p��l��
Lq�r�wF�+p0��lh��z`H�����S
��_��;�����C�������:C�b��\��2+@a�����3:�>�.
��5zl��0e��UVYq��_��1�������}�[�0����"+����+�zg��S�[��}�[o�Q�`q��z#Bp X�8���������&D�( �8cF�	8	,^�QoBN]~����z������f�$����8w��c���f��,���n��z��,��������������{ ����z����{H����[~��!�{G�c�-��E�^qL��zro�W���D�-�#��N���{"�����kf�{"���jO/�'����l����{
�+�������{	���p4^H�s�����{I��-�*�o�W��=����[��_�~�o��W�\5d�&����j����k���o�wSVWi�O�&��x�wB�	W�P�{���*-3�c�������O����3��
5�����J����T"�)�������~���~qA
���kh��?0#?��o��*y����_��;�_�OCq��������$l�����J+�S�����3���4�����JFg&aG����U
 O)�Wn�N����Cy�qq���-`F~4����U���R��\���/�����~
�U�=f�l��*�`O)�W����7�P�{���*�3
�i6e�"�/�������b�{���_���+������J	�7
�+����/�����~
�UJ���v�k���������aX	��P�{��+#�i�8njJ��Y`mA�ki(��_K�u K�ivm�u kJ�JCq��Z
��,������*�E`mA�[i(��_K�u"�i��-�N�S��	���;i(��_K�u!�i�8
pF��%����c���4��f������b�k��\yvQ{�w��4��^����H��b��sR.�!W����?tu]��4��^���j��Z�+�� 7���?����R�{���*/f��W�_����2�~~|4�^��������7����~)4SoT�W��R\���O����>�.��9zcl���Bs�*���~).S���G��m�����������3
���U^�})�W�k��Fy����~
�U3
���U���+/6��7�R�{���*of�7*����R����8��
�����5tWy��Q@�������_��W|�qF�;�/����0tWy?1���Q�]��Kq��j��~#�o��o0TW9"�F~E�7�_��(����6��7!��.�Cw��o��W�]%��$����6��7#��.�Ky�������/[�����I:����������+����_9^����o��o?������:���������������?��������/sT�
��ON3��U�WF�
������.���O��c"*���?��'���U��R�a4I��5��R�a4���3�m0������~
�4aM�~
�Z���/�N������4�`h�<�9����l�<�9���e���y��?�	������C:�I������C8��_��/���`h�<�9���l�<�9��e�)�6|v��`h�<�9���l�<�9��e������?�����'2�t"�����'2�t"#�:�_<�9�'2���;�D��Nd���;�D��Nd��Ag��'2G�Df34~����LR6~������2��~�D����l�����C:�I���<�9��e������?�����'2�t"�����'2�t"#�:�_<�9�'2���:�D��Nd���:�D��Nd�wAg��'2G�Df�������'OOd�oNd���O��G�3���y���y����uI�
I�_�<�
�;�����t�1�o{A�����yi��i����H��	qm�[;��C�8�x��t��M��4q�i����H'O����^����3~|/����2�B��x�7����"K\K��=���"K�.K��.�"KT�%��'S�E��J<X�3��sC��]��-]^C�h<K��Of��%�t��s?����W��e�����X�Bs_`t�-�Q�~����c�m���'i���+.`F�$�s0�]i���/&��up�Fq�����=f�>��2�^�Ki�>op������5ye]0�p���=���������S����R�{����Z1�p���=�����
C=�{��oZo����z
�U	'f��:(���R�~���2��
�����5We;0�4�C�^@_J��`$��z�]�|
�U��|)4���r�;�/�e~z??#:��D�O�����[����;���F���s��y��x#�o��o4�V%!�F|��UI�I_�z�o��o��V�7��+n,�QoF��<�>82\oF��]�����@��<���f�{ ��~�E���@�=��-����{��+.,��oA�=x��AM��-������R[���s���hF�'ro���|���{v�7ZZ�����W\W4�^��S�=��vN��{�.�FKku!�^<����f�{!�^��Q��sJE����ki�*�o��W<��QoE��������)�"��>�ZZ���[y�ef��|����8�zF�
��u�7j�sY�	
����^_U~�)�w���^���:�����������'�����C�u��Aq��j��5���n���z}�z������^����Ay��z��_�?A��W�[�+8SJ��S����4���z
��������'�������2�>���
 M)��^Cmu����>��R/(SJ��{p�yl���G����5�V��)�~@f���2���K�����)�k���R�/<����L)-CF�'��^���3�z
��W�����z���|#����)��#�o�����:�o��W��=�����x���L�7!��.�fKm�|����*#�&|�W�x�������-�UF���jk��7���`���z������R[������QoA�=x�_`�RoA�-]����� ��{�y�S�E�-<��o0N��D�-]�����D�=y��I���D�=y�/L�ju!��]�����B��x��I���B���'���{�.�fKkU�{/�{�a�3����U8�}��yl���������V
�WX�!���QoC�m<�>��3��3�����~-�UC��u�oYN��Z|�����1��GGq��j�k�0#��(��:_J����=`�r@�����[���
��WY\]���~'^����������|���*����RZ�_�������u��-���Z~)�dF�+�/����hO������K�n1�WW���_@��_J���������n1�W��bH����3���)-3�N�����R�N�������X�3>����rg�����S������!y_��QpX0O�V��XWD�]v����""p�X|�rF�	8��`U��~pb��`]		8�,�p9����x����H��!`K����3O�����/p�	8j�]p���4X�!���:��������� }v�� ��
VA.<(��\��,��\x�(�D>yv��kGc>��>;K�u!�<Gm�u!_�K�O~E�-�B���,��|�,N��QpE������"�>;K�U�+������~"p�N���m������Ra5D��#��7�����G�8?�w�W���e(n�_C�U��!��C�G��~����~����~q����k������UX4�Vu��Ai�]q����k������U�4�V���Ai��v�����f(��_o���
C1��iF\D2���)��.qh���b��v
6tX5�R����j�Ji�`�Kw�P�N��
�nC�3w����TJ�������)�Pa��aH~�nRVXu_�`~$�{r�c�W,�3Cy;*��_�����V�����������f(n�_C�U#"��q&)+��#�����)�������Pa��,��I����/O��|8������?�����_��W�����~�����O������������~��������������_���������'�������SNq�G����������}�g\?�#�������m�������k���6����	e��/����o�����������kK����O���9/���cK���67�(n�_C��\����5���)��w��L���){���um5�~��y��_x�qF�����`����>�����P�������Q3�]��P�/|zL�^+>�����P���bH����z��~hJ���c�
pq��v�5�~ms������_�@�P�/�{�
�w�kk��S���k[����������^������m����
�_�/�pV�~-SZ�����k8�x5�~-"G�������#�������&�������G�oU��}����g����2p������gD��E���@�m7#g��������'���{ �.���yl������xswF���!����?n�����{����[~~��UA�-�k[�4�m� ��.����yl�'�o�W[]����4�D�������{_����{��+��Q���{
��G�������{�c���{/�{��-�*�������W�*�o��i4��"�V{��-�ro~�?�������*�m���G^�hk�����s_em���Lq;i��}e��U���\�������q�~���_`��G���Z���os���W�Y������k=9V�/L|�����c��� �m�����Z�W��z�u-ek�
S�������V~YW�����]o�J���[�+{�W���m���y�a��aF�e-����W�
�
��Z�����gw��q�e�o����Zn�uW~�y�q��Vew�J����>f��]��U�9]y������WY^�����n�?����f�_�rN�^��4�w���Z���_`��G�{�v�����6���~u��+�o��wU�W~I���y�GZ��&�����o���W�0�����U�_e������C-�~3��m����j�����y�}�pup����y��Z�����������������U�_���y��Z�������o���W����������{���q�e�/��m����j��������N�������-�~O�����o���W��)������o��?����o#���W�_]����A�_U�������-�~+��m���o�h����[y�
���!���=l���o#���W�_5����o��WnA��
{�8����-����W�_����2�j�+�T|v}�5�W���Q�_���~�/���_}�ih������J1�W�
�������R�~:q]���_�Kq���+�f�W��6��u�~y�}2�o�k��t�������r�������7�R������J�Kq���+
f�W��6�_�_�������n]���1��
��Bs�*�+��R\�������=>�.��9tcl�;�/���U�Wn���L����..����������F��(��x�mF��7
��}<�"�o���j��\B����7�f����A��o��������I�_���~3�o��7h������k��2�o�W$��������}<�������R_������
�������M�x������`��
�o�W��6�_��"lk�>t'�o��o��W'��)��x�mF�'��)lkT?���.�K}u!�^��7�f�{!�^<�n�������o��W��J����*�o��wS�W��v�7X����[%���W
���������������_<>A��l��|zP\�_m�a��G�{�����3
sw�l3�u��Aq�~�����3q������c�(�o������/?������������~
���'f���7�f���=��������^���p�#�����_������]��uJ�`O)n?��'t��/,���{���_�� ��w��G�3�
`O).s��������<,���{���_�m����'���w{Jq��z���W6�|���k���0��xF��������2�>??z��������z
���3Jkg������Q�_��Ac7C}����vF<a��oB�M<������M��������J������uF��7�������~3�o���f��2���uF<a������y�}��jl�����_K}u �J{g��)�"�<�>��3����{���R_�_i��x�:����[x�}2=gl�'�o���n��N�_a��OXg�{"���j�]�O�����������3N<a�����{���dz��~/�������������'�����"�V��L�oE��]��-�UC���8��uF�
�����d���~�o���n�������'��]��&�����C�]�_�{���_���%�U�W����L�������R�{���juf�wW�W�������Z���������Z=�/���U�W�������ZW�������j]�)4����ZW�_��L��~�h]>�>���5�(�������Kq�~�_?Z�/���
���y�(������
���2�j�~�n�������Z�3
��+��u���L����������5�W�^1������Z�����+�r��oD��]����j���Q�_q��~�o��W��2�������
���������*!�&���G�G�7u�7Z�����%���W�7���d<��~�����h����C����������'�����{t�7Z����{���UA�-<�>�4����[��k��N��"�o��W'�������Hc�=��>�Z�����7j����^��>�]/�������_]�����Q�_U��K8�U����������_U��*�o��W
�����d���~�o��o��W
��	���UC�m�j���y����5�Wa��A�?���
|zP\�_��7�P�{���*8���3N|�zF�>=(.�������g(��_C<����'��7�_���W��F��3�����
k����_xT�]��R\�|A{�U��3�����
�cF~�K��*����W{�U��3�����
����3��*l`O).��?9�_\=Cq�����U���u�������c��[S���3��o6�Wa?1#?��%e"�S���g��?p����k��BD������BD��<���[S���3�����
	�WX@����
	�7	�!��H�{����XX�@������Y��`�����s�����:���4.i�	���#j1�>Cy�[*��,��qI[aD�"�GT?c��3��^���:���%4.k;��Dx�C�?Cy�[J�!X�B������OaC�W?e�4��^�������54.k[��|	+"��1n�����-5VE������*bpv$z�{�W�P�[�n�Y
AX�D����j�Ma�}�}[�[��b���H�Rs
+��m��\��w��������[e���P8+���
S\�am��9@a��i��fm�cH������<�0����Y�����
u��.R�ae�����9p�~�[��)n�`C���CJ0������`���-���)n�`C���C�0��xS
��).S��+��,Lq;��m;0$�~Q�Y�0Lq�����m����aaC�������+XYgm;�0�e
����E���AaC��ED����_�u�����>���#	�>	;C��%$����_�m����O����)?�	A8�A�Y��� �x�������a�R���3rp�s��tYrp�9�/�.�@>x��L)�@>��,U��|��m�U�����;'S
.�������d��"q���:�������)���g�����:��O���M��|
����~�����>;K�u!_;m�u!_<�G!S~�+r���`gi�*rp8�i���\yOB��\�4Y
9�
��MVCn<�'!S
n����`C��/+>B��EY4���������2���Q���w\NCy�
{C��;�!�E^�"3�a� �kX����P�N��.kw
C�S��SvY���0AS<��0.�����
e��/����NYf�+�T��5�}������i��f�k����^��m�@�R\�a�A�;.�����
u�2��g�z�]�)
�M��\����w\SCy;
��}�y������/��hx�Jq�W���K����i�Ph�;L���}5^|wF�;�T��5��]W�P�N��F�U��'�z�u�
G��(���c�4��j(o�aC��'�aag�����pBN<?p���~qY
���ki�����������7#
'��\��/.����~WK������5^|wF��pX�������q]
��4l��daak�_���pA>~r0<�a\XCy;
[���,,������SF.�>uJ�����v��Y'���������h�D>%��`�����i��g]����/��;��Y�X����E��P�N��:�"
�k��6���+�p�Q��\�}h�����v���Y
AXX^�Wm����������P�o����?��Q�[�c"�������6+.���g����V`aJ{�~�[��v�raD��We��0���ci���H����}�;��~]����&+z�`����}�2z�`�{���o�c��#
�*�����).s�R�t\=>�.���yl�+0e��U�Xq���O������C�
>�.���yl���2s�*+�)���a���P��u�������n+F�wUXq����M��/�����1��~w�%�U�Wq����W9����R�[����aD	}��U���.E�������9���#�o�W\�<����%�U���~S��P^������/�(8#�&	�Cg���\�6,8#�f����S
F���)��z#��@����a��!��}yF��!����c�UA>�G���� ����3
.��E@�'#��\�G��
�D.m�u"�?��>�����[J�!� 8hK�!� �����_�W�6������/������H��@�O���-�"�>[j��\%
��X
)�
,^1�RpC
n}
��X
)�I����� M�`����������K�+-3�S������ �+X����k(��`C��L�L���){�����rk���pa
��l����i�IX[�7e��<|�P\�`��U������
MVZa�f���M�d�4*��
�6Y	��P�{��&+�3��z��l�R�Jq���MV�}5��^���J�����^�)����H��\��&+���{/��d��aF~Z���MV�W,XX�(^6�R0������
MV�/��O�����J8��rk����j(��`C��"r����o�&+E��(p�x�dJ������64Y)![k��m�rp8X�m2�`�WCy���X���,l��������Y�`�����q_
��li��`ak���M��|,�7�S0r����7�r�-� [k��m�
rp8X�o2�`�WCy�[��9X�Z�wm�u"���M���j(��`K�u"[k��m�.��S�`�����q_
��li�.�`ak���MVE���L)��P�{��&�"[k��m�*rp�8X�d���{/��d5�`ak��9)�������&+/������&+/���+X�d�8��2��M��|x}64Y�Sh�`e��p0��
�6Y�U|x]�&+�3
�MV���������z�`J{���c��aF������+P0���{��c�]��)��^C������+������7S�{��+�3
�V���)n?��[��Ki�����(�oT6Xy����t�wl�{�G���`����K��z��U��~)������7z|t]�
��*Gd�(�oT�W9"�F�}��|S
N�������^��������*'d�$����oN��������*#�&�}��UF������oJ��7����^H�Y�_m{u �����oJ��������^������l���C8��M)� �.o��� �����:���p�`����Od�������:��O�����:��O�X��7��)��R�f��.��K�����.��K8��M)�"_]�,-VE�'m�U������_�)7�������c5��&pp��X
9�	,���S0rp�r�fh��%�#88)��c����m�\MCy����y��'�I�d>@(.W���:p7
��lh��`F~8�O�&���Bq��J���q9
��lh�_1#?���Q&+�_���!�[W,�������?��
��_��W���o?���?�����������_��??������������?��/���h��?q�����g��uh_�#=�����?�X���xm���8�g"���?��gb7�G<0#?��ge�wDP��+o�O)8����MR����H0��Bs+��#����_y�J����C7I��a�����G�a*%���s�O���/�����_>�~n|�m~�����
>��5��?m�F�m����������~M/��Zq��������������'~M/���E����O����S��.5�R��_��������'~M?�M����_�5����?y�|l��w���~
U�q��QX���G�oE����O�)�oE��}��4���
�4>�(��E��<R<y�|l�
�����R�6$�&,���+��~E�����C�-8����5��e�(�)��|����[p�9�e�������m�9�k�A���_��?�������W�
�?/��������+�cF�����@���������~^n���^C�W�3
�T�_\/�>���iOU+8�����S�����Z1�pL��U����s���=U����r~N�N����JrJ�8���r? �����r~N���Q8T�6Xg�S\����rl�8���f�S����@��6��Wb���������Vp�y��>��
V��������.G�S\�`��[g����s*��a��|�����v�8���rG\�s/�>/���T��������=Bq����q�9��
V�����m�9li�����o
V�X8���~���w�������m����?�~��o����W�b��s���~������r�|N�Zj��|�M���S���������m�9l��N�����o
V�X8���~/�,�|^n���`K�u!���S�������{yg����r�|N[j��|�M���S\f0������8����S���!�����������;�V?�����6��
6�X��
����>?(��r�t.�By�j��y���N�HN)����� I�S�>@(��`C�u�3��S�5�S
��Bq��`�����'��l��N_1#?;E\#9���c��P'n��R�
���
���\O���N�HN)8�E��\�0xl�4*��l(��p`F~v��FrN��Q)��r��V|x�Q�`C�un0��B���)o�Q)�w�-zw��P�R��"��a����+?S
���R���>��7|x(R�`C�u�����;?S
���Q�`���3"�.gC�u&���s������rp8X�B����S��������I�`u�������T���3rp�rp�4Y98�n���,q���:���>[��9��9X\#9���|,n��RpA.}�4Y9��,���S0rp�9��k���~O����`�X��9��9xS7Y'r��s���F�|!�]v������/a�������/���-�S~E_��W���b��*��������*�p@X\�9��� \� �K����+O����)
7$�&����sJ�
I�uI�-�2�Z�����!3�p:������A�ns�?6�Y�R1$����!S�9���X��JB�n��?6�Y�;1���:��A��������q�u����������!��YNB��L�~��^��p��6�Y�
4|����v�X�g]+�0�e
�~}�
�C��>�
@���)X�g]h��~aH���>�>;C�umC�0,^}�R�0Lq�0$fJ��0��l����cH����OS
���).�����S�N��>����YX��4���,^�_A�"�p���3�YWD�<����4�����������
'd��gag���p�YX��4���,����O���m8#�>;K����3�����9
#g����_�����������f������6�@>x�����oA>�$�,]VA.	����$\x���r������:�����)���'�.G���D>�4Yr��s�xqbJ�r��s���Yc?_H�W������H�O����)�V���S���Yc���������cUd��3�xibJ�
�����}h�
	��	�[Z���x�L���.���x/nO����J����a��`H~RQ�vX�����������J����`U�1$?�(j������~����~qW
���k����q�UXY��U���Aq�pk{F�����v�5�Wu�i�U�Y��U]��R�/����o�G����_CU��!�a�Q�_���
�M����~qU
���k����0$?�W��:��
�)���}����J����_��aHaa����{�~�)�F���7�P�{�������!�Q��(�)�F�_�����3��E5��������W�W#Nb��oB��<�>��1�|���J����_���+��I��*!�&���=�_\SCi;�Z����+l�I��*#�f���G�����v�4X���&��	��	����4�|�x�tXXXX��VA.<?3;��4������-%��,l�I��D>y~rOvl�����~��?�������8�}������.�.���'7e�v��j(�������c������5Y�cU�����'sf����j(�����F���"k���j����`��	+n����v��
=���,�����!7�X��� �.���yh�m��L��
�-����Wd���|t]~����v�/ef��X��R�/���V|t]�}��wl�~��<��/�Li��R�/����z _J{k�������#��+��3�����2���]{)�����~��0"O�Y[[��]�x������������~��.�( ���j /��N���
���v�=2�w+�Q`^mc�v`^������~�z)n�n�a�{��<�:)���{)/O���=><�������y�u���j�7
�����%D��?�5�V-!�&�}�1DS
N�I8�U7W	�7��~-�UF�M<��S����3��N]^e��?���Wp�	�-����� �'��'�����_~��^�^����
������������������/��������������������_����>�����'���������Y�m^����c��C'�~�G�#����j������{e� �&}�);�W���}��.4���{�����jv�ou���5e������]�PS�~�0'<����f'�Vf�>����+�G��ze��
s���]������7����_��tN���WV�t	^�_f�S�Hf���[��������v���{�������}sl���s����u������
��������.��;�r���%c>2f��x�1��
���������u����K�\"d,��@�\N(��rW{��N�����7'��-�D>@�|"�<{e��
�|v9���%c���O����)_����^���+r����7g��-�"_� S
���U�`u�U��k��-MVE�� S
n��U�`u����[��-MVCn;m���i<��&�/�Bq����,�\�Q���m���O���m����{/��dyW0��y\��s
�O�������W�><���
M��2za���������~��al����� T����k����kM��S
^��R��6�-8,��P�R��&��
2a�������R��6.���C�J�,���Q�:.��)o`R)�����H����
M��f���:J�;�T������� R)��`C����������Rp\�`~	�����G����`C��#rp8X��S
N�����'�
cN������&�'��$p������x~r�0�����,MVF������~p�0��98w98X��9��8X�d������&� ]�&� ��E�?���\x~r�0�`�����`i�N��"p����|"�<?9l[��|v98X��9�8xU7Yr��s��nJ�r����`i�.��K��U�dU�����'3M�\��k��������U��u�����x��C�����o�������c�w�����p/+~C�*�c������1���B����p�w�p�N?��/���������0��#����-������'l(�Lp���-��p����A0c>><��I���?BsOP[�������`����%�_�m��/�����\���/�����_3�������v*�P����+X[��������`�\��#���S���/������@m�`��G^&���Lhp�n���`C�`��Gh�`m������_k2��m����6��
6�r���-�6����;�i�9���6��
6��r���-�6�����;�i��^��7C���8���\����6����;�i��^��7C���D���\��&k���y���������9��dm0��#4W����`��G���������<w*��dm0��#4W����`��G������o�����
M�c�?Bsk��
����Nno;p�v��N��
����
�6Y�u�����4�"r�m�;lh�����M����os�
oo	9�6��
64Y[BNo�&+!����4�2r�m�;li�2rp8xS7Y9�6�����v �&�S��&�@>��M��|��nw�x;���.��&� o�&� ���oo9�t9x�4Y'rp8xS7Y'r��s��M��D>�li�.��S��M�d]�����=�)_��W��-M��|	�����|�,���RpE�]��&�"W���MVC�<��z����[�����j��M�`u����������~��.GC��/��#��n�i��}�O���m�v���ug�GC��;x��Bsk����'�e
�6Y�_��ug�GC��{x��Bsk����'�e
�6Y�����3������3
3�wm���`R)o?�x�wJ�+�T�{/��d��aFa���m��&��2k��=�H����
M�ff���&k���P/�N)x�Jq���}�0�0C}�6Y�&��2k��}�Jq���}/�Q�%�k��=�I��L��&���
/vw�%C��G��(q����#rp�9X��;�����M��������&kO����`�R���3rp�rp�4Y98�MVF�<��z�����,M�����&�@>V7Yr����di�
r�!ppT7Y9��n�
rp�rp�4Y9��M��\x/�N)�D>��,M��|
�M��|�,^��R��|u98Y��9�88����|�,^��RpE�}�4Y9�
�MVE�<��z����k��-MVCnGu����������9�u98���Sh�`m��`���m��R��u98���V�(q����8��2k�����)��`C����'m�=p0�e
�6Y�S�{��&+��N�&+�8X�d�8���64Yq�0���I�d�Ly���MV���^�����`F������p0���/�N)x����
MV�2f88i���S^�`m�w������d�8�Bsk���S^�`m�������&+F��(pp�6Y1"G���K�s
F�}64Y1!G������	98��`�>������K��������&+#g��BF�]v������Y�`u�u g���k�S~E��G���b���C����
�����x/J�A�tA�-�.� 	�����:��O���T�eh�'���Ea�X��Y�X8���Y��Y�=��?��a����[,}��4|	4��}��4|�4���O[qE��8�K�U�����Y�hU�����{�@ip����n�tZ
��
D���VC"n<�/�M�������R+-+>B����J|�P^�a�����k(n�aC������m��|�P^�a�����k(��ag���kRX����V�+6�������0������
�V����fm��V����O|QnJ�����v6�Zi-RXc#���0�U��4�}<�p�
��4l��R���I�c�h{�@�R�~��Cn�����
�V�`�f���,�V+m�U)o?��O���J�)��i��k&i������V��2_|
n���C������Jq���"�E[i��4�>��6�;l(n�aC������f�6Z)!
'a���[Zc�%6�����JH��*�E�he��$l�xpMkl�����v�4ZiX�e���i8K���56����4Z���������
#
��	��q�
��4li�
�����/�F� 
a������
�"��i��h����:/��;
����|q��
������������� ���������������?�;�����������������������_����>!�����'�|jy�?	#�:"~j��{M�����OO�b���8������F����<b������g��;"|�Q^������#|x���<|�Qj�amx$�`���I�v����c>�5�����Rs
kk�#����Yi7|,�����j���K����5�q����\<��+>������(+�D��pS. z)/O[D/��4l���aHA��7��D/����|�>A�R�N���8�D��&�����E����7|������WC
x\�D��#S����������<\�<�j��"W���5�Q��+��^[
y��yx5��GCn�<2���<�x�.�m�,��������*�0���vZe��L<m�U��������*x�Rs
k;����)/O�iW���yx5tZ��R�a�G�4���)o?���������
�VY�xX��)
�����iX�i�x��~��?������*9�}�
s
H,"�����%�H�jk��)�����/�c�
F�X�)�n����W[j�
�����}����~��qdN������W[i�=�����{_����Sf�_m�Uv�a����-�J����0������FD�(����*Q8�(�j����c���=��� �AdJ�	A8� ����� �� �����~3bp0X��)�f��,`����������
���@��2��!� X]d�G�P��#���"���2����{���5VA�-�#��N��\���"�L)�D.<u�u"�� ��O$�S `�A��|��
��|2�
��/�E�R��|��VE���`��+2pX��)Wd�*?Y��6��k�<��b5��&Q���jH�M8~�	cp����l���%�#�8X�c�|�P��O�ZG|.�Bq����y�����"�L)��g�e
~�;zl�>B(��`C�u�3�c���"S
��By��Y�'I��O�{/�Pe��bF~H�QdJ��������Q���H����
]�����Q�E�Rp�Jy������&����r��3��P��_�s
�Jy�>N.-x[���J�xg���
*Qh�`m�un�R)/��}Zx����St��w��D����]���K��L���������J��K��c����6/��L)8"G����y���c�����1���%�VYgBN<o��gBN]~sX���3rp�8X�de���s��}`xf�����7gu.98,��L)�@�<?y|��>�����o��[��|,��L)� �������
��aK�U������*���'2zl�'�p�����:�O�7u�u"�<�o�Li�B>�$�����
_H��@�������/����j�4�(|uQ��Ic�������������G�'Wg����(\�(�����7D�*���.��p�Q���������[����1��kAn	�_Tg�{-@�����������P���6�Y�R1����2�r+6,,�����|9@a�{/�Pf]���
k���
S^�����[�����
e���(���-�.$Ly�#��r�J�k]��uQx5�Y�
(L����m��
S^�G�������O��2�
@��+�����)/W��6kp�
^�
e���(��x�|J��0��~G?��cGo@���>��Pf]���	��2����)/���������)��`C�u�3
(�k��+"
G���3[pD�]�.��H�Q �]�e]	I8
$,����!���S�����JH�I �]]fe$�$���evF�I8wI8X���$�%VwYI8�$������������Re������*�@>x�>�
b����`i�
bp08����\V���\�,E��\_��R��|
�����H�g��-E��|
,�{�R��|��d����/���O��"�"_Gu�U���t �]pE
�]
�,=VE
�Gu����+O��W������Yj������.��x~�)��[qi
���kh��rbFaTQ��X������{`)���+k(��_C�U���AEQ[bU��c$�YW�P�{���z�Y��5�.��m����~�kl������6�Xu���U�[��KmS^A�R^��&kp�
�jTj��d�0���U��6��"��r
?�=�a�XCy�
���y�(�q/=Mix�Jy��|��0������
]V��(�qo=Mix�Jy��|��0n�����
eV�+f��&m�U����������
���{kx7�Y5"
�k|��Y5!
G����
�c��5�������	yXX_����J��IX.�=�����{/�Rhe�aa�O�B+#ga�������k(��`K�u 
l|R7Z��!,����Qqy
��l)�
������QB��}3����x��7�����W�����������������~����Lr���?�����������_������_~��������������?��;�������~W����c���{.����?a�~����Ot���S���2n�F���_i~��#��_[����u7��v��1B�]�h��
�+M��oo\������������N�2n�1
M��|��P����of�<��[p����g���a��	���'/\|���{������_�����O����=�����_�!�q3Vr{�������������p���O����R���?<���u�o�C_�.�(�>P)��>L7�?�2�*��{���������4;��T0�p������A��������+,'B���:�k�B_*N�X��H���Lq���t�2���{!S�n�S�v*����ux���^�������~��;���Dq��N����WF$�*��>Pc��������S����n�S�v4,
y�
���z���G�/��:��v���]Z�z
��[f��r�0�^�������_~7uh�n���G�{��>�-
3
�.����X/���:��z�/���kh���0�p���&��z=�/���[1c��@���^��]�W���C�����Kq��R��z������������0����R\n��v������o2W.�R�/����o���_�1��m�g�%�d(���K��b����|)���B������o2Wn_1����������������~w`_�{���\��0������Ed������oD��]�M���E�����x�`J�	�7���d���~�o��o�tW	�7��+�O�7#�&�~�u�oF��]�M��*#�f���9�"�f�c�)��������^��������~��C���j�T��
��`KU�����*�E`u�|"�>[
���xUX'�)��>��.gK�u!���Du�u!_�+v�|!_]���"_<���"W�
;uAY�k������U`u������~����_��[����j�M`m����h���<r��+|zP�{���/'f��^m��|zP\��Wy
�+|zP�{����3������>=(.w<��������!,�d�����m������<��zu���������W~����{J�+�S����s�m��������!`F~�C�X>�?�������C�
�O)��_C����������-�����2�'�O������u�����B������;�S��1h��*��4l���^1$��!h;,Wl�_� ��RpD�]v����!8
�-�|B�k�����C��Rp(X�b%��$P��~s��pF
N]
~}z6��3����������`q��������`�X��9��9x%�B��?�?>I�|�������Y����+p�5*��_���o�J���[���q���������>�7�gb�����D��	C���B��������6�^Bq�.�����P�N���omC��e��k��%�g�3�PX���%��WgWpX��Qj�`m��k���S
v�]�z�[�_p �(5S���>@(�N��|v�������A�Qj�`m��h@:a6�����W|v�����������i����_���+\j��
W)o�aC�����!�;������V^��J�)o�aC�B���-�M���m���[�OnI�mx�k���������!�{����;6��5������wxS��v6�a/�UO��;�a�jBq���c8-8|v�W��3�Y!"G��wm�"�p��W�Mi8!�>;C��p�ax��Y!!'������aK���3������Yz[��������3C��>�@v	��>�@>x�ZN)�@>�0�-}VA>x��}VA.?��4���0\�0�-�VA.<��M�4|"��G���g�����:��O���}��,|
,��2���/d������g]������>�B�~p�|l�Y������YY��,�uVE�<�7D��Gaoi��p�Q8����(�~p�xh���(��(�
m��
Sj�`m��-�������c[*>�>
{C���C�(�m���)����-�
S�N��6k�C�(�m���).�#�MJ�����
m����Q8j��m]�a��E�S
^�)�����fm��!y��6k������"�@a��i��fm�`H������0�����o�]�WC��m����)X�fm�0��~���g�^��WC�������iX�fm;�0�e~��ovlq�g�g���fmY8�,��m���#���(�c�WC��%D���p��Y[BN<
g�S�-!
�>
��6+#
'���mS
����Ga}�H�I�?�������8�}����a�������,�����v ]~�{��zD��Ga�n��z�����>	$��%���D��� ���{s�E.�(�������}�[��|�,��O��D
>y
���!��B�{_���{!_<�'�S���/a������[���.���yl�	�
�.�*pN�uMY�k��;�oC��+������u����[��]����	��+���w_����r�j+�}���{��������#~qV��~|zP\�_�m�v��3������YE���R�_�`~����k���Ay;o&�O���p-���W���+X[_�+T����cX�z`F~��h�����rk�=����3\

�`�+�����Rp}Jq�����9|x���k�`�&�����R���rkK�}k����L��1��=`F~��(����B���m����P)��`C��G��e&���RpD���k��������c�	98
������~2�nl�	98�9�Rd%���s����4����O���m8#�>[��� �y�e���$�,���awc>���.	�9�cl���������4�(|(�d�������E�7Gt�m� 
�e�?���,\^�m��,\�,�����
���'���^�)
�������:��.�9�cl������[�}��4|I4���.���K�o��pE�xv������U�a���������Z
qXXa�u����������q{
��7li�������Sw����<�x~r�4t�R\�)��`C��3J8��������+��S�{��J+�3
8���Vt����kX��V�+>�>*���)4�����p��~/����������s:�6�Sh�am�W�a��|�_��k�����7�t�m8�(���tJ�p��r
k��8Ly�
*��y�(���VZq��_~�p��0Li��
��/�Q�a�-��0Ly�����~w@aJ{��Pg��bF�����q�~y~�%kl�I8vI��!c��H�Q a�-�bB�	?��5��� �� �����'�$����J�������S�WK�������*+#g�@��~����`K�u {u�u ���\02��g`K�U�������*��E8~��c.������Rc���E@`���ND��G�'/��-�D>�,-��|
��-��|����pl�B����`)�.��K�`�U�)W��K8V�]��k������H�U�`�U�)7���S��7����[�����jH�M�`�SnN�H����'Wv��pk
��l����4���F���QpZ���2?��>�`\ZCq�z��`�fV���ZO)��'�e
���pi
��l(���q�IZ]#�j=�`� ��)X�[t��5�^���Jk����^�U�)� R)/S�����;k(��`C��������U�)0���)X�E'\YCqoo�&+mf����ZO)x�Jy�����N�����64Yi��QX\#�2���c��@����n�����
MV�O�(�IsJ�L*�eL���h�XCq�������5�{�s
F�<�o������64Y)!{k����������+�
/C��5�����������5�)
g�����
�����s��7K�u 	kk����4| 	<	��0Oiw�P�{��2� 
�k��S.���Ga��)
���{o��f�����'����Od��ga��)
���{o�Rg����'����/����a�
�)
���{kx��Y����&����4|�4,��8�a\_Cy�
[
��8,-�	�B�"W����4�l(��aK�����56A�h5��&��z�yAn]�
�V^��)4������0����sn���<�:��fx8h;����)�W�q�������
�V�3
<,��)
{�a����\�4���)��aC���3J<����
<Ly������W�a�{o��i��bF����V�xX�x�<Ly�
:�N�(������<Ly���_���
p���6TZy;0��������0�e
����^������;�0��
�6Zy��_yY}������ui8����@�����i8
4������Y9"
�.
GC���phx�6Z9!
'��Ei>���4��4-�VFN
o�F+#
g���|��pF�]��F�@�
o�F�@>~�Mkl������hi���C��M�h��C�aQ�Oi� 
�.
GK�U���D��F�D.���(��4|"�]��F�D>%V7Z'��)�?�-=��y���������/��wu�u!_��|J�y���������U��]]iU��*����\��k�����j��U��]�i5��������n������Pi��OP��][i|�P������>p�
��7l���0�0�w�VZ������c�)
�.�{o�Pi�aFa������aa��x.2�a�eCy�
*��_�QXh#~�Mix�Jy����rZ0������
����(������@�R�~��^0n�����
��2fF���B�`T)/s���E��E6�^���:6�y�l�����
�*��N^�?p�
��l���Fm�:�u���O��L��#�\eCq���#��������:"�p�Q���[0���������:����&j��#!	'�������.�{/�Rf%aa����N)8#'������2�{/��ee�`a����.�@�<?c�m6�^���:����6Q]e����`�����q�
��li�
r���&����\x�N)��P�{��&�DV���n�N����`�����q�
��li�.�`a����&�B�x/�)9��rp�4Y9XXi���������`�����q�
��li�r�����U
�7��&p����m6�^���j���J��MVY��������Ie�����b���raH����*@��r�>mxZ�����
UVqC
 ��UV��������[�����
UV�C
 ��UV����O\'2������r�[UVY�)5W���*+�0�e
��U�-8,����C�U�0��
�VY%S^���]���+>�.��Pe�m��'m�U6a���8Q��P6a��i��e��aH���]V���)/gb����)n�aC�U��!%��Y%lX���u�m8"
G�
mV���Q@��m�JB�
kO�)	Y81,l��JBNgu�����������
g����ag��2�p`8����0�y�.��m�@�}v�>�@>��>�@>x����KA>�8�,�VA.gu�U���^{|)�������h���E���n�N����a�=����g��������O��������/�����;c����>;K�u!_gu�U��/�������������iU��*����j����a����p����tZ
y�I<����?D���4��;N�hCq;
:�s)��\��x��������'n�����
���`��)������:|�P^&���<q�
��7�
���a��)������:=|�P^�xX�Z�����v6tZ�
c6Oa��_�����T��_��3�����G��N�+��'��E�i��*�����
�F��i��i�����$_�h;�s�Jy�|�gp�����v6tZ��0$?��/�N��Wl����j[�w�P�N��N��/�O�����:#�0�e���'������
������6~�vZgD�<������6�����:�����/�N+!'��Wmky�N��i��ie�aa��w�N+#g����S��6�����:����6��;�y��yXL0�a��������*���f���VA.<�7�;m(n�aK�u"�m�SwZ'�����8{bJ�����v�tZ'�����;u�u!�<�7�;m(n�aK�u!�m�SwZy��yXN0�a�iCq;
[:��<,l����_sF�<�d�4�;m(n�aK������6^|�kJ�
y��<,������ �>��N�Z��)5������a��4���/���C������wJ������)8W���� 1�eJ�V������H�������#
@,��5�_@Ly�~�/y\�����}����~W�_����
8Ly�����
8Lqo���Ezt�
#
0,��5���b�<��
����[_��.�(������~7@a����}����)�����D�w+Qa���9�S���K���uA��c���������W[e];`0��^�?G����o
�7"G�����������WB��C������������^S�M����_���9�"�����['����I`u������'�WF��aK�u g���
��|�}\xH�sA��`D�C@`�M�)D��G`�N���I��\��`��2pX|hJ�'2pX���:����q���:�O������|�,���|!���`K�u!_��M)�B
�x
��M)�"_��`K�U�����[@S
�����`��bp�����X
9�	,�4����x~2hxp�������"�.�����;@3
�|�P^���4����l(��`C�U�����"��);����	&U�fCq�79MV�f����&�z��������Qq�
��lh����Q���j����X0?]Sr=�`�fCq������Q��MV
`R)/�+Z3�a\gCy�
���(�
�*�P���kX�<��>�{o��e�
FlVa���.�n�R)/�KZ����:�{/��e�&lVa���.���R)/S���������6tY5�(��
�.�F$�(��8ZsJ������6�Y5!
+m|��Y5!
'����S�m6����������J��n�2�pVM��5�4��l(��aK�����6A]g�YX5��J������\��Y����&����4|H4��J������ZiXZi��VA.
�/7�������4Z'����fS7Z'�������W�:�2�{/�Rh]H��Fu�u!
_��	q:��a\fCy�
[
��8,m����VE�k��Pq�
��7li�����fS7Z
q�I8�}��2�{o�Pi�qX�h�7m���a��4�i7��a�{o�Pi��bF�7m����
8,�N�������
�Vs'fpx�VZ�S�~<���G�ih�h���64Z��Q�a�������)�W��}4��6�����4�V[��)4����j+�0�����)
�O�����h�8L�����V����+��4���uq8���(-x�6Zm����J��m����
�V�=fpx�VZm��\���m����
���1������jq8
8,����pD�]�J�E��(�����ZB������RK������Ri%��$�����2�p�N������<��<,�VF��{��4�<���au�u �>[*�y�xxWWZ�����{�N�������aK�U��������*��E8~2�ap���������:������N�D>~�����O�����������O������<|I/����<|uyx�tZy�x8�;��<\�Mi�"�.o�N�"W�����j��U:�����p���f���px8*;�mY�C��<,�Q���������#�#��_;���tbF~��������O�9���G�G^��/?���t����~y���������������^���_��??����������������_��sp��������-��2�,wx�����?�X��t\���q��;~����t�����H3�C�|T��+�������HS������(��a;��tbF�W����	����iV���W�
������a;��t`F~l����i�B���Y'.?�������o����|eL�����{q�����6��W�O�5��l����;d��s/.<��p=�aa����pm��������}������+^���M�N\a8��v��kx�D
�	��/+>B~���,�h�/�!By����^i�C������w3
�E��8�a"��;���J"�����|Ej�Q��/�Z����0N��EYS��!By�
*@�/�(��_W�����a����wp��Oo�������k����|q�����
��9�weMi8�u����
��3����qqN� U)/��6-����C�J
:-�E������sqJ�HU��4,n�������C�J
:-�o�q��#xq)���w����iX��5���O��������q���}/n���pD�+_[|�A�]��N����Q�am���\�������_i��S�����J��I�aq����3�p�xX�xd�����h��2�pxX�81��y8K<�|m�y���p������#�g�y�����V���[E�D|{�(�������A�u���<�6�U��?�y�����\��/�tmh�_�������|�����h)�.��K����_�����lq	l!n��S0���gK�W�-.���=0���hQ�x2�gl������R�5D�*�����-�!Y4�,�-qS
nH�O���!Y4���r`h���`��x2�ih��`Ay�
��y~�f�70�`\�
�<��!Ncv�%���
N�~o�u��r|@
c�p��
�<��$nJ���(��`C���:���L�������my:qG���W��{����
�<?B3?��2��8xy:qG���������P�����#4S���.c���������\��u98�W[a��Gh��W]����O'.�R�Ly����y~�f
�6Y��
k<��?lJ�;p0��lh�VX����]pX����� ^_���.'C��F��(�i��5![<��=lJ�	98�9��d�	98I�M�����O�d����3rp�s������Y�`u������N\6��98w98[��9��9X��9��9XX����aS
.��G�����*�����U�d�`a��W��)9�t98[��9������9XX����aS
>���.gK�u!�<��&�Bx:q����/�������d]������������N��z�x�������dU���s��n�r�����[�����[�����j����`�V����� ��N'.��QpX����64Ya)���#�j�S0|�P\�J���.���O*��d)4S���
>@(.W�������O*��d)4S���
>@(.W�����?A(�b���
)u�����4��I��\���#�����
]V+��g�����4@�R\�am��T��i�Pf��aH~&�x�mJ��T��5�}k'l S)o�aC���!������)
�+6��*t�F�)
�`S)o�aC��C�3Q���
`��r
k���c��b��BD�<
���4�4y�^�p���[uVH���a����~�p��+����S��bi�2�p�YX��8���,���������H��!aK�u 		���I��I�����"[���,�/.N�� ���'3��� �����4Y'R��D��8��)��)X�p2�_�Bi;�Zz�X�"^[����|�,�7��/����~--��,lo-N��"_<��Mf���@(m�_K�U��� ���9�"�V�4X�a�6��i��a5$`a'�xkqJ�
	�I���k[��[������pg'�f�vX��	�:��}J�n����`gh�6L����-����)�nM��\�G��`gh�6�bH���{�S��@���f����)m�_C���C
�m�~yc���V�,X�R��S�N��k[�8x��Z�m�'���.���o��Jj����7�c����R�o�n+�7f���5����d8zB�������f}��z��������8�
�����vax�x�w����������}u��q{x����o��q�0=N��;�a������U&|q�qv��������qx�.��������������������8�
�����vav�x�wJ�8;nf��������?9�yC�����]'����/�����q&�������0�����qr�.L�o�N�'����8�~qn��������qp�.��?�����vap���ql�������qn�.��O?���s�van����qj��������ql�.���>���c�val����c���q{h����o��q�05N4�S���q�05N��3����3��ji�ph�.��������������#����8�Z�+��3�D8�_��K3�����;����3��ji�ph�.����qh�.
����R�84n��s�����q�05N|�S��q�05�����
�g����qn�tX84n��Eu��C�vih���������qn��X85n��Eu��S�vij���������qn��X86n��Eu��c�vil���������q���?|��V�CW��8:nF�Em��ait�����S����{_�������Yq��L�����M+:���K��}�[���L��.+:`a�����������]���=�^ L��0i����).S����F�[��u9����c�]W��Sp�6Yq
��L���\�
Lqo���zl��aD����� ��~�=���``�{���s���6��p�vXqX�p�^�Lqo��w<�����<�&m�w�_������R�[�����w/�����b����K��7����;�oD��<�&m{#�o�����C�M��l(�bB�M<�&uq��|O�O���~3�ob�A��}�����*#�f}?��5��sF����a��o�W�\����O��������[����{�����UA�-<�>�Q3����[����� ��~���:�~O�O&����D�=������D�=y�����B�=y�}2�fl�����mi�.������n�*�������c����������"�V���������_����~�o�����j���������o��������&�Gq��6�U�qI���U�qI�����~q>\���{s
��~q<\��em�p<\��=��>�����;��)c���pI���U��pI'����/��K��poN��/��K�x������K�x8������R:��S8��0#?�I�������OI������t��F���.��Iw���J�S���&�-������6Xi+�����m��6����)X�@�=���NIs���w�N����V�A�R^�`m�������� ��GD��#�[�V����g`q����2p�3���J	8��m��Bp�!���{��Bp�B���8����nQ�X)8�,.������s�����1��)8��u�u kS��|t)��I��E
>$
V�X)��)X��
bp�b���8�\������D.<?��3�#�D>���$��������N���S0b��=a��|v1��Ac��/�����|!_<?��5�'�"_]~s���+bp0X|�zJ�1�
��9bp�b�j)�bp0X|�zJ�
1�	g��_�Rp�S����Rp(X|�zF�y
��_�1���S�{��+;�
v�+;�`���1�v���>���ce�0���N�ce�b�k����)��`C����w�M)x��_�L4�Kt^�)��`C����%�Yy��_�M4����u18���)4W����0��~�:���7�O�����d�
8�Bs_c�MV���)�W.Mix_��uA8���Sh�am��wa���Es����(]V�+fP�k���������)
Gd��e�`(�rB�{m���pXX�S4���0��0l���p`�����0�x�/Mi8#
�>
[���4���>�@�<
?yyeZ��4|tix��Y��!��W�Y�����|ml��pA>�8�Y
��8\��B� 	������8\�8�Y�q��pX�h���������B>�8�Y*�q��pX]i]��������B��8�Y*��8|	8��+��8\��auiY�k�7K���������j��M�a����4��4�Y��4�G��(�X�3�	4�}��v�{/�PhK�����U[h>B(/O�`�OCq������Q�R�j����'�e�i�9;pC
��l��`FiO���:<|�P^&���X��;j(����Pg+��<�M5���:V����{)��P�{��6�0P�v��U�ft*�e�i�gx���{/�Pf[�����U[f�T��������{/��e������U�e;�T���{0ovl������6TYG\0���5h��#S����{G��m5������:"�����m�u$�(����;��}5������:�����u�����@���n7�P�{��2+#
K{k�������Ga�g��8pe
��l)�Daaq��2�@>~p9k��0.�����-mVAV�8q�����p�YX�:�qd8��4n��������:����5N��1��Y�X�����?��������Y������3�4|!_?��5�a�\Cy�
[���4,��q�+�S�H�UX��.,qu
��l��*�����u���+����w�]Cq�[���,,l�q�p��Y�	�����P���6�Ye90������*�0��N^�/n���E�hh�^X������*P��~'�����uI8�����)4W���*H��~/������Q��f�5`F�7m�UV@a�����_V@a�{o��f��1������*P��~/���(Lyo
'C�U�3
(�i���
S������S�{��:�l3
,�i������t0�����)��aC�U�3J0���J������9�qh�a8va8������:�D�����0dxl�	a8va8���������J���a�`����3�p��p��Ya80�����0��caq,���,��,�,u��,���u��,|�,��W�g| 
]N�:� 

�K{�\�����s�JA.}��Y'�pPxW�Y'��)����a9��>
[��Q�PxW�Y��)��x����?m�B��(�-u��(|	(,����pE������0���,\�,�-uVE��+��4�,\����+�Sn����Rg5��&����j�M�$-�������l(��aC����������F��;��s����;�S�}6������:��<��6Q[h�>D(/�&��>k��,'������
���f&Em�uz���_��?�G�P�{��F�\=f�����m���*���-�)
�F�{o�Pi�a��� �����J��~�����q�
��7l���P1�0�W�=���c���M�����q�
��7l������� ������*���=�)
�J�{k�-�N��)L���N��A�R�~�'�4��4������
������6Q�i�y8�<,�#�����+m(n�aC�u&�ai�M�vZgBN<���4�<��<�K�����6Q�ie�����`J�����v�tZ����%u�u <���4�;m(n�aK�U���6I]j����;<���6�����*��f��.�N�����`J�����v��Z'���&�K�����X�G0�a�iCq;
[J�yX�l�����<|�<,.$��0������-�VE�6�$u�U��+���F�)
�N�{o�Y:��<,m�g�Li�!7�|X��.�����
��� K�m���z}���a���|���a��i��i]�cH��������)/������0��4l��.�`H��������)�W���8\�<1��Tl(�._1��Y[j]����b�.���W b�����j]��!"��V�
@���+�A�T�)o�bC�u�C
H�����)�Wn�N�x[�����z�k&��\��^����)�W��N�xw��(6[�PL�������S��\�Sq���P����b��gm�uE��(\�o�N�8"�>{C�u%��(`�8�wJ�	�8	X����J������Rme��$`�8�wJ��8��.��m8#�>{K�����D��j�@*��1�����@(>�P�-���P|HP���
B�!k�x�
2q�3��4[���L���sF&.�1��5�������[��������~�4|"��1��5��������Z����Ni�B"�x"���i������Z������~�4\��pmZ�2�U��+���V�!W���8�wJ�
y�	����S�GC nZ��8|�<{q������"���X������{�x5�ZuiR��+N��R�X1?~��#��T��n(o�bC�U��!�)��b�){���\������P�N��^���!�9��(����4�D���� V)/��������������_A^��������������?�������~����Ao)������������_�����o��c��}C����C
k>Y����������	��!�O��c,��?Q���P6����qP~�����go���=y���GAQ�N��6��e�&��N�6��M��������q��Tl�^�k�D(��u`[���I���\9[1�����
}`��xM	���lf`7�����W\�����?���>z~������5a,�w�N�m0�I7����7�e�Eyo?��a��'����0���j����&��{�����q������O�aD�p�;m!�����\�\0��������:=�	^Q	��u`K��M��������q�������O�X���e`K����'o��-�AQ�[��}���^�B9�+n-#K7���\0�������;Y��^��A9u�u K�\�\0�������;X��^�A�z�[pA����cF�0\�M�����'����0
�{u�u"�����\0����I7�
�%�&L��^�g]����'��7���(o��/�����iP�f�)
W$a����3��;������O���&��^�e5$a����XzJ�8��v�xM�����jH���;q�����e�O��?�sY������+X�e�����#/S������^w���P�>A�}��+X�e��\P�p�N\,=�`���u�	�9�d���w����]�+M���[w�^�97|x�����a�k����^�������N�7?p�c^/xx+���n��������)�|�����1�����R?^c6,x[0#��o���{�^In+K�����q��A�sE2"n��,_7��,0�
U�����v�*� We��{������X'O��soe��o��W�F����Pus�k����J}M�,����S?.XYem�6c�����
V��-���P�>^��U��>����M�6o�}��
V�����hR�.���@8�{S0rp�s���n.8"�&�8���+��#�`z�iH�98�9��*RpB�M~q���W0!'�������rp�s0]U:�`�����'��{3rp"L�=
)8#�>�E�C
������/<��
���8X�d����`��tH�9�49��y'�^��\����\	����\�li�*rp%L�=
)xG����M����9��d���;�`z�iH�r���`��tH�r����G��|������������>��C
>���&�8���+x"���u�u"�}�+JG�&�����/�9��
�	8���O���rp����m�Lzz��lh��[0#��E�d9,y;k�,s�q��,�=f$�h�,���%o�`m��`��#��`C���	3^�M����%o�`m��f�`�{-��d�������M�[f,���t;����`�{-��d��bF���&���������U���
 ,y�
�,�f�H@x�VYn�������t���
��*�m��W���r������*]px�� ��,��|���\@}��g�� � ��,��{���\D�}��g��c�K���#�z����p��0�;;��� �� �X��� ���*+#�>���C
���	��������0]01��� �� Lw�)� �&/�*� �t����+�p��0�8;���\��X���\����\�L��)xG�M^,U���3VWY;r���`�nvH�r���`K�u ����!���`u�u m�4Y'r�A8���R��|V7Y'r������d�i�+H8���Q���"y;o���
�	� ��������cF�'������[����'��|k�����Z����~��dK ��1�`����k�Jly�
�,�����7m��g�
�y��vY���}K*U�^6tY~���?��o�.�/�R%�g���5����
e�_2f�O�}�N�
�L�����Y����G�k��6��2��5�N+��
6U���~��au�#��aC����2��5��+��:U����v�<�^6�Y>,��?���yECH�������i8�i�Ph��4L6�x:�hH�i8�i��u�C���������J��d�����4���a�MsH�	q85qx�4Z	q����td���3�p����k�4���s��7K�����Og
i� g��Ol����<\�<�Y*��<L��x:�hL��������)�"�&o�J�"�-6�-RpE�}�:fH�;�pm��fi�v�a�����EC
����>
�O��;������Rh�d������| }V�<�d�������:���O�
)�D>	�5mC>���6��yB&Kl<�Z4��y�������<K�k��>k��HX��-����0aa��iH�XX�^�>kv3�s��4���%o�amT�=����6l��f�1#aa:�hL��������[�y���5a8��y�����}�<K�N�tK����W�I���g�����5����hX���v��r��k�p0Z��`F��tv���W�a��kX�I�+����6lh���cF��tx���7�a�����K�k��Fkfd8�m���8�8���eH��I���h�i80�6ZsD}�4)���~#�pl���������0�l3���,�,��wJ7����S��-mVBN���`�1�"	�>	?�U�{�������q��Z��.�2�f���3��������_��[����_�������������������������[�������������q�?2?���T�_�����?/������:���`��_����PA^�Z���_)j)����)j)�V����g�!Q��
��;�yG���H-���H����=!�-�@�8�6}f<)�&RDK�w R}�pO8�{>�(�~M�Od��������g�)�N����	o 'y����s�� ��Z���[���S`�N����@$n�`�7�n����
���f�O��Op���
D��
�~A��F�{-�P�-�.d-=6�`7��+X�,��A$��`C���0�p!kA�9�!�`�$n�`�/�.�D�^6{�2c��4T:"dH�h)��+X����A$���dxJmYf�OC�Op���NgH��3����H�k��&kYO����Jr)x[����B���s�� ��Z���Z�3����s�C
���W���Zp!���lh���L��xm��vK���`���.����
M����V�n�"rp$���s�� ��Z���J��d+=�=�����|�����H�k��"+#�� ���~3bp&��;���"�&'K�U���N�Y�c��B(��1�����@$��_K�U��J�Y]cU��J �������e ��������d#���~wd�J��/�n�w�H�K�n��X;20�B�C1��x�30],o����@$m�_K�u �� ���:��>���#��M ������:���>�Y�a�H�g�����}k����{6��M�
k��%u�_m��N�������~������n24X����~�
���%n��O���x����&C���C�X���������%m�_C���C�x�X�,q?���u����~
�:������Z��%�}�c]�%n�`C��.;����m��X�v�i��W`I����`�k��}�WpH�����������
X�^�u�k���0��c��������_����k�34Xk@}^�
���Y��}
k�������Pa�8�x�VXkD�de��)�5"�6;K����c��u����a�O�D�����S���������0�������������~32pn3��tX8VwX8���v�oA.mv�� �>SK4���\��v�pE�mv��"�>��pC
���k���X�|s�;B���`K��#�}�������>��{�--��|�!���R��|��B�z"m���D>���k�!�$��W8�'R���`o���i�k���U�cm�A$ng���Q�
w~H�F��ks3��O&Z�=���"q;k�b�p���ml��6�0d2����~\o��t�?��NzR0n�����
E��O��v�j��wT@��8~����
�}H�F��"k�w����j��m�*q?��Xn����~
E������i��m�*q?��X�����~
=������l���=���F��H��E���>$o�aC��m0>s#?6m��m�Q%n�am������h��dm0x#+?��dH�18�1�
��Fm�
U�����m��E����`���~�}������J�d���i8!�>;�M�n�����-]VB&{?��dH�I8�I�m�F��������������M?7�.�
�p&[$6�o6li��ix��Yi�V�Yi��5A�h�V��K��gK�U��+�au�U��+�#���p�E5������������!���<�V_������q��|��/5�T����@$&;k��dH�"�A�X}����j$��c�����W�D &+k��dH�'�I�X}����j$�����o��aB&k�dD�a���~��V��%�����o��'F��0������/�a�m+�K�K��=F�|w��Ga������~�uV�������k�7_��� L? c����~�eV��xM~����Wp���~�UV��%n�_m���������
.�������
@������i%�^��K��^	�{W�_���W[c��W�����Xa=���_	��F��K������2��
X��
��Xa����'f�0��)8 B���VB@����#�>�����#"p ��h%DD��ylXpD�}��!'d�H8�;������-%VBN}��1#'�Q]be���~li�2Rp�S0��)8#gB���
�zR(H���2�Rc����`�RpA.�'�eI�"���hK�U��k���������p���-)T����`K��#W���"kG�	O�������9��d��;�`u�u ��'�/��9�hr��c:n����G�����:����������|69��)7_B�����I�d�	o '�������-8���{-��d��b�����m�������=�!���{-��dE�1cVQ�6Y��
D����i�
���F�^64Y��L�H��$m�=�@$no������j$��`C�g����:�jH�3�T��y�a���F�^�5�XqY0c`/�D5��4���<��D\V#i��Z��z������-V\A�J��cK�]5��Z��������z����(T���Wy�h�U5��Z��������z����a�z��O�c��^\T#i��T1�W1 ��u5�5��~#�o�������{j$��_C}#�/�V�&u�~c�~������I{���^%d_����e�oB�Md���_0��/�����~-�UF�%�j�K�!�fd�LI(�����F�^��tW��,���X��[~�#��K'��I{��R]U�_����b�oE���~��n����~-����Kv��7�C��w����
��H�k���jG�%�j��!���{�������I{���^��dS
�:������/p<�_\Q#i��Z����-�������{����7�o���&�.��*M�������Wi����~��Ur�]�C��������������~��Ur'^�&�.��*�3�u��*y�_���W�_%�+i����4{�H��i��4�J�N���*���������J��	�:m��_���W�_��W�^�5�Wi90#�_����:c����UZ�%��_C���	�:m�6�_���W�_�
�W�^�5�Wi���-j��Wi����I?��*��]�
�U
�������J�7���������C�
�U��������J�7����y�7������Z����	�zu��S���}o�	�75�w��W�7����*#��>�>1���~3�on��j��
�o&����UA�-}�}b�����������_��B�������[������{����������������W�W;�o�������wG�����Z���w'�����������W�������_���_����������:��&�����D�=	�zuu"��}�}b����"��m�5�Wy��2���Wy���������2�����~
�Uvf$�����n���������F�^���U�3�D����n���������F�^�5�Wy�0#��;k��<�>���~��U�54�����������Y�_��c�d@������F�^�5�Wy���L����U^A�J�N���*�I{���_�5cF2�w��Wy}*y;�*���[h$��_C�7���.�Y�_�
��������2.����~
�U��������U����������F�^�5�W9"��M4�����7����/�/�����~-�UB�e�hfu��S������I{���_e�_����g�oF��}����G��h$���`��2�/[C���������Kg����H�k���� ��-4���������tt��~q�����k��*�/[B������[�zm��g$��_K�#��4�����w�B�_��I{���_��l���������tv��~��&�Ku"��
4���:�O����
W�H�k����L��l������+y;�*��2�J�k�����	3�]��Uq����7�GY`,q�
����X[`���>���#
�@��Z���*�bFF����@���W���*3 ���
V�3f$LWX�)X��
VvXe���58:��K�^���,����W���*������h(��
,�{kK��K�^����'^�&GC�U�3
�{,��K�^���l���Z���*�cF��t����bp�c�3kb�-8 �&GC�U"rp L7Y)8"G���"�D�����h)�"rp$LWY)8!G���&+!�&GK�����`��bH�98���G���s��-MVF����MVF����$�����`K�U���`u�U���`:�xD�9�498Y���\	�uC
����p0�e<�`�����di�v��J8���R������G�#�MN�&�@�	��C
>����t�����������d����`��bH�'r�I8��3Q��|698Y��9�$LWZ�(�Nx9	�y�
���F�^64Yu�1c$��;-���"y{+����h$��`C�U]����D�.�R��;����l�*������
MV�	3���:��bL�p����?�&��B�{-��d�gV�����C
���J�^��&��F�{-��d�&gV�����C
^��J�^��&��J�{)�M�*��3���ut����WP����������F�66tYus�?����C���J�^��.��Z��h�Pf��������n��pX�a6:SYfU\L#q
�����zG�[i8"�<B�fU\M#q
�����G7\i8!G�>B[g�r��h��g%�a����cFN���}������-�VF&Kj�r1���8�k-\P#q
[��<L��8��bH�y��C��4�<\:<l��*�0YT����!
W��Jx��9�0.�����-���<LV�8��bH�;��Nx��8��[�55����tZ;�0YV����!
��;��O���
����h��i��d]���.�4|"}��?�4��j$n�aK�u"��5�n���>!�}�@G4�O����������!	��c����?��us����k��3tZ�����������%o��O�<��a?��k��3tZ�����������%o��O�<���/^�������C��/�4<K�N��������������!	��C^��%o�amZ��a��h��i���!k;�}]��>�c�C^��%n�aC���;�d<����
xX�v��������%��ao����`H��t�������4����77��C�������p <Lw`�����t
����y8������_��{����-����������w��S�o�p���_�>|����?���������_��#?���#=������5�\�_�����:����'����+���8����
-��&�`&��
�[�@��O��iM��1���h�f����!
��?��/�[F�tD�7������|�:dD�'����|��O��g��{Cx��?����C��-'����r����?;"�J�E��D>]2�b�'������b4�g��{Cx��?���D�T�&����|w��i4�g��{Cx��?���;D�4�&�$&��
c77�&���|ohO4�'3�t���������?�c�������?Z�M�IL��kD�4�&�$&��-c77�&�������h�Ob�=�#2�a4�'1�O���a4�g����N�D����"�!
��?��b���
��?;&6tZ'����|O7��i�80"�������D|1���
����c��=�%2���D�DL�Ei8!�6��Z+!�>{�LdH�	�8������0qj�li�2q����D�4��3b�wKgF������_>Z~�����X�s�=](2���H\kw\��K��_{���^���xX�iU��B����~��������=I��oE�������4\	
k��#�M~�)��zwD���0����@��(LFy�:��&
��}o���A@���/���az,zH�'r����������D
>	�M"C�=���>k�&�H/q/���R��~�"�r]�#s�_e�������G�_����Ya������z_{#|o�n��d)���&������{��x���z����������������m�o��w�����Q�����7��o������'}�����w����4o���������������������w_�����x��������g?��/��b�G����k����?�1@��v����6�W�j���|�k���va+�#lc��a��
/��?�w�g�x���&���E��{���|E���e��D��M'C������������F�G���"�zW��A�{N��+�y;�v���}����� �����T��dH����������^�F�{�W��a�3�Jw����?�v�@�\/������*�0#�e#����l/""P���M����zU�fD�������~
�!��?}��5���{/{��^U���{/��?�w�^�x���|���CD���|/k��.����e��;��a<�L�E?q���~�|/[�_c0�� �^v�����*H���NR�� �^��?^��[}/��?�W]\UD�J&Ek����{�A�@J�~�}/��?�W�\������VW;��e�����#�^�����:~w�5I�]H��
�r�,����{�C�q����D�=��$myu"�^��e��W'��e
�G��u&c�E�=��h�����/�����+7�J�^����M��������rn�k������������~���s�����uy�~�vM�}qf����3����������wx\�_�+i���+7;�H�w��Wn����W������������r��	�����-����'������+i�_�1�Wn�1#��Y�_��W���)���J�k�����3�������%o'���r�����k����0#�_m�6�_������\�x�������{�
�������r�7�s����E���������oD�����!�F��H�W�_E�����G���oB�����!�&��D�W�_%��������oF�M�u��3�_��oF��M��-�UF���uU�3�_��oA�-m���W���]��UE�-����������_U��J�wQ�W;�o%��}����&�.��jG��	�.��jG��	�j�?:��&�.���@�=�.���@�=��KO���D�=���X����d����N���|�W�����{6�w1�W~Z�2���W�<�v�U~�a-�#��_C���/;�>Lm�a+�#o�_��Gv�<�^�5�W���j���������WV�<�v�U~�a!�#��_C�����q�����B�G�N�����:�G�k�����;fD��q�����:�G�N�����2�G�k����/3�C��_m�a�#o�_e�a�#��_C��/i>�W�_yXE���y���E4���~WC��7���u4����<,�y��L~?��G�k�����_YF�q���������g����/��e	��k��|D���x��_m�#�o���3+@n�7"�^6�H���*!�^��|����J���������~��e���k����e��/���UF�M}���F���/�g�_K��/Kh>�W�_����_z�`D����yF���W������~��UA�-}���F�[�/�g�_KU�/h>�W�_U����_z�`D�;��e���k��v������U�W;����_z�`D���e���k��������U�W��A�W���?�/�g~��Y��������~�����{�U>�O�������_���e���j��y����x����~�	�W�^�5�W�tbF����jv3���_z�`D��W�^�5�W��1#�_m5{�_���W�_��W�^�5�W�/���o��W�����~���</x������y����~���<�J�N���j^<^�&�n��j^�%t�_m5/����������	�]�7C5���������W�_���W�_���������j�f�H�7h��y����~��w��%��_C5�	�m5��@�W�O��74�7��9 ���A�_��7������oD��M�
��*"�F��A�_%����_�~�oj�o��W	�71�U�W	�7�U~�0g�����`��2�of����2�o&���|U�s����*����oT�W������.�oE�-M�
���"�V��Q�_U����_z�dH��������_�����oT�W;����_�~w�������_��;�����������t��~��������@�=�Fuu"�������{����_���'������	o'�_e���I{�7��e�������jqp����~��w��3������Z\���D>j�����C�~����I{���_-fd.lM��W�����m��o�F���g$��_C��0#sah���Zf������Y����g$��_C�,f$x���Z������U~����I{���_-���do��W�
�T�v�U>���I{�w��Z��.�2�nf�����������_��[��hy���?���������o���������o����?����������u���?�1J%��uV�]�m������*�.�xO������?0�����<$���P�-��m�x���y"�y���Q/�����z
}���'�B�PzH�	q"}F8��<$��^C��d�	�����RoF��}��>���&I{�7Y���4A�y�u�C�-���yH�k��2�"L�mt���z+�D���z���C�^��ty;�[����NbH������k<$��^K������x���������}:�hD���C�^��4y�I#�<�*�!����y������C�^��y'r/��A7I�����s��9�uB�=������p������1����J��*cY��K���dh�V�+�;�j[���J���WYk���K��^Ck��3��5�C������8d�z�^I{���Z�����r���zg�^��y�1\g�^I{��M��j]&�+�X�w������u����~
����Wn���:c�}��~���@�������Z��!��!�n����8��n��������Z��!��1��J�_�l?��0��k�������B�>��-�C�
���y��F����_7��5"��>��-�C��H���X���F����_7Y������K�X�7!��>��o��7!��&����^e����_��rH��7�����7����;l��
p�0]�6���\����$��!`K�U��K����!W$��'�7�T.�"�6;K�U�+A`u��#�>���r�;2��f`g��vd��0�������>k�q[d������a��G���&�!���G������'2��f`g��Nd����t���~Od�����{���l3�3tX����30�
8��m������Sf�
wxH�F��ks����,�����!q;���o��C�6�5tX���Wn��������L����������	C��M�C����J�N:�9B�����~
�6�Wn��������A�=}�����~

��T�+7Y�w�*q;���{��I{��
�m��Wn��/�S���n��+�
wxH�F���j�`��F6y�O��~7��������p���m�k������M��j������{7��!i���-"��M�
�7"��>��~q���m�k���/��A���~�o�����
wxH�F���*#��M��*#��>�j�a�p���m�k��2�/�����
�o&c���3�����~-�UA�%�<�&�!�V�����)��;<$m�_KU��&��rL������W�wxH�F���jG�%�<���!����;����p�����;[����l������{ �d����wxH�F����D�%�<�t�!����'Y3����;<$m�_C&�_��C�_�	�W���o8�7L��������
n��}��������%��1?'8�_I����_w`�>��SC�����������%m�_C|��d����
3����<F���W�6�5�Wa��l���Wa���������x�����|��R���q����C2��X�v�)+��:�tM~���vW`��+>"C�]�%���z��vO�tM~����v�#�E�����7��L���W{DR�%������m7x�H�W[^�x�~�.��W{�W��	��=:��nD�
}��U����}�~��������=8��.�o��/]�6������g��nB�MM�}�����&����^:<lH��7��7hcoF��M�}�����f����^�
lL�����S�CA�������������[��K��
i� ��>�je?T���~����{�����t.��z+o%��}������_�zw$��'^zoR������7h���w�x6��@����KonC�=y������G�}�a�'2��g^��R���{������D�=��{-����{��Vq�[���������iF�^�54Vq�1#��m���[���������iF�^�5TV����6��U�p������7�H�k���*����]mg=�:$n;]R�*h�M3��Z����3���d�L�KZ�o���?>�����t���_��{����-����������w� O4o������������������x��w?��o����'>>{�������;�|1�����k9>������������S���s�<j�������5_�p�M��\RV�	�2I���C����\"�����K3�k96��V�d���z
5_��s�Lf�������6�#sI��&�$i��j�����5_Za�t"g�������$��^C����\"s�(�
�w����+���	'2I�k���/���D�2Q�2����96�&�_�8�I�^�5}	O�%2�)j��`�t"��{�o�'2I�k���/���D�2%m��"�q"G��SvA	'2I�k���/�	�D�2Q�6����K�9�|�%�D&�{����%<C��\��}@-e�_r|�i��L8�I�^��tWx�.��LI�]�_r��9��g��$q�����Wx�.��L0��[�	:��/Nd���~-��Kd.��C����:�}1�D&�{��R_�I�D�2%u}u ��3t�+�O8�I�^���Wx�.��LT������s�cgNd���~-���Kd.SR�W'�/9E������	�g�_�Jrk��I�_�~fD�y��G&��]9�_���5���8���~�4���^m���>29H���dw��k���
V��t�W�������s������Z����x�NB�
�VXy���a:��y3� P%��`C���	3������C
^��J�^����0��:���a������n��Xy��`���N�Q�

U�^6�Xy������M�+o�P%o�r(��8T�{-��b�-c���z7ik���D���x���r���5��/�+����`7i{����`��_9"�&/�+G���8X[d��	k���9869x�Y	982V7Y	98��oF���S��K�����`z�mH�98��QF���s��K�U��3�`z�mH�9��4F\��K��-MVA.���i�!W��B8�nXQpE�m�4Y9������#�>k�0���{�WK��#�������w��t������������:���N]d���`��O��������:�O��N]d���'�`:ycH���g�WC�U&���`��Ye���I��6I�k��"�8�k����%o�`e�Upn���l(���0#�`m�U<`���\
��M�Z���*�������*���%F���$��`C�U��	{m�U�`����K�k��"�,3��"�,����W���.������"�����W���*+p���\
�^�&o�&�l���W���*p����,:�v��kr�fh�JX0#�`z�iH�980�.8 �&o�&�D��@8�~uoH�98���Z"rplr�fi�rp$��MVBN���N��������J���q�������p0-1������Y���������	�\��K��7K�U���`���1#���/�KE.M�,MVE���gu�U��+�`��w����`K��#���gu��#�����C�9xos���:��w�����:�������G�����:�������:��O�����D>�MV�<^A�������A$�gRp��"q����&���i����"y��<01�`7�{-��dUw`F6�H�dU����M��q9���lh��������c��<�I�����EG��4�Z����s��dN/�C5�`0���s)�H�k��&�.0J��55|���0���W������F�^64Yu�Y��,�q����+�T���|��kn��&�nfd�z�MV���J�^�������{-��d��1#���h����C����55�Rp44Y5"�e5t����#rpd�-:pO���li�"r0�V�����k��j$��`K������:*pH�98���TqS���li�2r0�W������	���j$��`K�U�����E�d��B8X{�N�]5�Z������lc
�h2���\	��\�-M���V���DC
���w��t����q[���li��`�����R��|V/��H�k��&�DfKkVu�u"���������{-��d���lk
�9��}B>	k�O���Rp24Y�T1#��U�d�8X��
V�����
M��2fd{[�M����%��R����598���K�^��&k�����S0�01�����krp24Y�,�{k��}���M�'^�&'C��/fd�m��8X��
V�,q���}���q����W�`����K�k��&k�&�H8x�6Y�,y{+��}����
M����p0�=����`�������`C����@8x�6Y{D�����G����`C��G��H8xS7Y98V/8!�&��Re%�D@xSWY	A81�6A85A�M�.+#	gB�����H����z�H��I�n��YQ8���4\�K���8�I�4I�M�2�"
����������021���(\�(�&K��#W���6kG�	�)#����&��Rg��;�au�u ���>��&���gH������N����0�31��i�l���,���8|�B�D>	k7|����h��h��<����m��	n"��O[x��F�66TZ����[`�����&"y{�a� 8�a�]#q�
;C�ux��y�
6A[in"���Vo������G��J��gIF�m�u��T%o�3L�M�h��H�F��J�X�$�{���:p����������H�F��N�XN���j;�c]���\M��q��m4l���u��l����:6��������8p���m4l����`H2�����p�*y?��q���m4l����<L��h;�# �>{:qbD���F�66tZGDf�l���!
G��HxX�a�a#q
[:��<�6�Du����S��=�91�a����aK�����*��wH�y83�n��H�k���i�a��&�;��<\+�9p���m4l��
�0[fC��i�"���
���h��iU�a��&�;�y��s'F4��l$n�aK��#�u6to��������z���F�6�tZ�0�g����<|��'F4��l$n�aK�u"��6ts���O�����v���<|�y�:�s�������:'�a��kX�x��������i�n��l����:����\v�������:���l����:=����5�l<N<,q
:����-w�vZ��`�������%�����i���!�vWm�u.��������8�a��h��i�K��l����:W�a���4�K�F��N�\�d�]����K�N�t���7�������:7�aI�kX�i�����\^�6��N��������:�p <LgPiy8�yx6tZgD�������#�a��#�pl��l���p���g��4����a:�bD�	y8!���?|������{�""q�#1_�;���H�����s�_{�����@��@�'u�U�3b:�bD���4���G�{�-�����|���~+�p!8��oE�M~�A��~+�p������VE���u��0\�0��c������{���!����;Ca�~D�����=D���� |�A�O�2�@>��C�E>� ��k�{�=��>��C�=�O�������g�_{)|g�q�f����E�[�_�>y{��j��0��{<�^�}�����:��#��wH�n�~]��~�����1����3��6�+N~������J�G��7��;fd�]�
V�f���MO�N�(V�<�6��<����*+��4'<��lz:tbD����������%AF���.�R��C�K��~�����Z���z� #�k��%�[���!����Q0��y��lg��2������|��%(x���4(�������gXp�1#�������!��t����bphb��#;�-8"��6t����#rp$�^pD�m�Y9���q�"+!�>{:nbD�	98�9��d%�`���.�RpFN���������/������L�������	�a#
.�����/������L����C
.���p�z�9�49��i�\���R�n�*rp%LGM�(xG�M~qX�����l�
]�;��9x'�_0r����gu�[���V�xu�u ���E��|49��Q�|"��6t����O���q�v�'r����'u�\0r0[h��M����O�>X��,q��,7����w��dE��V���9�`�+����������~����-����/�~x���w����������z�������?�����x��w?�;C��O���������|������3�\�_�����:���>�W�?�W��#��3��}�	C���3�S�t=���y+<TI�v�'V}��kp���3���l���Z1#9�M)x��*��?/������?�����}+���V���t�L%q%]���������oFM����O����M��V��������������������������w_�����x��������g?�����$�~IURb�3�}��%%�3v��z�'��~>]������W��7��U OW�xG	�">]��[�'6���o����������3���2�_x� y;�2�2�����k�cxq����&x� �{��7��1H�N��~�po����k�bxq����fx� �{���^1H�N��>}o�e�k�|�����{�-H���a���!�����0����x��/^�ro�Y���2���0\�/��$|o��/H�k��v2�����_���!����{���������#��m�UUm��wg�;^�A��w���[����@�=���j�0#����w�i�x'�����'6������{6�w��W'��I��~B����{��wQ�W~��������_���s��{�j�+?��C�v�U�WV <�^�5�W�E��� �O��~�>$o�_e�a�#��_C����	�����������<�?x���k����`F�P�_�=�A�s����<,?x���k���~�bF2��~B����>���~��������~
��_'�H>�O��~W����������������������Q"�	��6c���DOl���_X{�H{���_��bFr��~B��@�J�v�U�_yXz�H{���_����6�O��~�C���&{o��74�w5�W>"����2�������j�������Z�������O��~�o����do��75�w��W��-<���!�f�����U�_e�������_�_���~B��[�K���"{o���4�w��W��-<���!�V�����U�_U�������_U�_���~B���#��>�>�A��~w�������������	��������W�������_��l������� ����N��������D�e�'dH�'�����M�_�����_C5O��������'�_���W�_���������������?m5;�_���W�_��W�^�5�W����-���W�����~�����%��_C5�fd����<�J�N���j��%��_C5�fd�������o��X{o������k����bF��O�_�+����������W�^�5�W��1#�_�	�/���������m�k�����_����������
�W�v�U�Wspx������9 ���^�_��7�U�Ws@�
m�5�WsD�
�����c������������*!�F����*!��>�>�.��~�oj�o��W�7����!�f��������2�on�o��W�7����!������'����oA�-M�
��� ����2����[����UE��M�
���"�V��^�_U��������v�����`��v���-�W�W;�����'�������7�7X���� �K?!C�=��>�>�*��~��&�Ku"���'dH�'��I�W�_���g����Z�/ �_�	��2��C�v�U�Wn6���~
���<fd��������!y�����Z�<$��_C��	3�m���j�p����~������!i/�FC��3�%��j�=������2�<���~
��2W��v�i��e}*y;�*��7�H�k���jY2fd+������h$o�_e��������sg��
32��6�g�(��H�N���j�54�e
������
fd.[�����
���������=#i����%,������WK@�
}�}bA�����I{���_-��,���2����	�*��w�H�k���*!��4|���~�o"����p�����k���/Y@��'dH��7��7i�+�=#i��Z����K���C�-�����I�_��I{�7Y����K�x�	�/�o��o��W�{F�^���W��,���2����[����������~G��e��.�'.������O����u��\�������ey��������(�D��=�����?/�v��}��z���@q�}E�z��C�^�
��:!P���	�������'$n�^e��N���Z���[�3�y�=����y������[�����k��VW1c'�6��z=������l�V4!i�����g���	����^�	���WY������
�2o�&$t��'\������S���[�����.o]�%$t����{�]�U�������7���]�]Z2ty��`F�.�	po�+�J���~�]����4�{�������cH�2���,���J�^��2o��}%n�`C���	C��iOf��������&e���������<��y���i�{������nR�WkD��M�}��3,8"G�>M]_%��`7i��������gXpBN�����J�����n�6X85��'������5u���s�����
RpnR��O�a�1��#�����0X�b�������<��+rp!���*rpe���*rp�p������k��gu��#����������[��9x�s��n����p��6Yr���`gi���������:����N�d���g�����:���>��&k��rv�&k���Q������!��]fm��9��H�^��&k���Q����\����.�����@$n�`e���V��(��dm�nd���m�67��+X�dm��C�6
64Y��7��c�6Y�"U��
V6Y������
M����?�t�6Y�"U��
V6Y.�����
M��:�o:k��m�*q{+��
7{H�F��&k[O��o�h��m[����AGO��(W{H�F��&k�v�p�h��-K�^��&k���Z�74Y[@&>m��E��@8�Q0.�����
M������E�dE��H8�Q0n�����-MVB&;>u�����`zdlD���C�6
�4Y9�,�X�MVF������!#�6{K�U�����E�d��B8�Q0.�����-MVE&k>u�U��+�`zdlD���C�6
�4Y9���X�M��\k�,\�!q[��9�,�X�M���3�6Y��C�6
�4Yr0������9� L���(�|H�F��&�D&�>Vu�u"�������	9�ls�lh��,�;k��0K�^��&+�	�]��gC�p����m�������MVp^�6��&+�C�9x�6Y�K�^��&+x�`��(��d��a�>��&+����W���
3p��mlh��|b�>��&+,L8�Q�,q����������
+p����l��
,q���I8X�d�
8X��
V6Ya����������K�{�b����eV��%n�ce���k�D�����7 �>o�*+�@@��QoDM~�!��z#bp�c��-�BD�����!�"�&��}o�	!8�!xS�X	!8���F���S�_{���������K���	��b#��������=>�\/p�����
p&L����� �&����z�o����.�*�o!�KO����"��&�����z+�o������v��J���Q����7_��
��zw����������{w������z����
��7���{ �|�����{0��vW'����F�a�'��I�W�[�H�'#_mou"�����v��i�+�G��-��w�����o��4��r��_7c��\��m���������l�"n����~
�U�3��mu=�=$n�_euq5����k���?1c:o�vWq�����LG����w�H�k���*�;f��
��*.`N%n�_eyq9����kh�~\���y�����S���W�^E\N#q������2#YQ��U\��J�^���*�n�{���_�
&gF��&h���y	���Dz6lD���F�^�m���#YP����/S!�_eq3����k����X0#�_m�������U��4�����J��d=MT�W	�7����F��{i$��_K���v����2�o"�K�����H�k���*#���4Q�_��L����/n����~-�UA�%�i���*����/=6�_\J#q��Z����KV�DuU�+�_z6lD���F�^���W;�/�L����������F��+i$��_Ku ���4Q�_���_z:lH���G�-����K��Duu"��������B�{�b���J�/YK��U��%n�_e�&�_�{���_�������Ur3���W�_%�+q�����v������������~����z�_�{���_%_0c����J�W���U�Wi^��5������;�J�N���*��������J��k����o����+�;�j����J�^���*�^�&��8{��~W�_	��W�_��W���U�Wi=��5�w6�Wi�1c����J����������+q����f��o��W) ����x��~�oh����J�7��7i����_z<lD��76�w��W�7�U�W	�72���W	�75�w��W	�7�U�W	�71���W�75�w��W�7����xc
���0=6������X
��\��&u�U��!`z@lD�	�4	x�4X	��	�M�
�"W��������k�K��#�>�I�a���;a`zDlD�;2��d���a��{����.����@0=#6��!�hB�b)�����nR�X'R�A(�Q��|�)��b�H�g��������w��`0=%6���Kh$��`C����� �I�cew��+X�ce\B#q/��+���$�I[dew��+XYde\B#q����aRff�h&m��=�A$o�`e��q	���lh���23[E��MV�A�J�N<zRlH�'^<�R�������$^�m��&U��
V6Y��H�k��&+�3�Y�N�d�L����l�2.�����
MV�&�H��:m��70���W������F�^64Yy;0#����MV3����i���{-��d���6�8m��#rp L���(��H�k��&+G�`�������	��b#
�=4�Z���J��l�S7Y	98��F��h$�����de�`��������k�,�E#q�[����6�8u�U���`m���h$��`K�U���N�n�*rp�s��G�F��h$��`K��#��4^�d���{��==26�`�H#q�[��9�����&�@�������J�{-��d��l1�W7Y'r���`O���(w�H�k��&�Df�i���:���>{zdl@�eB>����2K�^��&�L����W���*���ks���*8XB�
�6Y�K�^��&��/^��
MV�f$��MV�����W���*8X�^
�&��32�6Ye�����MV���%��`C�U�	32�6Ye�����MVY��%��`C�U�3��MVYg,�p0=26��8X�^64Ye���p��m��,y{+���K�k��&�l3��MV���%o�`e�U�������d����&���@8�QpDM�&�D��H8x�6Y%"G���������c�����J���p��n�rp"L���(8!�6[������&+#g�������3rpns���*���p��n�
rp!L���(� �&GK�U���`u�U���`m�U��k���������q������+�`m��#�M��&kG�	/�&kG�	�#c#
>���&GK�u ��u�u ��������G�����:��O�����:��O����������&GC�U�
� ��E�d�	� ��W������F�^64Y�-���)Z�MVup�����MV�E5�Z�����cF2�h�6Y��D��
V6Y7�H�k��&�
�0#���h��:�I�����MV�U5�Z���������E�d��c��Q��Q0����������K��d^��m��
&U��
V6Y��H�k��&��3�y�����+�T��+X�dU�V#q�����<��v���&�n`R%o�`zdlD���F�^64Y5W��f�6Y5 ���������C������9�m�Y�MV����p0=26�`\X#q�[��������&+!'�������qc���li�2r0�[������	�#c#
��5�Z������lo��n�
rp&L���(W�H�k��&� ��5�������p0=26�`\Y#q�[��������&�"W�������qe����&K��#��5�����w��*w�H�F��.�@f�kVu�u 	���].�����-e��(�V�l�2�D>	
�Sc#��5������'da��f��Y�,,y{
+��}����
u��&I`x��Y������u���%n�aC���C��}��=6Lh�������
���+�$8�i��{h��'�F4<K�F��Fk�3�$<�i�}���������x�:<l���xXR��VZ�<,y{
++�}ux�:<l���xXR��vZ�
<,y{
+;�}=���y�:�}[0$�am��o���������7�a��h��i��cH���Nk���������ph��3tZ{D������#�p$<L���h8"�6;K���#������p$<L��h8!�6;K���������2�p"<LO��h8#�6;K����3�����2�p&<L���h� �6;K�U�������
�p!<L���h�"�6;K�U��+�����*�p%<L����o~������?�����t��[��'�!��y����__~��������I_8��i�������G���������������������w_�����x��������g?���A�/cs�������"�D2����0^�a<D�������n�e���9~�9U��!��2"��o�� �'�y�!
�x���'�W�o�D2>��0^�a<D��b���F4|� F��hXU��2�1�^=�$�0^�a<��H�^�����{�qYi�hXU�AH�1$��q�|�xp�����y�
�N��������|��~��D����
��MD��.�0�C��R�G���
C���8^�A<\k#y{
�o���q�j�hXU�a��!�^������6����p���@���6��U������8^�a<������p��p��q�k�hXU�aH���e���
��o����5<�@���6�e���aC�ul�W��~���vZ�����������m��f�G��N��$�����:p����5���\ms\V��u�
����/n>nX�i��F��VvZ��9.�m
[:��<|Yq�q��N��H�^��N����6��-�VB���������p����4L���h����6��-�VF�,���au���m$o�am���m��z�G��N� _��|�����7��������6�e���aK�U��/kn>nX�i����kX�i��������������/{n>nX�i����kX�i�������7_���G�/�o��"�e���%�k-\s#y{%kk-�rs\��H0�~O������U�Z��F�����Z����,��)�k����{N���M7�����	pX���UVZ�8,q/��� }s�Fd0�-�N��_��B�t����k�����*Fd(����~C������:=�������C������ �Y�A�K�N<z~lD����	������0X2���VY�,y{�*��sqx����K�{�]�%s�_m�u.�������:�/^{;�a������'m�u���������:W�_���"cX��1c���m��
X��
V�X�,q�T2,8L��O�~�6Xg@�����$��9 mY0"p�#�����A`zllD�8v���c������2p$LO��(8!���`K����`u����`m���S�m����H��Q����H��Q���*H���2�Rc��B0��k��\�#cC
F.�����"��N�cU��J8��QpE�m�Y;rp%�nYi���|"r��3��������_��[����_��������������������������������������p�?��XF�pH���Q����������O��O�n����Kl|���?�vf�-��	6:e��&�������������a��#��d���{�T1#�F�l��C�y;?��yo�0���Z���{��1#�F�l���P0������{���������[������[�
����J��`���{-����e� #������{K��`2���UI7|��kb���K�-�?B�
V6{o�"L�?�)���a��#��`;��&����+X������`2���EI���q����4���G�N�^����[�`2���=I������_\rs���dz���f/M	9�L�fM��'��������[pB&���W>����L��?�%���3rp{x��cK�-8#��������Lf�?�$���rp{v��SK�-� ��������LF�?�#���+rp{t��CK�-�"������!W�`2���I7�\�����{���/C�?.X�d���{�����to�;r�eZ�li�������V7Yr����g$�[��|�/[��9�2�����M��|�9���H�|"_f�K��&�D�L���`m��&�������G��`7K�k��&�M3��M�s����S���r8X�^64Y�e�H8x�6Y�K�N��&��/^��
M�����W���r8X�v
�6Ynvx��lh��,�{k�,7K�N��&��'^�&/�&�-f$<k�,�K�N��&�-���Z���r�����gm��V�`�������{^��%��`C���	3��M����%o�`m��6�`�{-��d������gm����������{��������r980�6Y."�>?�l���#rplr�bh�\D����MVD�}~f���'�������d%��D8�-RpBN}~f���g�������de��L8�-RpF�}~f���#�6[����	���C
.������,����\�li�*rp!L��)�"W���&�"�&��&kG������!���;�`u��#�M^-M����G��| �}~f�����G{����:�����h���O������,���9�lr�ji�N���p0=Z>�`���������`?�
�lr�jh���~��_��\����0����S����0���Z����.@������6Y��?�v
�6Yf�?�^64Y����2�������!�t�G�N��&��p�G�k��&��3f����k�,��y;k�,��q��,�8��:����M���������M��������
M�_N��:����M��������M��������7C���3�N��`m��a@�#o�`m��a>�#��`C����/�?*X�dy���������{�������
M����)��m�|@}~f���G���|��Q��#r�eJ��k�,��c���Y2to�	9�2��q�����|���q��&+!�>?�e�����/��GM����)��n�2rp�s�3[��-8#_��?��\��/S�?*�-RpA.}~f������|��Q����/S�?.X�dU�����g��[pE���51,�"_��\������k����2to�;r���`K��#_��T���:��w���&�@>�,M��|�G���|V7Y'r����`i�N���p0=Z>��9��s�3[�n-x����&C�5O���W����'�`��)X�d��������d�n�������!;�`��)X�d�8X�^64Y�w��q����=p����m�f,q�������q������sp�6Y�,q���y�1#�`z�|H�p����m��8X�^64Y�R0#�`z�|H�+p����m��8X�^64Y��0#�`z�|L�����S����7�����&k���%t�`m�5o����S�����������d�98�G�����`m�5�����hh������C
�������]�1
G���h���p$ L��i8!�>�I�e%$��$�h���p"$L�i8#	�>	�I]feD��D�h)�2�pf(�.�
�p�����mVA.M��6� ���6�"�>�I]gU�����h��*�p%0L���ia��a�M�>kG�M��>kG�	
��C����>
�I]h��{�-���8|�'��4| }v���:���6[�y� <L��i�D>�+�y�l�p2TZ�4�%$<L���hx��&"y{
k;���H�k��Nkq3�'yz�|H�n"�����vZn�����
���N��Y��)�!
��O�tN�i-��F�^6tZ��1cv�����4<�T���������k$��aC���3���zz�|L� U%o�am����{m��i-L�\�O�ix�*y{
k;�7�H�k��NkYa��B��xz�|H�+HU��kX�i-��F�^6tZ��5������C�@�J�^��Nk�6�������?]�e��%3f�����������_��[����_��������������������������?���������������G\��l����(�D���XI��������Z~d>
�������'��������[p'�����J�%!\�� O�<��d��l�[h;�w�H�K�n��|��l���1
#[d�����H�F���� \�� ������E!l��n����-%_E� �A���!
Wd�J���;>\"y
[J���,���4�#[��-����� ������;.�v�kpH��k;��6���p1��m4l)�N|�F���_�C>�]�I��yu���A$o�aK�w��6�����:!��]��v|�8,y
J�u�1$y�����{v�������[���m4lxpmuC��mO�y��a�a��kX[i�~����aC��z�aI�iX�i�xX��~�i}������������o�����?x����������_���7oO�~�_���[��M��V��7��e��������������������w_�����x����q�f���(&
_e���E�*�0d��l���EH�K����x����������|��	C�/��7d,q;
����[=^��W�S�o�XR��nh7�K�^�/��_y;�x���g&���m���N~��_'�?����2cH�>s�%���/5H����pK������m4�i	/!�����s
���!
�R���5<�b�������}�����������p�/�K�^��-�%�������M�
'����p�����|�_��n	/�P�%�~����6�����kpH��8����pKx��.#��<�a����K���4\��y[<���x(�
2����X6�hL���_�C�H��m��-�R$��a�)�.!����kpH�;�q��-6�-�R$o�aM�v	�<L���_�cF�	/����)�����|��D&�R�����y� <�?����@��m4l��N�ar.eVwZ'��IxxQwZx E�66tZnY���kpD�.���h;�
7�l�
"�:�
W�ld��58�a� ��
"���
W�l�"�:�
w�ld���C�"Y!b��"[{����Nk�%"Y"B/���q��Fv��E�Ko�Ddk/q��im�Ed#[D�%�0.���h�
��l�-"�:�
��ld���C�-"�"�m������F���Nk�="�#B/�����nd��[����{D��7:�
�ld���C�="�#������x�Hdk/q����p��F6��K8�a\$��E"n�vZn���D�l��6\%��U"����p���6��xC�M"[{���-����*�U�i�&��m���4��D��&7[:-\%��U"�����q���6�����M"[{���-����*�U�i�&��m���4\��/�D~���|��R�����H\�H��k-\&��e"4���q���^&�������.���Y�����*oH��Jdk�y�Q��~q��F6���J�ll��7�_\$����� }o��Gd#{DVu��kD6�F���/�p{��k�����[D6�EdU�Y�DdcKDh�!�����D����[�
�0�!�j��0K�^���2L�����k��o������UVp��0X[e,y/���R��~����i����%n�_oH� X�^�}����������ik�0�J�^��+�����1����9a�>o�+���W���
����@aX�,�;k��K�^��+�^��aC�V@`	�)X[a�X�~6������ylX�6c�>o�+l�����o����Z���
�a�>o�+��@ xS����o�
-VH��O����
)8
��)8"���`K��#�`u���#����I	18��F[z����{���������l)�2rp�spPY98�Y98�9��d����`�;pH�9��o�CE.M~q^��W����`�;pH�9����CE�M~q\���������w���w���pp�~�v�����/N����9x�s0�8��9�`�^��|49��a7�|�9��R��|0�>���p��&�8����O������w���#n���������&�7��8����#.��d�M�6Y�D��F]tD\p�n^��qo���&��6A�dE�o�~u�q�Ml��yqP���z�H��m�q�Md�m�EG��6�7���8����g�/�m~��Q�dE\i#q?�q�M�����
MV\`�f�,���`m�q����\�&E\i/+m�;+�&+�3f�O���&+�B����_0C
��6���F
64Yqs��?�7j����H����S4n�����
MV�N�����MV3L6��?E��{-��d��LV�Dm�#rp`���;l$��`C�#r0�d�MVD������q����li�r0Yd�MVBN���_F�`#y�[���L��Du����3�`��I�H�k��&� �56Q�d��B8���1#�6[���L��$u�U��+�`��I9��9��d������I�d���;�`u���k$�u:���������n����p0U�C
��5��Z���:���
��n�N���p0U�C
��5��Z���:�����n�N���p0U�#
Nr������d�	8XBw
�6Yi�����MVr/^��C��p����m�������MV�^�&/�&+y�`	�)X�d%,q{k����xM^MV�g�H8X�d�8X��
�6Yi����
MVZf$�m��,q{k���K�k��&+-'f$�\Y�1
�36�@X[e�@X�^6TY?.8��d�����~�
�	k���	K�K����J[��d���-�~�	�
S[>�����k��j(�R@}v�����+{��0��C���������JY8�Y�M�:+E��H`���!
'������Rg%����a7����4�
Sa>�a�������ge����a7���8�	Sc>���8��8�Z
��8��8�&u�U���a���4\��K��WK�U���au�U���a���4\��k��WK�U��+�au��#W��T�ixG��<l��v�����SwZ;���xX�i��{��-���<|v�N�@>�;�y�h��f��N�����SwZ'����aO����3.�����
�V�`�ff+l�����D$o�am��q}���6l���[0#[���Vvp������V�6��������cF2��i;���&"y{
k;��+l$��aC���	3��N�i�����5���2������
�V��H&�:m�������T�i��H�k��N+/3��N�i�����5���2n�����
�V^3f$3|����+HU��kX�ie\c#y�
:��������xm��7�����������F�^6tZ9 �m6^�i��<k;���l$���`��rDf�l����y8��|H���F�^�tZ	y�����N+!�>��0�*�{m��ie�a����;��<�	Sm>�a�e#y�
[:��<�6�xu�U��3�a���4��l$��aK�U���J���*�p!<L����q����6l��*�0�i���VE����6�0������-���<���xu��#����6�0������-���<���xu�u ���6�0����aK�u"��6���:��O���N7�H�k��N�L��l������<,y{
k;�2K�K���i7aF�����*xX�v��|H�xX�^6tZ�����������a��T�i�K�k��N���	��N����������*3����6l����1#��Y�i�xX���vZe���5y8:��K�^��N�,��������*������h���
<,�{
k;��K�^��N��'^�&GC�U�32�vZe������V���%��aC�U�������V	����0��C������N�D��@xx�vZ%"G���N�D����aK���#��E�i%���xX�i%�����d���p"<��;��<�Sm>���<��<�,�VF���u����3�a���4\��s�����*��������
�p!<L����+�pi�p�tZy�^��VE����6�0�pm�p�tZ;�p%<��;�yx'<L����w�������i��;��E�i���a���4| MN�N�D>�;�y�$<L����O�������i���'�am�U'������6�p�%7����������8�U�iU7��kX�iU�r#y�
:��*f$�}Wm�U=�D$o�am�Uq����4�&C�U}��d���-�������TL����q���mTlh���7+�w�j[�:�V������V�U7��Q�������l������^U��*��Z��H�F��^���$#~Wm�UW���W������F�6*6[u����]��V���J�^��b��������l�0aH2�w�6[5K�^��f�������Pm��X�����j�F��@����!�������m��\�����n+!G��T��7�H�F��r+!��7���J���q�����7��Q������l���n�2rqf\�n�p����V�,�VA.f�o6u�U���bj��T�\\�\�,�VE.f�o6u�U��+�b���T�[o$o�bK��#��7������w��T����H�F��v�@.f�o6u�u ���BR1������-���\���l�v�D.>S�>�b\|#y[������q����'���p1U�#*�'�b�����n�S�������>K�^��vkw3^�6;C��;�bI��X�n��X��*��[�wx�:\lh�v\,�;m��{�b���X�n������bC����$\���>K�^��vk���%��boh���cH��A�n�p���TL����b�����n���!	m�������W����W�b�����n���!	m��o+&\L���7�b�����n�[��������p���U�m���\�\�
�������m���\S�>���\�\�
����#���n�"rq$\L���rqls���[	�81.V�[	�8.�
}L��������ne����X�ne��L��*�!g����bK�U��3���n�
rqa\�n�
rq�p�������p1]Y6���\\����\\�\<[���\\	Gu��#W��T��xG.��\<[���x'\����\�.�
}H�r������n�����n����p1U�C*>���6��v�D.>	Gu�u"����BQ���p$o�bC�uL0�� q\��[�����X�n�G�6*6�[����Y�����:�G$o�bm�u�6�����n~����G.j����}D��*��[������������+-����qv��?���W��o����U�J�?~��/��������|��������~x��_?����������o�&?o�������}�����d��G\���[��`T������������>�7�?����~����7�K�q�O|�1b�]��}G�����}�g8��o�g���N?{	0n�7:���p��e���)��FO��{��������`/�������.i��#�cS$o��p������)�S�O�^B���M;F��K������������zo���2�3�)�K\qs��`��ki�����e�7��;���/N3�)�K��o����"���W[�&�K����	�{o�����Y�?{�}���VxW$�{����
��%o��H���^<�d�S��^����/�$s�_u��#"��WD����_�������9���xg�.���s��h�kCNn.�D>kZ;N$��O���t"�M~m����"��54�7��sB>?#>' `��x�bW�9����������%o'���: ���l��NW0#9�=i;��K���q�~���d��f��\����+�-�N,y���Y�yo��������&��\�,�{k[�s
���xO�E���e���������\�,�{kk�s���O���:�/^�
=��������=��K���S�+`���l(���aFr {�Y�,y;��8hzo�p����0Y�vbF���"�3��`uSy���������\p@���E����`�W�gD�M~m���G��H8�����	k�K:rplr�k�Ln.8!'��N�d%��D^k�k83rpjr�k�Ln.8#g��N�de��L8X]U���������\pA.�����*����V�P��K�8�������p�S7Y9��9X_UV������f��\��\	�#mC
����>���rG��li�v���p0=�4��9x�s���<���6[��9� L��)�D>�<���9�lr�k�Kn.�D>���9��s��l��4�
�lr�k�Kn-�-�/g�=B�
V6Yoi~yy���l���f�xxy�;v2:�udzfbH�n��Nb��`e��'����
�q�0,�o���m����M�[�{���Q��&�-��o �{�a����6�q��&�-^��g���s�g���[�����Q�>��/3�N��`e��/@�Kj�3���-x)p���{�a���Q�~\���z��B�kf�3���-xMp�V��{�e�fD��q��&+O���'�<�H����oC�*����H3��\������������g���[pX���R���z���7�c
F}~f���G�������d�eD����M�[�����gV��[pB�M^,MVBN���MVBN}~f���#�&/�&+#'�������3rp�s�3���-8#�&/�&� g�������rp�s�3���-� �&/�&�"�������+rp�s�3���-�"�&/�&�"W�������w�����g��[���79x�4Y;r�N8��qR����9�����| M^,M��|�o\��|�9�����|"m�4Y'r�I8��qR��|�6YnB>�lh��,�{k�,7K�N��&�M'^�&��&��32�6Y�K�v�g���[�����
M��32�6Y�K�N��&�y�`�{-��d�y����m��f�`��)X�d�8X�^64Yn>0#��E�d�e�������{^��%��`C����	/�&������S���r+p���lh���1#��E�d�8X�v
�6Yn���59x54Yn�����M����%o�`m����������d���s�C
������,H��`����`C��"rp L�-)8"G���&+"�6[���	�s�C
N���p���J������������q�����������F�������Y������������b�{.��������*���p0=�8���\���*rpmr�fi�*rp%L�-�)9��98�?d������������w�������w�����A�!�@���Y��9� L�-)�@>�����������:���������O�����Q�!�D>���,?-x	�s�#
��A$o�`���V�<�^64Y�y����j�,��"y;k�.�����Z����~��d^/=�8�`w��)X�u���5�����������d^/=�8���c��Q�A�W4��y��lh��\1#��K�-)x�*y;�����5����
M�_2f$�z���1�I�����E���G�k��&���.dd{k���!�`R%o�`�V�<�^64Y~� #�[C�-)x�*y;k�������Z����a��do
=�8�������������`h�|Df{k���!G����`��
>"�&K������u����S���_6����li�r0�[C�-)8#�>��l�98�9��de�`����[RpA�}V��rpirp�4Y9�������\�����"�&GK�U����O�-)�"�>��l���k����������O�-)xG�����aG��-M��L��xznqH�r�A����9�hrp�4Y'r0�[����!���'y�n�N�������d�r0�[�����p����m��	8X�^64Y�t`F��U�d��c����M����%��`C�5��	��5C
�����S����=p���lh�f�1#�`��fL�����/i��y����9��d�3p����m��8X�v
�6Y����598��y�����M��K�N��O��r��krp24Y��`F���&k^��%o�`���8X�^64Y��1#�`��fH�p�������K�k��&kf$L��)8 �>;v��4�C������p  L_�i8"�>�I�1+"	�&	'K���#!a��fH�	I8�I�M�o��(��(�,eVBN��+�1
#
�>
�I������S����������0}g3���,��,�&�w�sA�m��Ya��/m�4\�K�����p.H��M��>�"
B������+�p�����}GE�M~{�7�xG�������<��y�M��
w��	�o���H�;#bu�u ������D|4���9��bD�� 1}w3����`H���ND����o�����'ab��fD������0���Zn�����G��e��.���a��?�M���������~����-�����������}���y����z�����O��������w����?�������	����(�D����N.�:���W������a��_���yI��~��M��+A$o�g�P�-3,\�b��%x�G��t��$n�am���N��h�P�-��!�Q�������J���6}.����
U��:������6��������M��[A$o�aC���'���DuOH�{�l�?�������q-��m4l���m������	Gpo��B�v�y��0��������[������{� �$n�a��0.����
E����E�O��G%q{
k��7�H�F���oI0�!�A�'_�m8!���~��e���A$o�aC��d�a� �?q����3�p&<��]���A$o�a��kKA&B������p!<��U���A$o�aK�U�����(3���<\	�����H�F��N�"�!�QfH�;�p%<<�{i\"y
[:�y�,	��2C>��w������� ������:�����(3��y� <<�{i\"y
[:�y��	��2cF>	��Nk����6{C��N����}
������	xX���vZ�����y�:��K�N��Nku�������Z�������i�~��}��2C�����0]�=�a<,y
:�uv����QfH�3����5�����%o�aC���'���0}����`�������K�F��Nk]v��a�(3��xX������
<,y
:�u-����QfH�����5����
xX�66tZ��0d�����1
K��}X�K���������Z�p <�����</�^z�������Nk��������Z#�p$<L7�iy8�yx�tZ	y8�y���pBN���N�������������������3�pf<���a����������������C2���<�	���C.��������*������C2���<\/���*�pm��l��*�p��0��C���+�a}/�#�m�-���<��y�^�1
#�������<��yx�tZ����az	�4| ������<| ���?|���������D$>�HL����OD�� ����OD�����=L���6�x	kK�m�����\��pk�����������#���,�Jksp���~�_<l�4D�^�}�A��~�����0����<�=$n��_;l�3D�^�}�1��~O����j��m����C}%����{�����{��w���J/��~��������pc������k�{�]
F�J�pL��R%n�_m�����{�����������,
�pH�+�T�����
��H�K������
�ndg��C��@�J�^��k�u!��1�������!�
)8 �����p[��m|S����LV��+8���	�����H�����"0�B����"pb��8pW��m�i�,�,�WpH�8���
����-%VF&�B�RpA��7���n
����--VA
&�B�S0Rp!��[,\"y�[j��L���+8���\	o���H�k��kG&�B�R�����=.	����-E��L6��+8��9� ���,\"y�[��9��	�WpH�'r�I8xS7Y� D�^Or��0!�-!�
�(8L���W���
p���lh��tb�>�+8�`7c����MVp����Z���
n�����MV����W���
8X�^64Y��H8X�d,q;m��/^��_��qo�3p��n_Bz�<K�^��&+,/^��_�qo�p����m��,q{k���Nx������{^��%t�`m�V�`��+X�d�������u�[�6c�>�+8��
8X��
�6Ya����
MV3�9�^�!��@88h����C��
MV������
)8"��A�d�������{�������
)8!G��A�d%������t�[pBN}�WpL����q���������/�������	���������������{.���p���*���ppT7Y9�49��	�\��k���RpE������������`K��#�>�+8��9x'�M���79����| �}�WpH�r�A88���9�hr�li�������
)�D>Gu�u"�m�4Y'r���`zG'�����������F�^64Yq���?��^�!;��H�^��&+���{��ah�����?��^�1�
D��
�6Y��H�k��&+z���
z���"q{k����k$��`C�g��z�<�H����St��5��Z�������{�����T���<EG�\#y����z������MV\A�J���)�H�k��&+nf���M�&+n R%�g��{k$��`C��3���&m����Gh<E���{-��d��L��$m�#rp`���[k$��`C�#r0�]��MVD�����G\Z#y�[���LV�$u�����`�8�`�Y#y/��&+#��5I�de��L8�>�)9879x�4Y9�,�I�&� ���pH���F�^�4Y9���I�&�"W���pH���F�^�4Y;r0Y[��M������C
�}5��Z��������oL���N@�>i��H�k��*�@f[k&u�u"	���S���qY���6l��N$a��fR�Y'��IP�>�h8M��g�WC��&@a	�kX�f�	XX����Y�9�zm6�Y�K�^��:+9�a��kX[g%w��k����J~��d���������x�>i�
K�K����J���d���-��8,y{
k�4K�k��B+-f$[\'m���a��kX�h�xX�^64Zi90#�am��������C^��%��aC����k;��K�^��N+m��������J[�������J����5���R���5yx3tZ) ��N�i��<�<������#�ph��f��RD������Jy8�y���1
#�&o�N+!G��N�i%���xX�i%����aK�����a���2�pf<���2�pn����*�����SwZy���C.�������i��Bx��;��<\��!
W�����`��*�p%<�����<\	��!
���{��������w���NkG�	��!
��{�����:�����N�@>��!
���G�����:��O��^�i���'�a� 8�a�������i�i�KHx�k;�<�MD���vZ�H�k��N+�3��E^�ie7��kX�ie�d#y�
:��=f$������n"���������F�^6tZy�0#����V�A�J�^��N+�.�{m��i����d���vZy��p����C�e6���p4tZy�������N+� U%o�am��q����6l����1#�����V^A�J�^��N+�:�{m��i�
fmf���k;���T������V�}6�������x8��6^�i��<��1
#�&GC��#�0[k3k;���#�a� 8�a�h#y�
[:��<�����N+!'���ApH���F�^�tZy�-����VF��������q����6l��2�0�l3�;��<��;-\j#y�
[:��<�V���N�"���N��H�k��N�"��6��������0}�0�������������r�Y�i���;�a� 8�a�k#y�
[:�y�m������<|��cF>�<�,���<�����N�D>	��!
�f�{m��i�	y������V���%o�am�U&�a�{m��i7aF�����*xX���vZ�K�k��N��3^��V�&<L�4���%��aC�U|����m�Uf�a��kX�i�xX�^6tZe���������<,y{
k;���x��<l���<,�{
k;��K�^��N���^��
�VY��%t�am�UV�a��i�>�i��������C���C ^��V��%o�bm�U6b�����j��1$!�E�j��D�G�!$��$b7j��Cbm�U""q$HL��T�c��d��"2qdL���2q$LL�T���S���d)�Bq"P�����P����!g����b7Y���T�	��f+#gB��ipH��87��M�j� �����*���`1}RqE,.M,v�������p����*rqe\���*rq�p������+��U]n���;�bu��#�.��[r�N�xU�[r�A��>
��@.>�\�,���\|.^����\|.�O�C*>���6;K�u"���Wm�U'����������+n�����
�V�vIv���v�:��H�^��v��������nUW0$Y~�j����>"y{k���{o$o�bC�U}��d��m�������U�m�*.�����
�V�ag%�o��m��~U��*��[7�H�F��v�.0����7n��[u�*y{k����o$o�bC�U�C�������+�U���X�nU�}#y���9I6�n�v�n�W%o�bm�Uq���mTlh��vbH�v��[5,Xq��O�C*��7��Z�7�[5 �8oQ�+����p1}R1������
�V���d	����VB.����:�������n%�b��'+�\1rq"\�_1.�����-�VF.&kp��n�2rq&\��n�����-�VA.&{p\P�[��.��>�b����boi�*r1Y���������p��w�*������-���\L6��p���~������������_���o������?������������}����P����}��o��o�������}�����a��G\���;��'|2�/�����W����'��������<;����3o��v7c��j�u����I�~._��<;I�F���o�C�On;�?�b�N���	������I�6
6�}�?1d����O�C
�g,���	������$����P����!���]�V}��M���������S��ml(���`���m�E��������Z�[�����w	��
5���aJI�+X[��+�K���xO<d�[�������G���o��+���W����7x� y���x�zo�a�k��*�=�%u�������,y;�����Fm�

��A��m���(�7�x�zo�I8�Ix6|{B�������=!	'���',��
'D��(��/������J��^E��Dh8���4��Z��3�pn��k������3�����
�pf�v��-H��I��=I��oA.�����*���}�P���0\�0������VD�JP8����(\�7
�m��,\�,��c����H�;!����v$����Q�Y���D������@>���A����3[o�A�h��ko����D>���1�$o����'b�����^���1y������:&�}H��Y5�~�	����ko����M�*�%m�u8�}H��qS�~�=$nct�e�f���vI�b~���%�Yxo�n���-��}����.i�c�*y;k�L:f���qb���9c��yl���1�A���x�,���e�����N
^���W���:P���S����cux���>��a�+|}PB�
��X�
U�v
�~�t�'^<T�{jX��`��7�]��X�U�v
�~�tl�P%��`C�u���O��[��������{�����/2����k{�#"�>?�'���#rpls�������|7��SpB�}~fM��'����`K�����f��n�2rp�s�3�����������{����|/yR7Y98V7Y9879��&�\���V��n�
rp!�n�*rpir���K�-�"W2�kR7Y9��9���7�\�����{���+��5���9x�s�3�-xG������{>��w2�kR7Yr����g��[��|49���%�|"dJ��n�N������,���9�lr��cKn.9�d�m��	9��s�3�o-����%��`C�uN32�6Y������M����%��`C�u��	�o��)8X�v
�6Y�����9��d�8XB�
�6Y������M�9;�xM~qB������W���:g�`��k~���t�'^�&�8�����3�_��� ,y�o�!
/@�������:W�		���
ix����W���W@a�{m�Pf���	
�/�
ix����W���7`a�{m��f���	���
i8��09�����m8 �&�8�����p 0L��7���0���g�|o�i86i��)�6��#�au���c���Yx/,%�������g%���hX�g%�����gV�[pFNm��Yi8��>+#
�>
?�����s�-}VA�����*���t�����pi��b��*�p!,��}VE�}����\�k�K��#
W��^]g���{����!�H�{��K��#	���� �!H�{�����!�G�K�u ��$�!��G����!���g��K�u"����(�1#�}�+�\�	o g��;�����5�{+���4���<�v
V>[Y&X\��{-��d�e���m���0��*���4���!���G�k�v&�-���Oga)�g(��Gi��Nc
>���
D
�3Ye�������,�!�
���4��/�mxK������J�v*�L����y������A�K�&�����aq�#�����e���*������4�!
�4���i�/`i6�<�^��Yo�������8�!
o�O�����0��y��6lg��"U������<�!
�	��35�W0�4�ky�
����H�d���1�4�0�0���1���4�4������H�d���1�4��#�+���X�m8!�&��B+!�6|	����p"�%��"��
#�&��F+#��5|���3�p&�%��&��
g������Ri�a�����C.���l�X���
�pi�������d���S1�4\��k�����!��"�6[*��8LV�x:cH�;�p����~���#
�M�,���4Lv�x:cH������U����0|4ax�Z�0]b�.���������Y�h��f��Nda���N�R��,|�Yx�~q�&D�������r��������(,y?�/���9��5Ix3�Y�-���0�	C
v@������[a�{-�Pf9�1#a����%���%��0���Z���r��k�,7K��P��oa��%��`C���32�VYn�Xp��i�!/���Z���rK�����JR�
,y?��V�`�{-��d�5cF��T%�)8X�~&��m3^�&C��6�`	�+X�d�
8X�~&��������d��S�0��������M�����p0U	C
����p�:&E�����`i�rp$LU���rp"��M��0�������de��D8�~F����s��Wu��������de��L8�~F�\��3y���9�498X���\����\���spE�M�&�"W���&�"�>o��#�6[��9x'L?#C
����>o�| �m�4Yr�A8�~F�| }��9�@>�-M��|���!���g��7��'r����hh��4�$L?##
��A$��1��-�@$��`C�����dt/��)��D�~3����
D�^64Y����?�����������jj��{K7�{-��dy�c���^O?#C
���J��wW�q��~w���G�k��*��3�E6�C2��T���|��]��6����
U�_f${l�%S0�T��)X�Uz�`��{-�Pe�5@F���^�!��R%o��g�����G�k��*���	2�-6�)x�*y;k�J�kq��,f�H���K8��� � �>�����d��|Df;l�%RpD�}V�j�#�pl�p�TYA�����)8!�>��'���d���0Ya��%RpFN}��2#�&'K�����
O/���rp�spPw�9�498Y���LV�xz	��\��]eE.MN�&�"�6�^�!W��J8X�d��������d���d����pH�;r�N8X�d���{�����:���
O/��������Q�d��G��-M��LV�xz	�|"�}��&�D>�li�N�`����K8��yB>��M�<K�K�n2TY��cH��i�K�N��*kv�������]�����5�������]����%n�aC�5��!	
�k8�a@a��iX[f�����Da7��y�����m�<K�N��6k^&�xMv�����aI�kX[g�����4���������a7��y�1$�az
�4�
K�N��>k^��%n�aC�5oC2�Z�8,y;
k�y����
������������
�y8i��g�x����Jk����0��C������I[i�y8vx��i�y8��pH�	y8�y8�;��<��<�F8�e��.��.!�p������������~����-�����������}���y
����z�������������w����?������������(�D���������O������Z����������?�����O��� \�6\8K�W.J.�~����g�![�>[$u�W�-j�-�����-j�-�z���wD���I]���{-����-�>Z<�K���$������;�,�6Y8K�w Y}�pO��{>,���D�8�`�,��`q���=�n-x��r���{n����
��2���� ����������"q���������O��{vp����/���i��H�F��zo�0�p!KA��]�m��D����{�����
��2����l�O�v�������5���\"y�
{�#k�2c��8T��i�{^�����5�m��"y
��eu�?�k��e�������Zp%��m4l���������^[g-��
�G�I�g-�D�66�Y��c��DT����4,q{
k���H�F��Bk	��d5��ZK@}v���Zp+��m4lh���<Lv�xu���#�au��kA$o�aK�����r�Y]i%���xX�i�^��h��ie�a�dVwZy8v�N�H�F��N� �� ���*�����SwZ�D�6�tZy�����VE�������� ����l��*�0Y2�;�y�v�Nw�H�F��NkG&Bfu�u �������� ������:�����Y�i���azDpH��D�6�tZ'�0�2�;�y�$<L��hx����6��Nk���%u�am��N�������Z��������Z����4���V<,q{
k;��x��<<:���������Z=����5���V<,y?���/������J�o�����}$^���:K�N������g@b�{���0}s�'F���-��e�~	���C�]�%�������w�1b�m����������ZW�a�{����{�]F����-��`X����Z����k��k�����
K�N��:k��%n�_m�������=D��o@}^�e��azBpH�A84A�������c�m��F��H0���/bplb�k/���7!G��"+!'��t��~Bpj�~�����f��D�W]ce����W]ce���~%����F�}^�-VA���-VA.�7��� �>���"B��d���+p��6,�"�>��
�"W���`���wD��ylX����xUwX;2�N��R����_[J�!��C��.����@0=8��!�h�
��X'R����U�b�H�'�`z*pL�H�g�e�����/a�Wm��Mp�����5���A$��`C��9��s�Vm��9��H�^��k�� ��Z�������s�Vm��y��H�^��"k�� ��Z��������AVm���3Lk��C
�� ��z���dms���� ������W����p/���lh��%c��r�M�dm�T��)��R0�����
M���|�����M���H�����M��[A$��`C��m0_s#�A6m��m R%n�`m���R�{-��d���1c~��m������C
�� ��Z����"r0Y�i��-"G���8���q%���li�r0����������C
�� ��Z���J���5?�n�2rp"L)8#�6[����	�����	��C
.������&� ���&� ���&7�H��wV,MVE&{l�������q����
6��Z���������n�v���p0=8�`�����/�����9���	�&�@>�3�C
�
6��Z���:�����n�N���p0=8�`�`#y���0!�=6A�d�	8X��
�6Ya����
MV������m����`�hQ�d,y����*f�sp�6Y�K�^��&+x�`�{-��d�1c�����
8X��
�6Ya����9��d�8XBw
�6Ya�����MVX^�6���K�N��&+,���W���
��������
����MVX��%n�`m�V�`�{-��d��c�>Gm�6�`��)��	R�,y���&�����m�B@�����!�������d����MV����p0=8�����X�����MVB������!'�������d%������n�rp"L�)8#�&/�&+#�>Gu����3�`z&pH�9879x�4Y9��98����\�3�c
F.m�4Y9�V7Y9��g�\��k��-M��\	���9xg�n�v��������:���>'u�u ���M��|49x�4Yr�����n�N���p0=8��9�lr�ji�N�����I�d�	o '�`z&pD��H�k��&+N3�%m��@$n�`m�q_���lh�����?�(i����"q{k����j$��`C�=���diM�6Y��
D��
�6YW�H�k��&+�0O3��5I�d�D����m�"������
MV\�����MV\@�J�^��&+���{-��d��c�����m��
"U��
�6Y��H�k��&+nf��M�&+n R%n�`m�q]����������e��4<6������!
���{m�Pe�� ���L�.+F$�@H��
�0������
]V�H�lq��.�"�p$(L�i��H�k��2+!
��5���J����0=8�a\[#y�
[���,���L�:+#g��`����s�7K�U����I�g��Bh���0.�����-}VEf�k&u�U�+�az4pH���F�^�Z;�0�_3��yx'<L�iW�H�k��FkGfl&u�u ������!
���{m�Ri��l�����N���������5���p�tZ'�0[a�����<|2�vZiB>�<�V���%t�am��&�a���G�i�9�zM�N+9�a	�kX�i%<,y{
k;��N�zM�N+�3v�N+y�a��kX�i%<,y�
:�4{�Hx�i;�4K�^��N+���������J��	;m���a��kX�i�xX�^6tZi90#�a������a�������W�a�{m��i��bF��N�i�
xX���vZi����
�V�2fd<����<,y{
k;�f�zm6tZ) ���N+���xX�i��<�<
�V�������vZ)"G���N+"�&GK����#�a����p�����4���S�����������WwZy8�y����C��������i��Lx��;��<\�<��A�!
�����h��
�p!<���VE.}������+�pm�p�tZy���NkG�}������w�������i���;�a���v���������<�7y8Z:�y� <�����<|�y��W_C>���6[:�y�d<���N���������0����aC���/!�am��'��H�^����3.���������n��d�����������5���!�F�{m��ie�0#�c4k;���&"y{
k�y���F�^6tZ��������V�l�?j�S�6�a�i#y�
:�<���L����V^@�J�^������H�k��N+/3�������+HU��kX�Y:�V�{m��i�5aF2�w�vZy�*y{
�?K�Z�{m��i�
fnf��f�vZy�*y{
�?K�^�{m��i�<��v�Y�i��<S�6�a����aC��#�0[o3k;���#�a���4��m$��aK�����~�Y�i%��Dx�*�!
�j�{i�M�R+!�
7������1unC*��6��Q����H�l���n�
q&DL����qi��,�VA$.�u�U�Abj��T�n$o�bK�U�����E�kUd�J��j�!������Rl��l���.�v���@1�nC*�%7��Q���:�����E�lH��b*��T�T|4��M�j�D,f�nu�u"���yR1.�����
�V������E�m�	�X��*�v[e.����
�V�N��X[n�`�����Vq����Q���*n������V�����W���*�X�^+v�v���!	��v������S1�oC*���%o�bC�U��!	��v������W���*�����bgh��\,�{k���K�^��v��^�6;C�UV�bI��X�n��X��*��[e=����������p��m��\,y{k���K�F��v��!	��v���@����!����bgh�J@.��Wm�U"rq \L�nH��8���Y���\	��v+!G�����T���S��-�VB.N����VF.N��)�
�8#�[���\�����\�	S�RqA.�m.��v� �����*���p1e�!W����boi�*rq%\�����\\	S�S1rqms���[;rq%\�����x'\L�nH�;r���boi����p��n����p��f�r m.��v�@.>o�v�D.>��/'r���boi�N���p��m������p��v��;p$o�bC�U�C��������#��W��u�%8��Q�����`H2�w��[��}D��*�~���G�6*6�[��`��v�l�v�z��H�^��O���H�F��v��0���e8����3�U���<QW��#y���v�.0���m8A�n�����\��+.�����
�V]gI��m�UW�����y��M8��Q�������dN��[u�*y;G���W�H�F��v�n'�$q(��Tq��o�<^����s��������_��[����_������������Q�~����}��o���;�����������<��G\���[���d.��O_}u|������`��_������N���=���g�L����QL�k���S��6��Y�G���>:|t��d/���A�(�
i���S��5zfP��
W|r������^�
��!�����!
���T�/��yo�;>8�����/������J^���s��P;�icJ�g������Y���|����3�%�a��9���~�]��/��;�g&E�����|��S�����~O8N)�{�����&���������_|�p������� }k���`���iG|D���$oO)��O�&A�^�}�1��~������.j+��-K������
K�K��=D����0"����v ,y;�>�u�{������k��o���������}���>?3��~g�`�{���w���;W�H 8j��}���~�E��K�K���(���%cD��Q[c����������u�����G��[�
,�{k[�}�����-��9�xM~q���o@��W����7 `��)X�`����I�/�7����`F���
k���������������p�{����1����#2p�3�3!�-8"���`K���#���.�Bp�C�3� �-8!���`K�������n�2Rp�S�3c��-8#���`K���3�����
bp&��)bpib��CM�-� ��I�c��B8X�SV����`K�U��+���.�*rp�s����9��9��d���;���n�v����������`�����/�3���9x'��M��|�9��)��| M~q���������n�N�����S�G���O��	�/�2���c�x	k��c�[���5����c�[���6l��7a����]�vY��{���5�=��pp����
e���H�����i�{l���A���������6lh�_1#�v��m��l���5�=�����J�k��:��3f$_N��u�1�N������?��Wu����a��������}���O����� ����>�q������H�^��B�XA�J�^���t�'^=��3��
ofD��q��F����J�^�����Q���/�*�#x�HvM�J�����0�=���<�<���{������������#�a:"zH�y86y��	&77�<�;��<	�	�CN�����/0����<��;��<��<����[_<q87q��i���3�a���2�p��0]=���4��4����{.H����S7Zi��i��K�\�K�_��qo�a�v�B�"�>?�^�����k��gK��#W��N�g���{���y�to�;���FaK�u 
�����:��>
?�V���$��M��6�D>	;u�u"	�}~������g�K�u"�����:'�����S���s����
]�9U�H8�i���K�N��_%=p���l��N�1#�`m�u:�`��)X�������59x14Y������M����%o�`m�u�/^��C�u����S��6Y�,y;k��s>��59x14Y��`F��tt����`��)X�d�p���lh���cF��tr���W�`��)X�d�+p���lh��m�������!o����S���:7�`�{-��d���	���C
�s�3o��-8 �6��3 ��tj���#rp�s�3/��-8"�&��&�����p0�;�`����`�zH�	9869x�4Y	98�s{����S���:�!g�������de���8X�de����`�zL���������*���q���*�����t���rpir�ji�*rp!LG�)�"�>�E�C
������������+�`:�wH�;r���`�zH�;r������d���;�`:�wH�r�N8X�d��G��WK�u �����!����`u�u"�m�4Y'r�I8��S0r�I�&�����:���{m�Ne�e��p�G�^��*�-�/o!���i"���N����R�f���2������C
v
v�����q�G��<�^�sYoW��V����C��d����zs���[���<����r��]�<G(x������{?�������������0#[��,���m�����i��+ly�
����H'fd{\�mV������A�6;ly�
����H;f$�\���!
o^��5=]H?�aXb��{m��g�E*���r�^�4&hx����t!���a��#��a;��	i�������zK�4�4��B�!
G����a;���q�������zK�8	�m�CN������F+!�e6����pBN}�t�����S��������d����0�4���3�a��~H�y87y8X*��<L���I�C.����0�I?���<\�<,�VA&�l���!
W��Bx�n��pE�M�N�"��6|����w��Jx������<�7y8X:�y�l�����4| ����f�!
��G�����:���J>i}L����a��|H�'�����`��N�a���N����<|���G4�&�������i�	xXB��vZn����	7x��8l����1#�a:����_~+��D<�a�+����������~����-����������w������w���|��P������������������G��'~��)l��&�D�(�O_}u|��������������Vx�����Sa���B�����D���[��J��$���{>�����O���t����'m�6x����x��P�����s���l(]p���y���.�sU�������.������?�����}+���V���t�X~~�����������i�_���������w������0}Q��������������o��{��/�������?���x/q��B�	+��J��	+�'�����V$����0?���
Gx� y�
��J��f$/���!
'x� y{
?������p����Ue%f<1#y�@��i8/�0�mM��1��/$��aUY�w�H^8��'C.��A��~Be��p������������p����4\�YnM��1��
/$��aUY��+y�@�4�a��J��F��1�����k�p���3"��������w������obi����5_8DU�������>���d|���cF>�<�T�d<����t����O����0�&���O�����I���2��P�������
�	n"����o
om����G�k��N�;��]��O�4��&"y{
k;-�y�
:-�N���ch;-�gl�?�M�Zz����{m��iy�c���H����A�J��gX�iyX���{m��i��`���H����A�J�^��N����G�k��N�/	2��	>h;-��T��������e	����
��_d$�w��4��T�����%�y�
:-��Y#OV&���ix�*y{�am��a]�#��aC���������n����p <��v�{�����n2�Z>"��	���C*����3�I��8"�&���jE$b�7��~H�	�8"~fC��'$��$b7Yj��HL6'����8#'����(����H��H�&K���������1#g���^� �&��Rl�b�=��~H���(~fO��W����b7Y���TL�'�o���"WF������6��M�jkG,&�W��T�#����Uzs���{��d���b�C��~H�r�A�X�D�?���[����lQ�Q]n���'�bu�u"�.��['r1��@�(��x���O���l,���y.���������C.���T���%o�bm�5;�b�����n��`H���.�5�%�V���x�����9���p?���h�O�����~�{s>�����vd�"���|4��o���p��������C#8��$�"���O�f����������������\�AR�*�6�> ,���+�~��Lpy�<<*64�> H�N�I�.���\>�X�.�4����Q��\�AR�*�6��_�b�
�g6��[�����mT<�.�O�p�?u
w����S��~|���,���3�������<9�)F��?�.����W~~�s�~�`xC~�p��7���k��e��;J�����"]Vp���'�>�S�?�E��@AJ�����6��k~���nk��
RR�>%�
o` %n/�� ]�/^����
�%����G��Y����|������|�|�
���/B�/��S��pD��/��@�4/b/��]"�E���{���pB���.��@�4��I6�����%!]$2�	^����r$n�am��d��#y
[��\0$��!����r$n�au�W`���m4l��J��d�G�nny���?��X����<\�<�-5_E�l!�v�y�V�������������#�l�v�;��Nx���77�<��y�[:�yxgq�>������X���y������:��6H��y�d<���N������N�D>��6m��N��'�a�^�<,y�
��Nk�vIxX�i�xX����z�xX�66tZ�+�����Z=����5���V<,y
:��'����������%n�am���/^��gC�����������Zg�a��kX�i���������Z�aI�iX�i�����5������������i���!�<L�,:��xX���>�����������Z7�!�<L�d
ix��=ZR����%���~���|��R�������}$��(��,� 1�"���"qh"�k����C���!�F�@�X}���c�_{�����8�8L��=���8	/���	q85q���{�M������J�������5#�&��}o�Q8V�YQ8N�YQ87Q����{�-�������~�p! ����A��W��[�K��;�!�V��J08��+bpm�I5�wG�}��9��!x'����;B��|)��+���E����KdH���N�7�k���h�~�����G�)�)�D>'��Y��|��[�	��0E�o�?NB�I�`m�@$o���]��T0c�]�2�`��H�^����6���k��5tX�����S�����@$n�+6���7����'�J����[	�)X[bmn �W����m������Z�m����S����fp��W�����/^{������3����e+C
^@�J�^��k[��J�k��k[f�����V���E�����=���F����
E�����?��.ZR�6c�db��-��
<���lh��m���q�t����p����m��������{���������rp�s���M���C��_�qo�98�9��XRpD����MVB�M~qZ��'�����U�d%���8X�de������u�[pF�}��U����3�`�n�2rpnr���:�-� g���&� ��N�d�����Gu�[pE.���MVE������������/N���`����`�XeH�;rp%��M���79��A��#�}�kU�| ������:���6[��9��s��n����p0~<�`\
"y�[��9����A�|"�������	9�lr��S:n-8L���S���
p����m�����59��!����%t�`m�p����m��;��59����g���`�dH�8X��
�6Y�K�k��&+�3�9�n�R�,q;���C
���%��`C��3�6Ya��`��t�����`�{-��d�e�����MVX��%n�`m�V�`�{-��d��`�>m�V�`��+X�d�m�������d�
8XBw
�6Ya�����MV/^��
MV�����t���rp LG)8"�6����c�����!G��H8��e�w���X����L�_)8!'��t����rpjr�bi�2rp�s0�~1�����������X������MVA����MVA.M^,MVA.}��/�\���`:�xH�9�69x�4Y9�V7Y9������#�&/�&kG�	���9x'Lg)�@���X��9��spT7Yr�A8��:R��|49x�4Y'r���`��bH�'r�I8�N:S0r���`C��/a������	n �W������F�^64Y�y��TD�^)��
D��
�6Yw�H�K�����~���AEt����=�@$n�`m�qe���lh��?0cV/�y1��y���zE:�xH���F�^64Yq���?���������&Ir+I�+y�;S���}��,�]Bef�(��b1E�EJU.{��odOF���yp3�"�J6��VkB���QG�<@�*r5������5��lp�$+3j���F�$+��\�`���}5��lp�$+�0O3���vQ���T��l�dE���g�&Yq�y����D�$+N��\�`�$+bU��=�0��a@����d�d�����D���g�&Y1"���d�d��	���D,��g�[&Y	9�T����*'��D8��p%b[��=�2�J�����V^T1xFN�����*c]��=<�L�f�`RZC;/�� ������*c_��=�2�Z��Ik
-��c0r��8�<����{6�e��"���zQ��9xel�dac��=�2����Io
m��b���������e9xj�d�������^T1xG�	�i�U���{6�e�u ���zQ��9� L�W1+kD����IV���Yq
����p��E���u��:a�{v�a���5��V�{Q�a��������*; a�{v�a����I}+-��������aV������p�0+�5�W�|Q�a`a��9l�f������ph�f�XXDk[�Y�����qV�^�C�8+
�"Zs�:�J��������p��ei84���8�FR�J�/�8<�^�a�@+������p�@+M5�W�~Q��	xX�*���U���E�����V
jd<li��<���U��!���a���p`<l�i��<������?���_��o�>�����i�F�xA�p|���_��_���s�b�_���K��U7�j�����(��a�������O�����/?������������~��s��Q� �N���G�4|�	�8�S'm�(�QDyH�I;A��>����	�N������jD0N��	��go oF0N��	z����3L��g�M�7��\<�S'm��b��\<�c'�
^`���=l���F��E�:�hSG��}��+R��u���N����jD*^���6uT1xE*^����H�7����:Ms7��P��S'm��b��P��c'�]�*�.^v�D4��P#2��O�p�����;2�����wE����e�ND��
4���>u����*���>~���b��|d98��n�5���������'��}�]���c3�zln���`��F�����*c���}�]�*c��|����[K�w�HBU��Q�`�����+R�`���O=67~kh�_Q#9cD�:��=6��W	��=6�����o

�g�H����:C�*z_q�����c3�zln����N��2��['Y3����W\%�b0������54x�F�������I��=6��W	�|��e���I�<
���/�MU�����U�"��Tds�����"Z�Q�a,����JP�al��OM67�k�pD>��<u�:����F����0V���*���tQ��g��a�0�lD���c��|�����o�pB>�<u�<��.����@U�2��Tfs������F�'KH�:�8�0<�0��Uq�l�S��
�:� 
�*m�:l�ga���}�u�*c��|���qzC�W��S��S��-�����T�a��S��
�:�!�Jm�:l�ha���}�u�*c��|*���������Tk��b�LmD�k�U�+m�S������H��b����Z�i#z���Km�S������#��m�Zlk-"�����[�t���7cq�\k�VI��6wT����wc�&��[��Q$�b�`kq���577�X�{\�,?��7���j�b�dk�@���5W7�X�;\�,?�%4��,�����*�����5W"�X|��e������a@���i�G��b���;sU,��Eo�����2zI��vxT�x.���5W���X�f,n�n-S�"	��*O����5W��X<�����a��L;�$\L{<�Xz��p��u@.y.v
��% ��������8.������1���a��D��H��vy���8.���X���c��]�t+!'�������	�8.�7`�X<#�<�����\<3.6O�f���q�y�9#�y.v-���xf\l�n-���b�sA.^�\�Z�[+r�B��vzT�xE.^��+r���b�2����W�������r�F�����b��\�)\�2����7�������;r�F�����b��\�+\�2����w�������r�N�����b��\|����L����p1m��c1r�A�����a���7�7cq�tk�`�z��yj�u��b���}���*c��z�������bS8�S�S�����oD�k��V��o�S������{����p�Zl�n�X~#z_s)����>G���4��P�>���v�*c���}7c��zj���������H}����U,�������U,����T�������C���_G�=�X��7��5'��X��7���������(R���h�G��G��f|A��g=�|�v���iE���_G>�X�
8��5��X�
8���������S�S����+pD�kT�+p�S����
-����p�d�n��8.��X��7�7cq�t+!��7��[	�8.�#�X�\��\��L�f�b���&�tkF.�	�U,������e�� �7��[r����|�oDo������\LZp�d�n���+�b��pDo������\Lzp�d�nm��������W����[�[b1)�q�<���7��t�A��G�>��O������w�<�]F$c����y��#�����*.c��=}��{�.k��\L�p\0O����q�u��u��G���{�.j���f�`�lk���E�kn��1����R�}o�e
vJ$L����������b�&�'��{�.k��(�q���6D,z_s�����X����U���}�	�Tk���E�kn�U1��'���%.l��	
�Lk<Lv��E�*����d�}{�e
V��`�:��F�a���kVU�E����v��<�(�q�u�������5���<��z���6��:<�he	�u��M���5w��8�^~��a��$�@H8ZgY[@����:#	��tC�#�p (���-"
G����M�#�pT��:���#a�h�f%d�DX�����pBN����q��0�G�8kF�	��7U�����p�<kF�	
G�<kA�
����%�9�2�Z����<�Z����y��8���L�L�V����p4O�V����0�yS��
yx��p�HkC��GZ��Fx�^�����<��y�e��#����3�yx'<L���qyx����#=�:| ����y�u �����*��G�����Q����q		'�Lk��!"z_s����;������
3��9�HF%�Lkw����tS�a,��g�fZ�;P#�l��3���0�I��Tq;pD�������7�H�&�Lk�!T���rS�a���g�fZ{��F2�7YgZ����}���*c��=;�0������_zg�������\���0�����
3�}�A�;k�I���>B�*z_s�����#z�7���	�p��'YgZ����}�e�:��z���
3�=�����M������az�����~#z��YfZ{D&8����pD����u�*c���=;�2������w��VB����}�*c���=;�2�J����w����<��7U���{v�e�5#����gZ��Lx�����06�����-3�y�����<�Z������M���F��n�i������w����<�26����F��n�im�����w����<�1�wyx��p�2����I����3�yxg<l�Zb���=;�2�:��I����3�y�`<l�0������-3�y�4���:�::����0�8W�����	
3���P#�ag�ixX����\����=;�0�:��	;�L������5��8���E�������j$<��3�����\���p�q��<<4���xXDk[gZG<,z_sq���C������a�u��"Zs�:�:�a���kUu�q��<<4����G����u�u�����5W#�8<����
3�cr��������	xX���ZU�'�a�{v�a�uLj$<��3�#�0�az����y8�y�a�u���x�:�:"�p <L/��������~���}����r�����y���������������q�/=����n������wc��}��>���?�������/����O��/�����~�G��0�B��?���hLH�QG�]��
�!'}��6���&F!jO����jD.N�0�/�Mm�����>��JEQgE!j���o��x�GQx_?xyR�����R�Y��Q������jD&^�A����P2�����BQ��������MC7��D��c(����<$�UC�_8eT�����e�P���jD��!����P������/R���.;�b4
�@��4��#(����<��]Aq���9(D��s�
UAnx.������4D�H�� ���sA��,|�������������i*�L��a��A��xZu^��y�$7���"���>hy� ��=�k�	�F��������	������+5FE���������Ah����h���A���_�rs������qsS{�w2
�@#���D+����*�B��M��o��
�%X�|��d���5� ���W�:nnz�m(.���n&��
5���������Pqs���[=hCq#�]��f2
�P��I�J����������JYQ�������i��#h$�6�n%U��mnz�m �mnj���m�q�������*��_�ns�b������n��]~�u��t�x��T����K�m�4��7"���m���UB�%�6�n%U�7!��f�+sE�M���^��e~5#��^O���;#��^�+�rE�����6S��jF�%�6�6�W�wA�%�6W����� ��;mB��jA�%�6���T�wE�%�6�u~�"��mB��jE�%�6�������4�\�,�������	-��
����x�CS��
����\),�����o�	-������x�CS������\�
,�/�o��&����_�e��M�_�e3Z�W�o��&4��\��K�l<�������E���q~�:�_Q{��a~�\�	���*�:�_���w�0����W���m�_9��F��t�������:�^�,����g�W������u~�z�_���k�_��W���m�_�~F����+���^�_���
=�]�c�������t�������U�5����p����Wn��������E���q~���.���a~��5��;4U���E���q~�&�_Q{��a~��G���M�o���JE`Q�o��ol�_������{��n�F�xA�o|���}��o�=���� �����?�����?���l��?>���|���_�������O�����������O��z�_R�-�!���4�������]/����E�~������0��{�;��H��j����W�*�x���?:\��4��0���2M��iU����yyW������eg)���_��7�����_��7�����_��7�g&~=4��Dk�Z'~=4���*�'~=������m����;��k����;���k����:S{�75L�zh���V��{ZU�����^�_����������
�:�o�5��:�oz���oj��6L�zh������N�zh���U�5N�z����=��0���o�&Z��:���o��W��8���m����o�������h�_�k=����*��X��k����o�������h�_������k�J�ZQ�o�i>5����������V#�/i��R�V�������O-�����z���V�/���R�V�����o�O-�����Z�'��jF�%-�W*���;#��;�S��jF�e�t�����/���R�V���7�0������*��M��I����������y��L�V$`�0O�h��"���+e\E
����,��e��!��y�IS��
��_��+k0"p�^�u-3�����]�*����_>ZgX;2p�]�u-C�!����m�*�d���6����ry��L��`�.O�ij<t�!c��q�5t�����X�����1���	2���W�����!j37����-�5��s���d ����%5���C�fnd
8�[Tk[Y��'�@&{'� k�\;|~�n�d
8�[Tk['YCA�@F{'�$k<���b�k�d
8�[T+���*��d�w2N�������fp�$k�	��Z3�:�FHR2�;'Y����a�z3�a�5��oQ�l�d
$�������a�U�fn�d
8�[Tk['YC�x�d�d
98�9�5L��-�5����!"����8�"rp�s�k�d
8�[Tk�'Y	9��N�IVBNyv-�,�-�5�����L&|;�zU��S�]�(}�j�a�(kF&3�]g�e-H��B�-�,�-�5����I�L�v�u��"
/

��p����6�VDa2��u�i��,��Y��L�p���V�{6U�����o�Y�Y����a�2�����Zs�<�����o�Y�Y;����a_#��/K8�/-!���H�2������/;O����:'�|�8�q8�����'&F�$���x��?O���^~(�y>5>�cp1�]|�'|#�s���G�a�7���Tt����������-F2?�u�	����"7cp��o�1�#��v/��
��#��:��o�zn��1�a�7����t������@#���:��o�~n��1�a�7� ���t�����#���q�7bA����0�q��Hj�/��6x��e�����En��������G���_&��O=�o�9g��X�-r37��F��<��n�r2P���l#����q�7bG��=�7L�F�<��n��A��#�1���{#�t����
��1"��n��A��G��H8�bz
���[�fnxVmL������|����	98��^�`����[&Y3r0)�����<#���)�W19x�sp�2�Z��I[�7O����q�u��E�"7cp�$kE&u��<�Z��W���I6u����-��9��u{�$kC^	SL�a0Vu��������|{s�.�C�UD&���<���7����kx�u�"��%��5���;�0������Ax' L9�����-rO���]��1�4v��A��|��^��	�?D����^�����o}.q"��u�5u������1���"�d�}/�e�u0�p"��u�59xt�\�^�k���{��������%�c_z�k����������"�d�}��e��=J�g�����C~*r5{��	k?D����6���;t(Q}�[�W������5��&l��'{��.l������ux5�=���$t�k���"73����������uv5M��\�_��5����������iF�����:��&HNE���qn5a������i�o@�%��up5D�@���y
��C�f6��}I��`�\M�7��h^�_d��e�;'���7!�����<�J���/e��b���=��2���~I��`�]�H�3�_
�5����{��ex� �����<�Z����k���"��o��jA�%��yz�"�.�)���+?D��������Kz?��jC�]�Z�W��!r�����6�_R�1��W�����:����{>��2���I��`�_���;�_��5����{��e~u �����<�:��������{d����$E�
�/��������\�_��*t��"��o��*8�u������E���q~���=��0�
�C�:����U���"W��8�
�W���m�_��F�G��*�=�K���y
{�_�{��a~�5��;Z�Wa������U�E�����Uf����h�_��W�j��Wa�q����0�
#���V������+r5���09\�<�6����+����0��\�_��*L�]����Q��0�F����U����/��������;p��7"�����U�����/���F�����;�o��7!�F�'��*!�&���k���S���Q�_�����d�_�����/������s����Q���w��w2������/���.��K���Q���w��w2������/������K����Q���w��w2��V����/���n��k����������;��W��F���y��<����v��M���<���w�����������e~u ��:�N�����{0������#��C��*vW���u~;xz�\�_����<=D�����Utj�GM��Ut�������U��{��a~����C�:������#��y
��F���m�_E��F}o���b�����5��"V�����
�����Q�����Cz*r5����
4"��o��*03��`�_��S���k�_E,��g�Wq��������*����\�_��*b���=��0��������:����"W��8��X?#r��6��b��Q�������_��*b���=��0����t���*F�����8��X>#rO��-����K*h�y~��#�_��5����{��e~��IM0��f��D���y
�zF���m�_�����&��W3��L���y
�yF���m�_-���&��W��B���y
�xF���m�_����~&��W+��J���y��,��-��
����D��jC���R<��/v�����-����4�D��jG��	�R<��/������-����T�D���@�=�R<��/������-����t�D��*u���_��*u��"��o��*u+j��7Z�W���\�_��*9�_�{�wj�_%7�F����Ur��"W���y
}�k����a~�<���V�����������U��]����U��Et~�u~�z�_���k�_��������0�J��u�M��U�E���q~��_�{��a~�F�u�M��U�E���q~�F�_�{��a~��5������4��\�_��*M��"��o��*M;j��7Y�W)x���/���������a~��o��7Y�W)"����k��c��W)"�F��y~�#�_��*!��<�����o��7��W	�71����f������2���g�������;��x^�_��9���e~� �������w!�K����������2�Z���W��x%L����+����2���W�]g�`mH�!`
�5����,��	�����:�kG�SB�a���g8���vD�]G`��gX2�N�"z
�d�#���e�u :��<�:����+<c��=�0��;�9���:��;x��^�`�k��{6�a�5;��9���:��<AD�f�q�5c��=�0��=���YMg�c�� �W3�8����F���
s���Q#���YYs1������k�%4"�lp� kj$�x;�$k G����I��-4"�lp�$k�Hf�:�$k4X��)��0khD����I�<n���u�I�<A�*z5����{hD����I�<-��L�u�I� I����I��E4"�lp�$k�����Y'Ys@:{��5�&�{6�a�5G�`�G����9"G��=��c��=�2�J������'Y	98��)�W198�9�e�5#�Fg�d���3�`�$�hD����I���*i�y�� /����,l��'�S�$kAf�4�<�Z�����k�u4"�lp�$kEf�4�<����W���k�}4"�lp�$kCf�4�<����7���k��4"�lp�$kGf�4�<����w���k��4"�lp�$�@f�4�<�:�����+�t��G��S�$k���E�f�u��t���W3�8�Z�/���a���5��I����E�f�q��8�`�{6�a��x�	{�$k����W3�8�Z<p��=�0�Z��	{�$k�4�q�q�����"�lp�$k�7�H8�['Y�,z5����e�'�]�0�Z�E2����@X�*SN��� ,r37���1�HF��Y�2	�^�a�,k�<.^��]�0�Z&@aQ�8�[�Y�(,z5����%t�xYv]�4k	����po�f-Y8��^�ad��ea�5����0��q��#�a��5��1��k�g%��Hh�7���p"4La���	i8ei�u-��8������8�SZ����8<gq�u-�yx&<��'Z��Lx��z
���E������<���#�yxa<li������-3�yx%<��gZ+���x�:�����<�����<�16��6����0�����[��]�LkG��gZ;��Nx��z����<�����<��3�y� <Lq�������a�0�Z�����`�i�<DD���q��bg���8�0�Z�C�dl�`�i�"�Ws�8�Z��F�fn�i��@�dn�`�i��G������z
���F�fn�i�~C�d|�`�i�=���Ws�8�Z��F�fn�i���"���:�Z{UE���q��bw���8�0�Z���
��:�ZUE���q��b{���8�0�ZG������:�ZGUE���q��b��=;�fZ�C6WVc3XgZ����U��^��3����:zI��������a��5���q�a��F�aVe3ZgZkD���)��p[lDn����VDfe6�y����#�a��5���q�e����Y��h�i�����0��c����8�2����Y��h�i���3�a��5�.��q�e�� �J��<�Z�����k8�m6"7�p�LkEf�6�y��"���)��p�lDn������<�JmF�LkC�[gZ�g#r3���v�a�j3�gZ;���x�:��B�{v�o�i����f4������0��c����8�2�:��Y��h�im��Ax��z��xX�fn�im��"	O������E���q��9�a��q�a���E��3���^�a�Lk�.^���������E���u��y�a��9l�im�����p�0��z�aQ�9l�im=����6��������p�0���aQ�9l�im����6���a��C��o�����L�EWq�Q'A��:��F@b���lkm# ��=}��{�.���P"��:��&b���kjm��=�{��ta�Hpx���������#�- �,��"]���0[Z[D�)���7"�,��]���(
��YQ8��^���(�(|�KtY�p" ���� �SN���� �� |��pYg���`p0��f���`0���.��s���.�����A�����^�_��%�)|��pYW����o0��V����/������k~K����o�+�`�bm�`��5��7��pK���7B��<����7B��k�#�������;A�`a��;C`��@>������a�`�a��c`�k�N�{6�a��w0js'�6.X�X{O��L����i#r�7L�v�6wRl��u��;x��^�`�k�N�{6�a��{���b�/�A�{x��^�`�k�N�{6�a���j�'��h�c�=���W3�8����F��
nd��G�� _���}�U�jY;V�����
��}�P�>��E�$k!H����I���6"�|��a���;j����h�d�S���5=��c���=�0���5�S|]�N��I���6N�v���g�&Y{@&�6.Z'Y{@������lD����I���I����I���#�`�$�lD����IVB&�6_B[�rp"L1�����)��w��(k��Lm\4O�f���p0��c���=�2�Z��I��K�I�����^�`���g�[&Y+r0��q�<�Z��W���k�M6"�lp�$kE&u6.�'Yr�J8�bz
���F��
n�dm�����%�$kG�SL�a0��������I��L�l\2O�v���p0��c���=�2�:��I��K�I��|��^���C>�|����p����N��8X�j'YGw��e9��e
vj$������^�`�$�p��"�lp�$��52�N�,z�)��0�����
����P#�`�$����E�f�q�u���"�lp�$��w�Hj]����~�F����
~���}��o���o����������|��������h?��?����a)���_>}�����������p��i��W�_����L��.����n��-�����w,���R��J�
��#v��������#�[U�o^�����G|���R%��G�Q#���Y�G����_'���Y���/U	_�DX���H+j$7�;������*��	/|6x���_�d�I����g�H�,w���1�[��_'���Y��_�f�\���w
E�f�u�w,�� z�_w�:\<�\�[�+�)������
��W1��p���.n.��-��m@���rg�m�� z�_w�����=�2��=j$w�;��oGR���:�=�#�YZ�r��8�<�;����/T{6�@>�<�����p�3>��w>A��/4{5�A���M���vI���
5�=jg�d��{���U6N��M�x "�]�� iA�d��'Y{�;0���Gz=�X<��.�z��P#��v�I��������Z��� _������4�d��'YjV0���Q^h�,l����a�*�K�4��q {��8�zP3���~��B�gi�w\<R��vI���=j$g��q��yJ<��(/tz6x\a�FR��vI��M5����8�z�7���~��B�ga��o� Un�d=H:P#9�����������Y����<�K�$!���I��E���s��B��G������]�� 	98��IVB�:_��,lpBNY[&Y	98��IVBN:_��,l�����2����g���<����g��/�y6xA���2�Z�����<�Z����/�y�69x�r��2�Z�����<�Z��W��/ty6xE^�<�L�6���p0={^��
9x�9�B�ga�7��-��S�$kC�{�$kG�t�P�Y��9x�r��2����w���<�:��w���I��|d9xj�d���`�$�u���`�$�u��"�lp�$�u	52�N�\,z��.4y6�y\�,O
�,���E�bpo�d9,z���,�;\�,O
�,���E�f�u��<p��U�N���q���0�r}�	��U���E�b�u��z�`�{6�a���	��U��E�b�u���`�{284L��p�F����f��
�9�B�ga�G�`�{6�a���
5�4�<�^�`�$����7e984L����F����f�p��U�N�\@Y
�,���`zA������p�u��"rp�rph�d���'Y986O�rp�rph�d%���8�<�J��I��u��
FNY-��98�4�<#�:_��,l��<g98�L����p0��Y��9x�9�B�ga���%��-��9x!L/hV1xE^t�P�Y��9x�sp�$kE^	��U���W��/�y6xC��[&Yr�F8�^��b����|�����;r�����2����w����f���w��/�y6�@��[&Yr�A8�^��b��|�|������������0����y�7����I���	"z���,�:\<|���
�,�F���9E�^��b��'��U�N���q��"7L���Q�>����U���yy�<��"r�7L�|�P�>����U�!I����I��!H�g�&Y�?P�>����Uz4X�y������"�lp�$�j���zzA���#$��W1�:��#�"�lp�$��j���zzA������^�`�$�O.�_���I��h��y��^��b�I��U�N�|��x���
�,���`zA���98�|�����98d985L�|D&�5�^��bpD�:_��,m0rp�rpj�d%�`�[���*'��D8�<�J��)���e�5#��O/hV1xF�	�'Y3r�����2����Io��4�� �:_��,l���d98�L��`�[���*�������<�"�YN-��9���xzA���������<�����<�L�6�`�[���*o������<�����<�L�v�`�[���*�������<�:���,��e�u ��OohVq�@>tN�Q�� |dA�u
���C&�5�^���p�	�^�a�,����En���aV��$(L�hVq�
�^�a�0�w��"7�p�4�w�$,L/iVq���0aa�4����"7�p�8���d0lg�=���U����`X�fn�g���"
[�Y}4,z��[�:�^�]�0���aQ�XL/jV�x�����V?z\�,��a���@��Z��:��G b��Ylj=����)H�0��'@bQ�Yl�j� ���,����i��S��a���E&��5�X������������b�0��#Bq PL/lV�8"G��[�-�H�1O��e���#�bze���	�8�T���jmqB,Ny,v-���X��K�U,�����������s��]�lkF.�	�k�u,F.���[r���b�2�Z��������\�0.6O�V��%���e��"�������x%\����
�x�s�k�nm���bzy���r�F����[r���b�2����7����f�w���p�3O�v��]������\�.�8�X| ���y�u 
�L����p1��Y������A��Y�[�������a�5t;��gyz�����#�W��:���F�f,n�n
nE��4#O�qV���sD�j[�[6�����
����(R����E�:�sD�j[�[v�����
������i���*g�{�WE�f�u�5`����X�0���9��O/sV�x�|U�j[�[������
��aP�>�����U,!_����:���F�f,n�n
�G��|_O/tV�x�|U�j[�[v�����
��!t(R������*�b��Yl�n
�r#z3�H�����Kk�\����w������������<H������������?��?���<����_����?��+_���)������Q<����N��8���}��V>�/�
���e?�	#�9�����gkCDo�3�0�fDRB���>�W�!a��0�y���!���p�2�[�0H{�Z�8� `,0�y���!�7�p��oE� �!4i����|�2�0���9D�fn��m��?�-U�/6��QV�����-����������;�����<�����q�e��#]��o��>p�m'�n�<�����q�e�w����)K
�������[�|c{n�7�p��o�fI��.)�0�������F���!������f�]&�����E�b��0eMv��"W3�:�����"�}/�e����Y�������zb���kj������}��e���H���#���������������H��w�(�l�YZ�0,r5��q�'�{�.����D��fg�#���������PX�����%���;Jd�O���z���pof����=�{�NyY�%����,r5���1 �,��M^���t�9B��`� k��!�)|��pY#�o����U�������`c%�����oG���	8�L�*'�Dx0O�p���L�f$��0��<#����kF���

^�g�i�P��x!<�GX"���74xE^t�!B�Wd��0�`�a���k~;�e��"�:����B�J x0�6��-��2����7��i�P��)x#<��X;R���nc���;�`�kG�	�1�����F������p�y�u ���s�	�CD����A����������$���S��ldM�"z�7L�&#'RB��*;x��\���u�5am��=��h�dM~@��4�$T1��D�j['Y������
�����Q��J��*���\�`�$k���{6�a�5
j�'��$����"W3�:���2D��
n�dM�����4I�b���`}f����	CD����I�4��Q��J��*O��\�`�$k���{6�a�5M3j�g��$�����\�`�$k���{6�a�5�`�B��*��@8x�N�&�
�g�&YSD&}!4I�bpD�����,,
�g�[&Y	9����$���	9816O��&D��
n�d����+�&	U���g���y��%!��|g�e�� ���$T1xA^O�IV�����-��9����$���+r�B8x2O�� D��
n�d����%�&	U���W���y��� ��lp�$kC&!4I�c0r�F8x2O��D��
n�d����!�&	U���w���y��� ��lp�$�@&� 4I�b��|���,,�g�&Y�C&� 4I�ap���E�f�u�:�`�{6�a��G���������E�f�u�p��=�0�
�C�:�$���8X�j['Y�����
���w��s0M��{4�pp�N�B,z��9&Y�_Q���4I�b�,r5����0����
��0��Q�`�$�18X�j['Ya�q��<4L��,�����0�\�`�$+L/��C�$+L��"Z1�:�
p����N��t��e9xh�d�0�F��i�P����$+������a�"rp�9�&	U����pp�N�BD�YZ&Y	986O�rp"������<�L�rp"l�d����q�y�5#�yn�d������4I�b��<36O���%��-��9x�9�&	uF^G�$kE^�<�L�V��U�`�$T1xE^	G�$kC^�<�L�6��M�`�$T1xC�G�$kC��<�L�v��M�`�$T1xG�	G�$kG��<�L���]�`�$T1�@>G�$�@>�<6L�b�p	u�IB
�c��l�dE���g�&Y�;P�>��&	UvL��u���F��
n�dE��F}PM���"r5�����]5��lp�$+�5�{i�P���T��l�dE,��g�&Y�O�Q�K��:C�*r5�����m5��lp�$+0O3���$T1x� U�*'�$+b]��=<5L���4#)��IB�GRE�f�u���F��
n�d��G���^�$T1x� U�j['YkD����IV5�{i�P���'�$+bc��=�0��9����$���98N�IV���{6�e���Iq
M����#��d�dae��=�2�J�����&	U�����d�dae��=�2����Iq
M��<N�IV�����-��9���$���r��8�<����{6�e��"���$T1xE^�'YXY#z��L�6�`R\C��*o������-^���F��-��9���$���;r��s����,���g�[&Y;r0)��IB���]�`��'YXY#z��L��`R\C���9��9�w�IV���E����IV���s0M����E�f�u��p��=�0�J.�F��i�P�`�`��l�d%�q��&Y��h�`�$+y�`��l�d�����rph�d�8XD+['Y�����IV�w\�,��IVz�H8�:�Jp����N��,z�7L���P#)p�QB�Ga��9le�@X��ne��@����f	U�t�������$,zO��YV�6�H*\i�P��(,z5�����C�c�0+D�����iB�#�p ,������c��c�4+Ed�����qB��#�agg%������2�J�I�aG��*'��Dh���Y3�p��pl�g�H��N��
U��g���<����,�����8<�8�h�P��yx!<���yx��pl�h����a�HkE^	;�HkE^�<[FZ+���x�<����W������<��y�e��!o��i�P��yxc<l�i���{��[fZ;��Nx�F
U>��w���<�:���,�����<|��B������:����F��n�i���Y�
�j8<w��������6���p�Lkv0]sf564R�����������fl��g�fZ����3����B�=<DD���u�5c���=;�0���5��4R��p�������f���g�fZ��P#��K#�*��^�a�Lk��{v�a�5j$#|i�P���G�����[gZ3������
3�y�P#��K#�*O��^�a�Lk��{v�a�5Oj$C|i�P�aUE���u�5c���=;�0���0k���B��p <�[gZ3������kj������L����8 ��C-����[�Z	��5��P���	�8"��S-,���[�Z3"1����B�gD�� qoka����X�2�Z��Y�
��X� /��{�\mDo������P�zmh�P���x!P��[Xi#z3�L�V�b�lC��*oH�+���<��R����e��!�n�,���x#X��G[Xk#z3���v�b�nC��*���;�b�l�mDo������\��mh�P����`\ln-r��pq�tk���E�f�u��t���W�x�N��n���s�k�n-�G���i�P�b\,z5���������
���;I��fU,����W��:�Z<p���X�0�Z��"	�l���}�.����.���[K��H��4[�b�\,z5����e.���[���H��4[�c1p���,�N��q���s�k�n-#p���,�N���X�j[�[��q��\��[�\,�5����e.������:\�<�������b�tk	���q�u�����pq�tk����p1��X��#�b�t+"G��[�[	�8.��B�rq"\<��[	�8����L�rq"\L��*����p�h�n���s��}�tkF.�	�l���r�L�x4O���%���e�� /��i�P�b���p�h�n���K��}�tkE.^	�l���+r�J�x4O�6��5���e��!o��i�P��
�x#\<��[;r���b�2����w��4[�b��\�.����x�s�o�n��;�b�t�@.>�����\|���7L����2.�N���#�W��:�Z�G�f,n�n��C���fU,v��������8�7cq�tku;�$��4[�b���b}(�����KpD����a���E�NX�-T���|U�j[�[+������
����Q$i���B�!_�������E8�7cq�tk`8�J�p��X<@�*z5�����pDo�����:�t���8�-T�x�|U�j[�[+v�����
��uP�>��l������W��:�Z�G�f,n�n���H}���B�rq \<Y�[+������
��5"�NG��*G��H�x�N�V���O���������=.]�eD4&�8��U\N�����y���8���E������	����8.T1xF0N���-l��'��z�.l��XLZq���X<,�������w�N6xA(&�8�U^���<��>�{2�����������X���+"�J�8�[X�#zO��*]��
��T�8*T1xC ��X�pD�������#�FG#�*���;��`ja��=|�&qa��aR��h�P��a� 0�#-���'���".m0r0��q4N�a��!���u��u���73����[��F��y���E���u��9a������a7�FF��Y����E���u���W/�A�0��<���V�aB�=����������)��
���E���u������Wq8Z�Y[������Y�0�F�4N���0,z5����m�g��Y��Q#�a�'Tqx����y�6
����
�m�P#�a(Tqx������6����
�m�Q#�a�(Tq8��0��h�hmy8�y�a����@x�F
U�����p�����<�<�0��"�p$<L#�:#G���<�J��1�����(�pBN���3��<�G�LkFNY�o�Ga�g�����y�5#����3�yx���}=
;� ���i�P��yxa<l�i-��K����Q��yx!<L#�*���+��d�i���k�����Q��
yx%<L#�*o����d�im��[����Q�a����0��r8���������G��w����?������!���>�����?���O������������R����|��������/��?���	�{��%
�l�%zf����n���d������E��>����[�0��C�:�;�����=Lt�yyW�B��{�s�{6�a��5���h
S��~@��w�+M�e
���E����)��o�QGtGC�*0�M�*_�y�<�����
C�}XP�N��f0Ua���U����5x6���?
3�}L�QtG#�:�$7��|�5�������n"�a�O��$�5��#�}�9n�W1�B�[���������_C��%�h�`�T18�ts��|!�-l����c�oo

�=j�w��_��E�b������98f9���'�
N���pp������t��
Z�����|����#'����H�>#'���4��5xF��|�������3��d�d-�����WzA�� /Y�[&Yr�B88�'Y+r��s��V�����k��[&Y+r�J88�'Y+r��s��N��o��k��[&Yr�F88�'Yr��s��F�����[����I���36O�v��]��+}��
F��<�L����q�y�u :_i-k��|d9xh�dr�Am3yU>:�`��l�dp��=�0�:�5�3��u�u�
&l�d8X��
n�dnC���vg�d8X���]�-k��g�&Y�_P#9��Y'YG,z������g�&YG�P#9��Y'YG,z����c��xY&Y�,�5����c����I�1v�xyn�d#p����N��8X�*['Y�����9�a�uL=j$��;�$����E�b�u�uL��"�d��0�:�C������# ���t�58 �,�
��# ���I������W�?���c����IVD����y����#�`�$+!�,�-����;�$kFN�����9x�r��2����g���<����g���t~�5xA��<�L����p�3O���E��+��e
^���,�-��9x%����9x�9�J�ga����,�-��
9x%����
9x�9�J�gY�7��-��-��9x#����9x�9�J�gY�w��=��-��9x'����9x�9�J�gY���#��S�$�@>'YG����9�J�gI��=����
n�d=H�P#>F�l�d�_y8�����I���	�������`��F|�<1�'Yj0����''YG�\<|�����h��yj�q���f�=Nh{b�q�ut����������}�=��O
6N��,`p���])�,k����a�z{�kh�0�����'Yj<�|�''Ybv\<Roo

{��q�S����yO��
6N����x#�����O5b���`�$�A�O8�����I���o� ������5b���`�$��B����''Y���C���%Y����`o�d]D:_)�,kpD�Y���I���q�y������W
>����c��C�$+!'���IVBN:_��,k����Z&Y3r�L8�7O�f���p�y�� �Y-��9x!��'Yr�B8�<�Z���,��I�������"�:_)�,k���f98�L�6���p0��\��
9x�9�J�gY�7��-���e��!o���D�*������W�=��#�Y-��9x'L'2W1�@�u���Y��9��sp�$�@>���uF>t�R�Y�`�!yn�d�8XDk['Y�����I�s/���a��p����N������I��.^��c�$�y�`�l�d9,z���,�w\�,��I��{�H8�Nd�bp,z���,�����
�,78�H8�Nd�b�,z���,7����
�,7��p0��\���G�u�R�Y��8X��
n�d�qC����D�*O���W1�:�z����MY�
�,7-��p0��\�`�`��l�d�0��e986L�\@���D�*���s0m��bpDyn�d��	���U���Q�`�(Q�����2�J���p0��\����t��uFNYN-��9816O�f��Y�`�(Q��9x�rpj�d-��3�`�$kA^t��U^���,��I�������"/�����9x�rpj�d���+�`:����r�J8�<�����,��I����������h�D�w�-��e��#���H�*�����vJTq�@��$�ZfY��AH��d����$|�$�h�D
�}���#���a����#5o�5���,��CD�j[�Yjknz�7L��P�>�����Uv�����q��������
�,�=j��y:����"�Ws�:��P\s�{r�����}�"����f�bq����,�N�<T���f,ni�~G���^OG3W�x��b��H�%�X�57���Z~XQ�>�����U,!T�������������
c-?�(R���x�:C�*z5��s-67��[~� ���x:������W��6LT�*lnz37L�|@*&E6��h�bq@*��i�D���C��^Z�I���C��X�#�b�2Q���X�X��"����\L�l<�\���\����*'���pq�pkF.&u6�j�b��\<.v����\<+\�2����I������X� ���i�D���%���e�� �JO�5W�xE.^���*���k��]�tkE.&�6��k�c1r�J���MT�xC.^�\�Z�[r1���t`s�7���q�y��#oy.v-�����x:����;r����<�����<�����\L�m<�\���� \L['�X| y.v
���C.&�6��m�aq��^�b�t����Eo����V�:I��n�b�.�����V���Eo����V�vI���n�b���b���{����X�f,n�n�~E������*����W��:��{�b����a���3�$\L�7���X�j[�[�������7L���XTk[�[�\,z5����~t�zy.�
��~.�����V?�^�b�t�\�<���V?
(�p1�\��	�X�j[�[�\,z37L���Q$�b:�����80.�N���\�\��[}D.��� �*G��H��6QT�8"�<���VD.����(�*'��H��vQT�8!�<���VB.N���0�*����p1m��b��\<����L�f���p1�\�b���p1���b��\<+\�2�Z����t�s����p1m��b��\�(\�2�Z��W��t�s�W���p1���c1r�����e��!������
�x#\L[)�X�!oy.�[�[;r����<����w�������;r�����e�u ����`�*���b�t�@.>�\��L����p1�\���������:���F�f,��n
��5���pG��O��}��o���o�����������������?��?���<����_����?��+_���)������Q<����O���|�������G��Ot��_��g��WR�F�g��uT��c����|��}C��)B�_�����*��9l��
X'"z37L����T������A�������O�������f�]&��)��T��/��<BT%r5����;ED��k|`��w�(Q��J/_T�w��J�j�Zg}V�������EYC��8�AY�������l�'�C���"Z�Vz���������G;����"����}��e��+J�G�^@���&��D���u�7`���=�{�KtY���Nz�����I���h_G�ND����o����3b0���-��;#����=l�'��,/���LE�U�*�.��`��Q�_��!����v����"��Bz����+��J���uT��DDof�MC�7`R(BoYT1xC����*c����\�jh��L
E��*�H�;!`��Q�`����L-
F&}"��E�D�� 0���b06����NCC�d`R'B�W�0x����������c,z�7��nF�:��u����!��z\��np�kt@�"Z1�:�P����N�F�p����
c���h�`�k���"W3�:�������;���5�P����^E�{�`��l�c�=p��=�0��u��*�<�\���u�5����lp�$k;��s0�SQ��8X�j['Y�,z�'9&Y���F�����*O
&L�9�<����
��qZQ����>E�p����N����|�,����@8�:�rp L�9���C����dR���	�'Y98��UN��1��w�1)kpBN:��UN���p0m��c0rp�r��SL�<#'�����*���3�`��Q��9x���n�d-�������@����q�y�� /Y�s�IY�W��E�`ze���+r��8�<�Z���<�L�V��U�`zg���r�J8��qT1xC���2����7�����*����`��Q��9x�r���K��#�:�[uF�	�&�*��{����\R��9��9�^�b��|�=5��&D��
n�dM�+�HW�7P��������N�&,	�g�&Y��a�i
����"r5����	+BD����I��{���}�7���"r5����	BD����I��;��OC�W��C�*r5����	�AD����I���Q��J�T1x�`}>���U�r�{6�a�5
j�'���U!H����I��� ��lp�$k���A�W�<A�*r��!�I��� ��lp�$k�j�����u� U�j['Y�����t��I���I7�:P������*c)��=�0��"r0i�W���#�`��Q�`������e����I/�:P�������*c!��=�2����I+�:P��9x&L�6��u ��lp�$kF&� ��@����p0m��b0������-��9�4���U^�����k���X"z��L�V�`�B�T1xC^�'YX"z��L�6�`�B��19xcl�da
��=�2����I�:P��9x'L[6��% ��lp�$�@&M ��@����p0���c0r�����a�:�`�B��08t��"W3�:�
p��=�0�
��F�����*;�`��l�d,z�7L��;P#�`�$+�
&�������E����IV�j$l�d�8X�j['Y��g�&Y�_P�����@��`��l�d�8X��
n�d�!�F�����:�\�`�$+�/��c�$+���"Z1�:�
#p����N�����e9xl�d�	8XD+['Ya����IV�v\�<7L�B�Q�����@�rp ��l����C��&Y!"�����*G��H��;�$+D������e��������@�rp$���y����S����IVBN:��U���im����9x�r��2����g���I��<����<�Z���,O-��9x!l�d-��il����9x�r��2�Z��W�����*�������3O�6��5��S�$kC�t�W��!o:��<�����,O-��9x�9�^�b���36O�v��=��S�$�@�u�W�| �����9��sp�$�@>t�Wj;|����u���F��
n�d��@���"zu��� "W3�:��XY#zO��IVtj���U������IV���{6�a��������@��"r5������5��lp�$+�0O3��zu���=�"W3�:��XY#z�7L���4#)��W�<@�*r5������5��lp�$+�0O3��zu���#�"W3�:��XY#z�7L����F}`/�:P��	�T��l�dE���g�&Y18����W���E�f�u���F��
n�d��L�k���*G���8�:��XY#z�7L�bD&�5��@�rp$���,���g�[&Y	9����uFN���y���5��dpl�d������^�b��<��IV�����-��9����U^�����<����{6�e��"��zu���+r�J8��'YXY#z��L�6�`R\C�T1xC�{�$+kD����I����k���*��;aoeag��=;�2���Ys
�<P��Ix'$���,,��g�[fY�0����j8�:D����u��:@a�{v�a���5�Wz}������Ws�:�Jn����p�4+9`a�9lg%0,z�{�8+y������qV��"Zs�:�JhX�j[�Y��p��4��Y������V��E���u���W/���a���5�Wz���������N��<,z�7L���P#�a�H+����Ws�:�J#���=;�0�J��[gZi��a���u��&�a�{v�a���
5���8��E���u���p��pj�i��<�kuF��{�L+E������0�Jy8���8��#�a�L+!�,���VBN���E�*'���x�<����S��[fZ3��Lx��$����<<�������?�������?��M�7������G^��_����?����{�������_���NC7����w�����?������/�����>�����������g���Q�]<�cv�D2
�P#�����p��C��"�C2^����~���W/;{�u���D4^����z�b��h���C��
���z���3��@��l���'��P��
�x#�'�������7c�i�"w��M@����*��;�@1���PL���M8�t��#(��P���x'3(����Y��7c�i�"�}���jX<c����,����<x���^�����,��
E�����b1��^�������|j���K��b��H���u,�����,����<���O�6_��Z�!f�O
7O-���<x��^���!��v���n�u����=���������S8�9��U,��,y�o3��m�n7�x��u>��<��:����F�j[�[36������;�
-{IN��U,����Yl�n��q3�:n�n7�xr(�=�7!�X�%7�W��:����f>��|�+ni��"��#z���Xs#z5����{n�S��������S��S�����nD�f�u�5c��|j���[����\|��yb1�Q�b��H�x4O���f>u�|��mhqB.>5�<��<�����Yl�na��|j���������y��b�t�nD�f�y��}7�����.lC���S��S���-,������6��������
-^��O�7O-6O���F�*O����\|�������
�x%\LoDT�KoD�f�y���7�����.lK���O�7O-6O���F�j��[�{3�zo���6�xG.>��<��<�����Yl�na��|j�����������b�t�oD�f�u��t���������,^:�bQ�Yl�n-p���,�N��q��\��[�.����ZD�p���,�N�������7L�\,�5������^�b�tk�;�^��}�tk�{I��^7�bq\,z5�����.���[��P$�bz����p���,�N���X�f,n�n-��"	��U,{��pq�N���X�f,n�n-��"	��U,���E�f�u��L����lq�0�Z�E.��
�X\,z5����%�zy.��[K@.���u�*��@�8X�[KD.y.��[KD.������%"G���<�J��1��}�t+!'����VB.N���y����S�������\���U,���g���<�����<�-���x&\L�T�xA.^�tkA.^�\��L����p1�nP���xa\l�n���+r�?}��oo>��r�eD4^	�U\��W�����h�e���W��+�`�0��
��`�0�����`�e�����+�#���m�*���;��hn��{��{�.��B�A���5�b��P|(������8��d�}/�EWp����S;�S�����qD�f�u��b1�z*�����W��+�%�z&Qw��=�*c/������V��YO�8_���M\v�G���#GoT1kqD�f�u��b-�z������M��+�w(�"O�w���8�W3�:�Z�g=��|Qv�q��Q"�O
��V,���������8���6����������^0��0���^�a�<k�R��T�s�����qF���_G��qU��9l�e�X���Jqn'y:<�`������a�0k�R��8����Kq�S)�m����Y�����a�4k�R��9l�f�X���Jqn��
���f�������?^��0a�w������������<�s���/�~����?����O?���O?�E>K�������O?~��W�����S��'�y��#e
[����������{��y�/������b�W�_�n`��[��N��������V���t��t,k0�Y��fu[��oj�����Q��
��6}�J�iY�7|����J��e�{��oU;z���;�X��.��R����^��{��[���P��U��M�*�^u�+�t��5�����d�Zf�����jG�a�0x�p����U^�4-j�����=�in����jGoaT1��&��U���]�`{"�lp�ps3j�Oo;z����� z�/D�e
�=.�1��
����J�lnPY�*_Hx��;\�,�9���
���"Z3�:��z�`���w�����.^���}Rv�5��/�<�^���nY��`�{6�a���5�w/�<�^�`�$k��E����I�6u��q�u��M���W1�:��&�`�{6�a��M;jdl�dm���:_�-kp@yn�dm98��.������W�A���c��&Y[D������:#G���T��58!�,�9���
&��D8�^��bpBN:_)-k����|����+8#������*���3�`�$kF��|����+� ������*/���`�$kA^�|����+�"/�����*������W*A��"�Y�s�I����W����E�7��M��+��e
����,�9���
"o�����*������W�@��#�Y�s�I�D��'Yr��s��2����G����I��|06O���C��+U�E
�;|�yn�d��,�����E
��� �W1�:�������m����n�h�`�$kw�����I��;\<|��6���b����N�vO��l�d�~����m����}����.Y'Y{I��U�N���T�{6�a��5�7�]�N���T��l�d��"�lp�$k��_\v�:���
�/^��,k�A��=�0���
5���]�N��	�T��l�d��"�lp�$k���_[v�:��$��W1�:��p��=�0��rp`l�d�98�|�����98d9xh�d�982�N���u�R�Y�����2�J�����b��������WJ?����2�������'Y3r��s��������s����I��<�	^�y�� /:_)�,k���d9xl�d-�����'Y+r�B8�<�Z���,�-��9x%��:�$kC^	�'Yr�����e��!od|Wg�d������W�>��#�Y[&Y;r�NFYw�I����|�����r�����e�u d�ug�d�����Wj>�|t��G����I���h�`�$����E�b�u�ut;.^����I��z��8�:�:p��U�N�,r�7L��P#�`g�d8X�*['Y��g�&Y�?P#�`g�d���|�����=p��=<5L��~C����u�u���W1�:�:�`�{6�a�uj$����c����I�1����
��cL��p��N��8X�*['Y��q��<5L��	8XDk['Y�,z����z�58t�xY�&YG@���u�u���s��V��#�,O
��#"���:�:"rp�9�J�gY�#rp�r��2�J���q�y�������WZ=����S����IVBN�����98�|�����3r�����I��<��I��<�|�����r�����I�����I����|�����+r�����2�Z��W���<�Z��W����z�5xC^�Z&Yr�F8��'Yr�F8�<�����,��I�����I���6O�v��=���e�u ����y�u :_��,k��|d984K�|�u=� �`o�d}���	�U�b�m��Y���W�g��%Y��C���"O"��F0���4���*?���*�lp�$���5�s���M���
�Gi�U~^Y�U���fI�gIj���zo�d=����Q�t�D��W�|�{6�Y��Y���y�_*��
>��^�ILT1�ye�W�g��%Y�5&�Hzk|o�d}V����>J���b�����rO�fI�g�4��O+��<.`�����&�������������G�Hzk<�`�b����I�IL�1x��� ��Q�����F}^���U���p�m��Yrp�rpl�d=H�������
�*G��H*%���*G����2��������*'�H:%���*'$��%��2�JH������*�H���J�U���,
��a��(L�k<ma��0��LZ%���*/��s��c�4kA&�5��0WqxA^H��2Q��ax��p�8kE&�5��0WqxE^I�3Q��
ix��p�<kC&�5�1WqxC�H��3Q�a��-���e��#��O���8�#��a������<�gy8�L��a�_�is������y�u YN-#�y��x��\����ct���u����z�z���p�L�uj$<L���8���E��0�5Q�a<,z�7���[P#�a��\�a�a��9l�i9?��ey85�������������Ws�:�r�����pj�i�xXDk[gZ�������:\�,������E���u���a��9l�i�a����p�L��=j$<L��8<�^�a�L�������p�L�M5���U���E���u��&�a�{r�u
C-7(�1-e�bq��b�t�D�q����Z. B�������80"�N�\D"�Y"v]�X�ED�H��3���82$6��"q�"��Z�Z	�8&���U,N���01�<Q���8e��u-���x&PL���X<#�����*/�s�]�2�Z��B������R�B��N��c1R���b����V���a�y��"�����*���k�]�2����W������\�.�(�X�!o
��6���p1-i�b��\�.�3(�X�#�
�L�v���p1�i�b��\�.�S(�X| y.v-���� \L���X�\|.�s(jX�;|�y.v
�-���Ez�o�iUs
�}���Yl�ny����s��.vC�]�������*;x��^�b�t�{��������
-��$7��5W���sD�*�iu,>p��9�u�����"����6W���|U�j[�[��|U�f,n�n���H}�����U, _������ _���[~�P�>�����*����^�b�t��������
�-?�(R���ims��-��o::�������7cq�t�O+����zZ�\������,�N�|.���[> ��O���X�\��U,���!���a��#r1i���:���8.��)�X���c��}�t+!��O���X����b�t+!�<�����\LZo<-p�b��\<3.6O�f��9���e�� ��O+��X� /���p�*/��K��}�tkE.&�7��8W�xE.^	��U,^���<�����\L�o<�q�b��\�.��)�X�!oy.�-��
����xZ�\���x#\L�ST�xG.��\�[�[;r1����������;�b:����r��pq�t�@.&
8��9W��@.>�	5,�;��C����V��j�b�t����E�f�u��w�^�����V�I��:W���^�b�t�w���7cq�t��E.���U,����W��:��=p���X�0���E.���U,���E�f�u������7cq�t��wI���:W�x��b��tLE��b����a��+�$\L���X<�^�b�t���Eo����V?�(�p1�v�c1p���,�N������sq�0��'�bQ�Yl�n�p���,�N���p�������|{��.�����Cc�������1UQ�eD��E��^���c��\���`	�AU��1���P�58!G�������	�8,�c*���S��{��f��Y��ag���������~���>���� �A��>�����?���O�������������������_>}����������q�?r���8�_7����������+�������@�O��|A6���Q��"_�Y���.����H�N�BDPX�����<��.�,\��eWpC��t������!Yl�,�S��b�����k^vw��]�
:����;2�N�����/2��e��������L��LAg0V��@�8R�IU�=)�,R��_^t�n����`������C�j�Z�{V����4��;��i1t�b�<>D�f�u�7`����\�jh��P�>+�_�b�������N�,��3M-
�Q�>A�$6��h�>���U�>���ihp��F}~*�X��2)��l��
X'"z����./�����t�b��������l�g��X�c
R)B�.V1x�C"W3�:��LD��
nc
5H��X��	BT��lc
X%"z�7���0�F}n*�X�����U�"�{6�a�5D�`�&B�-V18"G��t(G��FD��
n�d%�`�%B�-V18!'��t$G��DD��O��L�r0i���<#'��t G��BD��
n�d����G�Z�b��<��8��"��lp�$kA&-"t�b�����tG��>D��
n�d����C�Y�b�����8���!��lp�$kC&
"t�b�7���p0�Q�`��-��w�2)��;r0����#�����,,�g�[&Yr0i���| ����,�
�g�&Yc�L�C�p��p����Y'Yc,z�7L��nG�������y4�p0�Q�`,z�7L�F��F���I����E�f�u�5z�`�{���0���u�c�,r5������q��|����K��h�`�$k���E�f�u�5/��wN/)��p��V�N��8X�j['Y�p��e9���%e�pP���t�b�G�`��l�d�#p��=�0�'�u���<�\�`�$k���E����I�:��s0�X���['Yc@Y�sjI�%D:�Q�U����q�u�5F������e������t�b�rp$L�mT18!�<�L�rp"l�d%��D8�N��b�����2����g���I��<N�I��<g9xh�d-�����t�b����pp2O���%��C�$kE^t���"����y��"�YZ&Yr��s0�X��
9x#����
9x�r��2����7�����*���;��d�d���{����I����L�&V1�@�	'�$�@>�<�L���C�`:7���S���q�u�5a!��=�0���5�c����*;x��\�`�$k�:�{6�a�5���9EtL`��"r�1�I��e ��lp�$k�0�"� tN`�=<@D�f�u�5a��=�0��z�9�>:(���=�"W3�:���D��&Y���F�
�N
�b�A����N�&��g�&Y��P��BGV1x� U�j['Y������
��i<P�>���
�b�4��d8g�dMX"z�7L��iC���^:+���8X�j['Y�����
��) �
:+���98����:����C��
n�dM9�T��Y�uF�����,l��g�[&Y	9�T��Y�UN���q�y�����lp�$kF>Wv<l�d���3�`g�d���s��[&Yr�L8�<�Z�����<�Z���<�L�V���p�y��"����y��u5��d��2�Z��Ii
�X��
9x%���,���g�[&Yr0i�����#o���y���5��lp�$kG&�5tV`����p�3O���F��
n�d������
�c0r�A8��v�08t��G����IV���E�b�u�:�`��l�d���e9xj�d,��������E�f�u��������a�|�u������E�f�u�<p��=�0�
�C�:�Y�U���E�b0���bp,z�7L�B�F���IV4�p0���b�,z�7L����F���IV��E�f�u�F�`�{284L����F�����*O��"W3�:�
p��=�0�
SB�:�Y�u����IV/���a�rp�9��
�bp@��ioW�#rp�rph�d��u�����#�`��U�`������2�J��Q�`:+���	98��]UN��)���e�5#'�����*���3�`�$kF��Z&Y3r��s0�X��9xfl�d-��K��C�$kA^t����"/��ioW�W��5��-��9x%l�dm��+�`��U��
9x�sp�$kC��'Yr�F8��vU1xG��[&Y;r��s0�X��9x'L{��| �Y�-��9��9��
�b��|��]uF>�&Y�q	u��k;x��\�`�$+be��=�0���G���":+��� "W3�:��XY#z�7L��w�QTDgV1��D�j['Y+kD����IV�j���Y�U�{4X���ioW���F��
n�d�~C���^:+����"W3�:��XY#z�7L����F}`/�X�`RE�b0���b0V�����
��8�<�H�k���*���\�`�$+be��=�0���������
�b�A����N�"V������a�ppd�5tX`��p  L���8� � �FY1"��:-���I8��]U���{v�e����Yu
X���(�
���*ck��=;�2�J����������,����*cm��=;�2����Yy
X��ax&0L���8��5���p�8kAf�5tb`���F��y�����-��i������U^�W����6�����-�
q������U���7�������X]#z��L�v�aV`C�VqxG�	��:#�yni�����N
����<|�
^U���{r�u
C��!�:7���� �����V��Eo����V�I��N�b���bB�������X�f,nk%��H��tv`�= ���,����$���Z�/(�01�X�b`b��Yl�k�~���2��[�(�����V��E�f�u������b�5L��T,�5����4�^�b�d+��^��]�0�J#`���,����X,z5����4��zY,v]�l+M=�$\L�V�x.��������p���X�0�J��H����V
���p1���bq@.
7L�R@.��������b��U���\�\�Z�[�8.���X���#�b��U���\��\�Z�[	�8.���X�\��f�*���)���e�5#����<�*���3�b��U���x�s�k�n-���b:Q���r�B���{U�xE.^�\�Z�[+r�J����b��\�.��^u,F.^�\�Z�[r�J��N�b��\�1.6O�6��-���e��#o���\�*���;�b�tkG.��\�Z�[;r�N��N�b��\�.�-_U,>����[�[r����:��;|���i�W
�g�����[s��H}�����X��9"z5����KnD��b�0����"��F���c1<GD�f�u�5c����X�0��=��I����X��9"z5�����nDo�����������8:c���=���W��:����F�f,n�n���"�I��N�b�����,�N�f,����[��Q�>���9�U,!_�������u7�7cq�tk�:�O�ut�`�'�WE�f�u�5c����X�0���E��~�5X������$NO{��X��7�7cq�tk������i�U,����p1m��b1������
��9"��G�
���8.��_U,������e����I����X����b��U�b,��g������\L�o�9X���x&\L���X�\<���o�n-�������U,^��������X~#z3�L�V�b������*���+�b�V�b����[�[r1i�qt�`�7���p1m�b1�����-��
����8:y���;r�F����U�+pDo������\L�p=X���xg\l�na	���X�2�:��I����X�\|0.�N����@.��o�����\J.���p�e��k��E��2-���s�zY4�������X4k[�[�0�������\�,��B]�`?�D�������o����^����~���������B��?}���O?�����q��������"�?,�������?���?_��?�#N�G�<����������$K�����������������_�	���ot�R�� e�\F����l���7�������R:������W�/�������%����X���oUA��x�'���_��T}v|��7z����vtXc#�TE�������F|���N�E�}��e�MJ�/:;:����	���~��JKhY�R%�i�"��M����(Q������*�����^)	-���"���};�e��W��_qvtFc�d������.�� r3�n���Q������:���U��Pe
^{\<�a�]�jh�
7E�f�y��"$����+�e
����,�9���"���<���7��t�6x�"��SP��#o���O�=�������W:B��#�Y�sJY����@0��X��!��!�JGhY���#�wN@)j�����A(��e�a���D�*[�Xk�{6�a��vj�7���X�`7���������;x�����
s��m�Q��vt&c�=<AD�b�u��zx�����
���/�Q��vt"c�{�QE�b�u��������
���O�Q?���<�:C�*z����u��x���&v�$k�<����N���T��l�d�c���A��0�ZG8M)�5����u�$U�*['Y����a�*7L���G���mG'1V1x�$U���]�-k�A��=�0�Z�C��qmG�0V18 ���T��58 �,�9�������p0��X���t��Z����|����G��H8��`�bpB�:_�-kpBNY�s�IY�rp"L'0V1xFN:_i-k��<g9��I'e
���g��t�b���g���t��5xA���2�Z����t�b���E��+��e
^���<�L�V���p0��X��9x�9�Jha����,�9����r�J8�N^�b���6O�6��-��wN8)k����s��#������9x�r���M
��36O���]��+M�e
>���,�9����r��8�:��:��C��+=�E
�:�`�{6�a��uj$L'.V1��^�`�$ks��"�lp�$ks	5���,z�����{\�,�9����8XDk['Y�����I��w�xY�&Y[,�5���������I����xyn�dmC�	�I�U��E�b�u��
��"�lp�$kj$L�,V1x����I�6���t��I�6��p0��X��i@�	['Y�,r�7L��iC������*�`��l�dm98d9xh�dm980�N���t���Y����<4L����'Y98�|�����	98f9xh�d%��D8��V�bpBN:_i�,k����<�L�f���p0�X��9x�9�J�ga����,-��9x&����9x�9�J�gY���%��C�$kE^'�$kE^u���Y��9x�sp�$kE^	'�$kC^u���Y��
9x�sp�$kC�'�$kG�t���Y��9x�r��2����w���<�:��w���I��|d9xl�d����d�d���`�$k��rd9xl�d�L�����I���D���]i�,k���x����ih��q�"Z3�:��<AD�b�u���������NMC�=�����L^�=<AD�b�u��� �;5

�{������u������^�`�$k�!H�g�&Y��P�>��w�I�>@�*z����}� U��
n�d����y���N���G��Q�Wz=�<B�*r�7L��qC���^�Y'Y�I��U�N�vl��g�&Y���F}^�����}�$U�*['Y;������S�$k�����w�I����`�$k���{6�a��G�`RZ�;�$k����p�y���5"�lp�$+!����'Y	98�|�������)��S�$kF&�5�3O�f��Y��+U�e
���{6�e�� ������9x�9��7�b0V�����-��9���xg�d��������I���F��
n�d������;�$kC^u��M���5"�lp�$kC&�5��'Yr��s0=oR�`���g�[&Y;r0����<����w���y�*ce��=�2�:��Io�w�I��|�L���0�����,��I���h�`�$����E�b�u�ut;.^��C�$�p=j$������^�`�$�p��"�lp�$��52�N�,z�E��I�=���=;�0�:��[GYG����[��8��p$,z�7���~C����u�u@��Ws�:�:@a�{v�a�uj$(����c����i�1�zY
��c����i�1�^�a�8��<�^�C�8���E���u�uL��Ws�:�z s\�<
7����4
{�<�H�A�aG���qq8�q�a�uD��@p�[ZGD�:;z����y8fy8�L��p$<����<��GZ	y8ey8����p"<��#�y816��f��9���e�5#����3�yx&<L��TqxA^�<[fZ���x�<�Z������I�W��%���e��"���{�LkE^	��'U����,�����<���3�
yx#<LO�TqxG��<[fZ;��Nx�7��v����0=~R�a��=���e�u ���{�L�@>��'U>���<���\�y\B���q�� ��C��Ws�8�zP��!r�{v�]��:��F}p���3�y#8��lMz���Pbs�{r8���$��Q�\�{�L�u�G��pMz����bs�{v�]�� iE��_�gZ��8��tMz���Pcs�{v�]�� iF��_�gZjp�'�5��*C��M���v����I����3�58<����J�������p�L�A�I���3�58<���J�\=UoWm:<
�Q���L�A^�'2a�A��0T����n�i�.x������q�� y8�GP�8��C��S�L��.��I���3�y����0=�R���<�<�2���������VB�����*'�������VB&�6~0��f��Dx�A����<<gy�u-C�������<���g�����@<g��u-S�������<�Z��F�����D�d��u-c������<�Z�W���J���,��e��!�j?��Z2�F��C�b��L�e��u-������|�nk��P�(��P�X�#�Y(v]�d�@*&�6~4O����P1=�R�����R��ZF[b1)���u���C�	��(5,v`���X�0�zx��H���u��p���,����.���[��(�p�hn9\,z5���-�{\=���[��j�b�t�y�b��Yl�n=�������5L�>� �'\<Z�[�.�������\�<����I�x�N��\,z5���-7����
�-7z���:�r#p��U,��Q�X<����
�-7u(�q�u��&�b��Yl�n�	�X�f,n�n�iG���'�t��-&\LO�T�8 �<�������p�d�n��\�#)U,���1���a��"rq$\<��[�8.�gR�X���c��]�t+!'���y�����bz(���3rqR��e�5#���'�tkF.�	�C)u,F.�.n�n-��3���<�Z�����PJ���%���e��"/��'�tkE.^��[+r���b�2����W���y��!o�����
�x�s�o�nm���b�tkG.��C)U,����<�����\�3.6O����p1=�R�����s�o�n����`�n���bz(���������b�0������7��������_���t�PJ����7cq�t��"I����w�������������
�-�'I�p|�N�������,�N�<����f,n�n�~@���_��-�C�*z5���-587���[~�(R���u���WE�f�u������lq�0��c�"���>X�[~�|U�j[�[�pnz37L����H}������<Z���t�PJ��	��7cq�t�O+����~��fkq�|U�*�C)U,�*�����
�-��I!�������p1=�R���\�\�7L�|D.&�8>Z�[>"G���PJ�rq�sq�2�J����G�t+!'���PJ���S�������\L:q|4O�f���p1=�R���xF.��o�����\�.��hLzq~��]^����\J�D�%����R�5xE0&�8>��[+��J���J�b��`�f�����#�V���
�x%XL��T1xC,��X|��tY�7�bR���y��#o�����x�B�}/�e
��I'������H�3$6�D�=����J�5�@ &�8_�m�| ��i����������w���Y3�:��;�a��lj��������6����H`8YGZ������V��E��������=J$�����^�`�@�����73����C�e	���%�;��������~���>���� �����?�����?���?�!~��?>~��/�x���������O?~��W�����S����]�bI�]������O����n��|�_v.��~�G�����;z.��G~���k]
��5����@����+D�f�u��O=.�r�����������	�B�j[g{}p�x�F[C��E����0V18 W���^�+B~��a��G����a�bpD���+���>"W������^�,������	�"1������/�)�
��~F�Hd��)�5x��5�����g{3������-��yG�d��B2P�����d����b��k��lp�poYQ#�`�p����+r�B���9�*���k��[�{+r�J6�.�q)l0r�J8���b���f9���&e
���7��v��KY�7���p0=�S��9x�r���M��#�d��<����w���N����,�9����r�N6����9� L��T1�@>�|�T��]�K��`<t�����I��"��lp�$kp5�sah�b�<@D�f�u�5`���=�0�����0�y���~@��	����b0������
���o�Q��J{��C�*r� �:��<D��
n�d
���I��u����"W3�:��:D��
n�d
CB���T��X�`RE�f�u�5`q��=�0�F`8����X���T��l�d
X"z��y&Y���B��<A�*r5����KCD����I�z��OH�m�U���pp�N���g�&YCD&�!�k���98N�I���!��lp�$+"����X���	'�$�BD����IVB&�!�g���3rpbl�daY��=�2����IcmY�b��<36O��*D��
n�d-���/�v,�19x!3����1�BD����I��L�Bh�b�W���L����,�	�g�[&Yr0�
���U���72���#����?�����������7M��/�C�9x����o�����/�������5��:
�����w�����?������/�����>����������s�f|�'qz.�B�S]��l�ID������'�����C"���"��'�����aY�p*�=�| �C�\?rCuH�9[DA0��?5(���{�a�S����	���x�d����� j8�)�UY��������}}����>� ����������'1�P��OGQno5��D���F�W�Vj��$�:H�Dn�O"���(���(������B��&(e0M[Q���_��Y����P�H������X�`<�2���i+j\P�����*����Jy9N/l0J��R��5&�H���i+��0n��R^����R�����4mE����P
���b0J��������,�<<�2>9��^�������I�L(\�O'Sn�`�O�I����~����'��b��t<��/��$�������^[�.UQ����gB��&d[|����qE���mP-�Iub���Q���!��g�-c���5�[�?���������s\�
N=.^6�-c��F����q�=���	�8rF��Y�f���0ntn���y~�3����]�������,Y������b���n��y�����f�o����������$J���/������?qM��A�~f�������.h��h��U�_\���U}��I�xA9�^,dW�e�E�R8�D���Q��6]�L��~q�Y�d���g���8�D���������&��v};gqX�H�F�/e��[�����������q�skFD��";�#��c�����	�a$"o�
��_�]���%�������	�V��7w��h��������r�[;YD�����{����0m��:x?�'g_JZ�9;a��H��^vS����}L�:�k�j8�z��
>^J.+:����H��^v7����G�������CmY�y)�����_���d��*:��zD�[�_�e���];M=�Dw�>�|�����O���#��G���
���h����o�����~�=(�����w�������pAd�.A�I:?�/.�k����9���7L��P�~
��-���>c����
�0��8*W$+
����
'�����7n����*LR��dP���������/����������G��W���&�=���{���'u@�"�s<n�}�otJp`G�������=.@!^2�o�25w���D���y������v,j��w������^ YI�������/q/_b��K������I>����@��_�E?=������w����\n��������]?2���t�}�8����������� ^e�����������O����Y�/�������HI$����Y	9�0�Oa����CL����X��_j�}����}a�>��X[Br�������l������]��K��8rc������98/r���}��i���/��}7K�P����*�:����e�<�J*y���*K�a��}7Kq�J�4v���������=+s��t}���?v������^%j���_Q��
���U���E.Q�-3����=��t���%�*��!�8����u�nCu��(Wc�F|�
�p�#�h"���[U��������Z�:K1������}KwQVW�������!FJ���X��}��O����4q�|��>u����a�������}����t�����D�w�}���n����xA� M�uq����}�c?Y==
2�VJt_<=}�u�rr����o<=
�|y'eS�w��/��np��/h��G��*�������u�������z#_���'��}�Wgr�:*�������u�g�DY�.0I[�c/����f�v�������7���cn�Z����`��77L:D���0�<<�7�{�����������+�Em�\���E�����"^������:x}�����^;�����\��q�_��_���~��6��^1��_�����FN������q������g��������)��W���;]8�7�������?�����?|�'�s��?�����yx���{���?������[��?J�_a���m�����#���v�%����P!��H�N?�Q�����lS������p���'��C��K��jE�	j��<W�w#�#N_AP�k�w`����Fc����(%���/��0�;r���+r����bw��#h�.$9�h��p>A���e���Q����W~�Kb�=~Q�P�6��bDup�Q�*��-s��
�� r�)6�1z�y��}����`�B�f~dR���}��J�^�<���Aup�pg�����Bq+��oz��TY�������PUY��m3�b�����6��6v}���m(���cO�*K�S�D��t�NA]\��}a������������GAq;�#g����+�������U>u+��������r��,]�SPW��@q��qO�.�X�m@c�����)(�oN���a�[��@��,��SP�<��pb����<���<���<_��?���|-?M��&�:��\�1���H�7�-t��A�(b_w����W�� �	\�u��O�<j���i+r����T�����Q�"���*����V7�����8������j��#�=�����\Irv�y(r��a����s�CC�P�X�P�8|�+��K�
�'���PA����CU7��y���Kr�?��s�0J>�O����'g������'�C���������w��I�c�����W��n�N�7����������[��p�P!	�HiT��[T	��U������N�����I9u�w������O}-U)�N���^��U�	.[���o�����JoY�/��_�]�����$�"Wye���}�������w�A���@7���;� ���7��?C�����y\�l�����r�/P���>��-�2�/@��Q�.6���������O�&z�����e����"*nEq1�Suz�E��L�M���Q��2���<i�m���qc����U�WCu;�����'WP\Dqd0���n���Q�@�`
m�8������������v��s	�7���������^f{����a���@m��_������
?���G���o����4�����������e�7P�K���y��u�<��41��b�>�J��Sxm8c��
7����;C
�[(<��7b�P���1�i�<��+\�0����w&�����7�+�,p��#��~���e1P���H�OO�E
b�nu�����\,|���=�<��}'O�
M57���3��V���0�)j�8�E��;|�x��w��o�'y��w�J��*�}���
Q<$]��n�Vy�^��C��$#�Jzc���6X�!{�������6h���G�����_���pz�Du;�#������Q����3p�@r�Q]�RA����}/A,�x�^��@u���_^��gQ���Zm���Fu@�"��@����(��S2����������,]�7@'�1�U�@I�*KW���;P�NF�K{4���Ut��`T���/l\Q���_�q	_�~��~����&WY���9(.�8r������t�>��DC�mw7��SbcK���	���W�p}���{�(�������{�����xm�x?�I|��
�Z>����8����+�;���d���/�w���y b��Vd��9���5:l�B������_I��P=��=a���w��/!T��Fq.����kC�Z6C��M���Oul�a�g�C��*��C7���>�Y:L�{R;t�
�B����'!2{}��t.��rw���2�F�K������:K7�Sc����q���8|h����~M�,>5F=��cw��8<�(j�������hO�2��6PH���Ze����u���������@EQ�,]������D��t��
�;p��m<v9���a��������9����L�$��3��v&0����l���G'>��a����������-9{8���m����������8Q�P(\0������q�CM�n��^��?����&T���}'qj��������U������J*?�����%��a�fO?<l�}�w��ld�\�o�����0
9M���Y�K�'7��/1^5���K|���T^��������*�����Jue����E�7���6]�\�Gu�:v��8\��=��/����������\b��O��z���x�+[�K�#8������~T7�E��)b��7u(������k,�b�{�Xg�"�#7��?u�"�L�,]p(��[2_�guE��)b��K(N?��iC�����"������(.z�����E��E��t�������1���������W��q��8r�����t	�s�\e��O�Gq�{<��x�.>?\�.N���\o�&�aC�_���������\���#�������5�����0b<������F��,aQg���J�Wf	�8�o���A bO�K�UVo����HVR�2���F�6������2?���XP��h�H���W�l,j���k+r6�y8� b�e:yx������Ur����W�*._?�Q�����{��7�{G��\��"��wx���|���+�P������P8w;D�C��!
�e�mt�Q=
=�%_��!�>��<DQ��D����vZ�s����|^�GSf�$b�6���^����	���}�B[���6��N�=����$[����:<�7��{,�,s^�aM���_�+���x�v�:b�����D������P\�����}o_������j��g�f���!�����YE��[|e�r�� r�o���[���2�%P������-���%@�����MCu��l(��#cc��(�ouyLZ���x�L�k[�G%�:H�'rh�Qt��wxG�i	@��;�8��U��zC��Q�~��Sw��������O�<�������g����\e����y�"�[P��k��bz���o�CD
;j�nB���]���R�&Y9|Ph,~���pm	�1D� ������n�d�P{�A�+bO�w�{��(t��H�w���j��6{��"`�
�G��K���Y'��DT������;�Tf��k��}�6�f���;�ds��#��/��x���d@��7���XR6����"��_����;�%�6��E�?rL��zx�d���"��/�O��1+��k��"7J��5�[�i@����_&6�����m���8|����j��!"^y��>�����Z\b��$�N�C���7����H����#d����2���F�K����I��V��E�{�'d����W���m���n����kuW����B�3~U�����:���J��?I�k�H��[�PP$J�W�B�T'qp�A���}*��{�Bn��^��7��"�~�-�cp��KFXx�KQe�vw��l�}��$nCq�.���5�����]���nX^\�_�rc��=����_������:����x|+��>U�=��z�]7��:�0%x�m�����xEw�G����[�q�F�xAd:�����V����>j"Wy	���:���J����J1n��*T����{wJ��V�������_[����6������t���Q���U�6��^H���-j�
7�D���y�Q�"^y����b��p%�Q�����n�I�����n�(�Q}��VMV�U�������A�[�����n�V���ZU��s�q7q��	Y�������Z��sX�����S�j�k�V�8�0Q�N����$g�J�	����?�:7�J>&������>�{����A��?���?�����?������_���~�����������O?~����	��'�vy{��K���eBY�gf�������B������7���~8���F�����go�J������-�"Wy�������P0���goI.���e��:H�E���w�����{��.��O�_�0�m����)���
�(����`�T�*�/��p�{h�n��S���]����}�����8�oQ���O�2�Y��{\��Y��?��Wr	Y��:����,��<����I��=���suk�?����d�F��!��������:��[Il�]m���V�jKW���I��J�_S���'q	�����=���A�,r���}_�y���UW��:$"r���}_�$nFq����o�Y�-�T{�:��{G������p�U�*KW���[P�~������W�~����y��I��������{v�bx�-������^��%����p��P�0s�������4~��qpXP����p���N��U?0��_�B'/P|�S��lw��@��l����[��N^����6=Oa����@mp$I����q�&��!�<nX�#r�X�������]9�����f�[���a/��l�q%���}��?q��z\���O^�������V�rO	x������i���3O^�����������s���	x��H��M�8C�%���Mz9���&��K�j���w�B{��r,��N�=�u�q%�X�E3��=�2p������b���N���>W�}�W������b�X��f%�h�����x�(n{�_�
�&�^[e�%��{����Q�����~E�[�L(�H|��d0<=P�AN��P�/e�'�8���P��������0M/������g?2��n�s�{��2d&��u�EuT�2"W�V�	
�����a�����������Kw�%a����{�Ze�vTGf������n����Y�>�k�S�D��v�O�����Mk�����"W[���L@���:�km����e"W[���LP��������.@�/r���~������v�D.�[����o��j�}�WN
�x;���GD�d�Z���y��5����`�Z��ml@��;����B5���5�����=-��-�y
�"����6�Q����_[��k�!���2�:�r�����S�P���>��(6����5�;p�����f�b;N}�����	��t����E6�Q����o^�����o^����� �����*���������F��s���mj6x`x������X1v������lp�D8�r������",�M
�pI�*,����v�P������4�_�6W�Y�BOP�{H�i��S�=�lS�88�q����>A�}�����q�o1� ���_�|�|��v������������A�s�or�m��Y��M����|�{�_�V/�M
"]D����U���Fu+�s�!k�,�M
�|�>R	���+u��
 �w���5z�mj;�Jzr��0	�Q��Q�ku]����.�:��J�xWY�
��fk����nr��1��M8;�h]�!��nFu�EO�xWY��%7 �Tg��Gu2�?w�v���]�1�������=n��6��^tE
;j����u����]���o��De6��.��2����]t-�|.>���IV�Oj�Y������v�E8����{~��[Y�B��W��C��M�����.l(�$+��?���������\4Z������������de�Ju,���(�B��S�+�^��~��_�U�
r��~?��������l��8x}��6����B�����������,������>CHS�>}��������=��3>�v�2��s�-w�v��:�������+[��������y�����D�����?��U�������6�x�|xfW���������uPf$b�-��
@V(]��*�����zf[�>�%�6���
9��W~��m�2�
P������Tz���&>�L��������[d7���;��nr�c��F�������ZG���;e�_��'�� .+z�&>�B��o�����&>����2���#���o���x�=@���[aG����:����^L�]|7|Y��� ��A����)��j7��E���t|{�m-T`-7������-�����F����nAu�w�	���&$UH����Z���~�'�'��O��V|�Q?����:��l�+��=G/W{�����������~�W����i*v��O����N�j/v/.�U�/.���H�L����Gu;��O���A�]�V�V[����Q<�D���{yzw���T�jKW}�>�;P����/���]��G_u�v�4A����.r����VQ�-]��oc�����K��.E��t���������K������Krx����������^:<t9�C���@���W'r���	�g.v��_�W�u����3�������:h5���p:Yy���7����2���+rh������W�W|��^[�1,(��+T2�7�8�j�o;�Vv����d�n��[(��E������_��[ q��pbo��On�8��E�+�9���tD����������TeSg\�K����:����Bq����Y-�����W\���3L+��}���"'�PDy��k��������J�����
�����7U�ou��V�}�����{���bl���!0�����_��N�={�eN�<�����>�=���b��G�:H�D�F�����8�D�;yz�VHSD��x�?P�O�\E]����_���t�JW��J_b�_�������p[�joN:�:?������}���RG�^����+�����������/�������*�Ne���#���1j�Aup�J�jw�����:H�D���w������p��(nQ����1P��o����P};�������	�W��
��;~C�? n�
?Q�-]�?�6eD�;�����e�|�?�nGu��k���	�7���U?��� ����B��Vg� ��NmO����T�dDfZ�P}%�/d~l������L��t���V[�b~��R��,�N�I��s�K�id�C��K�N�$�_����R�8R�����1��D�f�V��S�F���:��:����L�jKW����{�"��H����p�!���>]�b4�,]|A�����K7��	��t��`��`�@�����1�����z������1�y<�8>;�8�u("h=jx�L�7�,����:s�.t������p�����G�"�Fj�]]�8�k��-p6��o��5��I�]���q;l����
-�|i�YL"YY�Bs9~(??�>���88� j��Xv����`:Z�����=����+t�%��]bW���g��� n�Py�c���EqP��w���v8"���l�`������x���i.'����{��7�q&���@�:>p�/�f�=�����D�r����cnQ�?Z;������������}�K����$	��4���}�����?L��n[���h���hG':w��M�?t=<	�S���N���������7������$�I�����������0/��,���>~����������?����������?��W�������t��6��u�����|�w ������������������?�'^y@4�2�A��=YV��(H��s�Y; �oK�/�� q���92K��)o����~^�A���L��������'�+���ENy�8����/���K"J$�i����E�\� ���u���wtW���$�7J����(Q�h����Q��k�����)o�N"�����n�)��n�w�D.��$�(s��!*��2u�)�0|9������\��+��8��\������i�2��(��D��NX��#���@9
��"U����c�����:S���������j�V[��'Ql�-�~��~���M��KW��#��P����/w��]:<
$j���>���i���2L�k�N�K#U�nGu������Zm����Bup�u!w
���x�p!W
=�Z���.�i�w�O�4�8B�pa����.D��t/�C/�t�##�XAG����P�>L�|��I[�jKW�&.~��I{	�����E|%>Ul?]:k��~h��^�{9�C?]��4�����N�#a?U��*�u+hHj���������s�������!��
�Eq��&j��-�q���2_3���&���o;k[t�6���W
���|�������-�|3����
�:�7\����]���+�HV�������{�Em���/���L=i'���;-?�/���_��^�E��~�.��A�#���+t�E?-�� ������~���������5�N��8x���W�+rZ�a���}�����4-�J�*�������=P��<�;p�����gXx��e��U�g�:��Bvz��iy���6��
�3�A9-��_��M�U;�$���^>��:��x��A���K���������Fy[�m!>�xM������_r�/������|(���{�������_�>��}������Nc�����r���==���ww�z����|��_������+��������~(6%T�dQ>��k�9?�������{��t���:P���/�������:���q8~z�wM��	�����f�� q4�Z��c��'��/��y�"WaP��5��M-��N^�A��?�����I�Bo��.��\E�[����=.Q{��v��uB�����[�"��y���\�/�����}~�7�9���`�/����>?�m�ym���[�9:��s��=��%�k r_P�c��|�����:8u%r��$~+���|����+}��k��/�_z��_PFF��OY��W�=K�����]�>]���O�A<+Ow�.>Q���������O�������yS��X�c���y��*K���X:��qS�
���t3���k����(�_�=�����W��u}�����Y������!��a
}����se=\*$
M��0�/����]a����<�����A�M��|�&����(nq�*������:J��VBv��l���Av�G���TGq�=���^s�|���B�
���\{.���p)��c�y�l��8x���w������M��3;�P�g����U|�����l�����I�l��_w�R~S�w�7���K���4�|���/���������}S]�[l [�6�M��?_�xjA��
~��5��O�q��
����)ZEu�Cu������e���:x����qp�
��"^���~������$�UL]�
!7�t���kQr�o����Q��e�-�FP7��O/w���O������|��R�����������e6�N�"�]��`�Wn�B��)d�����K	?�K�.���S�1Z'q|��>E��s�~�������K�m
8�
�W@�?�Y���%�H�N���<�#$g�����ETG���/���Zm�j�%�:�wy�{�[B��������K7�.K>�K�N��_:�����.KFu�Gu�~h�=�$�CE�+W�Y������-��������������|T7��NU6��
��,j��+62���nXQ���l��;�J�`7�>�qR��N�~�6�n�<������>�qR��N#i����N}%����*�u�:M�&j�9��g�D���b4qU���HW���(.xG�����U��_��^�j�[��nj�������Nd>�9M�}%�@&k��pD�����7�HN~L�i�uGQ]�P����?���#����=�i}3����|-O�-�^?�i���{9�|H�$���]c�J�:���������}�o����������������W�CZ'q� j���0��&^��������Y�������`?q�CZ'q�8��CZ^a
�rH�/�:|9��z�O�1�CZ���:=����~��6%%�mz������"���O[_4�s��\x�������E����	���tzr���9TGD�;y,�Vx��'��}��y*��WROeb�����b<�����s����8���t������������:_b<��?������q���#s�/1���U�]����j�_�O�
kzX
D��MIz��YW�����8"���e��8�N�g�$�>>������a{��q2���zjqV
���Z��s��L�����Q�%��!\]:Jvr�����;�\������!TE�;��a
+j���~��k�A����n��U�jKW��������6��������
�����`N��s��?'��:{:�V[���^�1��fT�����1��m�����\?N��/h���WL�s �C�f�������O9
A���Cqpbxr��A��������5�xh �{B���Cq�6<�wt�������g!_�S�K���W���1�������o�
��9�l���7���K3�<�����c�tc�������jni=�����/�����������a�_���d�_��<�����vq���{P������v1=H\g���*��O`�!�'up�H�j�m�szP�������Gj�=��w�2O:T�o��E(U�s�[�{\�l����������������[������T���T��}��o�=����������?�����?����u=��������:Q�o�����~��u���7���p���������IfN���|5�
I�8���w��������������_����c���.���s$���F��}���C����%�;\��L�+�L�
��"�"Q�mP��%����A&#ru�7(Q���cC���s�r_��1`��p>�����-6(Al�����H,�-�<�8�Q�Z�\�������[
�K78���s��Y����t"WY���P�����Kz���%��Q��Ai����Y�jKW����"������pm�(L������aF
8������Ee�kB�z~��0��.Bq�N��W�+�]�6��]��I�c�����]����1m0#Z�*?u���;��m�{E�	�W�+>�l%����o"!]�H+�]���y�?��v�t�.��vQ(>l;~�K�������_���L���4��]Dvy�/�����	'�=�c?�\�.��D�����^���s�%�Z��7��D���D������|�����j�����(��@uh�'�]������w�t�yO�X�K��SL4��/��Q�����3@q����y�C���,����xD�}�%�[h�������Z�r�=9
(RG"��l��gp�{<��*��j���wc�'3��u��8�?��KQ$<�SNd�{ v��I�7����2$�[��kad�KM�dV�-+U���� o���U����T�Wr��6�]^��_��.�����������Aq��&j���>Y������������RQ�,],v����ap@�����v�����zO�;�(��R�O�.���U����fT�_/�_:|s:���H��t����^j���x�T�jKw}W��[��nEu������?�ZN���rJ�c�����@
������F���Jd@��D(S���<�E�i��L&*�)�
��M$k_����(nGq�����<��!y��2��3���xm��~�����������0��3�������F2���Xk����s���|��D��)���Q�<�>�M�x����M�TzS~��%�����:�_��iH7�C������������/��{8<��	�����wA"^���<0v������abT�Lr�����"gP�����y�x�5�����Xe�H��(��HaxZ����\��v����8a��h~'�����2��O2����{G����&���0�{��x�Q�:^�u}�k�_9����@��D����~���k����:�����2�Pd�"W�
T�_��8��p��q3����
MZ�Al8�$�{������p�\-�*VM{U���H����E���	
:y��&���D�jkW}��Aj"r���~������3_;����0���UY;�y��>���;��A"��;�	k�l4�������Z���=t��$��M�r��Az bq�nx�s7]���������/h�_�S�~�����w���l�pfBt+/O���������hc�m�C���u�wu�oD����-��������=�����^"Y��#�pev?A���8��b���~�8xt��w�^�����v���=y��IH�+Wz���d��}� ����I%�c�KI�7����~�8�8�������~����l�����_x�����IU���)
�7m~�}H�_�m{c|n�;��i����t��
��g?D�����������N{���Du���w���+�4/dR��Q��W2O�=��lR�88�?��\����-�������o����V��(E����%��+"��|��m&7WH�f�MJT'm�S1�|��5!������"�����|�n��0K8H^����k�D�������L��M�4�&%��S$K�t���� vP,i��X,^$�Gu�8�ZhT����P�!���k�a�������=���4u9��M�nFu,I�>V����l������:�9��\�|g1�����n�M��e��NA��]�P�>���s��Y�jkW�@����'Y M������:�$�S7�\u����7��
�����.^������xA~�"Nt�0�����D����2� n��Q��B�}��|79..8�U��_��������1,>Y�8X7�?���\O��}�Oo�����<)>y{T��R�����Y�*>��8H�&�=,��\���Dn~��������o��ux���v���>��@6^}����6�l~~k`�������z ���!e����C8$���G
��Bu���\������7>eP�����y���Nf��W�,��Au�5�y�����Q��=�����%�2����_��E��}���~!��<�+9�����-�^��l�$�/��x�~!��~E�[|����~!��GJ�g��`U�K��.:T�?D(���/Dup%J��{.�����s��/��Q��W�-�A�
���^�����uX�-r����2T�?�������O����_.uX&%r_q����J�>�E^u�Ai'����E���7�]?��Y�Tf�������g��:8(r���>������`�_;�E_��Y���k�����V2i�����&�l��������TG��[�6B+r���>����=n�<��N��Z�7^�E
��.�^w���EUP�W�Er����������Kpql;�t��U]e�vG"YY>��Ue�v���-p��uEq��V�+��? �,�Q����e���%�O�A�UY�������^�yC�:�
�c����U7Q������7v=<ir�m���� �������`�`o���:��b��:��� nA�}��`��s�Oy���_����������M�����A����������[�}���]?<n���+4����y��qS[�G�b&q�u��hK#��<�[�u�?�E��{���o��u����P�zS������y7������������^�#Xt���s�|�e�*�7L��N�y^�#�]����I�uq��iQ�����7N%��p����Y��� ��E��������M��~�HD�]���Z����R�Y��+��o��T�ld�����FG���"��P����A��!�i.$�MB�*����;�L:���������h��.��`��&^3���b�p)���u�} ���+��"7s���\���+C��.��d�������%�������o��\)s�e�����������B�'���h����{}�N��[�{^�QBu���/O�z����@W"��<{P+d�"��+�=���:%��}P7nr�_�+qI�/��_r����X;/�B���	dBY�.��:�@��>���(�����#~Q�}������`�gR�U\�rZ@d�g
i�������}Z.G�nr_A0e.��:H�'�f�7%�w��{?}#pqPfrS���x�����5������q���5�J�nr�#��F]\�`:��=����Z;�i���]��.T��:2~�W�����&W[����P��HS��wvH����1U�N��6TGF���G�A���Y����ai5�n�@�����������*�]���v;�#�G��:�nr���~�
��I�0�I=SWe��
J�jkW�:�;P���H�w���5���U�N�� 4���Y�
����zq�b���7(�����H	g�1�:22���8�T�s\O/��X���g��ze��3]���{�L���5W�	$P��(IP�+A�]*%�U���?��������A:C:	4��w�^I#if���Dg��8�m<�5Xz����a$:k�Z��[��j0���F)��e�Fp>
w#_P�Q�l6BH��DtF��5�1
w|A�m���7N���*�3��,����]�_�d�7��uS��U����|�EX{����;~�<�����!}���(P�G�;�s&��nl�8E��cD�>.�@�*Ds����o�t�Y�(������:E�������r��J�(]]�����;,t�'��W�4��-t�(������o:E�Ht����Q�x��{�?��ml�b_|���x�[�����0����W��d���>����������Z�m)��}��Z��km�����1�-�{��O��N|��F���1�<�����������1����Fp���s��c�$�
^����A!<��KZi����J�/_z���	���K��B����dW��B��Bx0��kXv��FL	�{����~�0����)+���!:��	��<�^[hKZ�f�7Ri�>���;�m�������*6��4m���@����o��8T{o������U��V�BTx�����b��W�4$F���y ��w����@$8������������N�����7���x�x7�Y�!2���=�1;�2��B��^
Ri�_�_}DW�����]�A$,��{��B�f>B�w��������!�k��)~���.$��Ij��X+~���m����=�Z���S}���'=[x�~�����P���T?���n����������KW���O�m|�+X���l4�0��F�<t8������3J���<z=��=�1��t����h��8��G�t�h6�����+�����}OKf\c4��[2���0_�Q*���a���D��i��&H���V�^g�������A%=uf�qRG)�������I�
��
�'s��X�Jp_Z��C&G	0���zs���JGB��C�J�j
���5D78�3d����$�
��	\����5:�n�!�=}�
��K��������������H
\����5������1%
w������?)��1����&N	\����5����X����FH������|:zm7!�_|My��k�|U�������������������s6&��n�>�a����b��<p��M73��,*0aD����9;,0U������BW�i�{.4U
^a�M.���m����~�&���n_�OtuE��T������X�H���y�Zvk�h���r���b]��T�����H������� ����u�K��&�����������0x>0���#�����G��1��>�|�����<s{�4���������������������0]��m?�S�7����X��7,�7|�KdnR>����J��B���y@�������G<������=�-Kk<��h(���Y�0��m;$	b%�k�+�2)n��qY}n���7:��� R�n�$��q��a\����$^h�EM�����o��^Dt����]H��������,���lh���+����X�X �g"�W�L�H�X�k
�����!��$� ���/V��8��0��x��kn<x4�����'�������H�>��qWa����7���N��������	�
W��OM�4����y����N�L����5D���~w�_�������wJo����
GSAt�
�-�'�T�Jpz�BO��T|�������FGp��[a����u��V;+�%�t[*W����n����n3��Z�h�pG_i3���
U�p��Qoq��s3x��q������WXU��s�D��Y�j�%�A]���������+[��������n$:+�w��+�`�w�uP@�*�3�N�}W8�ae�~��*���&��jD�����_�p5������:k���6��/W�w�:�'�<D7�N��������b�������y�a#����As�#iy����@V����q�<���(���hyn,�����(�G94f���$�[�x�xEX���~�q�<@7�����w[�	����:y��*'���������J��j@��h�)�����4.�\���#���G�?"0}����Z���g��t��4�O}�
��6�����{���O[�����V3���?�
/AY������	�~=L{\���9���lm�e|`{m6%�b��a���6�B�2J!"%[���������2�Q=W:�{���V���lM��%<�Ie�������L�C^����|V����^����P��B@��W��}�H�	�Ch������Xq�W������.I�^���./j&��=���q�mK3�ME���T����h�"O��!H"p���v��4����������?���������������������_���)�T
�(����8"���NO������u-b��u�	
��c��!�Xj�*C2XZj�8I����2�d��)�Bt��<)�-w��DM����K.��� :C�}:w��W���FJ>]Ot_Z���Ss�|���O���"r�y�a"�i����O@�z���U,%�Dp���'�EI>�J��=���0�1�����w�F�r3�����8��{tu���9j���n��B[.R���)m��x[iM	��|:��i��5��(��&v���Z�F~|�[�M$�
v��_���'���Nm��k���~	-�5�n��I���y@XM@hD���j���&:x[W���C"RT�������
���Am��,�8���Nj�6�F^E��]���k�)�P�Y1�;�]����1B�HQy��wX�Dt���[�I�7��`�
��7a6���':������cE������F��;�������tH�
\A��?������_���y�q�����_���_~�����Ka��Q������/����_�����g��������7n�p�#4d"sX��%�t4������������Z?��h_��#�������tz�L�/���@�}^�)���v�h�sdv���X�m�s[�-�!�-p�m�2<����1����^�j�%/�#���t.��-f�:��q��������tm����~\�j����=�U!������_Y��>����->Kz��%=�0��`�T���=����:��G��r��
�9����	pQ�*����}K��uP�
xM�����Q'x�����[�/t�J���dq��g���:�lv��Ri���q�*D�.=w?�����U�*O��|�[�)?b�G|5������{<��|�y�
�M{3����\�~����9���?|-���/L����L6�,N;�f��`U��F��s��P-p��
��@/6�$8^���>����4^Ez��!�"x��+V{�P+�B�����Y1��J�|+f��� `���8vh����"��Z��bvh���8i �c��w�K������b�;� <V�����F��R���h�f�5�6$�*?3U���
��5\���.��^t-�E��(��<�cxY����q�V�]����z�g�"E��n%�/7�+���E�+��w�o������[)e86���r���-dW���H��8�e��v�O��^&8D�[��:���Z�1�����TZQ�cc^_h�������"��yVi���H�1o�*��^:��F���=������O���n����J5b��M���_H��G^/�����4�����������z�/�=����w>��A������5�yl�����6x[��R��g��7T�u7����R�"��bX��Ql]���=���ZB��j����G�6[��a�����Z��1����}�=B�B9k������ 5�<�Y�w��i��a����H�`����~?J��C�`2t���$���$6\0�M� ��XG
-�15.��������3��OT+fy����8lJR+{B�K����J>�{<�)9t"�=�x�y8c����	���$���_L�\�<�2�-�NM$�ZKY���M;���$:]b�X���N�����������A�r�����_���F�zi�K��=��@�O�j	��i��A�!p�h�������A�\�(�5�+K��J6,t)�+���w���i��D7����t�-W�3Z07VX��$�9Gt_������}R�
LJ�Dl����qw��
�������@�k��8�8�H���:��&�(�H�CT����1�
�4:tg�s�c�7�W+�'Ite
��\��"�F?����%Y��z����,:N>������.�5�1(�.���ZI	>��X����{U�����r���������.�7�7`����i���e0����e�W�GPH:OPzIc/�]������Oh����Q���a��o��7��Jo�r�s}�s�Mv�~�]�=���m���A�_r�eq�6����.?&��ADL �#�C�/%/��E��r�v�%n��
{�(]����*�O�)��e���}.#�+���!�+X��L��)#�A����?b8�q22D��D��q{+]���?S���#���w�����%o@xCI*�e�o�y\��C��&2����8��G�K��������z����i��C�G��f<A`&x��j@����:��g�m�>"R^� �� uy�����yU^��x��(Ew�����^Ot,�zy�R���7�!\)hwN�!C^�lW��`�+#G���7�+\-G�����n":ch���U���W�w��z�j���a��B9
w=V����;�w@"�f�3�kV��$��%W�hA�w-J��B]�j��.2��
X�Z?���f�����-Dgh[u�I�C��+\���"�8��i��h��]�L��F��;s�`�6�3�_��w�����K�_���e
��,tI������dX-��hp�����r���\|�[
N]�ip���1@]�n�C�I�t�i"�"���V</���>Ff�u�.����65G1{8��7�bh����=x�4����D��z������F+���1���z�&Yh4k����Xo�o�}
�m|��� ��{������OTx��������~�|2l�����5�=58��[]�sy]X�����m��ai����{��W[�(~�&G?�8a�??��������]?.��'�>�����#�{-���|���wj�:�����j��u�/4&=���Z'j/���*��Z�XM�"i}����N�p����Y���'��Q3�����������2��X���W.UF�=�D�o����w*��m7����5����<e���!<Jmd�b
a5c���o�!3s�1��]1��7+�YM�H$E
�1�)p���[�
=��[ZJ��&m�c����:G�h$����������qg�*j�,��pi�cE�k�
<p=����c�7�>~��	��}-H�\W=���j��w+����8y��YS{�����0�����)���b�&����_�j�%�$�Ht���|����w�5I@�:�[�}�\�DtV���z ����DtF���J�3�W�.�&�����o����N�j�%�$�Lt������M�Z8�J�}�#�Z����>����x�����kQ�V��o�����7��H��]�Rp7@W[�5O�wo������{*y�6�3�����7�`h�L�c�}7������F�d�>��*��M�e��s7A�-p5����6;
Dg����6�x�MF,�;��@��+�w9�f�dF�
gV����7�l�dg�������;��X*�3z����B�l�SfK�4��&[,��l�V�d���Ye�I�[��Y��N?�������&H�����*��:��e����������O��.1��'�f�G�+��k
��7�m|6wM�E�j�E�+B����+89~�+�=��������N�au���tD�u����2��^*���)b�y"`Y;U��N�A�S�h��\kk�r$�Wql@�T_��<q�
�A.W��&@������_�o���F�J��Q����(�+�XV�$~�<�t���6aP�D�u���Y�O�����l����p����9#�T	�=�;����*=�SIp���O��R	p\��f���[���*�0����I�M�U[3����� y_F�n=��,���6��4="-*x��>6����N)�$���}�EY4v-Jj����C����?�GL?��]m���^-�|�b�������,E������{�����).���{�'�{"2��Y+��s6��������tF�����T�EpH;�7���iM�U{X�8�8�1v#x�u���Q���������Tv���s5!��N7c����v�����.���_���W�4����
qN�{�<<R���pF�zv|3���-�d���~"1�2�!���2V��8U[����V������L�|�<�gw�����9p��+�������:�$�����d4B6%dQ�FD7���-���nF�I�j�%i�1�n��_��Q��Gi�r7���wE���@���W�.�H�� ��ctp�z8��n$:��mO�����Q�x�]��Q��V;��[�*X�2�����7�j��h"��}�nDg�dE���@��&[�<�g��S����o�Mv�]A�����K^�q��/�3n���]_�D�w��?�n$:��8y���Ft��!��xRDteEt_'������
/��������h5������#D}��<"��7��}Q�����	Q�V����O��a�6����6�/��g �
�������D��$"#8��=QD���14F:��#"#8�
Fs\��
nz{�Y2c�iT�Y��$����
wF�jeI�d��^��}���+2i�w�7i��f�7��-����������Dd�U$v�w0q���L������mn�["���.��k�wO
����h���D��$�W����@�y�Mz��2��E��Kt�$�\�)���5��NVV�xMt�^�Nx4������|����Zh#�k?�s��`���o�+�5k�Oz��q���}O;f�{��N[��1�����:FO��.���;U<E��~���qZ^�caTf&O�
���O�����>���yn&�~��q�1c�&O�gbU|V�W+��v�v�E{m����+0\v��L��'(vc
���:��G+�?$�,R"���/������J��%KD�����t���F�j�%�WKt�s�F�W&�,�����fH�W��TDg����`
��a��qM����b :C�v�]1����]��R@W�D���N?�&&���[9�$���k&#�����4��&���5U�\�t�":�&;���n2��q�|�MDg�d���
7����K���� �����*�d�.��L!_�}W-Dg�d����7Y��ZU��/w�+p��;��'c�ne���z%:C�����MV����8��h�[��r�53����l���M�X>��6�b�����;��h{����f��>Y��Ue4�"���7�7�3'w}����������O�Y>����%
\����@GQ�d4JtV3�$��<QM\eFy�p7�Q�zz�b��7�f�'w��F����D���y'�n%:+Ovv�n��2�=�+�4�R�Dt���_'�W�RsW�����������c��_���8;���������*G���"_~lp�����_q��p���-�"U�\]�|�ub�
b�	d�1�8�7�p�
~LpQ*o���}K%��@ �����m��6�ck�0��ty�Z���e��&y_F|/F�����[�k+m5HN��#j����Ve��JGB�[�j��-�GZ��{�G�fFBG#
#�Ti��h��Q|x��/:��W#�*IKC_	��N�@�\tsI��g��^Xi��1E��^�	\$�����(��6�gL�;�4����B��VXi�c��lV
�}��Rh�*�{a�!o��aT	��/y��)p�hJ��<��gcTfYt��n%yV�����"yz\�����DB����}�ub"����
!r�wNC��a��%D��I�[�D^�i�e}���pZ�b)�-=C"�V�gn�'{G.,��g	�����7s����=���&t1�-8K���<W�<]Z6'{���F�j���a,�P���w���pX����;��X*G��x^s���T��	�'R���C<O�j���a,L�	�'r�i��k�g���	8i����O����x����;��X����<K�����<���w��� �'p��s'"o#yF<�������"yV���F�x����;��h��y�{]I��x���#N�?�C<O��v�k�k��F����6:��������]�j��::����o����F�6/��m�Mg��i������"���Yk���>�fN2���4���}��+��]+��$���i��q�c���T��&���1+	\��Cz�'2cvZ��J��1;-F����:D�~tC�7����7���<��7�`���0����[.�����!@��������8�c��jt�1��D�~Hp8���Q]�X�c	n#8m��s�c_�%���u6b&U��P����Z�T�Q�D� ����K�{����w���LtFM���
%W��	M>J�����w�$���/p�\��D��.�p��7	w�#:c��K��������rW��b5�+*����U`�W����B�j�%�NtH��Fy���?�p���+���%�� :c���wG�\���}��n :C�x���y��F@�%�Kt�����s��[x�-F��W<�S��o��1��D�u��\��`��G��#A�'�B���+�����o6����?6��/��u	��*��G�5�^��\��S-NY>�aw	�'�E)�'8���F`�f!��M�6Knb=8��h���ft�+�p����u��[���[��p{	���>0q#�J�3�4.3�y�f��������ED�7����K�D%<�+6#\Q-|���<#\a=����x����K.�%:T�lV��z!'"�w����\�tSA�������i��x�Nz���� :�����s��������y�A7;�g��g����{��.���(�������n���<C �&/��&yV����n�����U���
�R�F����Z�<�,���
��W#�tce�`5��]�BA�c�`5��Z�����t�1����=�'K����f0K�k�B��.��KZi��zM��<{n����m�z�����h�������������������t���D�g_1+��V��#M:'���������}������G��>|w�i�>"]_������*cM��#�'�����������
�bNo�����F�3�A��e!�d�0f�
�=��m��1t(��#�lu�tH��E�>��$�l8U��K_Qk�}c���]��s��,�qN���\_�Z�����W���7��\p}��\����{�e����N[m��Hk�//��Ik����n#:C�iuyK�]s)����K.;'��c�����X�F�YY��$��SZ��oI����
W�.��:����H�Y-��p��1.��b�a\����B�5.��z'�w�HtF/�����7Y�W�VV�;���+�3�qVC�$����zc����L��Dt������7Yo�d�E@)�j���������l0J2�"���0��W���F�d�Q�ic��w#b?�]����l4�t��I�[����:w���
W���6;! p��m<�&��X�5�%
w�
�����>���*k�K��y���Ov���N������/I��R�� �t��d��\��f����7�b�d�sG�l1|2k�K�V�d^�\��n��n5|2k�K�]\�����<	wO�U�.Vf�'w�]bPO����Q�$��ml�Y;�;W���Yo�h~Ew���Y
�����b!:��b����=Y�
thNw��:���������]�~H>~`��r^�Or�3��������
�c��]������`��4J�z�5�i�Fy�q���l>K�?������}�p�[] k���}��}\�>���}K]��ki�����)te�����C�k���2`�*��w
�����W�*ZRiD�)�)V�* ���J'�":������W�$/�{���'�"&"V,x�Z����@�J�g���V����w��:���F^��Q��H�5�>y���*�g�,���bz�W#/y����^�j��/��$y���/������K�����|^���3u�n%yVT/}c�k*�gL�O?�� ��O�D��LAe��O�l
tmA��y�$!�E�@�j��}a��	�'����[I�1�>�|I���3&��'r���u�{�z*
y��'d>i����+^���/��U���:KC��z�O��F��<c��9�<	y�#y���m���<���w��10�7�������������S���72�7��������������4�1����N�'t�y��3��'!�Y?���w��11�g����
MC�y�����0f��&K�w��13�7����cf<o�4z�{��
����DB�x�!�u���D�1������'{��y7�_���=���z]q���ID#��>�>b���|E���:b����&O����[����_�����~��>/����ua�6�me��k���;���g:G_��'�G�
���	���=R4��'%p�7O�6�����}���4fE�0D�������w��q������8D������-1��f� �)p�6���Fjst-2��=���x���q��Rm��	�i������G�zv����9$H�3���������0��{Gt�:�����!����4��j:����?���+�"����.��S��1s��a�|r�<0�����T�����?��?���_������������������_d���������L���_�����������Q���!����x�����������Rq�~�~���)���{�b��s���Dg5�{Hn��R���Z���}��':��������u���]U��Ez\���
�^A�Q����
D�G{��I�[	�h�n�������Q,f�k
�j���F]�D7�%�:���w�����r�Iv]1����GgS�;�1��Y�4��Dgt�;��hy�5FL��G'��ja��&��b��[S?��u�Z�Z��w�������r����<)�A���(����>����FB��}u����v�A];��s�>~`���(��\��9��&���@V�����tM 8�����tM 8�����j�cm��X�����:E��-���WK7Y�#y���l}R�l}BtXh����.�J��TZ+�^(Lx8������8cP�>��.
y.��2���I$t��F^z�0�m$�,�'�
tuM��a�f�.	y5�F���7$�Mt}
\���Ba�kJ�g��GGB���1�^�t#
y�|c��`�gI��H�q��s����V$��=�}a�H\�������X����;���J����9G=	yR*�W{��}ap�����;����5�}�lN%���ZCr���=�3j�qF�8��������WI�
�g�:��tJe	�!�-pw+K��ZY�+�%�xe�]��J��������3|������o�W�7~-q�V������y��23�r��������������c$�3�-��f�1��\-[���@�������w?<L�^�$��E���6 �x+_���2v���qly��x���z������1 �t[����D5H/&�������5�7���I!�.v�1)�I!3��v����
����Y�Z��RwV2�7��8�D�>^����r�qj���J�����](����b�`���	��S��N�2a����i��d]=`��A��o���-^��qOz
=�99���HgoI��K��n!:���*4�c����VY�RI�x��������`�/I.�'����{�t�+�������HB��'��'a��n&8�Br�<�M�z���Q���)h5��OA$:^b��b�NO����-F�fGt�qbNBNA���d6jZ,�-
ut8f�89������;���HB���L��.��4Y����Ra���O�E?NN�n�i�X��po����C�O���. 4>���������s/�%��u�� $-m��=��C��`Vb<�Eh�e(}����'1���!O�@93Z������
���-��|�
������$�
��
��G���m!������!�J�S�������������`���������m�yi�/���`��C�{�Z�x���$�Ui�dq����1���N��P� h�2%92�.�5y\z%?������s����.t��d�����B�4 ����,�i���:y�m�CXT��� ��rPt��i:H|�X�#������]����|�������p�����2�� {��p�s�������q���<Y!.!�r+�G���C
����m�I4�oV�c�L�����a����>��f�f����Z��$f���L��J����i����7��6�Y��f<�����R��\!�S�-�x*p 
�w���,I�^�2��5u��Z���3�:�GRg������(�L.W	�Z�b�3=p�E���T�H�:K\U�����u�~MvF�=����������S��O���r�����Ac#p�R�X<pHzZ��h��P�V��K�O�nt\W�SY�Q�:$����8�������P����9���&8=�]u�{:t�
u�&.	u����Q�I��y�Mz��t�f�&�~�UV�%
u#������>	u<MfCun�0�P�TD�'�S��4Y�y�Z����w�������<M�������:�7�w����U�l�ru�)
=t+�}'�(
��^Q��+�>��?6���k��<\�G�s���f�W�uE����%h�C�����o�����Zh,yw3���d:k�H�~�:Dt��B?��8�J�4Y%�iVz�~Y�j+�����.��}"���<d�����H��g�����b#���<���3&:��W#����<A�)x��l������?���K���w2D��(�$���{g��5�x�!���l��6��)�c#4�����m�<����Em��KC�G�������o#yF��_q+���A``^+��U��h����};�v�06�����
G�~�+�uoa���o���-��[��x��$�i)��/RvS �������x��]|6��w��_/Fg�]Q\�8x1&�*\y	<����p���B�����������u���:�Zh�*�+�������#x����1�����j�}�:�_���[��UV�
$\��)�/[�|��M$M1�!p-p�cM�D*
8F���Hu��:��|q1��������$<���v}�>j�=�^��GH�t"3�W��b�,��Zi����cD���M����1�
�����"�z�����4��P"p������J�Z��h|h�&��B�����2�)
 8�"��Q#��Jn�4}]"oPp�v�"���i���	&����J���]Ot��4�5��������o��*�N�Q�N]}����K�o'���t���[�g�U�R�I����������f�u���D7��Xi,y
�������V�8	u
/�F/�;�:�&��V�J��n!:�81�����ib��Tq�Z�w��P���5*����v���N?NN���i�d���$�Q4+p��:�&��$����]_��qrrd���d��j���Z�����O?0pg�|���P�T��'��@\���{p[75�����T-�4A��q��@��f�y5Xq�D��Ic����4N������h9���y,���" �w�+�(���������k�
w"���m��Q&W�]]�;������F%��F�9��M7Nt(��
weq�kJrg
-N�|&:<���]@�Vd�x�6z���*���m�k�������ncZ��[��W4���W�����+����5������]�j��}WP(%p���������I�}WP'��B��g�z�w7C"�,g7
w�}
���x������$�$�
��>����L�j����@�H��n!w_�2J���4�T���i�||���WH���i����4�/�?|M�����L��Z)^]�5����X��=�,��1M���!:�^FIl������X��F
o�u������2$������h(�q}5��n���)p}3I%2��QOcfL3V�D���G=�R_�H��;t�g�O����}��+�7���{���"�x��(���&y�/�������J�,��#F`��4?�B��k����ZK<G�Op#��a�F������4�1���Z�s(��s�c�Y�B�HZ���dg�U���r��	m��<�:���~>WC4yy u}Et������������FK�!��<���������
��7RCry9��@7��czw"���4������q�+�79�F�����b/��[�����w��;l��.u�\^Nt������M�1F=�R[�c�/�����������l�������^��	}]�~8�?0pgM���������(@�&+��8�Mf��}5x���$�5,@�z^vP��D��
!�>�1�+
H\�>�6O��CE�����l<���(�����s5|�U�����?���Y�Ow`��W6�J���R��p:�G�/R���
�x*>N���g�bX��T;�����}�P�Z9��FS
GpAt4������U"�3������m���L��a�^8Mtp�����{^��w_X3\�5n_X���5M��^���1U���`�%�i��v�
k"�b�_�B?����ct�u���>����4op����T? B�q����-QL���mf(9J�5���!�����E�E`�x*��2�(��L?��P6�t��#�c)v��$���q����b D�~"�+���o�u��)v�gO$���HO�����D�U���W%�U�{8K�t�\�������;�Gxehb�qKq;@���W�J�����Q��U�L�X�����?e�(v��A��q����#%P�����8(�:*;��P���v�E�6�@GeG��e�]r�!�T���H�#���������Q���u��
)��%���Q���&�!l-h5�����n$:=l����Op}�2O�V�=��V��n�[�y0�p����������~���WN��]+~����������o�����������c�����f���5�����@pz�������������=)�wy��ln�u�dB��Lh(��v��c�U��]N�{��JC�K�2�@�!�.���N�d�	�CA��(r�C�P��eh�F��+x���m��
��7����2f���3�Tu��[�x	��u��3��^Y��-����P2;��*V��C�6�u�OD��;cR��,Jt�2\���-����z2
%�/��!�Rc���g�f��1��t��ys����������1��(�4�m�N�+�Y��;*?��]��bD�@p��?n�K����	�w����Z�;=l�!�p�" p��,X�P�.p��+ �n%wF_�6Vo�o�x��O�2�{����^�{����?���~�[��������g���������FH#�������j8o�?n4�e���i��Ti����_�����+E��)��l����&O�&o��������������\Y\X_��*��W�n��P������_p*Jd����Dq!������P�$���":���|E��������+�W^��Dw^��^�H�.�r����f� �!p}3T������4��f��]��FV_�HY��������;���u?��������cid������������r?���r���8����Z����
�;���^"�1�Z��bId	���}�,�.H5F��9�=�����	������*���������[y
��Em�0��y����8��Q�%h��l�0�!\������}���"+bG\Fp��6�:�-�s���G�f\g���Q�\[��'h���k%�Va���=��k�������=W�@�*�=��Ffn 8��|�V���+�G

p��Wx�K
Z�KA�P)h+R��n-�@�x
'JA�p@x�5�b[�U�HA	yYA��(RP�CZV��e�e��Z��B��&���pq�SKA�o��&RP`�y��F&0����f��:'�Fo��x�����B����9#�-�kg=Bkj��p� %p�I��q'�{4{��;�F��Y���9���	.	wlv$p_�FEB�8@��w��yK���w�jH���{�6H��q9P"� A��'�#����.An�KA��u@	�7y�t����2�"
w� \������f�@W���K��f������{aVt��i��	8v���tu���j�"i�j�_�4�^��*;���'�p���)�5�%W�"�!:���r$=�,�������oAV�����	pS^���j��V�Yg�sI-�a B�	��<�&K&1��'D�E�i�-_���t��IKt��=��b5�6vL�Z����F_���]_�<�1%q���(����*U���:������/����x��&="rLK����*����DpJ���;d���Z:l�}.s�=Xf�w��	�];p,� �{..��tF��`�����	�t.F��a5qT1�Ne��M�[y�=��q��,\��nH�'�
�DA{<<���
qA�.��)��a+8GODp|Io�Kz���	��%��%�

�`�g[7A��\O�_ott��I����7��3G�_o���p���6��K���ak�5l��SO��[��=;�4j���w���4��F$�SUX�����
z�+	�C�c�R�z���#D=�jt�>:��C�����GA�T�"T�F��N�G�zJppO�#�N�!�0��#Z�>�y	y��P����y	O�a}�Rh`��4^����DG�����:��S��x�a���y,���~�
��<Xg���sx��'�D�u��B��*�h��Ml�G-[�~�UGzL�MB��n�_��%���������u��7z������\0 V�K
f-��w�\0�A�,p���������M�or�+��^I�
�S�������.�Xj�P3n*�����q���$f�"[-����[	\M�a
8�"� :�	�����b��e���&�z�F�2�EI�!Y#p����'���!F=g��zI�aX��U���}q$�K�������������-�"7T���	���C�+I+�%�pl?�
�]���&8hF�o���!�#h��5�dn���)���R�)�[��Y��ax��H��^[�j��!W7Z���MZ��������OBK�B]4ES(u|6���u,<��*)��(}������Xv8��.\���F��f��J�|i$�[�Du�h����o����xQ�H|�����	S�d���89B�C3)A��(9B��Q�$h�20q`��?����;":d['cb���h��f?�gX��c�Jr����X�j�9YQ��Yg*N&c����7� :��&Clb=@�p����1Y�H�;:��1Y���O�\����x�|����'c���M�'+N�d��m��'c���
M����dE�[}MRp��d���MW��/#B����~��/c�b���
�q��dLVtVW�$�q��dLV4gc�����1Y�Y�u����n%w_tL�U�������tL�������ES�4T��U�tP������5Dw��s���xf��6X&��Y@O�H�C�@�j�S��'��}�x�n$��?<n^�?^U�J������1�9���qHeM"3�B�=������A�j:&k]��+��i�
DOR����b
���q�tLD��/����Fq�tL�����7qV�y���-p���qtLG��=ZK�Dpp��N���E����
z-��|r��:6b��&��)!����.l�S7#"p��i�P7�.@�j�Y��$��
3��V�&
u��f]�y>u�|0���uqD%�x�l>(K�������x~��[���1���������s�z�&�����Q�������h~���I-�Qz8�H��L�����2u�ez`o����*�$c�G�4�M��Vm��82&�k!��O��"c"8H��[���*�����RG@��d��Ob�,�#c":\��MdL����X�?Q�d�� \m��K"�!3��DL�w��>?�!b&p�����������������O�������������������?������_��������������n���u�����������?�������o����O���o�$����\���<�AU`#�3�{��U"����E/���4�����><S���<��F�c
Nl�6��G�MU_����is�f�&x��W!/�r����y�;1E&�1�������$��H,�VP�����4�wW��_�_���k8M��O��3I3,�W[t������:�_���K�.4��8a�P�G�s0�&�Z�D����13������{p[�����r���+��FD�/�Fu��W�eGo�@;�JG��];n���V�m�ob����Nw����/F|�1��������m��H���	iz��������a}%c)���	R��;kpK�!�$p�6�Q����h���R`]����
Fz�q���79`�F�^9f��3p������qX�0���Pr���2��%���D���n#8CPr:u1���B�I�x�
z�|��F�&�n,���v:u#�������q�8���������wZ��|q�1L��K���K1r,��Q��'���-������7W�?N�h�4%��)���$��i�
�5��
��f/E����x��h��KA����t��EFp���z��Wx�m��>��lt'�tM��S]��Rh'���Bw
���}�
��@e��T�]�,�F&�����(N�����}�#�5,�k���O^^3���������+���WH����+���7��}�������p�\c��_�K��W`N`�V?�T;J��j��r�� �9�Q?b�=Y� �/�o�=�"�\�| ��`o�mq��K\3^����~g��2����m�|������Q����W�Q��!=:_L����~e��J$:W�Z:�x��I�
�@'}C�{pe�[d3B��L�t ��kf�h�%���tE���
�=N���p�^���G����g4�(�O-��{<���:���}���)���}��@��!�;�`!���U�K>��Z�3��S����U���EI�Jp_���t�p�l�J������C[/}�"�����7��i������p�~����dbnApJ���gV.<F=Te]��D�c��+S���eb.��o�����}$w��_�� VC�~��!@ p��N_�Jx���Y"�������0dx���xF���&:\s7�	�2g��fo�$��%�32����+^�
y���������xTFl�V���^�I�i�s���f�9�"N���:���J8��w��������R���=�Kk�����~M�_�F�_J�}\��UC&����/R���g������8�>_��u�#/N���7��}��X[��Fs�����d�<x<�[}nP��b���������G��q7�^�p�w�u�7�tO7N���Pv���v��@�J������c�l�t����D7�5�wo�2��#e�=�+@sg�`���d��ntDg�OZ��Y{o�Q���*�HY{�Dp_wH��=�.�z�����8����u�5���x	n-��	4ji���K��]���'8=���:>bV]�aE��P��j[���������<,n�����,I����9��rk�S��=�U_��k���}_�e�]�Z�������u!
�"e�����/����q]E��{� ��O����'8����}K���p�T���5Nl�C�cD�j��eu����G���7����fW��B'/���!@PY�<\�3X<�B^��S�K�g�N�'�=xxF	^���� r�7[�����<#w�\lCtSE���i�����M�^���b�W#�@�8������!���C�����
������<>�n�'2k_KV�/��}sV����=7C��}sq~��_�F�_K������CY��\�X�> � �����t��?���Q���K`3$��{o{�6��zd�)����y��wX��8�>��\�j����"Q��.����3�6���L����n��C&C�j�L�[o{��n��i�����`;v4���8Y{��*��;
���XY{�����Z��pAf��,���p��Yc��d�	n 8�/�z�����������S:z��L��=�n�*?C/)�u��)x�lz��
���R
�V�.u�������b�M�Q
n&8�OAe�
RPWD��t��i�]W�`�oC�`�{<d�����Mie�
RP�J.�����I�s�#�����{<\z����T�V�W��r�b������A$�v�ao�N�+���I�j�E�w��j#:C�y�EA�B�j�%xO��QV��&����1y�,�^q�[��w�Y6�i�������R4����;eu:w�I	\���
���m���YYo�����U8E4�"�f������:���Dg4x/�y��Qq(p�����
V�5�����<�fY��XU~�s��#����H^5Btt�z�%;�f{�d�!�*��+z�d�q���6x���Ofd���wCt�q���6��
����P��w}�����~�����'3g���w#d��]lv�M6ZM����'�n�n�O6~�d_U7�}�M���<w�����HS���x�MFog��84�-����"@�>�Q"�D��*@??�M�k��6�r
��}��++����Db��3u����}J�jY3*���.N��A��5�&�(Us��p���`�������XD�l��:Q�-Z����!���t�|��.�4j���J��.�Z��JG�@��Abz�w����A�JD�b�>�|��#((��
(���^-�8�|!����T��_���$��������9p C�k�6J'����m��Fw*�]L$}:��A���|����e&�7��#�X�F��}�_������L�U(��q����2�>��3e&�Xi)t_�Uf�z���n��=�������~�$���W��?�������^�\�������������o?�b���O?��O�����_�����������R*�&������;��/���?���^�27��c�����v���A�X�9D�(\�
k�����${����s�7Ni�
x'�^O����+�S�Cp8��N�~l��t��5�#��k�_X�w2[0+s�:�b�#?6�i!����Lr/�9����"l�x�o�����D�������\�Ft�=Y���;lF��q��&�����}w:w��
\����5���p�N��f#:C�c��L��8"A����c(f�&$�mS�;�b3�\Ft��F��������C���l�%
w��:�'sr��-Dg�d��l���*��&_���M���m�����!M�h�=o���7�*w�P*p5����o2�C���!V*p5���+����Xi{�y7�&�
g�cOt�M�X+��;�d�Qh�HJ�%��h�dM�r,�C�j����E�I���(�h�~�M�	�g
<Sp7�5���mvFvA�>#bO��HtF����)
w|A����.<I�6^����6�@�(p����b�q:����K>O�V���L��~�3	�wy��/�`�g����_P7=q��b�}Y��bY0l|�{c�$�������_:GY��CQ�W�����6��p�
Z/��2��u�h��uG�XmGS|BS��0���}�6+.����
���G��!8<M�rW����U���@V�O��S�����B�>.Jm�Upd����o&��X�(�����D[5U���+a��g���TCx����w[i�&�V��a���d�����jc!���G/kc�km�Sjc���1���3.���G|E:����(���om��U0Y�`�_��W���kU,�{m
'���p�k����1�6�|���������D��8����7zn+|���p�q�!�6�FZ�������1�v}���b*p��X�\�!z(f{�k":�;��i�3��Y�~x�/t?g]�o�T�U�At��
\?�f���9ru��S���`9G����W����7�S�Ap�DV�co����r���L�}����1t>��{�;c���av<��L��y�&�Y���K�jy��&���P�*���9.�C�\�j�%�0�JtF��t�8~@�j�%�01�5~�|������l�6�3��l�$��5W����8����j
���tu�����5���x�|�<�05����Z�����V��e�V%D���1�!h�%�Epxw�7��7��f�2���x\��j�����X�m�����j^���+�o����S��8�fL$Z��T�)k"a��������#�uq�%�U���\;�U���V����G x._��*]_������=�.����z�'Y}�\+��3�	����\@d�@0k�\�_P��dD����]�H���~�W�����������8�=����l��k
d���!<���o�!�4V�p��`~+^J�Z�1����)Ct����VKY�X��f�h'N�J����1D?I����0+����j H�[���B��ZD����d<W.N:�jGpzQ��C8��)��`��������;g��#���$��G�U�%<It</���:y� �MDg������o�8S.wcEtF��t�8cI�j�%/$:�n���.yi/�1�XA�:��,�����2�]�D7��x���!:>�����m����t1y����(�
�����C�Y�j�%O��JtF��O�n	�X�.p5������/(���|����w���'��D������J?����>,�\7���g9����=�\Eo���=��B*h1t{�q���<\
��O���y&8�P�[�����#�"R>���V�jQe^��3���_�7R�+���j�kM�O��mA*
=�pp��7��y&<��w?�����Z�<W�3�M��M��#~��bf�]��<m��R�9CF�7���\Xs�
8�F���i�+�b��1�2��H�ID�Ks�c�F�Hm����or'+�q~�����T��lj��q���Hm�cJ��[q���DV�N�����|+f`i�:)}�#e���N��F�Ub�y8�N��f����u�h�+�Mt� ��[$��ce��8A�e���LQ
����P�Y�gq2��Kd�#az�����+>?~lp[ApZ/���aTn-�_y&�������B�������]��aF��U��3+���n%:cF�����Y���w
&:��W�.yJ��f�3����6�)��5�h	����m0T�V>
w=�	���
�6�AQMh�cItF���}7��,p5���B��M6Z����+�������3s���w�6�&���s7�D�������b�M3�'��~9
wl�$p5��U�r7�m<[o���;Jx����~%<�%����%��������RpG	�fIx�������Xc��p���->�}��\YCm�JI������}��1fW�.��xR:t��m7�/�Xs'�]�t��>B�?0@b�yq0	��(�C8-��M��[�M���_�W�O��"#�{�����>h�4������^W�J���"F��^��7*<'�Tv�wQXT&Y���J=���0�t��:���(����F��5��c]��������1�#����t���S���*3�!_��q�?|M���oE�P��M_���(|D�7��5��~5F��t�\���E���A_����H�-���Cp+��{!�	D.zO9g�6"�����ew�X���b��W��b�pE�p��,��*���]����QO>b�y��I����,
i�|\��|�����W��|-��c���,	ROW���#_#:�#�"_3�q�k�KD�*�5������6�S��ei����e6����<N��:�2W��&oP@t��'B9i�C$���xzM��n&:#vs����31m�D���7����~�U����M�H ��������'}�K"�<������7�`h��I/QTDD�G���t�F�(��
0'n��w#o�Q?Q�@z��3n2�1����N�����pK�&D���]�"���:��D�������Y�6(�~�`�����]^�����:,�W�������Z	Q�b�~����9c*5��\�$��}��H�"D
K +���G�pMAp���E�@p���[�\�����V28N���VR��&��^$U������w[�������H��- ������9�x�*�P�x���Jh���VQ%t�5��G�Y�n�MUB������MJE�������m�n1�}���s�����+����6�Fs��YEt�4��������yS���N��&�F�A���b.��xcNz���c��H�7�W�t����x��Lz�0�k1��NS�f��������/��6�t;^h(����
�"i�n��r���f��4�Ke�b��:?�	\����U�F�kzfA�hT�=�	���G`���&��B�.�&�0��?&������dq���!��W�����D�ZY���'p�(w����GtV�B����A�w� D�}g4/vVJ�p�TFP�������~��o�-n��q�\Bt��U����Z�j�%Qt]Et�|�|��z�lg����)@B���N��>�;����]<H�\Q�U�-ge��p7���*yO
�[�N���=)���-��q�yR�@t|A����T����)�z��G������N���Y�{�ute��Tq���U�>�X��s����%b��V��
��(y'`u�Z��u�I��E����'��.��#{1��qW��1%����r�IV�A/x��>8E��OI�^U��/<S��5�)����T<?��|U@*�m_o�k*���_�������A����?�7���D6�Z��%�Gt�4[��_�T<��7�>A��I���1�p%���#:��Q4f�"��	����"�g��H�V*�l3�����T�N�����"�7z[+-e0R����@C1Zy��X�x�Kr������8V*� y��V*��v+�3��n�������I��	Z%����T|�}2�t�����,�9��v4�^|&o�
t+R)��P���P6�DV��UO�d����ju�J>�����6��8Cz������f�\J.
 ����
}����J�w���'�����/��+�������MX���� �����y���^'!��b%+��5<��9���'Yp��M�;@&�(%�� ��}K�� �h��c��+zMx��U�n,R���������a��|��J[)�$+��Ace��>�q��78��5@���QJ����STe�<E�~����G��*_���������0����������P/+���C�������!��HE���@7�=`�&}f�����	���]���5A�P�	��9�X!G�[
2���L}[����g���|v�:B����xE&]������z��=�x���M-O7����7���^��k���Yq���=���!�z���\q��WAg��q2W��J�@=6��%0�{�!��	(h�����0Cn��h��$�\oNt�\-����������� k�w��k�n&:C���k��n�+U�j�%��!:�����������YZo�4�-D�'6���}8����������k�>��YI�$���'p5���|%�����y����qe��n{�o
�}�w���_PV������������K����/���+-E�IC��v��.o���bHC��u�@�����\�@t�	\��h~E��[��Z
i�K>���x���l���������SR�}Wl���gg#��w�HtF�������MKi���"I�G�����X��$i��$
�]��������]��!���d�P+���b�Jv}G��>3�c�����>����#�~(#����c��Ei�Opkw��/a�uq@8����Q�q��������	pQtq�B��e���i\��6�Z��h����pf��8�8��T���J���x��c�4;�
�'��D��/��f�����.nPtqUl]\W|~DW<����ui����n�Wuq���T�������o0��%����r��������z��i���qfM+�_�q��=txj�L��7��
�a��Q�k-�Rk�<t���]��f�����H���42�+�W3!�a�����K[��K�����!�+p���kZJ�~�����R��������#��"w�y���q$�A��T=�TY���t���'�J��8�h�<p����K�1���>�s�C��SZ��L4�����5��VV�5F������4��s|c��<t(�w�50:_��]j
��n&:c�`�:'Ltld88#cm�
�pW�3T���Y��4��p�w�40a��P-DgT�V���D���W�.u�
r��1w������J�j����x�6�3�W�s���=���&�����x)�*�o�F�\��5R�;z�]�ky�^�=I(��k�3n2�9w+��us�F�}�9�3�Wuj����7Y�g���I�����N���7Y��~�lu�������t��j'��D�7
w�7�����X��t2SI��X���10��1T���2Z�����Vc�h~E�e�j�bg�w�.p�ilx����v_P�Q�uze�O6/(+�d��a��}v��27���4w3}����������wg�3���^�������2�E��3F]�-��n���R�0wu	m�Z]�����B�K�'J�q��MFS%�v����w�k�;{
�o���6��##=D�����8qJ�#�u1��^����6�"��R�@p��1/b\�����!��i|����x��3%�Z��GC�H��N8J]���,x�s�'��G��\Z��4+=!+*x��q��%����WZ�u	���R����K�OQ����G`>�|����������%�����b"G����o��kR���&�m����!�J����T��<��b��f��������������������������o?3���/g�O?��O����O��_�����g�=��.��o��#L�ZV�/����Ka�|�|��������?||�7�����z�������F�Z��V�&b2d5F2Rq	����o����p��]H.J':D����H�%��`���O��11��K��Q��I�c'T��x	��U��jK���S,p���;������l3��A�����-!������UaV�� �� uDei����&:f��R[b$����/#������I�C��9Zf�n �f?���(-��c�H�4�S5D��x1If#�(i.�[��HM7���@�B�.p�i�%�Jt�	�w�w�;!p�i��b���"���� ��w�[�z��d]����n�YM�������O�Mov}���d��3
L�p7�!v9{��eAt����eLOJ"�e�����^������>~`��*w��u��������Z\�l4����O����&8�,�)��E���j�g--�R�%�!�/x��CF�F\3���+��J�3+-�'�Js���it�������w�|3L������.�lt;]�v�m�a�G|=�ltu9^�{N�M�Y�z��/��s�K;�=8�--��v7V�g��f%��xl��y���N�j����B���W���5C�|�zZ��s<y���#�����=R��84C��V���������q�o%�9�3~�/ :$Z�{����p������R�dR#[��"e�9��g��8V� KG�z*���0���{��$��g	���U��>��la)�����	��C��J�-����'���&X�Z���S�3�g��u��,��ip��'(���#1N����gc����(y&�����.�X+�k�g�w�K ����6��� p����H�P������A���*�I��IIz!Z�~�e�j������������!~]��f+M��F��0���0��������V����!�"p5��w�!:�b9�����Z����'S�D�<��e����,/��kU���+hf���Y�|qe�t������Bn���NS����Fe���O�teF�xS
f�?=�������_��-��@��9B�'����qu�I�\�N�������	���}���J������V�)N"���!�6��DJ�n2���+=�:��J[�k���F*�R}3H'excE��2�L�����SR�C��y����<�<���R�M;�������$�?|-�V�/"_��7�Uld81��L�����&��x���i5�C��j�t
�<Rr����or��Z�H+��<�Ft�[	�'*<"%�	�;������^������7��d����-��E������}K3�
x+����h�[�u��� ���D��;
��:��8Vr �� �\Pe����:N&�J��%9Npx+l�(�N�@L���g�����	n$8����H5l��~�4�}5^t-�#W;�w':����	h��;���5�!��"���N/	9�����>;�!w���]l�C�R�j�%�Zt}Atz�2` @d�zd��]ri
��D�g2p����q.�y2�
tCIt_�_���>����[%�
�-C;�� ��0��27c����oG��$X���_�>WS��?r�bV��/�H	V���+Z�5;1�J�V��aK|'�Jp���&�(	V�k�����x���k"=�\Z?"���6l�~4�?q�����W����m*�Q�V�N��ny��zS:��L�+�md��2A��.�	�j?�Z����$$S�!���j~��?7_�����>^`'�~	m��w_�3��������[�~{�_����8�_������Y#@y
z#�Z�,��~�FC7�������H�_��	x3�-�]�S��d4WW��I#���Lz��)�Kx|[{�*��C|�DV<��0����[������e�����R��>�	��Pc��f��N�*1��r�@��	]h"�&���~	�w�j������o�!o����d���%��6}������F�������|��rh�7l���cR���V\�x>�����p�3��{�5&��%��mE�y���X�+\��h�����D���3p��� ������":�h>��'�������:�����%`�od�Z�(�QRc4=J�]�]��(������MxQ��D��!�}<>2wh�{��q�uy2oNt-��������wy�>�&��������1��|�j�#�,�p)���
�n��%�!&%h�%eIp���[F�e%���]Z��#%�o��d����^��R������}��^���z���Z��Yit@���V�`��o<%eIx�~nZ 2e��)�ZIYV��Q�GL��/'���M�k^�p���*E�+E���u�����)UH��Xy@tp����7�k'R�����	Z�tL>t�����HC�x\x��e^L3�D�>�g0R���6��o�!J�DV\���W��n�
|A�e�]%���7� B�4o�oN3nh'�~�j�X�B�CC�+\?[f������N1�rV����-$:��q�>N���F��#�������e�����p+�i���L�t!�.��8����=��$:3������F	��Z�~�����j�MLx��S*�����U/�:��
r��q��s w����n��n���x�����'�f�:�������$�$O�N��p��T�����0%O�]Y���l�<p�P�y��q�<�Ot#��1��m����x��K����\Et��t�uH�	\���S��n!���+qW9��f`'ogAtx�\��;�;�(��FI>e��V��:Q����<��G|����1���*�}�[�G�G��`�@V"��GApP��'�E�G"��-�����k����/��4'<��������?���/[���JO��F#u`R�d�'>�'c:�5�(�<���.�����*�hyD[���q����s����*X���(�_��#���?|-a��o��f9����c��	[@�x����j�%&l�c�� ��J��&G�]4!��M��{�uQ�����^���Y�j�W���V\Xh��[q������r D}}�Y�� 8D*��v
0��
�s����y�+
������"9�{�	\,��U���f��d�4���dVt���1�"p�:h���#� 8��j#���w��"���<?E�&�����.��`nB��I�:4���������&��W�o����j�m��Y&�������r{Y�����?�Q�U�����
��n'F��pBFO +�[#)'�p3�IA��(�e�C8T���Ko�lL|���������Lf��&2G�,O����n+_��1v�t~����g�bD����"��%����,���r�D������}n��=��+_���b��,�E����,�a��-n��k�����
����e&�U�+�s�) R���X��&��V9��d��q����~�+d^���s�����Ys�"�d��1��[q���pj���V\A����2��_|�.D���f��L�.f\�dRw���m^��4�����Yq��,@�.SPklU�E�Ht�r5F%fk,p��,��i�&A�j�K�����t����m���4(H%�_Y���3�Nlc�+>gS�
��R������U	\��he5����^���1o"��Z�w��j��X�+��:�4�������Vu�x�yS��J�q�����K�9�X *p��O:%���Qg%	�p7�>M�t������t�]���0��'��}�m�����%�S9
w+������++�3-������+!��o��k�����zm�r�0�\Atza���9�(NS�.^�~����������:8�W�.��xR�tUEt_������{4/N'&H��D>s�. N!���F���`�R�����$8������_W��h����H����;]�z��D?c����H�|�5GlDp���H\��9���m3��1�IP,5O	
���;�"���{}�+G�����V��������'�JWx*w���`?�o<Elx��$x��F�Ul�)b�!zk��]���v�N���d����w�u�F������j�?|M���o�����%���D	 v|�������E�Ap|�t��Jw�"	����J����F��	x%Ap���� :��W���M����"y�B���g�#BT��M�xD�V�jB��f��BtR	��4����h�N7����h��x$!�!K/p=+n��8��
 �� -!��4�#�"::���M^�Jp�DfCH��F����T�	���������1���]�9%������_Z�C�����K.h:��V�|z1�!*�����������,H�^�Atp�{k|s�|,�5��t�����-��q�\�Bt��b���k�3�@]rA���,p��;�d�|g�2I��Bt�Mf.l��#A�j�%�o2�?���i��������@����N?Q��M�]��c������'��5���h�����'Jod��R�Xb �J��:Q��@���.��@���5�����b�{�����������~#?��F�r����w?��!��$���`u#4�E�]�X���($�KD������q$A�g�Y-pQ$A��o��S��Zi������L�=��*	<&��^���_�����]+MuU�����J�a����H�otd�+�IPS\%A��$�)O�l��@F�*@���U�&����������-��t��|�@�K/�l9<v0z�}B#�1����\�p+\!A�&��"m+���r����j�� ]�:��x�G���H�nB��Y1G�
����������z����p
��4��D.c4�_O7����K����^���\�Yq,�@�� �w|U+G�CtH0�\���(h������l_J�����WU,��j(���7��,���+��'�J�;3p������?ZZ�����ZZ!���FGt���|��u\�������N�>����D�#q4�&��M<
�p�>}OtHT
\������n&:=Qy����/\��h��@�f>Sg���}7��:���\�\rCt�������-\�������~�%7�����7�bHn������t�o2sa�p�H����K.�!:�dF���}��DY
��M���V�~�����e3� �h~E(w�lFS��=Q��'�f���p��I��=���h.�^������O���5y�f��3UJ��w��o����cZ��3�����T��b���n5!��ji��#���7���,C�5c���!�4T�|<$G�Ep0���m����"8t��o�w���D�M(J��N���dX�j�����__����+��J�YP�}(��4����3s�����x����P`?��H���]u^����Nk���X�_�����\h������/����_��|f�o7R���,_7���� r��`V^����ndh#?���bsq�YE���[�m�/���(E��^������������N
�bvG�����Md�=�]�G��V��F�j���f����h��.oS+�a�.f<p�c���G�y�F�pk���f�q�_>Ha�&�2��c��@K��s�$L����1�5U�pL����#�>G���f����B{���h����������������3$�������e������K,j��5�������������6�@.^�F�k�}�:A��C�M�j�E�rG'xi���	.	w-�6-�l.m�&���6��u����{�z�&��C0W�>�bND�J����X������p+�'�/	Oo�PY�d�z��z�
��<^f��������Jt�ev�3�M��]���>:^fF����0������/^#'w#�<��{U$nQ����h�R���c�G�j���[0��q��Mt���Oe�K��&�e��������������"�d�C7�2��������B�����CyJ
�������B�ECz�_��H���� ���������/i 	q��N������!
d(�+E�vz�a`����t�iIq�w�Q%��_7�A���E���e�K�����(q���(R\�:��Kq��`)�q�����R\�x3F�Z�"Hq}px��7�o����D����iC����^M�bu��!�����o��+�4Z��=
��tY�J=�����v��v��><DZ������[p_�����v���?~|�������Z�1��Z��5���ysh|K��c�R���"��
ZC*;��oB��Rb����<=,�]��p>8D�m����A�&�%��fo�XD�e��8��PS��Z\mdy�sV��}�����_
8't�1�%�)k�@��� 2�$o����}����23��]ly�:F��:������v����T�/@r�feK#�������m�{�������a��<z_��}�O�����Se�����|vELj3ge��C����U�(We4�Q�)����m�c����Y}K^r��!e���s�7�������#����hFp6yK��1�����_�����C�
W#/����6��O���A�B�K������W�?[�x������'���v���}:���N>�� v�U�Z�|�-dnW��{����<h������j��dnO�"��J��{i��"%��n*����k���D2!�X�I���pq�����4�EI$��bz��8>V��~[����8�E������j��;N"����-����4�IW��J[�$+�L���&����h��H�� {_����Dr�$��������
^~|E��X�tF"���]�r"��~���Z
��*��E�,*,e��?X�-CC����:�����V��������'[	�������Xq9����P^L��+�����66��1����)4�W!m����
�A�<g��E��f�{��h�Z�P*����f\�N�F'Vo�XyV���,x�<kj� ^*�Q�TZ��cy�0Kn�������y������i}LN�<+�!'h��������6a��9��13��S�'�
t��v��6��
������4�����F
e��-��X�QoGU��R�-��q=["�P�|������e��:��������C�������MA���mv��G�9�����g%:>���G�M����Y��e��0����<��L�Ct
/���q�7���9���F~�<@�x���q�"pDB_0k��W�<+�Mx�\?�����g%Dhq�q�'N���V���8&�(yV����odqs"gC�g�,��}#<Z�l�l�4p�<+�-%�{��������V�j��d����W[��S����<+�md�������<�S���iyV|�X\?+ �ZU���s�T���Z]XQ�e_\�/{.bu��U�C����������������	�����w�����m��o����?�����),:�|�������|�|��%��
��tcH�
7���S*���>��'�7ki���m�C�B��w'�Mp��iUp^h�>A�
"�(�&�������� '�/G�O���o�������P�_������_?~._�����IS����FJF����ovt���S����^��w����8e�����B�� Z�����:
�F�RbEsz�h��#U�;A{\^�=K]����� ��}(b���zK��W��Yj��:/\m"e��+���Ke���71�^Icd��f���&��2��}�cb������|+n����|���W�&��I	W�~48�7G,�	@���k^����3���P�
:��@��~��q�z(�W���&M���4]�������
u�	�N�Z�C��6N����:���D��%�7����2�7��:�lLx)��yF��4��8�� ��y�g;�Lt�����c���x��^Y��8��:^m7y��(��7��bB���|]l7b��^�V�]^��� V��������
���V�e.���3��qR��8��}\�T0�Ah�Vo��Xu�ZL�j�'AHx�]�F��5����5"���MWz%�F�f�9r��n*Ri�nnv��f�SR���W���M��d���T�����
������<���_���/����{����UFM)�������-Ls�0�K�R���}�^_Rw�����K���+Ph&���������%����[#�������z�����fo����y��r���wQ���������U��u�$�SJ���}��������;����o�D��^�QZ���n��
l�����8Z����9���B:����*c���m��I��1�v�����|�w:T����~|:|�R����}�!���U��Vvy�xl�W�)��|1���O�*��z�^��&x�^����@�NwQwz�]>�z����=���G�d��#OK�j���Uj%vDt��0����j'�>��q"�ng�W���G���E������w8OJ�jm�?.W���g��'����r�v������w�����;�~��w7������dD�,En������o3���l�'p������k����~w���G;��������v��a�qw8Z�_�j;�q�t��	�W���QBQiv���x3�v�?�E��+�������JFG��q/��;|*!���6c���D�[�r��o��'v��/�wx�`�7�K���p�q�L-����aW���;%���n#��?���}w8�.�y;�.��2���O�98��+��������9X����� �,��+o0��D��J�S~������qo7�����������
��5��)�`����j������n��JT�����!���c��!��5v?p�-�h���_��+E@s��y������yW�#\�����+_��;jt���Lo)	���<b[�7��zl��k9�\���������u�DDJ�k���O��'���o%1�21~q]KB��'��?�;
�o�/C���"��=1��O
��:IE;��!nEE�F�Fk�����,j�=�����}�(z�":x�7`#���P�{}
���d��e�[Y�P��"�Hq)��i+���@����	���������6I��b�q�|o�2�
[y?wds5y�|���v(�W4^��e��f�[���Z�M�|�/��z(�}�,`������y}�������>q�fEL5<>�o�Na��������x=���Na�s���+��\��9�_m>r��%�o�����4;>�)�a�,�
�=�s�3���M������X����#�}������92'�������p��s>����3�����t#�5F���G[����
j���C���r*�82���%|���#�(�>fq�<�j�IT����
vW���kun�����m��O�	|D����w��+j#������/k@^�{��/�����~����T����j��*��k���{�����J��m�u2��n��������O�\?Y+�~|X������#��P����B����vY�~`�#�N?�b�]a�PLw`O�^�w���[���[��7^s����>_�����M��#������C�5��v����C��?4���&���=�����'�g�]��S#�#��HD�]cH�,p�O��N���"pN��)F��]���������V$t����R���z���v���Y��:>G��aA7��G�2��V�����9�p��^k��O��L�����Z^�20��$�<t���[h
G�n�����=��Y�����~����=������7����d������S�R�<5:`�1,`w�����������0��Z�����m�a�.���[B��������Z{�����[B}������?��WD|D�_�H�.��s;\~l�C�������"�^�DzO�v���K4J'�6��%RV�����:���`9�vZ*~�pCN�f�t����m75>8-T�t�d�t����_"0�r��?�^�@�
+7��41sKTE�������0�aKl|S�;�����$[^>���\t�B���#���}�����{��P���>.�G�k�.�������G+G�5�>�QMt�^u����d�����.=t�MB�pC������_=�/7�����(�[��Q-s�k��v�=����M;�)�w�rV���G<�'�����\�Y=�O������S��=d4l�~�V��"����,K�|�K��1?�nz|D�������2�$��/���y�Z���9������F��3�/1������m���n^��a;���]!�g�\��$�YrkW�|�6�~en�;��F�]#�]xTx�=��?�G���W�2����24,��}l��k�=���^�t����o�{H)7bC{�+XMm������u�w��������p� ����~��K�j^���\�������MK��������M�}@W~X����T w����=�y������W������k��"���=Z���?=t���+\�����9/�>w�p^4�{J�f��DDFD�{����~�j�$	u~�W��h|���T�)2���?�KE���=�����������3N�o�b���S�3�=�{��@ +��z��iv�?���3�9�<�6��i[��$��v��1S�mX�u^y�yl�m�n`�{����xU}��G<�'��
��>��n]����jt[7\��
�{�qb��'^l�[�����N{���-���._��=�n�*y����'��'n��u-Mi5^��p����X\�*��V�?������W�!�E��X��+d�*�jW�c����Elp�,�q�{����������2~^��E~.����"�x�(�������Dc�����r\]t����b=tHcn7`���+�</��s$T���a���V�@��M�lp����s�nq�l�������G0�/_�'��z�������nB�����
��m%�q�
���"H:B��/��/�����Ez�l��9�+��_!������m�������P6�!$p�+$yL��^ps`f�/�<j�
0���w\���h�E	l<.nc~���U���������\|�XVJc��*�����'VEQp���q���DwE����Mq��+;�����&G�������o�=/w�x��Y�{l���:8����)O�`���ON~D�-���}������Y����x�v��;���n���*�*��%0j�J����0c?����]A\)������w>���F����L����KQ]t��e��^<t<.���z���O����E��e/U
l=�������a�y����L �������a�"{9P�����7N�j���E
�\S����n2:����[�A�����m�<�\�Q-�����9�8l�\�j������D���{yq�(o�`���oN|��-;�]"��i���ao��~���!��E�D�{l[Al;�I���T�QEp�B2eU��hp�n�����z�KE�K�������� �
ztVC?����Z;����
\A��?������_���y�q�����_���_~��������,�e~���+�B���_��������J[��v�7����J�Zk?$�e���j�/W:OQ��?����*cz���-�~�����G��-��U�Y��O���y�~H6���{w�����7���"�	�d�.)�g����:�����k..�����b��d�.�v����������o|�2����EY����E���,��������F��^�%{}W�=���x�R�v�WV������>�7����4@��pi��-��|��W���]<Y
*^��>�����x���o�����2������'6%��������;@k�t����Uz�<Ne��J�������v*�]q����2��C�@$O���a�G<f��S��6�|������^���]���@VL0��^����g��U��'n�V��D�}���EF�W��Q��^���ot=�Q�=^>�.E�f/y���Ow��{�w��m9��x)�x��Z�[-9v���������xM;��i��n�9%����y\�y�7p���{��M�d�?�#�����������������7���"������@�����n
������D��D�'���������->�|�(���`�?�Cvxs�=RhC�WT���2��;��~�^���9H��;<t
_�>������Q�x�3��g8E����aw{��w�#���=�������%Zq��8����3,���)�J��3wwW��MA��K�R�Mk�;�����=�~'#Ph�s>�x+pw�����;�E�����=���'��Aq�a����$�Ga�����w��P�|���S����!�#pt����{��^w������e+j��S#�6n�uw{����\�x�s9�O�7?#�Lpz�%v��Uzd�s�F����fr�sx���s��k�����?�����U���N�x�����UG����[j�|�\s������b�Z)�V�N�5[�6��'+�[b�������}"�%�Kt-���U��8�;�a)A�_��������]?�������v���|���X�K��WK����{��n'��������G�������=���eF�o����7b^�����<p������M�w�����������;�������n���)���{B�Y�YkR�8�xx+�<t���o>{{�������[��~>J�jo{���w��s���@7���6�����@�)p���8�y{�
��h?�����w����"`.�J���5�w{ot�V}���&J��^ePT�A/W����NK����v�U��r��A&N���;-%4��">�#t�*�G���� ��o�J�Q���V�p�kd����i��D��|��`z��6D��L��Upfr�{a�k��U����\���Qvx�e'�
G9x�Q� ��P��3=yw����^��=~����5wwm����e���pw�;�����������������3=yw�?���������E���}v���+k��[��tlv���|��E��!�R�l���\���c�/��������V�
����v
�#��a���]�b���$�]y�n~�e�Ez�Z�
SF��E��s�8�g���7�xS��s�F�X��	����C�`�����3���3�y�<e�a��u���3y�
I�OW91��9D�-42��D�D����
96x)�^?�7����jx��c��#o�u�7�*f3grl���:Z	��+��6x�3kCHP���$y��:�93���+E�_2��oX�
a��\]h{b�����J����TE'��(fRr3���K��a(��su�U����3�
v����*�e|,���Q�G��!|�d�oX�
��
��o�F��'�op
�a
����m����lkv��|��r��=[��r����{l�s������_bU�������?b�GTj��t�>"8w��KU���XJ�K<?B��z���x~��l�}I�/Szk������{�"��Q�������I����5�M@g������'=���Fm���;�?4�I��=�������N���DI��l��u���I��!�(������?�����N�����E�����i�P?���oq���Y���74��!��W�o���������G�O�~1A��*~��U���������xe�Ka`��{�Q�1���F�����%2���|P��:�n�����^�����f�I�
9��"X&��{j����h�,G��3_���I��~���g:��5H�q����{��f����e����G�t��������S�yc`����������uQ~xU?6������-��m��ya�c�6���_�*n�+N�H
�{����_��i���p�?��L��GB���G�|�V�s�������r��Az��v$�T-�=\����/}��e����;��U��>NXVa5.����5����-�W�<��Gp���~��,m��������G?��.N��!��]���/����r{����q��ty����U������
S�y��3����
���I������[/5�}�����n�9���7x-����e�D����;���
�N�X|#_?Z��������b4~�����x������m@����_[��L���Lw��	��w_U)���F�uv7���o�*"�`��U���o����6���"��
�_�X��c	=�����!�������o��|"���oV�����m�����'��/K���[���7�K���"�P��B6Aa��r��m���Js�s������~Iw�A�C�������?�}��~R��R���������
��Y~?��m��N���tc�?��*4(+���>L�������h��Z�[���QPo���(�����pjQ^{��#�v�W�s�E.���~	��j�tM.?>�|����k�X�����X���#��K�����E(��^�g�!�)pt�S�@W�D�'$rl�J6������C����w�f������o~�!��
�0��
Wk���-�&j�|�u�|��:
�s�j�>��#X�*�������vnI��o^����nk�����������MqY�V�_�q��_������~]M�[����w��!���R�.vQ�]�I#�������p:���nk�{�qY���?�j���&�=��)�Ym�X�cR��w{��zQF��`�����~�R�'�d0����H��-���m���V�Vv@�X +���Wv��M�7X��W��2)`�2��c���o��x_���������o����a���~����t�����V2��+��5b����&>:F��.w��H�Y��=X�	�f��l��*pI��(T������e�� [K*��y�����Fe��-O���i ���mZ������&.4z�m�c��P+
��T5k���<�/l]\l|`�L��v(M�{�-���Y3���BW��V���X���/lQ�|��'�M���Goz����@
���W��Nb�X
�1Y-���x� W1H.z{�6A����y����(�up��znM�M����f�Cn���Z���B����x	q�*��B�����������kr�7�^�P�����>A���f�oiQo�Y�$�f�2sE���e���tcL�)�*�$���_�x���g����O]
�$����W�C�����Ya�*|��<pq���h66^����	;�����YX���C1�0#��P;����#�G����V|�%0l.aZ��G������
�����;���h}3z"����������vE��"����2�/2P�-�����9�C(���b��Se��#�a}��3�98,H�^���B����h�%�I\a��wH��#�g��>^���@�����.	�G�V���l���$n�
Z��$I(�<�7=k}�[p,x@o<��7w�F�H���Vp���z,v�.�72�w���'�=��1-���'0�7��K<�Gc�e�+&|�h�.���w�.�G��
��<� �6$���`Fwd.*2��4)����<����`Fd�i-�����G�\Vdp�=�2:$s	�X@k>N�D����[K��f�HfW����d�${��)�>�]���9��`��`��l�����]F�d�h���.���
sE+�v������5����8^`!��kZq�k�UF�d�i��e��"a6��z����I���c,�5O~Q�
�Z��g\e�I��&F�36�x�� &u_����IZ���1��P�'b��)������I:(��R�d�:Ob�O�nW�U��I8�D@+���]��O��y%�&qI��[3K���,~��4���kK�X��K������Xh��q�WRD����	f��|��+�����Fc@�5���>�u��+���&H+1Q.�b����*LW4+���
�9'�(l��0����0l6(lv�u>��-
���C�{���v���q>���v����q�����f��;�`�w�[��1H+���8�wr�7j2�[qi�Kc�}
��@W��=�@Z�Qt���I��I�W�>��2&���AY?6�&�
��a����K\1���-_�$�	�4�q���U�\ ��G������z�%w������O.�<�1������W�>����Z@+>~�%p�@�wH�]7�A-��f��#����&�G�xVh�&���Z�� ��^��f�H�T�A#����t��i�+n2z$n�O�W��s�����i��8$U����,��|��V<Y������n�����N�N����`���Fo�������Qo����UW��4�������?��+����4�������o��^FW����+��Q��f�@�7��Z�����$��h�f(�A`3��p���Z������9fA���p*���n��6�3�L(��y�7�����i��^�)�i����6H�����<�r���kf�lr�
3�!/4�y��3�t�BC^,C��E�����rF��Y)�9 Q��W��V�����N]�����f�N�P7[��]w��,3����R=	]@������}+����EE
+���$9��U��S��5i�f�R'�A�`���nh���������V<}�Hv�^����� �����~��(��������(���V���	c�uW�>������Q^��02�Hf\���^I[7dP/�9�&�0X�j���NI� ,�������n'�.�O�6h��L@�.2�����etJ��%�z3��8����n��n3�.�S����������0���s�$B�Zc��O����v9}����V�)�A�Zo�'�>�O282h����e�9Y��3��' �i��l���)Y��3��'!�i��lV��>�9}��"����"^7�0'����`��'�tK@k��v���n����>�OB�V;u����l/`xJ{"*a0�O���g]��cp�/�V��'Y^,+>�'a2V����IVZ���������u��s�$���a���$�Z�m���>��(����t��c2V��f�I�Q�����2xn#�����`F��Cc�+h��s��\�!��w�2�$:S_Ak���t��v�m���>I�����-��|�@���>�}��j��121D8�A�b��`F��������<�A�b��`F�������-�'{us��g0�O�5��u^F������e�����D�S����
}��-����h���L���nwSue��'�Z�����~Qw<���\]Y�tJ:$��F����]�c��M��EN��/	��;�����t�[�S9�����u9��G�@C�C���4��2����
yP9�c2:Rh��)�nD�]��P��3aK
A�Qxr���xR{�4�����p���U�E����Y�Q&��;���T
e$��Y��B����<����'�Crli�3��|c�\��������3���`�<�oO�����dE���@�e�=���N���I �i�D6��B���5��~���ad7��Q"{�������C!����?y��B�����?y���s��5~��(u���~�>�<!��`	�Lo���=���,��3���]E��r&���0�h��3����B���-���0+����`Fo��xTW��-d@I��L_��%p}3�#}M+��8d>ITkZq�o����Cr�������3r��9eF��������s�C�sDN�?"�����mM��!E�Ql��jw{U�9]��(�1xr���*2�������t�G	h���}�*e����s�$}M�����)Q�yJ��*V��'�i��5D�l�d����s�$��Za�9�'����3��'�����p��������!9.�O�!9�1$�i��AV���r\N�d�Y����2xr������v_�.�O2����us�v����wC�.�O2����usr��_���~����,<��/n�N�,�Q/�1j��'YyV/F��9�'Y�Zw�[UN�d�Y����l�dc�z��QW9}��
h���}��1j�zW�������Qw'����hK��f�I�b!FC������-��3��'J��Zc����PB�!p}3�$�s�h�>��}��A�%p}3�$����n��+���`F�d�xVW�r�;�E=T���>�}���Y]����5M�g0�O2�<�k���t�4	\_A��'���Q������Y��f�IV^��[�~Q��x�/1�s�$-�j���?�E��O������t<�;�O��{�C���3��'a�g�.���1x�����>I���7�}'k��=���`N�d��Fg�!�9��ch�����IF���n������G����]��'y��]��c0��'����]��'�������=Y�0L<���a�9}��V</������L+�w��������������6�/4�y����.�B#^#��n�@i����tIV�����q�������jrz$,-�Ow.�{��x��,nr:$��;X����������dtHF6|��������������&�C2��x4���� ������&�C2���h���Z��������&�C2��-�e<��
���G��M>2:$���Z@k���"��V�Q���B)����������)]��B�=�����^
�FB�`�S��-hj3z$c����g0`Ff����n[�6�K2����V�`�1���`m�Z=��>��t��V<}�(;�D��x�� >h�.~\L�&����N�W��� <O���g3�dp7:���IzD�b�y��V�D������%�����7	������'�t�
�y��2+p}s�$#�G^:����P
�B#�����0�S29b4t��8,��L������L�&�|�����=8���v�I��N�L3��j���q ���y��s:%�x��8d�P\+f*V���tJX�;z	��2;z���wVFW�����
�m*"3����[���tJ6�������B�c�m��O`N�dc.�k�|��oQg�M�m�vF�d*�dA@+[��>�v�O`F�d*+b�{,�'��X�+h}3:$S�L�����D������t{���M������B��h�n��3�#SU�@��]��%z��mA6y�>�������k�|����L�{��{yXa0�;21+�5_���;k����`Fwdb6V@+A���LQu[S�C���
�����X����Wq�s��)��a������B3#��e�<��]�����j2h�
�U;8u<��]����!�h���8`@X�=����]+rz$=4Zc0^�=l�P6
\���.�@+��V�.��$�h�����I(������ �<\���>�H+�Z=�2x�9�&��g0�O25d�������o���(a0�O2��'��n����3�x����>����V�OGMO3�Z��~u���,��Y����u�=����]+.��N�
������7����Ji����^�J;^�����l������];.��n���B����M�[���,2�%sY��N��p.�a�;ftL�b&H�c�\���p.Qk xw8����%�Q�Z���e.�F�;ftNfW���"d�A\k���aF�dvA=gB������K�����~����C4�Qi�xnWzm�h��V�����N<���K`�C�2z����%��%p=��k"�����\@���"
"p�p	lx\{���>���%���Z��-+2���n��u@S���p��__��@��� ��S&�	��,p}1pFY�;{C�o	<Y�5w�s�^��r�c�3�\J��#X-p�PkF�7���N�M�~��<f������5�����9�y?g\��C�F��q`&.#t��/�2��u���^���������L<�G]�u�7A)`}�8!U[}����#���K��?���}���^�\�����_���_~����,�/���?���~�������_���������������Q*���-���Js;-cI:����q�}�yV=���;n���w\F�ma��X��W�2!*�x�
���^��~z���^oPG�����Q���CF��`���^}a��a�Q���CNQ�,��-�;���$��]e��~���JR@?�s�:�eYxF/��(\F�mY��Q�����Wt�>�}��������d���A����q��{[6��k�xq���l���>�������^R95���\���i�������y|��e�DF��f�H�1�1��%�� �0�g0�K����
��q���Y���������z=�� �e�������.�O�V<������$�Z�g0�O��<�+������FO
��Kb2�$k���6&@�~�4����`F�de���&	�I�/���V f�IV�,�
�eqli�^�a0�O��.n
+v�Cq�x��wq��'��D@�
�<�=��0��'�k2h����q����w��*�O�Q�:=�aw�@���-��Ih��f�����9)�1=�����N�H3ty���u���f��)�
3>�����q7�U�tJ��@@k���]%/c�]�0��)�i��q�����L+�w��������g�����������{�9�����b\��[a{p�]����uN�dm��u���������^w��uN�dC�����������Sz�-��s:%�QZ�������������_4��)���@@kh�b�$[�����T f�I6�+�o���J�����@���llV ���X�o^�Q/g�I6�*���}��:��6�G�0��'���@@���1X�.����`F�dc���������
q���O f�I��V\���e�|)���V\�[qF�dkx��Gd0������]�d�I��wqc��g������3�$g�h�<�@���G�79=��7�5j�������O`N���E�u����>y������'0�?�����7�\R��C������tG��������oa�(�>�9���&��*�!0^H!����@���tFF���� #�lk/h}s�"������7��LkcW��+�s�"������7�<�eG	�C�+�sz"3M�kmC��)�m�	��&��Yx��	7g�ro�e����,���n�v�����-��i����8�-�L�g�������HbU�����%n�y#��Z�+�g[�1tU9����h�������g]=0$�_�,X]O�#��F�r��Q/d
?�����.�]>o�i%Fk�������O`>o���F�����#�	\���nS��������W1������n�#��|����MqP�{
��'��������\0�+�����vNhA����\Y�.�>�v%NhA��/1r������qsb��h��S��qoi���z��{:��c������"F�+@�*	M_��5-p}3�#��W�k�p��2X���]+�3�#��U\V Y�� ��z�.�3:$����q��=���n	S��#q�F�F	S{n|�r-O�f�������V��~84L2��8��[q�o�9=��F�F��&�K`G�T<B`N��F��5>7�T�������>�K5�tz��`������>�G24d�(C<y���a7�4��HZ�`�!��
+7�����A9=�q��e�g�fF����	�9=��V�5~��+<��b�N���{Za0�G2`�k�����w�����w�CN�d�{������f<��qN�d��FSH=v�"�<���o�9���v��qHAv\
W��o�9��u��e�'���(�'����!�r��j�
���Gu[�US�#�}3�&5O�����<~WwQ	�������]Fy`����P1]p������������]F
y`����P9]���t0��;��_t9)��F�+"�a�p�!��!g�N�
q.A�Pp#����\w����IS��7+�u�.l0��
w����IS���X�]��QwaC}����0�{��0�������|�����������r@�32�T��[t���~��x�E���8u[H�Df�*��m�c���Vx[7������Wr�}R�m-p=��i�X�������w`M;�����$�&\�&�������]>���K`����M8��V���2nv/�c����4�F����Wq�li���	{�D&�/�V7��1k�w`�u���H`G���t�	Wa��w�|,����!�c��I�p|b�����X�52���^�7�������?������W��B�cf�8����������4a�WO@AD�8���}���LH������O�i7a\�tD&��d$�����
O�6���i��!�(����L#���8�+2��
���{p�E�?�����,|J[#]�g�o���.eNg�����0'���a��Qr�9�j{#U0�9��h����Z���Af����������f?S�2:$-F�\A+$��Zq��.W�>�=��s��F}������	\���.I[�`��<�������+����`F��u-0:�8���8�AHl��`F���h��:�#
���h���g�I�j"F�����5��g0�O������0������3�$m�������l���H�+\���>I�����.� "���V��Zq��'i[Zq�[q�@�����]+�r�$��5���uG+�v�����t�������i�����Iz��{��#�$��E������>�P���^�1'>_����D���%f8���!����U;�_�D���#�*V@?]w�z��+�tH&G�8�$���Nl�|
�$=&��g!Z���
8;��������h+����s�n�3ZyZ_4��a����jb#j.�� ���������s�����It���kE
w[��9���
�6�pE����)���l5)4*���������0�C�!�.��.�����&����:�C�1+��.��*��
�:/
{�vd$�l�Q�ug�pW���>�=��!t$��nP��XW��ftI:G#�Jvo<���c�������tL�v^��
�{+���
���K�J%bF��c2V@+Fl��Y��yiXa0�S��w^�n��`�����eMF��kh����l8��Y�+p}3�$���W���AV�v^��J-'�������L��]��a���.	��z����u����s�$L�
h���_�=��K�
�9}��V��V�����i�����I���a���$��a�.������A����_�#�x�����'��
+>�E=�E=�����>�D+�uv��n�O�V���I��_@+������-��������-g���n����s��������+gu�??��&��~W�6�S������?vJ�
���&A���'YyV�Fq��B h}�$U[}��ccd�X@�����?\��������?������������g��q��?�������$�".�����?���������pJ�H�y>9;7e?�������������.}����/����*2��et���"F}Rq�����G�Bf$h}3zp=������:��*2�?n<��S�"�^������F��O����@��~�1�
�AO~"f���b%FjB���e��\����P��t�s0���V,p}3zp����a�\\���[qFn�
E@+D��2�v��~��.�7P�2��O�������?�
'22X7dPo��.c�FF��ftI��T��.c���.p}3�$C����~������nN����l ���.��d�o���I:�F3��o�9/��3��'�Pi*����� ������>I�RS�0�e0�td���A����IG������[\4{�>�9}���:=�a���$��3��w22�vZ�L���`�����I&Z���;{��0���}+���L31�V�,���o�i��G��'�y�zS������d�]<���CN�d���]\����$�x���!�O�����Cf<�}����e����>���x��8�I^dy��w���'���b ,�R����v��9��d���uQ)���l�P��+�������"�/x}
3�%#��^R�v>6d�A6�����MF�)�k�q\�`�o
0dtKFvh������������n�X�dP����Wu(�AA��B�_�z�EF�d��n������0j���F�_��P��1k<\�F��-/Gvg�;f�L���k�~K��M/G�g�;ftM���B=�P4O�Ka�����0�k2������h��$��������t1j�����&2�<���CY�tMz����m��:��}d�v���aN���%{������M��-����w?\y<�b������v'�O#�������5q+2��p���a27+p=��j"�.�����!������V��o����	���k�~k�gO%��]��m>228�dPW��'��f�����I ������v�>�nAvk��{Ikgd�s�G�c��<�=f��qn��Pk\W�����NA�j�~�5#���^���oA����$'�����7V|v������`F�d������~�	�~OOl�>��.3z$gO����||G��gO�����.�����18�9�Fl���ipv��'����18�9�^{r��\���>�T��h����L\
���>�����{��Af��)a��4�j��3�$S�8��V����E�����.h}3�$SC�����G��`Cn�M8�O254�F7���H�li�����.���&n�����GS������]N��YY�0xv������t�U$��A�q�������������]N��GG@+F|�����t��tw9=���A=��F�I����Sz�������D��V�x��18:2���w9���0x�M2BQ!p}s�$SE�������	j
��3��'�����{�����r�$3��Za�t�n�)=�����>	��:�M� �gO�����>�����6`�A���i�[k��T9}��V���0� ���=����}+N��Tm����>���V�~Y�4C��7�zw����C��o^�Z7�����3[Qv��
{!�nG}uC��{�
=�����W|/[.�7�����H�>���+b1���0�7�_@?_La�.�R���{�0�7�_@k�����
1��+�
3�qKAC���f��o�p�
E��ft��b&F����-�(,a����0�'�����Fa�3�B������'q������?�/�+�Q��C�	�����y���
d�����J��j�C�U�}�R7�������V4���c2�7�s�>�SL����r�`��:����e��ja0�w������.7�����V�y'��+XF]K
+xX����_��3��7�*Z����!�D�2X���}+���l����8��hdi���g�L6�t�
��I\k��^/a0�c�q����g0`p{T��	����&c�i������0u<j���6��MF�dki���������&���p��!�x��	��hf�xw��p���h��~����;�p�o�9�����N7��q\{�����t����
��_�Q��m�a7���tF���B���`�8��v�MN_dD�I@+���q�g�>�9]N��
�g?�'����MNOd�(T@km��ne���\����ym��6C�/��Q����)��r�Sk��������/�+h����3�~Aw_����H.�&b4��U�}��N��;��r��N-0N�|�2���������v��m>��.�����Cr�287X�y�-n�9%H1�n���s�����_���J�r�Y=[�c?iByU_��X�e7���sK�r�{��n���L��!�|n]����}#���\ �*�����5E��x��7q>�����^3��;p������|	��1J��w�+�=�+Z�����+�+p����2�2Qw�+	�-��2�#�@`���cb���`Y@`�[�e�F�����Z��������n������8Gvz]��!J`Ht�vm���pFg�����J��>�5�+�p�o�}W��+���x�p��i���	gtE\����0��)��;��H�n5{��q
M����O��
M��7����kkh���;��A`��;�����4�Vo 5�K`GnwM����t4��0����M��5�>�+����������wo�>�+��!���p��(.����C�O��Tm�~#?0�����%�~��Rh�z)�`+��\��J�f�+������&��]	_�������B�-W����[.��VAx�����U�^��ft�.�$1����z��H�Z����[����(b�s��A2��$'�'UF
GZ�`���E����x�7��\5��Gc^Fs:�
y�5�!�WM4��0����DC���gt����<��>~�D�p�!���<dt�>�w�[2u'���0�#W-1����`V��U������)�j�����~���L ����u�$�H���x���~,��K������u�$�I ��M��Z�E
�Wo��V2CF�����2Z�8%Q	������'0�ORS}R{��n�N
#��@�';3z$5�'z����pj�	�m�_���A�&����X_Owr�0�CRS"�5
O�����S�|\��p!H��Kw�!�%����+��I]�2���4Z��6�wo������
����OVx�
���v���>I�����l��ni��b����������-��U�8�W���[���1f���������J�!c�����!w�!�.������]C>�����(��M������H1FF�(E�J�8������o��!t��2�	��8�.��0i���{��%p��������G���k��^2q	�h��a�
��8���]>���L Mx2L8�Sw\�i��
e��W�8���~2!��#H�wM�Xx5.�KE
P�5�����[�Z�Ff��E/~
��w�t���uNOd��W@�3�=�F��+��uwl���h��>
6�1Y\7Z��o�9���V��V�+>�7�x�����HS�������HS����`F�)+2hX���HS��%p}3:$M��^{4�*.�����)���4�f��2�����RH;v�v��)i��u;.��^I��c��S��-i��@@kF�K�n��q��*��tF���i��!�(�vL���\�����4
/��0��������Fnvod��3i���q#�g�&M�����]F��a��Q�7	�����,
s�&�\ �5
#:'av����BaN����FaD�$�:�y#{m����IOC�-!fD�$�Br�o�9���7ro�����y���sz'o����O�NF�������;i��u#��5iF��k�UN�d��<Z��;	�p��<���UN�d��<7r��:�u2�F�vo�*�w2��g�FPT����<�rN�d��<��N�N�����\��N���q#�����7��{#W9����F�������r��;a�1r��;=w�$r��D�rz'L"7F�tg{'m��z?�\e�N.��{�Z��l��e�{��S��;i��y^�Rx�w��8���������J�z�2�8=�]�:����0�w�:������������OaF���h�^��D�����\�rF���6PXY�|���e�{��S��;ik��������mMC��
9�w�65)����������0�w�6h��z��o(�KLa�������OaF��m�������P��:�.lyT�lvu�2����!�<�oj>��^�aX����������V�{�������yJ{M��M�r��fZ!���0��yF��
���n�@���f���qw�@vM������I(����w�
w{69]��&�	���qw�H�M8�C���:9�a;�������MNw���[k���&�������&�3����9w�li��c�����?�����y�P�|9No���79No����mC��r�x�?v����p�xk�hm�A�o���9}�o�����xB\+f��v�x��������x�p�]�w������t:l��uQ��+K2����L,����'�"3�v��g0�?���W@?� �k�]�:�����)'������#Q�]����l����td�ZyP?k�1�
]�C���d��#����}�\�P�v ?Z���IW�����7>6��;�m��O`F��k ������|��;�]���K/�?��4a��s�v �>Z����H)E��~�!��Gwv|e��*�.�7���;]�^����Y���tF8|���>��8�w��s�?|����p�xg���p�d��n�x��������7>�����XEPB`NOd�	|j%!0l�����	������w^��C��;�e���'0�'2�����C#���@�
Z�����\�@����qw Kv�G`���i�^��
��L8l�����	���,��w^������@��
Z�����J�jv��Y�+h}sz"+���W�{C�����o�u�l����l4�M/	H+���Mx�7���H��_7��*�����������B`FO�/b�eni��;�/!��>�=���DF@+����@W��]�L���������a�Z0������������ ���?���?���?���"9�|����~�������_�������W���(���mK ��W���i(���5�����K����V=���6;�����-��wX�/��=9�:���/�2�nK����yL�+�nAV����CF�m`��`T�7�c����A����CF�m`��`�7�#X�� ������!��6��0�����i�=���a�����
,�������AV��U�CFn`��`T�x��� ������!�74�b��?����[Zq�o�]��E-��~����[��ZV���ICG+n��:4�3��h����tI:�	��]��{��[����Q9���f���;bR�	{�q�k�e��+Rh�q�7u�.��j�R��-h�]_���7�)i��b�9����<���G|�RHCC���L��=	�
��?i(>�;��L&��=�
��4a�|WO��������<�g�a�G������������EN�d�!��<D���(\h�
�o~��W���e���b4������B����c�����e�����r����^w��{��epk������=�����m�3^>G�����A�Z=��lo�E�d�-�Yc0��:���$��l�3#��-�5#��D�����tF�����a:� �^bV��9��U0+�Gf�rdp���X�5.����Yc��������w�3�Ha]�B����k&j���c��O`F�d��d���7>6��r����	����
^��7�����6�@D	�O`F�dl�	�����E�H���tI:l�Ba�v�AQ��yY��S��'�Fb��u����q7a�S��
,�9}��!�zd��{�����>�9}��f�%g���0Z��o�9}��V<XV�8���Z��o�9}��V<�c�a2'+p�uN�dB-��efo|,��k�_[�n1����L1��L�M&=g����8���0�W2��P��]v���y�q�9=��$��~�B;������0������rN�d�!/�!�~I\Cf>V����KV���Md�a2!+x}
s:&Z;�^V�vL��k���
^�����6#�]���J�T�q�v�]F�db�������� �x�o�2�&�LF��� W\�%`��PetM�r"F�>���:�>�]��5�h\�u�&,c^���,x}
3�&SE3v�<��]Ja�.�h���gtM��v\������)�!W����5�jrer�����\���}C���L

��9�Q������rF�dj�������r[���wu��5�Z��[�]�\��0lr����)���t%)4�L(�"�BN��>�9}����M����������/�����.O�L�[
#���������sz'CI
�!u.`�FdCxT�S�����0�>��������#��OaN�d�����};�*��H!����������H!��[
��q)�xTO�5&uN�dB���V(��	;g��n�I��;�Q� �
�"E��3��yw�d��;Y)�N�����w���z��8Y��N��O�t��"������rN�dE����(<�i��\L��%�9���"������R�
y�Q����59��m!Fcf]@k���p.*��<�d�N�aa�Qx��p.Pn"x}
3z'3��Z����.*[�K���^�V(������.��)����i��M��S��H�`F�dv&	hm��"�n#��	�&�s2W-)�x.D��
q��S��9��_�8k>~l�5��Z0����Sgtw3��\�����fWkSn��S�+.��Z�5��nS��=x�Dy<� ��[:�"�et��w�����g�Ee�rdp����[��]@+�"��"K�}������RW�h ����i���	\��������Zc0^�]�l����ft���V���?\������}+���--������;��[Zq�o�]�����dI�2����}+���-l�.�5�r��[�k�~}$dd�m��"�IvFm$��<����Ba�4����\@� K�Z%�)������J�V����"�*x}
s�%cC
�N>!����<"�*x���9��	�U��,=.�l�.x}
s:&��xm�����*.���w�rz&sC�FqD�H��!��G��[��tM�=@@kF�r��BvX��t9}vX���=#�BvX��t9�vX��>#S���~��.�w����= `�gdCf��e�{@��;a����0�2�.\���v�#����Z@�%��]1�H!\���0�w��)4:~�~��%����������%���]����[��S��;Y�����Mt�R�x���)������z���	������>�w�r��j��.��`W\
9t{���g�NVV�����2�8"2���^q�P��;YY�/�5
�]q)l/\��|�0�w��B_@kF�������+�
3z'k�0��>�,r��v#��a�>�w�
}�Qx� i�xT{����k)d����(����Q������k�����h��s����0�w2���D�1QW���9Z��S��;a���%j���"�B�hW�8_(����B������B�hW�8_(����B������B�hW�8_(����B��7�I��8l������9���aa���m���55�R�BF����������U��Px��f]��A����NV���C�E���=�W��^�������^�����j�O�u�CY��N6f�6=����M����vxe��;�
��g��}��p+`�w���������Z�0�(�j�'oo����"�w�q��f����B��?z�,2z'�oo���*@�B����go�EF�d�������"�=9|{��]��������"��������h�"�w�1Q�e�!5q)�yR{)����w?\y<�b�E�j��b�wM�
k/K+Q��2S+�O�4<�����	d�V0+��&b�!�:i!����,mN7B�p�����[����U�{��e��w����I[G�vm��s&.,����X�v
��v�/�=���� m���u!5;���������/�������{�Z����=�*��&9;����]^2�p�������[���h��q�������6��?�����������O��_���_��/�������}����k~#?Z(�]^)��wWU7���M��3�k�d=��V^
*���.����:������r3jAu|e[{���^������NI�M�����������������������	��Nv&!;@�k?�6.y���m-F^��^S��[�kS�v>cK�~>�/��
ueW���S��D+��\V=��J���l_�)�!�,`�>j���6�n�`��?��6E��	������J��M������$��^����E����D+�P��>{��+�i|�6����4+[�K��`�r��,z�^!������l����4�<I��({��}��K���D���Z�fi�
��g��4K����_u�oi;F���$/���������t��~W�Y�n�]��.Db�hi���Z05���E�������fmm���I�[���aDZJ�sLs$���z��8T�,.�]����"���s��0��~['[����g�c%���|�����l���@���YkWp����y1��c%���
����6e��TSl��W�/���������q��Y����m�����*K�f�Y�E������Om\�>V�,nY��"h����*�H���%Z`*�rKH�h+i��n_��/4U�����_��T��BSwE{�XI��5^+�'�������B�����Se�d��=|��Y��A�/n��T�u�h����
[����=|��Y�� ���A�/BU4��kr��D��+���J���Z�o���E��q"D�k���;"i h+iw�ke���|�rF�@0k�N^����l4�89BU�|���y�/BU.4�����|,��6�������������|�r�	�~��n�66C.|r���y^��W��u%n���w�n���������fq���v�\�/B��
'K�f�^�>V�,n?�y�]���-.��^1+����r5�\g
&=9B����v�\�/B�������k��:/t��Y�v$�}?7_��1$��v�It,w��9/t��Y�������+�|�;��u^�]H�D�;������4�;��2���U��cH0���hq'x�+iw�S~��s�|*� �`>�S(��<����@A�J��]�Z�wrU��C��+����Y�Jo��>t��Y�����~����.�3$��E����*�qXM�N�RU^,���z��k[�-����TU����=|��Y�r#��	4���q��UjY��dU�)WW���4k[
����Pp9���NM ����L��nTF��q��Y��A�ZUn��mQ�#��6�Kd�-b������fm���v�u
-�]�n!B���wL��=�
A{�PI��=^�������k;�4z=m��9Lt&�5��C%���|��i�C���k;��^ +����&��^Po*i�v�Ke���?W����D��s�>Y?U�t3f]g*i�v�#~�������+mc������j������q��Y��O�u7ip�67��n+!���d�T]�86���8V�,n]`�	�ks�.n���`V�;94UcT���c%��b������q����Bp������BF���?A�J�����
�ks�.n��������8������fq8����������`V:����[x��
:V�,nW�~X��T��`V�d�T�CW{��c%���|�����c��qw�Q�4'���~��=|��Y����a������
'�����
:V�,���������P�	f����S�Bo�+iw�ke�/��������'���������J����ZY����E����bV�;9B��6o�g���dq�b"����js�..�Q^1+�����q�6c�q��Y\����}�67��V-!o���S��{p���3��4�[m���;V�wq���7������!h+i�n7qp�67���4�FO��"T��roC�>V�,n����}�67����	feqOP5=�
A{�XI��=_+��8�Xmn��B��,���f��!h+iw�S~�M������c�m�U��<����i3'G�����i��>_��Y���
'k�����b�&;9B�,|�,���c��qw�Q��'G������'�c%��n|�����c��Q���@��8hO��k��h����]�,�m�	�s��VF���*_1��� ��3W��-�h�
�<���O����U��`eVF0���@>��W����"��@��J���<A{�77�s���ynk��jKA{8��qn9�����UR���Tm�\����]�%��������u�%$�#�3��kh�Z��Y���A�+h�����m�a<���UTm�LW�*y|���"h�����-Y ���1E��Ht[��T��v(.�������$�@��6C�3&���	�+������������v��0�\��%T��dcR6�T����Ls1�i}K
H G�g�O�s
��T��v�#~	���i}KH G�g���nL3<hWP����/�-��;�+'�mW�D�t����@�!h�,���#��8�XonZ��(7�����S]�<C��*y�[��"hO���un5��`I�L�Zf���E������5����donZ��OM0G�g���
:�CM	+y��l^�z7��OM0�������U;�CM	+y���!/hO���u.��s����T�#���5%��q�P\���:v�c��`�8����FT:�CM	+y�;�)?�������i!�x��7������/(a%�sg�V�pW�u�T�>5���q�_��f�)jJX����O�%�UA�m�	�����S�fT�+y������q�zs�:��H�-�f�����)�{$�������C�+hO���u.I ����~�/���	t�s����y�������y8J%�5f��y��=|g�q.������i��L���ec�T��b%h��<���qA{�77�sI����X=�w(Y�	�+��q.������i����O%�T�����=V�8w�V�����M�\�@�9��d���;�d�{$�������@.hO���u�����2�|0���g�s���J��|�����FonZ����+�����G�
+y������W�^�P�S�5�f�%T�6�O������JV��donR��S��3T�CUmP:��������kE����M�\��	�������j�A�NS�J�V%��W�^�P
�Q��%c�����F�1(�iJX����A{�77�s��&�#�3�P
-��A�OS�J��x����uR�SMp�m�ty�o��cP��������,��\snZ���-�0R
�@�pl����O�!8B������U�1���)����iq%�w'0��\nZ��(p�����T�%��=X�xw��e�;�0����a���
c)��B''p�G�<�]��
�s=�i��1�X��o]a��6�������c�ooc��x�nR��w�@���x������#K�:|{�\�nZ��3�U�0���
z�{<���n���=�����uK��&��B?��K���=Y�x���a��Jo���u/��s��������QiY�BK��(#��\��n���e��`��K��u�QiZ�bK��%�	��u����k�9�^c�j�niT����;���I����M����cP�..��j��y�rI��:��w���-��������s�����8��6z����#�{�����a�1V#9!�3�1c5�(��'�/��q��w�^�ze5��1SV��J���B�bK�NEMt����qV�Cf.�c4��&�w��=[������'{w���\	Q!��1i5U L�������-�d�nZ��=!j��tM���[��&p���<�m����^�ZM-�G�=^�Y��E�!p���<�m�n�';x����	Qy�������� p���<���n���c=�i�;���<^J�V�i@�!p���<��n�KX�c��q#D��R�c����	%�{<��q��w�,)��M��y D��R�V���cf��������-3��7:y��w��X��Ki�ZM+S�UQ�)�%�{W�[��*��X�i[Qy�����\�|lJIA�-Y�;����n����]O�J�[7�y��������y�u��L^H0�����U�+������:������������B���1k57��
��WG�6H*������m;BT2������	���%�{[$��G	������}A�JfY�Vs�i�xl���~ ����c}�i�;���d����j&/$p���<�+�#%�fgo������d�U2�jg�&7$p���<.��v�h����i�;�D��_*c�j^�6���K�.|�,���M���'B��R���	���%�w9�|�H����I��<�4��m�����=Y�xw)�p��z{�z�MD�<^*c����z���%�wKH�������e��@���Xj�TP�-Z�Y�x�Z�.��;�8��n���n1���
2�xd���o�{��7�w[��F{�SVK��C��,y���� p�����n�r�@���6f����{<���n�7K^�z�oN��a&D��R���t�����;��2����M���Y���\jc��2AF'p?��N|�L������e)Qy���t��0�X�����A�.|�,�Qt�z{���n�9�^c���2����������-kxe�u��Z�����Km��Z��{<�dq�Z�Dn���Z�F�J�[3Vk��W��-y�[BF'pO���uo��"���)����^��-y�[;�������uo��C0�h�Y�
�^�{<��qo3]8����Z[��F�{�I��C�+p���<���n�'{{���o	Qy�4�X��������cK�r	��=������F�J�Xc��Z�d��cK��|�x�7z{��wQy�4���:�}L��-y�;��2����c����cV/�1k�.L=E����<�]�nY��c��V����(�����Z7��2�E�-y���������M����Qy�4�2��@���=[��w+�n�'{{���,Qy�4���VB}-p���<��B>�{��7�{����Bc�Zm�2	���%�{��o�dLo���uo����,�s�1k�Q�$p?���Bt�1������-�G��'4�����:����#�{;���������{BTJ
���j��z��WG����%�c��i�;"5�1�k��%�{<��q��w�,)��M��i&De"]k�Zm3�B�xl���%�{��7�{����Bk�Zm�������w�����7{{��.�xFE����������9�r}�q��^����M���(�7��om�Vm����;���G���5@����:��-j�����������-ou�\���=������F�J����������R8S%���.�������M��f B%�lmY�������5�c��p�����n����:om�V7t�uJ�W�,y��)�w��z{�z�_�Py�t��U[�z�0U"K�|��yt����;"T�-�����n�Q)��{w�������������1)e��������1���y.�������{������M��e"DedJg�X���I�(
l������&����c��i��5��*��:[��
������-y����-�FooR��b#D����U�=k!�p���,�u�:n���r�
�1�h;����z�����[�D��}a�j��J���Na�����i2!����^����=����������������k�y����#�{����dooZ��r���GSV����i2!����^����=�����d�������}2�j�{���c��}|y�;�]/pO���u�8�B�����Ql��?�<����;����i�;#5w���G&c�v���6�{��������9<��:��-+!*�}����������d������+�VkX�|k�6>�V�i���`����jS�V�����e��o>����&uoI^��������7t�{K�����q/F������M��r&D����Y��*��T�r�����
|��=�����uK�
i�'c�v���z�{����^9��=�����mA�
i�'c�v�������rc%N��]/pO���uo7�"���u��(S�{����^�9��=�����R�R�u>+���z�{��������!<6�:��y>�Y��mw`[N()��_�b����������zh���tZ�}�w��N�����w��e/v���*W�Jm��`��*W����c��pO���u�����:l;o��zlJ��[���*������I�[9���9f@c�U�����cK���������K��r#L��l0��*����0��+���������"T�t�q`U��&p�{y���DT�b��z�EQA ��g�[U-^�������-�
�\ooZ�v3*5��������������z>\�`M�����CK���K�����%�{������o�!XR8D9�������:/c����y���^�N|�L�i������G"��[�����f���o/�w�Y����C�sZ����	����)�je���g�j�^��|���Y������e��@����;�.��*�m�����u�oO����M���
�Ox��������=���qoY]�}�:���p{���uVu��W��������.�>v]U��1������#��}|y�� ��'{{���n�9f@����E�[+�m������Ft���XooZ���1Vu����(�}_�����c��i�KNH0G��1V;���r[�qB�>�<��n��c�QV���W0��k�XOL=&%�U>�<���n��i������%+$�c4�������
�����w��~	����M�^�B�9f@c��^�zx����/�{7��Wfo��&uo�7�3�1k���6Js���eqoS��"pO���u/;�s����U��z4Js����q/V������M�^v�5���G�VM���Q����/�{���������uo��Q�%t�3f��%�{����^����=������@������jZ�������X}w�{��7�{{����������U�#�����~&�pg�u�U3�|�JI�L�������H=������X}w�{��7�{����4f�����)>6E�-y�;D�rk�,h��1�&c�v>������J����^����=������D��T�4f���c������X{w�{��7�{�����������UK^H���������������M��� �����4f���C������c��������FBT2���3��P���?�<��16E����M�^�B�9f@���[t/������f&:���������]3��U���U��m/p��y\���"p�����n�#�i��a�m��W����xw������X���%3$�#����V�����)������xw��eN9D:���4��z��i�vb�1)����������L|q�i���t�J�[�V���c�o���<�]�fY�u��M��u%B��R�V���cU��������r.p���&�nW�D��[*�9�]��C����x�s���o��M���C ��g<��+�s���^��x��s��i��7��������stZs�����n�7��=�����MK�������$�������FtL8���M�����Q�	�1[�u�:���/�{������c��i���|tJ9�2�����{��������>XN8�����#�	�9b�����F�������#_�cp
�������BTJ	�1a��L<&%%W>�<�������]�c����cVj	�1c�-�%��_��|�,����QV;�s����U�1������/�{7�[��b��8��c�6��R��z�i��B�>�,��>>�{��7�{�����NEZ�rz���/q>�������/����o��������?���?�����g����������������/?���?~��������r��u�����/�����~;i�Z��o���}��?�������w���HzZ:�
�������@gL��8�A��!(�z��	.,������]0��k�G��Xzo����AZ�H���&����~w���1��O`Xzo�����@Z���I����N�]�w��N�������@�����������.{������]y:�F�&��32s����x���,�w���{{����N��m&D���s{CzE�F���H�����E��l�N�������[�d��N�:$7����@Z�����E�c��i�[��M�d����<TH:n����,i�[��"hO�?��n=�"�j��hC��C�F��Z����MIp�����zC���`�y��rh�t��w_�Y�z��	.���:�j�^w���q���#�����5����O�>X0=�����CG����1��
����1W5�|�����qU��_0��k�U
��)^/��eI����)���:�j�Rw����m��txK����!eI���O�������CR��	*�#n��h���c����fI������)�������V"T
	�1]5Ly�x!a��%�s�5,A{��9�sG�A9�\c!���=B����l���&A{��9�s��}���Zc�X!��m��5&��j&�`�{�gN�\�A9�\c�� �=:����\���&A{��9�s��}���Zc�jl���]��5��F�5	�s-�i��#�����XU5��vn���L���&A{��9�sI�ZcSk,�$���=8�����$h�5<�u.��Z[Sk�S����[���\c�jdC��=������J�Z�k���s<�U$Ay��~&A{��9�w��ZSSg��W�
��]c�jd;��=�����v�ZOSgLRM\�5)�IP�N�Dp�}]����z����)��5U�2��n�����e~��9�w+��RQ�u�h�]+C&�e��s�S�UX�7���V���m
BT�au������^�F�kLBN�@p�%��U����w�|M-^��������D��a��=�����lb�1�3US�]v����H��x�_.���:�jVBT�au���i��^�F�kLUM#�yA{�w7�w��]0�������'���
��5��&.��'{w�z�Ml����3��&.����5E����,�=]�qU�:����7�SM+��5��Z������^O}W5�<6e=u�����g�A7�]c6c.����F�nZ��!*�no�U���.p#�5f3�r �`�{�w7�w���|�7�T�\�.p#�5f3��"�`�{�w7�w�	��w�5Us�
���A�5�T�
�]A{�w7�w���|�7U�\�.p#�5���O��[��F�nZ��
�1�sU37����]c�j��������l�`�y�XV5��`���]c�j�d���c��i�����9�]c]�<1����?x����g>Y�`�{�w7�w�	��w���ya���A��)��<�]��_�n������d�sl����j��txt��w���y��ec��F�nR�.�`�1����I��t�)��,�]\IpL7���uER��C����	��D�!p#.6&��r&8���w{��)�-X�����F�!p#�5&���A{�{7�w�����r0W-
2���1a�4�1�8�����]A�J)a0&������x���Z������C\sb��<�RJ�V-=2���1a�|���R�!�9�wGH�s�����eD�!p#�5&���O�1(�;�5'����RJ�	�ef�1�K	�6(�wg>��`)�����O�����U���c����6(�wW>Y�`)������s�92�M����nL:��tN�����'���k�M���������*���!�]=R�����������dob��Z���1[�rg��B�5f�V�._�u�o��&v/	�U�`^�U+���#t�{9�|���������d�Vm�ya�W�
r�����k�F��^.hO6�&v/)�U�a^Vk���qB�5�#W�/�';y�����
1/���K�W�zp�1�r~���k��7�{I
������ZG����
=����\9�\����M�^�B�6��0������G=����\9�\��l�M�^�B�2��*�I��K�W�zp�1%�r|���k��7�{������V����#���S4`y�����d;oZ�nll[�1��3f�6��cSz�X�n�zA{��7�{��&�c�M�Z��[��cS���P�Vx���
���[�-�c�5�
�j�7�^cZc�g�K�.d�6��	��{�Y��E��)mm�H(�{[<�������es��������:����������/.��!k���M@��k�ZmJ
��������w��e��5�&v/��t�����6"����6E'�����c�#�B�jc��������f�Jk��{g>��pK�����7so���]�_�%�M�mSt`y�����'�z�w�1N���LO��w�os��r��+
F����7:{���+�st�����v��
]t.�����_��������M��r%�xnY��j��5t���-quC��G
������uO�J����[���@W�o��������pS�����N�8��Ui�^��5@����N���1�����l�M��n"DE�\�N`�������Nq�d(�{1���d�oZ���c���v��
�tA��^[��������7Z|��w�1���J[��+�
�Fn����/�Zo���u�����9��t��z���������UW`����&���]+@���=��v��
]tk<9w�",�{����d�oZ�n!�WlWU2�j���|�oq��)��,�uXyw�{��7�{��Q��V����	�\<5w�d(�{����d�oZ�V��w����\���]/pc�5��\�\���=������H�J��2��\�]O������{�{��7�[$�:�_c���H>n�����k�o���r�J�Jm���]u�GmA���kL\��O�>��B��
<!�R[�luW7t�-����
7�� p�6������C@��kL]�	u���1��&�]�� ��+7O��*[��

�S���D,,l�M���'dQ:�*[��
3�5�Q�aX������~���-�	��k[��
�������(����,F������M�����X{U:�g���1}U��-������%C$�c�5�^�*[��=����*�������-�i�[o���~k����$C$pc�5����e�qC�����o��(���v��
"���1Uvx��7�N�oZ���O������o�����������o������M��a&������W%"���1U�|�{��;m�i�;������mW
��1���3������o�z��7�����7���3�%^�������{��7��	����W�
�P�1D��5����o�5<T�B��B��t���1U�UJ����b&����`�oZ���u]�N~���Jd 7�_E������~�{��7�����oc�_U��7�_c�d�1�w�g{����B�R��W����j�?�1����������M��v"F��������yF�*�E����~�{��7�{���2�j������^�~�1	�7E�o���O�2����X#^�7�cc�������i�;��'���X�UaI�n���t5WD�����i�K�H0��k�`U��G��^�xa�m�{��7�{I	��{�	�jc�QD�U�Cy������5yo��&uo]����~�&�����k��pc�5�k������������%(T�s�q�`]�|��{��Wu9]��{�}N��j&D���&c�v���_�s�1�QcM�������%=T{���k,����k�zt�q�[7��]�F�oZ�v!*���X{Uwx���{���k��p�����/�������_c������=v�����o=���k�{����P���{�����Q��=f�J��|�����������xBF%�m�W�x�zf�1i������Q��g{����������w����;����W���.E�oZ�n��
��m�
���q�)�_E9���j��l�oR�6�M��v������pc�5���Do�ey�����o��o�LF�:������pc�5&��Do�my�����o���[�k����������j8�����������@�JoYgL_5��w���1}��%�k{����	i����1�`a�n����U�����0�������gbT������i�^�.(��<��Dt�{��7�����Bg�_5#�7�_c~��Ht�{��7�����Bg,�jf�����3�������]xB���U�����O63�E�)��<��Pt�{��7�7���h��3���
8����������-�V�B���"ow��{c��u8!��=����j�5O����M�_2D��;�������Du���+�[�D���7�k��J������]�o[��+pc�5�'��Y����M��f%F->��d�n����U�B��z��;��i��������7�l�	������/����;��i�;@!!�c�5�_��[�S�;�D�-z��7�G��A����}�����������l'���l�oZ���'t����U;�}�1��W����w{��>^�T8���{�]�Q
�������9��(/t��x�R`c
���<�q�" ������[��F�oR�v`�q�`�`u\�'pc�5f8:7]�|��N��r!D�<�k,���:O���kLpt����:�������[BTf�������n��������.8[�����mA�q���W]������������D�����i���|��f��X}�u�=$pc�5f7����.�Y�����R�s�1y�qm���������[��yo���u���R[��vR�s�1��M|�L���������;bTj�����[�����3�;ok�;��i����N���u��ix^��vJ��S�ay���D��}!q�m1��k�`<�����
���y��[�����������������/K|���7�_E9���_��=�����UA���B]k��
�{���1u�sk��=������H�q�s]$��v���{���1w�7��	����i��B['�c�5&���{���1y��3��g�\�^��B�����0f���!���1{���E����i�;t�WG��1}�x������~��e�����������
���{{��n����F�����kz��7�g�e,z]k�z��n����F�����iz��w���+��y��Q�0�������?������n@n�������������G���������/��/���������/��#Y��o����OH���������@8�j�����������:
�^"��Q���"�Sepx����c*h(qM��m�IC�P��!�#��u��S�/�
�z�6�^Ea����Dt�)a�������1~W�Xp���
�z�6�^c�ohpI��M�i����4q�����;��38�x�	��{�y���FC����N��n#��n������$�������z�������b���wl7O{zpT�6�^c�o�lRtH�u�������u�<���@Q	��{�I�a��e
������������wa�1+�pEa����-KP~�?:�{W�%�z���<�{W��B�*�<����_��������t������w�X@�!hc�5f����=�����/���.�'=��g�)�EN�W�qo��W��m�N�^C:��d����[!�=^��R�]�V�{n���:���c$�#.6f�����t���*�����dktZ���H0G����������4���*�w���tF��.�!��n2�jgx�!_=f�����������K�H���e��`�x7m����H|G���T�Uy�����d_tZ�����;����������k�Z�9-pO�E��.y�Q�;�c�y���0��h�G��V��'�.c��zw	1�p���<��]�x����RU����'���):�w�Cs�����T ��1�SVS�'��=����n%���e�2��gw*Qn�1�3VS�'��=����UO�����e�io��C�F������(�{�#:�{�L��{����AK�������������V6D�uo;c���c�yZ��`Jm���t���D��y!_5�< ]���c�y���#��1��US�gK^�y!a5
1�_/;6��u������� K��n�����z��y.;��
�:m���|�4��2;6C�u��z�����Xg5-Pj��{�	�i��e	*5�B�u����_/;���
�S�5��]:cFr���
����I�;�@��Rc����w.p>m������
�O����K\ :�^c�j.������r$�`�{�:�{+�2����a����v���^As�1�<���ltZ�6(G��{�Y����N���k�9��Ft)V �uoWc<����<��j���.h#�-�Y��CN)p����u/�!q�qw��CC7{���{�i�y(�.�>v!k5��H��{�Y�����������G��f�z��7�{���*������2!As�1�1s5��=�����KG�������i��@F'hc�5�5fnE�g{{��w�Qv��X^�68��1�Z����6{��;��I������h;v�'=�K!�����8�]\EtA!������-Q����VK��C���k��.�BtA%������e������x��R#�X����2�Z-5���looZ���M@G�k�Z-
�Y���VV�Z��uD����M�^��	��{��VK�z��t���1k�t����noo���=Ig�w�.O��e7As�1s��i	����i�;��q�����i�;�e/hc�5&��q#��r�c�sZ��<c��}������2�a?���ee�[-3V�����i�����,�ccy���@k*hc�5����"��b�c�sZ�n��	��w,,O��
2�6�]c�j��n�<F9'��Z�������}�I#�JZH���kLZ����Bo����n9b�Gk����gw-q:m��������dooZ���<Ve���m�i�n�Z���x�6���I��=�����$�s�������A�z���w���E�+p����u/I!qo*�����!�]8��N��&v������]'?��
�7vr��$�+3������o��J�~|�I��}���mnz��9�����:��sw+W{��j���:�w��f���uE�@@G�k,:[W����M���.�z��}�i�������{����g�k�We���������[�/��6����x�����WA��kr'�w9{G���rN��r#�x����=ih�*��7�n��!�{+<Y��.����{b��\����iOo�V�F��:EL�^���g�������aSF������y�������!�{[<Z��.����fbTV��X���Qr�!����������w��.���x>�<n�����y�#p?���FpAE��.����
bT6��X����N�4��{_V�������.����6�M���vlkO{�r���l���iH��U�-���B�j[y>�����X��68�|��q5�QCZ���������w[�1.�w�`���=U�	��{_�R����s��=�����}�Fb�+�2Y8Gp��[���������-�s�;��]�i�[U�X*�����yN/��;�0������f�7�_�Z�E�c\;����y�b�7�^[���8�z��9�{[��&�Y:e�p�����w����V}��;w�g�����w����q���<��o���w�����
�-}���:��/����W=���b(�n����F_�|�xC���rN�^�Bw�1��6J���@�C���j�����
e~��9�{����W=���.�=�x�[��V7pB�7���.���]{bT6�+�I���u�5�lP��V}�������n�s����(�S�����Y\���!Zw�3W+��hOv9��.6��1��kL\9�����x���r�sG{��9�w����W�V������c��a����.����n�;��wm[%{���w���V�����w����z�1�xq�d�<g�]���<c��u%�;%�Q�i��W����-N,����H=�������=������L��NI���sv���x�����|���N�c�sZ�����9�]c��M#�)�m�1e�&>Y��������O������<�ya��t�5���[�dY�2��]�i���;��{�+�B��������r�,kP�q��7�{�����8e�p��[�xn���lUY���g{���m����)S���������Ue��W����M��j F%�U����B�+p��Zc���K���[{��������Wi���$�7�^���l��
����i�����d�J^����]/p#�5�z��A{��7�{����W�����i�����XgU�������i�KVH@��k��*G���G=��XgU�|�����B��D��t����U91�P��Zc����l��y���U���8+y������.�=��L����*>[��L����i���;��{�Y�rC�B�4����U�����;.d�*�����������_�7�^c��r�U���{{�����O@��k�ZU%:n����UU��P��������/�{+P�7��3f���&�pg���U��|����S������������<[������mWbT:��<�k��p#�5f�����[#�NooZ��=1*���<�+��p#�5f����o��;��i�;��!�c�5VZU#�n����U5��2��.d��i&F�=Ai�������oO��Y�j��e�'��M����c�?^����'8/�=���V��g��E������]7bT��<�wC���������6>[�`����������&�c�5���������V��	.��!kU��1���X$v�q�1kUc��m���.����V++������c��n]o�\�X1G{��7�w�a��9�]c���6�;��w����E�[G6�_�]6�	��w�y�����V��zc���&�f��H����gBT�����$��C�����=�����lr�1��V��.�Z�o3?�#�,c�K�����lr�1�&#�v��io������U=C($hO����.��s����o���P+�m�1gU�|�,	6��.{�s����o���P+�m�1eUo�		����I���96�CAi��rv���x���j�,��looZ��-1*
J^���P��3VM�\�C�B���y>J�CAi����i��
�������E����M��f$F�CAi��szt(��{�S���.��p!_�t(y��{����C�!p#�5�y�n!�`��������y>:���kLX52�q�����l�s������cG�J��������H=n���:�f��ev(��M��<����)
xy�;3���kgc�������t������������{�qV{VC��1�X�Y��{W� �������Pl�1��V��w���
��U��|w�g{{���u�T�	J^���:�q�1k�r/��=������D�J�������%dt7�^c���j���]�Z�5�G�����,��%1$p#����/��%�NsoZ�6+1*:�/��m���1��V-7�	����i���������<��CEK���kL\�\�'p�����/��VY����<�w������G�3W-w�	����i�;���(��&�<�w��N���kL]�\�'p�6���/��VY���.�<�w������G��-��	���i�Kv�Uv�9�
/��]��k=z�����������������(K�������n(�	��������������j�����)�xY�o����1��W�o/p�6���o9���S:�����B�M���k�_u��'p�v���o����Q������7�A�����y*p�����o[c|i�S�y�������������O���������Sy�(-=y�p���������z0��d�oZ�HBs���V7���1�SXW�	����i�;.���azc�� �1�3X��T��l�M���)��G8�#/���A�
��{�	�n��e&��F�oZ������{��;��������:O��F�oZ�n<��>���e��u�M)~8cz�/���|�����=�!�s����w��z�zt�1;�����1�9�{+g�s�����Bp�1��W}����=�����d�s��JS^��[���{���2Kc��o*�c�������mQ��1�sW}�������Q9�N�oZ�v<!��[*myYW=�!���17y�pyx��;-�i�;���~���<�w@�W���k�K��|.p��������o��?wJc^��������
7f��	�_�{��7�����������.��
�����~A�W����M���%F��;sW������~Kkr���������
�e�Sz�������^���k�n�.�l�oZ���M@�������~�����Vk�����=�����OH�������B�+pc�5���j!�p�{!5�!�a�
�<��A�;x��ZKc~ch���g[�����1���Jw^����sF���k�o�#:v�������=rt����j�Q~�1��C����=������D�q�T����������Xx5�|���*{��wB�.�c�5���	8���15L|�O�����a��1>�T����w{*pc�5����N�{��7�Wf K�w�T�������������6Gt������@w������wp,���1��Wc�]p�������%C$�c�5�K��G�!z��15r��=�����UG�q�T�����
�{���15r��=�����
��Q��^*�yy�o�������6��F�C�g{�����1���Jw^����u/pc�5��F�C�g{����uT���Jg^����	�������������xB�������'>��n��������7E�����SO�J����9�r`���1�5r,��=������p�2�T����I��t&�������0�x��7�{���o�Ri��sz7t���{��q��eN�;F@'u��8�s��k*��LZ�[mL`M��d�oZ����
��wNT8	��{������e��Mo���u/;�s�����N���V�WS
�t��Mo���uo��C0G���o�9��7	��{c�jjf�v/#����]1�x)���<���&��)��u:y��7z���o	1��(���<���&��)������5������cA���KYsW�M7�_c�j��N����������|����R���s~�n�1��V�����kz��7��?t���������������>]��B���i�	Y�����'>oL?VE��3W�����{!u5��M@��k����n��������]It�������"�c�5�^�%�_���1w5�P	����i�[���(���<���&���q�;�HgO��N�oZ�6-1*�������6�n���q�;7�E����i���WG�Jw^��Ku�����X{5w��u�N�oZ��#1*�������T7	����W�����kz��7�G��A����<�yD�+pc�5����o�1��p!5O1�_0������R�$pc�5����oO��N�oZ���M@��k�_�3�����+_�K�w�B�jf�����7��j���yc�t������9]����M�����QQ�)�yY������1������N����M���%FEZ�t���o���������Z���������i�[���Z�k,�Zj��������N����M��f FE\�t��9�
^�7�_c~riK�������o��������Z:��n���1?�t3�����M���'�S�_�;/O|���1��W�����������c�S*�yy���D���k�_-�.cp3�������!@�1��W��dVV�t���2�u?W���M�_6�	�����ea�������XV���o���ER�N��|l��Z6T����u�������?t���w�H�M���eq��pHV�$����C
,p���&vo9��3Xk��!pc�5V��UIt�����5`�s��k����{�	����.������`��W����[����=.�4�7����=�����]G�J���Wk�������X~�����C�sb��~s�����:�]/pc�5f�����!��"��w	1�x)���<�w�d�s�1y�N|������������})�c�5����L=fe/No�]�3:g������]VbTz����<�wEw�������ZW>\�po����������Q�����
�!���1��q���=������C��)��J�;/����u7�_cfcs#��u�z���o:�_�����t�M�|�J����m*pO��&�o��C@���������j�n������;�������mxB��~����'>�H@������^����M��n F���t��9��S���`�Mn=z�������x��Jo���������1��W�����=�����#O������<�y��~Tj�1}�M�-�'{�w��Q�-S��������Y�-���mAqA����M�����1��|��Jua0���u$�`u�X�ob���M@��k�_m�u����[�j(
~}[p/������
�\������������)�e�-u�]���:�j(����2�{+�������R�u���z��pO��&�o=����J�n��������6%��{������t��J�V���v@�1D�[/m�����
��]�_
E��2���_
E���������n��v�������&����"�S����w��nP���-5#�.CP\w��7�'��Q����<�yj�n���ea�_����2��������GbT�uJw^��+��Ju�����b����Ay������]��,J}A����������������e
����&������QZ���_W�@�)[k���+��w�'{�������������:7�S6�Z�gWD������.��+����S����j��R��Z�hW�D�_w�{k�Jy�t���n�6�������Dgp
�/�d�oZ���As��J^���@�jkk�,��DT�#�����Qy�(�yy���n�������w��������x>�x�@����	�2�s�1�F�[��n�c�sZ�N(���{m�W7tL@&��������O��F�oZ��3!*��?/��]�����YgG�-Kp3�1�9�{����������B�t�s�ub����	����M������*��;/�{o��3:�s��v�,F��������������v��
��c��k��(K$��l�oZ�V�At����UY�e/pc�����Y�.�[v!qU�1j�����l��
������A�+p�����/�!�����'>��}K�z�zi�\��.�l�oZ��H~t����������
�������rH����M��a&Fe/����'>S�$pc�5����oO��N�oZ�N-1*/�;/�'��7�_c����v���������]xB&��t����3���4f����l�oZ��1*�Jw^����wA���kL_��.k�w�B��*�� �c�5�^U�C7�_c���N�;����i��bT^0JwO��[�Pf�����
;��p�����o�����{�
��������*���l�oZ�61����1U55�5���4��*����=������H��L�������S���~w�g{����	Q6�UJw^��W7t�@n���1?Y��/����i�;l��/TJw^��wD}A���k�_U#_�c��p��7�'��1�P)�y�����������fGt�������rt��1U-�/�����j��~	�������]��W)�y���T���k�_U��w�{��7�k�!R��U����.��=������U�
���;�����%������.���1��Wu����=�����d�t�����������G��Wu]]pv������mp��������zH�~�����z��w�w���)i�X����q�r`���1�Uw�/�������B�'�������(��{kc
�J����1�i�;�E�1�3X59"�s�1�U��.k�z��7�{���)f����9�3
�7�^c��Q�'{��w�1^�����c������$C$p����o��������p���O?��/?���?��O?�e������O���
�������������wD�o���M�P�|�T���o��JHx	�z	?���8��{NvB'����4��������SN�Fb�k.�I��r!�`-�����J��E�����!��x�	��w_3yi�[��'���z��D�9�]c"�i��k�6"k���i��6���e+�`�y���k:����D���M��n$�]�i��O��UJ�b���C�'pc=����r�;��M�i��F�FY�V)m�yN���Q[���;���:�{�G$�c�5��lf����AT�n�L�^�F��=����l#j�i������.�(5J�ZZ��|�,A������e����xz}�A��(�C;hi���hw�g����-��+��*�E1��m����{�i%uo���	����i�[v��}])�P����x��:c���Z4A{��9�{k�/Ze9Z�yNo�w����3f5�z$��f����i��L����� ��m���t��F��h��l�sZ�v�'��j�Ja��^JCn�1��v��{s.d��~%F���0y�Ki����3�5���O�N�sZ��<��xQ����wD�+p��v����w��~w�\�Z�3�����
1�����{����6f�����9��s!k�.31*���szW�K\5�Cu���+��k�/�B���ZbT�rb(����{lq���YZ�n|�l����V]���xQ��,����I�F�k�Zu���1�������@�
i�CYNoG-��������*��<�;M�i�[��&�c�5f�:��n����UW�G�;=�i��,��H�b(��mA�
��{�Y���RH��myN���%F
��k�Zu�3	��{�Y����:�w:���w(�1�x�b(��@�
��{�Y����������Gb����b(����I���5��U7�������wN��r?s�q�d7C�-p#�5f�������w����.^xF���R��<ze����~�1s��|���m��pZ�n!*�
��s�76n����U_�����d��n�p���w��}�����x�����	M���uN��r&�x#@�0CY�n_�a/p#�5���
���=�����uK�J��Cy�[#����V}�\0�=F9��.��s����U�"����������M����M��n$D-�5���/z���1g��|�t��������q�1���Io�t�5��U?,��������%'$�c"�d����<!���������'>Y�`�{��7�{��&�c�5f���Y����3V��7��P������&�c�5f���i�����U��G���������&�c�5���

�����UC�W��P����~:�^c����x�q�[	.��!a5�1*��
'�er�P!�����_��<�����2VC=�"�SH�,w�PCF'p#�5f���zA{��7�{[��F)&(�P��(&��{�I����^����M��n&F����By����������z<�������ZbT�	
/���('�0������L����M��� Fe��B�9�r�q�1�1L|�O���{{��w�Q)((�P���=�xV����g�,(��M����cQ*

1�'8��(��{������5XQ8�����S�5�x�� ���->7�3�{����=�����#y!s���jt(��1��^c��}g��looZ�V����gUk,�+��n�����XM���������W!����y�����X�3r���=�����mK�Jg~����yz[��n������Eg��looZ��1jyo2�j��������Vc����=������@�JIA������z�F��V��g������'L����~���8A*$p?���-Sp�������y>&%�Ux�,��qa�1��������L����M�^�B����Qx�<w����G=����7>��������I�;<�"�Sx�,�y*Ps���VS1�m����I]�&7s�1s59��LJ[o�\M%����dooZ�VH�s�����T�5��WS�\PMw�uN��z#DEL�0y�n�����x����<�������m{BT��*�_���"����V��	����i��#7��
}�����n������r7��=�����O����Rh�,i�4"���s���^����M���#De�B�9�dn�`�YMsAp��y��7�w�k�1��a��������Xh5-��������]��/q����1V;���I�7�]c�j�*���wz{��w.x{l�����rx��^�q�1c5��������%$�c�5��K��#��k�V�%�IA{��7�{���Z����9�jY7�^c�j��>&h����u/!s��<����~�(���Us3\�}�B�jnbT��+�_����Y/p#�5�4��,A{��7�{�		��{�����~�H��ss�gKn����I
	��{�uV��qt��
}C������w��Gw��7�'�QI|^(Ot��|L����R�y��e
g��V��j������?p^ �1��V����� ;������J��P:��������/E�����7>�������mn:�_c�j)�,J��+������"p�6���/��t�����R"Y�7WsWK9]p.�����e��������Z*d ����
c�j��v�g[|����n:�_c�ji �[�7W�WK�]PKw��7���&�c�5f����4�}�XL��AM'p�6���/{�t������C0�(]n�0����o�>��;�����lv�1��W��tQ���3����o�1��!���M@�-X+���wf���9g�_-3_�s�K�B�jYxB�xy�V�<���d���3����o�%X_8�����[A��L�0�y���d����3������-����7���w�2T+`���_���1��������V���%C$�c�5�����c��k�_��Jt��������d�t�����k
i��1D��5������M���$�q�SR���Za�����:���1����p	����i�K�H0��k�1�v(��I��^c
k�f�
��1����5_!v���B���\�������������vr��?����������?�<��O��?����9j����~������t���������hg0����+w����f��x�%��%��;��=�����[��a>��6��X5:����~�dV�
x�K���%����cT|Z��
X5*�u&���dV�	�v���f�8��'u�V���)o��iDR�n���6�|��'u�����';��:��S0G��:H��LAq����J�c��d�sZ�V3!*���CZ��xP	��s_'i�[C"hO�=�un�b\ �cyZ�6��������JZ�6 �������m7bT����������	��w_Swi��Av+h�v=��n?c\|�cyZ�����O���R��y,�;M�i�K���Wvl#O�]�V6E��<��xw���-,[9�������t�����i��i<��R)�%�wgE7o�;-�i��4�/���E�����#h#����������N�sZ��1�%�;V�����T|��h���<�� �g�Szw,8�G@GhKT��=�;�08e`���{~����mwN�]�����x�����������]�W�
��O���8������B��������\�����8�w��^�4rW5MK���������Q�T���nX6|zMX|W5]A����������S�u���nXz|z]x]�u\�X�1��;����n�\�l��~U
%>�>,0������!^����<�w���x�o�:���E�������E�����#�w�������~U�
>�H��u\�X,-1�+�;6����2��L��>���Oo	oA����u#�xp���������z������z|{���w�����1�K�;�'u�+�����3������������-��	���P��H�m��������-'||e�w�B��U31���;��uo�|\����Z����u���V�6�uo�c�
�cyZ�����6�g~�����t�{��9�{1�:�^c������6�^����@w�g���������y���@w��*U�<�P�p��@����w�&�#�5��������k}zG�:�������6����8��w,!������l�j�e{7pH������%���M��m��k���!�����!�(��F�&��y#L����5���r$�/y�='�����rZ1�����=i�+g����P���7�s�{G{�<�s�{�|�����h���=����\������yN�\���1G�kL������}[M�������=������b��#�5��*�����-7L��
}�w�'���:}�w��|�b�h�Sy����;��M�i����;����<�E_���r���E_�������E_�s�~��^���;���hi����;��M�i����;��"�����{Gg}r�{G{��9�w�{1�1�W�-��6&yx���u/�b�p�v=�u/�b���5��}�w��+Z����w�g������w���Tc�hc�����w�g������w��o�<�Eg�������Ek�������Ek�t���TU�1WZc��1_i����;����I�[L<��������fol���������fsli������[+��;��u/�ck�9���5����u�;�B��fwl�t��X���������X�c�[Z��=����^HY�l���������������*�����:�{��9�{�[+��;���u/�ck�?�U���
�u�A�B��f�l�4��X����l������-�:���u�?�B��fl����������������FZ��?����^HY���������z�������5�������#��2V5�ck�?v�~���el�����[��z���u�?�B��fl���������������|UZ��=����^�W5l��������z�a{l�������awl�����j��(��;6���.�c�;v�����esli����j��(��;����.�c�9v�����eol�����j��(��;����.{c�7�6�w��6������i����Fi��T.y����F��U�L�q/[c�Hk��\U���Fi�u;v��u/{c�7VYi���l�m"���U
[c�5��X������m�����a����k�}��9�{��(m�n�F���e_l3�������wF����T��|���x�&�����xAV.p��*J���A{��7�w��Y�x��1i�l��We��uj���!hO��&�n��@���1i��#�U:��
Y���#�
w���z�����v�bO�]��JK������l	l�-������eK`������j��*=�J�S��'�
����z�=����
c��eS`�4��K�]6����c|sZ��)�U��3��Zv�ZW�qZ��+�
w���z�M�����1e��+�U�}P��)�
7���z�=�����e��.�[�)p����eO`�	<�7�u/{[�'�9c��eS`�5�h�M�_6�������M�����1]��+���w����/��HW���U���V�
t���j��jm�J����ll#m�RV]��RTD�Y��H���M�I��9������-��	���I��DZ.p���N��A�{��7������3���
�����'X��%A�{��7�pk:�_c��k�����E�]����=������J�JAP��t��_']w_�Y
]��\�
:�t��?��t]�t�"����2�o�������9�\����Y�&]��&^O�Nz�o�=g;�����?}<�d�w}�"[�)����@������l'tZ�R�'��?��w@���~�^��H��/A{�:�{)��1��}��2[�)��v����w�C@����N�^
���1=y�;����{(��������	����i�Kq��������<�zO����c}zW���n�����O@��kL��*m�'�{po�����
�6A{�:�{�b&F��V3}�C�M�F:;�O��Ph�g�����l�Q)�)C����D�M�F���y���-Qg�g������Q��)��<������0�5����5�l��lGtZ�6=1*e��X�64��nD;l|�-�l��lKtZ�v`�t������!+��up�Pd�g{������Q)�)!���GV.p�V �u����=����#�5s�1k5�������<�Qc�g����wZ�Q��)L��wFZ.p�7��������=����KO�J�]e�[
�r����)�W�<n���>��7l<�cc�j���o�f��
u�{�/:�{G
�s������pHFO��/{������"pO6F�u/u~�9f@c�j,q>FO�wl�yZ��x�����i�K��`����k�GO�wl�yZ��x�����i�K��`�P����e�������:�s[�Z����������	��s����CUp�wg�������dgtZ��3!*E������z���P�';��zwlQ�	*U�<�Q�=�k�*�wG��������6BTJ����<��Q�o���zwFIP����N���'F�$X�V���\�F�8�	���]Q�g���wCIP@��kLX��-^�!�I��
%AA{�/:�{�b"F�$XVS��\�F��������CIP��m�N�����������J$�7����y�[�"(h�vE�uo��R��	��FJ.p#j+cJc�Q�g�������Q)6���� '�����jjQ��g{�����&�c�5���I������kEi����!h��D�uo?�Rl�9��GV.p���u��R��=�����#x5s�1i5���nDLg}zG�:������VbT��7���4#+�1����;��!p���������
\I>��wAZ.p������z��=������5��1o5m��7m��k�FZ�n�x��M�I�;�MP@��kL\�l��6AMi���3��H������>�Y�T����/�g�Op�'��(8G/��f6
�Z�`cL]�l��FA�f�����#��rW3;g�S�5��fv
�J���:��_�
��V��������*��W3[g�U��X������#���W3{g�WP�`��WpVz��5Ai��f�9�,x��7��,8k���1}5�Yp��w��I�_6��f����i��f�YkTf��/�g�Yp�2���e��i�����,8k���15�Yp�����f��k|��7��(8k����<�e���5
������s�Q�`�oR�.�D�Ju�5��������.�A����wH��<������ZJd�7�|Vv���q���=������J�J��MDaU]�������H��������!:��{�y.c��<��##���2�o4���o��Z"��}���m����������a�PP��s�9:�qXk�V�9��3~+��
�XE����'uo�z���u}�9:�{����[gL����*pc���;�{[�Vo����i�����1��}+��
����uo�j��mv}�=:�{�����1��r��������(&��j�7����w�Q���}+�
����m�:wD%a�������sA�������[��U��J����QGX���o�G���2b|��V���]�v�o�6H��U��[��N{tZ�n��t���<����7���w��wCa�v������[��"���)���]n����ys�!l�J�w�����l�Q��u�*���]n�=�u�-�{K�6o��;��i�[�����&�<��^W�q�qp�jT6o��;��i������zc�j�ZW��~�v/wln�>�w�����;67m�foLYm���);6w(���;6����)��;67m�foLYm���);6yF�r����y�=:�{�cs�vl*�<����M�����=�{�cs��<�������i;6{c�j���M��9���u/wln�������;67m��2? �{�csSvl�����K6����i��K67m�foL[m\��)K6�����/�ln�-���VSQ0���l*���
�|B�pc���s�R������r�{�=:�����`oK\��M@W*Ac��f���Zl�N��� F�&�x�����Z�	��a��������G��o3���l����m��-�1m���	��G��oWc��`�m�y��u@�)��K�������u���������b�V��WS18������������������_���+��l~!��]��o�V��w����r�������
���o��o���M]w�����_��O���������������?������������?7�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������7��.~!��������n����{&����3q�����������</�c����.�)���
���5�
^W�����x#���@�<�^������c�����e�r�����	k#��M��X��,e�q]=����������r
��k�����,��O�Y��AT����(����+�lW�`���}��9��>�s�$�-�2<�i��l]���tU��@ny�A��O���/������3�w~�_���������e��z���������!���u���o��o�o��/g��������rn�������o�e������~���S�������?������^�2L�?7M�X��C�G�x|Qo�v��"h����-xc�XtrN�*):W�x��]G��2��&�{�x/����B��:l��;�w��J���C������������������+��������n�@Y��\�!6w��������@�=l\*�Z��o���\��>l�>lx�C�{�>l���}���9`V-a����6���������	�8�/���-����}#����n�8p��Cb�v�Q[�np^��Ss=�������o1}�������T��M.x���������s����i��
�9N����G�4�g�m��mC�k���'"��K�m%�m_�`���S]� ny��A���Xj�(��W����2�U���6~����Ou_���{�*�\��{�4 >^E}��{�"�=~J�����B�M�&@����F�0�Q��fU>��F�dQ���4S���zWR��Q������/���v�9�p��G���t�cI{�W��!��<o�;z��e1�	#'�CnU GL�E��	\�- �F�\�����|��R����<Y��������C&�������47��Z�����kn&��0�_P^F��\��h�1d�]f��o�h�-n�x�!��6Rf���]h>�fY���7��#W���c����^�1_4a�e>�c�[�C.��4_�"SF_�������d��J������e���~��L.�����=v��,h��r�=�GR��`��o����#'�#��oO�d���#w_�~�����S����Nt�M/���8����5�q3U�h�V�i�����=��fL��<�������fd�{�0&��J��L����ad�|�cr��,�������ad~������	�eLn�����V���2�������4&?I���:G��;/����
Q����1 1������k DP���*��zG�������_.S0_��hLA����m ���#��p�$�����v�P�~�x�e���w�P��l�������?���,���������%3?����_����h������n�4%����E8D��Q�'������w�N"���r�7"$��O�x�"��Cl
��h�����gx�r�t|���g��=vo.iJM���;�����9_�U�^�w�c��u�_My����)�e��u8-��L5�~::�����G��4���=�D�����A��CMH��	0��v������$��i/c�&B��<]���Oqa�rk�*����g����$��������z��\�
 ���H����$<�H�+27(��gxsQ�N��.���Ps�(����<�5cB�3J0GNwv�\I��ug�����CJ0��Wg/�������e��7�/.V����W��_P�ZZ��	oD��)��Q����,~b�h��\���x#8P�����e��A�
�����}	n���z����	�uE�������V���,�H�*W0G��]sp���������D� ss�~�%���X�����"�J����x%!�����jV����(��!�Ge����wa���_\�Z�'��_e����wa��A%�O�oj.	n����D�-P��\>O�{���:�{Q���������V���1y`L\�i!22q�j�g����CP�ZY�m���<�5������24�1&��b��ehbe�9�������4eh���^�J?�VhH��$<&�S���Juf������!��)��[�
�8�������l5����Ie��,�B$�9�5���=�[He��2we�6"	�%^�n��]1�%���\�Q�����:�%3?X����_����&Z�9>M�R���$<�D+����R�wPs����%o�#���������o��n,���LvN��$6C����[sIl|5l�����`��)�t����A��:J�=vc�K�C��;�U]}��Rtx?��Yi����ev�`'�>#g���I��H�'py��C]�Us����	(}��8ra��\aU��J�if���
���=za��\z�Fbk�}�u���w4��B~n�\8�z	�v5��
<F��a��x���I�R2�����l�I���J�hG
����]L�MM[��QMn�F��
k�D�0�9b����k�daj���,�`����z�x����Z�5c�F��;����U�����:�u�Zs�~�5o80-����a��{G����6���A����gX�� BV&�?�~+�GA�]�r��(^X�B�[s���xa	�j�*���E/��5�G��/��U$"IE���x�H|�A���0�ID*���c*i� I�\�Lu"�#�_��8�:�o����t������������RA���������Y&�\v����1y��6�i!22/�n��a�����x��2mD�_�
~�g�1&�����2m#DF�5>u�=��/C����~N���sS��FY����cz�)��4���\z��`n���q��9�����`��;�K����	���j�s���o?K�����We{�7����g�6�J����.��\]Z_s�^����x�>�����$V�8|���V���(�*h�xX�=~Ls�u���^�C&(x}&�n�%R� ���Sh.=l���g�r��K[Ol���an
_�����,g�[�Wmk�;p���\z���;���M[�
F�k.�s.��Yi+���=���g$�>#������A���H�#���oh-vN��|n_��v�K�ya%�\!�����DsIlPu��V"�%���m�>��,��s.��y���:���3�1���������������������[����u��j,k��Y�`�d��Y������g����������e/�������]h����������7�z�,jkY3&D���S�G�w
��j-���8����s����7�#�;�D���OB$�;���}v�/��#�������	���9���o!K����e�I�.��q�]sp+y��D�]p��V��k����kV	�����U$B$	����������X��G{a�����C��
�}�7A�wa��1	�9�����
p[Q�~�9��u��V������75���>A�����?���y���4�j�Y�m�X"2����!&Z�~�i!"2���-��~�V��2m������������24�1&W��n���S���$�`�24��%M�����O��$<$��w��Uz��Bs�%�1�2������m ��������j�LA����m� ���e{��_P���
D��9l����D�K�LA�k.��4�b��7~����X;�Dm|��k��%���&��Z����(�k.E����t�S���P;�%�L��hU{���\z��-��lA��)4�����%�v���[��n0����X��4��[<����GZb��������\V"}�`��Yi���'HG�=t~*�����������I�O�71o�}	S_��7�4�}	��������V
�%�	��V
���
�"{��J������<7;?�jH�[���Sr��c�:���,����\�[��JxR2����_n�����P�0KpNTgX3&��,�ga��N�"Y�5����=�da�83�.��Ff
�0�5c"Y�Maa�����ev��5c"9�-�9ll��`�]���3,~z���w���NE�������o@��'!:G���!�����~.���7�~zG���������~����e	���S����L,{�v���u$B�a�2�u��e�L�
l��-I����U<Avq�>�G�
����� 7D+
��1�A���h�`�MYr���~u������\�a�:�x�_���ES�����#w�{�K]6;�	
.����Y��}�l��a�	&o�e�F���m|
]��Gp��m��,�7@���8ye�t!:��.�^
��!26wq�����7��@�3,w�����hbe���y,!��Mx�2�x�Y��J{��c���;���c�r�e��c���nw,IB�`�!.B��Z��
A��`I:�X�~����)��������t D��"U/��^1�%�M�4�o������v5V_1s���y�UI����x�����JvU��)>c�,4q�A�� ��A�7������N>,��q!
8+��r�/�ma�V�
���D}Il����i5��.�
�4n��Y��Z������i��4�K��q����?w��}��2�e���
��?k���������qFe��?�����'p������(x�/��gW��[x������ ��/�$�Kb�e*`�^X�����*b�7��+�J�R�n�x?2R#�
��X�!��b���6�2��Ix�w��z�/��X<���������w���]n��X{w���`X:� �����{��&�Q�q���`X;� �4`���\n*��X|w���`X;� �������Q�q���+����������d-�Y}wMp��+����J��������`���0,�#V0�A����/�U�r�'X���ten�u-�~�
������;eeb�[���"p4�*yZPi�-s�A��/i�p�qqaB��	w����`v�n��f$�F��`�2�o�jZ08��$9�Ai�9p�������r-pw���X����,j��=�mdh�s0]a����=��F������$�/���,�=�uEO�ch���"�,S9`��'EYT����=t�����=�L;g�Fo��IJ���0�T�-����'Qdz��r.��av7S^��|(�cHrz�������T�2����&:���I�Y2�H�S�`���F�3<��v0���F�S���d,XD���#��gb>����2=������	�e������l��i�K����T�4�q�p*U��.��v�)T�DH�C��i��T)T�6$���x��N
U&������=�%m>�����%<�o����T�L��
Zo���-]���~�*s�`��b�.�5G#��A��Q�=�D���	��D�+k���N�9�J_G��2���i����+�*�����Q65eVez�fb�IP�]�|yX�9<��-�W�
~����'<�H����X��Kx��v���!����������{����W~�0&F4s��%Seg�ru���e�7Z0.[�zW�Z��h�`��5�;�{��t����@��%�S��W��u-�[�JP.��-������Y0�*��VZ08���j��d���V���&:��7`A��(1����b��������k&r6���X���H":���7
��j�-����!����m�������J��1���+�\�]Bt$C�p}��0'Y�N�
�e��,�.��/�I(�t���e� k ��w^��p�B��U8r����$:���S��vo�w��|$Pn��Y�e*G����\�?�=��
��-�\RZ�r��-�/{�B���-XY�r����JsI}�|�L
t��?�LM�H;|Lj���KS�&<d��76<Hc��(3�,h�y�5����3ef��S~]��[2�����4�����C���WY2�����4����,g���*K�WZP�P'c�b�L�����aL��2��N�I�����
�_�����V�jZmvs���8��R�7�NxP�����{�g���3�I���[P����X�(3���k��|�������m>�s����)3�����*e�B�:K��$<&��'o]�U�')3��_�>�\�z���� ���BI&�"FrtL ��iR������
5m��-�2��V��P�����f�L!�|��+�2�����[���J������m;?��I>/�I�q���w�������(����1~�����$�x���&����������_M�
WA�����>F�\��wT&�C7;Z0�m����>Fh[t���K)>:h[n��vud�F*��&3��[x�x�*�����t �?���{��<^g�����h[���8��5�m��
�>F����mm2��}t������+�z7&���m5��F�`k[k��������h[����X������]e���VV7�6���G�DY�,hWY�1n��2�0>&)�]M�����$5'+��Ij����f+�-x]NRs����Y0�p2����p��u9I]"o��o����>������k�����,��au��\�S��2����R��~D��\�)��2�#F�Z�S��	t
Cs��j�T�������J����147�B��ejk[��
��Fk;���><��oLj�n�PX���C�D������J>SefY<�������4�1B�"�/���q���%A�+-�t6�����/i�pgcc�@#�g�au^e���3�Sf�*e����B������X�G}|��k�adi�K��}4�K���R(3}xh�������L���R� ���(3}l���z�7���fz�&f
��t#�X���
����>iC3�'y
i�of�0����U��P�Y
@�����{��d
)`\P����_���
)�cg����v.�
%�f��z�������H3�p�h�w���������=|c%�f�Lp��o�+���'�f>7��/��F�]#7�Eb�������n�yR����e���_�`�6���]��e%�������e��z���e%�WZP����S��U�`p�k,+������Y0;#Ht�do��_�R�Y���l�6�`	����h,K���W@�,�]Gt+-���X�D��*iAew�]Lt n���%QbDV*�?��uA�&���%b�+�c��I":0�7`A��1.���P����@���`xwkY["F#:f����"p�0'i6ZPQ���$mM�����9	�^���v�,�x�i�������/o��{7���L��x�y�u�S ]��V�=f:m��8��gh�,�h-S9bd����A���14��m��e*�t��[�?a���y�[[�T��E�����S���<|������i����;m�J�:5�1��:����4�L���r�;���+��g�u����!�9��������\���6f���n&�9�{;C��H�sV����?Y�9�n�#��YQ���X��6�����7��Q�Y_���3WX�1�W_�V�G�����.	o�}�(�w`��m�|�������\�7����B��Ad�tU�yh�R�3	��m6��S�3=p|In3���
�F�m~����t���1��e<��������<xZ��y����luf%�
x��:�G,�k��p�4RF�rtL#�}�I4R<�q��oh(���3�s�y[��c�����J!�� �T0�qg��gz��y��J�g��J��$��"�m�W8�E�������+@='���={��d����*N�}��f�=�WW4�^��}V}��:WA��
��F<�t�|���k-V�v��d#�:f���7`A�j��q��������LV�v��d#�_�1�+p4,�#'��sk�<t`}[o�����eQ#����l�h��a�J���aY�9���&\iA�4h���\hA��m�CCn]�
-V����%b�+�c��p��������u�I�x�������x�������#dT�Sr�*����9	�_��sO':.�h�����0'�����{��M��>�CU���B�@�hv�{�)����U�e*�� �/~D���04��_���w31b������L�W�1:{��qp��VF�%.qU��%hz���o���R5�2�\�k�s6Y��6��k<�,�F�'hz��sn�J�}Q����?�4��Z�j�C�����aW����J~*��@r
\�~�����S _���+h������'��hN�|x0L*i&�����4��N�I�����������u�����.��M$xce4�N&�$<����lv���H3�j1.nU��I���2�����.�$�L�[	n���.�R�!�c�L�A��S��y��Gif����4������}������n?V��<{�k<���S2y1�/�c��*H#�<�����
9Wf��z�{�-���H3�C����;��$�L�C�N���I3	�'�}k/zW�uBi���f����jOu6Y���������D��Cx��
�=^o����t���PT���C��s�0%M���,<���C@�z�;$GJl?�r�~��(��������o�i?���D9�7�z�S.I�����������]������W�)+���������5�70���lz�d��D��ciX� 2������
f��b@�z!.�Ta��i&.$$6n�
JD��K�������D����;�w�W�!K���5�15�Jd
3 �!\�!�?%
�X�o�p�!k��R��+,r�5�-<���Dd#-�����D�Sb]_0M��2*�q�9�\���Q�Y>��x,����Y&p�.K0_��V��Vi��"G/�����������w`�`��<��J{�6��uuU�X���TF�vZ�.IU���[X�5�T�<���w���c6,T������nh������w Dd}��2�����	\���� 6
xi�Gt���o@K����	�������1��-h�oY���Ev%�+e-c���\� �!pY�\��J����!�e	x���+����_�������j���!����P�4(w�ak/���z�O�������!k_����!����V�K�c���r����Z�N�c%��$�5������������j1:����FG���2��(�����X;��u0@�?c��T�aRi��q��Q���M�DK���	����PS�N�Z�J_O�B��;+����5@0�qg���z�x�zKv�Yit�8���N��j��#F��)h����~a��M����{L{��>_��t�+M�!<>C��^�$�(���0��|R-a6��O����1.!;Cth���-K���4����^�":V���R�]��s���M������2 o�-\��,�?C
V�6��gm��@%O���3�����	���+	�n��b�]�/��jPQ�W���D5��}/��e@�����t4`P�������%���9f��:.��]���,��F*r�*������+��!���9�\"p}^������:(L����D
M�P����[i��0��.(L4a��K�M-+�A�0<T�����@SE���C����%���L����U�E�#�u��mp�Ge��"�s_�b�x!:��.����L������x)�c_��i�����L+��^�����2MxL4{%�,�-��iYo`��/;���x�_#������)��?���!���m��k��6�!�
�������� �#:��e�%�@�d7�]e����iY�����]OZ���{��&L�3~����hRx�
�D�%�����������T���/��������I�����H�s��1��� ��p��$jL���ai>�s�����1�K��Sm�@�}���{���4_6�|�SP��c���������$SD#s�MSDi�PE��n��o�n�i��1�X��X�^����J��� �Q"����R�1	��I"h�Yi��8�p�v�W��j���S�����ddH��+,��=��N}}xV]����C
<>���^o�6�&��*����%6,"{7�R��s�	DW�4`p3`mXD� �~�1�.�x�x�T���a�k^0���6�AR^������A��G0�7�21�a5����������p:���o@�j���Q�����]�h�`9�1��z��m�r����
\���e%�J*��&��������aY��NH0��[����
�����D�}A*c(�
����y��/�D8GA0J&��4`pEsa&�q
�9�����C���
P^������/����D74����j�����Q�Y=�
'��1���X&p���<)#��G>�c\��#����'e$p������S�'��L���yVz����DjL���-._]�&V�8�1�I���<&����]��R�1=x�4��w\���q�N�Y=�
W��u�%�@�d7W��1?yMt$6�`ck�;"��Uib����Fbs
61���!����&�6�Qcz�Hln���'5�u;�y*�&l����/Kb�m$�c�e��<�F�7vYX���w�J������tR�x'DB�oS�1=p��N��e�)��W:�[>��K��c��!�����A�1ik��;�=x��M���y��f��Vc�w�W������OP��kR@2E0R� �c�(-oJ��"<���z��k���7��P<�'O�p��J��D��O�`a���D�Ip(�M���]wV"5&�M���
�:0%1������s�6@~�{C6��b��5q@��L{�Y����}Y8��j������&oQ�d��EdBD%`R�����N :T&oW����L�+
�T�����K0X	h-����J�`�0;#Ht�a��t�����CA*�Y�
8�F�����"�s��]v-�-4`p:kkY
D1��!���&:���1�e5���zC.5 �o~�W`�eY	9�`���]v%������Y;��!�����9]v9+�qJ��M)Z�����7�����!DG�R �0�7P)l�g"KE��������`�}��G|{�P���/�DVR3�2���%����X�\��2:���*k�
�tj�������[I:���7��.�#:��-�N�Y&p���$������H,���2�#D�X�9f�c_��i�s%
�����2M���|L`�}k�����	L4�K5&�Q� xw�qC��z���KN��c����HA��!��AD�'��"���r4`0��
y"^�����C�����
h�;x7P���d�WD�ItuE~{X<�1]�=������r�����,=����x��W�\�����F���#z��1;���
/�!!���egF�b6&!R� ��<�Pcz�����Bw
5�n$�o����q�����Bp��f�s����Tj��$O�������}+�o��f�}�3<��~�6��O��kkN*E��:SDiySE��'�����4����~n)���*o��Y)��D>J����;+���F^���F=~g�Qcz�@�	��_�-y����j�Rb!W��irs�6'%�=�8����"���,����^�W]`"j:5f](�TS���=�+m�����	@7W4`p�ToXD� B�,�c�]J��A�,p}�	q)h@e�T<%�d@�3��
��DV{e���Y�Y�C�z�j(!���,�P�!��CGzm
��
��DH�s���&�����/}�jhW|}d���DH��@�����/����o��������?���?�����������������}���������/���s��o�������JJn��c���&~������_���������z���G�7����RB�-?���,+p�u�`��^��Lj��������!B�-�c���~`��o?��!n���f���Hk�����l�p]���`os�~��b���/h}�]��-����Y�����kP!��������`>}�'Y��m��7�J���A%?B��L�Z?�VXXO;���e����-ZM-{�#8��.�n3X&�������,�-�3&wA��`��"#s�]����h�7j����P�X�<,�#�8���vOxH��{�Q���v��z��`>t����7'd'��>SY���6�:u"�_�+����w	�K��W�O��g��n*i���
WX�
��W@G���-v;
S��_AP�V��U	����
�����w��2r��7�UIx��fe�E�M�j���D��]��Gy�* .!��X���$jU��,I�F�i�~�*��|:,�3����a��!\|�s�c���7�|�n�djU�c�^wR:��}>I���^?�[����'�W{^y�c��B��k�}|&kYS��!�
��P��$���Z�P�u��wV�* �����u�;+�Z���$����DjU�[n����:O!�&���=v-�!�.H��{�d����X����ib�!�{��5Y7�7�m!kE_��l��x�aD6,�#�pn:��lX�hX=&�������e��:8����c#o�:~���	A�B�S���~L�MI�s^s6���
+�Fh|t������h���FW�B���i�x)�������,h4��z��m��dsv�>Yoi�u��	��sk�<p�m���e%�F���x�u&�
$l�gx���(1`n9����
��Ldp4`�/�<�!)h�0�)�#_��	z�
�����s��Ld�h������{BL�q'�Z�������X�ubX�����QI�;bdt����G>���'���-8bdt��c��?^�ay����%�,dt��M�;6:��b���<�WW�=�L6e�����KR���1�\�r\=�J�Ix\~.x��q�p�&����!���I��{K��Io������5�m�5�`��s��1��������>�#��{�������o^l�1_5&�my������l/Scz��&�o����Xqm�6����vT��,�9�R�k�w������{����O���%�&wB,iA����jL�W�)���!��7���yX�|L����s����T��I�D���C� xw�y��w����G?G�4���6N����=�t*E���M���)�"�����V�T��U���1��n���h�p!g���B��A�`T0�qg�Pc\���=|g�Qcz� 6�{��6��;��t{�!5��k����^r��=��
��2���7�'�=��~������l��1[��u/"w�e�W3���d������"rWZ��r�M�D�d/���[x�+-����a���<� �9J`/"w�e�A�n�&r{.4`X�ZZVC����7ey<��d@."����]iY
%F�����<����$���]iY
Fn"��M���"�-�����e%b$��l"o�+������"rWZ����������.g%8�!�E���,+#e��u�i
�E�[x��.�D��|S6��g"�������L���7ey�zyZr���������Jn�����%����V�)��M��������yl��E�b��wg��=a\
n"��M��#�=�Xw�Z&p��Lb�A_�x8,"��
�2�#�T����|R�Ip���X�W������cm�V��4�50��]�Q`��1J��$��+�]���5��j����`�����%�@�-�l"�O^�V��o���\�h�+�>��"�;��-yb�a�:��u������f����=�1�������������6j�s���MKsYo#eyYi*�cj������x+��_v��1	��,ooT�I�����- ���$jL��*��>��K�=>�N�@j�w �Sj[�I�F�	x=������)�>I�)���������18��(`��;��"J���(��'p���m�*�7�Sc~y�?�����v���B�I�#%C�����B�����:��$���F���#7�d���R�w��a%x��!O�����=�f���a���x�T��34I����:��z�BS"��1����'Ux��5�9Q6�a�`Ley��N���0`x��5I6����:b���\���]�'��r������z�x����]��L\Y�Q6��pe�'����zl�2 �=�&�>���6�k�E�n��!����:b��z`�n��WVC=�
�Qam@W�4`xFEmXV�0>k���#��D��=���h4,+y70>���-g%8W�����6,+y����s+B<p`Am���e"���?#q�pG���.q%����O��s����m4 ��w^����������{jL���v��T�F��P`&Sc����j��*,�n,8bdt���������:�J�X&p�����EE�/����EE�eG���M\T���W�	�eXn>�2�aE�)�c�m�J���y���	L��	��1	�+i�e�7o�q���m�^S~]��[��z�)�����Yw�Z��z�)��g}^�Ef14��0b�t��C2�+������t���O�,l��d�	�.�,�����	_je�D�%�����!
e���<��e�+O��<#cvR:)���81�+ST�c
5��oA����1{��}�c���U���_�0�����o`b�-��3C��C�lMp��\!ffe`��2��J)��cQ`�VP��}]�������-�m�l���O����t�L��+��%^�)K-�K��"<�����
uE�M�Q�h�������O�(Eq#��]���I���������K�%�����_�0$W��������eQ2�e{�d��b1B)*�c�G�^����RT����PvEV��sKF�*�1�m,�������d�������Z���,h��R4�{���%����7`kY�&F0�:b��l%��4`X)�Z���*i��R����TA0�e������LE���uA����e��A�
��'�]�Lp��	��-K����������KE[��1"!��3�]'Et�Bn���E/b�hA%
-��m���i��X���z#TI:f�����I�,xa6�9Z0�5�F:��m��f#dI:�	��A���h��\��0�+Z0.=r���%:�qw�����GhD��E��l v|x�i12>{3
,c����4��-�8bd|����0D��<���eG���c\0��c��j�����!jbe��
[��%�P��IS�F_����73��v(F��R����Z1��;z�1�7����3�<��9��b4;�Mp��9���#i�%.;���y�Hp.a�hgH?�J�sQ&�(��f�CG�s�hF��4�d�
��hF=���VM3�}��m��VM3z`��MA#����<r�[����2�f��U�M��i�RhF=p�&h#��I!)&xz��k>�W��J�����O2��U4e��)�u�It�<l���������u��h� ���G�U%���,�����QF��:���>�$�(O`�c���oh(�`:]f���^�+�����Y)t�D����-�c]&���P��;+�.�������:7����2e
z�)�]��<Va���Y4�b06�y��S���ib�Al&x�x���N��j���	���k����T�R.;�tmIF(�Z������Y0wA�CJF�,hXL&���J�e����L^���=�(����B�w���UQb�KZ0N�8�;&�{0/7`A�����3�`n}��n��[�{��(1rk���R�P
����e}��m�m�����dA������,0#�
�&n����� YO���~��_��x��UZ#���
���LF������u���P*���d��=�����E��~�� �c�_���:�A��
B�\h?�4�����5��6�C��~;�R��C��������y�@�0(��.�Cw���W�E��{D���2(vH���~�Ju���t����,��������)�n�5�D�L���Ajbe��)z\���@����[<�,+m�mY�����WV���	e���Cj���.�ko�'�="����D��O�z�;D_'��F�]����'��i
X�eQ+ZW&��b�L���B�$��u�L@�
�s��{Xq	��U���\��������G�����n-���J�o�r'�D�	�T<�7T�I$����JrK2���s�<����$��7(��$3]#RL�	x-�����__�}�}�$3<���`��
/U���K&���&Fm���5��EO`�c���o����5�$�P����{g%�db�GI��Z���H2	�j�<I�wV"I&�������R�d�H2K�=���Z�����l�r�d����A��k��4�����z�+^O'���{��O�!<*��x�A��L�yI�$�<t�\����cB�
0.Yw���L��^��
��D��s���	Ao�)�T�:�%
��io��e�����A�jY0��[	Gt��92)�:.-��s�=t�+��(�B.4`|r����A�������U�Y�� y� V���k�b��T�d����D��Y�s2��U�0�FBdS�d��� :� �)$�����gA�3��@�Z���.i
��s���e1�F�d��e"
')4�$�#��{BL����A
��}��a�������D\n��J����e��*�e���2�#D�J����r���	!28W���>��L]��\}Ne���dS��&u��2��C��(J�nXPD�Ix����;Gd����/�b�%~���[� f���f��c�O^�14�y�%�@�`7mC����@l6�q�%�����h��d�WD�����<LcxTcV.���_}���N��4���,/�,����;m@��R8�eIx�~��E�	�Y&���F�Q:
^����kO
m�i-+�
|j�AR{/��B��A��8��6�������y���f��z�P��1+4>�e��~Y�1�
��o�:�>�����C3�����1|����O����'�=�f?�����������o(�����8w;���;��������B_��5�{��ZV"%��j�ZH�e���BU��
�4ZV�[��.;���u�z�tZ��df�k�(�����b��������Wr��x���{���y��-��I�_Y��	2�F����d�m4`p&\eY����S�Q:�]��EtP��;���%xB�2����
��O:W��A9zeY�'D���E������eA*r�&������	\����dBD�F0��]MMt+
��W��d@�JP������U���,�"�6�9Fe�q]]��A9zeY�#D���9f��b`�C���w2T�E9B\h@E�_)���	�u�����D��R���/�D�y���
xa&�l4�"GorH'����r���L���Q0��D����w��V���p�]jY��.�\m�z3!���L���
Zm�A��Gt�����eG���b����c\/6�-8@�^�V�k����L���^��+���dS�o��E�T��
������3�
�~��TkY{��cPIX[��8������k�#�9��Z��Hvs"�i��u�7�%�@�d7��2�.����Hl����'-�u��=�L�ol���%�.��fm�W�e�<�FK\�^�������G�s	+�wf6I���H��`�Y0����5��.��6R���9o^bE	\��bx��-�c
|S��u���15&���������N����j���t��Q��k_���d�(`tX
�)"���2�Q��(x�|C��DSc~��<����wV
5&!�%m��Z�R�1=p�P�api�������_a7���tj���y���!�o�c�r3U��0���&���$����ghW��z_tEN5������
�����&X'��=���wZ>�TID'x�P���U�]cxsp��*|���Bt��w�*����Ld����]nF�C�&\��%��e��T���d�W�w��3�U�N��w��p:�k]
����������p]n=��s��o@�j�����p��C���!�
���r+�<t�� p}��<��h&�#�s�Y�n ���6�e%"	�AY���V�x���A��0���nP�r�3.���K"�3.���%]��e@�>������L�C:mI��K�=5��u�n���)�����Q�9<�
�f������2�#D�9^.2�|D��<�I��	 .��"*��x!:��%(*j-8Bdp^QQ�<^�&��qy���������P�.��w�5�h������<f���������B[5��<*��,�u�������6�!?yMt$6��ZK��b�Y�6�!�GtxX��Y�%�@�x]��,�>�Qcg1�������y� #���.�,���,�/�&<Ni��)
e}`A�%�|�����1
}xL���	���{-�b|LC��jL����7�Rc���A��_B7X��a������u�m���B�~f������Q)�}x���S�f�A����n�����P;��W�V���`���o}��'H~��&Sk#o�FQWZ�@����E�o���
����-��>mO��I�����`~��J������Y�qp���^F���
�!0=��R����V��d^��(`�=Y�F�����Iib�1��y�e��$T��
"���	H�nY�&���TdfCv��8O���	�-���Y?(2�!{��� 3��1_�u�n@
�����l%����2����M�`����d���u��Z@�H���l���#:���o@�J-!Bf&�c��U��d���u��ZBdB:+23{�/��b@��!����
�]%tT2���AhY�"D2���������DG2�S2�-K^�H9C�(e]�dA<���Ld����)������������V�����!��q�O�g���Ld#5�)��\"o*E��
EA~#et��+����GqY��w�	!"8��"�!.\���	!�4��J9���8B���L��y��A���7*�D��<<����2
���%��)E�D�i�C�)xc�M��F)Jx�4��;��:��@)Z}9��?�v�u�����>D����"��GbS����|�
Hv�0���5
�*�v����`�0�V���@l
\_)Z��A�,=�mA�~c;/�,}���Ze���-����6j	N�m�N1�����z������� v��-\�6�#�R����)�4p	�vz�������O;�=J�>�o��Y��5p�ScjO�jL��gb�����y���ORc�vV����!<�e��H�akbT&LW��7�"���8�;��~p����UQ(}=�({��jL��G���Z��1}p�P'�I�D���#
7��@�J��lQ�����af�4��]#h��b��g%E�4�&M�!<>C��^��>��*��V��p��+"�Q��*|���	D�*����vEd"���V�w�K)>:z�U�����Cd�G��+{�r�7L�
?��=���J������*�`W
�!���T�K�YGtc�lm���>D���9f��z`H}�����C�h@��77��h� �?X����`�0��GR_���,+b�h@J�wU�3�D�,p}Z��9�`>\Y�e��2��u��XU4���[g"#�(\���e"c�di�����)(�X4`p��p]&2�H���K�-5��y����z����W�����a\��	�+,38bdtn��`��t-sd�\a��#�s��X��/D���i,WX�p��1>�
�U��(NCs�-4_^�&V���Bh����4�i�c��max���+N��<n`d�5WU��\����`�^��
K��1�aT�1�@�ycx�+,�bD-|T2�~D����
K�9�a���1�K�|������&:���f�Uj�6 �T����������uzQB��)�
r��������*x��r���wR���&g=v�W2y���������{���+#�N
���8��Q�����������=���_��~��������������?��������?����}�����l$��BY���R������W�7?Hd���1�|����������������������>�_�������������G������w����?�M�~�JR~����Ow{H�SZS�U[T���R�����"*��/������5����������7x8x����~���
H*�7��m'���
��:�����Z��
��iF��7��.hq��O=x�+��-t��Wo�{����`�7����^����
��f�����omA9xq'���
�����|�����=��k^��s^]�'���Z�������\�J+L��W�_�pqt�N^��n�O^��'��g����k_���sO[��7GN�v�dH����IiHV��8ylG���/��9y_k��?���cO����N^���u������O��1n��,
��{����f8i3���b>���\{��|���=y?��
�����s�{���?1�qke�,'���Q
#���n�I�-�TJ���������?���cO���y<y������]����8}��������(Cf������W���gLn.`�l��U�$��Dbq��s����������=W�8y���<���7�2�d��G�u�iUF�[��:i��;�''wtO]����������|X��x�Z���W}�����.������93Z���i�2�����gmXte\���@t�*��N���Xf����O�+K��'�\��we\M�+��m$,�&{sN�����yNG'\������?��i��'����������+b��������N�����=y
88;y�������������w�����J��=y�����kE7���u �m��6�-�H8A{8G�t��������X)��������{�e9�!�>zs�.�u�'zrA�����3������m�S=v�	\�����#?��.����J�r@Ff}�&fS��y�Z>uL�"�|=�����]-���y��N���-�s�����i��z�yf�1�����������-|�����I���S��4+hc�q�������>^|�Lg�
\���U��+����)��g�����Y��,�P%+��<|�u[��ua/���Vb�j��E��(�n
\{+iY
<y��G����s�,�k���Sk,�^�	�����������������D��v0����-�-�r��A)g����>W�r{��7����1��p&��}�!���H�����,�-;��:��,?�����.k�9������\M�������5�Q/
�:A9{���>:'��ZU�6v��u�{�.�������e�r��
|�sU-7M���	�����Y�����^��)��U��66U��qoa[���\�������3�x�{<|�J|�s�-�0�7���&Yy}���S
���p��^�go��nPj��B�<g�k%.�������-�&�����\i�2�]���������m��|��N{�f>�fedZ|2t��7D����V�v������
��\m���Y�u�����;�
�\�F.>c1���%^���3>�)��[�h[��������1�A��{Y��\q��m�������h�k�w��%mGJ|I�����"`c����!��[����������������%�����%n���|/�x��G�D���}Cp���[����Cnn�3>{�FtUY��=�kU�� �����U��5����#�w�ko��s�!+��'���s�����������C9���Y_~�Mp*g��g��\i������^[�t���\��	����`mlX�������
���>V��v�.��\������\a��7����Y�Gg������T�M������Y�G+f:|m}`2g����u`�1GsV��-��*[���oT���72���7%����L|�����U<ne:|z.��V�W�����W���s�-�����lO�����qm����3V���������0!�����54!������	�kxB`���^~��e���Uh�����*���+'�Jy��U��'��	���V�WN\��W���s�-�W����t����{�WmE�Y�V3�����T�����
 py�>���9���g�Uq��\e�V���q�d�u���Uh��o�M3�2l�u�6�\7���j ��������V�H���W���s�-[��7*����`9_�������lK���I��6v����'n�I�����7N
����������l�)�Ku*Q��o���M��#�K{�8+pSf��T��Y�[hV`�����������P���l�)������)�w�|i����2,���9,DPu�[a�F(����U���\u�6�a7�U��u�a�Pf���g���qX����.^��t�8,p
�?���qX�X���W�+o�8-pS�:�v���7e\`o<~���M�X����������c�Gl�������GT�+o�8-p�����8-pS�Z���62��@�����- -�?U�r��v�?�?{��-���[��������q���������-�V�L���t��<-�q�J���r����+��[��_�0���s���{��g��X���B�����z�*���_������U>���_?O�*�����E����V��8��`�U\K�J{:k~���W�l�C7t��q�z����R�p������z��Y?*P������c�^�����o[�_���j��������p��7�
�tm|
q�z&U�������4�*>�9���j�����O�������>�_��?���|�w���j�����>��7�O^����>��l[$o�xm�zJ�z�c7��?�����8,�c7���
����n����e��5��N�T��L@����n
L@M)UO{�&�u���WJ�����'�Bmk��z��
����W�����57+�c����M@���)��iO���r	
�_���,�'o�{n�d����V���xm�=yt[\�T��w�F~j��S�����mA���*�W"��Y�'�|�m����z�<'�9pt7���6��{N��F��<�&�m�O�QOz��{�H��w��+����,��Wn��q����q,��MWU@W*#�m��o���X�g;�f!��J����g+��?�?{�$�z���^���Jw_\��'�s,����g��t
*��d��P���D7�^J�z�����l���{�P?��e}��?�����!7t�8
���{��K)P�a�.^p����������l�}���a����g��r��Y��oS��pZ����@�	����s��J��tz����7��f��z7�����_jY>W�����1�y��d���jR����g�/�V�����SM�}��fq3��9����r��������YI[�d������*p#�������o��nQ�d�BN���Z������Jy
��w/7�}���m|�����������m3�m���2�Q���-������R�7����L�R �k�?$��=���.����d	L~UN����3��o���/�i�CE��V�<.����g.���q!p#��u�[���*����e�+9%�`ex[$U%>}e|\�\ �V<����=d�uQ��D��Z%�U���x#cC��7*���b0��
�mVC�����l���������r�����O�J�Xd����;��~�v��Zv���m\�O�2���o�.�-������u�2�`���r�������g��i��q�r�������\bm�m�������b�7H[�I|�~�Cp����NZ-Q����U��}�:�����)����ob�5�w��n���+hy���K&>����S���U���5���of�5)����L�oA#���tR��9��c����g\�)�������d�e�������r�HZIQ���2�Z��5�a�����w�eE%����d� ���P�V��[��pW�r�AZ]Q�X���T�������X���6�=����sH�*���z^G�F�k�����������K��`��W*kKc�� l�����}imW!����qCIUMD�N�s0U�o���'�sd���	l
�JeY�u	�j o�at;�$}�V�@pq]��m��Y�.�MY^A��.�_����E�U~�_nX�d
L��I��;��$�-h]��q��g5V��.>�����'�wD�N�4�����������4�'�`���x���2���}W ��n�7�T�#:m
���A	\��*�D�����o�1X��^�8����N#�R�Wo�#=*6Q	�Hk���Q�&�$zt�������J`���9��Q	����W��G���@�[�g��5�2GU�$�D��G��Q]a���V>n�@-���N�j���k���������Xp��;��Z���T�R(���5���b��P����y`]LD�(W%��L{�3��'��U�������ve|�\��gx��%�y7���;���QJ�����.�-�J:M5��@��O�����Gv���T����LF���;�TX��V7���|����.�Gi>c��Y��|����S��`�I�L�����(����}���0��[��	�������x�5+�aj6K	\����F@�U��0���[�Je�Tm\���-%p#9��'h��o�m�1����~����'?A�R%?�?�/���,�����R'����|���j9c1L=1G��H\��9����
\���`��dF���M�e��p&�0)��!���L&aV��5�-��R������.|�,�6�L�.h������W4�����'p�+���+��qWR�k|��k^�0iO�F�vU6�����N��������L�l,�l��[���M��6���)f�R�����@�4�x�{���s
N��1t����
Dh
l?�7�qx�O�����,��`��G*��m:E��k�������FK{9<O���� ��&����n�o*<��'���*�cY4�_;������K���-o�����I7��X��1�	5&u���1�	7&u���P1��E�F�KR��7 G�5]�����`7�R�����t�?���v�6=�?�z�v�r�L��d�H~u������A�>�^t��iJ���b.�jBK����7\;���Nu������ �N5�����&a�w�Q�N9utF�8��QO)�!��K�[��I���I�|E��J�?���9�8�:���f!��(w�������c�8��ur��d�����dfE=�Y����	s�)��n�cV��Y�0l��2��-�DRZ�\|�\�x����	\���I���J~�w�W$���$����?2����%H���#p#�4�*D[�!���wL��k�t�+�
D��!z���t?|u����s\[.����
p��O��U�}?bo��<�D�i'��{\��W~����p����s���=�m=�G~����o���������������?�����J�����������*���*5�F��,��6�/��qD��c^2V|�����/�!������������o������O?��/?���?��O?��o_��?�>����_�����������>����}����XW���C��-;������_������?��^"��Q���"ihP��K-�����E���UhM�!��v���
]��lh��D~��q�m��}1��q��f;������?�i��B�>�C�u�~�=n��V���"iT_�{#?�C����Yn�����
���P�Vu�6TQS,����^���j���T����T+Z"y$��<~]�	J�6��ww\a pc���>Wt+~>~i����b�.���U��K��K{����S�p������pw�n���]���S�p+E�L��-pq�\���i���O���{5��%���=�5��*����e:�58hA{����6�ajeq�v�t��.���]�Z~�_����vi`�K��w=��vs�ZA�!u����*M�����`�:����`���P������dUb�]��������R���q�9m�+}��w��:+c�O�M�����n@��{�R�x_R0��vi��Kf����4���Kh�M�k
������m��������M�>��6����:��$����`K���?n�����x��o�O�v�l:�t����=l�����]h�'s0��O�`���I,�K{7h'�U�w��`��Z���5	��,����q�6��x<�R�v?���)%�����;h������z�v��P���q0�n������h���,Z�������,�.P,?����%�����+h.������2���n��C+h?�����z��h,��k����9��F�-?�?�/W�|��oz��x�2���
ZA��e0}�;��(ZcL����<�L��-��������)?Y�sn����LF�����slK�)wLa\��{L+�;���d:�=Z.��>���{~�}:����&���7^�#a���F�	�0��:k�S&��cW��7�e3���~23B�.?�?/9�O�����_��[�`����������L�����?cL?�������d
f&�5[�^o�dL�l���V�:���[��[�%����q�������!��c�T�0H%����o��������OV�E�_E����.)A9��6�:�A����U0��.��0�st�</	�OV�%�^��#���i`������P���>���=�d�����?��*4�U��~I�|�
f�y�T�N���v��������A���h�u���/
��
��U� ��������x�o%�X������o~��V.��?P|�!`������,c���������X������i����>Y54�f:*5����f�#k��R3��d��#8�d'2�����������B2&?�?/7�~�hh�F����L%es��i����jd�T�����fhd�tUL�f�FVL�p��~����5C#+��R1m�1V�$#+��R1��@���Nj9����i���t�F���h\�?����^~��^1V�'K���O<e�}c�X�3�lA�Y?@��B����dh�������3V���e�I���W�U����qY�+����q��������Y3��h�Y3C5����L�p��y��|�fhb�tTj���fhb�tRj��}[���Z45
M,�N��i�������M��/�����������5?�,�NJ��MF��+TL,�NZ���������i����V�vE6��LB)?��_*�>���
d�y�5M5�hA;�<�T�/pc��X945�u`Ud��<��������������v���U�������|A_��Mk�� 8eQd����������������O>��k�_��@����V���ww{��EY�gw���\�7E�7M�_����������������~���?��O?��/�������?��/��~��/_���+�������?��o~����$��5������������������������������C�����+��x����������������l���q���<��������P���v��?>������{������.��|�o������gK��_p�?�`��-������x���U�h�[�5<�_(�P��]9���Ue�������^_>�����s��Oh���P7O��5�?���-{|]>~m�+���}���o��'/���S������<�������iW=�����|x\���>���#v���������}����G��?���?>����'�%�����`��?�|��e[=������|����P����g�C����0��_<����?*�{�T�����?G���^������?���������z��WvM���=�o)���<~��S�������
����=��O����q�����n����%���N����',�~������������v�Rw��?I�����p�d��%��������U���3CZ����~������G������^��������P���6o�.�o�����J_�����a���CU�p��������W,T���T�-7BU���}���]�w���� ���n����Y�2�l�����$*����%f��O�c����=VQr �.����\���T�+(5_�k�4/~T+�C������n7�YQE���T�*�����R~y�4�i
��Se��������O���#�v����.��R���*��� �������5��3+5b���������^5}�^�K
i���w��}wJ�~!���gh
=_S��-:������������E)0�0y�5�>�������k������>�TC�-
����0�������
rK���.�I������X ���������S�2�q��@��=d=%��%��y�t|����7R��Q���N�{�r�k{��r��Nu0vZo��������\f����?o��d=�^"���z^+�3[ogP!�\F^����z��1.��w����&�b�g��B��MU G�y�������\zO�/���
���k�Av�������oq4_\|im��a��/C��||�-q��K���i����|����#�s�~�};/^�
Z�~�C[E�����H���6f'���
/4S�-�r�&O}+G�o��r���Y��Q��cux�
Z�~�e�,�#�3>����T����.�X��Q0g�;v_��������.�XK����wj|��UI�1!�]�y�,�	���<*\l�W����3_��|��$���y�Wcr����w]��6�}u|��u�k��`�+�K<�������d��N���}M0����k����c_2�`����p��.�X;��6���O��7R�o����o�������f�)����TWo������oh?e��q�w�yn{n��]�
`$sLVdl��wR���I�e�`���o��e�6��;b.���B�`������7���Y���7�����jb������0+��&e`���8.U����0+���uV��uV�0�y�B�:��2�-~K<��L�����~��y����������2����wa^�1����WZS��������?��w+��p��.��
�?�k�������w]�����S�.��v��!�	Z�~��[��'�?#��J�?A�����c+��g�I��������.��*��J������f����u��V3�)Mg��o��W�_}]��5������~c*h}�]�~l
��2�4� g��Z��&���?������?��K������u���1�����:�qO����wa��3�)�����g��������g������|��>�.L>�A&�?B���lw���#���Bf]w�F�1��s���o���:����`�k.�=&F�)�jk�jf������0����x�3��f��9��s���o��?��oa�[�����ce�[������V��5�.L>V��5�*k����o�����oSJ������o������(:BT������������e��V��w���kK��u���t
��e��
��9v�>���++�o���,��A�`����W�/7(�W�K_�wY��UG����������`�k/K?��f��������o���`�k/K?n��j%�Y��a�������������?�������	������h�%�Y?�Z�?o������c+:��V����
�_���_�A������������W����g�������c`�������Oo���`��.L?F��!�Z��cd�����0���x�3��&��1������o�����>�aa������0����x�3����7��������7+��:[��p��0�X��x�km�k[�2�-��wa��2��J���?V��5�.�?6��U����������u��+�6%��_\��'h}�]���O0G�����O��_]����`�����w�O����.�peG���_g+���C������?\��'�#�3�_\��W�_]����D%���f��������������W3����w]����Z����k��p��.�p-�_��?�����m8�]�����U��q��:��6�.�?:��N���G��������G�����_o�~���`�.�?��>�z������-�zs�����{m�8�c`o}�G��!� i�72���[?aF��1e i�71�J�~�L��S0J@��of�Vm=L���3��?_h>��9�k�`a��������0�-��7X�c�.\g���o�����=X��p�{��6��U�}�7����c���#���6%���e�\0�[���~e�����9b?c��t�[��h}�]�w����\|��`�w�n������w]�Q�5��D��Tt9X0`�?|l
bZVX�����\V���7�u�GY1V��
��sY3V�x]�q;0`�,2-��e�X�c�u	H�0�Z4~B�
c`���� e��h1��]���m8^���-c`��@�gt���c�uiH�1vZ�~Gw��]0[����=c`��@��t��c����i
80�J��Q��C0[����������l��8c����i
82�J4A~�8�c�����8*1�����p�0�'-Zg"3c���f"3c���@�Lda��1��Lda\�h��,��K8^�������3��1p
��3��1p�b�u&�1n�xl
ab2nZ4�D��1p��c���*s�����n`�o��2���4�K�L�r���7�u�HU"
���3��D����D�1P0�h��T���1��L��+-g"U�X�c�u�HU3VZ4�D��1����2��a��h��T
c`���e"U��h1�8�Z��&��D��1��b�q&R���m0[I���c`��@�L�c��1��N���;%V�2���B��:��>�-%Ll@�gs��>�������������O!pU���P�~��������~����,��������M��MS�������a���=x�TLU���'4?�PM	S}�wGs3��n���������� �j�}i%�A�-`�/�2e#����P;����K�/�����c�M0G���2�k?��������i��1��R{k�1;�7���7�P�g���
�}��_2�`���_&h}�Y�k�8�~^�Y��{���~�\�68��������+����[�T^�Oe�d��g&�#�K����Z�~l1�L�\�G��+�����o��	MR�v�K�k]�������l��
vE[(y����w���5�������V�g�7>C�Fc�J�c��>�������g�
"��`�*8W�~�hl�
"��`��JF��������g�
b��~��/�k��F��/4����My���l���;����c%��c������.h?v���,�!Bla������q�����e6����8u#�B���kZ��	.$>�P2���D��������H�F�����QUf��?��a��`�1��d�m����lx�����������,2�XO���-������w(�c���O�����u%�������tO=�~����<eI_g���~�~�W�5Fh��{����k�0��_<E�@�5�����n�d\�5x�f�~�_c���]�������~�kLzEt�!9$�K�����2���1E���u��7��&J��_��Ggds��=��������q��������x9C���G���n�d\�
�,��]L����;��1����(�~���#�D�@��������n�d\�q�[a�1n��Q��,�����:�M����c��
v
��~/�L�,d;/����w��c�y�X7Q2��f�?f���y�e��c�y�X7Q2������Y�l��Qf���~������y�_�{��f5����q���L��q~.sT�	��~���T�}��K����EE�M��l?�JCTts������?X7Q2��<��Y�l��q\��.����GY���^o�U��
���~���l��WU������u%#������L^
�*��n���M��k�
�?aV�����B�Oh��{����i?=�O�'�~5�B����5��|�~�&����i����u%���A�O��m�)���vi��?�*����'h@�����A����l@$K�t���n��v7����q��n����z����������f��h��|�-o���/�}���zA�^��-o���/�}��4zA��d
���{A��>�Z���f2������^�������F/���{A�����o�-�^������t3�����13��hM2�*��3����_���G���:����
XeH	�%���]\#��*��7NVyN#��*����/�AU�S�p���V9DB���{��\A��-�+����~)�KA����#I.�JN.J8P�v��B�!�&����`��\��|���)g��M.g�9�
.���,'���$�yT�'�B�7�z7���N�q�W��R������[���_
�eu�\����4��
��';W����qy�����L�*��n�zpUs:������5|y�5>v/
�R�e����,��������o����������������+~v����������t>=���/�^6y^�/���/��ju�Bh.�d�e��o�~��w�����>�����}��w��������\j=�e�|%��T�)<�.$Z�����b�&p�d��hrpv��CH���6�"[�����7
��Q�3vyc����Eg��6�Ew��l8�R��_����~��Ko�o_����?������������I`�4�@J]C�U���^E�k�o��:4,���N\o�����3��/�TQ����
����������?�����G�-���|�P���@~�C��h;����3�1)k����Nb�P�a�����������!#\{s7z�FDV�^���<^���tH'��Yxq6"�q����-���k��u
��\����|��������
y��mD�3�FD<�1�O/�����xB������u�E��H����j��g#��k���K����U��(���/6-~V����r��6" r��0+��>�1�FD<����X?�e#�k�v'YQ`�.�oB��mD���Ap�������;o
���P���h��j�������P�~W��Y���k#"b���[���m��h����>�,zj#"\�����'"�_�Sk#Z��D�.�/7"/�FD�:��OD��IsD�lD�b#������_N�mD@�Pf�B��$��������;�6��E9��k�9�����=��Q�_�H��PzF��xc������nY�
���"�����������(�������
)B��q�3�0k�ZNm#��X4�{V*=�FD8T"
�N6"��m�]w�����o������.��j��g#"�](#�Q]�e�W3/�fx�u?��n��$��[nD@�h�n��4�>�FD<�6��p��j�X�<:������7"���M��������7p��6"/�FD�����NDu�X�E�����FT��]�vEE�����r#b���0k�u���#"cQ��X�Tz���p3��q��Xk����H��L\m#���lD��qRx6���I�fe{������J���*�=�![�����7��K=w�y�#������������l�`E���+;�q�����w��h��Ek��D���Bw��`�Du����8����*��x�X�2�
t����8�r�g����Y�g"����+/g�c
Khw������/';Q�����W����V/�x����a��6���DY-�Kh�r�5�}�U>�D�����eA�Yi�8s<�����'��������������p�o����g2�L������p=����E`uHj	���<tX+���E+���,e�2�o�2k�H��}MDCKx�U�<�������
�qNp�wT�CV.c`�������Bq�R�%�j���?�2�������9������LN��+V��
�7����o�����w���[Y'����'�3��=�S�6l�L��L
��VUq���D�U�J���r<R����O��
��z^��VUy��e�R�X~�z��>�j��6��V��V]�w��-�����j�������j}��u�v���OYo�:������������S�/��O�e�~
����u����tL��9����?��q���74+Sd����������~��GL�4���9��~�5�=�Wo�����H�<���K
�����)[C8O�l?[Y����^��=�:.��j`���=�qV��i<.�-�iV1_1�y'�x�coo<[�\�t
�Z��_w�����!�;Y�C��p�>���������_�����r�hjK�"����q��:����/}��3��DD|���lO����=�y���ms?������zB����DVT�	���:A��L������<�*f���>��f��z�����@O��>�$��M�l����1�Zr�z�`�ELU^���7�'�������[�>����w�x���?���_H��h���;�}����N�c���IyX��
4,z��R�q��\G��\��� #$��j�\��������
=�����)&+���Y�mED�ur�U�� Ah��/{.�A��+��vsSX�"�/�{Y���Yu'7�����t�����c����SqDVG]��������r	�q�
�a��0����W�*�����I�����r9�C�c��XC���:�����.������!�]I�G��l�0�r��JTw��j�woun��q5����R�H#�J�j�.��x��������)3#��t4�Csf{G�LPb���?A���_���O��5�B��{xLP����;���|�����������#�/\�r�������?�@p[���$_Zso	�Y�QjKz��9'�}g#
��P0���cB�v2�8v�oBa�'�(�
�PF�k<M��]y�Q�*�`��#u�<d�������=��d5t=C���z�����j�������a(Jq�����4�������?�, �����Dj��R������
f��f�����R]�N�wf���������ge-~�6�������
���Em�]4���Wu�������K�Mx�=�x���i�[������?b������4�����zE�OC���oPk<�az3��td|�n|��9�����_���6��P�����Q�_�~X���_���Cho���+u�+�!��+����<JV~��~�L�{��C���j�I�����x,��Ge��,cJ��F5���x�x���^��(������].�)�yT�w���<�%u��<�}��f��G`�
8N�|_�����!� ��Q1�H�]OF���*U��?wx��>������y\�w'Yq��WiI-��"\���Bq<�:.����)B�p\*��t��:.=��d����t� ��v����iR����9�Jp�o���r��{!H~]5����s��+iV���.b��
��R�u(ji��`>�s�2�5B"�l<A������F�#��}O6��0��E0�L6>������ �d��N��m�^K��j�E�M_�H:�*��X���?'
A����������"��l�K�!|��]`�71���dd��@+=Uzh�����C*r����1�1�p3c�E"��{Yy
���/���t\'�q2Uv��T���E-��E�u�x�2�������#e/��2N�RA6c�.W��c��NV�����Irkvr��
�q���>(�����"6���#�����U�Qf?c���T��#�^c��<V�T��e/�Yn"�Rc�SvS.�I�y���|4��"uS��,���7�=��)���0�U���LS�16C����U��`��t�������������t�'������r8�_-2����j�U-nh����^�-��Q�YQ�!��;�8�z��U,��B"��[�����f������D�nX���������3���vEwMiH�n�us\��j�����';����r1���3����;���{����{��6D�m��{�����7��"�q��2�� _��0zgd��}�]i��>�����eED]��
o����Q�%�t���era��qzCAx�����>���
%\
����"��n�o��h����iH]~�n����F<.��O��O#�{�B{C�ZV��4�N��zuu���"������]���5$���p����������P����!�eWk&�����^-�����W�z���`��z=����h5|zg-�fZ��������}���Y[�n���S�{;e���=�����*��=v����z��/���\ny���_����Q�����p���p���>~T�g����.�@/��~A���[�R���#�kCQ�����I��g����I^�)#��rYd��z2{��`/����(!��g��-�"�L��4-�xK1{2���N�����q�e����g��(�ae�.Wq��
X�u��*����4����Dk+EQ���Tx�8L-:VQ]NF�bl=9���%\	8g�gRE��+c1�����6��*�"�L���I�%EQ�-pu��!��
GG*M!mY���Ga��EQ�+=�,�ei�w�
�����m��(�
��[ ^`�*'�q�1��E��]���S��/��{��c���4��k���8��S��o��H��V����y���~[Y����G������x����7�''������t���mF�������.[�o�o�-�U�f�T�)�"#�E��EQTu]���������;��������$��]5
g	���" q�Q������pQ�Q���E���v�Ud}h4L�wb����������V��zq�P/&<-�7<]����@SZ�(���i��+�����g�Q������Nm%��8�7��M$��������C�w���D�j����H,����� ���(�]�r��^��z��/�0��"��v-O�Y-w���jba�uei������5��s�<��J~��y��g�~|F��Z�<���?��������)=X���
��/@�[����7
���u���7���j�5�x������?n��b��<]�����{r����W��x l����?q�q�a��,�M�F��5���e�$�k�X�6��l�L�����mD����;����xq����;�=k��cU��+�L`]5O��Y]�z�`�po�j��5�r���}]5O�����C���������������FU�7�G��*��5"�ZQ��!�)���I�/����4��N�W3���$��Ig��no�	����g�E��"]����/]�SK<]�����x#�����_����+���75��~o���������j�������g��K�Y�"����$���t�4^�aS��W"�����X&~�-&~�.�Igt�oo���"��|��8�x=��sGNb<�P���/�+���������9����^�x�n���H�g�ssGNb<��[=y�no{T)<�?���
��/@����Q�T��T��;r��6^�x�0��%��of��i�7�P�.6�a�#�>���+���z���d���'��U1�E�U�UJ#�b)O%���*�qT1�E���RGKx*��W��b��qi�W{�GKw*��X�!����NI�@<���b�$�k2�Y����y��^�x�n��cV���x����b{�*oN0��W�/���<�Z{��nNc<UZ�h�h���[x5�m}����t��W�G�N�U�5�.����t�Q�tm��<�t�Qe�F��JoU_l���<���Q��M��1���G���7�4G��,��w=f�����D���1g�[�:I�7�h0���w�Qg�X�4^���mE��t�*��_�&������oQ�n��������d��e����:M�m11o;������#T����i���g��Y?�4]�q=�BIp5G��t�Wf�%��Big�.3W^qt@�oTG���\��+���8���e�(���9^���������&Ki�>��l����S�������)�����dG;��\�g�o��Ex��h������p�c`����W4�����9��iJ=��W�4�f���j�n�;�`d��5���g�R���[75�%������0��%#KY�vE��������QAW1�X����O�#K�v��+1
����s�AW3�TF��1�fd�w$�LV������3c%�9��h�Y�����F�I��9��8z��X�z�r��q���S�e��rQ�7G�P�x���g�Z��P�w���Y"��tt�����i7��u,����6?�u�,�n�����)�L�yf�g`��J����=#K��vE���/0������e0������=0��nW��hJ��yj�U�������rQ��7O��C�5Sn��Z�	�yn}�I<=1�L�n�4��
�����c3c�1*4��OC!���w��gT
�����cUFO�FI��Y�O{���i����+������cU�hJ��[_�������9�B�5Oo���R�*��NG<#*��Z�����2FW��i<=���BK�,��)
"����Gde	����I<�\��W�u��*\�������`O.��-�i<]2�;�DHV�
�#��$�.\Jc������.e��5M��$5��������[*Ti<]1�T�n�45<���DO�.�������"��OO79Mi]c���U
�K�7�l1�x.M��5�f4�����x�epi
�mK�,��[�����n'���y�I<�1�����%����K�w��;4��N�h������J�y�q�����?���)�����Mw���W���+=�'�L2��������^����v�����&��4`�QM"�/4 �	������@T/������4�i�w�0+6���aDFTKb��B��B���^h@N j1ZK� �Z���6��l�T%�����-��.����p�_��7��1���/���Fg��(������������km���	M�}r#�k�����c�)�u�K3]r�4����u\�b��i��������xm����\:��Nw�	��}�n�5�[
�.��]����?���q�<T��\��~�t����������8�,�`���\
�-O�w5/�B��:�	/��{��t���p�]o����*���0�Xo@���> ��t[$<�f�W�^�SSd���3����Ei�7����`Ia����������zq�I���Lc��!n4��kT#�1�M���%���zHw��r�����z2^�������coBg�&ln<�&t��G�
F#}o�������,���N�*�3����_�����"�������D�Y���6^�i<#j���/��\xwc<	�BWo}����[�����5�����;<�V����h<�������S��7F��1���}�[�k��Ab����_�������};���o����K>rAU���o?}���~�������|�}d����w?}���_>�����8������?��
n>��o��_����e.��������WY�����w5���������>���������?|�������������J����.��������������������������������vL����
):��f�����'����z���U���
�}lX������|�
�����g�����/�]�
�������?�����+����'��~r��B4LL��������om�C ���zb������� N�����U���?��:�sA��C�n&�~d����jC�o2$I�\��������~�y/����2��U�x�������a�����2f]X��:�,����	7z��g���e����/���d4���G�M�2�����79�K��-���'�:���P+�/�M�r	�1gV������Q]���1�zcF�1��e���������;t�|���^��B��,B�|{�0`j�O3q�-���Yo=�E����Ig�x���4�+�r$����M��`�9^����:���M�_�H�n�m�s�`�����[�Y�:n*��m]A�Cx5���r���������X�-���L�$�kIg<G[�Z�����j��7�:�x��J��A�����Ro=�E�5��H���vdmq&��
3i��C�]��2�U�x(��}z��hJ�Z��7M���G��(C(��,D�t�h��G�y����Y�i�a�z�������Er����OO3�.����kQ�����a�3%�4�?�a?��V^T�V�\��x#��`�T���c<�q?��V�8	����#���e4���+obp����`����k�N.Q��cp��g�5�qq<=3�L�Q�]�26�s``O�Ex�����1cp�����`E�����>=f.��y:�m�9���L����Yv���e���d��9B���N����Ezn�����[����������I��n�}Rm'�G���y��)��	�8�Kp,��9Y��n4&q�FZ.���n"��`g���9!���[��g0c���k��{�x\�F/�3;�V��h����2zzV����{z��@�5O'�W_��\0e����mVQTN��{Z�z-K�����2�'}a��Z��XxowU���"S����]e~,f.s��yr9�y��]M��n���zd��4��|��}V���Y�'_������ls����h�+p��.���������@Ov��_�y@���]!������T�d�j����.���O���*�\��Jc��#5�3���q���L��b���'S?�����jg����g������t[������Z�����,�Y����2�"5�K���s�+�c'C=s�e�����}
�:��D<��O����l�f @v
!�b}����(pw�u���Ql�l=�FgT��������W��:�s��M�J���d�|B�@�%R�-���9|�:-��g%����K���_
>o�6�����������3�S

>o�%0�L	>�������x���oI��1�D:�v��Z���i������oS�|���}����T&^���Q�o������?f���l	���������K`6N��fZo?C�����x7������D�]�����IU����OS��>}�>�[
+w����x�O����&k���F%�O_�O<��8���L�x�dp)�34��UFS�Y��P�x.�14z�j����\���^���R��>}�>�j���O�|C<�z?���x��������p�~�|�x.������*�.���������T<���
1�2<���f�u���=z�������	wa���t�m'��=r���I7���.5�����A�K����T+W�|�p-��1B���R�M�	���N�-yVx�P������R��E\�	Mg��)�&�����+���Zd5�e��uO�-<]Z:����-�&���F8�v�4���g���_��l�6�*X�:W������uJ�v������x,~E�_q~���`��n�_��������P>7����NlQ�����b��)z�$���$����+�s�1?��?iv�%��~Pk9�n	-SO�����F��c��Q������<��;�j�u������T�M8��e���3vk!��L���������y@�S�M��[��	Y��{�e<p��uU�����D�`�sY�#��dn�	�#U
�r���~���x�:�R�����2VJ���|��%�f�J��l@N*����v�8�7g���(b|}qJ���T�lT��+K���h���g9�����Y�/6+��$�N��>��K�����x���������m��8p�h��������7F�9RM ��m�F%������%�!����&�D<C ��m
�a��	w7���@�^���&^���3^��_�wo�2i��`�R^�!�-��<����?�k�#�������h�����Wx^�i�M�#kS�F�O_8B��,���*��#� Ap��������
�"}�6�[*C��l_N�i��9����5���|��H_�M<k��)����.������)hJ�4�}�n\��O4b<Y�G<��y7e�u��������Y�Pm�k��F�J��,���t9/N���0��U�k�Vt9�������mMDk����'����G5�G���Y3��kMb@����oj���k��Uo6h���:��,{/�x��N-�c#���V�
rZ�=�F��%B��.>��X5� �����(a\8�����1����R�K���w�dv�Zd�kfK2! ��dm"������pf�i�^���E�xzY�k,gz��W����_��a��n\_���3p�&�=d�O���,v�O���"������?[t<��zF���B��z|�^-����?r��v�eo�����9�-N�6�����������N��]����u��9���w~�N��u��k���%�F����]>��]^;��'O��������]���fe�������U���2�'�7+��d��#&i��V�	�j �.��Z����7�mp|�Z��~���e������x�x���Q�����^�%�u�Gkg����a�a�^<NYH?q�e��{a�Oo��[��F�����p3m��e�N4�!M��2�x�n�v�&����x��G��b�a��R���+���;��=���j����a���k���������e��C�
<����e���f��a@��u�^�x(./������I7�N�67�4���GOz/�7}��x3^�k����O��&^���3�������xe�]e��|���Xf8
�.O�e�S��keq����(��E��
���1���!;�4�P^�t��P\O�	���P���y��|B)/�P��i���zO)�w�o�)�.�<`�odO����w����&����������WC�/��qzwdOS_M�w���V��9Ds���f��.�jE��UQs�e�����;�XJ��?P��dGODc?1s#�������yi�mX��	�AV�Z\�2>���$��E)�#T�i�w�i�!
�A+i�^x3����8��k]_Y�*��
�(�� ��=]e4�l�vh�G���\���j���~�*�x(�G�p�X/�h=c�G���x0^�z����Ge���O����7�z�����G�R�T��U��W8�_q���eKu�L����Uq�%NZ=)NZ_;������W��y�JU\�YU~5��m��*2�XU\��r���H�Bv�T��e9
���zER�o���i��w��r�B���8�QIBhwr) +�l(I�I�8��q�2�$�Yb�*x�����SJ\��>�2�4��N�q�N�%��*�p��4�����_(��a���������������@������/�����|��CL����?��_������~x��-S�k��#�5.�1��53Z�B��p��f���$s�G���1��WO�F�F�+7�Yc�(�}�8V!! YJSuHV���B����fpm�$/$�fk2G6��W�������"�c��I�
��}�zE!!`}GXC)�1�"�xx�^�")��y���'���,��$�+P0������$�Hg�Hmo<�(>�j����+)��)��n��Fo�ly�^�x���D��IgT�l��a(��W3^r]^�qS��I�����wo�K�������R�K�w�yijd^^9�~��t������^�xMF�E���������30!��q� -����9Gv�D�ET���h�x
����W���f�g�ER2I��"��\�u�����x��q�&�f����(���1�\�w���}NS��D!�q�3���>R�f@dG��,�2wg�f��;�4HG,��I�dB<F�aG�dE������=2�F��>H+Z=:�Y�sd��Go���CE�K�]LI&��E����O��_#�%���!��-�(�����Zpl7�Ga��AV����S�N8��
�pQ��W����"����5t[��f�$O�m�E,�Z���:�gee�7�z��Zo��n���&��q5��i<��F"�����?[�<�Z	��4�k�No�a���VT:�{����(ym���:v�kq<���q�WL�������}�_��:R���IZ=�I�^;�gD���X|��R}�lV}�_1��"?+�S,�������6�K��~����
Z�	8V�&G��Y��
�c��_��
&�J����T_/�x0��b@V��
����:���21D�\������<�D��vV1[�H�4��E~�!5q�.�X�1`T���q���e%�"�]�����8��U�e�l�Vb�2wl�����������5�8R!1!)�$�J!�q[�H�;�J����a�7J%��#��n[�+we%q�Mw�t1�&�)G�����-�4��N�H�a<��W+K-IJ�����@��U5xHx�f�h���!����x��x�yw��o��0G$tV�{�e[���S�qDM�l��(����G<�����q��
R���#4S��\�����af�;3���yG3������`�)�����1��'Z�x�x�������v���EA�8z�[q���Y�Q+e��wt��x�nWt��]�_-0���=Ko�1�����F�~?}V��^qt����`M�L����cdv�*����
z�������e4��)7�j$x�,�9��k$���F�����F���U�������SlX#	��bNu2�F������,��+������0`���T�<�0k�7�8E�:������)!�]�)[����Y��(U�8�e���U�8<���H;f=�L����p�zn��Ul\�\����*�R����*S�rn��k�N>�~��sKoLtf�s�*��-����T�
9���Z�b�(U�<�Z��vi_{*�+��U�>�^e*������������J������Te������o��������].������7u�w��'��V���_���t�������X=i��J4w�f�E����7�D�f(�&����*��ROJ8(�
���nt=F�'%\O�j?):���T�b����a�Z�t_���zR�!�(��U2�(�*v5
M�x�X�'%NB��W��TO
8�"���G�{������dS�Rh�z�hq���x3mw��9p��'d1R�F������D�Xh���q��SOJ8���VK�����z��:������%]y{��_QO
X�?�^��'\�1	Po��H�i��H�b��>����Z�V����RI:�b�������c
/���������:��1^_O�**����:�`W3�U���x#��la�6��e
Vpwc<�`�A�C*L�$�c8�c��-�S�A�gE����FY�a�Q�#Y��1�z.��s���Qx�}D�%N��&���a����������������������!x<�L�����)M���u�I���x���
�$��yU�����1�4��ci�%���!��#)<=f.��OO��������i1��s�}�#��s����]FS�H��mO�}_x5O�o9"������<=�����<���d����z���������i�D�����5�-�(9���E�P cKq�-
��C!T�Y�P �������7_����T�����q��i�)^���U���Xvx���6��T�y�g���F3��;K��pM7�,Jp�m
A�`�6"��x2�����8m
��3����&\�6��-Bhw�&V	�#��8����hJ��3 ��l�������+������?rL�i�������l��m
���g��B���Z���Qx����@<c��]1�>*�������)��^���y���P1����������������~�=�tm�d�tq7��?>P��4��4�Wp��9�m��hix���/@*eZ�y������`�y0��|�ql���:N(��t�JA���!�85;:�7p��m����p\'����"�lO�ZO�q�|���[����x��|w�Cvzz����HM
�k	W����`w\)��H�|�\'�J\�R<�Z�JS�����2�#�����1�l.Z����2_h�M�Xq�7�����Mf]SC����{���y���Iy��4)����ws��jT-9�8e��C�g�����z��S�J��t�������I�f��R������j���U�o ��.�.U�x��\�x�����h���c<�����!������o������������O���o�~���cL��������������������~x���#�"��O<�a���*������~����{'����w���V��S
]�������� ��k����\A�q^�v���@�na�F	�n��&'���*�����c:Jh�c��x������������p;�+�Q��z��m������faD*�#�p������9��(���R��t�3Ng�W��x���0������������^DO�-�U^����x��
�N=��@o�BZI�4�\z��:}��\��W����y:}s�����#�xzdpw4w�����F�h��9x����Z��y�������vMOxFx����c���2���K?�x3��4�vM�x�x���5&��g�Y�rfpI��C����q�k��z��|���o�����w��=}�
J�[i.�����ai�������G���E���<�.qm�<+������[7��~��������l<��E�Xq�;�<;��=!n'n���f �11���lU�S��t
�3���5�a��^)��PbI��k�n�����%�!�y������X�@����@�bT�|$�!����Qzw��s�}r#�k@$�O���#�����F�a�����"��F��
������?�>#�����a�,�S�'f�.��p���%�H8=�j�E��������*������KoP_���/�����*��W��B������k�^�.��rM��8��P�4�+Pr}2�rr���_�{��cQ�����8[���/^�:�������{g��Y�!�!�
^y?�[D�6����6��X�!'^-��BW(^�%���\�����b�'��L�Y5��q����3��v�g����t���n'.?�������N\��.��w~�����2�����_���t�7�`����~����l���(�����lK�����"��Z~V�g[��c]��~P�g+�dq�'=�w�}�h<Ako@��3R�,��u��$����p�nG�[���!���a�']�q�r�yy_����{�e\�������V��e\`���,���N/�6�3"u��1B��e\r���������:)�.<��V�Z�J<�J����e�l���1�Zt���V�y�.x��*.��cL�.x���3J+u��5��t3���g����r�0���ge�"�So����*�T���=�I8d4�V������v�h�m��~sqd�1�
����nd|��fe���@��h�@n�f��xz��u�Oc;�GC�v��n���O����tq�����d�|���&��\Z�"��x(��Y��������[U�k
����Lh��nom3�X���p��Y��*���x�7�������lG�od�����t�nV�aj�����4�����w���Q�SR\�K��
<L�:�j�N��N<�V+���7�v0�����w�o�)
	YK8,��1����OO{�U���2�Zy�3�x���l�J�������9�*P�YFQ��.����K���9S�$��K�b���.QE ��T%�t��R�����?I�i������
������U1�Tz��������jdWI�Pu����:�������������7��\]�Y.�F����g'�s�����H���0���5��;J��3��;�Y��@�^T��DDc�f������+���k�@,�O��E5`�!_-��c��T[�H����.[��,���9�W����8-g�C������A��w4���
i]�r�O��3O�ZQ�������F67��b��G6�u&�q����x3O����7=�>E<�c&��a��zh�o�U�p�`�l����;����������&6�G�a@~��V���������*���������k+�4���}~|���V��
Vj�
����B`��+�Tyr�[s����I�[E�e�;��
��<����w-����F?WV�}�N��X���XLV��[:�:�Z���T|�V��V��T�������Y�WJ����_�O����5�"�����kv��{GC2��r���z���f�zU���E�]��v�V0���1���dU�J�YJ���Vee�V����1
��R�d���8wlUy��O�������W�
&�U1i}��?\��a������y�q���a������;�t���O�j$�S���Yx����c��MGh5�Y�il7O�v�hc������	gTno;Vj�b;��-��:�u����&�Ul�%.p�r���|w�L��W�Z�Bm��x:����3��g@C�#����j=%����D�CRFxWg��n$��8�����Z�\V�Z�I7L�JB��5�@�Nx�Ek���L8C�n�X�rKi�C]c Q�hy6n���u�Lc;��[�l\��W�}w7��:[��$����^�v����J��+9�~�.��1�&�h��@�����uqg��'��(�^{Qm}��yF��3�������6^���b�e��;�����u��'�+�Q�����x�e��(u<��0��<���%����"�����+����
��y���"�����+m�
��yA��yF��-���^A��M��yF��3J��{��3�5�rs�����8�l|��3�Q�V{��:��YO<���^���~����E�l&�yC�30�������������|�#O6�����R~��/��`����1
&��T`��w�:��!�F�%y����=�5W�C�v�
4]�\po<j�;"������n�����g��D�������*�������/�[&�����������$�����2.�g������w{k�_��jZ�t��	�h
����$��	����M�M�UL��
�oZ��1,x|�l��t����/X-c�����������n�w���	g��nm�.#�Q���m��B����"f�������Z�t���zG:=�����	�dRo(���G6����Kj����G�^?oo:\\�t[�&��q��u��A?�[�&�$#�{��#�c�B���M�aB��01r;1�-X�������V����5�����`��N���O�������Y�I��fp'��f^�g=K�7����t�
��g�x��w�Pz�:d7�m��Iz��aCx5%����xz��i��������<�u����
Kx5O�W�����R������)
�S�7�����W�t��.�CMx��i���zR-��Q�x�#������]�������i6�����s �W0�
����f�������=���O?x%��17;_;Q�yOsr�������=��s�~�8;{�fg��$������4a^�i������vJ�i��$����x�&��OO�x�����[�cO�.����[�4��$����$>k���MO7.�������x�epi��������o�#k\Zc�������.m��5��4�q�1�$�t���Yc�1��;������=Mi\c��:�<�3��������=�K��vM��]�5Oo�#\��w{hoO��]x���1�)�kL�y��"����u?��GE�t��iJ�Sl�#�\��
{<sO�dCx���	
M�U�Ql�#�\�5��xzfp�w4�����x��[�����e6��o�#3������;�yz���>u����[�����z;�^OVt.����sdc��2Z�7����v4�����x����9��!������Q��=�3Zo������M���V�������5�� ���������U0>��������q���rO�,j��J���	�P�H�:��W~��6IV��c�
�.����4�~L��������^��[WYN'C����}FS��D{qO{��
�����,'�������Mi������x��4�1�b���T0��T�x��R�yz���DY����Z=!�yOsZ�t!,�7O������9���T��\J����eDI<]1�T�n�t�*o��<�u^q�\*CR�,#J������v��kTy���������WT�:�8q~�t���7O7����q6�5\,����Pv6���x�epi����U���Am�W�Z���O5���x����m��4����u���!�����o�9����1��pO�nk�\Os�d��6���x�s��~�������F�5/�����O5�I<=0���O����4�S�~i<=2�za�3�I<�4��OOs�d������i<=1�i���$��D����'TyO��������3��dvo~��������3��'CN)��9&�4��lvo}��3�y���s�*o��<�u�l�\�����$�������9G���k��:G6�.��H[NO����m��P�-�����9��!��r�6�i<=�z��O�}IS����4��.�*��:s2{������4�q�������Kavo���b���s�hJ�c
xM�����4&��$�.\�����UFS����V������S��}{�����~����_����cKu�-���������O��_o�����@�h��������et��������u��G�{�����.��a��3&�y}n�H#�Q
H��y�/�O_��k�b���>�}F���P���[
+����	w���O���v�#�O���0�R��y};l��������F��.��Q<1��2Mb@�]���pcl�ET+b��	|}g+6#������C"����12�=�'�'7��l=�<f��<�O�On�Q
X��e'��-iIX��s�c#l��b;��H��^i��y��T�y`#�j��@����m/&:����0�1����9i���y7��w�p�.s ��p��h����U|�I_�w�z����8�B,X�b���Pa����z����+��H_����8�p��i�N��n�
��N�J�7(����p����2��{��,� O���Eq��t��������LW���{N�.��V�`��o3�"/p_��Vl���6D�}���f$��+���,��/�����3�^���"	J��Y/�H.2�r���:Sy$��FZ�Z��gq�*G�iSg2���
���W�,��+2����5G�(��7�z���X;���j�*�9!�.0�J���1���5G������U���5��O����x�����2��CT��������{|2�:�9���(���Zi�8v����.����Q��s�j�R2r�#d��\��i�>��X@?F��8p�}l����}l0���q�7r�}l����}l4�5j�"����g��9t+��f����k<h��p5�m~o����W����x�g��;sWIb<t��x�tI�����[�
]{����.���o����};������?�����*{������#�������B�Q��������w���/?�x�������������o�������B���G~��������U��g��m��������>���������?|�������������J����.�����������Ww�W���\����|�+��������?�����Q�������l�o�=�:y�p|�h�6��B����7w�������y;wW�yy;{k�W���Wb�
$��gl�Uao���~pY���q��������M�^�����
x�]Q��_��w�#^kZ9��$uv:6��5�
4�M�!�'��t��N�����z�^��<\71�-�{L\��I��F�&o�"]�hI�p��������u���'�e�O��u�y2��������\��{��:~�`e�t���s�������1��N������[
��:����<������&h/�=q2s���#�I�K��$Yj+skd1����8�E#������,W�2m�}%��C�Vpo�2u�.s&�����o2��
���&F�jy/���aY\c�Z�*�NK8�r4�v��5bUW�����p5����l@�<dc��y��Pv+�����A�M��e)�_����FOIf�\��Y�������=����q&Hc��t����e��vEA:CF���Mb�����_`��t�i������\������924���)q1jJ#�V'�\�q�)�bisT��aB��w���x���!u�~\OW<�T��������h���Cq=�R��2�8��E'x-V-k@FdO����cq��i�B4Fe�Q�s[O7.��uK/���cpibq���6�)�!Mr���Kk
qH.���cp���;O���C�X���l�����x�K{��H=���z����e=�1�V��Y�����o�)����d����Y%:��H����qG� ����h��^[[?3���)�\R@1e�=�m��w��n����\L�.�)�lu��'u:t��K��*���l���\@p_�x�{TT���L� �~_�/GgA�����,�Z'*��}FD�;�*�Ic��Yp��j���'f������|~,��y~�=��BP�Q������y�{$Q!��������
-qAf����QD�p���	CT�p�|B��3U_�.T��6��t�s�H<����V��D����W���2�����5������M�I<]��Nx����$z�Gae����\0`�����U�w,��������yZxo7y4�&�*������M�����}��O?+����K�l���N(���1��S]H�2������_����������\�UE�]�;��h�eYc~�FR����_��6�I��EHr Z��{���P����@:��������H]H�Q�+�;9�����(�M>NyA���h��K=��������%Y�!9�T�xBM����gO:C_�����D8�q�v��x��8?��d�Q|���
.�aw��xp��K|j���	�yIH�������p�"���h�t![��jp�iaeR������a�9O���.S��	�������T^#UG�n�Q4�[�q*�A��Y�Ulg�[$��/�p��"u���%�>����1Up5��-�wG������q�,�K7��:��}>�w�L:C;��Mb���N����v,�\�v���Q�C3�nG��`�T��k�i����
f!r����Q/�C�G���9B:�����4FH7�;i��#L����B��=�����{M'�L�qej�w��gh���������Qn ���t��ko���q==0���U��wdO.�"!�O�F�z���x#���_���q�==2���n�4%�^�t�N�p<K�;`jFdOS�{���<=1/b	�o��\&=1��w�<�,���e:���fw�,Pf��fBp_�y=y�Y ���XW�4��)v]�q�s
En���
��d�@\����J�I"�j�GV�]�jW�j�CS��0�v�T�px�����j����Q0YgR_&��G�xl����8V�6���{�����`2�Z���O�]�!0��������j�$����|��o���R�X�gK��7:Z�\��J�����.��Y�R��X�R���q��,?+�6o�_J�����C��7�+���N�Q���5>��/����]���fE��H.��
��{p4D��b���L�Q���,����V�	��X��P-��|m1���K:DL�U���s>Y�M��p;z}!+���I@$O�����u�/�lQ6�p��:i�N��}IF�Zw�u�q�\%k�/�HE������.��+�[z�[�c*�
�z��XE��C������0$#�(��j%�c�=�+�[�������S�
8ND�J�%@?-�+�����t���C��T)��+���A�Q��B;�r7N��z�yW�u�e�I1r�UlgU���#q����yr�y����s<��np�3*G���$�c���*w%�r7����X�"V?O��z4�;���Oc��;�`\������t<��������7Z��hM(���������{o�Mx��j"����I_����3N�V�a�f��Iz�vT�DV�/�� ���DO�;��
�j�6����]��YN��{�����$�����n��0��y:�"1�������"[)�����}�e�z��JU���h�
P+S��y:}��\�Ej����[����2�5�����^)�J��x�3���rC&��9�Ox���"�)��������t��R�����x.��J'�:��F������%�Ka$F���t��R�hY��#����O��g�mg��������\�hY!0o;���gJC��1
������1��7���
>�N!������0D}�����FV�(u^��#�Xq����$�������8`^���DE����~�=�.{{B��b�����ubV�(�����p��1\����"w��c0;�60�q�sf�&N����RU@�0����e���E���������=]�`5nu���$�4nJ'^��)�'{{�����W�^@�5��pS:�j��V���Hx#�g]���B�U9�g���{�3�x�W��u��R}��JgT����{e���++�?����lG)\Y�����mq���uQ���H��p��m?>��vU��O����h=~���k��-+�`���-*��[
����8w`�Fkpv59��C�1R��}uz���#X�N*�a���v'7��XP�������3�q���jz�{���T��h<��`Q�T�x�����/����P��i�H�T�C���v��x�B1�V�_�#��h)��|�����H���x\#r�	���93�Lz���c���p���F1����p-���x�z6�t��2>��I�[�-��3�6�V�C�"e��,#�d�i, ]K:�,ce�)��[r4V�C
��t�{���+*x�0�-)�8���H��*m�f�h������������wL3��I�l9�N�2oo�
�Lp�����B�tU��B^q1&9k�T��G^�4�����������T;j]"+��y:}��F��o��$�t�3�����y��aJc����u��t3��Mm������{��h�a�k��k��+������t����]��O��H<������
���$l�BK�����32�R��=�1�tJ�f��=M�[:kr[O�.��P��=�K_�vM9M���y��{`p�h�����w�1���rQ�^]����-��+������Q��v����V���3G��]����.k��
k����9a�m@k�X��m�M����L�(���C���v�{��P��*�v�,[�SUI<�b�}�
����C������_1���8�����6SJI<�<��� FqT��m�1�j�tj�i�X��c�3Ry�����c���Mxo�q�Ggu���p��e��h3��s��Y�Y��,���Q}�
��\������;F��\��O�}|��RQ��\�
���~V��X6�c��~P��n	
����hU�@x6��v"C�ue����7~��M���*&������d2Yq�w��LN�� �����,Z11�f�f&`�T���x�B���[/cVH
��m����a��Bro�xf�b�S��/�y�%-����ck+���x>�4��b��u���W<Q+��V���b�0����TSL]LL8�\	�����ce1q.�j��^�t����`�bb��������
���v�G���c������3�i�7('�����t�� �t�1H���SKI:W��U$��v=�����(���t3�������Q�&�(&�]��f�����q���V�YI�4�]��t��z{�9�{���il��N���~�:�(������Il�=���N?�t8
���il7�N������$�c'O���{��/������y��xF)�b���H�������{���Q��@�Y���
�`Tm>��n$�Q:`=�&�;y
C.j{�Q-����T�^j��t���lg��#����
l
��5�(���4����g��8���a�]�3���kM�Mc�&'�qF)��+�l�����E�M�����Hg(������H�7n�f)n&��������y��p�Km��5�(����.#���4��:�(��l����I�<J��(���]��i��l�^h����N��h7���(�\�v�������u3^`;��{�����d�x6�����k��h���.� X��E��F���y��S�:����!���#��+e��6����tz$�jB��nr�3�����#����l��z�����{E���b�I��A�`���L���<��)�q���
�J6F��&��s�v��2�]|�O�.O�YM<a����hO�n���OO�������/M���ExH���t�7I����9�K�5O�W5"�Ki��
��scdO��Exw��������Y�&����)����%��=�)d��OO{�ZJc$���Y�d���>P����T�-/�]���y����u�BqOS�Dxx4L�K�
��y�D�U�5O��L<��J����^��R�HQ��P�x����_OW.���a=���t��R�HQ��x=x����_O�.����i<�0���m/T�	����sd%T�����D�fpiv�(
���)
E���q=�2������4���-�K�#EQ�v��44�B����t����&^�[V����HQ�}NS��!���z�gp���G��0��Y3"��������5&H�0����j���������e(v�������1Az�q==2�F�k�����\F��5=�SG���V�����e4&������==1�L�n�4k:^���92j1��!E0�%����T�W���Si�1�#0�x����c*�~���������*��^���9�*�����r�$��*���~=M)��<�u���q��r�=/�!��]N��{��+W��N��:SN:�����@)|O����mmh����yz�Y�\���f�~"O3��n�k�(hJ������$�.\
C��j3H������(�����)��3�/�x�dp)���)"��K���������k��:GVU.����J���,���N==���5���;I<]3�Tz�����fMSWDx����&��2�}�N�0��z�I@�����H����c��t��z:^8�z�~������>.�U#����v�YS=V��E[�_��y�V��[/�ce	���T[��~MNc�{r��j<a%��		�f@}7Ib�&��xs�%ta�M�Tl{"U����uS.��Hw��-�c#l�ZqD�p�����H�BA7�`Vp�a�n8+���'�N�R��3+�p�
�W=.��P����������L6j���O�@$W�l��C.��
-������t�9ZO�
�zW�9�B���mTW��f���: ����P���Fx�x�l=Tv
�vY_�6�g��Q����z=i��YoE1g$<l�����]d������{��
G�!�a����^%�P�����(�O�0�5^��x�90�47��J����6����a�U����bo���Z��w�����g4�'�5^�$��>���x�R
�����f�Pg1�m���2��.c��1�?\J��?���Y��x���7����?���o���������>�������R�����O_��Ql{p�_������~x��!���o�#�Q�)���LT��:>>��������w����/���~p]� �Y/�+���J{�[�k��!�
��q�{�1����^]
/#��_�w~E�_q�������mf
�� ���s}���/5����������������������vL����
y���fX��I��1G�^/���^u��rc)?6�s��]m,U�������0-�1$��g�l,eU[�����q����_������[I��8z"=���Q��r��	���yVpo�9��q�A��������~K�(x-���gA�u2Z�������x�4��q���1{�y/������g����e�����%�~���\(�����2�3����%�J(k{Y�����wY@S����'�B�����kXc$�+�l�������v!��F�
w�+�/�r�.����{�c���>�����#,�K�,`�^�
w�5�%�(�y��Y
�c�����-l���p�{$�{�����^I���iJ=�"u�d?���&���t�$]o��������W9 �/bx���t�`\����U��Ae�y��'�����}e��v
���]�s��Y	��RwI8������r�G��������Z����7���VT�!�)

�:�Vw��fx����v����c�`�B���1D���s�`����Ad<(a	�f������v��W+�]���o����;���	�>=a���6��������<aT���xD�-Y����9P�(M���f���k%����L�	m�����`���<��x�����1�o>�����pi�s����������o?������#����|�eMm>��oo�nP���n���8/�%�"%����D�������HI{�!�&���"���9��gl��������+�-��N�>�)��O����4����_���D �{Y���5=��Q��7���`����+��O��2.�N
#��+�%�e����+�]v
��'�{{d��b�����(oo�C�Hh��N�y{#\O8#'T�[������w�����&�L:E�M���g��K��J�Ez|��}�J�Yo2Qf�/��]�2V����H�Y9�4��9f0���7G�f<#�%1����h`eFiN"�qW
�Z}�Nd�)#���d��~�M�U&c���c��x�'��%�����xL#L�����g)�7��3fomg���W3��%�X��� ������x���qd^g<�i��nd���j��R)�7f�U�E�����x���t#��3���9n���
����M�9.����*R��p��}z��4��mj��'��CFx8���C4��zz�)
�cS4<��}ASZ���'R,�PF.���4���y:}���4�}�t������
A{�4�����O>#�xL��V���
��4��E�o�.Q�>y~g����4�Ki��[��4��\�����y:}�;�\*C~��d��t��Ri���t�"��<�|F����6�,L
�(�G��0���n�t��P��<}_�(����x
5�B�x����w�����4������.��x7%�4-����=����%w��T?7{�����X������q:��^"vFV���3�aA��u�]p�����"��z���q������;t���l��{�Ta^�~g���
�r	M���wHD���Y��2N�q�	7���`�E�;�����'	#�"�
������U<Z��Q���;�S���&G�)w�����qj����xzF�Kx5O��D��;��>����z�g��'�������a������L
��z�7�)DX��C��l����,Ld���g��%�^���+����'6b�Wx�7������h<U�4w]��v���,���,������+8IH~V@�eU��[r���W�.�����������	c�������[=�;��l�b�
T~��
��[��!���|X\���#�I��o���h��@��uaVveC�oe��3H��f�\7�l���I��V���D����u�%���K������F1kPp�d1��8(������T��R�^7_�
���6�Q����p4�����������6_�-���1*�����"&��-��'��M���q���%�����8��
��Vq��C��E��8B��)n]�+�]���������]�m�V4a���\���|���-3��%��<��C���s�D@��O�A;,��&^	�����qz�H���������7��L�6��������x�->�j�K�6N��tFk���v��2Z�����IW��j-������LFv���6t�9���36���<��x5�%o']	:������[���F�e;3�Y��yz��k���'��5mI���}��.��07�����������m��'I��Iu������^`<�a�x����1^�p�[O�yz��M�mn�3K�<�� �y���g��$�����W3^�F������F��x5�m|��1R����u���*�0r�M�w��������3v��.���t���*�2�@<��>�
#�xeF:K�zs���UJ��������-��M�����x�UJ����'Lm+UJcSq���*U)���w���*U*�!z�s^��8�4�na��y��--���*y���5�a��D:#�����x�Y�f�7��aV�1�*/0w����4�n�)�6#��������@<k�W�&�
#�x
��w[�����+��j���
#��Z��`{�u<$[���<�${^�Crg�7����qH�
$1^�Crg�������7�VU�e����7n����4��o���G������������m�l�1��UI��9��4�5��������'������L�6�����3�nG�A`�xb��gj�%��>�q���#�UI��x#�7�����g��
gj�%���c�l�������3�����3O;V���i#�$��Ck����B�$�vh�?����yNSZ�N/�J<�"�W;��yV��xx��}z�e4��:���1�����x���i�c�����Mit��cO{OS�+��f��.��vM{�P^��}���.\�uC5.�i<]0�Z���=] &����E���%�Kad��1��K�2���.�p���<g��'�4�Ki���]^��rQ��7OWx�x�������2^���8��5�K5�vM��x��[��\��R���=�0���P�x��+��k��:G���x�5�+��O�������O����;��C������2��#I�n����}i�e�q�"�/����Mi����^�x�c������3������-��}NS�%��4��azK�:K$�t�������3Mi��4���x����@�gO.C���q=MQ��<�y�ldp�TQ�cDOSEx����Z��Hq�>bOO.���U�����Z��s�d\OO(�x��VWY"O3�L�Nq?NG����2��G��3��^����2J�����q:��}��2��-��>C���k��:Q�3��<}?NG�t��z1gK��t^���1[�j.L���Ex?{���L��,��iW���lI�2�����jkz���\�w�������1�j�L�i���
�	3�����=��ov��GS��g����t��R�f
/�����������k��:G�KKZ$d`\OS[Dxw����4�^X��i<]1������K�<�F�w����t�
�gV`&�t��R�}&A#N�z�fp��n�t�V�W<mV`&�t��R[
3[�O�����v���"xcl����y���1�����}��������8Jn5�-��[�"�����_��~w����r������>�������������O_��Q>����_>�����=d8�#���_|\N��D��|�]}\���7��N��w���#���y���Lp'�������������?K����9*�����p1��
����������[�����Y��/����'�����?�����
�+�����_�������~���?�������>�����o�M3����Z��?�@pSY<��S�vr�o��E$��y{�-}z=s�����,j����N�d�tk�XN��"������]WY1?��_�&]���b1�^v�����+����4V�-/e�r�	���"���,X�b���a�)'Y.V����PN���%T�T�,
5I�/�����lP�[6���-���4z�1;G��U��U�Z�~��,���:z���`��nWxox�z������L�������p��'nsq�z���W���LQd��(+^�\��x��������p��k�!����{��*�����f���yd�!�*���&�|=��7�z�����4��7zZ�x�+6���:���w�:%����^/������V��\���*/W��������v��Z������1��qF���~O<K���?������w?}���_>����=w<����qv��s��~�/�r�-��e�#?�_{���*+U����w���������������������z��w_������[�/�sv��E{����?V���]����?���/�^�W?���_?��/_�����b��!�E�o�%+�$+���P�Pv�����.u�w�����m�������2t�� ~EA���R���\�6�6v�A?���_��~j(�'-�FyH�2wE-f�ejY#0���F	�1���No�at��%�A�Lpo�'�:+��L�$��I���`%�Z�D��	�!;X=:��V���u\!?(��u��M�����F^p�u\��/�Z���+b�A��Op������^���B�T&�U����Uk!{Y�|L^��x���3O����8+����P+O%��W���	�?sZ]N��]������;p#�9�&5c�Vk��s�5c�'���18^�g��S��O\����'�n5�,�n��Q0v���bg������}%��G�[]+=am��|���E[T��BX�Tkk��Ui��XS[9�6�<n�1�*���1���Um�T����I7��x���xSN<��5Nq������@�{"��	�6���6���@�����?�O��\�����Z'��fn*�1���c���[�y�A{^�1`�V��z�6|+��o��F
�n �0�9��(��dF�umZ^��r4K5�����G~���g�E�F��t;Ry��t�~����OV��Y ����E��4�����>�)��L�U��o���9:�f"�p��}:����8���CdG8�6���KG��m!�1�w���hJ}2�9M-��K���^��x�,e��Pq����_��I]1�O���)���#Ks.T\G�V��F��J����X��WSR&��kF�:�X������!�t��q4KmtdH�<��<6�	�>�0Eb�����I�0�4F�$��)��[F�&�P���n�&+����+����5z���";�cdic�����O)���I����/)2��J����;����Z��~R�=w��f����G����b���K��
H�r_�]V���}MDK�Y?��1`��Xpch=D��w�c�����Uk�I���pR�,�Z�|����,���F��}���sK������F���HDK�Q?��k��w��a��x�a����S�|�3T$��!�����-�H�-@,��,�J��qh���B8�����(�-��[�p�����h`�_�����7�'{���U<�O>&�i��e-����JD�Ak����4���y:��1��+<�F=�592

�W�^��]\���z���)(Gu�x8
�f���P�C���>��w�j{3���59��J??K?T���,v�tY���;���O(����=+�����)P��9���3���"������[=�;n��f�=���g�|�Ui~��@�������I����H��a0r��@k����`m��R�M:�A�I3Bn$�����,+�R|}X�.�g�N �h	T�=)@<fr�������{�h	l��'��&�E]?�,�"�2�s������\(����2��N)qgS�i��������O��G��B"���u3�1+��������U���M�i��\���h���
�+���������L��N)�oR���-��DA��k2�V�d�6'�UH�
���d5OF�#�h�����I�5�K�%� �L:�S�og�i�W3^r-��8��yi�N�1�H<����<M�l��t�+���cjOx5�E�5�[c�,l��5�g������d���tFK��_^��A����\�tg����u��x�,%�8��c8�v4����b:�7$}�1���t����A�	x=O���zC��SLo�����&���hsmGs4����7���(s2�I
I=0�X5��cG�������7D�G�u�u���2Z*[��4���2v�]�SAS�'�"}G6�X&�11����q���r�F�7G���Lz"����q4_IWstz1
�1��;�7x�:qr��x3�pt��l����544�t���M�����OG�iG�G���&N���sT�tEO|���:z�)����������`7���4��'�]4�6W��E�L�����Q����]����;����������U�V��k|�����s2���pQz[�!�
�>w�z�����:'����	������8z�(�x�g���������B��:�H]���|MF�c��Vd<��	�f��#u��� �]]<��z3�g���#u�7yZ�h
2O�I�7q���� �64���IO�P�
�q�fn��1����K<^�fc[.�7�������������h=��mE�y�9���Q��7����Yo��1gh^�zq����3����O,3���W�^��R�A�~6�������7�z�n=���hv��3Fh�������^�z[�5f�`�W{`����63�g��9�����@7J3����������s����?�[���p�(~if���\Xs����m����K�d��������U�������+P�,?+��-������;���.A����e�c�a�#k\�z��"N����[W����b�8m���p�e������U�!����}��w$]��R�+���q��xx���:�^��[���������������k[^�Md��4-�v\(����~S.Ep���I<J���.s�%"'��p�m��=�J���X�uQ��p���z���-�b�B����Ade���h���q���A����o����r.�f��	�i"��~�<�j�@�g[.�J�9������aN����g[��b0��w��H��1����7�G��4��A��g���0Lc��xF������x�kx���� q|�����c~A���xD�~��U�Q��RDMb����8�l����UJ}���Q��'�qT��xw�#��I���	w7����b$'�U)��x#��M�����T�!�*���1���@W�7�}e]h=��^�gE��']��6�~B���a/�
�����+�F�.�`�0�q�DKZ��q��j��Ga�����~Q2���8�e`i-i��q�1���Ga���k��b���$��X:KB�8A�qt����Ga���[��d�"�$��Xz#��%;Y�1����F ��+K�?���vI=0�:��2^G�,�~��
���mSZ��4�X�������Y��t��u�iJ�c%p�8zb`����,�����e�O���u�)�L�\�t3�d!�zRc���2�]�3���~����]�1�����Q�bE��b9����yv�qx��If,��	W���������g��6v~6��	�T�|����G��P��7���X��U%�b9t4��@G$���?^@L������
'����h<�A#�i�uH�	����&pG5�c��0k�s��F����?��]���p\7�;����F�Q�gv������%G^��%�}��\�(�:�p��N0�b��,���v�W9����UCx\��^b��8:�=VN�XM<�������{��iJ��"�����5p����N\�&��j��'W8Y��Nx����<z$<�
�'W8Y�M��~T0�=���w�x5�%W8Y��^���!�5����C�Wxo7��������f���>��l���������\��0�~���~�UA_��7��k�X.?������|�_���q���p[��/~���g�|�������A��u��`�X����S�����`�����T�~���K:�	����	�S�T�>���^GV��^i���z�!t3�����<��N<ff���a�u��g��gC�0�:����^N:�����������2�yA;}�[/c���Up�e�/�d_;�p��e�:l��k$�N���kM���N8\���t���pl9�F�i^�����N:����U_;h\�����W�[�����Vx����}���&�Z�b���tk5�%�k'�@:���6��i���~�������tx$�F^���$^G<����fNc<�;C�}{���x���Y��I���5Ipw�l{�*����,a�$�2����yw��xL�t���%�����qW��$��2���; ��Y�#w�y�z�Lc<�G��z{�1���vg�r��k'2�~��$�+�����\�ow&w�[�e+���w��k���vg��j4�E�U�vg�1ets��:����yG��d��c�H����tp��j�N/`�<�����i7�W����t8A�����s����v���"�����;�'����L�JE����Q_;X}AS�W����������<���Y�����Z8�R	���i]0���4O/`@<F�bG}�`-s�R������I��R}���rG��,�����:���M�N��:j<
���X}��cd�v��NV�	��������X*����<F��,������w��If�hXj���~#��}�������9���qw�:^�A��yS�wC��q��Js�q7��9R�)g~b����/N��5\�!�.��E�;%JB�v�I��4�4
Ds�|��o�)��� ]���Smr%�rO���������������\\W�_Z7�e��x���������$��i=CL{M%$<�i�b�" {��`�h��f"�q4$ r����z%w���"�|�R�Bx5��9"���U�zI�Pc\�*����"�\�p��'�#�!K$�����o��������x����*)�"��zT��'
@"�A����<��r���Gi(yUUD��%�P����/FT�(
%��R��x�g�~��5��QJA������,-%�b���<��hR
�l�.���y3��w�����k��k~3����cXxojX�����-�Rf����Wp�������E������eZ����������������V"�>>q[���Al%��_���E������A��@?����/�������C���������F�R�A�%����sL�g6"����B��g���4S�B���a�Y}�k�*��g��rdxR��xp��.���^��+���N�q�#�PYO3z~7�N��6�v���r9
�������+��*�������B<�(�w���jS�@z.g�a[R(�tZ�q3ZE���o��q~��jm�jVa�N�[��:��M����tU(cX��.c����u����G!*��)��5����o���1�:�5U���a"7���4d��y���l����}��x@�>_����14�%��I�t-���|K< ��&�Y����p@7;�Y���oF^�x��pH���j��z��,^�x��pH��p��N�ym�O��w�;��F��N�/w�
�Y#��r��W{�I��B��x��Y�wi�7��:[o��9�*��b����$�s����,[�]��V�]�C���t����y�<�W3��/Jc��tz�gn]��d����\nt�\�x�yln�Fa��.��z�Y5������T9��.��Xp,����,8n��cg�����$<������b<+��.��.��Xn,����������*�Kc��t����:�&1^�Cre�1XUwI�W��\����g5�$�W1�Ut����8�YS�77^��J�O�ter�M�qSi���u
Mb<j��f�h7�@�Q���4�����������F���k�d���Jk�\��a�o��5�w�h�qW����2�FX��xT���J�y��yT���J��F��JoU���T�c>���*[�a���F>����o�+�`�����0��tF������Y��P�(�~���L����F�*���c����HgIo~H�������j�+i��&�D���b���j�+iw7�����(�q��7V���	���)���]�(�q��7��m	�!�e��$1^�!��-�.���F����$��7�*��o�F�n������<��h�p���4�Hg(Ym~����!�4I$1��;��#���#�uT����Q��3z7������b(�;s�T
���Ep�R1�y�*F��3���0^���P���xw��h%�����%���l�l�*��J`��'1^�HgTI�['���JiTIY��i�����T���4�����F+�>�<��*<���mo<�*��JPG�a^���t���[tI�W��-���6���j<=
��Z���]�6��
�$����6Z	ZkSIb<��	�f�������!��
�����
���Ka<��	�nF����P�sfW�h��3d|�]N<����w���:n*�������:fU:Cl���Kb<n*��Uq��0���5�*fW
���Tz����1�7vKjs�����{{kU��Z�����p���������/��������p(���������4��_>�����=$�p�Gr�	P	�V8��[����7�L��'��������_��"��dmMZKq����(�{y���r�[��faV��G�9>��o�}���sbo��1}��x|N���DS�=�����[��f�:���������������h>'8~�|N�-E8k�m"��H����2�$��Ig�(lo<_��F��Y��x�%����>��G�����g�U�k�����p�3�l�.����f�hW�P�
��2%[�����-�L��BL�lK��w/i��v��o����s�{��n{�U%}kC�h7��e[!�.���6����\x5�E�a���z��<���\���$+��b��#��no��&�{��W�_^��Ec��l�Z��Cx�,�Na�6#�qy�<;���m�WxxK�=��m��j�������1Q��o�F�W�����n���x���7��V���{&���;t�<vg�4y����.��?<^�KWu�w����=�t�[:�����u�OC��*�H������V��7N�Ur�!WZ�x����Vj��t��a�`\�
���o�)Md�����'"����o�R�a�Igh-lo�
���o�[�0��3d��_�!������}�	o�1;�_���1���<.$1�d����������g����������2����at�{�Y*��7f�0B�}�od���j���E�#7��}��x���1G���w�7�c�t�e(������9r�;:Gg�����3M���X}4i�<-i=X�aG;\>�w����Wm\D�8�;Z�����rG{$��w���(/x����)����.����qt��r���7Gx_����z�9���0*^�G�4������K�N��<��+��K��x��� i]1���nWt����+�6��8�b`����V����������v��� .����K~G�,V��_J��kF�����n
�R��X�i�nq�}�6&��F��n��9��4�~����8�e`i��6��'���;.��tt�����j!L�h=�j��8��������9���Vn�v�8�F�����S�=#����9z�)�������Ko���S�#��w���Q����3c,�����\�FF��b��9zD����6�������h\YC
�8����OG�Nc4�4���D�f`��4���i=3�\L&���)="���7���,������j���y����28Z�Go��28Zp5Go�z5�9��_G���x��[g��'�������2����=Q�C�Go��N�����~��81@x��h_���M�j}O�h�}����5&��r���7G���o�V�~G,����#>jxq�����R���������,�
�g����u��H�������Ssk�z�;�T2��e�e��3M�_W-
�4��]q�������KUD�q]�D�SZ�
i<]3�T��5�>��k����vI�P�x��['�����6�����#{�ali�����%�yz���0�4�<�����=�2�4�n�t����<�y��epi�����_����K;�vMwh/x�����:���1�[M=�K7�vM��/x���'�z��P2�[WM=�K��vM%Mi\c,)�4�\C��o]V4
.C��5=z����X�)i<=2��������h\�f�kzr4�q��D^�xzbp��\������2U�]�sFS�K�f��������q��e>����G���/u���W�����������\8��o��"����c^��������!��dq���+?h��c.Qfc�nn)%��Ex����)���i��^W�
E�5Oo�V�+D�����s5�z����uIS�K�)��k\W�WK+n]J;��>��OO7��4�+��TO7.�!�e�N&�4e��w��nMi\W,��4�����*���:���-�K�����e4�q]1u��x�So�W���O�s�����������4^]L��$��\:C��|�L�i��}z�qgc"��_����K���������[��:^q=�)^�5Go�U�G����2���,���e�)���#��^����w���2�B
��.���e�)�����^q�)����C�d(y��I����2�T���i�L����3d3c��2P"sI���}`�v�	^s��	����O�Z���+o�%]g��>����yS��������yS���AH1V�%
���>�
ZR�����RG��t�l��Z������	w��������l�;�1�xC��,K�w{�S�-������/��)����CKa��7!hZ���mq=]f4�~Y�M)�$�.[JC�����@��R��m������o��������Ki��w����\���mq=]�0�%<m�q$�t��R��J���j��:�n[\G�=,iO���AG7�-��	����adib����s�����tn���������7_�-�JS�-����4d�s3����-�J����1����V��b^q����!;����$��W:�
>�4��{��.��W\G�%,i
�6�OI�3������s�$e�3��1���zc�O���7O�
-�����I�%=0�1���:zt���;m6&q���2]%��Kzdhcu���)�)
�i�0��'���������@��2�U���6�����y�M����e��J\��r���e����m�)
���<���t�1��zW�+6V�8�!��.=�g�-&'x����'�������J\��r��Ex�����)sC��|$J������J\��rD�����������)���e>%��Cp^��+G��w��^���
L��k�y�I�i���
-���4�=]0���6�X+��0�1��'����h+)7n�=�0�{m�����)��x�����%�Ki��T7�h\��6��y�iJ�9�<�$�t��R}%�����j���u^;��h�7�<I<]3��F�A�q#������ks|�7Mi4��G�$�n\�9�TiH������ks�m�)��xs_O�.��oPm�I{�cpi��@C���k���sd�K�7�����oY�K�����^���9����3����D�t�����;������<�y��gp���0�&���~���Vt����sd��`���������e�k{����yz����2�
.`.MdOO.�n���	��yz����2�.`ZIlO3�L�m�����4�1��@O�.��sPm~��\���M������i�$/��]O�����Dp<-���t�iJ����K��8E�R|���'�����?�����
�+���!�B��������������;�����|����4��z�6�������J�������o��&\_�6b������4�=��Q
���Dp/�dP��n�Wj��+�iT�4z6;�=5Kw�����h��7zn.�;<�
����u,<n%�������8�����
��*a��g�V����+��|�Ek��a���0+��B�YQ?Q���{��+���i�}�3�r1`�~�Q����t�[we�('��p����L8������@1����`_(��'�O��xeNS���p��
�y�UGO�����Zxox�z��1�����I\OcV��W�t@1yd<�#��Q$�$�.h=�1DM*�fJ�>*�}"��xh���x^\�59mgt�������AZ_x����HxH�������i=������\t<$�VARH~7��X�T�V���A~o^+x�<�.j���o��M�����������?�Y��B����� N�j��K@���5%�O����}��������_~�q_n����?�_A��Y�+�����nz.s��������WY������{S�������>���������?|�������������������s���s}���/�����_�����W������?���/Qc�_���w����|y;����h��������c���:LT%j�y8���#��M�]���G�����J���+���r$j*o��?�����+�����nm����p!��������`0�(9����u&��'���C�Wp������
��4��E%�;I@���iH]�*@���q�����/�W����1�s�w��C��S���+���~c��	W���N����[�vG=�`���^�1F��p��J�Wk{Y��I �:���^9��A�xq����{����5v��%X�l���pF����5p��c�M�[�m�g}q8���V�U���q�g�jP�:��M�KNa�����dG�a1��VC����I���\�����k�i	�.l����\�v�SH�Q6�6d������v��]��V��9�����#���uJ]g����ru�n"�~����J��j�3�������6t����('������r�J��a�t������v�'�����Ib��Ig�6�I���@���j����m��V�Q�
�!+�E��\���q�)����g;��W:ZoG��de$)
�IS.��KNKCw2@�=��+�N��N�����\O����
=t'c{z��v�s;|�4��;i��%�t��R���;��5�K�#�I�6��4z�Li�$�n\=��t'#{�apiv�;	�������4�	�x�epi�k�����i>��>=�e4��R`��&�4t�W{�L�M<�nG��d�iJ�q�[V�������?�'�qt(cK�-���7�EBA]#7��v #K�,����C�i;�m^}%�����g��v��KzM���>4�]�fR���Gp���M
�������a���k]����
#�CV�1�]���_�M�������<M��z��W�zO�xr�'BZ\O�h^��/�v�����1S5$o���W�F�����>���k�:���_�e'R[�p���5��G
vu�-���k������Xs���-�5�m�V����WmT��^���sM��k[T���o~���{���&�l�&�
���g�|�m�?�$�����/�an��hME+.c_��(�5��G*.&�����LZpQ���k��()
����zR4`�����CNTp��6	9Q�]����T�x�J�\����2�����nE��=���}g�!��:�xch�����&����B>�&�l���bh�F�%N��5\�1�2�3C�2R���K)���������X!b�5�;KR^o2�]��F����F�Y��E���\����R�N:fW�3R?�l��N/���Kb��tF]���k���F��3*�T��;L���n�f<	�F��'��ks��q�w-}���.^g��%@��t����x��w�V��fC�����3v���x�����x.ZgO�~�
�3v�u&��z�(�����u��}w�Z(�{��z�(��B��u���n"���ln������3�R��q����x6�\�7�P)����l�z�������`D2��Q:�H�H6j�������������J?x/���0����e�q��v4:��<�L��[P���3�0�1: @8��g(K	�>==�I�5O��_&C��?�j�yOw����^�t����x�|I��.���W{i��g�lO�������s�O����]���1Bx�-�����i�h�u~�o��y:}�(�p�������#&������M�*v���]��cp����}`L�i���o�%Mi4����D���R���sIOSV�+v��
����F�w��K�x.���m=���4eE�r�E�]�hJ��{�!��cp��*���4eE�jG��`e�Hg
�����u��j���z8K�i��t��:��:���5��:G�QVDx�z��>���UE�FQ������u����$�����*����n����t-�"]��u}�E�'���v���#����#�5�Z_���{�����dh���Vp\7�>�k,a��_�"�'
�wa�jC��,��R��4���:F��(p����8����o4��z3������YoD��g�g�����g/�
��&���K?��x�'^��rcq�z\���	���x��	�r��u�����8p�F�\��Yd�M4��=�.���G�Y���'[�,��-��q��P+��rA����3ZO/��.�X��r��D�Od�Am��V��t�W�WH���xVSg`6��W��-��fej��bj~���g�T�SW�j���8����������(]Y�_�a��W
������I��W���|7�O�X�K����-E_+I����@���������J�?'����~�^�mn'���t��F��t����}�o�}�������6���3Z�o;��m��OR��g,i����^?���PJ�I�=�Q��Gg�����#-�`��A�x��"�A���[Y�����dpx8�r��WS�c{�^�1��F�G~_��9��@�s�ho����Q���:f��`z�E�Qdpt���c�86�>�!k���������	\�5r�B����(28��8x�U�H�~��	�d�Y�:$T�Fi�I:+7p4e��W��o����bW����F�F��tzL�\�`A7�NOM{Sx!��FG:���H>�uA�C�h���3���I��wY�8���R����.���Y��������LFR�9�4���r�w�����;�d(��b)1T!t</����}�e���j�F�kHe�W�~zn�:R�Q�W+4�*�\���k��
�Y�)q��x�a�w���=M��7y��7v��#��j��_��9����OO���4
x����<T�
��������v�G�}z�g4%��/=��7v���"�����jE�4�	�N==���8�&yo,�
o\�di�>��cK������(��k�N�K�����UY���I��K��2���.�x���[c�W1��z^�Y9�u�n��r�x�r?V�-Uv{M��GO��9�I�w�y[n9S�f�m����w�2��������Z����8c�b��� ���zG:��L����C~Npwc;��z=?��w�#?'�{���W��6������n�8�?v@�>�#����}�ud`��V�o��m���J����f���v�P������xV#?w���u���3��������&�����Z�4N���e9S��r��R�B�5V�/E=�8�(g���P��*j:���PB�����z�\L��5��|^~w���.n�6�����v�6��/a�����w4<t�
�K1&C����U}r8=M��7���&�R�Ulg�K��NO���.Z5G��f������;_��������\�,��"���eq7�j �^�[q9��)s'�{�`jdE'C���&����w7�I�?�m��59=k����v
n����n�$����*����D:}x���]��Ycx����*��*��:I;�8�O���E�L�L��A~�!�1S$S���}Nr�)���#��)�wl�Z�)B�S�)&>C��o+���.���>�����HSL=�3���~���������o���t�����\�.�#���~��t����l\e�-����������b�2����2��j1������J��>1�,��t�;�~a�����|�$>��D��'+�\Z��'�������sOC�d��]�I�*�4��MV�FF������5Ys�8�kowZa1��p���&Z�����������\�Kf���34���l��������[�[q�Z���%6.d'^�����M=��@�����10����LW��o~�
�������<�`O�7��C�J��7�&�=�.t`)�u��z�����E��j.������#�`���w�o\�����}��\;|�g��?������@X:_�K�E��k����o�b���c��z%������������7���W��}���
��&�KlTJ�W�W��v����������#����-�b+uK�
�p�~V�V[��c���3���'�����e��N�����v��m� K��T��_���fHg�U�S���@g���zR(��%�
.~�����83	���qT�H�{��j��qO�[��h<�&��y�:.G0��l�����I�W
���fuK�U��*Exn�����Ph|�:FQ�	WQ�\�~m-c���tHG���$9m��M�zgd�i��ZO�Q�YIW��y��5��0�4�;���|g��c����e#�L:���L����~aJ��5}�0�F��z+�'�f����!�i��Id����������T4�&��-�u�4���tFQ�Y"��v�>8��e�����o�G���������o�f'�(���7�Z�4���%�~F�/X��L�|�����x��)�
�Y��Tm��f��~Yy�
�"�������
�,�"�0��]O�.=�2xZ�5O��^���F��:���t������9n%�y:���\FSJU�pO��s�R�<�:���Z�1�*��'�Ro�qE49`��x�	v��K�%`+�L8�Mo~�s����E��j��L:}���k���.����E��v#t�������.;c����c�����������Qv�����p�w��6�y{��<K7�v|����t<J�����9��<R�;�'+�Z����O������[y����&�P-��4�t���$#�Zw�|�h�u�
����d��������&,�.0�������v>j_��z������H���$��I�/?+����p\}��
�25��|�.�������������
~7��'��8en~R�h��8���'��'�I��%���v3O��qB7/�Il��!+��w7��>'�:�!5J��g<����
f�'��> ��"��US8�{�w'����#�5�'��
��w/�+Pp*�{��
t-�nl7�N�W����]��Y]4}{��x���|w%J�w/����b��S�ShN���.�}�W
�
����L8x>����C���!&B�l ��^�}���^|�g�������HI�r���\�=_�V����kc)|���(z/Q�l�k�7 ,e�4�,�@�p�����#��gh���l���P���:���F�QmGVoq�@�a��	Y���*O��K�g3���+�E�@GE����Y���H�M�i�����������gE���
���g�%�����7�4��?��YQ/�1�����=Q/YD��41Kw��q���f���zmF�SXo����E�J���;�1���zq��V�_}�~u����~��_����g����|�_��q��0A�q��H%�z�Ys�*?$T.���J��r�'������5���?������}��5�����$�����57E>�.x�����y�YO�o�(��#���&]����(�i�!pR?�PR]y��&����/�t���c������1�km������������QD��kn>cit��jA�9��
�Ea���)���'��Df�9�������Z��;��0���Ag����T
+�r��y� "z�y�X$Al����#"��.��Vl����WR|�����=���\�R~�1?fL�����b�(�ZDI����.��Ut���[K�o1�o��I �X��y�������i~���eQ,�)�K.�J�B^���j�7L�X��������yY��s��m]�����KB��������9�@��g��s`��u+�+a��i�f��:�������i>ZF��-0�������6,���y���F]F1��P��?���#����%������ZV�tx�,&�F�xl��OK8n���I���'���>Mz���PI��tL>�F�����V��xL>�7u�}�"�:.3��Y���|�^KWiI�O�7*���:.s��
�N�q��V%����#����e����������e��P���g�	�=U�����Kd������B�	�+7�<-�:�)��I�i�\-L�7�����H����*�nf�]�P�M���w���4��=���&�Lh��jF�Z?Z���l7��h�0�;R���1��c���]�kfii���lQ
{I����fn��qPei��fOV���=���S���s��e�0qY�b)���� ����������#p��;L��y<d�	�3F�f�n��#Lg�R(,M�4��i�n�7���)��dg���t�� �U.�+���;��u�ow��OK��OgUq�q���2�:���?�5��[�z�Kzd�a�{���)���#c�h$�!Qq�i���2*���H�\�VyF[���\��-��<�j��tzhi��5��T�����t�j��7����,���]K:��l�A$�n����yG:�v���C8Gpwc��t�p��y��v�3	����r��
O�y���`\+����Y��``+��V��U��y������i�s`��c)��X�'`	�sSio���Va��J���V��)�cn�W�����rBUe�+��M)����W���,@,�W��\}�RJ��W���A���p�����E��E@5��)#-����9G8��Pn �����U��gtK~�/�s���ni��F��%������!��d��? z���#�F�i�=f��}4�V������Ik���/0^O:�����7#�)�{1���3�}�1��xB���R/0�@:��b�/����4*�77^�AcOp�%2r��������k���e��{���x�)�S_T�����?)K�7�-����D���e��}�F3������t�Q)�������[�rug��K��t��Kt`[���!G�K���g���R6c������aaJ�����J��W3��&o*]`7]]:��=�
'�,	��"��{K��(�,�*��R���V)�j����Pp�����<$[D]�R���&�B/�kS��
��Zc��?+K<t��F���������Xm��u�~���r��krZ�|�#���"����������5W�����s2��%��[M�bVw���/f�B��H}�� ���G�^�#J�@�A�D~T�
��{6��
�n������3,����4���+�
u�.�����_�EK�	-���l����u�����zkj��y���Vw�	�������*X):��]���7�b8�*��U����-�q"�D��y*X�Q����v��xS
2T�r�8����)sa~X�2����a��5��F ��/�V�Btr�w��8�o��+S|��H�,LV	V��=���X�u����
-���_:�y�l.��H�5���q��W���df������|�icI���\�GO��F[y$i0��AVp�'}`O$�?�qK+c��>y)k��@������8�`�C^Xp�;����g%���]w��utM��k��Jo��~�<,��`�\��$���"���:nx1j�����q��:�U$����H�ky�on�}��������j����'�
���qw���wc��U�������W�����O�w6+����N������=��m�bI=��R>���uS�������AG�p�0B�T���g��2^zy8���=�����v�#�����������2����d�J��������tF���vB���j��z,��m�n��n�������|��e�\�}�%�]VU~}�o�Y}�k���6��KO�|�iO7����
����]<�\�3Y5II<M�#����s�[C�Y��i<������������h���i�z�4�.m�����Cp^mM�������\�7VOn��T[���������{N�_�7�H�UK:c�1F��2zP�w/������hw����W��<\��W�~�������;���~9������_����?9>T�=��������������/�~����t������?�d~l��c������w�f�����)uxx���}J�u�
U�U�D�_�����g����J�25)�{�]K8+�fD�����i+l�<<���9h+�y��;~/��v�w��������"t�y��W��^����xR����	�V65>���D��<V
�����L;ZM��&����qKd6N:���\�?�%B:J�n,�����5���4��>�t9BV�����Om|���Z�v[_�;f�:#;g�����D8C�n���9����k�/�9�f�:���>�]]��xt�E����G�����R��l�^�x�)�����m��������qH�����c��j��:���x����n �����wG���S���d����s[';����m���5#�,��&f��k3�o���C��yR{�H��c�e���G8
��Uq��H����h
�Hq��:�f:K{N�I���H��LS{.���y`�W�B�^>�xH�uF����J�~������E�%/���n����
�����T7��B��c)���s��i�Y��(��nb�-�9�n����y�y��68�V�{��Y�gC��2M���Q�[x�f����q�+�;C��hJf=��;����������]���4�.*�����b� :G&$��������z��':��"Yw�L}�':2�����\�!:W��;���T��#�i�Z*��%=�<~/�v�s�R�Z�i�Q�+����;x8Uo�fH��������_T�B����R����kc����73L����E�����z�����~J_��
'TG)��A2I���K��SOssTe��\DfV��Q}�4�<�������A�xS-P_n%��Z����w����\+v����#k���!6�g�;��;^����%�b���0?�/��IN�^2�2���<=�pQ3�-�K�4&�q #�'A��ztd���)��JF4���1M�	d�����S�n�<;n��i����q���I�,����eR��=����+���t�zy�Ng4�l22�4���~e�a6Y���/���Z�Mj�X�yP����l	t@��n��B��A9�4��p�VF�6�H��W��L���^�v�N������u�w�7���
�I�G��
���pwtK���C����D��#�W��U����#����E?�g���#�{?�}��@�����?���#����T?b�����������
�����#���V���.�w��B�w�uo����"��h�+$h��+���&��~�W�;6�}�_��������2m�6�oi�"(�X�)�W�����fF����m/����N�Qo�Ro������;\e4�C^��/�jO�����w�%+����,��8{Np{I��b�s8_��9�����������-��������Bn�t�5CP$�p����:�����ew\(��z����_���@p|�������T:K����b(V,�xo�
�
��*�r����^W���t?w��n����{����[����e���+a�sd;����eFj��%��W���.��n$��O��UIl��Z�Ul.��v�]��������J�g;��f�����U��v� ��pQ��Il�q?Z�v����x�R�~A*-A��z�"'�1:b{�8�	�m��h�K����V���l1OO�TVk
���p�r���]�b�Ulw_�8����2�����W�]���%�,FC�������4����K8�����ZF�w~�B�^�%�V���=S�e[�Z�C=]s����z�	^��<m�2���`�����jq=�����9<s\�z\z:����w$cn����jO�(`��zz�)u��c����\ZcM������\:��5��MD�5O�����\:�g9`�SdO�.}��5�3����eg	���4S���y��������r�����)%���-S��4��!���q���l<�/D���������KO�V�X�1��z�5`�b�i��^����9�`4F�:K�5��'�c�Ap���h�;�}:z�d�h�;p��vG�-�!���H%��Y����$��-m���:A6ep������2?hIG�����{�����m��|]V��D��aCp��P=��x�����,,�=�tp���z�h�R��yR�cjY��N)�l��D7�9�59�	F�V+�9b��>�c����7f���^���ou}l�>�a�Q�z��l�i���#��fC�:7���0/�g�d����'�I��*o��:���B��^�,��+�E����Hgx�t~���U3����C�<q�1�!���s:T=�K�����'}��q~���s���=�x����#����t�jO�Y��j��6{x��w]�r��<�B�z��x5�d����9�����aX#JW�x�Q�b�I�1^�S�\m��H��7�zF[���Ob=�i=�Zn6	�HN�x���w�jX���lOv�����������\6����;�����P���\��tV{���E�V���Dlk���:����Qr�w�����������W�&Z>E�_Q�����{��O���jJ��x�f,��5 r-�������Ii1��Fj�]�����1��.R>�x��������c5�f��t���+�����a?�H��|�5��E"9H�1�Bn��7����r[���O�F5\�|������o�;X�-WJkL��|w\(�M�������k`����gX<�����Ae�o}��ox8N>�Z��z1�!"u�����|nT������c~��1��H�TE5���$l��X���]�o�'�����Wi2���j��p�[�������W�]�|�!����)&�h�%�H<=�[%o���	g���o�%^<��~�$k�u�3�_`;D6�Ul�?����p����k�#�+��*T�|�1�y�y��+2����z�Jb��\a�tX�\�l�O�!����4Bn$����
���V���=�x�_�W[��q�n�7�z����Z�4�������'��h!����t��z����Zg4������������n�z��������<��F#�O����e1�����e,���������7F#�O���������X����Q#4Yyki�FhK�3��;��h�.��&>�K<�nG��de^�3�-A�D�fp��������y�������x�
ie�������7(��:z`h�w�MV���nn�C������_�������2�#�E�����l�'�&	�me�9rv]����V����#vn�*��~����G:d�7F�d��cGN�=��xkz��Yk=k�C��'�&�����ma�����tx����N������q���yf���4�����>B���t89�.���'x��$��������+�UP���x8:�N����y�'x���������/�.cg�����G�	�+�3� ��JG�q��*��g��H����j��k�l<\<�W����������h=����S'�^����j)�����M��������*?:����ww�������P�v����T���#�������8�|����7�k�+�����/��g[}|����ww�x�F>�
��~V�g[���F�@?��?%~��~!_$�?!�,����L�7����`���q�2�m�I��c�^hwrU#+/F��=���t\(F��Y�������<��oO�
I��Z��|#?��:y�,���}|�C����s�\)�1Iw�u<q��z0i�b���#J%�B�����i g����k�2�������Y#M�>>�
��&������wMWd\�2I�%}|�����V#oU����'^�
c���d�'�p�����e����.|�Z���`��0��s+��v�����'�S}�Q�[5il���'^�v��G�,}�1}��C�MQ���V
<�wW��3�n�fk���W�]���P�1�����l7OeV�s�5�p��9�;��d\�W9*���F���@�f�W��u��C��\���x�_���`��x���Wq��������<����x<�Z��I?�x(���zz�)�E��cx=CK��hw�"P*O���}z�����km��$�\z�I<Dz,�����vM��Y�V^O����e0�������cpw$
JV�Z����fO3�,*�/�����g���71���n�����dMSH��I<�I��8���.���-���%=�
T���M�h>����)]f-����]fx�������Exv��}|��i�sd���+������u�^���
�;B�r"�P����AFX��jc3���C:���#tQ�H�z<���^�������~�������t�����������	b������/k4�mI\���*�����"���*����O�� ��YS~	I�r0���wMc=d�K3��b����Mz�����y*����k��|����GCX�����A�W�^@�e\<���F=hn���X���� ��z�^��x�JA��m���eh��l��q�fO��o8�U���z3�p�W�^�9��C���j�K�7z�We�xFM@��Sd<�1
�f��/F�`T�{cIb�<�����[�5�W!���V���xJ�2�p�����G�g��,���,�WL��=�MU�����,��Y����O���'�*�g���l��=����U�2~E��������m�{��>Z��F!?i���^�����#�q�0N�+{��@:n]��5�����AW��$�;�/�gd�W�����mv$�����AWd.�,�:��xD������R���N�/���N�Er�����L8F�fG�ad�����e�-�����I��0�]�e���kZd����S���[����i>�Ul\��4-I>�]�"]�����i�9�����������e��.c6-�yP�GS��)��~���.*���6��R�����������Li5X�ia"�D���0%�F��pF��������3FZ��q��#��ZB���*���������3.����$���n^�v����J�#���p���w�[��������������Wx�Y�����@�Yx��h;n(�Qc�Nb;
��F>�z�Lb�g����5������^r*��(�Q[����b�0$9�W�$������U��&����z�LrF���T����������>�����{����w
��Z�2����(I��A1���2)���V���.���C���4:����8���k��4�}F�[<#	�#%�I<��Ix5O�p��t��n{~G���;�U;��k��&�t�����fYXO�����]�}ISZe��D�����}�������ow���=z��,3N����e0�x�b�$kz`p�������VQoz�1��F�|y��3��\�	}�u�hJC��,�N����e2z�CJ�����e���Yg������Vy��N�����I��h��7����?���o���������>�����Eh����������?��p����_>�����=d�?�#���\X���7���lX|_/�R���o��I��}��?1��hr�4�|�)�&��-��������	������v�7�5�5;��?rH�h����*�y
-Q+��h��������?rFL�h����>P����EN��6����C�)�N����e����6=�]�)Y��f����)U�I������3M{���Y�cd)���B0����2$�����������R2�$-M!�Y�S��*��^3!�!��Gf����
U��:	��l%y���&�^F}�����m��Xp/��&�x�^e��V�@+N9����������E_�6�����.[!^g�����P?��2�{Y�W��M��nQBxjJ�P:������2��0`$�@��9���_�.�t ����]���;��k���7��V�z������=6�������Sr��=]#�/�������{��<�^�x8��f���m��h=#s�L�6�u�������M/�F<�Y�W����F�C���j�K���6�������*��f�)*<�C�����3q���I}[����r&�H�V�Z�
�>��O��3i�;`Q���_U|��,��|N������0+_����>�C������}�+�;�]����:@?���U����#?i��	S�$
BF�%w�~"����H� �����jR�UA�|B!2u����FW��>j��q�������^�Z��x?�_�^�������,�t\�����"N&����@J��xh���R��yv0:��uI�x�����n��B������j�h�l��
T���t^�o$A$�Q�j�v�zLV�����sH���7C���_A$���Ss���M�����5�����D�c�rn=�QD"2r�B�*H�x�"R����>�mK:���I�/�h��^1emu���e_��,m�6��PG�a��}i��:/��n�`<x[��4����x��fO����V���N8�����Y���(�������n�2�z�wc��&��������%�����M��CYM�%l�9�Qh��fG���<FK3�w�w��oy�^��x3��Pf���n��y���	���`�5�&}�6�pV^�;L��:���h�4Y1KZ��&q��	Fx�����.2oG����+��k�N��M<F���V�������S��w����%�Yj��<M�����4���;�ut��R��]���%�I�U�v�`<F�J��������X�z�+��iI��������cd�������:�f`����h�
�������cdi��	k�I�����)v�������/���M������s�!u��v������]�-zd~7������dZ���H%#Kw�,��uGj�dG*!��,��<���d'�5��P-#���Z�N"5T�Y9�}�#5����F�x���4�w7FGj�B���,\����Ib���,��<�:R����hpez�Hc���}r#�i�.�*�0kwN/�t�O�'�'7��*"Z��~kOc@���pcl�O6F_s�Pt9�kVL�A��d�	���0����F3O�A�t#��l�Q
�0���0�8DU����&�u�;�>��5�p}>1kL.A�ts��j�
�!������o�8��C�����d�E� ]��{Me�&Z�x����"�o�:�����N��e!�}.����T��	��<=�d5�����4��qt�G�=��C�1o���R�4��i=#���~V����g������U��x>�V=�>�L�����\N�������V�7(c7t��q�,s{��y�_qn�������_�
"�4��|��=r�p������-!���t��m��s��
��T��']�Igl��-0N������.����`�`�B��
(�{�	�t�F?�>R	��{����_���B�M����v���B�x�0t�����i�^�������-"k���k��_�5n����_+N3��n��j��N�����D��Zy�%u]3w�:nF�u?yf|Q��I�2�4�b�>�t]3��C>��Uv�)m1�j��S6s+�R�i��j�J>�x���f4���0J����'���a�q%1��x5�Y��)�7!���yh�0^K<�F$7���/l�x�1&��`��<�L���!�����y�������f_�fxS<�����-��I����C������#�m7���l&����%��V��t�iK^��t/�Z�#���W����j���$H������+��9:y���Dx5���3o?m�V��
�b��z:K�h����QE��t3����d�-i��Y�+i]0�F�zr��K���d����4��-m�4�.YJ�-9��������O[2Y���4������<F�J����]1�T�iK&k���FmP���|���R�m���X"G�,�~j9�-i�%o~�jYj��3`�����:��X���yv���?9>u�m������2�b.,%Rf=9���H�y������Q&6��\�Ld������U��3N��I���X�~�(�q���
 3�IaA��`Y��m�M
�����.[	����X�ex�~x���\YS�'J��o���4�������<�|V���~	H��k�"^�z��.��
%��I��T$:t��F��5�<��x�i�1�,]��3�G�t]A���3�Q�N=
���{��=
����^L���t�:M�G�����Gam7BnME�����.np�����Bc�h�������S���".~7��|?�?��2?P}*b��brw�F�^|�������l:h��\�k�L[��N���:��=RW����\+�:���^	 ��l59�JXr���"�q�B�1�}<Gp^������|�thF]�e��\��SpW�#u�.�������[��n!�;Y�U��Ee�0[��t��n��n+
��v��q����?�� ��?��fGp(*��B:(�UF�N���[����3��Eg�Z�)c������v�F�� }db�bU���%���h,�8����N3�z�R*�QV�Z\N.��zz��'�j4z/^`��x�Q&7����O��Y�w��(�7�#����#�U����7����F`z�i���Q�]|���w�{�sC�1��F�Y�6}G�5^�9�-��BG��rm���=��z�i6#���x3����������a�wt�����=��G����@���tV���s�U��i1/�i�������N�i��]��HkP^�s^�=��Me�h�q^�>��x������+pT^�x�0���JaU�_��*�5�����x3�����_^Y��FV�<e���������3�x����q��]�4���=Du���d����6�\�|h��[L��[����H�"����k<��FC�����:��	������WH5Gr�D���{st�;��Pt�����
������^N�t�7�nW4��jC��Y�Ni�2���[���'�m.�Y���d�s�~�u�POw-������CH�����]��,�1c��J�������,>�p�Y�b�+�����k��I���������}z��1��h�=0�eL�rMz=	���,���2�.����e�w��G>���
�5�%���2�/w!r��==1��;�#+�^^��u�I������{
i������e�v��g�����z�N����e�_lCo�z����y���
�]	�����c
;"���t@�k\O�'��oOD������pV!AO�)�1�"|z)7��4^����q%-i��X�i�p���x���I�h�C����������(��<��=C������Rn^m�95,�����o�!o�Q�����(�p��9��`x1j6
+��dY�.EqY�9�u2��EkM����X��o~�����������/����}���O?�����������O_��Q����������O?����=�����?rqIvJ�d`�_��� �-&������o����=����1��h��*����X�����hQ�'����PC��u�V�s�CxR4�txE\E����YMK�u9mw~7���t��������@S�P-��C��FSc�Fl]IDC=�(i^��j���g�]J����]GD#g��uz�Y�����q�{��>!g��cF�g��\��Q�I�t(���J��z�D��]�h~��zM�e%
hu[tQ�@I�]Fpwy&���%��T_���R}��H����:0�S��=��Q��9j����b
�����{�����Z�������L��<P>���j�x����ZO�lU��c���j�x&�l;\<:���XQ.���i<�`�
ui��n#�}|�vq7�����6r�I"�1����9O������H��d�-���J������-E���J�Mv<�5���X���<iS��n���hS���W����_5�t�o�]5�]��6<�����������2�>�Lf���Q�Y��q�{Pf7��:g�_���"k|Y�&�	��G���m�Z)�����1�3$����H*������99���X{�=:��������I:.�^�M�'��Q�%�����y�u<p�7*��_���~6��#	�n�x8U���G.�Q�o��G���&���8
�����5rRx�Ta��*�^jj��S�
\�3�u��=72qvI����W>�v��J�K
��H���&�
[��"�6UO��#	r�����q�T��W���o���C��j���Zj��tF_�����x�q��/�j]��JG:�4�zkHc��M���gd���#�5{l{���/��^/�.6�*O:kf����CJ�W1�5�<���=����x5�Y������q��H��������sH��?�h���t�aj}�)��"�����n��='�
��I����1@�H��:�O���rvq��b�ao
SM_M:�����/��^(t]F���}��j����$~�3��*t�urH����g��/hI�k��%�s�����Ez��1���n����J��1�����cr����g�����r1�vo�s�R���zI�9���<���F}��G���	�{�������e�����2�b���w�g�H��2���E�Zq�����
j���2�N���3�q�&zQ�K�!��A
t5^7�������0k���u�U����?��!����:��p�F"�:g��G�M]�X+��}��z���2a�����U��4���3�]�tQz�@��zw����!�	��
pa�x�xX������2a�iy{,�9�a�yG�)�������y:����.���y:��1Ox5�\�#��P(���9@����4�Q0Fp5�\.����z����B�-�<Fc����v&2�D���;���U���w��`�����(��*����Eq�DQq�������ey��!�U�U���.�������� ���m��_��@��Z*-H�f-H���s��@}Y>����u���-2O����Fk]"���Y����H��C���N:���;��.���'�`����?g���g[H�u�[����Ov ���������p��{cF���x����jm�;����s�[�e<r�����x�:�XbU�G�@"�>��G��cu rbP��qs�s�$�1�3�a�RS���8>p�&���.V�x�����4 ]�N�������F*�&����D�t�N����� 77%��W3^�Y���Af2���h"�a{��)����4��H�o�fN4��JO��56��J���#L�W3^������T��3��n�l��xF��U���x�}w?�c<��v_��"N���t;jX +��ZOg��q��H���w�2�Y��g�5m����
���@�G?s���*~�8�&��<�4�M�LmAK���#��96Bp?$U���c#�V����;GK��f�G?w�*�^�Y�������Q��w������O�f�F?��*��R�o&�J������m��'�'�$~Uzc�a@���
H�cX��.�%��Q'��G��A��	��l�VF��=B�K��r��VF]�+����$�1�L��r��T]7 �M��kw�OT�;��Mez|�S���k��di2� VZ?N��`@�}�.J��p�����gVw
���K?o�x����h���FX�B�kc������q_xoy:{����z�����G��H���)��/���������a�G��H��**���z���i
\Le=4��z��m&�k����H?�x���
�������u��o�#�D�Y�Yq�z:C���DOd����: OE�����jVz"�
�g	��#��"��{�SY���Y�
ji�7�zF��K�����zFeV���7B?Xx5�m~1�. �J�o����A���n����l�*?Z�*�g���g��R:��Z��/�����g�[��[V_���2��B��h����J�`�Y� �u"���B>����|rlYs���k��'-2����F@tsC��P��lD�tN?"Y�)"5
��%��^��:a1B)�b�n#�y.g�w��������a<s�`��u\D�s<����]a��Z�Q�	7nG`-�P
�Z��2.�N����o�i�x�Wr��d�7md��R#"��T��A������d��q�AW;���}y��ne�`���k����jw��P-�+��k����h8f�pl���d�?}���s�C}�O�H���6�=����x�MC(;�&�i�"���j���x|k�Xc�����g��j��\��x�'���gi�'1��3�hLZ�W���$�h��-��$�v�Hg���xS�]e��NsK4>��x�������z�c<[�x_/Z{r���s����|�Jc���l�[U�i��p6���L<c>����I��.���������y�-F�h��S�L:�0�����j���v;j&+1�@;O?��{�B�~��\F��hzYqM������!��BP���3m���e`�-�k��;c?{F�g��z�q��U�������'�v�$~.UM��aG��\0�;^�2�%����m����&�W���;I�";��:����J���������uc;�t���]kA�l��QK�����[���O;��@�����Y�l�V��d%��~�I���b_h{`u�2���GcC;�V7w��[�����&��^��=���3�o�t�+�bt	-��U��R��u�
	��d���*����V�h70��{���+�n`?�6��:B�����$y���2�9D]4`Ef�;G%ZG���Gp���
�Q���E����dF]0\�<Z��
#��g�o+�����i����3������p���j�����x:�G�"���X�<
,�|���9��x��E����D�+q�R1��!N�]1����"{���PT�V7�a�^Z�c����aC��9��������bC������c�S`<���_97/��<g��#�a)�Ek'��b��-YFt����1E��}����  ��%3���}Lp�A'2��A�Jp_����������k^�~����������e��A{Ud�K���4���OQ2Y�5�7f���:<-:�P���#/h������E�4wZ�Ky���+]���T�i)I&��%*�3�}B]��������������>20!��G��gtA]�<k��x���}��M�_�P�@%�����Y��G��U|��k0����Y����i23�f���an������T��Sa}��*N���R�Ou6���/�~j�C�b���Sb*A�G�b��C�i=�2��q�4��W3�-��@�'�O#C�H 3�a�Fp��E.�b�2�����y��p@w3j�	Q��Qv"n\���������A��"n\��`�x���g���#�����q�3o����F?��]Rp)����<����������S�5��xX����_#�)�Lx@pH�&�����ha���{_�g�c]����_0/�z`=�'F@�4!"�o��7��(��3Qy���n=_yxJ3����L��u��Et�@�-��Q^�^��^q���(��(�f��x&���	�}\Y���8�f^��W^��[�L��v\eQ^��[�l9�j�����3�\q;2��-������dR�"���'6�#Qy-^g�(��/E>��)/}R�L���u��N�+1]�rc�)D�=���a6�%t{��Dt=���,�^`� �������,v�1?_,����Q������T��&�O��e�������R��d�<`)kx�����cq��?�|�ag��}���������`g_����FM2v�>c�����,vV=���36��&���X����/���;�F����}QC��x��%*e
mJ�$Gk��haC�W���X`�W1t�����{�y�I9�EI �u�k�����g^uN����{�d��ogV�%,���b����b>/�J����D���
x���>���ARmI�E���t�#iKZ�"9�}�D[�^�m��wFgQ������eH�x�8"�1F�����K��WnX����q�^���s$��^3�z���g���O��E������F�<�t�^��<$Hxc���������'���ui��^�M�xpH���\�����[#�y�ZT��Ak������/��W_���_����������_���?<��������?|�)�������?|����3Q�'U���+o��]�,<T��f���_�����m!����_��[�(��e�^���l����o(q�D":�Qy��	��xZl	o^�`fa�AbDpc�����7���-�	�-���D�1���*��*��������O\7�����S<3�S������'��*����>��V^��t���t*���	m���m��Xo=WN�M6���R ���Jh�-�/���-��]���Pw�����sCtb�������tw?11������Ab�|���'����m�s	Z���H�~����P����@��B�9�P_(�����S�����Ft��u/���X�J�#���E������GO��5P����X��G����x�3�g�����H�$���� T���a�����s�u�f�5�������7�z�����Fx`�z��pl9��@�A2�����2�������g6�o@�
�cZ���-�������@��]9gt����)��~��6�!Z�a-���<x�#���)��i���c���W�<�C,��)/}G�����w�\�<(
����f$*�D�Mo?]y�z%�1�e�-��ZD����?�J������:�oD��J�T�/P��o,Abb�,_^�#:nkE�� ���R2�s��Y�g�RJp_Gy�X�S����\����>A)��<��
��Rq��<��P�q�J�� Cf57�/��p�e�m8_y�*�T\e\.�H;�*U�Wq�:��<|'����yB��
�(~~��1T�\�rv��1T�\�r���A�r��T��K�d�n�Dp�8��IpSN�={K�d~�t���������-�>aQDz'\��o�!\���:�o�D��In�[�+v�@pc�������:<�:�5����u��X?��F�<���cZj7�7K����et���Z��[i��D���g�n��h`N��1��0�������GtL���������4L����k���e��(n*G�u���kH��du�4�c�����l���Lp#�;;Fiq����N.�J��������g���.3��:�-��]7�8]w�c� T��D:��A��e��W&�1������~�v�_�R����lUV^.�H�+J���'
7G ��J�QJ&��'�m�1J�QRFD���b�Rr]R�y��������������#��
?Gg4:|M$�O�������0b�<&���T�|��	}{�v�Q�����feY;��"�}M;�3c�<3&0������-����p��_�I�����I�e��%�Y����n$���`�a��9�����#V(���v'v�lC�V3�>��Z���
x��OXqm:���9�8kD��J��-O�d�\��R�l�U�h�d<uaO�,v��J7vpoZ����Jm�Bs�k�P�����dC�x�������[��-�+��-G�Xk�]���Y:�yo���l��%���^y���)~]�\�8��{�W���g�s��J�Bc�+>|������V���g�3>�k�y�t-C���������A���&��!�������x>����+�Z!�1Co�����5K��5
�x��be�.���b��{��>AJ�ch��Dx_����;f��?�(�i�X��L�Py/������g/���,�6x���@q��#�p��}M;#U�c�.�s�����{��j$��v�5K�5�����Y��N��bg�����K�ma;[�V�{Yvj2����kb��[���^'���]��E�<�&��K8�&�Ux�0-�	��v��V�"�^���	|��g��:��J��1<�>�y�U���;�>b��kb]�[�3����J���J(^����	|�����^+�������x���e=��9�����X��J����+y���Rw/��
tQ���O��5x�4L���-�,M���B{�����X�Ko(HY�'mh�Y��e=�q���O/�������q��U�7�dC������O���x�n�� ���%���b���x5;
5�_��U���!�R����v�^���s_���x�rzS]_��	n����je>6O���7?~�����+	]���Lp	�/�����}���������L�d\��&�[LE�p��� :���%a���f��D[`{�#Dn�h�����S�LyW���.k��.h.T`e9�S`<a���7ei����k����B�)
tjl�N\����(`�96.��!=S��)7@u��>��,�{�6�x�%�/y�
�FM��lu�P+<���������G��mPZ?v~j�;?<��C�l�6V�5y��cU5��h�1M�q�M�����D?}�e��|�+���q��d�a��>�h�mM6�'��l�(�8��$�8G�K��<�a�����K�dI�k�8���$��ME7���>_���#s���rItJ���=�)�Y����n��eIPX�W���w)Ea�
�<n"���7�J�1�"+����<��|Kq�]��i�l���w)�����R��3Y=��R��
GW������?��k���,t/�/�j���f��0�h���C��x��jf�Mq�Bw��)&���C(�~n�{��������
I����3A#�02s���B���G�t��B�����t����+���{��
�j�����NB��5���^��
��53��t?��3#�ut%�m^d�;�k�
��-:Ja>��[t���L�mB�f��0i~,��@vx��L���,tGt
���_���2�]_ ��H&���[���Cw�m��/]��WY��'ZiTeg�,[<�����cHF��*�����cP�F�nDw�g�#�yQ~������D����E��u�F�1���NI�Y�%0�}��]#�����Nt��>�}������bw	p������>�}�Y'
����^�,��������}��Mf����{������:D�B0�3hgfGN��3�� � �O����#:��	�k�R�I������������ZY]aS�	��5��3E�[��&�}b�VC�����z4>���������7�F����bh|#!��ih|#Q��*���<|$Q�#	;C+����DMI^��5T1�XR�o�x
�,u����a+l�/����b!�4�0=�E�[��7K�,�N��b�/����b!V,������������WH�v0v�%�ux�����%������-y��n���<��lQ[x�VLG�fZQ�����R���@|)��P��P�0�g�S`�8j�t5�w:�8:��l�C�Pi%�O<������@tL��E'������Jp_�:�
�A|�:Kh�:H�Gx��M�������E����5����.}��[�D���E��d"�7��J
"�B�{��*j\�	�|f���.����:T�{UH��|$����*�I��K:���C�"�bm�����%��t���vR0�
��<��`g�5����J)�@����w1��u1�p�X)h�	�\C���go�DZ��S231�3`��+#�����Y+�~t��3����.s�.D\:�_(.F����Y��\�(�����xz[&�:���L��C�0�@���K8�	���q	$���7����b0�g�Fp�[���_|��/;Qo)�[Jf����l�[J�FQ	��[��	��Z�Nme�o�z+��P��������G��!����zD������w�2x���7��4��<
�+Zl
�mB9�9����A����D
2�hD��4��4�e�>E���>R�^D�g4��|���I���t����|w-�M��r��b�#���N��(Uw	2����`@�w���Iw�At���������c����j2t|D�":�����G��D�'�Axx��q�6��K����u������5�
�MxI�5����b�qe1����A��-lhL�����3����ba�8K������%�R��4tY����{����l�2�J���l��	�kZA�B�c���`��BU2CF�7� :� �kZC	��?36&��M����@�)�Ym�b!��ih�)����4x��xj��
}��
�J�X���2ai�K�]�� �X)1����w1���2���'�������4���{U�^!:x�&����}�gd8���rT���
Q���,r��B��L�6B�$�L��{@��j#��qi1�N��
�0���d����fT���:����$T�~Lx#���A�6���Nb��TmYC�T/����)m�����^���.���j:�Qy��^I���� \ ��gk��.B�Ft��U&l�>2a�:U���Tm����~�R�J��F�L�R���T�8��r�������������,�����U��mN#e��|$V��h+�);�Q2�	�Hp� 6Nz>��	+��3���h�"dND�q�#e�/L!R6����E"`���'�B��.�%r":����$.J��$e�P���GF����q,�~?��c�B�B��hy�2B��n�DD��9��q&�e��J%T���T�m�>20���$.��4��P�����-n��L=O�������2l��+�N>vY>tW�[��r�di���1�s��N����<TY�
U��
D�c�*K�)��0��tF8}�a�rmV ����}�b���n�
Dg�Y���Ew
�m��]<|��;��������1�e�m
�a�:�]<.<�g��Ap#�k��U���.
������Oc��L���� �8��|������;fD�%��n������Veg�MHd�,�i��*�+�eHK�������$�����x����Fev]wCc����)���-��:�]Yq>���N�*�'T��!���H��5-���O�c���Cx^-�����b�
���e���H�X�+����e�!:u�]K{�[��e}�=���,��������y,M,��q�6�}MK��u���/y�\��~�n�Kt�E�����.X�~�"?:�A��RcrBc���?�!V�"��q����;	����T^���~=��|n�P�8,�0�?������j}X�*�d�F�������s2rD��}���Am����}V�0%
����X������$!9���!�}9`��2%��m4���W���O����*�S^BuF^P�<.g�������P����w��[~������F!G)j��=�gy��E��Bg�����<����}��*�)���b�P���G)�(<B�X	�b���s������� ��jV����}7R�S��ah��������z9��`�$��Q�9t�:Lq:�2!0b��d<��������:��H`��v�B�@�O�����f�\~<���L��t?0��#X��k��|/�!B����}�k��r�{��'��<��P����~��?0gR��jd��J3:�G!O���)�}b��|��yw7Ow�\{���l���.6�����h+������<��������W�4��'��\��S��Ft�Q����At����"��\��C����u��Hpc��=[y���7�0�Q����Et�i����g�]] �xy�����R���N�%Uw�����l�#�xj���v�5�������O�&^���<�������D?Q,.��p�����k����J.���p��0�l���5�g���(m|����lW�e�'���7�t�,��(�}�jn���"���GFx=&A����F~�0��$Ix_��=V]zfG��> �
���2�����.$��ZK�>f��9y����w`�����������Y:����0�]��Uy���?6���&[~��/?���_����qr����/?�����z1��5?~�������-~_\���~���������g1��U�����+����fa��}��/��M��m^�����:G�m��:GM���g�,�`h!�$��w���YK�.���t�P�L��h}����VNx#C���R��:��k�/P�L����\.�����:��R��=�=���gZ`�Q��~&��LCx����3�0���Y������
o�>f����.���C'4\��.���%
]`h3t��kO)T%c�����D�5
������JE�Fz����PQ��v�"�zB�y��5������������<z29�1!�!2��J�]���
��@p���]p���iZlt�8�������^��c/7����Lp���W�
40��0��6d��]���'�'/0�mA������'/�
��������OFt8��)_g��+�g�LVI��x��r�2��������`�$����v562X����^w�
VI��e
]������!���@����<�� �!��$)�1^���x��c��Svz�*����>�{��B�`�&��i/�
����
�L����P+����A������Mi������?F�7F�Ebm�#����J��;Z��o�w��6wlk���:�8<�'#���?qi�g���-XH��O�W����D;D[u5H�-$�2-N�:%����0��U�������":x�n�c�VQ�����]��_��!V��A�#���!��V]D���>>��&<���tC��[]��S�3������q[`V���1O���`m��	Hh_��[���q�Vi�$G���4��q�����.K��c��{�
����L��si[�#�{��3�
��%�T���2/M�r��;����ZW���Q��[�����>���k��S@����L�=Wa���Dt� ����3��AtL����o��D�F��V�[�"��X�}��*<���4�]��;��nLw����/]��|�y������t��o/?��������3��	��~R�'�����������L���fRt~5K������L��:�W+T%3�}{�bi\dNx_�����e�+�}?��M�-��<�v�<����M��f�>[n����&���ri�������61��Mv��5-�i��:�L�61���K��L�*��il�#��i�&Z�����������L����$�������a���Ho������x���e���$A�a����� p��&'=��p&3y�sx�1
t������������F��s@�$��[=%����S`<�v#:8A����D���vF�x�u\��\�2�nD>�-&����v#:x�����X���?��0:���lB��F�p�Ap��tT0�!6f�_n�^T%7;��!j�^��Bx#�N��e��+����oh[�����F�;v������$\x���N�<�+�3�]�E{%�c��]&��]Lxc�K�\a�u�=�����]V{V����7$�e�j�A����'��<]����
ko@�1L������s%jo`��0�OV{�_�����,y���1?v�M�U
��<'�Lr��^� �����Fs��3��<�P{�(-���E{������wz��kn{f��
����^���s�2TV{������r��<��=�}`:5SG
kJ�}`:5F�Hk�G�1�)�e�W���a�e�^
�*�{`�����\Ex���E{M��c
T)ce��@E��>/����Gx�����f�gJ���n�b}�a�{)�d��b}���r$T	6�#<�����=�.����b��@��z��#].z�A���v�t�uW��.�Gk�g���y������c��{?�����M���-��:�����7+����
�s-���� ^<�'���{f/��P`s��O�������VD��ii�����#�����i�� D#��^�����^XD�Bp#/�	���vD�]�q
/*��12Q��n��(Gp#-�\��HK;�3%�{��8������1�
%��7eZ�^�Qy�sC�;��A��R2�W�������� ��5������#8x#��G������v��]u��'�E�":�-�pEO�mW���G�#���1(��	��0��}�\��H,�s��ap�2��At\O��^��+�f@t�H�|����7�}�L�Ew�t��i������:����;d���@t�
���]e������=�|wU@t����}�����C�c{d��<�dU<o;���x���M�9�G�5�.~����`������D��.�(��j�l`v�s<�<��]�bt�=[�hYf�<����������]�_�9E�5x���.��swf=M�D�\�"��jD�z��h.�a��C��"��`��Ut����L?��#��0�i����w�(m<���#�=�a���O���Iw�tL�b��UDt�0����]�u���Q�9Yt�c����(��l�":���������@t����>;`e�57�*����2��(�O�(��yR9t�`h��Et�`��7�;��"�~����O�p��Tf	nLw'�W(�6�����{V)�U�l[�'�W(�"�x�����
-�-�=9�Pbc��*>�kD�����L��]<�>��3�q����D��q#����d�4
noq����.~�y.���;��1��?Y-��J���Q���
&i�p�U�9��Bt��4^��x����e����Eh�%���r�z��w�Y��a�l�����\���,���'ki�!����&pY�-����c�W�t�9�cZ��h0��+�Z*f�
;�,��+x�$��ii�Q��d.v�ci����zE,}p�8����W/���nQ�Eq�vK�\�Q�X�,>�r���x9Kc�������<�F��=`iY���r��]^��5�Ejfl����t��K���%Lv���n�ri^h3*b��k��1e�� ����a�(q�~K�x���e}����c�f^�2Y/n�:;�5�=����/������&,�Z�����������z�\��e}����������HP!��V^Kx�L*�f���*&�a��g�����������
���24����XX�Ic�!�9,���f����sXZ�$��kZ&���c�>�F�a��7f���d,
�XF��iimP�L�j���i
a��eY�/�Y��F������J&a�g��������,�]�����������@U2	�=�F�K�\Jf����
[����|����u@U2	�=�F�-^.%3H�oWN�-m�r���y5K[`�������i������%��d-��rq�e}g��������
/f���52a���r����i�R2�����]#�^.����j���=^.���D�a
�Jve��52��r���5v]N�|:���_��tQ���O���\�C�l����r	���t
�$|�����j�\jn���A]��R��\�N7%��Ic��5�/�&�v��L�b�/����iV�"B�c�>�F�����I��$ki�#Bx_���BU2i�D.��;�\:��$e����q��}MK���Ic��wY,����3-&a�� �O�x�����t��*�4�]����^.=�b���L���\&�`^�����W��3^.3o���c��o>|����������[��n!�����j������������n�~2�Ro���-�"]������
A`zB�T���)�>���Y�k�?N4C@�f/�@$�;E��>��s������}iZ,��<�����E������.>���W��mB�9��x(�G�^K��B\�Wr���"3���fQ�U������U�9��x�z���~L`��<�CW�;�]4W={J.��lG
�i1R��������:FD=`w��$Gvj�`��#7Q���'���iP$�����g���}G�3v������r;7�Th�/�CGf2v�1��0nhS=��j�>������2���\�n
���v�w'�C'��	�F�������L�Pyq��u�2�p$������<����������B���DT���<��
��������S^B�R�	�7���Wcat*���q���A�1�����
��+�=P5�4S�=�V^�P{L�D�,0Y��P&"��w��oOk�����|-a���=f�LBK�IJ���@���T�{������eW�S������o�����]������O���B�V���o~��������R(��R�����������_������-�����7�����5�]��h�����_�}��|���~�������o>�������[�8�����������?��i�?��.����v���?������O�y��U�_���/�*��*�+�v��5L�p�<���C���NO�RBoo��������s)�C���;���v�E��	�\�������b�tY��#�X�1���c��)���n�����M����.�$�9NU��Z4B�"�Z����6N�`9G+'>[%�C��]G�v���i��1>��o|	���{�;;�C~��0���F�N�b�/D`_��<�uX�{1�"��t�rc|nAxX�_���'��A��Wf^3�c:-��U�q����o?�<�&jN�B`cU�h�����8el�X8��������]9e��S�v���=X}�& X�Tp��d�c <Y	�~���J@WjD������<�+��&��I~��W#:����/�x��?��6�k�7��|�aQ��L�����j���j�/4
�:��,s���uN=��|��F8���G9�����)M8�n��w9��C���3I�[ts�]���}$�[�����
P��:O��E��NO�c
�SC�X���q~�N����R,R���g���3���i���@�E'�"Et�����������^���H�)P�������E�jhc��k���K�c���"Ex�2��av����@WT�{x�z���������~�3j������$�^�*WUG����������+G57���J�X:J��;��1b@���J�%a�+G$�t.0cq?>s�&<���&+<���"���G�9�GG���0�0)��JD�f��t��B712����8`���-�k%�k�
��5:J`����5:J��%)���V"<`������>Y��J�K��,����i��������1��s%�k���b��s%���+���\��&�\��GY���X�%Xj.�O=�&&��_���8���`��^j��B��!~psS���T.	nLy�$���c��p��dX]���5�+OA
Ex�?:�Q���-��2n��S���L���x���
������6���!�"�1�q��<�k^<��\/���>�3�{�Q���{��?~�AVBxc!u��}�S����U�������GxP�'��Lv�b����Z�j��U�nPU�������eG�d���\������
���,��<����{>a��d��������i7�*�.����^���{vhNKWx�T��W�to�>f���������XH	���C�^.^��O{xv$�/{�\|����eh�����~�Lh���V��FU+k��&� �\Yq��fUK������'�������,:R�]]�a7��z����G�c\��C��fZ��EI�Fc��t����B�E]]oh
���:��B��
��:��=Dy<��)/��B�g*�L�4&����S^���#��#F���c�#�^�<�C�om��|��m��[��'�z�2)/�������t/��O�=��Q��H���j;�
��*��i/�xB�������Nx!�)R���9����'��cA��D`�G���P������8�0���&���M������=�x�������)��)u7��5�������}�O��P�M�K�C�1�<u%z��g2�c
O�:����B��f�u��>��:|4B�"5��1yg����e������Y.��+�h���;�����8\���E���t7na��hJb���}���������3[����aClI��}���aA�[m��i3c��>d�9X�0Z8���:D/���)u�m�;�gvl�]wg�Gp�ipH3Et0���+��o�HSe�+<jn���?�
��.f������!�����J��	oLy�!�EyH�$���<����y�!��%�����ZD����Z<�(��
S���,��}IW[c�7�����k���<� �1��5��)������;�m��Ixc�kKt[SvW�{��������K�L
�����������,���Xp	���40�X����d�<�Q{��Z�c���v�*�\��/�������6di>QoB��[�*�����-Z�h�EH�X�-��^���"�7��H(��:vP{��c�Z�.Q�� h�����������	����u��7L-Yj��tcP��~�.�o�&�l�6��P�^0��3���9e��Q������?6@���`RB����h�����|�	^�m���H���Xt"�u@W����V�;QZ,��*�,^��#-S=J�-�H[W���,��Z�����s��������/��bM���&t;�p":��Z�V����y��������#��������,��9�-��@���A
'��p;������#o.D(�v?on�N���X�������z/�7�~qC�`��u?��.�r����{?|XR�
�����~�n��e��!���R05-��d���'��c
�I����pM*�����k����&3�z��\�5b�V<�x�+l���R�'������t�:��Z���������c\kL�_��;xolk���1KWd��p���,YG��������h���s���r����TB�����vB��� �
Ars��Q���������	n��;3��u:���G��9�t@H'�+��sky��4;w: Xf{��Hq"�<��	o�3?!� :cS+��Ey���7�<���iwHgZD�M��HqY�W�Cxc�K?����:<cJ��N;[������y�"q`W��Nr��h��Y`y��U�}��4��XQ8���<<cD0�Z�iT%3���c�dib��t���x����tU�*�
_sY����b8]�B�,���4Lx_���V�f�X���/���_$:F�Z����G:�^���	����/~dgH�����n	�w�;i�,����8��1��c�+�L(\=�/����0?Ar�K-�Ay��z'Yt|)@�
�5�z���	|���}����>}�$��n��g��G�
T^���zCk(2��������P�'�Cg��@E�S^�a�x=*/^����)�K�7�<�%5�����gJ�{�!t����Fw�%5����'S���X�$�1�e����a`��.��"4���������,��N��+Wr��24�<�&��@sTn�9��:������?�0~K
<~&��X&�q�?��J���yh����<5L��~2>��_����>)>56}r!�I����,�y1�'���q����ju��I���x\�1`�������_fl�L�!�1>�����|LD�wt�?y0�C�j�?�]�?J�t�AM2�'x\���
�w���B?n0������~����F���lL>&���y��h�����0�'Ow��>7�%��y>&��K���?y.@vXNj���L�Ad���}3����1\��H�
���n'�*\��@���ZRyF�W�1�`����Gn`���A�Exc�.�.*��Dt�{�},��4�%�7�<�����P!�/��i�J	o����"|L@g
D���8&E�x�!�1���PL<�*�y��z�3)o@x�@nl����N/���A�PB62p��\I�$����(���E����'9P��b.�t�1�xPA'�1K�XG&ci���]�
�v�M�#�	���v0b���,�9y,=��^g b��
�t�	�xx�T���>HfExx�T/[���d��a5!��^��8cv��NR���Zg����f��P�����#2/Kx�f��-#:�[&�e'�e=�-�F[.�c�c�72���J�)��Fr&m !>9�J������C|��N����0@^5@���u`v9�7	��
=�]������-#���G�/B[��@����O*\�+��:N^`'U��]�i&Ne��Q^���AN �:�Qy�U�5��Q�q�</{T	)�0��g���{�����o�e��gQ���������yP��k�G]���s�kn�(F,�x��:�ZFx�7����Y?��ud8k%M+-�[.��(�>�=�bi���������|�0�y��l���,��}?����>~t&�e��q�Q
�f���E��s����9�Qd9�������Q~���W�	�����1o{9���yDg]`f%�|@���jD�B�,+Fh!NB���Q$���SB<Bcgm�p�h5������<�k&L��A	�@��i"�G�"6��4�u�t�����u�|/n�<��76	���Tf��E���x��Tf�a��e�$�)���2���]���^%n�����yc2M�U��z����U�.�d9��i�T�c������a�!�yo��7��K_�+r
*�00�}��;��`���7���cy\p��0p���QG�1����M;�����g
�cZM*���1&3�����)�y�Cx�>},���:���*��_@���'������s�>6gR����1���'�|y�At�������� %"��q��<��C�bX���y^�m����96�L���C����������z��	�T��1)Ge,�2�T�	�kZ:�e�X	����P��bf�����t���d���Y���e1acj���T�o��;v��X������B�P;"�1K'0�d-����0�"��d�t��K�BY��">f���~���K�td��*9�����ri_�p
X;,t�\GV�.K���Kw�)G��^.�ud��^3:����ci|� ���;�r���K�BY�uP�J&�9?��r���m��IL�i���b�"���e�p9]�P��*�d����e��3i+��bUR��.�������LN=:4.�]���D_���[�0G�:�>�	�7����}b�����]�T`��4m�N�O����3�����{�(����� �OL��iXtu����E'�����{��U�*]�K,���%���������S���M�Z����'4��������\o��(|��	
d
�B�Gx#������ �#�1��_9�� ��\=��XW(o@�1�jv�I�u�����O��'�,-�����i�~���$����)l�%?�;���B���]��2-U�/����g0	���e@�d��9FS��q`����@��Opc�<��Hh-������H��X�����	���M�L�H@�-���,�K�W��Q��ImN�c�G;�]G����Ap��l&�h_����m��	��1�z�.�� <h(3�Uo�������!Hf��a*�2k	$_7Rjd�?�f����T�����<
�v�V���?���3e�f�D;�*��_����S�a��k�xE���.�]�,_W&?C��	�Y���z�N(D�'�b-�Ty���w�E�^�*���
���;�>��j<U�xYV��N(�8�n�_?�_ l�����<�k�af�p�w,���t�gL�^��-5
�$T�e-��o���w( <����t���t�������Z�,����2�m�
(i��5-��~w����=^.���4�H`��q"<�\z��>�c����]/���\�x�5a~��y������n����@W:m��U����
x������Ks����z�&o0w�}	�AXMp�A'B_t�zg����I	�wF�1jA�1����Y��.�����T��[��@�L����	��7b���������;U^����C����=O�2��F�1�Kv(w�a���?b���Cb��.���y�7��������y��4O�����<�Y.�yN����h _��Q��$OvF�a����2���A�!�����\�4����o���Ha��x�4��Cu��u����D�_�u��F���a�sK�Z��>~=����hu�N��R@)��Ps������%�FG���!������tX� �?���1M���
��Rh�:��c�"~
�1�A����������0C���\sx�@W�y;H���� 
 �KGN�����2����YY�*�j�!s�W}�&��Z�B���U�����c�����$�)� #�A�Jx�����L���	�t.���������M��ad�R!8��U�NFfp�=������LpW���
F&����yy:��1����A��i��6^��s����"��q�B�9��!��.`$�����_^V?��)�#��L�Et�c���yH���n�=Gdq���[�/�J�l�Gyx���xu�9"���������m�(wO�����4)f��g���M�T�L�����x�4/4�������������S�!��S���e-��e�1m/L�2����Nx#�v	o�����6���_��=^-=s����"<�BExc��?������e}z(Q���6�@��������\�!�/����O�-=0k=T�A��7���&��a���A�<�K������J���)����DgtK�������
U�>�*k��0���N��C����E-=�*��-����.%��6�mn_����d��[&�Ka�u���r��Z�~�Lzt�y��K��1n�����>��3��=:�A�X�2=:�8��[����AtPC'��y�aA�1u�M&"�"<�}8�������c���c��qXP'�+���g�:���MQ�ch���!���'�?���X������dR��������)��N�����<����������Y�+���x
y��cJ���d�2�,���*��)/k����)��!�
��Qy��uv�{�!��1��=��:�[�	��M�Q.L���mU�<n�T��:����(/��.�k�
Ct� ���;�c�NuVoXI)T��BUE�R����[�R�c��e�.�����2?7���}��hw��t�����@
���~�����Ux��,����@��DZ������Xz���s����R��7�K��+�Y������U(�
�T>����������b�;�L����i���du�';<�3w�tO����������+������
�b�d��1�)"��:�.Cx0��Z�)��'e��\w��a�7���w-�]����S1���sZ�����-^�a�R�e�3��7vIs���df�2��Rtw���S����M�OT^�������k@��<,`�qj��j�2->��Ct\���4�c�������DM�7���K�Aw7��)O�'4�mq=;�}�3��.�O�'���������*n���1|3������� :���/OA�������*��yBp_2}�8�3�A��?������� n�&eK�p?�j�6�2~�h�@+��4V�	o����� <Q��t�r����0��*?���U��-.�>�� ����.!5!�1K�ox/��a����X^.V��O���m�T�F�(���o�����^.���`#V(t���u��Q�����������*�\�
v@���@�_&���r��k�Q�;[�(��(^{�wK�~�@�Q���k9BpP!����0k9RER��.��m��c~^ �-G�� ��5f��f��"���HT�oU�@W[��9��(����M�{F��{w��%��E��C��(��K`��X[��4�!:x\'���izt���K����+1���Q�o�@x����R�u�E	��G�E���-�be���cy,��dHx�3�����	oL{�{^U�����K�V��7^�����]������D�p9��P�����\��%:����F������L��-�����������6@)���=_�s�V�j�&�����6h]�����V;���^J���-�k�cVX1C�dV�,������u����.����AR+�kT%Sme�D������Jx��l.��N#Ff�����A�����+��X���Ii�^���Y=,�i]�����n���|���x��.��)RM�,.�NG�C� ��u���w���<	�w�a�C���j\�~!3�v'=�*
*������������`�F���f���eN���*��p��AtL��f���pEP���n���u����d���W#�x�e�A���@�#:��`�2)������'�U���!������a����
C�1EzW�H]�����	bE���QR��;^�nf�0fT�}Z��1.����>C�c��>�x��5��QU�i�x@�'��ii�������Z����!�W�'[/�AZW��!�#�P�*�,Og��-�������c/���������d��:{����r	���R+��`/��u����DK�_&"k�r�����J��:�;s���f��i�9;��
����*p�������������2��� �X�L���^���S�)��������>�N� ��4���%O�FC��������^������m{�X��A�{T�Xxj��(�\�.5be�avqK�p:�<va�An"���Y.�
�=���� ���=����!��=�=�+p�����OZ��=�P{��|�ux�9f�$74"����s�
����=����?���y�����1�Z�c|�<�����{B��=(\6Fs��2�7�:��y��{�U"����j[Dh�N�VMM%6Q,�����?���jg����V���-�/%��M����}2U:��s���A����u��Gx/"���Wg�S_H��N�>V���P���SWi�R����40%�DZ]���
]c�z�������@��@����Q�����{O.�� Vh�#�����0]^���2]y���:�~�]zr�5�'�x�wq�����c����D3s>�(��Cp�3��������z�#����[s��\� e����b�E=�T��d[`��m�*�\Zd���$7��c�2�u����#:0HQ�8�}�:��9|�>F������7_m/��uG����:D��[�q�<�C�0��)On�u�	����#_���q�a���i_�����K���-�6�T�/����Q�����*Lxc��=��U�������U�Ys���R�T�{��>����B��
eu�t���x���)|SKg����7��"���t(Q���	��)k��wK`�dU	�h��P!��i���*��6&��T��5^.5SI�*l�/��zY�n�2^
�\�|K7x�4g$��,l�/���FqV|�"�/��x�0/Q~�}sp���-���t6��F��M;^��Z���i���s>}H������?x~^-V<��:�J?��)��;����_d���NC9��>�N�J���@Ep_���4DZ>�P�p�${<UBxcO�b�f�{XZ�
K(v&2��]oi�M�c��>-u���.���<U��^����L�{�A��i/��Q{L��	tf��4j�t����=C�oL{	��������������Uj�y"�C6����i/��\��
�o��at5YK��W����/'����� f����e������/%��]���w
�����AX7��&B���Q
<t����M�$<$�!J!-A��I����i���g�"Nf��R	�H��&�1~W<'��":������Gp��	�3�������L�2;iL�����^�\N���8��0��#��=3���1d7����5��G?��[����I�U�JL�����K�S��HLKs����`Z�K�\"C	Gtp����,�l�@l�^���v2�C�>���?�����p�t�	-���'��1�d�I���3U�L1��	�y��nLy��q#<x �1��M2OT�COf��s��,�sP�#�1�1��-�yD�T��w[d6����&��)��=3���E2s���
�q�]���W������7�<�>��3���������%�(�r�7���>"�<���{!J+`

���&��m�������Gxx���e-�y�t�y�j�}����;)��k����4�Ju�6��^�,�n0�d*�������0bm^h�
b�������-se�t��K���>�}���K�_��[x#�/sOwx���������duD�wK�~�L����	�M\�^������J�_;'�{3~i�%�	|<��1����E�2��7�4���
t@���t>}&b�9a�(�i���@K���D���h5������X��10���k��iH@t@'���iH@t�$Bp_�N�B�c/��'#<�c�������%X!<8�	�������G��7��W��������9��g>��QX����d�`�<�\�f
���iDV��,&1��#�f�\�$�<��3������
�n@�q����f���������a�Gl�B�Aex`�uvIG��xJ7L-�{������	o�r�P!�M��7����Oo@�������Z�/�>�:��{�tq��-^�wO�t����o�y���r+�����&�WE,Y��yB��B�_����i(��Hr�,���A��\�y��^�m�������7���?2o�������T�|05��DM2+e����[�@��!����d���)�-�D�v
��_��u�t<�(���fgJ��t��~l�D4��|?6=��0��)��2�^�Q{����B�"�#�0�L��d>����4G��7�N1v���D�Y�F�2S����:Dax=7P=�9�hh�P%������2\>���g�s�`d(��.�9��1��������?�(��)B�Et-�c��U�:���7��)/}���\[@�����y���K����u��Wc�_3��w3��<U�x�otz��L�8@�H��d�����uf���x07`��������� k����,�m'�di,!�����^������j��0`����k:�c�����'���X���F�u/��}����!��t��K����0d-=���K������@����f��������`���M����e�\�!jiU������8;"S\.�7B����e�#:�[���n�Lu�� T� 0;I�Kq�"
G�1�u<D������Y-�����{0��)�[n�����!�:��]����L�:@��I���m�!�#:8�	�3�DH�����|����Q��h_�cgeh]�G?���4��hI�T�g:Sm\%��K��-�A�b�}����ai]@�F1q��B�G��`�����<g��{��AK���4j����=E�������
�2B���b�o�[D�����}?�s5�
�7�������^��������@�o�x�Ug����&6!x���
�7��k@{�"��L������
��Y�W��=�a�\�J����L��D�G{�1"�1�X��lR�m�xV��������
���Q�7l��]�x���:
��aLQ������Yx�_�U�b�nn�
�:d��O�������V���.�@0���JT�
����V�2�+�/�j�Ao�d�D�"Dn�7�]d=�P9$��V�x�'�
���vMp_�6�X1<c���:2
=�CO	�.��G���0���,���p:r�'~���8�����H+��N���0�Fp��$d��AGi�e��q���p�$��`+��<�E'���R�0���[�����2{$��������� ���K��L���0�d�3�����r�EZ���0v�W���cW�g����H��7F�>���[��)�k���<������F�'1F)D�5aq�:Y����Gxc�K�/�U#:����Q���1��m��KT%W��?P�A,Cx_��.�t�1��hT%3|9�����I�����
��|����l����Rf��Z��������K�(��9�q������s������e2Q`B^�f�e�6f[is�d�c�9���
��������a~�� CEtx�O�-d����������]�>����:���Sn<�J�����(k=."������X[��dv����Q���K��a`*eh,����Y���p����K�1�N �!<L����f�si�G�1��(T�����k��E{��7=6�L���U���%!<h�5�<02�GFF�N�����3���0��3��e��������;���j���F�=~f�{2�&��Q��3����d�o9���?#��s����;*Q�y������p���p{;e�����@)\����7�utKS)���)��m�4a�Qf���t\i��!�)��������S������w?��?�h�[�c�[����#��-"7��0����e�3���� ��	!��/��' N�Vm(�g��E\)�VI�bU�@N�Yg���!{xG2D!�� '\��{�t��B��|X/%���4�9)���"-W���G2�!?�}I3(�L��`!�������K�&�x-� ���w���AP��:tC `,^�	7D����-�>e�g��(@��~Q�������Z�s$U<r��*���~�������W����_���}o
_����7���HC+/�C��D�dw��e��"6�[�jS�*�V+H�I��ZU�� �Ro�Q���R:x����%��o�c���qr�f�����U6(�t2����C��]<���5����0�c�<�i�:F�g��at�D/��%�
x��'<���eK������~����~��?����n�_qK����O�}����������I���6>IuL���c�!�����D�j\�.�X��������%�D�IEY^��?��Gn��z���������wy�$n�r�4xz3����}GOY7_QjQqEx-�A�����|����������������_~��������g��?~����Jw?�����?|����2��'��+j���h���_�o���'�d)��-��P�]<2���/�_�7���fSN��.�����D/x���Y��#��{����Mf1L�~1K=
���{�h:P^X]���V(e8o��12lk�Uo_�����4���S�S|]������p_���|�a�T	t=YO�_t��<y{�{�'��,.�YP�������]�4KD �s-�q��,����{��3�_W���4s�x��'��=��{����
����z�b���Pd��s�m2�N��QDdPlX}C3`T��v�������F����U�}l��Y�H�
����f>�_����������J��CB�*�S
U�I������}D{\u��;������^U��!�B�o`���J�Y�o{�z�$��s�-�W�\��=o�-�����f&��r��z��O�_�`����Zz����]=W�|r�G�
^E'��Lt:A0����9����8����[fu�6��&� �l`C�;l]�q��{��Z<���LF{������
l5`kW����y��yD'�s��}�+H{�6���)��&���>�wtq�e��}�s����o��[��L�������#���	������iQ8�c3����G����QP�$����}��T��� #6���B{�u��`_��;A��=���E���K`���i�xD�s9�E�5P�&�����WBT�M���wi/2�p�
�Ev��T\�>� Df�FB�/��Y(����2$J��s� �!��7P��+���*(-��0�o�I�����c�)�y���s�AY���I3���z��=�����s,����3�o(�EZ�\ �u8M���02�S6�_�?h��y�K�>��G����X����M�w]�Q�p��z�DR����>ik���Y�?�R��ee�e�����G�w���p��$\�%e���0G�'�}�Y�fU����$�'���L�D6�>Wr�d�$Q�
�(������0�!����X
��eC�"���\avE���CO�D0�����N�\�AU���qs�YV}=^��$�'* ��d��_��w�����3A~����b��\
��E�g�fY����/��>"Z���)��V7m���d�������V��S�	�8��g�!��z5������9�>�g��Kk�^��%��K���+!p!����{�.������=�����K&r��=��4E�'�X�=X{��������T���?�%�=X{���s��!�x��k6R;�.���-S;��k��}i���k����9����_���r1z0
V$�.�����A`�*���>��44]W�K�,83�SQ��u8Z�5h���%X*j����������������Fv������{'���7Q"������T��������\LF���}���\o�[�����g>���iv��5�^_��>�p�1����oP\�1���I����yW�������qo�
�4J%.w��I�\(|�#)>4�,�v���[�tU��eY�CE�x�@p���Es����3��a��x�B��d���d��J@,B�'[F���������C���l��Dnx�Y �������|�0G�'VkJ����F�������W������d�,��L��.�,6!D<bf� �O��;QA!���p��bB�#&0��m\�.���u������C3��52�v������w��Zx
%��I���:��]�����������T������v���0���;�1�t�M����&��t?�!��T��%���J8��Z�����G?��}r������dY�hi�
"�S/8�4S��]K�wU�k���]�.��}kI}W\���\}�2���oeQ�a]��?��5D��\};U$=�����p�Go	BA]��\^]g�~��G������������������r����@��DF��g �/7��������!8���O������@]"�������0�g.s����9s��8�	��~���$A��\S���<��]��sl����B{� /��J#�x{�\�����@~c�1�����!���Pyvt���{�{xV ��������9w�9�y���U��U7�U_���0�+7�!R�Cp������]e��A��C�r����A�Jh��e���A�^u��w@p����o����� �{&�+:GI/����A^T}g���5�hk���9,f�>A���N/%��k�"�d�a1��	����4������s^�����$����@��0G�����J�����]�y��D�#���ypV#��7�}�IY���'��_v��s������L����#�1o��9/R7B{�3)�?�GL������=�=����_�#��������/�=����v�����F;DL$��^oP�0�h��u<���g; 8�����IY��d���T��!8��'���L���ZX`F�X��#U$��� gRV=��]|����?R���5B{�3)�?���E�m�?��#�������X.j��JJ����?����A�C�Df�;t��x(��x�5�)v�m�������xS�g����?���?f(���k&���l����������o���7��\�c��X�}ti��\�84���,�+���?6�AS2�}����f���7���H!��q�g�cT���n�'H��__�1��b��#o���l��dJ������0G������$OB{�,'��j��y]q��T����$B�����8����^h'7Q�6�-p�Ch��;��3��PS!��I|L�Hxn?6��k�]2��,�D��N�#�{pN�����������h��k�i�����m0�m
��V�,���6Q�8��pGt(��,R�p^������daY��(�Q_�7g�4�[}s�U2�UN� ����]#�W����+��U��*A��O.IS����=F�U>�������4���i��`�+}�U����{i%���vu�{i��^�+{�U��h���*;��A��.�D�'���E7���{m��� 8�K�cdaY�u�X���O.�����k/-�s$�����������N+��C���������]l'~�,,������v���DBy�
�]���.Nh��e��}b�b^�DB��
����c�
��>�}daQ���G��e��C������V�vP���	wD�B��.��m�����_�L����
�"BfF���[�����6���s�o����#�����R��������qp���*4���������
V���o!�<>�{<���!G�B���X>�QL�+�J����/3 ���$�7p%����;��OA�y���>/U{�r5��G��
���r�9�>�������~l���j����E��S@�!G�Wj���r�6*W7l���6v��E?>
k�F���Oj@X�����
p�����X�YV}�#�x��go�@p-�s�m����������#������-q���t\u|F���`��9�>���?���@��M��	kpv��WV]��!�~����R`��;���=n�.�1�N�p
�~/�rTS�J����h����o��X;m����I���7�&{���=vX�a���	������9�oD{,G�U_a>A��/��]q>�=����vb��#��b����;.)#8����]9����ua�Q_��"����+��ULB!��/��s���G���LY��$�rD}��A 8�~��$DY��h`fb�b���}=�p��X�)��R����GA�Qt��2W�=Fn�U�v�0~u�����n?6���Gh��d�g &��I9Lx�3a\	Q)�=Hn��������XW@��[Zx^ ��M��s��J�#��J<L �
�c�F��M���P"/��&������DNhNB��_�#��k�!{c��z �=8	QVu&^,��,A����E!����������A���bU���Y���C�p�B�U`���bE�T�b��]!���iD�Jn�7QV��#���6�S
Rl� =������i��
���#���Z/�at��
�}�Eh<��
nUd��
���v1,��y��
T�����7':��j�o ���;b�)0�Dl@�Ya�^��X��e(����T���OH�.�O�2>!I�gb#:x!�Gt�*��)c�� ���3oa��
����%�@�0b�)P,I��
�- <�Cp�J��`�S��h������`����"��_@?a�����V���d���R��aY��h���RJl4vx<���?�Y����"����z�e��{1TM0|5�b����"�����`4��T&RU����6�?����.aQ���B��%,��D9�����AV��N�c��Cb�mD�����OX��C�SY����MW��B�����O2������>��>�&l�W�g��d2y�Y�,z�$�d����0���?6�������))}6����o��7SZ{�T}{+�_:��?��S5z�������������bDx$\:%-�1�;���_~��_}��/~�s��z��2��t�#G�����cL��W; �-"dR#U�0*�kC5��^M
w=S����!����	@�B�@pr�d��Ka�)P��4R t�I����3�c�>a�)0��`D�S�>����@B���z$s�*p�~c�{�.'��
P��c
��P����\��3���Deb�YB�9�I�H� �%�	s�
�����
�Q`���Ip�dhP�:��P���b�h�xf� �x�F�e�~1Dl4�{�0'�@5Z�S��<�4Z�����9Y:��A�c
�Doa��� aNV�:�����O�D�
(�� aNV��A�e�<9�<$�� aNV��E�e�<9�}o�.�E�0������;���9����'V\��4@�$�1f�l�V#�u����H�M�S�X&{jt��Op�d������*P*IU ��R�f"=&K���D�V*IV`��V�6��Z�*+n�9�@�L$U����b)��L�X��3����D�(g�%���L�p������t� ��Kd�fKY*�DsL�R�eJ��[z>���@t����.���9���s:��@���p�����N���^�B�&/)�9���vB�8/�
�#�� �
��}��Qqp�����.p*�/W>��U��j�C�Fh�r��Z�8|�����CV������&��j��+g����:7�����=J�����[;sq��a6s�7N���)���E�AQ���D�X��OX��FAR�DO�8� �!:��@�^%�D� ��)1�\D� �=��'�?l�#�1��5_$��A�yOV��8���>�
�A���d������='�lH��o�b����=Y���*����w�#:x%����d��aA���/;����@X�� ��J9�{p�i
����X���� ^�w�����9���b,�=�!!��'=���������':$d���sL�������z1���	Y��'�S`vR�s�NbY���#�f���xC`&���C�����U Nz"�1J�k�u�j�.�c�^yz�CBV�a��W��n{"�:���������U`�NRC%��U=\X�-n��FpvH�*���/a�)Pl".��0���8+�b���
�0��0��������HpvH�*�@��Y��*Pl
U�
�9��	YbC�c
�Nj@tpB7�0f�����|����Ch�*�md��p���g����o���}��������+�����B��/�6���=}���DW~�[8���I�G
�p�G<="V�	s������c���
D�N���?��%��.�pn�E����������*��+!l�+\�����@�{�1TVz	rL�C��	���PY�9HT	rD>�c(�F�=�*�?�������������Z}��U�����4���c�[jdg���Ft��y����k�A�c��*B8�I�v_�c���������s�?�DI�V���UD����b�]%Q�u�/�b�[�+����":�_���PY(tv��ASJ=��*�@s�=�*�@��A�c
��@|�P�/6�=����Ce��z�m��R)���+�x�
�p�D����x�U`���b��T�R9��w���;��]��c���!2��!=	�K���Q��:
D����5\���]6�����:���`5o��z��~�-�b_@�N�c��XRg�(c���8�{�mYV�!*Q9U�TV]�D1?�(�Q%:H>{�Y'��\#��:xB#��J����`R/A��On�j��*��������<��9��������)�y~C�8n����������Q��
xr����]����6�L�3?��/GD�l�{�b,�?����/f�p�g��m|8��_���W�E�7(�#��|1[��k�����O��H������O��Hp�U�e�g�Z$��_�*M�����@�"�=V1����r�3K��&:`n����b,�@|2#����bO������'�}cY�����73SY���7�P�����D�XV�d���f�Ax�{�j,:a�I��f�T��z]bQ�."��q��O��B���r�p~�;�^V-S8���L���
v�$���
��~$�1����|�7t��t�{��+�@51����|��tj����l �������6�EW��B�:���8~+��(�e;�u�[��m/�9��������@�:+�%����n2���1[="{[ad�`��W��D�ZlK�Y����\�(p��o�v��sWt/�������vg�B(�7���
�������ZY�E�30%r��c���'$�p�=1+�Q���1U>Hq�<:
�Z�<���X�H�c
��`@t�V�gt	+�/ r_�\���{]0�n�Wi�+��k��w���'kD��i����6T�_#�&�\
����^���
��~G���R
�`(��M����c���j�c�s�����S���f��;,q:=a0�=��"��>A��XZ���>A�{��EX�ro��X�0��z���tn�����0z��tL�R9Y�BeX*]t~�M���0�12}";��m$����q,���k��J��iY:��`C��b.�H,��|�=��Ga6��8�q��|h�,74�yG�T�58����!��R@g
�����SSO��:����=�R�Nh.��m2ZTr���h������/~�P�\�0���'��J@g���\��=��Y2���E��t�jc���XV��\�9�@���i������U`Y:H�	sL����.�U����9�w�*��3����B���@�g`���0"L�+�C#�G��57�ah��Dp�b�!i�������/��j�ixw
6t������r�
��7�f��MM���
,�����A���I,���f�<�������H1<_p�x�:x��]���8r��(�A�t�
�edXx�L��;���z�
Dts�������U	snv�S���@�:��g�nd5�G�����<�$�J"�)#�>N��F��A�&uZ�!�"�@t@9-=��<��j�CE�@�fu��*Q%V��w�}���`���20Q1Fg�k<c�������@BF��S:�i�,�V�R��w
Y
�.4�L 1N����l����V����|���`�~���I�:�g��.����3�r���g�b9Vg�Mc����#�,d5hH;	tvZg�m
��h��R��$�dv1��9^�HVl�Nf��d��Nk����e�drs��4�-F�K
^��X���b�EJ�-���~l�����gu����: CY.��4��y].:����R��$��;f:��Q?�d������_����U�9/ch�V/h����w��s[��XwP��I��j��A�Jp��0'�M�����hT������Z����/�IlQ?��iP,'�)�z1%�m��.5xeN�y1��i0='����QY���@��L�� ]9���������������l�LY�)� ��-JX���"o����G���uB�K����S�t�h��%�����VR��\|]	��� kQ-Z(����TE��,�A)��$�*�CM�c
�>��A�Gp��e�k��sSfP���U��$�*��b|D��b��D�P�&�I��
l���4(m����X<����4�'H��
l�*^b�*P��ea:���A"��;<I�T�b����89�����
��-B���m"+��4l�����)p6����=]�^Qa���e�Y�w744l9��l�|��C����V�Xh4��G��r�������m:��v�U"�l��(1
eSb�ZUb�zA���z�� � )R�^���:
a��sl�E�,^T�f��TmY�:�s�v�H�'����Z�*���-��slt�~c]���y�������2]_3�"��]8�'���?_�=�*z�v��h�L`�Ks�h��h� �k/���������<6��=�& ������@gov��h�����D�r9@�j���C�D���4(���=��vdo��|����������a���#=�:9��s�A������J�����Sw�6�������:�� ������jP��n��5�G�DtP�
�3]'���	:�A��{E��jQ{Gt�?2W��:�� ���-�S
��#\aD���b��3]'�l4b�y�Y��&j���J�{��DV��O�@�4�^xrp"���a�O�Q�l����:(z����I��g��H�.������u�86���P����G��9%b�4H�#��XSqlP��N�z3��;�X+�����^#��P�	�C��jQ�V/�@L�(V�����
t����)Y�!��h�]1��	�+!�$�+WO��b��4`~���x�Fp2B����mmi{��<�
���6dr�����m��j;�V�~;V&�j�g�)� ����k<�=W���q"�$�.���]���J�
�-Bd��B��7E :x�$����
 �&�1�U8�8���=H/U`S@L�c
�1���t���{�^(�@\aK�c
�JR�+l��t�/�U`Y#D�b]H��*�o(��5�=H�U`��sL�b9@���@'4�=J���/#SQ���5��p?Z�Xt�^Hp��t�����Zl<������-7�-6;�?�XC���@o��6�@��S���|l�`[�k&����>��G��XBt�A�{��YV��#FN�R���a�a,�AGp�>6�j����qqjs/n-T�	���fY
6��D�c�D�J%6*-�5��JT�KQ-v@m!�1-�=8k
���'wpR��qY����s�{-�A,Gp��]��\E�a)��>StV�xE|��a���`n���^5�����d<�;o�:;@+������~+���2��}���i�`)���q�a��\��=�*���X&�D)\V��VH�c
��mj�XL]���/�V � ���r�TbB�����.�@�^�4!�m{HV`��V+��J��
����9�@� U�Z%����'J��
�U��9��������[,�.�@��#�1J��
��v�h)\V�C-�����58 ��E�f��G�����cR5���[}}�,�Al �
��zP�4�74XC��[�<S��`�����c�C��`���+�l[ �1
���`�B��k��|GCu��9V=�jG�v��}w6	kC~n���U<��f�U�z����}�����3�������
��r���g��HkN_�{a��G\bq��M��ZRH�	��&����E���Y��86g�
�����OM�#��t�Q'7���B�~�_{�[IV��~���]�ob�V����\�$�?l�'����^Dlb[��|jN-��}������:Z��p��d�6%��L)�$��jC��f;�ACr.?�S}�XA�@�s�;�;����.5xj�=T�	t��g�=T�	�R��&���H���({���)�GJV�5�	�G**��Vh���c�W�����#��5h����	�e�$�E�h"T���c�����XB�}WWEQ����Sus�)�&�zOCZ�i����m�{ c�������1�����#%����:�A#�~U��$#�
2b���=p�c��D`��;�&�����215��p:	�]����`���%)3S�����%����`D����N2	��Ic��� ��	����`�i��8[=����������0�
12t%��l,�Gp�{OhW���C{2��3d��:��p�c3�.p�8��y4j�����������d�+���oF�~K��b�����!@�;i|y��Z��5;!���\v�=��O�^��aN�y��k�`vr��^�����5/����	tL��Oj�1�<=�c��ah8����^=G�H��������x����������1>���c������5x�����
�]j�����),��L����D7��F�K
�Z��n~P��c�^�At
�s�#���5�X���w������:@W�tT"�Z���+W��5�`��D�:?=�'I����O�Y
��X����9����//<�����Hc�S��Q�>-��eR��k
���z����.k��:���Q�:�����3���p�xm/�&������@g�:t�/�'�g�*P%8���j�@��h�FDt�����A�
T��v�S�Tn���J����d�#��������y@g"\���\D��
�=;�������0�jD�ri��S��W���UE���T���y���Aq�ub�_��?��/�,�5�n1����
��/���� :hW�A!���2�8����K"t��#(d��O#��*"tp���#(d���&��"JU�3����E/�{t��a
�:w���MA��Q����[�������%%����YpUztJ�2�e\�F
�����/PR�S^*f��������'����o�XZ_��s���c	0�
���;�r��������;��k�_:wi$U��'s�{t���;xm�]��-WI�`�����Y]B���s�`�^�:HQ�b/�3s]d58`��39j�)t�!Dv�����1�S4�;�d��@�W�{t������tL����!:U �U������
�#������V�,�u�.$���:�P"�����n$�����HG���x��`�@G>�R�Hd�C�Vmh�@gV��("�A��hc���Ot�M1���w�����P�0����%z��B>�=:}CV�U���?��\T�=I���
Y
z��<�6��;�]P�nz��W���
�J%@���A�B�FV�+�����.����\�Fm��6622wP�W*����+g���o��x��u�������Gb������O�����[�O�k�*:��{�{`���9d58`�������rD�-�{t&��K�/�����,��P��vN�� ��K���{�>�S�a�����Tp�������z����=`�p���^
�$��hY
"�d����F+D7I����%V
9���`/@p�.�g�8�t
�-���~����-q�n���[�3dTE5����yL�7e�7���>ag|oJ��c5}���?�I�f��b;Q}�����I}��)���-��\}�R�UR��|2�rE�{������E��K����*�AOl�e���!�������(D���#��^����
��+NW��i�+�v%���\����	��6��c���-��G��w�i����)����
��
��V�97�L;rz��VC�/�=�P+�@
�97�,6�q�x4�`C��a���97���h��@t9�=��(�@t����c�E����������;��'�}@�������mp:�?�&^�:Nh�}k��������t
����)�i�
w��+}J�(��Gd�Pc�hc�`��1?)���[�q���s������������~�W[
xu$�����	@�o�|�y�7��h����a�����U�sx,q=�r�fb�I@W�[��=��
�p���T�:��@�>�=��-�����9��������Hp��x�j�F/	��Fl�v�kx�"�G�Qe5����iP�0c���,8t1����S+3���Y�nv����VS������]���V+3;�QE5X��fJ�c������~;��(�V�Zl �!�1-�
�!���@�i�=Xb�U`�L���
�^�At��e5�\}��%"[_��@t?�l��q!�T[�O�/ �"�	�#�~�+�MJ;e��N~S.�;O��x�&%.���!��5�����f��j0�&>$4���{���2�(GR|S:xc D����
��
,
�[���{S�U��.�|Y�*�����|S�U��W���}5�t�N ����
�)q�9{�*�;����� D��j
f_UV���}��`��W�@���`UV��B�����������*�}�A�MR��t6>�h\WC�@2/���I��q,X����V�>e����l/��u���n=B��[k-�����MR���t��:����o�ZI�w�N�E������;��B�����N;�O�U{�K"�E����N�FhMU��
���|�O_��[5����{���TR�*�����4gQU5G�!m#������k�0G�R/���A�����y8���G_D�Tb]@��p�+1����=����VE,o 8����d��+�9��xn�K}�|tz���4<��	{���N\��t���^�K�@w������Z�{��*`�$��f�A��}]X���@�VW{&����p�zD_���w���jz�<8
O��(�D�l��@�>@�����A��Y��<C/��`	��`��L��������4���UG�c�bF����J>�n,Yw��S�ic���iP��0�-At�!a�����h|T�s�2<	�v��va�~�<��\c��%~~��2�,=�e
0���L�c����niU���\XD�.W���E���D�b{���O":(p5��w�/~�U���^L<�*P���"G^,RCt��Fp�\D�b�>a�)Pl1q����a�~����/z�U NJk����{���[�>�'���']���
����lH������Z;����g$Gev��|�q�
�������6@�P]j��� 5�����z���?�Z]�"�*{�sL�b�}�������.��� �*{�sL��S{D����N{�|$���t�S`�E��b7�{��LV��?G�c
�J���+�����������5���Y�z�t����W��{b�^Q�U���ox*}�gR����C_�co�:�eK���>����
t@-&�G��D5��+�=+9x;sw�N���h�[<�?��!�A�E�cK�-HvH�������,�RYd��D���Inb��o��<4�"���K���J�f��K�O3N7���q��d�Ou�iRI<�������/��������6��������?������7�7��]$��O�k�x�I���?����/gXK79��*�}%�O������|��|����d�r4���l��-���e�%��(O�4K�������	�X�|��VH�*BOYJ��0yzJ���a��E��@.G0V�y��&�.�T*�Sih $1�O%^�;^#j��D�����&�*)]+7����3�
�WC�U�j�"o����2��q u�����S��ZQ+�-������X!M��\��r��$f���} 9A+��Jx�#+�<VH�J���K�~�������U�V�	���B+�I�K��K�D�I�A*�+DR�'���\�[�*�X!M����&URM�5�$nA�
���0V0y��&U�/IrS�Tb��hW��Nx��f�$%�u;��Rl��'�+vEIL%�#`���,����Te�C�X�������W V���� �?�E0��^�v��.�D���H�lDJ0_b�3���#`��,jN�3h�\]o�ibY����C@����n��G��ItY�
|8u��!S��(VZY�&�b��H(�)�4�,z�p�����)\J+��w��>����h%�H5�X����L:1nzk��s8%�J+(h�0v�u.%��i������U4R�A4�V�C{� j[���_�=��{��6(��q���W���/����~����n����}��O_����x+~���on��?}������?�����xS��d��?������6���fiF��.e�:
	����2$��M(R*�Q�h���3�?���5~��2��a6<�`�HO��0�$��o*���(�VI�����.����.sI*�
���{2�����;�t*�>�n��g����
e5����#\�Z�qpx�Q�K����4B�TD�}��A`$fz��<sA��w�? %��!q�D��l��zw;x/��k����=��W-���wU��]'�����r�;��l�}��c��������p����|m��w�O����#����JpV��*��z���r�1T(���rm�$z�Uj�$��2�^U(K��$�h
�
���.3�$Z��j�2���L2��6+����g��VP�DM���
���B?��u�+ZO�`@�(@����iB��� �d���D�i�P�NsFH���0B�P�Fj��cO0�(1��<�Q��iTdr��ZNZ	�k�2�d����{�%7z�!^���EJ7�3�c�X��v���B�v����#�������LD�`��:��C�X����p=�����,/����Q�x9G��!��C�X�v�����v�)<��%�����Cbk�!���pI�z�%�<�|�+��R�Q�)��g�PJ�7}�_�d-������V}�*��$$��Mu�L���mbY��xl5��������eH��D���
,i�A����w5�W��W��}�������W��*Bz���v-������IK��h��#�	E����[�Jg�^��8��2�N�Q#mwI�
�M�,�]rS���(B�:A?��0j�����$�S%�Q���)�_��(�����@g�X&��b3�$���1�F�L�2������y����*�
4�&�����g�M�.����o�G��{`T�c��~�H����h>����+�/������6�|�(��}��7-nN�e�5�+�{I��4�f��'��$�H;����x���x@w��o�4�w���=y���w��yoq�fs��x����z�\�#�o������V���W#�s���=}�	�����r�^��GT�gQ�������A�j �")����03S��E��+w���
���
+7E��5-���Q�?
U�"����>O ����,Zh=�tq\����g������g���T�l������O�hKt	�c�����\����e���%�2����(�8G���6sH���pN���|�,�2�-��������x�z��/��:(�*d� X�<JyR��3����v��yR"�~��~�F`N����%��@3A?J�1������8�g�
�3 A����I�:��p���g�$J��K����g�$Ji���OB�-�(?�/{���@&�6���?�W���8���?�+�I�����O�
�L�-�����D=z��d��'�����C�+J�	�w�Q�
��e��]�]�R����B�r���l0�H�����&*������z+������{=�Tu�O�^�}�_�SZ����S�
�����G��W����|����6!{���p�O�^�}*\�S��o@�
���l._�O�K|J6�����K|J6�����K|J6�����+|��F
�T}�O���A�j.)��F
�Ts�O���A�j.�)���E�j.�)���E�j/�)����$��B�F-�T{�O�F�T{�O�F�Tw�O�M
}����W6�����+|���(z���
�*e#�}����d#�}����d#�}����d#�}����d#�}j���d#�}j���d#�}j���$QH^')OJ4�
�������hD15
u�O�N�H�G�.�)��b�=`Cq�O�F�B��w��J4������D#�A�O�K|J4�p�3Iy�P���s�}�O9��B�Om�$�lD����>�d#
�>�/���F}�\�S��A�2���lD�mS$��B�F�75\�7�d#
l�.i�r�vN
�tN9��[��KZ�*��{��Kz�*�����k��d#
��.���d#
l�.i��d#
��.���d#
��.���d#
��.���d#
��.���d#
��.���d#
��.�����O
��Oy�����K���lD��S�%�S��PR�B�����F�?5\�?�e#
��.�����O
��Oy�����K���lD��S�%�S^6�������� Q`��pI�T��(�j��*�F�?5\�?d#
��.��
��O
��O�����K���lD��S�%�SA6�������� Q`��pI�T��(�j���}���T�T�4P��O�
�����!�2Ra�pI�*d�
��.��R�lX�MT�%MT���+��j���J���Q
��Q�B6��>���>*U���H5\�H�
��;��K:�����[��KZ�����{��Kz��������K���������K�����I[��T���dlq�j�d�|�$c��
JU]"�dlqb@��K���-l�J5\"�dlq�
�J]�W��4oB�_�K�Jt��M�+u�_�����F�R����,��T�W����-4�����dc�~���+����_�k�J6�0�W����-������b�J�����T�W����_�����e�?f��N��i���e��~D,:.��-1�3&�R�4�R
Q �CNYC��:��O�!B�!�!��J5D]�X��������y�5D�r"M�TCt
�j;q��
(�>�Nq��Mib%B
�z�)k�XA�(B�6�!��J5t��r�B4lWv�7z!n�lwD�X��p����G�f���8v�j��#��J5D0 �CNYC�&G����D���\�H+�-d�$��!D�95@�M"�
Q�2D�X��Jk(�=B���5�j���<B4��0�i�S��c���p�i~$S�uY'�����?6�r ����&�`��Z{8�H�x�����%����&T�%DSk�@1�D��8�2�%Dsk�� WSH_��C����@"�-a}.K�&��� W��}B4�6
�$B�.�%D�k��\.T�����)b�qKT�N'���� �QPYK��������S���f	���T;������M
�
K�&���@�����h�m:(	���P������y����h�]x�u���	�j�r%Z�,�\.T��{l	cgG�OuE.K$��j	�<;
*k	��tp���X�R��b�J���A.��}B4�.�l$B�:�%Ds�24 W��}B4�.[��H��%L��I4�.[�n������������t���*�'�����ry�M��J��h�m<O���	��'>��|��w���r�3��!�����\u��������~���>|��������������������UN����~�8�s�p�k�U�u������_�����~��w���������_��������O�}s�������?�����c��7�������m
U�*_yP��<?��q�����YF�OT~�)����3���5*��W�������/G��;�h�j������PoQ��1t��
��=���/Y���]"����q���7?~�����;��6��Z�Gh�����]������7o�����7���wo��������O���o�����������
�/�?���?�>������l���7E������=�;��gK	��Vb_�����m����?������i�Q�P� A����I4	�J(`��g�$��Ue�2�%�L2�&F�U(Sw�L�)Fe��H��e
�+��d��'�����O�
}�������D�;*�����'�����?�+�It��Mt(w�C����U����(��/7����+\Jv�KU�OU�����[�OU���������K|J����S����{=�����d/_�>���)��/U@��W�����*�O�+|Jv�K���%�	��"�O�K|J6�����%>%Q��S�%>%Q��S�%>%Q��S�%>%Q4�S�%>%Q4�S�>%;�j���+|Jv�J��O5��e#�}����dg~T-�T{�O�F-�T{�O�F-�T{�O�F�T{�O�F�Tw�O�F�Tw�O�F�Tw�O��_S���F�x��Ou��1���&���x�]�]��	x��LU����^��~W����+{@A$N��eo��f$��B���C�B�-g����
��bY����8|H���'���/��KR�.�h*����W%��zU�P�B���^�O���%z�z�����%zOy�>�.�)�{�k�)u�O�fm^�O�K|J����S�
�r���F��W������������=e���>�d�)�>e.�)�$��)s�O�]��xt��{['T�>ev
x/7�N�^-!S'N7���Z6(�����z�Y����B�g�"��*����
��[��5�w��d��W�6��O��
!{���W%{��b��s	�x:ju����$�J��#E�r��KM?����
l�����N
��� ]�o�����2�����oa����5������Mt�
��I����it��[�X*<n���
�z��c�p=��4Z?����n�������CmG��l `����K*q���'M,Ca��
�p1���l�>�� 5#i�H�l������������D�R�����w�$�A6n1tl�5�e����vH�|������06h�yl��/�����W�!q:OZ��aZ�M&M�t�6�'E�4�����I���@�"dv�L5��wx/vUg����{�8�#���=u$��8{�8�(N�h�#�#�
G�a� !_�v�i8+
�����ogWh��J�6��X�����e����5J�(�%���P0��\W�N��"��w�!?v��@�D��xv���5��>��WC�P��<tQ���x���a���!?v��@S��D����/�h��k��������(��3��j�a�A��M���J�TS��!��@�>���m���ht��A�/v!5�WSP�4DU��j2��O�V�����@���{�0���|�H�Ds��k���h�4r"�� ���=
���V��v�` +'����S�J�(����|V��_��/��O�i��+<�O�#
~���.�J��
���Rx�P�G
�WH�g.�JJ��OB���T����r@��_�(�' ����~��
���X����/\v{A�
b��f�,T���y^�N6Jq���+��R���JSmTi~���.���pw��,T���w��J���wW���B�)��/�:����4S�qxu��,T�^a^��ei��k�vE�*T�7x��x}@���p����ZJ.��
�v�x<���3\6x�{���p�8���O*<����p���g�L���P��}B�8<L��L6�p��,�}B�#�a���>�+�k�
�A��t��5�b���M�(��� ELk���8��D\~A���d?�&������M���x�$^���2��f�p�]��_���6{�rR�A���.����j'�z�6vi��o������K�
��)�h�����'!��I�@��eb	��d-I6=��H��eM`��F��2��������D��f@���'�&���$��2��hjt��
������Q�%��i�]")OJ4�h ����%L�E�BUW%M���B5W%N���PO,���'Z�>�.�)���U�S���(Z�>���)��S�F�RW�����V�O�+|Jv�T����>%�x���S����(�����d#
�>e.�)����O�K|J6�0�S����(J�)s�O�F%�Ty�O�.�j�=LR�.�lD�������dO�}J�v�[(����O�K|J6���S����(,�����d#
�>e/�)����O�K|J6�@�4Iy�P�2�[w�O��8����z�P�E�>U]�S���m�>U]�S���m�>U]�S��G��.�)����O�K|J6�@8Iy�P���[�O�F}����J6��S�
���H���p�O�n$k�T���d7��5�T���d7��5�T}�O�F5�T}�O�F5�T}�O�F8W��<](���A����I(���A�j.�)���A�j��)�m�>�\�S����}����dw���DR�.�lD��O����lD��O����lD��Ou���lD��Ou���lD��Ou���lD��Ou���lD��I����d#
����W������G����)��(��>�_�S����}j���d#�}j���d#�}j���D#���H����(:���.�����a�TwI���
����K��d��t�?�]�?%�t�������)�
f�Ou��Oy���������)/Qt�?�]�?�E#����K���lD��S�%�S^6�������)/Q`�TwI����(����*�F�?�]�?d#
���.��
��Ou��O�����K���lD��S�%�SA6�������� Q`�TwI�T��(����*�F�?�]�?d#
���.��RE��wZ��6�*t�@�M�RFa�l�8-^P4Vm����l�&�Q)��wi�@I���r]c�H�d�����q�M_�WQn}8��DHG�=)W��x3R;~��)�\��&W�%r5��o'���G�I�+,�(M�~�����Z4�	�����P���h3"M�T�@NE�����\"-�+��*7����U]���2)��E#����o��&���(W���^[�+����0�Tzb��v����Z�F4$�����W�s}%�r��i��O���������_~����&K��������p���}��]�.m�����$�J?�I�
w*K��@��T'M\Z�c����,�0>l��eJ�
��+Q[_��3zZ�A��~%f�W�V���
�[X�N�������#���DiZ�7`�#���u���~Z�UTmux@�>��TtYL�`s=!?�����e'��L�z��\W~eR�o�����.-��I
}�FT����y�F�����O@��.�s�-�'^#�dJ��t��_IP��<�|2$}����$���2q_���2Q&O�����z�)�r2)Uw�n$6N��������� S]>�u��������
O-�+�K�F\�������	��>��
)|�r6��J����o�Pi�*��	�*oa�
�=_��R������G�W���JR�.�����ToQ�7}�-&�t�d�g��XY��w-B�&�N��D����$�H�����Y�#uK���^�(�����>��O��!��'�\�2>1�O�q������i���3�������H\i;������g�����J6�^���ML��v�
�{	z�kLt����u�^;�����&����5yM�B2	�tJ��D�N����
9$�Z���H�\�C�y&;�x�D6�D����m���L
62�D�/nw�ld��[.���e�����`^����}W��J�e�����(�
�0W>L	��7`��U�_�bq�!hf�o��#��_���Q�=`�$*��v�����f�U����5~�����Gm�2����@�Lp�j�BY�7����
�6���W�*C��t��O�wf/��B���T��F��g^%�����:��[-U�I�x����������)�;7����X-?��U~g:����\��)����3���6
y�L�o�7� �$!��I�Q�&B@��2������0���C���	�h��	�d��30o�������'� ��I����;x�+[n�����K��� �$���1�EeJ���D��#���x�9�80�!}
����J);!]���t����"R��Ii��
B{��}&�|u��<��|]q��@A����]!���z�qf�F;
*,��L�!����2��g�$B���B�-�h�J�2��$��~�E����L2�����?�W��do�M&�'{�?I��n"�?�+�I��&�����$�f�s�O�
J
�R�B�rW8Tj�0U(�(w�G)�P��K�+\J��U�SN��Wy�]��P5p��a>
y�L{�o�r`[m�����wb�����{�$
��F�O����.���g���"�W�MC�_�x�g�?/$fi�����VK]�'�$�[�x����_���kS�����C�����'�GK��f�ze3�3}���	y�L����g�o��&!�9�B�"��
4�}
���H<�r��]�\����"����>)��Erw��ov�[b�,�"	��1j�h�����v�.�]$M1ob�kS&���Q@�!!e]��F�� o��������C�xV7
�j����I_$��P��gu�J�"ix-�]�K�K'z�4X�'�/~��]v������iI���F��_�]�bJ���`��(�L�d��7�D0�{�,���7���9`�M�wO��r;m��*����yVnhi���CNJHW��}�v�6�����N���Q�q �!�=h���v���#������kS&���[JH��e}���2�d��u�2�S�3�$��k��<[&Q&���?��U�l/{f&�DI�<�2����@;�5&�T�eE�-*Sb,7�t�Q���i;f
2�N#���r{K�00H��S���w�k����J����jS�
� �!�/���f����=�L��.L
����e��~����:z���!r���@�QPa�6e��+����G!��I2D��T�L�\ �$�&B�2URWz�����@�J�y�2
y�L���}i��M&v��a�v),��M�e4�Z�R�+a���
W��z���0I�V��Cd���k~�Z=A"�v]iX2j����J��U	st,9�X*m����4
�?���K7(1����t�b����7�H����n�v^���&��p<�x�D��>UY)����(#�`�Z���I���JX�
,e���mW��t���v~���g�>Jr�RU�%((�=Do�dJe}��k8��r�����CT��C`�2��9D7EV�E�gz#�k�<��2k�	�������^��J�*:�	��t��k��������+vM�*��SU����s�rm�$g�~�w�"@�����s�����t��+{�����
����,�����!�^gU�a�4��f��,�ML*(���8)�q��B}U���Q	���Va��T��F6��b�
����O�(��0��&�������F�
I�1�x�D!����*��F���\Ol�����)�����;�~�}�<��7e���/�'�Ha:�W���A�#R����&m��.�Qn|@������O5��e�p�U�F�Q�x<���w=D�L��^�k�GI�
-"~�+�`��?n��6m ���&��B5{l�0}�+J}�!��K���c�4�n��g�cC���n�
��2>��d3W!���l�2�A�P�g����g�$��
5�/!�#�*�����mP[�V{.�mHN���{��Gm�Sv�>a�4�Rm��QJAHNE���7���0>��A�PZ?��7���G��]*7���J�q�L6����2���2��i�gZ���y��DI���K�;���U��Z���=Se����R����>�x/����x!�^�Q�UJ�jz�b.�L'Rb�l4��6���{3�
�i��p��.���,�I�4�;Y���N���U�H��ES�Z��D��Pf��D���Z��Dr
&��To���J6�7�R�jmP,����l�6�9�PH& ����$���&�I�������`����)`ia��j|��ck��yW�����U��aF���A��&���j4i,�r�'o�dx]�DJ�?z7��j�j���>�����	I*h�P�� qh;OA'EJ;l� 1PJ�AI)h�8����"��:��m�
_m�5
���G�������m`�� �u!�
%���#\���6@`M��6H���������P����.����?n����6H|]H�A�Q�^�D_��|���T�� M�d�(���������?�iB%��&8����pE�Z|�"�L55�
D������>�D����=������6H*�x��g���B��a���Q.#��*$Z�����u%XA6U� �'���l��+�j�"�
��r��}���YA6[�[�J�j$�.������t5'J�j���$��d�����u��D��&������B�T�_���?�M��JG$@�
�J��9sWt(�p�(uSC��H��� �5w
�G$��D��NA�F�	�I��'���7'ZAk�J8gK|L�����8H�~�
��sZ���-J�+k��^(���3x"i6k���u�J��'�>��h���$D n�L�B�T�1R�'��u"m�HZ4w�J ��Q+�L�B�T�'R��V��1�}"i����������b�
��s�3IL�I4w�,�";�������b���9�Hrx��a���p$�&������z�U3�:�D��;�_���Y��
��sS�H�x��P�M�+��*'|(����p��!1N<�<t�����l��1��%�
e�CI6��u�V�P�M�<M��2UV�J�WC�bU{��xU6�F�	���rEJ�)t�W���#C��M���C0f��
�b����C�>��l���3�>@w
J��C)��I4�����C)S��(V�Zh��&s�e� �Ec�?	p�D��;l�����'�A6�����F�63�f�]�b����`�,��7s�3�f�=,�]�y� �E�XS���<�e
X�J�z�)�B��>������C0f����(V�7x(
���h����R���'� �E�|]$��7�f�}�!^�%f�\y�h�+�b	WK�,�W@\%�Jz��M4��U�b	3WK�,��p(��A�)��1�$���T�f���CI������)�E�8i�����,�7x(�P�f�,�7x(�CI4��K<�?����K+�8O���4�h��n��d������(V��B�v�� �E�(�$c�L���b%��A�*ao��{�o$����O�A4�������f�������A���
K������+x}#.0�l]5(�������=���V�L�D�R�7�o$�`�fe�h�)��2���J��)��<%+�E#O��yJ�� �E#O���SJ0�l]�������!1�N<�j<�j�CI6�F�	7��T�H+��S����� �E7���<��dzM+���5���3�f�-��>}�5N/Q������R+\S��Yt�5���)e3Cb���������)�W|�+�Ew���8��	3�f�8������,��q�}��.m����k�{JDr����No���f��YdJ}���5I4�c�vn�O�5�'����W�����6q��P`�<L����D�=^�n��o^��
�JM�|�[K��V�
������A"��,���S'q����
����hZxU��{�6G��u���,~��?��0f���C0���r�2RR�~�GQZv���(�'��GQB�J�O�(L����k��gI�\r���������g
���~?t{��O����e}g@���|A�*]���B����~A&
���~*��R�������e�j��D�NL�b��sp�f����O�h��o�|�����)��;�M�y��l�$���G�Q��e�|!��T�L�Ce&�$��n"x�����I&�����O�
�|��F
W�����M&���
�,��D@���'�z�M���
]G�U�����%�l$��G������
%t��
��=p�}����d��}����d��}����d��}����d��}����d�}�_��K(���C����)�!�7���+|Jt��M������lD��OuW���D��P�S�%>%Q��S�%>%Q��S�%>%Q�S�%>%Q�S�%>�Q(�'|��!����S	t;U�
B,.hhiE��!m���HK������~G9w"N@�T
q4V�4����ib%�v���	�
������Q��f�$�R
a��v
�L2�h(i�|a�(��H+�0�`�S�������v�"I�dC��U7�!��E���k<"I�TC���?�)k�4��Q�"M��|����%��@,�o�g���X43*}���A�iy��C�X��y���+h��{���� ����4 ���rqR>�%���I�^������R)���PY�[���2#�r�B�M������A&JHW�E;ews[�Zw|����@���s����B����y��\ 7��=f���\������F�������H%��>5�L����B����F��#����.?�����5|�"/6�j���J��]?�Q6
)�O�����3;	��-	y�LJ�Xr�B;E.�h���X2����%�O���K��" �nX�R�?
�4���d�G��t�$n�:�M��
+�����D5�����B���D���Q��$29$���x�D��q����D
�'�v��lO��J�`��{�l��>�s�n?6�B�(���������U[B��U�B���IUvm���n�nZ�]Y�p�a'&md����{�d�S�����Ui���H��K���`!�'���f)�i�Kp���Q���8�od���_��H�����mF����W��S�D<K�%���Qd��v�P����#���Y�H$�
�Mf��%�ds��`@X_=w�y���YIT��.VI�;������S���G�0�"=���Y�Qqh�dJ�7E&��������a��$���s8�h<�� /��L�!E���2�B�8��~�|����[�H��d��v�;M:�N��*v�o�.~[�2u��?�(s?D��H��S�Jqp�o����mp6\b<��"��
�h�;���$h��j>mi����\J���~�?����EqE��at���Q��GzM/���v8"i=��$A�i�vs�]��R
�8AIPQC��ez|@#	��H���!6��FO4�P�ke?�k�H0�(C|p�� 	�6B=<�(�$��D��C�^��l#�Q�S��A���5�$3<e���2q&#�����p�i^��5�$+<0"f��l#$��l�3
)jIJxPZ�W�O�d�$�R����z;
)jIBxP~�H0Jp�$s�� D�5��x�� D%8�i
��F��#������A�y$1Jp����S�P ���J���I����>��gk�9�M�����'��Is0��"�n���&��F>L������85M�d3`�j�U�9���_��	�j�R�_�G)e� �:�a^�E8���s,���$�<�CN�WJ����p���5�h�l1^����iB%�V�!`M�-����U4�����h
�J��/	XEshW�=G)e� �D��_$��f��]S�P��>�D���
V���6�,�����XE���
����5M�d3`�Z����nC�kuI��&T�<L���5�h�~2<�D3�f�����P�7�h�;���Q3�Lf��}7�P��	q)f���$��f���A>`����X�Lf���!C�*�E��"b6`��� �E�z>!c�R��Yt
��F��&��w�A4����&C��� �F70x�|;���
���dL�aR4�n0dm��5�'}��c�F>f���Y>f�f�L�����ZE}���1?�8�DS����j�b��A4�n(����A4�n��j*�sI4��0l%�vH���m�d������[E�|���n#n��� �Mw�v�q�����
�q�s]o�vM��b��9�)k�t���0���A4��+RM��H�A4��aR�(��v��{�8�)k�|z����X������q� ������q���f�C�T�v��u��[K�|�.�C�|���Q2��I5o2����d>]a^E8����M*R�}[�R� �O�
��Q��� �O��������v���kq�(��v���kq�(��$��^�"������d>]���Z����d>]���|��2���I�j]�{�G1e� �O���W�F����h�R�n~D�M��j��f0�9A�i9f����?xl-�*�M�Ft!�8��6�m���W-������Q����2W:&����C����F"��f�?#�"�
a3��ib%b�S���5�h^\���Q��!�L�&V�!J	Y��2+��$d$B�>�!D3�������5�hfl
dd$B�!��$����������M�m
)�O�r�q���l��<�S����S^�qC�L��4�R
�$e$��!D�c�!� ��0iKy�B4;v�2�S����|:�c�&���N�������
��9��L6D���Z����R-|9�����{��*i�Y����s2�(��L��/�����W�jE���Vd��C�b4��n��}����������/��x�������/�P��@��-�"MU[�������]H?Q�$v��A4C�EvTA���{66���.E����PF��'�D�~m�_��P�o<���m%NS�r�N��PEI��

p$e�rf��\��p���)v�	�*m��M(������Zl�}�ue+��'��,s��RpO�
iH-;#`��.?+nZu:mO����~&1���i��L�n�a���D��E��>w�,�����;p�N��pb��KN��������Q�O�������CY���}	�D�!�Q�t��K-�����l���k����|����^����w?.U������$��
���5n/����pf��T��)��(ZxpFd��B�g+l��V���j���.�����!����}�Yp�yj��"#��>��F��gE��d�����^�&{V�R��"������ Rv�`Z�����]��_$~�
����";W�7T9$�������h�U����m���s;���;"�V���N��;�I���[�y��|��K���5`�V����I�~���o~��U.��m	�i����;�k��������|
�� 0���&`�C<��mK��+���>�����������]D�������OX���2�zd���"�i�o�2�D�����gI�'L<o�#|q�j���Q`U����kYm
i�����	MHW����x�g�����ovV�K���B�����^bIc�W���;&^{^.����*���n=~��'��?G�����$9G��9�����I4?F�����7�T�Q�g��Y{�q`�G`������wSt%k����=�fh����<TD{�����73K��I��M������)9m�K?>[����4
z���	{��i��DsN�(�3>��p��1�<���u�>���
���?���Y�X���=@3��������
p*G�yW�����M"����{9+�l�%:�1%��B��n��c�8����]���T�O;=�7�A���`��e�y?W��x�	�ddc�<���|)t��%6��$�k�%1e�����|d`���B�C2�$R��P��Q�,Zix2�w�u��V
��g#WJF-��X�V�%����[���^�z���o��|�����n<��F������v����������
L�yZ)=l�������58I��%M�Z�b�IR���8�HLQ3H��7��Q�?���O�!�����,��^��3���$�����&	�0���	3H�nR���G1E��2��`����?*�B>�X��$�,��JT�������	�IQ�4������i�F(5�n�@�]��7
��)!�"Ae2�B>�h��Gc�9`Sx,-�i��q��b�)v�����GOI�	r�B]���+��������"���C8DH���g�
���|�]�~���d���k��\�C������w�q7�-Iu��&�2G��#R��K|�5
��
�N.��M$b~����U���>YD���x�(�x�B��M����(�x�B�J">u�y�������>.H?�w=��v��5j�\�p7�Q���p
��o�����'���Z������K$8~��{����\m��������+�t�y�;�����f�Ie��!6� �w��2(� uI��WP'��$�����gI$O��	������F*Y`�F`�����u��0�>���=b�-J��{���������o{����U��r����s�����|������[������%9H��� �bo>��C���yAc�,�����O`����(�3'��,H��R��vv/Y���Xi���x5h�"��P�����~�����Jr�f��k�������H��D����}b�U�V����H���)��O����C�J���&�Mq�@v�G�z�6
X�Y?�8��#�Z��g��>�C�I����P��������17��%����$4��~?=�.��cL){w� ��:j��I�1Z7�|���+��1��d�zL-��0��������|���<�1�J%8����P�8�#n��|W�Mp	q�J���~�:"9&�h��((�%6�n��0���k�.�3Wbe��2��k�$��g.7 �C7�����>��*%[�oH�C7�}��rriS��n�G���[�����)aG�F�������.��T��-|���(��;>��s
m�>X8�����+��]|�p� ��t��B��Ns�R�Ab�.Q���3a8����=ke���"e�DU[�~���u�1���)�H�!b�8,���<��F����+�q�>�����%k���4(U�$�?$t�z���2�H��i���c��g���y��#m-"}1�22�U� ?�-��[~�Jbg����3vI������dN��L��["�;�	�(}�9$I��)KlZ!qX��'{�_���r����WrF�
�	?c���� ���u0^fS��69�&����L����d��x>Ha�k�4�������H�	�<}��|g������g�G���!���u�P8���v����`�H�He�2��G�hD*6z��ow�5M=P��pq��8;�s-��M%��4)��������B~8K�:������6��pABA@e�	Q���KDz����,{����}���/WO��B��b��,DO�\����e�jX7JyN��XY#t�P�
t����7f�S����R���p��
�����5��6q\����^(*)�/7����vGA��8��^�rJ0�]�L7j����%6��&U���ILI+��S����[!M�T+`�W����XAr�b*8�����L+�I�j�
Q$���6��i�8�
iR�Z!@�IbJZ!q�c�hG%��B�T�Vh������B�6�D+���Q����&U�`��(��*Q+�����3��&U�`^�(����j�'����\VH�*�
5��k%}"%�mK�l�8�
iR�Z���T�I%���f�p$��m��sm�L"9E� �>��'H�� �?������vM����H�� �A��3$��DS���W}��;���u��S��It��^$�v���*4���L��it=��$���yt=@�����h"�(�v��A4�n0'"9E� �J7���$�9���t�Y�)j�d���P�l���f�l�������h:�8`�7���T;���
�E$����h>�xhxn*~{y�8�|�������h>���i��,�D���"�S���t�=��$<��A4�n0-"9E� �O7=L�l&	��v��L�HNQ;���m����o+�f�|�Up.���v��[
�Ip�D�����Dr��A4�nK8�H�� �O��%�S���t��x$�v��[��k����)v��[��V���|vH��}�1C�
P�i'3�SvzF�����m
W$�v�����*&9E(�Aov�~��*#S�>^7'��VV�EeJlh����|��6mX}*���f��6a��d'N�BX�F�%�HmN���v����]�rw�������o������Hcg��0��������&c]N��
��.<6#Pt�UW��>��1��5vO�W�	�p�����":�#W�`�,"sg�P�YV4(��}��<�T�0�������j���GC�H@e���OZ�`g"}O�m���M���-H:%AE�������s�����I���<�`����M<��bMB�h�k��`!�$�����n���2�M4`\����NTe�v0�D<K�=#�RW����������:��M������%�)C����Y�R]�G�Q`���� ��X�\_��Zt��PC�IR��9�2,�j��Z�(Q��r�Ia$��O�>�}��lC}�O�w�d��}�9�'2lp��x�D�2
-�D���s�D{�O�F=�Dw�Od�8��}��En�h��-���/Ht��0@�nN+�i�w�AZ}F?8��[�=[�SE%����3d#T���vi�r�#�oH U��!�#���n9$�h��+�A�l�\���#�M.2��M���y�����|��(l�1|�a�`I
x��y5l�@���H��������\���]�2��P��X���b�$4�p�%��R�zX��cC�y��(h�%�:�'��4����mB-�xS<���
�z����,Q���O�%����;D�_d�$��)w������X��;,�piKR����q�R.3Z"I��{�,���(��=!I�J;��"\a�4�TI�r>Q���(hz��mI2xW:��r��v����iY�M.���3�`�h������#V����K�\�+=Ds�d�f�\�&L�'YO���D����X�0R�d?X"3b��0��0������P��~��7q���q`����5}�D���^�� �jW����XJ(a��(A��}~Igp�cS��lqwK<�f��d�����^��\3o��
y��CT���?b?����~	�yc��T�E�a������UZ��U���
�J�q?g�US�[��6�%u���+���}_���v=�8����	��-q�Ne�~�Q��y(����Q{�q�]�d"��E�
�#T���'��PU�P�kh���.��{�7�x������0�M�x��]�O�����Q�N8���sE���%���E��YJ"I��[S��F�B�&q6%�����g\�Q���������
}�e���[�~�Pa���=��p���4�an�0��Tp�6�]�I*�
�b����{T��q��������������"]���N1S[b+5��2�0�sN����o~>�&��"���������|�/�Y��9h�o��0��|[������������~���_�����n����������=.~};?�����n�����?.�������������
��X�}���F����_��<T���!�k&��������_}��W_���_~�E���?�����~���O����=�����?��������_<���_n������?���o?��O�f���{�$���������7�������~��?����?�����>|����o~��������/�����?��O���������������|�#����X[�&������[,���������2�$o~��T6�L� kt������$��Ga>������ ���7?�|S��?���?���^���o��w���_��v��[�������������5������|k~�U������������?���u�X
`�H�	����W_�����AtO���o���`?]��v���O���;�H�M��@��{�0A��)�������$�x���h<<��	�����o����;�R����p�����o>)^Oo�?�c�
�H�Q������zL�%��G;�StyP����A
������+�����(sx[d`B�@�������?sXD��E���!��P�=�b�|0]�mm�W�����������]���8J����*-�d����i�Ko�G�H��5BcY���u�d�	kR��)�������J��*}�*�zL����j+���)�o*\rf�M��{��L=qV��l��z��1�x�D�'�T~�r�[�Dz����)�s�^kI���E	lc�{n3��;��	5�_�R
�	{�����x���q�W'��>gA�6D���[T�N��������L�^��ke7+��ce�^i��{�$��e/�,S�VY���	Q�5|����P'L��AV���n>H��3
��A���?��d��z��
L�1)�U���T�PD�-l`[0���.�Oi���rq�`f��E$�#���f�*9-~���^�����c�o��o��~�������4��=���x�����O��_?|������7Cq����k����7�/���W�wo�|�H��?���?|�_]�����
�����W*]m�)g|�X�g�>t��=��7O���G�����84J�84k��U=4t�i�QWQ����kT�P6��I�bd��(��U�KS>���r^�����F�cZ��_~���S��B,��}�b}���L�����j�)��A��JR�Tky�c���v~�*y�e	Y���,�`�_~�]�ZHX���L���iO���0a��G��~������-�8!�#�1^��������<�
S;�U2u���N-o���w^	8��{���8�*�V��������z������z-�#��W��
�J,?t�u���d���~A�E��>��c�o�	o�
��\0���/��3O���Pe
��F�UV�*Mi��@�4�����E��9�{�D����v'��i��
��t�8�DH��t���T�{cQx��R��#�7>���C:����`��`U�d�7�n�sL���5P��� 6B�(�����*jS}���:6m]��a�����@���]�\�s(��C	����\g�L�0<�d��!B&��|�G�C9a~!%�=�+}�C/K�����#�����Q&%�Z��+)F���_�KT��
*�_��2y�5_�6hg�k�W�H�e� ��\��TX�"8���Q�H�������b���F������3~n|�c���t*K��0y�O�l?�&���U����2����kjg|����Y�Q��c���6"�|����2�����s�����X��?���?}����;�-��N��ve�A:��$�����x��������TXl>b�Ay���'�p��^�@����60.�zO>��Z�C`*c�^!nO���~C�5~�5�Zc6�����Xx3�Y�a����:�}uo����lD|��o6M�=�q�s+�c��l�6�e1t����"�x��`��;�&� ���*����J�J�c�_��0����'�El0{p#�7P�9���������D�s���^�%$����d�}�e;l�=����v�����������������0km&|q**b��giL	s`�G�)J�[L��i�5��`����T{�
�����������P�S�a�Q��YB?L�������^9�p_7P�-*ids�/�^�p�5D�Tl5��.m�Bo���1w���0��<x���5��_L9h�]Z�����k|D!B�LAOIg�h��x����#wV!����g��;{Q���5��kzQ[�}��B��C]�i!���r�D��D��TkK����jH�F������z�D���)W�V.�� ��?Y5�������������q$����E�����|?���?�����^1�'5��7k!��"������]}�AB��(`np+��7~�a�Q�o���,�� �

�f������?��1B�|?p�_q�8������e�����W�?v!0���]G�<�����
���~�}}���,
�j��sy�����<j.��X)F?!�3� f����o"W����W�_h��Y�]:o��_En����2!����#)��@�0�s���|�2I��.��@��� :�����������(@.
b��W����4�]�q#B�	1f�y&^����n3���;�<c����	_�\�{Y�D�������"����K�x�c����� �^{'�dDp��� �{��2�~B��j!�vE��A����e-"$��>�"fa�l������1��@�����0�A<1;�1fu�5� n��p�
"fag�!���*�{o��	������^&�~_!&+�;�� 6U,��x B����������x�u��g��
��Y�����;�� 6U,��x"B����#X�A�
!�mTS�R9��B�y%���p��T��T�T�,ay��'�B�g.�����5�"�R�!3q�g&R���b����;�� �y��q�Qe�i^�*��A�!�g��l�-��������r�.���iH�����g,���xDH=n�o�����,���e�bY5 \)g{H���������bip��HO������x��7���@a������.�-D\~t�����L-w���G�3�nt�gPoeD��������;�<��� ?��>D�����O^���+|;�|2�^J#u��_�����%���z�=���C�5y;x���{�%n����a��B�.����tC�T:��gQ^�06Yt�����B�g���
>��G�o7�����Aq���]b.�.��Sc!��)s�u�y��<�%��w ���K`�x� ����z#��n��Q��c���S�O#_9E��I� �������4�R����'�6���Oh�mL��S��nPdp!�l�Gu3���(5��8@���>X|f�1�{`�/y��,m���������Ucb@��	�V��@����������/�����D�*��w���=�V��)Q�,��4��:���u�](��B���������P��]�>5Y%V	bp���
������eR/aR��:�Rq�.�����e���R3�"!,����)U��������Q�;\,S���J^�2���HF1�i�e0M)<�
a�F!���)U���Q�0�>9;�/����g����6�w�<����^pMR?]���z
����3db�'m�?��<���/�4.���d���1;D�x���w�p�Q��"L#���Pm�����9�z���U�$Uu�"x�sA��9�b�w�
�����W�[��n���B����"\aD�Wku�OZ��y�������sW��(+����p�c%�f����|e��Z� �Y��9�l�w�-=�!8p.\J^�������t];&��@!t<"���B�)����.�]��*�����l+>�������4����m�1����@_����8�[n���Y
�)p�}v��k&��m���S�]�Y=j�E�%7������jz��6�����H���������#}�Fz��FZO��B�F+�4B
w�'
Q[|�L����a��Z�#7��9�|���	a4�,�P�1�h����v8�Y#��-���c�P�����������P�-�F���6X7!�V�5�G�6���`������l���G��
�3� g�������v���h��hf[��q�]v�?�=�;�O�}~
�3�$�����o��g�K*�������l��{!�+��l���:C~f�$^�����3�%�:��_�x�����Qo8�Y#��u������z����k��:z8�Y��$���:�y=}��l���L���q�u������]�`hO�
%�F4a��Z����v��o�q{�W��]]�A��|������jraZ��3o{_G�K5�>��T�x�>$����|�\q�j������S��w�x����<v��fQ?��9��T�H2����(��}�������w+�������x��|e���]kn�N�x<Q��^Q<��T��8���d��o3a�qeXZ~����\���A����(�o��/�������q�r���������o���B�y����������_��u��}���|����^�|r�S���'��,����I�A��{�����J���_���&�W���������v��|r��3\$-�����H�	�q{��,�uIP��^7Dx�0`������� +�Y���M�c]��� +%",gAw���w�j:����0�tm��:z��@J��To=I���
4?X�����:mx$B(��#
�n3�e�f�������+�"2�
V���4��;��"�D$@~.��D0��� ���y�@�e�j� .y&Z��w�4�A\�
P��y
"����APG{[<",?��bD	�m�"�RnPG{[��K��Y�����\�o^��������ck���APG{���Q�v������
�K�8���f$"$���{I� \qL������J_9DH�lc����4�:�ld�FT�������"DB��MK� ���	0&��0��D#���b��
���J��l,�C�D���*��A<!����x)%`.
�������k(C�D�+�#y���Jo�v��\y�4�;&�;��K�P,X�%@.
��5q�d�Rc��Al�X��m&����x`����l�9�}K?9����3��F�<���������;�����q(���{���]�Y��i�Fu��$�p8�>y{mQ7o���9q ������ruR B��ue���c(��@�\����
�e�C��D�e?���\�!�gDx�����B��sBq:d*\j�cP3@�9| ?u	�iq�Q��t6��SGOC�!���Kc8���-���8y�.��,��� ��:!B����!\q�Y�c'3����Jx��Z�:�4U(u���kM��m;�����1p���C�Dw�1c���.;��pI���t9�3���4��I�&7����O��gx��YL�M�1���������p�0����{���C�Y����Y��M8�D��T>�l�:�\�K��{�����������t�����������J��p���]��?�D���>4�B#�y����1���s����}}�I��K�<48����Jm���n;<p��K�I���j �
�/�Y���������@>���r -����%1�+!��l�����"�/Tx<,�����&(yPw�5Ks�c����od��������� #�3�-�7!^�f�����u�`0?������� �9\�LU�w��Q<p�W�*k��*Uu���]� ��{�t�dig}`�X6��N�u`;�c�
���R/�|�����8��;�.������D���W�~��~���os�����s!Xqr@���_���D�$��*n�oo��g���e�oF!��������o��������?}���?|����������~���~����F�����W?���|��������~���O�%����s���/��_��~:��}���(�k-����[��sp������}���~xyS���M��N�m�?l��x�o������[>=}~������$9�XU3d�W�$8��,��G�l���Z�>\Q�{�X����<�J�b�p��`�]UK��0���`�=��-u�Q�8`WY�by���C����bF��[_Q�u�~D����J��~��QC;�F�n���\��vz(�C`�kK��J��l��:�
$c�MK����8`�m�S�=��m���+�Q��\?��ED������1�}���n����;���1�M�vg`~o��D��]������lO�w�^�b���j#i���S�@re*�G\���fQ�M��c��(�tw?N�m��������=�!�M��sO�b �[�v99�C J��/������p���Md����-M��@J��������+U��{���8����P��c�����H�r�����e%�L+(�8&u�,J.P,!���e%�3�Zc �[:r�p�LY�l��H}�Yk�w��D�6���I��p�>���iR���0!���%%un�tPe3����UI�m�x���;�w��3�q�xZ��U��Xl�f��#}A�l�����q��>��o�!p���;���r�@8p7��O��
1�Mw��L��@8p������������j�]c�{��~�1���������M��NgI���V����9���k~��Hf	��b G�-m�y��2��p�n:O����1�-��yq�2��p����+m�y�R0����{�����
�?4�#=z�q�<�|�R�����`:vW-3����9H�w���ni�������Y�qB ����X�y�z�3���@J�3�e�JR��������U�h��-~�3dw���Y��$���
1�MsoR�8���iNrB�������R����0�RK�w)�5�^��>��2�[J������F	��c��"-�%uj�@8p�LJ���Fq�w��D)�o��]�t{g�c��eN/��@����KI�wYip��L��HS��n���!� >����*)y�o��_H����@rV��#�t��:1��n�F)���[3YRk�4J�%��b �[�(l���t%q�s]}�7�-��9�.`t�N���4'�OXC ���$��0��������I�#mKi~��6�u��$���j�n�a���'�O��
���[�m�b~��n?�e����1��-�t^R	�n�,����1�R��W�%,��w��YB��q�P�-��1�-S���I��c �[�$�-�Kq����Z�LI�E��b �[�$���M'c �[�$�V�_�wUJ"Up\���P�@�����7��:hv�'ffZM�������:�'!��ge�j���5��	{���qdv�����t�l&H�c�����	�p�n����e*����������t���p(���j��A��;�Ox8)�~~���+O��S���n�#'|ukv�9��x��c���.�N��������qVa���G����3V�Si��]i�T�����%1�>[��������:�J�t�C ��$SZ�vj�T7�"�;�1�)�2)Y_{@%�C �[&%�z�f1�-��UC)����D��n��f1��*{~%�{�Rw���9�cMO�+���	b��N�!pL��9��H��2�i�iN��T�@8j�LM��]�G
1�-���������4+���.�H������h����\��w����}��l�Na���i��`����v��21�X=we��+���!��j���b�������|�+��;t�����8Zu��g����TC�#���k��:���o���jJ�B"�Y~`~���4����n�R���0�lZX4-���)m�#a�2����L<D������H�3�HX���M���o1�-m���Z��x�e���1�U	J��L���H.��eG�.��}1��{nJN�;%���c$�[����-uw��`�?
�?p������1���M�zo����7lc�M��S�B-F���^o�5=E���o���P�'�1�u���n��+�1��7	De)�I�	���{�!����@E��5��<y��0]�M���^f�HX���z��2N1�-��Y��p��x������S���P�)FR�d�w�+k��](0zI��I���`�,1K��!�1K���3v����o��l2=z���o��8�e��x]7��[��������U �*���go�g����!�������x�X9Gvh!c`�#M��c�Mg��$'�����6�6c$,���'�I+��HX��������f��x]E��P���NU'+��E���/j>��U$��Y`����H���kw�$��+��iZF�J�������Q��}��o?$��H��I6�~~�4��kl�1��ny�c�.c$,��~�+l�1�-�a����oy��.c$P��������e1�o��l2u�c$�����P
[�)�m��������gJ]y��k?����i������-o9�������1d ������>�fb`��MS�C�f"a����~��2D��iz�O�,C$,���'��V����o��l\����o��l�R�HX��LO6	W�c$,�[�'�W�c$��
���?���'����1�r&���RW���������!F�pS�����z����C�6��q$�W}��m�$e[6
�
�qq�Z��
��c$,�[�����;#a�r��������o���%�#a^���P�@��T�m��$FR\?�~�m�u7��
������#7���l��Z3�B�4=��T;�H8���Y�~�T;�HX�7�3��j�	��9^ySi�'h�	�M��*���\}�!��6}�#�.(��Z�7)�.C,��e����n�1�-'��`��x���Sj��HX��U7U)����n>�M3FR��8����0uW���i}�I��JM+!;u�o�b,��e���#�^Ws�����b$,�[&(N��O��x�$��-��#a^�������&��#a��TW�T�����?4�
��Hf������i^e�	�7���i�U��{��r���j-p���b$,�[������!F���?lZ� F��j�	��_���v��I	�u��2��������@_�kZ����d:�!�IRY���>�[�	�����z�S�1�-��.��n��x]~Rw�j��t���0���,h������C��A1��z���M�9��:���"H�Ua���4?���o����N��	������4?�����%�U�;�*w���$FR\O��i���i������^i{��iM���P���lZ�u�������;����I2�4p��b$�I�t[9�k����S���I���n�Q�f���2�lZ�u?4��	����_S�*F��.=�����*=���0\����X�F��|�!�o��bJ��	����`��w��C�O��<�E�N����7	�b$Mo>V������.+wH���CN�=?=�Vb=�i��I����X���+I��xK��P��=�J������6#a�2?9V�n�1�-��C�t����oi�����b$,���'V�7c$,���'�������oy��p*��#�^W���&������I����������������;�1������������0~��q��}�H.�z��q-��K��m��{�.�.�V���������4?9��w��x���Op�;F��e~�'��#a�2?��H�j�HX���O�����	�������	����W6=.�lG������=���1��E�������7��:��Gc$7�e]Y�����p+9F�����f�����r�\��e�J���4K���o���3�Rb$,��n���/�c$,��n��YJ��x������y[���,%DR������%L�
p��2C Mo�W.��sd��W1�9�4=9D��c$��*���,'!�M�L�t��HX�7��'<����{	Sw��vHO����7�ee��E�������}��@�76?���i��S��`�$-��Sn��#a�2=9g���	��^����l��x]��PJ��u.:=���g*jW/(u�}��s��'F��
x�"X9K��f�]��k-p�+a��x��4�j���i����Jh�V��"��W��
WBK���^W#TXpK��R���'Y�[������$��2G��'�
�`��x���P���	������X1�u9x�}�;��yB��I�������uU���KLo��H��hY&�9�[��$���Z	:��G��az�'�l)p��0�e9?=�J�S%D������
��TZ5�=�+�uuM_�[I����^��$�w>��4�On��M!/�u��L������i����O�R�7����'!�
�=�6BO��\�l�2�z2�����{��M	������T	��>>�W��5�{W��-mB�H�w%-KR� �G�c��#-+���M��ol�G�*�V?U:�!�
�r�i����HX�7���x��x�^[.�
+�i�����(^K�����5������������Xo��#��$i�����B"a�2=��a��xK� n_L
<D�����%�$]RI���t!�����?����uoJ�
�O��H�)i����%�2K���Nog^H���M�w�$3���[&�b�6�b`��9��W��/[V �B�3��!�-�a6���o��X��S%D��i�������R�2C���T	�p���+�Z;��H��	����C���L�G����n��H�����������)L]Y���0Zx��c m�����~)d�f�WVbU�����	�T{:GB$Yw��[�Ur���� X�e~"�H��b$,�[�'R�I-��HX���O����\�DZ�b�r>�%F����"Qa�HX��\�%*LYR�>��Y��jS�J������i�5-uZw�=��O�����!?�w����$0R���u�}��-��|+>���r�kg��k1���t��i���HX�7�����\��������]��=�um����h����L���M�\W�T������s���Hrw�?���47��6��e�4�O|�`�=�-��jy�
��#a�����N�c#a^�g�g�c��"m0�I���I]���7%z�����H��)�\k'�t2�,����$-��yN[��G��e~2+�f�1�-����<�*!�ufD��}[o�s�	��������>�"������1�����P�LOf���$��2GZ�'��ar�H8���b�n�����o��lS���HX�����vBz"a^����0��[���2����?�f��Z�f���zA��S����v��*=��1������1�'1�M�/S�*F���Q�|N���HX�7�����8�HX��|
��6�{$�����UM���0�?$n1�^�*�'z����X��iJ�?����$-��j%�.����o���9���	���A��K�{$,����%P$]E�%���I�
���oa�����I��0��`�,Y}zJ�`�%-��t����o��(��O3b$,�[&(�n�#a^�����Z"�?$���o�b$���,����g0j;`)	10<��[�b��A�	�$iY�U�}M]�	��	�EPb$,��&(^AJxpA�[�!���"(1�U��K�r�2	H	�B�x������i�s�eR�ci����:�Lf�����,�:/o��n?$p���;F����n����^�J3��`�L������!�-�w%��$F��e)V�,,%!�-��e9��2F��e~��^��k��+�Z\����HX���O�Rc3F��.?�{���-=t����6��5�����SPd�{�l*R���Z5����������A��If��\���#-��e�a��
uL��{�Kki�G��n��{���LW����G��_d�`:uc����������o������HX���O�iN��	����* ��<�v�iZ�o�Sz�4F�2�-os��L���HX��%(uo��r�	����MW��c$,#�r�_�t#a�R���J��	���~���L_��HX���9W#R�-F���2G�.�\_���J��/@>���U	�|���5}�i�N��:h��;��2G����v�HX�7���v�HX���>���1�us����z�gw��������J�v�����WX�C$����/(M+%�'��!�Y�4?9}���H8��U6����p�T�hnZ�R�=�.c$,���}xH?�yH���V���g�3k���������w�c$M�5-��o[A�8��2GZ�'Z�3�\��	��J��HX���On>��1�-s��W�J�	��w��������k��b$��$s��r��u��T����5����=���;M��jk�{�1�M��M��rb$,�[�;h'=1�-����Hh��x���p�����j}�IO���w���mV>T��
~z>�P�r!������Cb�,�!����lZ�T{x\�`��MS�s����=�kZ��L��.F����1���
1�-#�q]���jZ���:5�b$,�[&(F-������+lZ��,*5�b$�0U��~f����	����|
/�����f����I��F�j��
'���Ws[��/<�(�����kZ�(�h��5�14}�x^h�c`��-�c�f��x���B#�	�����0c$,���'a�H8�7�kjv���	������c$,�[(���a��x�u����	���%v���	���>�|�s��
8,����?�V���|�k��N�G�����B�M��?�?4n��%?O��8��H��J���1���r��xX#a�r��jI�B�vf����N�HX�Wm�"��wnX�uN��I	���Te���7�v���@��I�\k'�^av� X&I����%=P���o��X�;D������dz�#a����u��	��WUW$T�k0��V�mi"#�����`��;v�r�1�Y�4A9��l��x��0c$��������� SUV	
:m���N(%#)��|^��U	�|H�M�Z F��!}�X9I��x�'�1�I�2A���6�HX��LP6�?�*���j����#�=#a�R�ojOOc$O�U]��-��C?Q��-=	����l>/x�J��#m�c`�$-��m��"1�-��MCE�	����6Eb$,�[��l��Bh�����"�/�.������a!��>>�6��m[jn�@X��^�lzy&F��n����v�!��&M�c$����o=mg�7�b,��4?�3��vS��Jh%�S�O�b$,�[n�n�R�#a�r�w��f)1�M+n:q�YJ��x�iI]y'�4K���/o���t�L�C�e���q}�;�����#)�4�����^(^��4�riv#�����G�c]w���f�[�t�1��Y�xb/[�0c,���Vkw��x������	����3+�����
�7�O��*�	�����`
�poZq�9�.C$,�[�n������G�7]��)=������uE��S7"F�PPD�U�|	�/w������1�r���q�m�vz3#n?4n�C �,��jM���������mZW&b�,�YJ	�/Q9�+�z���Q`��e�[�'�p���	����.��j���o����M�X�H8�7�k�+�*�	�������\��������{��%�k1��5�����5��
��@X��2���%O��x�����"��0�C$�+�����7w�����|��i;�������4��7��^���o���9�dc$,�����H3�	�������}���J�I����RY#����~@}�I�r?��`�,�[Z|&�2KZ�'�i��31�-��c���1�-�C�������+VWQ��*u�b$E�����o�_V�B�!}�q�H2���X��;�<��}��e��LP������o������6�-�c���0F��i��cu�u#a^w�#X���uha��X�����Jhee�C���H��JM<F)�L����i��X������o��l"Mc$,�[��nJ��HX�7���L��HX��=,���r���O�����`e��I����
��D	q�����x>�Mf�6G�f'���`�����F�q������o)���'1�u5B�Yy���*MOb$�+�O/(K]-��E^�t���4.Q�������1�Y�2?��~���]�������������[�'��������:���(��MpO�"}�D�RWp��?{�=�������0����rR���
WMc,s�e~�
\5��poZ#�[�j#a�4?���i��x��;�j#a^�.�/w�{���i��|���u��Dhee%�Oi&i[Y�r���$;�9!�I�4=9�fe��xezb������W���B����;�cn���,�!��ny�sN
�w��x���s:�c$,�[&(��B�1���M��o�3���0��Z�*�����b$,#�2A9��8�����L�W�������}���>/����VVV:WiZY�rrK��r*��@V�iq�!�~`v��,�u?�b:'^��b=�K/k�HX��t|N%Mc$,���'���5c$,���'�N��HX�7MO����H8�7�kz�KzQ)F��izr��}��x���K�zB$,�������w������I�&���l]���Jm�	}�b$�+�-u5B_o�}~�f�����^2e[��H�$�yNd�{,���^o&!��	��{���XR�!�
�z3����{$,�����r~7�~KG|.�|��_�RR;���`� 8�e]S3-;D���vl�}���iM6�GR����SW��v����y�e����I;�N����iY��L&�}�#a^�������9��b
�����-u5B�}����C�$,*!�����W�����E:KB,��i��������o����o�	��f���M�Seg������pSI�7���S��=�"���Y��T�5��Vi�3-:�I�j��k`�$9����������d�����2~�j��kb��G��e�"�2��C$,�[����Kn��G����nUq9#�1�������B�]Uz��q��[�������>�
�1y��OZ�55b��U�HX��LO���a��x���Fh�;D���7s��HX���X	
����6u��#)�����jZUd��{Ns�H�"��kw�$���D�A�L����0�Wi��eYS#�	��	���A�'l={�4Q�u���)Ch�q@B"i_�p�,������C��
�x$��|@`V������a�� X&I��DN�����i���F����{$,�[�'R��}#a^WJ$�,��#���I�(�����I]���b�F������-VY�VN����I�e���O�:f�����R������1�-��n��HX����U�*���	C����������������T�$w�����e��d\�C,��i~b���2F���k%���W"b$,���'n��"a^wV����"ws��C$E������I]Y��Z�Fi���H����\k'�a��<��-�$M������o������HX���O�I�gy�m=ueM_f��������L�IN7|r�m~�rJ�1��u��d����rJ
�W�'uuA�<���{$���.-��p�&����B���������giY������5���o���p�0F����n������H��I	��eeU��b�7���x�m��������Z�e�4MO���6�HX��<����Z�1�u��y�;�?$�-}��Inz@��,4lfgazo��i
��2�:�e#a���b��j�cM��c$�A���X���`*F�2�MS1�M������S^W�,�w��	��I�
��x�rXW��(.J��i�����{���X&IU�R��NIg����s��r��R�Sz�>��2�-s*5����{$,�[�'J�{�:k�Z�F-�H�J��x�Z�F�[z^#a�t!�6u~b$,�[�'��4?���o��(���I��x]-��"�FmK���H��][�5������@X��)L=/wD�r�?!���x��YS���[�bi[��v�,�
�������� ��L?��i~r�=�!���4?�3l:!�M��S�t��H8�W�b��Ll:!�-��������c$,�[�'���m#a�2?Y����HX������.��#a^��T�5���S�I���k]�PN�����e0�!��S��{ce��.���J1��f��9R��j�YV����TS�U{+�G���Z�!���ez�h���"a�2=Y(�	���X�bA��HX�7MO����{$,���'nN��	����.Rq#a�4=9�T��HX�WJ���
�g*zb$�������M������1}���j�ZW��E�P�>P[�
�C�$�F��I�t�?��'W���i-�u�`������+K$���{f��i���y];�bK3��X7-�zK�V�qe�u�Xk��&��1�-��U�#a�2?Y�%�c$,�[�'�mR�!���O�}rg�_�L3�I�b���|�2��6iza����Y=7\����V^�Y��^����/L��U5��
�A�l�r�H����{}����
0���O��J���������o���2}#a^��W��^�)}�#i[������c��;�2�M����}p�r_�J��pJ"�������;DR�i@Q�z7-��'�`#a��K�#a�2A�R��l��x�c��*�z��T6F�P|�+l*&���Szv�c#�,��S�c����O��c���V~�'�c���^������oiF���B"a�r��zKOyb$,���������Bh,�!����uuM+��ku~b M��W.��s�N@����6-����V����o��l��O�*Vk�:���0�C$,������G�1�uuM+������rb$�����eM��v���C�v���H�Z�&I���[�aC,��izr���	�������<0F���Y�K�b$,����\�q��T�v����l>o�W�5�+n����1��e�k��Y2����,i��e��;F��e�bx#a�2A1��!��=
�+lZY�&��c�I�2�k]]���b_��+�.<
|1�94-�|�� \�Oe)�J����HX�7�O6�&V1�M��Ub$,��r����w|���J���y�SW���
����U>P�r	��$��^H�1�L����W���HX�7MON������o���I�."�^Y���
�
[#a���6}}>�E�����#����������$��2GZ�'VB��	������II��x���*hR#a��"�4)����+�Aqo\M�/c$%�Y[V]����@�>��C�2��+��1�9�2;�:�HX�7�N���.��0p]W���u���HX�7����I��x]���"��A��I�"�����\L�{gt /c �u�#aK�fw�f.}��
��?���;F��iz����;F���v8gP;!�ue9��-����$����/%?��������6��fX�$�����R�l�N��3=��M��nR�7�c$���5��5��1�-�M-i#a^�FW��9M�c$E�u]Y��f�����}���Hr7��6�+���I�� {����k-��W���	��	���4����o��l���dz������>
�����8_��{�7���1��
���u/a��o�OUO$g�?�6�H��Yd��w�V5�v	�`��x����`��oyV�gz�#a�t�{�`��x�K��"������c$������������yas;}zw&�u�?���in��1�I�2=qbK7�	������~"F���vp�I��	��Z"��wp���D��<Sa�vA��ZW���3]c$���/(��`�,Y��2�1K��5u+\����o��8��%<F��e���M��	���uU��5���H������B�Y�B������Q�$��d*�V�uK��6��Z�1�L��	�[�t�C$,��&(��<D��i�r���#a�4	�V��#�k���"��]�9A"�=)��X7�ONx/c��$M��������o����K�HX���Ov�R<F������|�>���#)_��z�����H��c$,#�r��o"'�	������t����o�������1�-7�]�t���p��*��"��*fKUO��x���E��Hhek��N���H�Ey�Di�Zh3c`�#M��mZx��T�M�����'D��������#a�t�����HX��=,�+�����H��?��]�To��Tw�A?���c ���/�M<�~K��� X&I���4���	����q�x��x�����L�	��9�����|H��1�"���q��RW#��F�1O�yw�${��JK�s�P�2�2KZ&(��$��Y�����_Lz�-F��e�r�:�
1�U	��yse_�����N�I���\!��\���U�?�M��C�Q���������	�$i��Kb$,��&(��H8��6����$F��e~��L�vdRW%�%�*/�V����")���RW$����q��i����|��l�l�!�9�4=�j���VW���)�tr�HX����H�v���C��Ho��Hr����i�^?�c��`��.���01�-�/�1L��x����[j��H8���5�l@����=�[6-���K�����<,�����	�����wp���j���/T?o�W	�����L��b$����[�����,i��x�7~2UP�ue��b�A7�kz{�)a�$wK�y[�i�[����q��e���'N��{c$,���';\U����{
S���pU)FR�����]Y��r��?1�oZ��5}�#a�4A9�\r��xK�vNP.9F����k�8_�|���r�1��|�u�J�Z�bN'J�#w����jr
(�c`�"-����.�� �nZ��� k��x���Tkj��HX��Yu��eI]�I�����U	U�[{���:��>F��iYPZ��S����`�%�ie��������o������HX�7MO��������JODXP��e�
������'U��K]k��)X�C �
E��t���-�SC`�"M��]I�0�U���i-�C��"a�4=�V�	�:'b^��|��<��F��df|s�]���R� 8�e]S;MP�%F���m]U;�59|������=���i������C ,�0;��LK��G���	n��&��{$,��������c'�����|�i�������o�E�)p�P���w��"��!�Y�0A��z�B"a�0A���u:KV�6Y��8�k��/�	��RX<D��H��Q�E����S:IBc������k`��xU~R��N[���=��������M���3�*�����������C$,��&(�Z��"a�P����""a^�&|�/�>�S��T	�o����kW�Z��{�-3������v99�L�:��2GZ�'b��[.����i-p�&��{$�[���B.*"a�����yN��	�������CW2�2c$�;�XP��@]�����`� ����_�[�5�bp{�����i-�5��	����XOXOV���e�P+�S<D����H=wL��j-)�Ix����Y��W�����0UB$���/�m�-�]��,i��8)�����X�������)u�c$,��&(�i��"a^W��F��O��I�I��J]�P�L8��-p�u*{b$�%S���l*x��;��2I�&(���"a�2A�����C$,�[&(��R���c$,�[�H�]
<D���	\X_�,�r^��?����g<��5��j-p��w$�h�C�2�����9b��#u�Xk��}�����iY�����t��HX��47���)�	��s\�#�*!�G���'�uM��&�n?$p�m
<D�jYPZ�iW��,i��l��z�e�j��w�C��HX�7�O�9=������OD.�?DzN#)^��z���<��M��px���Vz
S�(�lj��f.�����o�����)"a�r��C�����HX��5T�sf)�;y1��M��]���,���'�2�u�u��8�y���q��x������i���g���@X��^?����{$,�[��r�IJ��x������z��=V�#)�tO���u5B�j��Y���O�${������w	�G����%-������G��i��G�#a�4A����������N�6�n�nO����L7�j�u�����
2\��1��|`
liF���,��]��,lZ	���aI��x�����$F��i�r��C��xK���5=5��p�+*��"��*J���!FR,P���RWE��'�
�I��H�)��H�uP�=�#1�9�2=Q��c$,�[�'
�����������I�z�'�[��j�7H1�u{�$���n?$�� �HrB�J�X��*��x���kw��Di���@X&I��D��p�u�VW#�����C��x��~Vm"u�b$,��^�SV�1e�v�g1�����]���U��r6}4#��,���n���k�d7�2K�&(�����HX�7MP���.���o���25dc$,�+���9��?�e�+#��K~�H�[J��
� ��vc(����r=Y�s�+�v�2AY�O���HX��LPy���b$�m��~v�]���HX��<,Y�g��x]�����[U���1�����b����u������*��P����:�N'@���*[W��8\-���o��,���^����eB�k+�x��x�9n]*�b$,���T���O1=1��s��2X���7}y��a;�(!��=�������v�8�|�c�4-����	�����dc$,�[��,~��}p]��uUBE0��3y9��l���>m&��"�u�n�]z��'���^�&�:���!�2IZ�'�����1�-��U���Y��x��d�uz�1F���]IUk��5=�����|`=�l�����������~b ���~`�[��uY��1p���5B�U�W"a�2=Y���2D��ez�82����K���3�q}V;��gb$�������uMn��4���d��|`Ai��l��W��������$F��i~�����HX�7�O���1�uG%u5�W/���1���������z��_h�G*b$�������u�W�$	1pL���M��7�HX��LP�t��Pb$,�[&(Z�4���o�j��G�1�u=��B(�,�zi#)�����uEB+�9��H��H�����y�V��������Vgzu=F��ez��#��#a��&�^���z��x�9�]z�#F���Fhekmlz�#)��~~�+*����C�>R�>�����B�����6���`�$M��M��c$,���'n��'D���v�;H�	��9.�.�����WS1�"���Y���m�u��wPb$���/(M�$k��b,��i�r�m�	��	��Lz�#a�2A1bM��	��*��5��\�?1�������*�B�Y��?4�3�*1����������1�&��2IZ&(��Rc��[&(f�!����|x���S���HX��L����C�	��&pa!|����I	�G���������g*�c �'<��y�1�@-��2G��'vNK��HX�7MO6x�#�����q"�c$,���q��b$,��^���0�7�~���:XY�t5o��C��rg1�����B�R��:{� X&I���Cg�	����� !���^
���v� !����O�.�8������#)^��,kZ�Z�J8V��d��|`�[�+�4?�A�L�����}zo&F���~b%pu��I��x���..�Ob$,������v��}>FR���zRW�TNo��_H����@rW�����Vv���56c,s�ezr�e�[���i5����<D��iz�A+�	��<�>���:�F7��<�^O�>��nv0UB$�+��/(M+;����,i��65�b$��*���:U�1�M�����HX�W�:��*�M�n*FR~S���RW��e6�
m$o���Hr�>��	�&��II��e��LP���
|�zR���6O���	��	�6�k�	����@�HX����
���.�Z FR��u��)L]�m��{)<�@����v��
�H��c�4�����:D��ez���'1�-�rlvJ_��HX�7���L
�	���0u���8�I��7C��EM���oN�V�^��X7MO���A�L���D��MG�;��/3b$������Ro�N=��`7M��������o�wN������o9U�4C�"a.���X���c�
��)��I�y�y]���2�N����J�N��g<7�-�7��x�g��*���re���1������y]����n��".1����}���d1�v���'-}�jXC(<��.��=IwzI��J���G�I�|�ix�������3pbC�A�4W�:�k1�M��
�Lb(<���*nI��Px���S���gH1���=U%��!!W	��k=��7�L��m��g��.�^��\1��7�u�cBJ�r/%?lD!�����L�J�_U���]-F��2x��O������
y�m"��c(<�[n��8�m?�������������D.��g����jZ�x����>F�3�-s�]A��
����u���Z��P�W��>��o)��U��/\��o�����	CB�A�2W��O-�
����p�&����HO�c(�l��U�be���B1�J�2���MGn1�y�4W���-����i���Z�y]�Saex
&i�;�C��df��F�i�r���A��v�T�O0O���i���V����{�x�|����i���t0�C(<c�2W9�-=v��� o���
�>EC�A^w�|����rH��j�����|d�W�����yI3�J������c�i[��<i��
���Px���U�eI�[�ye�V�C%�`�XU� "��}a���n����>g�A��v�\��s�#b(<�[��
�����6����e}���[C)^����YW��v�7���	�����q�R�
����.`��Px����	2H��A�1���b(�74��u
������y��m�����
@/ly]�j�g*:c(<��n�'^�Px�����t��<�N�������"��t�bO���P��
>�q��(u���\���E���\���\�,`�C(<�����3U�1�-���
�O6���&�_�Tu�Px��U$	������_]��"�RD���_��V�-����^S/+����x�UEC���<iZ���
V������e��-���� o��lP+�����G������ �|����_�4��P+��YU2m��W��>�UU��nS/+Q����%�iaW����	�4i��p++����i��
|������
���+B1�-�S����"�� �+����w
�ZB1������R�u��O�S�#i[Y��zx�����^�m�[�*��R�3����e�r�9}�C�A�RL��H�D�y�������:�b"�����
x�����U��C7��#�����h�@�^R����'-s�����A�y�\��sZ�$����i��A�
����2/�;����R�9�R�B��e��nje�����qd�i�����r��"5'b<��i��C��
����e%c(<���*Z.�Px����u���z.�Pj���W}����rLP��i�0[�B����U�e�mi�� x�I�\���Lf�{(<��*�$�O�K|-��m��>z�ye
�������M���|�1�V��"�u��i�6�-!���kW��y�8�bA������6����-WiY�u�-~���Px�7�U���0��C(<������+y�y]�RUw|�6���C(��������o�^y���"��B��X7���Md�S���T��X
C(<��f*��]3���\����M�
�a�y�y���"?�
�������S��s��V�J	�$��+�)���I����{$����a-��2����?]�f��2���N]G�h�<Iy��4E���x������T��Hx������i	��Px��W�r�71K�NI����3.~��������_���o��6�^�����C#w"�J@���_���>��������}�?���-����_���������eF�J���hT:�^D����62��o���&Z*Fk�������/�����o�W����������?|��������?4�wL��[�z�}]�>���4�Y,��6:j�Z���/�-�^�y�b(��?������������O�~�����������/���������"�������������������?~��/����������_�����������?�����E�<��������������_�����?����m�L?��?����������^n�����}?������o_����_����~����������o~x�������W���?�-������~������|�����������f_��_`�b���k�_���w����-{�G����U�7�f}������������/�5��U���M�?�?�BJk��c�!�/�WH$�>)w�b�$5B����L��	 I]IrA�i�j!	&Hi�w�U�&.H }����4��(�u��1V|q�Y��H���k��!u��T=� �k-�'79Y�6�����0�D�Q2�M�w�@jO����t��4��m5B������mHV��������v7���n����9��l�(I�r�p�$'�F�H��rW��U"��m?���f��	��"��
�k>&D' :�JD\R�DtV!Zki�w�c��M�	�k����5��V9F�eZ���=E �Gt�y��<I��$yx��?I>�����y��l2`|��z*��m���K�UwFiU�ns�A�yrnu��0>��5`�GIy�Kc���W�4J����HO�7AC:5B���n�V�QZ&�'� =>����e{"`���NLsi
!U���%q���%��$a���~.I����0����$��������Gi����������$`|����Jz�^l(c$�4JGIUn(���qGIW��L�bp�t����q��/��(���d�F���0>���\,���V:�j���i�T���g����8�c�`��Nn�X���_v���;�o�V�d.-;������������N�� =k
*��YLN������Z��������(�1s��,,������D�	nn�����{���kV����]���:U��fZ�V���V�[z�d���{Kk���0J\�+�[Z+�-����j�$���V�[z���d��xoi���!1%'+�[Z+�--l7rV���V�[��%.����Zqo)Bz�X���V���V�[���S{�
�	y"�:��GH����NDB�'@
���4:�s����AHKkH�&�Q
��>L������� ���������H�q��Q3X������,=J����#���k�D�o�:�@>������l2� ���jI��-���L�������.����L/��0p�$�|��k��MTq��5��L�/�4&���&�@>���U�^����x�����{�n�[2N�#�Z��R�t� I�_�i�K��G0=�����{K����qz}�;�-�#��X��q�K��!�|S�T|�M����L���4w�8����LO$��8�{:N�#�]��U�������G��G�����[�t� �������&�������JW���
���sAC�&S����k���4����:��w���������D�@z|��!�iM����H���w �95y#� =�������e���G3^9��W�qo������%�����
�\���&�Z�(j]�����H������kuC���{�R/<�zz��+?�wH����sM�	�;+&��\lTfJ��D�@z<;���2"�1�Lo����{6������HOd'���@�F�@z4;���@p�1b|�����p������?Bj�z6�(��Z�ulB��(��;Mw!�Z��V�FH�~qB���r��)���HqB��{6=���zz� m�����.��~4�mFH�������Hu��z�|�N�2��K���
��e6�)1>�����\�mzP1VA�Ito�������K��\f����/�'��A�@\��S_`��FH�r�2]�[�}H�R����_�������:1</x���0���+{?Bz|���7H �
���h�G�/�����T���$_��g�<O�������x2�IM���:�}�_��;)����c
$���qQp�#b|R�Q:��S��=4���e����@j>��
�����Q���	,�qc
��Kh���$B���n����h��	��������hYv%WWN�GHO��� �(��K�s
�.$
�W������;��
r@W[^����w �9�1>������v� ����x��!j�n����.
i��N������H��F�@z�:�=HjI3����u��Z��0��@>���b�jx�A>���j��=�
A>��Q�YY�a��l�x#�G0=��������(�|Sk?~��qx������������
O~�dR�������v�Tx�X�^]��^7H0JG�
O ��\�B"��Q���n��s���H�����zH��j�	�s>����\����O��B�(���^���<&�z^����{}�d�-h4$����/.B�1���4���K ��Pt���G���:7Hi��?m�tg�x�f=	��j����}��t$Q{���������jO���� ��
�	�d���<1�klI1>��Q��J�-�tmK�Y�<��7H@�mI$��K�D'�z�wicM$���Z�����~�����io�w�U��s����i^7�d����)[�^�1�,���Z���J����_��!�@Yy��^�4�����X�7
7H0��*H<�R�&��"� 5���5�"�*H<�Rk'��l���y
�0�xLO��g�t�������+�� �����	������������Q��\k�R�X�����'�K��Z�i�f�/�����g_��d�PLeO�!�~�|�������H��8�C�w�"� =����Y��%�z1>��c�A����I�u"� 5OtO�Z^������#�*H�>l�,�X�Tky-�=l�����s�P"� =��s�,P�(b|���QZ��T���G�U���q�}1>���0/�>�7��~E�@j�.�M��I��������T�s�l3���6������'�3�:#���D/��y�>��� ���#�',/z]�wX�� 5���C��r��ON�����'�tT''����|g�����H����0��z.����B���z]��2$U]3�9��HRJ��T;Yy��6E����si����Z�Kv��c��~���.�n�D�@zt.-�$mS3'b|R���N��1>����`yE�@j>���R�(=wjy���OES�����{w��e���'�7��x�1>������&b|��w�]n"�*H<�7H�}1>��()����S��T���#� =|G����� U�B^xR�)�T��<�7H�M1�?iR���0� �!��)"$��7H;@��m�7H����C�$b�8"4����A����pN"q<����K�Y�T���e��k��+b�%��7H U~EH\��*R��|���� �u�_7H\�[+�Tw�u����hHt��=n���8�"��f�j�Z��Bl�XIqb#�
����
����B��05u�A�|i�tt���a��U��/�a�TY���./��%Ww
��k��1_��N���o�C:0_����Lg����/u����8��Re��$.�N��|m���Mq�Kgm���v��^��6_R<��)�)"�*H<�{��wL�X���\��&)Re���(�|q7H@������6�3B�;�m(<��
�������{o�ZR]���(=�.	�B��&�����������?~��/����������_��_�P��w�?��?��/�����B����?_~��?����~��/�����|w�B
q����_~x�c������������_n���������/�{�����?���o�������w��7?����_o�����������������o���O��_���?~�����m��&v��?�(.i��5������W���w���������������F�{��	e���'3�{5�{����_�j����2��������������s�������_��/������?]�Bf����e�"����`?�X���c����/���b /������6I>���/�����E����(�k���?#
��(���k��������D�B�!���������~���!�����Z]����wD�(�C/T���]$�O�~_��^���_}��W������!����C"\�v\�W�_����&����_����m5����lY�����qyq����_����?����bw[����_^��|�����^�����E��������������!��n����Y���qB���;�`c�"�����R/"c����O��m�����M����~���, 
����n����u�~�����~��7�_���|u�+���_}����������
��������m���6����RM#�g�����T��c���P0"��~���������_�������������.
�
���w��X�OE����w�������_���/~���T�����m��]�:@z,SnEn_�On+�5��3�KX�;�����FQ��������Fy�K�����t�hn�$�iB������]�"2 m�$����[L@j�J�B1�����DZ|�@���<0w�$�?w`j��I��_����_��w�������O�6���X�!���A�/�P
9�}�MGU"��\��UuwT��B�������Qm�I�FU�(
r���T;z3�.����Fs��
��ef)l���?�f�q��	���E�J�jz
�
�E{aV
d�#B[=�iaav���
�f��1��cv�dq)gKgf�	�]0=�����

-��0��cv��R��D�b����6f����s��q�j8q���Wt����;0��S�8�5�m�1k�1kV@hDq�Lgf
88�g�����������
���#�X���g�z
�����Y1��vCAk��VTxDm�������jiJ���v�JZ������CM��5�he�U�CQ�������P�����(<x
�����v���,k{��e����b�����	���u�������������@7�@e{����mG(m�����&{��GV���~�Gm���V�6�<�[_����A.�ah����N��gY�����Ph��B.
�3+p�8W�L�_Y�������h�H�5l�V����q��3B�������L|��~���e�[F�@=�[)"nu�Y���e�O�� W���^/[�3��J��7:�SfVH��8rgpE�+���)3�x���2�~.�}"� W�-j��a���SF9����'�vv���h?r�E���h�q���Bs�����Y�5�T��B����J�8������h��=Lc!wc4�}�z��Cc4�gP
27`.�_g��h�������&�2Wge�gP�2W�e��lP�2��en��\cP�����
*�:��u��mPY����sIp�Z��6�sTu�%tno�jC�k�:�{������:w�C��������r�s7B�v>2u����y�C�P����-?�f"wG������`G��gu�<���Q��e�;�v�v��{Y��>78P��Y�;4���GY���
�e�A���[�G�{de�<���(s}Y���
*�2�2�7��r}V����U�/����?u��=�*��-s��=�"wgO�	E�Y�sg{�BA����x^m'��v�j�y�;e�!�5n���B!�e�����
�����q���Js������RV�%.	��\	�^�q\��)+B$$ngs�B���	p�� q������)=�#���u6����e����UG.�q�8s�BG���P\��9eh\�������"�+���)���R����9e��v)k\�G.+r�8w��3B,�\����+����	w���Tn@{%w�;e�@�e��:�SV���e��[	iT�:�r�8w�jT���rUgw�T���Q�U���\5��2�rMY�����E�k�����k�E�k�*W
��,�\[V���=�������-�6T�[V������*w+��r+.rQ�n���-���-�r�SU�#Tno���ue�K�� wG���*w�?����	�����Q����I��Q��Y�����{Y�.���E�Q���E����@{���=�"w�mOy��,r�L��\�*�gU�2����r}Y�.���U�/�����(s���]�S'���,s����6��q�e.��1��M�g�Wr��S�t �r���?�	�3�'��8��g�Wr�T�p�\h�lPm����	
�A�T8r�g�AgPmJR�r;T��=#��<d��=[�+���m�����e�lPm3X����Fh��-���q��M�7�{�����X��*��$����q��
��T�2#D��mg�j�n���8���-���h�&?���V��R���mk4��L�\���^��Pm���6.��M�Hn�e�/[��Wr�9T���bY�����2���s�l��\���^��Pmu.��e��P����s�/���%���;����s�~.ko�����e�K>b� [��Wr:T�\�������P�ne�������\�+�*�:�h���v��\G4�|��a/���J�@�jG�KttY{;T;����s�l���u�����u�N�����:�(�����6���^��P�s��.ko����=�:�|�A.�s	h/����G�K4u���u�/���{.�s	h��t�N��DS���:Q��e��{�u��3�s�8��M�s���*7��
h?��NH�����*'@��r;;TN��
h?���NN8rY���9TN��
��vv����>�����q��:W�s��<#�����*7��
h�pX8��A��Wr�9TN	�X����C�����	���\:7���;��r�D�D����[f$��sI����tn@{%w�C��!:��C�V����+����J�8���!:��C�V����Z��eu��P9�:W�u���P9�:W�u.��p�kP����5�*gP����5�*gP����%r-�\���f�CeQ����5�*�:��u.�����:�fu��Pm�smY�����:w+�\�a� wC��eu��P9��[Y����C���:�tX8�u�s]V����C���:��v�v����sI����u����f�C�����:��v���{Y�����#�s�@��@�{�u���P�sB��v�<��#�s:Tu�'tno�����e�Kf{���s}^�t�N��'�s{;T'����s�l���[��r�8�j��:�N4v���}�=#�}"�c!����=#�8�j
!5o;;T��=#�}"�� ���Wr�9T���\
�vv�v	{F@�D��A.6u	h���s��yB������C�����Od{�bS���J�8�j�=B,����]�H���8���.���q��v�X.zk;;T��h@�yT����K@{%w�C�/B,����}o4�-��[
aS���J�8�j_�<�N�v���}o4�-��[
aS���J�8�j��s��.��]���e���9��]]�+�������z�tv�v�:��u.Y���\l��^��@����%�����,*]Kt`�mc`c��6C�@�jC�K�w��L��Zw#z0�62��K@��w�M���%:���v������6����.m���F�C�K�x��L��z��z;U��%���;���Q�R]^��^���w'Z1��z��K@��w�Yu��%���v��@�{�z���%���;���(z�V/7�����z}Y���~vy	h3�4�N��D�������{����+���f�gY�^����:{V��7�}&�c���@��~��V��#%|;�V���>��q�+@��W~�8��1��lK���������S?~%H�7��8���;b$���l\3H��������o���w�su�b$�/����_���3��j����_1��:����og��P ~�g�?~�c�W�b�wu,�~�����c��>����{�����g^�B���%&�+���������o���w�{uh�	�+:�W�F��	�Kf�j��:��8��0�5�Eg��0�
�{w�;�_S���+���P���eQ������kQ����h_Y��������
��%N~{���-�~�@�jC���W�v�6T��~{�.���W�r�{�P�:B�����C���K�~���~]^�������w'����^��~���]z������r�yu���	�+{�W���,~�'Wj�#�}�@����=�+{{W��'^�������y�+ZW'J_OH_���:Q������������+_9��:Q�������+?��q'�d������0n��q���<b,W������#�}&������~�9W^���\T�
~W~%l�3��� &���;���rC����7�����#�}&���{��W~�q������'Z����w�g0N�<����=v�	h3������j��hs��^�i�[����
�}b����+�(�X.�{���|��@o�k;��z�9W~���\H��3�+��n��ogc�c���6C�8���	1�K���v�W��
p�����-&���;����/�4��3���.K����<��	h3��s��A�K����L�E�k���wm:�c�O������2r�����/�;F����a����}{����6&��|���m�oC�K����� wC����o�����rJ���C�K����� ���ue�������1�����������%z�Rxp�����������mc��%�m��@�K����� �@�{���U+�mc����m����%z�2+� �������m6c����B�C'����.�;F�9�'�]O���V3��	h/�>t��x�P��c��0�{N(vOB�v6��	�n@{!��3����!BB��9��s�����)f���C'�m�O��
�K�v��NB7��<6�S
��	�8����t���=�S��
p?�]��']��w�Iu�
!RR��Iu� u��d��A���#�q�*�)����:h��3�wh�����8��\&�H�]r9�]@���������n@{ew�Ou.!j�|����*��������\A��Wv�U��#DB��o�9�� w����]�rW�/5�s�N�zWzw��T���&�n�{7�A���zw�Uu�����Ko����5e�����iQ�����UY�����Ko�����e�K.,,����Y��X%���������]z{U����w�����
��������h;~��F�]�	���+�]����������h������no�jG����.��p������z��"����N���^��zw/����m���������h<~�wB����*�z�(����mN�z�g��c%4��]O����W�Q�zB��>E8Q���=��^��z�$�.������Y������]7a������0��1-o1����U����F�[`��W�&h�^��U� .������n`6`W��Zv��}��q�p�����$g�HTZ�zU7t�������m���0t����d�W��Y D�k������[����i�W��l0t3����a^�
�����k_��MJ!���3����D�Wz��U7DB$���}�*7-�U��3����D�Wz��U7D!c��n���	�]��f�A/���p����n�,B$���v�
�z�rIKr��`:�D�Wv��U7�(y�v1��]u��W����lP����}�lF��3(y�f1��]u�������lP������U%/�*F��v�E�k�F���(ym^���6��D��{�UJ����Soz7��[^���6��T����r�y���%�vJ^���j�_�P�R}bto�jG������
8��Q��Y���U;*^�K� /�s�{�������
8�=P�Y���U
^�I� t�����(^�[�z�GV���n�G�K����[�Q����%s>vO�>+x�@��D�K��y{�����Y�d���.
�3+x�8�JL(x�1d�'v��7�-�����
�����8�J�	�K�w�`W��
p?�w�7,�w�+���*!N�H�]���R!����l4	z7���;���@���5��*1��
p�v6��z7���;���C���5��*�@����
���P�w���8�J(�	�k:{UB��
p�vVDb�8tY������z7`.��������n���
�.�w�q^�XA��%v;{Ub����|� V�C����8�J�!Rz��W%4�]]����������Y������A��	�k;{U���5e��=�2�wMV�.�*�z�z����,�]C�i&s>z-
^���@�����������
�-��9��zw���e�W�����k{{U��V����C���rw�U�P�:B���V�C�������Q����hU�(wwB���V��rw/�]!z;���=�w��^��z� ����U�w������������
�u�Y�Q���%o�p��Q�z�Fs������Y��t�NT��R�����I\i���xO��gV����%�II��v��p�8��������&���;��������$���];G�[��� ABW�����8�J�!�K���]%%ln)��M/���p������t�\+W��uX���#�-����HB_��J�8�J� �a�����3x�nam��.���h���s����h#����T`��v;J��^��X�e�Ds�[Z�������n�c@	}a"��z�a%�!������au���+Q�r�l7Kh�^�gXI-b�Z�$kCq��A��%z{k^��Wg5�gXI���h#��P�������&+z�8�J�DI�������5�vp������Y��:VE/� ���k_zQ�Z��Coz7�6+z�@�jC�Kt����e������g��w��^=��r�z�1�, �A�C��������e���^=���Q�=b��mY�({w�kaoa������w�gu��%��H���:P�T�����@�{�u�@����%��H�����{=�{�J��z��>�{�@����%��H���:Q�zB����9�=Q��Y�k�V'�^�O�$�3�;O�{���%��2�;O {�+��L�yr����M�y�������B��eU��Y�To�\b��g5P�nai�L��8rY�k�9V��0����Y��
p�:�;O8rY�k��U��7`.�����gP��gB�����]3�����	�+;�U���~�gj7���;����	�+;{U�j7����|Cc^@��Wr�9U�r"DB���N���HnY���rWP����q>���P���O5kP�n��Igr�(uuV��q>��Q�jB���>��Q�����|�0T�:�t�8�j6�t
�t��X�T������\�J�d��hRYT��R��M*�J���dN�A��Z�f���Rm�u7J��v�6��q����������j������P�so����u��n�N��C���z�t�v�����so�jG��S�����A���w�*^;���Q�����{{U*��8�%'�j�#�y�@��@�{�w��Vy��u��w��Q�����Wy�����so�������������D����w�cu��=	�;�v�NT�'q�������0��^1�����-�%F��-+5���>�p��b���\+%���"��Hr��W���>���{�����g\)�c���$W@~%��gR(Ea��7��8�J�1�K�J��,�3���3�8��>1n��q��Rb,W�������4�}��)&���;��R�#�r]I���w���r�K��+&���;��R���%t��l^����t�b��7��8�J�b,�����{�V�N�g�q���b����+�Q�]c��l_)��W��D��/v�	p3�����A�K�������_C�_��M^�����E�Kt��d�s~-�_K�2���w��������|�m��~~��C�k������_���k��������!6-?[��6������w?������//��O�����o��������W�?6�(��Q��1q���#*�K�O�!����P	o�"�U�a�u�����!F���>2�����!:��n�[��q���������U�������{l�U�^�>���#6�<�.
d"�=6�x����C����P�����b�u�����!FT��.2�����:l ����g��
��K���nOw
1���4���]vw
�a�����w�{��t������#��K�O�e�����|u����L
G.{qH���b�@��ew���w�CF�&$�\A����#����.����@�������	G.�weOW
1��
�K���j��n��G�^��y�������e�#�w�b����w�<:���
�n�aw�W�(�)����Z��w�#d�z7���;��Z��)����Z��%��ufw��f��U-��	��v����n�[���/�!8�m��qf��:�H^�%(� x�����E+�������E�����%�qs��Q�j��Lg�j1(yu^��qv�bP�B��������5�o�����5�;����y-�y�*��Z������^�� zV�^K�^�J7�����|���
U��W��@��������v��^G������^����@����u��]{[V;�^Gu��L���w���y�g����)����:P�����m8�{�����V������M�u�A�����G�{�u�<����{=�{uo��������m9��{}^��]�u�I�^���:Q��D��{���c���\�u�2������vv�V��������8t�s�����2r����
�0�72��q�b����3��@f�4�	���+%"$
D�����d������
d�K�p�o�������i�b���Yu>�]���zi ��
$�#B�4��lY��A&�-��|��b���@&\�G��!QBw6�V� ��u>�]���zi n��#w�!QBw��V� ��u>�]���zi .��#w��������v6�V� ��*nu&���2�^�8r5��K�O���V���c��C��������	����kP�^��|Jng�j��1�gbTa����>&����E�{�"�)��}*l �~&>��Y/�c���q�n�t/Md>e��G��c������1��}L�}3�]���2�������1�gbRa����=&!�c�������t�z�T�=&�-���Ra����<&�	���b��A�Sv{�T�<&�-���mSa����;&^	���j��@�Sv{�T�;&�-������1��uL�4�]�r��?�Sv{U�:&�-������1��sL�4�����}����v��sL�[`�����c�K��xh�zB�{��i���������ngRO�w�+���*-&�H�]�����n�[`��"��n@{����U��m��|o�<B�I�������w������77d�������o���~<R���~���
���]������O����C��O�����6�_�:X<i��`���o~����K������?�g�����b3�|~���\�H�/�D�>��������<��<�Gx�����U�C���z-��.���.<���6k���V��x�=nG0`�O<"y��o��B����������x�=�\;#���H>!� ���o�	�b@{%w���7��#�����
��r;�)�
����J�8�So'B,���r�Br���b@{%w�������"y������r;)�����J�8�S����m����-�*b�ypd�[r0�+���O}��<��4��gcpP#��L�e/q��F4������;`~�+��a�o���{���X#:���=Q���]��}�C�{�u.�
��\��gV�>V�����	���j(��\3��������f�=#���;��2bF�T����
�3��������g�Wr�9TF
�HP�L��=#��<����=#���;��2�D�D�����g$�\=��E3�7�^��P��@�D����Q����=���<��
h���s��r�(����2
����3I��#����X�������������.���r;��3�����M��9Tf�R�wW9�]�
h?���	G.[5i�P
:7`~��*�u�&tn��J���y�;��2u�.�\�n#�u�)�\��)�u���\5����sMY���*�:��u.����\�:�fu��PY����sIo���
u�%���&wC��eu��Pm�s���%�yr����s�F��:��.�s�@����ue�K��,���u���|Xov��.�s�@�jG��:��C����	�����9P��Y��:T�������u�A����z��GV����G���:��o9���s=�s;��0u���\5��:Q����%�[rO��gY����hN��g^��s���:�,�\��e �N�s���~�����J�8��N'B,�\2!� W�HnY������^�]�9TV��s���r;�_����V=�|��?y��Y�}��`^6ej�����$L����Ng[<�l�-l^��x���8Co�'B,��!S<��n�@y�����m��&���;����!�_��)��w@�yz���7���q���B,��Q�
�m��~�o�^��Wr�z�nb��
�����;�-������#�}}��3���w��D��A��;�-�������#�}}��3�6�;`~����w@[����������Y�z�9#���2!� ����u~���Pe"���;��s�K0`~"!e �M���Dp�l��	tn@{%w�����`��DB�A�PH.�s;zN��
h/���=�M�'Rr%�\G�\;�'ttn@{%w�C���`��DB�A�:��{��n��^��P9,m0?����:�����J��eu�:��r�D0`~��� W��uD���{�2��eu�:��r�D0`~��� w�����������eu�:��r�D0`~��� w�����k�S!���
h���s�6���88���s���k�S!�Q����]�9T��O|���D������3�sM^�t���`�����A�E�K�\;�
9�:��u�@�
{�O|�n�s���k�S!�����:Wt���`�����B.�\�y���T�9��[V���v���88�u�s���ko�jG���:Wt���`�����A��:�h��v�v��{V�������88�=P������:���\=�������u.�8P�v�<�\���z�C���'>rO��D�@���:Q��Y��:T�<0`~��` w�p� ����-7Ig^@{%w�C�OB,��!?r�m\g�j�g�Wr�9T�p�\e��8X��=#�-���P�R��e�L�q�.��D�����A��=#�-���P�����V�0��}�*��3x�m\g�jW�\����P�
�L�O|�*�F�����<�\����P����U&�����������C�/���Wr�9T�*b���qp���7��uv������J�8�j_O�X�2A~���-W�0��[)�Wr�9T�F�{��\�qp�kP����5�����5Y�k�9T�A�k�:��8X�E�k�:��v�,�\���f�CeQ����%?r-�\[����C����y�;���P�ne�K~�n�s���5�*�:w�����C���:��88�u�s]Y����C���:�t�v����s�����u�^����C�����:�t���{Y�������sMo��@�{du��P�s���%?r=������*�:�gu��Py����s�����u�'tno��D�{fu��P��sOB��v�N��gY����1��=�:��s��	tn�����@�1��
h�vv�!q��:��s�:7`~��� W��
h�:;T��p��:��s�	:7`~��� W��
h�:;T��8ry�;��:�!�u.�qp�;��
h�:;T�:7���;��:�@�e�K~�*��m\g��P�s��bgQ�D�e�K~�.3�[���Eu, t���<�c9cY����+(�����Gu��t���L�cu��,u����]��m\g���
G.+u�4��:4j]]�������F��	����:j]���bgS��!�ng��0(vMY�
j�X���vMV��i�QeQ�ZB��6�,�][�����7��wmV��i�U����e�K �n�x����%0���P�nY�+��n�C���5/��p��P������0��u�z]A�4��^WV���������e�-������w/�������w/�^����@�����-��������+_1��:P�e�K!,���=�����t����=��W��<j__������G�������t��D����Wt�NT�gY��_�'�������+�M_����+?A�JO�~��~��G�[B������%���;���B!�r� ���W����������/n��q���1�+�_�v���og��c��7��8���b,���~g0O������0n��q���=b,����~����kX�����b�7��8���1�K��_���n	]g��c�7��8��/b,W���~�=
pK�:�W;��W~�8���P��
a�/�����������L���w��5�_�'��p��Q�jB������~0n��q��7���0����A�k(������0n�����E�Kt���~-�_K����v�	p3���6��Ds���wC���W����1L���w����%���_���F�_�����0n�����C�K����~w���������a�����/�%��BX�E���W����CL���w�u��%��_���������Mb���+����C!�z��������}b�+��@��D�K����~O��'�eo�
[��~��W�����C!��������uN������SL������������u��N�7���;��:�G���%�~���R���uJ��n��q��)w�H�����9��
p�����9��
p3�����yC�����_�3����og��T3�]^�����[>
��/��_�7�-���_����C��/_���H�#�Mq	p?��pP��pK�:[X�r��e%�C	t[vW�	L~"�� �������p/�>�>�eWKDH�_���`W������;�W�F��������-���&�/�up�kP�B��������5Y��P���]����������E�k�;���,J_���%�m��(|-!|�����
����oo�jC��e��C��m��P�n��%�vQ�n���m[9��[V�>t���]���Q���i�P�:B��������e}:�m���zw��no�jG��zW���v��{�������(xwB����
�����cu��=
/~���Q���%�z=*^O(^�����x}���8zO��������A����$$��mW�(y��y�@zQ����%�������[�Ih^�����K���J�0����#D���}p�+��#�-��kX��i;�[G6���!�"Qn��>8���+�R���cuC���I�:�a��
���j����B�z%Q	S����	�D�Wz�yV7� �e�����yzg����Y����p��3�nW�H4���z��*�������9q��0
���V��(�H��%�z�.D���kus��-���[�\�}Z%B$*�����
��D���ku�`�V�L��\�}�B$
����Z���B,}]���:�{����^��D�����������]��V7t�{MV�>Vd�-�u/�e��>8���{
�{����E�k����m���{�.3���B/�^K����k����Y��X����n�{�&3���A���w#t����r�{���}��F[z�^���}p��P�:J��v��^�����hK����j1C~���{wJ��v�v��{^�t���T������@�{�w��Z�{����Zy��T������������N�G���������E�K��!���u�'t����<Q��Y��Xq�����{��2�2�+&��'�{�����@��Wz��Vb�"�{�d�to�[B���b������Jk��W��
��@z������))�������*k��W��
��@z%������))��c�����hK��"�{���w����u6%��7���;��J"DB���A�������eW5eW��
h���3��2!DB���M+���
pKWI:����
h�������"�z;{V�D��n9wfw��^�gY�uG����lY	
�7�-j����yuV��q����y5�yug�Jh�������A����W�s��A�k��{;V5��4o��@aQ����U+����W�v�,j^Ki��������Y��:Vj^Kh^����P�n��%�z7��[V�����C���W�v�j^Gh^r������uY��:V;�^G�^����Q����%�zwT�{V�������w'T���X�zwB��[���#+{�@��@�{�W���<��������A�G����w�g�Q�zJ����<�^O�^r����D����w�iu��=)����:Q����%�z��[�����8�JNi����0���k%'�:�g�z��L�{�w�k%��62��k%l�3[����@�8�J�!e�Lg�JJ�:�g�z�L�{�w�k%g��Z���k%g�L�g�z�}L�{�w�k%�!�tMg�J*���.����^��^��ZIu D�����Z�,������^��^��Z��!D�����Z�bz��%�up��c"�+��\+�Z�H��5�]+��e�>�up��c"�+��\+�Q�R
dLg�Jj��������A�A����w�k%
�^�����ZI������:X�E�k��w�ZY��T�����{-�{����^���fu�:���P�R=dlo�jC��Q���k������w�Zm�{�&2��k�P�n����Z9��.�{����C�Ku���]�u�#t/�up�������w�Z��{�62��ku���	�Kn��{���]�V�^�����Z�{B��[�u�����@�����������G��	�K�-���{}V��]�u/�F��v�N��'�{����^��g^��s��	u/�F�vv��	to�����@�<��
p���s�f!"�{;�V���>��p�+@��z�8�j'B,�^I�c�W*�������A���^��Z��@�e�+����<��
p�Y[8��A��Wz��V��bY����k5+���3k�
to�{�w�k5+���WN�]�Y��
p�Y[8�]$�]V��q�����
�K�������3k���c���z�k5��{��vv��to�����B�����^=�������WN�]�Y���e�K�-�j��:�{�8�j6�{uY����k5����{����^����u�@����5����ZY����{����^����u�@���������Zm�{mY��k���-�{�@�jC���W�v�������]+���eu��Z9�������k�P�:J��v�v��.�{�@�jG���W�v�v��;�{�����u����f�ku��=�K�����@�{��\[X�E�{du��Zy���{����z��������A�G�����t�N�����d�UzO��'�{+ju���D�{fu��Z��{OB������p�8	�[Q��)�
;��Wz��Vj:b����]+%`�p�Y[8��2���q��B,����k�$l�3k��A&���;��R�!�rI]):�VJ���>��p��d��v�k�f({��62Rvv���i�����A/v�	p���s������h##eg�J)�L�g�z��L�{�w�k�({��>2Rvv���i�����B���C�4�;��R���%u���Z�,������^l"�^��Z)-b�����]+�A����-�b��J�8�Ji��D+);�V������%�z��L�{�w�k��^�����]+�����\[8��.2������E�K�����keQ�ZB��k��E&���;���P��d���Zm�{7B��k��E&���;��r�{�V2R�v��^G�^rm�����z�4���Q��d�����Q�����m[a�7��@��@�K4��so��@�{P��7��G&���;���(}�n2r�m\y������}Il$�f��\y��D;9�v�N���������/v�	p3���N�D?9w���	��I�_r�`�w�@��~�yW��#�~����2��
p��=8�
�.�~�4��Z���4����E��
p��=8���.+�4��Z$���4����E��
p��=8��'���g_-3���4����e��>�{���q�
�w���1R����(��n]gv������^-�@���U���e��>��p����
p3��s���D���U���e��_J�vv7��o���w�{��b$����^-�o�������F����W�s���W�Wuv���W��\]8�5�~u^��q��bP�B�����A�k�K�.�ZT�&�~�@�������U��+�����\]8��P������
��F�_����P�n����<��������W4�������y�P�:���3���+��������Q���w����)������^�����N�������w'�/�upl���#/~�@��@�{�w�m^y�%~{�����_9���(~=!~����G��	�K�>~O�>/~�@��D�{�w�m^�(~OB���������~��W�h�q%�����y�N�{���>~��L���w�y�
(���e����Z��3�����w���8�j�
1������*a�p�o�bk�7��8�j�%b$
�.���u�4��L��{��~��W��#Qiw��^�
���3��Wl.�f�g_��#F������Z��%*av����L���w��.;b$j�.���u�4��\�gl/�^����W��!F������ZWpO�g���_&���;��Z5�_������Z5�_M���W�Wl0�f��_��/�ff��_���!�/��X�E�k��w�_Y��T����eQ�ZB�����_l1�f��_m��F3ko�jC����To�b��7��@�����:����+�����oE�����+��	h3����_�������Q�:J���'��L��)����_F��X�DT�T�����u���
��$p�/����/����-��_������:P���%7�����vJ����Q�R�f����G�������s�O���r����{�������������o��#�1�^�}(on���P�R}ftg�JO�{����FM?]=��
h/�>�5�%WHDH�^����Do���%���j�7������o[v��	��;[VZ��
p?��(Z��
h/�>t���\�	��;�Uz��\B������7�����io[v�ZWwv����~o����f���cWm����Y����'���]f��Y�8�J/�v����*���
p�9���w8v�����]A��%z;[Uz��>sN�B��cW8�G�V����*�Q�jB�v~�5
^�?�gVi��W��t6��A�k(��{�5�xM��w�[eQ�B���n�E�k	�{����E�k����*��������6����y����n(y����v���w#4��mW9���y{j����E�@����u��5�
+���Q���:���uy�;���Q����5��E�^������j�=�y�����5�Ah^���:P�e�[Q��1�(y���}��F[v=J������a�Q���������]���g%�c�5��{�������W�(y�����������U����h���$��x;�Uf�}#��<4��n2���qv�B$�
��v��o�v;�Z7�K&���;��2�#D�����V)��r���z�m��N2��]�J�o���{��#��6����_�������������������������?�x������������������?|���^�{������?Q9��	|:Xu��R=��~�k��0[�����o;�xO!��\�|�`_���:��ywf�
��h�!������y
h��*4&���C�)�n��]B,'��cp�;�r;_#4��#���;��3Z"�reR��!���&*��6�
��p��n��v��~ �r���8�5(Q/���n�G�{ew�og��%�p��]���������b/����8��X�TC����-�
.Z�����`;q�Wv�v���l���.\�h�y���.6�p����T�7�v��`���uD���7�
��p����vT��6��`wG�������,�����r��R"m�@�K������r� ���o�8��&����N�G�Ku���Ty������ckv�G�{ew�Uu����p���N��'�w����b����@��D�Ku���U�	��I���+��@���2"��*;������*+@���<��`W��
p�������"�w;{UV��
h�yn����q��zW�����0�O;{UV��
h�yn���,p��zW����z7`.�����3�����w,��8tY���yUV)�X����xv��������*�����q^�]$B,�]�n<���������.�w�+���*�N��w����{[__�����z7���'^{�}z���P��8�d�O|��I�2H�6�q8.�~�"w_�SW���M�<�\��q�����'�0�u�O47����������Y�{ew����M�������3�K��S������ ��+����
���O�%�`W����$��k���j�g���e����U�����,�����$���?m�5
�.��{��mxU.`~��<�^hn�%����m���.��{��mxU.`~��<�^hn�%���n>�����6�*0?q���
jm�%9Q���1���v�y{^���v��6�x#.���v�]����8oo��rs��������%.����tm��Q��Y�����6�*0��|m;P��������#�w��^^������<�]����h���]�z����@�
���v{{U�.qI���FWvO��>�wzUxU.`.����:Q���DE+���:,W�^�]�yU��9�f���U�	��#.����
���b�����8���U9G��!�v�]G\���3;,W�^��U9�*���5��������Kr��*��j�+���*�W�����O�v���z���DE������w�+���*�W�����*�fd���K��]�@��Wv�yU���v;{Un���Kr���`[v��R�{ew�W����#J,����]����$�_au����8����wQci��U��n@[r"{�X^)���;��r�.Qd���j�������W
p������A�KYZ:{U���5����w��]��&�w�@����%�,����]�z�z��FP[v��R�{ew�W���%�,���9��P�n�������],��^��Um�w�"K���`�����[Q��-�X^)���;��r�w�"Kdlvw����wmo3�+�WrZU;�]��Y@��\��;!w+
Q�e�+�WvZU�]���A�����A���3VW
p����<�]��)98��(w=!w+
Q�e�+�WvZU'�]����r�{��=����VVW
p������I���.Y0���}�m#�-}���3�����qV�.$B,7*#Fs�+`�h?���]���^�5���]N����,)����m#�-}����]���^�gU��#�rkn���`w���rg��rw��%
h���s��yG����dEar��m��5����%
p���s�v�!�rcn��caL���39����.�������
h�v;[U�&i@[b����W�C���m�YU�
������}�4��L��}=q��}��8�j�
!��r�5g9��(w5%w{������]3���
�]]�������A�k����|�X��rw�UeQ����%k�r�kQ�ZJ�v�U�[��6/wZU��-�]���`wC�k�r�������z���6���w{[U��F�����m�u�w]V���V�C������r�w�w��;�]���v�W�����z����v��;�wIt��w��������Q��������z� �nw'�@�{d���Uy��GY���^�G��	�K��`����Y�kzU'�]_����Wu��=	�K��`�D�{f���U����w�.������ng���@��Wv�yU��bY���^�!fd���$:v�����8��;B,�]���:$�����ng����w�+����Cn��wMg����w�����c�q��zWL���c�@��lV3���Dog��P�.+x�4��:(��@og��P�x�����C�8tY�+�qv��(�X����]u, y��$:z��n��q~��J�X����_u��y�����c��f�gXzB�e�k;V�F��	�K���W���Y�+�q���Q����%�
s�kP�jB����|T�&�z�4��2({MY�����E�k�K�������Y�+����E�k������,�^K�^��^[��M�
u�V����i�����K�������
�w�k�P������]+�����D�B/�^���b�k���u����Z��{wJ��v�v��{^�������w'too��@�{�u������u����b�k�Q�e�+(t,�z��,|��[�z�>/|�@�����e�+�����������z+����W�b�ou��=��W�_�~���,K_9u�F���~�W~�#QF��B8��{�%~;�#�
b����+/6�H�:[W^������l]yl�f�g]y	�-=�)�\9���{�����Mb����+?C�KO��!W@~g0N��e}�61n��q��W
1�s����W���%~;�W��W~�8��/1�b����_�:
pK�v��<��	p3�����:!F�������+x�n�����<6�	p3������#QD�t9���-W���g��^��f�g_y���j#:�W�������m?{��f�g_y���j#z�W��)����G;��~�W�/�8F���,�_K�_��3&���;���P�R�cDo�jC����D��/��-/�@�����������C���K������~�W;�_�}������N�_��:&���;��:P�RdH������ �o�>j�/6�	p������/�CF���<���,%���_l�f�h_y��T���:Q�zB������~�W'�_��9�,���=��_��Y�9��=��w�_�f\�1�.����:'��n�����N!p���w�_��o]���u
��n�����)N������W�T�����r�+A��%~;����f��_��D���%G����o�[����q���O������2���K�AT�$$09�+��n�����@��O���1��?v��Xv68�p�{a����-���	�K��+����ng{�\A��vJ����n������s��~.���q�������-�����og���(}5u����5(}uV�>�8�e���5���;W�A�k(���^�iP����}���-�e�!d�����({-u���]���fe�C��m��P�ZB���M�
E�F�^r�q����������e�����;����]G���GF�C���G���6��#�����Q�:B�������^x�;���N(���[u���	��z�*��p�y�J����so��@�{��\[8��(y��y�8z=j^Oh���_�Q�zB������F9O��>�;��:Q������W��yOB�v~kt�(y��Y�0��������}���t��p?voX�}#���;��:&1#D�����W��`W�+`J2�k�����0v����q�R D����kX���@�,W��d��A/t��p��s�n�N�H��U}�c��[��)����^�*�^�fY������ZV��$�;�+`J2�����D��+�,�"�����e����U�
����8���2���a��
�E�D�]�b���K��$?z��L�{�w�eu��"�[F���n`v�w-�����BW��J�0��q�To�����A�������Y�E������m�5�{��2��guC����u/��s�kP����}��F[z-�^����mZY����{����^���fu�c�5�����-��v�6����{�����
u�����U�hK�����-��v�����{����^����u�@����u��]z�V;�^G�^2���wG���u�@�jG�K��Yz�V;������]�u�������hK�����-#������� t/�p��Q�Y��Xe���z��Dk��v�<�^O�����{}V�>VX�-�'�^���Xz�V'������uQ���e�������h���P�}e��������8�eWL�z�+��<+1��R��=+!�K�����-�Do@{ew�e%��)����Do�[�x�g�m���y�+��+!B$4����3h�����i��A��Wz�9Vb����kg�J��y�g.�r��$�]^��s���0����X	�7��LN��2���5�8��&c�Bh���c%���3G�,�z���U��c���kg�J��y�g�>q����
p���s����kg�Jh��,z���#q�(zuV��q���(z5!z����0(zuY��+�E���^5��2(z
!z����E�k�����	����Y��:VU��Too�jC�k	������P�nY��ZV���R��-�
U�F��v�Bv��w��^5��r�z�zuo����u�I/����U���^5���Q������=�U�^V����fV;��=/zZV������eu��=������������k����G�{�W�v�<j^_�������Q����]V5�'4��mX��y=���D����(z���]V'������a%'�8N���D�@���1���q����X.'$tg�J
�9����f	}c"�+��,+)B,���e%ln]��JB������8�JJ��1Bwv����#�-i���B������8�J� �c��lX���7���U`[v�]LD{ew�_%���1o������,
p�����]�C�^i`w�]%�!�K�
����x���aWIh�^�gW�U �r]a:�Ur�4�-����*h�^�gW��D����t������r���n�m��(xuV����*�Q�=c��lWI��W���
iP����]��U���%z����2�wMY�V�l��E�k�zwhVY��D�a�U�1���s�]��������
����7����o�����O�!8����o���7?|�����������o���_+��������OC���lI��p�c��~�k����8�
������p���1����SD�aa:[{J�6��bdYv��p@{ew������"�
�
mWv%l��x Vq�1�'����q���Gb�(6,LgkO���*�}X����b������8kO�1E��������xF��`��Wv�Y{
��)������=������a�����E��+���=�/�QiX����Zgd�|ONV<�iz���p�{�w������"*
���S|eE<�/t���E���z�������*
��������:�?�Xd8���;��S�FLQ��mgwO����0I>�����Wz��{
��)����|MY����0I��c�E���^=���7b��4l{V�^�y�$_�q��E��+�+|#��J���c�P���$����^,2�^�hY�1ET��e���%��I���Xd8���;���Gb��4L�c��@�K���u*z��p�{�w�i���Uix�mZy���1I������Wz�V�LLQ������G�K����*z��p�{�w�k���QiXN�]�u/�BL�7��]��p�{���s��	t�B��Sg�j�@��%z;��p���s��"�u��Z-to�[�����`���J�8�j�!OP����"A��%z;��\��p�{�w�k��B$:�L�\+#���:����wS�s�v>��������[��,U�Ky�G��a���B���p��~�y��a��a�L*�s���|�����>uv����.?����2��]����D*�;��[��������[&R��d���[v
�Q����8�o1!R�;{|��<���L��}[v-�Q����8�o�;B,?��K�q��ae�O&+�ew�,j�����8�o�6�X~�-�Z,���A�������������������ng�oqpx�>]��-�������7\v���������noo������w��=q��� �;��;B$d���8�=P�'��}o�-���#�w�@w���=�+z�{��/����5��]�z�g��h���w=�wE�+i��z�$J�VD'��3�w�@��D�{Rz��W�N�o�e����M_���H�^@{ew�W�NB$������]�F�[X�;;���m#���;��Z�C������U�����ng'r��m�Wv�yU���8t&kC���F���������������u���s���^�:�O���\�`U]���U�
�C�%v;{U��4�-���s�Uy�l'1�3��eF��Uk���n���|��.���z��U�*#q�Zvv�����@o�s�u�4���;��Z�1W�eg��F�[�	Y���-�%��J^1���V��W�����A�A������$x[z
j^���bgX�E��Doo����5e�[���-�E���^1
t�,�^K�����E�k?�z������Y�+������w#d/y����
e��!���^��w��^1
���^G�^���u�+�^��ov�{]A�4�v������-zw��;�{{�;����{�V������5z���{{�V��#�{�@��@�{�����A�G�{�uoEQ���z��>�{�@�������%/�p�{���e�[Q��-�'��3�{�@��D�{���'�@��P��e��tv���7���;����E���%/C���7�-�����B���u��Zi�7�.�����to�[���k���C���b�k�%���Dog�JK��n�������.�{�8�J�3b$t/y��A��7�-�����3���6C�8�J+�	�K�r��@��z;�VZ��
h3��s��:#�{�#Uz�����k���m��q��^�H�^�H���to��tj��&�^A��Wz�8�J�1��<R��W��
p�N����Q������\+�Q�jB��G�,�������|V��:�{�8�J�������*�u�!to�^����5y�+�Vu�%t/y��A�E�k	�{��lL/�^���r�k��������Zm�{7B�v>���-�{�@�����(����r�{]Y����C����Wt��^G�^�H���u�+�������Q��y�+�V;�����d��A���w/���������(�������� t/��p��Q�D����hmJ�G���w�k�Q�zB��G�,����D����s[zO��>�{�������$t/��q�{��=���=����	w�3�{�q�����e]���ke&�:��k���WL8t�sDz��VF@���Dog���:��#s6�������Z9#F��.y��A���#�-�������s�z��Vf��\FW�G���`��z;��038�m��q���O�X��+I���^5#��J�
p����1
h3��s��:c���$}?z�L���ok����Sp���/��?���v�,��d��0��n����
fU8th��QG�
%/���m+��g���Ut�mK.��	h/�>�8�%W���Z���)�e�.���B�M�{
v�	h/�>�6�%����:���-+cP������E/6�	h/�>�4�%�������
+����**�6�8f�iL�{a����-�*^�q�$E%�*���xu��@�=c����6&�.�7F����\�zw+�]�U*���-c�����%���%��HRPr����ue��{[��1&�����o[rw�D�IjIrQ��e�[����r�aL@�)�2���.�5F�b�����QV���6l�f��c���%��HRpp��Q�����}��`���6s�f�'j]�k�$sRvO��gY�VT[h�.j��p�;�];��%��H2oa`�N v���E��@��Wv��TV�H�]�����n��y��V��
h���3��8"�vug����-�]r�q�+A��Wv�UV�����Qeg��n���uR�r7���;����C������*;��
p�v�xc������qV�U�w����*�@��v;���������q^�]@��%v;{Uv����|���]V�>VD�-�+��������U��n�[`����z���}��F[v��	�k:{UV���e�KN=v5�]������h��A��	�k:{U���5e�KN=v
�]����U�h�.�]C�]�����wMY��S��]�z�f��c4��kQ�ZB���^��z���.9�8��P�nY��X����n�w7B���^��zw+�]r�q��P�n����*�z�z�����]W�����`wG���z���m��Q����5�����N���'��M�.�wzU����������Q��������w����Uy���w{{U��'�no'����Y��X������w=�wmo��D�{z��y��=�z�����E�{z�v���	��������
[��Wv�*5�������G�?m���/����s����
�
�����?���?�����������_��������o��������"�'*_*�0t�����:������7�a�]��]�m���/1�����2�1���F@{�����m���vC��M_�o3Om�������6�+����MA���h�A��� W�������n�m#���;������G��v�.`;�r;����h������U"�r�Q���+�Nm�������6�+��\�MO�(;z_��%W�xh�v�d7���^�g�m��lC��m�53�[.�o;{vv�h�����6�#�r�Qy_��%������l�m�c#��Vg�mvC��F��
�������2���c�a����J�8�n�P�m6��*m��P�n���m�a���J���e�C�K4���=���:����s5t<���uY��ZT;
]����mQ�(t���So�
�k�WvzT*]�����Q�t���So�
�k�Wv�T�.�aC�6�<J]_��b��Rao����@����%l��.��Z�����z�T�Z#���;��:Q��5dg��M(v���Sg��&P����q>��6�XV�sg��M�v�����3]^��3�n� ����;UN��
hK�v��N
���]�9UN��
��vv���������']V�.��*7+�X��sg����w������A��Wv�yUNI�X��sg��)��m���z�)�����q^�[&�X��d�vv��m���z�-�w�+���*�x�X��d�`v��%�n��ln��^�gU�uG�e�KV�� W��
h��*2�%W���Y���s��F��	����r��&���+7m�5(vuV�.��*gP�B��6��]C�����E�k�bw�QeQ����U��*�b�Rb����,�]����
��-�]����P�nD{�����Zw�j�u�O�P�ne��z�T��#��������P����]�T;J]W����M����)�����Q��Y����v��{Y���6��Rw'�.�����������@��@�{����mSy��GY�����G���Zw�Ry����uUo�����e�K;s�{���Y��t�N��gY���.��Z���n�K;6�p�����nIJ
q'�j��6�>������|)c�����q>�.��Nt�P�}�]������|)c�����q>�.B,W]Y:�T��m#�-�K>K�`j�Wv��T�,b��(�����,����n�K;6�p/��qF��&�X�2Jv��`W�E����|)c�����qN��<B$�Hvv��E"��2��|���.6�p���s��eG�D��N���I�����C��P#���;����
!]$;;U�
&i@[b���cC����8�j��w��Kg�j��wuY��nq�c?���J�8�j7(w��Kg�j7(w
!w+�v�~��O#���;���(w��Ko�����e������4�+���
�.�Sc��Tm�v7J��f�i�Wv:U�.�Sc��T9T��P�'Dm��v����N�C�K��X{;U;�]G�]�a"��N#���k:U;�]������:P����%&r���4�+����.�Sc��T�vB��9��v����N�G�K��X{;U��'Nw����b;����@��D�K��X{;U'�������DvQ��Y�k�9U��r����vv�n�X�n@[b��yL�w�+����CH�X����:v�����ng���w�+����CN������C��
hK�v�UuH�����q^�!=B$�ng���%�[����D�3�c��^�gU�������C��
h���s�6�V��
`���3��!�������C��
hK�rg��Xf�������c�0��lT����T+���|��.+v�8��XA��v;U�
b7�-���d>��.+v�8���
!����lT��&�.����]�bWg��gT��.�]���:�]C�]�Y1�����];���(vMY���F�E�k	�K>+�`����Y�kU��-�]����P�Z�p�|V����jw��];���P�n���mT9T�q�K�+�`���uY�kU��#�no����u��%s����uy�;���Q��e�kz;U;������M����������Q����Wu��=(����:P�Y�+��f�G�{���mVy�����bz=
^��b�V��x}Y���n����$/�������U�bgW�I��%��lW�	v���P��s
A�M`����*?���\1�t���P�.���sA�M`����*/�X.d:�U^�������V��.0n��q~��1�����~���*
hK�v��=��	p3��3��lc�@��lX�����Dog��c�7C�8��+�d��v0��c���m���n��F0n��q��_���'������_�-
hK�v��=v�	p3�����:#�r�\����+��m���~��^0��^1���Z �r�\����U�.�^A������z�yV^��%������7({5!{{��&���;��2({��0��eeQ�����nj`;��6��@����%���������R���i��~0n��������hc{{V���P�duz�#L���w�g�P��alo����u��%�{p��=a��=�U/�����vT�;�z��,������W��T�Do���:P���%|p��]a��=+���h#(t,�z�����d�~�1L���w�i�Q��a����:Q����d�~�7L�{�Wt�N�T����muN�|O���,����9��
p3������!F�!����:h���og���}�����SX�X��b��\��o�[����|J�c��r�uuJ�t�����)A�����|�]^��q��9��
�K�v����o��y���q���W���N5#F�1����:����:wv�O�7���;��:�)����:P�nY�����o���w�yu.'b��og��\�K�_�b�+��7��8��\�H5H��^��o�[����|jT���~��W�F��	�+:�W�A��	�KV������5y�;�s�N����W�v��_C�_�n������y�{eQ�ZB�����E�k��_�r��_����@�jC���W�v�6��q�K��a�������@������+z�W��#�/Y���_������<���Q�:B�������w��oo�yG�����<���Q���������N�����������y�u��=(������B��5|8���=�����_F��X�D������-�%�/K��H'*�3������{��=	�+{�W'�����d��������L�{a����%�7�i����n_��&�;"����U�O�O�@&����P���\�!�EF���n`�+��/Y�����2��������R]dd_�����\�R��X��8v�m�{(mn��<#B����k[��i`w.W�d�-v��L�{a��C���*������iuC����|yan��B���B�C'���=!QWW�u����Hn��� ��q|��B&�����yo[v�uuI=���*���\�R���8��2n���8zW������DzO�w-��dq5z��L��yl4�^�z��$#�ZU70�w5�w��=��:+x����^���j%3�5�n`P�B���{8���xMV�>Vd�-�%/�Kf��VY�����d�zQ����}��F[z7��T3���_�����K���wC��e5�cE6���P�R�d����C����W�|8�u�z]V�>Vd�1�({�v2so�jG���l���i��z���}��F[vw��T;���cu���	�K�g��x��G^�����T?���gu��=�K�g�����=��w�i�Q�R�d����G��)�����N��>+{�����e/�Of�mZ�({OB��������������k4eWL�z���=+1��
pKo����P@�U����hK��"�B��g%���d�v�x������8�JH����-+!A�����di5��W��
p������<"�C��e��0�6;����������Lf�l&�L@�a�q���e5�K�_������������u;��t��oU��
2#��"^^z�8Ym�������UVn=1��DU��z�uxW�z�8�ws���w�v��#JKT�+@z)n?�x�1����u����c�n�������X�
���2?��R�{|t}��+���K�9�����Ay).���|��������v�����Qp^q7���7������S�������6Tc,���%�U.�\B�M��zq���	�7u����c�f��$I�vc�Qz�$��'�.������6Rc0^��,H���~��7���y3�(�GWz_��1���{�+n��������zq�����t����c���"X���z
^���[�W���������������VA{�
�3�V���k��]��{������6Nc,����W�p=���{���]j4���k��ae��z�`��~�pZo�������p�y[�y
���	�+n���B���s���w,����+�]a���OP^q���o���).�N����1�i��4��*��(-PU�����
�������X��=�=���]]�]���!q=��~E���K�/Uv������k���QZ���V��R�����LV������+��z`Di{�rY�WhJ).w9R�.l�yO{�k�U�� ��>F����R����tao�{�;]���o;D�����qg���'��]��7�������k��0��8U���;�����|�������w�vU��#JkS��*�w#���h�t#�n���]W����6F\�;�nB�M�����f�M������]UB�����+qg������������������vU}WZ#.��A�@����>�V5����{t}w3���]ia��Ps
]���������-��G�w7�������b�����[�U���+�n���f�UU�]qY�vWU�w�����^}E��]����}W\��U���'����tO������aW��w�E1�"�t�n�}W�B?�nC�m]����}W�#���A�B��x����{��^]����}WZ#�(;�����^��*����.��������bDiE�rW�:�]���U>�]�.������Vw`DiA�rW�:�]���U>�]�������]W�z�]���U��V�Kq�7���w�������n�U�+�.e��*wU�
�Kq���
�z�����n�U�!`D�w���3��]���U>�]�.��������cDi1�rW�n�������n����N���Z�#
�+�C�Aw����t���3������N���Z������]�W��������}7v}w�������w�����w#�����3�&��������Z�n|W\�6�.�n�}W|�t������k�Ue��,����m����y��>�A�@��}�5����C�]q;�������������G�w�aWU�w�w�����[x�_?�A������F������w�����[y����[�wk�w�aWu��V�w�vWu������C�g�=�w���F���D�=��f����wO�w��I3�6�����h�U5��&���5s�}���+�M�A�B����
��}�|W\�9�.������6i��{a(���]Wf��0�]UX�s��2t��f\Ci�t����`�e�v��+3g�u��Aq��
������uU��(� ���w*����s��~�p+�������0�0%W\�8��
=)�e�j�f��0��F7�uU!x�(�CU��B����2�����.���w�v]U��(�CU���=)�e��[s��P�;]��*l
#J#r����{��O������Ka(���]W����0�]U���R���g������uU!����a����w#���=s��0��N���
	}W���U����x������a(���aW��w��0�]UF���������E��]�M�]���+l������{�������f��}0��N���*���R������w�]v3��:J{�k�UU�]q'�vWU�w����]n���7��������J���D����jwU�����vU'���F^�3�nC�=y������`(���aW��w��0���E�m��j�Gp���5��.�]a'�w�]���{	���]����^]��v]����Rf��rW�-����N|�i
�]�w�]W����u�]���w).CW����.������6�1�����3�z�]��u��y�]J{�k�Um����u�����R����m���w�v]��6�(����k���.����n|�����uU[�Q�]q]���.��:�Dn�.���u�]Y�mf��W���6^��u\���]Wx�b�Vm;/���*�U��Kq��[�[t�������j���QP^q����7������l�7v��-v���Pz� ��v�|Jo.5+%l	�7u��-��UF�M����%f��h���^q����7w��-��������K��{�����{Fg�=P{�������:�{�{���xz��{�|�z�������������*h�E0_��ZU4�����Hv��oE�����V��
���k���[y�7���{��V�|
{����W\C0���{��+��������}�u��UC�m��j�V
����+����������V�o��W���P|/^|����B������z�}Y�
�+n"�������'Hq������a(m�]m�;��1�*�x|tP�~:q%�����v���V��0��$F�E0���k)n����P�^��j�'f���*�V�
�)�e�*��;.����v����(�E]�k�=@gJq��_��!��v���V{���������S�BgJq�����+b(m�]k�o0�r�xq>��T����\J��#��v���V�.waS�4���CeJq�}���)|>;�L�o��VoX0��U�8�oD���6�
�|qO���������+l���(�|�o�W�Pa�E1������Jh���/���7��&�|���3���J��k�[e4_a_�����{��f�|���3���J��k�[h���/N�������**��+��v��V�W���q`S����|�pY���5��*���2����f��h�U0_����P�^���D�v�xq ��'�������{
^��_�����
Kc�8l����x�7����b(m�aou��
[c�8l�����W\</.���w��amu��
kc�8l����^��j_�x/����k��rbF�{�[���{).�WY������v�Ut3
�+N�����R\��E�Ki;x�Z��3f�W6/x/�e�*�Q\=>����v�U\�{)4�W���+x/�e�*�Q>����v�U������Z��Kq���5�S�6|t}�]�Z����Q�^q���x/�e�*���
���~�w����w��NC���0�������wP_��V>��;�/������y0�
�+�7�����jv���������p#jo�W/4nB������fg�M�����/}m7��&Iz�+����x�����QzsWz_��<nF����jV�7��+����@��]�}�+�X�
�!�8xf�����W\3;nA�=����1�X�u��+������Aw�����[����!�X�e��+%����V��WnE���C���x��=�s����H�pO����\�`��X�'���?�}��w0^4�S0]q$��
M��M��[fg�m���y��oC�m���#If���u����t/t����lG�B���'�L�����x�u���	x�����S3�i)�'���$S��'���*7U	��P�;^��*9v���1^Y1��O���U��.���w�veU�0�2	�c�8�b^����V%�Cq�x�������$������xWhJ).�W��J�:�����V)�Q��+����7@WJq9���F��1�����J����]/����w����rx��W%�Cq�x�J��]����W�g��W��O�t���xqw�����+��~bD~��_y��7��R��d\J��1�����J�WX ��W���E����jOKI�:������V)��
�c�����	�7	�+.���W�P�;^��*��
�c������7�+n���W�P�;^���@���x���x��C�^q�����G�{_��1oA���������[�{������xqs���5l�*z��>������[�{������xqs���5l�*z��>�'���D����j�V�9�����V'z��>�'��������j�V�9�����V
�WX���S���6�{���3����{������{��1>i�Vz�%x��sv����^]�}m��P�y���^��*/������Ze����z�k�4��u�������Ze�Kq9���Uv
�]�{_��1�_1����<�x=x/���*�V���R�;^��*�#J���Z����rx�[����R�;^��*�F��W���aE����+gg�
���������������Hf���{).�W���x/����k��V0����{S���R\�rk�������Z���������{)3E��������|����-��������?���������0������w%�o�o���?������������o����?����H����O���-����Gz���������eO����������#R�#�:���#����K9��C���F��wg���������jD�5B<~�A�@�8�����{�E]��
��q�!�>��[P"A"���3������`X����K�x�8�nE�(�C��wg�����������w��q
]T�*(��{w�����B���D�8�����`,�N�(-GW��k]��,�w
O��pr���������	g���t/<8k���`X�]xpv	g�YK�B���s3q�����W�w�]ww,�pn�����t�>6(-GW��;p������pv8��-����>6(-GW��:p��������`D~@�x�8����
J��w�����7(���f�U�aD~�x�8���"]~d�W�����7(���]Wu�#��H�3�t�������U�z�����uUG80"?�T<r�BjRJ��U����Aq�t���c�����~C<c�Aw����rt����nP�;]����an�!����f���&��]������N���:b���DR��m���������{7(���]Wu$�]a��x�6�nB�M����vg����N��������
��m����%����p����5��2���~C<c�A�@����jwU�z����vU���C<c�A�������vg����Fw7��
����C<c�B}��+.��A�oP�;]�����
8�3�t+�n|W��;�.n���w��]���+����f�=�wO�w�5�S����]��
����+l���f�m��M�]q����{����vU����C<c�A�B���7�����7(���]WU�]a�x�6�nY�w)-GW��*�.��������0"�����nE����;vg�u���N���*�bD�w�3�t=�.���*wU���R�;]����#��+��M��Ki9��]UYW|t}�����
�K���]UY�w)-�
�rWU��G���h�U��K���]U	�������U�p����n����0"������.���*wUe���w�v]U�=F|W��*;�.���*wUe���w�v]U�F|W��*}7
�+.��A7�����F���D�����x�6�nB�����{vg�M��������J����]��m�����������ws�w�aW��w3�������Y�]q����n��n4������]��m�}��|W��*��G�w
����[x���f�-��E�]��������vU}���+����[�w������t+�n��n2��N�����x�6����{
�+���A�D�=�������{��+������w������t�n��n2���n|W����w������t/����������w/�w�������%���_w���6(���]WU����A���>6(-GW����g�����uU��$��M������UU\�Aq�t����a�evm�gl3�z����]�����
�{�k�U�FYVa��x�6��
5)���*wU�lP�;]������!����jRJ��U��*����w�v]U�<F����gl3�nP�RZ���Yw]\�Aqot�]WU�#�Cr�3�tw�I)-GW����a�����uUuo��+����=��6�{ug�����������}7
���U�����o�?�	}7u}7�uU5��&�w��������&����`(���aW��w��0���}7KK��H\Cq�t
��}WX
#����{�����+���E�=���
����+,���f�-��E�]qc�������vU}WX
#����[�w����M$����w��]���+,���f�=�wO�w��H\Cq�t
��}WX
#������wO�w��H\Cqot�bXV5^a+�x�6�����^q]�����v��U��F<e�����W\�<����^]�u�]]u.�����\W�(/���*���s��������t����;���������p������6���f���o�a����a��]�������������o���^"���|�l_6���e��q(pK��<�����f��	��3~�U�6@i��v��Y��0����k���0#OX<����\�pO8+7|�	��)n�]�w��u��/
�G�3�6�6p
��r�w6x1��v��u|g���3V<���pJ��U���k�G�}3�-v%�yAN���%�yANi9��%_C����v-_C�l�H��W�6�&��r��P$#����k(�MI�k^����S/=�9x/|t��S��Z��f�OO��x=|rPZ�r��<|tP�^����3������+�RZ�r��V8>���v-_f��O�3�x��RZ��������v���V-4����gX3�n�
[����m��R�^���m3�����;4������Z�*S���k�Z������x�5/4������Z������:���E���{oVn�ZD�����E��j	�72�k�Z����x��df�M��I�^��*��&�{
[����x��df����Y�^��*�����z���@�����g23������N��:�{���z��������g23���"x��n�
zo�{�7l�
zo�W�����E�^��ZU����^o�ZU��*x�vku��V�{�vku���}�������{����C�)|Q|OA|�vm�P|���z�����6^|�x*3�oC�m��:���B�m}�������{����c�|/T�KP_�]\]��W_}�]qu-����N<����Z�})n?���1���
�{-��������������:�\f^�Kq�����@})m�]qu�3����s�x=�/��~;+������w��]su��y�u�����G���*��
�Kq;|���k����_'�����~).�W�y��/�������p`F�~���+��R\��W���m�g�������6�_
��Un��
���r|���kw�������W��K������;�/���*���~�����j�^]1`F�~���|#�oN~�r�|E����������o�W<���7��&^�������~���yG�
�<�f�$�x@3pF��������3�o���K���E������33�h�Y���u��t���k�/}wK�@�=��ff�-������t��
�[P}KW}_��<nA�-���3S���I|��}���[�������t+jo�W,vg����U�^�C��D��]�}�K�X�'J�)I�viu���������':��u���{��mh��d���UC�m�y��Fc�6��_d�B�m��������%�t���5����H��{-���'��X���������q9����oa~����3;�����Bb�;���������K��~n����u'Ff�e����_�rxu�z�����<~r�?6;��`D����nWu-�x=?��?��<����X���$��]3F���K��e�[�xW~��_uz�%x|vX��c3���"F��-��n]����O����9��l>;lJ����Uo7��	3u���3�n�����~�=�}���aWJ������}���L]����{�;?����e�[�
�n����Yeu-�aDa����t����]u���0�����f��["��(x���t����]uK��_8�g���k�Z%��$x���t�����]�[��������l��x3zo�W�n:����%��n�����������@�=���N���{H���Z�������������{���3���"xo�n�*zo�z�k�5������.������
��[���[����l��xO�^i����t����7h�V'z�����Fk����{�]2�w�xzo��{U�j�eA�m]�}m��`����*����jo��W����{u����c�^h��&����nA�������������UVn)Q�^�������2t?.$��u����N���r.cD�y���S���R\���;E��]Wy_�1�����]���yP^�����{�u�G�5��j�����Rf��r_�V0^������L����
�k�4��
+F�W5�n��������t�.����k���0���A��r�.���3+��p/����k��vaDAx���g������,��xw0^�{�k�V������������x).�W����������M��7��FIy��*�Py#������M������]]�*o��W��J���W�c����������uUF����n�uUF����~|�;�������kXW������v]u����~|�;�.*��U�`XWT�CP�M��*��EP^�C@WPyKWy�a]UQy����v]UQy�t�Y�nE��]�
�uUE����n�u���[%�U���N4��k����:�xO�x7��������*�lv
��u�7�U
��	��i�UoyE���B���������w���.T�K8�}0n(^��G��u�`�W����-�3sx��*��G���h(�l��4�=��]a�]�����)V��G�e�X�~o��2�=��]_����1nW������O�|�������w�vu�_W�(�����*�BUJq�_���$xX���w���|p����v����J).�W���b�����V>\����v���o+���[z�N���������k��vbD~t���+�C[Jq9��w4<��y�{�k�X��`D~v���+�C]Jq�t���xaU�{�;^���Gt^a_�[e��7J��|�'t��u�����	�WX�v���'t��;���x3Zo�Z�f�Xe�^aY�/�hU�f���[���)x�{s�{7���@����������{H��|���������UA�������-��E�^�����[��k�Z�^ac����UE�-��������v�w7l�*z��2�E���D��������'z�������:�{��1.j�V'z��{�+�xz�������j�����[�����+�x/����������{��1.j�Vz�%x�X�N��.��W�{w��j]�{)3�W��Z�^����EC;�ui�������V�[1���Q��Zh/�e�~�Ec�:�^J{�k�Y��aD�z�;����R\����V4�����w�v���/�(I�re��+�����M��tWp^J{�k�X����M����y).C�c'K7��R�;]��j
#
����5��R\���J4����u�7��U��K�9��}����R\���F4�����u�7��U��K�9��u����R\�����c��]�w�][�F��(�nRn�����������������5��F�w�rY�&������C��t�n��n4��2�n|7iwU}7���Ue�����h�Ue��,�n�����,��vWu��]���]���{H���U�����'�c������h�U��"��vWU�w������������]UE����f�����V�w����{�����vU'��)�n���N�������c�6��������j��M����U5���������t�w[�w�aWu��6�w�vWu��^���%�������d�U����|7+wUa��
���U��
�#�����uU�-Q��������s����)o��"�����UU�5�(
�U���_���P�.����w�vUU�#�Cs]V���
5)�e�)�	�"�����UUa=0"?4��k]�P�R�~:����"�����UU!�h� ��qY��
jR�������1��N���
L���)��������<�;��J{�kWU�=`Dah��\U�jR���U�pA����vUU�#
3s��*D��(��2\\Ca�p�����v�1~Qn�BB�M��>X?5�.����w��MUB�v��E��������������0��N�����������@����>�?�.����w��U���+��Y���u��u����tq=���5��
���#f���
�ntW.n���w��MUE��V�,�MUE���
��/U
���[���
��mWZ�h7U'��)--T��p;���5�����"F�������6ak��}���a(���aUu��Jb�vUu��^��j���j
{�����B���8��j[�w/�wu�n�.��������bF�w���t�.�e�DP��@w)l��]W��3J;Q������R������W|r]�u�]W�y�]
��U��6�Kq?}5c���mu�������j[�x)4�W���V0^���[��^�������j3
�+n!��7��R\&��go����v���y�(9�ra�m���I�=�u�@z)n��]e��f��W���v�^���U������������������W��{���|#�od�����"�o��+�V[B�����{��o�����������B��E�M��zqA���7���6W�7��������y�����|����_g�]�����^��:PA�YS���}�u��UA�=�
s���[�#_������[�������[����UE��������������:���D����z���D�=y�u�on'����_g�_��������UC�=�7����m��������j��M�_���B�m�����O3�^���������{	��j�W���������{b(l��]{�/0�r���U��������oge��qS����v���`��.����r{�;�����og�7w\Ci;x�������]X�W��j���Aq?}!v0�~r������5`FaM�x9b��S���\*��e1�������������U�����{�B/n����v���-�QX��*7W��)��Zi��}1���������=��rs����s.���p�wg�Cq;|���}��QX��*7WoY���O�k�?��2��v��W{D���U���#�o������?��4��v��W{B�V���\\�	�7���=�l��1�����������/N��7��fA}�����7����������+l���l�|t�C���=�l��1�����*(���/�?�oA�-��>��}(^\Ci;x
����+,���|�x+�o��W[�pu���5l�*���@����f�=Q}������qy���5��NT_a��'����P}OI}�_Z�q}���5�����D��3���E�m�����&���2�������}�52>hWW�����������^(������C~�[F>���Sp��r`��1V~1%.>�����y0^0����r}�/��Jn�D�Kqox_�=��Q�_�������R����(z�_�{������x�#
��)�Wq�����/^����S����>���0����ry�G���~|�j,��Kqox_��<o�Q��M����/�e������x7�_�{�����`�����������R\�r{��]�~_:��w���^��*� ����\^����uO~_:��7��F�{�A������/������_��O��������������o������?������OtN��o��������/�����������~��������/>��|9V�N|��s������_�Y?��qH;X�y:h�~^������r��vx9	����my(�����n�m>�`�x��Bs|�{���$��sb�<�o�g��G��|��|�.��F�(})�+�I�E���y��Fq;g1�|�2���*7})�+�I�F���y��Fq�|
�����(4�W��K��|�c���X�����5��^���_��/���ktN,�g�-�j�����Kx��Bs|���T`W��9�i���|v8|���}	��Qh��r��*rn�9�j���D��}�5������_��/����M:'v�3�6������}_��t���|W-5�_�&���)|�[�_�P2�/����_���B�n�9�m���B���������|3����_��*/��Y�E���t����(���a��.]�4)�W���W�_��*�x&�{�k�_e�L��!M��3�z��,��sb{:�/�g��w���U��tY��$�M1�/�o.��f���M������x�.Kc���)f�]��p��=X03�/Nh��w���U��tY��$�M1�o���U:'��3���&�{�k�_e�P��AM��3�n��Y�K�,��������a��F]5)�Wy���e:�`��X�8������W��eqP�r�#��p�N{M�M����a}�#��4�I|�b����}�_f��/�h��w���UB�5�/S���Q����e2Nh��w���UF��4��RL����y�U�=�q>������T_aJ��*������oR��q<����l�
��0�I~�b���[x���c��x&J{�kY\U_aH�O��UE����f��3Q�;^���D���4%���D�=y�����2�g��w���UC���4%�����6����mC��x&�{�kY[5�^iHS���.��&y����c��x&�{�kY[]������\[~x\���{���=�����%����T�(��K��������2�>�v��u��Ai�x
k���QX�'�����Aq�t�������{��aoux��E��(���>;(.���Zr,�����.�������-
��U.��JS��M��{�����3��������3���~0$��#������D��]f(��������<��H�q^_�����3����B���{�^�/�%���e7����aF~���x���a�Ai9�P�Q#b_#[�#�FD^#��?�c�&��(X��%�X�	-"�-���;ZD�-�}����x�p������"R�";�#�Ed�"���3�f���K�[����-"�-���;����q���J��K�[>�b5/~i=��Y6x-���~�c��zAi���~,�W/(��e�W=f�+�x+\����??�����{�k���f�+�xO�����v|6���{v�w�l�N����^���������:���xjo�j�fx��h��M8=����X�jo����od��{��^]��,;���N��;������z��x���{u�w3,���K�?��M�[�^J��U�zV��G������*��B�������RZ�rkU��������U�3
���Z�Ki9���U��������*�����*�Ve���^��������w7l�JX0#���f�xx/���~|8o���w���U	
3���*�Ve[����������R�;^���l3���*�Ve���^�����������*��y�]�[����RZ�rkU�������akU"zo��wUn�JD����>Xk7oB��]��
[���{���rkUzo���Z��x�{S�{w��*��&�{W��*��f�{���7������������y�]�[�����W|l�M�r��}��,�
j�!h�viUP{����`3�����^������z�;���[$�����
�������F�����V^z�veu��VAz��3��(�gWz�eeu��������D�=y�}0Ef�����{v�7Z6V
���������x�}0Df,���u�7ZV*��+o�.�.T��W�3d�E����
�����y�
�}U]�c��2t�_r��������U����h	�uUu��Ai���8W\�Ai�t
���=f�'����z����]��z+.���w��e���aFa2�rYUW(J)-�D�w�	]d�}������k���hRq����#^~p�������8(��a]UC���hRq���4�������J~�e��F7�Uu;0#?�T��>�.4�����|�Pq���5l������C��>��M)�e�*$T\�Ai�t
���x���C��>�nD����~|�f0]4��5�d�V���+l�w�����xo�NzvS���{�kYWeT^a���}�����a����xq������t^a���}������qP�;^���@��q���g�-�����+�>�.����w���UA��q�k�g����E��/���0����{�kYXUt^a���}
^t�*�������{8(��eau��
�8�%�3��(��0)����xq������UC��q�;�g�mh�MX'������u�7[VVj���C\�>���{	;��&���[8(��agu.���.q�����Ki9������\@{)��aiu�3��+.p�����RZ��W����@{)��aiu��y������=�v��wsg���������:}�������g�]�{)-����j,�������V�z`F�{�5XS���R�����V|t]������{)4�W��:x/����i��>����V��K��������RZ����o�}���.|r}�5,��=`FA{�K�s����p��p�������}�7�=���W��:�nD����~|�0oD��]�u�agu&���[�8cu�����U�Rv&����^�XvV	�7��+�X��7��&�z�9g����^�XvV�7��+�X���@���fte�J���^�XvVZ��[�8cu
^����^�������J�[,;���[x�g���[�zo����x+Jo�J�[,;���[y�g���[�z+o���)x�zk�z�b�Y�����^q���'j��k�x{���d����j�������UC�m���7�g�m����^���B�m��j�Vz��{�x{����{��l�.����^q���m�O���^���
w�P�^���-'���	�3Vg�u��Ai�;��`.������UsC���!�3�z����_e�m�5��v��V�g�O�M��U���Ai���
��P�_����0��	�c�3�|W(M)-�W����P�_���w���1I��jZSJ��U>Wh�8��v�VWm[1$?J7)WWm����2|��(f���1�����j����0]q���;������U>8j�:��v��Wm�0$?MWt>�o���v����f���1�����j�W�!������������qy������UK���q���7	�+������P�_��*��
[d�y�S���f����3������k�_���q"����!��x�~_\ Cq;|-����+,�gb��[�����u�)|�K��eU��U2�T�|+�o��W��3.���������+,��b��{������sf��-2�����:��m2��UC�=�	���{d(n��e���}2���������tq�����l�.�_i��r{u-h�o��7�����v�vW��1���������RZ�j�2]�����w5l�.�K��7q������2��*��>��������A|)5�W���<�/�������>���������RX��(WW�
�Kq�t�F�?�+�/��6����0��GuQ����Kq������Ka;x
��+\�7_�(WW��t��\m\�/��6���������E���vp_��L+���})l�asu�C������� ���������Q���y��c7�)�G����\_]8
�����:p�:�k����Mh�I2`��*�'��W�{�2*p�*�k_����(�Y`��*�gA��O�)xQ�sW�_��<�����u�����{�+~p��{��]�}���X����W�p�������W{b�UPKW_��</�o�W�t�����A~��3��p�������[�|�`���A�D����gm3:Q}����v�;����{
�+>�t��)��2������������Py�����B��I7���^��������X�:�%8��g���y/�yU�5�e��2�������3�f�BsxU�������?q�y�x�U�?i;Wr��
2
�e��g�u�:~�S=��9K�G���_�
��3
;U�'8�����C0l����[e�������z��:����u���w�������	?g9���X�����{aF~�����aE���{�����V�����5��~�tbF~������[�����������2�I{�k�Y��`F~�������a.���C0u���,�]+���w�f���3d��8�ZZ���;?�ks��^�����5k�~���+��q�~�x#zo��w�����{c�{_��1oB���8q���	�7���j�J�����/��7��
�e��_f����y�]��Ze�����gl��{��
�e���x�����U����,��G�{_�1/z��^���^f�-������i����{K�{_��1oA���8��������������v���c�V�^a����L���[y�]U�{��������/����D���8����'z��{��}���{����8^c,���+��q���xzo�W����{[�{-[��WX/��o/3�^����������{�����rz��^���^&�ux/�����>�[�{)�����9��������{).��c�����R�;^����3
�+~{�����W8�U������w�����'f��W��z31��y��>��]�n�z���5��]f��W��r+x/�e�*w�.|t]�}q��X���Bs/y(�V.��R\�r��6�����/���w���^���m������9�}�G���gk�����Rh�rk�v�^���U������u�w5l�\\1������x#zo��7(w�.������V.��F�{��3�&���{oP��]B�M}��l�zo�W��7oF�M��*w�.�������*��f�{��3������]�����{t�7X�Vz�!x���o
^��C�^�#W�{���������{�[���[x�}�f�������������VI|�k���[�W/��=S8Q|kW|�emu�����n�����{��^������o�����)��8Uw����x�������P|[W|�emu��6A|7���B��x�����s��+�����P|/A|7���/��q	�������
?��OJ{�kX[��aFa��82y^���U>�>9(��am�]���l�M���>:(.�W�D�{����7��am�������rm�=|tP\�rm��~r�'0��&�(����k+�BgJq��'�>8|tX��h�
;d���rPo����2x�O}���ae���a�w�Q�&��Z�
:S���U.���)���5l���1�0QwWn�����w�G^��f���1��w�����fF��k�g������.j�F����������WZ##n���7��F�{�O�|B�M]��[+��{�=2�vk��{�����5|F��}��l�2z��HF�1/zo�W��������k�Z���"�]��:�{�{��Z������ekU�{�E2�vkU�{�����)x�{K�{w�����J�dv�����V�{�/3�V��������:�{�M2��xO��S�^���D�=���[�V
�WZ%�k�V
����+~1�����������UC��v�D���B�m�~��]:_(�WW|w���B���(�V���{��+~���w]@|)��am�.f�7*�V��Kq�����V|t]��
k����Rh�rm�:_���U��V��������Z=�/���*�V����^��j�>����V�0� �����+�/�e���k�u���7����Z�����F��j
 ���K��
}Ma
 �������Z�3
�+��5��Kq��e������R�;_��j�f��W��Z��������;�/���5,���bF�|���5��R\���"�5�����F��j���QP���\��7����7	�	�7v�76WkB�M��&��*��&�}����5�����F��*��fA~������<����P~�����o��[������r��{���?���?|�����������?}���������~���?���_�����o�/�#^��>�V�Q���~C���~��H�>���	��@_��m
17,��"����r�pq�
#�r-��Q[p
���J|
�����)4�W��8�8�������m1�5l�#��^��/�4�p�Fl��������_r%��/�0b
��Un�N#�i�v]}�M>��^��/�0b
��Un�N#�i�v]}���|��!&��e_�a����\��Fn�������N��m1�5��#��^��/�4�p�F�^�� D���1^��/�0b
�]S��N#�i�_�U�A��m1�5l�#��^��/�4�p�F�^��!����^��/�0b
��U��pq�M#����f���b�kY[�0b
�����pq�M#�� ���b�k�Z�0b
���n�pq�M#���c�
C����b�k�Z�0b
���n�pq�
#�����;oE��M!�%W�l�p1���3��0�pF����h,���6���Z�V8��Bsx�[+Fn������W��xz�m
1��l�p1���j�V8�8�����#��x/���b�k�Z�,b
���n�pq�
#�5�x�f�7���6����V���{	W8�x3�nx/�e�*����Ki�x
[��9�(��\�[����R���F���@|)���am��3
78��j��
����3�z0_�{�k�[m����
�E���V0_�����|WP_�{�kX\mk�����E����/�����������6W[���w_�(7W[����9���w��������j��~)5X���6�_��|��[���|t]�u�ay��������\^m;�/������w4������n1l���bH������V��U���E����_��W[B��+�W[BN����g�M�����n���
p�	����(��`�~#��������0��Q�� �N��:P�3/���{��]�u�e�u��;������oA�-]�u�e�UP�� �N��*(��`u������_����V��v�U�+�����|O�����e�u������o���{�����*�n'����_g�_5��S���_5�����x){�������,����	���������W��=����{���Y�W��%��r��tb���U�7�><��X�w�������)�gF��������x�/�*�����6����a��xbJ��k3��|��6�����7v�m0���������3#����O��6�������|t��������q@1�����|qB�~�P�_��j���|
��'Sj��r�����6�������-���<}�k�_�8��Rs|���G���_\�ogO���a{�����qF1��+X;�(�o3����`�;���m:1��
��C�)5X���qH�~R�%`�
k��������
+��Sj�r������6���t��#%t��|�w����c�)5X���1��mL����%)����,�pN1��k�X%�>5��_��-�~���{��@>g �|�����\P���{���A��M.3���k��������{���W���13W��*xp�.:*zp�{��,�N��*x��]d�������'I'z��x�e����O��W�&��7���5��7��-�������|�7�����=��{�j�d]������,�	���|���2\��)n�a���!�MLq��`�.:�������a�x0��+7Y��S\�'X{�w��]��W�&+z�`J�Vn����`�&+�>����MV\��)58(7Yq����hu�
�]��W�&+�C
�����).X���<��v6YqsR����d�
<��2��?�;�!n����t�����S~���/�)�pP.���"c^��83d��*Lqo?��}��w?1� �A���D��rx�oU��"�"�����x#jp48(Y1�G�8X��!&�������B���P�� �A��J(���`�i��(��+��}��7�gA����x3*p���W1T�������}}��@>$����C�]��<P����v<oA�=$��.�
�o����7���[����!�X����+����[Q~+/��U�)�[Q~k���#��x�{������'zo��?> ��D�=�G�����{�����n��UC�=����r����6�u`C�
��	�+��S���6�x�.6.4��\�6�{��^��������%��j�M����v���Ff&a�����������*_�L������VW����$,��_��������Jn`%\ECq�|
���f6���r�������~%�d�U4�����J����<^�)�Wi����~���W�P�;_��*�3��x���|T����,�"��W�P�;_��*���y�r{?���"_~V��~�;�&�{�k�_��bF~�\����CyJq��_�����h(����a��3��x�>��Z��0�E��A:hO).���������|����-�����?����������^��w������J?�o.����?���������7��}�7�P�
��7�8�o��������N�>�#����Dd��D��O�a���F]&8�]���|�f��{pq,_�Dq�|
�����0�����_���6���}a_��Dq�|
�����0�����_��y���tN��0����gS���!_�O���M�r����Y�J���3���&�{�k��e�P���M�r��3��Y�K�����
90�m��w���_�+uY��$Z�|@����tN�00�m��w���_�KuY���w��/����tN�00�m��w���_�kuY�������+8rn�9q(��8�����~/�eaz����_�����:'e��6Q���<��_��uY�����3�(���:'e��6Q�;`���eaz������[uN�a6��pl����l��n]��7E��Bn�9qG��`�Dy��
k�/�eax���5�����!\�{�R��X|,��Aq�|
k�/�Qh��r�u8��8�kuN\B8����������X^���_����������p_�����:�r���*�X�
%�!\�s��|W(Q)���a�u��:
��U.���!]������*���5���\G��'��;�#@�z�����S�n�]w��jXax��Bs|�+�c����=������]w�}0l��\G�9��
��C�z����S~~������>XG\1���>)XGD����>�7��8"�o��o0,�����_m��7��&�����M��������J��I�_���|3�o���/���3
p�
p�,�2
pX|�q�8������|��+����:P�A��v�UP�^�����������I����\x_���������WI����\y~���`�'
p��e�u���g��D>y~0�q4_��/��VC>��VCn�?��8�oCn]�fXa��	���'x��_��w9o���F���w��2/���i?����_�,�������[�p�{���6Q��z�%����������u^q3
�p>n��|��LPZ��;G�P�;^�6���y���M�.Ai��em�	8�����++�D�����f�]A%(-�W��-8����Vy%�Ji��M�X�L��2x�����o(��a�W�3
Sp>.���@$(m?���g�Ai��7��N���+����A��f0���h��N��R��7��N���+���c��K��tc@��)��-�������x%��Q8D���X�	�7
�H�/�������k�������3��������zo�&����zs�zw�;h%��f���+,����f�z"��@��]��-;���N��;���n�j��Q
Z�������*h�E8@���
Zo��W��R�zK�zw�������L���h�UxR��w�������egu��V���2���^��m����z�n�Y��������UC�=��m�������[�V
����+��4������m����z�n�Z]�������	x��������M�[����w���U]
f������U]����rx?��x]�G�����V���A
��Un���OJ��UT��G�]�
[��a� �f�*�V��'���*������
<�Vu�������Z�SJ��Un���������V5���_*���7@cJi9���U
P�R�;^���n3��K���3�n��RZ�@P����������Vu�0#?�Tl9��"^~����b����������������rkU#x/���*�V�vP�;^���F�^ayGPn�jD����>�L0/n���w���UM�������Z%��$x���c����{�k�Ze�^auG�n�2zo���V��xqe����l��^aqG�n���C��;	�E�=���,[���+����UA�-��>�H0/����w���UE��v�����V�{�[+\�Aq�x-[���+������{��V�{�[+\�Aq�x-[��WX��[���{
�+j��������Z�V
�WX��[������m^��Aq�x-[��W���[����W��	x����zo2l����B3���[�s���^���t>���&���t������Z����rx�[��5|t}�5l�N�bF�{7�����������Z�������V��0#���rku��������Z�+x/��������^���^qN��aE�����6o���w����N��{�8&|�
���rx�[�s���w�������{�8Dz
^�^J��Un��=���zo6l����B3x�[�s���������=>���f������Q�^������Q�^Q�f�M��������:zo�W��:zo�W��)x�{S�{�ek��{����x3zo�W��x3zo�zo�l����{�8?z������z��x����������{��+L�������>��4oA�-}��l�
zo��W�<oE�-��>��3oE��]�u�emUQ|+/����)|Q|� �v���{���������:�|O�|���3��h��d���UC�=��������6^}���3�6T�&��vqu�����������}/�}w���B���}��g0_t����n1����
��\]�><(-�W��j|zP�_���9�!�	C�rw�|xPZ��rw�p����5,��>m1$?b(*�W������*�W
7�P�_�����!���Q��j��|�u���|q����5���Z1$?\7*�W-@uJi9���F�]2�����j����t���_��)���*�
��P�;_g�_�
F`6a�LT����)���*�
��P�_����0�	ke�r�v(O)-�W��h�P��v��W-�����U���Q�_q����Q��v��W-��
�e�r��o���������������UF�V�D��*��f��z�w�P�_��*��
�e�vu��f��z���P�_���@���$�������f���
��P�_�����
�e�vU������y0_\+Cq;|-����+��I��UE����f�m�
��P�_���D���$���D�=y�����.���w����j�������_5����o��xa0_�,Cq;|-���W�0#����{��^��f���
W�P�_���Z��3�	����Ki�/��{-����������!y�Ohf�u+��W����/���5��.W1��������)-�W���<�/���5��.`H�������RZ�|Azvs�+>��{��ZA�)�':��W`J��n������
�6XW���(g`����]a]��g�(�a�umC�
,��3o������a]80��6����cH���p���r��K�k	��w��a������`��8�G����b]-8�-x5l���y���ZpnA���N�P�S_�W�+�'^��&p����k��K�Sg�������������`�
�=8,��:�����ZYz�!x�v�u�����N\������MVA.�k7Y=�,��=��=x�l�*zp�=Xng�(�Ua����E�����?|���%����x�W���Fp�e�dX�.6��2|ve��/�c�6T��Wa�����7����bS�6t��u���G��&�x���|/T�&���e�>���"|uE��/�c�^����r8���G>~v\��s������iot_�=��[���qDb8����'�{\nX�2]X=���F����c��#
����-L����>n8����3�iot_;K�'�(��Yt��0�z~J����~�z������1���QZ@���Woa���S2�1�|�-����S*�����A��n{��.���|r�0/��y����b�w��Q���t���t;���!�O�����3�q;�!���(L�u���[�|w~H�����|a��{��K�
3
�x�nm��u�#_~H��d���|c�|_�1�oD��������	�7
�+N���7������8�c,���+m���)|Q~� ���|3�o����c8���������7��faI���h��k�/����@����������!,�P>���{t���1c��_i����
�o�wU�.(��/���UE�V�8����W^���������������:��M4N��:�O��)�3�_���g�_�1�/�����k�W
���W�B>�oC�m]�}q�X�
�W�D����������1��u-xvW�_�1����+m�������{���_P��,�]�_�1�����o2Rh��r��m A:����)���t]�}q�X���Bs|��+��).�W�������g����p���f��+�W���R���/S{�_�{lX`��cF��r��V�_����e
����6X.,�Q0`��`�Lq?S�L@�)��a��B���+7Xn�XP`���x��w����*f�X��z�F�7�X��5��p;80����b�a�����������)��_=�7��������|#:pXl�g����Q��`W��_�	%8v%��!c'��$H��\b����;���9���S��_�1pFN���-VF��-h��C������8�c,�-8�j�XZ��[��z�)�;�����8�c,��|�j�X����]A.]~q�`�h�E0�U���h�E0`q��/��vx���*
px���N�*	�6����e�u���k7X'
�)]�V~��5��/��VCn�kX
�	,�*���B�m]�
����{	������W\U<�/�����`X`�e�'(���
u_���������|3������w����w+f����;�����t���=4�q�|
�+�f��)�W����e�=�F8����=4�q�|
�+�/�(���|��|����h��/��y�{�kX_�����^�����S���W�	p�������5��|(�Q�+�S��w����~��|a	�{�;_���o3
#x�r�7hO)�g^Q��v�����5������QZE��+�C{Jq9�U��a�{�;_���G�_/m�	���������_�d��E��]���+���E4b�0�oB�M��>�?�oB�M]��,����+����������}0�,�������Y�W�WZC�i�W�o�C<��?����{t�w����_i���_����_�pzJ�Q�K�7������7�������g����[���Y�W�WZA�i�W����+NO�{�����n�����+m���������W<�������]��,����+m��������x�}p}r4_����_���B����l�����{	�+^���B��lX`�
���fS.����~�����Lyo�w�k].�(-bUn�V�`����)�(0��6��VwbFi�r��zP`����S{p`�{l�a��`F�����f^��)�gn�O��S�;`�k]3f$xW.��$��~�
������Z�n�b�,�Bs��[�5�S��t�So>����5���Sh�r��n�������JZ������a���+f<X\74�Lq9��E���S�;`�"k�3
,��8�G���G����`�&k���Q�`�&kM��Q�`��k
����l�d%��$y�v��������A��=8w=8Z6Y=8,����@��?�J9���|t58ZYj�!h�8
_�����W)�-h�G���e�U���`���z3���"���>^+Zp�Zp���*Zp,X|�k��\��`���\�-k�%�
,�����D	>y	o�O�{��]��-VC>�]��������/��
�u8Z�X
�	
,�����Bn��7��������G��B�d�������x���h(���a��3J���+������~�U�)�q
��6���+�Q�G�\a�3�������'�
+x���4�]3{���������}4�����
+���V����WhP).��}�p
���5��B���AZJ#�<��7@�Jq?3�m��+Tl�a�m����;�*���K���q
���5����0�0�7)wXa���r�>�-���m4�����
����4�V�+���ezq����n���w��V����N���a��v��������X!�K;i�v�������N���m4���������N�K��8�`d�`������[�X:����%��@>���/$�GCyo��e�UP���4.k�X%�H+#�kJ�HCy��-[��,����-VE	���u�h��k����:���`�Y��:��Oii��U��;i(��e�u�K�i�v��P�Oik��]��Ki(��e������4�h��/��&��{0n���w��E��,����E��|	,��x[����g�&k[��)�g��	��<��r��=xs^���a��9�`
�Vn�6Lq9��o�m~����`�&k������dm<��r���8�|����`�&k[W�(y�r��������dm+x0��v�a���!y�R�)��0��Z�TnD��vvY[�0$o�~Q���mE��	?�e(�
D��vvY�vbH�����em;�0������'��"Lq;�
��m/�7a�(wY�&Lq�+�3����uE�-�]���#o�~Q����&y���P�cW��b�em	M8�&��.kKh��7�']�X�E8uE�-�]VF��	�E���h��7�']�`�(��+�n���4����_���M��M�{�=���"|0"l�e�Ca�.��^�4�P�5�0lYe��"i�v�UQ��p ��b�V��k���e�U�����N��:��+��O���~���g���e�u�������F>�a�����
=��{��l�zp<X�\>pCn����f��zp�{��l�.��K�`�r��z�%����M�����l�d�����}5�)7Y� �3��M|����w��M�����y��d�>@(�g^���P�`�&k�C�S��Sn�v �3/����j(n�a��������r3�P�R����X�����v6Y��0$?��;�&k+fh�/����j(n�a����!�I�����7(R)�g^���P�;`o�d���!�}5^���7hR)�g���*w�TCy;�
��}�i����F�41��M*���*��*w�TCq;�
��=�k�W����"y�u��"�"�
��=�k�I63'�$�����a�TCq;�-���",,��^���(�Ya����qS
�����aaa���U��"|"�`�X�����v[VY����F�3pA>���w�P�`�*��+k����*�p�DX���]5�����(����_�`]�(�UX'!�70.�����U��,���^��:��O���[�3���{�ZVY
=XXZ�W�*��7���[�S�����M��,l���v�u�_���zg�}5�����z������MV\��)�g��N�`��l�dE�`H��W�&+:�`���[�3;�`��l�dE�0����r����y�o�����)n�a�}�����MV\��)�gn����S�`�&+��<X��;0x0���������=�w����w�/1C�b��c�2+Pa�����3o�]W�_�=�"L�9��UV�@�)���t�{�����k_����F�4X���;h0�����xw�`�{���W��x�����C0f��(�Q�`�B��%8v%��/�c�&T�((�8c��
�����P�SW�_��</
pX�1oFN�+��1����v<oF������V��{��fI�+�x��]�}�x,����W�;/��!���goA�=������[�{������xzo�W��������k'�c�V�*��8�f���[���^+�oe^	6�{��V�|��3��h��`��G���{2�
�6T�SR_�����6A}�[�3�6T�������}��������{I���\]��W������P~/A~7��*-��q	�+^���7���{�k�]��aF~,����������~����������W�U��O%��ry�<|zP��\����P�;_��*�3��y���^%��3�wg���4�����J+��L���)�Wi����~�����������W)���$����r����3�w�����ay�~q���0#?��o��U��=�����;�/����w���U�=f�l��U��=�����;�/n���w���U�f��l��U����3Wwg���4�����J�WXO�7��*%��(��xsw_�KCq�|
������4~���2�o�WlOg�J�����[XX�N��qSS�gI��J\KCq�|-�XZN�kX
�!	�vA�[i(���e�UP���4~�.�

p�X����4������(��n�kX�
�`=�X�������ZX'
������g�=Q�OA�l'�W�P���)�VC��]��j(��`�W|'\ICy��-��,,�y{N��/4���������K������ZX
������V^P�/^���?o^@)��a��3J���_����2x?>>������������x�/�f�F��*;�_������h,^���u����c�z�_
��U.������������u����c��3
�������R����8���
�Kq�|
��<f�7*wW9��R����8�o���w���U��(�oT����Kq?�f���/���5����0���Q����G�����j��;�/����0���^1���Q������~���|#�o��o0��rD��������(�Q8�_m��7�������*'��$��vw��~�p�+��8�oF�M]�
��UF����*�~�:�_�?�C���������7o�����z��������O�������?wu����������?���?��������$��o8���#��f����WF�
������?�H�������?
f�����a��5����a4I����wJ���/���{�0�{�kY�]�;���$����N����/�N�{��c��4�`��xsH�1I��;�8��c��Ag�������c�<&)7~���y��2��x s�d�a�w���!�$�����C8��_����g�=�	����'2�t"���Od�DF|t_<�9�'2�a�w���!��$�����C:�_��Od����f��x"sH'2I��;�D��Nd��Ag����"�6~����LRn�<�9��e�|�D����l����'2�t"����x"sH'2���3�����?����Od�D&+�W������2��x"s�Od6�����C:������'2�t"#�:�/����mF�_�`X?x�x"s|q"Cgd�<"�yd���c���������KJ$�X|=��7���<����y����mB|sR��+h�o�m^E�(�M�k�^���4�Dd��n���6m��m����h��	qo��'�DdB|�y����2q�e���;Q&N^&��'3�6t�Sp	���x�D���n��5t������d
^T�&����;�;_����e�w�K\�K��Of��P%.�r��U�X�e���W�%v�.�,������,p�Fi����M|K��'�=I�
���fN�>.��up�Fi?�b��^i�����+�cF� ��{,c�z0_J���x��zP_�{�kX��u���A���X��]A})����
����R�;_��hem�Q8H���X��#_a��x�����x�/���5l�J��QZ���w����pn9�e(�
�����We;0�4�C/�/���{0o0�}�G�7_����`��{�E��Ki�����H�N}(����zo4��JD���Re��7���`��������
k��P|� ���UI(�I_u�	�7u�7Z�V�7��+n,��7��f^|
���{s�{�emu��f�{��E3������{�`�=�{���F���@�=x���[�{�{�qPS~|zo�zo���
zo��W�W4oE�-_��o��������������^q]����U�=��vN9�{k�{�eku��������f�=�{O�����9����}��l��o��W<������6��Iq���(��/�������x�ef��P|/��Iq�������dX[�e�'(��rm��U����~%�[����w���Uu3��[��~^���������G���5����0#?�E�ug���^���Ac{���������V���?A����[�:SJ��S���BiJq�x
k������OP���:SJ������7@iJq�x
k�2f������P�RZ&����c�nv������L������w����~-x�v������;���x�3��P�RZ���O|����agJx
k�W����x�k�Q|#/����)��#�o���amU�o��W��=oB�M����n��M(��+����J(�I_��*��&^|�W���7w�7[�V�7��][��������=�{���f���@�=x���xz��{������t�7[�V����+��������+��8oE�-]����UE�������g������^�����V'zo�zo�l�N����^q���'z��5y���{v�7[�V
����W&=oC�m����_�c����{�k�Z]����q���z��{���8�;���{�kY[](����-�	|�����W��z������w��������_q������r/pk�8�/���u�aqu��!�U.�N�Ki��^���������:}����*7W����_�������u��-������R�O��+�/����hO�9����k�n1,���K�?� 3�_J���������n1l��m�������g���)-3�N������R�_������X�3>��Li��u�;0��6,��������[��
��������c���b�`�8�
,�o9�oB��?X3�oBN�6XgBN��/\�����o��:������2p�
X�x��E��G����@�}v�
��|��`h�o�Q���YP���;���A����\x6��p�����*p�
X�8pE���������+*p�+����NT��+p���NT�Sx�������OT�������:Q�O^���R37T�S����A7T��W`g�a5T��+��!7���
��S`m�*��W`gYa]�����g��m�O��W�������
��P�_�
�-C�S����)|����~�����`��v�VX��H�&,���Vs��Ai��
������kXa531��i&*WX�������eC?n���w����j+�l��q��+�������������l�a��bHa��r����������p����5����0$?s7)WXm���~5?��e��vVXm�0$?u7)WXm_0?�=��1�+������V�O���M�V����������M3�����jX�8��+�Q�#�����)|q����5��ZBV��A����O���� *p�U������y���_��[������������'�@~��������O���������������N����c��/����N���S����������Z�������_Zp�s�
z~�����.�kw������r�w-X�\|m�`����y��=���5����`H��O�����x���[2���rps��v��~�����&��:�/�.���+����{|v��k�a�wyh^(�'�o��C�Bi??�f,�u�G�����~�
�����Q3����P�O|zL�^>����������!��k��Q3��](����������5l���aH��ZVn��
jJ��w/��x7��Fi;x
;�k�0$m-+w~��pmM���k�����������\�]��2�\,:���(��/��a�wE��pV��v%���{p�x,���P����y���m�SDN�g�+�'���\-�8�����z,���y��
VF��?�X<����������t����_������!����L�����k����-(�� ���UA�-�k[�4��[P~KW~_��<�nE�-��jWW��JcK��Vt��u���8���[y��o��{��VaQ��H��D�=������X�'z��{�[�����{�����U\
����4�m����^�hWzo~�?���{��U��Py/^y��][]���p��\[�'>S��D3�o{U�=4�W��z������_���/0��=n�u-C�.B����/��vVoa
�u��ZO�������q;�r��
2��>�W��z���^�Rn���4|v����j+��+f�_�r�no��.��[�+�Voa*<������,C��aF�e-��6Wo�6��������0<������,K�f���r�nw������nU����%xv�����Y�|�3��j9�[^��=��e�*�Wo�vxv�����Y�|���W���m���\�w���Z��+������w�v��[F�����/���Woa�#���r}����{���~�e�7����>�W��z���x�]�����{���~�e�7����>�W��������'W�E���{~?�2�{����>�W��:��W���@���{~?�2�[�oS�����_�������_������s-K������_����*�o�W������q��[�|+��m���|�����
���_����i��[�|O�����/�j�W'����oP����m�����!���{����=��UC�m�����B��
{~?�2�{���F>�W����/��v��������-;�n���_���-������_�������a����o�����).w��cNC�:�_�{+����(d�W��6������t���)?�������W�_�Q�_�
����|y�}2�o�k�o��)���a��3
�+^a��7��R�������������W.�(��x�m
_�_������x������/N��w���^���m������}<�v�����/��w���_���������}<�������/��7��FA�l3�F��(������������a}��o�W��6�oB�M��u=J�������UF�M���7�f��������}<�2�o���e}�Q�������{��f^����;P������@�=�o���[P^7��AWPKW�e}UP����
�)|Q���Q�x�U�����`Y_U��*��x�m���[�m����'�o��o���N��S�_���'������~<����������6�������x����������,����I���_]�����zu��^]�
���_<>A��l��>=(.�W����q�=���a�������
�||zP\��v�a��{�;_�����1f���7�f��+���b>�v>�/,�y�{�k�_y_1�0vW��6��
�)���_}�<�����3�qo|7����f��G�S�B{Jq���=�S~~a��{�;_������3N<b��7@{Jq��W~?�~�a��{�;_���o;d��8��u�
�S������^���q�=���a�����3�'��;���I������W������5��|��QZ;�\_�����>��7v�w3��|B�����'�3�&����o|�w��oB�M]��,����+��OXg�������'�����������e}�Q��3�	���o�������|����������+��OX��E�=x�}2=g,���{�����*������u���[x�}2=g,���[���[�W�W�=���|+�o�W��2_QkWw���D���8��u����������|O������e}����3N<a�����6��L�������������+��q�	����������c�^��W�w���B���8��u�uA���}p=v(�u���w�����T�(��r�:�_���}p=v,_�Kq�|
����Q��]��Z�/��J����������W����_��j����+���������a��������_�+�/�e��h�~��>����Wk�Q��]��Z�/�e�j�~��_�{�
��u��Q��]��Z7�_����~�h��)���a��f�wW������2|����;�/���5����aF�w��j�+���W��2�oD��]�����������|�o��W��2�oB�M]������������UB�M��>�4��2�o��o���2�o��W��������'����=�s��eu����F���@�=x�}2i0_��������*�����Q��*�����'����-�������UE�-��F�����V���G�������Z�W'�o�7j�W'��)���}�����g��eu�����F�����������oC�m]�M��UC�m��F���B�m��>�~4����{u�7Y�W��%�o���.��K�_��7�P�;_��*,0"3�g���`�����e�j���y�����W���� ��q��3�:����_��7�P�;_��*x���3N|Eo_����}#���{�k�_�5`F~�/?<�|WhO).s��=�*���{�k�_��1#?��%��*hO).�W{�U��3�����
����3��U��=�����X��z�����Wak�����	D3�����1���)|q�������U�+f�����_��)�e�3h���z�����W!��
h\R��BD������[S����{�k�_���+,�qI��
	�7	�!��,H�{���[XX�@��v��Q����������s���e�u�+h\�n�4�CZ��}�p������
*����%�
��i?������w��VE�����aUt�*,��������[�X%X�B��v�u�WaC�W?e�4�����:���54.k�X
-�VDx�c�@Cy��-k��,��qY��j��M������\ACyo��bYd](��&����E�D�k�t���+�n1���L�Rs����m��a����r�����[���)�pV.�6*Lq9��e��@�)o��a��y�!��m����).GX���<�0��6���u���+�Y�
2Lq����\��v�Y��0�$��u�<�eX|�b
�.Lq;�
��-T�����M��S\��+��.Lq;�
��m;0$/�~Q���
d��2����m����qa�:k���)5X���vpa������E���Qa�:k����Wa�(�Y[D��
?�^�F�}v�m����#o�~Qn���&�x�M�	N(��/�����(��a�h�YE8�",^*�8���;�.�@���E��:�����;'S��G���e�u���E��*�������)�zp�{��l�
zp�<X�������`����=��=�Y6Y=�J��dU��*
?8��-�D�}v�M��|
����=��=X<
�������;�&��7���v�������I������`�&�Bn�;�&�B�xOB����/��
��}Y�
,�E����).�,�� ��r�{'�
���9��(����|�P\���+h;������]��.�O)�N���}@��M�0d
a\PCy;�
���������r�����R\������+j(o��a���C��z�Sn��e*��k��qI
��6����1$?�����N!m*��k��qM
��6���
�i���/��;��u*��^V�.��j(o��a���0Qs��x�m��w�S).GX��4���������O�����3G��(��X�L!��j(o��a��'�aag����A8�'��t��P�����v�Z6Z	mX�Y���qg��h����;���e5���w���2������o���{�g���\����P�a�>�@��x�u����!�������qa
�����
��������N!�.\��)�qe
�����*��������� \������,w\ZCy;�-��]X�]���qg>��O���c�h����lYg5Taay������
7^��E�����5�������P���5~�.�.���c�����5���p�����C~	�>�!��k���f�]��]��`����.Lio?��}�J7.'FLxUn�����w,�����	S����C���
F<xUn����_�����S����A���3F,xUn������J�/�q���������tW0`���Un��
Lq��^q���C���]W�_��<o���^�
+�_���8���>����v<���bD�~W�+n`�������R��������F��W���;�/��_\��w���7���{aDI}�����.E���(����9�X��7
�+._�8��F�~�A'���?6,�bB�M�����g���I�_����73W�
g��,���~y
`��,�\o��x�����=P�A����3�(�� �Of����
��?���
*pX\�<pA.�?�>0*p�[VX��+��\~2�},��\�g��%��\	�%��|
�d��X�'J���
m�b�h��`�A��jh��`�O������[��-k���$���.��&X�x�d
�-��[�e�u�_�+�Xi��K�`����	W�P��%�+-3�S����c�>@(.X����k(��a��L�L���)�X����k���pa
��6����i�IX[�7�+y���`��U����w��MVZa�f���M��J+�����d%�WCy��
��V��O���r������d%�WCy��
���9��O���r��6(R).X��J�����6Yi�0#?��o�MV�W,,V/�L��j(��a���3��z���d�Lq9��MV�}5�����J=X�Z�7�&+E��(x�x�d
`�WCy��
�������5~�n�zp<X�m20������U,���,l���v��������m�)�q_
���l��`ak�����=�<X�o20z�����r�\����5~�n�
zp<X�o20����w��MVE���]�����U�`���������[6Y=X�Z�w�&�D����M��}5�����:����5~�n�z�)x�x�d
`�WCy��-���,l���v��������M����w��M��,l�y{N��/��K�`�&+/��W��
����Sh�r���`����L�|x}6l����`�&+;�`���n��k������W�(xpTn�����t,�
����)��a��W���=V^��)n?��w��w��-V^/�(8pTn�rX/��x,�Li�x
;�N�(pT���Lq����X��/���5l��V0���Q����/���{`�c��]�~�a�w�_
��U����Kq?=�l,����u�7�W9��F�}�r{�#�o�W��7pB��]�
��UN��Ip���^�������������k�^et�$��v{��}�p,���8�����Z�W�o��W��:�~�X��7���{t�w�l���C�_q���������~S4��5����*h�E0���_U4�"�?-;pE�]�,��\N�
VE�����o
�-�v-x���N��S����a�h��p,������]�,[���N�-VCn�������[��7��B�N�=��|	,���=��z�f�dK�G(xpRn��>@(.X��:p5
��6l��1#?��'�&�p�Bq9��M���i(��a�u�3���|Rn� �3��O��i(��a�u����>�j�r�%�������:=�O�����po����x��������?��/?������?���_��������o����O����1�����W���"4���~����~����xm���8�g"B7I����nX������[����#B5Iq?���i����$6,��S))4X��;T��3o�O�><�&	���/��<��~�3L���_~n������/��s�����������o�������DD���-H$��[>�LX?�L�������"���L��^�kz�~M�
������"���Hy���i:��^����P�)�+~M�����azT��^�M)���5��C���T>��	�(���az�3
�4>�Q�m('?���;�c�6T��W
�&��R4a���5�h���W�'����{�Q��QX��%,���+�`�����7���-8������e�(�)�_|��X��-8���2|������r�N|
k��f��h����|q�9�e�jR����6����1�����Q8���2�`�8���~��c�������m�9�5,���`F�����@����s�����T�����m�96��W���c���
���).X{�Z����6��6X%T����Jr
`�}Nq9�x,`~^n��	�a�U�3
�j�
V����y'�AC9�/�>/�������*;p�
@���m�8���r?��C�
�>/������*�6���"��q�9��k��*8���f�`��$t���/O����s��qi��,8���f�`�+������M�S��s��V�����m�9�l�����/��X8���~���?w�������6�����%_�����/���X8���~��:�/N>/�������*(����_�U��p�9��Z�Y,8���&�`������X������kyg����r�|N�-k�-�6����5>��_�;�'����slYc5�����/��X8���2�������6���Z�XJ�m��|�k,�{Nq�cj��~|^n��	�a�U���P�`��.��Aq��������6��������"��������$I���>@(��a�U����)��)�=|�P\�'X�(�z���w��5V�
3��S�5�S��C
���o
�jT�{�
{��V���N�HN�E���<p����Y5����"���jT��������{TlXd�
F�Q�O��3�=*��j�E������;�����x�g
�zT���������TlXd�0#?CT|�g
��%�>��=8v=86Y5�G����~�N��I�`�Y5���g�&+�'�������%~PU����s���e��������M���%Vo�������M��|�,���������.������MVA.��k$�F.�?ymt���������������M��������'���|�������:��Oa��z�u����[8���>��������j(�'/��z��P�� ��"�)��p���[,��M��&,N��B�B�wqN!|�	_]v�a�u.������!3�8��r��������9���
��si�wa���)�q:��.Vj������� �w��u��*�dX��:q:��_\~K'���I���
���R�a�>��I��!��Gx���'����a�>�\����p�_�k�Y�
6Lq��������cl���:�0�fk�Yg���3����/����:��!y�>M��S�O��x����}��{���x�i
�\��r���o��;�0��6����`H����OSGt�(����
���c���a�uFt����x�i
��.��oO���%���S���e���������)�3�p��?�?;�pF�}v�}VF������F�����hmC���������:P�A����U��U8|�r,��&|�M�YvYM�&��e4�����$���F�-���"\x�>M�[Q�+/�.G��[��+���M��\y/NL�{���?��5����|�-�[Y
-��-X�61�oCn�?��5�oCn}��=VCn���&���������C�^h�W���e�u�_��W&f�m~z\���'�m����v�vXm)��T�;������~��������v�6X�e�O*��
Vs��Aq?qm{_�UCi;|
���a�fV�D���y�������=�/.������U[a�fv�D������R�O������������a���!�a�Q��z��1����|qU
���5����0$?�W��:���)���}�|qS
���5���vaHaa�v���|�)�F�����j(���j�_������^q�����~��������v��W-��
�j�I�S�&�������C��������UK�������_%����������55��������������_e�������H
��P�a��@��$��@>xvb�9�������VA�$���������KW�P�`���k�z�UQ�+/�O�����j(���~���y���8�)�Kk�z�u�W^�������P���k����=����5Y��j��'��O������j(�
�k_���m������^c]����`��	n���7��}�K�B	��d��B	��C`e���|u%����C�^(0ef�jWX�
Lq?}Ev,]����
�k����u������]`]���~��L������k��c��#��+��3�������'���`���F�����tW�y�_��Bw���L:m�+h/���}��w0�#����k�+����������B�������|����n��
���~%St�
���v�=2���(8�vcu������������R���C�{����:)�$����������=><���pD�����E���"�o�k�+������aou%t����<�h
������_��*������eu�Q����)�3�o�����W8��~-��
8���Q����A�_�?�C>~U�?}��o���������������O�������K�7���w���������������}��?>�_���+_������Z]����6����~����X?�#���X�����?��G���{��A�M�PS������C�=/w�I�w�[�����f���n_1����\���Kx>��{��0���P�+�Vf�>�����x;�|������0<��-v_Z2���f���8]�) `������[�/�/3�Uo�N��W�nQ��V�=N|������t;<���v_[2p.���v�x�1������^��{K���r���%c3
��x�1p�_�j��_]��������K�.2��@�.�������\�������+zp<X<���W���r��=�v=���%c���U�`�d
�=��=�+�]{�|v=���%c7��S�`�d
���Vo�zp�{�e����������zp<X�������[6Yz�%x��n���� ���v�������z�,���Q����dy� ����dy ������`Fa��X��� ����
#',��|x�B�
�,�3d���q�����'���a�X����� ����k����kM���^�I���?l8,���H%��M�d��5���8@�Jy?�0p���E*6l���bFa��X�O�A�Jy?�0�E*��6l���0��t\�����I���?lx�"���6Y~�0��s\����+�� =9l8���6Y>�G���:
��y~r�0pBN}6l�|BN��u�������'�
cg�����`�de��,y�z��������>��s���e�u���7Yz�!x�z�U�����&�����:
��\x~r�00zp�zp�l�*zp<X���������'�
cW�����`�d���U��U��:��O���tS���g���e�u�����MVC>y~2�d,����,����^����~������.�����>��������1��M���0o��1h@�����?x!s��D8�;_�
o��	��/�������v�`��{���������'6,�Lp��.��p���A0cW�/y`��/������.��p���A0�_�����/�6��/�����`��/������3�	���mt;6,�p��.�Lp���A0c78�������0��=4�;P��0��=/O�|&\p�n��	�a�`��{h�v�������k2�����v�N�
��
����k��r����4�x�v��N�
��
f����k�Ls����4�������a���8���`�klt����4�V�����a���D���`�&k����y�����z���{�a���P���`�&k����y����[�n��	�a���T���`�&k����y���������l7l�6�����dm0��=�Wr�x�����Dwl�dm0��=4X���`��{�������o�	�a��E��(x���dm	=�6��������o�	�a��%��$x���d%���\w���[F�Mt'��MVF��o�MVF��u7�i���������:����7�&�@�OY��i���G��w�&���o�MVA.���4�
zp�z�n�dU��"x���dU���{��M�����[6Y'zp<xSo�N����`���'z���`�&�D>�����|�,�������G�&��7�����=��,^���B��-��=��<X�����/���K�3�~�\]��M���������d�|�P^�v��;��;C=6Y��7)4X���|�P^�v���^w�z4l�vo<Rh�v��{���`�&k�
^w�z4l��u����]���WhR)o?�x�w
��T�{l�d��aFa����d��T���n��E*��6l��paFa����d�[@��u�R���������3
3�w�&k��I��`�&k��H��w��M���(�����=B�Jy��M��^��K�M�������M���#�����)�zp�zp2l����$�n����x/�N���S���e�������Q�������`�R����������:�����Q��:�������=��zp�l�
z�!xpTo�
zp<X��*��������*��E����dU���{�x�w
��\��,���\��M��\y/�N|��]N�M��|
����|�,^������[6Y
=�	�����x/�N|���[6Yz�%xpTo�.����`�R��qA���
����Sh�v��`���n�����u=86Y���Q�`�&+:�`���n����w��MV�3
�������)/X���<���6Y�_�Q����d�5 `�������S�;`�&+�'f<8i7Y1�S^�v�x0��6l�b(�Q����d�
<������z����)��a���N�MV���)/X���������l�d�<�Bs������S^�v�������MV���Q����d��y/����l�d��N�MVL���������|jp�j�[,����$Vo�2zp�=�� ���3jp�j�[,����%Vo����{�x-���=��z�[,��E�D8�WYE��EX��?�pA.]v�e�U���`�Y���h��7a�d��2qE�]v�e�U�����Y������wa�d��X�'�p���[,��m�l8��Y'�����{�>i,��:|vu�-��VCn�g�F��7����J������������`�Y�����/������|��P�/F�
K����%���VZ�c��2����n������VrCJ;l�[���S��2��������w����J����2��]k%�"a~����������v�Z��R����{��B�Jy������6�C���Jk���)�$�P�R^����p�
6�C���J�k&i����k��*���{�1<��!�J�l�j�
�k&i����j�
zU�����Sx,`�`Ci;�
;���|�$��Y�;��C�Jy�/	>�n���T}'lXi��bHa���]i��6�>���6�C���J	mX�d�h7Z)�
'a���[Zc	���!l�h%�ai����he��$l�xpMk,a�bCq;�-��6,��Y��m8K��	��{'�-�mXXf��tZe�h���gB�0�������VA���E��*h�EX4��di,a\dCq;�-��:,������Bx�>����P���:��o��[����������������?��/?�;����������w��?���?�������������c��/>�<��������Z�v����~���T.����C(�l�'��P��G,R�`���_{G�6����U��w����`3l�l��#��	>�(/w��M8{|x��a
xd�`��a�����Fy�oV���^����5�q@�K�9��5�q@�Ky�x��>�~��
k���R(zE��B�@�Ky�x�5�Q������5�Q��^Q���P�R�O��7�p����v��G�0�P��obL!|�H�/z��7��	E/��^
k��<1�P��>2�pe��L<��h������a
x4��&��v
x4��������}��}x5��}�|X��)�/����a����P�eA��>�vZe��a�N�,�������i������j�i>L�9���Vq�������i����}x5���_1�����L!���)o?���i>Lq;�
;��:)���#S�����!��i�|��~��w����w�/ANc���9%�d
��"d^�W�Z�Pb�{�1~���X������B2��BLy���V�@�)���k_����
FtX��9|A�)/�W��*{�������H����Sf��v�Uv�a����.�J����2�����|#�p�TX��*U8�*�j�Y%�
��
��%z,��"�Ed
��"�x^����"��"����X�58	,j��58�^ee���������=P�� ���L�{���YJ��=~�Hx0_��C�_�@��-����A��*���$����X��,*�����[��\�A��+pXt�9���+o�A��:��+sA���
|

,J��'*��+pP��*���n��Mp`�B�n��M8~�#%|���y�e�u�_���XZ�%?��1�0j��?6����J��c�>C(���Q�#�>B(��a�U�����z/���>C(/������|�P�;`�&��3�c���"S{�����,��������VY�7������L��������
E*��6���Z1#?���*2p�*��2����j�&����rvY5��P��_�sC�Jy??N.�����J}g���(4X���t����	�>-�����U��)�!��)Qh�v�Uw�R)/X����><�R���p��_�����)�#zp�=8h����������zp�<X���	=8��i����������3zp�<X��������M���f�����gu��F�>��3��O��E�=��z���:�>�������)�z�!,P�|�K����[VYE�"��WYE��"�������[VYE�
"��WYE��",�U3���&\�&������O4�S0�M��:��O����j�F>�*��������)���^f5T�������c���*��*������/T�&���^f]����.f��M�����c:��=4�K0a�����&Ly���L��$|.����N���:��%�.�N�"aa�p��w������
S�;`�2�t3J*�]f�T��2���u�X�L����Y�?0�`��v�uz0a��	?�+��T?��^W�W�6�\A�)4GX��:WPa���Lx��pp���&lXf�L�B�~��L��r�?n�����E���:����O��S^�w���r���
L����t�Y��1�`��v�u�`������Z�����A�)��a�u�3
*�kwYgD��
?�g8pD�]�]����`��v�u&4�(���fv��pBN]�eVBN�	��eVFN�	�[fg�h��k�����h�Y2a�.+�	g����0�����,��=��<X��:��������|t58X6Y5�����\
V���\�,���\
_����WA��>pE�}�,�N��*X�x�i
�-��-������O���o��EVC>��EVCn���6�����Y�X
-�	�{�-���}%��P���o�5��|	�k�����K���r(��Kk(���a�����QEQ��j>?(o?���r,_\YCi�|
K���(*��%Vs��Ay9G����pe
��6l�����M�[���]�>@(/G��w���qe
��6���
35��������^�F���M�`�>=�Q��a��B���W�V���T��~�=z,a�XCy��
���y�(�q/=M!�A�Jy9��I�%�;k(���a���3
{\�[OS���R^�����c	���{'lXf��aFa�k�.�Z�H����l0K��P�����jmXX^��v���p�m�=�`8�0n���w��}VK���������>���������w���VF����^he��,,�����pw
���l��aa��O����6|�%��u4\^Cq��-��2,l��iT���}3����P���2��o��[����������������?��/?Q9�������?}�����?���O?�������7�/�6;�_��y�����|���op���o���sY?�3�������o�����]��1C�M�h��+��4��k�������{|x��&�]��1B�]�h����4���x�u����������|��A�(,4���[��oo\|1���'�X�
^w��>���/O0�<Ax��=�����/���b���o��� |j��+��_�_���?�7#��_~��'�>�������"�o��.e���#����]���v}�[�3
G����A����q��#������nw��N�]��`F�`�A�2��|o������+,��vu���u�oQ*�p���H���S���?��L��P�':���:���B�2�S�����e,���v}�����|��mh�{����}��F�����X�
��vy��Yz�x�����:���A�r�O4a?�C���������c�^���:�5l���0#���C�����o������C����g��i�x
�<�\�Q8�}ph,^�"^����u��x�/���5l��;1�p���&�X����~����x=�/��������`F���5��x�|)��_��w
����kX\���B���+�/���h�
�]W|�aq��/����)|�/���\��|��]�|�aq�60_
����w����1�o�g�U�dX\�}����jWn����Gc���������r�aF�}��+�}#���?��7v�7VW.��F^~��S�&�������.c�&�����d�]%�����xt>�oF�M��>�2�oF��]�M��UF�����'os���f^�c�)|�����d�^����������!����j�T��

��`����^�W����A�����\�lY`U����^`U�*�z�\Q�kW��e�u�W�n�z�u���+v�|��]��VC>y^�����7�������-���V/�.�&��j����t(�WW��e�u�_�kX~�O�K���@�G��xK�������K������]`y��9�U���>=(���a������A���>=(.w<��������!6X�'����A���>>(�'�|�/������~��
�_w�����M�S����R�O|�����g����
,f�7?���O).s;��u(��)���5,��>�0#��!hX~����2�'�O��)���u�a���B���v��w�O).w��}�w(P)o��a����!��A���qE���qH��8v�-�%��(�Q�`��'��(H��!�O(��+�n1l�|BN���X	-8	,����#���S���>=	g���k���ce���k�8�j
�58w5�-�E��|���*�B����|�=����?����|1��ziT����1r_��R��6���vs���9_-}0*o��������:?����!$������_z��K(������/�](n�a��^C����]���/���8�Q�%`:�Y��{uv����fk�a�~��~�pp
`���u�'����
6J�����������)�����{?�9��/x(�(5X���Y4 �0�����`�
�]���s��_XW��P�����B�Fq�W����(R�a�����
���(n��_P�Q\������4pI��v�!\����i�a[��pK��-���7��Hy;�
��������k�a����r�\TKx�7�(o��a��!�W����s�U��4�>��P�1�������a�"�p�]x�n�BD���z�J�)��p���3��BBN���uVH(���a}�e812lYge������^ge��,����Sx0a�����e�u�
�v�>�@>x�ZN|�}��}VA>x�����2\~r�i,��2\�2�-��2\xo�L!\Q�/����+�p������*�p\X��:�����O.��%|��}��}��.|
.��g������.�������{�:��7���z���������p����l�.T��W���f]�������-��W_��a��-������fm�0�e>��v��-
^_��a���C�*�����
S��_9��
S�`�6k�C�*�����
S\�GX��6*Ly;�
���_�W���fm���y%O��
S�;������C�*���-�
S\�GX���@�)o��a����!y��m�@�)������|v}^
��m��`�6k�@�).�#��=k����.��Y�.L���m���S\�GX�f�|v}^
��-�G���v��Et�����
GT��W������p�U8i�Y[BN�
g�S�-�
��
��mVFN�
��������Wa}�h�M�w����w�/1�c�"�p�eX��4���2��>T����+��}���@>x��L�[P�^��M��	��	��%z,��\x�M���\V?P�������}����W���3�)x+Zp�-X_�O�������@��{����'�S�������Dzxs�6t�����}���7���K������E��l���������{�7A��+��^^�;�
��/����/� ���Q�������]a�||P������uF����)||zP\���n�v��3��p����"����������v��{�����7�����b�?�
�)��k�W�
*��\�1�����*��sCyJq9���V|x���
�`�+��D�?p����r��+�}s���3\
;�}���������]b��������c�3��L�
�*T��
a�n��:T�{lXc��cF~��X�OQ�����v��G����fb�c�	=8
��c�	=8	�d��X�	=8�=���J����`���B8�'A���K8���[VYE8�",��Sh�Y0�'���>����	�8�c,�M��MX���F>~2�n,��*|tU��c	T����\�O!\������z�U��K��_��1�pE���{���(�U��U���(��+�/��K�D���E��:��O�����m�����C:�nh�'o�nQ/��p�tX��4.���w�����:,��q�z�u�_�����5��N�������6�����������S��;��:Lq��
��T�(��v��0��Z^�t���	VZ��Q�a�]iE:Ly9��_��_���u����t�Bs��+��A�)���x\>���8�c,�t�Bs��+���S^�cX�|\/|z]~qN�X�!`FA����S�a���>;�t���	VZq��Q�a�]i�
t��~�
�m(�
d����Zq_0� �N���;�0���+�c�����������{���
;�:+���*��K�X�M8vM��!c�F4�(���.�bB��	?��5pBN]~qH�X�	E8I"��e%����
C�f�����������Y�`�*+�g^�H�X�Jp�K�e�u��{�"�@	>�3�<0:��w`����{����H���\P�KW��e�UQ����^������W�'/��\��k���e�u�W���z�u���?9.�D	>�,K�%�$X|�z
��|
���_�Zp�Zp�l�Zp,X|�z
�-����
���/���k�������/���O�9���/���\�
8���{l�c��i&iw��)7pZ���2��~��P�;`�+9����5���S;���`�o�	��P�;`�"+y����5���S{���`�o�	w�P�;`�&+�3��z�W��^�H��`�o�	w�P�;`�&+���5���ShR)/X��N�����o�MV�����_��x�&�����.:���{l�d��aFaq��v���G��@���E'�XCq��
���W�(�Ms
�M*�e�,�_������6Y)�{k����F���o������6Y)�{k����N����`��w��P������	[VYEXX\#�f=�pF����0�!�&��&�YvY����F~�z
�M��MX~�y
a�YCy��-���*,l�q�lN!\P����+�S���{'l�fUtaay�ms
��.\y�_a�B7�P�;a�:���k���S�(���a�
�)�qy
���-��mXZa����6|�6,��8�0����w���VC����B��7^�����6��N�������56A�����/���	�}����nXi�|�Bs��+���S����:���O����a��]����N+;�a���w\�v����N�����cF����w
a>Ly?����|���	vZy]0�����V^��)�g�s�Bx��w���V^f�|X����#a������)���a��C���o��V���)/sx���������S�;`�J+oftx����:Ly����������p4l��6L�9���V���)�g^V��;::|z]���V�h�Q��M���m8
6������Y9�
��
G�F+'��(����h��6�K�)��p��p�l�2�plxSo�2�pl�����3�p��p�l���,����hh��`�O�i�%|�
]�����6|6��7Zm�lX,��.h��k����*h�E�a�F��
�tX,��������������U�a�F��W�t��m���O����a�F�D>���}�|X,��n��g��-+��>���+��>�$���p��p���.��&����i]���������B��:�+�cY�	
:�kWZ��!��3�"3~��eCy��
+��9�(����+���g�����������	VZ��0���f�����0dS<�Bw�P�;a�J��'f��tS���R^�c�Ag���l(��a�u�3
�|w�F�P�R�~��7�P�;`�B�3
�|w�B���R^��_�����l(��a�ul0j����]��:6(T)�W�����l(��a�u�0j�����]g;�����=B��U6����:���Q�.j�YGD��
?)���]6�8�YGB��D�2�Hh��7�'U�X������[�Y	EXXh����Sg������c,`\fCq��-���,l�qQ��:��3��O����q�
������`i�MT��
z��{�x�s
`�fCq��-���,����MVA.���?��m6��������J����\yoN��l(��e�u�+m\To�N����`������g���e������6.�7Y
=��,�����P�;`�&�BV���JA��|	��d�6�{l�d]���J������_��f�&�<�������*��!N�UVq �����!�}(`Li;�
���
�D8iWY��S^&��e�X�<��vVY�g)�p�������x�:��W�����n1���
"L�9��UVYA�)/���r,�����z�[��@�)5X��*D��2�?�*n�����*�l+�D8iWYe�����ye����]V���LX��*;�0���m�;�0��6,��~aHI�����F?�:�����Qa�6�DT�(�p�n�JB��
kO�)	]81.lXg��.���uVFN���v��(��/�����(�Y���^ge�����pqg,�m8�m�Y�Y��!�pV������a�=����������*��E���^h�������_
�p����l�*�p|8�7Z}��>��g���>\�>�,+�}�
>��+�}��}�?��3���>|�}�YvZ'��)�pV�������W���p�������p�|X�������^�������;�N�B�$�����"���4��;*n������V]
��'y)�$��!By�x��e��6�C�����lVa��_�;���C��2��[��m(���7����1�U�k��N�z������vkYq�
��6���
c6����/��V]�T�����3�p�����;a�N��C��|���i��*������q�
��6����0$?��/��V��T�����3�0�������V�.�O���v�U�	�6W����N��!l�i�����$_�hwZ5�S^��vkYq�
��6��jD6��E���}8�>�j��w�P�a�N�&�aa��_�;��>�x^�[��;m(n��e������6��wZ}8�>,�%�Bw�P�a�N�@6�x��i�����`�9��������VA6�x��i�����>a�iCq;�-;��>,l��N�������aq�������v[vZ}X�l��z�u�W���	�N��!l�i����f��;��>|�>,'�Bw�P�a�N���m���������aq�������v[vZ�������~M!|�_���'f>������a�u.����#��i��0�ek���[������?|����~�(1� k�Z�%��d�j�t
^W�_�2=��_1� ���_S�zb������qzb�{���W��|W�_���w��_�W�s��7�/}�������/~M�V�������2Lqo|_�=�o81����k_S�n������}���@�)���K_���
FDX|�k_a���|��>���t,<��L�9��U���S����s��������`�%8
,��5�oD	��k
�	%8v�_:�7��&������M����_���9|�S�H�����3
p�X���(�Y`��3�����e�u�g����
�X���<�����%`T�CP`�M�)�*��+�x�h���gA.�y�!��\_��������\����%VE	������\y	��M�	>Q�k�4���:��O������>��O���+cS7���lYc5��&h����
5����B
n����=��|	,�4��|��d��`���W��
���|�����������4p�m6����j�cFan��
��>A(�W�I
��P��M�&��3
c|W�&�y���LU�}���6�{l�d5�0�0�w�n���"`~��8�z
`�fCq��
���V�(�
�MV��R^�W�8.f
a\gCy��
���(�
�UVP�R^���yR�}6��N���j��l�R����A�Jy�_���

��P�;`�.��0a�	;m|����]*�ek��
��P�;`�.�����A��jM8
&,���B��P�;a�2�%Taa���eVK��IPaq��������	[�Y]XZi����.��U�h�)�q�
�����2����&��Y�pVM��n����7W,��mXZi����6|H6��J�����	[ZmXZi���6\V_n�p�
���l�*����fSo�*�p�m���+cp�
���,�N�aq��z�u�
���	q:��a\fCy��-��:,m�����:�$�~���2�{'l�h]���F�M���P�/I����7\fCy��
+�kA6��M����a����	_�0��6����aFA�7�J�r+tX��:����w�����*ftx���.:Ly���/����P�l���6Z�?0�`��o�9���)�g����C	�+>��
�F�Z��)4GX���V�a����ES�O��������0��k7ZW����`4���O����������������S^�]%�s�k��w�����{�(���]i];�0��k�;\;�0��6���3
:�kWZWD���3������������"�ptx�����:��a���+����J+�'A�w�J+�'�tX�����s���e���������9����t:�^i���������>|>��WZ�����{�N�X�}����e�U������z�U���p<�d��`�������e�U�������VE��?y�,��>\�>�YvZ'�p�|X��:��O��au>����o��VC>���VCn�����n������e�������Q������t<�}�������o����>|	>�;�mY�C��}X�J���|����#�=���]���bF~�����=�����x��!�y)�����7o�����z�������O������D/
���������O���?�����������X���u�����{K<������O��>�������O������@�������@���-R����6�������{��}�)�i{���(���]��bF�W�r��
����iV����x<������]������6/.-�C�aa����M!|����[3�+�2&�x������z
��aa����ps���[�/�v��-�?�����n6�����"a�ps�o�=4GX�|�����i��+��Nxz�"����]�%����W|o�t��L��+� ��W��u��rc��
������Er�����0���W�:�d>OrGH�vp�S�K�a����
�	n"��������4p��u�vp��aF�_���!
;��H�/�P�[��H��a;�����|>��8�a?c�����.��������6T�������_W�p�����'tO8��+\��#��aC������|�oqH��
��{BGwe
ix�*y��
���3f��G�t����A�J�^�����W��4l���!��?�����!
/ U%o�a�-kH���W��4l����@�����|C^A�J�N�tn���O�z(UJ
���3��#x��oH�y82V>���y86y8:�7���������}N����-��ANM��N+!'��t����3�pb<�n<2�pn�p�tZy8�'�4\��3�a�c�o���K����5��.�>u	����<,��~�=U���������\��8�S7�?����������{UI����
}���#�#\������@���p-%��pq�YX��!��`�?�-�tK����-�6[X:��� g����|"Z�-���so�'���FK�w!Z����O��{��,.BtK���/$��M���B���7���&����3S�n-8L��.�P�X�����O��{v��,�t�q��`���*8���<�;��)�[���l�,�ttI���=�f��u��z/�:�G�N�O�����l�,�ttG�������|���^�u������8�ro�88�E����R�<��krp2�{�y>Bw
~����������tt����O�xMN���,�|����Q�{^��Y����!/����.��dX���)X�d�88�5���R�
,y��
MV�e����� ��&�~���.^lrp24Y!"G��M�d��L�x:�=lH�	98�9��d����yS��3r0Y����)po�98�9��de��L8X�de�`�����aC
.�������d����`z�sH�9���ttw���7�����li�6�����A�dm��d��������598[��9x�spP7Y;r0Y�����!���{�����:���>u�u �����R��|498[��9��spP7Y'r0����\�-r����li�N�����A�d]��d}��[��|!_M��&�B��LO��(x��B�w:�TjD��w�[lh��i���)0�T����"q{G�E��f�xx��
M��`b����m�f7��+X[t�����;�lh�f%t�`m�5{��H�^���c^<��H��Pe�J��5����4��J�^���c'^<T���
]�<���J��
ix�*q{
k��y�*y
��yq�?�l��.U���>�3/ S%o�aC�5/���D�'��4�l�?����RC^��J�F��:k^���:k��9K�^��:k���	�n2�YsD�}���4�4�4��*bN�����n2�YsBN}�g������i]yo�Q85Q�M�6+#�>���C��������������$�;$l)�
�p!$�.�
�p����n�9�t8��em��d7=�8��
9x�s0=q2�_�	"i�~�������fznqH�;R���`z�dD��D�6���X;20�B�-��@��L������H�F���@&[A���!��H�G���q���6I����a���d'=�8�_����
VwX�
D�6�tX0�	BO-i�B���`m��L��W�����Zpg���4����	x!�:��>�a7��kS�3�X�
�����-����%�g�(p^����M���b->`�>�s�C��@��3���K�F��k	C
��X?~c���{�}�r	��������Z��!	�������!�������?����x�~7<��~i)�{�Gz[����k�R�����
���w�e?}���V�{?+��[����7�+�[��8z�w������lx\�>������=<�yC������L���y�4���V2=�~Ye���������8�
�����V2<����/<��dx����G����q���g��dv=�;�_����q��_���'�9o(�V���q���~qt�JF�=1A��~O�t�/�;o��V����q���~qr�J&����s����8�
�����V28����/�[��8m1�����=6�yC���������o?���s�V27N[��85nmO�s�P��86n%c����!�������{b<�������=4�yC������L���tH�85n%S��?����=3�K��C�V24.�,���qO�N��_��G��`��pf�Jf�Q8�_����qQ���+��[�3�\�4X84n%C��%�0�[�����U������q.X:,����q�i���dj������_���g��`��ph�J��Eu��C�V64N}���C����8,-N�[����n�pj�������Xqj���������q+�=��[��8�q+��[��q���w_=j~��[W��8:n%�������0�>�"N�������(}k�q����������������>iE���5i����{�u����S����XX�v���c����	�]�_{���^ ,��0i����%n��O?c�]�������=C�[o�O�I�d�,q;�~���z`����}���zg����5V��%�g���zg``�[���{����0b��������������.�������������I[a��W�~)��@����������n��I�_��+q��z#rol�~�-���F����m�bD��}�}FO����|c�5����	�7��7�����������������:��
����������������Oa���9#���+`�~�o&��n�
�o���3����oA�-�W���jC�-}����jC��������{��~��`Kw�!�n}����jG��������{���~���_Ky�#��}�����@������|�{�=��1hK{u �}�����D�=����t�{�=��6�Z������oV�W'����_zF{H�����_Ku!�^}�����B��������[�M8!N���6�U�q�����*���D�=s���~q>\j��{q
����x�D��em�p<\"���9�~s�'^��|��p��/��Kd<\��W	��%2����/��K��p/N���_��x������Kd<�������R{:��S8n������p��S0N�K�?%]{o����jR��k���|`���t7i���>�����j���>��u��+-f�OIw���J�S��)X�@�u��������{^aH�������
U�v
�V�)z�x�!�/�������&m��"2p�30]s5����l��RBN}v���J	!8�!�		}�K���S�_�qo�!8�!�M�+#�>�EWC>�)87)��Y�\��s������
bp!�MI)�4)��I7��\�k�
)��)X��6�����/����
1xc���v�����O�����#�M~q�����;�`�nrc
F��$>��&�8�������`0���������O����|"M~q�����'�`�5�!���'�`u�q!�M�"�B��/R)�B���`���)�jS����R�E(�~�zD�y
���=�����,q��
=Vv3
v�+;�`���c8n.�K�z������������>`���Mt����.��ce`F��t����`�����D#�s��u��"+�
32�Y9K��8M4��y������Pd�0XB�
�Yy���s�hH���������d�8XB�c�MV^��%��(��:��k��l���
 ,�{
k���K��9Q4���^�gC��c�������Q8�G��4��c��gC���p$,��eVN����0=S4���0��0l���p"0��uVFN}����4���s��-}VF������*H��O��|y%�ZpA.M^,}VA.�����*H��O��������8\�8�X
�
qx#8�����8�1�~-�w����������w���FkG��;�qxo��b���������:������@>�8�X*�q� 8����8|�7����D>�8�X*�q�$8����8|V�!
_M^,���4|��zG\&��\������N#q��
�V�N�Hv�m�U�B$o/�v���F�����v�H��m�U<�A$o'�����j$n]���*�`F��F[gw������X�-w�H����Pg��4�T�uV	�S%��R0n���u��6��0P��]5.h��2�N���x��3,��F���������k
�2�,`S%o'�����j$n]���*���d]k�vYe�*y;���7{o���F����'�HV���*�D�`���gw�=#]p[���6TY%"��5n�VY%!G�O����a�W#y��
]VIH�dk���]VFN���8�ss���F��
[���(�����2+#
�>
SPq�����[l)�
�0Y\�fu�U�A�'g����5��n��fm��du��CO�4�!o}�G���}���5�*8Z��Y���qt&���wd������n����[7l���a�����	C>��O���a�\#y��-}��4L��8���!
�H�'Y��.,qu�����Y'�0Y`�fu�u!�}��CF�)��F��[��Y�l�qt8����	Y�"����n����6�Y�T0#A�E[gm����B����������f�adt�m��9@a���|��/^������<�����-�6$,y����o����FaC���3^�m��%�����-
K��aC���3^�m�6
K�/�+��(,y�������	3^�u��
K�/�+��,,y��
u�����������5`�����W��`X��
��m�1#�am��E�a��y����xk�a86a8��-"G��:k������!����c������p"0�����0��0��ayo�a85a8Y���0�	��:+#g�Z������#�&'K�U��3a�U]gd��gaO��<���(\�(�,u��(\
���C
��7���s��
Qxk������7�������w���o
�Qxo������w�����:�w���������Q�h�p��Y��AP������(|�o?�=�{>���&gK�u"������1
#��������/���	��Rg]��au�u!_��4=�=����H��aC�������;�iCw��hx��&"y?����q����6Z��1�;[j�����&"y;�d������,;����u��Bk�3f$������=�C$�������6��n��h��c��_�����J��9�?�a�h#y��
��>O�����Jk�A�J��9�?�a\i#y��
��>��������4�xl������4�+m$o������3�A�Q[i�+8U��9���4�+m$o������I&�Fm��� U%o;�3�t��4������
�����b������<�<L������+m$n�aC��'�a��&j;�=!�>�ucFNMv�����l�MTwZ�8����#�0������-�VA &�m\RwZ������#�0������-���@�6�$u��!o} ~���
�N��h�Rjm�l�MR�Z;��b��`H���F�6��Z;1�l�����@�����#�0������-���<�6�$u�u }�	�4�;m$n�aK�u"��6I]j���g���F�!
�N�[7�,���<�6��7C���/�~X�I��H�F��N�����j������k�lX�~!OZ�<,q
:��y�xX�ixX�v�vZ�����
���'�xX�ixX�~�Q�/�@,yJ����q��ZG�X1yCL���8K�F��V�;�$D����1K��9:���X�6*6�Z�\0$A������X�~�i�!/�^�����:`bI��X�k0������C*^^���c(��������K��9:���^��
��gI�8k��#"Grl��RqD,�m,��j�H���`1��;���X�koi9bqjc��T[�8,��}�4��3yM����{�H��M��Rme����X]m��L^k�x8
BqiC��T[��0(VW[Bq!���w<2��fboi�6d�������02�F^?!��mxG$��H�-���H������C��w���	�uo���&bo��$��O������D|���.U�0��bo��N��������@|�c���y�y����������>{:�wH���E�M��C���@|u���j���k�bO�������."y{k�'>q����+�V��.If���sC*v3V�����!������Pk����d�/],8�b����X�=���n$o�bC�u�
C�9��]^+��m�C��� V%��������������?������|���������=���o����7�o)�=����?|����?��3/��#�����0�'��o)�rpg�K���������#>����;����p���Cx�a���������{/v�����[+�QP��Q��
��0�EBy�m/����{�����,(����P^x�"�����W�{����=s����q��mTl�/<�w��P�i��k��;�����n�����������z��R��^F<�w��P�i;�k�9�;���7��m'BI������{�4�E�By�T;���`_��3_���`�%y��_{���
^��r�;m!x���SxO���`%y��_{���
���r�:�J��;���	���iP��*������ "1���e�����g��wo�8J�V��(}��sx����]����{�|���,(�[����{� ���<(�.�
�0;�������QP��*����^A<�w�qP?���-xC&����c�.axC�)�k�����x�"���WZ;r09~������AP��1���a<�w�iP����A��{f]��
� (�����e�H�d��:��I��{����;/�%q���3x���������;�XzH�8J�6^:�'�.2�{u�u!	��wt�����i�;��~7l���2����#t�`e�����w�G�N�O���-��x���/@��
���G�^��.�-��swt���������'����{� ��{�������lP09uG�J�)����7����
3f$�{�	�!��N����p���xU�c��a�����p/=�4��9B�3~��]����f��7�J}|����e���S������-P���h�9��n.x�p�T�������}����U�:��/4�+X��oE��xMcX��cF���V6Y��������Iq����>�]����p0=�4�`�����'FS�\pB�M~q���W0!'�������rp�s0�U:���������{�`F������!g����`��tL������/N<��
��L8�{RpA.}��J�\��K��_xr�����`u��!o}�{J��!oM~q���WpG����9x'�n�v������&kG�	�cOC
>��w���&�@>�li����p0=�4��9��s0]R:��9�lr���Nn����'�`z�iL���g�����!_��g��_tr����/���������>��#
vr�������z�����Y�d�	8X�v
�6Y&==���,�f�H8x�6Y�K�N��&����G��`C�������gm��<p����m�Lyz��64Y.L��p��m�\�����M����.��d�pbF���&���s0�N:��8X���,7���q���rp���|we��$�K��aC����	/�*�-�����v�n
x�� l���
 ,�{k�,�K�N����E��	����rA8����*�E��a�{vL���	����r	A8����*�%��a�yvH�	A85Ax�TYA8����*+#�>���C
���	����*�������
�p��0�:;��� \� <[��� \�C
��K����!o�[�gK��!o��z�!��[����!���{��gK��#����U����9���R���79x�TYr��8X]e��G�����!���G��-M��|�c0�|"����M��|�9��d]��'�`:cH�r�E8X�d]��W��C���� �`:cD�~�;����m��fG4�'��H��aC�����dO ��1�a����'�]��`�`��[l����0#�H�`)��-D��>������G��aC�����C{����|��0���i�u����t�R%n]����a�����~�vY~�*y���0l�y��6�Y~.��?���:�72U���fa�ky��
m�_d$�k<�V4��l���5��J����G��aC����2��5��+��
:U����v�<��
�,g�������!
G���hX�w��4�4l(�|B&l<X4���4��4��:�!
'�������he�a�����EC�����0��9���8��8�Z��8Lv�x:�hH�q8�q��5�C.��������*��d���3��4�!��Ol���
yxk��j��6�a�����EcF��<L}���w�����������O�
)xG��8Lu������I����:���O�
)�@>�4�>y��G�WK�u"�6���R��0|�aX}��?���&��>�B&;l<Z4��Y�",L��
i�B��,l����,L��x:�hD�a������t���%o����
��	��ECv&,L�<
i�K���h����1#aa:�hH�XX���F����%o����
�`F��tp�����%o�a��!�zM��>+�a	�kX�g�0,y;
�-1C�^�&
GC�f�a	�kX�g�hX���v�a���5q8
������0�]4��pX���v�a��u��F+�3����4�K���P��pX���'��pX�h��8�8���%D�����hh�BD�����VHH��O��&%7��oBNm��Y	Y8��m�����S��?�N��~3�pn�����H���0l3�_$��'�'��to�98798�pYs����� ��9�_���?�������|��_����?|��������}����������������w�����|��#��G�s?/)I%��u�=���������>�P'���O�����*�K�O����wD����R��{)�V����g�!Q�
��;�p RM�H�f�D�8�H����|"Q���>3��g)���;)�>R�'���_H'y����2��d�d��.d����	'pk���7���^S��9�F�[l���i���)0�	'po�n �W���7�H��`C�7���S`��ps�p�����_���D��j������������"q{k�%�q#���6�zs�i�3YB��
)8��������X;�F�[l(��9`��4T:"dH�3h)��+X����A$oUp6<�6/3����'��[��3$n�_����A$o]�����3������C
^g,�?���o��q!���64Y�z`��4Tz�sH�8X��
�6Y3.��u��&k���d+��6Yo�4(8V��9�B�[lh���L��xu�����`���3.��u��&+#�� � ���3rp&��[��og�"q�~-EVA&KA�1�!���B0��w���E
.M
��kC
&;A������7B�O����_�"q�~-5��LV�u��#��?}���_\"q�~--��L6��/Q��@�	�E����.�[��&K�u �� �;C
>���>���R�zk��
D�6���X'"0Y�%��|����/n���~-��L��u�u!_}~bs���.����_7*�e���~��2K�N���{�u^�&����`-XRw��6X����~?
H7�{��k������$�-�,q������J�F��k	C�x�XK��_����%m�_C���C�x�X�<c���Oq,3��mlh�����}��
��K�N:��,i��e�0d����
,q;�>m(��w��u��P`-k��}�WpL���3j�=^�6;C��D$��'�Y�`-	8�������������S�gm��$D�DV�k��Z2pj3��tX8�xVwX8��K�{o�8��Y:���	�;��\�L���� �6;K�U��a`u��!�>��.#����6;K��!o}��hH�;"�F�����wd�����Rb���{���k�!��{���X�|s�B���`K�u }�����|�>���G�--��|�!���R��|��B�r!�m���B����k�!�"��W8.R���`o���i�k���E�c��A$ng���Q�w~H�F��kuC�'-�kup�����G����C�6
6�X�w�?�h��X?���e:���O'=)7~H�F��"k���O;]�E��;* ]?�lD���>$m�_C���C��~,�"k�A�J�/�0���>$m�_C�������X�E�:�F��_�a�w}H�F��k]`z�J6~��k]@�J�$��"k�]������ZW�������ZW�������Zq���m4lh������C2��������
#�6C��&�`��C[e�	98�9��/�_q���m4l��2�0��A?$C����N}���?$o�aK�������!�pA�}v��Q���q���m4l)�
�p������e��,\��U��
��4��i8X��
ix#4�n�6�������G��yxk�p��Y;��NxX�g���;�#���p�E5������:�����!���<|V_������>�����W��_*���x"��5�s2����$H��pe�m5�����0}������)���@| V������[������W0N��dc
����7N�������������}�A��+xa�>���~]�~	�o[�`X�V���}�<0b��dH�PX�����Y�
K�����o��F��0����@X�����Y1�x�� ��k�{�`���~�UV���������������^
�{g�`���W[d� X�v�U���	/^���k�������d�������+q{�jk���x����_{#|�%\f�0��)x�����-V\�%o��I�G��L?"C
�H��������c�h�e�������#2���	�/Z�	8u����S���GdH�8N�+#���`K���s��GdL���@pR�X!8��[Z��\�L?"C
.H��P0�xC��7���~l��6������#2��
1x#<i/K�;b��>m��v�����I�c���;��I{[R����6[��9x'�.����p���.)��G��-M��|V7Y'r�I8x���<���&�8���K�|�98���9�$<i�?^��W��_��q�%D����MV��r�>�.���.���u��&+M;f��*��&+9��H�^��Sn���u��&+��������Jn �7�N�mp�u5��.��d%35YZ��MV�p���Yh�/����u��&+�����:�jH�D���2��$\W#i�z
=V�g���K'Q
�w�*q��),	��H��^C�����z���JHT��eaI��F���:��N��?�7k;���B���z��&\U#i�z

VZO������
V��%34?����zqQ�����b��RD�%�j�k�!�&����_�}�	��H��_C}��/�V�&u��~S�~������I[�ki�2�/YV����7#�f�I��/����H��_KyU}����uH����E��t����u���jC�%�j�;�!�n��#��K'��I[�k��v�_����b�������vW��F���Z�������oX��{ ���.���u����@�%�j��!����G�������I[�ki�N�_����_����{���8�/����u����B�e�j&uu!�^}������'�����������������U��%o�_e���k�����_e�+�{�j����%o�_e�����������~��������W�v�U�W��J��_C����������W�v�U�W9�J��_C��	3�u��*����������3�����5�Wy>1#�_�����_����*/�������_�e�������+���������
�+i�~
�U^fd�Z��U^�%og�����1��k������72���W9"��>�>1���~�ol�����	�71���W9!��>�>1���~�S�K���_���2�o�������7#��&�.��� �f��^�_�����'F}��oA�-M�],����[�zu�!�n}�}b����n��[�K�!�n�������>�>1���~w����������w��^�_��{���}o��������_���_����������:��&�.���D�=	�zuu"��������{6�w��W��E������������o���j����*�������*�>$o�_eUp
����5�W����L ����8�}H�N�����I[�����=f$����*n������*��F�����&�H��mU�S���W�_\C#i�~
�U	'f$cx���*��~��LeUp
����5�We�1#����UY@�J�N�����I[�k���R0#���UY@�J�N�����I[�k���
#2�E��UYA�J�N�����I[�k��J�-lM��W%"�F������I[�k��JB�e�h���*	�7����/�/����u���*#��E4A�_e����_:�xD���F���Z����������C�-�����tx��~q�������� ��54�����K�������I[�k��6�_��fV�W;����_:�xD��~F���Z����-������������
��H��_Ku ��4���:��B�_��I[�k��N�_��fV�W'����_:�xH���g��������Y�_]���_m��g$m�����&�_��f��W��+y;�*��m���u���jsf$�;k����J��xe��9`�[l(�6wbF��k��0�_<�`,q��

��w��X�`mX��
VVX[��U��Pam�`F��t�����%o�`e���/^������f``	�+X�am30����,�����kBp2�X�,�{kK�m�����-��\x���-�����P0�c1��(X��
V�X�
,q��
5�=f$LY)8"�>?�&���#rplrp2�X[B����&�!'���8XYdm	98598Y�����UC
����q�����������de��L8���RpA���� �����`K�U���`u�U���`:�xD�rpis������7���&kC��Q�#
����&gK��#����:�!���;�`:�xH���{�����:��w��t�������p0f<��9�hrp�4Y'r�A8�.�R��|���G|"�M��&�B>	��C
���/��t����/�������d]���`��bD���w��p0�g<����H��`C��Of��$rt�����A$o�`e���:�[lh�v�a��L"G�Z)��D��
V6Y;����u��&k�3���:��bL�p����?�&k��4�.��d�g�d+��k-���J�^��&k��4�.��d�3L���ZG�Z)x�*y{+��W�H��`7��}	�?����C^@�J�^��*k��4������W�!��y�m1��\���5���v\K#q
��}�0d8���-�4gl���T�Y;.�����
m����zG�[i8!G�<B�f���F�66�Y{B&j�p1���0���m���i$n�aK������Gw\�ii83��Y��F�6�Zq�,�qt�����pa8�-�pA��m4li�6�a����=C���7��t�������[*�y�,�qt����w����0s<�a\R#q
[:�y���qt����������q�O�6�kj$n���tZ�0YV����!
�����O���
����h��i���d]���.�4|!�}��?�4��j$n�aK�u!��5�n���1!_}�@G4|L�������:��!	��c����?��us����k��3tZ�����������%o��O�<��a?��k��3tZ�����������%o��O�<���/^�����:B�������!
�a��iX���<,q
:�cv��0�}1��xX�v���c����
��1_�����:���0=:��xX�66tZ�r`H���N�X��%o��O�<���xX��
{C�u��$<L7`i8K�N��~yxs�y8�y�:�#"G��t�+
/�O�p�?y
����<�����[���?������|��������*���w�����o�����������w�������������wO���G�l�DM/��m�������T�g������~&N4�g��{Cx��?���{CF��;��������CF�vL�7��'����|�9dH�h�Ob����pk�(�������D�2�OW��(�B�2��\����x|o�/����tw������"���Tn��b�WG�{C	x�������C�T�"�""���T7W�&���|oh/4�3�t������_�3����=�&���|oh/4�3�t������_��?�a�����_��
-��&�b&�n�0�����'v���0���c������_��{�FdH�h�/b���2vs�h������B�����!
�����b���
���:&?:�M�EL���D�4�&�"&��Mc77�&����`��.4�1��n�0qdD�iu}s�	��2���
�����S��=�%2���D��DL�Ei8#�6K���s�=]&2���@��@L�E�i�8��8XZ��@��@��6�!
�B�X���U��������W��_�x��"n������.���H�$��xC"��D������"o������<��ozi��v������=I����4�3V7Z��NhX��a�h��kO���{ 
��dH�'���Gaz0z�3��(|6Q��g�{�=�O�t���~��>�c�C�����&��}o�R�E(�n���|�)X��8�Fz�[���K�;�}���uY���~�E�[�_�>y?�u���0��i�z_{#|o�n��d)���&���2���{��x�������?��������n]�C���N�v?�;���?���}���������r�7���e������~������W�����������?��W?|���������]��~�_��������k����?�1B�j;������
��P���F>�5awk�����1q����@�j7��z�{6�W���7�O�,���/]�+����3�J7����?�~�	�{�������SE��.3�J���V�?�vF�(���aoA,��0#1�t���za!�#�����^�F�[��j�0���@�;N����y;_�R�v�?����
6��\m�_�x��2p$U�^�D�[����0#p���}����CN}��kn�7#�V{��^U���{�m�����0ro&_�y�����j
�c��a���ZF����~
�!�2-��#D����[m�|����
���E��_uo�!�nlw�r��o����R�����ZE��_uq�#��dR�����}��������D��_usu �������:~����f����[-�����:~�5I�]�H��z�l���D������W�]]H�'���-�.��j�\6Kyu!�Vk���K������"��Q�WnB�����e3�Wn����~�����%o�_e}�������/�
��_�+�{�j�+��%o������x�������{��3�
���y�_��;<������u�����	�m�������T�7�J��_C���	�m����������w�����g����H�7h�+��J�^<�~�_I[�k����aF��A�_��W�v�)�+��J��_C����j�+��J�N<e���k�������oD�����������{V�W.!��&��8$��~�o"�K�p�7!�&����*!��&��8"��~3�o"�K�p�7#�f����*#��&��8 ��~�o&�;�����[�j��oi�o��W���������[�j�7�������jC������jG���j�w�������jG��	�����@��	�j���������:������:������N��������:�O�����:��>���#����&�����B��������"_��~t!�^M��
�����������4���~��yXK�H[�k������q�0�����4���~��y�I�H[�k���O#�~��!����WV�<�v�U~�a!�#m��������xy�����������������������_�p`Ft�����W��<�v�U�W��<����+?o���~����e4���~����U4��u����/2Vi�����<��y��2���"�G�����_���!c���}�����"�G�/��3��y���5�W>��j��~����������,��_��j	��k��|B��w���W�_��������
�[�M������_e��j��~��UF��}���F�����3����������/���UA��}���F�[���3����*���������
������>����[m��~-����[-�y�������>���#�����3�������4��U�W;����_z�`D��o�zF���W�o���}����@�=��KO���D��v�H����D��6���W�_���'�_��W�D��v���k��W�o���}����B���*����o�{F�5�WaB��6���W�_�	�W������
�����5�Wa�0#�_m\�~��KO����J��_C���j����%o�_e<�����5�W�o���o��W��J�N���*��]�WC��������B����~��U�=^�&����*��������
3���������2��k��j����+�{�j����J�N���*,'^�6�����H�7j����J�N���V�_I[�k��Bt���o��W!"�F���~2D�����h��BD������
	�7������oB�MM����*!�&��Q�_e����_�~3�on�o��W�73�U�W�7�U~�
�on�o��W��0�U�W����~���K������7��I�_m��[��������[������w��I�_���{����!�"��M�����@��	�&uu �}�U��@�=��-����{�M���D�=��KO����D�=��k��N����oR�W��I�W�O^��W�-����{�M��j���q�U�W3����U���_��������f����W�g�=#i�~
���
f� �I�_�n�����w�H��_C5{��9�4I�_�n������/����u���j0#sfh�����S���������3�����_�������������|~��/��{F�����y�������j^@�J�N���cg�=#i�~G��9�t����N��g���������o���y�������������_7|���>|��oR����?�����}��??�a�����y��9%�$��n�J�j��������O���������?�	�"�&��r#~�q�����
���(�F�'|����'R�'�i���.I[�k����<Az���C�����	\�!i�z
u�\'�>��gH�i��iB�����<$mUo��y�Y�A�I�wC���0�.{p�������y;���A�I�wG���,�^/����u��.�@�`�<������I��e5�q������Ty���.�'L���������9G#��-��������&��������{!���E�6��I[�k)�.�^���n�S/r���^�sJ���{5�7�C[&�^	����c,7�����U>��8�������Z-�WBw���V�����O���X��������j�3f��5�C������8d�x�^I[�kh���1�gn�Ro���_��%�J��^7j�e�0�gn����+q��3h��+i�z�e>1�gn�����>�j�TX _I���P\-��!?s���~W@_��e�qXV@_I����\-k�����rL����3��G�^�&���P]�}Z!d��/�b9��������KB��M�u���Z�o��/�b9�������u��oB�MM�u���������t���~3�o��/���~3�on���,�UA��}��[,��[�K��xC
.�����jC.}�k���!o}~M��7$��C��kC��L�X)xG���F�����{������w���
�@��������G�����:������@>����m9���6;K�u"�}��,��{"�}����\��g���������>�M�C�����>k�q[.d������a���W����7��~�	���N��W��!i�:����37Y����C�v�)�^q���m�k��V�1�gn��������B��������Z��!?s���~T��I�<Gh�������Z��!?s���~g����j��[q���m�kh��y�����rH�T��I����wxH��_o(���`���d9�_�����2�W+�����~
�������l����!���O%n�_e��I����_��we�<����c���0���C�6�5�WkB�%�<��oB�M}�U���I����_e�_���^�!�f����_�=�+�����~-�UA�e�<��UA�-}������I����_�_��C�_m����������C�6���W�/��A7Y�wG����9�~q���m�k��v�_���n��/�����+��;<$m�_Ku ��Mt���~�������W��C���Ku"��Mtv��~O���������I����_]��d��.5����"k����q���m�k������6yh��8�J������~��+i����&��_:_jH��W�~�s�����~
�Ut'���/05�_���>�jOX��W�6�5�W���l���W1�J�/c�J����������`H��R�_��+q��+qx������z��R���q����!R�,q;��V\^�&��}o��d�����v`��_������	��=>���:cD��R[_��F����>�j�H�+�����}����v���~�������b~��|�����������&D�H�W[]������g�G������������"��>��iC����|���f����^���nF��}������[{s{�6�������^���nA�-}��������[���=�9n������W����!�n}�������!�n}����~��w��+�����[���������R����������{����H�{�x��mH���'��m�$��s�������#/��
��D�=	�j�{"�������^��g�y��cH�2�E^�j����j���VB�E�W[X�	oWz���7��I[�kh��t`F2rW�X%����W���p�����5TV�m��?m(i+����!q��O/n���u���*����]mg�<�:$n;]V�*h�M3����PZ��0�7���V��/���H�T�J�?|�����������������?|�����(O4o������������������?|����?��o����'�����?rkY���4T��O_}�^�|�o>�7����q*��}������x|.��LI[�e��L��eeE�q(�����j����2���5_p����\V~X�8�I���j����2��D��w�{m&G�����8�I���j���2���5_^`�t&g�������$m]����xr.��L��������
A}�y��L�����e<;��\&�Z��a�t&������'2I��_C����\&s�����Ogrp��'���~q"����54}��e2�)k����39:����8�I������'�2��De��~3�/9<������$n�����x�.��LY��Z.�������q"�����tWx�.��LY�]mH���s���8�I������Wx�.��L0���#��t��_��$q�~-���d.��C�=��:�}1�D&�[�k���$]&s����:��:��O�g��$q�~-���d.��c�E�%��������$n������t��e����B�%���9��2���j���SIn���a:	��gF�[&�{r�����#�u�]sm��SI��O�I����X������tN{�Aq^����`(�
�������
V�p�(�(����V�p���u�����:	�+X[a����tN{�f	 P%n]���*����u�K�!�`P%o�`eF*3T�[�&1tXe>1c�����%VYL�����#
^@�J��`C�U�3�w��I�b����Y�#�e�*q��
-VYf���w���*+HT����=�������~6�X%"�>�I�c��	k��*	9869x6�X%!'���"�$��D8X{?TI������������q�������p0]3�����<[����	��lC
.���p0��2���\�<[��
9������!o����o��[��-M��������#o��������{��-M�������| �}��&a9��&/�"�@>;u�u �������G�K�u"�����:�O���_��g�K�u!_������/��t������&/�"k��/��N[dm`���B
�pj���6Y����a����`����,�6��$q��
E��'��0X[dm0X�~)��&�[l(�6bF��^[dm!`���@���&�[l(���cF��^[dm3`���R
���%n]������	{m�������W����������"k[��%t�`m��-����K)xux�����m�����M��K�^���c[/�xM^
M�g�H8��yRpD��������������rp$L��7����kOi�rpjr�ji�2rp"��MVF�����������������q���*���p0-1���\��Z���\���
9�V/xC���Z��
9x#L�^=�`���p���mG���Z��9x'�M���V/�@��li����ppP7Yr�A8X{:�v m�4Y'r�A88���9�$�^��|698Z��9�$�M��|1�r����hh����$�M�>�D�~!��@$n]��������"m��;��H�v<OL�(��
D��������M)�6Y��Xp��~���F�����������c����J�^���c��4�.��d��`F2����S0�T����j$n]����g���55|���g0���W����qE���64Y��4w�����&k_��J�/��/^s�}44Y�:cF6�W�d�+�T��+XYt���F����=z�Hf���&k����������[�M������:InH�	981���F��[��������&+#'������[li�2r0[WCG)� g�����v�T#q��-MVAf�jfu�U���`��qU����4Yr0[X3���
9x#��Og�]5�.��d���lc
�h2��9x'�_0r����di��`����$R��|�&F��j$n]���:����:rH�'r�I8X�`\W#q��-M�����,�&�B��	#
�}5�.��d]��lk
�9��cB�k|L���*8��c�1#��E�d8X��
V���u��&�p3����&�p����K)��xM��&�����W���:<p���L'L�(88�xM��&����W���:p���b
���598��c�1#�`m�u�����W���8f�`�[lh���cF���&�X��%��R�,q��
M��N��p��m��8X��
V�
,q��
M�����p0�=����`���G����`C�uD��H8x�6YGB������'����`C�u$��D8xU7Y	98V/8#�&��Ree�L@xUWYA83�6A87A�M�.� 	B����*H����z�H��I�n��Y�p!(L�ixC��(�=������&	��Rf���A�U]f���;Aa:dbD�;���Da7Y��Yxg,�n�d���0�21��Y�h���,u��0|0V�Y'��A`X��a�l���,}��4|��>�B>	
�9#����&
��Rh]�����.�.�����v�'n�����
��9�\������F���&"y;������k$n�aC�u:�y�6Q[i�n"���f�#��5�n�*���d��m���J��p�����z�'^<��<6TZg�����J��T%o�3L�M�h��H�F��J���$�{���:gp����������H�F��N��/���j;�s����\M��q��m4l������l����:W��������8q���m4l���u��d|/��;��RU�~)
���h��i�y����vZgD�}�t����q���m4l����<�����CN�����z���F�6�tZy�m�I�N+#�>{:sbH�������N� �U6tg����pa<��0n���u���im��l�MRwZ���xX���kl$n�aK��!�e6tk���w�����v���F�6�tZ;�0�f�����<��s'F4��l$n�aK�u �u6to���O�����z���F�6�tZ'�0�g�����<|��'F4��l$n�aK�u!��6ts���/�����v���<|�y�:�k��������&�a��kX�x\�������i].`H��U�i]xX�~)
;�a��h��i]�aH��U�i]xX��V6�����
���/���j;�+��0�a�������N�
�d�]���5K�^�������%n�aC�u��d�]����K�/��xX�66tZ��1$������xX�v�(F4�z�xm�N�Z��%u�am�u�����Ki8Nx��<����#�am�uE��Hx����0�pl�p0tZWB����������a���pj�p�tZy8�y��xc�����0�A1���<�������z��R���W�8���/�RrA$���K.������=L��oA .} ������b:�bD��������wC��8����wG����#�M~�A��~w����~RZ;���`X[w�{�_{����Q���0_�;��Q�`(����(|4Q����{�=��>�I]f��'a:}bH��g�_{-|o�b���`��wH�b�E0X��1�jb�k/���7MS�� XYd������������x����#n��k�����9�H&��C�u����6����6����,�_����Q�Xi���9�#
��6���o*�����*�4���MO�N�(V�<�6��6����*+��4�c6=:1�`Xi���x�`X��!#�kC�)x>���?eS�`Xi��[l'��2F����8e���f�����MOGN�(V�<���Y���dd{m��!�
^�36
>���C}<�fd�]�5�[<��H0��QpD�M~qd��'�`���.�RpBN���N������"+!��6N]de����`O�M�(8#�6[��������C
.���p�z�9�49��y�\���Vu�U���`:lbD�rpir���:�-xC&Km��!o���`��w�����/N����9�-���&kG�	�Q#
>���&�8�����`���.�R��|�/9�hr���:�-�Df+m���:��O�����D>�����{����F��wH�r��8X��9�jr���:n.9�-���&�M��y��In��u��&�Mfd�]o3Y���!���9�`�+����o���������� o��_>|����?|�������w�����o���?�8������������=~~���'��J��?r�O��Lr�~�����������b��_�����T���?����'f$���z�!��x����xO�������)x�g*�[l����cFrL�.<R�
U��^����w?���~����Z���?�?>���$������������7������/����L�o��;?M9�j�����>|��?��_���o���~��������������$F
�W���:�����fd��KJ�v��z�'��~#>]������W��7��U$OWa���x	��b�-�g��7�KI[���(1���K�	�/�d���~�~�o���5�1�8z��~3�c���~�J��$o��O�b������5_1�8x��~�b���~�J��$o��O����m�k�|�����{����7���~B���!
o�7��/n���k�|�����{����7���~B���#��Ol����/H��_U;	D���_���!���G��B����{�=��6���6���{0��� ���{����-���{"��m�U5m���d�;��A������f���B����;[����"�K?!c�E����;+�+?���j��l������l���~������!y;�*�++i�~
��w	2�=�2�_����W�_yX��H[�k���_!#��@?!C��p����~�������u�����3���������
�ql������������_�����d�#���w}*y;�*�+�i�~
��_&�H>�O��~�����������������_�����(���w
�o�(�e���<����+�����$���!�F����oQ�W�<����+����	�/�o����d��7!��&�.���'�_���~B����S�m��S�K�����	�oF��}�}b����"��&�.��� ����2����[���h����[���X��
��-<���!�n��[���"{o��������_���l����wG�����h���wo��b��v�_���~B��{ ��}�}b������G�Ku ����2���� ����N��������:����	�/��I�W�_]��g�-������O��~/��������
����_C&�_	��W�_�	�W�v�U�Wa���5�w5�W����-���W��J�N���*8�_I[�k������-���W��J�N���*x�_I[�k��B�0#[����B����~��U�������_�pbF��O�_�9`�}�}b]�����������_�y��l����
����������+i�~
�UX
f$�K?!c�����~��UX^�&����*��������
+��������Btx�������#�z���BD�����U��������*$����W�_��������UB�Mm���W�71�U�W�7����u�����s����*����/���� ��>�FmU�K����*����/���wC�-}�}b]���n��[������7���2���w��o��W;�����h��v���-�W�W;���������������_��[x��������O,�����h�o��W'��I��~B��{"��}�}bU���"��M�����B�=	��O��~/����������&�FC5O3^@���2��y���������f�l i�~
���<fd��������!y�������<$m���������{m5{�}H�N���j�p���U���_����l�������~��1�����SI[�k����cF��O�_�3�S���W�_���F�����y.������W3n����~����{h�j������fd��6�g�(��H�N���j�54s����sg��
32��-���W�
�T�v�U�W3����u���j�3fd{�����c��X{o��{F�����9!��4�~B�����_e5��I[�k��2�/Y@�W(�7#�f����
w�H��_K���O?!C�-�����Y�_��I[�k��
�/Y@�(�wC�-}����
w�H���l��6�_����O��~��>�fm��g$m�������O?!C����>�fm��g$m��5��.�>q��wh>����
����~�#����Y��yII*I��{a%G��?/�v��}��z���@q�}E�z��C��?��Bo�(�F��x����t��S���[&�	I[�k������}�pO��{�u�%8���8!i�z
u��v���	��
��^4!q;�*���MH��^C�����4���7�0!q;�*��%�tm�0�yK����z�p���%$n�^e���/]�%]�2KH�+>A��;��4����coL�^����l���e���]�*��~x�&q{�*��e�wi��������cH�2���,���J�^��2oY�}%n�`C���	C��iOf��������&e��D�������<��#y���i�{N�����nR�WKB�MM�}��3,8!'�>M]_e��`7i��������gXpF������������n�6X87��'����\�5u�U�K�����6�������<��7���)�.xC�k[�
1xkb��O�a�;r�F8X]c���;�`m��#��Yr�����.����p��Yr���`K�u"}�&�D>	;m�u"�mv�&�D>��M��|v�&�B���,M��|�98h��u��E8�)��wzH�F��&k�6����M���"q{+���zH�F��&kuC�G�m��:��H�^��&k���Q���Z=�\�n��m�V7��+X�d���C�6
64Yk���+Y��M�@�J�^��&k���Q���Z��!��M���Zg��W���Zq���mlh���a��x��m��D����l�V��!q��u�0d���m��u����=16�`\�!q��u=0d���m��,q{+��w{H��`oh���L6|��&kM���p0=26�`\�!q��5!����J���p0=26�`��!q[���Lv|��&+#g�������q���mli�
r0Y�1����\�#cC
F.m��&kC&[>fu��!o���������(��d���d���n�v���p0=26�`��!q[��9�����M���3�6Y��C�6
�4Yr0Y�1���9�`�m�p���mli�N�`��cQ7Yr�I8�Q0.�����-M��LV},�&�B��#c
�r����`h��,�;k��8K�^��&+�	�]������8XRw
�6Y�K�^��&+��]������>`�>/�&+z�`��+X�dE,q����s��m�b�����MV���Q�������}^�MV�g,�p0=26��8X�6
64Yq>0d��m��`��+X�d�8X�6
64Yq�0$�`m�W�`��+X�d�8X��O���~�����:��^��9	
k���
K�^��2+F������=F�[oD�}^�UV����0=36��� � ��C���&�����U[d����cC�ENM~���z3Bp�C����2Bp&L����7#�&��}o�8�xU�X����F�[�K�_{|��^���U]am��0=+6��
xk�k����wC��������w#�KO���wG������K�{��~�>�����@��	��sb#�=~��K��^�[���{��wU�Wr�A���Q���{�_����~O������:|O����B�=;�6��B����{���b����.$��s���4-x����U���!q;��#b�M��F�6^.��f��%���*9�{H�^���*�f�[�k���w��?�(j�����!q{�*����i$n����J������Q�]�����LG����w�H��_Cy�����y���J3�S���WY^%\N#q�~
���~!c6o��Wiu*q{�*����i$n�����q��/3�5Q[_�������������u���*�093�
5Q�_���KHGv'��a#���4�>�a��R�MdAM��W?�L�t���U��4����_�=�`F�����-
���*����i$n�������d=MR�W�7����F��{i$n�������d;MR�W�7���F��ki$n����*��d9MR�W�o!�KO�����H��_K�!���4I�_m���_z4lD���F���Z������I��jG��	���a#���4����_��d3MR�W��A���/����u����D�%�i���:�O���t��~��6�Z������I���B�����a#���4��b�����/YK���U��%n�_e�'�_�[�k���taF����*���2�U�W��J��_C��������U�����/=6�_�+q�~
�U�f��o��W��J�^���*��]�_��qo��WBw���W9�J�^���*��]�_�qo�3����������+q{�*���Lx�������{�]�%t�_m��_���W�_���k���`���0c�����+���������
�+q�~
�U�3��7k���#�_z<lD��7����_��������UN����/=6�������;[�������������j�������;[�����	��������j�������;[����[���X�1�B��Q��\�<[
�
x����
�����F�#oM�-
����	�M�
kG�	�bC
F��<[*�x�#�����|�G�F| M�-��|��M��D>	�3b#
>��&���D>��&u�u!����!�_H�W��--��|�)�M��Lx��Sb
.��F��j�2���"��=Vqp�����=V�%4�*x1�X��H&M�"�8��H�^��"���[l(���I������MV�p�����MV�%4�.��d��2[E��MV	 R%o'=)6��/�T)��d�y��d��6Ye�*y{+���Kh$n]���*���d��6Ye�*y{+���Kh$n]���*���4^�m��
&U��
V6Y7�H��`C�U�3�y�N�d�����LGO��(w�H��`C�U"r0�D��MVI���p0=.6�`�B#q��
MVI��l�S7Y	98���F�{h$n]������l�S7Y98��F��h$nU�ji�
r0�G��MVA.���M����u��&kCfi������7���&��H��`K��#��4^�d���{��==26�`�G#q��-M�����xu�u }������q#����4Yr0�K��M��|�9��#c#
��4�.��d���l1�W7Yr���`O���(w�H��`K�u!��4^�d]��W��==26��mB�����m�����M�6K�^��&ks/^��
M����%t�`m��9�`��+X�dm�����`C���3��&k�����W����<p���
��&k32�6Y[�����M���%n]�����	32�6Y�,y{+��m��u��&k�O�H88h��m	X0�`zdlD�p���64Y��cF��A�dm+p����l��8X����m-��pp�6Y�
,y{+��-�xM��&k����pp�6Y[D������'�����hh����m��%��D8�R0rpjrp�4Y98�&+#g�������3rpns���*���ppP7Y9��G�F\��K��-M��\u��!o�����o��[��������7���&kG�k��9xorp�4Y;r��8X�d��;�`m�u MN�&�@>��&�@>�#c#
>���&'K�u"���gu�u"������_��g��������/��������/����������&'C��O+^A������'��H�^��&k�=5�.��d�n��dN��m�vw��+X�d���F�����{�H���&k�p�����M���j$n]���z7�H����&k`R%o�`e�����[lh��pbF2�w�6Y�����(MO���(w�H���lh��y��d^��m��L����l�v\V#q��
M���H����&k_��J�^��&k�m5�.��d�+������E�d�+�T��)�Q0����u��&k���;[Z�h��="G���������c������r0�Z�h��=!'�������qa����4Y9���Y�MVF���������[li�
r0�[�����\�#c#
��5�.��d�`��fQ7Yrp!L���(W�H��`K��!��5������7�������qe����4Y;r0�[����9x'L���(W�H��`7Y��A�-�Y�U�� |0�VY��F�6�tY'�0�\����I�d$���pi��m4l)�.Da��fU�Y��EP���0n�����
m�1!��5���:&`a��kX�f���m4l��7aH����:����5���0,q
������������aB������=���m4l(��cH�����z{���=�azrlD�pX�664ZG(����m��<,y{
+�cx�:<l���xXR��VZ�<,y{
++�cqx�:<l���xXR��vZ�<,y{
+;�c����y�:�c�1$�am�u���������:V�a��h��i�cH���N���������:"�pl��3tZGB������:�p"<L���h8!�6;K���������2�p"<L��h8#�6;K����3�����
�p&<LO��h� �6;K�U�������
�p!<L���hxC.mv�NkC�Gu��!o����
���[��������w��Q�i���;�az���
���?���������n]�C�������yx����?�����C�����/����L�o��;���j�����>|��?��_���o���~��������������(�_=^�������E�d|��q�|�x��?A�������/^s��s��
C"�d�D/�0��I�O��nC���5�O8�*� ��d|�q�|�x���H���h��A�����|�e�sB�z�I�q�|�xp������7L���Zi�hXU�AH�1$��i�|�xp�����y�
�N���i�hXU�AH?aH�W�x����&"y{
�o��!g������|��'�$z5��o��H�^�����zV[m
��7�cH�W�x��p����5<\�a:��g������|��C����7�zU��.� ��9��6��U���zV�m�7<^�a<�������e����b�G��N�\A���~��
k;�W�H�^��N���6g�������:��!�q����N�m#y{
+;�W���j�n��i�	y��p��am�u�r��kX�i�����v�<�tZy�Zq��au���m$o�am���m�j���aK�����7���N��H�N������q��Ym�y4l��
�p���}��N��H�^��N����z�G��NkC����oX�i����kX�i�~���o�h��i�������
�;-�p#y{
k;-\psVn
[:�y��s��au��+n$o�am��n�j������W��_*9�zOD�j��������������n�9�-7�����Zu��_u��[n$o�_m��Kn�j��O�^{����kB�6���W[i]���������	pX�V��� }s�'Fd0�-�.��_��B�r�������{�u;Fd(����~C�������<�����}�!��~}��}�,��~�%o'=?6����5A�������%s�_m�u�`���WYe]�������^
���,�{�j��k���~�E�5_x���	�]f���_?ik�k����~�5���J����W���'m�u����W����V`�����a�q��}�����"p$L���(8"��i���c�������	�cc#
N����>�������'u����a`zjlD�8�_[J����K���kK����o�--VA
.���-VA
.���-��\�/�-5���v�kC��#cC
F��g�-=���v�kG�	�c#
����6[��9x'�nYyM�!���x������������o���y������>~����~�����������M�K�������w����O|����'�������/����_��|���������?�o�����P�og��"���`�S6{y�)����x��KZo-��?��'[���[�3lt�f/O0����S����C�q�����[��	6:e��������g�%�[0�����3{od$#��S6{oiv(���fW����G��`;���q��d��w�f�-M����gV%�\�����/�.��`���+X����KP0�����{����u�vf/O0���W���{��B�d~�3���-��?�����<���G�N�^������`2���=I�������_\rs���dz���f/O9�L�fM��g��������[pF&���W>����L��?�%���rp{x��cK�-� ��������Lf�?�$���7��������[��LF�{�n�6�`2���I��#�G��8����w�`2��S�?��9�L�fE��#�M~qf�����������9��s�3��-�@���K��&�D�f��/X�d���g���Y�to�'rp5�_
�4Yrp5��}��&�B����~�{����Y�R�����������6YnB����z�[vp���64Yn�1#���m�������M�s���.��d9W0#���m�������M��/^��
M�����W���r8X�v
�6Y.8�xm64Y.K�^��&��`��)X�d�p��kr�lh��<cF��A�d�8X�v
�6Yn��u��&�-3�&�-������}C��K��`C���	3�&������S���r+p���64Yn=1#���m�\�Xp����6to�9869x64Y."G���&�%�����g�
�[pBNM�
M�K���q���J�������������<[����	���C
��������������<[���\���C
.������l��`����`K��!���h���7������,���
9xks������7���h���w���p�������&/�&�@�	���C
>�����&�@>��X��9� L��)�D>�����{>����deK�u"������!_��g���Y2to�r������d]���`z�|L���W����1tk�~�������d�)�2�����/X�dy�����)X�dy���[lh��������`m��a8�#o�`m��a6�#n]����~�����w���C
��������M������u��&����6��`m��a<�#o�`m��a:�#n]��������S��m�<�����m�<����64Y~�0#���k�,�y;k�,��q��WC���3�N}_����0����S����0���.��d�u���4�wk�,�y���Y1to�0���.��d��\M�_����98�9��C���������&�'��jJ����M�O������,����\��51,8#WS���n�2rp�s�3[�n.9����8jbXpA����/X�d�����g��[pA���?���!WS��L��)xC������{��������&�#WS���n�v������l���9����8jbX��\M�_���:���>?�e���������&�@����+X�d����`u�u"�M��&�D>	���c
F>	���9�lrp�4Yr�E8�-R��|�9��-C�&�������d�	8XB�
�6Ya�����MV�N�xM��&+��	���C
v����S���
8X�����fd�m�������MV����.��daF���&+��sp�6Y!K��`C���	���C
���%o�`m�f�`�[lh���aF���h����`��)X�d�8X�����d�H8�-S0p����m������9��d�8XB�
�6Ya�����MV�^�&'C�"rp$L��)8"G���&+D�����dh�BB������!'����`������pj�p�TYA8�g��4��s�����2�pn�p�tYI8����4\��s����.�
�pi�p��YQ�0V�Y�p�����m��,�5Y8Y��
Yxc,�n�vd����nR�Y;�����d��v����0=_>�a����nR�Y�����d������0=`>��i���������8|�q�Rh���'�az�|H�'����a7��y�l�������O�������/�����������&gC�5O/!�az�|D��7��kX�i���F��
:��9���X��!�!
;��H�N�N�i���F��
:��]��?���S�C��O�tN�i���F��
:����?���c�C U%o�am�5���[7l����a���^O���i����5���f\`#y��
��<�t��l�������g���������q����6tZ��5g������C^@�J�^��Nk�6��n��i�+����O��ix�*y{
k;�w�H���Nk?]�9|���6����_���~��o��[����/��������������}����������������������G\�������$�$��MXI���O_}�^~d>
����{�3�E�\vN[���D��?���o�d1�?���>�� [d���o�� ��*�M��� \�� ��0�ad���B���R��h�R�md5�-8��
�b#l��n����-%��pAv��_�C��-v�^���Z��h�R�d9�58���� l�������-%��pA���_�C>�]�I��yu���A$o�aK�w��6��������.����;>�"y
[J�_��� ������	q�"�����[&�a��h�P�-��!���'��������������%o�a��k��0$y��������������g�x6tZ�����������%n�������w?���~����Z���?�?x����������������N�������������,��~�Yt�����?����?���~�����7����?��������6���G1CP�*�$���|���d����(B��X��~��7�_e����U����}�_�a c��i8��oo�x��_epNU�aH@cI�;����d,q{
� �>�v��	/��LLo'i~��=�v�#��"(8I��Q���U��!������J_j���������}��hX�V!��w���������#|�A��n	1^rx����}������������p�/�K�^��-a���������M�
g����p�����3|�_��n	�x(�2~�����6\����kpH������a�%����+���}����
���K���4�!o�mqn	�x(�6d��>�c�0�19�B
ixG2���F���x E��
{M�V�D4&�R���!
H�{�m��oi<�"y
k��*$�09�B
�iy� <<�o�H�F����
�<L������J�<|���|�xx E�6�tZ�09�����<|���H����
���Dr.�����DV�@���Nk�
"k{����Nk�"+Y!B
i7��d���gx�"k{����Nk�"+�!B/���q��JV�|�q����!����Zq��J���K8�a�!��"n���+.Y�KD�7tZ+nY�z	�4�KDV�D����c�-"k{����Nk�5"+Y#B/���q��J���Y�x��Fdm�q��i��Gd%{D�%�08���q���^q����#����Zq��J��K8�a�#��="n��l���D��"����DV�I�^�!
�"��,q���Zq����$����Zq��JV���Nk�M"+�$B�
i7���M".X:-\%��U"����M"+�$B�
i7���M".X:-\%��U"�����q���6�����M"k{���NW��d�����p���6��xC����M"���w_=j~��|�eD$��H��k-\&��e"4���q���^&�������.���Y���Y�*oH��Jdm�y�Q��~q��J6�,�J��l��7�_\$����� }o��Gd%{Du��kDV�F���/�p{��k�����[DV�EdQ�Y�DdeKDh�!�����D����[���0�!�h��8K�^���2N��������7�{aD���*+��e������U�����_w`�>��"+z�`���������U�����_�a�>���+�_���W[c��+y�n3�x��X1K�^��+�/^g�a�3����m��,q{k��Lx��/�
V\�%t�`m�@`���|��/^�}�a�k��}^�V\��%��	^��%o]�����a�>��+F��H xU����o�
-V�H��O�����	)8
^�)8!���`K����`u�������I18��F[z���	�{���	G����\�l)�
rp�spTY9���Yrpis�������>���C
���7��Q�M����&�8����w������w���w���pp�~�w�����/�����9x�s0�8��9� ����9�hr���:�-�D>�L)�D>�|"�M~qX��#�}���|!����Os�A9\����/�����9��s0�8���n$��b�n�I�
7/������nYp�MV�7�-�Q	�����'u�[0��Id�M�6Y	��$��F]t$�o���m^�qo���&��6Q�d%\o��zu��p�M��u�/������5S����K��MV��6�K	w��j��lh���5S���]��&+�F����MJ��&U+m�;+�&+-3���&m��p����}��/�!�F�Tm���
MVZf��M�&+� R%���[l$o]���J����{���J1`�d���S4.���u��&+E�`��&i�����#�`��h�a#y��
MVJ��d�MR7Y	981V��6��.��de�`��&�����k�.L��F��[���L��$u�U���`��I	�H��`K��!�56I�dm���`������9��d���d�MV7Y;r��8X�m����9��d��{�����:�����&��H�z:���:�����n�N���p0U�C
��5��.��d���d�MV7Yr�I8���!���[li�.�`��&���9�"LU�����|59x64Yy�����MV���%n�`m����������de,�;k�����%n�`m�����������8XBw
�6Y�K�^��&+�/^��gC��C�����MV���W����8X����<;�H8X�d�8X��
�6Yy��u��&+�f$�\Y�1
/f ���� ,y��
U���!#��:i���B<F��.+�@���jx1tYy�0#��:i���{B<����i8�x��(����c���m�~���#,Lu����pl��bh�rBN}v����	a8��|H�a85ax��Ya8�a�M�>+#
gB�T��ii87ix��Yi8�i�M�B� ����i� �&/�BkC.}v������7��T�ixC��<�X�
yxc<���v����0u�C����&/�JkG��;�yx'<L����������N�@>;u�u ������<|�y��i���'�a���N�����������&��N�B�;u�u!_}�T��h����[7l����5[a���V��&"y{
k;���k$o����*n��dl��vZ��MD���vZ�H��aC�U���dn��vZ��MD���vZW�H��aC�U���_���J�*y{
k;��;l$o����*���d���vZe�p����|H���F��
:�2�����u�N�, U%o�am�Up����6tZe)����u�N�, U%o�am�Up����6tZe���-���N�� U%o�am�Up����6tZ%"�m6^�i��<k;���l$o�p4tZ%!�u6^�i��<�Sm>�a�d#y��-�VFf�l�����������:,��F��
[:��<��xu�U���a���4��l$o����*��l��WwZ�p!<L����q�����tZ�0[i�����<���|H���F��
[:�y�����NkG�	Sm>�a\g#y��-���<���xu�u ���6�0����u��N�Df[m���:��O��T��iy�l��������Z����.���������6��n��im�0�k���6K�^��Nk���%o�p2tZ��0#�����6<,y;
Sm>�a<,y��
���N�Hx8h;��l��0��C�����n��im~������������5����<,y��
��
f$<�����%o�am����^������f�a	�kX�im3����5�������k�p2tZ�<,�{
k;�m��������\x��<������������V�a��kX�im+����6tZ[��������"�p$<L����#�pl������p$<<k;�-!'���NkK������N+!'���������������������ie��LxxVwZy8��|H�y�4y8[:��<\��N� ��T�ixC.M��NkC���NkC�Sm>��yxk�p�tZ;��NxxVwZ;��Nx�j�1
#�M��N�@�	��N�@>Sm>��y�h�p�tZ'��AxxVwZ'��Ix�j�!
���g��������O���N�B�Sm>��y�j�p�tZ���xX�i��D.��T��hx�%7��n��i����8�E�i�n"�������q����6tZ��1#��h;���MD���vZ;����U�n2�Z�/���]�����."y;So>�b\t#yZ�=������Y���@�J�^��Vk�U7��Q����g����7����g����W����q���mTl���e��d����������U���v�v#y��}����]�����Y���������n$o�bC���	C�!�����#P���U�m�v�w#y��="��7����bq$XL����q���mTl����\���,�n+#'��T��7�H�F��r+#��7�������q�����7��Q���*��l���n�
rqa\�n�p����+v�vkC.f�oVu��!o���AS1r���bgi�v�b��fU�[;r�N��*�!�������n��l���n����p1U�C*��7��Q���:�����U�n���'�b���T�{o$o�bK�u"��7������O��T���H�F��v�B.&�o��m��	��"\L����	�X�6*6�[�T0$�bm�uL����W���:\����bgh�\,�{k���K�^��v���^��
�����%u���m�\,y{k���_x�:\lh��0cH��Q�n�X��*��[G.��u���n��������:f�b����*�!�����Q���:�	C.��v�X��%o�bm�u,����Q���:�C.��v�X=VL��*�!�����Q���:�C.��v������W���:"rqls�7�[GD.������:"rq$\L���rqls�7�[GB.N�����J���p1U�C*��������ne����X�ne��L��*�1#�6{K�U��3�bu�U���b���T\��K��-���\\'u��!o������\�u���n����b��lH�;r���X�n���{��������w��I�n��;�b���T| m.�v�@.>'u�u"���BR��\|��8X����$\�����\|.�
}H�r����`i�.���pqR�[r�E��*���G�6*6�[��9O��%m�uNp���������p$o�bC�u:��y��8.i����}D��*��['n�����
������<rI�n��#��W���:q��}��_���G����[/cp��?���W���|"(V�+����o���������� o�/����������^���}����������?�����}��??Y?���#��6V�&�_�����>�P���O����_��oT�f{�1n���#�Q�em�wF|x���������F|v����S����~���}wY[��	��yi�������N	�~
�]���������;3>6%���	�{o���2>5��%����|`�>�������L�����]���[�y��<�����7�[6��-����{�_�~�����6���i�?{�����n��H2���|��%o������������Y�?{�}������H2��U�{;�3����#i�{Lx�p��O�^zY~s��(���~�����|�_=���~��&��6����O�����;��/	�O��	��
9���	�d�}h�����>���|5��	'w��|���,��~�		�������%n���]��t`F�z�VX����x�
�r���.��a]n���h����.,y��q�/^��_�mrs� XB������<@��m�{f�����	��M6���,�{k[�+K�N�'�"�[�<��kR�ksMn.x�����5�5K��'X[c]�������Zf$G�'m�u-�������,q��
E��:�HdO�"�Z�%o'�M�-x���AC�u�fd�-����>���+"�&�6����#rpd�-���	k�*�rpjr�k�Ln.8!'��N�d%��D8X�]����S��_�ers�98v�&+#g�2X�]�U��s��_�drs�9�v�&� ����rC.M~m���o���`�n�6����V��!o����&kG�;u��#�}�W�;r�����f��\����G��| }���@>�li����p0=�4��9��s���<���6[��9�$L��)�B>��M��|59���%7|!_���M��|�98(��2Mx������[~���Yl�����M�[�_�Ay;+��2��o �{�a�.AFG��L�L)�P��Il�
V6Ye�/�@����
=�F��l���lP��9l�
V6Yoa.�xxy�;3f������M�[����s�g���[p8����{�a�����S��l���E(x�O�yf����\�E���aX�2aF���V6Yo�(x���yf���/.��"�q��,����S��l���,�?1��E���F�x+�T)��d�E�1#�E��)8:(x��yf����.^D�*����H���p0}�:�`�����g���[pB�M��L�[F���8X�d��AN}~f���g�������de���8X�de�����g��\0rpnr�li�
rp&L��)� �>?�>���rpir�li�6��B8��qR����9������!oM�-M����o\��#�}~fu�����{��gK��#�����!��{���Y�~o�r������d���`��uH�'r����g���[��|69x�4Y'r�I8��qS0r����g���[��|�9��d]���`��uH�r�E8X�d�	9�js���rp����m��,y;k�,7]x����,�f��8X�d9,y���Y�~o�8X���,�=fd�m�������M�����.��d�0aF�����r8X�v
�6Y.K��`C����	��&���s�3���-x��u��&��;f$<k�,�K�N��&�-���.��d��`F�����rp����m����59x14Yn�����M�[��%o�`m����������d��	�s�C
�������,H��`����`C��rp$L�-)8!'���&+!�6[�����s�C
����p������������*���q���*�������F����\��Z���\���
9��9������!oM^-M�������#o}��Y;r������d���;�`znqL���{����C���79x�4Yr�A8��[R��|�98�?d���G��WK�u"������!���g����C��|69x�4Yr�I8��[R��|�98�?d]��W��WC���� �`znqD�~�;����������G��`C�����l^����� ��S���B+kq��
M��f$�z���!{��H�N���=��y��
��&��3�y�����������4���hXY��[lh�|�1#��K�-)x�*y;�����5��u��&��3�y��������J�N����ae�#n]���z����znqH��T��)X�D���5��u��&��+dd{k���!�`R%o�`�V�<���,g�H���s�C
�������/|D�M��&�'�`����[RpBN}V��rpjrp�4Y9���Q7Y98�9X�e��������&+#��5�����rp�s���_��K��-MVAf{k���!o������/���598Y��
9���������9X�e���598Y��9���������w������/�������d��do����| }��p MN�&�D&{k<=�8��9�$���M��|698Y��9�����}���/����V7Yr����dh���L��x��fD�a�����MV���%n]���
����Vm����	k�����%n]���
n�������!{�`��)X�d,q��
MV�3��k�,y�����
!��ks���
8XB�
�6Y!K�N��&+�/^�����
3p����m��,y;k?E�������lh��2cF���&+,����S��C�,q��
MVX=f$L��)x������V�`�[lh�B�0#�`��fH�98�9���7��� � �
UV����0}a3��� � �&����$��$�-]VBN����!
g$��'a7i�1Q87Q8[���(�	
�W6cF�}v��+�P��s�����*����0}g3���,\�,�&�w�aC.m��Y��F`������0��a�M�/
��4��i��g�H��a��fH�;����a7���qxo���S�a����xX�h��G�������@ >�@���oX��D|0"VwZ'���X]j�H�g�����-+F$>	�w7C*��O���Z�B$��H���oX��L|&�ooFT<Ox�;m�5����x����O�p������n��������o���y���������������E|���>|��o�����������w�����|��#��G�s?2)I'��u}�I5��O_}�^��4?�O���������Q�g^����D�6~�
U�``�L��',��?���M%q{
k��w�H�F���o���OD}�S~s�3h*��kX����D�66T}��0d$�{�����J���6}3n����
U��\�?�=!	�mx�����BGo"C�� ��������C����'��
G���I��?��D��
;C�7G���?��6�@RI�^���a\"y
��9e����077�J�����3n����
=��a~�L���'N���pF�����k��W�H�F���o.��dA�����
��Bx�k��w�H�F�����
y�l��2C���7��^[���D�6�tZ;�0YBe�4�#�������� ������������(3��yx'<��4�����-���<L���G�!
��������q?��m4l��N�a�%�>�i�B>	u/�B$o�aK�u!�5!�QfL���������	y�j��7tZ�<,����>��hx���%n�am���	/^�����Z����4���<,q{
k;���x��<�
������0}����������!
{�a��h��i-�a�>�G�!
�a��kX�3��%o�aC���C�y�>�ix��a���^z���%o�aC������0}���<,q{
k{�e����
���l����QfH�+����5����xX�66tZ��1d�����1
K��}X�K/��������Z"�p$<�����<	��^zI������NkI�������Z�p"<L7�iy8�y8X:��<��<L
i8#g���
g�����`��
�p��0�58���<\k�yX
�pi�p�tZy��y�~H�4�!��t����7�������im��[����dH�;��FxxV��#�m�NkG��<L/����������>���6K�u }��pL����au/}"m�N�D>�<L/���O����������O��_���5�T���2^��W��UR��H|$�����H|5�����[�]�� bm��Np��_J�+n
��U��=J����?f�VZ��[�������a��!������{��#�G�,�Bk�p���=�~�����[���c���^�?,u��Yk�o����^qe����}�!��~����R���2U������+n��U������y���A����T�������V\"y�~_{)|o�L0\��z����H��_��^q_����}������0�p%;C���
U�����X+�����,�G����WpH�8^�-���B$o��J�'$`�2�^�!'$�DxQ7�,D�6������z���3C`u���B$o�M�e���da��C
.���0���8pU�����X!���WpH�Bp!�j��\qS�����XR0YB������7B�����E!��.�Rc���d[��C
��w������5!��.��c��dW��C
>��������%!��.�Rd���dS��C
>��O������!��.��d]��dO��C
���/������!��>�ah���L���+8��8K�^��&+N����.��d����}�WpH�.`����MVt����.��dEw`F���&+z�`��+X�dE,y��
MV�f$�m����������a�����gu�[p���KH����p����m�����59��Q�<K�N��&+����W���������/N����8XBw
�6Yq�����MV\N�xM~qP���3�9�^�!����W����+p���64Y1:���`z���#���m�bD�m64Y1"�>�+8���	Gm�rpjr��S:�-8!�>�+8����Gu����s��_�qo�98�9�^�1#g���&� �&�8����rp!�n�
rpa�n�6�����Gt�[���V7Yr�F88���9xkr��:�-xG��L����w���ppR7Y;r���b���:���>�+8��9� ��M��|49����|"}�WpH�'r�I88���9�lrp�4Y'r���`z�|!����������6[��9��s0��#
N�@.��I�d%\_#y��
MV�v��RD�����@$n�`m��p{����s���
f�(�WpL�p�����MV��5��.��d%�4YaC����=�@$n�`m��pw���64Y)�8�D6��+8��"U�~)O�	W�H��`C���3��&m��f��Ky�N��F�����x������MVZ@�J�/�)�H��`C���	3���fm��V���y���5��.��d�����i�Y�d����M��h\[#y��
MV���dyM�6Y)!G���O���F�����������n�rpb��>8���[li�2r0Y]��MVF����3���qg���
^,MVA&�k���*���p0}S0rpir�bi�6�`��&���
9x#L���k$o]����������n�v���p0}R0.���u��&�@&kk���:�����pH���F��[��9�m�a��4|"��C���q_����TY'�0�Z3���I�$$L��4��j$o����������I]f]��Aa�8��<!
_M^eV��%t�am��'`a��kX�fe����Y��fe,,�{
k����%o�am����W�
��:+�3�-�����hX���y� 8�a4,y��WC�����d���-�r������V����n�Ph�y��d���m��<,y{
k�<K��aC���32�VZy	�p��=}��<,y��
�V^v��xX�i�xX���vZy��u��N+�3v�N+����������1��k��j��rD�������y8�y���!
'�������i��<�;m���p�����cFNM^-�VFN��������������������N� g��N�i���xX�i����aK��!��N�im���a� 8��
yxk�p�tZ��Fx��;�yx#<L�4�#�M��NkG�	;u�u ���������������i���au�u �������O�������i���'�au�u"��������/�������i]���a���.����0}�0�����h�����%$<���V��&"y{
k;���l$o����*n��d|��vZ��MD���vZ7�H��aC�U���d~��vZ��MD���vZW�H��aC�U��� _���J�*y{
k;���l$o����*���d���vZe��p����C�e6��j8:�2�������N�, U%o�am�Up����6tZe)������N�, U%o�am�Up����6tZe�Y��-���N�� U%o�am�Up����6tZ%���k;���#�a� 8�a�����d��JBfkm���*	y8��C��6��n��ie�a��&�;��<�	��!
�J�[7l��
�0[l��VA.�������q�����tZy�m�	�NkC.����.���u��NkCf�m������7���N��H��aK��#��6A�i���;�a� 8�a\k#y�����:���r��������0}�0����u��N�Df�m���:��O���ApL���g���������z����.����0}�0n���u��Nk����~�����	xX���vZ�<,y��
���&�Hxx�vZ�����������%o�������	��Nk�&<L�4���%o�������	��Nk�������������6tZ[(��������<,y{
k;�mx��<l���xXB��vZ�<,y{
k;�mqx��<l���xXB��vZ�<,y;
��1
_x��<��xhX�:cH�����Vb���X[jm+��mTlh���1$!�Y�jm�8"���C*�H��I�n2�Z[B$�������Ab�,8���H��H�&K����cbu����ab�08���L��L�&K���3��E]l��L��>
�� �&���l��B�xQ7[��*�O�C*���K���d��6���`����6���`1}R��X�5��M�nkG.�	/�nkG.�����x�p���:��w�����:�����r�@.>:\li�N���p��n�N���p1}R��\|���Y����$\������"\L��T|!_m.v�v�B.�/�vk��>r.�O�#*�q���mTlh�����d���m�v����X�n���F�6*6�[��0$Y~�h����}D��*��[;������
���3�$�`Wm��{��H�^��vk��7��Q����������j��=�_���������o$o�bC���0�s'�o��m������U�m�v\}#y��}	�,�]�����_���������o$o�bC���C�������W����W����q���mTlh�����d%��m��8c��Q��>
���H��boh���\Lv��E��8!G���ipH���F�6*6�[{B.&Kp��n�2rq"\����H�F��v+#�-8?Y����3�b��q��mTli�
r1Y��Vu�U������>p��mTli�6�b��Eu��!o��)����xks���[;r1Y��������w����Y�q��mTli��b�	����V���|"r��3����~���������oA���_>|����?|�����P���>|��o��o�[���?|�����a��G\���;�8&|2:�sL�������'����[��	���o���7�}�����Em�w8xv��_�5�N��Q���;�������>�������m�{0��{xr����
e��/�?������C����)���{��$i�����;��!���]�V}��M�������<�S��ml(��y���3�.j��c��	���	����e�k��j�c�����W���;x� y���x��������7	��
%���W%u�`m�w��&A���=�F�������#<
6T|G�/J�N�I[�hY�v�=��77�(�(
���#A��m���(��7�x�zo�	I8�I8
�##	'B�I������3�b�����3�pF��W���Q�K%�{�"�p&4���VA�l�v�q�4q��G�{�-���pR�Y�pa�v������&
��$}o���FX8���
Yxc_*��wG��0���������;A��.�vD��|�P�f��{��_{����I� $��]��$|�1;�2�D>�(��C�����'au�u"�}~fk���"�M~�����^��'�`u�u!_������B������[�='��@p�Y����;����9��C�V���6��~�����]��X������7�����C�6F�X|b���l��-���?(����{�p����oo�w��?�����:XT��)X�e�@�J�����C�����.k+�3�A���x�,���9��C��p����B	�+X�a�3(T��)X�U��8�xhP�����>(�{kK�s�*y;k�I:�/*��=5,x�1c��.k[�s�*y;k�E:Wp��.�Pc��c����z��-8"�>?�(���#bplb���L�-8!G����L�������	������l)�rp"�Mf�����S���Yxo�98�9��de��L��<��������7.�-� �&�8����rp!�K��MVA.���M��\����{���7���I�dm���`u��#oM~q|�����;��5���9x�s�3+o.9xor���K�-�@����I�d��G���Yxo�r����G��[��|�9]���:���>?����O�����/.���9�$S�&u�u!_}~f9��_��W��_[rs����`m�uM��W���Y
xk��,q��
M�5���q����p����m�.,q��
M��
f$L��7�`�`��)X�d]>��ks����<p����m�.,y;k��+8�xM~qB���`	�+X�d]8X�~�/�c��p��k���#:�mx�1#a���!
����s~�ix��u��.�Z<f$$L��7��HX�~���!
/����n�Pf]��	
�/�
ix����+fH�+����6�Y�zbF����{C�&g���v��
G������t��pD�����4��#9�����m8!
�&
�8�����pb4����p���3�����4��4,}VF����}VF�}~f������aK�U���a���
�p���3�o.a��a��gm����W�Y����a��jH����d���g���aa���vd����t����wD�������:�w��^]g��G����!H�G��gK�u 	��� �!�H�G�����!��g�gK�u"���$�!_�g����!_��W��gK�u!_���(�1#_}�+��M�@�&�v*�-�/'j>B�
VVYoi~yy���|�r�`q�#n]���z�� #�^Cga)��P��O�����kkq���L�[�2��5���R�/P��������|����lg��)���?���YC
	
�Y����6��9��4��������c���^O�aix^���?M��bH������jx�sY��Cf�O��t����^��4�0�4�ky���d�[�3�g�z:cH�����5�70�4�ky���l�[�3���z:cH�q����LM��!
���G��a;��	a�,��t ����c��w0�4���c��;���i�,��t"����p"{%����
g������Rhe�a���/!�pF�d��3_d��a�������h�a����c�pA.d��3�d����<\�<�X*�
y����t(���7���l�����6������NkG&l<��1��yx��0�V>DZ���{�-���8LV�x:cH���������
)�@>�4�Z�i����t*���O���O�����a�l��j)�N�a��F]h��g������d���g]��l�
��1��Y��������M��W�WC��&@a	�+X[g�	PX�~_bys��k��jh���1#!a*����%���%��0��.�Pf9�1#a����%���%��0���.��e�0aF���.��`����|B�-p���6TY.���q���r����L�
)x��u��&��;f$LU����`�����K��`C����	S�0�`�`������xM��&�����W���r+p���BD��/^�����r98�*aH�98V98698�,���#�`������`uLJ�������de��D8���!g��L8X���oa��s�����*���p0��)� �>/�\��K�����*���p0��)xC.�}�:o��[��������7���&kG����s���798Z��9xg�n�v������:��{��-M��|���!��G��Wu>���6[��9�$L?#C
>���>��|"�MN�&�B>	�����/��������9�jrp24Y~
x	������w��e��{7�[lh��s�������!;��H�/c��[��H��`C������<��)��Xp������tp��u��&��3�'�z�Rp�*y;�]y�U���;ly��
U�f$�l��dH�3�T���k�J+lq��
U��3f${l�%S0�T��)X�Uz�`��[l���!#[cC/���P�����3mW�a��#n]���z{p��l�
��C
^A�J�N�������G��`C��c��d�
��C
�����S
}D�M��*�'a���^�!'��a���>!�&gK����
O/���3�p����7�}F�M��*+#�6�^�!�����*rpirp�TY9�����)xC.}���rC���-U��LV�xz	����98���9xkrp�4Y;r0Ya��%R���V7Yr����li��`����K8��9� �n��������d���d����pH�'r�����n�N������&�B&+l<��C
����>'u�u!_m�4Yr0Ya��%Qp����>'m�&�`�[�&C��C��pH�@X�v�VY�K�F��.+�
C��pH�HX�v�vY�	K�F��2+��!	
�k8�a@a��iX[f����5Q�M�6+`aI�kX�f�,,y;
k��0Ox��,�&C�f�aI�kX[g�`X�v��Ya>��5a�M�>+,C��pH�����4����4,q

��:�pX[h�pX�v�Za����
�VX/�xX�h�8c�}��F���.^�����
y8��pH�	y8�y8k+����S��
�VH����0��C������Y�ie����a7�i���K8�O]B���3����~���������oA��?����?|���������}��������o���?|����?��3���������OLJ�I�]|[/�_��������K3�~�����#�!\�W�Y]�m[.����.�>\�'���?���C���l����l����Y:��b���{B�[��hq��"�+���h���T|���G�'~��\��dq�P7|'���&gi�N$��O�	9po���I�B]�]W,����,�>X�'�����@.��~o�m �Q�����
C�g��'H����"q;k����H�F��zov0�p&;A�f����@$n���xc�u �������=+��R��i�{�p���������@$o�aC�7�V8�� ���.�6@MI�^��zo�� ��n�Y���!��P��]�mx��������q#��m4lh���a��<T�m���jH�^��:k�� ��������C��zm�5���*t����q'��m4l���������^�g�hX���Z3.����
����j�-���8�8�&m�5�V��h��h�	y����F+!'���J��H�F��J+#�� A]ie���xX�i�^��h��i�a�$�;��<\;u���A$o�aK��!�� A�im���a���p3��m4l��v�a�$�;�yx'<������u���i���dAHPwZ��Nx��;-�
"y
[:�y�l	�N�D>;u���A$o�aK�u"�!A�i���'�azDpH��D�6�tZ�0�����<|�gG4�L��W�����Z&�aI�iX�i-����5���7��k�p0tZ�����������%n�am���/^�����Z|��}�������%n�am��x�a��>�����W��_*9�z���}$�����%n�dzTpH��X�V���o����} ����2��1=)8���X�V���(}o����8<k+�e���~����K�������w�0b�gm��,������Z�/^�_{����PX2w���Y�
(,q{�j��%z�xM~�!��~#�p����-��� 	��C�M��	���������<k��%!'���|��~�S�_{)|o�!8VY!8������s���k����� �f���� ����� ���+����\0p���n�6��X�bm�[���������>/�kG����C
�����i��wD���������w���`���D���>�����3����d��00=8���h���X'B����E]b��'�`z,pH�B��~li�.���O�������/B��T��������`C��N3^�>/�k��"q{kk�w�H��`C��:��s�m��:��H�^��k�� ��.�Pd�~����E���Z=�@$n�`m���f�[lh�Vb��z�E�d�!`�d�&=8�`\"y���&k
;f�oY�M�:�H�����M��{A$o]���Z����AVm��� R%n�`zpH��D����u���+�
�j��u�*q{k����H��`C���0_s%�AVm��� R%n�`m���R�[lh������?�w�6YkD����i�!�N�[lh���L���&kM���p0=8�`\	"y��-MVF&{AVu����3�`zpH��D��[���\����`u�U��3�`z pH�9��9��d��B8X�dm���p0=8��
9xks������7���&kC���,�`#y���X��9�����&kG���,�`#y��-M��L��Du�u �����1#M~qF�����d�MT7Y'r�I8��	R0n���u��&�B&{l������/���L���q����64YqB&{l����p����m��,y��
MV�N�����m��X0[��m����u��&+�3�98j�����%n�`m�=p���64Y������m�������MV/^��
MV���S����8X��
�6Yqvx��lh��,�;k��8K�^��&+�^�&��&+.3f�sp�6Yq�����MV\��%o]�������}N�&+����S0=8��8X����'�����m�bD������!G�������d�����MVL���p0=8�����<[�������MVFN�����!g�������de������n�2rp&L�)� �&��&� �>'u�U���`z&pH�rpir�li�6�����I�dm���`z&pL���[��-M���V7Y;r�N8��	R����9��d��;�`u�u ���M��|49x�4Y'r�����n�N���q���:���&/�&�D>���M��|�g�|!_M^,M��|�98k��4�
�"L��(8���[lh���c�����m�������m�����u��&+��������Jn �W���J��F�����a�f"Kk���Jn �W���J��F����`�f"k���JD����m�����u��&+�3f����&+� R%n�`m��pY���64Yi���?�7k����H�����MV�m5��.��d�u�����Y�d�D����m�����U����J����^oL��c��Q��
�0.���u��*+Ea��f�vY)!	GB��T���qe���6tY)!	��5���J����0=8�a\Z#y��-eVFf�k&u����3aaz.pH���F��
[���,���L�:� ��`����K�WK��!��5������7B��d���qq�����Y;�0[_3��qx'8L�i7�H��aK�u ��5���:�����l���qu����4Z�0[`3�+�y� <Liw�H��aK�u"�
6������O���N��H���h��.�a����;�y�b<�����<|5y8:�<K�^��N+O��������sx��<
�Vv��������xX���vZ�]x��<
�V�3f$<���V����������xX��
:�<f$<���V���������xX��
:�<O�����vZy������V���%o�������	;m���
���4�K��aC���3v�N+����������+����6tZy-�������+����5���rx��<l��rD�����V���������	y86y8:�����a���rBN����VBNMN�N+#'��^�ie����aO
i8#�&'K�U��3�a���
�p�����4\��K���������a���6���������<�5y8Y:�
yx#<�����<��y����C����&'K��#������:���>{zPpH������d�������WwZ����aO
i�D>�<�,���<|��N�D>�<����!
_��g��-���<|1VwZ����aO_}�iy�j����*��������*�D$o�a����H���l������1
�N�8��H�^��o
n���u��N�x������������5�����J�[7l����0#���V	36����r�0����u��N��3���A�i�����5��,]p����6tZe�0#���VY@�J�^������H��aC�U���L�����RU��V���6��n��i�fn��&h;���T�������q����6tZ%��&h;���#�a���4�<�<l��JBf�m���*	y8��mH���F��
[:��<���u����3�a���4��m$o���,�VF fnfu�U�3b���T��m$o�bK�U�����Y�jmH��1�nC*����&��Rkm��A�Y]k���Abj��T�n$o�bK��#�=7������w��T�
�W�H�F��b�@(f�nfu�u ��wR1.�����-���T�v���f�D*>	S�6�b���I�n�T[b1�v3����������f;r+K�+�]S%�����=a�T��BV�-M��Y)$��({��\r��r�E?�c��]fY���.�9��Y�"XL��&c����X�1���b�w3Yg[�\,z5����m.��;�[�PP$�b�pksZ���:��p���X�1����"[�[�.���������E��b�1����"	����6�^�b�5�x.��;�[��P$���:��F�b��Yl�nm����s���nmp���,�N��	�X�j[�[�<�����uL���XTk[�[�\,z5����m��zu.v��mQ$���:���b��Yl�nmp���X�1���C���g�tk���p1
��X��C��]�tk���p�l�nm�8.�L����\�\�z�[�8.�����\	S�kbqB.N
�L�rqb\l�n����p1e�&������=���xe\l�n���+�b�tM,����:�����\�.^���
�x#\L����;r�V�b�3����w���y��#���)����x�s���n��;���<�:�������X| u.�=���\|.^����\�	�7�o�8����L�2rq&\���[�8.6��
rq�s���n��B�x�N���#�p�y���8��bq�tkI&�.�����9"z5����w,���;�[��P$��X�[������,�~���G�V,��n�s��g�N�v���Yl�F�c
���X�1��G����2��:��G�WE���F�c��=[<vL��	Fs��
'X�[�����Z��w,���;�[�<�HR����}�|U�~5o���#z+wL����H�����}�|U�*G����pDo������I
q(�<eq��o�./�h����������o������"��?��W�����W?���[����?����^��W������~}����������������nuc�7�p�k���w���G��?���������N+�;�����3�
(R��v���Z���i���h7|D�qx�W�
_��M���pF��������_�6}�����{���i�7�w��::��(R��v��8|����o]y���8����o������L��]�u�;��bZ���������������N�4a���s$�5����
Y�3�2)�^�'d�Ox+�9�����)E���y�Wp7��)�����_�L(���V�s/���{J�7���l%�^-2��`'A���}�5�^�G����������E���X���E����^����(��p��� ,z/\��_ ,rO�>�]~��%��G��qDu�2�^G�`�{�����{�w�H 8ZY�,z���c�'��(���iE���u�uL���W��:�:����O�8���XDk[�X�,z��S�cq�xU~r���/@�"Z3�:�: `��l�`K������M�58L��!�u�uD��#������C��nr��80�����u�2�^�#2p�o��Bp$��C���t�2�^�Bp���L�Rp"��S�)8�|e����H�k}3�g��"���y��!���c�
1x�b��CM�5xC�'�kC����;r�V���A���N�A����l�+�@���3�:�����<�:���������`�����O�3����|N�IVF�:_��y��98W9��a&�\��3��d�d��B���T����� \� ��,�[���%d le�!�Ws��BO�"z�w���P�~?�%�,+;x��^�a�����3D���fe�Q#�����q�{tX�3h?�1{x��������w�Hn'�iV!M������i��=;�1��������:��#���Ws�z�c�F\=�S�=;:<�8�9l�g�	�T��9l=!�W�������0MGDk[Zy�@U�j[�R����3�^&�����['Zy�DU�j������=_^�i��Q#�5XGZ9 ��tFt��p����#L�u8"2�k���rD������&G��X��''���0�pd<l�i%��Hx�N�n�pBNU~r���'���x�<�Z�����WZkn�x�+��Z��'�u�k��8�v����8��8L���!
�U~rX��oH��ag�hmH��N�W6��5xG��0����{
��w��<���w���+�l0��^e��g�u ����y�u :_�V���Q���p�8+#
��y������Wv��58#	�:	�L�
�p&$�����$\t���t��A�TAx�f�B@�Y�Ye@.:_�S���2������2���p���������WI��g�;FY����q�u�Up��U��JZ���W���c�U<p����N������IV.^����IV��E�b��N��,z����2\�*O��2M��p0����	8X�*['Ye�g�;&Ye���p0�����8X�*['Ye�g�;&YeP#�`:����p��U�N��,r�wL���Q#�`:�������:_��������1�*98�S{������W6��58"�*�����#�`:������Q�`Z�����<�L�rp"L��618!'��it�W��T���g��"������9x�9��A�19x�r��3����W���I����L����!oU�{&Y;r�F8���mb����L����#�U�{&Yr�N8���mb��|�Lk��| U�{&Yr�A8��mbpF>�'Y98W9x��de��L8��mbpA�������\��3�*���p0���`��B�	_�;�6�V����������|��6��^�|�y�U��'��5�'��~Q���Y�
����`���N����D�~�������p�,�E�Y�
���a�����4��^�d\<|�<R���#j$U�t�k����`M%���+6�g���Y�09���\���y8<��5;�gA��C���~i����Y��q������5}0C��C���~q���5�&W:������g}�����M���������Ij$]�t�k��/�lMO��8-6�g��Z/���I�����5H�A�aO��8�C��%Z/�I�����5����0m�o�pB�u��h%�aRf��8�&'������}�mFNU=#�y���x:���+��Jx�6�7qxE^�<zFZ�0������8�!o��i'}�7������g��!�>>i���;��Fx���7qxG��<zfZ;�0)�����8| ���i/}�������g�u �F>i���y� <L���8���s��C�L+#�J>i�������0�.o�pA�U=3��<�:m�T�&��Bx����p�
������c���a�9l�i�xX�~%'<��q��8�1�rnD���X���~����	y���W��������}��o��������~���/�~��������|�����7�����__����7�|����W�+���P�c��M�D������?~�}��?�3��ko�7+������1��g�8���t�H�_{3�Y�^-$��G`������/Vo���)�[F��z��S@����������~�sm��*�{6�c��C����:t���~���~�;����?�����o?��-�o��O�������j����ox��4���?����w���y��n��l���}�����~��_��w��������_���M�>K�7�P}���a%h����V����V$���������p�
�{v�4����F��@��4q8���������^�l8�����a%j,��l8��'M^'t�t[�{M^a�A��6
+Q�����{���
6D����(�^�7�p�g�M�J�����
z���;b�F���E�&��� z������x'�:P���wr���h���q���4�D����p��E�8| ����71�8�\���C4M�P#�q&t�I�3�q&�&F���s���i��p&<L��4q� ���&F��p��p2��>��W�a:����~�������kx��zz�w���s����t�I�<DD���u���(����p�L����t�L��������z�w���?P�>&��L����^�;l�iy�Jx�=;�1�����9�>XgZ~�PU�j[gZ�z�w����@#)L��:�����Ws�:��P���{v�c���Ic�[���BU����-yhKx�=;�1���5��2���o������������������3���%j$�����&��@x�J;����P�a7t�|D &�	�r}�#q$@|���^�#q��z�Z���&���M,NH������{-NH��J�n�k%Db�����7�xE$N��t��k��H�V��
=s���t'���m,F&^	��Z2�Zeb7��6�b���/�7�xC(�_�)����x�B�z&[;R1�O�7��X�#������R�^�b7����b�����7��@,>_�*��b�����n��me�b�����7�8#g���'�|F.�
��
r1iQ��<�*���q�y�U�����=���\�z���rq!\|���V���X��-v��q8P$�b:H����X�j[�[�.��;�[��P$��xW�5�)�V���<�b�����ks�����x����������S����W\�����|z����{���U���L(�EF�Dp,p�J�j���As,��(��H�:&�� �j�b�Dp���������;��������������/�Z�8Y'�� L��-�N'O���j���c"8����,�N'?��������{-����[$���v
��Skx���O�O��z����,�t������=���AO1�'��w�N������s�~�`/xM>�d��i�y��l������|�;F������O��p��R�~-7Z�e����w|y�vtx�RTk�k�H E���: ����W���\��t
#��/<�����������|��P��1�"�E������f�#�E$xA��4q8"^�:^����/���BFp��	�"���@�8��M6���wL���t����p��+������A�����[q�g��n(�������rD���y�����[q�g��%I]82t������s�b�^�w������g��#������yx'<l>f:���:�����y�`
|�����+�7;�<|�y����2����Z;���3��+��:������=3��<�� k��pa<l�i����p�L� ��f�i��p!<l>�k��E����c�5�$<l�i�xX�j����xX�V��i�nC����3���\�a�Lk������p�Lk�	E�<<2i�0������������yx��i�#���V����xX�j[gZ�4���yx��i����V����	xX�j[gZ��q��<<v���yD�:���M���E������y��;fZ��P���tHV��a�������<,z?���o������L��]��:u$��(��&4� 1������H�H��������1m`i�oD ��G��8V���W�{����Q�az����	q8��_��p���s/������a�@+!'�����a8Ua����{�]�W���q��(�N�/Y��ZE��^���wC�t�{�M���7�����!o�*���������t����;b�N08�?w���^����!x�!�Rf���@p2��GuS��-���E�=t�������{�M�1VF���-��v��58#g�)�41� g���d�\�K}G�g�U���N�AZ���(���u�����c;�^�
5�C~h�J��"r5���e-n�������a-F��h�`�kq���������x���C����[�lb- "W3��T�2�x���S�e���"Z1�:�ZF�PE�f�u����>��c��L#j������&O��\�`�k� E�g�;�X��P�>��V�41x�U�j[�X�1��=�1�Z������h���������u��,��������e9P�>����418�\�`�$k	�����O������t����% ���`�d-98T9��q�������b���9826O�rp�r���:�58!'��g�$+!'���I��������{
^��W��i�J�W���p�3O�V�����O�����
9x%l�dm���`g�dm��[����q��;r�F8�<����w���<�����*?9��f���w��i�J����p�3O������O����9��9���418#���y����s��{&Y98���'Y98������ ��lp�$� �~Z����\���-rp�r��S:n58��"Z1�:�
p����N��p������{
v��"Z1�:�
8X�j['Y�e\�*?9��^���u�� M���"W3�:�
8X��
��d���F��iF�G�`��L�71x�g�;&Ya,��p�u��
&L�71x�g�;&Ya:P#�`�$+���"W3�:�
3p��=�1�
��u�IV���E�f�u��	���c�$+,��"Z1�:�
p����N�B��xu��d��t�M���p0y������1�
98�L�/���#��e�w��<�L�rp�9��_418!'��t�q�rp�r��3�Z����������+r��8�<�Z���*O=��9x�98�'Yr��8�<�����*O=��
9x�9�v_41xG��i�M����*O=��9x'l�d���;�`:����r�^���g�u �����9� Lg718#U�z&Y98������	�Q�M.�����S�$� ��i�E�rp!L'�19��9�c��	�P�`Z{���8�D�j['YKkD����IVt5���h�E�<@D�f�u���F���;&Y��QTDK/���"r5������5��lp�$+���Y���������zE:�����X#z�wL����F}X/��hb�A����N�"�������8��Q�����8A�*r��k�#��������8�<�HZkh�E�gRE�f�u���F��
��d��iFRZ����@�*r5�����U5��lp�$+�	5�{�u�rp l^���F��
��d��Lk�u�#rp$l����F��
��d%�`RYC/�����`����m5��lp�$+!��Zy���98�����u5��d��3�Z��Ii
��hb��������}5��lp�$kC&�5��������`�$kD����I��Ljkh�E�w���q�y���5��lp�$�@&�5�����r�A8�N;nc0r�Q���g����Iq
m�hbpF������&ce��=�3�*������^41� ��t�q���F��
��d�9������@X�j[GYi�g�;FYi��������&�&$L�7q�	�������v�H�[i�E�=��������g�;�Y��������6�^�a�4+�#�^��C�4+���"Zs�:�J#���������p��0:�Yi����yV���E���u�����W���1�J��I�+-�h��8,z5���4������x�Hz\i�E��a��8L�7qx�g�;&Z)����u���p <L�7q8 �*���V
�����u��"�p <L���?��������~���k������'�!��<�������?��V��{����������u��������7�~�����7���_���?������o���:�_�Q� �N���G�4|�	�8�S'm���������>v�^%x|��'�:!r��fo��8�S'�k�����8�c'�U�&�0uB��
6��P#r��O�p�����r�����7x��"�l�i���7}���MmF,�����H��	�:u"�o��x��N8������x��N��"M><.^u�D4��P#B��O�p�����B�����wE��\����h��Fd��O�p������8�c'�]�6g\����h�����H����6u41� }�"�+����\�MC��5����qp��
��D�~�]���c��zl���`7�F�����&c������"M����c����g�HBU����`����qW����c��zl���`��Fr��6u41{lD�g\%hb0������u4x\Q#9bD�:�I�����M����c����Op�h=��|h�u��b������M����c�����p�h=��|h�u��b������m.�x��E�c��.j$��hSG���F�~�U�&c��z*�y\G��G��|��h�0�����J��al�YOM6���pD>��|��u��b����j��Xe���l��aD�S�����YXe#z���0v���.��}��'d�S�����Y�e#z?�:P���f=��<(���+������%�umF^u����8�m6���������O�6:l�ga������@M�:��Tg��������N�6���F�~�u�6#��l����y�Tj�������������a,�YO�6���;Z��O�6Zl�ia������@M,�J��Ti��5�����Tl�����v�����[��6�����{~O��O�6Zlkm"qaHl�-�@b�[��c��
;�$LL�;�X���E�Wc�&��;[�[Q$�b�`ks���snn6����zU(~y��h�*���������E��\�lb��p��T�������XT+kH�;�X<���������W���GHG��	E.�
M,���E����kb�\,z+w����H�������3p����[sM,���Eo������(�p1m�hb�\,z?�js��b�{��uL��%�H�������aD�	���������c����@��6y4�8"�����#rq�s���nm�8.�]m,F.�����&'��X�b�3�J���p1m�hbqB.N���
�&�������g��"�������xe\l`���k��]�tkC.^��[r����<�����:�����\�.��M,���w�����\�����L����p1m�hb��\|.�7a�X| 
�L����p1��hbqF.>���M,���Y����VF.���i�G�rq&\Lo�6�� �:���VA..��i�G����bz���;6�������}������C�����oD����mb1V�����w�_:Z�`
�~*���b�tk����9wb�X��7��������{����p>��:����F�~���6\=|�������qB���_G�=�X��7�����o�S����/-�<��g�:Z���b����s����X���o�}�:Z<(R���h�G���F�~�I�&c��~��yw����E��~-�hb1����_��b,��O8���w�x�Q�>�����&c�����M,��������}G�r���C����+pD��0hb1V���
�w�;Z��#���:��#rq$\L'4��oDo����VB.&�7n1O�rq"\LG���8��x��n�����-����\�.�3�X��7��bq�tkC.&8n1O�6���q��6������=��������<����w����6�����=��������<�:��w����O�X�#r+���bR���y�����t�A��G�~(�7������O�����H��
��|+#gB���{��	G������Q�kpA.&m8.��[��0.��>���T�����[
>�b��l�mP������m.�zU*~�m�^���	�d�p����s��61�������K�k��(�q���D,z?�>]�=��=������J$<�S�c��s����#���=��.��g�Hh8XgZ���`�KL/Z51x�'���#���iG����c��s����3���=�����+Jdl�g3p����KVM^F\���s��:��he	�u�u,���s�X5q88\��q�,�H���p�����$	�+VmF����GD�@P8Z�YGD�����&GD��lwt8!G���<�J����0�}����,����=��a8��q��0���o�8�"�����y��4���y��4�26�oH�[}s�g��!o��y��#o����qx����h���;��h�h���;�az������^������<|06������0�x����<|�y�g����3�a�L+#g����M���s����q��y8N��VA.�����&��R��''z��pF\B���:��<DD����i�p��{v�c���C�d�Q����������K7M��{v�c��]A�d�Q������a2����i�0v�����3���H�&�L+������r��a���g�;fZy�P#����3�<A�*z?��M��G����i�)�F2���i�0����s.�4qpD�����V�agf-8�:��3����s.�4q�oD�����V^`gf%8�:������s.��q8��a�*w��rQ#����3����az�����~#z��Y:fZ9"�
���q8"G����M���F����iE�a����L+!G����M���F����i%�aR���LkEN�����&c���=;�3�Z��I���3�
yx%<Lo�4q�oD�������<L�o�`�im���az����X|#z����v�a�~��LkG��gZ�{#z�����aR~��L�@>�;�<|Tyx��ie�a�}��L+#g����%������=3��<L�o�`�i���x��a,��g�{fZy�4���:�*�p!<L/��p�����<��c�U�5v��Vq����s.�5q�����3��6�Hx�YgZ�����8��a<,z�w���O����������sq����������1�*#��������<,z?��\��W���S�L�L��"Zs�:�*�����kUm��zU�:fZeQ#�ag�i�xX�~���&������p�L�,5v��VY��E��\�j��<,z�w���RP#�ag�i�0�������&��P����V	�����u�U"�p <L/���?��������~���k������'�!��<�������?��T��{������w���y��n��e�f�����W?�������������������_������q��>�#�q���Q4
�@cB2��8
���o(�8��(��Q��o�a����l��F����x;�����8��(�TQ���
�(D��_��
5"��(
��o oC*^�QW*8o�w�A����i����7}���c7��L���(��P���>��U�P���jD"��1���P����/�2������U�P���jD>�!����P������/r����:�b6
�@cF>����P�p�GP<��g�������~LMAn�X(�A���i.����A����(Y�������^1q+���i*���c���B��xZu���y?Hz/DF7������C��_�L4B��C��o�L�E����\�1��_(�y�=�k��Fh�y���m����%-7WZ�n�:njO�.�Ah����h�_�p��_(�y�U�m���kW��YL�6��Q#	Ri�y����W��y����]��f1
�P��I�J����7�����67���n��
5����t+����%
7W:�n��mj���m�1�F�o��VR����W��y���������i���H�m<�Jj�o@�%�6W*������m�����!"��nO�����I�����[�����f��g~��I���[IM�M�����J����&��z���3�Z�I���[
M�]�I���z�[�]���6K��jE�%�6�6�7�wC�%�6W��n�wC��w�������K:m<��i����K:mf��jG��7�������Km<��i�/�/i��Rx���o��&����_�g��M�_�gs�8�V3�o��&���2�/i��t��������\�
��_��z�M��_�_�e��M�/��������[o�	�+7 ��&OwhZ���_���k�_��W�����_97�F��t�����W���])��_�+j��v�������/��i�������W�o��������+�w����:�r#���U�5����+j��v�����F������E���q~�������c~�����_�C���	�W�*��Wnv�vU���+7��h�_�������W��8�rs����o��_�eB���M�_���k�_��W�����_��Q#�_�C�����t��Rx���7T�7v��\D�
���3���0�V���<���������}Q��o�������?^����_^���������������������__����7�x����
W�'����V���4O����w���]���O���~#|���������@c&���V��x>��^�7�q����kW��;&~�����i�tO����W���]�S����kW��;&~#t�?Dk�Z'~#t�?�*�'~#4�?��������<���k����<����k����;�P{��c�7B��C���u�7B��C���q�7B��C����1��u�!Z���i5�Z�z��:�j��vL�F������N�F���U�5N�Fh��=��1��q�!Z��:��q��W��8��o����o��o����h�_��o����^�_��o�����������5�O���6����k|bm������������5���1 ����+�k����M��c~5F�_�4O�����I�����[��������3�����g��i5�7!����+�k�����-��g~��Y��b�_����e�J�����������3�Z�Y�<��i����K:��������[o�wC�kCf�t������b�J�������y7�L�v$`�0O�h��#���+e\�| �UvC��@f�t����"0)����w�����zy7���220����4M����_>ZgX��.���!VAf��t����!�L����w��!�^.���)VA
f��t������O2�;�X��Q[1�c�5�poQ�lcM� ��}�-�V�<?Dm���9����E�f�u�5yx�Ld�����[
�����;Y������A���	2����8���	���;&Y������I�4B�:����8��&�k�1��:&Y����t����$�������ip�0G}�1��p�����N������N�I�4g\;�QwL�&�-�5����i�$u"���q�5-��������	g|�j�`�$k
�������) �:��I��C�E�f�u�5E�`2�;'YSD�uv��	�|�j�`�$+!���:�J������g��c�E�f�y������o�V���+�p����e��oQ�9le��d�����
IxUH�g����E���y��!	�)�n��vD�MA��a�����a��(L�|��:�����:��i�����t�����0����8�@>�0�{�Y8�[Tk��Ya���v�u����s��}�<k�.�4~j	���{�y?�k�~��@|0������8�����������k����H���S��~����C���i����������8����[�V>���(����}:��	���b&���`�����-r+wL�f�<��n��x�f�=��L(��8����[�V����8Gy&%�������@3�����o�~n�[1�c�7� ���t�O�7<X�d��s����"�bp��o�I�3����v��3p�Lf(;g�����-r+w��f�<��n�iR���eD��M6����+�En��������gR��?��lp�M��LQv�8����[��
;�{3S�IS���A��
F&c��3�f,���;�{sD&U���]n68"G���[�-�"�bp��jsB&]���]n68!'���[�5�"�bp�$kE&e�t8y�W���p0��&#�u{&Yr0i���I���1�N���[�V��d�������'Y;r��8�:���n�[1�g��#��no�d��;�`��-��n�����|��o.?�q�w�Ig�7�2��AP��z���[������F�koF&���y���3a��-���n�{�����{�-����{4�
bp!L)���V������B�j����c����c�e�G����5��l��'{�{���^
��1Z�X��G����5�,��'{�{}��^?�D}��ha-"W��8�Z��C���}n�^{G�����u������\�^�k���{���M�{�����>���e��T�j��W�~�����m�loF�����:�Z���G:��-����[�G���yG�����:�Z�NE��/���b����\������F}��h�[-$�"W��8�Z��C�V��t�7 �����:�Z�o �K����X�!r+�������c�N����	�R4o�/�o�����J��7!�����<�J���/e��b���=��3�Z�~I��d�]�H�+�_
�-����{��gx�!�����<��7����[���"��o��jC�%��yz�#�n�)���+?D��������Kz?&���@���Z�W��!r������_R�1��W�����:����{>��3������c2��2�o&�K������!r�����
�/)�������[�R<o�/�o�����In�7����c�����+r5���0��������<j��w����������Up��"��o��*�5��;[�W���\�_��*x�_�{��c~|F�:����UG���/������"��o��*�;j��w�����+r5���0�������0��Q���:�
�����5���<�����c~f�_��k�_��W�j��Waq�vu���_��WD+�Z�Wa������UX
�]����q��aB�������_��-�
�����O�������Z�W!"�F���[��c����q��	�7�����W	�7��x��������������E�M:�.�������R<o�����V�������"��:�.��������x���
�w�����7��wC��t�]���
�w#�K����;��V��'go�����������W;��N���y�����c���@�=t�]����� �K������G�{�W����w1��2�of�k�_e��\����UA��:�.��UA�-������[��;u����q	�Z�Wq����U��x���8��C�����_E7�F}��b�_EO���k�_E,��g;�W�e���
��U��%�[��4"��o��*�5�x�u~GHOE���q~��F�����_�qE���`�_��S���k�_El��g;�Wq��������*N���\�_��*b��=��1��3�����&X�Wq��T�j��W�gD�����U\&��O�
��U\ =�����U���{��c~�G����`�_�����W�gD�����U�����&X�W1"�F����U���{�w��_E�_RA�����	�R<o�/v�����=����Kh�y~�"�&���[���3"��o��jE�%4�<�Z�W���[���3"��o��jC�%�3�<���7���[���3"��o��jG�%�3�<���w��������W�w��_���}&��W��A���y�sF�����_e�_�<������	�R<o�/������=����K�g�y~U��_��-����{��g~U�I�L������[��Wi��g;�Wi�Q����:�J�W�j��W������K��*�5����������[��G\�*�.����E���u~�<�����5����p����t����+��+����4��\�_��*�����K��*Mj��7Y�Wi������U��E�����U�=j��7Y�Wi������U��E�����UZ���o�����+r5������������d���o���R��/�_��-�
�����K��*����o���RD�
�)���7"��:�v��RD��:�&��*"�F����UB��u���_%����o2���ob�k�_�������g~�"�������w%�K������k�C��jC�]	���W��F���y7������g~�#�n:�:&���;�N��y�w��
��g�u �:��<�:��B��[| U=�	��	�
�VF>SBoapF�U=#���uv�y�U��3a`��-.������g�U�����n0�
Bp!L���+�����C�u�A�+���S�u�'���6N�Vl��g�;�X��I�+���c���D�j�X+V�����c��������9���	"z5��s�;hD����1�Z�5�I��u�������<O1���XB#r�w����F2�w�N��	rT��l�d��B#r�wL����F2��Y'Y�<����LO1���XC#r�wL���@�d��N���T��l�d��C#r�wL��eC�d��N��I���6N�V,��g�;&Yk@fu4�:�Zrp�9�SLoa06�������5"�>g�d�98��)��0�hD����IVBf�4�<�J��I�`O1��������=��9�5�8�$kE^['YXF#r��L�6�`VI����
9xcl�da��=�z&Yr0��q�I�������`���g�{&Y;r0+�q�I�������`���g�{&Yr0k���IVF>SLoa0�����=����ji�y����3�`��-�F�{6�g�U��Y/�7O�
rp!L1�����\��:&Y�,�5����m����I�6d\�*��I��F�H8�['Y�����I����E����I��j$������^�`�$k���"�lp�$k�5��I�6Nh0�`�$k��E����I�6��p��N��	8X�j'Y�,rO��c��M�d lem3���U�����@X�V��emsB������m����Y��x\�*	��c��-���Zqx���PX�j�Y[p��(���i���a��:���p ,LQ��������n�gma8���-"G���[8�c���3�JH����h�g%��Dh��z��p���zZ	q8��q8�����qx���z&Z+��Jxx4O�6����0��o�����=#�
yx#<<�GZ;���x�:����w��{fZ;��Nxx4��v�����u�u �uv=3�y�`<l�i���a��-���G��]�L+#g����VF���)�7qy8�y����
�p&<<�gZy�������<\�<�:fZ�0���3�}�����6��v����;fZ�s(��-��3���CD�jgZ;������3��I�M����GtX���)��p{kDn������I��N���>B�*z5��3��kDn�����>n(����3�}�PU�jgZ;v�����3�}��;����3�}�PU�jgZ;������3�}��;+���3�}�PU�jgZ;�������c��/0dsg56�u��/��^�a��M��x�������0�H2�w�����<S\o�0v�����3�="�*��:��#�p$<Lq����b#r+���"�0+���3��<	S\o�0������=3��<��lf�LkEN��)��p�lDn������<�
mf�LkE^	S\o�0v�����=3�
y�U������<�����al���{fZ;�0����3�yx'<Lq���Xg#r+����aVj3�gZ���x�:��>�[q�g����Y��l�ie���x�:��B�{vx��i�aVk3�gZy�����al���{fZy�������1 ���8|��"��p�L�Ixx���<,z5��3������3��m(���b�ixX�jgZ��p��<<v��<,�5��3���^�a�L�=.^������1�j�a�L���E���q�uL.^������1�j�a�L����E���q�uLy�7������O�o]�yD���X���E�f�q�u���"��5~�e�^�	/�����^�_�P�X�E����^�o���D���u�u��e8liq8Tq���{�
����u�uD��@`��z#�p���s�����#Ca�8+"
G����[���c��{����� ��0+!'���[��"�*?�-|��+b�J08�GY+b�J0�Rz7������m
������A�������_����)�����������`c���;�_��-�������s;��| ���y�u �)��0�@>��=
F>�+#��)��08#g��tG�3"p&�#���[GX�(��
.���0p0��
2pal�ae���g�;�Xy�Q����`b�� �W1�2z���F��
��be�63)�q�:��� �W3�8���i#r�w����A�����
�5��D�j�X;mD����9V'��O�u�:��#���W3�8���i#r�w���Q�>��E� +O���^�`� +c���=�1�����9�.Z'Yy� U�j'YmD��$G�$+�5�c|]�N��2���xMO1���Xh#r�wL����F}����IV���^�`�$+c���=�1��9����h�d��'Y�lD����IV������E�$+G���8�:��6�{6�g����I���������SLob0rp�r���:�5xE&�6.�'Y+r�J8�bz���F��
��dm�����%�$kC�SLoa0V�����=��9����d�d���;�`��-�&�{6�g��#�:����9x'L1���Xd#r��L��`�f��y�������[�=6"�|g�g����I��K�IVF���)��0klD����IVA&]6.�'Y9������2 �*?9��V��,�5����2�^�`�$����O����`7�F���:�*8X�j'Y��������=jdl�d,z�)��0�������2��q�u�UF�`��l�d�8X��
��d�1�FR���=gp��o�.o������~��������/B^�����������/��y�������*��,������W?����/|���
W���y���[�
��4������������?�������D����/U�����8�FrV{��J�����&�P�9����*�K�����Q#��<X�%�[U��^h�����/U	_�DX����5���u�WV|�J�u��7��K��/U2��c�W�5�+��u�WV|�Z����=o6x���7����_��N��������W1������7�����w
E�f�y������U�t�{��7�����1�Frgy0��]����wo6����{6�g��=j$w���/#)g}���n��
������S��� g����_A.:_������\�<��
rp!�����a�'H�9�B���������{6�_��"�@�d��'Yyp?Az����u,�����d�H�P#��v�IV�;}��B����	��D��K�^$%�H���q���&��^�>�P�y�������[as�$�Ec�#��v�I����c�Z=o6xp�0H��%Y/g�8�=jg�d��Y��I?Fy���n�3.�bp�$+���Ymg�d�����1���7<��x3�bp�$+�C����3N�^�-`����P�y���
��`�*�K�^$�H�j;�$+aB��c�=o68 �*����I���q�q����t�P�y��98V9x��d�HB����y��������<o68!�*�=����{�$+!'��/�y�l�����3�Z��W���<�Z��W��/�y�l����9�g��!o���y��!o:_(���`�����K�$kG�{�$kG�u���y��;r�^���g�u ������&������<o6�@>���L����p�7O�2r��s����
������K�$+#g���<�*���p�y�U��K����IVA.����,7 ���I���E����I�jdl�d�8X���]h���`�q���tL������u��p��U�N��p���tL������I�����W1�:�r>���9�c���5�4�<�^�`�$����"�lp�$�M5�4�<�^�`�$�M��"�dp��d���F����f��	
�9�B������"�lp�$��j$L/h61x����I���o�rp��d�eC�����&�`��l�d���:&Y. ����f����`�$�E��P���1�r9826O�"rp$l�d%��X���3�J���q�y��������<�698U98�L�V��D8�^�lb����|���f�W������g��!�����&o������<o6xC���3����7����f�w��M��u�7�#�u��d���;�`zA���r��s��:��
>���*��I��|�4������/�y�lpF�U�=����	��mF�:_��������{&Y9��4�\������<�5��)U��,?|<O�!Z3�:��<AD�b�u������1�c����>����Mv�����I�w bp�$��5�s�<����`O�[�w���f�=<@D����I�j���zzA���#$��W1�:��#�"�lp�$��5��z=�����iD��Q��<o6x� U��
��d��@���^O/h61x�$U�*['Y~� U��
��d�yC���^O/h�1�T��l�d�e��� ����1��K��>����M^ I����I��T1�c��rp L/h618 ��/�y�lpDUN�,��Io��4�������<�698V98�L�r0�����f�rp"l�d%��T���3�Z��Io��4��"������9x�rp��d��������M���W��/�y�l���U98�L�6�`�[���&�������<o6xG���z&Y;r0�����f���w���y�u �u��d�������M>�����y�����:�L�2r0�����f�3rp�98�'Y98W9�
=��� L�k<������ \tN�QVA.UvC�,k��Is��W4[8<@��Wq�:� a�[q�c�5:�"	
�;�Mv���Wq�:�����8�1�]A����%�&�&,l�f�XX�V�g��@�����q����q�8������q�P$�a�<k��Eo]�c����i�����:&Z�<,���E�&O���W��:�g��Wb7t����XTk[gZ�D,z5��C���x�z
wL���XTk[�Z�H,z5��c�q��z
w���0�H����f�2q���������P�P�:[cD(����&G���C��{����8����L�"Rq$TL�l6�8!G��_�[�-N������g����bzi���+bq���������x�s���m���+�bzm�����+�b�pkC.^�\�z�[r����<����7������\�����L�v���q�y��#����y�u �u.v=���� \L/o6��@.>;�t�@.>�\�z�[�� \L�o6�8#g���<����Y����VA.�����&��B����[��(\�3�*���p1�����i��H!\����	[mD��b�1����"�YF�^�lb������,�N�&����;�[��Q�>���k�M,����������6��bq�tk�+����zz�������������6��bq�tka��Dn<������U��Yl�nM�n#z+wL��	foN������M,� _��������6��bq�tk�'�O���:g�g�WE�b��N�&l���;�[��Q�>����M,^ _�������7��bq�tk
��'�zz�����X�j[�[������-��i|�����5D.��������������?^��H��W�����W?���?w%~��?_�����	x����������?���+_���)�]���(�D����''���w����#���`��p�g>!b$=�xy����cm���|�;�}���A�Ch���G��:$���7O��7D��{�}i�QK�7���7��8D�V����>�&-M��/v��Y6�����=����������������<����[q�g��/H��Y�8��.2����CDo���I_F� 
"��ov���[&�n�<����[q�g�Wp��T��������{n�����9�<�����8�1���E�=��_nvxX�j[�|�q������}������et��"\1���{Mv��"W3�:������"�s/�����E�����/����E���u�5���W��^���w�P"�o����pX�j�ZGZ�8,zO�>�"}���G�d��:��'�a���kh����=���k����J$;m�q�<
�\�_�8k��E����^�o�7�Dv����eD	��a��������������D���Q��E���u�5��P�������7 �i���_��� �:��#Bp�n
?�%|���7��KS�&�F��H�w2���o�o	?�#|��	8�L�&'�Dx2O�p���L�V$��0���"���'�kE^��
��W�i����
x#<�GX"���w4xG�t�!B�wd��0�d�a���{};�g��#�:����B�N x2������3�:����i�����|
��S������=c���	��X18��c����g�{�X9�6��
rpal�c-X"z�w�^��k\H{MZ������A���!��lp�$kq0�p!�!4Ihb������^X'Y�����I��I��'��O��IB�=<@D�f�u��`k��=�1�ZF���4Ihb�A����N�,
�g�;&Y�4�F}B*M�<A�*r5����+CD����I�2e���G�IB�g��3�l�d-X"z�wL��yG��tT�$41x� U�j['Y��������eYQ�>�&	m� U�j['Y��������% ���$418 ���u��`U��=�1�Z"r0��IB�#rpdl�daQ��=�3�J���-�&	MN���q�y��5!��lp�$kE&]!4Ihb���^��,,	��;+=��
9�4��$���r�F8x1O��"D��
��dm���'�&	M���7���y��!��lp�$kG&-!4Ihb���^��,��g�{&Yr0��IB������y��� ��lp�$+#���$418#g���y��� ��lp�$� �~�$41� ���y��� ��lp�$+����&	-p����N��,z�wL�����p�u�p����N���g�;&Y��Q�`�$41��\�`�$+x�`�{6�c�|F�:�$����G�	�$+�����<��c��5�L��&O��"W3�:�
p��=�1�
��u�IB���E�f�u�����S�$+���"Z1�:�
3p����N���p��<uL��,�������\�`�$+,���S�$+�	5�L��&��@88X'Y! �*O�������4IhbpD����u�"rp�r��3�J���p�y������`�d%��T���g�����`�$kEN�����9x�sp�$kE^u�IB�7���q�y��!ou��dm�����4Ihc0r�F88�'Y;r�V���g��#�:�$���;r�N88�'Yr�^���g�u :�$���r�A88�'Yr�Q���g������i������	G�$+#�*�=����u�IB�rp!����\�<wL���p	u�IB����l�dE���g�;&Yq(�QTD��&�	
&���:��XU#z�wL��;P�>��&	M������IV���{6�c������4Ihb�A����N�"��������8&����IB�!H����IV���{6�c�'��Ig
M�<A�*r��u���F��^:&Yq�y�����$���3�"W3�:���W#z�wL��2�F}`/M��@�*r5������5��lp�$+����4Ihbp@���u���F��
��d��Lzkh�����'�$+be��=�3�������&	MN���pp2O���F��
��d%�`R\C��&����pp2O���F��
��d������&	mF^	'�$+kD����I��L�kh����
9xcl�dae��=�3����Iq
M��#�����,���g�{&Yr0)��IB���C�`����XY#zO��IVF&�54IhbpF�:��<����{6�g����Iq
M�\�����~0O���F��
��d�`R\C���9����$+
����lp�$+
j�9�&	Mv��"W3�:�J8X��
��d%�P���4Ihc0p����N����xU�����E�b�u��<p����N��8��U98tL��,�����4�\�`�$+�����c���5�N��,r5����4������4;�H
\i����@X�j[GYi�g�;FYi.��4��,�����v�YVZ��E����1�J��I�+
�8�E���u���p��p�f��(tv4Mh�pD���u��"�p��p��f��,uv4Nh�0�p$0�����0�0{�Y	a8�0�h�����4�
;�<kENU�=��ix�i��@���+��Jp��Z+��Z���3���W�M�8�!o���y��!oU�=�yxc<li���;�agi���{��c�HkG��gZ���x�<�:���:�������0��8�������VF�u��ie��Lx�F
M.�����7��
�p��p��i��Bx�F
mF.���u��b��=;�1�Z���)�px�!"z5��3�lD�������`���jlh���a��9l�i��`#z�w��V�5W�cC#�&{x��^�a�Lk�
�{v�c���#j$|i����BU��9l�i��a#z�w�����F2��F
M� T�������%6���p�Lk�
j$#|i����yD�����[gZ+������3�u>P#��K#�&/��^�a�Lk��{v�c��.j$C|i���aUE���u��b���=;�1�Z�0k���B��p <<ZgZ+�����n�j������L����8 �C-����{�Z	��5��P���	�8"�S-,���{�Z+"1����B�WD�� �hka����X�3����Y�
��X�!o��G�\mDo������P�zmh�����x#P<�[Xi#z+�L�v�b�lC��&H�;���<��R�[��g�u �n�,���� X<�G[Xk#z+���2r1k���B�3rqf\l�ma����X�3�*�����fM,.���q�u��
��E�����6�j�b�tk��E�b�d�nmC���s���nmnD���i���b\,z5������������;I��fM,����W��:��<p���X�1��|A���i����qD�	O���6������m<P$�b�-4�x.������6������m�P$�b�-���X�j[�[�<�����uL���XTk[�[�\,z5����m��zu.v��m.��������^�b�tk�^��]�tk���q�u�������:��rqP��c��E��@��fM,����q�y������=���\	�l���	�8.�����\��\�{�[	�8.��B�W��D�x6O�V������g��"���i����
�x%\<��[r�V�b�3����7��4[hc1r�F�x6O�v������g��#���i�����x'\<��[r�^�b�3�:����4[hb��\|.�����\|����L�2rq&\L��&g��L�x6O�2rq�s���n�����<�*���p�l�n��R�b�1���k���:��x��^�b�tk��[��c���E�>X�-4���sD�j[�[;V��������eIai���b?���PN�X�[;������c�tk�;�$��4[hb�����,�N�v����;�[���H�
K��6C�*z5�����pDo�����>�p����8�-4�x�|U�j[�[;V�������}���;)�q4[hb�����,�N�v����;�[�2�H}���B��WE�f�u��c���X�1���G��`G��&��@�x�N�vl���;�[{D.&�8�fM,����p�b�n�X�#z?���o�����g\��{�����8/4q9!G���V������W��
N����p���+�qb`loa#��=����������h�����+��`na!��=�����o����`���B�F�8�G[��#zO?�2}��;"1��q4Vhb��H�$��������O�J�l��@L*q
�| ��y��m8��d�S��7��I#���B�3�p&8�C-,��'���$����0L
q
�\���`ia��=����#�>G��rp!��c��	.�>�52��� ,z5��������-���52���$,z5�������z�
��a���E��0
�8��E���u�u�WO����,,�5����c����:�:���W��g��	�8�����������	`X����g�G���i����hX�j[�Y�4,z�w��e@��i����pX�j[Z�8,z�wL��%�F��4Qh�p�a���:�:�p��p�H�����0��8����hiy8�y�c�uD��Hx�F
mF����y����c�����q��	y816���p"<�3�y8Uy���7;�"����3�yxe<l�i���k�����q����Jx�F
M���7������<�Uy���7;�#o��i����yx'<��3�yx���s�<nv�@�	�H�����Ax8�gZ��Q����y��0��Ax�F
O9��[�������{��w����������!/�?^����_^������������������R��o��~��Oo�����_q�_����W���e�d�>2�O�}���,�������oEv�����s��j�!�������a�������:�j�<�g�;�����3��)L��	
����4��k�t.r�wL�x�F�
a�<�47��|!����	�\��
��iC�:�;��41x�Yn�W1�B�{��3���=_����9�F��`���D�b����{
^<.�pa#���f������s�D�b����^������o
��$��i�����E�b����f�3.�5��u48��Q��v4ibpT����{
�������M<����	'��/'���s��n�{
N�������;��`��D88Yi�+rp�9�J3�����k����vr��+r�J88�'Yr��s��^�{
����*�=��
9x#����9x�9�J+�����{��{&Y;r�N88�'Y;r��s��N�{
>���:�L����pp2O���C��+�������*O=�����'Y98�|��f���s����IVA�������\t��z��9�T9x��d�9��C�L^��,z����2������2�H�l�IVqL8�:�*8X��
��dw�Frd{�N���uyWz@�5��������7�HNl�IV��E�b�u�UF�`�{6�c�U������:�*#p��U�N���q��<uL��,�5����2�^�`�$��.^��;&Ye����IV���E�b�u�U���W���IVYF�Hn/�IVY��E�b�u�U�`�{2x��d��P#�`�$����s����{
�����s�$����8�:�*98�|���^�#rp�r��3�����p�3O�rp$l�d%��T���g�����`g�d����p�y��"�U�{&Y+r�J8��'Y+r��s����{
����*�=��
9x#����
9x�9�J������[����I���v�I����|���f����*�=��9x'����9��9�J�����G��{&Y9� ������u���y��98�9�g����3�`g�d���s����{
.�����K�$� ���IV|�����|�i���� �g��%Y/�����
6N����� g�}`�q���n��s�y��u4�m�#����5v8������2�	 �����=>F>4�8�zQs��'�}`�q�U�����������1����
6N�^�l`������R�y������A�������'�S?4�8�zQ���	��}`�q��"&��a��x��h�<�F�S?4�8�z����4+����I���o� ��������F�S?4�8�z�7��N+��`�$�E�
��`��x��ipA��~h�q�U�0��8������u��������I���p�7N�������W
>�58"�*�~I��$���8�<����Q��+�����c��C�$+!'���IVBN:_�����98U98�L�V���p�h�d���+�`�$kC^�z&Yr�F8x4O�6���p�y��!oU=��9x#L'271xG�u�R�y��;r�^���3�:��w��t"s���C��+���| U=��9� L'2718#:_��������z&Y98���\�����W�=�5� �:�L�
rp!L'2�19��|���V���\��1�rp����N��,z���,�<.^��c�$�9�`�l�d9,z���,�\�*��I����"Z3�:�r8X�*['Y�g\�*��I�G�H8�Ndnb�,z���,7�����,79�H8�Ndnb�,z���,7�����,7�H8�Ndnb�<��:_�����8X��
��d��@����D�&/���W1�:�z����-U��,�l��p0����`�`��l�d�0��U98vL�\@���D�&���s0m�hbpDu��d��	���M���Q�`�(������3�J���p0�������t��mFNUN=��9816O�V��U�`�(���9x�rp��dm��+�`�$kC�t��M����*��I�������#o�����9x�rp��d���;�`:����r�N8�<�:���*��I��|����|��h�D�3��Q��3�����0����� �uv�S���I8WI8���
�p!$Lg27q� 	��-�h���R�(�:�Y~�x��C���u��x��^�a�4�Cm�C����i�wj�gy:����"�Ws�:���[��{v�c���G���"O�27q��CD�j[�Y�kzO��v�xP�>�����M,!P�������������#-?f���t4s��-&��[���P^��[��c���E��{=����BU��Yl�jy��y��X�1����"�����gnc1���W��:��P`��[��c���"I�����X�@�*z�i�D������bq�d��bRd����&��@��vL���8T���E�����T�x:�����8,�-M,������//�-N������1�M,N���p1��hbqB.N
��V�bRg����&���+�bgn������=�����x:����r�J��vM4�xC.��\�z�[r1���tXs�w���p1m�hb��\�����L�v�bRj����6#���i�D�������g�u �ZO67��@.>��[���s���ne�bRl����&g�����<��������g�U��I���C��X\���b�:����\\�\�:�[��\L�m<����q.������8�������
(�p1���b\,z5������������eI���nnb��b���{����X�V,��n�~G������&����W��:�G�b�[��c�5�+�$\L�7���X�j[�[�4�����wL��	�XTk[�[�\,z5����qv�zu.���q.������8�^�b�tk��^��}�tk\&I��qnb�\,z5����q.��;�[c�(�p1�����\[�[c@.u.���1"��t�s�#rq$\L�(�X��c��}�t+"G��t�s�rq$\L�(�X���S��}�t+!'��t�s�W��D���Q4�xE.^�\�{�[+r�J���snc1r�J���Q4�xC.^.��nm���b:����r�F��6R4�xG.�.��n���;�b:����;r�N��vR���x�s��3�:��w������\|.��M,>���:�=���\|0.6O�2rq&\L{)�X���s�����VA.����`�&�����<�*�����c�t� ��t�s���#�q�u�5a����X�"����k8��Z��"�?M�������������E����~���/�~����J����z��_����������z��W�����S������Q<����'ONS>���w�{�H�=~���3��+)?����uM>��&"z+���q�4����t����}D����J�j[�}��������i�a�)��/�8<AP%r5����	�DD���~���}������*�'��T��/��<CT%r5����	;ED��k�`����Q�>O�^�h��9�������&��'���{�
J$�T/D��.D���u�7a���=��Z��/�i��.��=����w�����X("zO�>�}��qG��(�(u��	�)���k�M�'"zO�>�}��iE�z��p��_��O�w�����X'"zO�>�_~��+b0���-���"����=l�'��,���
!�4���M���7�������B�[e��������K
E�=�&����;�_Z���_���96
>�I��e���� L�:��]"��r����	���;M�H��0��hb0V����i��#�>z����8�UM�&�[�i�hpA&u"�~E����M-�``�{6�c�5+j�!���hc0@�����f7���w�;�X�
����)����E�f�u�5{��W��c�0XD+[�X�����1��.^���jr����u��*�<�\�`�k��E����A�<y��s0�U���	8X�jgM���y�g�;&Y�<�F�����&���"W3�:��g�`�{>��1����u�7*��x4�p0m�hb�,z�wL��eG�:��M��"W3�:��rp�r���L�58 ���I����`���������$�{
����p�y���#�`����������{
N��I�`zq���	98��mFNU~r������I�`zo���+r�J8�vr41xE^���{&Yr��s0�6���
9xcl�dm��[����`r��;r��s0�2���9xgl�d���{��{&Y;r��s0�3���9x'L�8�| u��d�������@�3r�A8�vq418#�*?9��^�3rp�9��hc0rp&L�8�\��s����\r��9��L�
41� ���������������e�q��
��Z������I��%!��lp�$kq0�p!M!��@�<@D�f�u��`E��=�1�Z����/��@�=<@D�f�u��`A��=�1�ZF��i���@�GRE�f�u��`=��=�1�Z���Y���@��	
��:����`,�g�;&Y�t�F}*�:����T��l�d-X
"z�wL��yC��Tzu����"Wb�d-X"z�wL��%�F}
*�:��`RE�f�u��`-��=O���d-9�t���M���p0m�hb0��������%"�fzu���98��mF�U�z&Y	9�����MN���p0m�hb0�����=��9�����M^��W���o���X"z��L�V�`�	B�41xC^	���&c��=�3����I#�:���9x#L�6��U ��lp�$kG&} ��@����q�y��E ��lp�$�@&m ��@������I������=���L�@���&g��L8��l41K@D����IVA&M ��@�rp!L;6��\�<wL���Lz@����8X�j['Ya�g�;&Y�9��s0�:��`,r5�������E����IVp5�N����`���:�
8X��
��d�F���IV��E�f�u�F�`�{6�c��
5�L�41x����IV���E����IV�j�9�^hc0p����N���q��<wL��,�����0�\�`�$+,.^����IVX��E�b�u��`��l�d�%���9�c���u�W����ng�������1�
98�L�418"G��>X'Y!"�*/=���u�W����#�m��������L�rp�9�^hb���Hk�`�d���k����I���6O�6���t��I���U9x��dm���`�$kC�Hc�`�d���[����I����L�41xG�u��y�u �U^z&Yr��s0�:���9��9��I��|T9x��de��C�`zu���9836O�2rp�r��3�*��Y�`zu���9�06O�
rp�sp�$� ������ �p��N�"V�������8��*�W���"r5������5��dp��dEw�F}P�:��`��l�dE���g�;&Y�o�Q�K��1 "W3�:��XY#z�wL���4#)��W�<B�*r5������5��lp�$+N0O3��zu����"W3�:��XY#z�wL���4#)��W�<C�*r5������5��lp�$+.#j����M^ H����IV���{6�c��C���^zu���8X�j['Y+kD����IV�����^hbpD�������5��lp�$+F�`R\C�418!G���<����{6�g����Iq
�:��`��D8��'YXY#zO��I��L�k���&���+�`o�dae��=�3����Iq
�:���
9x#���,���g�{&Y;r0)��W��#����y���5��lp�$�@&�5��@����p�7O���F��
��de�`V\C�4q8#g��<����{v�g���Ys
�<����$�		{�,KkD����YVAf�5��@���(\
[�Yi�g�;�Yi�P#�p���8,,z5�����&\�:wL������qVr��Wqx������zu�g%0,�5�������E���u���W�J��c��F�a�9lh�pX�j[Zi��zUN�4������+M���E���u��&�a�{v�c��f�[GZi�����V���E�����V�jd<l�i�eD�	���VZ��E�����VZ�Hx��"h�p�����V
������c���p <L��qy8�3���C��S�L+E��Hx��#h�pD����3��<�<�zfZ	y8�	�8����a�LkENu��i���+�az����+��Jxxz"����?����������\��,��?>!yx}�������|���Q@�q/���q�w���y��n���}���������������_����}���������o���e��c���u���H��jD2�����y�������72{bj���}�����p�i��"�w}�����X�#�d���>}CyW�:}�
���<��w}�����X| d���>~Cy0B�V,6��@dF8>���|hbqF8�d��>Cy0�B�V,6
�P$�q�GP8z�����8�S���,F�[��4�C���E������Xk#z5��'p(�#�����&q?���@�$d���X��6�W��}���9���m��w��m(����D��9"z5��gp �m�S���m��{�Y�S�����P<GD�fq��a��zj�y�O���r���q����S8�9��U,���,y�o���m�mw�x��u=��|h�u��b����,�N�Vl�YO
7�v�;Z<�(��<�!�X�7�W��:�Z��f=u���*�h��P$9zDoB4�KnD�f�u��b��zj�y�W����"��#z���Xs#z5����{n�S��������S���[�[+��^�b�tk�����t�n�������w����2D���#���<������u�n���	���x��������^�b�t�n�S���]��������-6O���F�j��[�w���n���v�xC.>��|h�y���7�W��<������x�n���;r����C���-������y��#�:o���v��@.�	�M,����Yl�na��zj�y���b��S�����[X{#z5���-��YO�7�va;Z���O�7Zl�na����,6O���f=5�����hqA.>��|h�y���7�W��:����S���]�~op���,�N���X�j[�[���zu.�����j�bz-����X�j[�[�p��\�;�[�.���������E�f�u�����W�b�1���E.��
�X<�^�b�tk��Eo�����69I��^7hb�\,z5����m.��;�[�TP$�bz������.���6������m>P$�bz����p���,�N���X��-;�[���H����A���E�f�u���	W���c�tk���p1�n����\�tk������c�tk����q�u��E��H�8��[	�8��x��n%�����<�J���pq0O�rq�s��3�Z���bz����+r�J�8��[+r�Z���g��!����u�&o����`�nm��[�������\�.��
�X�#o������xG.�������S.�����;Acz���������<�:��*?�J}�
"��}�6#��y����*?�B}�
f��L���6hbpF,���y�U�s��{��wBq!PL�41� ��:���G��~�e�����c����C�����qD�f�u��c1�~*�y���W�{W�mT��D}�������8�W3�:���g?���U��6��+�=J��9z����X�#z5��C�kq�S-�[e�m������)�����A��G�j[GZ;����V�����"�y3J�`�C���KqD�f�u��c)�~*�yLp�����F}����8��8�Ws�:���g?��<n1utx^Q�>����m�@U�j[gY;����R��I��/0�s?5�|��u��c)��UN�a���8���������,|j���a�4k�R��9l�f�X���Jq�����f��-��~����	y��=�������}��o��������~���/�~����Y����|������e)���__����7�|����8��|����_���
_��=<�����c��?���{�;�Zm�j�����v�D���0�w|���]�+��������oV�u�h�1�F}����M>����w�����k��/V�X�����G��V��w1����*��HWJM�58�{U��*Y��`P��U��M�&|�*���+���\������[��d��oU;z������E?Vy���V���D��(L��v��oU;z���6D�b����{
v�� r�wL��F����w0���W1�B�{��~���=1�cxx8V)�5����*�^��	������O?�wG�`�l��#p�����Rgz�����O�>�w�	5��/�<�^�����O��"�lp�$��=j$L�^41x����I�1������cP#�`�$�X��E�b�u�u,��"�lp�$�X2jdl�d���:_�������1�:rp L/]418"������kpD�u��d98��.��u�R
z��	98V9��q'��`BN�����&'���s��b�{
^��S���vr�
���+�`z����+r�J8�<�Z���*?9������W����E�7���p�y��!oU~r���+�#o�����&������W*A�5xG������{W�@�	�KM>�������k��|T9��!'7� r�A8�^�hbpF>t�Rz��98W9��'7� rpfl�d���s��2�{
.�����c�$� ���IVA.:_����<���9�c���Y(������� �W1�:��������Q��`7E�f�u��<AD�b�u��������FuG�=\,����IV������IV� �����#j��.�d�d��T��l�d��T�{6�c��'����.Y'Yy�$U�*['Yy� U��
��d���F���K�IV�'4X�Px���^�gRE����IV����[v�:��$��W1�:���"�lp�$+/j��-�d�d�I��U�N�r�g�;&Y9 ���IV��A��+�����C����IV����q�u��#rp�9�J���'��X���IVBNd�������t�R�y�������=��98�^�y��"�:_�����9x�r��3����W2�k0O�6��M��+����!oU�{&Yr�Fx
�I���6O�v�����s�$kG�����<�:��w���I��|T9x��d���5�'Y9��9�J���g��\���g����3e=�'Y98�|���^�rp�r��3�*���������\t�R�y��e@.U�;&Ye����IV��E�b�u�U���W���c�U��['Y��^�`�$�8�`�{6�c�U�C����u�U<p��U�N���g�;&Y��H8�Y'Ye��`����{�k�,rO/��2��p��N��,z����2������2m��p��N��,z����2������2'�H8�Y'Ye����IVY<.^����IVY��E�f�u�U�`�[�w���^����W���c�Urp ���������WZ=o698T9x��d��;�$�D���s��V�{
������K�$+!G���IVBN:_i���������L�rpbl�d���I��+����"�u��d���+�`o�dm�����WZ=�5xC���3����7���<����7����z�k���W98�L�v���p�7O�v��]��+���| �U=��9� ����9� l�de������g����3�`o�de��L8�<��������g�U��3�`o�d���s��J�{
.������[���aq	{�$����� ��*�&Yo�|�y'�lp�$�E�s�Q�S�iAd��;}�&0����+k��=�-�z#��F}N���I��?���(M:`���W���{6�[��F���y���&Y/jF{}�&0����+k��=�-�z#iC������J�0x�Gi�M�����������7h$�5~�M���9��I�IL41����wrO�nI��4��O+��<o`�����&��qe�;�g��%Yo4�����xZ����%���>J��hcp��� ��Q���0�F}^���M���p�m��Frp�rp��d�H�������
�&G��H*%���&G�X��3��������&'�H:%���&'$�T%��3�JH������&�H���J�M^��*
��a��(L�k<man�0��JZ%���&o��k��c�4kC&�5��07qxC�H��2���ax��p�8kG&�5��07qxG�I�3���ix��p�<�@&�5�17q�@>H��3��a������g���I}��M�M����4,�AM�������g�U��I��U�M.�����y�U��K��S�H� �O��[8��z�3���^>S���=;�1�r��	�2�&;�a��8LgM4q�����3-�6�Hx��1�qxX�j[gZ�O�zUN3-���E���u��<���������q��<�:fZn��������E���u���W����c��&�a�9l�i�	xX�j[gZn��zu��i�yD���i#s�g�a��9l�i�xX����i���F���������������<,zO��c����"	�R�&�-&@LgN4�8 �*��c��q DLk��X��#b�T�E$�X%b7t��\D$��i1s��#Cb�X+!�*��g����abZ�����L���M,^��S����3�Z�W������+B�J����hb��P�V��
=��
�x#TL���X�!o�����6#oU*vC�hkG,��G[;b�N����hb��X�W��
=���xg\l�m���b:����r��pq�p�@.>���&g���p1�A����\�.��ne��L���47�� g��t
E�rq�s���n��B��5����.�s(ZX�|��:������Ez�o�iUs�����Yl�ny7���s��.vG�]�������&;x��^�b�t�{�����w��-��$7��57���sD�*�im,.�z�y�����qB��t_O��X<B�*z5���-?B�*z+wL���Q�>�����&O���^�b�t�O�������-?(R���iis�g�WE�f�u��g�WEo������3��g�zZ����eD�����N�hb�����X�1����"�)��77�8@�*z5���-��Eo�������������6#��t0E�#rq�s���n��\Lo|�N�|D.����d�&'��X�b�3�J��������&'�����<�J������g��"��O��X�"�������x�s���nm������
�&o���b:����r�V�b�3����I���%�M,���w��t:E�w������g��#��Ok��X| ����x�&��G��}�t�@.&�7�97�8#���|�&g��\�b�3��������*�6#g��t@E�rqV��g�U��I��e�M,.���p1�P���q@..
wL���XTk[�[�\,z5����q(�zu.;�[��P$�bZ���b\,z5������������{I��V:7���^�b�tk�����bq�tkI���:7�x.������8������q�(�p1�unb�4�������&O����bq�tk�vI��;7�x.������8������q^Q$�bZ���b�b��Yl�n����W���c�5.���Z��:��b��Yl�n����!���?|���)��[�1 �����Ac:�����������R�kpD0�i�s�#�q$`LU418"�*?�B}��	�8,�
�MN���`1S����X��X����5����
N�'VpE(N�������������?^��H��W�����W?���?�$~��?_���������������~���?_����+N�+?�1�#�����/?�G�?}�]�^>��N��O��~�w�������&���b���stq����b���]�nV�p�3�0����
����+x Z:Z�I�M�=�,F�)_F�8�;n�������"�PA�06�7#Sd�tXG�)r�)��2�w2E����`l�oA�()���&�D�RE����o]�i�pu��[�;
����������"��2������F}Z���`���l�M�("z+�:�����������!r5��S�	EDo�LSO�3j�'�^���
=�O5tt@G��OD�V�_:<��Q��J/61x�LJ�j[�z������-b��K��F}z*���`8�!r5��C�	�DD����)�4�X��T����M�������N�&,�g�;�X�C
'�(BG.61x�U�j[�XV�����s�)L�Q��J.618 ��t,G��HD��
�dM9����q�M����p0���`��g�{&Y	9�t��a�MN���p0���`,���-=���L�D���&����p0���`��g�{&Y+r0�����!����8�&c���=�3����I����`���p0���`��g�{&Y;r0��C��#����(�&cy��=�3�:��I�����9� Lq�19��r���L�]��L�C���&g���8�<����{6�g�U��I{�����\�'YX"z�wL��9�t����-��`���'�N��8X��
��d�CF�������y4�p0���`,z�wL�f��F���I����E�f�u�5{�`�{���1����u�c�,r5����yq������{�p����I�<�\�`�$k�.^����^r�N��"Z1�:��'�`��l�d�S���r���K�]�yB�:���M���E�f�u�5�����lp�$k^<j�9��Slb�,r5����y�g�;&YsP���t�b�rp`l�d�98T9���%7/!rp�9��RlbpD�����9"�*�=���u������#�`:m���	98�9�g�����`�$+!'��t�F�W��T���I���6O�V���pp2O�6�����S�$kC�t�#��!o���y��!oU�z&Y;r��s0����9x'����9x�r��3�:��w�����&����d�d��G����IVF>t������3��d�de��\���g�������tnb�rp&�����\�<�L�
rp�9��Mla�2��0�N�,�g�;&Y���F}L����`��l�d-X"z�wL��P�>���	lc0<@D�6"�:�Z�D��
��d-��/���	lb������N���g�;&Y��4�B61x� U�j['Y�����s�$k�F�����I�M� H����I��5 ��lp�$k�j��@���&���\�`�$k��{6�c���5��z���&/L���I�� ��lp�$kY��O������E�f�u��`���=�1�Zr0������i�����?D����I���I���`���8�<����{6�g����I�������'Y��!z��L�V��se�{����9x%����9x�sp�$kC^	�'Yr�F8��'Yr�V���I���6O�v���p�3O���F��^z&Y;r0)����| ����y��}5��lp�$�@&�5tV`�3r�A8��'YXX#z��L�2r0�����\��3�`g�dac��=�3�*������
lc0rp!LK�Z��R���c��`�l�d�8X�j['Y�
�xU^:&Y��h�`�$+8�`��l�d�q���tL��Q���tV`�=p����N���g�;&Yat�Q�`:+���#p��U��]M��E����IVj$l�d�iB�	���&O����lp�$+Lj$l�d�8X�j['Ya�'�C�$+�j�9��
lb�,r5������������$��s0���`�`��l�d��q��:&Y! �����&��@8��v518"�*��IV���Q�`:+���98��]mF�U=���u�������`��������z&Y+rp�9��
lb���26O�V������g��"�:�Y�M���W���I���U98�L�6��M�`:+���;r�F8��v51xG���3����w���I�����]M>���:�L����p�y�u ��ioW�3r�Q���3����Y�`:+���98��]M.������g�U�����tV`�rp!L{���\�;&Yq�q	u��[x��\�`�$+be��=�1��nD���":+��� "W3�:��XY#z�wL��w�QTDg61��D�j['Y+kD����IV�5�{���&�#�O�������XY#z�wL��x�F}`/����	�T��l�dE���g�;&Yq�P�>���
lc0�"W1��v51+kD����IV�a�f$�5tV`�gRE�f�u���F��
��d��iFR\Cg61x� U�j['Y+kD����1��88��:,���A8��]mFUN���Ys
�����$		���&ci��=;�3�JH�����l�pBN�iuW���F���f%Da�]C�6qxEN��iwW���F����f������l���0���]M���{v�g��!��:1���H��a�<�kD����y��4��k���&���;�a�@�kD�������8��k���&���a����a���g�{&Zy�����M�����0-�j�0�p��p�H� �:5���y��
^M���{r�
C�4 �:7���i �����V�Eo����V
�$DL'6���h1!b����bD,z+w���;P$Ab:;����X�j[�Z�����s��7I��Nlc10���,����8��U��
��4�j�b�`+���W��:�J����B�:&[i*�����V���E�f�u���W�J�n�m��XTk[G[i,�����V�3�^���1�J��"	�)�M,^��E�b1m�jb�\,z+w�Rp(�q�u��rq \L;��X����������b�t+E��@���z5�8"�:���VD.����,�&'��H���z5�8!�:���VB.N���4�6#'�������+rq�s���n���+�b:O���+r�J��v{5�xC.^�\�z�[r�F��Nlb��\�.��^M,����:�����\�.�3�X�#���i�W����:�����\�.�S�X| ��������s���ne���p1�+����\���[�8����L�2rq&\L'6�� g���������(\�3�*���q�u���)��i�W�W����;�[���H}�����X��9"z5����KnD��b�1�Z��"��F��lc1<GD�f�u��b����X�1�Z=�\I����X��9"z5�����nDo�����:�����8:c���#���W��:�Z��F�V,��n���"�I��Nlb�����,�N�V,���;�[��Q�>���9�M,�!_�������u7��bq�tk]�O�ut�`��WE�f�u��b����X�1�Z��"�y���lbq�b}���_M,���[��c���b�|����&G��@��65�KoDo�������I�����X�\	���&c����X�3�J��������M,N���p1m�jb1�����c�tkE.&�7��lb��\�.��_m,F.^�\<�L�6�b������&o���b���b,���{�[;r1��qt�`�w���p1�kb1������=������8:x���r�A����5�pDo������\Lzp�<����\|.�=`M,�
�[��g����I����X\��3�b�tKpDo����VA.&]8��lc1rqa\l�nmrqA.�������S.Ow.�6�p�e��k�E��2-k��s�zU4~���^���h����6`,z5�����\�*?�B}��~B��o���~+|B`��y������o������"������_~}����������~��?_�������R��o��~��Oo������_q�_�������o5l�w'Y����w�����O������R,�v%?��K�����X�2�hV�t`c��z�[����+E����\<|�z+�9����0�D�X�������*�w�����o����/Uo�=��=J��t;:����_��~�JM���F|���N�V�s�������_tvtRc�S%������{�M�J�p�����6�o�7�D����c���z�W�zx�$�^W�f�'��Q���uG��gGg46�w�M���{!����
�Dne�MG��5������`�b����^��wW�:���C�l����~��JG��H�{�����r��"���<�;���t��l0"�QE�'���kpF>[�j{��g���t��kpF�U~r����L �NflbpA.:_�����\����[
��>*���\��<AD�b�u����g�;�X�PP��I��T�&�	
����4��k����=�1������iGg261��D�*[�X����=�1������iG'261x�U�*[Y�1��=�1�����c���clc0��W1�:��'���9�lbwL��	�S�h�`�$k� I����I�>�x�����}���"Z3�:��gHRE�b�u����T1�c��/#j�l;:����$���.�J7��/�������=8���vtc�rp�9�J5����P��'���l0rp L�0618"���4��kpD�U~r���G��H8��`lbpB�:_�����������{
N���p0�����98�|��^�W�����ON:���9x%L�/�19x�9�J'��o��k��{&Yr�F8�N_lb����|��^�w�����=��9x'Lg/61xG�u��z����{����qr��r�N8�N^lb��|6O������ON8����|�s����3�`�$+#�*?9��f���3�`�$� g���4��kpA.U~r������8�:�:���s���[
>�`�{6�c�uj$L'.61��^�`�$�p��"�lp�$�p	5���,z�����{\�*?9��^�=p����N�,z����cp��<vL��8XDk['Y�,z����c��xu��d��	�I�M���E�b�u�uL��"�lp�$��j$L�,61x����I�1���t��I�1�H8�NYlb�2�������c�g�;&Y�r�F��t�b�p��U�N����<uL���['YGD:_i������<uL����'Y98�|���^�rp�r��3�J���p0������t���y��+rp�r��3�Z��W��t�b�W��U��+}�7��V9x��dm��+��d�dm�����W�>�5xC��<�L�v���pp2O�v��]��+]���#�u��d���;��d�d�����W�>�5�@>��3�:�����<�������Wz>�58#�*�=����	'�$� g���IVA.U�{&Y9�N�IVA.�����<��T9x��d��i�h�`�$+��uyW>�5�y\<|�<��t4��8M�l�deO��l�d�<qq����S��`�4Et}=���`O��l�de�q����S���qD���^?X'Yy�$U�*['Yy� U��
��d���F}^����<A�*z����<A�*r�wL��TP�>���IV�G4X�y���^�gRE����IV�������u��HRE�b�u����F��
��d�eC���^?X'Yy�$U�*['Y�jD����c��r0����u��rp l�de���g�;&Y9"��?X'Y9"G���I�����=���LZk�`�d%���s��*��
FNU^z&Y+r0����y��"�:_����`���g�{&Yr0����<����7���y�&ce��=�3����Io�w�I����L��41+kD����I��Lzk�3O���]�`z����XY#r��L��`�[��y�u :��&M���{6�g����Io�w�IVF�:��&M���{6�g�U��Io�w�IVA.:��&-.rp�rp��d�8XDk['Ye����IV2.^��C�$��5v�IVq���W1�:�*8X��
��d�P#�`�$�x�`���(�N�8��E����QV�52����8���[��8i��$,z�w���x�FB��:�*�������(,z�w����F���:�*�����N��<��UY8tL��,,�5����2�^�a�8�,W�
��c�U�a�9lg�`X�j[�Y/d��W���yV	H�������J@:
;z������������aoh��8uv��I�#�p��p��h%��Hx��'Z	y816���p��p�i%��Dx��GZ+�pb<l�i���k��c�LkE^�gZ��Jx�=i���<�Uy8���6�����y��!o�����&���[��c�LkG�	�����<���O�8| �U�=3�y� <<�gZ��Ax��>i�pF>�<{fZy8�3��<�	��'mF�U�=3��<�	���VA.�����&��R��~���KHxx4��^�}�y��6��^�|�y�=;�/�r�P�>��������vd�&=���a(�y�=9��eZ/�2j�'��8�r��a2\�Ai�0��<����i�H�Q�>������F{2]�Ai�0��<����i�HZQ�>���������d�&=���a��y�=;�/�z�A#)���q�����'2_�Ai�0�<����i�h\@#i���q���f�g2`�Ai�p���P�q�������1�~2��^�%px!6��&C��C���~���G��_?gZ/����az���y8Ty8���^�y����8�z��<	�#(M������=3��<Lm�d�i%��Hx�Ai�pBNu��i%�aRi�'�LkEN����&���k����3�Z�I����C��xe@ljm�k���3����I����S�
�xcDl�j�H�[����3���I����c��x'HLO����x�"�z�Z21����y�u ���1�&��G����3�������Hv[�3Bq&PL��4�8#�*��g�U��I�������T\��(M,.H��J�n�m�bRp�g�h��!�,�'QZX��b�[��c����E���g�l�9�b��Yl�m9\,z+w��[Q$���:�r�X�j[�[���z
wL��.����������W��:�zy����s���n�|�A�H�x�N��\,z5���-7\�:�����&I�x�N��\,z5���-7�����-7{���:�r3p��U,��Q�X<�����-�(�q�u���b��Yl�n��X�V,��n�%�H���u����.�'R�X��C��]�t���@�x�N�\D.�����&G��X�b�1�r�8.^����\	�3)M,N������g�������<�J���p1=�����8)\�3�Z��W���y��"������6#�
�L�6���p�b�nm���bz(���r�V�b�3����7���y��#�������x�s���n��;���<�:��������\|����L����q�y�������PJ�3rq�s���ne�����<�*���p1=�����\\�\�{�[��.��VA..�������#����c�����r>Tk[�[o~A�>���C)M,�
������-�"�$E8>X�[��sD�j[�[Jpz+wL��_@$����:���#�W��:������[��c���	E��}�N������,�N�<��<�V,��n���H}������ _������������c�t�������`�n��U��Yl�ny(�y��X�1��sF���_��-�x�X�����&C�Co�����_v���};m������U,��R�XU8��;�[> �B��-���bz(����8��x��n��\Lq|�N�|D.������&'��X���g����I%����VB.N�����6#�:�=����t��h�n���+�bz(���+r��\��o������\�o]�
�������vyC4��s)M\���*?�J}��;�1����<���w��TJ�w��
���P�l0b1i���<�:�w���LJ��������N�k��PLJq|4��2B����<����
���L�kpF$&�8>�[�83$6�
"q�"�s���\�I%��{���B���Fia�8 �*?�M|���8,�5��C�q������8\�*?�I|��nB���u�5:�a��li�`X��~n��^��G����u�5z�`��lh�8X�V&�4px�.�4~b	�5��?~��o���_���x�����_~}���������?����^��W�������~}���������������r1��Q,����]{��?�����������t�s���#?W�dG��s9M>�3p���\���Km^Q#)����0�3p�������e��S��v4x���Y�W�\�`�loO�h�hp@�:X��&�����:�rE�o�u���`t��5�M���q�u�7F��X?|�1��E����0618!W$������%6���c�7���l�] �{
^aM�j�_�����D�������Q#�`���k���`��FO�41x��5�{6�g�����l�]8�r��;r�F���9�&���{��{�{;r�N6�.�q��`���p0=����9x�r���M�5�@>���3.�| ����&g�����ON6�������y����3�`z��������O�5�������y�U���`z���9�T9���&�<
#.!��il�4�D�j['YV��������9�������Mv�����I��"��lp�$kr5�Sah�b����=���`��g�;&Y�?P�>+��.61x� U�jA�u�5ay��=�1���
5��Ri�b�'RE�f�u�5au��=�1�����9��s�����\�`�$k���{6�c�5�0�p"�!�q���3�"W3�:���6D��/�tL���N�;��-61x� U�j['Y��������)��Q��J������d�dMX"z�wL���LzCh�b�#rp$����	CD����IVD&�!�i���	98N�I������=���L:Ch�b�W���8�<����{6�g��"�������
9xel�daU��=�3����I_�Xlc0r�Ff���kc0�����=��9������&���;��?�'YX"z��L��`�B��| d~��D���/���?���W��&oY~+|Br����������7����^�'}�����w��_����|���������������_����}���������7E���>���B�.d:��<����D��H|�����>rCuH���-���|���yX2��B���D�Sc����Pq!g�h"���Wp���0�U3��5�U>:����^2�f���x&�PhW�=�DT��D����>}�'����{��8{���A(���OGQo5��D���F��������� ���>� ���E���%����B��M�P�d����5��uh��=�DP��Rfz(��q�??����R�����4mE�j��8����`<�2�C)���o6���C)�i��j$a\���A7�C)���o6���C)�i��!��������`<�2�C)�����e������C)�eaq1�|Yx���H(\��O'S�`�O�I����~����O�I�r��x�g�,|�'��/_{m]���'��P�}�-��e~}���F��mP����"�r39��@�cp��_��
���OW��o���6C,7�3*W�q�lpq��a�l�4"'=����MN��3*���b�.�qah�V�A(�q+�q�{:���}�,�]����nxk��n��y��>��C���������o�G}���[]�������\����
?	+��>���U������WWu���������'�����b#�B�V�W
����=���MW?�;�_�f�|�}�g���8�D�>�������&��v}?gqX�L�F�/e
�=[�����������q�skFD��";�#��c�������0�7����o���W��JCg��Y�}���p���N��V�T2�����U���SE�v�.����	����e��{r�SIk;gl����n��t���T'rM[g�����������:8�(���W�
k�����kk��P[�z>Y6t��o���T��:��zD���6��,�e�v�4uH�@��76?��������|G������
�e�h����?������xQ:����o�X������y	��H��)�u1\������9�)�a2'�2�S�ly�����|���P��/d�Q�"YQH.��a:)|c�'��f�7S�)B
>��/������7����������_��M��n��Ak���"^yso~����Q�~��Gz�7:%8�#j��>���=.@!^2�_�e���^��^J����{|�wx��cQ�u~������Z��$+�\2�r1c��%�K��wi�s�"�3��s�O���o}�q�/����������;�Eq.��U�X�����_2���t�}�8f����/�qo���8x�ID����7C7^�U��@y|��t���k�o&R��4�dV@N#���0<�~�ML����X��_j|����}a�>��X[Br��������~��_�|�.������+��[���!x���e���N^P|qE�W�t	��/-y�o���^^Q��,�b�I%/���d�0L�_��A���8�]$m���<m��1h���,�8�:}���|l�t#�W����	;��N�bW��|a�"������b���~��u�\�O�Q�N���6Kw�:rA��k�t3>�&B����b4�����&_�yEqz��Y-[���M�>�����(��E����[�!FJ���X�?���������i�&��M���-�{�������o��W��M����?�q"�;�����ay�o���|AZp���5���~�zzdb����xz������NO�7���4(/��N�����?�_�m��~+|B�<"��r�'}��z��Q!�y�Z�YVo��w�D�_��Y\�������~���$r����q����-���n����V��������/<��=��<H�[����/�0<0��_������}��cn>,����J�G�l�j�8���Z���<�3R�+67sR�o"W�����k�Cq|���<.���������o��X��W�����??l�\�o��7?����[>o��gv��y�%�=����'~���������K/� O��������������������>���{�?���O��������������~t���GI�!,�_~������W��^�y{������P!��H�N?�Q�����nS��7��#���������b}X"�+y��Vt���������0�:���w~��6���o4��gD)���k|�\����!F&��C�(��}E�A��p!�!F�����	"��_V��#������_��1���(d�gP�bDup�Q�*����#���]A�jSln:�����;�v����}
Q[�%�Z_��3NT���v���-T�
3������Q�~���\����p�E�>?������l[� �O����U���m��@q��{�6Y:��$r�������� ���(g�tp�N�>��w�y�Q9{g����u��<v-�m����u`'g�����\e�n;uu�
����{zu����7�.�OA�8|s:����ud���]?��Gy@N��x�g��(�r�(��-�7|B���&C]��:��������H~6���4j��Q�~�Y��r\^=��B��~�8��_%x���5�v���S�UxGy����5	�
��.�n�B?��6� ����#���2�{i?��\Irv�y��P�����A�<*��
������C���G��O���z����q��u����?�/��qI��������F����I~|T������O�r�'��+����g��INK�Q��}�	���?~O���F���u
�����F��u�� ���:wa�����:|e�����;h��`;�S_KUnz'@up/O�*���n�g��E��K|��������$�����@R+r��Q6������^���~�_�~|�!�����������?C���/@���v���+�o���@�4:�}��[����u~Duz����[�_��>�g�5���_|3Mo���/��v��c�N��h3�I��v8�_VFu���#����{v8@�<�8�t���P����}����Q�`���0v�3�7��6�@l{<���������v��M	�o��Oh�@C}{�Z��=��p�O�B���j��NN����@m�����������v���CVQ]��<��;vr���
���_�<l����OZh4�9���^�x���[a����!��#^����Px���1�i�<��kav>�_}{C�=��^���{��#�p��W�_���=�(D�w��g$�"7b�nu���_���X�eO����C�W�$��T���<��a%IK
C�{BmY��=}���7���-�$O4��]��\�����V!������[��F>�-_�)�J���W%}a���X��z��SU]����q�o
�>�j������u�ePG�.�nF��G�_[�7�
��Gu���X�<�E��r��b�'�����tP�8X�����{�Yo��V[��#�QP��}>h�t��{J��:8Y������&K�
��Itw��P���5����
����~�����W����Ql�����wT�o���W�@\�������_:h*|�U��ym�K(�\�����,p�O�)��|����������u�����S�����{�(�����k�������k{���fO�������+� ]��s����
��g=!@v���;Fm�<��k�e��9��5:��B������_I��P#��#a�=�w<��!�x��Fq��������l������_���<�.��j���U�G�=�>���f�0EI��7n/w#	���S��;p����'��#n��t��{}j�t3>5f}~��=n�
R;�o�6K�O�YO(���G�g����?I���}t$g�x�I���Ze����u���}^g�����VY���UQ���\e����$�����x�rJ����s$y'�=��L ���3�y'�	L�3��~&�
f3�g�_:��
z(pY��������?%gg�_~������`�w�����8q��&P�a\��/#���5���{������5�:��E�W'�V|X�z��.[��<Bu���I��sq���|X����/�n������L���[�m`�:�BN��.�F��������K�W
D���%.�=!��W�h}��DT�o��"�-�R]y����EN�7��Kg���\�Gu��v��8|��{T_���%�'�%����!�_��Q����G�eb�s� v�'�^�6��������}>E�g��-�#7��`�K���X�>�"�Y�����{�O���g��M�.8G�-�/]���"�����%���������Y]��|����]=������"d�"WY��S�Q����A�d�d��
�������t���Q�~B��X��9D��t�����
��?���p]��p]�8�y{�iX8�M	�%�e�~�����+�rD��������u�f1�
���}��3Kx+��+�V�n%��g	�������9��=}/4Y�e�CW"YIy�Y=�6�����=�����w����6��g?{7��Em"�ym���m"���2]<<eE��O�&9����+r������q��{���lE�bs�S����E�b���'�y��e\����p����!������po7�f���4���U���n���u�������_���>6O9�'�s�h��i��-ll�����r^�����Dm���M[���6���<{Pk��$[����:<����{,������ZN���=W�}����u�������\���'9�8���|p��k��#.�~W��K��6����B_x^��6��=���P����������Vr"����q�q��{���nG������tO6�����9�y	����:�N=�K�X<B&��-���P$�94�(���W<�#{�����8�%r��k�P��V������|.�i�������^��P���l�ta����,��S:�����6�����b�hq��p5d�P��x����gk�J��d���M`�-����kK��!���;���^���HV��7�P��"��zW��������n�����W��}^�-`�
�G�~�`q�N�?��h����7��9v���
0�M����7�D��AP#�G8M���|����m��8HDm}l|l�%el��Z$��!^������x �
��M���-7������L�_~Q����Ccp��8����-7J\�5�[i��I�,l��'#�/{D��������	�V�"��7��#:N��M���w�S�����i~��_����8�7�)"�_�Y@$��N/l�Q���<�����I+��"�k�'d����W��}�F�I]����kuW����Q�"W��$rk�
�e����*���$�w�#�.���"�P��*��OugD�W�O�b|����r�KqG���p���}vo�18�C�%#,<��h�t�Y�:[��<�;P���i/E��+����]�x�
��KW������/l�������7,?o��$��������T���>��u
ip�S����u�6�=^�]�Q�����i^~+|Bd:��}�������}�D���g��$r*Q{Z�+��7�V��
(M$?�Sz�n�I�y������[u��2�����n��q���A��n��_��4�]��[m������:m�a���W�#l!��|8\I}�$mu�c��$^�Dm}�j���qPv���������}��VM!.����b���/�V5���)p�M��������c��&���[����nT_O���n�[���D�W��@���M��M`^��[���s����������q/���y�{����__������~+���
����}������_���������o�������+e���
/��|d����.��?�3����p����-�5�w�^�����D�l����-�]�*/t�����=�E�W�koK.������f�� =�����7�/��Cup�p;5}���J�q���\���?�0�{��P���\���]������T�jkw��^������P�������O�e������i|��/p�WrU��:���#y�'��'3�I��=��
������.�'���
�8E��t�� �����NZ`S�jk�5��V[����N�6wR��Z��<�K(�\u���M��f��,]���(�{G������@""WY���5O�VG������@";���ZOUGq����UW��u#�o���5?���6�o��]���;i?N���|��I��A���������>i��:���[�_xt��fN����5��
�o���88,(j������w���~`����n:y���p���e����*�`�8}?������h�j�������
�$���2x<fx����_������\%}����m�����������R��^���q%���s���!��� .��t�3<y'/�r�"Z
�=��"!?���a���=O^�����������
O��'�s7E����+�X�Y����o��Du�c�\m����}��&��K�~%������z������=�3nd��]C��~��{�8��z�\��-��{B
�o�+��'u�0;�Gc��-���Gq�W�%>�kr��U�_��'�~oqb=�Pu����WD�������'J&����[p����Le�r��;#���{�|BZ��L�'~����!���	=v�?�G�-Cf�zZgyK�������U>��o���i@q�s�~�&8)*r�>(���]{I�SBq�4}O�@�,]FudF8���|�f����5��l�v8�K�jk���	�[Q�������i-r��k~��-#�c����Y^&r��k~��m��m[[�d�"W[��M>s�������}k�����N
@
5���gN
�x;���%�L�y����������`�Z�~���[��,*$��7����(���|W����kP �����i��H������y
�"�"���
^����pjJ�_�B.G��<�l^���K������]l��Gp����� /���Nf�e��<����uzl^����������:}���%m�S]��N.���y��65<0}����ck�b���������B�p8�������"�i�����UXN����Bu@*������V|);t\ag�oz��:�C*�=��2�x�65�����w��	��[\�{�����b�A�O�*��|��v����a�������E��6?�*����~�65���������Z��]�� �E��Yu�=���nuN�!dM��lS�8?���TByu���F��&���/��5z�mj;�Jzr��0����>��������
Q]Bud��N�n�v8;�����
A��P"b��[pv!3���C�Q�����.���n�v�%7 ��f��Gu2�?w�����]�1����>�{�a8~�a8�EW��QCu�����_��
��!Y@t�f���sP�P�e]o]>?��~HV�Oj�Y���������pvm
���i��ne
o�d���
�j�l�����
��de���s�����%�����_�����?�������cA��Gq@����_�����G���u� �Pn��q�?�~��[6�Q�>��6����B�����l����_b�?Wf��>CH�P�u���������=m�3>�2I�����-W&\���:������?*[���-������'~H������G?�?i�_����m��o�O�5:|�*�������~�fm�J�rO�A�=z=�m^��j����
9��W~3����<7@�8�J�gR�%�[6�Q`��=��0f��0�"{h�Z��p��!W9��|`��(.}=o�u��	�Sf�%��{2������/��Gu@H"��-�u���"|�����Lv;�����=^`P�j�V��[v�A���\m/��]|7�]�7|Bp��%<�k��m|P{@�/������o��Bu�� �>K�����m�jtX���6T���4!}������
��y^�Bz�����=�F�h�[�xNn��q����������7�������O������%9�4������q��8�@IP��0QTM�A4����{g��a��I����Ub?i�'3{���p?��M�j�V	v��;��v������	g��
�h��<�f����]�t.+��L���t��WYu���#�!P��L���>����b�@�k���w����P�1]�{]p?�t�
�f�h���k��H�+X7e�B��.���t�����U����4�iLG�ei�.�6E��%�4��L���!�<������4�.��zQ7:�������,�u��6!R�����/|{S6��O����k�Em��r��E�[`�5��U3�h�i��>��pH��{������Pd�7�r�px����
Z~��[@�[|��z��Vn�t�}.�rpb:B��9�j�A-�/%%I�T7��{���8�-��>�WX)�
��|gt+���PE�E8���Qm����r�T�[el�V�_�un?z*&U�W(���t���[���1�	L�f��y�,��^�kO�:����b��E�	F\,R��!j'��'�Z>��;���������r=�o(G:����������|���+�B��6��6�uO��M\ �-���I��"��H���~�..u�O���LK�a�2`�P�~���]��teA��T���:T?����.��0�nC:T	�V��|X	���������������	>�-���Fy�~���J�u���H�!�'���0���M��3~er��f$��V3]r�����Yu3�^�p�%��n&�q������F��.���t���F�Bk�Z�!z[{��G�%���������Uwqe�]����?6���Z)���01���N
�f�h�M+:j��Lw'7]�,Ac���*�T��H�'	�7�L8C+e��R��9������D���	�V���"��s�t��x��1Z�t��@��Z��RIb������}4]4o�m�t��H:]�p��J�&�L����0]�d��~�5Q"�#����OQ#�������'qc�nSD0T���{SY���Z��\�/I�H8>���v���Q��V�E4�1�0��P���qBAx��pZ�i�wM��p3�B��64�����Y1_�����������M���w�5���P�5v$i-�(tZ_Z��"Ik���]g��/�8�Z������EZK8(��#���Y��k���`�|w7s�zy���%�8�[
����?�;�'����"�w^P��y=����q��8EZ��3�-�����&��im[Z�d��d[?���!nHk/�]^�Jk����
n���Vk�:��c.�.�]���
���
�v�����wN�s��}���@M��.5��B�M��$�?�������������������_�.��~���
m�=/��s��_v�U�[+��/c>��Q
����z9������z{_�E�h2d��UeY�(�xN�5������_�t���F�9��J$�7�F�5��`k��ro��k���I�}R�aeS�E�M8$������y��i�h��9|7���T��`I�
�6'��j�����+J���-7J�_%e�7����tm�Z��CU���<H���6��8]BA�����������&]���&S;U�MyUy7����Vx(�>e�3T���C��V-Xj�8i^�!�$���0��tT
���"IL�p�(^�3E\@��t��q��X�&����+I���P����M��I�G�%W>�n"����g��5�@B��.y�3�A
4j��������2�F��n&�~��aYk(�����Q�����5<|���p0J
sS����c��PyM��[uuI8��0��)LW��\�t���#�n"�������]������n:N�Z�t����U�I�C�'��������h���	���O1����h�po�E�2�x��w�.Un�����aC�����~���J�g�1�+����\�t����&���Qc�����l�!o!��im��o�'��>��&�_����q�����^���|=�k�}��j���I,���"u5��p�`����O��#�F��>�|�_��en?��w�}��j�%C�G��E�w����C�Gh}�|�	I-���0���DR�����E-8�V���
,W�bLZ6GR%�
,����j0�q���[h��&�������1k�����;3�X=
-�J�<�p/i j~����Q��m�F��U�V7�Tm�V~U�������F�����w�iu���[%������yy�p7�9�5.t]���~�����]s����w�����6���w�|��c���J`<�����������n��}������}�wr�'����Ol���/�u	�B������JE?F:������' {���t3�����������TE��l��=���['�P��j�Q\��k,�Z�Cw��*���F:��\��Ar�5����yR�u����9��PBDzQ��j���Y��Q�&������=o�5�����~���![��K��'$��37���p�S��o����I�l��w�Md��b��I� ���=����e��B�aLW�/���tP]	������y��n�2��+=	��l��?t��9�/�c�h�����;e���U6l�\�s�����2>��A<�J�i���@�"=e�:��OX��ur����y����h��@���������Ka:�y�h_p����'�����'���j�yT����Y�+
��#�weV���j�m"I�����]����phHh"u��V���p�3+L�p%O�uq��Y 7d�|�:��Iu�U��F��N���D�b
1�pq���[x��F�����T'\����������C.�(�<���g���ES��c��%�N8\!B���9��}����-yB����7^�;������S���+a���H���n�zR��c'����,*3�ya��#��~+��gM���'���rc5dk��i���b��OPp�{�����a�d�AnT`��8�VIW���ogT���%{tx�	�g\+�������t�BK�*�.FB�pUI��O%'��5�I��e���
t���i{�y�M\����P�l�z�!������)hI�E���qB]�5�C0����h	!B��)F�9W[)�>�G������w��hypV_��C��z���\�e��?6\�nR����
h���u���B�1�||3g�#44Bqr]K:C+~����Z�t��%�u�7����4�sx�;��2�RK��:�����M�|��j�K=,�t�#��mR������W�1]O:=jMIc:<��V3]�&��QHW�������/e��L�e`��+G��O��o�*��(��y�Z�����T���&�L���j�K�����t���9Go�:�w5�-Z����u5�N��M���xp��j#�]G�&B�f���R�$\�g��[��$������~��=��V3���D�����po�-�]
H}�7�B"��b:��ZC�Q�{�II�e��?�~H��Y"������6���x��,�[�=?�iq���Y���"-���b�k\���cm����_��q����?������+�H��C"@h?�;��
^���*�w�q�^7����o�7n]����:�u��V�)"�"����*n���z��L���*�fN���C?�KJcuIi��^��4�"58����.h<N�DL.�1k9^��8��t5��1����H:�AZ �r-���������V$�BK�Q�6����]LN��p��\������S���������Ng$z�lb*p��^?�������C��ob���������)V#���k
{�X
�=wJ������#V#�8���=E���N*z]���O����-�	��`�p}�~Zw��3�j����ta�u�������"��D��c�d6����K�[��Z�t�E�C!��~��cVh5�%!�����x=l��qW��LM��e�I�+�������xp�q�)�Ia�<'�~���r�t�V3]�����z���:��\���k���\Q���?\\��H����)�f��H��#W���0��$�5D����0��d���f�������C���n�8�9��5\�TiG���4D��
�%��]AS���6����������\yK��Jb����+�k���L�M�w����+������~�M�Z]��?;q���o��l���]-�8�=�1^6��/���Y��o.����Z���������=1}\��cOD]U\G`�&���WK�%���n��<��s��9�����#_���E�5|'t���[4�O����M������~#l:vu+����O������������?�������?��/���|��;��_������������O_�Qw�~�������)��o��k�X���l�j���xr�����r�m������?m���_�6���>���f���������B�����6����[J�n�'NH@&^�����j-Ai5���^��CLFp��	J�A\)�����vw&(����s��B�r��g$([`��F�����F�<��"��j���=�F��)��MW����~�Ya��tlM'����"�'�QtiV�FIP�n&���<|�Ux0�f��5\�Cs�e��=����TQSE��l0�d`��������^�cGL=~aua��."�SB�\�t�&��"O:���'n����:+|����'��^���1�~����i�TW���+��w.,K&��3�D�����8�"�����'!�E�-]��tQ��v{�E��#��?�~/�������t���i��^��x�0���.�m?CJ�c�h���)�dz���������Nrh�7��[@pw�D�T��#�
�}�[������LF�+�t�����c�c��EN�1�'��d����S6q�HgT�XpQr���(��<�������&���K����7R��tp����a��c�Y���]"g�l�����*�=+g@8��Z�������3���
���A�\��(2�3r�x�4z��j�'	��o��
A&/j"�Qeu����x��j�K^�D��t�H��W��sy�[?\�j�������]���!�&����wV���N��u�wMa:V�
�b�6ZQS��80�K_u�.Z�t��4�n�Gi����X]*����wV%]O:���x����i5kDR
��/1�����eu��j�����Z&�H���}O-O��.K-w�W����B^U�Y7���g%�A�~#��M�7��z��L+)OBm��m��Iy�������Iy���<	�G����u��������{������Y��g���������&�E�������*�y_�o���'����>gR��%�%)��N�W��GT���K���mh&���o�'��z���4���{���y�	�������C ��B��~`Vm��ZKELL:^�FEn�6�hH7������3k���A��F"6JgT�X�i
�;�W��)vq�����!���������F�H���p��$+��3j+������W�5�5�tEF�q��%;T@H�(B�i�4�����}\��3��Y��8"�!v-����_w6�1�_6�z���O�S�p��,i�{��3I�.���Q�F�����3��n����PP��W�$)H����j�K�� �&���.���t���p���]�:�kXn�
Kb;�<�:���{�CAg4;�-�'lg_lo�7��������=6��[���^���
��e��|���A�;��_���?<5���������.�"�4��<����/}WeW��l��_h_K��1_EBK��o�H�O��DPh�����O��d��3N�8�O����������$�.����E_��x-+�������������w�K&������z�A3.�D���hJCl��S�7N�~�C�]�~��-�Y�g?�7�u���t�
�-�����gSU���������{����s���^�������@��C������0JCX�A��[j��IJ�!\&�rs�u��<
����H��y4��Y�Z�$%���������$�x����s�.��������(Jh?s�rE�?es0ZoT�C6c%)I�m�
F�]6	9V���@H���YS��47%c	�O��|�8�Kp���w&)�����j&)	��)3^�3���-K�S�2+,%hO:\��������n"�Q!�[t)l�`��j��V��� H�h��ESO�]O:+����.�f����mW�3����%��e�Wp?��������US�d�5��>g���f��lM�j;�d�1I��u���3n2��F��Q���t���=]=&�]X:Zf_���?\]-;��Kq`��_#����'���G�}n_����i����
��`��K�����F;��L�`&�B{��c�o���1���:�����c@q���(�`����<�w^xk,��M�<��|���Ap�s��-X��K=	(���X�c�g�����L�uW�wJFI~���^��~����|�W��qR
@,f-���#���H�8��*o��L����&���s����2K�_��s�������^N���B��a\��*m��WHit'?|W�Zw��(R�p�#\���qw1[�)�����lU�2�����h;n��a��c�	�+��{��p��5���I�_"��'_H:�D	�^]�������o��\O�z�����/�����k1���yA������1����G�1��������C��2�q�����GHb����5>�
y������[�il���+�E�������*�O���t�
�f��=zI����`8�v���F�Yg��S�nb����4���`I�*�5�:K��'�@:�K���nbZ��l��M/���t���=�Z?�Z�7�}����@�Vi�P�,u��oXZp;
U����pl�*��S�I�7�H	�b>��Jb��!�#�J��,�{�m\1�~A�1b�Bh��5�k���D�o�R����oqp����#0������GV��X���Mh�;����
���Q�V�����=_p7��`��^�
-9��E�GT�q7��}��j�y��b�H�B����1����`\����X6�r���Xn\�����j?���b�H_B��P�q��q���8���cT���H�&�������+�����6��&�_���7�7�������b�c=��8ox��`T�����1�.�Mb���
Wz�<��ET#�8k=$i(�q�sZh�<����["
�H�H�e_Z��?pxI���`\���r��b�H�����p8����_���H�+ �<��7Yq�WW���h�E�]G��v��|�H�����FKl#��D�V���������T��Zp?�C�Hr���m�L������>��m�:�r�t��w�r��U��J�J}vW~UFW����0O��+��\)�_gw��g�����y����^������X�-w
}��^)�v(�n]��;g�y����w%�r��1E��]R��!�E�������t�x����8$\�h��&F�C�M��A��3������t��3�q���ct��-7�Q�`�Kb����Z�V���+hd�;��s����p_AK����������t�j��4}R����\��c�a���V���Z���]��n0t��4�m��5�����&���(�v��������kR����j�K>��t#����.yI�0�����.y9�*��
���e�/[Z����S�n"����%����r��������R���AW����ZW�p�\E�r�P���3�G�f�p5�%/�"� Mmt�(,�$��Jp5�%/�"�B:�����������.O^NE:
�S���/(#L��h-Sm�f��_P�����5ZJ�G�mG:�e��o��/�V��:��?����tF;����_P���8���z�Y�������/��([6!��]�Hg�-��4�������e�B�
�3�����il��1��Y-|��i�P��t�gY�$������K�I��C�����y*������u��w��������!]�S(P|&l�9��F7X�"�����W ��>�����c��G���>V��Y��@��5�s+G��2����>���K<A^��Q4��C���	�����Q�f�)E�-4�=�G��m~���X(���mv]�m��Z��?���0�E��=_7�,�����Sd������{������Y�|�����:y�u|��o��Sn\�vs�k
�7�7���AdT���4g�p���X.�k�p������Y;4I��k�x�9(�C��3���V�|�k-����7_�tH�t]��>�;�C�+�
^�������=~h#&�����j�K?Jx.����������%a�����CQ��mI��|���4F
����;�����_��EG���eQo����~���X{v/�
���}������/�������gb#c��y n��Fh�z !2�����x�
�v"��7������u��!��"����#��/3�/$��SFS���W�Jo��"ae[�o_}.o�+$������=��������uO!�&vHR��s�1�}�*+s�C<��^�Z���S�����j�Q��A".5��P���T?���	��EQVy������+���~�?�Jk��;�<�)�Qn����*���|F)����{�G��G���������l�F���r�����F����{�{p�k�g�d�5z#�q�NfX�7���3J%0������7�����d�Yo��5F?�h;�*���3k��:J!��NI��(�������Xn&�]��t��QL�����&7�R��zt�W	���J]^C������Z����CNp5��.���x�u����u��v�,�o�����������\�v��k<��tFZ����v������?)l7 b&����N	�f���5�D:���wC���w.�����GG��!$�#�W��	�:,�W�__6Z2��e'��!��s4&��n�>�0^�F�\�������0S���Fd������a���hJk`��>��>��~����A�K�����BSZ���d|3�����+��rg^����rE�������Z���Z���_��������n9���������~��������|���y[�[��^,�{}nl���G�9���������,�;����������������w����������_7~���J�m����~C)�����=����
�w�|���O�}���K��B~G������vZW_������lm�j��e�F]&���w��
��C�+]�/��${����.�k������&I�a\5�P�|8�/�;H�P�=���7����}����ED��z�e�������e������7����X�X�#	����1;R.tU��x��H�
�U�����_�d��I*�5�%�����Q�sV[�8�
����M"���m�d �������)A��q�z{�<!\G��s|j�r�4F���wq�}���IP8����t-���N����Q�4��x��F_��X�q4��@���H�\SA��pz�BO���T|�������zG�y�������<c�V;+�%����)g����n��5�[�v�V+�4�����^���Il�����8z�9���j�K�f���3�eVi��6�p6�f��:(���t����u�����~�"��t=��|���.��Yp5�%�A���3�N}W8���:�&sEr��Y5��uP�����f��:(����F��g1�����.\����t#�V�nV�������W����
���m7���G������ +��X�q�<��g8�&\-���������Q��o���#y��W�����WG���WD�">�Cp}^���[�xx=L9���\=���t3�w��V�����b]�S��s�������1�����n��$��8�������~��e0��i�=���|[�U��~���������
����(�KP�(��oX�����s?�����r��%�&[+�2>��6��?0��LXx��E�/�R�H�V�=w���*�[+�����s��{��
��lM��%�Ia�������L��!o�~���]��.�^sKO��=�@��7���K$��,�*8!+n���p�6.s�R�\�\�75��{Op�mv��L�*i�N5[=��6)�T�A��i��|yi�����?���?������������|�./������/��oV���*�(��1�cqD�[H�'t�C{g���1~�a:��v�X,�y�Z�����Z+Nt�����=�"%PH�����=�.y��t�t�f���u�M���� U\�v��6R��t-��Z�{��zN>�a�'�\��\�l0d`�v�+���#4��V�P���x��/�EI>�Q%���w��(La�c����_�^.�T��'��LWf���"G=�C��	���-)��.)m+�x[nM	��|n����������S;�tq-~#6~�[�C$�vwe���|2r;����������2�&��2�5V<��B#bV�V��(^5��m	�r���D��<���p���d�mP��9K5�m@<����
��WQ����xx�2��y���A��]�OY�
�I��<����O��5�I�7�:a7�(F�	�IU��<�R\?*v��������F����/���������+t���~�������^8.�������������o��(��<����� ��������_~��?}�g��������7���������a���<��b�v�����O?��������%�?2�z��U��������T�����H,8���v�h.�����UY�m�s[�-��\-B��tT�VF��m��7\�v���H��N��y���,��#\�v���@7��3f���KzH���j�/�{1�B��tw��=�R?gU���������X�C�����R��*��u��u�U�V��8Y�9��B�\��
�������j���k���f�GY��j��}�����*��O����(��>t����+3��xGY,�dUH�.=���U�^AP+Y��Vn�VEb���G���<�MT��?��^
|������~Ade|�,+������<Pk���"�����y���������� �������(u����v������N�m���lhI8^�M�9�X���4^Yz��C^����^>tS!X{
AY���b6�
�����j����{$Rp� PR�"�Q[���� P�q�@�c���W�K������b�� �W���6�����2��� �f�5�6$����"gF�p�����;#������������{2����m���p���XtIlG'v�[8��)�L��tw7�Yn�"������7��fXx���2�
�#��E�>dS�T��"0q���+v�����	����~�{���	�����e?��2���:�C�����	����*���7aU�&��Mi����p���AG�aS���������r��o�����m�V��:l�[�u]����#��������4j����������Z�/�=����eW~���^K���������ck��ylEUJ�
�1����
�y�>���?��(��o<��	<���~a��]�������Ql��nc�(� ����N�����s��	9t��p,��k�6�
<���r����CO3}�U"e���E�-�~��?�C�`0t��S��|{�
���18��	���������I<���W{{�����Y�/��.���d�-���wq%���OiDJ�n@$Cp?s<c���x@,Cx��P@����!����P������!BBp �Zr��5�o�Y�N�r�����\OZ�8��x�LzX^��*w!�@��%r~�`���zi��%u���n��\-�>
#d��B�4��Hgz0�:EI��.�Ig�lXt)l�#�'����5�
�I��������g�-�+�,JRt������������u`R��&b��e�����V0�F���!k�Yq2�8�H��~��j.J>�p�
�G�c[��FC��hcly����j%���#I�P��~���
Z����ZR�$���^x<kG��G�!
�]/wio��N)w����JJ�#(��_xw���o')wi���r�_����M������z�l=wY�cy)w����#($(�����.������Oh����Q��~�<"68>�M>��������������c��tY��'��'�
���]���7�	��z\���K��� ��!	�������?BpC����1������2J��o�e�O])��e���}-#�+~Dk�V?#�,E��x�X����#��'#C�6'��m�tQ��;~��~�#�c�;P���w����iJ�CE^�����;�<���!S{m����y��{�KWI�Xp1����B���x�yh��:~�	��W
���^^����Yp�m\��#"�U	96������I��^����YO��;�M�DF������^�������M8�+�v���N��>�6�+k�XY�9��y��p�M�6��@:ch���+��o���R���J���rK���v-�l��/wF��D�Ig����_IlW���F:�kQ"��)�
W�]�"c����-���Yj�(�|�n"�Q�m�&����p5���YwU
:�e��wE5`WT����c��n!���:��C�
W�]j��G��5@�����n���
'�j�E�C��/�������\|�G
N��ip����,L7��P���;���9L�C�q"��F��yQ48�����1\
�Waoj�����o������t{xMi\���>������9=V>AgctSk�tM�������}�}���t��-|��� ��{�>_���/Tx����������|2,a����n����c�[]�sy]X��=��{Zy�c�-����m��NQ��M�*~�q�J���_~?���q1?A���w��qG�g-���j�<�}���>MY1U�_XV���D�M�O��q������|E�a����jJI�:�,;����ev�qQ�>�����/��`w��~&>d�y�L<���z�RaD���A��p~�&KO����[����gpQ��<O����42��0�nc�����!3smctA�1�6�f�YM�H$E
������57�
=~��)�~�������5���&���U���J�+������	���p�U�q����:xp-��Qz�>E���/��?p#�������u�K������nec4�Y�'�B:�5�w+?lsf�����t���0��*��W�]rM�z����m����j�K�I]�H7�.�&�t
�l�+��@��
!�@:����%�3����.�&�tH�^������Np5�%�$�n$���;��ky�5�����b�����14�M��!o��av-Jb��t�Mv�]��&3)8�kQ
�u���Vo���]���3�pu��J�B:C�p���y�u��T9�Xw=|\���u��&�����T9������(�<�vT����.�_�g��tF���o��7�`����
����~�y7�'3ZU8�� ��y���Ov��!�\�vG�SA:��������Mz*�l���v��&�';�v3}�������$����Y��?���t�OfV$�����*���:�n��2��EgFyR���O�����e�����a��2���m|���'��j���W���#�UWpp���f�=�����v��F�a5�M�;��O��vXF��K��X;E6�'�����v���rY-��j[�P�=xj����Sm����Q���M��i��K��o�/����s(�#F�.�>���V�2b^\���g�b��aP�D�k��Y��~}������#6�����M��-�;����*=�SI8Tg
�pQ
 ���f�}�z��@���P����P��Hjo"��
����@�]��w�����{��^�����C�H�
����M��f�)���i�{Z�Ec����X/��?������c�����xxW[E5M�Y�?�
 ?�1��kq�)E����+�(�������%���>�������V���l"�O}����:��HO�E��"�B�!�8Y��x���z��������j��zNF��"�M�:�)oN���+�hLW:|;HMW[}���o�]���_p?s-i���9�wyx��-��pFp�}�0���-@�TF�_H����L:P�T��P�jp�y(�J�V�>��5���g2������)����W�������:�$�H�cf0!��(B#�
�3��Yr��F�W�]r�����p�	���4�?�h"�P������.K��t�=(������H�l3�����y=��tF#d+��d�M�-'�����b��`2�?�v�u7�U0e���w3o��x��DZ��n^Hg�dY����[x��z��)�P�-���&;����Mp5�%/�x�k3G�7�����p��f�����Ig���6[Hg� ����Ed����O����|�uo�������f4�p����k��/1��G$�p�
��"���������j4�����
k��a;<
m^`�@#V�v^��#��p$��Z?z������UF:��#"#
�:���	EDF8\a�Co�KftMECUe�3/I2�k���P���O	��]�[p?�C�-i�w�7i��no��}h���#"#�����Dd�M$��w0q�:�����~�t��vs�-YuyQ��v���Tg���T����+=��Mtz���#/�A�S���H�rI�L���%�"�����w
XY�.���"���x�(F�{^O�8�)�����Gn��y��C~:���m<�[�f��O��3~�3�1���bt�:~3��Qo��`$��3]��C{Q����)B���*�����}fTf&O�����>��T��-������l���k�O�3�mB��}&����X���'��J{k����+0\v��L��OP��5 NZtL��V
�K.Y"R"������I�`eo�����%�-�3�^n;��\�v����y���Q����%�Ak�[=j��}����,#�!��^�)l7d+�f�h���u7d�1��w���[\�v��J�.�I���?�&�W����`�u��5���wV�K��&��5E�\�:W������+��Lp5�%��A��t�Mv��+p�	�f���jI��~��+x���0�|)�]1����_w%o�B��*L!_
�q���~�� ��!��Yl�b��3�9��o��7Y����h���nIp?���F����h���MVY>��{���[��lw�_Q������`;�d�^�V����@�5���Y�g���O�>�1�6����5�Ov�y�f����.y)�(��F��jF��v-OCW�Q�$�Ig�����mh
=��Ia��oc�u�	����oc�4Nb��tV����]���{��i�|�t�����^�T=�/U���&WW�Z~������#�������K��k��r�������+P�/�o���_�K_�w� �Ty�� �|�:����X~���!���p�������RyC8��B��J���*@�����m���=\cK�0h�t��Z���e]]�x�M�,F*���|o����� 9���QK/����*���t$:8����h���s�����kf$:n������!�����(>�Q�����j��J������h'��b.���x�3�Y/�4�1Ex����DIp5��/�%�B�S�v<
���RHp_h���x��J��o[V
�^�P`/�4���|UByi��0'e
�M�)����������4����pwh)h<=�����l"�!�'�/�NLd<$�GC���]��o����"[r�$���D��i�yy��1qZ�d)�-=C"��4�Q�Y�aL�0#�%hHc<�\�����;���rhB'c���
i��2O������ �\�xG{��*Tx5��aLV!�����0���xF<�:���
�����w"�!�'����0&&����w��%�g���	8i�W"�'�/���<���w��1U9�g��,]C�U��	�f��=�
�<�}A���x�g�����i�W4�U7u��Q#�'�����0j��W3��F��xF<�j��������uu��W)]���F��G��i�Q?��_�
����_G�~V���[�9:�~�:�PO�~���6
��c
��6M�}"��$2���4������xO8��+G#	��5-�5N<���Hyk|�6fc%���qH��D���&�������&�CPnD"u?��P�C��O�����k���`�W�ml�7�>��?������������.#�Z�C#rgt,����Fwc�H�����!(�JkF���K��p�L��F���K����l�L��5��k�\�F*�(E�!�-�����^ �����.y����3jB�]���Z5��G)�o|��lg�%�������%�@��t���Yr�$����IJ.y_2�!!+��rW��b6�+
����*0�+�?�X^!�����h''�Q^����4��Mf�q����n�Hg�?=���H��l��/�:��������l4�.y_2�M�nG�O���n�M6}z\�_�����|�1�z��o���������/�	Z���h���{����~n6�6o�/��?6��������B�;����	���k��k�q��)�'V����,�pX_�����B���-���zp&	�.5n���2���Z�C����F����p{	����1q#��nG������q�/���'���N.,"�x��/��xW,F�"7Z�$2�L��
����x�W�f��2^��*e���9��z^�x�e��2O�;����x/�A���D���;�=�^�J<^��h�� ��h<��=:���x�����#�������k����x�@�N^(�����&��k������*�k�
�U)���pwh�i<�,%o�
��L���w��13f0��&y� �4��>�V��4��`��L�7�����CreyL����V�P+�m���Z���^�?��=�x���*��wK~��G��w�?|O��<.�6sK,��q]Hw�XZ_ �<���Djk���4��t5��������}�
��_X����Z>��n��!-�G���xLY]e�)�q$���`��{�v�����
�1������t=��tPntY�$���p?s�,i:a�=LY��������}��4
�;T�H��o��d�X�;%�a2��p�l��q$��kK����M�>�~q��~#6�Z����)s�FN��?��%�K:m�y�#�!^^��Ik���I����aZ]����z��p5�%����]e��?�v#�l�w�,��w���[��oIl%�
W�]��u�kIg$��oil7���h�K��0.���)wE�Bn�K���I�]�����t�y��&k�
��
z'YwmA:Cg5Mb��7Yk���4�il7��a�]��&k��L�(���t�Q�y���x�uFI�Y����F�~�����M�%�f1F�u�#�#����z�d�1��,�Hb��tF?��m78~Y���Y0�b�������d�������B:C�x�y7�'��YaMI�gG�d����g�	'�h�d���$�n�Ig4�=�v}�Io.PX�_���7�d�d���>�d�d���$����yusg�ws������/il���lt����Il��D���baFyR�n��@p?%��DY���Ib;���>k���e|�,��8�_f;�����kG��\6��x������^�����pY��<�y�EP����/I���
�.�����<r|=����3*����w�U�{��`�A%������s�������~yu-Q�N2�Z�~��}@8��.���,u���b���� �FB���27�4��:2����9��W����������� B�!�,�)O��EV��Fd��r��K�=��}��U@�C8Op_�8��xyI��:��t����B[�D��.^�� y�#�\N�Y������+Ax5��m����/}�(���`��������d��F�����j�K���tx��f��e��+s��`��Q��\�x�����*�K?S�t3�gE��7�^U�x���caI����Md<d

C�|�dS���g���C%��j�
�W3��F������|Ld���3&���/	���x�{�DNb����c��U=��x��2�4�����f��/�����:Kc��k�>�G_�D���)�I��9��`��
��\�x�{�y��K���t��uF<��r��x=�y��K���t���F<�|H�1�y^j��~R����x�9�<����^�xG_�yF�����4�c<o0�y����x�`I��0F��F#��}a�����F�p��_�}��N$:�����>&2�y����z|����{����^w������k��=�6$�4�2��#f�=�=������_�]�<]�l�1�7����_�w����>�}^������g�9�����}�:������p�����X >#��PL?�#�G#<)���<��!_��X���4fE0D�xx�
�����8����Vp�m"�M��������m\!�)�Z�C��Fjs�W���}�v<�1��Fh�4����4�ls:��\o7��m		w�4��\^�������NW'X����9$o�VO#���}m��Z��^A�F��/��Sf�1���aS]7rSml�����T����w�������?/$���_��_�����_~�>.��������|M���_�������j[��F��ot1O�*�3]~������~�� '���&~��������h�l�����e����m7������Z�t��<��%��{�h���Z�t������Igd��+w���@�Wh5�%��@��tz��l!��t3��v�V^:��+��b1���0]	���j�K���t�,�����x���+'�d�UC��=:�t��*�����Nc��tF������wXe�t�|t�Q-,���(���5�#�Y�����>|�Q*\M�+
���'%D}��R��<��];���.��w�h��v�A];������l0pe5�\�[��X]@�@3*���2�~��	���Kh_���5�p\_�M�zf�����PHSV�"L]g������,����b�^[��-[��Zp�>�;�K�����tz�0�p 
���2Q�8cPp_hl��x.��2��o�Ht�W3^z�0��,�&�
�����a�f�.��Jx����K>/�t}
�f��Ba�U9�g���GG���[w�Y���x�|+c�vg�gI���x�mk�QOb�����a���F����j�K_�H<���W3��F��xz0��s���AJEx�w���	�f���!JNjc��Uds��8��6$'�9���8��g���/�Njk��Yq��x]F������7�N�,!B���ZY�����V�,q�+K���Zz0�^F��=�=n�o�m�v���%��Z���w�����]����v��zg"2�3��j
#�I����h4F����e���@ tB����o�����{���0�ti@ni"�a���2����/-���g>�g>�ow�y{yqD4���A�7Q@
��I!��}������q�����>n�j�����S�@:����q)yg��.�B��J����v�t���:i+'�vp���*����v!���YG�
��	��)�z��u��ta#}Z\-Y���G���M�R���9T�4��2"G���l-)Ur�<�&��K�B��5F����Jb������x������%�%���I��s�o�� �/-,EF��|"�z�x�����!$���n�Hg����F	?Sh5�%��H:^b��bn:�&�u�Z�$���������t#O���i���4���1������x����QX:�$��P�)��b:�&�^�YX*�4���x����M7�4�,�w�7�bu���s�����V]�=U4����d���W�B�B�fZ>#�
*��Y���������k�.��Nb��.#� �F��h���%��[od����_G��0��$'�_��kY��}��=�~�BD�Y��2�e�\����x��9v[h=����~=#��1{�x�D�K8\"���y~�S���9���� 
�,N��P��IL�(uj�C���~dJ�g�]�5y\z%?������s����~�7I�{�����1�����Cw������w�&������,n:�N�A��� �#��?�=�t�u���W��� />���
|���%������&�j��O��[�e����8uD��>V2%����C
��j�6�$��7+�%���Y=Vn����Y�L�������Kb6����$���xL�	XH��D�x�+o1���������k �~���������C�Q�?eyNS�E�!��Sgzt������I�IHW����(�L��U��\u��[Dhu��F��Y�pEF�Q��_�,�����-����������)���LaU9GQ�yt���b��*I��LM�j��tz���������)�
�(z�Iq���
����V}s�-��56��n(	����&�b��C �ULgi���n"�������t#/�AO]n������a��qIc��t�qb��Ob:�&��:�rIL7�����M7�4��y�Z���������p��<M�������t,o�O1O�������(��f������&{V6���������a���).s����p��Y�������@<8�\B�\���%����x-4�������k4��,�_�G�����}�������@S����4_��~Yx�/����G�Qp_� '22���~�/�D��������78��E����D�Qp5���2��S����xz+���c�7���5J&��F���q��}�����h��6��)��Fh���uV�6��&<����Em��Kc<����/y�go���f?.V��Z�F``��^��5����~`�],6������
G�~�W���>��!�%���c�G�����3l���)GL~�����G\:�W�x����ll%���R7�&OFg�]Q\�q�dLvE��><����p�l���3<�"��R�Z ��L�uX�PIUB�)U�QU�����0���Z�����j�c����)���L�]Y�6�xpv���5^�����M$M1��\�X�_"�J�H���>=�NV�/NF�:7�tq�����Yx��+����m��A������N��[����S�1K>W+
�.�y3;F:��*>?m�����>��RO��3����5 ����5`�UHj'������S@:�`'Chue�S@8�"��R#��J7�����<��^�`��<Ur�6��Ef#PPX��8�v�����H�\�I8�(�V3]4}{����tz��p���	�f���v�u��n�o�b&��V�J'1]�H�?Z7]�7��j�K�o'�@:��RY
���2�mU�tq�U��*���x��4����V�8��&������>��j�&V@�J'1]
���~��x��FY�\�N��t�qr���&�QAf
Ob:�f�SL���1��]�7�Z�#��9�����}�=4>���d�^��?U-�y`������WV�gox�HU �X8AVJ
�8U�pK76���pQ��3Mh?2.�d(�X�>��+�:�t3-iL����)Z]^�vZ����8��^�-��q?t��j:�0��f�Ul ��l����D��U��+����lgi����D�9�=M7N:�
�b�������r��Z�\�L:<�W�]@�Vd�������RU�����k����v5���(�L/�$����	����������h;��kz�/���]p5�}WP(%�Z��p������:���Nj1�����$�k��]�����4�C�Sp�{�il�e��Q8`M2Kb����N������	�f�}�t�4�tmw�Q������"�o���G�k���i~�5����O����������%3rWz�o����^ �$V��g��~���Ur:���e�����I�O8�r�jx�����Gv������^�q����U�|��6�L���qH(�6^�4�`������t�Q,z�3���I��Dwy�1��|P�
Y����?d_h��7^E���S������_�������t9 s���X�)���/t������q����	��U*5��S��uWi~�mYn&��Zh�P��q��N��^��4�k`��P�v�����	m��<�t<��|.�h��@���t}�5�%�����5Z
w�����I�g7]����F��K./']	�NO����#����&/\u���p?����Dg���{IV]_���k�_u=��^��Yry9��������c�z�����8B_������B_���7�]�����U���e�����g��+k�E�sV��� �
��-�����/2��n��st�6b^b��e�xOd��"��cS���I��kj�4�s���1+������w9�������y������<9|O�}DaV��;����WW�t^Q)M8�����������!�O���v �8����R���E���P��j��C��$���t�����
�D��<������W��~������.��wN���t*�����	k�����bk���^����P�G�����������UXGS���-/�kM=~p�����7��S���y��nE���)��YK�[��(���mf(9r�5���!�D8mr�	�"X����#)�y3�O<n�E/�p���X��!�$��6�N��E����������[x�p5�������]����~�>.r�\�S�q��]����X��Q#��>n����R����������(v@���7\%[bDr�(v)GQ��2�b�p���S��`��ze'=�)��v�Y��A����Cp?�t<�
aG�%oC
:*;�V/+o���Ra;�,�N�t��������T��,yR��9�t��I�K�p[�f��:1��������������2OB+p3���=�p+�S���v����v�7Bs��4���	�c��?�Kb�'�m������?m����p��?�1����Rn1N�m�a���\G8���x����U}������^�	=�]�8�6�:w�P�$���~�Mqu���z�S��A�<�4$�+C�vA��;��!'B�B�\�9�9��-�h�y�W��m��p-[�M�>)cg��h���������CHpW�sw�w��Y���������-
%����b�� �8���-��x"�B���wdQ��Q�,�����x"2��`J�8_"�!�Rc���g���9cN��{v��1.t�O���1c��Qil��v�]Q��4���Cp5�%o-F:�KO��`��-�H�H��j�K�vtsN���`S��v3�����������W�]z$�f����]�����O���t)���x�����-.�?|��?����������������Oq�������|>?iD�y�9j�������A���K8�+L�&��i����4�q~�H�W^���[�Z�)��U6��9���^��E�.���pa}�������$��2��'�+�?8%�|q]}����xW���0*�"��@W�3����W$�,�x��z`��(Y��xM[�yS[���������"��o�
Y���q���$��.���1���5�E��4������%�u������X[Z���1V����9�F�t�XU���=����?������z��Y�>���'b�����
�;��p/��W�zM�$����*��"���TPe������.�L��������Zn.�'����kx~-j��r<�g=hk�sOa9���v�6����*C�u��x�-z����������_g�%{N`�:�Q�����=���3<���3��:�Q"������Q�\�g������\�B�U,�-��l��pz����	�%V�;�p��^�KA�g)h*�E
Zo0pi9�k8P

����h�m�W�#%��B�\)(��������l�#����H)d��%-��7:��t�x��HA�:����L`z)(��f\�;'�F��7�h<��KAI7�v�U{��t��Q�����$�����$y�C�Ip�f����7�x:@V��7�y2�������}iT$:��Y�+L�[�-|������'��	����%�$���~b9�B���:����aJp?���df7F��il	��j��+^l�	�<���d4�t7e������|OK���cG~S������W-]$-]i���D8��/�r���p�E8@,q`
�&���jQD8�C�^p�#i{���Z:��&�A+�j�ip��758��Z���j���\GKG:Dh<��l����I�q��c���5_���t��IK�����}L����>�Z���jA�/bi�@�f4����8TKGF
Z��Y�*Q�t�c�Ip�X}q�t��%b�����>-����U����@8��d�2�]B-�
�7���7��e��2`Bj�v��q��	1��(=�,�S�<;�h����6vMU���Lh?�r3�;�� Nc9>g������� �(����I,� �/��b9>�=�o����������;K���rm��d��X���k��Mh?��k��k��nV`8����k
�������5�u���E
�:���Yw
[��ak��zJ.-O������������2#�ij'�z$���*�D����f�~z�+��:��G�.��7�4�����z�����w�������G�})r��~T�tF��F�G�zJ8���'���� ��3|D��g!/����%�	E�K8<����J���8�x!����[x1�vV��8SOI�3�����}�>�w^���T����}��,��w������t����*�(oB�j]�Q�z��T�����c�� �����U��[������\p��i�����)+3;0�qIa�r�����&���>����cW"� �r��oZ�WR�e���T0���^����&��UA�1�!�8l�`�m\#[-����k	�&���F�t��}�������X��}'����)��e����!Y#�/U���t������l�@�#� �	��}��G�A8^"�>�H����tt�5/�����+���3���C��$��I������z�r��$�	
Bo��?�r���b�h�/-7�
���N�Y���������ax��H���6���'�����=�&h����[r�Rw+���t,=\�t�M������<<��c��������@�Ko�m��e��!}i�M/j$7����k$�G�Dq�h���d�o���B^T;5�s��q��������5).N��ph&%�/�E��E���~d<`��z������;"���1���V�bW�����������SJyvt�M��9YQ���?�|g*Nc��k�7� bf�!6��il����1YqO�;\����hV���\������|�C����1Y�z���'+�d���,'+�dE���v|�]k�5Ia;�#@��o�B:�X��k�7�!_,�d�&}��q��`LVtVW�$��d����h��Hc;�C�dEgu���c"�L��"������^�15����;�MS[��:��:������@4O�v��i�����
��#���B����$� ���uVL�c"NF���xY��?<n��?�(iJ������1������8��&�6.+"�������Ap5�5�.���t�J�3�q�������+�b
����X:&�����z�8�Q\,���z�g���1��m���"��1�":��[K�D8��c�t�?E�X�V�^��'�E:^�Fl�Z�q4%�	gta;�t#!��?L��t#��V3��xIb:�aF�����1o�Q�po:N>��V��8��!�?�����%1�@:#��|���p6����{4znYo�$�c��h{�`��tF4?\z���	p�������y�25�Z�F�L��=�ax��H2�g����4l����#c\
!���E�D8H���#�S��*��o�H�#�59-i�'�F���1���~��	�-������$��C	��j�9�$�t�	�1�=�+:�����A����
��������?�����������?�������?��/�z�r��������(u��������O_�9`C���|��x�n��%�R��������?�4�a+��o�7F]ns������o�$[u�;\��Ym��"0����Lxw��Jd�>����k�{�����w���1���o[��x��G�MU_�
�g�}���I�7��^�x��s�CHVp5�mwb�l<�dg#&k���oDby����D�E�����U�W{�5����0�O��.�0�_��Q���k���1��{������7�z��a(q�#@�La��#V��(��!�<s0�����z�[2���y=�pF����^	��	��!��W�e��#��L�>^rG�����:m/9�fa��}���t�S��|3�K:�`�372[#
��l���)u
NH��7`�Ch_p�}������dYR��;kpK�@����q`��5R-STWj����)�&c�p�#�R_��,
�r���g�������qX�0��p(9_��y�|�� (��A�4�[gJ7]�GL���a�u��:=w����Fp�����gtP;�t=�������q�8��k����Z��I���o�^"�@^���^��!���J��,�q����R�����}���qr�}M���~U�B��o��7��W�
��f/E����q�!+�+#�G��NwM�(�0�5����A�Y���C���C��A�d�n�ZOu�fK��0����`�&_��>�C7L��%�fW�4z�%�����(N�xmI�������-m���
/���yCw�rJ�q��~D{�[y�6/[��)o���.�����������{#B��|es���[� �R�(y�����A�r��~d�=X� �o��7���|��.N>�x-�7�6����%�6����~Go���tj?�-X|������(r;a�|��Czt��$����� ��}+Htn�Z:�x��I��QC���!�3\��Y���)+H�g����S���E��"7�8!r��:���LaA�8����3B�����DDFp�����"o�c:<brc4d�|*�&����7,�7\�t����)}8�tx�b:.J:�p3����{:�{N�a���������P�d��/Y�31 y��z�Vi|�8����������������~�g�O<F&=Te]����1b����F��21�s�7�go����������KFVC�~�� \�C��Y%���:Kd<��Cl�'�e��gT�ji����GL$<�e�pi��$I���4��)?|���e�U���Z�tH��f��Q��7�xz���T��x�����Yn�����'^��{	S�������}qX��?�g���a�����_S�����?|+��u<~�0�~/��"��HX!>+�Z�O�6���<:�*=>��G^����7��~�OI��g��<���8�>�gs���������{xm8�Y^pd(�6n:���o�f]cxCN�t�d�I����g����U"v�>n�<1���L�|/kO���Q�z�a�8R����i��u�����']�Hg�OZ��Y{��H��_j.R���w�CN��v�,�W]^��3Y����	L]�K�9#�Qh(�����/���Jc��pzH���3�r+r��t���h0y��]����������#�%)=�t|,���%k�"�k`��~d���)k������>�=�B,E������/�Jb����d�=8�����Y{�a.���#=���1R4z����qb����,;���g��G�h�7'd���f7x�C'/��� (�n.��,�U�����t}N�Y����g�(�U��\��!w*���N=���3r���6�
����.�k���U��\l��! ���v���7f4����m<:��G]m��e���[��{x|V=Od����|�)Y������#x�<Y4��e���f�on���K���������^r)c��@�@"\x����>+1�/��>����K`1$��{o{p�����}�g�2�g^���c>N��x����k��-e����z��>m��HB����K�L��j�L�[o{tx��g�c�����	��q��'�����(h��Qy�>���d�7�PkY{������h~�]�������#��\�D�e�]s����
��pJG�������2��P�z�H��g�*�}���+p'H8��V3]��q�����b�M��.n$�����D)L�g��c�V�4���q0���~�����1�D8CSZX���s9?�����IL��G��1���?\��ta/�
��o��r�b��
W��tI�]�b����s�[��$�������]���d~Q��\�v�^����p0����Il�{��<�g�
�8�����S�,�T^��G��RT����;yq����\�v�x��m�+��^Xo��c_��6�p�hNE����7Yq���Hg4x��y����Pp�����
V�U����I�gY�WYU~����G�7Y��j�tt�Z�%;z����ZC���W���Z�&;�m��&k
�����9��t�q��6���u����P�Yw}�����~����:�'3g��Xw=d���){��M�[M�����n@7�'��7���&��)���1pu
�O-�4�
�u��m0z;�g���o���(������7D4T���oj^-{���5���kU_��7����I$Fo�8S=8(���%mT��9�fT����j�p�,�F��	�j�px���L!k�F���b�"�8�x������l�e�����{������t�hJ��������9^��}�h��2�!�'��e��"W� ��e]qU�]��?��R�Ueu�T��AQ����[*��[�o�J���������v�@��1�,m�����m��Jw
�]L$}:���4^W�GUu�2�5���y��iT���W�My:��O��$Z�b�6nZo���=o�#	�2���Xi)�����*3I=����*������Z�(7-�Gbw�J������b����^@.�������������o�����������?�������������?������\�W2�.����"m�W}�%������?H]�v��b�7F=�Zk�_�;��4�t��������|hi ���m�8����qJs@����z=I�_�8Ni�p�	��F?v6������f�r���V��������(����v����I���6G��m+�>~���49G��&�P������H������4��b\�v�kb@W��3������Tp5�%����'��*�g��t�P����b�qD��~��c(��&$�mS�;�b:3�\F:�b:���5���kP<��}Ic;�d���9�|�t�����=�:�Y���k��ky��F���=���zE�����7Yk��+���v�P*��������7����x�!V*�����+��tF��>���y��V�����%�q�U��Mb;�d�Qh�HJc;JN�������X�C������E�Il���(���~�
�	�+�)l7�5����������"bOb��tF����)����ui�]x��m<10/����U�����#���t&��l�|�
�f���L��~�3	��������3��bH��CO�{Y�{.���,�����7�I<W��M���8���%
��V���H�1���*�^V��h��!�����}�Uv�Ufo��]�������(g��V���>Rm��4�UUC�.3Vm\YAV�O��S���Ao!�/�E��\Gvx��a�����BW�$������<k�d���-��}����a0�g�F<D0K�`���TC<�0�����io�1N������d�K��6.�����G:���������1�V��R����=�|���[�Ve'x���@�<;��Z��Z�k#��I��Vg$tW$R�8.~�>��EV�t�1=>�
���!�6�FZ���xCF�1�v{�������O��cN:C�P����D:�;����#��Q�~x�6��~���������t��
�x����99;B��Tg��Y���g����O���)� /�Y��k5!������)�kM��������S�����c������ur�5�^]���i�k�H���*tM���5\�v�5L��Igd����f��&��3Z������?`6�Mb��t�������ve�/k�O�F�Q����ZCp��.���EX���p_���?��������
|~�n&�.��*!����X���%�E8�;�����yh#c�e;�����v�����e<�Z���w�Z�C�h|�c|�������5c"��^hJ�5eM$����X�z�,?�Z�\�Z�z^����Z����J��������Z]VV��y������p)��d��=����5�	?2�pA�"��r�~AQ����oQ+2��@��1��W~�+��tu��3��x3��7e�&���ZY#�c��T����8DB�fO�|*������dL>�:dDJ��n"]�9O@�:����E�������E{�t��'	���	����1�,:B��Ra�t�"jW�x�\�t�JG8��R�!�K���}Y.���M8D��v����H��3��^{tY�)Q���C�y�f,���I7��<o;�'��c�L�������m�K���.y� �x�Y3������cp���e��Y�����2�M���Hg<����GH���U�~��e��d6]L��'V�{�\�@:D�W�]��=�f���6y�%���]p5�%O���/(���x�!u/����S�/��I��tO�����s��
K?������Y��	�k��2���s�T�d��*����y\��)�/�E�<1���`�\" �Z>��!"�#������E�-�8�g�����R��g�l5�������uFSz�n�\�o��y&��]�<�[��T2�E��sU^DUn���?�������.��N��2������U����od]����v�ra@�C��	8�q�G*M"/�N��Ml#e���e)�r'��8�_7d���f*�p(���p�5%%RFxl@)��.��h���lt�<~3�4[��>��2���1~�|��<G��8|Ot!F��0{��h�����r����Xm@R'�ZF�����t�����*<���&/�Y���6�2�.�~�����pZ/���a�\j�)_y&��]�cFp��g����C��j�K��!f��Bg����Z$�L:cF���k�Y���w
&�f��l�<�M��tF���3�b�r
�bM�5ZB��]�����n+��v-�����w������&��}N:#�~����`\�v�����M�[����+��t�Mf���g��w�2�&�����n��27�9�#��F�'��~9����Ip5�E�������h���>�(�\�vG���,���j���v��,������v��,���x�!]�Xkw�-����G����_�A��RR�nF�Ep?�m����j��+^������!bv��UO����I���+d��g�����I �@�������]fo�7q�c�{��o�/�E������~b�������7�Y��8�"�5%Mi�VW�H�1���^�A��d�a���.2��I�t�hJ=���0�t�x
���E���7�X�H�������6-iJ6-���#��AS:Vd����_����+�.o��'|���"Z(���/|�����&|���H��
�3��E�8����~��H����C�
p+��{!�CNzO9g�6"�������:R,����pEo�������p��,�}��tdHWc�-����<=is�6����4�n��+_#�s������vq,� ���z2���_���\E�f�#����KDh��z��j�B��p�<�S��������&�u]�SFp��k��C(Gp_���"9yc���h��P��tF���u�f�31u���������]�aW����N�H �D:�F�x�u�t��I���v���){����34N���(*"��Q`��:�v=O��x�7R���7Y��(f =��&�7��Md��NF����pK�
�T	�f�pE��Yu�������Y��9�^e�/l��������l��	��rm!��e1?�+f"�K��O���<gL��W��o��
W"	'���/�*��Ha	���7��qT	��2��b.�*�p����#�y���B��������&�LS��	gY/�*xuA��w��}��������H��k8@��}��Cs�x�*x�W������*�VT	�a
m�#��qe��*������6I�?|/��</t���?���K"��n���Ai<�v����t�4��������|�Z:�N�P��F�A���f.�t�1=R��1sq$����1��y�x�F��a�m�� H����&	����8�>��S��������2�OK�`-�&t3_���0a�8�&���Tf= VX��}����0�2��HzM��gZE���}����=��#p��2�]BM�-`��/K~�1a�����.`�I��K*���_Q������ �������jQ�h=)�*G:�L!yf�tpPW�]r��������@Ic;\&������]�H�_&������j�K�!�@:�
��AC-������]S�N�O�g�_�1FA5� ��I�WAo;��W�]<H�\P�U�-ge����#���*yO
�M��GA�<yO
�Q�%���� /�H���j��bh�TU������_6:2��$�����eta��Tq�����*�/����r��q�2GlYh5o�� ���w���_���\w�-��-
�v���X�v��t���.���S�}i+���K;h��W��;�}3��T<���������oo��FI�w����#p���
H�W]V���O���<2��^�}^'�.�^w`�l$�Z��%�G:^����/u*�p3���'�)wXY4&��!��7Sx��>1����R�T<��a,����y����h�����-��������R���
�}�����)���?|w�(F+oC�+�>��VS�E�6���'$/��J�[��}��ay�f(��6�qR��C�!�UR�����������f�r����ByFb�lG#�Z�3ym��H��VC�6ZC��-2s�z*������nW�U��]|J���3��il�T����K�E��HW�o�����T��j����x��2��{*���h��UX���^y�qATl$P��$�wP�dY�S����q��k6�j�2���A��H�j ����c��+zM����U�n,R�xmI����>�K3�.����R>I�4���}7�,��S�s��=j�<����<E���(��y��������������<E�e��<�����^��{�0*��K�!����#��>d����t#�Fm�5�r,��&H���~�5AV��~w&V�tSFK��;S�)u@<�����cw�>�u���}<#�.��t]�">�!�'����������m��CZ�����[�����]\?s��ce�!/��&��l�������t<
�Bg��q2��q
��9PO���}[	�^`�p8�v��I�:��u;���Mr����C�@p�0d���u����m�A�(�������n$��jt������J\�v��kH����~�������>���6Hc��tzb�x����*��������������Jb;<�W�]�����Ig��;|���_V��������/���.ywZ��e�[�i�Il�������)z�M|A��\�h)zMB:D��S�(=����t���A7�5��\�@:��W�]4�"p��|A��4�%�qM:�d�5�h�bah`6��G�o����)�������s�]�0��c)��Q$I�tM��l������Y��v�����_6����BR]{���V�����/��
9�uf8��Z���u\��p���:�~���Y��XtQZ�a��s�%,{�.�����Q�\]�=������Bh?2��
i\��6�Z�x�����pf��8�8��	*���g��x��c}iv����D�����C�X���M�)��"�.���?���~��q��M]\�T�]]��F�3�r�5�[C�����-�������������y��i���cs���/�8e����{R����p����+����K����OW����	��n��Vg����_��q1Q���K��w]B��G�P��~�>.�SJ=�{�>.�QJ�2�r�q4��
��{D��a�8����5/�J�(V/�(�<:����t06G���N���]��i�\s��k6-7Ni-�v�2�4���wWmL{-��k�8?���.7��s|c��<:
�f����W��l�Z����3�
�s��c#��k�m��v�1]���%�Nc;����.�&�^���tFej�:�I:�\�v��Txt�)v�������+��l�Z��-�3�W�����{0��M�g+D�:�����3<:�d���'k�Xw�2�SlW�&3�{�P�uWw�3n2�9��f��us�F�u�8���2�^���M���u{�F���3n���l����C?f�:����t�Mv�_A������Mc��t�Mv�y�1`(���A�u�tF,�x�1���1T��e��=�����������7J�To��>�8�]p_il��v�u�_P�Q�uxe�O�/(+�d��a��~�?;�D���lF��v#}���������\�vG�#���^����m�e4��feg���M������K������|�.�c�}5�������z �^��h�d�������
[g������M��8�~-DaV���8qJ��B�F]�����Fl{���zcVDe��Q�����"6�b�%xp8`������{zz�y�[��8ju���"=V;�(u	��Yx?�K%��s9�Ui�����������K ��h�{Z�u	��t�R�P��K���(��g�G`>������"�+W��K�������3*&.�}��'�������
�?|�u����R������?�(&�:��O���?��.���y��������/��O������/?�r�����,J�������/?����������������&G����3/�����0F~���������������t��;W�I���������@~[������Q�H�%��G'���k�X��k}���I�����m�T\B<���?�B���*.b�Q��I�}'T�.�!���U��jK@��)����
���jyt�6��Apw��b���n��VK���]����HH]QX��(��I�L��*�%F"?Nm	�x���F=dvN���k����9"\G�j=���QZ��������jH��x2If#�(i.���3R�U��>�f����f�Q�����Op?e�q������/����"��m�@d%���R����d]p?e�.��&��eL�tc�e��]���a�}��i�
�3�.G��1�Hg�(.\���$�t(s\J"�gIDX�����,��g���+_���e0R6��#���j.N6�p�����(�h�!f1>H�?,*0����x��/E�Q�}�}A)M<�f���_z�)u�,�|�4_��tFO������&�y��0f��[6:W��M�lt)���Z���q���"�����c�fV�^t��������������v7V��#�Q�Y�3l��|3�@8h��V{O���^���k��|�zZ��s<y��t�����S�)[<�^���������q�.^r�9��m��_@:$Z�3����p����o�)�iI]�lM���-$r ��g�vq�l! sGH=RX]�dI�^p��\�l!�p�����;���s/08vO��C��J�-�a��
{mNa���:����R�Q���,Ue�'O�3\~�r.Z=��]IG{V��m���g"�B:�v��Z��F�Ip5�%/�$���1��kAp����H��+�t]�AG���Iz�U��������0�*���o�qO��g������~�� ��M~]��f)
��z��0������A
��0������l����xHz��x��9��U�.�x1eI:�A�)K�����^�Uq��W���E)�<�
�qf�taV�B���B��kp�*���\��d���K��D���f�~zp'R7������-��@��9	!�d%+m\]qR��k�t��	%eN8��B�����:k����V�)N"x��!�6��DJ�7��~���p������5i��BS��f�6N�x}A��3�L�����SR�]��yu��^�l�<��W����x{���~�\�_����K�������*{�;0�D�xg�q��V���fZ�p(������GJ������sNCZ���Y5�!o%�/TxDJ��;������v13���zw�o��d���������3�����~�6^2x+���=q/������J��n��(8����c%�����sA��f?Nrt�L*�J�����'�
�1��Q3�;��mq�7_��p=���B}F���LX�2	h�n�t5�#���������'t��Gd��O�����|j���%!���)�e_����v
����){�A�Rp5�%�Z�6#���v-����.���t-����	�C���j�����[]���^:q��������*�+�G��P�#A�a<f�e.�L�N?��&XKI�n�=��o����&�������W�+�0��F��f&XI����!l�/�$X	7N/�4��$XW9|��^�Y��kCVz�9�:~DJ��{���h��$X����7����u
S� �z�D_���R�M���3���[h��e�k����z����'X7�$$��!�1kJ���?7^������^`�~�6��7���������5�k�w[���5*�?b�a}5����f������F���Y���*������@cH@��/�x>s;���P�4���U�U�f��t�&�@0;�E���okoV����.�.�X����w�8n���<`����n*H7�sBVn����x�6��O&�*1��r�����N�"�&���~	�;e��NFdg�7l#/��[�
2������0����(�n�C/���(��~�>s^x��s!�U'�O��x�
W9���QZc���I��5�$����p5�E�o�]O:�����
�M���
��G����p��f�h-�Cm7�N?Q�F�]��2Jj��GilWW������D��i�&^��9�f����a��m��7\�v�Z�����A�����7/���mXMr^t_)��?VS�A5��R� �2YA�����$bRB�\��%��i�GF�i�!u�;���GJdo��d����^��R��C�Wx?�K��}f=��[���|it@��j_zg��o���$����LY�[��TR��am��#����d��.o~����V�h�f�h��i]�}����"��D�<9a^�������g �8�UN��CWW��� eY��x��e�L3��Dp_�3)[H���[��!J�D����W���+�,B�e�]%]���:�����{�6��O*�*1������CC���-������lx�}9�������A�������'�l�/�/[��W�}����	�)�v�2������=qFo/C{+�I:3������F	��n.H�����nnA7ro���Jt��3��]��n��Dp5�E��h;�B�cl7��.���x����O��%t����$��I�J��'N�Ul��T�t��9L�S���s�����'��3o������I��N��g��t����	����3�(��Y�D��j�K>e�t�^��Hd�����������F\��;�v<Q
���|�4�f��O��<�z�G4���k���?6C���`�7��x$y;�Y�P�ny��.����#���~d��yuz|"7�q���CJ�����IA<x����_z�}����I���'�`L'�E�G��]�G�7yD��#����:���/�1f����)���������]4�?|/a[?/���rd_�[���@\x����j�%v&l�c�p�	������Qd��&Dh?��zf-�����?��z3_K:|f��n�hwq��C���C��4���;"��7�.�"�C�Bh��S�6~���s��>�JVng<����	��&p�d�+2�n�\�.�%� $�B��.�:�(q�1�"�J�����]1��������H���G�U�h���St�3T����r�*}Tth�}�������[
�o�c;��������Y&�B���}�,�O��.�,�����V�[
_^n9��,�p@FO�������Y�oRh_��Y&��B��/��g�1��z3��7o�6�C���)�L<�����$+_��1v�t~�|������X��#E��%���G��[d�V"�M��r����p�u��p�+���r�����0F=�z����^4�y6���u��2�*����yF�2��y�+��D���!����<&��A�0�������y���'������Ys�"�d�G������=o3�T���wq-oe���m��K�t��3�1�2�S�qY���C�m�Mx7&K:h�������X1Y@�.S��lU�E�H:h�*��6>p��,�x�Tz��V��;K��kLV��YpuA�Eq�eM����+�9}�L�����p�u6e��,���t�{����Jp5�E+�	���I/���&�R����.ZYM��0���_g��v3�5k,�UE��v�����a%��l���j�K�9t,\�v�'����Q ��$A�
����n�:C���8=�.ZYM���'��~�����tF�����v3��x�������x��a��!��y���H:c�^�\?�v.#�^�p��O���\�\?���]G�z�����j��+^{��(Hw���b��Y�Q�9����	�D>r�.���z-���5X7��e��-	����������d3�V`��i01�r�����_H�3�����D
���p�����H.��p��&��Ld�{L�5	����#A!�pc]d��~����z�]�i_���^����'��.�Tn�L��~��<El<N`�u�Q{5����^�Z^�k]n,W����AM����e��#6����Z�����I0���T#b�x3����(�b��Km��~�Q$����1�T�{IH�B*���K���	������T`�n��jwZ�����+h�U!U����{����Cvq����jB��m��B:��3�q���7�T�o���\o��x$!���\oWa�8��
�cEHKHe$M��HG'x4����[	�Kd4�T����SpSA8MH���x�)[NK|��9}��txw��|����u��_Z'�5s���.��t,�o����b �!*�����Kb��tz�I/� ����$���N��M�$����\�v�-�H�����]���5�-���Yp?�v����6��e��v������Il�	���.���t������Mc;�(���Y���v�����Il��Di�z�]���CjMp���il��52kz)N,1���t��.j�@e��)"WWG�KB(G�Y�;V7�����N1PS�F�l��F��r������V���2b���2�Y�M�(� �5��t���Brj�$A$D�^������g�Y-�(� �a�
�G�;��:#�����q�"��&6�j���w%A�cR�k����_���md�rS]��Kw�	���w�0�f�)� �����G� 	���$�]�U�a���#��_ 	*���U�!�������
t�K���d
�����^,�9<�3z�}B#���qg��M.��WHh?��"+���$�n�7U��t����K�)I����x��;os$�0�.�3������H�Pp?r�9r�Q�z�6�s��ww�%���tx���
����?�t5!�w|�_8���tH0�Y���Z%����;;������7���p�Ba�*��gC�T���?��+���J�+3��w<�=���hi��+�ZZ!��t�#�.}8�v��W�]r�
�����6}��t<{C�`�����3��
�����C�Rp5�%�L��tz���=;"� ����Inm7��:��������Q�$�����M������;�[\�v�%7���~�%7��Mc;�d�!���KnH�'���d��Mb;FW�]r�
�x�������e6$7]4)����t��r���(�Q�E�+Bm�h�b4�I��t<QC����/J���N�\J��g���}����5x�f�8G����6D��X���>�W}�z�����*�o6��k��$�~��F�;���t���3`R�K���8r�
���h���=Fcb�	E�E8t������yNC�M(r��N��P2,�Z�t�d���t����~��^hJ�Y��}(�|i�Ks=f����x���x(�Z�Q��n:�N�y��~����#�������_u^��/�������f�R���,_7����9�E������������
8>_�a.N?����|��p�|�Xd�F�1�N{K6���37F���6;5t�;����8�o�]���5z���[T�������oy!]������6�Y���l����3fq[~z�������X�$���mG��CB+�����3���w��Hg�1�01�_>7�`d�T��>�����P����7�F���c�>^LE��=xF#}���#��!�1Y=x�����#�����|\�v�E-]�H��/��4��j|���e�%�]O�Z_w��>�m���.��%�vt��JO��pIlWcl�dy���Mb��t������������7i�5�
�/�D��W)����Z|��t�[y����xz���r%������Pg��Y�?��,�����I�_f�?S�TAp5�%�����23�(]0�!����v-��}�"g��G��dtx/��-*}��tF����7�>���h��q�����`�����)L�+o�]6��Yn�)i����(�K�=����`T�o��/�Q����SjH}:�f����CCz��z�����!���������oi �8{a��Zd�ks�2��3E�vz�a`���<5������s��T��+� �Y�"�oj��pFY�l��Xg])�O��Np})n��"���ca����!�����cD�A�����2?Tj|X|�2R��fO�M�Xx51��2����$���g��hAk�4L������-��9o����*���i�u)n)R���������m�����l������1��]�f�jq������=C��[��:<^��h	��X��	i�K�
���<=,�]��p>"_B{N�G�F�Ah?��$+o���E\�o�I�������h#�Cw1g���N����n����Q,���x[Y�����<����O������a�O�����a���c	}���o�Z�^��
}�y���i���O�>�>�=K�� J���������<z_��}����[�	}�T��+/�St����Z��Y��������:��"��?
<��Zp?�x�Y�x=���\D:�l�]�����l�<���t��fGo��6f1�}����B�|��p5��W�o!�~����w/�]0ey�p?�x������B�T�t<�F������t�{=�|�����}-�b���2���^�_qg��~���
�t���=CdN����=7�d���r�1y�H&b�o<�U��'�L��pz�����H��b���8>+o�Q�-rs�L��"���G��u�U�'��)���uG��4�I7x�K[�$_z`JO����-EC�D2������L$�����Hnb'�������~�|�eX�����r���o�d�S��J��
���G�|T���*�`_�
q=�:�����V��\��G����V�5��������9���}���f�t.�%�6�e�a���3�n�/���vqQ�h�v�..��Z�9���tH7��������F)�F'�o����htb�f��g%�d������yV@V�TJ��)�R����a;���_pw�����qMWg������XyV�!'�G�Y7r���Y�0R��x|�tz���"����}�n�c����5;�E+>
5^G:��B��oD�����Q&^
�A�q���gKd<�=�x�9#~��x|Xe�F��T�C�5����o��x�������*#r^��6J��t|T��G�C��=�Y��e��`h��I�G�	�]��u�d����ovN�}��_6��\��!"�T���f����)�
��w����A��HyV"B�#����8yV�����8&\�<+�Fr��#�,nla�����#K�d���]<�++
'�
�)��>�?9Y�"x�K[���|i����j_z���o��g%�B���?0��~��:%���g��@���
���������Tg��������|�6o����Xd<t�}\����?o/��><!�������������5�������*����Oa���zn^��?�����o������������.�*|#���\�w�{>�'������4_��6������N���	7��L��y�m���������p����y�yQ�	��h����������x;T�������~�����������~��y��������d���>z���S����z��������S�R��������a���.���38�N������@,���^&Z�B�H����s'��������{�j�����q���MR�-�B^�of�I��l�pU�������i<�����T��Y`a��m\�+��,���:��p5wF�|�sLV�9j}���k~��j>�=��]�	�0)���G��zs������TY���\��]�C@]p:��@��~�qs�z(�U��;�&Usue����� o���By���CAX+uhU��I�C���H���P��&t=�	��h�i6&^
��<�Gc��K_L<���W3^���Ig
I=�x�BT^�G��WVo<;����x�=���{�/����m�_lb��Y�V��_��?3!���y��������I�Z5��=N*�p���pQR�����.>�w3Xux-&d5G�� $rW�hq��A���I���/=��F�f�9r�/]4���������������W�������r=|q&#�����+.6~��_����yS��L\��60��g�s��=}����4x/��Z_^����GH���*b//5O�_�B3�Y!��l+kyi�������GO�GO��Z���'1�^����������wQ{Wv=��t��${�"��R�������u�������
�������5�&������1N�t=�^���A�����u0\�7�1�M:�C��8��!�p����c���G�=�������7N�r�t��R����}�!�9 �$�ZY���0�@��*�k|1�P�'��*������
^$�W`�A�.�\�.�J����QO�E�*w[�|{��i���i)�Z�8`��E����^��vp2�#���5++�������_���bk����yR���V�v�b�>�OE?�5��.�K��G�0�+���>"�&��_���
��nv�
�~%#"g)r���	���*+��.f����Op����]�s������q�W[+�������_����a�qW8Z��p��]4w�c�
�+<J(*�
_�����>���XT�]9u�
��_��H�l�B����"��Vx��s�9�����~�
��^~�����^m�4���]��d�`�h�����\m�owJ����B��?���sW8�.�/�Vx�m�����sp0�7n+��������9X������Q�i��7
�t=���3�W���S�qcp7�[-�Y
{~�OA������_����/U�->x}w��|/���hK���!�Z�����l����������h����/^�r�<&x6����-��g��I���������tA7L�������3r�e)��������:�s��l�~����Y''"R�]�>���,��~-�����g�y��x�'�_�)��F���.���"�*=1UP�'���NR���g�%+�h�i�&��;�����B����Q��1D:x������|]��r
�����%/hP��"�Hq)������0k'�%��~�u�xx�u��&	�������J�C��y���J�q����{�!���x��/�64K_�`��`��G�9�4����^�Cy���L�~�2��?�-�b�����fEL�m��R��SXy������!+�����:�I����7��
���+����G.������}�<�_���rr6|l������r.��pl��������z�@,����#�}��<��{82�N������Xq��s>����3��V��]���v�h���AX����pdtyk��JwdT��K��V���{��+�ITzO�l�/�����}��<t}*)���G��&�#��|�u����������
>/�<��U����gN�������Bx�VKV��j���y���=y�T)��l�N���p����/l�S7���Xo�]��������~&���67d�:�<������pp8�y{sY^��i�}`�Y�w�
��E����o����x�>�`qp4��*��xh�����!	�������Q�y�]����x����O4��V����F�G���HW��2$E������t�S7���3��*�J���g���A'�*�.�������h�q�����9��&t���(_&�}W*9�|;��+��m�'��L�����Z�ve`0_I�yt
�Z�-���|������3�RM$l�vf��;�_��d��7����d�_��`{���-O�l8�v�������u������%�����oxX�U�i'��Uk/�����R{�����KB}��`����O��_���/��K��.�������U�{AD�*�H@���.����'���U�����yw��A�#Zp_���{��P�s�
8-\V��\ #�c�C�NU7���6���:��G�S.��g��~���0M�^U�&p�Q��$�)���}w���-o���s.�������#��������}��]��}\����]�7���7�~�rT[�����s�B��Bg�oGu���������pC�eW����{T_�u�Q�7Q����Q-s�K��v�3[�h�E;����\9����G��&�#�	?�paguQ4/]��g�+�T;����m���U����&8��W�~I_�QV-~D���]}����)������>�����w8s��kQS�L���������W�M���������T���?�,�[��\������@����E���a�H������D��U�_����w,r���p�w{k�����'����o^_�F�����"p#���`5�E%���5�{�on�����Y�{I��*~�
�/)�yV�k!2W>�M��-��'�w������M~�����(`�i��������~��w����?����&]^n���e	J���{�?�p�����s^�9w�
9/��%E��'%"R1"R=#�����=A�P���xQ�������2<E�|}���}������}�][3�'�����7k�kK�)��3�-�g�q� ��;����5�������(� l��p�\����������<@�vr��u^�
����F��/���O���~�<��SvdW�ZUQ�,�2/��7�������O�l\K����4�=�jW��f��
�_��=�f�*���y���'.��'�Z��j�E���=�X�p��S+���G��,�
7���]qNl})
t���m����E68��|��^�.�j"��(�����?/O�E~.�Gb@�Ml7J=���O�s�Dc�����r\��]�k:���X�i��a�}\��9/��q4�&����{w[)MK4u��	��������D�My����P����5�d��D��sa�y�cM�7r�+� �L�~�
��("H:B��/��/��A���e��"���O~��'�
,Vo�:^ME�����I���*WH��"�&^pc`f�����L������B�D;.r���x�y?.�g-��9�=.�f��q�=cY(�9�����?�����g���x/N�� �S�;�+�������Vl6]}���������V����o>9���2�3W��(�/���V	�����(�d]`��8"'<9/���Y����5��v��;�[���������|	�Z�������v��� .�Kx��;?�)��e����{s���]�F��w�e/��&��^�6�]Z.�-��F=.��^�l-����K���d/�q�0���jN�}�
+�������~�P�#Y�8�]���5�� u��A<H��y`o������c,iQ-�����9�8��\�����a�'Q���^^\T��3Xk���?b��/��j�(/�B�2�~����]"�3���mE;����*"4��[H��(6~7���:�}/w,��R��y��y�w�b��	i=:���~��V��l:���+t���~�������^8.�������������o�\����{�?���?�s1������������?������|�\N�_)�Uk���7�6�R���r�)J�����?�dL�?���k���{�>�������_�}����[-�����l:����3�sU���`@��&<�����?ct��/����*"����*�u
��Ed�.�7�Z�����?.���7��	S��-��+�wz[����V�l;��mDs�����w�=����)mE�����v�P�qC��0oK�.
x�4y�����.�,��a���G���?�x������j��B���v�'V9����+���;;@k�t��L'�J��T���\��+I�R�����;p:�+��>�����/�}�jk��,{s*c�.?Z�e������"�����det�;y��\5�{�"��}�AT���P~���y�j�����7���Q�=�ow�	�"h��<8������2q��@�\p���9����7~@
�FK����k-9���5^r�4��a�qy������U�e�y�^p��3�.r'�|���*���O���hm}���_�5�qe�o�*Q)u�Z�}u�����-�[X0M�&'��h:��.����x�\��G�����Y�e���H�u�^Q��md��v�w��V��~$����t�w����5�|����������.�|cy?��_�}�_X�{[�wy�=�z}�u=�����B�U�M���Lo
Z�/Y~��mZ[��U������w0��<�}��W������/j�����Ww�8a���vSA��NB�
��g�r�'k�;u[9���U���qW���=�L�+����Z����F�X�����]f�;�b�p���������2����XA�������
(�?y����sx���s�K��P����������U>��NS������UF��.�[j������+W���Z�RN�*
9��k��_X!. ?Y���M��Bf%J\�t5���*nS�������/z�p*�zum�k;X�u��n����9&��!����CTWp��������nV���������������fcu����;.���ym'��Syp\������������^k�R���;�;w�?Ww������5�wuH9�o���n��o�q�G�Np�x���{,H��r��X�rxw[�|��������w��s��=A7���6����=A�)�����F^�sE��g{��n���n��g����fuyGM7�]�]�Y@i7������CW�U��E��r��J��4e|�-amwJ�e�}��&�L��Q>w(�rh�v������+���V�L<l����8���OJ�	W�F6�8�����������(�����Z��p3�\���������]v�+�{l���Q�����N\�r��Q� ?H�j�;fz>��.������~��]�%Wwi����e��]qu�+��<au+�A����Z]������������?�X��~x��]�~Gh_����ry)�}K>�A��aO����\Q4����<��Z���'�<tc������S�l���~���hK�k�w�"����B�����@�L~���������Q4ae��o�����^����xk��z�X�V	��xO���!�$�\��	�����/6~O��[�f]���cf�#����G����UvGL�|���F�B&�@�tSF��f�;c�����%����;Zu[<f:>��G�F]�l�L�-��|AG+�}�<l��>��w�%��+kG���N;.�~��+���6��,����5�:���|�~>U��'���&y���%p{J��\]r�3[�|��`����5W(/��c)��h�#�L���o+�7��
��������MO��U�
s��/�&��7p/K���{������7���2�+��K�|f{���v}/��U��
����=~D��r��#�s��?B}��G@}�U,%�����;��m$��l��
�|]�cJo�4�vQ�u�U$�7B}��Z��vER`;-yM�t�,�����x���vX��h��o]x��D'����N�z���v�o�	t$�C�zfk2���I�����W[x{��?���Q��b�7�����f��F�
��oo��7�<��Y�
��o���7p�>����������f�?�+�#���W�U���\'��+��5.��}��]�Jy3��+���O�;|"C�n��;o���t�zK� x3~��M�����X��`��-��P���nk}�,G^�#_���I��N�E^�#�������6�����}7'�o��#?]�iu4}���c*�#�ol��fe}o�|a����/����M�0�0�ek��{�����7oCm�z�T�����t���������y�A��{�6�����)�H����H�_���y�)%h�V��~�^��	1U�q�����z��6^�2��s��p����	�"��%py��$�Jk�<?���']������_��9��S�y�C���/���S�C:DP���7[�%Y�2ZnM��gg�"]������*��_�����]�����������$�	^.�+��K��Oy�W
����<~��b�r�����/��J��y��(���o?ZY�������b4�NT�� ^k-F8t8��$�����1r����>f�u�f���.H�m�}W�P?����v5���7��B�o��H���o�>��6?�U����2���XB���~�:d����|�G����D?z��oV�����6�m4�G��	;��\�����&z�����<���{��<3Y�}N�m�o[=U3G;�g�9#�.D��<n��0����#��_��#���'�j/��A?�q�����}EN��_��z~��=��n,�����B��3c���V{b�����i�V~���0�"x���E��{h���l��������U�\�%���/�?���������*����r+���gxq�X���i�����j��I(��^�g���\�.}JtEN�5!qw�"/d�o54����L����5��o������q*�@��t7\�=n������B��������u�����7���`�UO������1��[��������Ix��V�������>]�����jY��C���?0n��~5�~��?�������b}I}q]�E)�bM��o�y����q��^mm�L��#���V�6�Z%�j����V���gKa��
���vQF�M��C@�0���J^X��l��H�����v��v���}��bAV�n$�.o������eR`��2���1�e�����������6f\�@����]
���U�;��]�[�|<��[@�.c�d�Wvx�����v����h6���������j��"��uQ(:�C�-75��A�>�,�jc�
3�ze��-O�l��4�m�r�u�z������!�+�kf���V���@6��Q+�������l|`?L��r(M�{�M���Q�
��B��e+�6i7�>h��5�WL|b=�M�}�6�7}�������j�tw������U���bbG������Nr�]���
r5e�m �V�yP��p��znM�M���_5�!7S�u+`N`B����x�8�+�n!�w�\�����z���4_OD��!7���U}B���>�~SED��gnL��i����!37Z�~����!]�fr��%��f�_�x����h?�*c<un(���_L���z�����+*J������7��;�� 6�6���W���N[�
��f��,�Qm��j�&n&�P����#<��+�p�!j��8!�!����)
��Z�n�qW �}�h}���4<�c`��f�0`����F\M��'�"E��\&��``��m���t�*���<2#��K>S�����z����.>��3��p�d=�gl��;��K�3 �j��_�����]u�!�]z�������2���pA(Uh}&�HB
�sz���G������{s���S�-��\����g��iw�7��w�@��>���1-�F�0�7���s<�{c�e�+&|�h�*�����i��#	[�����E>��/��-x�;2f-��4����y�p�o������@k�����1/h����;�!s���Yp;Au�9�Z��[�D�dt%u�8�&%Y�N���<�%9�C�5����A���j|�����wq��������Xp���8�)K������a���..Wwqq�W2�������E�,Xq����81I2Vp�Z���/���[�Z���}��.��{��/�����o�3}���h�6��,������m��I(�Z�W�Z�'��
O�fU�U���p��@+���]��O��y%�L�����F��	��,��H������g���%�J��8�������$�lF���'���sM\V>?�n����1E���(���WP���\�f2Q.�b�n��*L�U_��S!&<�9�0v0a����>n�	�Va5���j��<�;qY��\���.���k����^���y'$���h��0���n�z}���\��}[��Y���Y���y'���]�[xi�q����j��<�=� �d�]zen��q���7�y�#wq����7quw����>/_���{�3��@�n��[�_���U�\���{co����Z�O��n��D���xr	��F���]�\h��
x�S�xV�b���`\v
��b�]��A-��
��{G����=��Z�����j
[��{��-x�G���4�[���A7��V���D��
������X��s#w����8$E���5��6�`�.��xc�������Q���������}�78������7q�����v���u�e��M������{�?��+�/��_��������o�����\���7�7�Q���`Bo���L�D�9Mh��Q`��0���&�)��j�i����� a�U8d���j���Dg��p��5?�0 MwL8�A�M
p�	Gn�AoT$��k��y\����]5r#��FPa���7����Ot���y�6r@�.�	�����|�OW��&�6r@�.�F����w���U�HF}6Ksp��Zr|��q�[��D.��K���.�gOdr/���D���
Z����t�$a�!�*��	OtM���V�d#>h�,�;Zp54S�������A+<|
�Hv�^���>��(��A+<�9S�����[�D��Fy�
Z�`��L�Q^w��-x�[R=,h���4!�lA$�����^I]V��^�s�MRv�`���oNtJ�
�`��V%,X�vbmN�I�
�`�V��d�"[p�W{�6':%u]��z3�<;���B����j3��L����)�����Y��`��N�X�L��A�P�5[���6�W#���>	�������lA�jo��=�'�-h����� s���[�L�������g�$L�
�o�3}�������jA�����>�P�����,^7�0�����L���-��,xl�WS�U�K��3}J����K���g{��)�����g�$w��0c��a�����]|�O21
<Y��h���X��-x�O2s{�3}���x^��g�$������I����Rwg�$��F[��}���X��-x�O�d�7^F����6r����%��O�I4��Ak<v�����f�3uw�O��3�
Z���>I�\l����;�'i�����}�`<�$����
�o�}���hAcdb�p&���\��'�$M�(p�ed���d.Vp}���4%�����}���^]�\���<�'i*��/#������e�������)]����}���iA=W��'j����!]�����D�����jm
��nxJ����<;�)i��j��W�6
��f5Y�ggz%mNHK|�����v�,'��tKZn����qG?�;n�V��g�%7rgm����7r�l�3�����F>8���H���	��L�RC�5�o��^3�������f�=V,��Vd[
Oo��e@���jH���djV��h��#�j/){�u!�6 �������M���������O4 ������=���������d^V��������m��3
�c�(�
���*f�l�^#�+F����Q"{�������]!��l1���F���l1�����4�LDk���Q�����z}l�+B��9�3�Q{���^Y��[�D_�u
�L��Wat8������H�&2���#��,X��%��O�F��Gua��B��|��Z��[�Dw�-���!�O��%wq���O�GZ�h��k�Z��i�g��':$-g��������#r��9��I[���1\#�H;�k����^��.I
}�@k<8K�6-���"?�'i��h��G�$
T�������I�������)Q-���nWU��L���.n�!�G�$wq�>��L���]�VG�$�� ����I8$���/<Z��I�����w�O�!9�1$'i�����m�'��3}��g�W��h��s$������vg�$#���xQWk���q�q5D���IF����������q�/vg�$��������$c��j������<�'#F]����n�����L�d�Y=���h�da�z^�Qg�$��h��G�$c�^��X�D���xV/F��9x
vD[��[�D���&2����5��Pm	�o�}�.�Y-��~�t94��[�D��s�����=�'�t[��[�D��s#
���k��pKp}���t���Pn5������[�D��+yVF)��k�DM���<�'�J���Q�t�+�4	���>�'�*���Q������Yp}���t�0�����<�E��n���<�'�yV[���/�}����>I���1���	\��g�$��,��b��>:���X�L���Y��>���[]��L��[�L���.n���]�s0��G�qw���L���]����YxIvq���_����Iz���q��,������]|�O2�E=wq}�f�xJ�����IF���xQ��]T�����.���IF������i�:�&�����M\���L��������K0������&>�%����M�}
�]�3_Z�jl�:�#ai�@���,�!���n���:�!����*-�G� �������I����5}7@��9|�_�[����,.�����[����zqqu�C���so�������w������I�
2Z��x
+�����|����"j��3�"��,
ZpUD]����J!Z{Oo#[��t�Z
Q����eI��u�!�a,yJ��M��I_",��X��-X���j[��D��g�g�V�`�1��D�Z��z�}���X�V,x��Qv�{����r���Y���x��$�M� Q�{��o��L��h�.>��mF�F�3}��A�Vvq@�.�.f"Vp}���t9-�G��o&b���w�O�!<�{�����Z��X��-x�O�3~��cw��5aXh���Qx}������=�6o1+���tJT��^>�Qwt�yL��$��N��m<�$/�@r����L�d�.�]2d(�.f*Vp}����~���gZ���������N���0���}�`@����ck^��l�tJ�������B�c�m���7��>��\����a	H���
2����}�!C��V���}>��
�o�]�!/���X�n=8�lWh}���929�W��/Ku:G�������q;=�V����[��'�#CQ���v��K&�	[�l�,��OtGfc�����_2q��������OtGfcZ���E��xg
^V,x�;20+�JP!`4ST��P�����b�����X�����U��yJ{yX�����PC3#���k����f�;�iJZ�h0,�vphxJ7����L���.n�&��������Y����IM�@k��m[�-����[�L���.n�V�.��$������]|�O�A�&���>��Yp}������^��G}�����<�'*Z���G���Z5Qb�3}���x�������akp�.�w��>���@+�OGM#�Z��~�;�'���G]���q���]<���<;�)�!pj�1>z�|l��6�Lx�W2s�|s=��h��0s���8��tK��&46����a�skY����~��AV!����A&3hXw��':&c6���2� �2s���
OtM��(��lx��2�P���
OtNF��hV2� �
k�]������B=gB���a�g��>�������7C�2c����B�-qm���*^^����}/��,yhF�����,�@	�g�}�����]��a.��Vd"
"�~�
X���Jy
�-I�k�
ok��[V�h��gue���R�5`
Yp���3
�c�6�v;e��p���h@������G����F��W�g��tcD�&��5`�`�����
���0��p�!�4�g��}a���c�x4���pa�c�x\��g�!i#g���k�����w�����u���^\�����;�xD��v�h'n��R`}�%pB�������
F���]��?����]����r�?������_���������������/����^�����������������+���%����*�r�������������Y������GTH~���N��&6,he�|eL�B���@x��6�_�@�0����cb���kTp��p���`��g�^}a���F�.gZ���,��e�a�rZp��L~��6M����unQ��L��i��;�s�fG��(B���]�3���o�}����ZkGq�bz���i}��;�{���'k�xv��1-��\��'�osV��zlH�H�l��!#��OL#��BF��f�&�k�1��-x�G2����f�m�$��\��'�$�+�hU�m���Z��
����>�������`_
b\�w���;������j�w��7I�����<�'�K���U�~�MR�'�����}���Y] �I*xL��[�D�df��N��$s���u+�����Y ����Z��.�����Ij������vh!�����]\���Py"�cA����D,x�O����������`��V��g�$�-��-vw���!�b�3}��"��vq@)q�t�@���V�E��NI�m������s�m��o�3���������[p�c�_
o�g:%lZ ���	���������@,x�S2r�e0"�G��qu�g:%#/�����y�������z�g:%/����#�������xZ���3������8�.J�3O�yU�_���,(�hm�ru^xJ/�7��N�y�@kkp���8y^xJ/�Es':%�f��Q��d�PQ�x�
��'�$����������)���,lV ��C���.^�.�^>�'Y��@�5n�$q-���Z�b�}���
:}�5�����kO <�'Y��@����{0��z)�X��b�}���..���<�W�f����\��'�$K���4vqD����wq�zW'�$K�������
���Z��OtI�h�<��5������H������k���Z��g:$
/b���C
��cH��Z��g�#-���������-�P �~�3���[��T�`��oa�(Z��gz#��������B
a[�=
��7���H�-��*8��lk/����EX��x��xp3��]��dWx�+�����m���#^v$��|H{%�b�3=��[�km�`��S���-<�o�3=�����o��hWn�-<���gz"o�I����]�����~'�D�����_����@���(��-?�SD#9[�,�Y��<o�����A���(���+��Y=}���
���\;0��z:`�H�m|a��u=%��<o�����z!S�����Z|�i��9�� �d�f�l@4~���<��0�`��?�=�����Z�������sz�����|�k�u����y��������(���]�zYm�����\�y7����]�Zh}���./�������]�Zh}��� �d4��=�bNC,��-��	OtF��[Z��>[�a�����!-����Wd4����������i��-x�;�
n��xMg.qT�����.nO�G\���4vq�d5�y��wq{�C���4���"���`�S�Z-ajO�H\���(a������)]�"�'�$��.�z?�&ZM��kn�z}���4������o��l��=��L��Fn��>6�T��������L�j�tz����/���#��IW��F���`/t<���Sw�G�qwFb}�`�p=wq�>4�L���a����G�fz����	�gz$w����1�������|��.��<b�3=�1���wv�w����O�qU��������^��}��M�m<�o�3]���x4*�B��c�]�����}|�S2sO�mR���37�����tK�&���|�|��{�pU|������Z"�!��~T7��[%E=B��D����]]z��wu�����Q���;��<�KO����.�c^�YXR�SzG����D��.=y��r��M/t���wT���4!��l��"�0l.�����O�N�q.�VLp#�]��\��b���*�F^�@�����h���	OtO�/��������
+�{w��'�'U��\y:�5z��������b�������7r@�3�	���G�������f�]Vtq���S�����V��Gp����U�����'�y0`�+9�>)��\����4q
Xro��#�����\oc{���K}�4`�
�����-��=��/�J���"����q�z�{��5`�-\�Wq�*[�5�p�����e"�/�Z��c�"���/�z]r�n��xO��p���fu�����_[�~�c��I�8>���|S�/�������o���ST7��X��LG�zn���e�qW`�'�z���LG��6z�D�]�=�p����tD��:��V��'���0��tDn��H�#[�{xX��gz"#��`?�!�Zp�&�7�����{x4t������H��L_d�S��r���^�����0W\#]f���U�WJ��Lw����H�|���bO�s+X;����b���[3��z�������r�V,�(���k�t���<�#��C����.�[0�6Op}��������=X���`�2Zp\���>I�j0:�8}��8����
�o�}���.v��>X0��:��wq���O�I�b ����_�%���[�D��.q��X�wq�~������R����}�#]n��O�I�����0"������]\����5wq������-�]\����L���.��]|����.nVwqq�O�p7�.>��-wq�����IZ��[cG�I-�u���.��I��|�Es�������7��.I7����;���{�KWZ��gz$=Z�
��EqW`��G��b�3����}�J��]�Cl�|�i@��h��B��Qapt��j��LodD�X�����m�U�h�-��h�Lg������F�\��A�������gz#���F?�<$�w�M��B�<��!���Y�3�G��7����R��Fe���pA�]x}���,H���Q�`��4�j��<�!i���� �������K���'0�������p���\��'z$�C�H����a����<�%i7�W��`��+9�
�o�������+�}�`��
ak��$����R�x�W�0+��#�V[�,�m�4�X�D��)n���4[��B�6-�N�I�������u��b�
�o�]�����+�=����m�4������]���>X0 ������4�X�L���X�^�`{������K����I��h�����[�b/
+<�'i��[}����[��v}���t��[c~�t������L���.����=�E�s������Iz��{c������W_���>��]��/���G��]<����L��m�ZynG�#[�m�������>	��7F[���vy
{<7�]��3}v�o�����X���Y��_���L<�����NITp3#�$����If���Q�}��Z��	\��.����fd�X������o/����������?�������?��/�[��������������)������������u<�\9�O��
FYO���t�e����i���K7a�����v��L~���Nt��� �>�8`�}T���!3Z��'zp-��~Y��G�.-�>n�D��E���C-�nbO}"<���(B�����.����'b�=�.��HM��2���������\�ct�s0hw9v���<���\I�8���kA�]��w��\G�@+���� ��w����=��*����]�<�=��M8q���������,X"#��OtI�
�T�N�Y���.��O�I�
9�����Zh���H{�O���@�]L�I���=�'iPh����I������>I�JS���-��^�=�'iQj*��r��*�Z4{\��g�$�������J�����Ap}���t�6���,�9-�:��x�D��@+���s��t���3}������=������]|�O2�d�wq�
�0�|k
�M=�3}��w��7��)O�IF����]����L���~:��7��]<����L�d�.��]2�9�kf�.�Vwqw�O2�.��]�$/�y��wqw�O�8ZP��]H�0�j��������;�)aJV�5�8���j�>c�����	O�J�q~��Va�Q����o����Mz/)��
�7��jA6���t'�%=��FSWm���dS�~�)@w�[��C{o4p^.��j��;�-�����y����`P��/�\��yv�_��x�
����~F��������	OtL�W��Lxp�����w��'z&}��k�5i4��M/{�g�������	�C�<9�	kw��'�&}�h�P�7aP��or�p5��gg�&
BB����~�D6!O�f5��gg�&-7���}l��:���g�v�]����I����jO3h2��l�.��t����������XD�b�
�������7#�����}����Z�Q�4Cw�����z����l@t������x�I���]p��y'p�����?��������.�~��-8������#N43 ���_ew�!������K0 �w	�[{���KZ�Drnv�ul\�G���������j�k���~cl�	� [��k=����^��S�������L2���?���#4l�.��OtH����~��������V������D�d���������q�E8pp��>8;?�%88{0gWG��
�=���O�I�h�`���������[�D�d(r2��:�=����
�o�����6�����h�S��Wr���D�d(hEL�]T�)�N�B��D�d����~�i���%XqW�[�D�d���+}��G��`�M\�nbw�K2���k�&>���P�&�Wobw�K���@+<��xh���t�M$z���h��G�����R���wgz$-�8�X0�c0l
�<�����;�#�-�����7I��xJw��~w�G�!�#��#�$a�-���wg:$=29�X������Bp}���-������ 5PS�o�3}���No����X�������>��|�@+<��yJ�����L���X�N��Y���������>�4���j0� jY�0��5��f�3}���x�U3.`�A�����]<���>IQg_/��'��������������f�W�����B���?$������FV����V�����n�z�M;N��^��,���qF(F�_/"����v��^��'zq#k���
�`���!��+�������h��j���pALu�����'�qS�����,�	Z�d��*��Mx�#7e#���Elf�Yx}���M9nl��L�G6!nd����I\���06���e1�����N(�-?�S�e�nP�}+�����
��n0D�Q�\�3u���n�<��[����n0�����v.��[����{�z�<X0�iu
.���xG�X�D�d�y�x=],����s���;�o]�N���iAc<���A����<�7Y
�b��CZ���`�]\���]���..�]�J4�����]|�g����@+pL�Z��]��r���,�!���U��p���>a�:1��p��bL��:�G�������D�d����
�kn�zuWg:$
/����7�Y����=\���4���~����n�f}����|L7�H�5`��t������F:��Z1��K0j���������3��!j�V����{��j��:���ih��wn\z����7���'k�b������`��LOd�(T��6[j�<�Cf�i���y��)�e�v_��Q����)�+�y��������sH����o����r������6���<�#� 
d4���>]\��wR���'Zp��80��h�m�.�{|�a�I]���������:0$'��
�w\u������@F�-��?��������y%e>������O�P���/t=������sK�|�.���=<
��L��:1�����q����<��������`�x�)�V���x^���sK.�5�5;q.<��U�Vs^��tYAFCI}�
t���t��
x�?���
���\f�!u�����8�����;0�p�11��\X&0_��iN�F�+�hu���F�Z����n���9�q�{��Ut��C0��!�����n}���\<4���p�[��p���O�E\�=\�{��w
����[�\��'�"��a�����)��+�*h��j��DW�U���^�~�
�����-|�+���4���+�na�z�w|{�+Rs�z���Q\6����n�tEn����G�n�fu�g�"-o�����|�0�����[�=�i��n�[8@j�����C�����o��,��&�*�^�f���8��f�E���BMQ(R����kY�+������Y�*��Y��6�����2D"uWW?�<��{�n���R�Ez�B�i��X��p�+M�R����z����g�#x��R(����L?�z��*?(��.��j��@��_�����7��/�>�IbL'3�{�pDD���0x�Qwr��,
�qnh�������Ku�	'��Q��qd��,�x<�S�_��3�����h�M8� ���<^��3��dK;�3�_taW/<��r���.��	�%z����/�;���2�Noh��z��1]#�8�Y�F�z�z���)�z�1��^u������<����['����o�C�<.��5���8��u�$���|���[|`D���_�|���d�����'�2J�@Pbj�S�nhC^�4�>i��_w��S���a���DxaD���D@�
�:��MU���A�eqa@���DP�ImLS-�7�;������a���N��9+��<�A��_��+M�d����AnJ\G{������i���	�j����q}������iya7�s�\���(��^�4-�q�n��������M�����1����;,n:��.q���Jz��N9�v<v�{������~�����x���#�?`� ��A��q�A����Cck?���79����E�1.�KQs"c|`��hj��>u|	�9_���<�/��;j�c'x�	�'��+ck��'xJ��#+�l���Gx��s���g�I9���p���G��#cl@�Y9�&u���G8>P���jk��GX�'sdP��y���>'��p�i@��:�=�+C�5��Z��W�-H�zM7���m�	n���B}e$���W@�-�?V����w�][^��<�[z���d��y���)�2�y���)>2+���O�?��#m�S,��G��X���0i��TN�w<��p�nh�����1�{sh���	+�K�74��!I[�W�6��0�I������������1}���0*9f����
MxaX�r^��N��0.9��4x��`T����%m���(e�w`�6<�M� W&m��Q���;����En�/ruad��|�[�E.�C�����F_��������2�alr��<���1���	'��	
��c&��"C��W'�] �S&4�N�='_�`l�����d�A�BL����	y���A�2:�"�Av�NF��c�E�2:�"�����L|����|et2� O����5i'�)z��+���/��d����	g��s�E���Nf����"��6~N��s�E���N�Ey�TT[��y��+���/����=:Y�"����2:Y�"���\�G'_�5�"�WF'L!��	�s'�!��r}et�r�����=w�$rO"�WF'L"�J�������U�"�F'���1
��	������oh����l�����	�����U-x��������1=���,N?�v�j�������x��� ����;����	/�N��9�z��������������a�Z;���u����74���I�� ���M�-�w
r?�F']����A��;����	/�N��r�`���	��>l�C[�:���	/�N���`���	L�6�
;^��]��]h���	y_��|>4��H����D�������t�~��j�����[:}2t�1�L@'��#����Ct�Y{eX2��@�����8���#�^�L�I(����a�N-8Eg�W�$��W�O�
��'�)~��H�y\@g7��/���������p���;m������.�w��2���N�;�m@������P���;m���<�Q���u��oo�D�u�����l{���V�v\;�����W�"\;�ik����� ��w���W�"�;�i{���z��)���.�x��0���T��v��!��,�Z��h�/0aC@?��3=�}Y���q�t�K�U���L��8B�Z��x�gW��~>Ab{�+LA��~��x�+-���|~���������tF$}�2G�p��Z���������$�#���i���!�Q�9�Y���0"���`���a�/�c�mh���E9EL>�~���,h�Yz�#}�#�b�c_ �>���W�#J)�`���G��_`O/��V��WF#=�p��B���@�{���F�|��>����e�r�s_>�_�p�x�,�����/��������PdD-T�}�3��2#�/p��5�Jxe$2��t��������64�������>��|�F��d���

xe$2����V��~�l�����D��L������]Ap�2Yx����;��c_ '>���WF"+j��`���k��_ �umh�+#��G8���b�c_ �umh�+#�
��}��{g@o=p���E�F�+#��GxO��H+�~�;��?�F"C�~��G�@���8(s�����Hd(bL��H��~�C�A��Hd(Q"#�����}�UAF+d��H��_��0�h������?�����@>��/?��/?���?��ORr�������������������O?��_������Q�����@U�_-���i��X����7��}|������n���O���md���N�Ygud��o�/��F���J����Ua�	���w��o#;�G���}�A���o���c���0z��?*���c��d����/�F���J���15���?�������m����oi�c� ���x��xa7��T��D��� ���x��xa7�<�J������x���)�0�;����C8�o������E,xa6i�y�;z\�Vt�=Oq?�W�$=���!��78�����;����d�1��;,Mx�#x���1.�+����	�sl�S�
Gz[#���	�KF��N�7��cN<�c� _�L<�S� ��A� O��|e`2�AJP�L�����D�FLxed2���P�Lh��3�B�z���eqeh���^���`�"j���K4<.�+c��yI�����|��+����w?���ov<e����|�We0�/�Y�"x�/��[ck�
��1(G����r-k����s��y5��[Z0=������N�k�O����|��
}�C�
�z���������ho�)���,X�� ;[$����\�-�S4��Z]�S��[*�/� ���9eAC���+� NAbV��+-�U0',x�����uEF;��������
����&{�Hdr�	��&TZ�{3�c�'����/�I�.����3��Clk@.���/I��l��3��3ll@���64�����4`Z$4���#������G���N��r\�!�pb^V��&�2&�'bLO��,|��{��}TX(��I��L+��}��� ��7���1��c$g�|��,8���S|eL2���)~�������x���+c���x�9��,����
%�+C��LS�������j�S<�����L��1�<c������G��m\<#�#xC^�,M���]��j������^�=���q��s��{M��c&\y���A�2.Yy�W� ����|��
Mxe\�� I�L��	����	�Lv�v�����Wx`C��AfFV��&�22�gb��uo��%MM8��h�quah2sF��NT!8���q��������d���YpD��� ���)����\���~���������&s���7>���9�+���74����\�W�>�_�Q�
k��:~�/M����V���%�M��\������� ��A>�m�� 7<�M� _��-r��N��	[�6~�/M�~��N����q���4a���/M��~u������.<�r���
Mxeh��4��d�@%��W�M��74���I��l��7��]�e��7,��28P�<;��Mhx4!}�!����2:K�0���:�W�� ����������d\�1����g���B����	��N&�1��������&�U=q������d�hB���&<���p�U=G{L�+��M&:aBK���]�����M&�����&�0���H�_���z�.�l��N��&L/���6�
W^�kt�dset�� �������R�_����������v1�2��k��]L��-�WF'{M*K'�2>�;��=�/�^��+1*;��F��
��&�������d) ��	����@���
Mxat�0O+�&�
��Cm�K�v�%H��	/�N�s�q����i�ca�:����$�08Y*�I:�z��K����^{ap��M�N�UG�AlMXC���	3'�?}�k��C��@���Qv�����������K������W��zp��T������Z+�kb�O�����.������Z!��_~vtk?P@�O��`�2�`]��q7��xn�Xw����X���"k��}
�������QY@~`��i��� ���/��V�u�)�������N��.�����M���l�6� Oq?��rk�S�j��q8l{�;��.~�/�����SN��,��{��.~�/�V�u�)>��-H_+�~s.� ���D��d�� �u�5t^�fZt����M�����	�s|�+�����~�,����Voh�+����	�I>G��m�iU��S	��KfH����t[r���
Mxe`��k0��dY�i����k|z@ed����4GX�m,�,���hsDeh��:eBC���W��k|z@el���6=��~O�������������Vmz����&���5>=��2:���U�p`���A���5>=��2:���U�p`A��W�%�E�#����@��N}����A��K��&�0:���&T&~�?'[	�P�&.�N�j��~��dc�V��&�0:�*��[�����4!�B�����d���-��^��09��wnF'wno����; v���K��������dc���,�.�4G�z�4��	/�N6v���	�]�&l�nAs�����dc���N��P�9�n��-h�^�ld�p
��n�	�2�pet�}�2�wA������oS�.4!;�t�����1<�As�m���&��Q;��s��74������$j�u?'��
���WF'����D���.���9�-h�^��C�'��m�B�h��9_Lxet��-H���~��
�����|1���	;�� Q{����}���BNx���|1����BY8�~?����f[K��������d�,�)w&����V�`��	��N6��kzC���s�7�����WF'�J����#}j�s�����#����dgoOg�,Mx�#�yS��^Y\������X�ik���9�^��\�-�&<p�����������0:��{{WvoX�imB�=�z�,.�Nv.��������8[r����]F';�o����#!��]���{|�vY\��L�����#!��W�.�=�E[F';���F{�g���
o� E�w?���ov<e������
��
��cVlyYYZQ�.4 3��9a@w���U�h�������
��\�����ES{��j���N�,�����������hE�9����=q�.������<�}��sgl��6Z���
�����l���m���c�+]������Z������������S^'�`��d�~��]~�����'SU���w�����h��m�������y�����~����������/��_��������O?|1�!������@K��������������n�/0�J�L��
�����V7���?������l�+��i|e��|������LJ��-���n�"���w?�����_����?���J�LB����\~��=�Qv��FG����Zx�}�����FmiM��I��i���\��}���������3y�������6$���W�)��Ll�&�#�f��@��@�[/Y3������~{�>�����%�pP��YH�7�q�%K�����f`S��}����s��
�S�R&f1��9n��|���6-��SH�'y�E��
�Sa\&f���J�4�<��;���<y��b�w]]Gm���QC�/�3�VJ��B�p}�j5�V�����V���)1�D������3=�P^nhO_)y���rCI^G����(-e:r�s%O+�Mi�^�T���Ep7�!�9d���.5 ����m9����%�T��<�.����&��29�- ��0��8����@�9t��!wkn�6���)Rm�3����<�������[�V����[���|�u�TY�p���b�J����sj�����������"hCr����j"D�g1������7����<��5��+����q�`N��L�:xrQSwC{�Z�Cno�
�n��#�]	Q�#��N������������
��N�*�����v��1r{D�������� �h���N�*G�AYk��P��pC{�Z�C�Ho%>���N�*����
�'wB�@���V��;�[��Y��:��\�6��a��.�6e���BU.t��h���N�*W�E+{u��7F�6O�������s��S��} Dme����m�J���BU���^�����J��9a?���
]�7����<��+�E���:���$��s.������������qn,w����\�'�aN���z�j�V�bRg��j�����u
UEH0'�����C�["��k%��Dp�8�:���$��N��t-���U�t�Z�C�@o�g>���:rG��U�bwd>N��;"�����<���V�h�[_�PU����=���mT�t�Z�C�LW~����u
UEH0��)��Z^m"��k%�+��%Z W_�PU�?x�|v�Q���1���V����[�g<�H\�L!Hp'lh�R;�u��C���R�<A�Z?�)�u����8�Tu����=}�����	.�����l�-��r�|�UT5�\����T�p[��qJ\���}j��|�Lwr�p�VZ��K%�-�A�ZW�-��q���}��mmT���T�p�-�}JZ���_�0���'
f�v@�!hO_*y�����:sm�y4�t� =�0��<"���/�<�N�T�h����l���~z��0��<U�3�tC�r���v��2G;�O����.3�����~�^f,��8�R���J'~������%w��X�I���~��gl��[�U����U��I�s�����!����~�)x8�t��r�d!�)��	�{sM�m����������ohO_+y�����{sm����K���\?����5��s�Z�Cn�W����kKn���:�O5-�\A{�Z�Cn� W����kK. ������N5��&�]+y����7�]'O5T�s�\���f@q\(@���<��V�hq���\[r���>K�\?���s��k%���1�^'P5��s�~�U33�4�C�Jrg��s<��N�j(	���������F �V����[Y�M`�)T�6�2��~��ml�&0�Z�C�Noe�7�]�P���y�����B��6�`���k%�m1\t����\[r����9a?�Tm�h�U�P*�Jr+x+����\[r�����z�K��3�:]�\+y��w��V�����%�-Q�Y���E�!hO_+y�mG��&�������p���Ag�P��;D����������}�7����q�9A�sU; �����<��V�hq���\[r���>K��P��
A{�Z�C�DW~�&�����;�pL��Ag�P��gF��m�Y�jz+s���:��]Q'��s��jWF����Y�jWz+k�>�\o�-��L�i��sV������N(�Jrw��[4qp�7���.��t��s���
������������'h_���%�*1�v�5T]��!hO_+y��F���x�7�6%�B��N��Y��j��] �Z����u���:�@N�����kQ#�:���%�-B]A�Zo�-��J��H�w���zD�����������}�7��[�@9���D�
t�@:t���v,.����m��$���)T��	r] �T�p;�S��r��e[n����J�\B��6fe���@�-�T�h�{JY����@N��Y��V��t�R���J'~�����m��$��sn��v��t�R���NOe�V����M������J�\?�3��K%�}Y\�8�\o�-����9a?����B�!hO�*y�����{sm��BT;e��2���.*hO_+y�m���{sm�e��`N���~�o�4��5�Z�Cn�\|��u�T�>5����\?��X��+j��������}�7��\��	����T? ���5�Z�C�X\���:u�g��`N���N�2����\+y����O������~^	1�2���~a�1�S�����������N����&��s���W�z�CM�V�����_�]��	T���8����s�T�C����<���V�hq���\Sr�@��>���P
%\�!�]+Y�J������\[r)	�������
q��@�[��s�������pTJ���P

�\A{���C.���{sm�mgBT�e����E�J���V���������\[r)
����zj��������\��/����;l��%G�T�����=}��!w�q��LY=��kK.E �� �L�:xr'���@:t��!��������.�;<(s�G��a�<A{�Z�C�BW~�<�'zsm��$��s��VF�t�Z�C�Foe��V�N�v��[�g�K��}�=�+�Jrw����������S�	�9+Tc����t�)�Jr����}�7��\��	�������j�Q�NS��<����W�^�P��Q�	��)T����A�1*�i��������}�7��\6�	����k�������)�Jr;x+���7�1%��j�;n�RA����9F�KM�[�0��e��5���;D��[����jQ$pO�-y�����r��e[r��&�S�:R�B�Q�S���<��PH�k����.Hp����+���@�������N�"wJa�ew]�0����s)���NN���Y���A#�������3����o����j��t��o�,�N���Y��]���N%������0���?/p��,y�-��	���tm��"LW=���V5�p����%�5�4�k����6�������]V,	��7Kv�<LA�������oM0��\P5�fiRZ���%��SP��D��-��\�	��%US�<��4�iwKz������s�����wM0��uV�&�-MJ��?�#���d���][z'��Q�]J���C��+����#�3���h���][z)		������ �6����#�kAt��������`N�Y��6$��@:v���w�_����^'YM�s������#�6����%�s�]|��u��\"2�):kVs	�^���[��[B��/����[m�����h5�L���%�5���b��-��@���b�x���6�{�n�Co[]|��u����|�����Z�B�{�n�Co�E����kKo����T���< � p��-y�������^[z����rn�G��������~�_�z�j5O;!*�Ke�Z;�3R
�������~�M)�����w	Qq^*g�j^z,��9v���w���0�x�������cU���Y��7��RE��-y����l�U���V�����T���R�|�JJA�[�����������.�@�J�[97.%�^��.�V%�����T����`N�N�:�\j��K�{:��������^[z�����Y�ZZ�{���#�-�J��bO�-�]O�JdY9�Vu!�{�n�Co��r	$�'�zm�
BT"��Y�ZL�����<�#�E'������w�Q�,k�Z�����=���w���������)�3���D���ru���6$p��/y(�������^[v����v��������������B������n*�K�<�j�2$p��,y�� �%�������<�4���g��y-{��7Kv����}�����r&B�y��k�����=��a�B)��}����]��	����K���t�����,y��7��V��R�m�mv"��g�jm� #p��,y�m����z{m��x:Z�oq���1��=��a�G>A����k���t�@N��qV����{�f���@�e��j=�7��;.��8.�s��:A.��rx':-St����^[zgF���4�uV��2:��.�w��2�;������ D�ui���ue���'�i�AzW�-kt���^[z��&�S�:�Y����M�[����o��+[�������8/�s��V�|��wKz�b#�x��u��V���D���b�U�z���%����������!*et��d�������%�MIt�2�s�����x?s������"�����<��3�����D����h���Y��z��������~��}������#D�yi�T��������%�\�'p_����w�	Qik���6V2	��wKz'�-A������#!*�K��Zm3�����%���9�>v�j��<��������2�X�?�n�C�J�e���]�Zm���8/��j��=6e��r���w���G�����5�w/zBT�����j/�� p��-Y���-���^[z����uV��
�������^.��/����[O���Zg�jg)��=����+�������^[z[��ve1_�:�V;k������D�:�'z{m��x>Z�=��[x��w�Q�-p�?y�����{{m�BTR
�s��> �����<��%�ES
�z{m�������V�����=���w�_?ES
�z{m��BT&�u�����TH���[��� � p_����w�QI)t������_�����u':��O��v��<#�R���s�v���RN�<y(�����z{-����������o�UW�������Gv?��@W������:"��g_���t�v=��V`>g|op_���e���PI�v��UW45���f��,y������z{m�mG"T"��W��@�]����FW`��
�k�����<�������]t���Un�<�b��
�k����+*~K��Yu�X���������>��GwJp�ew��P�[z�B�t3�MJ�����}�����ew�������S�����s,�<�����2����'z{m�]gBTF�����:���R��<y�����L9��kK�����z�}��>������������}��hAO����[;!*���Y�*���7����,���te�}�:��D��
s���S�?���/�2!wz����[�������V����S�?���/�2!���C/V������kK/5�2�wo@g���J�4�cOGz������^[z)
����{:KVe�������/�X}w��bo�-�T��`���3�� �#��2P��}|y����{{m��&BT��Y�*'$����/�X}w��bo�-�B�2�wo@3����]�m��?�<�.������T�r�Q��3�� �C�U����/�]�-^�|�jU�t�6��|g���k�+����e��*���Q��\o�)�u�Js>�v~�C�[����/�q~��bo�-��B��h?8�VU]]�D������z��}������#DE��T�����_/p�|y�����{{m��
BTD��L�:Ho�]�E���8U�^����kKo?�RF7�u��{H������^�9��}������y��:�+��~��=����w��2���\�ZU��6�|����)�{���C/�������kK���C�u>��Z;�*����/�+��%���:����R��Y��s�U�!� p��^�9��}�������C�u>�v~�c��+���������^/p_��5��.����k��~��=�������~�����)��N�J���X�����0�5���k����6#*�t�s`� �&p�{y�m+��V��R�m���T�)�9�Vu�^�������!� p_���e�_�P�)�����=t��;�V�@�e��Ni�������JA���)�{�����H�e��NI����<����p�����=���aw��2G���R�m�]&"L�-U��Y�
���o/�+}�%:,���l���|�@N��Y��7�[zV����aw�G�Eg����m�e��@N���;�)�*�m��������'p_��5��)GBL�U��X5%���=�������.�>v�Z��x=s���uVM��W������[/Do�N�j(	��������&��}|y�m�
�{{m�e��`N��;���6Js��������.���������`N�Y�j�M 	����;�D
z�����KMH0'X�)V/���&���}|y���������$�fF�+�S�:w63C�Y	{��/�3��9���������`N�Y�jV��*t���C�J�~�����������`N�Y�j6��,t���C�N�~c��Do�)�-;�s����U[���U����/�m�E����kK/;�s����U["�h��6���C/V������kK/;��`����U��F��*�m�����z#��D�s����6<u���*�U��EJA��������w7�/��������9/��U�!���?�<�b��
��������`����U�v@�!p���a!�xg�u�U;�|JJ����:���N=���%�X}w��bo�-�sO��h_9�V�L�~N�M���<�.����\�Z�+�+s�^3���k���_��+��/�X}w��bo�-��L�J�Z��Z������/�X{w��bo�)�]��#�}wo@g���.$p�|Y��8��$�'z{m��
BL�M�*g���p>���/�s.p_������Q�,+����F>K�������`l��}����^�B�9e@����(�]������v!:��O���w+a�{���Y��z����������}������G����a����W������;�u���)���]*C9a��N�:vv'N�e����������rJt�ew��P�^jg���{�J��|{y�]��������l�����(qo��Zu+C�5�\������gYu����ew��P�[jg���ylJ2Z�����)����^Sv�b B�o������{����n_�D�x�|o�-�N�@N��y{_!�����<�V�Y�k������M ���\g�7�9z��M������g�/�����v��9.��U�"���?�<��;�1�x��������U�	��Z���:���/��Ht�t���^[z��^I'��rU? � p�|y����t���^[z'�s����^�O�;���/���):��\o�-��J�J*�q��������������n�_�z�b��<��Kh��~E.A��������oY��]���zv�	���%�~g��5�)_zw�-{|��u���B���4�uVC�2�!P��}|Y�J||���^[z�������9����;T8W���������o>����������?���?�����o%����������o����/?���?|���o�F�7�C?�l�~-e��k�J��o'�������~��/?���oP����F�7
�����.>@�:�o�gB�.:g�o������
Ae���\�\�:}o��w��b���r!����;t�[vG�g���&h[v��]0��u���
��w�C�X�e�MN���h[v��}�:��.�a��<����;P�b�.{���-���n<Z�Sk&�����]�&�}������!���D�-��B����:k{cyE�&�},��;pY��
����eG�����I{�-t����[v����I�s�����!*I��L�;v3�5���`�q=�-�5\A�b��-��H�J�W�\�66:n����,�����W_���R��9��s���!��	v�����-�[}�V5r��`N���>9:�`����Z�8�e�	�s�����=!*�^�s-�8"��	v���q��2��V_�U�3d~��b�Y�gs:_z�������_Z}�V5r��`N��\�6.:�����(e�ew���0�x��y4ex�LP��`�s.F7[z��j[�7�-C��}����*���Y��
��{:�p������@K����lJ�D=H ��u.D�JT	O� tG��Z5��I����lK.��OZS�\�6�x�`����b�T/
xO����R
�)r�������Aw�:kU��k=���r���57u�R������]�w�:KU���k-����v'���s���D�7A��R5��I����lK.��Ikl�������hAw�:U[��k
���r����5u�:�4#���E�w�:�T�������.!j��sM��2�X���R��]�3	���m��
4iMM�sM��1�d�;v�5���L���ngSvg.������Y����kVv)%AY���������5;��[.��U�;�T���,p���
���e~��������R*�z;������c�n�]g
r��
k�2?��l�n[���w���[x�7���9�#���T_'T�\�.�S�:��;x�s����]g�j��K����l�.��s�]g�j��nV�����<�+��WT_'U��F��2����j������R�<A��/�����
��9���Vu�f������u��f.��/�����&�Y[��;kU3u�J��R����.KbO�uZ������������A���O���aw�C���S_�U-�]YO=�iU�n��r��M���f,>�%�����e�*Q�wg�j��v��`�Y�X��������][v���xwp.�Z��]�&�uV3��&�h�{�w��]�A�9��sM��"��r���5UK�xW����k�n����EUW����Z���eY���O����K5H0��u��nn_9��]g�jK�����iU� ��b���j���Z9��]g�j���L�����][v��]0��u��Zf���;v���e��2G��s����R
�)v���ee��A��)eAy�]���7����e�j�`NMrs��Zv�t���V��tYv�O�������M0��u��Z�����eaw-+�c��d�nY�R\!-�S;Vk��C�&(v��j!8���w���yD*e��<�jmy�������o��u���v��v^����jmy����������|��1�}A�J*at�����M��,X��Hp�T�)�������WR	����u@�!p�:V�H�e��Ni���N(��)v����	���M��,X�]�)Z:wJk6fw�QI%�����0�����6(��%�J8�5���t,J*atX��:�tH���aw���FS	��fcvw��	��87^���3����sJmPvw�,{�t�\�-�[�	�i��.���D��������������.^cz�m���Y����}�;z�������`]�m���R��	���\�qi�(B����[����>^cz�m���Y��Z��[ 	����Fn�^.h_l�5������0/���G��hBw�:�����;y���&�iC�g�j���-���u�#7�/��u�O���KQh������6!��U��^gAr�sA�b/�1�T�6m�y��Ymc�@���Y��8�\����kL/e�M�c^������[����,In_������5�����1�Kg�j�{��7tJ
Xz9�\����kK����Mc^����^"����6�,�{	�^����kL/;�t�^3�����W�=v��M)�Co
�E����kLo�|��N����7�=n�^gYco����]�Z��m�)z�U��C��+mmJ�Pz;������^cz��&�S�:�V{��cW���*�<�����/T�vv�	�����>"��+�mJ�PzG�-c4�p����^��	�����>!����6�N(�3��)���j���M@��uV��������N�B�~���_�Z�lp�)z�z�~�7�v��M��C��^����kL�>cZ��3����~��n+����/
��;��':{M������|���w�������\*�By�-?}7�/���[m���-�����/ 
������>��@�BOt������|+�r�t�5���T�������7����x���Ne�y]��W�Z������R2��c�7��}�����~&D��������n�>=;�TJ������7�/v���}��9E��X�t#��=����z/#��'Z|m��vBL�0u��^��\���|W�;�y���z�������Cs^Wv��y�#�E�}��������|m��j@�����;��]t[:8/���<�b��
��]����+!�Wl���zu��*��{Z:-���,��Xyw��b��)�e�����}k�>��@W�C�R)�C/v������kKo]b����^���t��n�^g���?'~op_m������QI����U�l@����R���o�^����k�o��\@��u������M���[��Jt��c
We���[�}���r@nA���u������?v�rU�<!��[�}��>�!� pS�:K�����}��������N��,]�3�
7����Q��]�� ���r��QI,���W��X�����]4�p������'dU:�j���t�@�tGY����w�l/p_��5���>$��6��W���U�>t��R������.~?_(_U�L����8�^U%�g����Y��*�����_[~�	����WU��V(D��:�WU�]4�{�����f'F%���6
�"����Y��Z��U�
=��k�o��*���w��:(D7���~U��]�@z������i���Y�����tj�T����;�w����_[~���L�8W^UT�n�_g�������3m����<!S:�����������R9�����K�
=��k��Z����W�]�����?�+:g������R!�)~����
�CU�����_U;}�->T�B��F��
t���Y����J��;�u�]���d��-��J�Ju]kW~uH�+D 7��R���_LA��}�����z F%��:�Wu����M��\=Yc�
�����������a�u�\U��?�)~���s�op_�������Q�/���W_��|F�)��:,��~��j��-�b�Z�^���U=�����/&���Z��V��<%�L��;���������t=A��/����;O�������������t��D�������R#�)z��z�hD��zG�+#�`K�����R"�)z��zgHDw�*�Cy��!�����'zM�m
�{Z��;3����m�&�7E�s������`M�����V�Ps�^�������)z����j&�h����lKo�����������A�W���uV7����}����^�CM�,��^�����_���=���o��DG����_[z����o�\{����n�^�������W{m��:�����u����}�C��:��H�e��~O����Ke�	�����\{�L��6�2t%�=�)��=��k���2)�og'\�%���������u�����}����_jC:��s�`�Uy7�)~�k���$:��_[~w�~t�_�e�����J�W��������}������`��+�������������U���m�,���_[~+�~[e2z�;����w����Y�j9�
��=��k�o���[�;�^�X�w����Y�j9�
��=��k�o;��[�;�W-������u����"�hn�d��-�=OH�,������npS�:�W-�����gzm�bT�������
t��]P����������_[~����B��_��7�����r$��}������ F%��;^���]��Lt��j��-�+O�2�����C�d�2Y��:�.,��.p_����wg���F�{g������	~���<������Z���.P���yw���UW��t�Bt���~�qk��}����_*D]�;��_����Bv��+��+��������	����`�_z��_����Y�������_[~������w��B$pS�:�W]���.���������	������w��B$pS�:�W�P��gzm�Q!!�S�:�_u#�[�]�'���=��k���2*����o��������d7C��������@��)~���n��"pS�:�W����g{kS���8�rp��6h�7��s�`�1�������7-v��:���	z��,���`u������%2��9A���`�\�'pS�:+}�]4|N����Z	�E���:`�\�'pS�:}
��V�=��kKo��2[tt����9O���u��������E�����v!��zt.��;$�n�^g��#�$:&��������������s�U�c���M���n���>�Y���lK���C0��u�z���)z���~����{�����i#D%�0:��g�7E������[��^�s��-�KO�Jnat���sk��}~9���=��k�/��ze2�������u�W:�J�2,��Dt���
W�>c�z���^�;�]����Y��5O����k��P�
��y�,�(����C	�^�&�U*���[��������[���+4�s��P���)~����[�������61�k���L�:x~x�7���v5������������N@��u�����M��,^
�Bt��*�WC�c�{�)���a@���M���^
�"�������=1��#��Y�Fx�7���|5L�]Fz������;#��)~�{V7	��������CP��L��-�O�2�)�k�V7	��������CP��L��1~��+��}��
�p7�~������~����@>��/?��/?���?��Ou������?���B�������������~ X��o���X!aY���n�P~�X��;��������~��/?���a`����F�7
KWe,����Mg)h��L�W��M���F�C@'�������c7�X���	z�
�<��3�E��������Y�1�VXpnKoWO���u�����}�I�����M��o~����sOO���u���5��i[z������7�=�D*A���Y����W[�m�GbL���nn{zGhT�6E���7Nt[F�i[zg�Y	�������w�D%hS�:�|�L�e��P������������=�<\���C�J�e��������w�Y��������n=6E�U
�����������hSz�i@����4b��N�3m�^g�o*��	�W��m�e��N��8Anzz?��S:�J��*��^��js�-��t�^3������N�.�
\��.�5�^�k���R�#���Y��Z����]T)Vy(n�
�[�m�e��`N�k&\d�C�;)�E�R^����":��h[v)
	��f����y@��(C��:�V�@�e��/��m�e��`N�k&[<��Ii-����<�r���}�/��]
C�2y��Bs[vg��.t���j5q���}�-��]�B�2w��>s��ye��B��:�V�J�e�.�S�m��&BL;.���������n�����<��tY6��hSv�Cs�]g�j.s�����\�e�/�D��[n��v\,37=�s�t��M���X�\��jK�-��@�i���2s��[#��	zKg�jn0�E���mKo��	���Y��[��
���j��ND�z�!���n&���r`��-��RA���Y�������6/�����O;/V��^��A���Y���-C|�����<����^l2��wB���}z'����nh[zg�Sz���E�����A���Y���-s�C�d3�-�+�:A�s����RC���u$��n���8�mK������k�m/�����n��JgEr���
�W[�M�]
> {�R��s���8�6E��$����'�]�Z-���Y�Z*����]��&����'�m��y@�t�{`��Qz�Yj���6E����4����}����HG��������N���u���v':�����1�C��M]��G[��M�[9�VK��R����kK/�!����;pPC���=����2VDo�P�Z&d�t�^g�j�.$hS�:���|�(B�����;�����;�����.(�)z�e�����������=1�����m�]QF'hS�:���	�W{{m��y@��h���^���m�^���[��@z������`l��F;������
�m�^��w-k���������BNZ@'�uV��
���M�����Jt�J��������M@'�u�i�6=V�����k��~��}����^��	������"��*�mU�\k�v%�E��'{{m�e��N��\k�����Jg[U;�Vk?�������<$}Z�?�����i7A���Y�ZG��������N<#c�`���r[v'x��6���p�N;�E���S�m�]x<�t�����������_����v����E�������!�7��Xn{vW��
�������D],rNs�ewG�M0�
x`a�-�;:dm�]g�j�W��n�<'9���|<��h`_����Q�)v�E�����������V#!�{��+7=�[��!hS�:kVg��{{m�m�xl�����m�n�\��M��8KV[��W����k�.E!��`�Y��:8�[�	����Xm�]��jo�-��t�^+�j��#���4��N�M��:�����C�N��-|�7���qP;<V�q1���OL�����F�����O�|�3?�`s�3���;w{������m\��)���54����h��/���
	�`���l��lJ=�cq��]�����9�����������v������������ECp���jw{���`�Y��K���6��cq��]����v9��[���nb/�l7��������;P�`Ko
�E����lKo3c�s)�l�=�
X����q�hK/g��W��m��P��+#x��mOo��C�&�}\�`Ko�E����lKo�������v�F�}@A��M��8*����w��]����<�����v��y��#p���q'�hE��.g[z���Mv�����5
7A���[z��[����lK/�y��6����v�����we����[zWdm��2�%�}��X�����e����F�~KW�(j��w[	.Z������}#�t1��A���]H�&�}\�`I�����
��]���E9c�r�T&���?�m@W���e
��V�c��W��m��k`��Mv�d�<���
n���[z����M���VC�����(���y��0t����W���\�=��lKo����#�R�,��r�P������P`��
��]���%0*#xJe�l��;�@7���_Y���!��~�j5�L�J�����sz1��7A���1��`(�3]���B��N���(��n�@����V���`(�3]���.1*q�2z6��]{,����U�>���Z����t9���
��lpWf��9��t[����U��b���1��l�sgIqYT����)���Y(.��C�np;+W%V������l�.6��0��u�J����M��,\��sC�b��-�uK�i����u����N��[g��������m��n������C���7�	v�e����R�w����m��FBL;/�2Y8���V���	��Y�*�������$g[v����R*��������}��;@0�/v9��;.����,���y��T��Nw����.���<'8���������U9O@�t����U9�e��ut��f[vW��Y)�S:x���+����uV���.�-�;��lK/�n�S�:+V��J�Rimk��r���E+5N����[|>���R*S�����@�+p�:�UU�oO����kKo���>�L�rz�
D�&�u���
!��}�����z$F%�U���[#��qt��^U5�Ec�������<��*
xy.�A��M���V-�^A�jo�-��B�J��4��9�=�z����9��z�-����^[z����W���C���W�&�u�������a���^[z�
	���uV����
d�;z�����n��{/�*���@��u��������9�V�B�e����V������J^���2�X�3]:g��Z������'{{m�E��
t�^g�����P)�m��jU�t[�x����U���7�)z�U���op�:�Vu��:�^�do�-�J�t�^g����� p�:�Vu5\�C�B���gbT:��<���Ln]��Z�MCp���U����h��K�4����[�7A��jU�p[������v1*
J^���5b7�	z�U����Rk������w�Q�H�4��9�X!v����Y��G�-�
�gz{m�����)z�+��	�	7A��jUOt[�xw���U=/���'(
xy�]{�����Y���-K�=�do�-�+���v^J�/���2�Xy@��uV���nK�E���^[z����/����� p�:�V�N�e�6(���5��a{��N�����{���wV���!�xg���UC]H@��un
l�H�7A��j�`��
�EoooJ1��e�|����9��1�G78+W
V������k�.6��0��u�l��M��,\5B�&�a�Bv��&�S�:�VM��Q��g���g��F��Dg[v�����u������}��;�TH����k�.��s�]g������(�m�gw��2E��I�����M0��5���ao���
��U��PH����k�.��s�]�������(�m��f�ltYV�
�����M0���]��-
���68KV��2!A�bo�)�m��cW:��,g�-Q�-p�:+Vm	�E����kKo�����4����B���M���X��Np����������/���6;n���V�
�A�jo�-��D�J���������P�	z�C���	.��p�^��Hy���zU�#��	z�c��_	.��p���������oO��`���<n�^�:�v��22�x������'F�CAi��sz'�7A�s�U;�m��
'{{m�]���*��J�/�c�%�vvt����n������^[zW�����=�v������{������
U����^[zw$�t�^g�������2��Y�j�������^Sz����|�����r�J����Y����O����kKo5��>�4����B��M���ZuuCp���U������2:�/���Q�	t������|] 	=��k�o��RC�t��9�j�n�_g���f>��jw�-��@�J��������h	����U��|���^[~)
u���R���s~G��]�
����\u��'p_����wZ�Q��S������t7���t�q9��}����_�C����T������t]����,nt��'p_������P���+�6�<�wC5]�C��:\u\�'p_m���wg�,�+�>�<�wG�M���uV�z�����������M����Ri��r~�u7���|������M���V1*5uJ'^����H�	����U��|��._[~��Fi��s~d�n]��_�
�S��j��-�]A���������vPxn�_g����>�k��;�r�O��x1JKO�3��tH��8v���
��}�����A�`N��,a�#D^����Y����O����kK������
V?�tH���uV�����}������!����(���<�w��+pS�:X�J�e���D��-�r �9E�s�`��&��.�rY_6=��kK����l�+���,�u��dW���<9���h��9�������`N��\{5����@���Y�������9������`N��<�j�q9�����P#�%p_�������`NPi��szd��@�_f��]
mMt��=��k�o����N���]
*������D���g:~m��yB:%�T���8W�!����Y���?x<Q���_[~�������������
�����������_[~g�~e�y�4��q�f����+�Y�f�~��M���.1*�_�u+��]���)~���aE�W����k���������a�w�)���[���s��j��)�c���@/���,��X���)~������"p_������o:���zu�K�}G���r��+�����_[~k��J��k�����M��,_��Jt���B�j�B$���xy����(D�k-�����w/p_m�����1��WJw^����sF���u�7��$:v�<��k���]@��u����n�_g}c���W{m�gbL+���������@n�_���q��2F������wF�.�S�:�W����M���_�3��9�[v�~5.;1���UJw^~W��7���~5�(��������1Y��������~���
�������D���P��
t�����S�^���u���b%��P������R!�)~�{�
��(D��:�W���W{m��{bL+����������n�_g�j�4t��j��-�-��I��^)�yy�o�^�&�m������������v31��J���s~;x�7���~5q��}�������2�R:���; 'pS�:�W��W{m�yB��������~��
�����������w4�x�S�����<gxF,pS;kX���{m�]������������BV�3�q�����������_[z���>L�4p�9�;:|n�^gk������u�hSzgv�	���Xs�d���gk.P!p_������	1]!Q����3+�n�^g�j����Am������N0��u��Y�4k�o��|57O������_[z[��9A��������I�&�m����]�.��pN|���[	1��TJ�V����&��.���t:�MO����;t��������<���M�]N�@�%�kz������ ���RU�����&����Y��'(�sP��L��-�3��)��P)�yy�/��n�_g�j^��uM������"�!�S�:��+j7n�_g�j^������*W���*�Jw^��yg��)���r5��]��F�����o:��s�����E�|k������.���v�TxCt�_����B�+pS�:kWK��!��j��-��B����J���s~Y�$pS�:��K��w	����������Q����<��E�+p�v�����.B����k�o_c�:�R����_V7	����WK?��gzm�&bT�_�;/��n�)~�k����KP��L��-�O����Jw^��yB�+pS�:�W�D�e��.\�_-�J�i�R����_V6	�������w	���������o:���~���@��7~7z�k�w�B�ja���N�kWyuhv��3Q:���Y�\8]����k��Z,��T�)�yY��Z���)~����De��}������#F��N����o�^���u���j'�hi���_[~��J��������}~��	�W{m�mGbT�����<���w/pS�:��kW]���d��-�=�Ot�_g�j�������>���E�������w�	���W���s?���n�_g�j������d��-�SO�i�R�����	��M���_�3}�)��d��-�
Pt�_g�j]�,�j��Y�Xz�Kt5���_[~��&�S�:�W��D�{+{g}c�����=����
S��'�S;�`�;�p���V���N�e����:���n�H�+�����,�n%��D�����k����V#!j����U87E�s��VWD��O	���6�s�^���A,pS�:X[�]4>�?�K�H0'�U:|�\���-P��_:�[��W����kLo�����������)z����� �h�{J}6�wD�+�S�:�W��^���uV���~��~O����N!���Ji��sz'L��)z���m��2E������]�})�S�:�m����gp����3���_c~����2�;/�����#pS�:kW�F�e���]�[m�@��^�;/���Q9$pS�:;w�	�{m��KD����R������Dm��M���l��Dt���s������M@��u��+L��������+�5dS��b��1�
����N�:T�7�+����9;w�	�{��myB��~�����~���w���w/p_��5���Q�,(�yy�o�T�&����}@o��}������o����)�yy�����M���^�#R���_c~'��Q�-(�yy�������Fg�j��[&p_��5�w��Q�-S����������������"� p_��5�wCvA@��u�������dFg�j�&��f������7���Y��w���J�[9��WcQ����{q�����;����
t�__���t��[6��W`v����]�_�E]��[�to�8������:��[�op_��5���Q�}K�>��@�h����m+����]�_����J�V����@(D�[/}��0n�.�[v�~5�J�������j,��zmk�o��:�.Ctt���_c~����:�;/��t���.|����������s�����<!��*�yy����9�V��~���������b��Q)�S�����l@�(���W������D�������1Y�������~�����
_��}�-�_8��k������(�[Y�oYT@�+[k������_��}��������Q�/(�[Y�oY�@W*k����*����g{KS��8+��Ni���q�]�������z"�����mxHj���}�_}����Q���%:c��}�/�����!�	*�yyNo7]���uV��n#�h��9���~'D��Q���������V9��/���'zm�y>�t�@������GD 7E��~UN�[��n�s��-�3R �9E�o��: ���(����~KP��D��-��B�������9�+��E��+����~���sN|��w�Qq^���<��M7�)z���~KP��D��)�U��cS��;/���gt7E�s�FULD�-;�=��KuH@���z���o�C��:�nT_��j��-�5^���Y��jx�7��o�������e
WU���:�^U-B_����Y��Z�����_[~�
	�����<�s���
�������U��w������; ��)~�����~n�_g��P9$p_����w\�Q���t����Y�$pS�:kW�D�%�kz������#F��Q����;#��)~���j��2G��������<!���(�yy������V9�W�����j��-��H�J�������n�]�)~���j����{�/����:��s�U]�rH���u��j����}�����r%F��Q�{����Be��M���_���w��j��-�uO��3:��5"����Y��k�����_[~�������Y����Z���r��j����}�����n"��S+�����wA�����w��j��-�O����V��r���@�D�&�����z@~A����k���c:�P+�yy��	�����Y��'z�S4�p������'dJw�J�G��yF���M���_�KIt�z�����1��N���_�+�7���~U����h~�d��-�cte�_�t~�9�;�S����Y��������_S~�@!R����s�US�z�	�{~����,�.:��d��-���������P_'pS�:�WM����}����_*D:��s�US��o���_g��i����;��k�o�7D@��u����C�]�m7�c������x�����Ub`�?/������n�cg
��_
�{m�FBL������H��������ES��h[z'���9E����P#�)z��fBt��������+!�C�Z���sz$�n�^g�Y��/�����������J�9z�������	\A������O���_�����������������������O���������/?���?|��n�o�F�7Z���-��R�?����o�Jx�~��coK��{^��6���
�4���������+'pw�c-�5e�Z	.�K;'���[o��^�Q+��Y���''p�>V�l�m�
���m�e3�`N��,��-�Vk#�f��N+h_l��e��D�9�������i[����Jk�n?�E�-��L��:�Z�S�sx��	�T��3�X�vC�j�-�l$j�i������Ni[�����i#8�h[z�G$�S�:�P���V� ��P����h7���@���6�VY�V+M�yN���Vi :P�fK�F�e�V(������]D:e@�����
�V�:P�fK/�����mJoW00W���J�b����8 7����eJoW�����?��[����}]+�P���U��n��d�q-��}�������NY�V+�A������	t��F�L�,r�����v&F�:IQ���~��M�s�5:.E��6?���#��)��jE9�szY"p��e��_	.��s�j�
1*�������!7��Y��F�-AQ�3����N<���(�ky���
�8�eI���t��xg���U��|�J��Cy�������{g��[��,���U�n]�Qq^a(���{����Ug��nt��x_���U�w����(�P���3���US��l���������V}����(�P�����I�&�uV��nK1=��lKo5�"�+�P�����I�&�uV���������g[z��t�^g��g1��M���Z��Bp,cz�����v%F��[�������M���Z�*���-����1�`��^g��g9��M���Z��Np�cz������ ���R+�P��;B2�	z�U������
���N1�G���0�����I������U?�m	����w��wA���N���,�/(��	z�U�~������v�����gdI;0�"���7�k���uV������V~�������l(�P���`C�&�u������'s�C�'D0��u�5��|n�]g�j�&4A�b��-��B��F�ZQ������c/p�:�VC��W����l�n���*�Pv��7���j54;�E��s��-�lr�)v�E��C�;(�m��h5p��}�����~"D-�u�����M���Y
]�>���m�e��`N��\h5�z���u���q%8�O����KMH0������7���cP��:g�j�����x�do�-�lq�)z��aa��4�u�����gY�
�U[�t�^g�j�v(�m��Z5ltZ�xg��r��7���Y�vt(Js[�,W���=��p�^5�(��)z�������}z������
Vc�����hBY&��5"����Y����3�:���b56#1*et�(�����	����������������|�J2AQ����!� p�:�c�^����kKo���MPd�<o���C�&�uV5�n��}������#F%���ByN��t������e��K��������1*c�a(���{�����8����{�O�����L��$a(�c�%�������mY�	������n<��QP��<������M���nt[�hF�do�-�;C�-����r���N����;��S�oO����kJ�D]H@��u���J���@����g��3A�jo�-�5:�'e�Y�9�YM5�z����Y���������VS���*�P���"��	z�+q&n;�������u��t�wf��������	z�U����������1jq��ju����n�^g�j�R������;�����/�����8��Y��&�-c�3�B�j�1�B@�F�9�V��R!��&��t[��.������.<��*�_�|��2�X�q��,JN\t&h_��������*;n�/���at�Cw�:�V�N�~���9��kJ�\�|�J)���e���97����Y������l{���1��Mn<E��r5�h������Y��+������^[vk���9���p5�PMn�]g�j�7��V��S�m�mvBT���/��m�T�	v�u���c/h_���e�Q���y�n��C�&�u��f.��/����; 6��
}����aw@JA��	���'h_���ew��P�����%��'�7���&9OP��������=!*+�Y(���� #p��Fg�j^
�c�������(�S�:�a�Wz�kz���\h5���������n����`_f�����a��M���X�{Mp��Lo�)�K��cW�(�_�����
�����R��������K=H@��u�\*�%���uV��
���}�����z$F%���}yNo�\��M��,W-
��������R�)z��Y--��%����u���v!�x���������LaW�<���[/p�:KK�T��}����^jB:E��b����@���Y�X�-C�}�B�j�($�S�:�Y-��-�*�
]�/���):��ds�-�3����.��v�|����,�Kq�����|/����h����?pYQ($pS�:�V�J�e�v��l���w��QJ�(y��~l�TtY8+W�N�~�Oa�P�Z��&�S�:+Wk��cU���Y�ZK�.��_[~��&�S�:KWk�dU:���Y�Z����s�Nv����F7���Y�ZkD ���V�����w�������N7���Y�Z[���J�[Y8�Wk�]���d��-�lu�)~����G�*Mn_W~{T�	�W�|m�e���N��,_�
�V���,���u��2D��Nv����f7���Y�Z'�����V����:�w��M��W+��t���/�#���,���u�w����/����'dI�E�����@�tz�,���u���F�'}m��bL{0���9�;#�=]�W���������}�';}M��
�!{z�P�(�Y��
��7���~��
�E�������R!�)~����Bn�{~���������gz}m��B$�S�:�
n
J��@!���Y��������5���)i�Qf���Y|��E}��Mq��am2\��n_[z)	����[�$��D��:KX[�]����}����
�o@VB�����_�������|������?�����O��������������O���������_~��O��������2�o|�^3��t�?����o�������m?v��{R����Q��z�99��.��ir�c�m?N���<�%JSn�lq-��o�-��M�G��R	�4%�����f\8������1w��|F���p1m\�X�7%w/�a
�;�m���a
����[r+8��6A����+�c����g[r�����������M��8x�%�Am��}������#�t���u�������������-�-�;A�j��-��N��x�8�m�n�N�&�},������V����l��0c����:r[v�J����}vY��*�3M����peW
Wl#�e�u+�R��8|y��0�f�����y�e�:��N��8�m�.����J�\,y�]���9<��<������N��En�.���8�xhEI���y�����m'�tI��U����������j�����`A�j��%�S�a<:a@_�����qC�l���T��=��W��m��,����J����Y<w��zUX|zUt���fg[v����W�����:��{`��-�M�O��O�N����#F�q���>�M�*{�}��,;>�6^|�V5}A�����U}�k�W�u�zUX|z}|]�uZ�T#1������;�7(��������7������b��qL��� �ew�nJ�����e-V7���8������AGvQQuC����U-->�D��uZ�T�1�3�6����N�*�q������[�[P����b��1�<���������T��cK�>��fF?��lJoY���NX@nJoY ��7g��[��s�7��67��[AQ���<�V�m���qo�-��������_(W��B��$�����6��m�������6
>�&�<��lKo�c:x`�-�����M�3?������np_�l����n��:V%z�nhS�z�^��}����^��>-���s�nh�*Y�<���t���@'��m�� �	����U�eg7�)z�O��TG�9{���3�x��3=z���C���e{u�/����\���������,�����6��=$���o�U���l����/�H��:K����,G������y���4T�J�i���v��Z�b�����zM�E[�
��=����-���t�9�h���=]Q��\�������lK.�bo��:�|�boh��&�%}�7�/6=��[�/��9A���W�/����rCSrk�������lK.�bo��:|5�bohO�Sy�E_�
��M����/���tMPr�{C�t9�-�����}����\���0'��,������}���\�������lK.�bo�A��^����8������W��m�E[�
t����^����T��c%��^�������lK/�bo�Ok��}�7��W�������W��m�Ec�
t�^g��Fc�
m���; Bg�
��}����3������^t���>_�dK/Zcop_m|����7�	z���zg4�����|������W;�M�m
Jo��E���6��m������/Sz6�6����������{`Q�-�l�m����r�5��m��
V
�c�;���v[z��(����In���=�I��^(Y5l�m�����m�e{l����������&�{����^��6J��=����?�Q�c�����A�I4�^�Z5l�m��k�m�e�l�5�>$�2%���M�?�B��al�����nK.�c�?���a�.�c�D���U���F��=����]��6�����-���m��*V
�c�?��~v[v��(����,[v��$�c/���6J�������?�Q�c�U���=�I��^�W�l�m�����M�m��*�������;�Mt�^(W���m�����m�ewl�t��]n�.�c�Ds��jU���Vi�=����]6��Js�������7�M��^(V���m���[�m�eol���6��n���6�{����]���Jk�V���^���Jo��g*�l�m��jU-[c[�5�<����^���Jo���$�l�m���U-[c[�5�<����^���Jol��X�5�
Zc��|���m���[��nK/�b�9-��_nK��4Gt�>����R�BW����P�"*�Ow�R�"�!h_���ew���{v�E�vgT�)��C��A�b+�)�s�]g��cG`�t*3����#��w���m�eG`�t�v������Ni	T�Q�����.�xNo�e�-���X��U���N�	T�������.�xNo�e�=���X��U���Ni
<�7f�.��xS�9���]6vJS`Y:kV�;�+�9,�����������)�S���Y����)]�J}Pv����������'�Sz���<��)�S�1�e�=�]�'���lK/{;�'�,���M���x����_6v������M���X��rU���N�
<��k�/��DW���U���N�
,Kg��c[`��*A[~��%�/���b F%��f��/�����M��K$��]���V��t����U_!,��wm��[!#(p_m������Q����U_#0������ %(p_�������&�S�:W}��\���u.b�[$<������v1*	A�P������:����j�z�W����_�pt�uuv���u�}�\U����>?���Zh=b�Od}�t�8�x<���<|�=�vB����~������z$�����>�x�����p��������O@�w��;"�6~w�����w�' h_�����~:E���7LH�
A��]�N\z'8���^h[zY�'�����C��<����F���]�g��6C����>���Y�V8_CP�w���}z7$���������O@��u�����!(���7�S��wG�M���mJ�X,��d�*g�o,�i�����;�H�	�W��m��ZbTm���<�VH�	�D��c���
y6A�jC�-��N�J�M�^��� *�������-�
�l����h[z���4[�\�6���n�v���;d���-����P�t�^g�j���D����#�&h_����w��QI�)!��; *�OW ��;"�&h_����w��&�S�:�V���\����������}�)���y#F%��0�����\��o�������}�+���u F���v���q��}�����
)�k�=�r�C`�)����qgp�k��7�;����hSz'�	�����T��LA����-�S	�E���mK/��s�����T�|LA������V�^��������O0��,^M
��SP�wn��-�
���bk�-����	*C������)��;3��1%���2�+��	�����O0��u���Y�)���;�����

�;�m�BT����r5�H

����l���/vF��;������jv'�n���ne������}�3���y'D%%���������}�����)AA�jg�-��@�JJ�qV����M��<4l�����6F���#%(�S�:V���|O������#%(h_��6�w.fbTR���`5�n���	}Sz�)AA�j[�-�45���Y��+�7Qm�~9��[!#(h_�������Q�6���� $��j+gIcn���6E�����$[g�jn��D���k5wHu�W{�m����	������#(�	=�q�����A�jK�-��L�J.�u���Q��}������A�j��-�t5���Y��'D�7QL�}z'�:������1*��[g�j^��T����� �!p_m���w��Q��y�]�����l�����������C[�)~�u�yg\�k���j���#�!p_m�5�wa���N��,\-l\�6A��>���D������>�E�T�����}���'x���_6
.�F��������(�:KW�QP�Y�����K�S�B�ja���u
v����N�E����<��UpI�
^(^-l\�V��Y�Z�*�(����_���WpI�
^�^-�\�^A��y�e����
�����f�%�,x����_6.Z�`�,_-l\�f��dl�e��o<��k�/��YP�u��_6.Z���e2���YpI4^�_-l\�f��Y�Z�,�h�����e��4>��k�/�QPYb��_6
.Z���\���Qp�7
�l�5�w-fbT����~��������H
\�f����
:�Oq��a�"t���|Vv����B�P����kKo���"��$��/����]�]�
:�y���3��O3�ec����w/zb$���^����Y�f�o�[��'���<0>�ynz�	�=/6G����j%�S1����q���MeT�h�)�
�	[�����h[z����[�,�m��*pS	��������-X��Ds�-�=4+����Y����U�>?������-���D{�-��J�����Y����U����>�#�	[�����h[z��������q���M�{HnkJ��L�,v}�=���� De�G�,�m��*pS�Tgv��`�������!��~h��<�r���}z��-��[�����h[zwhU:E����q���Mh@��][zw$�`��3������J�J�_�,����*p�:��{���t}�=����#F���w�R���U�&��'�l���B������G�������)Mny��^W�����r�d�`��3�����#1*U~��d�s���Mt�{���{�����h[z�cs�vl�������c�@�-����'vl^(Y����k;6g�j���]����g���;6���������r�����TJ�������c�@��-�����wl�l����;6wm���,Z����+;6������r����y�=��^��������<�r�����,,����K6����e��K6wm���,[�\��+K6������-�{b��u��\>�-�Jv~���|BnpS���s�,��@��s��}�=����'F%!8�
W�f��������f����:�m�oS��T����i��Qr�v��������hR�d{�-��D��3�JW�6�k�57���\t��6�<�m�o_c�x0���<��=��J���%������>�<�m������W�����A�\W�������w��������O�jl��g���Z|}��������������*���������������~ �������?����������?���~������������?�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������?6��)~&��������~����{&���=2q��Z<��M4����������B������������7����.���"9P�^�^�����q`����d�������3�F�w�����]_�X�������������?���k�n�!�,��7�,q	 *[���(���eY}=�e��Mx8��7�Y&���,_�$�n�����L��d_��'Y���������\�w?���o����o3�~�_���/C�5�[��������}'��������#�5|{|[z�^z9[���/4W��)���*����o��^����/~����?�?������/��V��b�a��k����:|����V���"hm�����e,
:9'Um���i<��n���r��&��������3��t��!p���CQ+�ww�������/��o?��������zw�@U��\�!6\����6����B`�J����t��	��S6���V����!��=�/��]Q���=��#��{��f����a�^6�������tE{�=�ah��<���o�#�ay�{H��5ik��C�ky�4\uGu�\��N��e��J���R��\�����-�;������N����c�S!?�����s�}��M�Gv�����������XsAp�?x��N"���������M�A<Au*4���+������)��OQ�>��S4X=E�7�)��y���
�=)���8�=���^P���^BM�&G@��9�E�	0��0�
��|����f��ai��=�zWW��})v�_�O@W�q�����P}���Z�9U�gz�q�����v\��W�[3�0qb��Vr���M>~gc���Kgt2�o�=�6i�i1O�a��}*���|[I��wh��oC�I��;�7��&�oK/(��AX.��4�3���y���4��6_:���|;%�������/4U����u������VvX�c����^��0_2`�e>�c�S�C.�m4_:#S%=�L�cBf2�c�L�cRfV�2��m?�d�2����{�_U�~���GbS�UP�mh�����"'��KoO�d����
w[�~�����S����.tT� 5O�p���c��*���������k�]��l
��:����!�fnx3{^{��Nn����3d#D��-ofO���x'����~�1!�fny3�������'�	����~���N0X_
��j�x.o��)�&	f��KZo9��
u���DQ��W�11�����Sk DH���*�������yK8]g�Z�`�*�#8���6����@�;�G1���1�����v�X�~�t�u����M��{����{����������m������CI���o���%��%���?��Kd�P���hT������J+xT9���rP�8UUy��;R�<V�x�"��Cl3��l��**M��LrNt���Q� ��svo�hJ��A�w�����9_�U���g����x5�i'X�o/�_v�����,�&;.G[�>���J���&�O<:�w��7�Y0���|3K��$���u��2�427�%{��������Y9�e��l��j.�m�:�m�>��h"�w9j.�����i��q�.b$�J@9*��.�����!����m$aXs�(�Cyx�x��	n�`N���*���G'��]g���`�����<!8��
��~�9cB�i�t�j�]��������g���#
�w�<DA��3�	�uI���U��o�W����L~"�^���_�r_��i�h�j�����������k��
��~�Y$B��+���^spmI�E+V+�,!B��	�e/Y%8���6��g�7�/�3	�����_�f��0��P%��$��P%hC�]����Ym�����Ge��
�wa���>J0��~<YsIp�7:�Nm)~�:K�������wr�:�[R�����7�������#8��#�d���"o�1]���m��w��Y�=�6B��<�kV�s��ih���<}��/OC+C�)]�Z��Tn��������Cj���K�c�9�������.5�~���"A������9]|�_�&8J��L����@�4�t�j�h�VJ�K4�]{�
�HAsM��[3�+UsIp�2�oR�}�e}]�%3>X����?����%Z�9>m2Sa�P_��R��C��;Ys�I�%S��G�s��-j.�B��BG�3�=3������0]�&���5��F�a������]�u�P7Mx�o�����M�\nk�{���H��;�\J^�O��������2�Z��J���3t��I{lJ�'p���~CM�GA���/
����`���������T�N3�\���
���M�e�m"���'�� �gj.+�x�sk��)�k��P���`$�w����G�or��PJ&x��>��s�W���,(���~Q0!�
m�v���*B*��
':���Pas�~��'���_T�is�D�0�9n�.�
�����wk9���;���v�__�~T�o�������"���]����"hC�9&?	q(i�������
���L���sL~QV&���~����[-�u�c���/t�k�p(^X���c)����U)^�r����x�B��E
 RQ����8
ST�h.�?&
�J��{�1W�_T$l/�?f�:���/���r�6�����B9F�M{��x��2��RA{@�h�Z���u�f5���a��;y�����a!�f^�����=����F����a r���d���-�;y�����a!�f��S��s���44������ICXb��T�*��m��<���2}J��M�e��>|��VMC{�\���l��=���z�
��hO0_�V\�hO����T��`�*�#8��6����@�����z3�+QsIp\t-h�������1�'�����Jb��!�S���������)�q`Uh�������z��<D��7Tr��\!����F������3h1�E�e�m ��m�0��o��pm`�3�����5�<q�����!,�n
������2>���<+m���-�g�����'b���M�[0j��M��aD��=�
um�2����.����v��2��$Bw���I�%���C��}��j.�m��m?�	���'i7����o���Z<cv�#)���_<�ls��l�A��j�:��=���z��	e=�9gW���`��M��~��C����=yBpP\�`����B�m�_zNT�]����UQ;��1!B���b?J�stNT�����B���5d�y#8J�KtNT���$D
�K:y<d��%8jK4y�y&?qe��uw��T	�h����""��5�<���Fr��{+
��~��--G�kV	��-��<�H�HdK����N�c�
����#�7�?v4�m�|�����$����{N7��EC�E�����{9F0��~<YsIph��G��>&t�Ame������r%��V��3l�
7�`���#8���6��g�F����Un���_������nh�t��p��{"
Mp����Y�`E�)�S�$I�,

xMES*i�BS�mj.	��=��
���������1�2�����Qm ����������LA��Qm B��E{��_�f�wT�4s�~��yF5�8H��6��/��3>����W?����%����6�^�_�>]kSI��|�������!s
�0�WsI���>]��9�5�6FC:Z�nm����Nl���w;�#��}HOMw���\,xS5��/nRs��,1���v|���ZJ�j����}
�����9���)���}J�����&�O�73n��c�X�Yw��2�����>X5�D���H ��,j.l�*�g,������=�	6�:����B.��k@��(����.`\���u�/����PJ&x����e����P�0ktNT��3&��*��Va�L[�Gf��0�9�"U�-�����'�S���*�c�8�HfWT��* ��y�����c�8�H�Ow;�o)�s���������
s��S�e1�gQ�74�c����Lkic���\������c�3�8�~e����~;��>x����i?�WM7�g2`5��U��f��#�V���2���d����m7�g"�[�N�eZ��e�	��}7�e1���L��8� K���_��f�,����~M���L+�����M��f�,Y�����7g���*/t-��'TU��0��+/����:^�m4x=�7B�����������r�F��
{��]Z�rp]���rU�F���y7�i��,�}�O���n�����/OG+#�!�c���f�h�c�9���*M�U�e�q�0|��&��;�^v�������.���@�3�=��P�����~c�d}�qjh?e�j�����iN�|��):"��I)U/�d�T�%���4�o��]��'������#������Jb�[4�����n.�������SU������rk��-�;���rP��2 �euX��K`[yq+�
��gR}Il����i5
���
WE4n��Y��V��������q��K����}kjT������]}�2>��
���-��^�����qFe@�v�����'p?V�[�H��a������,����X}I�pH���������
���Q�%��5��}X\��E�9��# #4��|��Q���!FR^j/�5=f�1�^�Y���n����P�Se<�>:������Z����#s�e<�>:���H��Z�=�f�����������; n4`:�^���@�c���'�G��qY�RK��	�2�|/�,(12�^j��t�������mt�eY8�A�#,���-��
8@�������1J�X�p�.�zX0X�����-8��]z�eY�.B"�����/��1�`l`�^Y�X��d
�A�:f��+-�4�V��A�n�h�x�qqa@��	7���`v�
n��F$�N��`�U�)�D76�`t
fY\���hF�%��K�\5f��k�{D���+���f�x5��9�e����zJg�.?���<G'a��g(G����t]��Ct���haQYz�r����������7x>E�����O�:���sQd�N[�m��&����l�*4���"3���s=6
������"s��c(r�n�S���R�2��A�&:���Ie��@#�Ne�C�t;U��,���y�wj��0��2S�U�:��{t&��^Z���1c��}fbkU������������$<x�2��J[Ue��t�pP����$BV>T��-KeQ�`CpX)��cQ�IlUIl����
N��OUe�wy	)��8�ia��*��������]��31�U�c
���	�[��cq1b��
t�8J{L��x<����h3�.U�96J���2��mh�4���eQ�`�c�*��2We�b;(P7U�F�vU��������*�!�x���f1��.��4xF������v�
�2?�>T=��`��_�u�8���-��L�]I :����=����������o����������g����e��`v=����,\�k��uKZ����Q�,p#�L�#��t������n��j�C��,8��������������X�3!J�P���Xp.h����u�dA��	6�+���~L�k����h������^�
t%�9:e��<3K�H]dI��*���!DG1d����c�����_�1���e����1��
f��5tY,������/�I8V�R�*�yI���$:�UG�*�E�NUx�jL�������WsbC��#/�]i.��}FW���xsI��#.h}�Ct��nh��3�#��T�K�s��ij�++Z�������S��JM��v6ij�C�)xS��4���2����[>sM�d�ae���S~]��{*�����4�����C������T �Zg�Mi��T�:>���=b�hAeLCc���*3��c��1
����u��D�X����p�sI�|�����f7�<����
�2��*�Q�'+3{������Y��7n,��aG*���Ie&��z���/we&�1h���=�\� �S�������je�B��:3��$<w�T�������2S|�������z ?������bV E�H��T����Hr8���7T�]�����b�@��v�/�t����W ��*3Cl�����G,����T�~���m��\<% ���7v��P<�Z4�xB��|J������\<���	��>v&O"�j�O@Q�*�#q�_9��2W}���QtKI�k[k�<r���:e����j[n��~y��N*��mf=0@���	6��T�:r���~R�
v����:nT}W����\�����k[k��h�����������Ct��xmk��
0�J7�����;5�=^���e�B�Tvw��5�	)�.n��e�B���euC�e�m
�!P��e�B�;-��+L�I�d�����
��b������$M���	f+�,x]L�p���NY0��"�&��p��u1IS!n���$OUf��vZ��z����E1oQ�iU�Y��	45��*�5��06��ke^a����x57qI�����t��)���]����KZ�g(G���[E�J�������jn�]����]AK*�V�����Cx(b��R�B����%���37����U�y����K[��QZO�Q�"�/���	q����A�-�t6����n�h�xgc��@#�g���<���gnP�9�WUf��+��i..�u�{4��I��6����$<�Gc���*��3���jop�:���BV?������!6ZO�zH7���f�fF
��t#�Xy��O%�s��7��
��\r������a>84sh�7_e-��� ?K|h�y��B
Wdrev���&s��1��l��!��������5��9�b��f�V����?�f�>����6����}���� >���A���l|����f71��=��~}[2�<��R�{�����^����; ����]��g&�Q�#�����%�}n����db�hA�����L��������3�L����)fW��LL�k��u�x��T�q�[����&���)Qb��+�S�^Gt-���z�D���hAew��>�� ��=S����T@�����L�<sK�mW@�,��&���L
��=sK�����B9d�n������;��1B�)f/
!:�!7b�c�v���V���kh�xukwaL��:eA��7�Q<�v�������/�`��s/����D����n��.������-�1�j3?�h^��%�g(G���epP����x5�m��g(�#/�A�n�����1^��y�r��zT�[�s��yj��x5����������sR���6_�&OMx�8'%O]jJ�Mm&��9�cy���?���k3����~U�9>m�sT ��:g��1��MtU�9���;*Fj��R��=��Q�\�����`���(����
���$��*��M����l.��3VX�)�W?�V�G���v~��K����JINyb�����6�G��F�s��0�G���"�����CgQ�Ip���j�����:3GOr���!VTh�������L��+x�uw��>1�������G���V�������F��>_�J�#	k��hV5RF�rt�FJ��Mj�xH���PY�C����s�yWU�c<�s���(� �T0?�fY�g��y�UJ�g�����$��&���W��j��L}f!wO�5 C����=G�9����y������f�{��i������v��e��s��h�1�`�+%��{��'][���
��1�`D���NY0wB%@�
W���c69����J���]���L�p���Fh��m,�W�F,��%FN6�)����A����7:�E��~�`���s��6Z0^��;�E���
�`����L�.�i��b�-}�ah�]�DtcA�+\��1B��)��p
�Q	��5�u�)������!D7Q	�����:N(����L(��^�p���NY0�$p����n�W��$�{�{/�{I���������x�J U]���j�5Ezo��Wsb���#�2��.?�����j������73�1bekD���LW/��x;��9��~o�5]���m3*���n���������q�����;g�R���3���!gUjR�I�f�1�~0U]���}��~e��j���O��/����R�������"��
�w�i4��N�|Y�teA�E�[O�>��+!s
���a�J3���
K3��J3�x�=����?��ZU���������	��C����J3	���
#��>�Ii& �-!��[��G��L�C�T�&�i�Ii&�m7����,����L���r�Y��%���v
I��L�C5F�=������������6�'Z�Q�1��G#�x��R����<
�X����+�����+gi�������So�Ii& ����A���7��4�������,��L�������H�p����������������C���������Cx��
��7e���+��
E&@�\�*Hz-&���)�y�J-��t���~�������@N�/w%@��~���b$[�M
�����(��&>/St���R$c�Q{��"zw�q��}�-&�g���
evD.�iG�>��f1�N�[w�M/��P(��{,��D��"��Z��0T��O"����F��h���+���b@��R�����%��`����o�&�]g��b���h~�f\
�Q��
��aW`�w	Cv�4��.����9�]�i�+,r�9�=>���@d�,�����yD�����`��dt����UbV��%t,�c��yp�-K0_v����
X�g��0�\����5Sn�.4 $,��0`u�<����4�7	���4��--��l����IV:��WX���j��0xx���7��:���0��3C�������+O���	���k�C�'pCz����4��Q�!���=uBD�'�S/����(�$����E}w��eQd��,+Y�X=��K�7D�����XI�s��K����A������4�GW#�ph�C6���P�4(o��:�A����<��1
_�Su�C!~o�C*�Z^���5��yP�k��E+���m�K����X����:���!�#xSu��mR�JxSI�-#�/�[���RK��5@~�hn�>�.X���\���+�����,��8���a�:b�j�\��D��7�����5@0?�fY�����K�Y6u�8���A���b������\S����f���o0A@��#����C��|M��/�������GYo��#F��
#�F�j��Y�)xBD��`Ni	���C���

��������u�D�1��G�B�������J&/=�?�����L�g
�3��`&oW2y�d��s=c��L�`N0{%!��4`��P�K&�

�T����������h/�Q�.����UIF�����X�]0������P�.pCz&�q��r�:{10��5
-G�=�r�AD0���r*��

x]$26%
�^��������Hdda��&�����60Z�P_��,L��������D�����0AW=>���B���.����XB�;��y9wJ�(��t=��.:������s�^������>�������s���R����'2�@7�^��(3M�6e�Kz�Yf��hJ�Y�-�L����HsX��q}]]����c l������@�P7GmB~���
a�oCh<uB���,Cp�����f|B��;"�MeB��)_�ZV��.��n��Z����&��3~;���hVx
<����F�B���R�wr���3��x�<���rt��I5& �!R�<X�hR�Ip(��	p��jL�����o{�9i@���1��������&���/�����}����b���<�n��O0��xv��"���ZE��
�TDO�>����3������b�;�S�h|]��7��3��D0?�fYTc\	�D��~�l�1p�������;��������X2"$�
�%��bd���>=����	�!��Z�u����>c5f](��%vL"w�R��s�	DW74`t3`��D B~�)�N��������c�>0�����B^��1�@D��`~�4 �|����PBlk��>��]�C:Y��t���N��
m�z`��J0�Nn��D����N�7 BQ��1�@�h@%����D"����1h��V
 B�)�.g
�a��

��V"����1��L�<���F"�� ��%60:���0�8���sH���o
(�/�DF��	�����1�n*h����5V���o�w���?�
�f��S�������������9:�������������{y��d��!�r^���t>��3@�{y�v/_��&V�8������x4���YUc�i��7�����(������Q!�Fa3��������41������mb�<uB���)M���>��)ln�&��Sw D�������)_�j������������<�oj���%��5���2���^#��z,O,�~n�{o����vj:;�	������8�FgeB�E���W�����K����)Cfq�C���Mh��x�����
��m��S;������x�?W����h���IfQ��"�����&��(��?7������}C��������Z�So�I5& �'
�Y&���4��
8�fUc�Lp�����#5�9v����?g��oxn����C��\+H�fw�!7+x�^m���������`Q�D��IdBD&`V�|��[N :d�`W��3�L�
�d����*0�	�<����L�`N0�"Ht|a��t��3��cA*�Y�
8�F�����"�s��}�Z8�[i��t��3
�b0C�
����(�����PBd@1������_���i%@��yR����+��������{���������������1�gZ�)��
�
��"����C
��F"�N*�M�Hd�i�hb��0Y����/0����74����FifU���xD���$:�.�o���z���u�E�]5�����{y�����!�r��v��7��^���t�g��RP���v����A���=8B��%�S<�>�������X�g�����O�d����+,xS&Z��M5&��A�y����=�_b�O?Q�)��w�����U�5��%
��G�!��B0_���X�����Cq���o0S���D��4�7�������=�X��N����e���Q�n�Z*���$���Q�m�H����������
����`Dm1�Y� ��(x������V�J������M���~�c�!?�(��N�f�s����Tr����Tc��&��������{�j��|���p�e ?}tb���9VQF$�t�"J��L*�x<������`�d[p����R���z�V�}�,�1�tJ�4���eQ�Ip�QY��~�l�1p������.Fu��3����=�\2#�)����dv��L�'%DJ�nv����(�uW���l�K5G3�c9�����P�!��tKMF�J
�I�"*�s���S):.����IdB\P*��3��nh@�$r���U*�o@&z��P��1J��=�2Tj�]����E�J
���"J�s��]Lt{AF�_������d��D�,f�������O���_���������������������������o�����O?��_�������Q���c?��%�V�?v�x�����������W���cx\�\?D~��Q�����[[+v��
�5�!��[0�H9�L�WW�_t9����#Dw��e�m?�F�6��g��w�Oi3~�V���ih��Z4^��
�[��������~H���~�lk[�~�,�����Zd�mh�������%�_~?�+Y
����7�J�����R�j�y���|��1��<�\@dNm�rj��=����G�mF� �y39/O����}��j��q	�7����:����~O��	�w��F�{`e���O$��j�Y�����A��}	�]�>Q��c�y�9�?pM���l�z���T��������c�z��`N��r_��w��GO��7�O�����\�~�Ye�)7#�_�xw��4`�Z�� �
�H�j}]�*!3B�����?����-��]F�����y*	�o��L�H��V��x:���Rt�M�Uq�	1=�B-5�V%8�%	�8-�7�V�����>#����Q��?�:�A�#��V4�V%<^��QIg���Z5����<|ne���p^���*�>c�
��A�����EM6c��{V�������	V��zA���eR�
�eC[��u�7��Z������o�Q�*��7�
�0�������U���2*�5G$���������6w�!�GX����h�������JD����#�a���s�	8D��6b@��116
����N����4���e��>0��i�/L�[��4`<�-����V4`:�u7`��A1�c&4���0��"x��;
��X��Pb�0�Jn�jA&vH%��s�F:�]:��n����.�G�}�{(B:a��5H8�
�6b@��R�q��zC��:����
6�gx8p��(�0`�r��gA1����X����X�HdD������HdDs��N|��'�p��{��#������N<"�b���N����B���X�m��<������L�;b��<�'����n��<�Z��3�#F��KzP~���x-/����h
"�y;/����_��$������Z�:3`e��*��Fm��If:��8sUj���cV���������������b�~u�`M���{��HysK�.��n���E[��Sw F��{�w1�Gp�5�h�bYz��HysO7/�f�W�������M��T��]V�@F� ��MKb�k�������������)���t�������q��A����>��Xlr'��,��pj��E5f�����q����37���Xq��T��/�1��R�sl5���3���A��y�j��}|�jLq�9���<|n���HXuD����
0"��k#J-n2��
�!y�7+z�/�W�j��s7����c<�s����� �`T0?�fYTc\�"}A{��������H��
�Z�����,��a��2����G�������@�+���t����Cx������`�Vcv���=����<���������6��p\D�����g�Q��+������C9�_D^V�Id`�0�]�D�����%�����g�!���&r�4`������#7���&�t4���\D�����g6�!���&�tsd.R,�/"/+�l(0r��l"w7 ���E�e��V"F
��&�.{%�q�_D^V�i%b�6�l"�������"���L+#e��u���"�=����/�D��|W6��G"��������7���&���"r[r����Y�#���L����G��jL��h�o���zt�:C�-*0��1?�
���\���<�O����wey����>�X7�zp��Y�����y8,"����3�#�T����b5&��0`�M��<3
��E~�*0��n�d�	��)����&�#�jL��`�����q�����s��c�����"��Sw �W6���	n��x�wh�g.�4��Q�a�
m����10`���z3�+U�Ip�|��>Uc��Ucr[���3T/����M�i.Gm���cIx|��=�U�U�������?��h���r�p[��$�.�`��Q-x4��$8^��r��3����&��}|^b�!�JR����V�R���j.�M5&�
t��Hc��>����RU^��|��O���6��"
���:U��M6Q��8���6�l�/�'��z�V�}�,�1	q�S2��V�,�j��)��(o�M5f�*�tL���16���j�x%xW~�<3B�oh�h�VwO�������47���	��
�����Y7�w�g�]��"���f�h8�����&�>���[`��"���$�L�&���s�Rp-_D^j<�e@�{�M�}nE0�&���<T=����=�&rwn��������\d�G�D>���#���Z|yy�c�d@l"��N0w=pn��h�K�8fC�+
��Q�m���h�����1�`�\�|�0`�J���b����J��L��r��\�����e��V
0B�	��	�A�^���p��H�A
7����"��B�����(��#�p;
������E"e]�������s��8�����,��B��]��l
��:^F�zp����I����|��Zn��$�gG����tQQ~���x-�����3�#F��m��h8���L\�k�}��t����O�K�!*&���L��*0�����$������o\=^���k�c�k����{O��!o��,���5�a�
m����1B�,�Y��>���Y&f1���0b�
t���������A�,�f1�Wc~f�[�@f�p7�����X�������7z,o�k�i�jmt��jL�ly��D�31����cQ�I�3opeJ�Z�hQ��C�[���>�j�A,�h��xu��2���_~`����������������bekB�nQ�u�,�,�R��a�*ExL
,���?>6o>�3�E�k?`
��&�����q�3��37U��t6�Z���U����*M6'+E;%�[<Kw�=5���J���Z}OM*E	����T
�-gT)Jp�
���,}��w�[S��&d���s$�5�{���:u�h����Cx��GXlf'#��-UY���J��3�M���t"R�.u�����3�
�UA�+E����X�RT���<��EU@'�]�$���W�v�	n`�+0])�n�R����3SK��t�S���`S���R��3UK��Tt��^�Lp��	��=S�������������v�9/bD@*�Sg8{��!
�z&��q��0��^mt]C��E;��1�*I@�,��b��P�$p#�0�KZ0]-����G�^��(K��O0���N��E��������g�'�E�r��=�}�U�]��.4O�����#�gG������w�M���i7z�q���yR�"�w`��7�/�=�8b��<�F���7�D��8dA��I��Xsj�4xFj�c�9k�IO��b�������+�������}�1�7�xEO�(?)s.����"6���7�x�h�(?)s������_���/��b�(s�����LK���(pn�������2C��}jF�|�6�f4��?���mZ����j
Z�|���Q���/����5��X���JI���f4�Qm�6N�b1�37\����.?����2��$�1����LK;�����.3��[��z���L@{���Nj�P��WW����4�jX�F��Tm�����F�x�c������u������]�u������� �����*}���$���=�f��e��-�#_��S��e��S���Q�X����1�{��%���O]sCm��C���=����9�2�@�R��UT�c.9�����+Uf���h��$��K0B��)�N�� ���������"���eA��#��W����#��m,�������cV���LK/���������cZ4���3��`����N����iQb���.dmC=�����%bDmC��6�����,���:Q�0x&���
�V����eA�"Aq�����?����k[#R����m�����z�K"��o�B�T5�%3��	��~�[�q��@N}�g���	�*�r��(�,�����s�����;���6������4���?��W^�K�K�����g�/�U)	��/����W`�J;����Y��;�.@��R�x)�������b��q7���QYf�����F	jbe��+
z�L�,A�^"��@���E�&e�<0���"���^>���<;�)�5Et��)��cO���e6�!����N�����i�K�=�c���
E�S���+x�R�PVf�W�$���U�HI�p]I& �
�>K��x�|�����6O%��-�����o�tIf?J-���F�E_���fR�	��x�OT=��d�n��!wI&��5��O#R���*�t?�-�7U�i���*���Nb{l���Vm���$3>���a�����q������o�Q[��EM6eQ���[��}��:*��\��G�,��L@���
���eR�Ip|P�%I�YF%���Aq�5v�$�����?w�6##�!Zdvh9���C��|���57���!<���A����:*s����Lt����L��q�2s��J/0�t(V�����84`�d�L7�g2���e��1}@D��`N0� ��3'��_g�����2�
��`Y��t��Q�,�S�]	Gt+��%1)�:�(Z�)�.��\Y�F��/4�J�'���[n���:rsC�)�2��5H:+7��k�b��T�d6�kY�n��E�d���a�������lr������/� �T%��
�����74�u�H[ w-�S_��.�w0:%��.i9I�U&)�yD�+��!o���w�������m�{���_�<8B��,�/������,pCzp����Vj��;/D�{���U�!�r������x>3Mt
���}2�V�>U`�I�&���V��P�v�������mspD�P��A/���C�a�
�7��=uB���j����@�ym|C��;"��V��?�#:�m|C��;"�1��4��L�JTc� l�w���1�2{5fY}��k�
�aB��Y]�X�@�{m@��R���$<�?(����:|,�����c8�R���zt5���������HWc���G�Z�"-8�Em�������&>��6=6s-k�A�&���A��jY�B�,���
�R��u�}�Z�
���x���U����u�<��]�OP>!�dG�}�z�#��t��L��L��x<�K��!g-����]��]�}����e
 �)Y��g���5�UI�+�ljY	n����>��6/�eZ@f��E�b������!Fr���{�Z��m����v;�zSD*�
kY;�K�_{��	e�2��l��1D�����p�g
�3�������_��QD����`'��3O��L����{f�S���i�h9z���'Dx���mGQ����%bU��J9z������	�����dBD�F0������60Z�^{����h@����5\V��3)G����� �����������I9B�n/�S�^Lt����N��3)G�+
����W
e2 ��&��7�E"]�`�R�F"]�8I���0iwP)GosH'���������H��G���#�d-+���Q�Q=�����e-���Wt�L��<8@�f�N�l���#:�����gG����������_l�xp�������;�>��&:��w{
.�L+�Me��^,j��<V �TyN�ZV�c�yW���q}QU����16�h%a��;�LusJO~s�����LaS��;"�����k�t�s��=uB����9(S��jY�����M��T�z���2�����y�c	�+_�E��}�{����.T����f���G�s�W��lL�1���9e������[�r���Tc�N�x[���%V��|����Ex����4����MUc����d���uY��Vc~M�5
{|���{��"
K���"��N*fQ��(x|Ce����K�Pp-��~�,�1	��hK�j�Y�����A����Tc�f��~����jW�9~n��kDH������iu��y��k��������GY��2g5�����g��g�M�6������Z>���	:d��x���\\i@%��N���}<��$�����,|�[����g���2�N*Yxw2�����|�Ld����}�Z������;�0d2`_���P�>w=p�s�nh@�lh����p��C�Z��!5
���sW"�0�A��tL+��L0'8�.g%��b����:���DFeQ���"$@Gd�� ����E������pID_�]�pID�-����x."����DtF"��kK"N<"�Uc�����P��B���f�������{9>y�������N9�|D�{y����<8@\y9/JQQ~���x/�����3�#D^��RT4���g��n����Of:��`sS��2����-hV��V��<F��t��kb�
}�1���Bz�b�_�{O���nj����DGa3>����>C8���f1���������y���b�f1f�W���8�a�������=�d�:��l��Kb��!�S�e����)
�2��jN,�~PI g������!>�����S��G-�bzLC�n�jL����'����<
A���yB�~��������O��|��_���b(�CP�q_)�}xq���MU�f�A��������T��S�h-�Z5�y����D��C�C�j-b�+�*����4`S�x_���+�~Cu�Ff�V�v���{�=5�%D	�'�,�JQ��+�O�5�gT)Jp�e����m����J�B����= ��
������`� ��{4=���!<C�Q��*���qP1C0O@"u�7!���Rf6f�:����`���3�M�(3F��l���!:��
����z�7 N%
������J��3E��z�7!B��oc@�S�������L�`R����uzD�23��3SK�(3�)f�U��b�-3�=3����tQ���
H� �dz���	������������CP� �Ly"��������Km��bHP� �Ly"��UI+��rp�
0�/�D6�H���l
��_��
�s����T�.�DvJ3�2���#�d��gtcQ���DU�h�^�����v���G�%�e�c��yp���Y0_v��e��3�#��TV)�w^��� nh@��q9��8����Df��p/�w� .�Lk]���t^*I~��4�!�����6��R��i
�#o\��3�*E�/����4%m�2~�C��`�H��A����t��NR�t��tmMFk�?�!�uS0�h�|�+ECt6nX)���A�x,�]A�~S;/~,C�|�:e�{���+����SJpm;�����F�E�����h0�3��L�pU��J���^���3���j��vu��1���~��%�1���jL�%�����t�o�o��m��}�j�����(a�3�'���*��SC����Z�����
��N��o���;0����
@���G9�fTcg:%�B��,Tc������K�gR���7�@���z�����������i�js�F���=�H�%D�5����!<���A����h6f��u���ad~�g��$rY�Q��Wev9�����Y��/�@d~���e�TJ����x~�K"���Q�����\����~I�"������7 ��c<?�eCC���(Y���\GtS�hm����!D���9e����!:��74�_64�������n��������V"D���9e���H!:��74�gZ	��d���,r&V��nh@��!"f��3����Q�~�.���T�{�Hd����Hd�,Muz��2%����nt��D���`~�y�3D�8I�Q=���/S�Y��L-��&���gG���[%/�����sU���3�#F^��&cew_��7s����3����s��X��o���4��j��]��'����f�Z��q�&9Mx�5�-�5&v��xAf���2�������?����������&e���
t��0��1����@���O�@���������S}FNd��b�����<>�y�x�DGy�n"��z����_*���E�����(�O���u�����S���-��������xFo9��������Y����L��Y�Ix�{�o~����|�����U_o�����y"��4��7w����oo�K�������__�'��!W����?��?���7������Z�����������������W��?�����������~��_��?l����������&����(;��#���_��/������~y���O|��
?q�(�j�����;U����&8�d���JW[T��E��`H{dMVZ�~�XS hq���=x;���z���W?:x����@I���'�m�rQ��0BA���{x�[�!��qpc:��r�f��-^��o.+��^����7�^�G~s�9���U��m�6�4��7W��m���U�<�.n	^�������}t���=xM�����E��r�l�6�+�0Y^}M�&���e:ymItkx���=y-?������������%Y~s��i�J� o�Pt0+
�*�'����6u��I�<'���v�����������{�=������x��7����1��������M�s�'�9�Y��^�+�������]��o'ox��7��������}O�4�'�?n-m���q���=+ad:y�->k���Li��7�]��-���7�����s�=�'��~����
U���v>}������[e�L���0���6q�������M��[dYH�ex���mO���rmc�^Y<8y���<���7�"���������)#���r��Y�������]����W�����a�-��?{�Z�Og�~���)J����[83Z���i�2�����mXt���[����e�����-cY�*?(<y��X��=y������k�l�R����k�7�[jhp6�.�';�9y�,py����e��Y�MK�?y�
YN�y��f�OL��������������k��	���s�6�v&�>r����ea������=�dy���������Q�������M|������'hO����^��9zo[����.�%z�����!�>z#c�>�u�z#rA������3���������z�d�<{o[��L�0�������j�ed�gof45)�w��S��Y��o`#�A!����9������I��R�<�o��.R;]�m=��0����������d��o�[�����Lg9VI�p���M=|��B�J.4{��y+-�1+py����e�����M��?{�JZ��d��o�J����fI���o�_����'�l�����uN��EEt[��{������#?(<z�Y���e-;�F�q��K����n��{�b0M���Nt��Yg�se;��e���&�Vn9]�h)g�(�W�oM������������31����g�#1�`$�}������[�H-g������w���������iY���1�yw�u�k�N�&����F��Z��P%hSg���zeO����{�����������_��U-+7M��N$���^g��jUVM���i��r���MM�rn�[���-��v��6��8�:����_���-�8�7����,�~�����Fnl�;{Z/}��7�������/���ZI�����)���c�������(�W�oi�:��SZ�T�.���`���M(��+�m��B�nQF��'Cg:{�Htm���m�oe������=����[���t����,�~��m�n��s.�^7��[�v:���2��N��E����V���
������������;-�����
�u;���I��
�[��E����I�!���������{��V�����)��-m�*�,�����x��G�B���}��4���U3����|��|����"Ue����o5�����p���oe�� 	+?:�y�={�\��AY��M����[5@�������D�Y�m�����l�S9�G=�����l]�����u�>"���n]���9�^5@����:���z�l]d,g���-[��������T�[��
-�6u���S
��7��&��6�KO����3��N���Y�me�62���9�G�-��V�lS����-�gobL5�K���*��2�����9���������<|o�]��rK~Px�e���-m�:v��I��������*A��\��qB��(�n��	��'n�	���f�7N���G���}+[6�����j�<�2!�u���qB���g��P���qB��X�mv}���->!�~�]����e���Mh7�����sy�^��:5�����eCpJ��uN��%Z.���&���������(�^�oe�^-�����*=�.�����#p��7�����p�m�]w~��z$�HYY�������,?(<|�����V�������_W'��8|-��7q��-����m��9��wN
�c���������'6���[��sT���
���DB���weV������qV���
�����������m�;g��Y������[��sX���w;9-pW���l�H�N��v�+�E�:�����*����Q��~���}�c7��:+�D�>#�*p���}��@A�0]:����qX���m�}���=>,�y�a����e���]�Xz�3��+����;������p���9-p�Ml�vx��i�{|Z`�hxD���-;����@�1�;����@����NE@�|������GJ��w�n����������=�n����e+���1}{�g�gy�>�-W��[F-i���*	.���T�����������k���V��|����?~9we����}���UY�?�<���F�ah���~�O�mz���>��:�?7����?!2|���?���V7�8�x���{��r��t6��k�^��-�@7]��W�gP-�>�l���t�zUz;�����x�����l9���V��������u�����;������KO!n���=~}��KO����3���>R�n�����.}u���������i���j���!��;�'o�H~H���o��8>c�X��V����t��h���R�����&�BE�|��>�����e��5��N�\��L@�@����jY�n{�f�:st��J����[f�Bmk��z�t;�-�R^u`H_s�7�(�U_&7��T�,T�=y+��5Z���N����}�6�s�V�����mi����i{�v:t{����������)S��R�=y���c�V�?*R?���|������>M���s����M�+��fY�������'�,g��m���Q7=ze�9#}�A��+���h��>{����.Q/{;����Y�5�U�H{���p�m*����f%��Jm�u���Z���G%�'z���^��l���t�K�X�drG�&�=g��l�P�ZJ�y���������P�={?�v���G�'Z���^_�'v����;�2�7q���Y�`�	.�p����C����h�|�r��n?(<{��h��>|#���n��U.9��B��}�I8X R	�T��w�7�gc��������]N�m�kY�����[����]��-3c�YYg��`(g�us:-Z���B�j����j�ra�����?\n���,�J�nQ���,�;x�VdWn��~�i{�V�u�RI�]�Yn���:��m��Fy���/nX{���r�c��g�Vj�S���/@�+�]�\F]���f�:=F(OHU�Z����#��iHU@�����HD��?d8����nS`��r�������oQ�Q���ka[8T��oU�SP����y��:87q�>n������rY�LN�$XUE|��!��W�����s�p��m����k���wQfM"�D�
��npS��sC�B7���w1:�U-�m�"�����l��s������r������O��[,r�bi�
n�~�w��V���U]�+e:=}�>�-b�L5>=��>�0�0�zf}������:���\
�n�{4)WX[uC�8��r52�#�
l�:��o��9F<N����?��������L�o��NY]�z�3#�)��`����]������]�����2��N���G�g������!��,gK'(2����7�I����C��H�?��N��D��;�/+��u����KFlK�����k�R���!K7��q.+���%p��&�t��U����w`��U�[����l��l`�6�Ji��+g�f�V����WmmW"���>.�yu9\9�o���%>M�I��\j����RY�X9+0u��f��������v5�,��J�87���Lt����G��H�F�J�fG�*�{KB�`}�����HF� ��h���U����D��G��g�B����7����N�5'��9��n�a������l��V��X����*�7�mtk�^A]����|R[�XMD�1MY<#	sr�_���5j��H�xs���{`\�L�<�v'aNF����%�jt
��F'�����	ls��6N�3�0�'����n7�0G��q��V�]�,��r~J�j'0����s��X�7��I"����2
����c���xw�S`����'p���F!��2(=���2����(��H]�6����@t�9�Q	�GZ�[��{���?����ck0uff�j�I�'Bg^�f=F����0n��f���OB�����Yt7I����Xp���N`�^���T�(�x�~
*�2C�~���N�8����`�sA�,��2��<��������<�,��O���9s�8��,p��
����aE��R�V;���a�b"��eQA�T@�D�<���"T���<�,�J���`�4L'���
+��J�*�n�[�@p�er����e-7���n?}+���V0�����F�M[{��-a���5F��1�q�z�+^[����aJK	\����P��D��5�G��)��OiPI��k�%�������=��Bp�����0eG��.�+hy�+(G���������0e��)
:)�'4��y����r��a��1J��"��Y�Hp@�V����Y���&d����B.COGfc"^'��tGfFc�\�x$��
�3�5t~�H'p��f*�.�:rt�P�<���J��Y����=�R�>��w<�	����u������	{&igc3��/�.��,����i�����������Mj
�SX�>�U6�I�z�I�!S������&�)���'p5t�;b��#��������U�[�<���7���|��iL��:���`�p���s��=�$���L�S���6������+�K�<��������IY4���`�bDU��W���7��&��`����%n��8�Tm
&5��8�Tm&5���w�b�@�*k.����������o��#��':�����j�?�~}mV-�?��umn��;21� �F���L��Vu��u��y�E�����.qCL��S���������k����S��z������{�*c���S'a�w�2�N�&uF�8�����������I��y������1���N�1��q���c���D�d�sp?���c&=������rfJ��9	3�_�����Vf�PR�����F9�I������=7E���d�L�:�\�x����	\���I�:C7�<�����0;����:��zW�3�0DH��|��U�W!�"A���}�0���ZDW�]Gt���o����[Wx-�
pu1�G��6x'�6��;�|~�k��J�M�a�����98_y���W���>��G�ob]�|�>���O���>����}������?�?�+O����������G(��iUJ��XY�Xc(nDu�����`Y��|����:�sW����_}}w���~�q�����o?}�����/���7������=������������G����_~�����������v�#:���~���~�����������(�#jZ;�7�a��y`����C�h��y���!�{������l����K��/������*���������a�����a��D�^�C�:n_p��m�������Z��7������g����>����6Ua����*����L�LU�n���T���C
+V ���x�&����^����
W\
]�^��+��_�_������a3q������c��.�����X���#?n�n�-���O��k��"P������8~yX�����K��V�/�����{K��O����H�DZ����E:�=Li��9��P��<��B6��H�x3
��.���d*}����������s6
}Lm=����`�:���<p��iP��GZ������va`K'��������q;�9�vw�4}Lg:]�N����.��30M��Os�����L���{{:�N/�i��������)h�F��7Pn����s��7�}{��#�`�1�����f&p�]���m���w��8�x��kc�Y�8uDg�a��D:��Dt[{����a+�<��7s0�[�����l�;���p����`�$(yY����)�Hp����R�8����l%�GZ��;h��
���9�����
�����m#h���
�rY���`b���(�n�X8���Xi}o��yJ���[�j>�n�M���u��
����%n�W;���`��C��8���������
�#���U�����.qL[!C+h5��
���c*+E��
�����<�N��5���H�x+	S��%o�<�r�%a�v���mi��d��m���1��z�$�l1z p9t�$L���l��x{��a�n�S��x.	�v�������!`_��H���H�������Bz�L�6wy������9rL;L|J���L���9�
�D}j��vd���V;��`���c�7���S0#S\�����-�Gn�i��O�����R0~�o�o�K�]��G>A��?����qH�� R��8���y�������]0]��)�[T�8�qJJ�*�/1�F���������]0��.���0]�S�������9rLW��K[9�'�:�I	��� �.������{��9)��X8�9�vns����9rLW��8}�c��8��������E�^�o[0.	D^;<
�������������G~+�{G�����o��'���Z�V���<�f�w
����[5�����5�~�fZ��X�#w
����F��c]]���g��7j�]�=Y}��Q2��
��_�����w��U_�eLi}�nnl=r�P��|J���L��8
�>A{��U������_�����~�bZ8c��b�oWL���Z��3��b��*X���e�g��7*�:��;������*�z�/���������������������V���e�x�3��W�3V��t���Z�R_@��B�j0q�P?�b3n.W�X�#����,��2V��-C�4�)���:��V?#�-h����f*p���g�g�����VG���f�o�L���#�
���F��N�34�f:5��s[���Y4M�44�h:lM��`M�U��������������!��BN�pZK��*N�p���HtF�T�yE:�.#��]����0I(���^�f����_Y�!���:q��P"-h���8:���\��%�*�rcUdu�<�@Jy������9���>��*�NL�3����
}��4hX�5��"�
���}��O?�����?���5�������::���?����>]�����9?��{��_d�/��_�����e����|��������?����?~���?�������_�k�|������<��?���_�|����gU�������?������������������?����\����������������/�������*������������������F{���������]�(��������?��z-���	N���,\�W_������.���R*������K!���C�<���+�,����k�K�������G���G(�����|���|�S�x��|��<����������+-����v�������W/S~�N������O�O^]���%��_���%����6�?�~����8�~��_^=oq�E�/��_��Q\?`q��E�����������G(�k��5�.���Fw}����]��W��W�Jy���m�.��/_��W�/u}�����������rW?��[������/�,�����Ywi�N?���+���k���W���d���]K���;�����
��^N_]���z�+��~K����$�HV���B/�U#���F���;���%C��Akd?jS��f�G�����y�jK��T�����6A+��}��v��V���{�&��������|9y2������)��Jy,�Te����*7�����s�%�<w_� w�V7y�M��Q��������?&t<ANy$���WV�ZE)��pyT��Jy����
J��q-����ke�(������t�\�6U4E%�Pi��Ky���Hc
XW����J+pp6�5>i��=�<EW:���[
��~_U�����x��@o(p}�Fy�jt�����w'/w��JGM[��|*��+Ot�;��)Y��|@��5���/���a�����������0>+fq&]_��
\.��p�_Mm���ox��W�j��F�v2v��_�?t�XaC�����vn�	�wo���X CzMF��}�|{���NQ +���g�8��8-]���o�X�xG��*�+�q��<M�-�����CO�u�)-�(�1������t:��>�Iz�)vt��<���V G���Q��<9�tr�����^o������{�b�Jz���1U��4�%��������s��4���V +�����idc����y��r�Oo�L-�	}�v-�A���x�����<�m�S~3S����/b04�"J0+�v��t����k�=1Z�����q^���B&��X����c�C�}���o���Q���b�9������A���R*h��{^�1��fE~�����Z*h��{^�1s��`�wx_�������{^�1�gc�4���]A�1 �=/��Y���p�m^���������)>��D�~�#��mv-��EsE�W��k�m_E�Wm���y��\��U���t�_M�Wm���yq�\������6�m_�m��w�
m_���}�3*��T���6�����]W�r����_��Ou^���>1(j+��`UM\��[����E~O�:d$��V�X~n���,�u���y�z�Z:�����y��zR�1.V=�_�YH-�
4�n�R_�Z�a���'FE#��`�'�R�Z|O���8:���KUN4~+��w����o���t��/��%?Z�i���'�E3���[���c����������o��_�:%���-������B���/��]2��e��=/�X2�?��

�����]��y���W��1t���)��O������c)`��1b�����k�=/�X
�?�|�v������+�},����/��o����]��y��R��Cg��oI�Wn���y��R����F���#���]��y��R��$��r<�W��U���y��R�����K}}�i��m����cih�j�����qO��]����GK�glL��_ZZ�v��=1�hi�Z��%N�,�_�m��|p�L0�l���=AV>1��i����u�����7�_���c���u��R����i��'����[�2u�j��6�_���c��u����i��M�W=1��h�F��%�&��i��=1��i�&����s3���m��|���n�\��	��Z~O>���(����,����{Z��dYC���/��;���9�]��i�����g���M�<8�k ���"���'D��sZ����_�(�eK~������+8�����	�����=-�X2�P|��2�����4����%+i��n�����8��r���O?N�h�J����_E�Wn����'�4�n��',����{Z��d5�_e�������o��O����c�����i��'p����{b����5�������{b�������/��ki��m�������ku�W�M�����u���yb����u���S���������������_��o���7�_���c��t�W�M�����
���yb�1��
��K.���o��O�?&���������o��O�?&��I�u���%�i��m����c���
��:��i��m����c���
��:�Xh��m����#�h���%������]��y�G���	f��/����s�o�����?��O0+�K���s�?A�������h(?��5i�'O�`��Z~��?r�'��%������m���y����D��%�?����m����yI�W�/q�������{^��W��a��yE�Wm����yM�W�/q�������{^�����a��yC�Wo��'�
�_c����GC��l��'�-�_���6�����k7�_������ku����?w���Zw����y�+C��N��m�3��v�6pWV|=M`���6���	�7M��$��Z�����o0-��iw a�7��Vm]0��6�#
�����D�������R�&��q���y��h�&��u��m��]�x��f��I�}]���L�7oG���B�7�/��]h��M��+�,>����}�=o�U�i��-A*�"���w���/q���������������[�/���u���"� �7�k�=/�(����T��&�,:���?�o
bX�,��y���\8X@��������:��Y��sQ��m����t$ ��Xd�%�@%m`�m��m`i���W���
��m��B���
�,��]�����
|^R����eS_���z�>/)��������
m`�i��D+��6��l`��tK�n��}K�
��
l
�����h�M�o-b`�v�
L��=m`�i�-F+��6�7l`b
���~�>1h{���,��a�>1i���DF��q�>1iG���D&��q�>1�h'���D&��i�>1�i'���Df��y�>1Yhg���D��e��[CX����eG".�
\6m��E�A�2�@��0�*��@����"���a�����a�Z���D\(�5&�D\(p�|^$�
�@��	0q$�\Nn���E"��:�&�D��
t�6�y��+i�eG"��
,�m��"W���
L���6������D\EXY60q$�j��j�>/q5m`m������i�M�o%aX6���eSG"
m`�i��$+��6�1l��d�W�qm`�i�-%,@��
�m�x�����������8W~%6�.��>:g�����_�RdE���������"�~QU�R��)x~���6CT��*�B���MQ��;�9	�7'���?��j@8�;T���VZ���MK��D��Q;��������1��X|�����|�G_�]{���1��HS���[,c�)����V�"���!���fE~����|��]�/e�F����2����+���^��o�cX�M�++��q(z�o�Uy��*��sf�Y�_�l����������`�������0+��O�yS&8I	��7��t!mpS�C����ST�SQ�J>�MB��]��-�F
_�11�����R������xU���(�'�2�5�k�����X0?+������q�h�a����\�����`��Z~)�!@,*��&���E��\��MSFC���<���h���w,�g��-�,?�Kc&/���������/e4D�5�Wf�����k������)?�n�X��)���������J����Y���?�N�������a�G���(��cD������&�Y����)(��8�kP��k�=1�hP�����(�)����6�1�6J��_�j�`V��Cp������t����1��	�!A��������N����G�g������(V~=���������~3���Q2��������+?��f��o�dX���?VK�.6���G��f��o�d`�1���#�FO�q���c��Q2��������?����j��Y������c�����v
������?V���#��]�������a��0�X��#y�ea��l��6J�_�1�X��#u�������T���1��*w��f7����a���L0��\���k�=/���**�����H*Zm����(X~�T�hr��������(V~��Y�?R�?���k�=/��������m���_��A�����������Y�����j{�s�F���C���f?�w�\�Q~���}%���F�O0+�7������k�=1�hr�O�������_����]����G���`��_��t��ks�o3��o�dX����	fE~��/U����]�����A�r~��{
�����8������`e���>�����A�m�+>N�V�4h���a�j{�{b��a��M->��V�������V�,h���Y�j{�{b��Y���
���W~��m��vO�>8Z���v2y������,h�������1����,h�=�=1��,he������f��{b��0������S���f��{^�Qg��.z�/���!�{�����EX!��*�5!&N�yN!��*����/�EU �����A�s$���>�y�+J�O��A(F|�KA�&�x����Y����C	TA���{���c����`����2��>�k&��+����BSf	4(���8�2��Q�9��+�����������^��Ji�F�s jY���(T�+��B�|%@S
�����]Q����q����+2-�uE�L�z���n�W������_��L����e��V��<��G5_0���~�o����;����?���_�E�E�������������o�}l���'����z��!4�MS�������?�������?�����>}���w���1�����}/eTe��|�Qj<
o�+��}g./*�x�iFk�T5E�=
}kP��}������v�����N�@/�V�8t]�y�~�����>L�-WP
b�����_�������������?}(\��_���a.���&�
�)u��n�8�:(���������w��wo��-�g�C^�z�6�j�@������O?~��O��������,���\�h�(����f�q�Q/���Z�</�G�
%<x��w��"yZ�J��P7f�mZ��"b�uO�+�H��3DD�t����/�!"<Z���4D�7����h��[��o{�O��Y����3D���<��"5�f�1fk������qO��+��]Sy��!�'p5Cd�c���uYF�y&����z#*�\+6�\����y0C�\�'��W@���*r����� �"�c�F��+��U��g�0�!":�W3D�0��\A�����tYLCT�o�j��J������)w���>��P��+�Jg-�3r�a�
nD���d�C�������s#Za��H����
e�V�p#�VD������^�Qx�7�.����ZQ�2D9�����r�b�6�� B46	�6DE&�����O������d6�n��u�S7:�+����@�}�o,xa�aZV��4Du��.j��n���p���2���Z�&�`�g���f��v�`�������Y�� �����(hb����n�����@��]O^$��"^CDxPt��d�����V��T�P�-��~��$��)
 r5H�bO��l�R�j9�O�V(Cp���Ef����X��&�Cd�d������/�!"����nD���QsD��!*��V\��eM�nOY�4D�X#�*�5Cd?arD�G_T�9V3���Bp~���X4�x��@����L��!���1D������0DE�EMVW��|Ox��N���)�^����-�D���h���V�<�������O�������l���V�X"���c����Ik�Y"�#�B��`[��,�^���S^�<�5�������������lE�pi��5Y�w"���gg���=�%"V^�VN.,Q���:��	\�E��^���w���}�D][D�$��_��Uq��9d<�o�{G>�F����f��3GQE�+#�zR���o�8)>��������UJ�z&���-�E7\}[��Z�Ys+t8+W�E;���e�2�w��I�9��!D�K8�)fP�n����!.��=��;P#�����b2n+��K*���s3{	���KX�O�����~��y�������b�����f�?���o�=��7�q���s����oxgz��3�({���*U&���uyC����)���{p}9�Cc��n�*����Yv��u]��jA�d'�G�/�=��R�
bw���M���]����<�~��1�:[��]mnJ�� �99y��Rm"��z^;��y�#��z��~���S���7��y�c*�t�)��J>n���>"43S��5��\�o������/��i���9�S�9�(����k0v���,P�pc�Q'�7����5�����T+r��1ku���d"�e�f�j�S<;
�Gd�g�S�*�`>�)^P���En���!���>��G;�,a����1�=\�'��sw_8��C8�-3(Z��\8��{����q=�:���I��d�/�`V��~��'�+���m{;�\<f����� ��X�u&��6�	t�����v���9�l��wNE�9��#D��:�).1S,h�-	=)�Hl�q��Z���z� �!&+�������w�C]r�����*HR#���A/���_Q���c��s��Y�Nz�p�uR�+p�����W�0�yZ��	�8!���	�g
J��Q��^O/�=��{�I&+x��3�s�����d�S��!A�*���<�X"��z���?L�������?�)�����;����N���c�n��)<�����=7GdM�cLn�;Y�E�c<�b\�>x��<as;����#k����]��Ie�^�����y�����:���mn��l�'wr~���B"f�f4G#��\���T�M�Q�q����7A]�4�q]
�4^�W�>��B�4�Q���RW4if�1M�����I���	
��77�'�2��������W�W
��<&(����~;�����������~�� W���&o���~�A��<�/H��6�m�V	�E�(�E�T��'��g
��P0���Os2�9v:nBajf
�h���P��:�R�H����UF������o�C�]�nh�x����X
^O��yXMw�<���o����5���V\�{O�,���v0u���<���~1��P
��j��H(*xv��w��:���R_�Ns7v�m��vq��$��]Y�g��f�`5�u�[���b���.�i���:������u��U�������C�WC5��4����7_
��j|�������_
m���0��x<�f����@��;�P�oO����	
<�����W�R��8u����F�	�L�k�����!h��u�;uk�!�!��=�}�X�"�z��j���WKO[�&�c����6*�1&��dt��>�s�p�bz�Z|���	GC������ �x�sJR�=�sB���hV�P�>����H����8<�
����I�O�X�h���V� ����Z���m��g�C/pb���I�,.�:���v���8�������C>��<*��t��W���d���
t� 8��1�q����?�1�R*���\�������F���t�������C��I�������U �mU�G���V�gcy��F��H�o����ea�C����a 6��0��7���X������H%;_L��,����+�������hUF�X�{��?F
Ax�������_�u���RC�I+0q���?%71�kI@+3U�k3���T�<�7cKc�+$�-������*b�-h1V�D�*_��9Y����f���e�z�����%�Q�R�%G�^�*�8�H��[��/9���?�)^����=In�N4Rx��.x��P5R��"����+���
�S��f�k���T[Olz�}�/��9RQ�����%����{s���WH/���ey���
4MAx�e�g��9�q=MFxL�	\Ex��4��a�������%<OS�Dgl�{����j},������]���@u)bE;���M2���j��-np������&�9P����C���`��h�9/V����0��5���/,���G�#)��c1f�skO^$E/^����A%��ts]�����Z���y�G�r���b2����;}�Y��~� �������y�k�OE��V�e� ��
���0zce���+~���0�{_Y9���u�r���`^�HD�������l������
�k>�w��}Z��P�k�>&�@��7B��q�����)H�~��3�Fx<�
K�����3o���U#��*����!�������l���5q�;�{��h��������v���l(�M��A�ewkF�����w����A^
�YKn��i�
�^gd���������Pz�%�OV�����dmz|���t�,eO��}������+9Y������+�>6�[]�`�[~�5��_�j{
�I6��g�n�{���Q���poL�zjA������l=%�=1N4��X�[��#8��&�[&zS���(�E��[�aot�:�y6Z�����G��o��x��c���������!�1���=���El8���8��X�s���yFI����b�u���(���T��N�[t��(`,rb�c���g��*�+��L��(b��Xm��:���PMQD���}SxJS������u����eY���o�>q����rDg	�h�#��Q�w���,�i�"�����'��	������4E]tu~�{L�����=��S/���<�3NF�
ML}��AbE�?����_X��s��mg���n
�@�o��mnt�39����X�o���H��2
�@�o��p��~Kn�;:�����
�Ex�,�oMQ�uST�GW��7�W��z��U[���3]7
.h8��;f����F!8�G��jd���Bp�.�7fI��&��V���,x����:�o7���+�b��������k:)JK�-�a5]��
^M������(���N��NmE�j��7@�&��������C<WPz��.+<������!�[m��N���<�Wf��G�M�{F����%���3���U�	#�3�����3�X/Os���oy�aa�u��Q����g��y��0���y��6����O
j@�'@�jC']
�
�u�������j���x�ntk]�^7�`3��>�(r��6������+L��x!l����?a�q�a����[���=�� ��I����z4���zz��@�bEmD������Q)�3�PPx����<��� yR��(�u�x*�����7�
��Cl�&������)��6����x��?uc�����������Q��
���ZS��"�i����~Hrgd��o�9���,�F�@tF�5��fdg�&<^�^(�+�nf��S��������H+�����K�7o)Og����
oA��Y+���y��
^Mx�x�<m�Bw�����u.b��*��������+3�{�!$����u������O��s�3���/Gf����W��<��@t�i������v��q��)��i��y{��	/X��+�����}nZ�(�s���3��p;�U�t��q�7��2q�Q�4*Ng��M�Ex%���&��FYvDg���9��f�3����FYD���|��*Z�JozqMV�
DgdU�sEx5�JedU,��(���U�6�*���#<^Uj��bOEy�j^U���>.��Gx�U����"<vf\Mx�SRe3�9�;�����,���6���W^��Sx������A�����(�\{������J���������8��U��
@��m�yn��	/u������
�g�W�^�*��cGx4*�qU1UEx�*�uUIa��V�E�7o�Ue0�*yl�����`\U�od4W��,��w�f��#������g�Y�:Q�7�4 3��"<�L�����ah�VD���
���#�d9]R������iT��%V�[f����q�n��y�������g�
�[xo���*z�/Y�[L�15V�:�����k���U}����t0EW��^Q���oPEW�����w���Q49;�La&<��sT��������&:8��XX����X�3����=���������%�(�.�X*cqu�%7�<��=���~ �E���#::�� K~�I~P]�M�eNQ����M�(��&W�uK��������p�^(J=��R5V������0X�=KU�DW��xE����]M�b������kz��8�����(�E��k
t
Km41���
=Ks RfbE��W�:3V���j�������+��g���8��I�!�E���U��V���N��:z�����)����W�<3���t��<�fw��=��{��*�W�K���Xz��V$����,�a�����(��K��X��0}=���aO��(J=���g�F:����2�2FR�H�2��=�SAQZL���6�a2&]�E���4���2ynl�k16����"F��L�2W�=��*�5M'O�-�-���<��
���\w�3��#P�k�N��3jz1Z���X�uM�Cj�&����4�:=V�Eii:u0]��F�cj��*�������\ ���"�v:��5�.�Zh����v'GM/����b1��iR��cj�a���B�z`M;:g������%��;�"Bb�D���� E�%�Ky�HdMWt.��6+x
�=��(���\*c���I�t.U�3M�Oj"��k:��#�X��h��s����irx�{RQ4����$�3'5I<�15��������-�K���X
Mxt.m}�3�e�����h��s��m��,��;:��<���f���}�Q4���t��EG�=�K�{�{���L��}K�����f�l'<�����\lo�����kxq
���� hW�'2L���u���2����-s�����7��`��M"pW,�(@���=orQ�Z@�O_�����]R��&~Rl9�X���E�-�h�������� ��H
�p���]- ��`��*����E�]�:@�������;�`�?�G���nCt�]_��J���p�%���{�?*:���gBS�>h�
����7��zJx��J�LW\3Mt�s��s\�"@�m������	����v����}�NW�	��t�pl���-�!c��El)��`�{.=/���:�V.��v�j�����z[�ZU�3�;��wK���U� T�k��(��U���Io������0�F���"=�3��F�|	�;(��n���I����B������8��JJ�`R��0�H�Wj����Kztq�M����#��.n2��{X�������E�IzHw^������w�������a������MH.<�&���G�=Fso�5��ZxC�Sx��[���TxC��W�Fx��\Mx���!�)<k5Pj����3���=>��r���0�CS��U�5������5�\x�����M� c(P<�����)<�n���1�W�j�=����/M'���@16\�W���~�o����;���/�������������/?~�_�~��p���W>��3������?}����q����f�~�x
�����������Y��s~�w��~�U������i������������?_������w�>���?}�R��?g.��?7�����[]������u���?����?��/�_����c-?��#��~��B�O�O��QgK���m�U�����*��l�^^:Yy����� =�p��j�"���2X�/�z(��+��~����� '?�H�D��G0/�F��YkS
������'�
��&;_��){xV���z��X��dr/(*��-wxb��!����$}��t���d��~
3.��>~�Y�V�+A�=��1l0
X��1���U_�����?V�'���q�����Lz�4�1�xN&���,�nX���1v6����xD�/��1^]z��c����bD�u�sg�`T�rG}��Fp�'��*cM�+������[G���
t��F��72'Wr~K_5o�������L�~+x���-���nA5��
Dg�x��L�U�	^Mx��\{��B�W�Gx=���Mx1�<����9�5�Y��G�Ye� ��W�hTj�m� ���!x5���r���5�#����-x�����#:�m��"	R��	/��k?��S|4:�� ��sc�_J�Uv�kx�n$����#�wR�`&N�;vh��Z�#:��
t�15�g���k��F�t�+jo�!��gk��7������J��[�i<�a�jz������et��<$<�15����4����8�1Z�F�)��9�1��a�]ae�b�����o�s�H���:��G�2��w�'�i:u1b��\&������f:��8��+��:	xM��)�V��\f���g8.��:��8��+���-Fc.��iVQ�dTA5=et.�qWX��#��OO����4�16���
�B�}8���2��k�#��T���fO�sSn����<�_���������-pd�	+�	):��?p
CsBt\�%pW������b7��#-��dn&8�`g�AsBp�o�1�{?�V�>���Cl�����.��[����^�����5=�^ �5MG�W_���`����0�����^�(=�Z}`}�X�>p������V�p���TEy��(3e�
=UQ�o��Un73�E���8��TEQ���c`��F��y����C�@��.�n>y�_������a�:�0��)p��/�����i�;���"(��������S>�����������I��S]-�@m��i�*�Jc��
2g�� �ebe�l4����<��:2{
\�u;���0�!q6oS{>����1���A�q���l�D�X����G�m��+�cg�=3�1frm^���r��"<������Y�a ��[�����pm�0��9��:���lf�����yo�
���W�q�9�����)#K
>AG�%P�-���s68��u[3�t���w$\�o�}18����(���Yf���[2�S
>g�� ��|W^�I*��	Ozp�{��Dg�5��R�1��|��m���o���O�Hx�$�	/�H���o��Z�����@$�X�|E�F}���)��`6L��-��q�F�+)J�n��7������X�vH�
�cj�t��	��7�}Ki�������8K����)J���o�'<:������L�h��s���4�X���4n�.~�>���������A�k��s���4z��qKmt����������wx����si���k�u
��wK��X[�=���o�K��5�,�����F�@����[���gCu_A��E���o_�����x����:�{��`�D�mg��g��o�t�R��}]�%����i�&����B��}��f��u���Y�(H���JjK%<�ROhf�q��m�!�R�|F�6�V%�uY+sG�UMW���G��	o��*�['������vh�n~�}��jH��� el��[(��m�>�Rv�����z��O�Q�7�`��&������w]W�~������VbK�R�\�*����SZ��d-�x�.�S���|����%�Sj/g�'�I��zS�3B��{^�:���������	��^��Z�	���@�x`�;��5�}��s���d������%��o��&�������&�Y�����������Gi��)'��j+���W�?���d�r���Z�Xi�&<��&�=kVB�d�L�2�=����pKp��E��/LK6�1���BzAwgKvY�I�,oI������+����\	[�od|������3��y�s�l������|��,^ �\?��b�hk;?�����2�	$<�������p������� o�s\�LxA�����f�3���!���>%�LxQ�7�QeNlKZg�2i��`�V^�C�[����c��^k��,���%M�jt�2>���x����A�X[��2:(]���� ������3<(�x�����(k������Mx�-��lg�/G�4V���S�
���~�����Mxt.����=���\������(��lz?�����}`���?��s��ws��W^��=��
���+�	��d��u����k�E��iU�#�����+�"G�U��s�O`���	Awpq��3���������&@=�E��)-�or��#+��Ugh��x�r��6A�~�@�[��
a=}����8����s��\��]��>46�zx�������p���%����&� =��C��������m�bQ&x��M$<��4�0
��4L/�A�e�hz��kgj��[����_��a�m���>}\y��=uZ�������j��S�;�����M��W�����mU(�H��;����v�����Gi��<����)=#�nnk��
x�Qz����{�l���]���d]����OA��>R�f�l����g���im1cW2cW��#�YS��W��zU�m�E��
�O����l�_��S{_����5�`�Y}D�>����7���Q����N�]���8+���}���6l�C�\^T'�b�*+�u������Q���nto]�1V�6l�k��W�	A�3O�3�^����q��Ni���ei���	�n�+{����4�����tg�;�����m�����{�PT�6l�xTz�{�J��k��T�����A�x>L6�1�`mb���v�aW�[�a����F�����|FS3��0 ��s����6\�*�������n":�k�4�q���F��,�3uCx������	�O�|;^�-Dg����������Ve��\����Xe�
�C���@����_�x��^��g�$<\�\YRqM��"�5M{��4K(�UB��
�qM��R]�P���#��UO)�O��BQ�S�������v%���L�]M�k����Jxt.����~�4]������k��j�0~��jUiD�>��65^E�rA�v��\_55��\�E��|�A�R�
G;��m|�89B4��������x�����lQ�6> ����JR�����4	�;�i�#8�
V�qc�y� 
�A+i�_��Y�)�V�}m|U#���\��/x�X$Rk��(���������:�(����7�G������N���g,����L�&����������J���P]q�7Sz����{�R�t��������S|D(V��������W[��������bH�!��~�����Q���d]qx
r��� ��U��}]q�zP�iZ<z������'e;
0V
1�I�n(��������
p�
�gu��$�A�b��
&	3�&?Ct�W�Da�����<�f������'��u��M�� ���	N�%�+�����k'U�^���
��r�����_}}���o��	����������o?��O��O�������?����������������y��_�(�q����h���WL���7���7���n?cP����#�����		a����8T#!@���1�����]������pc4�Do$���f���2�����{k�y��6�A�w�.��h$X�������Dx(j^�#)��y�c�'p5�Y��Q�W�a�5�G9S�Q�7��"�^x�Q|��	//��Z��}3���8��e�+x�+"	o!:�S&�����g���������N�#o"<��8�^��������`���A�E�+@����2/W�2����6��RxVtK_����{XE�HE\M���+z��2xV4g<��h��{XEs����&)�������j/�:��hNy
xE�
a�!�v5���*�����\�wM�CNQ��D>�a=��?�g@`E�,��w��fd���V$��G:�����2!<z��@����[�D�2sc�"�`���G�2}x��~�����d�r���d��YY5+��n�`?�5��b�w2���/H?:��J-pW���a����R#A����*h����=�:�B����k��*����RB�b�������}�V��Jo��u�V6����X����M������4}�'��~t�#����##Gz����L������j������ny��[^[���	��Z�]z^?n<������1[^��W�{vT���8I�9I�k%�(�`|��W�S���d��x�1�<���X�������m��&]=M�����s��I�/G�>��Y
�!v���!�J�����t_���b4�b@��m�J55v2b��� +<�l�^�C%�[�����V��9�l������x�Mc�y������|
p}V\���aOq��G���2��Vk���;�N�v#1��%e���_��� I�$��Fb#��H��������%��o�N�����q�Z=�;;���Mto�.&�����B��Nb��V�4j�$O���<\�������jGtF�����������������0���'�9�����Lx1��	���Nl\�{c+�3��q�-��a��� <��u��a��-R��Wh���(y�!�=����f~�0���f�����e����N�7�XcE���Q����Vt�[Lw���GS��W�<*��Xzk8j'
���r
o:��P���	")z�c�9��YW�H�2g�a�)9�(:z��
�hm��>���G�2�*�O���z�U���D�2s���P=�+x�,��g��������������FVu�Y�����L�#	�C���l��8�-��#Y��W�q��w%@����Hz��	P7"a�LW��w��$���t�.SB��c#���� ]�+p���;���2]�C�u��F:�33	x-�d�� �s+x<�F�Tx\[�2]�C�W����X�7P�k����~����X���A�LW�po��NE���Szz��n�e���\���n����}U��e���]�r��[�}�YX���*����e���6�o������R]3r���K��N����~R���']=/�G�n�tMU��O�����~���g���.���h�GR�	h%��Z6�����L�X7����@p�qRt��#��� �'n�J�j��������w}�}�:�EC�'w�S���n�V��^�	�O
pM"cqN�V\&�AN1	-��O�"����B�m7{��P��Y��w�Yta�I�B�X�*��E��'%8�����W���~��~]W�]Gt���i��O
�L
z-��N4��Gwl$@���5��Lt�#6����I���{���� -�D�[���|��x���{Li�������W������P�NUTf��UW�������&�8��O����nc[�`�a���8�}H�	/����F���o���q��Y�� �	�H�5��{$V�r������'z�@
/p�ab	�%x3�W�xXE�LZ����Ga9��gfcfk�Dtr�<^c���cFJ�A�h�i�hz�.�{O�CM/����gz�Ei�XZ��hz��[�=14=ep.������R_?�[��8���\�=�Q4����cj��(Jc�u���i��^M��G��e*���4�P����<K]9���(���3G�G���a��C�D�$��J�g������M(}K��[.&��	_gmB� hWJ�'���o�>7����wA#���aS�n��u�7�����q�6w���D.�+��a��{{L����(��S�z�)"����e�$�S�<#8�Xl�2�@p�E�Cz���G��k`��k��)J����MztL�
G�)	�g�)+b'�50��$�������&=:�x����\��rX�9�=���)�����/�;�eL�S�^����_�cyt�7MW�OS4�`Qd7�Qd���_��F�f��M�����)#
e��>�@���1_�6��;Gl�.�H���5��:H�
�
/���O1���f��J�6:�� �L�!�8��+"p�-����V�xNZ�C��"��L�u���y���;�=M~g����1d�����h���:�+�����'��i����s�����w�Y�Xj <��������j��>e�o/Z���Cg��U��q6�5�LpF'~��}C
y������F71���Iyed��C
~ya�\�k=��m�6K�C�g������P��Q%����U��W�H^Mx����D.W�5�Gx#����Rx�T�a���L��	/Xwt��	�io�ary����7�������o��	��9�������o?��O��|r}:�?~�_?|���"����/?}���?�~�1>����o<�a���5vE����|3���M�������4��nb�J���Fz]�*����������Op
���W��m��);O�l��=�{���������:�������]Oxz�P��D�+}z��v&��+�Q^K����"<�+e����Gx��uj����(��jk+UM����V{�N��5�����X^�{����������e�����2�����fz`0Z!�$ZM�t.��^����\��W+�������1�������?"��':��@{���Q�dL����co�s����0'/�hz�s�����et�i:�p����z!=/��i���e^{�����i+������e��]��\"h��.��e:��>a���|�x�u�k�����kM��z���Fi.��o�����_�����{���D
�W���H��T�����[7������������;�O��+�f��G���@���)���	���tw�k��[�]t-�3������_���	PwbQX��vg�!�Cv�2�g���<W)v#�u3��^*@�O�h��:=}E���.���>h�
��3fM��e���K+�0-�a���U�CX�#!�q�/��,�
��|�#�����x�b=cV��G��Y��N����������;6rcA�VE�#���t�[����<������V(�f]�BE�7��KJ�pi8�P(d�(�r}�
��n�{�3��[S������[����/�~:��z����zg��Y�CC�*���i�2��`�K�?��!F��!g�ZBm�P x5�g�d�u�8� =�b�G��B�Y=��a��%�g��{X�G��	�*��=N\�����{z������N7���g��wY���s���w2�Z����UW
����b�_������)�&�<�"Gp-�����6M�>��u|�� �+�t��]��Y`A��V�o���g���2(
&�@S��
�;P|K��6��x��Kp<'c^�f��rs�����,w�L���q	�/��r������m�9#�<��#h�y�+��J/�$?�5�IeL�;{e�c�L�^��<"r���S�����������5hd
���Z�{
���3Zk���Z�Gt�
�w����<���1�ge��S�����U��n/�{p��������	�8�CFC�n��n�����/{��&��Q�oV�9�$�U73�������>l��������`�M�������su{1]�3;��<�8� ;��Y�0W���";^
fcg�3���{�*��0Q����R6j[��Z��F��^���3^�Fv����:;���B�ufi:�4+�ak��q4
��3�cj:GGNmPq�E�iV����3^M��'�	���8����eaq���f%���4(d-��8����3�cj����v�<���I�����o��VM�t.�����D�g]ME��hM�t.���W��'Q4]����a�t�.O�QMWt.���_��'q4M�R��=�uIQ��������T��������ZZ����[��2�p����2��Z�����S��T��Y.�F����G72��*���g��/kSc���6��[�@#gD��laC�3{A�43!�7K����+��]���}pf/���j��	0��Ku��������3/	9��+��4��0#g7+h�d����d��@-�u� �p�#W�`k>�a'����w{���)��������X���������Y��h;�x5M�zt|��p�j�����M�a��uV������#,�W�����?g��Y�ZaI������<��(@���,�gU������k�������~������J�+uR��@PT�������I����O���#���&e�;0����y����-�� :^�[�Z\[��A&U����@�bb���5���W�������n��{%U!<��������=�9�yR:�6����m�z��(U!8:��=�9

�.���x`h�sT��ljV����(xW��K:��l%o�6����5���_���F+��YfT��H���y��}�*E�6���qo����Ff=�b9���h]���^?L�]M33mo@��Lq�xM��~���r���g����A�0m��W�?^��7��,�������A�8��O7;U�5Y~6��r�3�?�����W����Gv=�}��l��I�*�6�yfi��a��1So��:�H����3J���&#<�h�s�9�
Y��d
�q7������3F�d7�Q�L/�������:�H\+����`�C���=��m�X'x�����Bp_]z_����z���1�Wt�w����}�����~7���~�]O��Ywc��Ev=�U�W�]���G����JE�.��c�76L���
O�
���
v��jO�$;�Q���NW���%��#��������+F���3dG�2��v�j��W�����%��x�e��(M8�
?�M��L�%>���	D�*�W������y���"x���+<eG�b��<��.����IiR������(�~GiR�+�Q�m��e7d4)�qGIW�(�V�����C6�qG	W���<_[�e�![����X����\�N��[�E���e*����P
�5Ky�+]|l������m0q^�Fl0��MtNC���h���w��X��JJ�8�Str��Q���v��W]���P�g��yx���cQS�*�K\�j�KV�Iz��q�:u��8��Q�q�Fp�q�+��$:=����E]�6A��.��`ES���[�r`���t�^t,h
\Et�#���N�a�G�!��f�3t��:�0k�!����W]����
g���]�����:�����=�����]�����A��.��n(�Nwb]t~t�c2i0�<���E�+���������+��_�����"�����+��n!��iNF�J���&8$#h��a'�c�B��`3p���=���hN�m���(���A��u���n�91�-Xk�c���y$8��<�[�0K<�����(o��{���.��[z��#lkw�=�{9C�5�1[����-=G��3�
��1�XeD�cM�cj:/)JK�����]X�W��m�����q/���tQP�����E��������]i4�{LM�����j���G��E�j�������\\u�3�}�i:��+�\��<��9�/x��i���y����x���7;��Q�qMss��=���9{46g�.��������m^�h����Z��y���^2+�s��)���\�������iv��cj�A�4Nrg��(�n�\���[�8��&�{LM�H|��Jg�(�n�\Z#�i���h��si������^�5N�#��\:c��U���i:�n8���+��c�E5�4������G�E�������{�GQa��Q'��:��Z����=���a�4g�����9�����z���F�4���15=e����sd$1����Q4=��(�����BQaL�<G6���z�(�f���=��g04�VG�<G����wr4���B��h{=��WG�k�N�#�2:���^�<G6ep.�����24�xM��sd�����NeM������X1� �5M���M9��d�;L^�����;��zb�d��W4]���M��d�;�XuX�.���o�wU�*���X�f.�/i<~��x�-����x������k��`�����(�_yp���D��Q"�����Q��`��r:��W��V�(�c�qx�!��\��~M���y�������SwY�n�����vE�_�e�Q4�0�*x5M����n������)Jc��\FE���(�]���sI�R*[��i�J	xM����3i�f�Vj����5�m9����4]��{6����bi��s�����l#�������{�ktyxM����sM�R�bfQM7t.�|�3���[�k�N�W���$x5B��y���k����i�E��l�����bq4�������FE��K;�Lw���T������t�|��FG�t.�a�S���(-����w3�p^���<sB���k�g����5����8������m�E�4�p��a�S�1�(��Tk)^M�t.�1�j^�hz�s;�:�Ei��Z+��hz�s�����0F�4W��cj��hfcMn-�������Hc��D�47��cjzF��l,�����q4����Vcw�x�J����^��=tJ���1���\��;u<�dt.�a�S�]�^�t������{�r�h:/(����.9������9�%�s����D�t�Sz��O]
tyx��0u�l)�\�r�6/�q4�Pz��O]\EQ����8�vt.�j�N�9Y��;�|�R:��c��9���s)����g��s);��TEi�1���8���\*c��ya������:�|�Rg��$�Z]j:�Z�O�hv���?����5t��+o��o�?|��~;�����������~�� Wv���m{�DTd'��q�J���M:��K�k�u��������L
��>�uB�� )�����?}���E��.)��Rt)�����o1�xBw�}�pW�a�Db�����8�
�3���������y�8l������ACT�Ev��x���4�����s���A��Uvg��'8�H���n���CT��g��#��!�y���!+��������Gb#����0�������y�HZ�9���
a=�<=��-�i$d�q�8R��ud���`U���[��i�:\����0����y�p�.�y�*����p��V{ �0�a�4�h\����]|�I_��
t�-��8_�|$X�"A��P~������t�+��"}u7'h��V�}4My��[`}�EA����3x%��y���d[8�C�T����=�S������M�eyC�Xt��������LU�`=mN�)�3�5X���{�����D�R��E��|��,�a�=��x7� ���K�<��J��(=c���X)��CBI�j��h��g���\�y$��&J�:��ga���g�iL��(��kH�6���G3W`x��
^m8jG;@ x���[�z��J����6�<:�<����x�26��G�Q`���eMU{X����P��&<�6���k����������m{s���Lt=��~Dt7�����i�m7�>��+���uA�1�J�+B�����F.��4��
����{G����c�C��vl4
mw����h�F��%�&���h���Q,<��I�L���8�[(<����T*������	/y�.�3^m�"��F�`�/L�Ex��;���%����/M'���*�b�����O��������������X�����r�y�T�w
��5�������}���O�}��/?n�e���!^?n<m��d���_���oO����9?��;��EV������O��^�����~����|��O��/�}��������K�.��}���>��|�����?����.�\����o������������|~y+
����@�����W)u,utW����!!�q���[������W��
l�_^�����cH��@�M���7�Y�����CE�|%�O�z��|��D���I�E�Q���1{V��:�
#��Z��u�&;_��������Kr�p���:Mv�1=T�^��}�iC�[<VL\aEI��V�F�"���$����A�U���s���g��~�����w�h�%�����W	�����?����t��=�9h�����trg�������J�;9��<�4�v�Y�u�W��0������k�����p�G$Y+skd1����0���EF#�������vX����������V���2'gr~	K�>�6=�`����H�Z#�U���l�k�UkV���{v���n$:��X�qd��=g����:�>��9��@�5v�<Avh������A��D��R�?���f������D9�7|�{���
Dg���;A�-D�_X�]�qdW�Dg�Y]�QdW���z#�d7�q��zh!� a[[���!W�
��
�Q[Y�&:��

Le4K�����6��S�5o0���������t�+Lm,q��(	����9;V�lemkc�C�tr����e����i���M�%a5�*Dkt��Q{��tK��Y����+xt.m�%a5�������N:��G��YK������\l:���t��6���������
��s�>������F�s���x��-�v�s����/���3%�����D�K�>Z�=(�n>b�������@�<]�T���G�2S���K�h�,����X�S����(�i������X�� O�
���%Og�]�t���t�@������%�C&�zP��������B�����l��G*V�CF��t��$G����}�T(�0��1k�������M��7�a�}X��A*V��?c�]`D*DtUt+r����d�B+�����a8� �B+p3���	.�����	�C���}�^��H=6����S\[�j����BZ�:�59��l�)����6�1�1�PyM7��	���:E��XY�j��N������"U��w,���6���������h�Cu�=�W���<J���-��������(3W>:���u�4j�>4��JCq�����b�=^�����wlO!e�)$>�@+�T������SH~zP�
<*m�H���'9lzG^���f0f�^ :��������@SH7�UW��fL��/MF�n�u�+t�.M�u�6E��SH�7��4��$��'G��H�	��������a�2�Dp��
�c���q�o$�9���W�7�p�.���A��j-�y.�@�A�n�A� SH�E-�v?M�)$��	�8���s
�uo
���������m+S?c
	`�5+��Ei����&��������
�Yt������q�(����3����@�4D�����	��5U�j�3�[�����(g�A4?Zl;n��D���������<�7��ZGt��Oz���K�j���z��Ht��VR�x�5-~������B.��!h�9v(�]��a5�g��B��?ICx���z-?� b
���1R_5�0��z#dj�O��@���W|��5=��@�S�����{�y�F���H�2<T���5=���
��4=2:���.�$
�Mt.���kz�s����iR~xM��&i����X��[3k�����$����y�<��{�s�����=����-�-��o�(.���=8,@�+��{�����&N����}��e��k(s;�05�V��`W�1�X��$P�6���*p���u�Vm@����J�����j�s��pAZ�	���?�0�.�~L
sY�T��P����C�j������>�UX��X��i�7����1^M����m�&<d��&���V�fJ�H y�|�U�����hHa'l��	[l�j�,x�v���RV��q���,���	[U�s���w�z��~�XS��V�B�2}p]�U|�N�vS�s����H.�c���U����������z��=j�H�fN�y�`����ck^5����6s*_����JS��f���	�'�U_�w`�Q@DO�]QR���6��M���+��]�c���X��U�ht�&?�WK��d����)��f����k���,>����L�w?�G��l���������'#�) I ��������)���>`6���/LS6�q#�\#�ma_Sv�u��{���}�s��~��h��t��^i��:w�4���4���|]t�y���Udgu���=�����yt�y���N�����X��9b�DE�G�+Y��qdG�b��X�<qd��h�-����#��e4�#���� :^�&��<Av��MV\l�����}�������������'2��xQ���UO��Bt�M��23t���5$+�����E�%�]h`�1i����������tTM/B$�i:uvc�p�����3^�QzZ�B��V
xM���>�e�f����`4=SzZ��L�xM���>�eY��/5����\��@C{���^i�Z��h�����r�&����O�S�eNQ��ra�������4��"�(����j�$���4Z'-xq4]���Fb�L~�+:��@�@���i:�6�#5�b�v��==�iw��@�@�D�Q�IO/��^jc�����>DG��ln)�|�B�+
��;�0�b/KG�FV�hu�9�#�Xy�[Pf�����	���`^0�o�
4�t�u�w=��Coj����Yg�J��0����Lp�\���C wF{Dgv��B�FTW���03�7B���B�=R���=U#��ll,3rg��v��t9��f�&��)��j��H>8�x���x5�y$\�J����8h��p�o������(D�^�Sz���!�;'��������Q��q�R���B��T����������?���8J[5���Q������>6EU]++��o��k������U|�O���StOq���~m�&�s����5�����$��,>&0<{���8��8����1���|�z���=X�I*����3��D�Z�@�v`^���g����e�X�=��NR�L���x���:�#��`����a������Z�A*�C���1����bt��?���d1��,lY�X���Qx<#r��s���r�S���A��,� �1_/b�7� �ugD����P�-�����m_�n��;��c�m1����0M�D������ 3�`�uD��e��L$�!��;����{�!�� :�^�^ve
����E�f���z��G���Y&����QdW9������;����Q�l5��eN/��L���f���*����f�����<TX;���y�P���q�Y�����4�D��HxM���o�(���-K$M���\��?����4�����8�nG��m�3��;�qMw�7�Lw�f
xE��v�8���\:}*6w��	����{����46	[���h��s���~`M�t.���9��GQ������-��:�����������eh{�����W�<��=������]�{�����[��r��^_5����-��+���vedx"�@){��!%�����-s��m��p�����6a�6!�8'��h-��Mp3���9\��m�����!mqQ�w����m�m1LW%���j��e<�I��nh�{�W��1z���RM3RXy�9*T�6�1R4���L�D�^�bNa�>r�K�������7����Y��m��v�qY$�����2>�G�����du�s���4�[{��24�J��Q���������(���2�)�oz~,�W��_E���Sjb�'�IXq�z���B��w��'2hZwv!j&����mtzP�fb����J&+��b�����D�x_����LLx���	���!�1�yP&k�x�c�I��d�,pA��	�n��C�h�xa�b�S����2S�i����u��f�kx.s�v3��9�L� W<�V���~�]��~
v9����������s%h��O=;��s�W�W�jD7�7���L�Ll�u�y�y�~�`��z�N��<\q_��gr@���4��M1>9�5�WN�kt��H���KIt�
\EvV�l�
Dg\-F�0��D��?��]�6�{Ca��(7����Wj�{���3+���6�e��~�N/������8���N��HfZ�������Qd��������p�w����Htz�}c
D�'yJg��[
}Q�(%�(�$�d�;Ji5CF_�Dt�(eT���%p�h:�"�
�PiF5��3��&�3Z��h�q��4�����lQem���`q���z��-J���rtG�j������6����Ei����w�������
������������]��qG)��~�k��zSm1"��Dg0����
O��D��?�$7�������(+������3�(e�����N�(m�\@O���e���>GNt����E������W�]���Sv��^�������Z
\Mv��=���f<Av��X��+&��y7��q�3�n4���.�"X�cE��FK��M��G�"`R[G9�x3�adGO6�LosOI��i":��Y=!qd7Dg�U�����l�g����@t����?��W��h�+�.�/��w ��l��h`��X��@����������i���/�����OV�0����hMW�q�{LM�E����E^G�9\���#�G�9j�������/�i:>����T��/���_#�h��,����^(J�.[����i�(J�a�v{`Ms��=�����XIV$V���"x�h���i2�V�.G�t��He��CqM��D��Q4���+:���i�B�U�k�������\*+��g�j:��@���
&
�i���������6�4��lM7t.��E��c�i�����������|G�-�Ks�!��E����4�:GV�AE��Q���i:��@�������(���6��;:��`�J�q4���tb��Q�g��������\z��k��e�t.��E�u�)J�Q�g7pXMt.���h���4{F�15=f��x����H�2Z�}����5=����a��8S�z��WV���h��zl�����er�=�&u���a5=��L�f����;��g:�9?��fO���4�<GF.�j6�(<v��4�����1Udc�,6&sFM��XtLU�
G��4=�L�4-�5M����4-x�h��O������i�H	xM��sdu�kD���y>��5]���tT�]
DY�ka�IG�t�k����>��]F��7���a�i:u��vt.��a�q?���\\�3]���f�eM�t.�AQh���tI�Rzs&�tUP�z�Z���Q4]��T���9G��K��L�ED�k�N�#�k:�F�v'B�(�<"����^(J=�)���(�n�\j}����s��+"x����&��2�~Z�n�\}��cX���xDG��~����x��v��s;^�J���q�J��D�����ynx����=V�+�����]+�|���=�Y���x����(dk=L�#�6���yoX�$��cB�Y�nM���Qo/��.���K��@�FW��5m����{Cw������vA�8��
pE����@�B�nF���]��y�pW(!�5��>Y�9#��P��[hT�LpAv��#�^�f�f�rP[�?P�}p"��/����b����|�tY���������>_�]�����|T�]�����T��BzpY(���F�>P
,=tv
^-X�16��(=�����Vz3i�W���f�@�`������fJ�b�����W��A��S�
��$_<��\Xt�
�*La�We�~�i�
+�
-?���M`��sX�*�n��Bo���^a�:HX���g�x'�^�$��}��Xx�R
^
^r�-���b�F�2�Q�1���������:�e�������������N��O@N�����������?}������������,�=������?���k��+���\z�B�[<3Q~��Y|��������w����	n>c����d{�"��������t�
tp�W�q�{�������W����������|�x��O������u�U��w�.������������nu������������������|~yK�����@����r��������#9���a-
K�nX>���a����N��t��|
Ph�c���j,�r�B��m�k�y��[�#�j%U�u��8�h�.������N�:�g�6:#�����k��Z,!���{<N�d�M ^K����Y��9��u��ZY�c<;
os}��c�YA�|�c��b���$��~��y��uw�n�V���BO|����d1|I���:�N���u0��n�i������ yI�z5�5��u��������w!��&�3��*�+�j���Et�-�q�N�>feN������MV`1^2w���%�*�sea1 ��)�N��	�C���!�=�l�����������>T��G��15]"I7�lO�t�:��U.���l�':N�	\��7�U�����2{M�~�A���S;��t}���=~�Yq��wIp\�7���/H��
���p�V�k	x�*[����VPxcFQ��G��w��fW���%x74]<_�#����
)���X����ql<����	K�j����Zz'���j'���o�6���Pz�$,a4�F�)��v	��]�j)a��S��"N#Y�I��9�����������|Hw#2#',h=�+Mw��nc!����2f�����k��R��v�����������o.U�
1f4^��B/��hO�������}�'���V�e�d_��= �!�[�rckZ��=�!�&pw*��\Q�q�6����-���;:#�
�I�/��{���7�s9��3"��'c��cn����(P���0A0hw�
+�5O��W<'��K�����1Vjo�����]O
��'���dM�b����V���!E$h��N����@pFN�RM���[^�����O���S���7O=3�6Z�EVz-P�
�F�+�f�d���_�CvM�����$�������s�#<�cF�+����@�j�3<\�M��LFVf��D��dp��:�������Y�(��iUfc��5c�Ox�7��#:+K�^xL#������g1���Dg�N�m���&<�$�8��� p��-�Y�r��y�����5����W�u��!�)�U�V������Y�&+����8{��5GT)�����zy������"x��Vj�"<D�����.r���65I��h�@F��q����D�T�Ei����Q4�J���?���bm�����fr_�k��?rxd����y���i������i������G�FxL�OV��
�h�	��"�4MWh{��<a����4�Ke��[qKM�t.�����^�t��w��s�
�9+��������8B���M^�t�a+xt.��earp�=Bx-�K3�L�(�
xM��I�k��si�R��G�t.�p�3�U�A�>s���tz���H3�Dt�-��o�Z*�����v�DO��m�������> �o���{#+bp��Y��B��u�����a���h�7�s�;�������:8^�����T����$����?(p�G�kcF��CBD�X0+}[�-:��!�-g�{���;�	��|$
#b���wtX��"<������QG��;,��y���
o.(=%������G]9������i�:J`x���;
���7SzVU>���[X��-��v�(��r-VY���da�
����(�ngaK/�(=��,:y�
�]��	�vb#�������s^��f
O�<�����b{^�t�
<vY�oOq��������n�]�'C�q$����kL	7�!v��A��r��	/���z�;��,�1����X>/�;!�o��O��ay��#y�U����0��! r��`V�����s�P�DG�f�\7b�@C�DG�VW�1�3�_b](I=�,�����q�����x4=8DLx(
����wV�����X���E;���Fg�$�"&8:��@��������������eg��4��0S�����cxyfL:E�=�J�����}S��
��8/h9�0S�7`G��.���".��)����x)4b����M8Fl�<7��,_?,�U�~�VV��������q"@�����]��^x�1h%.��b]GtFv&�?�Fx3�YS�����n*����N/<���j��>6Nt������L�2Y�������:k�8��7���Fv�66�u�9����0*��<���j��>6Nt�Y��O^�ZU��:1��Bwf1��l��r1�x���Ey�N��5���a&�yyv�Mt����m��'I��Iu�[�No'z��P�<����Gx9�Yn�0��7�7C����,��(����&<�\DX6�x5���0<�7���M�0�R��W^�#�J�3���'<���8�����
������aU�f�(�+�+Y8�[�Kx#�Y���"O�U�Y����W��TF�U�8������b���$<Z���vn�S�y��W��0*E�{^���A����"�7��U��
���yMNx�U�
a�	�a��X\���*y����ky3��UIo�ZGxFV�M\��[fUZ#������FV�
ax������������?��*A,��^KtF��%�:T	�&��5���;��"Az���$[���>�(6��%��.���m�Kro\���Q�7����d��a���l�QE9���y�[i�&�����wnu�X]h���*�h����8��;�:i����J�[K9��vr���a��&�vrv�F�6����D�3o��>�P�z��O�hbf��l��"~#�	����P_��r���09��hz�5f�x�wv�?���a��q�9��v�xM��k�����g�w4F�t���3�cj:�)JK��	Z	���]�o�<J�Gx�G�cj��(J�:]��1��\#��~:��\#�A5=S����i�h�9����X��8����8w�3��
xM��yLk��sqV�j�q4]�������5]"&�5M[�&��+:�����/bMWt.Uv�3]�p\�y���I�t.�E*�t�j:��~��i�F5O�k�������\j���n����n�\���g�A����4�:GV4t.��1���X�-�K�,�>��[Tq����9���si�2�y�����h�d�8��si��3}��G�!I��+)O=�)�9�8�f����c�/����"�E���;�����4vKZC/q4�����LN��U�G���-V�CNQ�%�	�8��a���KD��@���B�Ei��4���h�����	�8��\���%�j��(^�t�D�D�b�����(�&+��=��'jGJa�#F��L�2�Z�m?8���\���%�jzF��W4mM�E�4��l�����t`M/t.s�}$a5���X�k�N�(#E���4}�O�����\���%�j�e�����S'�\�"x5M����5���^���a5��en�����h:�s����Ckz��B6���tQQ��nIk2��8������'��s����s����fM;:gPL�)�Q�st.�=��.�Rc
k�4��K:��>0SxQ4]����a�4�E����92W��X�">��j��"����^(Jc��5�G�5�Ke-�H�b��4"x���C'��)��(�n�\j}��k�IXM7t.Mq�3�`A�+�6;0�h��si,����i�����a�t�Qg��)�!�H��si
n�2u����\�%��n�7����)�\�Q/X�������~w���~r�����o?}�����/��?~�_?|����"����_~����|���|�J��+���*��%(E�cuODt�r��7���;wG�|Hw�����U�3�Q� ����?���3�����9(:���U��L�A���q���?g������Y���Q�u���?����5t��+o�c��]��~�������?��W/�������/���&�"�_{=_?n��QY���Sy�v*Z�^�)ID�0z_,~z=s�����,Dq�������#��s������|�u���o%&����r��^,��X5���Q���.���lP��A��pH�Z�^�s�����S����V'�C�QNW\�/����&Yl�&8�R����E�n��o��r
��A����_	<O�/<�������ud^�.�7M�q7����+x74]?_��@��N��Am`M���	��������&�������V,x�{}��JfV�&=��#�����3F���(�1r/x5�y�����$������%<o���#�;iKor��Q�+�KoB�N�j����ZzH\	^�G�����4���&1qU]$���o_��S��,Y�����������^~��x��G!��:���������?}����q#�+���yq�:;��\��������h���������������EU�K��.�^�����~����|��O��/�}��������K�.��}���>��|�������nu������������������|~y
N�]~ �E��~��B������(a���[������Wf�
l�^^:Y�����(A�P_t
�f��M�0c�/�z(��+���x�P�#��F�O�2/�F��ejY#`�1-��v�&;���i���4ew�qSm��
��i#�C�$h�6Vn��Z�D��	�Cv��w��V���s\#?(x���'��7-1y������_�j�]"�t-Z��1rK���M��2�2	\]��}�:�N2����e;����y���'�I�P��J��x��"�A�s������S���8W��{���n����I��������E��[���g�����h�T_~�B��o5
k�u�*�_4��|@�_�C>V��|����|��5�2��[���=���<�"�eN��v�Y�0���5��S����:�T�$q�7�j�X)�.�>n���(�������7�0�}��j�{��{$����yn[������?�o����n��=V�N�-4*����	���]��-�>n/��ft��mS�6�n��h7��A���r�E�"<�{��1t����)��R�A���7/��_�j���Y�Ft���XGE����(�?�aBt�	\-a�4�����T��)J}:�yLU�U�C-_�j����Hx{�1�z��W}��!��K�V�U��R��i[�������)J}3��M-��+:��Z�����Y�����*�����
���(���X��knr�DQtM�R��V�,�
xe���>��:��jR�DQtC���\V�
�3��qM���-��5��1�2Eb�����Q����F��c�)��;z�6�R����P�����3Kg�>{1VtO����	V�=J)�(	�����+)4��RK��X.�
�k���A��hU��q�rF�b���(��O.�* :��
�uw�84�h>�W�8`�n���Y���8&����H�'k��}��!�G�T{����_���+��}��P��x��%������!+�q"D��Q���k��W�~��&�@nC��|�y�������N���x1�^9g �('f����4��l!8�����p�j��E��`�������f�=j��dN�X=XL��l��F��=}3V�&�6f���i&���i�"cXM�(��F���
�&=��]Xx�����P<���N(x5��g�"<��	��g��Rm/<������S��/��6�C��������8}�x
������+��|���gb��1�@s�����{��2�����c�����)L��cy��.��;	����xd�����>H��a`��e�
�w����J�7����:O��r�Dp�e�$_W)���L��	D��2Y�o3	+��s����L�?Y�������W�����1.��%'���+��W�������/�f�0�����,��xD�����j�� �T��u3�1;�������A�c�L����\��g�fst����Y�6��u�D���*��g�;�S��A��4Z��a���FBU�jcN��d�1��������b3�^t.�[����T�������W^t.��p2�g�����#�����bk�4��ms�3�4����������Wx�n�QYHo�Z��V�g�����v�#A����A��	/:���u����g�����b�3�Mttg��v+MLo���o0&:Z���1�;h���s��b�-f0fC�Od�sk5���6���c4B���=�&�(��X�K��1�����;�l�b6D�+��������e�X���i=���D�%E��d���DG�2�����BG�3=�E��h�^��z"�
��(�U��):>����,�7x�u���iU3�Pt��l���gki�G������E�c*���(:�D6��1��7f��'zfqG�T�E�G�����()I=�n����%:� �jP���-�v��M�����q�J�t�t��l��{���V�R�6��0�-���X�j�2�p=|��=�5���'���#����]����#�����lKY�i�,ohz�����������^Su����7!�5�^|[���~'x5��_�Kx
���g�Io�����"�J]���g����(��i�gc4��
�%=��Z
�c1��Fz6V�W�C��0�U��>��5p1��E��W��)=��mG�yxK�(=�5��?PJxh
���R{�%�������Qx/�(=cZ�J}cY�u/x5��(%<p�/��[:&��fJ����RFKQPz�
��c�90<$v�&��������
��af�s���z������2���3�oSWUn��G��>�����+
����a��KkoyYx����rw��
7Yy�_[���v��r�ll�O�.gy,�����9���-{�Aw|��.��F^i=�X%w$�A���V�w\���j���h3�����1{vzy������v��>�;]����+���a��W�P���s\?�w���v�s�1�����m�����W�fb;�6-b�yP:=����.E�*�fI<���
�.K�#"7?whl� :�^��X�uA��W������A��	�d��V���Nd����j��|�@�@|��eO�[�F[g9����m���^q]�<����b��\����0*�O���9������2��9�����#�F�/���#<��y��yO����QF��	�8�	�����[�{
�p#<P��j��=1�B��QDHlKZc�aa1�F^U�qsI��U�*��e��Q�o :���^x5���;���3����V�HNV�\�MD��'��U��K��(db~������+�r�6�B��=}fcP�N�kia���'y�X�
^	���Y����������8��)I���Q#��;�F�q�VX[���%��*��;:���F�A�F�=�/�q�VXyw��\��E�=KoQ�7�8��Y��P#��2�6�7Y��-��:����e��NV��Y��P#���e�K`f�]E�t,�za	/��Gz��8��
��3�mQZ�UEOt,��[e2��'z��8��:���X	�8���Xfcb>�Nv��G�2gb~�u�(���N�@t�l4!y,�z�c��e){���=���/��<�cY��9Q�D��b9�=����z��� ��T,g�
�������%?����T,g�������@�Yx0�k�F�}+p���D,mvM�Q{t���W f�`�D�h�����-�h���f�4��H�	���m�*���2�Y��s�����%7�]������owX�5!�qFS^���+t=��������!�
�>��4\� �:+p-�Uz:��^g�_���R�ip���!+x<���b�U��\��uN�����p��.�����(�����G>����	�j;a����Mp.:��
����������Bkt���'+x3��_�uOq���g����3���!./��>�5\�����������C���msV����j�����)z���5��o������O�k���\���r�r���[V�������c{��,R����58y,�W�u��s�~zP�a��'���2w�J9�3
�dQ��7�@��D��8����v��-f.�o������7����p=:t���z��<8�Nx�.,<#�������h���0�9[���������
M=�����%�h���>�.G�U�*���_���v���B����~�8�\;@r��#��&�0s����C�����#��9�Ut����Q�s��k�A�3&P�:�h6�uh����N��v�����a�������a��s�D7����W�8�cO����}���P$vF����$�����n��9��x�
������W��bf�"��$�{�c;��z5�����o���(���FZ��(&Y��q����������F-�j��"<�����V����q��K�d�����]g�V+G��v�Cf��������|�������DGcL�Nn���0,�4�L������?�Lt�_�o9���.3*z9��3�B���G��?�LtP���������;��s��������D����������;�\;�"H�����;n��%���f
�@s���J�RY�KwE;:g$W���G��4��eAQ��0+�������4B�<>������k�*�(�@��?�Ltt,�1�nq(�QtE�Rh��X�R�T����@G�G��@,�\;�����k'V�	xE�������c����2��n�Y���+�*� ����ci�����_���'::����\��W��U�5:����4���
�*������s��S \��{���0s����9vA{� s���PA{HCReh
����E�;���P�zo�/��������rG�-���=_����j��\XU3������.0<D��3��\�%��W���A����?<�i^Ez�G�(0<Z�R'��ef��4( r��Ez�`iM�$?������<�����UU��QcXxuN�=Re|���e^�>�~�D�W�^|���)=���c�>,��QzF��HF��<�
 �������<��t�G&��`�����A������#2yT��W�B`x3�g�~��c
2yT��W�?0<d"+���Lk�����!%�����3J��7S%�5z4`
^�����������&��&�E��sX�4-U����OA���M��E�3MKz��*7�M��~9�|/o�6Q����m�������O���E����w��D���x�A�w(������Hkz�.%�1�����1F���A�%@�D��c:=������)hR!V�Ji`/�n_��w�FWgT�b�J>W�iZ���s\d�;�5+5� ����I������
��Bp8�����.r
R?)��q�*��U�������p���s\�IyZ����E�����S����UxZ���i8�������U�����doC�M��N�Cu�.�5����X��4-&�&�^�6oDT���,�{��������}��E[�_��	�-P��g� �]d8��2i���"3�Kx(=�Gbay��&�����|�< ��f��������R�5��\x|�����������S�����W^t2�Cv����S�7��:��'���Gx�U�������Y#��rD�W����s!���������o!:�n����*�>bSX�wQ�W��S����*��
`u��!=:��nT� <������g����':��3��H��%Y�j��N�	t������y��Aa��.����z(������TV�]���X������3���n��U(��n$:��>��j����uY}wQ��vc�{o�=x��n\Xmwq�������n�Q����\cV�]�5�$7�%9}x��OB�*�����DmAt����kyUi���E�n��hTZ��b�B�����W^��Sx���,Nzc�v,�u�gmI\������#	��U����*q
��y��������U����*\
��������U�K�0^Uz��R��a���U�hK�%<�������12��|^k��"��U����U�kcOtF�_�|����h�YT�k��)p#��V�X�����Vx#�Y���/�3��d���SG���wqG���JS��#v����+F;����SG���VF=iS"	�V�h�)��F���� �2YS����U�Wc	��K\�����,
����UE�j�Ka����G�m{�c��q��ZsGx#�LV��y=G8�CQ�G�����-��H��	���$�0z�����Fzo�;Z���0�J�_�Q:zG�b���:��+3�3X����U)�Q��=��:�3�J�c[����(�EoExUAtF�T�:1�W�*��%eQ���@t�Q�����U��Q}�y$��(\��K/<Z��%h�E��Y=�aTr]�5��&��]R}������^+��hU��hv�E#��%�,�Ex�����wI�-�z����U��
�.����'p�0:���+^a6q����Ht�oz����g����"�7��Q�
�"u�@�3��d�f\����FV�Ha%ukdU�&��hT��	��5t0��E��Kx������c�J����o~��	��o��	��/����������?}�k��R����������e������?���k�,������x�x�+�R��{_���o����iz��n?@��iA�vo-��6�����Q�Y���h6fE�~��3�f�st�������m���8�D��=��XN�r����"����rb�:�XN�r�Y*�p�XN,F8k�m$��Ia���ft�-Dg�(��+�[�I�l��!<�����R_|���`��*���.�u�W�a�+�3�$�K%���	/X��+����LI��PQ���)1S�1�m����=J�i`�N�j�K<�>p�`������[���0<�m�������<<�p����,��7Y
�ly����P��&+���6��M/�e��
���w�7�e��5�&�S�C���5���6���2�3�������n;���Yd�Q�m��Tg�����d�����RG=�&��%�H=0�=��eg�^���L���
t��4�K�N�K���������^��x���J~������_��.]�N�<������N����Ur�>!�+�����,*��Lt:�a^x���W��s=��S���#R=W���,<���&���v������^x�&��Q�8
Dg�B�?�\!x����>����h��x��7�a�zq����(����-��\x�x��|�,K����x���<���	,<:c���e�o���a,��������w��	�?*�Gn���t1�~�=rS�1���l��
i�`�
��
�����c�G�T�E���Xs4q]8J�*X�aE>�1�-^Q���Q�+(Ic����q��h��T�C{��WmMq�At�{G5��Kz��A��)�D}A�o������h:���x���q�
�����P���}
��WEWt,�Q��� q]��T�aOt��T�+�6��QtM�R{
�����*��z�z<������Wm�q���X��V~)��n�Y���'�-)J=��f��(�������8�n�Y.������Q�zc�)�QtG���mVOEsv\�S�}NQ��5BG�\z p��9��h�OK��hv\L�X�y���hn@�����H��Y.V N�3E�0�hfE�t,�AP$O���,�;���G-�E'���C��1�'���Y.�1���	�~~[���kE�t,�Ape-)��h�f�c*�}���a��FR4���a-T������b3��M��(:yfl�c�xE����9�����'z��h�(:ufl��h��):u�j�s
������#�E����9nWSt���\d�pT�=��C�+�N��� f�����^�� x��hWR�z�j���Q4�>����E����\�}M�eAQ���5�G�%Ki���E
'�v7�����]����o��S��M����r�SW-^�8���]*�95���G����������^(J=\�8�(��w1�ArkG|E�t/u�Q�Ut�����"l������6x0���q4���4�a�tv	�i:u�ln�Zc+Qu�,X�-}K��L�.���Sg���������.W�tG��.�=��K����)�����J��vB`M�t.�|�3�c�D�k�N�#��\z����n*�:�~<��0_"�5M'O�
t.��d�Rw���0�L�Ei�1IM�t.�Ar�R��#����LO��4��7%��':�� Uw������ej{����4���%��g:����u���3��\�L/Ei�1#�.M�e����q���1Vrk�����}{�^^�o_^���W.F����~RaKI����������A��p,��+t���T�(��J7�������G�Z`�:��9�w�pe��Q����i���G���K�����w�pei*��W,.�8�n�^-����vi�}�15�:��W,��8�n�\Z����NF�4i��15���X,Yq4MRo��Xo�:E��Kw�pe�3��WL��(���[��i:uI��\��4^�5�P�F��$�������7x���dMs	��=���w16����q4=����O;mT�#}���+��G�xM�����D�2D^f:����[��D^a5=a*^�k�N�y�L�-��(��q:����Z��D^a=c*^�+�6���(z�k�
&/�� ��^�Z��L^a5M�i�i:y�l�o�X�=Z�C�&�"t�{DE��^+�^St��	����x����*o�#�d��>�=����4H�s�C)�����u��f��G4�g��TtQR�z���JQ]tea�����
�h�L��S��Q�������<�g����bQl��kq!I��j��)J=X�M�(�.�ZJ���L<�|BC�R�dm��*�(�`57�8�h��o���2��	
}K��-��g�R�Vs��#��k:���m+=b�����\���ma5]O�E<m�qD�tC�R��=Z��^���&$o[XE7$iO�f� ��[��F��O~�n�Y���ma�����;��)�8z�gi�A�����_iC����s�B��tn�����_��9x�A�V�=�J��+����4h�s3�E�=�J�������U�@���$�
����$�E�f�)��:��`�2g���L:�!$�WXMc���������������1	{�Gz�1$�WXEO%i�N���Q=��L�TI��HOt-S���a5=��A<mF��L�2[T^���Oh�[��Ry��-��<m^m�hz�o�����L�q�G�����m�(
�������t���,�TIQ&f�8��s���t�]����+�6�<Q4���>UR���#N��\�15�enpy�E�8�^(J}��(3G4yQRzG��:a� ����2�DQ4]��^M���#����Q��OX[��a�y���iG��./��4�5]��������ei�1��'��K:��+�������G�o���(��x��E��Ke����iOh�\���7y�(Jc8���D�tM�Rs%u�A�:�����M��1o^y�h��si�q�:� �	
�Ks���&o3���7�<Q4�����p���E�-�K{������4���=|Q4������A�x�����;�p�	��v�M�#��\:}���X8���\��N���a�@�k�N�#�\zc:�c-M`Mt.�Q��O�0} �5M'��
t.�>pPx��	����e8�x�	+�����9���e4��=����D�2u<���^�t��D�2���^�����\��NM�3�����9���e�'
�m%�5M�2vl:_J��cL��(�^�\c��NO/t.�a�����^��i�%/�������N��Pd���=��sGQ��nR�"�-B�*=���\wF����~����_
])��[�p����W����?~������?��
������e{�DTd������ �`*SL����N���s�p]~%6�>#D�o��5i]�/*��$��,�}C�K��'�O������$i�lv):r���kX<Q�}O��8y�����G�T����'��!*��;^�w��`�Dr�J0k�3I�x�D��|�@��O����zn|��b��*$�5)�7�]R|M1%7��L��^�:va��5��-?�g�+����W���Ci&8������D3��=���*��!�(�dA�U9Ei4�����.��tQ�i��q,����t�|McW���������3^M���������&��DXxMI���>lR���/:�Q	������!]��
���+�6����\��yX��H�^-��c$<�������[(=�fl�p@.:<6$UVC�O~7����TuV���E~/�N�u7��ju����~��or���%�V��������|�!���/_q�/4�j��9L���S|��O?�����?����x�}���~�OA�y,y������)�+�"������%/~�U���i�"k������������?_������w�>���?}��\�9��s�}����c��w�������?���w��?����������~��������/o����A~ �F��~Y�B������e��P��.��x%j��D5���J����t�W�q�)�����U���D�/�z8����<A}�5�6y�u�'�e#b~��
Z�~��&����������JZO5Yy��4���J�$
�mNA�\T�5E����*���9&��]�c�zz�s���$���1����*�,pg�=�Mw�x`��3���c��=�UR�;�_�c���'����Q�������:��[O�s<��m�a	�"�1�����g���>����Go��jlS5���U��Z���W�q�����u6�F��K�/a������"�`O>�`��]�U��5�\W��V��|�=e�wF��	\EvF)$��H��q�������{���5�q4�_$��D�{7g�R����%\�o���N����'p5��QdW����p��;��	\Mv���yf%M�2Mt� :�r4����O�*��V@G�n :c/��OGv%&�&;����DmMI�Rh�".������!<������|t�����;�$���T��IE�/���;���X�5o���x'�����(�f�gc5zz�N���B�6�vz)J�w�$������������w2��:��@����:����2���h��si��G��;X�-�K{ �I`�����IOE��K��-��d`M��#x���>�(���}5��Y��Z�3>?4������$���4F�GY�K��'<����'�P�/:������'\�9���P(�gd�(v'�����������v�3/n�������^Y�n�@���[�Q��E�Bf���0�#p�Ad��J4��C����^3tT�����1�ZX��}��y��L����V���u��t��������t��u�{����iR���g�T�I�������.�;h����} �VzMF���Ve'�X��^/x�{����z{,��C�`���[^�����-�=�eQW����wT��NZ�~���@s��]4������;���@�lHO��^����;�<��6�x^�V	���T��b`Jb4�w�5��������UZ&-pA��k;()
�cAA�IQ�=��6r��~�����!'*x����k*�9�xRF#���\�j�b	I��#��+��Z�<�9&xkp�7���!�[(;r���M���'�����K�!�kp]����f/e�!�/���<$p��_����]Kt���F�x����������Y��E�k�5&p5t� ��D����U���H��Nor�/���3�R�����i�	���,�qLt�0�Nz����(	\
]�������N��K��u��	\Mv�&{�)���N���G,���tz��C1����aQ�O�-JoL��&{<�]?�aQ���(�hQzc�7����qk��=��hQ�=�������Lt�EI.���1�g�8�#2��0���x�s���B�x�Fz����J-��w���d�j�L�=��E�OO�u���������f��1������e�����:�Xy����[���V��0��:��8��0K	�cjzAI�k����Lxt-�^<*��A4�g+M/G=�}MxE�f
$�����Z������3	�����q5�c~B�k��?%Jx�F^���>��5]���&���u�i:��(���$"��1���FL�S���~�T�R���D	�������G�t.�@���ZV�1P���%<:������%q4MZ��<��7�V��4&���S��G�R��Vq'��I+�W�mr����4&�,�&<:���rL��I+����VN���2�&u����H���V�,��I+�7��&���4��&u��'���U�1=���v��d�[����n�r���F1QMV��(����2��=���\��\L���S������ hV��6��+��!yO��Jk���[��������3�w%�}���
��1����)�Np�C���]	�N��@�����`$
��8��`48����8��p\o6��
�7�H>8a
x�f���|��n'<�����=}+8��
�Z9��{�	�$�W���XXx9��Y[`x��r���u:�3�p
F���Y`����=�Q�x������!�o�&<4�^���`��r��+������Qzz���pEz���t������%��_q^�|���x��>�����6�J}�����l
zYm
�S��Nk��O==��7���v�����.:�{�9�&�9�w
�����cT4���4�����c����x�;��h�s%�T4|
��c����J2�h�/	���������v���UHWO�4�<��	~7����?����O�v��h����������>!}�
#�S���������J�?�9Gt)�~�C������=FZf�WG�&}��<(���xT���Y���@����Oz5�9f���>�9�������o�Y=F��7�G��h����������c4=�&� 48+t��W�c�:���>
A6t*F�Gg���E��y��T��H���!8��������?#���]�CBul�����r=��HQ�z~������\��T���&.���x���#:}���l�B7���v&�B�M��E�2���:^b&��(�������z���#��H5(p5��f#Y�CVz����w3-�l$���3�#;F��nQ��w-�l0��d)!X!V�x_^t����rvW�j�FF5$��
W�qfn�u"C�������sU�)�
LaQ����^������t�(J���m���<\a����M1�5�#����t�S�FO}6v��W���\L`M�G�����(Jv'_j:�l�
����4}�W+����M�T�3Ei�sk���^I�������&h9l*�[�������^St��X���[J�����4q�tE�R��=��"^�t��X���[*=/RX9�}�n�[p�:;��j��:�>�;��ce�'n���NM��V��YkO��9�������B����=��:�32���8S�f��� �^vCAtz/z�u��9�{�1���\��n@~N�Evd��{�\v#��&[����\�8!p�y�����q������m�[y{X�u~�V:�W�@G.p7;�Ul�2�M�����Ml���]v=���|qGw�
�����x�]�mg�fPF
�u;S��v��T��Z�6�_�~�iAS��������sT�Wt<}��������~�\D�����q�n8�-\E�6X��_��	v&7��_�����:�pW,�I���f2b�]m���>�=��3���vs�R����j��#;���&�`���[�N�/��\I������{�g�l�<��
�,k`��`�V����qM�;�{� +:,w��i&��Pp����Dtz�-�{�����/��ZD�W�]�$����*p#�����U�����f��U�eGV"���.u�v�p��
�=��!����>.����"�����G�SM�4���7M1����:M���+M1�!�������^4�B�z�l�!:���HS���A/��M�IS����/���W���v��A���z����)������U�ll��Wv|
����)��f�y����W����|��L���D'��7��G!���4��'qy~��0�<[�����>��e����D���O�v+�7��
-�5�6k�##���qjwm�^'�����WX���	�����W#���H|��l�����\��E��L��{^�H����o�?�I|)���rg��6C@v�+��o�~Q�o�W@���)�k`n_O�`�
���U?�7�W���qh��=c��f\�vB���������D\g����h�4�'����8=E���C����=�n�<���.�mR�����;���
x
�7z2v]U�S����>W��a1���1�w�h;���)��t����7���W��}�k�
��6�+��������^#r@��R�n;U��T�mv��L�n������n���7[���`���.�^,h=?��]�c8U�����6+��B���x��V�1���{Y���.��@g��;=)���J�Q����Xqg�wF�a�#:�mW�pz�x������cnR��O<����A���9��]�E�����j�}�B<w�s\� ��y���t���[�����Rg%:�#�US������C�Y�-���Z�� uV����}�����"�UgUM��:k��e���Y6�[�N��V1���zV�4�����n�7�Za8�7?��43���^&��zhv�������i�h���N�l�������h�7[�b��g�G9��Htz��3[���F��������?�3-�A����� ��D��qV������}�5���x��(uSX��Xm�f9�2^�"��E��X��,�"�C�EM�Cj���i�i:>���9Ei�>�;MM����15�#*������^�Q�S��G�E	�
S�4]�e�Oh��Z�X��)J}T�(���c����`g�G������M��C������Y�p�_�-D�[�&>G�5%4[���e�5Bg�	���ra�J/;���y�8�c�qa�?Av��	���];A�� ��]��t�s�7����W�N����]��_�+Uw >qb�_���U�4M���u�c�n���$#:4B�-N2]r�8��~���|��-�n�9���W����=a~}��E�b(�o��y�	|^�(�Ag�3#����FGt����=a�}	��o��0E����E��|]Y����q����;@d8��>���7������y��qSZxC�u�Y��qd����7t3��";��
Z������b���Bj����xC_�ms���s��!���1�.�� �����+���'��J���QdW��T���+1� p#����yk�P�U���I����BUW������,p�";��9�Ud�:������q���]�]i��m���cG��J8�2|�L�$u����5+I��Gyf�����AJB�*A�.B��Xq�J����
��Et�g\�4�=��`;���(@X�q�,�@��j�W�����K�,>�H��D�3�Wa�"�����#�7�������Y���:��
��.�Xfd�����I�td4�!�"V�y4����s����#Eq�s�QR/�������g��"�	9mgi��}F��z������E�%�!�0���]�f\0g�Y�p�^�� �)X7����I�*���
{�4�`��{d�����/.��/��o����e��_����{��x;*��	��6�"�,�)��u�N�r��/(Tr���'����y���V�����[�w�[�^*�IrA����sS�3�y��J}�(G5�)�����<>�7�������W�������8���(�(��gN��}�gN��y�N�1����/[������z�������v<���MC�s�0�g��h
�9@C�(X/��>frQ��M�1�Y�\��a�w~e/�����b���*�+��Rl�B��BA��u�+�e��@�'�� D�;J_����8w�Wb��E%	�[GB�������������.h����E���$u�UR�Q�*{��H��]��]df�,�Ws���5-���F��U;�`��_r�W�W�J��Pk�<0�}����`�1X����W���h^�O���K��V�_��/���������]����O�gX���D���������2?m����G�z#:��V���o�/���a(�����x-���_��%������ZV��P�,g�G�(6��%8���������.�>�z���P�����|Z����=��(?-�1��l�L;�;D�s\e<)��9��W�%W#i��Op9"*A{�s\�h1�9�U��J����OtEF�mT;'=[�<�q��R���<3D��T��_���"��$�:��Z�IP=���i��':e<<*=�����(���.�t�!%+p�F7s�.M(��D���X��qd�8�3(V�`4���k���hq
F��Ht��9�Cv������ ��Z����c��i�%����03������XT���� �'@�zDu���h����eU���f��E��`���n`����
Cpx=-Lw�}<��Lo����3��0��J��8U�hz����F�CIQ�
��/��	^%`�?�������H��������������e�y6���R��Gz�o����i�Q�.�I�8���[&#�`.�
�NKx�-��ix
E�5�:�(�E�u�"p�g|e���Z��l�D�V*�{�9�����#��@�,p#����h��AD��e�{�����:l����8G�Fv=���9��a$�!f���.���.�-G���%�Zi���gi�����[u�W�}����������pl|,�5K� ,A��TK���U��$L���HU��tB�A�������WI�I'T����o�P��Dp��+r5�����Zi%y
�+�r�A�koa���d��j������a��H�+�AFo��$<�^Mx�j�������O���uk�[��� �D�Kz_l��#�w���w������K��~Jocf^�'�k%�O�Hx�i��=�	����c%�$>�Q��`�L����Ix��.�n�'o$:c�"���dL}�����d���w�F������}\xA���m��E��:�v!
Iv��.z5����`	����K�8:R���
]@ko����FDtHM4F�UT��7\[�kK�\���x`�n&:���)<�[���AG�S����%j��Wi��r�Q�T���4%�����D�����o�����s���
�c��N(&X"��@V�[Y�FA�`�����t2l�.&X����
������`��g�F
@�@�6Yz1�M
6�6{�'�Q:X���ncLl�u=���5�������}�������n���"�t��D��^`����j����
�525��g������\�~��{����A�K��z?�G���]�<T���6�[N�al��c���]6�N.M�C�J�z��4m����y�������fg�\���������&�K��t��m���NQ_���"��?FX)���RxWV�8�o��r�]��� vb�;�qB�q�����rD�vwC��#�M6H_��}E��
E�H���	+cH�@1N0�MX���H�����	+wA,$�/nIq"D��wV�x���]��"���.:j�����+�1�I��\�*�=n�mWfD�A(��%��b����U>��l�o���Y��iCQ�c��������@�`D�Y�����=�(��&�
9�`P�5��>[Z���P���W��oM>J�Gx���,��c��h�s�����Xl�s������%s�����ZE�����e`������E[��U(����@@��"�n�}{����#Jg��
C�t��*p��k{^���E������K _U���n�qs�ad,_����*r�/WWx�x)����%Yt��J�`��'�M�#hM�'.������	��Bt�;L��������~y(-n�0�z@7��0�����X�����^)~�0o���1����h������ c�@�0��C�m����)_�kE���G����k�������~���^����=��;�n�U���@���t���%?���E��<���t�wg V�kMs;����t|�L��)���i�j�()J��`O����E�jg��^�G9��E����
HuuN�z��>�j��Z��R]��ar�U&����{�5�YC'�b��?��|���@J�
������������������?���������V�O6�����������l����>���_���P���|�7����������o��I��&|w~�W�G�U�G{�,�Q�!;T�2'z;$��!#8cWT���cjR�Ev�Y�4�"IvH�u��H�!�0��1'���������S�%����qG=��n>�����w�q/f���Y��A:�@�LPimA~[�=��)��}�p����e��b5.0aH����� ��Hf����HpF�)W�OB���en(���h���b�)R�E�.�_�W_�S��"=�s�V�]�@�gv�7�sM~��gP������5��Z�K{�q�������������	��?�I��G�{��RA��.>
����7zJ��n 8�.�{��� x"��A��.u��oP��G��HpF�;�{G���XS�\v-2O}k�����=�T
��e$�����,��6d���2����s�7�r�������H1�����0�sD���X�h-����=�����S}R(�9�c8����|%gX�+o��O�FxH��F�������F�������E"�-/�W������
�s���T���s>�������sY�v�6a���n���,t���
��/8!Ot��m�����+�l��D���K=���6����6��`�qo�c@����vot�v����s��v����H��0 �#&$�����j7���t�����Mdj8��1E,P7I��w��f�t���R���!`�-������M��(F{p9E���v��sU��|���[�������)~f�;�wf����kK�����5�l�������K�?����9n���~�_��������E2I���/"o=���JO~�(�Y��������v���_.��7��<��vB��X�� r��`��_.�{�}C���~�}�Z���
�4�=C�=�rQ�8 ��w�����$��^c|�3bd��\&|��f&[@�1��0�Gb�}�Lh�D]O1�y���|&F��5�8N��L���9��F��go&�m[��q�}�X�:S�E��J;&��q�y�>>��,LG��^�����+��}Z�9���g�M�k�Od������B]��g���%F[�#�T�e}�Y{'�s4��x�VF�6O�~���2y[����{-��3�%��C�x���3T�zXRy��gho=���-���(�����~�!�g=�*������h��.�Ct�CT��{�C`�J�j�!��n�b=���hT�t�8��IAbsy���p����w�]>����!����l[���$���

4�����c[����b]5�!�����)��O1��e\s��w-��*�����e��	x��63�����o{�������1��w�mo����h�jc��X��8��qD�a��\�_cE^Y�+=��9�#�^��I1�9
w���1��<2���f����w�rK�o0��?�]At:��A(�8
A{�sLbu�s�������1~�8���{g5#���
�@��[�����b��q�`0V�W!����xt���UE�ez��u�tm|������4��ee���+~��rd;�UU�r#6����b��.��n"8��07	����=��W��?�B��va*���'�n <�h��f���n!8}�=��c������\T��c�9�G�V�]�i�5<��H�E�`\o��	�X�^v%�}�w^m�Ey�����Q��g�\OO���k�U������]�f����6Kq`��g��L/;�w^Ev�����P����g��w�Zg��#������]pw,�21�+�w�!��Z�C�j2R�o��[��Qe_M7�0MsXM3�+�5M[�����7#�[�y�������=���<sZ�z\j:6��c$cof���8����"x�����Y���p�j��s��]4��k��s��a�t�����4{��
�@��3��kz�s�������A����6���������%��G:�����4M
(�i�eM��PEu�O?��m�k���izb�u�F�R��'���\&=���g���4qk��=����`2V�ikE��-����#��h�;��T����XwPX��q���,e��&���gY�O�X�l�hk�f���A��w?�e��AktP��t_�|O��5�o���[d�kK���
��?�}l������|����3[gkH�����	 �9���
��b>���&q.yC����s+���W���cK��7��u[�K�/M�6�}�����z�f6��4�%�	%�� ��
��}�+���83Ct��	���a�:o�T}�!��Y�.�W��k�� :���D�V�}�R�0����T-3
���f��|�z��vo�1���o��o]�3/M��[����<\I����gk��2G���m��A�'x��+g���=*��]��3^MzY���������G�����EWAx���b�$������zEc��Ho����D3�Ez�������HN��:�����@z�G������x�G�tM��B�'W�����q�)h~.������jjk<�y��LL�}�����>6�_\���a�����W�P&�oR����Stx���I��x��W���hJ�:x�i�	��8�B
�cMCRG�5��w�������1V\h��x�i���u�:�45wf��L�OJC&����G��������d/��H���o��-�rW]����n�@���~WmG�8�OJgl�J~�{�N�&�G���>���]������CM��@�������74f��:�t7b�!M����|nU�������	���!�� :�+�M�?�`���A�A�2�>�]W��x�!�`���[�����8E�x�E�'8d}�����^���7������\��E����j�+�+�5/��=���O�<��Udl���s����g�!�+xV���GG����'���OweV�+����J���*rE�]Gx��U�
3Mp�hXA�p�5���%<��h�h���0c7�7Bz������)Jc��?Kx����A���3�����4
�MFQ��.�x,���4� ���MXM7(�	��j�W���v��c��sY����t|��si4M��[c�����������X�Kw�Ahbe����=gM�t.�1]��&>:Kxt.�����y����1#i���7�a=�A�����?�4��6�����?Kx�-��@��V�#]�p�9hbEeG�&��ZF��S�� ?:5	t=���Y.�&���dW>85I4+����}S�N[]C,*�s�U!���V�y?�CfN������Jq��S�g&�=3k������5����NM�c��0��
c�O��?�C���j��'�p��5g�;������#:�{� CD����=������^�(���mFq��(����j�4�Gx�:���+���k������4kf����c�T��?��!��h03Q�W����byt���x\Mxt-����C�*�^�12����g4��y�(�����Z���������`"x�'����(���\B�{�/C�r{��4?�G)���*��l�3�w���>6�W^+[�o��k[����2�ws�x�A><H����������t=����Txd���H�|�Y���#3��X~��������H�w�7����� ��2�0�����@�?D��b����1��1O���M�>)�X�x��7������c���b���%�1����2�t����e��I������U���|�#^I��r�S��M�F*#��1_t7�F��#����M���B��]�+3��E����9>����3z�G����#Ox�p���A��(�L�����>Avl�������/%�}���[��H�	O�0V<����+�.�����#;�<�Udl~���2�W��!;�����m����wMNp�"��g�AI�*�6?�+;:�� �~����]���Ev�#8���\�Ev-2.�W�*���	y�v$���!o������k-�
�yHx�/ox�`��x���"}4M��^�t�S��
���/��+�M����^(J�E���������w�:#P,M�������������Q4=������XXM�t.cq�3=28�����E���h�����	��e:)(�2j1�z���q4M���0�l*�}������eZ{�g�Efk�B��M��s����������e�{��@�=�Q�������C�UF���v���*CeG�%��2��{����#�����,s|�������i^��^?lyAN�*����d���0&a���?�tA���x����](Ik�'��/��J������]���)�7M��
MwH�-M@�CI���9�E����WS��R`x��
^Mz��~� ����~� �h�3�Gz��Wf�c��	�Fz����y,�M4��e�����Fz2����`��T�j�����������9�(�cCh�j����W`x���V�6��(�1��4���cXx����Nn����������O)��A@�j��?7z
��
�3z|���C�����:0���6�`��%����������5���������g�������
�8����6��T����uCPbI*l�(��C������F���)��F��S��������B!�*$m��E��Y&<�B��y�g�����,���,�O����_�Z�,k�G���G�G���*���~�l��=��_��Y�)
��r����._\>��`�c� ��#-{c��f���Xv��������1�>��R��*�e��e���9	�7�/+|d(�{�{��.��
��26�\;
�.��{�N4���R�w;o��'��\$6��e��K��3�XQ���b�mFI��a��	��e�/L�.�e��kZ����*�SN��mkZ�Tp�4��
(X	�m��	I>A�9E��i��k�����!:z��g����i�����iy���_EY�+��{����t�����fIE�0="�/�Y���Z��M�!O$x-L����LpJ������������_�fr#�U-A�>�C*x�K��p�#8%��4�&�]v��
������$=R��k	.����.�������j���NRK
SKW����.�ig����z�H��B)����;��8��V�YZ�2��J�(�6W]��Fv�-���SId���6��x�U|+��Z�2�W�������&��Z�2��R�B��q{��w5���w{�%�wW������^)u8dl��
��d���'h�2)Y7�_�0�O�m�4��DQ*�*}��]�Z�0�����e$�
�4��[��oH�N[Mw�w��:��i������_��D���Na����4�f���ok�}IQj���D��K�t�G�1�mA'<>.}��6=0��+UX�f�D��A���d�$6=�q�����S��7����2*-��:����G>.�
��)�(�A_*};��'>.��#C	�������F���u�(�0F]��I�E��d��M"�]�������~��_^���zr��������������Q�����������(����������?~���?����;����I��!��^�����o�_
yl}��M��q�i6�mS���-�_T��lXa��L�����*�����]�qc�W��$��o����b�XnrO��m���
�W|�$��
���I]8
�m3M
=�+��$�.��,�8�q�mc����R�m��)K���)2I4]�i)�����{��,���R~�,w����YU�G
��Y�A������x��� IKS�����)W_eY�k&�>s�#Sl��oDUSrN��]���'���	1L��r��`[�:�����|��7I1�"R��@�J^Fi]�$����o���nFh*p���	�#�P0�v�7	���������B�-(����G"�z�B#t��F]��N����LFR�-�����(�C3�OD#������*��v��)��C�W�^ �Q����~�t��m��^��4�~����!����Fx��d�"�����k<�.�6��6���*xC,����:4	�����n�6����_17�C���/0�����%x��3���8�������T2��Z���)x���}b�8�����:���mp��G�E��}�}���f��zn��94��>�a�}x
��������W�K�}b�
�>��Kp�H�LN�4�� ��a�����B1
ti*pC�����,�2u��D��B����������]�N�?q/>��;��������DZ��]����ya�����.@P�y�#

�g�;H��?;(��^�:2�Dx�����n��b������j�Qjp��7p���}�.��h �q��P�Q��XQ=��Wj�!��nP�R����@$��);��n��C"$�+�nj-���t�x5(��V���Dt��
��WQ��7ND���D������m�.@�mR��T4]iAe�u��������Kk�M�j��+=,����K?���07lP
�Zj3��&��8AvsN�����������E_����r��
��n�K���,#8e�������e����y��]KpJ���M�~�Z�9/q�������]lv���Q���
�L�����������f"�����L��mn������ ����6��o�&<���7�&�v��7��]���]���<`E��`o(�<Z�EF���.ibE�$�C�N��Mx|Y
e�r��X�3����.J2�K�k3O�(���R*�_#���.�����Zt�S��&���];_�*���|[EW|X��m-�v�d8R�U��c���R+�9#���*���RWok��(�C�N�zLx|Y�aB�o�(����ok��DI�����M���/K������v�_�6[�n�##��&������&������D����|Y�:R����fgG*A�^Y,}y�#ug'�#���-#�C>u�:1j�$:d����T[�!*}�Y�����+p-:RM�3�Y�����$R���b^��x�#�V�}G���,�X�`�E���-�e�J"�C1��^�t�%��������Y�.�� 8�7�����G�]n�CRL>!����7�;/B[�!*9L�|B�@72~�"4��"�����CT���w���{|�npw^��C����� ���Vol��C"��n�C�x%�a3��
����Tt&�!���z�wMe]�M��R��HfF���7��G�#T����C�����r�WCzS ��aj*M��X�Z�F�K�����}��i3�����Z�[�2���L�)���(���
��YN���A����/�'�����L�w��=6���>o�.�6t����uCw��We���2w���l�����h���70�C�����#r�p��n_�2J����z@qm�
}�)S�7����]��rm*Q�M��]�.�����:A�E��6�<��	����~��
���{�j��5C��Mc���v�.�\��P��������{n��W���"b�y#Va���v\#����l�����f�w�`�l�&H��n�CO��nk����f:���2��3i�&���H�LL
�1���}����Gm���CJ;���p��)���R;R���(�|1�/�Q�f�}�&]ft=�iMZW�a!�
oHxZ�e
�M�l��>�3��^�#����[�w?Ote�
h'��L�eR��)#��|y3�|���/o���4����S���������]�xx|���4���Nym���l&<�-9~��I�V�����-y����%:"�(���xx>o����A�������-y���):9m~o��
�;Z�yF��O[�+��> �Z+�%Qt��%WV%4�@7Sx���L�EAI*�>m�JE|Y
���|����}�����)I�-Y�M�F�%_�RiKN>h`��K�>m��Z9JRiK����/��e��!�27��+>,���%k�Q�
7�N�������%+��D��������\`�(I�-������R���[dv6�.��ai>��fU�=4����S x�4L^��)#sq)�2��S��u�:�~�s��Q*:$l��c������U��i���@���\tOl���(8[)�W!�_���4),��,��x�E��aW�
�[>l%F����k#����x4�Z�2�~L��fJ/�f8�I�X���!M'�U���@�T�D��m��H������\�CJ�<�
�������T8�Z�T��S����Fl��q��B=
D���?�����p����G���Q(�M,�����O���T{w9�_{6v#8m+����c���j�w���~������}����qq
^�g|��E��V�H=����#]�������#�����S"���Z��`t������QZ���B����&a����3#��e�]	I���e��A����0��z����#��8c�|:cx����\��S�nv��:C��>��}��-�"��ob��ClQ)�7��{����)����C;C��R���O)���#:rv��r������Ja��&(�m�!�_;C�_t�]Kt�5����x��JPxe�Y���	������
���x�J�E�E)��8V�Z'��K��i��L5*�'o$��+����i��]�7�oc�o�I!�+���j��#:����7��Ri+0�y�i���Q����M&<��s�7�)�	o$:��M�����<�)-����$��3�����yu���fSY��7�Ro9^x� <m6L��.�1C����W���f�6e ���#:���p�y�*>�iQ�4���N���y�i��[�+�HmQ^
?��s�S.��_���
������@tJ�s��
�*�7$��#����R(���f[ �Rk�-�%ii�7��U9��+K�V��h��L��/�!���//�N�<dU�R	����6��@���|��dbE��V�|�|i���*<�"O�����C$p�S�5
���P���A�������,��)z��f#EO����n�n+
E��c��]m�����Ic��y[��d�Z�l���Ni��ei���b���������}[JV�1���]Y��J���OK�}���_��|[���t��-m`VE�|Z�p���Bt|Y��m-���mRtDO���>-}x�v�~p��eCS�@��_��(���'x#_�A���.�<�#_����I�,����7�J��1\���o���O��F���^|H�Z�D��e�kL����g�-���6=�b;+1�V�N��������4��j�����m��
�]	����N�5��h2M�����fOD��=
{"�'�kD�4�fSD�4E��G��L���zy7��$�i2Z0��=���^��t�(�������<�$�MQZ�<��s>-yx�sa8�-E�mN
	w�h�[|I���8I�h��o���5���Qh��$f]�u)*C��St�e7��IkM�Q��o������~��_^���zr��������������Q��_����������\������������{���W\����>�0���m5He�����|������������8�Q�D��cc��~�h�����F� [��|����!�Dt��
��L�uv�LK��e�Y7��i�gZ6;gZ�����8f
��4�G��/	Q��P�7Mc�`K�Y�.G��(��#D%�X��y�Y�q�}�XA��X��g��#��H)���x@�
��h((���+p�S��J������6�@�uYIj��:�y�D�[F���O��7K��F�E�v��<�d�����m�{����:��{��#<D����M��k�#���N-�m}K�i� S��4A0���P���Q�����^�B����D���F�6$��2���xtJ�Q��.n��p�B����4�c���}�����^o�S���6�$������u���
�^`-��|}�����>���>��Q�yf=�����X���c%������&}V�g��;�6�X���#n���*�t����������m�������m]�������1�8��r�����~q�n���9����"k��
����}�,�V�m��#@t|�;e����k4e����w��#wz3��#��)Tz��e3���h(}���o����Kx '������x���0��������~���]�������HC����f<�NF�1Q7�L���Sx�����C'�$�)LUg�l��i�3��I��+�	�D�pm3���&�~i+��,&��@t�^��v�L�_$�f���)�h �!��kc~����H��������+Ph�!��M��^KtJ_�VlH$<�q�7$<��u��+=�)�T���Fx%�M����N#�����c�Nt��z/��s�����N�x��rI��
O�d�Fx��X`M#���Y^R����6����
����[�%����6<J��
S�o�"�P$�kr��m���T�
���T{e�j�~&�qj�X����s�����L5=/�����\d����r���(;����z��U�/4�%�3�$7�.�������e��/(�����%�s�W�3���cr���J���=�V��"�k.���&W��^��}Ox|V������GGQ�C���D���+p���V]��v?�Y����nz�2J2�XM|V��0�j�.��A����L���]�Z������
j�KebL��b��q�&j1|�xex�Q����n
��~�d�P0��C��V�E���XA�WwXT_��3������2���7
��Z���h��F����P�Z��lz��n&:e�����7
�<�W���;0z<i>�
��$��X���D���4�^�2�:��Sz�\q��s<�>�����V�M��t��oo��
I/"6��P�����6;����cnHx������g\No�}7Lv3B���l�����D��(<��9����^x���>y���_;<�@{Un��Q�GQ�yo��3P;<�&���W�gm�
w]Bv��� ���m��]?�@��hhA*kA�)x4�0���%�z�)R�����-2Or���Z��@�|$��z���Q���,9.'}�k�w \Gp��Fv:���#C;.����r����DG;��ue���$�c<����p��x���+;7��n��"u�1�3X�{�5���2�+����H;��Dc�u �>��"Gg�VH9�Q��qu��M�1�3��m��M���!hCc2���j@":�[s`��)
H�`������ep�(������
Q��[�����F��&A.<���!�%�EMtpd&e���M$<\���][]�Fx���g5'�FxeN�*��6��J,���#<�0�!���
�9S9����x��
�S:�5�R�Uh���#<�g�����S�4 ]������WLNg��6<9��
S�o�2�,���tMF��o��iK�B�G=s���
��pEM����4o������;4j�G=sm��
�9"�j�g�����@�7�s�)��H	��#��;�*]��Yn��k����JW��=���{�*i#��{�*}xrH��A�����o[
�zF+}x3���$���W�WVF���6 ���x[�@!�/�:I=�Y��b"�t�m@":>+�[�1�K��K`5�Y���"��6 ����Y�k@���6d��_��~�c�x�L�/x��^x�8��!MJDK��t/(p_Ag��@tp���m����N�����Bx���Ji��#^����"�rc���X���/x�i:;_�������/�!<������[&��/25�������a��g%9��Tf|�YY��-\L%=4����M��
<���[��#�~�bV&��`���7����A��&JOk���e����)c>�N�D��� ���1x��>�im���7d�����C"x�������7$=�QK#���S:}��7�=��0�������oHz�F#��@�o�\�/
�@� ����t�d�_[��@�`uX� N�Q:r�������_{7�jk����e��j�,�j�����~�u�g�>�g��xL������@�gp������1l�i�	��l6D��S�y+������:v���FM�D��U��u�1)�R�A�6�F@��P���i6&B��q^Cx������v\���o�Et�2oU�h4i$�������%
����qI;Qh�N]oo�4Hx�W�Fnc�m���J����2R6M�D7]��&k����]������6v
6�UvM�"����?w��=�='������p�8�`��`����o?����R���!R@���^,au^��oS���
6
SD�os�Z��^�jC��6=?DG�z�Z�4�&��������O"��>�����W���$�������$f;eD�,�<^xS�[e
�N�64>���iMZ�4}���=[����Y{r��������Z�J#���YO��H������G<���g�S�#j=o6M���\��l��[�Y��2\1��v.3����t��Z����5+��B;O=;�=n]��V@�3�����+�$�B]:��=��@A�0��L����2`�J2<�M���9��������y�6z����o��X1T����1���*�L��eG�z.��o��XKGI������D�%_�2�����6�������k�Q���E��(���Ri�q�����f����.z;EO��gH��
t5���
�;t-��W�]���5�G�.t�w�#����&:�+���r�
�<t�~�:B����0(��m����zhQ���Q����q���`���MR4��6#Ne����K#E�o��]|���b�
0w%!*
>u&`���np����v�����p8�F�-<���X�4,��p����qR�D�kq�R1��"N��B�H�����"4`�{BT�<�/�K�1����V��s�`���DR����Eh*�*G�X0�v�7�Wn������*�;'p-.��T�eN�
/J�No�d�����1E�X�=����A@
s�fL��=���3SDt�W�[&9�j�$5�5����i����4&`��d��H�lc9c�2�6C��%�����!M���Ax(-Vj�&��c����������|��=,I%<8������{�,�L����I	�+(<m���
�w�2���O�>�Go���7��	��~��w�g�U��6���O��'8\����?JJ=xqon�/��E�tz�j���>��Y�.���u������$�?�7��}T��l�|�m��jS��.;l�OA������uIx�C�B�����	&^��%�W��������0r
g3�R���
_���5���6�$������D���Q�p�T5o�t�P����legb�uE�.��=��k����q��`�����'��7�g��������.f�i'^yK2-7������]�������x ��#HeL��xh2�a�n�<��4J��d����-hCc����	}Q���t5�b]s���m�z�/���iB$�5L�jB4[�)���t��n=^x���uqN�rf���@7]��Q��i��9�7�;muX�u�;�Y@��'^Gx����Jb���N�H/���[�L��v\%^���W�h9�D��{�#w���$f�5u7��)9���Y�7�!��M�����LE~���Q�7�!��O���}G>g����/�������Oa���@�F�L������&:���,�^`�3��gu[b=O�����r4�3}��}�j��0iz�.��g>+s8J�������T��>ci��ar_���|I�����f�����1�s�A�M��zv��T��|.�����$zv��{���@> ��s1��=4�F�m;�v��/��}�o����'��B�������hm�m����J�>�XQ��E'�At���ss��@�u�{��@n�Q�:�G�M�w�P���GV;�%,��])�mO�����:r{z�AD�����J���:fg�U[!��R���|d&mIt ��W�Y�%-�����}3���T�_-gmCz_��H��eV,�lO/d�^����/������s��^�zF��Q��W�O��M���v�w{�k��:]���	
����or%<�Qz�z���\�pI����or]��%-x��r�D�)���Y�m����L/|��Sz��������~��_^���zr���������������������������(��Du������������5�$������}�G7���%
�"�����o�_J���!��3�~q%Zl�D�/.y�j��7d���P�D�Ht�����y��<��
�������C`$pC�K���7Sx���6^]PxJ,�m�J#�Y�^D����P��!�H����*S<��>
�x�����VP%���b�gd��I�����y���L�}2>�&��[���������M6���S�n.��h�m�Rm��kw����Z��]����+����'&|�*/��@w�^��^��9V�g[�W����l��'���#-���#�B�q�O@��B�1�Q_(����T?�pw��������F%\bET�C���{C�n��������jc�S�m�V:��g���2��p;&YR�>G�8�F�����;q%�v�<�s��q���7T=��w�w�-V��@��H����[��j��MtxFn��_	�l����D�����-����:���
:<#��=�������
��G����V+�%��������
�M�������N)�iU�4�#V������Hx-��;h��B�7$<�����s����.<�^oHx�g�@tJ���;�p������tx/�B�4� <��o(@R|�$_^1���"�H�+y���m�n����
��]�R��j��$�^
�(i�W�VQ�^:���FxtU*�UI?����(���i��=����x��*��Zf�.����j�*jU\{���Uq��=��Uix�hE��]���J��*GG
]�FsU^�S���ba4�p2��m��q���Ip�����-������|��e'w�����$�'���+
�2��4��-'
}Mv���LqD5@��������
^t��F�P�E\���56��1��+��&�bJK���&q>X�o#;�FZ)�����d7�F���G�n�g4+7�V`L#;�[�6�p�MD�D[���8e�W��������L�q�T�4��N�k���le�<�)dm�E�wvp  �����Q���!���Zq����N��y�;;������������n�p��F�S� ���D]��N��h������nH�Wr�W��O�oe��k��������.|�hs�����R(QOsp\1�Q���3"�Vv%}�B����+L�CI���Q��:��X�����g��&�c5Q��0�f�"��c�+&���+d�|@�}{�z�(Ie�_D����YY���g�����6�3�o����p���U����������2(5Gu�r=s���
D�Zl4,���ih�h<=�"�:(�����I��Yi���
��uC�g�}�������>��������J��-�p�l���Y����j�=%]��1���WI��.�uE_���4�o4�XGQ�cU�I=�Y����.����+��-'V&�e�u�q�@���A���I\��������x������i�<�]Q(j��D�������+>���Sb3�����I�L���}O=��A7(�-��H�|U��:�^7)�������3�|F�
��(z�������_hcEs���}OE_���X��K��I���]�/���(�{��{*��f?*[����b���"p_`P%R�L����`�K�2�����(:������I����5K�=�L���,]R��'�s�wE�jD\��z��%���z&qcT�.��m�����R�������K>+e���\e�d8zi����_�*��Q�4�3�����y�$��K{tNl���(-��c=�|U���7�s
����������U��1�G�����J��t��A����������Ui����i%c�g�����[��|@����Z>+��+?�=v|W��m-��\�}xN�����i�j�JE�|X��m-�G��(���X���W���/g|Y��m-z@{��(������e7�,��V4_��{[��<P��I1�+�y���F�,w
�M��W ��><+���b_A$�%It5�a���nz�%�_���b3��9�Ra��z���������Q�s8|9��n��g��r�W��������w?����O]!��5t���t?�������������������+��*�����KHD>�>V;|�X1(�K�f���o��vj&B����������1ty�!��:����`~�'��sH���i���R���\�Ft4���8�=bX�[v���H���	���8%�����r3���t�B��_�iF�V���k6g���l}�+�����`��70� �h�
����O�����P��O]&St^�I~�������,��L��g��D��i�?}�e����W�
��@��}�}���u��=��~F[���;9Q�8"*���\��Yq���D7d�8���D���E��9s��zr�Xv��7�/p�K��s���`��[le�w7���V%U �f����w1Ic���6�j��{�J~Q�V�V���
<�R����]��a��
p_�R�|g����r
�=w���]��������t�g����V���B����[-t����n�����^B������yv�Bw���)�&��P��k�#�\]<���R�${y~�"hb��Q�3���0Z
tH3���)c
��]
t�5=+��j�-c��n������vm���Bw�����Fn��v���������1����>GWh��M��@po4tXJ�0o�
ePm[��Bw�cd��.�g�V�r��2(�Wdh����z��_���6��n��.<�������i����jEvStS�>^'���h�)�)���Y����Kt�cHnpCY ��)q���F������t'����
nHvf�S"e�{�'���v	���dg�;%�f�K��]l�npC�K�;���~��.�]���Sw	h�Ma�hP��}��7�����^�$�+K�+��N����/Y./;�Te����F�{��Z����#'K�%<D���Z6�`�C�.p�S���$�V
^E���#��(��S�	X���T��,}�-�!��/��J�������m-�%Rt�[�k��(5u�VE�F"p�S���8�F���-���"�S�$��$�f���I�M���N+�d�[l��������������o��X;H�WzX��-�����O�W�h%Q������X����_N��,C8CR�;c{[��n��2|>,w-y�cK^��%� x��O����e�}�*�S:������%/k>X
?V��/%p,O ���0����Z����}�[�c�����<BD�U0�P`�i��>#:%���3i�#:dZ�[>g�GD��������$|���������������Sx��]�|E�D���V�#"��mE�1F�A��H��C��+�BD���w�EA�T!�����j�$��_I���N���&�r�k�:�"��A�����T���I�4*�����|Pm��n��VJ���~���.���.���+�����.�8=��N��i�~���������+7��1������t���N���.s�.��.�o�+b�\a�E,W�K&:Z���E����]@��mD>��A*;.p��w����
�7��m�b��g������g�����\�ZKAk)�����rIk)��E��w�2���w�-u��2d���g��Wdh��@t��	�P��d1lZ�n":����������k���������V��@���k[���P,� �R��5�������R�V����h�������Kt�����	�CIR��d����|w�>�u9�f��(pC�3k?��=AeB������n~��n��.<��x��
��J�O�fC�'���,g^�(����/Bx�`�0K[]�eC":T'�{*z�(Im�mD%�V�3=�9\�R�q%Q����l��6V4�Yai���GxE�Pt�����J���U
����.2(�X�#�����\NQ*�N�`Ct����T�C�"�C�N�`x�Q�����
6DB����=R ���1I�ge8�N1N����}OE��L��x�E��%�������������>,w,����]�]�B�V
F�R_�jp�8�P)CM���:��~��n����%���P�������3����U;l�FT�Gt%�Aw!��H�6!"H.3%G�m��D7�k�L��@G��,;�L���!�_:��(�K�IB%<���
$4#;��@G�����S�m��^�W�����*�c�Je�������
t����c��Z����]�ck�]��Mt���S&l��2a��T���S��+e��C?E���a���m���Tm�w]j�������G%�|N�O�(?���[�Rv~)��@��c�|�E��F���C�����*6��&=I����Q�Lc�5��	���@�!Rv��4"eW�7�������B�^O��%r-�a�}�E��w�����(;���<N�c����b��#:�)N���'8���{�1���2�x3�L�R!":�����&<d���6r�`�c$���4�����Mt`����%�g��&:���-�m�c�UvE�&;����<�3�������W��WQ��('T�}�Se�8�A��}�UFg
�J��m�
$:��n��4�wqW.#�0���(�Id�po�����C"�5D��O���JI-;mS�
���#��_x����!p�5�x�Fv��]���;?]�6����$6��Df�/��/��]|��I�T1�-p�2\���\��$6\��7])���
l����)��U�LI*
+.�Q�c�r�4*����(�}��]���)�D�����f3I]y�R+�j�I4]!F����
��tz"��|Z*e^�:.��k>-��&5+.����W�������;�.���-���6���#�C�N��Cx|\e��JK�i.�����]�����7��[>.m��u.�^9��\&p,���E�w�7A�^���X�#���k_b�:�������Zn�s]��G���]��N �����������������H90V�M���t���a�";��
:9�!7-p��=�9LI��\���l'7��h�/�O2b�R��M�������c���*��_%x��>1b��*�^Dv�^�(<-f����E���bv����[|��6
yy����x��h^�������R������(���{�'�'W��b��Slr���A
9O�"�+�S����
�|�\��B��	������n\��+�)1�t�4�U�U7ROw�K
��\CgA!_�c�3Vo���Q��P�Y�����.�! p�QDw�>
��wi�1����x��LJ��p;��V���E�dC!_��C3����q�U���n�
;��+�|
��,Z�o��r�tA�5��"�m�H
{pM�3�L(�t��	��<�mr�����+�����N`dm������4��	���tu8���b�	�s����
�N�<��]Ot��-�b��\��%����e�"�(pC�K=[y��S�(�j��4��.<m�kY�$��2�����:�nHvf(��k�.�D8�f���������Id�{�O3=^v=o�>����<����a�����.|���$�������n�DvR.��a��1�����g��o�!<���wv,��������&(t��
����p�o3*Q�|>2�M��V�n�e�x\�CJR����'f]&eG�O> ��f:���L#���<�%���S[M3-�C����g�i���26Te���t�1���?���[�\�/���i_����xx\��-����?��oy������_����������G�_����������W�cq�?��/?~��?~��������v�/�����_�Gx�D�����o��v��P��y��G���q��h���qh��/��\����S���m;���.�����(J�w��>[M�����P����0�x�#������2JRq|���<�o@�-������L���i�u�$��L�f3I=�i���e�a"E�|Y���������):y�%�u��q����KSEw-p�R�]E����o\#<�(JE��{[E;x�=�P����Q�H������*�t�.������=���y��Y[�����k��+OJ&6�b��RhWV�lj�`���G����HS��b�G����cc{m{���{�5t9�d����-��`���9$���a��Lt�':��%�O^`�k!�_����'/��D��g��Y�'�v���LVY`�/��*1[�u^.���Ke���W����r��I��]}�R���
�����DD����Q����4������/p�	~��
I�xS�~�8
O�����m+��F��J�9��F�0MS����|��D�i4#21e��j�'�6��>��G�o��yh�o������0������Xr��~���0��[��o����m���m�������7���x��w������{�b@�E���7���G�!���q�����aq��)�V]`$�W?�:�K���)�m%:��{���j��LZunb�c���gu��)>����2�m�%:�����2���������{����$gR�1�s�M�x�+�9�D���w�f7��}K3H��ob�����F��X���8�qOx���e�$�9���H����Vb��K����&��fV�#S����8(�&e����muvm��?�
]��n|�-�g��,�>�@�5}�)�U�gJ��^�0��Pw{�:��z�S��]�~{���.�/;f�%#��Y�}��j��JFZ��&�"9��]�~{�k2������t4	������m���%������3s�~�?+��17=4a��^z���"<�0wI�w�4���|������Q��p���D�\d.x�S�\d>(��]�|?�q���n2O��iY��n���i�G�s��������K�>#�;���Mv��=5=�4:hwy�61���2h�#�Jlm�Mv��=5=�01(w'xd#�1\����<��n+)�V::6�	�[����z�ay��|� Op�!��y�H���zj���D�@�G2�!�_5���+W61�]u���j%�;V�[
���������D0�v���D�D�.��Q�x+j70r��8j>����P��6<.&���3�vJr��Fs�������9Hx4�9����R��j�4���i���8��,4�kz�-E����H�jz�xUo@���-�t�^�
mxp�o��S���������'x_��I#�"���A����$�+���/<v����X���a���)=%����Vz�������h���^	���
qO�7J��7$�������)=�I���VzUA����"f��J��eoHz���Fz��M���Sw�$�^�(=��3��Vz5RA�7$��_�s��+��4��)=e����L"=���!�jp������@9\z����=�1sAm��=����Vc�����N���38�XzH�N���1��Zz��,c�1�J��)=�
��K"��*��c���������K"�>���U��@[�����W����{�w�,>c�1��+�?cZ�M�����^���b��Jo`~o��rDd	v6��{�g~��e����?o�w����.=�8���g�+�������m�_��^�Z��p_K{��������>�G�����7�������v���79V�G���-�;��8�E����=����1�9k���~��^�@��!� p-�8��v��	���O���&����i����DC��
g��������	�����R����Q��7c����
��k��&-���F�q��������1��
�W��6-��Wx
�����:��� ��J<�e"6���r�]���v6-�����
����m-�y�?D�_�����k�{�=�����(�	�@�r
�x�7���Pk}6��%�
�f��\!��z��z���G=!03��=��eW=^7�/��������Rz����4���J�i�����@WgD����%4[+=��#�wW�D.�o�����y�����k�������������_2�q=���'���r�w2�
nHvf�O"e��@�p��@�d�A���C^�y���Dta����lWP��y����7����	�d7]�_�5E���Q:e�W��;D����(^K\��]Gt��GI����e��Id�Y7��"��7�2��k��4�c�3(3H��F�(C8���#�;;�G�7���M$;�(������*}e�ps�71�2*>�6�"��&F=S8�r��N�)ymVW����������<�&*zm�U�1�2��('��7�B��<��s�~��&�sXh|���Y\��sYOt��=\v�Y�����
�m����~g�k�Y��}qp������m����;jV["{p\�<|c��.6�;�S|ce�q"�MD���������MfqE��b��
����/�2MC�[����g��d��|&�fi��n���Fv_2e������$���C��f�]���s��{/Xy��J����M�$<^0�6�Gk~��e
x}��[MW��|H�]y�����T���.���'J���y7M���*�5Y��h���R+�T�fI4]�&)x�S���(��*���F�
�F����������������nq
��i�vM�|\�Q�X�$6��q�u�v�f�������4�&�E�����Mw|\��.����y�N��E1i4��q�����N�V�=���6�+3����w�����W�(i�~M|\��6���7�!M+��D����-TW�&y�G>.���6=�z,�C����d������M�I��
�&>.���6=��&��T7�'�4	*�7����K�����C��4=W���1���$�����������������M�l�i%�Q�������i��a�����$����4&����4}t��c�
oH����h�Xnx�S�>�(���<:G�=�����+�Q��p#�{j:����G��|��E��4���6�t��%�������T����/���$�f=j����K�F���u�(���<:G�K>.�2H�Y��k���r7���4]��#�C�>:G�+>.���."Gf����K����9�D��4}t���|\�!$�Y���t����������> �������h[Jb����n����:����(��%G��|���Q����r���-��m���E��i��Y����vH���vx[��0KB��4}x�����i+��f���K��s�G���T���z>.}��@_��D�=����i+�������
|\�1"Q��l5�9"��=5=:�R	c�%rI4=�q���]O���\�����2�R	c��wI4=�q���v��`OO|\��mmz�(J%�Q��%����eRZLb6�������n��izF�����<��2+C���m���������B�
AW����"p���v�����������������
(�j���k�����=?V@���D�D�9�H�l���f��#��u�r�����
��@����o?���D�n�#�m�I�p�xH��K9���W�.>���W��6!�`�L#���b�W���'��u���R��IX:8-w!��D��J0��^o���_'0�q���C�\4W�zZ.��W�I1�Rm��+ec�u�D�0���]�!W�6�"rGn�G����?H���+��W������KF���F�%#�R�����F�|	���D�*c��"������@,�W��e(`���)������yDb�T����7���Z�1:0+����XM$��������A����Fp����g"V�L�-W�:d_*e&������w^8�r��z�	7$��$�1<�	�7 ����1����<�n�-�<���B�6��^#x��
�YSc���B����,M���S�'bf��J�@�H���H���7����w�|-c�M��2@&�%!�
�����kuteN�}&`�����������$�������w�~��u�����|�������_���������~������������5�pW��z
^?�g�i����?��/��a������Y�?���7.�m���������?������������/����w�O�]����>��h?��������6��-���X�������~����?����_LU�@�r��e�d=3����v�>Q�u��j�^B��;	������}=-��<���s.�~	5E�]B��z�Y����	��p�Z�=-�����E-b��4C�ZbDq�R���&��������;��n�D.I����
�D-���!h�$QK�La���y�rd�*)~�9:���I�v��\P-~�J��f<����f<a���
��b���i�3�Cm��V��BwG��4�\����c~1^H�83^8=&v\g��fe ��<����h�w�_~l)�FJ��
���J0[�e���)������~r>��-S��2�����;�����d�2mW��z���*x����V�]��N��=!i�W����I~����R)=�������g����{����I��T�@m���V���V��|(`�����S���m8���xI�8������z��S}FJw����S_����H�3CG� �-:�9d�aZ�6����F~��f�8�E��dfS6������#)���<���(6�����5
�^-3��H��{�S=�	�����	��|���W��*��Y���ge��U'�lb��*:�%�������
�����H	o�(���:fS:H-�"��>�{T���kU�zN-(��^~�|�X9��r������z/��=K�J]X��}U��Q1���b��x*��Ub�CPi�J����������CP�e,��2��g��P��o�L+J2> �u���2�54�:\�Q�I�+��f��4��D3n=1*��������jq[�j%���F���������������t�[3�kg��������1}�v�J���:A��~c�2��{|m-�rQ��+n�.\���d�U����t%p����k�r�JeV}#?t�\`%��`����T`�4#�������*S��*5����	�9|qkS��\D����
	O��$^Kx�m��M���F�S�/<�J�n/:��CaK����rz���^pH$��������<�S���M�)�<GK����Q^�o �����^T��>������jbET"�C�����	Q��
�������{[ME�������'<���+�]�h�@?C{��~7M���w7�:��y���R*���.I4]"V���i�P|H�����|���I����KU��MW3E�u��?x5����9I4]�q��gl�A�5j�>��������Rk,�v���������ok�
���m|���K�;���
�������o���~��6q��]�M>~�����|����UmEj�y�Q�O4��!5m`~�	��]�����w�M:v�	��-��?���;��O]��m4f���Cv2�9G�]��h_K���~@!����E���Gt��nHx�^�(<e0A���D�z��
	/��B�C=B���b����R��z���l�.7�o��B�O���%�By�������[��'���i�W�������%�F��%�!��OHx��$�|D������M�W��^p>a��6���J��`E�K���u��*r>aQ��&���F�R���R�<*��G���S�_?���������R�S��i>�>��X:W�6�.RA�x�x��W�"�$u��H�80v(��c<�K��":F�]�h�~J���&h�$gB����0;M�l���.��\:bW��������%3nO4��$F��z���"pO�RGlt+�7Z�
�#��!�l9��G��F����{g��1!6>m�,�f�Z�}��lT-
�fJ��b+pO�Rl3��I��6��mmu���i�D���w_�}{E�({������.��+��,{e��/�O�#����Jx�}��rI'���}���W����Jxm%3���n :m5����Dx$k�Jr�k��7�D=m}���^�j:��#��� xC��k�^�KE�w����)xC�3k�4��%:%����>�Lx�LX�Rk��tuNt�s�������.�����Cxh`���#"|��l��Sz��j����(��uD�V�
�FqQ�
�5����@�o3J�yW�t���n��G��-"'%�"j���n��!>FDz�������
�V�]AQ*����Df���ic=#XU;)�����L��j��)�p��	�u������7�:����?�;�z�HY/�(�m��r�����J��D��7��M��|�^�
m��P42�����t�t�k�}�e`�H���U�g��#��=��-I[w���J�;����?���f_��):�,^�c�fPZi#���R8����j���>���a	��/�~�9���������H�s\e������N�Cx���J�\��7�(��v����XK>����C����L������������Ry��������QI}U����������R��]4��L��j�����<;�&E��A��5B�&�T�@t=_�N)�(S�l�\/�!�%p���^`���S^�����(Et�P*p_�w����
���������c�5��b�#���b��':e��
�q��1Z���5�	�\�]�x��'m�uDe�qTB����v���H�sM���km��&�c�!s���
��n�h�B�&�-��^�!]�>�f^[����y�-�*���F�3�`,�������l�l��CtyNt�O�4R\��H�
��������!c>�6F#�%^�;F���?~����t�c
�NN;[��O�z��y�&~�XLDg9����K��|��K>�s
b�7�N>�w�w��f[MW��T&8(}l�4]!C,xC�N>�w���}OM�E����J�5��Z�t�5�h�iX��������f%Y�H�
�Z�_D�G�Z����:��@�
���m����K.?�3�MHSt|[�����4Ud���6r��u<����WZ����z _��J)�_ 9�����^��I�_
���]�����!5(�C\����h���e��������(�������d�!EGPmm����E'��@�$��
	/����������:m�1u)p��ZR��������r���b�����4�+2
/L�8�l���!�%����7pRR���m���D�).�:=8����>i�J�nhCs\��cu�����n4�"{Ns�[���ys=E��������"�I�|�*�S2	�_������,�{���Mw��y}�z.����I�A�����S i.����ZW4/N���C���O�����N��cby30�Sm�d���[�@�i47��\?���It|�[���;C<b�)Ie��z�/�����T�OF��v�1�	`�����D;���vZ��h;�A��>�6���Ip����i�&��b���<��0}n�K�E�6|L�C���]��<��	�#�I�6R�9���\�c�7*�'���
�&�"�6�2(��|�:�r���\)�c.i
��3���`gGQNZE�eC�"<x^�7D����&|L�����X�y�%�7$<�����������<�R��5��	��������H#�������;/���+��7:��f�S�jcl��@��^�-���@42k��X��$Cx|>
e���t���x���,��j���%�C�N>pt����ud6����������+�F��(��B���+���!MkWNM����L$VV7|H��'.��q��	�6���Jx|\��Mv�����2���(��j�3fg�t�m�V��1;���}7M���T�n��q���}�����Lt|[�������m���h����z,�J���^i9�Pj$G��q����W6�e����~�	m��� ��� LYFk�A]�m�M"�GE��>������-���op����>#VM��'.�P���I�6�G�k!<����"�4�)�p��(����S���<���
���i�:"1F�Cx���i��D��)�p[�:v<�����7$�����@x�~�-D#t#����R��&F,���g���Lx�w7U��Yb-��p���VZ9�X�cy
�>�����J}V�N��V.�%���p�9TW]�&����]����\��0.3OAo��,-�����5.s�����
��E.N�����FH`l06
�L�l�@j�DW]��J����	��:�{�q�J�
���u�{/	�:ZJ���Y6\f�����F��������)n��JD�]��$-Kl��������u`zD��s�L�h������N*3������=���#3���%��$�F*s�{<N@7��*icoM���&�
l��l4Y�y���E���j�1���L�8Q�����d�f@��������7���_�kr:L��}���Fx�0p�^���D��i���0��7$<���q�������������V��l,o��Lt5��3��/�	O������1�����=��������Z_��<����D��	/��y�>����s�Sj;y���CH$x���i��K�VX���y��n����56�M���Ri�s�����k��6���P
x-}R��XD�v2�	Yh����n������nwkM������`r�j��kr7S��4��iYL���t����l��
iz��YM���{��,bE�H��4����t���W�E��r�D����:��t�tzN?��q����Y%;�7����F�k`������]����e�Y������e|��,`�����Z�GM�0!xC�w��0���ez��,`�E��1�GY3�Y��Z'Y�����^��X�Ht|[�;������7=����.Fp|Y�Zy�����v�:�]�g�G����
�gN=:2.�]��o`Z��
^5����p�������/�|b����<��$�)���4_��t�/��7�CG�z�c�=��jX$D����i>6
�@�eD��*:��E���v��zU�C%V������'<�q.�6��tE��;�	���)���S����5
Rt�@[E��o@��;��.��
	/�������|B�a]����S���*�$�sJOI!h�O��'�KK�>�B�i�~����~aCY\OQk���3~���.�����Wj}:���V�p_@��� A�w�l��l���1�`�*�2������7��v���J��&�/���������M@�7��_K@tq��|	���D;�1*���v�y�7���)�6�zy����8�w3c�sef��f�Uo7�;����<����|���k{���<YV��4�����Z�C�%p�F���i����H��N��y.��5�\.jD������)R6�D���o�_�
�H���Rn�l_��F�5�f]��XY����Y��
�Y���z�N(��
�X�~/��]���N�p}c�	��u9�i��v�Dxo�.���M|'���
D�<�����y�tJC���5@x��{m�����6��y����jz�S�kNMD6�V�. xC�N�C��@I������'�2L~V�j�����eP6���w((i��=5�����������e����""�};y����erok���S8�z�;=�q��y����{������m�#����:�q��K�����c���u��}�bQ������lC_":���t&�%�������L
����Q���&<x���zG]d3o��f
����k������$�&aW��~�:���/��{��Nx#�����:m����SR��P�$�c�R���b����Xh�Ku(w���R;<�l9��P�y:u]G�q�g��y�Fp6M��CDYh�<�I��t��
E�����C��c����4��|�:��b�:���)�f��~����ES�������T��0Q�����h��Q1�����~^_�����h��6Z��@*������W����V��C��U?�`�s32�!<��H12L���
���h�:��9�)�I~���D�<��}�X�X�JVDRo��z�Wf4�9��l�D�0@�.
9n(sC.]N��M�Jb��CVS������99��������P������x�9�)��dd\V��0����HN��/��l�����29Z��c�����FS	�n##�����n�U���,p��3��L�m(�y�~���h#j���i�i��6^�uD�<�E�i��7�F*4��r
t-=�F�����`����4����\��N�����0Z*���V�Hb����
_��6����v�xu�����3����jd�$���)�^��f#��RQvO�p�q�T��o�t���n�����@\bE]G�o�P�Z�����
������Qz��jz�c2*m/J�2���^�MW�m[MO|M�r�����O��<-Y�1���)T�7���C�	o��������(��m.�4`���������C�	������MW5=+k=\��T��C?jZ��r����y����{j�y�R�tz�<����/tF��4������we������m�7B��n��C�	n��}SM�ex���QV����7�����r�W9�����r�n��\�@p�/�]�N���S����Wn�����ra��xd� r�`u�(`��Ct��W�(�I��!�.p���cB�R�N�LbD�%<�>*%��������W^O�����	u��D������JK�kST�(�C|+e�������Ot��V�_m�J"��^�{@���N\i#|�)*i�������^�1:�+����x
i�71$�t2uL�1�*pC�K�ZGx����������S��S�����JI�n����o�&��6�Fxt\���_�:�(<m�T��:�Ch$x�������{��L���y�m����
+$�*VB�:�x�O����S�M���7,iw�������G�����yq���@wY~XwN����Y����y��,N���'@�]��HB��M)�X4���k����R����
�R$�J����<9qF�XQ��!I�''�v�M�T�.��3��2��i���dw�%W��+e����\;��p��Mc�52c�=�����J��x;��"��c����2����z1�H�����v�e�a��6�H�wm�]Ft�����p���i.#�������i�\Ft������S��v\�R����[����S����M����@��M]�5 �S������M���D��G.�������mv%�.n�; }�
���[���g�g�\�.p���k2�������3�	�3�&C�E����6�Lx
�L�)�����R�=��sH	����{BM����A�[�o
��4�p���y'<<�6���I�F���
y7M�E~L����j��u��t�},���K�������J��KOe�"�(���J����@�������i:}�(��|\
�iZ���Bx|\J��6������o<�(hJ��QE0$l5]�q��h
6�"�%����F	��KNt�*}�?��|\�7�@�hi�o�{�|\��uT���#	�W��M����|[�r�n�Z��A�h9jZ�\�r�������c?��	����&�Y�ie�]�h�M^Y�v�p������]��������|�'
0�qR~w�	����*��":
0]�VMo�X��+�Cme��b��Ft(��W��4�]����}���-Q%�!2J���G;.��+�Y�[��Ix�����tU�R(����t������ �"���oHz�{�.(=�G����'��^��Ox�K��D��+��=���S�<�g�B%:���_�����_���'���^�X��������E�
EM[���(�%�u�&Z����7h�����J����al+��y���zGt�
+e�����:�����ZXi&��H�gfv�Z	o�(J%����4!�/�!�*x����h��'Fe����<"$p��+�
y_����t�������.�i�j��Vo�n���|���x�J�����l7c��\����+y����8K&�P�>G�+�aBO��+�Z�_�L��HO��L���
:\�](��'��	6���
��{������P����
�z�S��e�=��A����k�Lx�t���ByCN^GxaG+�z��Dt����	��_���g�U���?#pC�K��^����Pf�,�����������xB����%%���<p3;�1������x�T��j���t�y�x�fv
c�����/���/x�S������#��j����F!���'[/�!����!�k�Q�J���������
��N�������n���iz�(��O��Ax�V!�k[jm�,��q������������������z��'��k��:�-�3vf�=�3����e�A����������~���I�5f��'A.2�E��V���s^I����P����� ����+p��F�=��>TK>�z]�w{m{�X��J��f�Tx3���J*M�X�gXB�D�ng���.L3!�-����������L�)��-�xeA�)�=uq����	^�[��G�w;i!��*G�)���-��W)'������R^8u}`���S��������}�<j���F��E�Z��VBL$=$.�Zq��	�"�/
���j�k����$������,@���i��DQ��bq
�?�g�V�U��l�%Z���.�?��J������DT�P;�G��4L
�����j�I��y��Q������}�U��g��Swq�R���O�cJ�iIt���jDt��z�������@�x`P���hDY'���>����7��=�J_�
��F���t���l(��~��]Zr�5�%O���0K�xK�:O�!���O#�:���>���[�ze��	��5W���*f��N�:�� �Xs%^Os(e���1���]J,m2P}�/��
����
e�\Np�w��+�:��8��P��s�}���
Q��o����Lr�u���Nt#�)�V��p��8,xC���kw��8<h�����F��k���8<,V��j��

W8�
PI�����F>��#UX����z�5�����w
���/q�"{mr�A����
�P�"�\�k2J���+�����i:�d�<���b
������]��)�q�
4���o"�(A�j����*k���"���[�@�{j��)Je�MQ.��t���Sr �Q�5��q������Q��T����h����+��&���{>.���V���xd����ovN;^���2��J��Alf�����+=����#��������>~� F~^3�eI��8:F��R���*=�y��+�L��D��}��n���|�P���${G��P)�l���������s$�<0��:_��-�C�N>-u�����V�PJ�D�A��������������	
d�7$��m�7QzJ��tf��<��:Pn'�^��f�7$���wcx�������q^�QzJ�d��B
��^�6�C�!x���/
����]���!���J~����q����� f�������
��U���>�qE����Gh�#�
<������</�.�9��\�"���C�BZ����H�7��Hw�����S���TF4R��hk��w�c#)�a^�8���V4*�W�)��\�QY�4fC����h%���T������]yb������i��s��{��D;��[o�3�d���)��tp�CW����(���D���y���Jk��Kl(�D��D�n5f#F8�������A�md��E���XA����F>�
�a�h���<9AD��H��dx%�T�2A$��L���&:nHx��q
�7$<�I����h��q���Dx�v�7$<�Q���]CtJ��x�%�Y���g7�<Nxd6O�����d�I!3�JPl��'����*��fK.��
	���(��kx�(�eWi�i�����
	/���$��������
�����Y>O?o����1�}����o�i&�|H���mr�S���i4vRMw���7�4C�.���j/|M��=�L�k���'<z��MW!V��}�}�j�+��>.���6�g�����M(�	��y�G>.C�>qy���Nt|[�����	^<0�}��Y���������������M~��LS�3	|<��)��M�.�A)~q�J���XA��������	����9 @��{�K�e��eB�y�j.Q��
	�X����vs����4$���t&
	D����}�7mf
D��*��'�X�����65$	V��{Z�>��_hZ�hjz�|�n��l�>�5'/`���9
+R��J�l���������Fd����a��N�r����H�wdn�i�7P�L�i���mZ���}V��6}����{�|�6(�2����K:�o�-�+�`���Fx��o�r�!4���w��^��'��)�p���=�������O��Sz�CT@w_�����	O���4O��S�y9���Pd������	�F����w[>�vF�p^$E��f3���9������V��nT�{�VnpCk����y��E�D�x9��ZE�;C`u%����p��2o	��(�B�Q�a��	o��sK2Q�DC�N��w1d?��E��6��py���Ook�9o�\!�o��Q�J�|����z�+<�������<O�30J��P>����8Cc�7N)
�6]3��+��(�e%b5P��F�0�^����Tt��������6\>����(���i06\�ky�4���ZcW'^�@�
?.wO���Kt�)��j�]�Dx`�����?����J��quz�<��}��s~�����:�����h{7������]���7��x�}t�%/����y�����<��m�����P�5�@u��c:8�V���A,�m'J�i����z����7��������G:����kM�i4=�mzR�jz�����6=����9��'>.��B������e�\�a����(ge��7L��������P��'��
4��e�\�a�i��>1k�0���\��E��?����Lu���"pL������d�����I<E��c
� �0�8�aa��jf��f]	t�`t�)��f�����
_"F$u���nx���H�: �4�!�iBlH�D�KX������Nt����m��q�$���W�����o��J~Z]I������2]^�<%t��M��k�N�S�}���O�i�!W��J5i#�#�!,xC����4�C9�gZ9{-�����2�]+E����{,x
n#x=����V�H#=�Qz����-��W�!���� <8�7$���7Rz����k����������JM>������ ��S�8ufJ�����*�v(&�^QPz
���xsM3A�k�+�^!��.���1�!�X����=��x��������
������a#���g��S~�i����h��J
J�E��a\V(��\=��_G����+�~r�����'\(�3���#J4m�^[(�� ���	���O���z@lB�vIhc�MF�]����
���c=�V�C�Z��In�X��)Il}�
���h)��K"�����:�g��]��������]Gr����
�������
Cp�Y.�������+�$������k�$"�xg+�1�h$���G�*��(��#At�]/F�E.3�i�!�����ke���V�K0�����M�\������V��Y��<v�~&�#�<IS��h��G�jy7$<�Q'���/�!������br��Nk��u����'xC���o����#��]}�����!�c�1����R����Nx�e�{j��1�!M��
x��(���m��������}OM��'	��������oK�$�bf��j���/x�S�2J�mnoN���z1w/y�J�-w����y9���|�����ls���i4��6��b��`~��`C%:>���|�(������}6��+�C���Q�����x�
������5�u}�Tx u	�'�>c\0�
E��������G�eP�0�
�64���(�#�2.�����Ge�4�cp�$/�RNL%���Sr�P����\��{��Dz���a���UWB��
��e���+#�~N�������a��s�E�12��W�tP���k�U����AbO����=�����Q��3j�{���=8��]����M��'���+IQW�)�/Bz8���.<\n�_\���(!\���o������������o���'���o�rg�u��}"��a�����]����"��
c�]�������Mu{������m�E�"��}����eD�u����lqM�B������Q�j��7�CE\;D�r�b�e�@���Uy�\�:����A��%�QW��N��r;#����S�_��L
D@�
n��)����
�'gC~���fP��u*����W�`�-Wq��V�����������������z�A�L^�	"^��m^�/A����F~��b�E�r���<��=Fr�5F����`Vhq��V�b��������������>��L.�������8��D�9R�r�@t���V��5���V��H�FH/G�.U�p�&���$JX1��^3�����n/�>���H���Y-�P>�UV(�r3����A���]y\��K�"�}Ub$�_@�h�JV���w����%�+"lQ���x�����L��w?~�����������w	��K���������>l9�b9>�Brr!��O���������������Lt�]�3�R�����%�S��v�Q�����"�o��)r{����-x�WO���$WO��[/�um�z�,���s��+�
��Lw{�~�����������������������?�x-�_���w�����K���?t�����������L�d���=�+y�_����/���;Ne1�A������(2���o�_�^��������?�P��z�7�/�����W��z�����l��0�z�,���m,������OW���J	.��n F�m�U���^Q��M�^�
c������
�=-�`+�B�����Z��C�n�����GZrh��^	�-������DH+�����!�!LpP��k<�t��q����v�����|6�<Q���^`���)�������!�I��n��>�K�	���n��L�f���yC'^*=?6�}�\������}FA*mx*���}�:���9�uN����
�w�s]�-\'i����+���3H\��#����zV����g��������Y��=__c_�1��%��?�jm�)/�T� �����;�Yq��~���'�����[��ZJm�\�v��8'~��.���8	�%"��	�Qe�K�W�e�����2�W.��U����|�+a���
6*�b����h��c�7�6���d6������X�����.����FzcC�a����&�L���`�E�l���� ����1�-W	��I��o�Z����&3����Bz�D������m�����H>b�3��3���~�H/wHm
����6�y�\{����N�.�W�'=�
���6�5�l�_���
o��]H�9OzyC��7W�[����j��^{��
x��d�Iz�Q�lH	�e�);O|eO����o���+�B�K�%�b�W�@J��bo\@]S�U�?��H-�Ja<�,���#�bq>��������`��N�I$��!D�d|��7 �X6p����o.`"��.��:*/��+�������*����a_1o�do�_~���\��
�.�{���w^�Qx?�E>�N~V�GY^�����vW���K��zu���~X�eu��.?V��Ws���:/�(Z��9 ?�����U�����_��D�b�<��)���B#&�� �2�A���r����#�9g��K��g�����]�M�����)F[��Q|�y=�+Fd%�����Yg[�M|��I*v%I ��d�<=}�7���c�Y ��	M�)�w.����+3p�J%���/�&>!Z���\NpO7ml��l�����g{k����/o�q�{����W����&��V|$#�����q�2��V.�nO=�����"��3�{�9.e�E���=������s��=\^���S�x�������*t<������X�U,�������;���U�+?��@�����lP4/����]{��+��r=wZ6�������y7�V./����eQ�n}~�w�6'��)���~�U{4]���$��Up�8��Z�h���u	��J�O����eQ�7*�Os������������N���}���N��|��%�Z��^�j���_�����F~l�����r���bG}<�~�^>���]����6>g���L��|���&�5�}P�����l�~������������������<I�x(V���;�;�G��s�E-�~U��cYK��^*�L�h�y��h+�|1<\�o�h"8[U�<�:2��EK��`+7�4E���B��,4����1L����'�_	����Yh���A���Y�)R~
��"����_�+�
��fI��HP�.��G&��W�C<���#��:�{:��l"D^1��j19��:Op�\n���������C3��56�v��s���r+��'��P���U�)��#8��v)�������?
��#V~#�����wb�1�;�R��h��!��&��t?�	������o�-����L���\�?��v0���}&f���e���j��<�[�A��"v�Z�����=�������}'oo)�:��,X���+bSa��v%5?�w0�O&o/C�+��eQ�W\{>~��-p(�U������� 6(����G�7����p�s
����2�>80Id�[b4��\����N�7�O��c�o�	}��}q��2����3���F�9�xv�
��y�R����@^m��/�w�5�
��F����=���
3�vA�V|�'�p{�]�Y���@~���A�� o+�f��scd�+yW��w�iPV�������_��:�i���4�S���7��@�������Mcxj��|W[���]����i�H���]�>������	��Y��x����<��6-m�7� �(��Y�9Hz!8���>����Z�|��s���4����.f��@�����
��9g�m"�v1������<j��9 ������W	��y[��������s^�p�|��y�G��O�9 ����+=�=��o�L�����s@~�9/W���f��3i+��WL����s^��������_�+��nEr�����;9���ky�4��6er��!��;9���c7�`��n�C������������*���o�|��!�'hwr&m���,�9 ?��#�"8:��'�l�L��o-�UF��V�G��F��v'g�V~��1<\���?b��������4�ha�"�v'?��#��p�#��D�*��'D��.����~5w���=���,���u�������u�S��z[��M;:�"�o����?����Qkw�4l�s�������6/��k��7_]�7���<�|��F�s����Y��rq�a����,\U|����M���5��6�U��zn����&Fd�����+�����q^ ��~}}?b��R���z��
��LI[���Is@~����I��v'Y�V~r�������o���a\��]���� �T��]�M��M��8t�����L�<B2�Ts@~V	�<�<�+�P
�K���	@�4w���Y�9�~Ns�Os��L�b�'nP���0�~�M _l 8$l�Y8r�m�9�Ppdh��,����a1�p;Y�V|!��K^s�����������8	B �g�v
Pn��	�i�yS�k+�Y ��]'��3A��,l+>Lr@|v�G��X0�L7�o��c�tP���]�9��`�tx^/������"�\Z'g���a�%b;Y�V|�������j�!8�%�>�����B&'��g{H��������N����X��p��6�=\�|~?tp,�
���/��M�7�X1�L����(�p�u����p����da[��Ol\�����Q���k���c����>�mdaS�M~"De��Q�����>~��r8��� wP���Eh���Q���JdX���G�1=�^F}�I�os^�2����V_���c�?�Z��Fz�r9���^��7wH�	X�);�-<�t�GO�����>@W]�`W�O���y�n`��m���7������Jq`J��q&����K�Z�.�2�WZ�^"��������$�s�;� ?_c�{	r5y��}�S[��\r��Q���u���X7��V�M�����@��A����k���d�.�J`{����v6��<��� >>�a��v?~��{L����K;���j�0�7m��I�p��6�Mig[���u�������+Y�������z��
[�a��
r@|v;0$��W���1�#��l"�?Yuh�Hh�Sh���
�=\����v|��=\�u�hUqj��Tj������m����{���f�����mw�ey��f�ENB�T���D/�7JP��.�G�y�KgR\�$y0F8������������/��K�q�����}1�����9 >+vNU�v�� e�k�y��lS�n+>Tn��K�@p������L[�a�
�s��v��8�a�
��(�V|��x�_�a��77��h+��
V&!�V����oB'h�E���+��)<
��E�,#8<�v��V|�"�����5�k<w��_���In��_�xX0�g����+��]W�+�;�M��+Q^���u���E�����In��_���`��*��[��v�~1���v'��V~
R��b������R��v�$D[�����p��M�@p�
���m���P�bA��
�M[��@�=g�}=m���]f~f9�C�����h+����bE���z�kyB��'d�D����m��#	���6�K��� ��E|��4D[b��
sH�f���Gd��n~��{�8DS���9���e��a��X.���0�V�Q�`	0ys2�yGtO��mm~�
sH��'b�e�!{^R���J�"{�8`���	I�"e�[�OHrY���D�"���9��V�o�2\�V7�|��
5L��sF��1��9$@�H$��k�[@x��P�
��`���h���`�Rp����!��_K;QJ���u+��d��m��}�+����_G
��^)��Fc��r�k�r\�n��}T[�����J��sf�\�	��M(�,�����c�@�H���*����W�+�;���aS�UYM��#l�9�D�l����F����9$?�8$��&:���C=����>d<��h�&��)������"c�r����%��~69�1���`+����w]U��J�L�A'O07~�\��������I���+��[��[^���[�����K�������V
^�On�_���~�w�'tA����J����� ������?�_��o��/!
��UVD��������@��F��c��|���+�P	mr��D�Z�z����������2�����5�%OM���A�����
p@%M0�hW(
$��n��4<_�ydr'��sH������(�#�c�8;B���s�
pF����I�3`�T7�!&/���u�|s���1@t9!��%\n7�9���X���0g+@gU0�h����k�����I��`N���B�'�#:
0.�#Sd�X�������l4���0g+�9Z���<�8���
���9[V��!�C4�D"_�
��w'a�V�5��bC���D��M���0g+��'D��Y��
M���0g+�v D��Y�\�7�k�E<1�x�t��W$������'F"=(��9$���M�<�=�l���l
���"�P����/pw�l8�\����*� �mw)�#����"�v'��*��@tO�6��Z�
�7��U$+��n�"�&</i2�����?WZE"�l2����nx^$�dxDsH��gt�����#�m������z�����-��i|FtO���H���H���������}�M�vs:��n��:y�����0��p�96G�l�96����e�f��FT����&p.�/W\��uAn5�M���*_��]���q������RY����	Y��oe���+~{�ZU�������G�3_�\xkg*n\K��}�9���v��m��v�b�td:T}����{/�*��9�Y���Q��5h��M�� �!!&�Kt����=[��yO ��g�|)?2\[��=[��y���e�iTD�H�5h���_O
k�{��!N~����5����l�7�*�.8���K�Nt��
�}�{��cA�]Pp�����t,���������i�z@���t$�
�}���A�h�{�%g5<��2$c��	S�u��$�C�KNj :����:$l�IO�9$���j��{�-�<��!a+@Nz�!&'5]t��m���NY���
��X�9�-�<��!a+@Nz�!Z�k�u�n�.����C�^���`������i���+��YCR����!a+��F�*���je����sk&< �&pwvH�
�g�W0�h6WVr���D�J�X5�B���=��������G���C�V�9R��b`����PE
0G�C����� ��`rR��������RL�y'�����������r��*�EY�
�����m�?tp5�Z}Z�Z���()���W��}u����C%�n~k�C����E�B>���Q;oO@d�]0�nO�m�My����+$E�_d�_,�6�Bo�6��N��Mtx���o��L���
������e""�W ������+��(�C�K^%:����b���*�9 �&y1���������#�X ��g��'?����i1jS�V~
���Q�Q��b��J�r�A���D��?oS�V~=�9$?�$D�{������K���j+?�������A2n�X�[%:�n��nJA��o���(�i/N���Z�Kt�_��b��s$:����{ZCc��9O��,��
�=sH�VH�]�d+�F���F�m�P[2T���U�7�'8o�'x��q��P�`�b���#q/@�$��oH^�o��]wg1�V�cF�J1��B����u~��������Q��<��,$��<��+3X?6t�2F"����}�# N�v�����R�2e��s���;k�����8��^�VQ]+��Ut���Aj�5b��s��uZ3�k 5�@�����Z��_�I�9$?���q���u	�}�U[�5p]rH~����*�<�����tq��W�������ut��jys6O�?69k;? �Q���f��������2���#5L '�������j�����i�
��16����,.F~Y1[���(p�e�m���,
���8�y<�w_��V~9�E���bV{��D���E��/cl+?��r��Y)��Ut`��s������Y2��Kf��#��d6?/�m��
�s_�Cjfy]J�N�����b��c[�����f+�A{Ew
�Ttpa�;K��"oN��Ev��E�i�{1H��\v&�w~G�8��������*o�x�"��@��3qn)@�q��`	���<���{|Kopwfzm��#7�!��%_���=/_��o	Q)_oX���8y
���|��u��)�������l;�v~�Xv���,�b�X�^'���[A7]i�e+���^*d$��ce}�����=�a��
�A��e�R
��8!���*�&8��	���3<-n���8M�jmw�!D��|�����nzZ�����
�-�YI�.D�D�8!�w_��X�t|s@�V��\q%�}���y\�n��l�1��(�CL�` :~���]�l�/�.���	7:�6��^��Ucv[e����c/�����������#
��z���{J������q���^i0������O��c���i�cS��V�������8�v�����WLq�ap����b,����I�,,��`�OP��,�K�B�-�C4��[������@W=/Y�c�K@�$h����l�J�k��y�&rhP��'F�Od������9\�]tC�^���e����:m->?�G�C$g�YO���#f��@��<��W	��1��wgA�X�3%�M�mSo,�<���<4�$F-tH���{�sDg4���m6Rtp9xH�v4�@��'���_O`S�!&�	]t��e+'
����a����%`Q]��1u�cl+�Y.�����8w&/
��Y`[V�sH����.��@W=s��)�`�;�
�9��=$0`q��w`�|�a�E�����aHd
-���i��|�~A�ki�6���/��~���	��N�O�P�@�������+��6���5������q��|�B7�-?��S���,�������ay��eym[��<T@J�|�1x��������8hl��^�q�]t��F[�Y���c�
7�/��D�Hb���Y���CZU0�f�V�j��+�F�sL��R��� &d�@��������X,(�D)�>��#��o�S�:K�!�EAt����WJ7�l���Y���LT�L�a��
�����[T�V���1:c%���i���M�c��L@'�tJ�j�hZ%:�R�������2�����[���������7�5l%8�N����3�pf��o���->1")fz\����:C5�Gte�����`a+�2C�)���:C�5��h���O�IJ�������x�&QqI:Y��N�m���s��J�Nf7�*N�oq�����1I���\�HAi������txI��Q�?1&)+��J-�3�4�y],:��d(�����1I���+e:���_�d�+�h��s+>1&)[�W�F�b3���j��VKt��
��O�I��%F%�����V&�k�����]J�����bT���G��FM��
����O�I�^��I�,&�)�~1%��@��K	��0.�!	��$zA�������t�f�������?����&������a��f�h�� ]�-*X��w���<o"���u�C�$��T.�C�t`���
�s��a+$�[,�@W���$bo*�I_������r�:�b�N��x��9$���
�����I"�`�Q�(��0��*�C����I"�`�bxD�/��m�����;I���yva�/����X<D�;p1M���>��A�����Y�@��M��$��
p����h�j����w����;�;�����mm|mYQ��a����%pe<
�K=��VQ����e�Qo^_B��4l;���"������}���n��B7E=�h��P�P��q��[��p�+��
;�o��1�
%bQZb�|AQU��
�0CN�������y����8��j����Yw'U�V�XGt����8��Itx���[�6R�m%�b���N�o������������k�nSdM��x�p�X����m�TI9�Z���
,`_s�H��7*��K/��m��k�+p?~��Jxvo����6|
���=������	�/�b4@;B��C[E���0(��h&$��z�1��t����${������>���w"��]';
�c���7Z�]m�y�����c���������ub+A�����u/A��{�\M�lh�D��l�`���ub+A�O�!	Z��k�����;����d���ub+A��o[b�%h�|p��������W�Nl%�{b���$�J#%���R���:�� �)���s/N$:�<h��)�.��jw����|];"��>�J�s�z1���B�zp����Mvjx(�2r���L���g�t �2k*
�\���4?o�;2c��5T@�$hVUD^t�v\�Tn*E��[����Y���X��[A��U��dH�
01<����	$N����)p�<=A��%N����/���_�&�
���}	\|q���=�ltp5�Z}>��T�����]��|�V<��/M��G97p�D�;��;o@�x}7Z��*��
��%�u���w��������T�r}gv��/��P��;�����l���2q�Q8�;����3��9$@�H��?��tpo�Nz����V0�h�
�+l{��t�-�`��B���b���%Q�"�k���<b+���sH�f1@���@�Z��%��J�)�QI�����J���:���*��7�������=�����4h�i7p���?o���]���c�o�Y|���h���������l*�!�;������k�.�":HP��-6�J0o�Q��U ��0���0���	���f[	�91*n\������q����l+�u&���X%iT*���@j������RAm�!)���8s~��G��wgF�V�|9�`�v�:�rw���A��e�����J��5�3���F��s\���I�A����:�����<��)���Tx���U��Q�u�6���G��H|g*|����(&�4�u����.����
� k��9$������b����m����� �C��b�.��y��T��Kz���`��!Z�#�=��nK��
��7sH�V@�+�J����/��m�U��9$����P�K�_H�}v�9$@+�?V��k'p���m%���j��O��!Z�3�=_Tph��*�C�*��J�E7����J>�V�l�	��zp�H�Y�`�\��h	x%l+����qM��!V�=%�?�����tH�G�#l[��<3�h�q��1���X	r���|����#c	���F�nX����evZ��nrD����Y����?�h_���q�C8������[����L�a��bQ[E&�V^f_ E�.��6���d`t%1���V�qh<������
���46(��&y�L��+�J���O��<��K�[����x��%[��]^@?�_�� ����|���110����"��W�u���q��"b��4�����K*+����*0r��gqh��5B�:����!��]J��@d�t��g�d��R�����=R:u�3��&:^�&{�l%��N�=R�{P����I��e\�Z�"����n@����Ww��u2�-��6��@
��zOlDc� �x�KW��=u�������m\�i��~\�4M c�������1b��-L�d|^;�]`�=�MO�whN�7�d�~�/����mf�I�.�whN��y�w����F~�N"`��;4'�����Q335��8�D�.	���$����y1�����*��&�-������C���i���84[=r�	l������������YZ6��z���?��^B#M��Bf/��L{����=?p�6�k�3���R��nl��/���L{�]q�[�~���B����5s�vw����94����6�����T{��'�=���������I09�����#p�<4����-�C�/��������=�$DG��n��~M6m��5��_J�??���
���C��8�����}����M�!��::�o�R���0�YI�[���>y��}����@c�xQ�@�$�<�Ct=�UOG���� ��n��*�����Y����tT!������k�u�K0y���&�k�o�� p����,@����W��*�\7��k_]�Y�HC�S����n��n*���vM��0�2���]?v^�4�ze|�\E��*je���M	�3�}�pN|�����(�����]^���YM|�_�a*@�0�E��^�fY���Ht�}7�;�
�=��7�!Z���v��C��`+@�5n�C�b�=
�k�.p	:�v�5��:���05<�r1���6����"{k����?�����|����J�w1_���L�k~�U���>)�@��b��#(l8��N������npw��0���q���D����#(l�K7�geD�����#(l�qM��	���x]���C�K��Aa+ALA��N����
����9�A��9�����V����v������������Si��l�!��Jm?o=�;-�"��&��=�V<��7�|[�(�����U-������qp�Fz�ZJM;X���O'�n��b,A��t��H��'�w�\[	����1�����DKp"������.#�s�@�$���w�!�_��|e���gF��&���@�!�;��(�c�������y�1t��
���4�%�����I0��?�s�=e�l��a+Al���I0>�m���Htm�?�������d�l�u#�<�G�Kd�w����s8�:��VI��]%X�	�-��O�l(b+�r�1<�&/R�?-����?�5�q���+�J�2l8/��D�V\!�/p�N���`=#����k���`'I����a+���T��M��PD�:��I>3n�\�]��:*�uO��#����J����u����n��
Tj�����Q�W�
2�V���*~�~�������G$D	{��������������x	�9�?���5�qB�@@����Jp�^����a+����Ic�'����-��w&���t��{�������S9�%�t��RO�':�����W�r�J��%��������y����=0z�$��J!��%�{Gs�J��B��fW)VD���p����+@#�x��P@���xu�cO�8���\E���K��,�goQe��oM���.�t���Q��?��`	;����hx=��������#�����og*����ao�������w�l�`=V��pq�Xy�O&�|"�-��l����V��I���2bOK�_e��0�!T����VY���{�!�^���=�@6f����qwU\�]�!��3M4��._m���y��8��=���W���C�D��l����Y	���3_��W�gXz��
��
����P!�S��Bs����;jm�9�7���f�|����A�7�;�mX�Q*s.��f�l�����_s���b�d
����z�u���������qA��YQ�T����=���-r
|�GX����@�>&h4��n"��(�)[� ����v������2��.���U_�7��l�Y��Xu�C�W'������5D�x���[�A���
��::�x�=���*^KZ�����w�j������m+�O�`�O����l����=��lQ��!��@�������m+��V����f��c%��P%p����J����I�*1�KG�h� :t1T���ff��	�JY��oX��2���i5��W#�;>��llG5�`]�f*�C4��'���]�Z�XkS)��gxH�vC�p�V�1L�;S�������^���3DF�.#��b��3@6D�|5b�}?W�f\��q!�T���1�:�&��%`#RG���p���mR�����)�~sU�w��i�M*
\~K1C�Ms0���<4{�����Br&�
3�����r���;kJ;_BDF0�n`�`��������K4p	���W����YS�`���`N���V`'��iT[rJ�`N��*���w\��~����F�`��pS+)����/�AYX��L��
��	Q)�V;�\q�o���M�C���qRk�%�3��ub9������h��a��
�����������5{�6������Z{�����a��"�����'�6�Hh����b�!���h�c`����f��3�g���>�i���I�ns�D�mVZs������D�V��S����M��z"���v'W.����G��]7i>xU�#R��M��,N�tK���!�nic����J�����kp�	�E����"h)�.C�^p?b����s[��>�VE�7�cA�ZI&���q���c�M�s��������\�&�m�G�q�-�7�!#�������c���~>����*0�4��Es/A�����������>]��#Ob����0��3�o�}��:�up%A��^b��,���h��������
��V��;:$�������]J��2
0�x�tH�V�������Bw��N��]J��:
0� �	���*�!n	��B��}�UL��W���������������p���j���Q*=
2�,=�����:��[�v����(J��%:T]���1�"��< �����O\���;��?�
p���hV��������5����b*�����9$@�M���/{�c����u��d+@NJ���6�&�:���|�OL���z����,��l�|�������'��,#U�f��@=n:��.��I>��ab����5��V3)*w�Z/?V���)�f���H�d��`	�,�Q����a�����V��Q�!&������N{�|d+�N�`	0��c���&pw��l��9��U`�yB>�D�����?��id��d�v�5�=�ev�'<���{-NW��t]y����{q�����'��t�������z�^~���X����Jpd�P������t'#m�D	���+�[	rh��I�,x/�A*���A���X���`�����,��%:�/��������/?th�@h��K�������
?J�}������8�d���
���@N<�r������v���������������s_~��_������S�����E��O��e����|�����_����������,��J�?�����_�(�?�>?���s���d��~���Y��9�Mh;Q��2q�(�o�����#9����%M�j!�Tz��Tp����S���7��T=b99���2��N�3��2�V�{��r��[I?���TCA��n��w*WH�V�ha��9f������,V	#<o���N��/�W+��]��,(����T�@��~!Ui�w�BL�X3�T9f���~!U�Z������-4i�w*�
u����P��3����T��};���6��N����F������&���H���r�v���,��N�]N5�Tw��l��T��oP����B��bm$��1-m�E���j�2�o��9I���\���V�����6yIJ&�+`��������R��!�X���]�����X���m���e�\dmn���&��y,�����xJ�/q;g���W��t�u%>�V�����z�z�;V)z(����8VWn�m��W��At�
=>����!Q�y�����X3�5�[�!"��,��"����jm"w)�Xq������M���a=�v�������C��_���#��y����8�s���CB�vE����X:�3n[F#�L�i����Pf�����y#�F��s���������?��_���/���_���������������%��/���������������_�����������Q`���������fi��.��<����E=�7n�H�@���]����	�W���D\.E�|�"������-#I���7��pD�� �a0�M���j��%����}7���z��x*���].�o��z�4��Q����5�e�.��\I�E��E�*!�TB����A^�"�c���3���Xw��W����v%DN��{��:��>�n;�e��,�?��Yn\�?�y]�����]G�����r�;Npe������{-����#H_����~h��7���lp�����"�������{��w
�-�rP�s����}�[�&��G�������gRi��d�C���gRs���d���;�3���Dg2�m����!�>S\B�jJ�BM����7&���7�����o�q)!�P�J=u7Z�F	���z��w������w�X%�=5o��G(����`����(Kd
����B�e4w���>],S���#�V����t��9��>D���hr�cm��7G~6�u�o�� ��<���=�+�RjJ<�rN�K����`L���t���C����c��#�o�4��iL�`���a=�����!|���h:<�M���V�2_���A\�r;������+j(,��M���n-���fY�k��:�2@Fg�K���������L�6���~���m�q{����{0��E-;�\�Q4cG`�S`���[�����j��kCb� =����������������dj�3=�;��N��V��p�O`���x;��iwVE���%E��v?eq���� ��G�f���!E�������Z�+]����~ sCz����5��������_,��R)�-r�����}?dV�>�z��RF�Vq5���o�_��d�V������������|������Wu��D�sI��}�O��S�6��x��{;��|��7�o��U��5?�V���F��q|���.@_	4\w�E:�}
U���C�a�����}ek����%{?����na6�I��o�s�^I�p�{v
R��4�(��������-}�
�"������{}7_Q��E7��+o����_P�JNy����{��!G|��}�`��
���r��[3�Q����pu����'�q*\�cI
=w0�0��k��3��z�e�3OuM��6��O|h����&asMN|h��C��{���a�� ���r��b��9���o���s	��[�oG<�D	.��)�!��<j?���>����)�Te�2�/��o�<(Lm\��G������.E�^��~rO`��E�����=�}/U|����������2�g 5>���L��S�GMy��LixS���3�R�&&���G���6���p&�6���=g���8���=�g��i+�T���3���3e*iO��d��1U���{����*Tu�A�6!L-�:��l�SE���0)[z�T���Sl�����9�����&j�T}�M�>�5m�>��l���6U�bS��oC�j��)o��6�������oC�j��)o���������������Sl���miS�)6e����������;�T{�M�zm�;��l=��6��bS�EG���������iS�6��z=m�?%�n�Q������m=��6��bS��@��O�)[�b�M
����GA�����C�zmj8��l=��65�bS��H�����A����M��T{m=��65�aS��G1���3l���(&��t�M�zmj:��l=��65�bS��L��N�)[�b�M�����G1���Sl����iS�)�$S�b&y]Ny��L=�9�M��6U�zs��Pg�T����CM<�)6e�Q��6g����G1;���+,��L=�����)6e�Q��6�N�)S�b�`g9���2�(f�u��6U�z�6�2�9��l=
O��g�Te�Q��)
'����iS�)6e�Q�������(�6%�<�P����S��*[���S�)�S��G����������`��|J�Tm�Q�wj>�w���(�<5��<e�Q�{j>�{���(�>5��>U�z���O���m=
�O���O�����S��j[���S�)�S��G����������`��|J�Tc�Q�j>����(�?5��?��z���O����{(��)�S��G����������`��|J�Tc�Q�j>����(�?5��?��z���O��jl=
�O���O�����S��Z[���S�)�S��G����������`��|J�Tk�Q�j>����(�?5��?��z���O��jm=
�O���O�����S��Z[���S�)�S�3T�NE�:���s}���hU�tP}��9[��SZ�\f�U��j>���e�n���S��\f�W��j>���e�����S��\f�Y��j>���e����S�\f�[��j>����N���J5��J�lGM����O��r��&g6S��4S9�a�3���S������2���:��,}�������y��,}��!z��>�T����3O��r*K���\�S���������v�N�+�A��C���)ve:I�r��;��LGi���]�S��t���T�+�]���v���+[�����9ve�[��+�]��9�*?��l}��v��cWq�E��7�c�T������_N��3�����z8�������Y�R*kq�"6�Yf���j3y��
q��UD��X�s�*���i|:�#���RD��b�e8V;�[��w6��t�G*��R)"�X���5��a�P�#>��iQ%������9�zN[E���}��#�Q�RD��b�N��9ma����qo��aE${#������X�dn���kf|:��T�Nfq��UD��X�s�*�48r=n9BP�O���c�*b@$+��U�i<�f8�r��"�T��;V�"���3s�0Mo{�W�z��"�daY{Lm���T�c�K_�U��H�6�cy���O�����*����&����7����TS�*��<W�I4�����&aZ��9B8�Q�4a[��������6*^�	�9BXe�J����J�kr�6a\��9BXU2M�F��+�%���it�c���aM��n'��:� ��Am5a^�5\�\��7�4a_�5|'9��&L���CF@�p�&L���q�.7�	�;��#(��,�&L#�|Dy[j�	������j�:oS�:"���"k�%5������������,�&"��	L���V�1vQ�e+����K��F�+VU�sU��M���E��M���O�	��h{����m�4�.�lr��&�d��i�]�n�Am5acs�ogP��E�*)y.�_5q��r.������p1�0������<�6Q&�������w���UU����s�2/���~����������~���_������������Y�L�*�+�:gs��_~�8�9.8����������������p��?���~��?�����?~����~w�7���~w����������7�[�����4��g���z��T�����]�E��V��
�2~�����Xt�}#?�CyO������`���-�}�i��������C}	���\����z��
��/��y7L_>NT)w{�q���w?����OH��|	�����E�~������l�~����������������w_���������������������/?.���������|�������>��"���sb��������+wK��ai�/�,?�/���;�!]����3��@Cj|��3��u����3��su1�Lj�#��L��t<�x��LC���=�!�>���^����{2u
���T�aO�E���=�g��i���hO��dZ8�+�Su�=�����U�aP�3m���EUgX������hR�&e;���iS�)6e��������}y�T}�M�>�
m�9��l���6��bS��oC�j��)��/uK�j��)��/uK�j��)��/uK�jO�M�z-m�=��l=��6��bS�EG��N�)[���Mu����G����Sl����iS�)6e�Q�������S��������R�����$��G1���3l�v�G=���Sl���hS�)6e�Q������(F��p�M�z#mj<��l=��65�bS��H������ki���0^O��q��#�_�+��w5/�e����7��tE���X�KK�6�m4�xm_�D9����k8�k&�<�P�����Pj�Y�C�����C���T�2}8�����OLC�&�WNy��LC�&x���C�����x���C�����M�)?�����*/�<�P��T�hS��2}�O�r���i��x��?��l_O��g�Te�Ny��?��*�w*�M�3l��}�r�T~�MU��TN��O�)� ��iS�)6�������>�B�C��|���b5�P���"u9��J�}W���:#R���^�&��b��>#u�D\�d���Z��bM�����~��kX�+^px+��kX<Ts��l_�*�����T��|
+i�V�
�K��O��!��iD>j�z�\~�`�iT�S���^�	��^h��F��,#�F�5k��������_����V��Y6�"n��vs�;�k�������&����<��4�_����n
p��������{��m�e�����\�
��N��rq��57������n��e���
b#�>'`����M���pz}�_7cs�wy�X��y���.�=���]�^]#^D.�����c�!Q���F����������������y����a�x7i�y���<mv���YJ��2����S��M8cGM���#�����7��l�>gx$�6������
�������5$1�j��'����V�p�q8kq���������E�����]N�sw����X�u;U��J9T�v(��S>���������� �w����@�����GJ�
���F>
q@����<%�h�����r?�|�v{�Fm������F^��\��~���@�Mh��+@�����e:�Fk�
�E��������@�m@c���	��k!�{N�>��47}�Z7R�mP����<R�q�A�E:����$��z�h�S��$v��w�;b�w�%9�Iw�������6�v;a�#*����c�Q�9Bx9�����s~��Z���@�]��_x�����|��������_x*�G*�J!{EN���M��m����I(�{��+��y�~�n��iI8�������dJ~���/�v{A[��v�*�P��y��u�W�^J�/�<��)�P�di��,M�/������#��wxu�}��;��^���k�/��^�q�G*N�5��z����8����/<�PqwxM?������L���~x�����m�\J�w���mx�7j.%��cw�4���=w����o�;<��m�p��S�(�H�W�����g����<T�f�������������l�i����;hGm��]����Y��>�^;s��Z����E�?�9aZ��u��}r��������P��n�?�M��E���L�������i������{-�:=f��o��uH�.�
pWwi�#+��E�����z��M��~�Wj|��3�f��W���3�&����L*�7��LS������3�0���L�	g2M���i:��L��~�=Mg��iOO����3��h�g�|�A��h�gZ�|�E��`��Kr��e�K��r��e�LY�C�g��������8��;1����(�l>��?18��;��L�����)6e�Q�6���)��S��M�3l�v���iS���]<5x��?��lO
�6�O�)[�"�M�Sl����iS�)6e�Q�������(r�T~�M�zm*?��l=��6U�aS����������� {x(��)��SCI�2�o>��GQ���Sl���(iS�)6e�Q�������(*�Ty�M�zm�:��l=
2������� Cz���)����M�P�7����iS�6e�9�������?j�T}�M�z
m�>��l=��6��bS�Y�r��e�Q�>4����G���t�x�C�z-m�=��l7�
-m�=��l7�
-m�=��l7�
m�=��l7�
m�;��l=��6��bS�EG��N�)[��s��������iS+������iS�)6e�Q������p0������7������7�5HNy��l=��65�bS��H�N�)[�b�M�����G1���Sl���iS�)6e�QL������(8P]Nyx���G����t�M�m&��t�M�Ff��t�M���f��|�M�z3mj>��l=��65�bS����)9���2�(F�O���O���?5��?e�nd��xJ�������S�)�S�K�F�O���O�n0�?5��?��z#���S��S�bd��xJ�Tc�Q���O��jl=
�O���O5����S��[���S�)�S��G����������`��xJ�Tk�Q�j<����(�?5��?��z��O��jm=
�O���O�����S��Z[���S�)�S��G����������`��xJ�Tk�Q�j<��e�K�e��[Y�0��j�k�����g�q�����ne��Xaf�x��8bzg��@�XY 7�#&G�F�k��"�{��*����C�����'�����1#u�G[�Y��>��������b���	[�c�$@9���<�L���2%z��Z9h�&"a�/�P1��h*"�\�&AN�8nz��L"��+��*V��)�*�q��d�1��M=���\��o�(�T�N���v�N���B�\����B��0�n��c��5�aL]����f�%M��$�\�l+�f��W9��W��o��_�{��D�X���������'t������]�-|���*
��Wsr~����@� ����G�\Z11�#�M�V�M����v����N���������<~�W�o�J��"�zE�%���@]�������yY�W.�r"����<rw�
h�	P���QNa��&���b�
���qv�o�������C?W�!���c��_�G�]���I
S~F\�	���5|F��#�dw?�������9���L��B��b�+i���!_t�M��S����5�_F�+��]F���UI����N<S`�dTb*��f�Zl�����}��/e��L]������8/�+����w��������]��"7-�O=��o9��cO��s�y��{.��bB�������<�Tq"��~��bZU�f�uqM2����K�T��>����p��n�g��Z1Y�8���w�����z���rJowu�gUVB������'���4�&&����B<������&f����m�K��4��Y���|M�6|�+m��|W���,|����]A`��������Z�N����+���1������Zh|�������W{����k�����,��r�9��u�5�,�6��?���9QU)N����x���'�K�h>PG)�(����<PG���������W.���m�
vE�
��W���"��WUW�����n����U�������/�~��U�����|
Z���G�4>��z��]�ryl�+~�~�������_utT��'����Y�����i��r�#��(�mrKN�i
��;,�uM����G|�w�;��w��<�S��SG�������M�;����*���<*4� ��>�e�����lK`����,������\�k�L�%�*�Im�C}&����L%��G����w9B�3�'�)���e����-�F������z?��l��r����g������`���
�u~7o���b��{�$��a�f~I���<�/�3E:�EV�L�=����as�~`�� }	Xe��!� }��m�P�}9'�4���������!���x����]H��JU�5�{�����B.3����*���j|��3����<���3���UQ�L�C}&S�*��8�L�m��#<�����L�~fU���3���7�r&�Sy�=Y��.G�=�g��e�����{�������T�aO�R��hP��8�=-�:����+Q���3L���vU��*3_�����Y��~d��y���d
������z���$�o���#\2���������"�UK�m^�n|vB�$��:m�����C��yLD:fq�����j�VK_L\�N|�m��A�rk�]��\�g�����t�������7U��6��erf3T�����3-��w�����Z��uXd�I�n����9���a������S=$�L�N�%�7}H>L��������Y�C����&����&���������c�����Z=��C�;�c��6�n�FJ� �� r�����CyW�w��%���~Hz?R����p��C���ZA�3���!����o��|���o|`���{Hz��{��~�6��9�j���AmR&���)N����#u"�����g��c������b�5m�������Y�~����h�1� }���vl����~�^��7��xaJ=[�4"����t�.�x��>w�n����Z=�i�gfK���3�{������d����gR�':�)odf����3�2y���d�_T�|�y�2�3�L J�!�;S���<d��Ys`���r�Q�<S�/7c:���O\�u�����GO`�����c`��K�K�w�:�����������d+v3#��o���8���o�I���D���(��2�(�������-����m�"�>{�s;���V�d�"��=�����3Y���3�8��O8�%�r��g�����Yo8*����?�)�Cu�z����G�r�
z�����TX���+����KY��Y:\p������I����#�M���?�����$����c	�Mb{k��2anS&��k������p-�������OpM_��z(q�TCQ���U%X�/��p��l���k���}.xL��x����>uQ;��URTnl��=}�#�Y�����%��)��q���]�6@��O�~���y��4ug9[�.�j�
�k<���M��:\H]�<��4�CT}E`�4��9DA��E�;�7[��J�j�-i��j���?���*��-
T��Tm�^�#}���s.�4�*��NUW#����?���L��jz�;�iD�l��*[F�E^���X�����10��r�fG`�s�,(���O.2�u��n�z��s�gq�i`R#]��A�M��j&����Z��Y�a5���]�}�gc�)���.����"������r��z��O�Q�F'�{,G<�Dmk����sG2
v=����D7��<?��.����S�����?/�WA�(]���_����oH
��������BX��G��
z|�;X���[�1v�[56R�N�G���M��-s���r�`-�R�N��`�'����� n��zh^���,W�^�0�P�9L?�5�>�ME����U����#?V��PM�E�}?��d3�m[n���Jdq����X�S�E��������:�.�� r�u�������y]�S/��.������/� �P�:��vJCXNE��E������M���Cy}�_y����69��Xw�k9��n1��v�p�<+�h!�T��FZ��#�vD�����MS?���������6��u"�(�TN"x�����i��N����rTf����I}��,��2�^�V+Q���^����0�t�g�e��|�"��4�9X3���7m�mJ]DD��!s�p'��j(YC��"����R�s��T/�f��/�2�5�R�:��Xfo]����>r������3�o>��c9�K��
S`�/|C����0�u��u�.�&���wuW�|�= ��H�>P'���A��F����
�H,�qoM����U���m�Q������m��������P���P#p*u�����zX�A�������P�~�P����:���]���H4���l�#������a�itY]����C�i�
���0�p�XQ���:���y9T�C����V�I`��AT�g�"��:�<5���iua��~%��Fq�����C5�v`Z\z�D��:�;Tdi�1�ANi�@�
���0� %��lj��i����7��L���hP��"���]q�������.�-+#/�A��R)!���������6���m�<"����Xyr<�&�E�l������&��i�6Z���:kd.���'��V%z�#O���o9��l�����v�V���S9/�������T�[���k2�RGr��R�PMc�1y*��Q���H-8$���k�4j�GrLK-����C�&����/h!2n����<�q�Y���G�&�I�~A��s\�b�O�)j[�^8��y�y#y5jk�u"Ok9o���F�����I�r��������
�H��i�G����X�0/j�M�.D�*�F*�m���7�7����$^�1��F�X��i�<r`���F2��������x��I����9�J�������!�J2
��
}������!��dZo+~]����k���kL��(��T��m�\���+�K�6|n0�Cp�"���K�A'����R����8M�ZC��R�
�[~]�`|)��-JSrE
�2�����W�����\J��mM��@!#���lC��O����iB��#P���"�����Rg|)��14�;r��`Z�{^J��K)B
�A4G�������S�<V�4��ws�m�`E��_p�LK�#���m��j���9�y\i�O��(z�x�M��"�`EO���NP�m=1a9m���(zbNiRg��U"�5�X�q����d4��'��Q4y<rE
��>��������l})�F�S��W���F����(z��u�9-��4����xU�X^��L���9���Z�F��qU�wP��m�Q�����Z�F����$8A
����c�����RaEO����/�&U��i=q�����L��)�����R25�F�S�K)���L���������D\��c����d���j0��'���
�R*�Dm
���UC�x�M��5�F�S	��@QC����cE����jck0���
�79����/��4��*T����j���+T��'���z�3���V�F�5�or��`E�=�e\}+m���v�V�
�� y����A�M�i���Q4yJrE
�R{������&k�RiE��4�<�tj����S����"�`Ew��t�R:5DF���R�K����l�h���a5�D���c���<�iO)B
�Qt��M�)y�"h���������E��6��S���-�8��c��
sJ�qN������=��L
�Qt�J�idNi��S
��	�m=b�`�J��`Es&����l��	���Q7\���K��u�8�H�i2>�W~m|~�?.v6�R?M���F��oB�6n���5����O�W�����6r����[����o�D�>^�C���5����a*����^[b��6�������#s��r�&8lA�x����['r��f���O�;b������O�6g{��t+o�Y����t�g��[6�G^�s�=/�>F�����(�������E�����(�
�C>�������r��N�\���+��w����<��'��*~��ax~��]�nk�!�<�*\Q%�(k������/(���L��yAjpQ^���[M479�����X�G98z3������7�n.�>�&�?���,���3=��o�<�L�E���y;��g���]�T�Lz�2��,�M�#4<�:�#��,k7�#���3���������aO�U���hO��d�������aO����hO��d���q=
J����P��DO�����e�J�4���2�=p9m�?��l���6��bS���@�N�)[wb�M
����?1���Sl���iS���T���(F��x�M�����65�aS�3�/g�M���&l=��65�aS��/��MM����G1���Sl����hS�)6e�Q�������(f��|�MEy.�����r(���iSt;��
����]�hi�!����/("�X.��O?~��B��v�
�PJ���8�;�75'SD�������6ZD�"L�2?�tVRr�u�XE�Y�c��GF)��������#����cE+�n��U����w��v�#����cE+��q��7�S���
"�����c�*�����s�*�4�(0��v�w������B%]�5�X��9�A��'`���h&�y�
�yA�����S���Z�c5�=�u5��rE�'M���RqR����w9���|�v��
���&���s��Cd$�|B!]'J[r[/��
�'�������q�;M��6�AK�������2�v��J����R��/�c��z�`�C������h�������R��\F�Z/H�:-F�9�
/7�Z�������<>v��D�4�_��W�����!m�I}��0U�������Vy�����T��z
<�A���k)���V���F,������������^@##
���1���������V�snEii��Gz�������D�����
oG<�Dy�!�%G<�Dy�����1��:�������=qM] �-X��+���Hu�st��r(�D����~<���?J��
?�n���7����6M;Q�&���y�u�	Wv���������v���[w/��Oe�_�Fb?_�+�lK���5>�l7.zi��p�u.j ��Y�>L����� �����z�Ma���nE9�Q'J�Ri��:
L�X�
S`I|C����i���f?�HB��.m���`}���b���=�D�i��b��Mbu�W[��X3�P�i��H��E��K���s�mR�AF���������zSJt9-g�S�������\�g2u)��q*���&�|��>l�����Dr���d?d�r�	z��$:�Lu����R��_�����z�^�H\�q���H������������upe4�Hn�"��'��1�f���@��hp���nX�����Q7�=���Yq�U�����.F��O���5��r�n�dhp{�	�L�������l8W�"�7��T�y��49APqY*bU	q�H%������i"B	����CNp�����J�@i�C�*��>����	�VB5<V	#��rHS%X2����	XM'RB-<N	�3=��n�4U�%+��0"�v���u�h%`B����J�����{|5���DJ�:S�����i�KBx���F��	�V�e��:���C�*�r�I����Np���#��3%��������=��	�VB\su��g�����k�	��c����Gk�1��P#�m�O�,��6��z;��j���/��������S���~j~��w�h5�Q��U�9�m�s">�S�;T�
�Xu���V
��s�>f�nG8\
��s��8T��/%����'|8my��d=�tW���j0
�K���)�j����@��L����%����4�.���	V��*">�a5�������vJ[5��U����p5�F�U��P}e})�Namk:�r���m�QtM���wXM���5���5�P�j��Z�;���n��k}��w�X54�0u;��L����S��
�:P
�Q�G������\
�Qt3"&G��J��(�gj�6!.F
�QtK�U�p�L���kk���Nln[:�������`E�tX��i����U��I��(���2n��U�i�a����v��a���`Fwm�S�
����i�c�����4�����wc����qtO���]�Tz���������j:���������L��tO���wZM}�C��>�8�LC��xl���V����#&G8^�����8U_��K���H�U��Cd�f=��#����o5�����[���'��i4=�o��V�)���9"��������`NO�c����z0
�'L���x=���S��Tw�d��`OO��{;��z0��'l��V���L�uZY�J���L�u��[�xz��:�����w�h=�o�����2��2_�����B���/�zl2��V��t��������e<}9U�S������2��������e<}9���z;��,����o��x=X�����z;�����5YrY��<�_��}��� >��4�%�&Q���[���+id����'2��J������}�5=��b�\��|-8�y����Gx�L(7/��'�q�����V���Gm'@L�����h�U�q�6s����'���+b�����P�@�U�	7��h�j��O��~��x����w����j[�Ft���rU��7��}Us������%�������Y�iF;y��p���l�5B2��^h��3�:���N�@��b���	�@8�/����@���	Y�J���,�P��
+3�0�h'o X�qo��E��R��X�qo��E;y�J��(Y4�L���8����y^��7��xP�^D���B��uf�bP@�����`%����"�P���s{ X�����E;y����m���rk���:�z�4>k�q�,�N�vV�^g�=�m���+g#o��{��J�lcf�88�C';_�����/���z�V���wqD�#;$���+D@����������������������~��w�� ��u��h=��y�#RSF�nB����c�����e��J_.p��F�=�KQ��B�(���/���u_�~{�B�t���~�6�����ct����lt�5�@��V����[���pRj��3��F�M]���Ud��.��X�y���B�/��f���K�9;���d��kG�����:��9�t�fX���O���#��N�!��G���EIX�=���"}�c�?���.��cF/?���.���1��}���<pfd���`��@�:@p��_]|Sg^��.w�����z��X��q���;�>~�V���,��X7@p���h��j�>X[s�*#R�cxw�c]3\8����B������[��`���x�*�����2 �������0����E�V��r��������#���>*�w�X!�HyE��\���� R��`]���-)��E��\���GCY;%	�78	� ��^���[t�Q_��X�;m��������9�
���E�����gD�3�yHh6���"����:�7;#�E���/�_��{��|���C+z�Q���cx�����h�soSn�Xy]�p��=Wz��%�����:k�{8�"~�������Xo��������,_��~�Z	������V��+�|�L<8��k�����vx,��IC��|a��CG���m�/�������6�U�I|uu�{��Y�A;h����������M�������aAe�������?B��Q���S7A�-e�G��}Ti���[��
��V��a7 /�H&�C���I�6{6��&Y���n�l>�6�}��a�V��*������{�+��������s�z�Wr~f� �M����?���hx�ms�l�-�s�B�[��T&����bV�&���hB{�]��n��M�
���Y&������d����9W����d`�{o��Uv���2/j/3A����)�L�X�U
�k_��m��������?��]e)��?]�����,w�A�������T��r�/�+���sz�(���j�/#q5
�s��{�B��<wA���W�\����=�=��F&9uKIZ�6�=Fi�3�8u��w
�
�f.���Zz�0��U�0����m���N���~���*��*�9��x=t�J{��WYI��OW�xZ?=Dy�A�����~Z5o�<u��#�k���e����e(������0x{V4�5���'?m�(�{�U��C����z��?h�f ;���0t�����

�h��<q�#�E�U�}q2�%[��^��T~����++�9���8������R�	M�EB�(+y�a��������`5�n��n�7:~�=Y����<��O7�>�� 6�����V�=
���V�0l��i��&���_	�[�n���#c`�[�=��."+���C:��U2���'h ���y�m�_���x?���)�UrQ
�A��]�u��L����;�L�V�N{$�,��Ce���4h�pW��qru�oe!��?�~Z-n�/�'�n����EXy�n��R�h�]��g~�1-\bF�w�����
�AD{p�Z��1�l�5�w8���W.�U%���qq�V���v\7T8~���Vn>����;,y9h�F�#����;�\_M��a��d��@\
'��;e������������nQ�'[Y�_��B����F/0="�{��8�x����>n�`Z��;�43�����K}�+��������B��A�������s���=�w����v�k����|F�X6R�����lw>W�C�;��\�H&����a��w`=��a2���s
��v
�����s
�;�����a��.�G��3B[^%���?~~/�^��q���u�|-����h�[J�A�M�o�1�����]	)��h9[J�z��zlR���{���m77��keP�"��G�	"4o�5��-�f=�2��>�S��>�g]@~s�/����2f�?��8w1��Y������vcy������E��m������U����\�&o)2��&7�:���Y�����p�o�����Iek��g��Q�k�E��$�����$��+��e%�������e��YEn�@�7�����Eat���o6��2Wl�}�E��A-9�x����.t�=S�_��wWr>
���B7��U��6�9nq��e�l�p��5�xY��{"� ��'��s��(��
�a��CC�n9�k7�Aa���\WY�u�p����RI��t����p�>	��D����p���Y��u�x��f��sw$o��A������^K����*�Mf5D�$R��yX0������w�q��f5l�u^���#~c���*{Yp��Mr�b<.W��Q��|�
�M�Mp������z>����="��b��9d�U���r�.������3��Wg�d���q1?� -,�hj}$�oG?�e-�H$�D$�]����f�&^�z}�9X5t�|��"�r������A��p{8�R���If�����5�F���nP�����"��I��5+0
�$��m�< �*��'���l����Y�u���h`����
�
���k�<�[&��tB�s���.�I#R���W�������
<(L&,���n�q�OZ�{���
3TF��Vs�yXp���
��>��q��@y�k���ZD�lT�n�-��kw�5�*_��NQsC��Sl���N!���N�M�a\���J��z���:�$
�*��Yw�=���E��G7�
*��%��{�j��v��t�Pd#��W�|P���dh5�/�r��*����H�Q��_D�j��������h&gX���w����Q���6
��+��_��g��98����g]-�PgUmDE39�P�n�2
����PgUm���L�(Tv����Q���PgUm&���frF�rCe`�Q2�}����t�IfrF��Fa�t?�hz�2
uV�F��$39��9�0*�������B�U�Q��}T�;Re���(�$�d@�(�YU;�h�w$UI�+����-8�������=)��V�<:����V�<:�K�v����@��OEN�+��3�N�8�R�q�[�h�	q`����L��5�$z�k�h�	q`e��
�����)�4z���$ZpBXy���F�d�+���vEN�+���E;Y��J�'�����4�\zBV�d�+��z�(�����+���E;Y��J��*����iX����(��z����'�'GO/��c����h'kX��4B����grq`����h'kX��4Cy����4�+���E;Y������LN/O�8���	iQ��5�|z�p_��i%bq`����})��V>=k���'���O���h'kX��la_��V>=��/E;Y����g|�-8!�|z��x�p����8���[.����.�:�L��o�����5����53=��?f���W������s��8��RB������_���4�7>N
mR���6U>���(y�k��f���f������3�8_��3��sa[E#��G�u=������7:^��C����%��W��E������Z��}5������m]����	���]�����������;�������W��t��G/E���[�E��lh�C��U��&>��V��Uz,>����p�.
�1��T*5�����1�����`oo������
�N��,k��X���r�����-un3���su+w��B��^�+6��j8���kF����/^��+���X�m��5��Q�	g��Z�D[YtK��G�E�i���m����o*�;��Xm?	����c�z�����O���"0�&�Vn+,�����
��R�he�4(%0ps��UC�x�������D�V�Nd�������(�4�71��&&n�U,���"��L����\�&�7���&�S�	�Lc�obi�M��V�&���_W���O&"��+������\�m��:=��� �>�?(��=F����T�����!KP;=����l)�#���5D���2�p�$��
��
�����Uh�l��x�m����?H���7H�V��/6>�,_���a��`\D�]���4�`�A�5)�k���L#T?"�,_L�?J&��*��qO��\�+%����S|D�Y��~D��3!�HT�O���+v�`W?���|D�Y��qA��I���K�tf?=����j�d�
��8�9K��9@<�%���������]N5����g1�b��(�pF$��R6��]�&,��%C�S��q�,_�_�}q��6u��u�~������U	���g%e�k&������\}��9����0W��q��������>P�/���%��CdV���j�|��+^�����&���OF_����M���X�{���0!6wi*+�7��,LpL���}�U����Iq���?��}x@fn_Lr�un�����)~��2}m�Q���	{�m���n���T�_���n��b�g;�]]���T��W�B*����SaPM��G�d�n����6����W/i������qf�z����*��f�8��r��j���z�r]�.��l�\5L�u]�P����_�pVBU�~�����*����o������l�G��/^���&���p�yYs����+N[�y`[�k�L8'�E�Y�*�b��&�?JHX�>7��s�p�7��2�	j���������y��2��JY�=q��
&i'��������w�W\X�GL����,�*f��?�X�����R)�3��d����o���/��&����z�Qdn�|J�(h��C8_���0������\�vU/�������_������r|�
B��/�][vq���|���Oa�������/����1����������O������9����!~����������o���{����������/��W	�����M���	���
vH����]����/��������_��?����������_�=����������~����?%
��vS?�q�K���|���������������"��1#z��a���D���O������?��?����><|x�����~�����d��������������������>|�����}a
�'����8��^d��]�o�\���������N��?��2��������IB~����1r�s��X������_v�����av�tF�?h?N���������f?v�N��Y����U�������5�a��7�#���_���?�=��G������F���~�����zy���9��������x`��<��������]�;�Z+�
\>}�+������ive����y��r+�7��S^r��r���g)�	��p�E��o>:^�t��^>��Z�h��L�q�:���s���q�/�,�m_�h�:G�nW���h��}��"sx�`=��q�����~;s�����0�������n��J�|�]?�����]F�������_~�����J-.���&���e~�U?6�c��pkb�	g� 4�����z\d�k�Jx�eUN_-\�FS�~��nS,Y������p����W���a7bD���u4�'f��S�e�i��V�����+���C&����Q�F97�ZK�J�v��#�����������_&+t��7{��w��	��	w;���l�
=��E��x�r���o|�����,��e��H�2Yfx�,�����:	������e���e��8�p��
���=d��t���,H�����X��������"�=��M�(���1�K'T],����3��W�i�m��A0�A��#-F|��*���0�����_d{������������Y���/_~��?Z�����?n����|��_��������<�`b�l���#�n��;�/�����/�m?u$��������������u��j����H�G�gj0��%���,���������[F3�(�M�e��a���X�_��MCM>A���%���{����{@9�G_pU*f|FK�,����7����4.���D���o���e��+��}\�w������������tx}��a�F+J��i����v7��,
�Z`1w��3�\����K��f���������X���&����o��W��w-N�c�}�.4���
|?x�C����U���������4��Jh2����-�ywe;r�VD�����x>}����<V�v�V���o���#�Y�T�r��O�vW�: [>{�>�J%������;|��D>����@_�����%����+G�_�P\�HW��7&"�<m�������	v)1�mN����i�����]��4@&����z������hh��Rs(g"F_Y����(���@�2�~�39��u�_K$�%G�^��#Y�b	r���t5%�D�����5u�9�����G
��p�p��|�$
��Pe�7����}:0����{�DH�JO'�2N�:��#�7����#B~K+q��f)b~SN\�H�DZ;r"��N����Ej���V�J��rj~�7DH��sV�6g���;�Es����$�%V6u=�n0�,P����/'i.���j���
�#��axee&����R�RCr�Wg�O�#�_5�[�,�����5��o��2��T(���$���W��jwK����/��^���t,��/��v���b����T�V}O���ve�B:�Q�"����x�sy3�;K�*6O�o(y���ww�]<�E���t�e���Wt�q���e��#d�E�u������H���+2��r�0VJor��[�Y^�ut&T~��s/�o���}�{�S�i�y�.��
��R���
��z���5�=��03�p���� �77�T�+{�`k_���"����v7_1\�s��(�.%�WP�}T3\}�(����=�H�����A{��9�J�Ek~�Bo���B��iv�}����-��a.'�	�	a�t(��&J�Ee�o9����"��������f���P��{��x���g�
8�c����-7��%�`z�A#������*�J����^��_�/+���;�G>������G>8��%]��#�E��GC����I������d�b��M%R��o��<J�!U������"�PI����+/e+7�	��	+��5�����X���A>��/q4���E�[{�w>o \F�o�;_`�W2�N�vc�b-��\ a.U,�e���"dE3CU2�7��a��7��{��,�p���Y�*��9?������k�z���>p�_�.�({M~}.I~]92B\����W�#W�eT~�fD���_Q_�h9`��U������O��J��V���h��c\;�!�����s%r�L�Cx����
�,�.����K�Y?�mQ&�Qb�W(%S�B�F��J
s�����.���9q��}�[����@���Dr��m
�"��s��M����	q�g�q&^����y�8;@8�3���g����KN�Q��"$� ���\��0�*a.9���"����m!��p%�r"�s����1�8q�a�[�IN��]	s������81 B�Amh�@!b��Ec��8N�"$�`����8q�,l+?�0��k'���P�Nr"fa[�!�����F�����o#8u����;�b��<c.9����:qA����p-�q���x�uM�qb.�?C~S+1o����DV�R��
�?��`e��-B$��XV�R�D��~[��#"�q4�l�2�J'���y�#D�qL����z��GDH�8��D�;�!R����T:1�����6��"�8�,4�����:qF��k��}��#�q��3�DV�R����=Q����������Kc�WDH=no/����qz�q{c (e��<q�g ���6��Px�r"�������G�Yo�g
���|���l^����ro
}���Q	)C�W��.7��y�[DQ}-A��z�J��1��� k��|���n�x���~�x��������=w���@n9Y�=�9U��oz|�����S�1���V�.g�T��*|�QN6_{��(/�0�l:zt�r�T��7=�
x��mV����(��yGE���+���Xizm�	��� ��mD}Z/1��\�(�YC��'����Qg��f�\��{��NK>�|D4����J'jS������~�Fi����TyR>~BC��`�z�J��m����E����vT�����P[�]4���gLH�
���r�Y>���]�Q;��Rc����jLM��R�VL�~�����������=(��.n�nz�s������y@I]�V.���.��z �h���f-B�k9��w}�Xv�A^������mEu5���Z��v�n�6/=��2��D����[�T�c ]�fZa���XR!v��h�fX��(�3_������hV��f+n[R���h�K��}���z�h��3������w����6~���=�~*�}�����R�2��������0������m�EO��u�����������FR�0���fG5v�z����~7:v��T��G��)F���J���# ���7�'}};^�5o~��p����Z�p��y�����
����T.e��
2o�g(�����{%_���V!�{>c>L��+��;Q!Xp-\�2�HNP<�����	)��"�o%BB���i�2eW�M��+���a��R����^���ro1Gc�:>G_��3�^�����U��\�)t�z��{}-���/�^�n���Q�,��G���e{+&�3�����-O����|���]g��������i�g�V�y;�0��E�b *��(�zA_�|��j�������S,�P���`�,�P�0�`�B�PO��C!��#F���f�0b��F_oG�o5T�E3�rk9� �D;��k9�z;0f�b�M��^����G%��K�o��4P������NH3�������iV��t��7vFb��{���%�7vHZxe�^�7����NIEx��KV��NI���v\�~c�$Vb��J��NI,�p������X����1�E}c�t5��}(d���HI:�:���B���Z�\�
=}�c��D�Z����;��W@�����}y:�P��F<W�_���
��T������+��E�u��i����S=�E�:����w`����E��eY����^��K57���T�xQ>$����s���asmY����-�w�X�v���v����/��,�h*��ckv@+���h�B�GS�~�X[���{��g%��W����Z�#���Y������	��z������E�y���;�76�
��m\x����+���/�����_���������c��O�~��������1��3��������������~�����~�u�n���S����lQ��Tm��8��J������,x������1zU�>���2�5�
�@�E���$��h�[�$C�x�\/6��$�s���/�#�Wl�S�qBT9����+o��U��a9���y��5$Ap��to�O�jv �����LE����dn��"3�k�F��&���3��jGCtt��O�y4#BO$@�8��.1���|��#BHD"���H)'�P1��x���q���B�IN�5��)7\�D��C	P�����=s��'�����juF�q0�)7��G{��%B~S+q��o(��3�	}�G�!B�5�9N�^�s��'��}T�]uF[�[�F�%'��G{��u��$L��w_�$��|V�#�	�B�I���n�\r�	���o$���k��BN��}+c�u���J�sR���@�XK�GL�G*�>�`'�H$�����:qC���s�J�������3�r�H����'N��L� /�|V�hF�i*o8'9q�d{&y�3�a��KN<eO�1���������e0O+q0WV�����)��r���6������;�O'�@?���K���\{�����{����}��_y�+��&|;Rq�	�nRp91�x{9�n����MjA���	�N��:i�����s�x}���@�\��	�n�#"�Oq���z��C��.4nE�u�&��"4".��27�E�D\���
-n5�5�?��M� 0B��C�����rrj�	Dn�+"$��NY��2.B.������x����Sv�����x�'��i�!Qa|��k����p�4
L��^3<��2�:Efr{M%������������&7!Bb��9>����`�O(��<�y��^��Cp�\��m���}�3"�����
�)`�������I�"�d��Os������3���w�t��]J��}��N�������T���^�!����^�\��UC�u7<
���}��s�����w�w��V^�gz��1#��+�h�����I�>�U��D�8Pd#��+��nvf�q���q��I�����r��c�����X�Xi�8�os����+�Nt!*����2Bg�d�������E�_}.�`��f����FJ�j-2�x�����_�rDFZ/#d��A���H�e�/�3��w$u�`1���Nh��2A��L�;Um��B^\���������KU�8�e���O���K�q��7����_B3�8�z��@��~�/�|�*2�hY��;�.��\�C�������|���~|��a�?�?� ).B���~�����Nw�������U�����:k��d��7�?�{�_�����_��������?|���|���>��
/~�\�3��_���o�w�m����D����/�����[�|�����&����u������9Q�g/~�{��������/�����������!��7�?����d�O��7kUuS����g�G�?�t/���j�l�R/������lB�����::N��%
�||��j�U�d%l��m�v���%Y[�\^Iv�6����5�d��*	������d������+�d���vo���d�lW[�O�������(�v����aQ{Ng>�"��p6�!���k��������]$�����!��D���~��W��f=&��M4D7�99�ms2D7�A998q�w���YO�z4%C$pW����}��!�I�Q��{�����=�����N��������j7@<I�7��7�M4D7���;��jH�H�2N������d�������k����O�q���e�N�����D�)�IL���$u����O�a��!�>_�������/�,J�	��*��]��d���L�u��JC�A�������cE2D7g���u�/�S����H�[�g��	�U�_-n?�>�!�9�(���)"��5�C�i'C$tb�<j���d�n��{����	��G������!�9��Z���!�Y��
Z�$C$ps��f��9�M	j���4���d�n����5��!�9�K��W!A�ng%6*��!<�r���BW�d���j�yY)`�~��a&C�L[w\V.�~��@%;$�I�q����=\�=���!R�m��]���N21��g'�V���{6���	�#���CT�!�Y�w�di���q���a���%C$p���#��O�H��k�P�N>��I��o�}�v������4���8R2����d8f�+�d�D�'�7\a'C$p�M��<#W��N��������!��I&Hx�����d���/��:�v.o��������\mU��-I6H��3��j�e�d�n�4��U�MH&��
J���$n3�42R�����=ge����	s^+���w
��,��ev0���d�n���:
�e4Dw��]��Z��zC2�7o�L�+]���'� �j����H�!�9y���J2Dw�����@���~������N���J�k�-�H���~��w��I��V;�`o�Dr��:pJ;v�����H,l��dY`���H�f�I�>�h���!�g�`}GC$ps�$}7�O2D7'���M�H��;��r�^�\�I���Ru[w%-�����d�-s�9Io�\�I�H,N�a'3
p/B���Sv�{hO����Y��!���V��5)��6�h����rWsWu���:�dH	���gJ���������)I��	qUs{��$@�d�n��d���{2D7���OC^����]u�Wr�~��[�d+w��Hj3�y�2� �Iy��d�w���R���������j���d�Q���_"���m3�
��LI��f$C$ps�$����/"��s�j���$C$:~T%%����W�7�)���e��I������I*���vy�Q2���d=k;�l,� �i�,jg��J���������\(N�H�f]'N����!�9U���\(N�H�f=�����d�n�>����d����Q��,� q�K�&CJ�����0��0L&����U7��N�f��$K��)�q��l ��v�����\,�h���Q8ue�`�DKJ���w��Y�A�V�P�Gd�{��Y7�u�+0�"k�����n>Y"���w��k0�%"�9�y��r>Y"������\�N��	���re�+�Ir>gq���%�W��4��|]���_$����7���8gz��)O��%"�9�7�y��,�y��\��
%K.T]��J��y�3�d	�Z_�T�������d��*�LP�or�%"����U2���d	�*a��Mf�9��������%KD�s^���o$KDZ]s2�Ny�q�Dx�|��+v����d�Q�+�4��q����6������������h������R�I����$������%"�9���<�J�����^�mz���'Y"�mr�'���'CD�y��t�d�p���*/NJ�H�������w�#'K���������B�w�'!$���u�-�YF#X� *�p���p��lY���I�y��,����*���%"�Y��q��*Z"�u�Ok^��,�)��y�=0Z"�5?Y�1C�D8k~��k�d�p����s�d���k����yil�D��u�H+/���yml������MRe^v�2';��*��$�5?2�"k���z��*ud�v���%KD�s���B-G�Dx�Y_���j9�%"x�������$���K"�%�����:rY)#��c>�+#������N��2���\�, � �-rf��pFFKD�s�T!���!Y"���V
$S���%3a���k�D8�~�.~�%"��r����0o�FK���Y{��e3�y��	����_�\�N��g��9���%"�95����~2���$mTc�u�%"�9O�Q��H)Y"����O���$K$���V���bL���<����u�����oc���|0��,)���t��*��J�D���'��&X*��U'g����GX*����r����m&C$p���X��Y(U�fe�����#]����������'�O"����3�bm��
W���#����5���t�@GN��g=�g���%"�9������,���Wx�,^�RW��G_����dI���`e�:�~��Il2�Y��l�]�y�,���%�u�9�	��&#D6�1�@�Il�����Z'�NbeU]��Z�8Rv�2R�5�9�������Il��bm_:�!/�L���LP���t'Y"�3A���K���U	Je�����r-Y�\9S9� tO�������5���#�������"uZ�`�X2BB��k[|t��Z�D8�e�4���5Y"�I�f(s���%KD��f(�
K%Z"�5CY���5Y"�5CYa�U�Dx]/�Z��[�*5�J��A�;�z�,������e���uJ]
��]�4�%5�u�AU����q���%E)�����I��s)9�+%�������(%%��4���_7$KD�s��s��Rr�D8�Y?��a<Z"���gvc�&K�?K����w9�L6�Z�6O����+%KD�������sX�;�d	�l�Y���a���s^���x�D8��9���GKD�����x�Dx]-G������%�f�l��[_��O4�P"��z��������'!�HX��Mi�����"�N��<�	���Xk�o�[�d��:)"~���w��58�%E���J]c��W_��Fm��W_��>�����
"��3?Y4jK��g���`u�Nm��������,��E�48���%"��^���.���}���HVW����\��m��{L^��`!u2Bd���'!���J��gmk��.o;�,�yU�LC��<Y"���Y�p��}��'K��{]�#�r?�gX�����SG^���Ylu��'+��$KD���'�����%"�����{:����v��h�����8t8O�����l�5�g�*��:Y"���N���j�������3=Y5�WI�H8��k-p3��I�D8gz�Z��,����c^$�,^���.~����WI�����W����W|����ks��E�z8y�^�j������r�,���g
P��,�}�S�@T:;l�������:���h�pV�O�����	�<��$�	��
�:��]�?H������������u���jg]���$!q�S�?�v�l&/�L�����j�T~��,^���.9�T�(����s/�T�3�d���9E�M���g^����f��0Y"�*��|~��>���%��te�J��
�J�D�����/�T�%"�Yw�a��-�^�'�R�����'Kx�M�s~s�:� ���	<}�O�+��l�B~���OX[�n��%KD<��Dl���z%KD�����K���;����6�4�d�{`m��xf�R#�5k��m�3s;3Y��n+�����Y��NK�6<3����j-��Kh�+�m��{�d�+�L�u]��6H������?������pe������~f�y�����!GD|�
\���*j�.��3C�+�������los����Z��z��K%Z"�1=q���x�D8��T�/�h�p���u>��l���������W8z|�]�k(}]�]�<�uA��=�������k����[�h��g����f�9%������y��'�� ��i��2Z"�*?y0��4W�����GK��O��,Y��9��l���Y��e��d{�����uk�~���������y�D8gz���������W%N�\�}�D8ggS�����d�p�{�L��>["q�P���Nh���9�L�mu�M�Oi����m�|SI�>��_�a=3����<!��Y��y��gKD�s��M8r��X��&�N�i��J�Dx�a��������G������W�'��u�


a~\�9��)f�l��"a�O�
�]�f�z��}M�����%KD�s{5�K<Z"����S�����_�mM�d+�jX�������js��E������Y$u�X�n��?R{���&�s�����\p{���z�i��\0Y"�3��j��e�D8�~��:�MJ������Y��2Y"�*?�;��,� ��|��%�Ix��������%'`�����k�r��_'K�S��������l���=n
���%"�9���\dK����O�mu��J�D8�a?�)-^��������0�K%Z��l��2T^�i�-<�h8{�8=w�XECD	��9o��DKD���'q��k+eY`?���+��_*��X�^�����Hx��k%�-@F����_�����8��Bwg�u�}�+gT>����W���i�a��r��0��bo*kv��C�6�,����3�d�pN1��!�O�%"�9{����,�y����~-^WkZ������J�D -�mlZuCo���g�!�7������f+T8c8��:T^�,����]��GKD�s�f�`yGKD���'u7�f���d	�
��kl�`��>h�{���S�6���ID���Iw��`;�6����d�a;���g��W�I�D8kz�X��������}`�Dx]gS�*z���
d�dI��������i���U}��$CX/�*���5����RO�z�V����c�%���*��Z_�5���l���9*k�u�D8����>����eC���?xM�034�q��w4B���)�u�w�D8gJe���-^�R�����x�ayGKK��_��]��U��"�������3�d���Te��J�Os^�,��8g�6g�	�w�D8��c�1/}L��g�P��?M��g�P6�?H���$}7����%"�9O�IZ�D8�i�k����U��kZ)�F���^y����|{����d��KS���RA�M>=����k��6�
���A�Y�u]Mk���	=0u������+�{����"��<�z�p��'f�D���G}����#Y"����xbFKD��������uOu��~�3Z" �W65�{Z��./�I��>��<2+E�~�"�d�h�{ZN��gD�u]z���u��<v�0��hIWCf=n�5!�
�f�t�/K~��,��R�s.B$KD���Tu�f�M���%��&gj7 �OF�8�����r4��{��4~�����c��C��3�L���$M�_�S���?&I��g�Uz`����%3������%�Y�<R�|�DKD�s�g�8��]������Y����:D�D���'�h�#?Y"������&
G~�D�"����0AAr�D���'����%"��N��8���^���%'KJ���]g���V������{�!�l]_���u��!����>�����5W��
��������*����b���A;���E���r
�"�%"�9�z��."Y"�����3vny�%�w�u�|�k@gB���
�+;��I����'����>���}�I0�
0OR�tY�����o]�%"�9���P�ZD�D8�Rq}�E$KD�s^�8os-"Y�{Y������+m�	_�v�u������gM��!o�,��RM=��h�p��j����d�p����\iK����O���7j��U��
��#\�u���dI���������\^7�qx�Y_Y7����h�@�L]W���^��<����u��W!W|�����5��}�
&KD�s��>����%"�9��=	���	�u}�dd��<�J�����������#"�p�Me�N"��uG}]��wP��,�/��um��~b����c2�������5;��	*� �F8�����X'([���8v��b��,k�����X'([��4<������<�	�(+��O���V�@�y����
�55���w�*Ypv4Bd�pJ~�!����g�O6�l�D8g~:�l�Dx]������T��&K
leW�������3Y�{;��~=�<=����X�	�y�,���'X�*%KX�Tf�����\O6H����O����4Y"�S?	�2�M���e����W�%KD�W����$�����S�d�������n�a�f��/�m���m]���5 �J�����j��*Y"���#L�R�tJ���'������%"������0o��k�D���vb
��W�$K$<^����:�u���g���%"����8\E]�2v���lFx�l[�#��Zi���H2��Z��Z���Qi��:�X�������2Y"���������g�h��@�D8��KN��%"�+��U]��=�H�\��u���P�%O��!�j��a�\�O6H�������e�D8gv2z��8$KD�s*cPy�U�DxUz��S�x��v�����8Yr�D��/�2���Gh�����dmj:N~��6?��5?��������2�N-����v�h�������|3�FK�j�ku��*_���
;a���e�|2u]��2� �HX�M��_K%KD�s&(�Z���d�p�e�s�d3Y"���c�W���uC��j�'��'�)��5����i]a�daL�0T�r�\$��_9$#D	g~2
S���%"�9���Q���GKD�s�rL��mM�%"�����]�N�����%�u�6k����)x2�H�?��Kk��hr��l�X#�-B�I�)-����
I�D8kz2op�GKD�sj����-^�N$6�{��oZ��v*YR�_�V��5?�������V�j�:8+�
"k�5;�68+�%"�9������d�p�#sV�{+Y"��A���>-Y"����,��
��J�D����|	3x{��}	S��+�g�,�����4���'����G�<�<!L���Z*������0Y�{��:av+��h���9���/��b���uq���9����%��X�����*%KD<���L}�X%K$��65�g�*%KD�s>��
�U�D�����ieI��v�T�%�%�={�u�Iq2Bd��&([�)f�D8g��t0Q2Y"�3�]����,^�T���`�C�&K$**[����Fm�A7]��.Yrx�����3�Z����U���,r�d�p�e�!'L�Hg��c^��,^7b%3�W�/�%'K����3����R��U�Z%Kx�d�N�6'J6�,�e��D�\s"���6'Z����5]�9�"�����i-plN�\iN��ucu���e��0K�9��������LmY��>����0�.�e��d)�3,��d���d�������AC�d�p�j��������ou������%���7��������|u'�e_���v�h���J��,��d5}�0�%"�9����|O����O���3Y"���cT��'KD�s>�]]�'(����}]cSt�5�Wp��� r���&=�;s��LW��e�(3e��� !�����]�gN�D8kF&8s�%"�9��u������kR�YN��h	�g��QM��+� �k��j�7^����o��%"�Y3��x%KD�sv�]7�W'KxyU&%���:����q6���)���,^��Xjo���o&�%K�%��b�V���9�O�Hx���fU�0:Y"�3A�����������s�d���I�u�`�a��d	�;�����6ly�R2D��������T)Y"��gn~��'Z"���S^��,^�K�����T)Y"�m��5�|c��s~K��c��u5}�������'������A��2yS���nm�X�u�Xk��v�h�p��~���DKD�s��mU��DKD������)%KD��M��
�������l��X��}����w����$Cx+MY�A�������E����Nw.��J�z�n9;�-���-�����wf�s�GKD�3V����E?��T���}M+7���|��B���6��$����r������k��Fps�Ada3�T�s��;Z"�*��C�/0�n���n��GKK_�Jy���v�*�F�8������GKD�3J>;�m�WI�D8�R�V�P�%"�Y��9��l�p���-l(sah�+Jfj�J_�I�A����c}�i8u�%"�9��=��E-��TT��9U�D8g�����>["�.A��J/]<Z"A*{�T�����J�T�%��{�^�^Y=����,��^�*?3�%"�9{�o�v�,^7�����_>��������9[�xU���Hx���iU)�W��t�V��(u�M+�B���%Kx�B�ng;�e�!GD	�a?�m��-^W�Q����i��d,���n��r�sj�l�5���'8��%"�Y=��p�GKD��=/����?� ��2�h�������zN���gD|]�RU��[�����s��RJw��M��gY�U>�����b��N��Ua2-���'U�>^�>���l	o�g������_s�T���Ro�8�z��\�I����O�`r�'Y"�3?�N��R�����O���x�Dx�a_��e��|�DK������X�&'��	�s6c�z�y��,^W ?�
���$)�����
��m�v�&W�!"g=7�����%"������jQ}���b��W$WuW�U��;d
�w�A�Z�����Y���u�Xk����NJE��������>Y"����t�C�D8�Qo��+�%����Vn*F��?$K6����U=�v�C^�����W�����t�Ab6���P���o�����0~6Bda��PD�,��R�>oo�l�pN)�����b�-8;�z�������LP��!�
�-�s&(&��R6Y"�5A���'KD���r�����L6�L�4~�����YI���v��<�gK�b�^���������0U�U���T� �LF,���k-�U��#�1��.\��d���Y�u_�J�r�Zgo�H�g#D�����.��8Y"������F_O����P�����%"��F���>Z��J�D��q���Z�q�<��sJ(��-O�Dx]�����/�mI�Db���	},��,� �>Of�%G5�w=�IU�"q,�h��"�LP�[a�DKD�s��/��Bu?g�Po����$KD�W�u�d���8$KX{�V�4�]��{W;IK6�}��-�5?�&����,N�B�gKD���'������	4�}�D8g.o�	��%"���9����i�����{{���Ihe!x��|7L���W���k�����>�����j�)}�D8gz��1��N���KO*W�	9�O���nVN��%�'I6���3=����E��d�����~��e�D8�R�}F�Dx]/��������d	��P�����n�K�!gmf��0�Q��q��l���s�>Y"����]����>Z"���jM����E�	�q��d&C���� ��3��d����(�'��Xx�����3�&KD�������,U$;��5�W(�M������g���3�f���dI	���g����uM6�-����6������d���h��"�k�Z\
��e�D8���]s����J����$3Y"�����d&KZp
��6���u(��zj^�3�P��Y%u������&KX����J_k~�l�5gN5�9��,��S
~�_e$KD�����O��������L�m%��&���*�=�c����pve_��}{2y��d	���)�s�s�d���Y�y��=Z"�5\�=[�D8k"�B{�d���D���~��=[�D�������$U�T������S:?/�%"�93��k�D8g��4�bM���,?qf�;%K$�W���k������d�@����k���)/?I��x���tC�O�d����0q.���2z�|�1�%�J�W,���y���,�89���V��;?�im������ 'DV7�a?B��d�p��~��u��������%"����zj7��_yaw�$[�%�!<
%{�P2��yU[���8����n��]$k�U�Ab��66u��N�D8gcS�-�O����s.���RED|�)F<;��������9#�%"�9�����!Y"����.�&����\�����]�Y&D|��Ry��L'Y"�3����?��u����5���_:$K����34�^�~�`�GC$^����[a�GKD�s�'�/p�DKD����a�%-^u�W6!��'O���	���.�O�="��:)��_�	^�'K$�e]g��Rj?���d	k)5���1�z�'��f����&��X�������/b	x]/�Z�&�k!g�y��������u/u�J��ry�O�D����G���*h�4n�J�9������&�A�����Y$�JD0>�pH���LO����d�p����C�z�Dx]��8�D_�T(^O�����J�a_��0��$Kx��f���\�NF���%x���N�w�m~*��>�-N��gMPF�w�I����*��;a29�L����:�V�
oG�?dL&t�su�Xk����W���5����K����c�j�6�h�p��d�`�����v�DO���WG��������'j���i����[s��a~W�:�b|�^�c^����k�Z\ymo�D8gz2�>�,�yU2Z���&KD�sV��=LM�T������=�=RO	5|���d���rPG]��p
���[��
�pu�Xk�;���,�����2&KD�s�'c�����Uk���q;8�Ca6�+�+w�Z_�PG�l����[ �|2N0�$Y"�HX��3�Q'KD���'3�Q'KD���'����M��g���%{�,^�����j���f*Y�_f�X����
K<����W��:�W�%D�gz2)�W�%KD�s�'�����d�p�|�[^�,�y�Of�3�d���>?��*';����%��*]]W�J�j�0�5�+XU�l�����^��E���L����%"�Y�c��%"�9I�����!Y"�*?���`���d��`U������6��%��~*7��U2.
0oB]k3�i�_�J�%"�Y�y��Z�D8������4Y"��{��B#�d�p��sr<Y"����l1w��'K�D8���sIx�D�������\NN����y������g�����J������U2B���r�l�\GI���:�U����tV��>�Q�%���W�'����O��DCD�y�����$��Tv����!'KD���u����,(�vu�++/��B�%���#(�`�N���E����P$�,���L*�k���g���t-Y"�u��[N��%"����������
L��������W��.�WK���+Un��kdu���
"k�5=�X��	��-B��/����d�pN-bQ&�"�%"�9���u�E$K$��Z�V6)ZL���%KX���'����k�Ad��u5�O}����0p|�z�wW;��[.}�S�d���9%���r��,a�|X�i/��MF�8�3
\��M�����Y<��M��g]*��&KD�s&U����*Y"����2��{GKD��&U���*Z"�.�����,&8�,���X��.���
'KD<�)�,[��9$KD�s
(����'Y"�������a�;�J2��\�z�s���F���%J2k��U�\�H��,��s5*?9�%�Y;�f�O�d�p��s��80Y"�S�X�%?9�%"�����+�u�r9"Y"p[�q�������9�hg_����?�}�qq~�$h���9������2� ��9�����{�����������{�%"�Y����c�D8kv2�=w�D8kv2�\�d�p�.���*.5��u	��
\���,��
���+�u5�{/����R�������.�vG#D�k�M�vGKD�s�'��q���%"�9���B�v'KD�s&(�vy��,^7c����f�<�J����klZ�p3������5�����#������]E7B���]���d���=k����9+�����6���,�ynn���%"�Y�M�����J��7�D�-@Ur�D@��7��'K�~|]���g�����%���+�Lm�*:�4�9W��G�_�S����C�[)!�I�&(��Yq�D8����C^ �,��T�>���	�umB����u6�4N��*�����eG��
"�fL�B��������IU��]r����IU����R���g#Bg���GKD��~�}��K%Z"���d������u�U�PB7�=���������6�::�������J��\��
���}������%K���f���s�GKD����c�s����'���|�DKD�����g�D8��9�!-^ur����[&8��%����l`��^����3v����|�~����_��q���B��!�
9�:����������h���������%��Zn�W.�yx�Dx�Q_�+"(���x���WDe"[�krA"� �k��D�������C��$KD�sf'�����u��J�j�yv�,���+3���c���1��c�1G#J���|�l=��V9�Iv���k��|g��";�
7�c�R�P�%"�Y���O;|�D8g�������%"�9�5���-^�p��z3�9�9��0��5���L���OP0�d����b�=��^��g�����h�����uZ����h�����os>���I�o�u�6+��.�[�l�p��^�1�8�%"����B��u�����B�����S����	|�xs������@uf��]jk�J�g#$VI]��Z�}�J����b�����RO5<g���]��K%Z"�n|jl���;�-'�����;t�������PG���Y�y���P�6��V�!o�l�p��d��C=["�5?���!Y"�S��s���	�u7+uB���C��_'���Y�$o�=�BY
��i�W���"O#[-��\�JFa>��Q��9K��:C*�Y���6A*-��Q�n�T0Z"�S?1���^O���,>�*7�����2p�1;�1�L6���3�2����:Z"�3�2��w����)����(9Y"�3�2C?���%���mVJ>���3�-a�|8��������d������'����%��|e���x�+��	S^s�,)+�����=B�]���%"K�5A�8��%"�9�p3�9�I��g=����������sV�,�z�o*/�K���<�m����%��z�V���n�S�d�@�z]��J�*�;<" ��u}p*�E�+�}�&C�������i�������
\��F�%"�9�zk<|����G��.��%"���YU���r~�,a��W��W���sf�l�5gvb�	��h������\���s]���'K�g�����E��{���d���9[�����Ryl]��������0��p�.v����q6+�	JM�%"�Y��Y��ts�i��R�o��E�]�a���0�(��)�c^r�>!�JXs�u��$Z"�S>��	J�D8g��w�h�pN��W>OP�%"�93�^;����]B�d���y�R�D@�]BCou^��,�x�c���}��9a�D��@�������������!Yrxh�/��2�~`C�F��N�w�-�y�����-�y��A��<��uM�b+sM�2��`'�������P�q����GX*ca��+j�k���E2���d��"a��-6�%��������oB����f�,�k�d�pN9�_�\GI����LVWK�oc��$K�k�C]�Me�Zj?��a���d��68�b7��iC���
"K�3;:xv�,^�O���uPk~�,a�v�eh�V9'N6���S>���%������g�<["�3;l>*��	��]M�>�U�l������HvF�������V���v�4#!�l��j�>'����tg�4#Y"�u���>-Y"�5A��_A�D8�|2�v�I�iA`m�:,:��N���b
u
�j���>0"�p��~u�{������t���>0Y"�3w����%"�9N�L.�'KD��I�Y���g1N���$K����dY{�:mw4D��u�H�J��Q9gK������^?�e�������/u�6+[�93�{a2������,�hLF�,nV�=�hL���<����I/��1��u����N^����k��|��]H�4ju=BM����4�9��%G�����e�B�d��*���n���d�pV�O6��pW����������u�����-l(������*:[]s������bRu2�����P��Y$�	�u����	�~��~���m�v��
�6�%"��^��U+��Y��]���j����Ob�^���,�}S��jW�q�T�d��*�LP�r<Y"�3A���[S'KD�s&(~0��,^��TU�{���9��
��.��}��[�$<Y������U.�8� �H8��>0Y"�5A	l��	�u�Mk����7������f��%"��:s�uB�����%K�;������-�����(�����~������z��J���v	�+�/O��g�O6x��,�Y:���'KD�����]�+�eP��;YR>�bC�{WRWP��W''Kx�YP
�;� �H8��`�wA�Dx]��Z�W�����:n���wA�D8���\�I���,��j�F���k�Y�f �����`������-L�Ad�p�'�w��GKD���'~�
<Z"�2=�������.�T���#��OF�8�S?	��O��g�Of��,�^��txj�����@��d�����X���d	��E�c|�k�TY<V�N�D�x���YX�\�M��8�n�+�	������b���cC��"�f�`�W�D8gN5j��,��S��z%KD�s������,�y������d�������8���H�D�kk�q�����Hx���i-p�������XRU�7zg����5C�gG#D���������%"�YO�	�
$KD��M�����J��8Ck�dI�{��*[]���b�q�s""Pl��$t��O2Dd�������b�xX���k��d�%�UW�%��hs�`�T2E�hsG^7f��������:���c�5��:�__&d�	�i?�!?4�)2����N?�V����B�d�Qn��b<����Qy)G2B���9�d���$�"��*I��U����v|[��Z%��~�]~�$#d�����!O��)2�Y}�l.&Sd�sfW�7�-}2E9gz5��LA^����`i��b2��`�6����8��U2B��u�=umB����0���&t���]M�~&"�qN1e���L2E9k��@�d���L%���W�ZM+t�I��)�k�9�������d���YO�m�%Sd�s��s�G��u�~]���|���)U��c�:k������5�EnL��%Sd�����+������d
)�����������fQ��(E��w�n��=fg�'�\8�^�c�9��{��HV��m�\e�\"�"����cvP/�L�A����
&�)2��^���*&�)����'f����.�x��Y���z�y/t+�#�TU�I�������Z�Y��M�A^�_��G�K��.M���G�f(��^`�P�B���G�
#��)2�Y}����d�r�de�`�P2Ey]�J]��EA��d
��8g���.��O����.W�E�W�$��c�)�/�p9�����Mh�����_��K�����[mu�)2�9e��_r�6�"���]�)��L�A^���U.n��;�)�U�;���que��[�t+Y�_v��������x q��>z�ggx���4�5OW���+�,��g����2_%k�2�yF�L�A�y�L0�1�"��u����$5�qG���,N�h�r�.����&$���}��
&���?��[0Y{fV�{��}a�B���	���a2E9�D�*h`�L�A^�Z���:&S���9�TW3�w���*���P����J������LV��^��W6��\�v��$KdV8g���>�@H�� �LV����D2E9g���!��O�� g���zx��L�A�)�����~2Ey]���*�u��<�L��cmu���F7�"���s���l�&8=G����*��z�je�V��4���~M98��k�C��s����d��:�B^�^o]��f<���^�63���������Wv��D��`�d�r�\e����d�r�\e���obuY��]75�"s2Ey]��:����MO�~�L)�>�8�Y��n*'�)2>��U6����u�@ue�[�����`��p��\�LF�x�������I�����.W��p�9�W�'S�;��9�����FKd\^u�W�n~��\H_S`�:da�l��o��*�%SD��5z�E>����GcumSk�O�h,�"��5U�}^��L�A�zx.C�A:�"���}]���y5B2E����
��y�d�D�������y�d2Ey��_W�5v���(�"Q�U����>��z�A�Y��gK�N�W$���m�8:�����uO�E�B&�>�"������i����)2�O��3��h�r�un{�#��� ��R���.E����j����W����H�z������gKx{�Vs������a\�Vp�6�<:<=�~�A�v]�A�A\;�Wx��Y�z������"+����������B_�Wsf�c��h����2��sZ����9�hJY^�2
Xc7�p\FSd|�xo5v���2�"��5-\4��	����n-�5oW�l�r��p��]�������*"'��w�+B��2rs���*����\u����s�J��h�gSd����T������L�h������XK��Z�Q���dJ	�Ag�z�u�m�?�?h������Z������������?|x�����~��q�G#"�������GHw�����2�U�����w�w�a��7u-/�]�����D3�_,�������������W�m�����������������?������������?���?������������oH_�4�Sjg��k��5�9��?��n���C�������������������K��]���M������W����E���e�A|��A~YD�������u�������o���������������G�?������{P��C��?����?�����v�_��~��b?��������O��?����?<����_�����?m��X���7�y����������������~���?=�[����/��o���{�����_���������/>�.���/*�bv�<�5z���?����e���G������w��:�����}��Ca�lP�=����������|���{��KAZ��k!Y!H�!��6pFR�j�c$-)����@RB��FH�R'iHVWA2���R~?������W�� ����I�K��������KA��0�B��@�]�!9���:H��kI�{�gM%�1��?p��g��:/���CHk-$��r�RpW!=n�R�����y�R)\^V�����t�R�|>�3��^�Zj�����!� �
���e��JR*AZ��TAz�F*�hD�P�H�
�mU�z+�M����H���=�!��H������J��8��+��Q�x�N��]y��=�$��i�
��9n��&Mo�l2b���^J���-b���k�������������[�x�������]a-E�����V��"� ���
is�N��!
2^�;�'"� �������y"b��4tBk�W!U���n���	����$��4l������Z�@"�*H���zI�������A/�j/��/]�������H7{i����[8P"�*HA�K�d+�gH�_�C/�J/9%�Q���j����s�}q������R%7b�;�������� �!U*�����*�	��~���&: $��(��T�����$�~�����iB�R?��k�n)M�_09�����^Q��bN�`r�\ON�$�!Hm�+����H�{����oP�1VA�"M���
������L1���FH��n)b�)YpB���uKCE��� 8�[*�����.P�[*����}/��	�������/Ni���uKCE�R�$��X�4T�-�b9�-
�uK�Z�
�-
uK	���:�7`��PQ�� �����	x�!�:��#�[�u����)l���"��������S�i�[���H=7�eT��"� 
7��r�9�q�
���k�������H����^R����H�fH���]�����}����#��&�A�������j�BA��������Uc���$��`����9�f���&��`�y��i����L7���Q�6�e	�-�n��iL�q�P�)�����8�h��Z{y����k���-�Sy&�}\;��	�-����8�~i���L���t��lI o�t�>N�Oz��%����8����5$��`�N�M��>yy���q:vFm��Sy�;�q�Of���@����}��?�>��?�[0���������gpy&�"B�L.$�7@�V.��;o>c�����\������l�F���\\�4�y��0��;�5����	�
��w�J� ��Y��l7��\�x��s�+���E���H���W Y(�Lo�tk��;��Z��Mo��n/������m�}o���D���_�$�7@��KZ��vG����]�z��F;l+@r���3�[�d��Y�a������2���wyiL�x���E�X������fy��
��(6��}G�7@�#;���	Xo�x�[��k�	���	�
�n�N��H�T6~���{/!�(	�
����]�!�R_M�UH�si�%�	��_�Rtv��?�1���/NYry����
����iH��B��W���]��F��j�y/S��k���z�����zO�%
�n�XI�Oo�A�o�tG�'��L�/��*H2��	����Hw��$����g��8�Dw��B���8����B��A�d�7s��J:0�{+��}qsHs�t�e^��f���������n����4�����W�v�Kk��*��B��vH+@Z+_�� ���7�CH�m����UH����m���}�����p��+R�HN��co��#a�����lu���y�������H������Ce���e�g\�X��� M!��q;�{�8Z>�!�&1V��1B���~F/Mu�4?B�C>�	�4Wo��1���H^	�
�n�O�@
�W-y%H�_�^�4��..a�wIc�(`��
��+�u��;b�����4��������H�_�^���j�x����A�}�	$���K�{��c��A���{��SM o���[a�Ka�[0�*4�@?,��3��L7������^%�7`�����'�7@�N-��'�U�d�RH���{p:�`�	c�{u'�{���KK� qw��R��dt�R~O�0���0ZC�R�=�������f8�"� �|z�DYp��k 
2"��]|q���p���oh4$����/.A���m����� q(.���c�^���)O���AHW�$�4�NY�T�/����*� ��zO����B������D(;�
 ���y�	]�;I�0��v/�[���D�v$�Q��5�iH�#���k���D�u�.-a���$T;����]�,�#$�&�nO�rHc�&p_�o��@2��Bu�d��u��sV�V1�������(	�
���8�=B�m�2�PK�y��0��f:��ovH��#�*H2��
>��� �{iy���
��tnR)T�mx�����	1�hB�'��!]\�tgVy��iH���%�D����eAHuCS?B��KW��;�B�1VA�)�un�|)b����;����|����Ha��W���������7�	�
���8���5z	�
�n~E���K[�w=Io�t�5��������k���H���r�+a�;i���0a��t��&����aAH��W���kO	�19CIo�t�&@�%�C����Hw4:��4�L���H�n��;Dy?��i�x�[ka4}+�G�_~%�7@����hs�$a�w���^$[���;��:� ��l��I��8�T����>:���g����P;�1A�C����y��;b��7/ �����sy_=v��HKurr��<�+[�:�&1��{-�3���H�k)<v�x	)a�����H��g�}��+�����nv2��%2E�x$��d`g�x$�})���0V-����B��2'a���k�wW ���9	�
��[/���"s�x$��@�Jo�����2��K��Z^�����)a�������2a����>PV(�Io����W�p�0����+��
n�*H2�;�\>Mo���%�R�|*s��r�x��kt��/��Ru+�^�"5lJA����[�"u���	���&��n	s
�6��L� �<g�!�I_�)� uw�	\��I�XqE�����C��r�PNR�d&o�
���b�|�R��
x��0�xI��)����Ij4B��wHR��0����k�$���EHu�_;$��A�1V�q�H}q~@H�������� 6a��d��	cE�������VYkz���;$���JE�)H�Kc�����&��*;�>��
A�1_���`vHRg����\w�d�};p����\G-���
����RG-wHR�[1_����C�
����Z�/�+S\����V�/	���q�5@�������!�2E�XIfy���I������
 U����$����F��+o��4��3!�����&�C�����B����!�M���t�����],@��
����������}��_~�������,_���;�?������~������������O?������������C�+�����_(���w��_?<�����_�����;~�������������������?�������������?���������������q�?����w���|���_����?��}��L�t����<�Kn�^���������?}�����������������+��'������<��_�����c}���?���?����������_}����a�����>����S�����@��g�i��=Z�)��������O_|��7������?�E���������U���U+�����?�
�&+�?�='��L��@���hv���/����o��[4#��h���M�s���;!>��M/TY<����e��K����������_����w?�?B�g��p��q	r�I���o�E�;�����/������W�����A���w�|�����/���������_���������q}���������������������={���6|��)=��w4��������)�"����=���O{��-�n����l�qgi������'t��:�����~��{����~������w��������������������w/w��=��z)V�f���t��[d3��-_y��������S���������N��w�{����?%W�x����}j��������_���_}������������n�txj"�	�.}w�Bu�����}G����x���`%��Bl�m^����0��j�E/-�%l��n}C�����c4o	C�-�u@"#R�-agC�nK��G�6G
����	��DZ�H����oX�����W`:�����������������U��?�/�6����=!�\A�_/&S
9�u��^��u�^�W�j�
}{�)�{�f^����^�H�"����j�g0�z)zO3��jlD��#Ka�����)����9/��C�S�{E�%Yk!����Dd-���"������0�G(-"��5Fv��Dd{�z}������,���o�������a���-����p^d��E�)�TdW��0��M"���������"���9B>�^QU���!����M"�^�������"�@�U�{�qd=(8����~�"��l��p+z��L�l@>�]�$"���C>���B;"�
eB�*4"^p�hGB���ZX�;"�)���j�7!���VqIh����NeR������N��V��D��k�\�mk)jFZ;�imk�3#��i�:Q��������Z�Z���eb�����r{�����Rf���� �]���u��"�]��:Q�Z���en�ZR+���Ln�C"�X��^�DIjCz����j�Ia�BD{8��"��	�:O��]��+3\�X��~�	���@p}G����/�{�0��A�xr��_ce�����M��^��������j����+����##���Dp5�e��y���Qi	s����8����n����U4���y��7B$^@4�<��Kh��$�kA�e�����)o'������6V�<4�Mh�Hp{�E}��ht�y���B	s!���)��.�_t:���VG	�ep���������h��4�� �F�w�����s(�F\�	T�����k,Py�4�4�qi�wHs�!���	T�#�ue��T�#��e���*�{��������<��y�n-P����sIp�
�s�1�=Q�
�s�s[T#��P�����y�x�sOT�F��#�s[+T������/���<w:���D�jB�;�yn�y�Ppg���s[���s�C�kNT�f��s����
��<w.�����������i�R����@� �]����]��.�4��(P�Hs�2�5��i�J����E���\s�>�!�]�,����6d�[��6�������������!���$�4��4Mh������
�!�5��S��b������VY�m��6�3
(n{������:"�Bl�S[uU��$8��j����G�u�8��	��X�
0E,���Dp
P�`�)�y�T���	s����`��S����\��s���'N���0�K4���l��6�rapSB{������C_����8z���/s\�HpW��!����Sa0�Lrmcu*@r#�;����r#�����N�b�����Tp�r]���fBY�;d��<u*8d���rmcu*xd����\�,��\{�:����2������,����kB@�Y�=Q�
�rC�������,7,�5����,���O��r�2�-�2�
.���`�����,w<f�'�S���`����	Y�Tf�$8����r�c�{�>5#��	��Z�����o�&7�Hr�C���(O-Hr�2��[�S���Lr�+������'�S+���Lr�����$w-�\2����,w=d������,w-����<�!�]�,�yp7���!��O��6��[��������3c+�\R;�����^�<}j��Xn�7��FgFD{�}�Dp��ep��F5!�r���@5*83"�;8�Dp�E����v�@5jhI1��X�5�����#�l�h/�{�@5�I9�[���h@�h�����D���=O�q�HLo�T�it��v�$8����9�F#����7��t�X�qZuD{8������Gi4����P��B�D���
�8�4���/��D���=O��
!c\+T�3�r?��_.�p�h/�{�B��� �y��X�zl���<���$��S\"�����P�y.1�eh�Py����s�o�8�%����
U@�K�sZ+Tyn(�\��Dpq�KD{��y.1�eh�P��s�2�m]e3�(���2�'*T�\b���Z����N�@����#�r�h/�{�B5#�%&���y�\��d�'�y�|�sOT���3�s[+T����s[���8�%����
��<���2�V�V��K����%���\"�����y.1���V�6��k��6?sq�KD{��
y.1���V�6��[���>s�y�v�s�y
������m�PM����mTbLJ��y�;O��������
����F�o��u�z������I����m�PMxnD{��"�=w�s�y
�dB,�\�X�������E"�xnD{����*�X����B5Y���
�Dp-����2��)T��"1���B5��[����"�xnD{����_"�s+T�<7��Ca��<7���y
�4L�����i�����H�Y��!���)T�C���<�7V�&�<��y.��H�#�u�<���PMy�/�\�X��<�\_����"��<��\�B���2�����<7�y.���yn8���D�jD��<��V�F��c���
�DpG���!��'*T����s}k�jB�;�y.��HwB�;�\�B5!���<��V�f��S���
�Dpg���!��'*T3����s}k�jA�;�y.��HwA���\�B� �]�<��V����s[+T+�������P��sW���V�V��k�����Dp7���1�=Q����n�m�Pm�s�2�%�=���8�%��n8O��;�N9�]Bc�j����h���D�������N;O���E�D���
�����h���$��C]"�����P�Z#�r7��X��5����Dpq�KD{����t���64V�f�hD{G�'\��^�<�j6+B,7�
������$��C]"�����P�vF������B5���F�o����C]"�����P����MoCc�j�A�h�mM�p�KD{���y���31�%4V��������T��D���=O���\j�Kc�jv�s]���~N2�T���2��)T�G�K�vi�P�y�/�\�a�Dpq�KD{\��(Q$��t��U@��	�e����D�jD�K�w��6��\w$f0�2p�KD{�e��.1�e�8������:�8�%�=��B��t����m���Dbh�T�x��� �'JU3^j�K�Z������(��_/Nx�h�{�X� �%��@�wA���Z�8�%�=��r������m�Y�Zf���^�S^"����(XmH{�a/;������ne��Z+V8�%�=�y���!�%�����f�t�{#�{?��.�� ���V��#E|�V������I�W��p/������"F���c�%��
���|��O"��o�{����E�������p����=��D|
p�� ��)W�#�}��/"������I����1�U�IW��A���X�Z,�����O"��B��_u�v���~#�R|kWK�7��'�����;���<�j,b$�/�0%�;��p���$�;��p�{�z�8�	���W�C���Kf�u��1�U��W�G�����W�G��	��z�������=Q���=�[�W��'n~[��o(������7P���|5"�
��o��wD�;�_}�z5"�	��[�W#���`��o�	��x�~������w"��n�^M�~'�����D|gd��1��'�W3���`���z5#�����oM�f$��1��'�W��� ���x� �]���yr� �]���>Q�Z��.�������J��m���zL}������w%��n-]mH}7�}o��yC��3_}�r�!����+Wk�G�F�����@|W
���<�j�V�X�(�m_gG�{O�'_����<�jU3b,7z��4�����O"�8 &�=��y���G�X���m_8="�{r?������2��<�j5��r%F�(�X�Z
��1����W����<�j���r%���@���p����nc�91�Ax�S���"�r�h�����F���6.�XqRLD{����u����Hw�8���n��ocar�Y1�Ax�S�V�!�r+�h��:��n!���/N��h�{�r�:�����h��z���L}[��Zq^LD{�����#�%���@�7 ��e���7��c"������/�H1�%��>D�K��Q$��0r�P����\�86&����oJ�y�7"�%f�(�|HwD�;��o����D���)q�u������H�!�	i�T�����86&���Mi3��f$���E���Hz�2�m�-�����"�7%���[���cI;$�� �]����j��1�EpoJ�y��"�%f�(2+����w%ok���D�������}Hw��1��Y$��!�]	��Zj��1�Epo��ev�]bv�"s��n��� �������^��;^f������d�"\�������A�_��t���?D7b.E��N�) ���8t7��u�7��iT��1���X��40��m�����u����T������E����p���k��F�W�E�j�Hq��*�f��F�o����u#����'Sm}�	�K:P"�=���P�������F���=O���!l�|�#�Act�l����m��^F�<�jf�H�]�M�Dt�������C������S�6�|�|�o�Tm��#�n����#�u�|�<�j��w=�w��R�G���|�u��- ���|�D�* �
��[kU�n(�]rc�.��p�wo������n �n�Z����e�Kn,�����|��>�������%�PHDwB�;��.�bK"��������E��3����������\����"���|�wok���?��3�w[kU����w[O�����!��������.�ZkU+����w[��V���!����������ZkU+������o6���q��Z��|w#�.9W"�����w���?�S�cc"�����U����	s)�m��L~n$���������$���=M��!���3���v0#DW��Z6���cY�uxl����UM�6��4���vt���]-�����:��F|br�V5uF!Dbj��V���
]C��l��v,#���L�{�V�#�"�5wh�UM���{�J���$���=M��-�h�;�����^{�8C������2���U;�	!c��j��
���w��DxaVL�{����Q@����V���������<9$��b����&W���R�b\[�j�����������C�{[�^�y�����V��� ���m�3{������������\k�* �
� ���
Hy�1�=Q����b�k-W�HyG��v��;"��9��z������Z�Ur���y��@"�R�������	)/5'����f��S���Y�Dtgd��!��'�U32^bJ�"��%�� ������
$�� �]	�=Q�Z��Cb��C$�Hx�2�
�	���w9$��D�jE�K��Q��Z�"�]�����$��!�]	�=Q����#b��7����w+^2��.�������*�!��&�����: �n!�m�^w,@x#����'V)�"Ax��N�U@x#�7�p�|7����yb�RB$��o,V)m1��m,4+
|7����yb��B$��o,V)|7�-D��������2��iU�L�����V�,����]�1�U�nD{��<�J��	��kU���p�m��T��u�|�?O�R=������Z����F���6�X�s(t�!������|7b.E��V���n!��o�����n�V��A��m�U)�|���n�q�;�������iU�#�u�
��������2�m�Uy������'jU��'�nh�U����i&s>��$�����'�U	o oh-V�HxC�����G���!��O��F��#�wCk�jB�;��n�K5!������R��tw"�nh-UMHw'���"g���1�=Q������
�����\��J�V"���!�N�����wCk�jA����.��]$�Hx�C�;�(V�Hx����-�]���DEs��wE��2��D�jC��R���Z�!����f���wC��R��D�jC��Q���\�;<:�2�%�4��j�
��^F�<�JwB,��:��*89"�BYd��
Sa����'Wi� �r� �5�����#�-%V��ca����'Wi=!�r�\M>�	/n)��/�4��Ip/�{�`�M��p�5���4�-����sa�����Xi�"1Fw�+mA,�p�m|
�a.LB{��+����������Z����P�\���"��<�J!������`��[!����4��5�Ip/�{�`��B��n���
%^�7�-��5�u�y�!�u�	V�!�%��h�7�Dx=r^w���z$������+����a4�J"�I��w��Dx��pHz���U@�K�y���6�Hz5��uxG$�����%�I/1!F������w�f8���'d��!�u'JV�^bD�&I�wB�;QC[�3������%�i/1#F������w���&F3�������Y-�{�!1Z�����5��51Z��.���D�jE�KL����h�"�]	�Kv�����w=���D�jE�K�����j�!�]	�K������w;���D�jC�K���d�z���y�V��d}�@tM�7����y���&�H��������F���6�v����C�������1���X�2
Xo�[��Wk��!���)VF������+���F�t��k:��!����U����K�m�W�7�}#�]�s�|���Vk"�wuc��X����xh,���2��iU�W�`���Vez`��1�����^�<���B$��n�T��`p�\���;��`/�{�Ne�!LW7������^�4�!�C���n8O�2��#��n�S�T���n�+����C��S��G��	�K����G�������
�t�!�
'�T�n��nk�* �
��.�H�wD��n8Q�����m�R��uG�v���e3"��n8Q������5�u�	��D�����n&���!�
'*U3�������R5#����fj�I�wF�;2�p�V5#��	�kZkU2����%�Dx���!�
'�Ur������Z�"�]��������w=��'�U+r������^�"�]��f��.�l�z�c�{�b�!���kZ+V�����m�`��|��"��;O�������mKV���#��'5��/N��p�{�je�����Mn��UpxD���"���wxx���'\Ymc���&w@��j8="�7�(����� ��)W�h�Xn���7��5 �F�����/���p�{�tem���s5��H���n���N"�8)&�=��y���+b,7��d/!����[npI���/���p�{�xe�1�[�j�X��(��=�$���b"�����^�aD����6V���i�{:������ ���W�!�%��h�X����#�/�N"�81&�=��y������1�6���G��	�K��/�_����U@�KL��d�s������eX�o~���/�����������+����O�w��7��������?���������_��_�����}��������_~�������������_~�������>��c�����[�l�������P\gCt��G��Hz�l8?�^��I�m��!F��sd^FW\eCt����� �=wX=�TK�
0���/�������������!��A��� ���Ra�r�����6D�x!��G�����1)�-�5���b������k��D�����{��C�b|L�nKu
1"��"�2������1��8wqz������R[C��~/f����������n�����n�Y��a��R-�5��7�.EW\YCt@~#��26��s��RWC��w#�Rt�u5D|7�}�n�;��1��-U5�|7�.EW\UCt�w#�ct��L���;���<��71|�l*]|7�=F'^�����F��=O���B��m�U��n�{�#d�|7�=��yZUo7�H���ZU��.1��qt{���At����~A��kU�|7�-hU��`oD{����~�#Ax���"�����X���E�3^}�Z�;d��`��;n��:d��x+�X��=R^wLy�yrU���z������#���o��9 ���{�^�����]�%����GD��"�
�{�`5"�
�%�tK�wD�;R���wD�;�^s�b5!�	�;�V�&d�q��Zn���N����(YMH{'���%�i�DM�k�y�|�{������w�xok�jA�;����� �]�y�9Q�Z��.�m-Z-�{���N�V���1�5'�V+�������j�"�]	��Zr���������Zm�{7��������w#�4>{����<�j����p1B�ex�VN��pKGG��n�:<9���/�H1�%�����"L���k,\
8A&�-�ka 3\��������h��VN��p���.������k:DHt�p�E�'�D�����u��d��2��������h
�KVN��p�_�8@f� K����!��5�� ��5��p��p1@&V���~D�DS�X�p�L�[@���w�2���X�w^p�1\��y��b��d"�R�����2���X�w^p���!2/���R���c"��C���E�{1>&���\�<�b����6�����
���cRU�y�
Ht/����nk�
�D�oD���1����T�w^tGd�Cd^F��F��c"�7�Q����b|L��91�Hu/f���nk�
��D�oD���1����t�p^t'��#d^���J��c"���*�.�������;#��� �2��e*�^i���pv�p1;&���������m�S������:��.F�������"����2���*���Z���1����Tt^t7���c^F��R��c"�Bt[��88f����N�����^L�y��4��\|7�-D���:���et�����"�wCc��)��n!���S�w#������'�Ys�+B��w�������������q������_>�������J������b����O?�����??���C��'����3vw�g�m,��G���_���������X�}]�e�"��������[�Y�A�����` ]����|l>\G{5���8�Y�A�����{q�^G{5��]��fq��3<n�����NR@�|�#�[��jp�F(�-��j} x�m=>Jw��7�X��'$�
���� ?D����^�<���
!�F��DpGx����N���-F���=O�t���#�|D"�����������2����nZbY_$+X%�;�������W�ne1���y���Q��j�����1"�cpd�[��. ,F���=O�t�������<��A?����d��F�a#�$����#�;*X%��B7������>s7��+��H��y����nD-��Bfp�s�2�%���y�v�sok���?��p�QE��wpfD��m��m�����h/�{�B��A�T����UpfD��/�q��WpfD���=O��Z!D��R��j83"��q�5��ep�S���"�>��B������'�.�����2��)T�,�h��X������p�6�������2��)T�N�h��X�������$T�E�vN���
��z(����(^�n�hD[n��<?h��a�$s�B�������]���hD�6*�:��a�$s�B�������U��:������*�<����*����2�%k%�����2�%��J�#���<���P����sMk�* �
e�K3�n@�y�=Q�
�sC�����DpG����:�#�������y�X���6/�	y�X����Z��N�s�C�kOT�&��S�����Hp��N�m|Y�g���!��'*T3�������y�L���r~A�;�\{�B� �]��Z�Z��.�m�y�r�s��
��<w-�\R����<w%xn�J�"�]y�=Q�����e�K������ne�����o�s�c�{�B:��[�����@pC<7�}�c���F���=O�
���<�LH%����s[��A��h/����P� �2�%s���3|��4�����A�����=�Sf����3
�
Y#5���;Y�~����o��,��I�oa��&�s�-�'��aC���7d�'���#0���mz��o"����'������o�O"�0���mz��o"����'������olcAo��yG�o���8�����2��	z�b��
����wD[nc�g\4z���M��7.��#�;�w��.��#�Bpk>����_���	z�
�;b��|@"�+0������3�+z���M��7n!�_��	�Dp7`�m\��]&"����'�M8K0b�#!����!�}cAo���F���=O��p�`�|GB*\e1��m,�M
xnD{��<Ao�!��	�Dp5����84�'�4����2��)T���HH%�k��N����g�d��F���=O����a�|GB*\��1?���k5z����)T����8$�k��N����gn���y�p�B5������C"�=��������W��!��S�&"1��qHw�;����B�<7���y
��C#�;>��:�������������C�;��PM8D0b�����G�K��
My�?��'*T8D0b����n@�K��
Myn8��'*T8C0b������<��84��F���!�u'*T8B0b���	.�\bx���Vh�����<���P������C"��\bv��Z����N�<���P������C"�3�\bt��Z������<���P�������C"��\br��Z�Z��.�<���P�������C"�+�\bp�k�P��s�C��NT�pz`�|��!�
y.17��V�6���!�u'*T8<0b�������A�
t��=7�W^D{����[b��
�qHW����5V�fgFD{���YM��e��8D�gFD[�X���E�v�p�)T��.��Dp5�m\c�j6=w�e���P��LD�w|�5��F�p���v���.�<�j��e"b�����m4�-�k�P�vE�v���)Tsob���qH�m4�-�k�P�=h��ep�S��A!�r�	�����hD[�X���F#�����P����]&��C"��`p�]&|c�j�Q��ep�S�f�<�b"r��!\�<��y�o�P�y�?���<�j��s}����Hp���2�����<��\�B���2�%?������s}k�jD��y��
��<w,�\�����<w,�\�Z������<�D�jB�;�y.�qHwB�;�y�o�PM�s�C�NT�f��S����Dpg��s����
��<w>���D�jA�;�y.�qHwA���y�o�P-�s�C�NT���K����DpW���s[+T+�������y�Z����!�
y�J���
��<w;���D�jC��<��B�!���<74V��y�v�s�y
�������8��t�s#�Bp+T����C��S�<7b��������5V����yn8O�Z4������C"�xnD[�X�Z���;���)T�1��s��C"�xnD[�X�Z����2��)T�U��s��C"�xnD[�X�Z,����"��;O�Z���D��:$���n��������h�{�F��b,3]�����L7�-�k�Q-0��� ���T�0!�2�%?����h��T����C����T��!�ue�K~�u�u�u�T�G���������d�d��L�x$��Lv�:��d������D�* �
�m-T���Lw���ux���C�����	o(^������w,3�=�i�)�xHyUw�Z5!�����B$�;!����wOa�wB�;X������w*�^������w*��=�i�y�\��'jV3����{�/D"���L|�,�q|d��1�U'�V2���|�/D$�H}�2������]��.��W��[��}�2������H~�2������������W��\m�~�2�����nH7��6��V����<�j��y�J�~������n	]c�j��/�A|�S�Vec�]��H�W����������_"����'_�Z#�r� ������#�-���~����� ���W��c�9.��H���x���5��V���<�j5+b,������Z��-��������0�A|���V;#�r�\���o�i�[B�X�ZqL�{�����c�K.����������~��$��2��<�j���J�������F�%t�����D��=O�Z�_b&��H��!�u�U�����D��=O�Z=�_b,��H��#���m�_�H�� �'�W�/1��B$��������p*L�{����/1��B$�;"�	��[�W8&�=���������C!���������+�
���D�jB�K��������'��������p�{�~5#�%���_�H|�������+����D�jA�K�����.��������p�{�~�"�%f��_�D|W��+�uk�
��D���5'�W�_b\��H�wC���W���pTL�{�����C�KL�����n������~�u�#�����_m�C��%���*��n	]c�jS�#�����_mjE��%���j����oc�j��#�����_mzF��m�_m�o�[@g�W�����<�j3#b��oc�j3�#�R|�W�5��c�k����|0Z���_�D|-������~��
}���������[BlX������H$B��pK�KX[���)�M	4ot�	L~"��G�%t��m�^D����7�N#B���_�Dt�_G�_�X���_wHoJ�y����:���_�Dt=�_O�_�X��<�_H~oJ���������:$���z�����U@���M�3ot�@_�������7P���p5"���M��������%���"�)��Z���������K_��NHz'����&$�Azmk�jF�;^��t�����L������|w&��m-Y��w��+��n|y�� ��	�K~�]��.����	�Rx�{^xWd��x��C"�+2��`���Z�"�]���wC�����>$��!���k[�UR��p�{bx��n�%����]�G�Fp^�V����GG�{������~C��!^�	n	][�jG��w
���4�jG4#D���}H�Ww^E���m�]��xtD`�IV;�!�v��C$�+�W�0m[�j�`�L�{��4����x�����!��h�i�jVs�e����&Z��H�������k�>�}[�j���P0��NS�����h�K~��=��'�`�mU����Q1�U��Vs7h�Ht�%����w �`�mU���P2��=M��;�!D��.�}H��Y�+��P}[�j�������l0�y/1d��>$����:���mU��^�{ok��^����2C~�
�{=�{���U@�y�m=6x���RSf��C$��{�{������7���Zl��wD�K
�!�����{G����U�	y�x�{o����	y/5c��>$�;!��(��Z����N���������R#f��C"�3������U�y�|�{OT�����������w!x��Z�Z��.���D�jE�K
�!�����{W��6���w=���u�`/�^j��@��n�{W���E�
y�v�{ok���
y/5^�t�@xU��w#x��X�T���2���V�"�{I��xo�[B�X�T���y�m�5x����F��8P"�
xo�[B�X�TZ��y�m�5x����F��8P"�xo�[B�X�TzC����k���X�H�^���5�{#�����2�{#�����Z)�"�{IJ����pKOd�F��F���h/�{�h��!�wh,Z�ho�[*%i�XoD{��4+���b��5�=Q��RU���;��h/�{�d��!R���d����$�5��C��9�=O�R9�#8�k�X)���Q���e���y�!���)V�#���u�+���S���e�
�y�!��'*V9o 8�k�X������/U@�9�=Q�����������w$8/ytH�wD�;r^{�b5!�	��Z+Vr������!�	I�tHz������w"H�k�X�Hzg���G�Dxgd��!��'*V3���`���b� ��	�K�]��.����(Y-H{��������w!h/ytH�wE����5�y�J�������w%x/ytH�wC����E�
y�F�������w#x/yt�Wwxtl���?O��]��2a.8�7V�tGG�{��!^� ��^��<�J� Rcd|c�J+8:"�{�����;<:bx�S��6�h+��VZ����stH���$���=O��F!D���o�Zi�i�{��!^��^��<�J�
!�t}c�J[��%�]�G�DxazL�{��T+m�Ht���U+��d��stH�&�$���=O�����v���j�����n���!^��^��<�J!�t}c�J �F�����1	�ex�S��C�K
���U+���:���G�Dx=�^w�{�S��G�KM���U+���z���G�Hx���C�;��Z�����Z�
�{�{��C"�yo8����������!Z�V#������U�y�x�{�U�y/5D&�V�&��#�{[�V�����'�V�^j�Lh�Z��{'���G�Dxg���!�NT�f�����Z�Z����%���.�{�C�;��Z-�{�12��j� �]�K�]��.��w8Q�Z��RcdBk�jE�����[$��!�]y�p�j�!����������w#x/����y�v�{�S�L���#�V��������t�{#�����Z�"�{�VF��p��[$����F��u��VFm��{5�N$��bx	�K�-���{#�����Z� �2��]c�����={�Dx
���2���V�L��{u�X�2xo�{��"^�7���y���!�y���V���p��[$��k��!�u��V��1��X�2=�����E"�C��;���<���{#���Vf�������wE��^w�je�A�e������q�{]���{�Dx�^w�{�y����{]�����je<�^_����"^�����U+���S���j���2������������Z������U�yo(�^zo����w<���D�jD�;�W�V�&��#�{[�V������U�	y�D�^�Z����N�m�Z��{�C��OT�f��3�{Uk�jF�;���[$�� ��y�?Q�Z��.�%��J�wA�����[D���w9���D�jE����l�*�y�J�^ro����w=���D�jC������*�
y�F���^������n�����Zm�{7�����������[���5�'�D���=O��������j�ZYGG�{��"^� �^��<���!�[i�X�������E"�8A&���y���B,�����je5�={�Dxq�L�{�p�je
������V��d����H�'�D���=O���^Zb����U+kA2�p��[$��#d"�����Z��^Zb����U+��d������wE��d�{�je��-u�n�Z�$����E"�8D&���y��u
!�[�j�X��xo�{��"^�"�^��<��:���(��V�#�u�%������2���V�#�%F�h�Z�
�{=�{��E"�8E&�����U@�K�����j�����{�Dxq�L�{�U�y/1JF������w$x/��H���D���=Q�����d�n�ZM�{'���{�Dxq�L�{^��([�H|�Y2����f$�3E|[�V8F&�=��������&�Mk�jA��P��u|q�L�{����/1MF������w��ok]�D��=Q�Z���d�i�\m�}W�����D|q�L�{���
�/1OF���U�!���K���; ��A|����nB��5�������szH�WY��!�U�y�U���F�%6�z�7����������C������^���Kl�^��o�{��!_���
��<��7�#���W����sz��wE���y�Uo
b��oc����#������~#��������W��`���z���~#�{�����~#�����^���	�k�W�`0��m�n���� ���W�� F�����U���F���.�u�~�1�U��W�C���k�W�C���K�.���~�1�U��W�G��	�k[�W��'�/��H�7 ����W��^d��`���z�������D|Gd���������H�_�Z�������=[��"����:Q����������	��D]�6���w*������D�������w��o���H~��=Q������m-]-H~g���G���� �]���>Q�Z��.��[�W+���"������zL~������w%�o�Z�Z����%W�D|7$��1��'�W��� �}k�jC����\}�p�L�{�����_�c��2�o,^
��=�O"�8X&�=��y�����@���}c�jPpzD��p7��n�;<=R|��m#�o�o,^
N���&_-���<�j01�v����`@:�p�H�<�l�� ���W��#�i�o�^
��������p�{�|5�1�v������/�	�y���e"�����_
���^�}c�j@<�p�J���e"�������a#�lwh�_
���=�M"�8_&�=��y�����RSf�������:��6.}p�L�{�����#��������#���%��H|���c�kN���_j���Z�
��I�&_1���D�jD�K
�Z�W#�����${��/���p�{�~5!��&����	��T���bY���1���D�jB�KM�Z�W3�������I2��D�O_|�E
�-!��NDLM�Z+X2����+Z�~�8g&����oJ�y�� ��f������B�_����~q�L�{���g���H~�Q3Ck�jE����oE�g�O��D���)s�
����4�Z+W2��b��o�p�L�{���f���y/5g�5��\�7�-��~m����hoD{���f��*�	���VN��p���>]���F������7��C��u�%+���F�o�=��@y#����t�����5���1\��������^D���^���\�5V�������F���h���];"D����b��@v#�{�p�o�7�������*����K�m,T��n�{�E�Dx��+�:���n�\
oc��
�w#�{�)E����
7����Y�H��Z�sHxAx�u	�;��=O�r�#�o,V9���S���������k���������V�R�@P�����xR�p|�{�\������r���7�9/��V"�#R�����D�jD�;�����&��#�y[_�	I�tLzO�&$�Az}k�jB�;Q��q����N���D�jF�;���V�f$�s��Vtf������!����ot���y}k�jA���9oE_v��"�])�m�5x��"�]��[V+R��Ly+���FwE��R��:k�FwC��R���^�!������';ot7d��!����kt}���m,W����mp"��d"����'Wy�!D��Ph,Wy�F�[�n��u��d"�����Vy�"D��Ph�Vy�1��~���y���d"���
�U�<���k������w_���o����o�����z��/~~���|�x���������1���������]�����OT.e�c<<m����E��������Z��7W���u�S�����{���^����;�CAO�P��?38P�"�cp������PxJ��y�,B,7'U��?38��"�Bp�z���^�<��;���I����uH�1����qG�{���<��{��P�U�Dt=�O��o��{���^F�<��{��H���Dt�O��'�kJDgqD���=O���5��:#�7B�ED{��>���$��2�'�v����!](��h�y�+]��^F�D�n�����i����ND�����pD���=Q�����;�C"�3���h�O>��.�������J����]rG��.Hw�M>��O"�8�#�����J��|����Z�Z����%[KDGpD���=Q����Rs8ZKU������kk�����2�'jU�]j
Gc�*t�w7�����C|7��l#r�V�!|��V��������U�w#�����U5"D��6��������Z"������=O�
�n�\�?m�U
|7�����Dt�B��]{�V������ZU0�w#�{��DwC��]{�V�E�e�K��KD���h�yK/]|7����yZU�5B,�]�6^"�=�����������F���=O�
C��|����!����X���
8��mU�z�������Pe\Z
DY�/�8M���j��q���S��u�O��	|
�z������F,����xK ���=<��9{=�=kt{�g�et���F�����xK ��`t�9{]�����,����y����r�o	$�����H����7��Y�{��<mo�R�����"���#U$g��?���]w8��?O��T.b��z^"�^h�T�\��_����;������X*1�Q>/�/4G�H�}t�]��3ct���F,���������=�F�HNU��e�����vD1��i{#��E���6���	�H���v'���!�����F,����m���3�]�HNU������|w>���y����rs!������.Q$�~g^��.�|�?Q��R�����Z��|�(�S��y��"�]����Z��E������V��D��S�F��n�w�c�{�V��rs!����
�.Q$�*F9�Fw�v5�Et����	K�&�g�m�UM���(�S��
a��b���2��iU��MD�2o����;Er�s�	��D���=O���Tn"z��'�Dt5���(�k�UM��&����yZ���r�e��O�m�UM��D������5�w#�����UMX*1��X�����|�o|�;Y���et���&,����m�UM=���(�S�y����"�����UMX*7-�H�!]��Q$��aw��2��iU�|w"z,����i�������.�W�p/�{�V59��D�%�sHD�!�u�m����R�{�����#�%�,�����#�����w�]���������|�h�Dr�������=�x����"�����U��w�&K��z����wG��V����.�W�p/�{�V5"�%�,��C"�������(x����"�����UM�w�&K�l����w�2�
�����^�D�jF�K�X"h���L���F����J�etO����D�%r��Dt��Ew[o��])�����R��t���DR���HwW��V4���.vW�p/�{�T�!�%z,�I�Dt7��u��Z���J�et�������t�l-���c#�-}��������2��IU���<��l-]�FD�F.�g�F�{]�T5�!���-�%�����hK�nc�j�pnD���=O�������I�O"��`t���[����J�^�<�j63B,O�&;
K��H�>]���T��2��)U�by07���DD��������A�����IUs
�"�BtKUs"iD[�nc�;
]w8���'U�4����m,U����"�aC�����IU���<���9+]�t�Qt�������C�����f�t���.)�ID�#���m-D>N,t�t�D�* ��e�K����n@�(����jHw�1�=Q�
HwC���R�DtG���Lw��#����������H���R��|w$�nE�T��N�w�C�N��&���w[KU����������t�w��Z��|w.�]�Z������%�IDwA�;��p�V� �]�|���$�� �]��\�\��.�|7��U��w�2�������J�]�DtW���!�
'jU����w}k�jC��|�D'�
��v�w�yZ��!���|���!�������X�Z:���et����nE�e��kU�2]����$����F���=O�Z���|�7��
|7�-E��V�h���et���="�2�����E��hK�m�U-���������7�.���X� �m)�����*t�!�U�yj�b��F���6V��7�-���Z��
]w�xUw�\��1�)oh,W-=P���^�Dx{���Ax����A#�2�
���e�����X�Z���Ax���!�2�
���!�u�%�I��!�u��Wu�)V�C��������G������y��z�!�U����G����7����^O�^�Dx��pH{Uw�f���2�
�5���7��D'�yo(��E�y�X����h5"�	�K�����w,��U�	y�T����j5!���K�	/������U�y�D�������w�xok�jF�;�^u�j� ��	��Z�Z��.e��$�7
���w9���D�jE���y�����wE������Z���zL|������w-_����6d�k����5����n��W��[m�|�2�U�"����c+S_�5�F+���p�{�p�v3b$��_�D|�n)�����b"�����\�jD�D#���t�*8="�R|KW+���p�{�t�j�o�R�b�P"�N�����8$&�=��y��j���J��!w@��N#���?���� ���W�������5V�V�i�[�oc�j�A1�e|�y���k�H����Wk�i�[�oc�j�Q1�A|�����C�D���~���F���6��ZqXL�{����uX#�D�T%��4����R]��-kxqZLD{�����!�����������:�����W����<�j�H��1��|����2�m~{����� �'�W�/58F�����@�_�D|qfL�{����/5:F���F��#AIt"�E�;�_}�|5!����������w"�/�N"�87&�=���������Tk�jF�;��D'_���D�jA�KM�!�D|��A+�o|qxL�{_s�|� ��f�������w)�_M���/���p�{�|�"����������w%��n�q�L�{���
�/5G���H|��n���n��l���n�����_�+.�A���X��:��n)����6��w�����_m
�o]�oc�jS�#�R|����w�����_m�"F�����������X��4��� ���W�������%�k��F���6�76�7�}��������[B��:�v����%Bl�G��7�868����oJ����"B�����n�1������^D����7���	�K�O"��������6��p/�{S���aD��m,^m����|������M�3otR_GQ�������:���������C�{S��]�����4�6���S��q]�����C�{��/ot�^O�^�Z�
H{u��:�io8��7]��FwD��kZ�V#��� ��������w<������7��������d5!��(����h���N�W�7��2�	�D^�Z����N�%�Dxg$�s���y������5����L0^�Z�\��.������ �]�kZ�UR������"�)�R��=/�+r������^�"�]	�{]jf}��mHy������
9�Fq��z���w#8o��F���w;��=M�Z��G�Q���^�����MDw���	�etO���N�H���m������rLMf}��f�)<7�����B$z������n���rLMf}���2	�exOS�vDB$z��������-w��d�'^�*��^��4�jG� D���m+Y-��^S�����O"�0U&��,�8M��M���k�JV�� ���S�y�Dxa�L�{��$�Q@�D�]R	�
���
05��I���$���=M��!:�H���m%�����/��0U&���i�����l�V��� �ue�K��"�E��y�m
6x����R�el[�jG����y/��K��#���������
�{��2��h���2���z���������^�9��{��2}k�jD������%�;"�y�m�5x�;"��f���U�	y�X��t^/�	y�t�{OT�&���{������w"x/��I�wF�;��U�y/5[�o�Z��{g���V����!����ox���l��V����{��@"�+�������Y�7�+�^b���[�V+�����%3��"�]y�m�5x��!�%&����j�!���{����oH{�C�{[[
���i/1WF��E+���pK�s���XoD{��4+�m�b��5+�,F�`��Yot����2��IVJ-�"��%+���F����z��]
�7����y���B$8��X�R8o�{O}�@Z�p��2��)V��Hp���b�p���]��Z��;���)V����K�m�X)�7�}#�E���w���<�j���'8��X�R=p����J�����C�k�S���!D���+5��p�y�$�Ho�{��+�B$H��X�RI�+�^rk�H��^wHz�y��rHzAz�����Hz]���;�Dt=�^Hz����G��	�;���^O����LPYo8d��D�* �
�m�X��z�z[�i�Y�x�z������w�Xok�jD�;7����-jB�;�^{�f5!����ZkV�����%G�I�wF�;�^{�f5#��	��ZkV3����z+��fV3������(Y-Hzg��������w)�^���Dt���1�=Q�Z��.�u��9�Z����x��"�]9o�`�"�]	��ZVr��x�K��8x7$��!��O�6$�Az]c�Jwxpl�M/�N ��$���=O��������k�Xi'G�[
oc�Y����2��IVZM��OH����VptD�t�+
Sc�����Xi"1:F�����prD�%��8�03&����y��6 �c�k,Xiji�{���U ota\LB{���*m{�H��yj��4����@������]�u�����'W�� �r]��U��4�}r��q1	�et�����b������*=�T����Y��Ih/�{�\��
!��*�X���`t�.+�A�F�!�u��w8O��	/13F��r��HxAx�hh�|����<�J{�����[�U��/�������
�w�!�N��]bf��LbU���,����n��w�����������q����w?����w��������w�����?����w����������P���3���������B����_�������������N������<i��+1K�V���g��x F�U��.6�h/�{��g���%�
?��it5��x VQ��
]��l��y���Gb�h6�|ci�8f-�>��	ot��pD{���=�o�,�kX����� +[�y�lN"��e8����y���'b�h5�Bci�� +[�uXE8ot��pD{���=�/�,�iX����F�\'�+����[l2�^��<m��1KtV���g���x�+^����G��u��{��Y��ph,�Y�������G���=O���F�R��Ccu�z����0M>��/6�p/�{��g����:
���h6 �%��i���Hx���C��N�����:
�������x�����&��exOT�����:
�������x�����&��exO�����%:
��Z������4��O"��d8�����>�T�a
�Hx����0M�SI��G���=Q��Wb��4���V���1M�SI��G���=Q��gb��4��V�V���1MTI��G���=Q��gb��4��������x!���*����e8���?O��;��=�jXw�U�������X����p�{��T�^Y�H<A��V������X����p�{��T�^k�H<A��V�������e���#�����Z��C�����K���~\A�7�}Ys��R��������������[U�(��;
U���}�D)��Pux=��^u��9�IE{.?��T��i�H�w�U��a&��O&�����F�a"�0���=O��}����k,��)_~2Y���7��(�yT��y_�W�H=�n����(_~2�����
�FL�bt����0#���l���DtGL�B��d��b����E�x{�{����#B,?��d�����A�{��b��N]��1��	|��&#�Rt|������x�;+t�<�
'�{3����{�]Ir#[�U�\h'��$�N'	 ������RAz�Y�����f��i�w"T�B���r���#��2s�j���(������n�G�G�����#
/d���f�[��+��������nE��C���v�!�V�w���k�����������������
�^G�m�:�+i[G���� m"���}����Uu��.��������<���?���������z����������cg��cF�>7(.��Y�D�>6(��];W����Sg���v��iW�D�>6(��];W����Cgq6��v�s��~'��W��n��#���}�����kW�U�+xR����<�`>��&�l����!)3�����xR���fV������n���-v�j�V�(\�G���wQJq�^�c�}OJi����}w�Q�j��m���)��L����������U��1�p��+��G-X/������y�y�b������/���7!�F�y_	~o�	�7
��-v�jO�I�^ma�z�/,����������Cc��z�D���*#�����[�������Ceu ���w\f�{ ��+������{��-��� ��{�K.3�-��������roa��PZ���E�^����zO��S�^m�|"���Z���{
�+^s�QoE���j[���[����UE�����\f���{+��/e����������UC�m��]f���{��/������������UG������'����s��l���Ki��Y��d�(p�xbJ�����W�ZE�������Y���{)4W�������2�*[��|tc�uv�*z�^
���l�����L���*���n����Z�u����G�3�]�{).S����+p/��kg�bp�Q�^�HuF����2�*[��{)��^;kC����G�3���+p����p/��kg��V1�������zw�^����V����;p/������U�f�W<R�Qo�����juo��7����Y��{�������z�{�����`cB��c��v�*&��$p�x�:������U�53ros�7�V�7�+���7#�f�{�K���E��c�����@���j[����W�@0����{���*�������� ��{w��X�{��{���*��E�^�HuF�'ro��wW>�'r�9�^oh�N��S�^����z+r��s��} X�{+�����"�V�{�o/3�m��U�t���[�m����^Ck��{�������z�{�����s���������Z��������z;ro6|>w�������c�]��UZ`�%���U�Vi������8���|t���Q���Jf]Rh�^ek�|tP����sr
~r|�kg��_1�0EW<R�Q�������|�*y�����z��UZf���z�HuF�+(S����|[#�`L)��^;k����9�^�~3�
+��O�|a���0��vP���J�bF~�����z7P���W��F���R�����������;
��>��1�a�^�3�a���iX�T!�JSzjv��0��"s�*k���3���t/l���\\Ci/������r#b��:F�n:����y�}a�����	��P�K�o}m�����+m����UJ�����
��4��^�}�K���fD^iq��-�2"oV;�0	���c	��P�K�o}g����WX�E������{���������r�:���\�]ao��rF�y��yW|+u��.�����r�:������+���"P�(�D�-<�Fm�c(�����x�-�D���x�%����{����g��?��0������[�t��1^���V$��������c(���"�v���5���1�����x�����pa�\��k�#�
[c���tF�Y���������E����Y�yA���x�{��v��Kq��7��Ki���y��F`7*{��v)����9;�]J{m�NTe�1�@�QYTe�b�<���f���v)��];Q�}���FeQ�W�]����<'%����������k���FeS�W�]����|�&���n��v�*�]������r���L���n�����y��U�
x�2s�*����R\�]�k7y_��
y��!����Rf�������Kq�v���������{34�m7�Q�����rD��<���f��w��w��qo�	y7
���]UN����]����v�n��{4nny7	���]UF�M<���f���w��w��qo�y7���]����y����h�@�=������{�=�w�w���:�w�w��z3�-����"���*��E�����
�n�yW��7��y�y�����{"���&mWu"���*�>>$���y��UU��*���������]�������[��k���n�xW�U5��&����l��m����������������#�v�w�MdG��C�}or���"�v�w���:����*��W�P�k�\UXy~a}��F����?��������_��#�#��������������P�/��O?���T�������?���?~��~��7���x�M����$�a����t������{z��i��i�{��{�I�?�����kv��u��Ai���������CX������o�+�'J����e��Ai�����#���CX�!���Qn�Di�r�����6(��\;owl#��G��v3��@;QZ�\e){��
J{-�N������Qq���rw�N��)W���i��^���vG\0�0v�9��[nx��L��J��=��Z���;"���l�?��{�M+���������-��Z���;������9��[n�Di�r����;6(�ur���;���E��
���E�����l���Ai�����@��l��T�-�@�=��v�_��^���\v�\a�����-� ��s�������[�����+������D�=y�u�����������H���
���*�n�I�-��
�kP�k����!�
6���j���G]�h[*��Aq��Z���+,�����#�6�u����p����k��:���_�+k�� �vv��L�e����v�<UY���������Ki�v�q���w�D�� ��qwUU��RZ�]e�-�����fg�����L����x�]J����y����n�����*k��<����������kW�w�
�Kq�����<F�ywUvU%�RZ�]e�-x��^��sUe[0"������n����kW�w��Kq������5����8&xF����
��<�������Z���*��y�'��(7�R�q�2�[nD��C���LU�H�Q�]eSU"�nh����{�M�q����*	a7	��-��n`W�C7#��1������y�
��*#�f	v�%s��y����@��<�mQu ��zs�O�Y���n��
����n��TY����+�{�-��e�����:u��A[S������������{Qw7�T'����n��TQ�PW|�iF�Y�Yw7�TY����5UC��<����3~17d�6d���R5d���n��T
Y���+;�(�#��!�����#�v�u������]b]�K'.����v�4��K��Oa�FP�T���kW�R��5(��];Ou:x
[5���:|jPZ�]�K'.����v�<��F���l������Ai�v��g��5(��];Ou�#�SF�Mt3�]A�RZ�]�K'.����v���:���)��&��P���kW�R��5(��];Su���-�����<���t��k3��������:�#
[$�M���$��\����������:�#
[$�M���$��\����������:#���UcSVUgD��<�j��<q����k�����+,���U��w���/�������4(��]CU�w����������]�]L'�����r
M���+����M���{H���.�����v
MUA�vj���� ��v_8!��]\�Aq������+����M���[�_L��.�����v���:�v������H��@����3��u������H��N�]�TU��*���b��vq����kh����Sc�6U
i�	�����3��u���������N�]�Tu��.���b��vw�w�������ScW6U���o���\���.���������cD�w���f���w)-�����x��^��SU�/Q�]eUU=�.���U�UU=�.���k���oQ�]eWUW����+��8�������Z������������]J;�����n�.��vk'�j80"�QYT��Ki�_����n+>�!�f;QU7�]����,���Ki�Y�����v����;�.ef�UUu���\������v����1`Dv����a7
�+�U<��������DUM�����,�jB�M����h7!��!�fCQ�v�Q[Te��,���Z��v3�n�n6Ua7���E������]����H���v���:�v�v�EUA�=��]������2��l(�
�nxW[T��"���b��vO��2�]CSu"��<�&mSu"���jK���{�y��UU����n�vUy�J����*�n��[eUC��<�&mY�x�����3�m�m�n1�U������mUG��������#��!���NW�����7)����'�e�)�l������Um������uUs�v*l������U�U���J���y������fe��p��k���/������}U[A�RZ�^e��p
��k'���1#? 7)���+��\������;���X��,��&)�@�RZ�^e��p��k����,��&++���-��\�����&�;���Y�}������������r�*����`(��^g��Zt������U�H���^'��Q/n����z��U����R����ZB���jK
\Ci�*���+l����*#�&{�������v
�UF���dmeu �f�z�O������z
����+������@�=��{��7�P�A���� �
�a���*H�E�^q���zq'��k��N�^a5L�vV'R�)P�8�cJ�H���z����H��n����*Ro�W�1�^�
Cq�:���+,�qR�)�6��&`�8�cF�����5�V
�W��mk��{��N�1�_�
Cq��zCk�|�1�����o|�1���/��k���R0��uQ�V��R\�_e���/��k'�����g_�(���~).���v�������SW��Rh�_ew�=�/��>�s_|tc��v������W�]����~���
�~����a���b�E�]��Kq�������_�;���]��aF�~��U��~).�N��3��
������W}��Q�_e{����
�+N�����Kq�����W�(-HU�W=�R\�_e��#�od���^����u���'��(��8�gF�	�7��w��W=!�&�~���JH�I�_qn��~3�o��jh�2�o��i�������_qr��~��<����^�����N�^���p�+����/��1����^��C�_�m�
�o�W��3����[��������������{J��m�O��s�����:�O�������������"��1�����"�V���UC����3|f�����o~��%�Sq��!"7	��VGn<� u$�>$���?�[nG���zm���������~��d(�����=���#���/?"s����G�o?;>�2����;t�d>�^�}������	�-2^W]=�(���/�8�k��.,���{i��/����7H(m�����&C���|��\S�m���c��`o}m���u���`]����"����/�8kF��A�#����}�m78L(������n�v�0���/�{?va��G�K�o���\n���\]�k����X.?�����f���
����v�:�����bBa����3�����c/�8\mF��B�#�`��]�{���`]�B��z;���c/�8\mF��C�#��e#�z#���I����G��(��8�gF�	�7�������x�U2���z�A�M���{f���x��x��qo��W�%�j��������L��7���!��{ �J�dVm_u ���|f�{ �C�}o�����^i���-�
Bo����|f�[�z��z��qs����:�U�X������f8���R�{36�m�D��������"������f��V��:�^CgU{�}2������U�^q>��zboc���j���>�U[Z5��&a��%��t��6���&l�[oG��������#�v{u/�4� ��!��7_��v��K��v���[�z).���{C�})�
�������V�(�PUvV��R\N�*��:�^J{m�NY9�0��BUYY9�Kq����h�?����^��SV�w�(�PUVVn]�^z�8YmF�+P/���k���Z1��DUYY=~]@�+O�/�x����Ki���+
F���*+z)�8�x�1��-��2�{�5�mw���\����m�����������#���r; /e��UVn������I��>�1��	+�y����n��Fd��3�'^N��7��������y������%d��3�^��7!��!��7S��z3Bo��W�Xe��,A��I���y������^��,@���~F�Bo.8��f�{ �C�}o��������v������^/���QoA�-C�}o������"P���zJ�H���^���{"��!��7O��zO��S�^q���zO����^/N��QoE�=����8�{����U�^q���z+ro��W[j4��:���PY5��&P���zF�
������'��r�y��y
�UG�m����g���y�p��y�m�#��1��	+�x|~����'�������\:�v=���H{�a���[0��@U�Wy�I������������v�t�w
#
C����3��+�+�T�R�aw�G�k�v���#J�S�m�_A�R\��^�vau�G�k�v���F���*�*��)����H�vas�G�k�v�����1��������������v�T��v�(-�W��hwOJq�v���x���������{����TeS�w���iW�^���1i����*=F���*�*�w#���h��F��8�];W����6F\�;�����x�G��h7!��1�����+-�W��h7#�&�w_�Vu�	����y����������q!��v��������m�@�=�����yWZ#.���.��������m� �C��]UA���h����[�U���O��2����U�����mWu"���*_z�'��9����UU�]qU��������]���v+�n��f�����(F\�9�����x����h�!��!�n���#�
;b�5�3������]���v;�n��f��:���$F|QvB������U>�]�]J{m��U�������ju���iW�|wu��������Z������ju���iW�|w�+>�!��v�j�����kW�U�x��2o�+�����G7����U�+�.e��UvU�
�Kq���
����
yw�sUkQ�]qu��v�.�e�U>�]�.���k����cDi1���Z7�]��}�V_7�]J{m��U�����!�hw����t���3���w)��];W��
#JKQ�]�Wl��]����F��8����U�y7
�+����nB��<��o��h7!��!��v�jM��I�]q=��v�w�����3����i����*#�f�w��l3������]������y�����@�=����h�@�=x�_?��.��1��h��
��!����*����]������2��h��N��"����:�wO�w�)�3�=�w�!�FCWU�wO�w��������]q���v+�n�n4tUy�
�+����nC��<����f���w��w���j��M�]qk��v;�n�yW��4�������
]UG����K3�����y��&Mh7�^J{m��U��Yq9���
|nP\�]����P�k�v�*8�e��0����:������\Ci������a�ev��;g���s��~�p+���k���0�0%W\�8��<)�e�����Ka(���d��B�Q�����BOJq��]�[s��P�k�v�*lF���*����'����P�5p)���k����0�4"W�U��c��Kq���vq)���k���~bDi3���
<)��><s��0������
yW\���BD��<�j{��+a(��];W���F�U����x����h7�P�k���*#��ka�]UF��<������������]���+l�����h�@�=x����h��P�k���� ��Ka�]UA�-<����f���`(��]CWu"��;a�]���{
����p����
]���+���vUy�xW�U�2J{m��UU�]a#���gF�
y���+.���.n����v
]UC�V��r|��.�n�yW�=���`(��]CW��w��0�i�������]eW�-��}����Um�.e��UvU��Kq����������
y7�����(��SvU����L��6cs��������������/@�h��R������R�k�v�j[�(����kF�+�.��>��V�]J{m��Umk������f�<�����;�[����v�\�N�(����kF��.��>�Dn�.����;Y�mf��WYVm/��>.En���n�n��U��K��z�m���R���V�>�!���NWm�7
�+���QoD��<�:��&[D��C�u����Bo�W�.1������K��G	[B�MC�u����H�I�^q���z3Ro��W\3:��������Ceu �f{��3�={{�=�3�={�!����Y���������zr��s�|�z���� ��!����Z$�"����V'�o��W\$;���D�=�5�V'��)����V'������IvF���d���[U$�*����`F�����+���QoC��c�u���!�6�|��UC�m<���d���������UG�m�j{����y�}a����v�>_g���e�(����`B��?��O��2�*[���P�A�v�jw3
;b�U3�u��Aq�����3���0�vP����]����q��z}�z��������~J;��N[��bFi+����Wp���WY:�� �����V�Z0��uU�V{gJq��_��!�����V{���������S�gJq�z����+b(��^;k�o0�r�xq>��z7P���WYJ��#�����V�.waS�4��weJq�}���)�6|v�L?n�i�G-�Q��*�h��oD���6�
�����;���[�	�W���Q`3�MH�I _�C��P�A���*!�
�b�8lF��7��+���Q/n����z
�UF���xq��z$������{F��*���5�V���0����f�[�|�|�v�Ci�z���+l���8�)�"��|�pY��k��N$_ae������D�=�����-���5�V�W����`3��H��'_q���z|+����!�
Kc�8lF�
����+n��Q/�����z
�UG���xq$��z;ro��W\<�^\Ci������#�
kc�8lB�qA��<�j_�p/��kg��R1�����*:�^����F��R�A�v�*���������R\�^e0�������V�g�(p�8lJ�����W�������w��Vq���\���*�����W�bX����w��V1�Rh�^ekp/����N����s�jg���bF�{��B3���{).S��y~��{)���~���~��������pwS@_q����w@_��4�|�w@_J{�~�����vL(��8`hF�1`�<���fg�|�|���|o��7
�+��QnB��<���fg��{�{���|o�	�7I����2Bo��W\4;�����������{����YB^ma�y3��������y��o}e������W<3������W\3;����{���c�{�-��E�]q���r�npW[V��2���y�-�D�-��CIf�{"���!�v�'��9<�}����r+r�)p�8�dF�9����^wto�A���x�:���^$�*��8�dF�
I�����-�3�m���y��������G����#�6�u��������l�nG����I&�����<�:q���z�����S�z�R0"?N��I�����W�T%�Cq������`�e��xqd��z|rP\�^eW�pq���k'���Y�I����3����Aq�z�mU��1�Z���J+��L��/���Q�
���r�*����c(��^;a����9�����p���WYj$�Cq���)��9���������n`K).W������c(��^;i����1�^|�}F�����S.��mvF��;��^og�I��W������+�3�����;��pw���k'�RD��x���)�"�F�{���$\Cq���Y���{��1^|�}F�	�7	�+.��Q/�����z
�UF���x����f��,p��qvF��:��^�5�Vr��?�������@�=�W�N���r�{�4��� �J�c�W�g�[�{����������{���Z�����/��>�����W\:;�^�Cq��Z��WX������������
7�P�k����"�
�c|��V
��J��m�ps���kh�r��>��+����������7�P��k'���#�
�c|��V���+���Po^�{��{���qk�y���\���*/����W�Ze���r�{�4����Rf�^ek�p/���U�V�5|vC�}o�����#
�+�#�Q����\���*{�^�{���Z��aD�{��U^�{).W����+p/���kg���1�����*���W\9;���Kq���Y�*F�W�G2��
���r�*[���R�k�v�*o#
�+�0�^�^����l������w��
�/0�O��K�)�������������G�������?~��O����s���?������gj��������������?���n�o���mI��H����O���������{z��i��i�{��'��l��xg�eO�i�v/g���s�x���_�W�!Fd#���3���y��N��1"�!?�h�@�8����h�@�8�
��q�!�>�h� DD��wg�["�"���+����qF�'2DB\�;���2D0�w'2��3�x�8�]D�S@q���v+~e=��]E�����s(���
'g��kW��5��nxr�]���&��=��{�mxp���3q���v;����Y0�w��pp������v��.����w�����������|�����++��{,��Ai�v�����7(��]�g����";�h������UvUn����v�\����hOg���c��2��;wg���7(�����U�aD~�x�8��u�v���N\�;�]��Aq�����c=1"?�T<s��nMJi�v�]���7(��];Wu�#�I�#�)��&��\�����������:6�x�7�3��n�I)-����:p����k������
��mF�;hRJ�����\�Aq�����#��O$��f��w���������
�{m��U	yWX�!���h7!�&�w�e�3�������������
��mF�y7K����p����k��2���~C<c������%��vU�z��^�5tU���C<c��nA�=�7��hwoP�K����*�����mJ���E�]q���vq����k��N�]a�x�6��y�xW��;�]��Aq������+����f�[�w������)�"��!�����!�
8�3��6��&���ewF��{��^�5tUyWX�!���h�#�v�w�
�3��������*����C<c��nY�w)-����*�.���k����0"�����v���
�+���������v�\Uq'F�yW<c������\����x�]�{m��U`D�w�3�)��RZ�]eWU���w�\UY�w)3����*+�.��^aSvU%8|tC��v���]������J���\�������n����U�-`D�w�3��n����kW�U�
x��^��sUe�Q�]eWUv�]J�������Kq������(����*y7
�+.���nD��C��v��D�����x�6��������h7!��!�FCW��w�����v3�nxW��;�������
]UF��<��glS�E����kvg�{ ��!�FCWu �<��gl3�=�w�w�]UA�=��k��
�n�yW<c��nA�-�j����[��k��N�����x�6��y�xW��;��y��n2tUy��yW<c��nE����+vg�[�w��w���j����]��mF�
y�	�+n���nC�mC�M���!�6�w�]UG�m��vg���w��w������]�]eWu.������Nh��E�����:�#�C��3��:����\�����=�����:����A���v�c��r�*���lP�k�v���0��vm�gl3����Ai�v�]��[6(��];Wu�0��Vm�gl3�]A�RZ�]eWu��
�{m��U�!`D~H�x�6�����r�*��wlP�k�v���<F����gl3��@�RZ�]q���vq������\��/��+���hwMJi�v�]��6(��];Wu�
#�Cr�3��F��
K���3����q����U�y7
���������o�?�	y7
y7���3!�&�w�]UB�M��K�g���`(��]CW��w��0���v3�n��6h�H\Cq����yWX
#���h�@�=�W&Oiy��n6tUyWX
#���h� ��w���3��u0�����:�w��0���vO��S�]m��`(��]CWU�w��0���v+�n�xW�D�:�{m��UU�]a)�x�6����[%��6����^�u���j��V��mF���	������>�;���Vu$^a-�x�6�^$�.��.yB�uA��C�u���� /�f�U�Uu���\��2�:��n��n��U��Rh���|�����?O��RZ
G����m�.��l����_����w����N���������q�������7����p���?n	��g��`'���`F���x09���	�(-��NY���	S�A�v���
3����������	ge�W+����z�_��u�������6�6P���YY��/�R�A�v��6�:��7c���)����\��������X��I����Sh�^e�W;(pJ���,��$��kg��d@R<��PoC�l"H*[�� ��tv��!H6$���"H6��z��������:gg����?=O�f������r�*[���������|m���?>��f����)���U�|m��S�;������`F��T<��Qo��SJ���|+�8?���z��U
3�����z7��
[�ek�6p�wP���j���T�kF�;SJ���l��������Vm?0#�*�aM��)���U�V-�������Z���y�����E���s�_��UK����^;k�ro��W<��QoB�M�j[�����5�V�7��+����7#�f�{��UF��c�����@��<��g23�=�{�{���:�{�1�zCkU�{�{�3����"p���V�����Z���[���V'ro��i[���s�7�V'r�)p���������N�ZU��:�^oh�*ro�����2S�E���:mm�|�|���j��_'�����!�6�|����H�mL���[u$�����ef��}���N[\uD�>F_o'�����y�u����~��Kq�������GwK�}����z��Uw3����s��:`_��������z�/��k'��_0#��N<��Q�����oge��=�/��������f����33�]=�+���x�+�/��k���zbF~�x23���Kq�~��s@�w���������*���~).��WV�}[����w��W}���\����o@���W�=������jg���K��~�����@���WY>������jg�z�Q�_�tfF��7
'�^�>�����������������~�o��W[n$������~��G���o}�8	,��(8#g��s;yo��7���o�7�����Ogf�{ �faf�������{�������{ ���g33�-������t*w�����[�����{�-�E_�`fJ��E_�c�~"��!������vO��S�^Q��h�D�=%�U>����b�[_��m�"�V	z��UE��<������������{�mH�U"^mc��x�p������ro/�+�#�6wE�;��������^��F��}< ����,���������G�o?5>�r���>�|���w0;������B���Q�Xo��=�}�K��~n||����*Ff�2wF��C������=�}����y���xlv�������zu]U_�����K����{�]<�5��I�]�k��(K��WWV=�4�w�'^�U���/���CQJ��LW="F���~]���z�9���O����9o_���Rzlf��q���0SW�n:����z7~��_u�ya>;t�����U_�#
3u���3�����/��+�aNxv;�Rzlf��/�aDa����tF��7
�����G��8�^3i�H�������7!�F�{W]i���xvi����*!�&�{���3����I��U�Ze��<���fk�[oF�����Mg�{ �f�{�����{������{ ����M����{H��m�
r�1���fk�[oA�-���Mg�[�{���A�Z���e���������W�%#~7�Q���{
������{������[�{�]2�w��V��*po��V����������{�]2�w��6��&���^�xdA�mC�}o����"�J�d���3����M�^�v;RoR�{c5�m�#�J�d�o��uRo�Ww��#@/���k���R0�����:�^����\H�������v���s#
�+~/��.0/�e��}��;���
�������y)3����r���2��^��n]��
��������Rf�]e_�V ^�����F��n�G7���i��nX1������^����\F��n����v�l��Fx7(�*��R\�;��-
��R�k�v��m#
�+�
=��=`���0���zw ^�{���V��bD�x�wwf��x).W��-
y�y���qo��7J����\B��<��0�������������*�y�����*!�&y_Cwo��7���PWeD�, ����2"o���!�����y�����@�=���u���{������vy�!�C]Uyy7m]Uy������� ��!�C]u"�y7m]u"����f�vO$�sH��PW�H��@�����H��D��7�]E��C�
���"�V�x7m_��x�D��7�]C�mC�
���!�6�x7m_��x�p�+���z;"o"o0�U����i������S����Z�_����7��*�|;��#3W����|tP\�����fKc>�^��V�E�(l�q����>:(.3�J�{���1a����*�7�(��q����>8(�8���*�b>�^���U~]1�06wW�U~UJq�_���$xX��R�f��|p����ve_��R�����N��m1q���	+:F�'��]YX�m�z���^�i3��e1q���+�U����u����;�R����|G�������z����F�g��]�X�t)�e���.0�Z/����{���X���+��y$Q�7"�F�y����������+��y�u1nW6V>!�&�y��Kg���z��z7Cc��z�e1���U�7#�f�z��K����������WZ�k�����W�8�����{
�UA����bU�-��E�^�����[��kh�
r��1�Emku"��{Ea:����r�nh�N�^ae�����"�����tF����w7�V�W����������^/*��6��:����Z5�^ak�����!�6�{Ee:��������Z���+��qQ�Zu��.p��L'��.��}�����Z�^����l�����2G����V'�.
�{w;i��#
�����{).��s,��]�Ki���9��;�(Q���Z=P/�enj<��{���������Z}���*+�u]�]z_��qo�+0/���kg���bD�y���Z0/�e�}�D��y)��];a����M��j
���i�9�����
�7���u���\���j��x).��s"������o��U��K��v�u���R\�������|tC��v�j���Q���l��������O�ony7y7���5!�F�w���Z�n�y��C�{�M��i����Ue��$�n�vUy7����2�n�n4tUy7���]������vU��1��h����C�]mWU�w�w_8������[��
]UA�-�j����[x�}���vO��2�]CWu"���fmWu"��<��p~o�y��������U�����*�n�y����{�m��u����U5��&�n�vU
y���������"��!�&CW��w���Y�Uu�����(�g���w��w���
���'�nVvUa��
������pG���k���[0�057+����s����)o��"��^��SU�5�(
�UVU��X���P�]\Ci������O���uYYU�4)�e�)�	�"��^��SUa=0"?4��k�vA�R�q:���vqE���k��B���A�����
4)�e�����1������
L���)��v7������<�;��J{m�NU�=`Dah��������2�*��� ��^��v�*D�������
q7
��\.�����r�LUHH����(����vO�/����]\Ci������+�������������O��.�����v
MUF�w�h��q7���� �{���0������:w�1���:ww_��o����^�5TUqW��h����[�U.��P�k����D��V�,���D�=��/U��.��9��lh�*���"f�6Ui�JK�of�Cq������+��>f��w���P��k��0��������������:�n�yW��W�P�K�n1TUyWZ��U�� �v�wu���]
;h��Um�����g���w).�&�r�p����sU�;0��U�Umx��~�n6�����[�\���w)4�����<�.�����[�Um��G7^����m���\���j[�x).�nU����"�[�t�f�W�B0���Kq�t��������V��1�����j��y).�N{����R�A�v�j��(Q����v�^����<�u��{)��_;g��
3
�����W���^����H��!_;k�E$�(��W�V[B��<��{��o����V[B�M��?!S�E�M<�zqA��~3�o��34W�7����UF��<�zqC��~��<�_g����C�_�����C�_qE��~�1�:C{UE���oA�-����{c[A�-c�u���D�-�zm}u"���������D�=����UE�=�����"�V�����[E��c�u���"�V���UC�����Xf|�6��6�_g���o��W�_u��&��+��4������5�W����j�����y�U>]�qO��kg���\����*��}�����vV��7�P�k���^��\����*����g�e~;+�!���J;��N^��\����*����G��������������^;w��3
kR��3�]��R\��R�^\Ci����=x�(�I]���@�R\�]
�zq[��kg��m�����U�\�xS��
�����P�A�v�j�f�����j�=���������qc��kg��������U�\=�@�;?�R��3~|qe��k'����+,������#�o���m�������;��N\�	�WX������o��W{j��[c(��^Cs�}��1^�6��������[����{�w54W���=����f�{ ��~��e;n����~
�UA���x�e�������p��Z/�����z
����+,���|����'��h��c(��]Csu"�
d�8lF�����W��3.����~
�UE�V�xqB��~�o��W�����P�A����!�
Kd�8#lJ���M:�}~i��~q���k��:���F�mu��};���������~���~�(����r�S�0�:V�Wq��\��/������[��o���(���������������)�����@�\��Q�_������R����(z�_�{�����7��.Q��M�^����r�>�xuo�+0���������mQ��MY^���^��_�����Kq/������z������U�).�.=������R�K�o��\�v`D�~7e{7�_����l�������[��7���Rf�^eyw�_����,�bt���'�o���\oD���n7��������'��{�����?������~��������������������3�>�������?����_6������������?����������>��|yKYi��8.�����?��������x��C�����3@c����*��~�]_���$\�s/l����|v�m���'��_�KG��~�=_��
rn�9�4O������o>����]:
��Q})�+�I�E�D�<���Fqg1���e:
���l�R�W��p����yF�H��^�5T}	/�Qh�_e������������T���~
]_��t��W���#��p����yF�X��^�5�}	o�Qh�_e��
��J�=:'�������`��/�}:
���l��	����tNT�3������
u_��t��WY����+��s�k��oC��c�5�}	��Qh�_��j�!�
7��(����������������t��W�_u�_�&�m��~;�o��{#J��7�}:
���������[tN����8���^�5�W��eqH����n�~%�U�W�3Q�k���*�e�,i���������=:'����|&�{���_e�M��)M��S����E:����{��M������x�.Kc���)f���f�&�{a������&�{���_e�O��9M��3�
��Y�J�D{:�_�Dq�������0�I~�bF��o������o�g7�_C��F]5)����f�2�{a������&�{���_e�R��AM��*G�_�6����#�(��=C}�#��4�I|�bF�	�7
���~�{|qD���k����0�I~�bF��7����]&��&
{m�R^e�_aN��.��v~3���G2�g���v-����+Li�_������{�����cg�Di��Z����+i�_��QoA�-<���b��zq<���k)�N_aH�O���D�=y����2�g���z-�UE���4%moU�{+��Yy�_��L��Z���j��������bo�}_����~q<���k��r�4�)ik����$�}~�o�8���^���V�W��������G������~�><(�u@���:�3
{����:|zP\&��oW��z|xP�k����pf���t9�^����L�����������{����:<������rF�>;(.����������.����Xa����UW�
���r�������;��q�_`X�<�0�������_���_��wA���~S���-)Q!�D�c�B���j�sN�F@�������?����_�$���e7�x��0#��=�/��|1\���G(�#�#-�#"���O���&��(P�s�so�	)"�)�P�	)"���;���E�H<D�E����HiL���H��q���z3BD�!�-�������a���)��)B��<��!��!�-��X�\/~i=��Y��q�L�s����zAi�z�so��^P�k�����o`��@g�{��J����{�=�����ki������
tF�����������"��!�n��"�V�zE:����[y�u�+�3�m��m�������!�6������{������^'��=��������Y:������3mg��{���/������ ��!�n���,����oB�e���\��W��s�����Z���{)�'���zp/���U�V�u|tc�5�V��(p���*���r�*[���{)��^CkUV��U�Ve���\��������R�nh�JX0#���f���^J����<��zp/���kh�Jh����U�Z�m�z�}a����n���Z���*��y�]��U��{)-W���*;p/���kh��~`F�{WekUv�^J���l�J\��
�w7�V%"�F�{WekU"ro����v����{��{wCkUro��wU�V%!�&�{_Xkws���i�����������U�Ze��,p�k���7#��!�����@��<�����@�=x�_�p�����{-�UA�=���V����+�
6����[��k��
Ro�W�Y�H�E������a����z���:zOz�����������V��:��h��*Bo��7h+���[y�}a�����2o2o�4V
������UC�m<��0D��v;"o"o�V������UG��<��0C��v�x��x���:� O�A�W�|lPZ�]���O\�Ai��������h	���t��Ai�v��q>q%���kh�N�1#?�%(������e�U~����������z@f&�*��sQJi$��Mp�'�����z
m��6���&����7x����/}3��u�Z���:������N��n`J)-��Y����qP�K��PW�������F�)��)��L��	'�����v
m�����SX�!�s������2�*$�����^�5�Ug�=�u�6��F$�(���77������m���x�m�.��&$�������zq
���k��2"���C\�>������a�������{���W���6q���zd��{b^\�Aq��Z
��WX�!.r�QoA�=�}������J{m�RXD^a���}F�'"of��3�&L�>q���k)�Nd^a���}J����0*_�7�^��Aq��Z
���+l������"�VaR�����pP�K���X5�^a���}F�
��	+��9[S�E�mC�����#�
�8��3����]���i�����{���Y��W��!np�Po]{)-�����������^�5�V�-���^q���z`/��~z�9W�Kq��J��f��W��>�^��^aG�x7wF����^�5�V�����^q}��zW�^J���\Z�[�
�Kq��J�����^q
��z�{)�w������{������B3�*[��{)-7EM�����s����p/�f�U�Vu����K��o���^Q�:>�1�J���(`����;`/��S�Sw�^
{)��U����1$O�����F��(P����{���q�n1tV5!�F�z��3�MH�I�^�)e5!��!����Y%���S�8cuF��7	����9#��!����Ye���S�8cuF�Ro�6�+�{ �C�u���:�z�z��S�E�=x��_��� �C�u���*H���^q���zRo��W�=������-���D�=y�g����D�=y�/`O���R�[,�UE�=y�g����"�V{��3������^Kg��{������!�6�{��3�m����^Ki��{������#�v�{��3����}����Zu���s�8cuB�m�O��s�x{B�
w�P�A����-C�����3�u��Ai�;��`.����~
�UsC���!�3����Ai�~������;���[5�1$?E7){������2�j�6\Cq�������&���Tg���4��\�����7���54W-���&��I��������W�\����;��P]�m���(��������2���Q��7�P�A�����C��t�1�3����RZ��W������;��P^��cH~��8�|F�1`���K'��6�_�Cq�����2I�^����U����c(��_o��ZB������g�������]�����;���_e�_a��8{J���Y�_����~q}��k���_a��8{F���!��x�~F��@�����W�WX$#����oA�-��������[���-����+���b���D�=%�����Kd(��_KU��e2�\��V��*��8G`F��E�����W�W�&����o�W$0�_�#Cq�Z����+����W��	���=2v�����H��>e{�����������R�A����/C
������Ki��9��:�nL�������R3n�t��:@_�����\�_����w5W��Rj�^es�=�/��<��{n���������RX��(����R\&���c�O�
�Kq�����.���`_��]����/��kh�z��'_�(����W:�UV}�����
�U�*����-�������9�V�w����z
�U�����-���G�_����j�oD�������w?|��V�����yv����8
�����2p2�{���m7!'����UBN����{�8
������������*#g��O�)�"�!�����z��,����W��!����1������{_���� ���n3�-�E8������o��{_�o����+~����D�-�*~�3�m�s���������{
�+>��V$�S���MF�����C�{���U_��h�!�V	|��m��mx�������6D�& �����������vD�6>�}����z;2o�W|�3����]`^�o�nYp���odU�������wh�^Ua�%�7�����cP����2�N;��cX�� ��\��OpF�.C����T�|�di��������a�~���NU�	���G���C0_�:wo��n��w�k�f��iu�����'8��u�zW~�W=M����G��.��BoYo����]'>������`�����z��*����z����H3�cv�WUV�0��z?S7��o���;��^3g�%R����]�U���0���!��������2�N{��LZ}��!��]�yUi�%L�zw~������^����kf��dD���8q���z#ro��w�����{��{���qo�	�WX/���23�M�����U��UB�MC�}s����f�^a������7#�f�{W��V�7�����{ �
�e����������a��,����{��qs����z'~{�QoA�=x�]UO{��C�-C�}s�����^a�������D�-<�����_�!��C�}s��������z'~{�R/r��s��z���R�{�!��9_��z+r��^���^f�[�{+����yoC��C�}s����6�^a�������!�6�{��UG�mc���V�WX/��o/3����]�^mk��{��{
��[�{��2N��2�^��R�O)�w���^J{}��Z9�0�������:�^�����{����R�k�������������X�p���������z
���3J��l�$�z�{��������C�}s�����3J��l��
�Kq�z�����{���qo���Bs/y([+�{).S��sv��G7��7gk�[��K��z�����{).S��sv���n��o�������Bs�*[+��R\�^e�����n�����rq������f��{#��A�9�����kh�\B������f���{��A�9������ki�ro�W��7������Uv�.#��!�Kk��{������������]�����{�7XZ����W��7�^��C�^�#W�{�!�KkU�{������ ��{�l��=|�|���:|O	|�����{��^���L�"��C�
���"�V|7mmU|������E��C�
���!�V|���3�m��_����_�
��
�7Xj��������UG��<��Nt�����7Xj���������_������L���
_��'���k����0�0[H�<�^���U>�>9(��^Cm�����B����>:(.S�������Ai/�n����3
u7em�=|tP\�^em��~r||'0�wM�Q�'�)k+��3��L��'�>8|t�L?>4�
;d���rP�����2�*������2���0�w�Q�&�l�����2�*Kg��2���z
���=f&������_�zw~��nF�;SJ{���Z��`Fa����zF������E��������Z+�{�52����&��(p����O��i������	�W�#�k[�����U���3ros�������"�F��z�{����_���<�^Kku �J�dvmku �<���*����{wKkU�{�E2���*����^�{��z�{��{wKku"�J�dvmku"��<��_f�{"��C��-�UE��6��[�g�[�{������"��!�����!�J�dvmk��{�����6��6����Z5�^i�L��V��	�
��t��}�������2em�.��_����z����^�5�V�r`F|���Z_������V�����n��V�K��z����|).S���Z��G7_Cm�z_
�����V�Kq�z����;>�1�j�u
�Q_�TfF�+�/�e�������R�K��P[��cF|���Z�/�e��='�[_SX�/���k���m�����i��w�����2e-�n@������Z��%�U�V��b�<�z�=���Kq����u?1�D���j�@���W{��}�}���Z#�o�7)��5"�F}��&�5!��!�FCs�&d�$�o�6W	�7����w���7
�7Z������M7���y���'�~�����?���G����������?~��O���T��������_?���?��?�����������?��������
������oi+��az@���_?��~O���	���[ ��/��2��������)4��,�#�a�_�eV>j�����R�_C�p1���U�}���4b������|��!�z
m_�a���W���F.���\}X��|��!�%W2�}�Sh�^e�pq�L#�s�!�7�pCL������)4W���8�8\�������pCL������)4W���8�8\�U��+;�b��b����FL��z�]_�i��2���z�UA�Nc�z
U_�a������N#�i�_��|�8$��b����FL��z�M_�i��2���z�o���{CL������)4W�������e�W�jsoF���!�z-�#��\���
���4b���@���!�z-�#��\���
���4���a�so�����{CL�ZZ+FL��z��#�a�_]bz����{"�^���+[Z+�EL�?���zqq�#����`to���2�����V8��Bs�j[+F.������W�{�m���)�T����Y���W�Z�0�pF�U�������#�^�S���
gSh�^mk����e�����73�9w���b���Zmro�pJ�f��-����WYJnp/���kh�6�0�p�sQ�V�����9��������~
���:fnp.��j���-��g���|)��_Co���������V _�����������������y�������/������~�/���kh���1#��~Q6W[����9�������
��-��j��~)5W����6�_��|~Z�[n�w_��
��-��j�)5�����v�_�;N�����~>�!����^mq���*���O+��U���E��8�_���-!G	��������e��&��4�_�X����vB�)�f��������y������f�,��Xp�X���c��n�X�!��X��X��o��[,VA.;m�U����{"��-���{
������{��+^���oE�=��X��
�+�Q;����[�U>��*�o����W
��J#|��UC�m<����g�����������M�_���:�o��W��=��������,�UG���*���S\�_e��/���_��k��v�NL�?3bmF�8�x��'��_e��;���/s�?�5�W;�'����6�_�O�_����������~L��9/���|bJ��kS��O��2���~����|t��������q@1����������2���~���<>:�����'Sj�_e�����2���~����-��P�~�k��vQL��~����#������.���������=�(�P`�8��Rs+�g���_�l����~�NL�����qH1��
V6X;)�/C��.XYa��2���`C����bJ����v�R�_��n�f��|�O�Q����qL1��
�vX8�x��)��`mH����[J,�SL����%VF�N
��W������<�`oi���C�`q�������`��b�1�`o��
bp0X��2���\xv�[43
>��������:��O���13
>��O�����8���1{K�U��O��Wm�U������'I9�2li�rp8x�6Y
9�I��I
9�1li�rp8X��7����$�V�9��9x�4Y9�,�"�Pp\��;���/��8��
64Yq)R�`q�����).��������������)5W����8��2?��3������������)5W����8��r+���.�������Sj���l��
Lq�_��7|vc^
MV+�88(����).W����8��
64YqsR���l��Lq�_��?���7�`��u�����>Z~�c�S��S@��,���b�<
;qf���P��^~���}o�{��e�#�0���U�U#�p��{_���7"G�����18J���g
1!�!����zBp 8hk���x��v�!8
!��/���������i��z3"p���W1T�=������|o��!���:��wmGy C~���z��!����*��E8�����o��{����{"�~�S����'��U�)�{"���C����o����W<��QoE�=�#���7�[�{�����{���U�M�]5�*��~����~�oc^6��!�6�|E?�_$�&��b�#�6�"�a����+���vD�.��j�M������M��L�>�)��������U�D�p
���k������IXH#��5�_��;���p
���k����Q��*��5�_��;Q�	W�P�k���*�3��x��,��
���~F���W�P�k���*�3��x����P����,�"��/�����~
�U

3��xe{?��m�~�Y�N�U���h(��_C��3��xe}?���)��~~�n����{��*�f�����&�>�0�A��$�S�K������������>r<����������?��O?��k����~��������������������7������(�[��~��a�_?��~O�VO����?��?g7����ah�2����'�+����m����#��/�n���~
�_��tY��we��w����E:'n_��/Nn���~
�_��tY���we��#|�f�&��/L��������k�/������]����9W���}aF�8���^�54~/�eiz��l�r����tN�������s�(��`C���J]�7���3
>@8g�6��2L)�6Q�k���/���,Lo������c��}:'e�R0�m����
�_�kuY���������Y�Q���S
��M��Z����x�.��|T�~�D��9q(���qn����c��2^����&/�QpE.�9q(���qn��li��n]�7yq����R�p���;�fP�m���~--�������m�:R�p���;r����&�{-�Pcx�.��|T�X���p��Ky���c���{��Pcx��Bs�*k�����!\�s��	�������:�r���U�X��/���Kg������^�5�X^���\���XA���:'.!���
��^�5�X^���\����P�Z��zo��
�P)��_C�u��:
�<�����
���������y|v�=����:�r���UVX�����H��~�|v�=���`x��Bs�*�c�z����S~~���n��>
�#��QXs����#��/���o�7�7
�#!�F��Wg������[�S�M��i����_%��$���j��~3�o���_�����������Y`������^�����p�X�!p�X����7�[������*�E`m�U���k�S�=������:�O	����|�����7�[��1[
��\���"W�_�xw��u���!W����j����:��oCnC�f�������	v��+?y�������m����n��_��������KJT��"g����O���"���[����8��"��/����^p���m7�y��(L�yn^���b80Ai�z���(8��^�5�y�g����x�oJ�����W[���Cq�����Ka�xhF�+��e��v��P�k��*�@�"��yn��7IPZ�^m�Wp�
���kh���bFa
�spo����{���zPZp�
���k����0�p����mw�s4J;�}M���J{m�����cF�������]�M��R�p�Fq��J�+f��_b������K����KB�Mc�5tx%!�&����{��H����&��\oF��C��
�������#��WXn��7���� ���=�z��zwKgu ��	���:�z���� �C��-�UA�-����*H���^�8JA�-C��-����[��3mgu"�����������{�w�tV�����*�[{�����m3����u��������U�^mg��{���"����!��!�����!�6�{���f���{���"����#��!�����#�v�{����=������6��s���{���Z�K�����U�Z�|rPZ����{o�.���D�
���`� �f�U�V��OJ���<:���p%Z4�V��	���W�Z�>9(-W����s]��
��GCku�0_�B3�*[�scJi�z����6|t�m����+f�����-g���RZ�^ekuP��Z���:7�����h��n`L)-w �l�N\�Aq��Z�s���]*��Q��b��L�W^���^��Aq��Z�s���\�*[�3�RZ�^eku���{���Z��WX�����{���/l&��^��Aq��Z�3!�
�;���J��I����[/.����z-�UF�Vwmk��{���/l%��^\�Aq��ZZ��WX������{���N���E�=���,�UA��vmkU�{���/l$��^\�Aq��ZZ��WX������{J��m�pY���ki�N�^ae��G}F�����W�Z���{���ZU�^aaG��V
��
�+b��zqQ���ki�r���#h[������mF�����^���V�W����UG�����6��� ��!�&CkU�^
��ZR�Vu���\�������{������B3�*[���{)-W�������s����~��<�n���z�^J���l������z
�U]f��wS�Vu���\��������Ro6�Vu����^qN��z���
�+b��zp/���kh�j����^qL��z7�^J���l���Kq��Z����s�8DzJ������W�Z�=��ro6�Vu���L���������{}[�Z����
�7Z��{������F��(p��m3�M��q����Z�����U�V5!�&�{El�R/roro��V�7��+��QoF�����6��������-�����y��G���@�=�}a��������{-����{��+L�QoA�=�}a������2�^KkU�{���������E��v��[���{��-���D�=y�'&O�������?��[|�!����[U$����82yF���J�����o��[,�UC�m<��3�g��}������#��!����\ud�����m�:�o����?7�������Cu����P�_eu�����\����-��Aq����<��'����9����\�����"�;��P^=>m1$?b(*�������r�*����d(��_C{�|���l��l���b���q���~q���k���zbH~�nT�W-�:��\��~��.�;���_�p`H~�nT�W-�;��\��~��2�{�������&,�����m O)-����h�N���5�Wm��MX+��U�A�RZ�_e��p���k��Z����U���Q�_q���~q���k��ZB�6�De��o����_��.�k�R�����W�WX-��UF��<������~q���k��2���[&j���7����������2w����:���2I�_�������z��V�;���_�_a�L��W������������2w����:���2I�_���'��Y{�z��2w��������~����*�o��7k�[o�X��^�����!�
f���j�������x��~q���k��:���aF<���oG��<�f���
W�P�A����/������fB�}���L������/��w�����K��<��'43�u+�+���������5�W��R�_e�=�/�e���W��R�A�����C
��������������������
V_�)�'���W`J��m�zp����

V@���pF���rk+�:>;�
V���X��3
��)-W����00�l����1$����Q�Li���%V��)����Pb=�C�,z�G��(\�^�-V�H�qL�����)8�,��'��(���a�RpBNc^-5VBN<�&pF�18	����X�������WK����3���
�R0rp8X|�uJ�rps�j)���C�`m�u ���N)� c^-MVA.k���\���)9��9x�4Y'rp�9X��3>�O���bS>�O�����>j~�����X��O��e#8���0\��M)�"�!��E��~�p�QX�3�m��M`a����~�p��{��o�I��$,���vD�&��sY���nG�C~�K���v���c�,�o�����]������v�����H{i��o�w��HtbDa�hg��������
KRnV�|�������{�uF�-���A������{���3i/��w
|o�>ADi���+�aNh��S2_y����U��!~p���~�"Jh]�s@�+?%��#�;_~����P��2�7�(�]t��#]�z?$���{���3qsV��<f&�:]w�H�C�?$����{���3q�!��/�Q���t��#]�~w~H�+����g>���X��0�0���j���9���C2�8%sF��7���1��}�%4���oB����S2g���}��}��qo�	�W�B#��)�"�&~�)l3��H�iH�o�������+�����~3�o�D�����������{�=�=4������{K"��a�!��9���~�����i����[�]��p���:��U4N�_��'���c�{����{����_U�_i���W��
�+N!����"��!��9���~��M4^�_5��*��8�|F�
��
���1�����M4^�_u����oP~����Z������qo��W�D���UG��<��T��������c8n���s�&#���U�W�o	�����O�%����c8����Rh�_e��/�e�U~=���u|vC�}s����������y�_���2�`�Ky�
,�z�(��WXn�����/S
^��)��`C������� `���2��Ly�,f�X�`��c��fJ�00��l���vbF������	g��&�	�������f���r��^�����)��_=������2��C8��7"G��E�?����+�/����tB�C~s��'��$@��,�\BN�h�����������qo�)8	�j[����[��/�>� �!�9������,P���������4�����@>����{�-��������*���g��|��
p��8n�	��j;�	�,����D>��Z*��x�VX��X���\�li�*p�X�`U�*]�V~��5�:`K�������!7��U�3����m���R`u��.�o�X���+�*��/�o�o0X~��	
�+~C���_������m�_���a�G�k�����3
������>=(�8��7�{h>�^�5�W�;�(�R�W����e����������|���kh����Q�+
������c��G7�������~
��_+f����g���R����L�[��-4q���+
f����g���<���yEyF����#��_C�����A�_�
�)���+�3��4q������2J�h����;�S������+h>�^�5�W>�ziMP�W>"�F�Y���/�o��f��|B����
aF�	�7������{�M��i����������M�_e��,�����7#��!�n��*#�Jkh6mu �fa=������@�=���Y���W�B�i����{��+NO����w��W����i�������>c������7Ku"�J+h6mu"��<����S������7KU���3��������_�pzJ�
���w��W
�W�>�i�����x�}�����"��1�Z����+m����UG�����������
�� Kh6e��.��3��g�.@���R�nh���cFi���Z]����O)�S�k��
ku3J�X����)�g.�O)�S�k��k�3
,��5����~����W�`�{-�Pb�k����k]�)�g��O)8x|xC
�
-���)4W���ZP0���C�R����b�n���
0�Bs+k�u���t^}T��5|xC�
=����Q�`q����w�`���-*�8��^6Ykt�Q�`q����#rp�8X����lh���%V6YkB���\S
N��i���&+!'���MVFN�]S
���y����de��,p�8F�rp�9����7�{ C��"�@>G�O�1��1����7�[���!GK�U���@���z3�-H�E��}��H�eH���c�H��@���\3
>��O�0X��D>�-5VE>�]���"W����S����u����b5d�*0�8�bF�
����2��������j��M@`q���~;"p�X��?�����-VG��2�����G�	X��?����h(��_C����qD�
+8�����y�uJ�����^6TX��(�#RVX������"�R0���������
Ffi+��B���=|~P��(�)�>�{-��a�ffi+��F���W0����>�����^�5tX!��� -�W��7�A�����6���*l����b�����Q�
����%�_�����^�5tXaw�Q���V���R\n�������~q
���k����1���F�a��b���L/�<���w�m4�����
X�I��VH��Q``����h(��`C�2���&iK���v���P�k��+#K;i�/13
���Y`�F�\0n�����--��,��qI�b����1B�����h(���li�
B����em�U���2B]S�F�{-��b���^��m�N��S��N�'R�9��l��*R�)Pp��X)�JK��r�ICy�[j��,m����!Wik��]��Ki(��`K������4�h�w��&��s0n�����-EVG�v�dm��������^�orprp64Y�L�?�z'�-���+X��7���
98���Sh�`e��9�`�������|xc64Y���\��&k����+X����7|xc64Y��bF���M��S\�`m�������R�[U���A�K��4�)��r�r��w�����B��<	�E�em��
�$�
/��S�A��.k�*��I�/�.k���)��g��z����wP������!y�����v a��]�P������n�n1tY[D�<	�E�emI8�$��+:!�!���em	I8�$�e��%$����+����3�p��[,]VF�<	�E�ee$����+��������b��$����_�]��$|�$�����@>�tYA��@X�e�����c����\�TY1�H���N��"�������������:��O��������'���'��\�����������U�`�r������p",�7�3�!�1;K����������7��&��o��(�#�1;K����������w��.����M(x�E5wP�������j�S6Y� �3��M)�������
M�����y�l�v �3/��(�P�A��&k�C�S��S6Y�������f��j(��`C��������r3
^A�R��������;(��d�k����^��M�V,X��)�7�`\TCq��=����+o��Q�"��~������{-���};0����+��}�Jq?�p���qS
�4l����i��������w0�w�N\�8�U�����
6TY{D�x����� y�u�)A8�A���=!k�I63
N�Ia�������
�TYAXXX������Ya������;(�Re�����U�� | ��$�{�U5wP���:���5����Ca������;(�Reaae���*�D.k�,�UCq[��AXXY��	�-A��I�o��(��P�A��*�";k��VY9��,���Q0n�����WK������5~�VY
9��,���R0rps�ji�:r������&�#w���[�3
�}5wP����r������&+.���3�z'�`�;(��dE�`H��We�p0�����;�`�;(��dE�0�������~��y�o��(�S�A��&+�C
�*���S�����Q�
Lq���R�`qf�����)�gn��(8��������~�h�����O1
Sp�ce��0�����o�����}o��0e��UVYq�����qs������}o�{��+���S��\��Q�Lq/�����z����C0f��������F��8����@�[oB��#0f�������u��&D�4D���>�\/pX�1����$V��1#�!�w|o��7�+�[=���7K�������{���C�{�=~~�A�S�E�=$����-�����#�{�-��E�^qL��zro�W���D�-�#��N����D�=�g����D�=���^O��y%�����{
�+����oE���j/���2�
�m��UB_mq�}����-��6D�������}������#�v�}��UG����_Ku�~�����J~zt~�+��M����^�5tWii��K�7ew�|zP������/n����~
�Ur'f���MY^%��3xg��j(��_C{������~S�W����������~�{��P_�fg&aK����UZ��R��\���/n����~
�U
0:3	;j����RyJq?s{wJ���������n3��y��������~����~q5
���k����1���fS�Wi{Jq?swwF�����^�5�W).�Q�O�)���)�g�����P�k���*E�_a=����UJ��Q�_����~q/
���k��RB����]�_e��$��hOg�J����^�XX�N��qSS
F�kJ\KCq��Z
�XZN�k���X[P�V�{��R``a7���VA.kJ�JCq��Z
�X�M�wm�u"������~q'
���k)�*������g�[���/l'��_\ICq�o�X
��,,�����j��`�W|'\ICy�[��,,�y<'��;p�	����o]]�p!
���k)�:������+/����������R�k���*/f��W�_����2�>?>��^�������7����Rh���������L��O����;|tC�}s����z�_
���,�����L���n��������7��w
�Q`�����
�Kq?�^�6�+�/���k��r��Q`����r����y�qF����^�5tWy[0���Q�]�
���~����n��������[���Few�w��
�����3���})�u�����������*G`_���Wg�~�~�����7
�+��)�"�F��W|�qF�	�7�7����~�D���*!�&��W|�qF��7
�7X�����%��I^}�:��?O�!��_��?���p���?9����������?��O?��]����_?���?��?�����������?�p�����������?9������2�eX���c�=�ty�G\�����h0���<��K���wJ��$m���wJ���/�����0�{��R�u����i4I[�utj]�F#�:���r���h���;�8���c���;�8��c��Ag���1��<&��c�<&)��c�<F~tF�x s�d���;�@��d���;�@�d��A�����
Od���;�D��Nd���;�D��Nd��Ag��'2��Df34~����LR6~������2��~�D���l�����C:�I�����C:�_��/�������x"sH'2I��x"sH'2���3���c|"��Od�D&)_W;�D��Nd��Ag��'2��Df3�W����LV�W������2��~�D���l�����C:�������C:����/����m��
�/O0�O� ��_�������3�g��|��>=��#���%%*$�X|=�����<��w
�<c����4!�9�m�
�D����;�&
O�����v�a�`�������t�H��&,m��4q�4!�-��oE�8�_|���[&�&,e^E��<L��Of���%���{�3�m�m����k��g	q���z%��/�����sG�hC��-]^G��<K��Of��%�t���������W�>d�����X�Bs_`t�-�Q�q�����{�����'i���+.`F�$����]i���/&����� ��^�5y�{�(�=��ro����~~,���z@_�{��P��u���A��{,����R��OM������^�5��V�������X��7x�W�!���~���@_�{���\�pbFi��r��/��{���[n�w����z
�U��(M���������0��z���|
�U��|)4���r�;�/�e~z����:��D�On����[����;���F���s��o����q��P[����U�V%!�&|��M�i���Ze������hF��7��������f��<��h�����s���hF�r�!q�s.��{��c����[������������^q�����[��-�UA�-<����f�{"�����������{���:�{O�{�uES�E�=����o����{�7ZZ���[y�����"�V�����9�!��1�ZZ����x�Oef��|����8�zJ��m����#�6|�C��v�.�:)���QoG��C�M���\V|��*k��W�o ��N��\����^�5�V�s����"Z��:������V��z|tP�k����t3��[D�;�^�����t��8=|vP�k�����3�'�W�*{�sgJi�p���W���Z���:��Q�~������RZ&�s�qs��)���k����1#��@�����2�^��|o���G����5�V��)�'~@f���2���K�����)�k���R�O<����L)-CF�'������3�z
��W�����z���|#����)��#�o����:�o��W��=�����x���L�7!��!�fKm�|����*#�&|�W�x�������-�UF���jk��7����z���=�{�!�fKmu �<��bhF�����W|�qJ����7[Z���[x��IO�����+��8�����7[Z�����W'=������W�l0��UE�=���-�UE��<����g�[�{�������7[Z���[y��I���!�6����_����k:(��^Kk��{�e�,��v���s�+�qn���k:(��_Km�|�e�[����o��W][=>��}t�Z����K��<����g��|)-�������|)��_����
��WY\U�Ki�/Y=�/��kh���R`_esU=�/�e���-YW��n��n1TWu������������=!�����~�b(�j����@��_J������n��n1�Wu[1$������n�����O�}c�n��w��������<�w�g��SZ�lA����
6Xu��'`�u��������{V�H�qH�n14X5"G���-g���#��/�������64X5!'���.g����O��z�	83l��2p�	Xt�S�E�<G���z �1;K�u k�	��	8j_{����4X��m�
p��@A$�2&`g��N$����;pF�'����/�vto�'"�9F`g��*"��#p�VX�
/���+���+"p#��tX��,N��QpC���gu�������j���G`�CnF��I����vD�>F`g��:"p�X����o[�����_�����
��P�A��
�-C�S����)�������)����;��Pa5#1��h&*+������~'
����;��Pa531��i&*+������~���[?n����~���j+�l��q��~W������������;(��a��bHa����j*�e~��/q4�1Cq�*��9���M�
�m P)�w��[f(��`C����!���IYa�}�������[�~��=3�wP���j{��������Z����~?�_�4Cq�*����3IYa��y��O�W�P�A��
�%D`a�L�Ia�=|y�_��I8D��+���������_��#�����?��?���?��g�@~|����������������������+w�~�W��|��?�;uO]8���7u���?����{�g\���������e�����������2����	e��/���/,���w^_@�S�A����/C��>)k��@�P���-����;��Fq�j��2��o����N���e�wXM)�{|v��k����������3
� ^(���������_][
�__��P�O�5��������������\[
�_+��o���G��7�v���~po�.�Q�A����oC������hJ��w/�[������k����1$m-+;���W�����t��)��`C����!y����G`J�����[�����J��#�Y��ZO��`����{�M�	�7?�������x��)"'�����J���g�W��[qFNC~����f��p�6X8�����{�=������|o������xswF���!������]��c���}{�����{��-�
�o^�z�N�����2����:�����[��VW'��)�-�n�D�=�������E�=y��o���"����F����"��!��w�{o������mq�|+�^{_Eo�m��������x�u������M8�}���{����}��������y�u������]8�U�V~���w0����G�o��}�����V�0�~v|�e�U�V~���q�k��"d��}��_]g�S�_���������������{9���
2^�>����z����^�R�V�0
���m-;m��u����Zn��V�t�]������z�9��]&>�g�f�_�r���z���� ���l�axv����Y��v�����]w����w�nUvW�t	��e���a�a�[����Z���+������L�����n�gw��q�e��^0#���s����C�;����l����?�^���W�������_����a�#������KB���{�8�2�7!�^�>����z�A�M<����*#�^�=j���/S���W�_e�����+Wo���2���T�����2���~�����{��������2���X�����{���u���� ��WuU�/��?��,�E��}��_mu"�������{��q�e����{���u����"��������{���q�e�oE���|��_mU�+��A�_5�������-�~��e���o�h�����x�
���#�^�=l���/#���W�_u����o��WnA��{�8����-����W�_����2�j�+�4|vc�5�W���Q�_���~�/���_=�tk����^�J1�W_
����W�f���)�8���l�������~
���3
�+^a����b�<��2�������)��_C��������7�R����9v�����^�5�W.�(��x�mJ������
����|tC�}s����n����WY_�
���2_�������
��������Rh�_e}�v�_����}<����n��o�������o���7"�F��]D��C�]
��K��Q�_���~�o��7��QB�Mc���W�7	�+�`��oF��<���A��-�UF����2���7�������{�7X�����W��6����{���i���[��,�UA�-��7�����[�m�����D�-C�
���D�=�o����D�=�m�������o��W��
�+�`��oE��<�n���
���7X�����$���W
�������������,�UG�m�j�����y����UG��C�
���/�����
�	��>=(.������q�#��_C�������
��:����L����������~
����1f���7�f��W��������{���3q���+�O�(��o���w{Jq��W��o�~�a��G�K�������������~��R�q:qO���_X8�������!AFa���Xg���R\�����o�~�a��G�k����o;d��8��uF��S�����o�~�a��G�k�����3
�g�O���`O).��������<���H{��P_��1��vFY_�����>��7�w3�W>!�Jkg���&����o|��{?~�o��f�����sF<a��oF�M<��r���~3�o��f��2���uF<a������y�}��������-����+��OX����{������{�-���-�UA��6��'�3�-�����W�������[���[���W�=�����������o������n��*���|��'�3�������W����oE��C��-�UC���8��uF�
��������{�m��m����������'�����#�v�_��|o����w��W�W�?���	���o��������.�������Z�3J����V�Kq�~_�{o����^�5�W�;0������Z�/��N���W|vC��
����)4����Z=�/��N���:|vc�5�W�
�K��~�����R\fz���G��������_�!`F�we��_��������)���h����cF�we�n����W���u����~
���/�Q��]�_�;�/�e���^���������Z�������W���_����~#�o�o4�WkD����g���#���/�)�&��4��h������$���W	�7����x�{�(#��!�FK�������*#�f�_�to��o�o��W��!�o��W�����+��n����o��W���7j����[x�}e<�����2�_Ku"�����:�O�_�to�'��9�_KU�O�������Ux�W��w���u����_U��*�o��W
��
���?�
��
�7Y����������#�6�_�~to����7Y����������#�v���o�<Cq�������� ��q���	��>=(.�������g(��_C����'�A=�_���W��F��3�����
Fda��_�����O����}#���{���_�5`F~�/?<���`O).s��=�*���{���_��1#?��%e�S����=�*���{���_�m����e6�����?yo��z��^�5�Wak�����	D3��=��������g(���l���~bF~�K��*D������}2���{���_���+,�qI�_���y������g(��_C�����%e�o�C����f@��3��Z��������VF��v�`�]0pp�4X����%m�u �zD�#���g(��`K�U��4.i+��\����g�~��^�tX'2����em�u"����~���g(��`K�u"[h\��X!�6Dx�S\@Cy�[Z��,��qY�b5��*���������^��X
1X�C����j��M������\ACy/��Rduaa���"�#w���M�mA�Cv���� aJ�5����H��r
k�u���oH�n1�Y�R@��,�6(Lq���e���)��aC��y�!��6k����kX�fmX��6�Y��`H	��u��S\��A���m����
u��6)��������y_��Rp����
u�N�����M)x��L���|o�0�l������<�EYgm�0�e
��s��+>;��
u��Sj�`e������)X�R�>;�
u��#��~Q�Y[D�
����[0�p��3�Y[B�<	�E�fm	I8�$,�)������������a�h��� �y/M)8#�1;K�u g����������`�������c���Re����~�VY9��9X�s2���\��,MVA.k��9��,�9�R��|�9�Y��9��8X�d����p(�������+r�9�`gi�*rp8�i���\y�B��7��:�`gi�rp8�i����xOB����4Y9�	��MVG�<�'!S
�����`C��/+>B��EY4������GHq��`�(dF�;.��������������"/~�����O��5��
���i(��aC����!�)E�)���lX��)�Li�P�A��2k�C�sz�S�Y�
.��r
k������6�Y�Z0$?��;e�����kX{���Kj(��aC����!�Y�^|wJ�`S).���w���P�A��>k�`��.l�����3�@�R\�Ua�������6Z�5wa_������>��r
���U5�w����z�!���^|wF�y8
<,��)
���;h�Pi�	yX�Y���qg4�����/8���~qY
��ki�����������7#
'��_��qo�����^�]-}VFv�x�m����Y`�W.�����P�A��>�@��x�u�
d�C`�W��m�P�A��>� {k��:���������O��0������-}��,,l�����3>��O���/X�������YYX�]���qg4\�����/��{�h���;(�Rg5Daay����QpCn<
�0m��_�ZCi�Z��� ,,�������������/n���_���������*��}������*��� w��_�vk�q������E��n\*FHxU6Y�	S\�;�������)�����C���+Q��U�dELq�~��WFLy/���
��~}����&+z�`��\�T�W��n���}}����2s�*[��S\��W��C��[�
>�!�����z�/e��UVX1�R���a��?������{�����Q��UY`�
���~7�n������{�����;�(�����;�/��_\�������^�}���~;F��W�^��_�R�����������[pD������g��~�D�����o����������g��$���o�����+��g��,���~yJ���Y8~�7������96��@>�/���@>~e����� �#`KU�������D�" �+#�o.����-��\�
�D>~e���������RbU��S���-�*Bp �����\���6����H�U���m�Rp(��y��������-5VC
nkk���
��L)�#�1[z���%
V�Xi��.P�x�dF�	W�P��%C�����)E~S�Xi������Y��5��Z���J�i&ao���=Vr�Bq���_XI����^6�X��4�$������J>@(.W���*	��P�k��&+�0M3	[k��l��
��rk����j(��`C�����i�~S6Y)�H��\��&+���{-��d��aF~Z���MV�@�R\�`m��p_
��lh���1#?��o�&+�+,,V/�L)��P�k��&+�3��z��l�R��\��&+���{-��d��,l�����J98
,�6�R0������
MVJ�����i����o�L)��P���*�&+#[k��m�2rp8X�m2�`�WCy�[��9X�Z�wm�u ��M��|9����\����5~�6Y9�,�7�R0������-M��,l�����:��O����&S
�}5��Z���:����5~�6Y9�8X�o2�`�WCy�[���,l�����j��U�`�����q_
��li�r������&�!7���M������-MVG��<��r�9�K�m�����lh��L����MV^��).S�x�dJ�n��7�`C��p0��
V6Y�S\�`m��]��7��`h��_1���Q�deLq��^�`wk�(��^�5�Xyu�Q������
Lq��^`�{�]��)��^C������+�������Li��:�*f8*;��S�q����z7�_J{���`��`F������/��{�~��w�����U��~)4W����;�/�����{����}�����7
���U���Q`_�/����o�o0�W9!�&�}����	�7	�+���S0�o�������Ib_m{��}�p,���RpF��c���W�o��W�^H��p,���R���{�w��W��!��8�sF�������~S
.H�eH����*H�E ����N$�"��0Z���Od�s�����:��O�����:��O�X��7���|)x�tX)�
��VE
�����oJ�
9�9x��X
9�	��-VCn���������7K�������I�cu��.p���oN���}�����:���P���l��>@(.W���:p5
��lh��1#?��'e�u8���\��&���4��Z���:����D>)�������+�S
��4��Z���:|����^��2Y9����?r�u������?���G����������?~��O�������_����~������������_����_��_���+_}�{�_Yo�+�y�G�M_������/�������LDp����L�����f�����,��j��~�-�)��I*�P�	�RRh�`e�w$P��3o�O)8;|x�&���/��<��>y��RR��?7~�~n|��_n|��z�s��o��;����YT��/LJ�H��������}&�O?f�}/�5�kj��S����^�_�wCz��5�3D���W�~�������tq����O��~����.�8�k�)l�x.Rn.�����r��K���[�����k�B�zbFa��s�rs�
���3�_y���~"E#��	m�M���\���/"E����W����#Q�1QX���D��E�����oG��<Q��F����Nq��z��P������<G�{�-8���2�jc����2���5���������������s����
H�����szS�P��1�pP��2�����s���O�	{�
?/���T���+���c��W�n�g�S\����~^.���`��|em�Q8�z~���q�9��
���Vp�y�?��

V	'f�X\%9�`�}Nq��_ �{����2��
64Xe;0�p��m�
�>���;�/�{�����2���54Xe.��_���/�>�����P�����e�9l��JD�@����v�8���rk��*8��\f�S���$d����O������;���{Yp�y��>��-%VF�@����$����).W���h�}^.���`K�u _�U�����������{wk�8��\F�|���)�2���~�-N>����w��_�|^.���_K�U�/����W]c��s�����Xp�y�L>��-5��|�U���S���������e�9l��*R�e��W�k,|Nq��wN>/���T���jH����_���p�9�e#�p|�G0>/������������_����p�9�����O�q�y�>��
5��|�kk�s������$�|�P�k���t3��S�5�S
v��Aq9H������{-�Pc�~����q����=|�P\�'X�(���	By�j��7���N�HN)x�X0?�������F�������:�3��S�5�S
`Q).W�|o�4*��l(��p`F~v��FrN��Q)��r��V|x�Q�`C�un0��B���)o�Q)�w�-zw��P�R��"��a����+?S
���R���>��w|x(R�`C�u�����;?S
���Q�`���3"�!gC�u&���s������rp8X�B�������������I�`u�������/��{���y����de��,p���:������&�@>�li�����`q����r�!p���oJ�9��9��d���s��FrN������W^]n��D.Cv���:��O��7u�u"�<�����W��s��n�4Y9�
�$�MVE��[8������u��n�TY
A�� ����� �qNi�!�!���eu$����8%vJ�I�$,����pG�Cv�����p�QX|7dF���S\�am]qz��A�h��f��aH����C�4�s�).w�R�*B��A�
���N)�����8���/.���0NB��I�
���)�����8	��2
��#|�������gh��g�h�^���z�X�g�h��2k��R��g������h�R3k����)�'���)�����3�Yu��a�����7�a���!1S
���)��`C�Uw�!y�>M)x���g��hu����
}V���YX��4���,^�_A�Y8�Y�����#�����)
'd�(,}{����
'd�4fag���p�YX��4���,�����������,��,�,}VF�<����4�,�y���hm��{ 
�1
;K�u 

���Q��Q8?�]yo�I����tYI�$���
�p�IX{K-��aK�u"���OS�=�O�_�}o�'r��p������'�����)�V���s�7����\��������jH���`����~Rp�)���Y�����������j���g`����~;2p���~�[��H�}L���bu$���xebF�m�O���xq{B�
w�P�A���-C������j>=(�'�m��w�P�A�����!�IEQ�`5����g���j(��_C�<��l��������O���[�3��e5�v����j+L�l�������
���~����~>:�����V�������o��h�7�g���j(��_C�6�!�a����)�n`O)�'�k��7�P�A����mC
k��U���O�|a������J{�w5�Wm���+�b��o������=�_\TCi�����}5�$�)�&������9n=_h�����5�W-!�
�j���J�����^���_\SCi�Z����+l�I��*#�f���Gj�����4X���&��	��	����4�|�x�tXXXX��VA.<�2f��_�����
��X'B���&�K�!��!��{����j(���~���~�h�����OAXXZ��EVE>y~�������{�!~�{���V�`aeMV�X
9������{��]5�R�{_����!k��������`��	n����v��
}o�!XXW��%VG��!�r�}A�C~�������23�j+��S�O_���]����{���m��Rf�]m���/���������n������_1"���>S������z��v=�/����������#��+��3�����2���]{)�����~on�cD�x����!`�<����y|��g�g�����o��Q@^mk�7@^���L�� /��{d��V0�����������W�����R����~��y�uR�I�R^&����=z|x���a��7���mk�#�o��UO��q|�k��zB�M<��c���~�p��n��o�Z�����x���M)8#�f������y|�ki�$���[��W����?���C>~E�����?<�=���|y�{�����������~�%��������������_���O���|�~�W��|�;�3�J������:.�*�����_t��?��?����P��]$���#�7�CM��=�|���������;������Y���+f�>����#^��w�CM��=����������[]t�Q�PS6�x;y�����#�/���CKn.�cF���r�[p
X0�v���{�K����2���{D���W�nQv��
N�������n����n���%��f����?�|,Pp���Wv�t�1��o�-���#cFA���s
nP���]���+�P��9����K��E�������	^�j��_��\�����{>��O����)���'��^��=� �C~st��W��S�`�dJ�9������=� �!�9����rp8X<�RpCn������li�rp8X<�RpGn������li�:rp8�i�,��'H�9x�6Y~��{}���d��bFi�����>A(/S����>@(��`C��]����qQ��)>A(������z���lh�������E�?�`� ����
��z|x�B�,�F��
��D�?��L*���a����T*��d��A� �Zu����T������n��P�R��&�o+f���:J��T�����{�@�R�k��&��3
K�E�?��L*���a��� R)��`C����������Rp\�`~	�+�
������
M����Q�`Q�O)8!G��_9l������lh�|BN�:N������W�-8#�!K��������&+#g��_8l���9898X��9��8X�d������&� C�&� ��E�?���\x~�������������:��������R��|���a�������������������������`1���+rprp�4Y9�
�����\y~e���7��6��`i�rp8x��}��K�/�#�����W~�>���}L����_y�e���[�}��?�>��_x!����p�w�p�N?��/���������0��#����[pY���%O*�P�����+X[�������`�-�t����'l(�Lp��=Am�`��G�������/y�l3�����
������� �{���/\F�S���/����\���/�����so�
�>�ex;l(��p��������e�i���g�2��
6�����
���q�����&��-p��]F�S���o�A���������?�~'7�7�]��S���o�Y���������?�~'7�7���r�f(�6���+X���?�~'7�����r�fh�6����+X�dm0��#�wr�x[;>�1��
����
�6YLu�����4�p�v��N��
����
�6Y�u�����4�6���2���`����`��Gh�`m���\�����M�m�.��`C���X���\��&k���y����[D�Lt��
M����������r�e���M�-!_&�S��&kK��I��M�d%���\w���[F�Lt��-MVF�o�&+#_���4����Dw*��d��������:���S��nor�1����d��C��M�d���s��M�� �!��&�D.o�&�D>yV�i�������-MVE>��MVE�<����\�����-MVE�o�&�!W���{�S
n��m����d5��&q��������`�R���;rprp�4Y9�K�n�:rp�9X��;��}��>��hh���x����6m��/�	By���M��<>���hh�vo<Rh�`m��;���L��&k�>���hh�vo<Rh�`m��{���L��&k�
�p�z44Y��bFa���m��L*��/�N)x�Jq���=8�(�P��M���R^�`m����Z����C����]�d�[�������)o R)��`C��o3
3�wm���`R)/S����w��Z�������]b����#�T���m��Uxxq�K,��="G���M���#�����)'��8��dh����$�6Y{BN<��z�������������Y���n�2rp�9X��;�`��<��di���,ppT7Yr�!p���:���!'K�U�������*��E�`u�U��������*��E���n�N���s�x�wJ�'r�9��di�N��S���n�*r��s�x�wJ�9�98Y���\��&�!W���K�S
n��m���&�!7�����j����`�R���;rps������]���n�:rp�9X��;��� �!gC��`
��m��Ly���MV\>�!gC���%�6Y�S^�`m�p0��lh��w�Q���m����L��&+z�`�{-��dE�1���I�d�5`�k���S�k��&+�3
��MV����)X�d�Lq���
f88i���S�q<�R���7�`�{-��d�-cF������p0�e
�6Yq�����
MV���)4W����;p0�e
�6Y1.���lh�bD�'m�#rp�9X��;�`��8�`C�rp88i�������/B�o�7!�!���de��$q�����������[pF�Cv������Y�`u�u g���k�S~E������b���C����
�����x/J�A�A�-�.� 	�����:��O�������������bi�Nd�S`��n�Nd��ga��\�{+�����b��*�ph8����4\yv��O����8\�8�K�������Y�h5�����{e���#�!���iu$�&qVwZ���D,�$7��VG$�J����$��R+-�1By�����n�����
�VrCJ;l��Vr�)By��������������J�cHa�k��Z���0?WS|OnJ�����6�Z�W)ls��^+��U)�8������q�
�4l���Z0���F�7�a���iX�x8��;h��k��5���f��Z)�X���x/|�z��p�
�lh���5���f��Zi�Jy��^���`�`Ci:���|�$��Y��V���R^�K���77����T�h�Pi��bHa�����RD����>��mw�P�A��F+%�ai���m�RBN���ni��0.�����-�VB�V�,�F+#
'a�����m��P�A��F+#
K�lu�u 
gi��v�����^��F�@���2�V�a��C�3��0������-�VA���E�h��",�x�d���q�
�4li�N�aa��y��������<��8|������ox�{������?��O��������������_����~��������?~��/���������c���>�<���;�:"~j��{M������������x������D�
C	x��!�6�)���wD�`����Y�_{G
���6Cx$�`��\���H��Fy��$������|�j�#������G�6��}��n�X���E�7�����Rs
kk���Ky�x�
7|xc��
5�QV)�^��4\@�R^&��<
�^�;h�P�����nJ�'�^�����nn��Kq
j���R���S�+6��������
���^^
5�Q+�D��#Sn���������<��<�j��!7���5������^[y��yx5��GG��<2���<�y�/\0���� �1��N�,����kX�i�x��2���Vq>�1��N�8�aJ�5������L<m�U\��7����i�bH��E������x���*x��6tZeuR�a�G�4�S^�am�UV�a��u�����>j~��t�S��S@bI��V,�G�U[k�HLq/?��}����P1��"�L�w ��L��R�l����{_���w+Q�aG��8Ly�~��V�>�!��E��~w�a����-��0Ly�~��V�����}o�Q8J(���JD�<
��:�$D�8D���D��oBN� 2��� �x^�eVBNC~�X��~3bp0X��)�f��,`������y���
�����	dJ�B�!@���:�����{G�7���{�+��~����oP�X������;����\dJ�'p�8�[��da|"��2�`$��'��n�*��\�6,�"W�E�RpE�<u���+slXpCn�2�������Wa�[��m|li�:Rp�(X�bu��.��	������<��c�K�G(q���:�����F��Y���G��l(�N�1#?���(2�`�!��)�������#��^64Y�_0#?���(2�`!�����}�tz�����
U��f���{E���X0?9:h%�+�T�{-��e�����^D�)P���)X�,�`R)��.���:����^�%8�`p��������o+><T����B%
�����
\*�e~��O����C��q�nX���(4W���:wp���)X����;><T�xiXp��_�����)G���sp�>/<#rpr���:�-8!G���U������������������qo�98I�n�2rp�9x�>0<3rpr���:n.98,��L)�@�<����.�<���!�9������C�`�gdJ�9�(m/|����� \� l��
�p@xSWYA�� ������A��A�Re�������:�O���j�4\���!	�9����+�pHxSwYI��$,�W3�aD�:D�7'u��pC�
o�2�!
7�_�:{��l��m��o�����(���eVG�<
�p1�^P�H�}H�o������ 	w���/�3���0���G�@J����(Ly�
���4�(�����n���e�����[?������
eVu'f�PX[fU(Ly���s]yo�H��^6�Y��Q �][fU$Ly�#�t��+�������jh��
(L����mV]�)/�#���{����7&aC�U�0�����) a����f�\p��7aC�U����O)x�����t����7 a�{�a(���1�@�����;�0�e��p��V�Qw@a�{-��e��`F�wm�U#�p�Q��y�����������I8
$�k������@�����	I8
I8X���$���eVFN	�[fg����������H�Y"au����3O�/��po�rprp�TYr�!q���:������kA>�,MVA.Gu�U������T������:�����K�S
>�O�_x���O��sL��"�"�����\��+O��l�����\�l)�Rp(8������a��RpR�f��Rp(8�{���x
���U;BpB�f��:Bp 8jk���H�!�Myk�
��P�k���-'fFEm��|~P�q�,�����J{��Pb5w`FaPQ��X�����I�FV��5������jFj6ao�/Kct��By��_��uo�����^6�Xm���M�[��KmS^A�R^��L��
w|z�Q�aC��B���W�V����T��5����{��5������j����W�����7P���k��o��6�;k(��aC���3
{\�[OS���R^���K��0n�����
eV�f��&m����������
��6�{k(�����f��4,,��I�f��4yv�l0��a�\Cy�
�������5>����<�����������-�VF����.�2�p�Kh��h����^�4Z�����'u�u 
�r	�k
��P�k��B� l|�Kh=�o����ya��
����ox�{������?��O�����������������������_���O���|��W���|�<����w�|���7u���?���z�e}�g��g",���>�D��	;���!�&l4I�
�����&y?������p��ng#d���&Y�>�(����{��[p\����z�	�G�
2Fa�IV��4
��q��l�W>��-����3�g��������	����^�{�{A���A�/3����S��_q�����k������+��������?���?�o<�`��1�_p)���?<���u�o�C�*f�v_P)/�}1�`�����<R��n�gw��Nw��l�#R�����&��~;�{���U����r"T\��S�v.�����u_)��{"S\����G�
N��[�).7��_;���LQ�C�<���VD�����~~����[oC���[�z�D�##ENt_P���(.������^/~y��Z�z�4hX:�D�#�@��w�?�~���{��'<���u������aF�,���n��-���������Z�[�=��H{������cF� ���@���V��?by�:���:@_J{����9W1�p���M�{������o��[�����z���="�(��p
��z�|)��_����5������r+�/���%�)�������o����������w0��|)���B�������o2Wn����1��n@���c!n�����o2Wn_1���������������{���})��_Cs�����j�+�}#���?��7�7�+~#��e�)�&�����+S]��7!��!�&Kw��~O�����~3�o�����.������������_��mN�����_�XzJ��o�o��W�����xt>�������u�T��
�1`KU�����*�E`u�|"�1[
���xUX'�)��>��!gK�U�O�n�����Ux�N�+pp�X
��������7��eCnC���!7��VGn������H����-VG�k,���Gn>��w��x��O�{��P`��������-���O����*O�x��O�{��P`yw`F~�C�X��������?��_��
W?dC��}���_��
����Aq?��S~A���p�C64X~�!���~7uO�wJq?��oN���p�C6X>��o~�������B�����������z|jaF~�C�X~}Jq����'~}Jq/����`}��BH~�C�6X~Jq�#�3`��@����
����7?m����
���!QS
���q��n1�X>"G��%�O�Q�`�CB�����bh�|B
N�[���
�oN��H�iH��O��3bp�1xS�X18�,���R�����K�u <ow������?O�!�r��Qy_����8��[����������������y|��K_��y~���Qy��L�
����h�3a��� ���}���_zk��%������;x�;(�P��=cH^�l��o�p���~�lp�
K�tx������
�5J��m��~��~�ppJ����^Ot����f
��������������nx?�9C�<6J�������f��p�zs�
�����s��/�+��o(n��/���(.�
�
�j��
W)��aC�����!�;������V^��H�)��aC�B���-�M���m���[�������
�)R�A���/lC��wm�v0l�k�����6���z�w���{����z�U�9
�U���>������n���s�6+Dd�����m�BD���z�J�)
'��8�ag��BBN<��:+$�����~�a810l��2�p�axW�Ya8Ko���)|s�H���aK�u 
�vu�u 
<
�K-�| c��>� <��>� �_��to�a��a�[
��0\xo�Li�D.<���>���1{K�u"�����,|
,��e�{���u����gUd�*�������U`�.��[pC�c��:�!7�����j���ga���(��(�-mVG�<
Gu������/\9���mA�c��6k[�)5S����@a��|gm��-
��������!y��6ks����W��-�����[�%���
����v�q ��b0���_���������!%���mi�*m� G���3�Ug�F��kG<Op�	(,q���;�G��m�V(,q{amRZ=���m4lh�V_1d����Z���0]�<��PX�^�
m�:���A�f�����}����PX�66�Y��c�>
m��.�������[����k��lh��PXRw
��Y�
(,q{a������k��lh��
XXRw��Y�,,q;a��k����Yx6�Yk@}��6k
������(�C�gC��FD��G��m���(�(���
�Q8�Qx��Y	Q8�Q�oRpBN}�'��$�������z��R�����0��0L�?
�8#'��/���0��0��s���fD��Gaz6fH�;�p���>	�H�{��_{����9x�s0=71�^���p�����79��G�{�-H��O�����zRp�S�>��	��=@�[��|���QR��|�5&�����D>��������H�'!`u�u"��m���)OD����������|VWX��/	O��"��"O�~�����/}7��m����������	n����k/����M�3g
����C�v���ksp����A,����?��Z�!���pu^�`m�����$��}������)x*q{k��m�*y�u�3f��p�L� O%n�`m��-3^��WC��-0�UB��R��T��
�VX�����g�:�m����3���W��W�������������-�����J�!o�P%no����6p���Z��������e&T�)8 ������bpho31�X[D���=���#��g���[pD�m�Y98�9���!
'�H@��aw�6��S�-UVBN}�2H�I8~f���
g$��$�Gt��pF�}�:L������3���mxG�M~qD��
���{������,���mVA��,����{.�����|/����p!0<����0\�0����{>�K������������:���&
�8����O���O�nRZ'���pX�Y��H�k��B�"�6nR7Zy�2V���5���������d��Oo�U�p���3o�n��&�a�{-��h��`F���J+8�a���|<8�a�{m�Pi�1#�a���������������q�Pi8,�{
k+���%����0;�zM~qN��
��������
3������������k���s:�mxY0#�a�tH�����5���0,��������
�������
+�����o����K�k��B+lf$0���V��%�g���~7@aI{��Pg��������
a�~�(��C���$��$��t��o@�����
I8~����#�pl���C:�-8"G��.+"�>?�����&������Re%���0X]e%�����' ��~3BpjC������@�WY!8�w�O0��#�6[z�8��kG��+�'���wD�������*��;A`���
"p�#�3_B����\��XZ�����@>�����{>��&/��@>��Z)�D>��`���)�lR�bi�N���P0�����+R����g��po�)�6)x��X)�
�w�1#�>?sd���#n�����
=V�`�fd�k�]nD�q�;�������{��5�Z�����iF����zH�� ��S��St��5�Z�����iF���~�zH�� ��S��St��5�Z��������z�W��<�H�������#������
MV\<f$�k�W����I�����]t��5�R�jh��:a���^�U�!�`R%o;����#������
MV\O�H��o�)x�Xp�����#n�����
MV�
f$C{)i)8�I�����+7�H�k��&+�`����zL��������S4n�����
MV���do
�����#rp�s0�
������qe���6l���0Y\��f=��� �� ���<�a$��$���ee$a����zH�I8�I��yH���F�^��Y;�0�\�(lixG��(���<�a\[#y�
[���,L��8J�C.������+�C��5������*�d���9��a��a��uH���F�^�,}��4�V�,�>�D>�4���8�a\_#y�
[
�q�-�Y����8|�q��qH���F�^�4Zy���Y��VE����N�pm��f���<,�{
k+�4K�������+^�&o�N+�3^��Vr����s��:�a<,y�
:��=f$<L����=�����o�i�K�k��N+�fd<����<,y?�{�C���%��aC���32�vZi��0�am���a�{m��i��`F�����J+�����<|�Q����i����
�VZ3f$8�j+��K�N�����6��k�p04Zi������V���%��|Y}������5i8�����U�h��4
?sF���Y) 
�&
C��"�p 4�j���#�a*��4��c�����JH�����n��p"4�����
'�����`i�2�p"4����4�	
?��uo�i87i8X��4�	
��FkG����4���4�7i8X�ixg4�n�
��N�Si>���8\�8,�VA.���VA.���3���m�@.m�4Z��AxxS7Z��Ax�J�!
���G��-���<|�����<|2��N�������iU��������*�p�������T�k�������W����������9oEF|�3������
�Vv3�1������!��s^�iw�H�k��J+���B�M[ie�`�d�&}/2�a�e#y�
*���H�����gp���s~�Y����l$��`C���3�Q�����(U�����M6�Z����K��d���-��FU�v��k?Hg\d#q�������L���M�g�����B���q����l����63Yg������T��)X{�V�U6�Z����a���Q�.h���C���Y���l$���d(�rDfm����I8�I��qo���F�^��YA�,�q�9uH�	A8�A��qo���F�^�tY	9�l�qA�ee�����gD���6�{-�Ree�`��&���98�9���R0n�����-M���V�u��#�}��?���l$��`K�U���J�MVA.}��?���l$��`K�u ��6.���9��s0=�9�`�������d���d���&�D>�L�~)��H�k��&�"��6?�R�-�"W���&��H�k��&�"��6.j��}B�}�F�M�'�`�{)�M�*k�I@8j���K�^�O6��Z�����
U��vI@8j���K�N�O��{�����Q����}�������=���m���DF<{�vMv����gaI�+X[e�3�����iWyo�������n2TY� ,�{k��}����?�*o.��k��`7��}�1$�����@X��N�(�s�Wa��h��e�������]��	K����nx����
e��U�PX[f�a�����'\��
D��AaC��D�@P8i��="
���Sw��,;,l����,	'u����c����v�m8!�6;K���������p�������
g����ag��2�p&4��}VF�}�����q8�q�Y
�qx'8�����8��q�k���w�������h����pR7Zy��y�k����pi���TZ�p!<�����<|�y�?qx����������i�������N�����^�i���g�����:��O���N�"�}��N�"�6;K�U��+�am�U&���>�i#�w�h#q
:�2��?���x����������7�H�F��N�8�Y�^?i;���&"y;���e��6���7tZ����B���I�i7��y=�m-n�����
�V�a�f!{m�����RU�~���>���S}4l���2c��$_?i;���T���}����q���m4l����0d�����VYA�J��>�ss���F�66tZe��?��O�N�l36���9k[��;m$n�aC�U�C�'��I�i�<,y;
k[��;m$n�aC�U�0�l�'m�U�p����m-������
�V���d�����VD�}���e��6�����J��d��w�N+!�>��C��6��������d��w�N+#�>��cF�m�-���<L6�x���v������
�N��h��i�a���;u�U��K�����!
�N��h��i�a���;u�u �>�7�;m$n�aK�u ��6��;�y���0N0�a�i#q
[:�y�l����_cF>�<L�iw�H�F��N�"��6�~�kH�y��y�����1!�6��N����%u�am�uL��������>��y��_���G�����[��$���������%o�dm5}�/^�_z���_?cD���_C��������!��K�K�/=J����0"�a���!������y�>f�a�{���������0����~������c�0,q/���}s���	
��}
�w���~��w+�������C����;F$ L��5�_a���<Do^�&��Z��~7�`���W[e`���R���������^
��o@�������`���GD���/������	���{
�7"��>�������7�_	��F���pd�n�p"��F�H���F��`e$��X�`e$�LX�u����s���e���� 0�&���wD��G`z�h��I�x��6,xG�	�/
)� ����_��_[J��\���)!��!���	>�K�m���:��B��k@C
>���>�#cC
>�����`K�u"������|"�}�/�"������"W���K@C
���������`����`C�uN^A���;@#
>'��H�N�O`�����F�^64Y�����-�_R��;���B0��m6�z���d�~��d���m�Nw��Q��G9N�f#q�������L���M�9�Xp�&r=�`�f#q���s.���]�M���I���_�t\���q����6l���%cF2�w�VY�*U���~�t�>�{m��e�+��<�R�h��s�*y;���_7���F�^6tY�6O���/�.����J�N��6��m6�Z���:����E�e�I8��5�4��l$��aC�uFDa���/�2������0�9�a�f#y�
[���,�V�,�6+!'�j����0n�����-uVBf+mu���Y5��J��F�^��b��2�0[i����i83Vg%�f#y�
[
�i���Y����4�V_nx�6�{m��h�a��fU7Zi��i���������H�k��B�@�m����4|�Mt:���0.�����-���8�6���B�D>k���e6���������l���n�*�pe8�}��e6��������0�h�Wm�U'�a��ix�n�N�����������	��J��&8Lg�i�K�k��J���	��J�z�a���G��[�@��Z����>cFB��������%���{4�nmx���5ix14Zu������V���%���/�����5qx14Zu������V]�%��0�p�������h�u��l�����+����}WI��C]�%��aC�U7�	o�J�n�������{��K�k��J�
�1#��M[i��8��^C���������q8���V������~�T#�pl��b��"�p$8��+��8��a�sx5!�&/�J+!'��t�����{;���2�pj�������������2�p���{�;i�6�#�6[:�yx'<��;�yx'����ps���{��WK�U��w���N� ���|�����pi��j�����xX�i�����:��G��WK�u"�����:��O��t���O��������:��O��A�iU�����>�S+�pm��j��*�p%<���:Mx�}�cT����~�����H{���h�E*��?�������l�o�<���-��W�����}�������� o���~�������o��B��_}���?|���������?|�����ip~��������%��G�,�������������W3��x���_>5?�B���|�tb���6����_��{����������_y�����|�T0#���,WW�W�#�f���o��W�w�4l'�"e�������1
��0�4����!
3^=|j����[����rOWZi�(�0�4k�>^=|j�)�f'�2n���0�t�����
�M��������H���\��}��5�,��Eh�l�ut�����W��[$i�N�~���G�{�gqD�~�����5��"�-
�D$��a;�z�0#�/t�����D$�r��-
�D$��a;��bFr>��Z��_���{BGe
i��MD�^6T�������_W����a�O��p�77<op�fQ/
:-?��������4�L���O����!
/`]%��aC������<��8�a������6-����C�*
:-�����#x�sqH�+HU��i�n���6��C�*
:-���q��G�t)���7�����0��5���J���C������<��7���<+[|K�<�<���bF���N���
G������ �&K���#�a�pbH�	y82V7	y85y8X:��<���C����������x�����a��Z��.�2�"��yXN��{�����%������q �n��cC1J%��u���_�;6��hvlh��|A�(�����@�(M����@�8�,�O��z���a�%nL��G�-,��lq���O��{>-N��L������l������'���v���+�E%dA��
)�"Y�6YX��dQ�7���<O���3S�n-x�,$��`C�7�:�G��%|�
�[����"O���{v�+y/GC�7�:�G�9>A
���5�Ly:�$nH�^�I�k��zo�u������07o�f����qC
�=^��[�hh�fX���)���.�<�d���;���Lx��
���<�;?q���������tt����O�xM����fX���)���.���d������K�k��&k�e������M���d�������K�k��&k�e����� ��&�~���.^hrp44Ys@�����#r0������!G����`C�5G�����j����O��N�{N������&+!'���&+!���.RpFNMN�&+#�>���C
���d�������#�&'K��#�}��M��L6x:�:lL���{�����*��{��gu�U���OG7�
)� �&'K�u �>��&�@&<]+5��9�hrp�4Yr����Y�d���d��r��x��g�����:���>��&�"����n�RpE�MN�&�"�>�Sm#
^&������.�Q�2�D�^64Y��c��z�mL�p���#���cq^<��H��&kq0�PBw
�6Y������-:����D
64Y�����S���Z<�@$n�`m���^<��H��Pe-3,���kH��
ix�*q{
k��e>���J}4l���e������\���P������Xp�������ZV�!�3Q���!
��R%n�a�S;�
2U�66�Y�Z1d&*=�6��m����
�(5��
l��m4l������������Z����5�����0�0�&C������azxqL�H��O���"��,�,�&C��D����azvqH�a8����������c��di��p��0=�8���,����O��{��H��C��2+#	gB��2+#	�>	?1@��~��s��-]��Lv����C�����>�'#��� �����4Y)�l����[��K�������FI����cd`��[���\�L������H�F���@&[A���!��H�G���q���6I����a���d'=�8�_����
VwX�
D�6�tX	�����4\��+{����	���:�wvJ�N��k���W������Cv^�6;C��:�`I�iX�b�(X�~���w���x���-��g��`z.uH�(X�~����z�`I����b�������-�����e����>T����������Z��!	����i�~#�������?����x�~7<��i)�{�Gz[����k�R�����
���w�e?}���V�{?�������7�����8z�w���
��mlx\�>������=<�yC������L���y�4���62=�~Ye���������8�
�����62<����/<�odx����G�m��q���
g�mdv=�;�_����q��_���'�9o(�6���q���~qt�FF�=1A��~O�t�/�;o��6����q���~qr�F&����s����8�
�����628����/����8m1�����=6�yC���������o?���s�627N[�n85nkO�s�P�m86n#c����!�������{b<�������=4�yC������L���tH�85n#S��?����=3�����mdh\P7X84n#C����~o�82nk��s�����q�G��~qf��f���Ro83nk��s�����qG/���qh������Ro84nk�s�����q�G/���qj�F��}���[���q[{f��-��������ph��������ph���fK��S�625.�[,����q��.6��������c���������mll����
��m��q����_=j~��[W�n8:n#�����
�0�>�"L�����1~�Q��~��0"�am�&�a������9�}�
���k��k�������%s�^m�������������^�&
��}o�@X2�/`�VY�K�N��~�����]��_{����y��}
��&+�@��S���n�w���z_{�����a�>Gm��`��������X�^�}�=���V��'������`��=�z�+������k�{�]���������+q��z7�_�{�����������Q�_��+q��zroh�~�-�������m�B@�
}�}FO.��|C�5���
�7��7���������������;��
�M�������J������Oa���9!���+`�~3�o"��n�2�o���3����oF���W���jG��}�M��jG��������{��~��`Kw�#��}�M��� ��}�}fB������~�k)�
�o��oR�W�o���3�i���@�=���-����{��7��������3�-���D�=��k��N�����I]_���g���!�V��������"��>�&uU�k���pk�'�I���
Cq@\$�����8 .�q�r��_����^��qo�8.��pI�_E�x�g��������9��)�����"���U��p�����������b{>��S8����E2.i�����"��~!�t�����������?��xc
��pq�OI������2�M�5�Wq90cH���V\A�J���D�t\A�J�k��+�;f�OIw����+�S��)X�@�m��������{�`H�������U�v
�V�1x�x�!�/�������&m�2p�30]s5����l��bD�}v����!8�!�		}�K��c�_�qo�	!8�!�M�+!�>�EWC>�	)85)��Y����S������2bp&�MI)87)��I7����k�)8�)X��v�����/����1xg���
b����'���|.�����/N�����\;v�S0bp��0�@.M~q�����`�%�!��G��8�u�'�D>����{>�O���k�C
>�O�����"�M�-EVE�����\�+y��]��k��
=V���+�`�M���	(X�~��{NP���l���s��P���X�K���qs�0X�^�pz��*f$��=V�3L0X�D',q�z���H0��R�,y?�0����4K�k��"+�;fd�-��,y?�4����/^�C���`	�+X[d�0X�~�q�!
��^��C��V�`	�{��6Yi���s�hH���W�	����J����5���� ,y?�D���O�zM^]V
3f$(��]V
����0=R4���,�,�����aa�-�RD������!
G����aK��#�a����p��0?T4���4��4l���p"4��}VFN}~��+��g�������ge��Lh�����4��4���
������������w��^]h���;�a���� �M^-�VA.���VA.�����8\�8�Z*�q�`8����������<��&��J�D>��J�D>��auiy"�M^-�VE>	��J�"W�����+�pm��ji�*�p%4LG��(8Ox������g�N#q�
�<��������Vvp���x��~�{-��geW0#�R3k����"y;����e�P#q����3fd{j�uV�p���xO|����qG������<�<��6���:+��S%��R0n�����
mV^`�f&�j��m��:U�v�i�0���{-�Pf�u��d_��-��
6U�v�i�����F�^6tYy����k��]V�@�J�N�'���[0������
UVf$�Zm��p�����;������F�^6TY9 ��5n�VY9"�O����a�W#y�
�����������$		?qv���qc���6l)��0�[�����(��(LA}����+k$��`K����������(�	
?q8���0.�����-m��,LV�8:�dH�;���gazt�����'i�Z#q/K�U����Ggb)� ��O���#�{k$��aK�u ��5��L���0|~�p��
���{m��g�H�d��_����4|�����W�H�k��>�D&l����*����a�=d�����k$��`K�U���G�C�(x���+Y��}~v��%��`C��O3^�u�>
K�/�+�����5Q8��7,������m�v(,y��������k�p0�Y������e����%������W�zm6�Y��`F������g@a���|���%��aC��/3^�m��
K�/�+��(,y/
GC���f$(�j��}��_�W��XX�^6�Y�zbF�������f/�����o����������k��=K��;�'���[��	��Pg�a80��Y{@}�O����0�0
u��#��M]gE����a���{N��	��Rg%��D`xS�Y	a8���t,��-Y85Y8Z���,�o�:+#�>{�U�gD��D�h��vD�LP�.�R��(�3�������{�-uVA�	
o�:� 
���o
��(\�(l��
�p!(����Q��G�/���
��G����:���t%���OD��}[���9����,|6Y8Y��Y�$,LW�iY�$_�G��4\��&'K�U�+�au�U�+9$M�p�h��:�{m��g�=��2ca;m���
�	n"��s�pi��H�k��B�8�Y�R��-�������|���>��o��g#q�
���H&m�U<�C$�������6������*����9�.h�2�Q���sJH���F�^6TZe�0#���VY@�J��9�?�a\i#y�
*����������4�zl������4�+m$��aC�U��� �����NU�~�9�!
�J�{i�M�N�lC�I�A�i�
���m�{��}���6�����*y�-�	�N�����a��`���������
�V���l�M�vZ%"�>�ucF�Mv���J�l�MPwZ	�8����#�0������-�VF &�m\TwZ�8����#�0������-���@�6�Du��#�} ~���
�N��h�Rj��l�MT�Z�x�1]G0�a�i#q
[J��@�6�Du�u �>�}C��6�����:���f��.������t!���q���m4l)�N�a��&�K�y���0�H0�a�i#q�
;K�U���f:�fH�y�����OZ��F�66tZ��<�V�Dm��v_�e���y�:&�a��h��i�cH���N�p��������:���m4l��?aH���N������s���x�txb����Pj�������:f��7��,���g b�����js�������: b��9�A�T�K�F��Z�X2�$H�����K��9
:��u���fbg����XR�*��Z�
L,y?�<���7�W���b���%u�bm�ul���s�������P���:��!	'm�u��@�M��C*������Pm�8,��}�T�#�b�--GD,�m,��j+!G��t����bq"���8�wo�	�8���[���T�����T��kb�GF(�m(��j+#g��jkG(��5����cG&��L�-���L������cF&��k�'���
D�����RlD��GbO�i� ���	�uo�qi���Z��'bO�i�@">�DL���i��h���Z'��bO�i�D >��i��<��<|vx��jU��������pE���4�=DyT��bC�uN�a�=>7��s�����U�����U7��Z�lh���bH2��N�R�[����MOG`���H�F��Z�t�$S~�b�!{��H�^����O\w#yz���������Z����7�o�*y%����W��?������������?|�������#>����>~�w������?�����}���?�R��?�:�o��������;�\�_����>�����������������o��X�����*�'mX�{+;���W����((�����V<�W�@(��m`�p����3'���gAI�F��:��a�J&By��������=s����q��mTl�+��d$�w�>�.0��cx�|����O�z8���_���G�/�|�e��x����N�	��`Wv��o���2N�����kr���x�L����vH������3_���`�%y/��@}����r�;m!X���SxO���`%y/��8}�<0"	��u`������{�����4(�{)������ "1���e`�����3����`%y/��(}��sx�
�r�G�jB f'��8ss�8J�^
~����W��U6��K��8��=q<���q�������{� ���d�O/#t����;�����F��J��k�{� ��d���B� ��w�����`%y�n�Cx�L��^�g����3��nnAI��7�,F&���f�!
�H��������)Xq��m~2,��U2�{u�U����;�XzH�8J�6^:�'�*������H���],=��m��R����\�[�_��{������������)��{���/^s���P���p���W���zKs@���],=�`���5�	�8���+g��{+���4;LN����c
�x������a�����^zjH�s��g�N����p��<p�fT��n�/3���������/���w+c�[�.��*��5f���	3�O}_���z��B�+~���xO����5��[Q�>��Z|bF���VVY���X0~��]�����x���k�������/X�dmSpP���g~W�:&�.^@��xv1,8 ���������C���Mus�9849���'�^��	�cOC
������tW���rplr��#O���	98�������S�����1#�&�8���+����`z�iH�98�9�.*RpF�M~q���WpG����M����9��)R���79��y'�^���3V7Y9�V7Y9��9��d��B8�{R��\���9�hs���:���������O�����tI���O�����/�:��
"������1#�}�;J�\���&�8���+X��+��E�dU����`��tD�nB�M~q���W�M���
|Z�M����%o�`m��`��#��`C����	/�&�9�`��)X�d9����{-��d9�1#��E�d9,y;k�,S�q��,7O��p��m��,y;k�,7K�k��&��'fd�m��2c�}��I��K�k��&�-32�6Yn���������Va�{m�Pe�5cF����r+����|��]��f�xm6TYn�����U���%o�`mW�������Pe�� ��cm���p��0�=;�`����Pe�� ��cm��"�p��0�<;��� � �X��� ��cu���S����!'����Ree�D@xUWYA8�A�n�RpF�M^,UVF�����!����t����w��	������w�t�������a�qvH�9�49x�TY9�0VWY9��9���R��\��X��9�`��������t����O������&�D>	�1C
>��O���&�D>�li�*r�I8���RpE����MVE�M^
M���������	� �����.�����"y�
�,�<f${��!
;��H��>��[�
6����
U��f$[��!{��H��GX[VzX`��{m��eyb���^�i�,?{l�������u]�[:P��Z����s�����~�vY~�*y���0l�y��6l(���1cj��uRod���5���6�<�^6�Y~������tZ���W�������+%�ky�
���_������t\���7�������������������a�������+�p@���}�H��M��B�G�a�����EC�H��O�����pD�M�,�VB&+l<�X4���8��m�CN��������J��d���#��4��S�]�8���<��<�Y*��<L��x:�hH�;�p&<���������&o�JkG&[l<Z4�a�������)� �M�,�VA&[l<Z4���8\�8Lu����������hH�d���C��| 
}V�<����	����:��O_�
)�D>�0�>y����g��7K�U���O�
)�"W��tM���+�pm�����'da�����E#�'`a��kX�I�����6l�����������!
;�
�K��4���%���`��fW0#aa:�hH�XX���F��K�k��>k�3����4,,y{
k�u���^�����g�a	�kX�g�3����4L��ixqx��4}��
K�^��>k^��%o�am'=/�^������3����4�K�^��Nz^��%��aC�5o3����4�K���P��
pX�^64Zs�0#�am�5����a�M,s@M�FkH�������#�p����I�M����c��-}VD����d�!�&d��g�O�S����$��$li��p"$L���I8�I���*��oFNM�#\�2�t��0#��9��_���?������z�����������o����_@|���?|���R����������������q�?2?���T�_�����?/����u���������?����������� R�&RDK�w R�>R�'���?���C�8�6�w���Hq4�"Z�����#�{B
�[��Dq�l��x"R�M���b�D�8�H��p�\�(N�~M�+2Em2E��z�����=�n-x��R��5���n����
��2���?�=��-��
D��
�~C��F�{-�P�-.a���'�\0�@$n�`��n����
���aZ�B����`C
�p������/�D�^6�z��
���R�VJ��
��b��A$��`C��,3f�OC�#B���������O�,�D�^
N�����a��4T���{^�t���=�kpYp!���lh���b��4Tz�sH�����:���.����
M����?
���Rp�����M��A$��`C���`��k���[�o�\p!���lh���L��xu���#�`���.����-MVB&[A�A�!'��D8����{�.�D�^��Y1�,�������3��O����)87)8Yz�)����=���
~b�����6�{��Rc�`�dV�X!������~q����ki�
20�B�D1����������] ����,-��L6���P)�D>�LK�����*I���Rb���d!��.�*"��G`�xD��	D�6��tX	����VE�}~bs�����om����:K�N��
k��%n��O����	/]��dh�V,�;�j��K�N�����=��5��M�k�3�$�-�V,q������J�F��k�����-��X�~�W��+i�
�u������Z��%�}�c]�%n�`C��.����m��X�v�i��W`I����`���!�L���~7`��I�iCyo��������%�`z��,q?����_����k�34Xk@}^�
���Y��}
k�������Pa�8�x�VXkD�de��)�5"�6;K����c��u����a�O�D�����S���������0�������������~32pn3��tX8VwX;2p�30��2��xo#��tX;"��G`j���[�w��]�\��K�����*������5���d��g�'�)�\��|t �Rb�G��{�1#���A�'B���`K�u"�}�/��|"������V���
��RcU�����U]cU��JB��p\+RpmS�7�X���5�S�����	� �3�L�(��;?$n�`C���C�'��ksp�����G�n��C�6
6�X�w�?�h��X?���e:���O'=)7~H�F��"k�C�����"����?��j��c�}��������C��~��"k[@�J�/�0���>$m�_C��-;������E���F��_�a�
w}H�F��k[az�F6~l�k[A�J�$m�"k�]�������6��������6��������p���m4lh������C2��������
#�6��*k���l�����"rp�s�S_t�����h�Re%a���~H�4��S�����
7~H�F��.+!	���C2���$��$��O���
����h�Rfed�����V�Y;�p&[$6�o6l;�������f�H�;�au��#
�d�D�>���������*�������*������~i�����h��h��d_
��i�@>�/[�pS��}��_���G�/�|�e<����9R��H|$V_�����{���0}���de
����"W���V6\V#y/���(}��0�XC? #�
���������8,y/��� }�����2�_7c�����0,y/���}�<0b��dH�PX�����Y�
K�K��=D�|w��a��/������-�����k��k�����3`�d������,q{�j���x�xM~����Wp���~�EVX�%n�_�M+a���5_
��J��+��J�N��+��������
����J��7��^�m��}���!o��W���
��m|?����0c���GdH�	8V_�p���,8��~D��A`�E+!"���`��#2p�30��)8!G��Q�a%d��~l)�Bp�C0���)!8��+#���`K����s���GdH�)8
fo�������/�-5����1�~D��#��'�eI� ������ �>Gu�U����I{[R(������"�@.���E��|���%�9�hs���:�����&�D>	O�_�'r�����t�|	���>'u�U��O������CE�M~qJ���9��98i��8�
��>�.���#.�����
MV�
f��*J�&+:��H�^��S"n�����
MVt3�g%m��@$no�������j$��`C�=���diM�6Y��
D��f�i�l���F�^64Yq����l�����<�H��_����j$��^C��3���ITC�]@�J�/c
K�e5��Z��������y�I�b�$���2��D�U#i��:��M��?�7i;���B���z��F\U#i�������?�7i�f������;�{��E5���MC�/YW�_�
�7"��>�j����F�^�5�W1"��m5nR�W�7���N9�/�����~-�UB�%�j�[�!�&��D6I|������I{��R^eD_����d�oF��d���.��kj$��_Kw�#��e5���~w�����P��qM����k��
�/YV�_��� �B���
��H�k����@�%�j��!����_my�Kj$��_Kyu ��U5���~O�����t���~qG����ki�N�_����_�oE�=��K��W�H�k����"��E5���������t���~���[�����4�J�N�N�_�	�W�v�U�W�9�vM�]�Ur�������J�W�v�U�W�U�vM�]�U�f$����U���������J�W�^�5�Wi�������Wi����~��U��%��_C��	3�u��*-��������J�����k���rbF��N�_�u�~	�*����J�k���*�3�u��*m��������J�����k����1#[������+y;�~��U
3^�6�����_m��o������7"��6����#�_m�"�o�����o��76�w��W	�7����*!��>�>1���~�oj��j��2�o"����UF��}�}b����f�������_������W�W;�����'F}������7�w��W;��N������������Q���[�K�WKU��_��������'F}�����{4�w��W��A������� ����N��������:�O��^�_���'�_mU��&�����"�V��^�_U�����'F}��/�om��������������>$o�_e�q
����k���[0#�@���Uvp����~��U�54����f������ ���U�p����~��U�54�����������Y�_���������2�����~
�U�O�H�����*/�%2��U�54�������K��d
�����
�T�v�U�W��H�k���*�3�!�����+�S���W�_e�B#i���������v����*o�O%o�_e�q	����k��r��l����r@�
���U�4���������m����U������t|��~q����k���/[D3��������K���7�H�k���*#��=4t<��~3�o��/^<�_\@#i/�K����E�_������tv��~q�����k��v�_��fQ�W�w��/]<�_\?#i��Z�������,��� ��B�_��I{���_��l�������l���W�|F�^���W'�/[A��������/�]<�_�������_U�_��fQ�W�����W�zF�^�5�W�����,��j��%o�_e�O�����������	�.��jw����7�GY`�X�^6X�;1#`m��{����/Q�����

��fd�m��X��
VVX�,q/GC���3�+,�,y{+;�}���58:�}�������K�^��k_^�&GC�����W����W�`��+X�b�k�����hh��m������!o@���W����7�`�{-�Pc��cF��t����bp�c�3kb�-8 �&GC��G��@8�n�RpD����E���c���������p0]e1���k�����-MVBN���.�!g��D8�2QpF�m�4Y983V7Y98���G�#�6[��9xg�n�v���p0e<����798Y���\�uC
.���p0�e<�`�����di���B8���R��|���G| MN�&�D>��C
>��O��t����O�������dU���p0�h1���\	�q�#
��������dU��J8���Qp��R	�y�
.��F�^64Ye:0c$��;-���"y{+����h$��`C�U���3�]j1�`w��+X�d�G#q����f��ut�����"y{#�MV��4�Z���*3�,d+��k-�<�I�����MV��4�Z���*L�,d-��{-���I�����MV��4�R��UVYg����f�!
��R%o�ae�Up)��m4l����0d4���-�4��K�����]V��4�����*[������n��pX�a6:SYf\L#q
�����zG�[i8"�<B�f\M#q
�����G7\i8!G�>B[g�r��h��g%�a����cFN���}������-�VF&Kj�r1���8�k-\P#q
[�y���qt����w����0r<�a������J� �E5�n��pA.�����
����h��i��dU���.�4| ��?��~��a\S#q�
;K�u �e5�n����<|�4��0.�����-���<L��8��bH�y���0=�9�a\U#q
[:��<L�8��bD���<\�<L��h����%n�aC�uL	C�;/�4<,y;
�A��������ag��<,�{
k;��K�N��~yxs�~����ag��<,�{
k;��K�N��~yxw�'^�6;C�u�3�$<L7_ix�����i����%n�aC�u,C��/�4�K�N���t,�������:��!k;�c]��>�c�C^��%n�aC�u��d<����
xX�v��������%��ao���m������!
�a��i��/on8 �6{C�u��@x���x��u����'�!�p��������zK��_��[��?�����������O�������������_���>~�����;��q�?����w���m��������?������z�l��������M��1����h�Of������N4�'1�����������
-��&�d&�n�0�����'�r��`�gG�{C	x��?����CF\Q��L�+\���������������!c
���J<�3��rk�(�kG�{C	XQ�W&����!���D�?3������������������
"C*F�_�g&���{M~��|oh+���L>�!2�a4����'6���0���1���V4���|�EdH�h�+1�O���a4��c�gCX��Wb�=]#2�a4����'����0���1����h�+1����0��JL�{�nnM~�����iU4���|O�iM~%&��Mc77�&�vL�l��*��JL���D�4�DZ]�\qD"���G��V�F$��'bOw��8"�>�e�CN��
����J����.�pB N} ����4�@��@<[Z��@��@��6�!
g�L�X��R���y��_���G�/u��zwD��GbO��xG$�	kw�#�M"~�Y��z��w���N� ���^���kA.M~�I��~�pa4�n���BhX��a�h��kO���{ 
��dH�'���Gaz0z�3��(|6Q��g�{�=�O�t���~��>�c�C����g��_{�����\	�M"C��H��O����	7�K�K���������\�����WYd���������_7�9#L�����R�ko������,��t���z]�z]O�����?}���~���������m�o��w�����Q�����7��o������'����N�o�����M������?��������~�������������������~���s��2(,�$�������s�D�l��s8^�a�U��m��_v��[�aw��W�x�M�����
�e�w���'N�[�����a�z�3�J7����?�~�	�{�������SE���3�J���V�?�vF�(���aoA,����T��dH������s���[/l�����j�0���@�;N����y;_�R�v�?�^�Ul�	����}�������T�za�#��^U����/����;��a<d����O|���zb�e�����0#r�e��z��5������j�8Dtk������1������{YF����~
�!�f2-��#D����{�B���a�;��e��~��������I������%������D��*��������[��hmsU�}/;�Hi�/��e��~�����[��!muu �^V�?.�a���e��~�����{��I���D��l���f��N�����������{��I���"�^��e��W�����]�t���~+����r��e��\6C{�&�_	��W�^�	�W�v�U�W�Mx�������{�u�������r�W���.��������/���_?cF�����r�W���+���%��_C�f�	������������R���W�^�5�Wn����������`�}�}b����.������C��3�����[�%o/�r�+�����k����cF�����r�����S�Wn����~
���fd������+y;�����]�_�ro��70���W. �r�Y�_���������{������/�1����	�j����������{�M����/�1������j�����������{����������2�o&��}�������������������v��L�W���#��m���W;��N�wQ�W�w'��}�-�������� ������:��_�����{4�w��W��A�wQ�W��A�W�����{4�w��W'��I�wQ�W'����_z�`D���l��b��*�oe����*�o%_��~T�k�C��/ �_m�a1�#o�_��G��<�^�5�W�������`j�+[iy;�*�?�����������?�T�EF����W�_yXI����W�����4���~
���3�=�}�����B�G�N�����:�G�k�����fD���_m�a�#o�_e�a�#��_C��3�C}�������������������������k����4����WV�<�~|�a�#�����_���!�e��~����E4��_��gXC�H{���_���/�h�����|@�
}�}f	���"�^��H����G�����w�j�+�c��Yrk�����F���W	�����}���*!��>���#�M����3����J���-4�_���������KO��7#�^��H���*#�^����W�_����������~w�������_����4��U�W;����_z�`D����zF���W�����}���� ��>���#�=�/�g�_Ku �^6���W�_��G����������3����:�/h�����N�������+"�^v���k��W�����}����"�V�����|E�����~
��<!�^6���W�_����m����;O������������j�����o�����:�_I{���_����������%o�_e5{�_I{���_�~�������=���������y�k�����_�3����������W�v�U�W����5�w3�W��+�{�j��y����~����Nx������y����~�����J�N���j^O�vm�5�W�6cF��A�_�����������+i����98�H�7h��9 ����~r�������_��7�
��j����������~#�ol�o��W�7�
��*!��>�����S����J�������J��������9#��&�K��3�_u��3�_����77�7X���w'�����������.�oA����,�UA�-����*������t��~�K����:���������������G����:���Q�_���g��������g�-����{�����"�����dE��m���W������j���Q	�*��w�H�K���_-S��do��W���������������~
���2f� �Q�_-n�����w�H�k���j�0#sah���Z<�>$o;}�5�_�=#i����e��[@���2�>�������_�=#i����eY0#�������>��������w�H�k���jY=f$x���ZV���������w�H�k�#��2�t��p�0����_���?������z�������������~���7������K�o�����>~���������u���?�1J%��uV�]�m�����?�T].�����(B`2=.7��yH�����["�����9�D��=-7�^��!i����%!O��t���z�D��pWyH�k��:o��d���3���4��4�}�a�M��Ro��y;�Y�A�I�wG���0�.{p�����k)�
���A�I�� K�>K���{<$��^K�w K�eO�����$���2�.��C�^��Ty���.�'L��������s�F��[<$��^K�w��4�����RoE�=��4m��%��Z������d��$=�^����^�sJ���[������p������1����J��*cY��K���dh�V�+�;�j[���J���WYk����ks���Z��?s���z=p���2��W�^�5�V��1�gn�R��+q��3���+i/���P[���!?s���~_��e�A[_I����[���!?s���~������K�u����~
�����[,����J�/�����J�F���j�2���-�c������l?��0��k�������B�>��-�C�
���y��F����_7��5"��>��-�C��H���X���F����_7Y������K�X�7!��>��o��7!��&����^e����_��rH��7�����7����;l��v��`�&mH�;���7�T.xG�;li�v$��O�t������'�7�T.� �6;K�U�A`u�u �>���r�2��f`g��d��0���:���>k�q[Od������a���g���&�!����g�������l3��tX���n��oE�}����Vd��f`g���i�+�g`�pD��w��I��������~
�����,�����!q;���o��C�6�5tX���37Y����C�~!��I����am��!?s���~g0���Ny���;<$m�_C���'���M�C�]<��3���o����������!?s���~W���N��G�����~������!?s���~��J��w��_1l��C�6�5�W��7���~B����>���~����;<$m�_C����m���W[@�
}������I����_m��l��WpH��7��W���;<$m�_K���&z����S���0n��C�6���W��m�P�W�7��W{��;<$m�_K���&u�#�f2f_�?�I����_���d��d9������5s���I����_�_���n��/�oac����������:��&��pH���A��k�+��!i������D�%�<���!����'Y3�}�����������d��.5����[��9��g��!i���0!��M��*L���3��8��0�J�F���*�	C����������_�����%m�_C��!��KL
��{�����V�����~
�U�C�M���*������f�_I����_�9cH��R�_��W�~3V�2��C���W���Q�K��^�X���dH� ����SVXaux�����������3>"C�]�%�g|�bH�/]�_{|���m��d��������/�m}���6�_I{i����{�
#���W?^�_�}��^��oh��k����}A_mu"�o$G���"�ol��k�7�����KW�
i7!�Fr�Y���|S|_{�{o�	�7����nF�M}�
���{s{_{�{o��7���n�.Bo�C�����#���K��^��������y�.������yW�+�� ���W���������[��K��
�� ���7���[:��5��@�-}����!�H�G�x���:�x���g�zOD������6����$��]���{v���[�y�>�����z+2o%�{�}UE��������"�V���*Nx��}�������f$��^Cc�3�����*:�uH�N������f$��^Ce���������n�����I{���YE�0#������[��m�K�_��iF�^�5�Vq�y�����wI���/���'��0�����_����po���y�s��������>������o����7��������>~��������?�	������������N:_����������p������C��L���~5_��s��f���/y��&rn.)+��C�$��X���Kxz.��LQ[������K�+	g2I�k���/���D&3��C�]�^�����lq�d���z
5_��s�f���/�0y:�3sI�Xx��L��Z���Kxr.��L������Xo�������$��_C����\"s��j�o�����s���g��$q����������E_
0x:��s�=������$��_C����\"s����K�8��s�)����$��_C���]"s��L�oB�%���S>��p"����k����Kd.S�>��2�/9>���r&��$q��Z�+<E��\����v�_r��9��g��$q�����Wx�.��L0��[�	:��/Nd���~-��Kd.��C�=��:�}1�D&�{��R_�I�D�2%u}u"��3t�+�O8�I�^���Wx�.��LT������s�cgNd���~-���Kd.SR�W����stk��~��w��������o��t�3����7Op�����K#G��^��������/����=��-����G&���X��*^�����P`e<O'�{k������Q:��-����!q���'�$t�`m��g���s��7�U�^6TXy�0c��.�:�������Hy�*q��IV^N��?��&m���&�������P%��`C���������m��U��,�����C����
-V�2f���w����HT����=�/�/^s{�b��r@}v����98�^��#rphr�b��rD����EV����p��~���c��K����#�`u�����`��fD�	9859x�4Y98�g�����3�`�eD�9879x�4Y;rp&L�
)xG�	�#
����6[��9x'LO�
)� ����������`K�U���`z�iH�rp�s��7	��|41x�Yb�A0����1� L�n�(�D>��Z��1�$��E��|V/�"�M^-EVE���������`0��1�`������Pd�bp%��E�>K�/���6I�k��"kw32�Y������E��s�$��`C���	32�Y���_J�8�I�^6Y�?1#�`�-��y��	��#
��M�Z������	{m��/����K)x����
E��d�H8�k��}�����U���x��l(��8XB�
�Y�
,y���7��������7�`	�+X�d�p����,:����kr�fh���`F�������rp`�]p@M�M����`���!G��H8X{J���c��7K����#�`�n�rp"�^pBNM�,MVBN���MVFN���h�g�������de���8X�d����p�z�;r������d���;�`���1#����_��9xor�fi�
rp!<����\�| �6[��9� <���9� �=z?���6[��9� <���9�$�^��|698X���|��MVE����EGE�M�&�L� ��Y�d�	� ��)�Lp����
MVqfdC��MVqp���x��Q�����lh��;1#�R�m���Xp��~���F�^64Y��H���1TC
���J�^�����z�{-��d�9cF2����S0�T����j$��`C�U�Y��>�jH��T��+XYt\Q#q�����,�B��E�d�L���b
�x�������*����^m�U60���W���(��F�^64Y%x�Hf�.�&�����`��qM���
MV���lY
�$7���k��S#q�[������,�&+!G������{-��d%�`����
RpFN����%�T#q�[������,�&+#g������{-��d���la��n�v���p��>���j$��`K�U������dH�9��/9�498Z��9����+��| ��������{-��d���lg
�9��9�$�^0������-MVEfKkVu�U��+�`:abD���F�^�4Y9�m���>G|L���p�v��,q/'C�uL3^�M����%o�`e�q8�`�{-��d.cF��U�d8X�~)�/^�����:<p����m�,y;�	#
�^�&'C�u����W���:f�`���\��598��cY0#�`m�u,����W���8�`�{-��d������M��K�/��8X�^64Y�6aF�����:6�`��+XYtp���lh����������!�V/8 �6��# �����:"rp L'L�(8"�6��#"G���������p�z�	9869�M�*+!'����J���������	�n�tYI8��]VF����F�Mv�����3Aa�pH�;���Ga�!��$�7I�M�2� 
��7u�U�Aa:dbD�Q�4Q�M�6�@.���m��,|�S&F4| Mv���:���:�D>�7|"�Mv���:��OB�A�gU����0�31���4\�4�&K�U�+���.�*�p%8�����k$n�aC�uN0W�d�k���:'��H�N<m�q����h�Pi�k�l�M�VZ������}������qw���6����a���6�m�uz��H��gX��/�C
*�s�1$����9�S����061�a�^#q
*�sq���
�J�\��J�^���wN\_#q
:�s��-s�vZ��`�����
����h��i���!�6Wm�un U%o�ae�q���h��i���!��^��wH�����R�
6�����:�0�c�����<�<����
�
��h��i�y�-��{�4��#�a��q���m4l���0�d��VBN}�t������S��-�VFf�l���!
g���xX�a�b#q�
{K��#�]6Q�i���;�a�C<'������-���<������C.��;�a��q���m4l��
�0�f����<\��#�E6�����:���:��wH�'��AxX�a�d#q
[:�y�����N�D>	��#�U6��������l�
��;���<\	k7\'����ao���<,�;
'm�U'�a��kX�x������ao����1$[�������_J�xX�66tZ�;�v�j;����%o�ae�Q=���m4l�����-w�vZu^�a���
������l���|`H��U�i�xX��V6u����
�V]v���j;��K�/��xX�66tZuM��w�vZu������
o/^��gC�U7�aI�kX�i�
xX�~)
�	/^��gC�U�p`<���j@����!
#�6��N�F���xX�i��<	�7��c��gK����c��=�7���<��#N��	y��_���G�/���{�S��"�!%gD�D�X���H��H������f��b?�K��8 �S(F��#�M ~�Q��~w�����|���~��NpX���8\�8����������a?���0\k��a�4a����{�=��>
�%�C�=��������G�_{����A������e�� |��'��� |6A������[��>��C�����`�z�1�61����w��i�� XYd������������x����#����^	���s�L0�|���V���m��+mq�Y,�����Q�Xq�3��s6G+mq�T2,����wU6Xq���s6=�:1�`Xi���8�cX��cF��UYa���P��������J�G�������^��wH��/�)���J�G�k�v�-c��l��S�Xoiv(x���t����a��#��`;���q��l�
]�;��-A�[��A�'^<t���?�����~We��18�'F�C�_�qo�9����|���#�`��#rpls������l��SY	98�9��q#
N������&+!��6t����3rp"�^pF�M~q^��g�`��F�de��L8��Q��������{����R��wH�;r�N8X����79��i�\���R�n�
rp!LGM�(�@.M~qX����l�
]�;��9� �_0r����gu�[���V�xu�u"����E��|69��Q�\���F��wH�9�2�.�"�&�8�������B�m���\��`mLrp���lh��t`F���6��������%��������O����������������>~����}���)}���?|���?���C(���>~�����!�����?�����4��#���/��$W�}�����?Ha��+���+���X��J�>�����s���)m�f����$o;��>��kp���3���l���Z0#9�M)x��*��?/�O������?~��w�t����'��3���t�������O?~3j�_���������v
�{Kov����?��_}��_��������_���_�������W?��?�I�$���H��3V������/��u������[�
�t�OW/�_����OW�<]��%���t�o��8{o�^2H�k���3����d���1��K���������]����W��7�;	��w���x��A�v���+�{���]����W��7�+	��w���x��A�v���a�{��'�v�7/�]���iy'o�'dH�;����0�����x��/^�ro�Yx'/�'dH�a��_0<�I��~�_���~U�$d<�y�@?!C�=������������@�=�����0#����w�j�x'�����'������{��W��aF�����x��*�����'6���oE��M�],�UE����'dL�����������<j�C��_�e{�����������W�_yX��H{���_y!#��@?!C�up����~�������~
���dd[�'dH�n��������������������N@m��D���ql�������������z�����G�	���T�v�U�WV<�^�5�W~�0#�H?!C�]A�J�N�������G�k�����'f$G��'dH������=�Q��~a��#��_C����I"�	�o}*y��Ve�a��#��_C��/�|@?!c�E�
}�}b����F�������_������O��~#�o�������ol��j���/�z@?!C�M�����Ol���_�������_e�_���~B����s�Wm��s�WK�#����2���w���[d��wG�����Z������O��~�o������
�oi��j��
�/[x@?!C�=�K��� {o��������_��l�����D�=�j����l��j��N�_���~B����{���W��l�������l�����"��>�n��j��k�
��<�J�^���j��%o�_e5O�]�7C5�3����jv��������������k��f�1#[����f�+y;�*����J�k���j�'���i��y����~���<�J�k���j�O���i��y���>�>�.��~�_I{���_�K��l�����W�_���W�_�+�����k���5cF���2�_�_���W�_�����������7�_	��W�_�������������5�w3�Ws@�
l������o ���������k������j��9"��>�m�c�-�UB�����UB�M}�}b]���&�����`��2�o"�K?!C�������A�_e�����`��2�o&�K?!C���s��X{o�;�����`��v����/���� ��}�
��� ��&�KU�[x���
�o��o��W�oi�o��W�����������������D�=��,����{����!����g��X{s���g�������'�_�	�oE�����UE��M�
��j�����'dD������W�_-��@�^�5�W��������W�����m����jqp����~
���'����k�����C�v�U�W�������
���O����i��e��o<fT�W��T�^�5�W�\0#���������������T#i����e�������Wn����~����{h������a�+��\.�h�]�<�_\D#y;�*����,�54��;�~7���ll����Z6��������Zp�����k����`F��^�_-�7���������g$��_C�D�_����O��~#�o$�����=#i��Z����K���C�M���������3������J��d����!�f��������p�����k��2�/Y@�(�wG��}�M��
w�H�K���_���d����1�"��}�M��
w�H�k���� ��4�~B��[�K������3������?]�e��<��-���z�_7|�z���a���\�G?�����K�RI������y���4����C~�+E����-�p������
�uB� =�>����g�OH�N��>o��'$��^C��N'f���{B�[��X/�	e��:�	I{��P���`�>N�'l���z�	���W���hB�^�5�y����O�	ps��S���[�/]&e�:LH�N�O��{���%$n�^e��./]�%]��KH�+>A�����4����coL��]�]Z2ty��`F�.�	po�+�J���~�]����4�{�������cH�2���,���J�^��2o��}%n�`C���	C��iOf��������&e���������<��y���i�{������nR�WkD��M�}��3,8"G�>M]_%��`7i��������gXpBN�����J�����n�6X85��'������5u���s�����v�������<��w���)�.xG�k[�1xob��O�a�9x'���
rpa���
rp�p���:��K��gu�u �����:���[��9��s��n�N���p��6Y'r���`gi�N�����������'�`�m�*rpms��4Y9��9x�6Y��7�J8�)��
wzH�F��&k�v���2k����
D��
V6Y.�����
M�����v��M���"q{+��
�zH�F��&k�0~p#�=fm��y��H�^��&k���Q����f�?�������f��W����p���mlh��e�����������W����p���mlh���a��x�Y�dm+�T��+X�dm��C�6
64Y�Z1d���m��m����=16�`\�!q��m;0d���m��,q{+��
w{H�k���dm9�l�X�M����`zdlD���C�6
64Y[D&+>u���#�`zdlD���C�6
�4Y	9���X�MVBN������z��(��de�`��cQ7Y98�G������-M��L�|,�&kG�	�#c#
��Q���*��d���n�
rp!L���(7|H�F��&� �=���:���`m��+>$n�`K�u �E���:�����&w|H�F��&�D&�>Vu�U��O�������q���mli�*r0Y������\	�#c
rpms�lh��,�;k��0K�^��&+�	�]��gC�p����m�������MVp'^�6��&+�C�9x�6Y�K�^��&+x�`��(��d��a�>��&+����W���
3p��mlh��\1d��Wm��&L���(x����
MVX���U�d�8X��
V6Ya����
MVXwI8X�d�
8X��
V6Ya���������h�����W1aN���2+l�������
���k��k�����C�7m��p  L����7"�&��}o�18�1x�Y!"G������z�c�_{��������k�����b#�M��	��=@�[oFN}��%VF���i��fD��D���o�8�xSWX;p&L����wG����k�{���>�n�� ���I��������^�[oA�-}�������[��sb#�=~��K��^�[���{��wS�Wr�A���Q���{�_����~O������:|O����"���o�[�|+!_uoU�|+#_moU�|k� �]�qZ�
��7h��8��C�v��G��q1��m�\0�����?�(h�����!q{�*����i$��_Cu�����DA[]Ew���WY]E\M#q�����+f�O�
��*�3���������n�{��P^�������A[^�������,�".����~
���~!c6o��Wqu*q{�*����i$��_C}����_f$+j����+�S���WY_E�M#q��������H6�m��7/!��H����W�H���
C�o$j�����e*�c����"n����~
���f$������@���������F�^���W	�������*!�&���\��~q/����k���/�N��UF�M������Z�{���_e�_��&����7��'�F��[i$��_K�#���4Q�_���;�_z4lD���F�^���W�������� ����l��~q'����k���_��&����� �K���W�H�k����D�%�i���:�O���t��~��6�Z����K��DuU�+�_z<lD���F�^��b�����K��Dm�&�_���W�_�	�W�^�5�Wi�������Jn�~�*����%��_C��������U�����/=6�_�+q�����w������������~��U��vM�}q������������J3������������5��������J�N���*-�������J������/������WBw���Wi����~��UZO�vM��
�U�f���������+q{�*����J�k���*������U
����/=6������k��R@�
}�M��*E��@���oD��M�],�UD�����UB�����UB�MM�],�UB�M���UB�M���UF�MM�],�UF��}�u,���3p&L���(xG�M^,�����M�kG�	�b#
.H�{��K�U��K������
"p!LO�
)�4x�TX"p�#�����|�G�F| M^,��|��M��D>	�3b#
>��&/��D>��&u�U��OB������+RpmS����H��O�n��Xy�;H%LO�
(8��{-�Pc��`F2�h��X��D��
V�X��H�K�����.cF2�h�Y��D��
VY��H�k��"+{����*�I�dew��+X�de\B#q���<����V�8m��g�����Rp���"U
64YyY0#����MV^��J�^��&+��{-��d��cF2��i����I�����MV�%4�Z�������4^�m��&U��
V6Y7�H�k��&+o'f$�x����a����2=-6�`�A#q������&�m�rD���q���{-��d���v�8u���#�`z^lD���F�^�4Y	9�m�q�&+!'�������q����Y������8u����3�`m���h$��`K��#��4N�d���;�`m���h$��`K�U���N�n�
rp�s��G�F��h$��`K�u ��4^�d��G��==26�`�H#q�[��9�����&�D>������J�{-��d���l1�W7Y9��s��G�F�;i$��`K�U���f�n�*rp�s��G��O���������'�`	�+X�d�p����l�v����9��d�8XB�
�6Y������M��*^�6���/��p��6Y������M����%���`h���cF���&k���%o�`e������Z�����	32�6Y�,y{+��}����
M�����p��m��u��	�#c#
^��%��`C���3��M��K�^��&k���%��`C��o3��M��K�^��&k3^�&C����@8x�6Y{@�����G�����`h���	��&k����p0=26�`�����`i�rp$<������#c#
N������&+#'���������p0=26�����li�v��L8xV7Y;r�N8�Q���798Z��9xg�n�
r��8X�d�����hi�
rpa�n����8X�d��G�����:�������:���������O�������d���'��E�d���'�`zdlD�9�lrp�4Y9�^�MVE������!#�&GC�U�
� ��E�d�	� ��W���*��F�^64Y�-���)Z�MVqp�����MV�E5�Z���*�cF2�h�6Y��D��
V6Y7�H�k��&�
�0#���h��2�I�����MV�U5�Z���*�����E�d��c��Q��Q0���������*K��d^��m��
&U��
V6Y��H�k��&��3�y����*+�T��+X�d�V#q�����<��v���&�l`R%o�`zdlD���F�^64Y%��f�6Y% ���������C�����*9�m�Y�MV����p0=26�`\X#q�[��������&+!'�������qc���li�2r0�[������	�#c#
��5�Z������lo��n�v��L8�Q0������-M�������&� ���������{-��d�`��fU7Y9��G�F�+k$��`7Y��A�-�Y�U�� |0�VY��F�6�tY'�0�\����I�d$���pi��m4l)�*�0[]�����(\	
�Sc#��5�����:&da��f��Y�,,y{
+��c����
u��&I`x��Y������u���%n�aC�u�C��}��=6Lh�������
����$8�i��{h��'�F4<K�F��F��3�$<�i�c���������x�:<l���xXR��VZ�<,y{
++�cux�:<l���xXR��vZ�
<,y{
+;�c�x��<����-�����:6�a��kX�i���m4l����1$�am�u���xX�iy8�y�:�#"��A�iy8���F4��c����������pPwZ	y8��F4���S�����J����pPwZy8�'�F4���s����������pPwZy8�G�F4�#�6;K��#���������w����������ag��
�p!<��VA.���!�_6��������?���V�m���������<\���������������I�r�����5��--��~���O��W���_�������?��W?|�����|���e��~�/�3^�������E�d|��a�|�x��?A�������/^s��s��
C"�d�D/�0��I�O��nC�x���'�W�o�"�dE/�0�q%��y�
W�(q
���_�<'���Lb��������5<\�a:�����6��U��tC���7�7��i��w�0��9/;m
��7�'I�j/�0�D$o����
��=��,�y4�*�0��!�^������6����p���@����6��U��,���8^�A<�k#y{
�o���yYk�hXU�a��!�^�����*y{
�o������6��U���z^���ox�|�x�W%o���� .�9/�m
:�s�z^���oX�i���F��VvZ'n�9/�m
:�3,�7��N���6������:q��yYm#�m6tZgD�l�y����:q����5���N�ms^v�<�tZ	y����}��N��H�^��N�����6��-�VB���y�pRwZ��F�v���F4��m��v�G��N+#_���oX�i�~��kX�i�z������������/[n�7���p����5���p��y�o�h��i������
�;-�p#y{
k;-\ps^�<�tZ��e��������������n�9/n~����z��R����x"_v��/Y]k����+Y[k������F��[�/�n���.�p������-�p��yYr�S���o��N���M7���VZu���~��V��%�����o�������Vu�e0�,�����~_{���_W0"Cam�����u��uV������k����3F���g�� ,y;������3^�&��Z��~g�`���W[e�0X���UVYuqx����K�{�]�%s�_m�U�`���WYd����ko'0�w]0b������
�+y{�*k���J����7���'m�U7`��+X�b�
X�6��dXp�0c����m�j@�����$��9 mY0"p�#���V���� 0=66���;��
������~RwX	8���F���S�u���J��A���J��A�������6��be���(X�be���(X�b�H���2�Rc���;�`���v���`0=26�`���}6��c���p�S�X9��'�F\��K��-E��\��DV��o����|�����w_��?���_��[����_?|����?|����=���o����7������?|����?�����������2��C�����2�����_}��_`��_���������_��og��"���`�S6{i�)����x��K�n-��?�^O�����H3lt�f/M0����S����C�q�����H3lt�f�-�	���,K��`����{-����e������N����)P0�����{���������[�
2�	��)���4
&��Y�ts�/^_�]ro�0���W���{��`2���MI��q����4���G�^��f�-�����,J��`����{-����	��?Bw
��f�-������I�����������F&���W6{iJ��dz�3k��-8!����8����r0�����4e�`2���-I�������_[ro�9����^�de�`2���%I��#�g��8����w�`2��{u��#�����H����������{.��dr���H�9�L�fE��#�&�8�������������9��s�3��-�@�L���-M��|����`u�u"�}~fA������a�R����������V7Y9��9���H�\��/���`K�U��/���m���\���z�[vp���lh��T0#��Y�d9,y;k�,���%��`C��\����gm��p����m������9��d9,�{k�,���%o�`m��f�����&�����W���r3p����m��\��59x14YnY0#��Y�d�8X�v
�6Yn����
M�[=f$<k�,�K�v�g�
�[�
,q��,�M��p��m��,y;k�,�K�k��&�m'f$<k�,<���g�
�[p@M^M����q���r98�9��eC���c��C��"rpd�n�"rp�s�3���-8!�&/�&+!'���h���rp�s�3���-8#�&/�&+#g���h���3rp�s�3��n.98�9��d����p0=Z>��9x�s�3���-xG��li�
r�N8�-RpA.���MVA.M^-M��\���C
>�����&�@>��Z��9� L��)�D>�����{>����deK�u"������!W������,����\��Z���\	���c
F�}~f����	o �������S�eF����`m��a6�#o�`m��a4�#��`C��]������6Y��?�v
�6Yf�?�^64Y����2��]��h���a:�#o�`m��a8�#��`C���3�m�}��&��x�G�N��&��t�G�k��&�/3�N}_����0����S����0���Z����K���S��m�<����m�<������,��u����M��������M��������
M��v�x�&��`m��a@�#o;�3+��-��?�^64Y> _���/X�d�������{��������&�G������k�,��c���Y2to�	9�2��q�����|����`u����S����2ts��������&�g����������������{��������&�����)��
�G���#�}~f�����������&�#_���/X�d������l����|���8jbXpA�L�_���:��K����2to�r���`K�u _���+X�d����`u�u"�M�&�D>	���c
F>	����|698X���\	���C
�������l���yB�M�&k���%t�`m�5O����S�����/^��������	���C
v����S����p���lh�f�0#�`m�5{�`��)X�d�8X�^64Y����q������sp�6Y�,q���y>0#�`z�|H�p����m��8X�^64Y��cF���h���W�`��)X�d�+p���lh��5aF���h�����%o�`m�5o/^��
M��K�^��&k���%o�`m�5�	/^������rp L��)8 ���&k�������d�98�G����c���zc���	��Re%�H@��-�pBN}v���JH��I���e%$�DH�.�pFN}v����������RfeD��PX]f������nR�Y;���d�hi�vd������*��{������
�pi�p��Ya�����4�0\�0�&u�u 
�&
GK�u 
����!
H�G����.�N������B�D>	��C>��>�I�h���g��-�VE>	�#�C���������������Pi-�����0=c>��e�����5���\^#y�
:��9���X��!�!
;��H�N�N�i-��F�^6tZ����?���S�C�36�������Zp}���6l��`���^O��ix�*y{
k;���H�k��Nk�w�����9�1
�T��������l$��aC��,0]s![l<=h>������5����`#y�
:�e���Yc��I�!
� U%o�am���
�{m��i-��\�O��ix�*y{
k;�w�H�k�#��2�t	���0���g���������o���y�_����?|�������/"����>~�w�x��������w�����|��#��G��~bb�J"��F�$\���_}�A~d>
�������'��������[p'�����J�%!\�� O�<��d��l�[h;�w�H�K�n��|��l���1
#[d�����H�F���oG� �A�o�!
��;a���p+��m4l)�
��
B
i� [�^���Z��h�R�d9�58���� l�������-%��pA���_�C>�]�I��yu���A$o�aK�W�eYB
i����J��yu���A$o�aK�W�e�B
�hx��+y����:K�F���o�I^�=q��������5���V<,y
\[��!���'����0����5���V��������Z=����4���V<,q{
������_���/����|���m���x����3���?���?�=������Io;��]���R������?��������~�������������������6���G1AP�*�$��(:U��!w���
�Q�t�����(��o�� y
��7�0$�b�z�@����<^�A����k~��9U��!�%u���v�+����5��|���	��&�x?31����������AA�I�����%������n	/��K
���8�b<|�/y
kZ�KH���;���������|�A��n	1^tx����u�����������p�/�K�^��-�%^��������M�
'����p�����|�_��n	/�P�%�~��1l8#$�s)�����3�q&o�����\F&���<�
����\
�58���x'o�������L�_�y,F4&�R���!
$��m��-�R$��a�)�.!����kpH��q��-6�-�R$o�aM�v	�<L���_�cF>/����)�����|��D&�R�����y�$<�?����@��m4l��*�09�2�;��<\	/�N�H�F��Nk�
"+9�B
�hx�"Y �m������A�yC���
������4�D6�AD�3��
���B�yC��������pH��Bd#+D>��Cdk�q��im�Dd#KD�%�0����h{�
��l�%"�:�
��ld���C�%"Y"�m������E�yC��������pH��Ed#[D��m<6\#�������im�Gd#{D�%�08���q����p����#�fC���"��,��pH��Gd#{D�2���l�E"n6tZn��&z	�4��D6�H���Nk�M"[{���
����D6�Jd�vZn��&oH��Idkoq����U"Y%��;-�$��M"4���q����$�fK���D6�J���0n��&����Idkoq����U"Y%��;-�$��M"4���w���&�_���5�Tr��2"�}$^��.��2oH��Ldk/y�a��~q��Fv���RW�ll��7�_\%��W���(}o��Id#�DVu���D6�H���/.���D^{���_�#��="����5"[#B���a��F����{��-"�"���,\"��%"4��~q���^"��C����	A��Y�eV��%n�_m]&a�{�����7�[1"�`m����2�VY�K�K�����_w`�>o�"+x�`����������~_{%|o�~��}���5V��%n�_m�f�_��wcX��0c�7m�f`��+X�b������0,x�����
VX��%n�`m��	/^�����
+ �������
,q��O�z����6,x�1c��7m�6``���|�7``�{-�Pb��0c�7m�Bp ��Cp@����+�����M�b��o���c�e�������`���J���`pP�����g�-=VBN���=VFN����CVF�m�Y98�98�����	���98�9��d���{�����!���;�����?�����/������\�L)� ��A�U(�����/�����9��9��R��|�����|49��i�|"}���|"����>���&�8�������>���C
���'�`��oP�69��Y�\��k�����G�p#q��q�Mlo�yqT��G\p����m�".��l�������&���8����q�M$�m������&��6��#�~���o����{��6���	�&+�z���������m�o�{}qN���0\3^6��|	������F�~)�#�N�x�i#����l�xYl��`m�q����R�&E\i/+m�;+�&+�3f�O���&+�B����_0C
��6���F
64Yqs��?�7j����H��_�S4n�����
MV�*f�����&+�&�^���q����lh�b@&�l����980V��6��Z����9�l���&+"G���O���F�^�4Y	9�,���&+!'����#n�����-MVF&{l�������q�����l$��`K��#�56Q�d���;�`������9��d�`��&����\��M*������&�@.}N�&�@>��,�^#y��9,M��Lv�$u�u"���*R0.�����-M��LV�$u�U��O��T�)w�H�k��&�"�
6I�dU��J8����	9�69x14Yi�����MV���%n�`m����������d%,�;k�����%n�`m����������J8XBw
�6Y�K�^��&+�/^��C���3�6Yi�����MV���%��`C���	k���K�^��&+-����Z���JK��d�+�7��u��k���K�k��*������r��]��[!#am��6 a�{ix5tYi�1#��:i���{B<����i8,x��(����C���m�~���#,Lu���#�ph��jh�RD�}v���Ja8��|H�	a86ax��Y	a8�a�M�>+!
'B�T��ii85ix��Yi8�i�M�B+#g����i8#�&��BkG�}v������w��T�ixG��<�Z�yxg<���
��Nx�:�!
������Ri���xX�i����0��C>���6[:�y� <�����<|0VwZ'����aK�u"������:��O���N�"�M�,�VE�������������j�
g\^#y�
:�<�p��V�8m��'��H�^��N+���{m��ie�`F2��i;���&"y{
k;��l$��aC�����dn��vZ��MD���vZW�H�k��N+�f$|����3HU��kX�ie�a#y�
:�<���L�u�N+/36�����6�0.�����
�V^
f$#|����+HU��kX�ie�b#y�
:��f�Hf�:m��W�����������F�^6tZy���-���N+o U%o�am��q����6l��r@f�l����y80�vZ�H�K���i��<���xm��#�p$<L����q����6l���0�g���VBN}���a�U6���������l��WwZy8��|H���F�^�tZy�m���NkG����6�0.�����-���<�V�xu�U��w��T�i��H�k��N� ��6^�i��Bx�j�!
�:�{m��i��l��WwZ��Ax�j�!
�>�{m��i���l��WwZ'��Ix�j�1
#�m�tZy������VE�����n�����
��>!��6����'�a��kX�i�����4
���&�Hxx�vZ������6������
���N�Hxx�vZ���a��T�i�K�k��Nk�3����>K�^��Nk���%��aC���3����>K�^��Nk_f�zM��Nk_��%t�am��/���������W�W�����i�+����5����xX���vZ�Z��5y8:�}[0#�am��o���������7�a�{m��i��cF���Nk����0��C������Nk�����������<k;�="�6[:��<	/�N+!G���N+!�&'K������E�ie��Dx�j�!
g�����d��2�p&<��;��<�	Sm>��y87y8Y:�yx'<��;�yx'<L���������d��
�p!<��;��<\Sm>�a�����d����BxxQwZ��Ax�j�!
��G�����:�������:��O��T�i�D>�<�,�VE>�;��<\	Sm>���<\�<�,�VE�����V��&R	Sm>���Kn$��aC�U�3�qF���*n"������*��F�^6tZ��H����N�x��H�^��N����{i�M�R���!�|�U[jw����z�!�������j��o��f��Ze�*y{k[���n$o�bC�U�Y���U[k�����U���
.�����
�VYIF���^�� V%o�bm�Up���mTl(���1$���j����Y������V�u7��Q���*a��d���m�J*������V�}7��Q���*��m�Y��V����`1��C*��7��Q���*����Y��VB.����>R1n�����-�VB.f{o6u�����bu��+o$o�bK�������M�ne����X�n���{��Y����m������\�.�}L���{�����*��l���n�
rq!\L���q���mTli��b��fS�[r�A��*�!�������n���l���n�N���p1U�C*��7��Q���:�����M�nU���p1U�C*��7��Q������d������1!W��T�������%o�bC�uLC2.��[�\,y{k����x��\������%u�bm�u8�b���X�n����p���:<p���T������%o�bm�u��W����v��I�8h��c.�������1K�k���n��������:�b����*�!/����Q���:�	C.�v�X��%o�bm�u�����Q���:�C.�v��<VL��*�!o����Q���:��!	m�u�b���X�n�8�����# ��A�n�8.�
}H��8�����#"G��A�nE��H��*�!'����boi�rqb\�n�rq"\L�����S���������q�������p1U�C*�������vkG.���������w���vkG.�;\li�
r�N���,RqA..����VA..m.�-�VA..�����:���b���T| m.�-���\|.��v�D.>S�>����ls�li�N���pqT�['r�I��*�!W������������pqT�[��.�
}D�'������
��9�x��l�qQ�n��G$o�bm�u�2�����n��s�d%���v�tp���������p$o�bC�u�C�g��m�N����X�n��G������~����WZ��[/��0g���	�����?>���x��w_��?���_��[��?������������^�������������?�����}���?Y?���#��66�&�_�����>��P�������c��������%���'>����.i��3��S`��>�3n�7��S�g����7�F�s�K�������K�'t���F|p����S�����~+F�C�K���L����'\���&|jJ���S�����~�������;3>0����gv���o������
�W��o�1b���K�����2�����~�/N3�)�K��o�w��E������;w�h.y;��'����g������7�[�]�d���n�
�3����#i�{Lx�p��O�^zY~s��(���~�����|�_=���~��&��6����O�����;��/	�O��	��
9����|2�>�vV$��'`u@���	��M8��_$�J^C�xC��p���N@�������:������Vu����O[aU,q�:��v�H�fO��:``���8���xM~m���{�`	�����z�`�������{�=^�&�6����g�`	�+X�b�(X�v�=q����	/^��_�krs�`�������,y;�`m�U�/^�
=V]g�H�dO���������u����
EV�f$�'m�U7�`�����A�{���%�� ����[�����EV
3��`uSYrphr�k�Ln.8 ���"�F��@8X�Ua�������M3����	;u���#�`�wI5!�&�6����rp"��MVBN�e�������S��_�drs�98v�&+#g����rG�M~m������;�`�n�v����V��#�����&� ������*�������� �&�6������B8�iR��|�9xVW�r���`K�u �����!���G���U��|�9��d���'�`z&fH�9��s��n�*rpmr�k�Kn.�"W���&�"�>��&+O�@j��_�]rk�o9���W���zK��;�#o�`e��'7������aX������#�3C
v�p����MV�����7�����`�AF����+���4;�q����M�[��o �{�a����6��`e��/A�3Na�9�3���-x>���(R����Q��/X�d��P������2�{^v�x�������u���S��l����P������*�{^\�E���aY��Q��/X�d�i������g��[���m(R�`;���`F2���qRppP������{+\��"U
�3Yo����`��uL�������,Q��������������q���zK����
�{N��������J���q���J������,P��`�������de��D8��qRpF�}~f}��g�������d����p0}�:��9x�s�3���-xG���X�����o\�\��K���Y�~o�9�49x�4Y9��o\�| �>?�8�����������:���������O�������M���9�lr�bi�N���p0}�:�`������,M����|�9��dU��J8��qRpE����M����k��
M����%t�`m��&�`��)X�d����kr�jh��[0#�`m��p��m�{f]��;�`�{-��d9�1#�`m��<p����m������
M��'�H8x�6Yn�����M����%��`C���3^�M�[f,����,J���8X�^64Yn)��p��m��
,y;k�,�K�k��&��3^�M�[��%o�`m���/^��WC��6�`	�+X�d�
8X�v
�6Y.8�xM^
M����p0=�8���������Fm64Y."�������#rp$�n�"rpls���J���p0=�8�����������Y������������j�{�������������q������s���Y�~o�;r������d���;�`znqH�9x�spP�*��������*���p0=�8�`��������u �&o�&�@>�s�C
>���>���9�hr�fi�N���p0=�8��9��spT�:���&o�&�"������!W��������U��k��7C���� �`znqD�~�;����������G�k��&�;���^m���A$o�`���V�<�^64Y�O���������"y;k�.�����Rp04Y���������<{,�?J3�����5����
M��f$�z���!/`R%o�`�_�����Z����K��d^/=�8�`0���S���hXY��{-��d�����lo
=�8��L����}�����G�k��&�odd{k���!o`R%o�`�V�<�^64Y>,���������C���_6���M����lo
=�8��������G�����`i�r0�[�n�rp�s������S��-MVBf{k���!g����`��
>#�6[�������s�C
���s���_6�9xorp�4Y;r0�[C�-�)9x�s������798Z���L��xznqH�9��9X�e��\�-M��L��xznqH�r���`��
r����hi�N�`����s�C
>��O�>X�d���g��������do���k�\��+y�n�*rpmrp44Y��L��x��fD��,y;k��y����
M�<����o�6Y��X0�`m�5;�`�{-��d��`F���}���=p����m�f,q����g�H8���S0p��m�K�&k�g�xm64Y�,�{k��y�����M��8�xMN�&k^��%t�`m�5/����S��S��T�xMN�&k^��8X�d�+p�������K�k��&k�<f$L��)x������6�`�{-��d�a�������!����`������ph�p2TYs@���!
G��a7�?fE$��$�d��"�p$$L��i8!	�>	�I�����S����J����0}e3�aD��Ga7i�2�3�pj�p��YY8��l�4���s������p��s�-u��0��/m�4�#�}v��K�yG��4l��
��Nh����pA.}v���(�����oO���������:���>�I����@|4���1�����`D���N$�����:���&�=�[V�H|$��n�T\�O���Z�"�&�=�V\��+ab��fD�����J��i{�7�H�F�#��2�t
��S�p��?�M�������������� o�����>~����}��w�}�����������?~����o��g>�?���#�����������eT�������4�i~�?���g��GR�F��ym���J����7T}���=a	��}6h*��kX��-�D�66T}�2c��D�'>�77��������M��KA$o�aC���C�G��',��
���$n�am���V��h�P�-k������	Ipo���
��:z�0�����
U���?�=��m8]H�N:���� ����34}K@� �A��po�$���5���� ������[b������	Cps���$n�am[��f��h���-	��/d?�����
'���������_p5��m4l����<L��'N���pF������_p7��m4lx|m������(3��yx'<��U���A$o�aK�U�����(3���<\�����H�F��N� �!�QfH��p!<<�{i\"y
[:�y�,	��2C>��������� ������:�����(3���<|���4.����-�VE&kB�������+��Y�i��pm��7tZ�<,����>��hx���%n�am���	/^�����Z����4���V<,q{
k;���x��<�
���g��a�(3�a<,q;
���C���������Zg�!�<Le�4<K�^����xX�66tZ�\1d��������f<����xX�66tZ�r`�>�G�!
��������^W�a��h��i���!�<Le�4�K�^��^z���%o�aC��n	C�y���0���������<^�:�5 ���Nk
����������<:<l����<	k;�5"G��t������c��gK����c�����!
'���xX���<��<<[:��<��<L
i8#g���o��<��<<[:��<��<L?$C���3�a��{H�;�������i���{����dH�yx'<���[*��������*������i�@.������<|�yx�tZ����az	�4�<|0V��'�������i���g���%���<|2V��y�D��W���Q�K%�[/cE$�}$�WqH���$^��tE$�M$~�a��~�i�+H�X[jm�D$�����[C$����������?f�VZ��[�������a��!����k����F���Y������!q{0���a��!����k��7�[1bX�����y�~�3����+C$�������w>0bT*��C�]@�J�^���r��!����k����w�1bP*��c��*q{�j��
�H�K������&ndi��C�]A�J�/EFo�/D�^�}�����n0�p#;C���U�����X�����,�����WpH�8^�-���B$o��J�G$`�2�^�!G$�HxU7�,D�6������z���C`u���B$o�M�e���da��C
����0���8pU���l)�2B0�B����w��L x�>Y����{-��b�H�d]��c
F
�	o��H�k��� �m!�
)� ������5!��Z���:����z�| ��7u��KB$��`K�u"�M!�
)�D>	o�"W�H�k��&�"�=!�
)�"W������!��z���d�	9�l	�WpD�a�����MV���%��`C����L������3�6Y�K�k��&+�3�6Y�K�^��&+x�`�{-��d�cF���&+x�`��)8h��0/x������{���%t��+8��8X��
�6Ya�x������{^��%t�`m��`��+X�d�u�����'u�[�
,�;k���K�^��&+�'^�&�8�����3�9�^�!o���W���
p���lh�Bp�����
)8 ��A�d���lh�B@}�WpH�98�&+D������t�[pD�}�WpH�	98�&+!�&�8����rp�s0��c
FN���MVFNM~qF��g��L8X�de���8X�d������/�����9x'�n�v���ppT7Y9xor��:�-� �>�+8���\Gu�U��K����&�@.}�WpH�r�A88���9�hr���9�-�D>�L����O���ppT7Y'r������d���g���RpE>	Gu�U��k��-MVE�}�WpD�q�H%�MV��5��Z����S���!E�
)��
D��
�6Y��H��tC�]���E�
�)n �W������F�^64Y��<�HV��+8�`7��+X�dE�]#y���8�8�H6��+8��D���R��#������
MV\����MV\@�J�/�):���{-��d��c�����m��
"U�~1O���F�^64Yq�0c\o�6Yq�*q���h�[#y�������?�7i��f,�?B��)��H�k��&+�`��&i�����`��h�Z#y���������n�"rpd��>8���{-��d%�`��&������g�!���{)x�4Y9�l�I�&+#g���pL����������������n�v���p0}R0n�����-MVA&{k���*���p0}R0.�����-M��L��$u�u ���3���q_���li��`������� |��C�}5������:����I�eU$���0}
�0.�����-]VEf+k&u�U�+Aa�8��4!
�&
��2+M�������J����5�m��sx��,lh�������uVr�������J���k����J~��d���������x�>i�
K�K����J���d���-��8,y{
k�4K�k��B+-f$[\'m���a��kX�h�xX�^64Zi91#�am��������C^��%��aC����k;��K�^��N+m��������J[�������J����5���R���5yx3tZ) ��N�i��<�<������#�ph��f��RD������Jy8�y���1
#�&o�N+!G��N�i%���xX�i%����aK�����a���2�pf<���2�pn�������3�a���v����0}���<�7y8X:�yx'<���VA�	��!
�����`��
�p!<�����<\��!
��G�����:�����N�@>��!
���G�����:��O���N�D>	��!
W�������iU��Jx��;��<\	��1
#�&C���
/!�a����7��kX�ie\d#y�
:���H�ym���D$o�am��q����6l�������/��N+{��H�^��N+�*�{m��i�y��d���vZy�*y{
k;���l$��aC���3�I�^�i��c����>i��H�K���i��`F2��k;���T������V�m6�������k��d���vZy�*y{
k;���l$��aC��7����R����RU���vZ��H�k��N+�����xm���p <L�4�<�<
�V���l�����rD��������q����6l���0�k3�;��<���!
�J�{m��ie�a��fVwZy8��C��6���������l�����v���xX�i�R�{m��i���l�����
���xX�i�V�{m��i�a��fVwZy���C��6���p�tZ�0[n3�;�y� <L�4�{m$��aK�u"��6���:��O���ApL���g��������l�����*�p%<L�4��m$��aC��O��l������	xX���vZ�<,y�
:��M�������v<,y{
k;��K�k��Nkw'f$<�h;��{l��0}������
���f$<�h;�}�������>K�k��Nk�3f$<�h;�}���������x��<l���xXB��vZ�<,y{
k;�}ux��<l���xXB��vZ�
<,y;
��1
W�zM~{<4�x[0$�E[j����U�-��
�X�6*6�Z{����m���D�G�!$��$b7j�="���Zk���� 1}RqD$�M$v�������1���J���01}RqB&NM&v���J��@��.�2Bq"PL��T��s��di�2Rq&T�����T�	���!�H��I�n�T[;b�N�xUW[;b�N��>
�� �M,v���*���p����
rqa\���
rq�p���:����U]n���bu�u .��['r�A�xU�['r�I��>
��D.>�\�,�VE.>	��v�"W���ipH������Y���\\	��v�Lx��������n�����
�V�Iv���v�8��H�^��v��������n�cH��f��[��}D��*��[��H�F��v���!�.�M�n����X�n\|#y��2�,�B���M�n�����U�m�
n�����
�VY`g!�o��m��~U��*��[W�H�F��v��3�$a7m�UV����W���*��F�6*6�[es�l����V���J�^��v��������n��bH�v��[%,Xq��O�C*��7��Z�7�[% �8oQ�+����p1}R1������
�V���d	����VB.����:�������n%�b��'+�\1rq"\�_1.�����-�VF.&kp��n�2rq&\��n�����-���\L����n�v���p1��1#�m.��v� �E8.����\\�g�������n��d��������?>������������������� o�������������P���?|�����o�����>~������������w�qL�dt\�1�����?<nL�������3L��$������;��!�o�]��}��g'���|Q�p��$y���;�?���3���=<;I�v�'#�Z��''I�(�P��b���mG���<�Xp�0�xqo�3<7I�k����;�C�Om�������$o;��U�-x��&I�(�P���!�g�]�}�o$o;�hqo�����%<
6�|�
�)%u�`m�w��.A���=��uo���k�oJ�c��J�^������M��m�{�����	��Gxl���_0�������;�����{�onQ8�Qx64|GD����;"�p$�,|�}��
G$��&��P�	I8������$������6��������W��_*��{�����n�2�pb3h�K�������=J��oF�������3������4�7i��'�{����w��Q�f���;�R�v�axo��k���[�A��.�
�p!�(T�Y�pi��k����{ 	�����:��2fG]f���G�_{����A�d ���N����l
��_��	�������|2V7Y1��7�����\�����[�='��@p�Y����;����9��C�^�}�m����	#�Oe����N���;n�������m���,����3�.i[���Xp���3��-���C�6��eX�/��"�%m�u�`Q%o�`��I�U�6N�<g��?�����:g0�����e����x�P�>��a�|�PB�
�vX�
U�v
�~�t�/��<5,x��J�^���\��J�N��o�����C�����of�C�%m�un Q%o�`��H�U�^6�Xg��������u������,
������� �{����q���:#rp�s�3{�-8"�6[����w�Y�1'�����g��[pBNm�4Y	98�o&O�&+#�>?���{������/�0��������'u����3�`u��#�&�8����w���|+yR7Y;r�N8X�d�����/�/����\���I�d�����gV�\0rpir���K�-�@.dR��n�������,���9�hr���K�-�D>���I�d���g���Yxo�'r������[pE>���I�dU�����g��[pE�M~ql��#W���&�N����������:K�k��&�N32�6Y�K�N��&�:�`�{-��dU�1#�`���1K�N��&��/^��
MV����W����8X�v
�6Yuvx������{���%t�`m�Ug�`��9�`F�Q�s����Gt����`F���{C^�%������$,y�
���z�HH�~uoH�+�����_1C^�%��aC�U�	3�_���(,y?�W���7`a�{m��f����������4fl���~����6�����[����
����vF�!"�Wy��\�,��4��,hS�H��������1�be�i��
l�`�M��<�#5a��S:�m8!'���.
g��D�~���{�H��I�O��qo�i836�Yi8�4�����T��s��GO�U���as�U���N��L�[��4\�4���V����p4�Y+�����#C�7�0��a��gm�+��h��6��M�a:~���
Yxk�����vd���p4�Y;����0���R��(�7Qx��Y��NP8���Q��Q�_u)�@>�$<y��I� $L��RpE>t��W]
���	��������0=	�K�'�p�A��^u)�D>�<y��9�$L���S0r��s0���P�6�r69x�SY/?=Q�5�V���zI��'�k^�`�g+��k^�^�3Y/3dd�5�,�.�
�I�t��K�0[��Z���z��@F�]�Y]
�+��4��S��O�x�"���m'�����Y]
3<�gi��/:�mxIs����J�~*k����z#=�K��
O�i����.
�p�k�K�����^�TaF���HO����<A��~�&�K��\�������z�T1�~fo��atix���~�&�K�0]�������z��cF���H����p��E?S�����a��y�{m�Og�DB&6����a����0�K�i85ix��Y/����M�'bti8#
g�+��{,�6\�s�gO�U���
!��pA.dY��Ynny�4yx�4Z+�0Y��{�]^��W�-���,�6�"�M�=���<L�k"=�K���F�%&�oZ����aO��#��HO�����<��<L���H�qxo��������M��bt)�@�u���_�����I����:����M��bt)�"
:
��7+�pm���)�*�0�1Za��0<��8<��k��O�u"�z*F��Od�Sg����a��&
/�:+��Z+�Zg�PX��g�������$���f�0aFB�T&t)8	K����X^�K�k��2+��	S���� ,y�3^by	,q�;��0��q���
#p��Ue1~B�%p�������X1#�`k����L�u)x����MV�v�H8���.�����?Dt�8X�^v4Ya^1#�`��,y�CDGXF�xMN�&+,��Z+��d�8X������^�&'G�rp"LUB��rp"l.:rpjrpr4Y!#'��T%t)8#g�������s�����*���p0U	]
.���p����/a��K�����Z���`�g�K�+r��s�l��+r�����i�V���p0�3���
9x%���9xC���<M���167Y;r��s�b��;r�����i�v���q������w��s>���6{��9� L��t)�@>t^�9�"m�4Y9��F�\������9W������i�N��J8���R��|�����?���&gG��� �`�g�G�q�O���q��K�����MV3��{���.����g�����{-��d�pbF���H��t)8NX�~����w/��D�^v4Y1�Q?�7�?#]
��J^���G\����D��y�{m�Qe�q��d���!���*U�*��]e�	�����UV�
f$;6��)T��U
�v�l^�^vTYqN�����K���T��U�>�v�l^�^vTY/_� #[����K��T��l�*#��������b1#����K�	A8� l~�aL��	��Qe�� �6l�%�RpF�:��j3�pn�p�TYA�L�Dz	�\����o��� \� \<UVA&6�^�.��E�d�*W������Se���d�&�K���
9x�98���
9xkrp�TYr0�����)9x�98���9xkrp�4Y;r0����v)xG�	���9xorp�4Yr0����v)�@>���9�hrp�4Y9�L�Dz	�\�������dU����`O�u"�	�H/a��O��S��ln�N������&�D&6�^��r��sp�6Y�,q/��Qe���!	�k��� ,y���U��%n�aG�5�
C���K�HX�*
[��1	K�F��2k�C���O����Wi�Zf�c���D�08��q��Z��6k��%������/^�������	`XRk
[��q��J��:k�*^�&���g���!	
�k���hX�*
[��q��������p�Zh����U�Z�8,q
;�q91$�ak�5�	�y�X���p�����JkL����0��]���I��b����<�vtZcF����5��pA�:s�U��K��C�5��\�i��%D.��������������?_������������{���o�������]~^�o���w����������$(�$?���t��o��������?}�M�V��������{�7�r+��K�
�bk�E��|;����Ex�<��h:d�]g�b��vd����������=po�����E1W|���F����D�CG������dq�07|����"x��dQu���{>,*s�w"X�m����D�8u���[��9	WX��	�@$n�`G�7
�����������U
��{��H�F��zo
pV�D6A�f���|�H\��v��4�s �������"V8�Q����.�6�D�j
[��	�@$o�aG�7�pZ�DVA�O����jJ�j
[��	A$�������4�R?5>����
O�������Y.�H�F��6k����C��6k��Q
��5l��&�����u�4�R?5Z��i�a���0X��	7A$o�aG�5-��OD��>kJ@�Wk�ZhM8
"y
;
�)!�i�h-���8�t����pD�6v4ZSF&� ��he���x�\i�,��m4���
�0��VA.������H�F��NkE&� ���Z��W����i�0��m4���6�a22�;�
yx#<��.�H�F��NkG&� ������w����i�4���6<z:�y����N�@�	s��� ������:���B�h��*��Ax8�;-����=�VE&!��������0}D�K��"y
{:�y�l���N�D>	�g{4<��g��GG�5���Zi��i������vZs���yxttZs��J��Nk��Wk��i����k������8bH��'k�5G�a��5l���<,y?�������k�O�<�z��9u$����<K\�d��`��G@b�{�c������=1��������%@L����@,y/�>�U��~�#�8<Y+�y��Z��Jk��%�����H����aD�'k�5��W��Zh����	��}����PX2+�Z��y��Z��:kN/^���}o�	A8� <Y��9!'��	�.�f����n��oF�:O�*k����`0}>�O�������������	����\����[�K���s����wE�-��5����2�5�X+����%����F^u��-���26�X���#�i�6$�M'���`�H�!`�d`��w$�]y@���x�x6WX;"�N�>���xW�;| :���@>���\�����`O�U���������@0},�K�'Bpm�
��X'R��S�ln�N���P0}*�O�H�g�f���Z�	/������Z���Z��k�m�{-��c-!bF�����c->@$�V���ZpD�^vYK0�~n�l-�� W+�Zd-�"y�;��%V������&kG,��I��R0�H����&kw����,�&k�@�J\�`k���.����h��i���8�bm��	D��U
��v)gA$��`G���p��B�Ak��� R%�V���ZpD�^v4Y��k.dd�6Y�"U�j[��GA$��`G���;��������Zrp"L��R0n�H�k��&k���dd�6YKF������]
�I�{-��d�`������\����� ��Z���*����_67Y+rp!L�R����9��d���+�`s��!�����]
����6{��
9x#ln�6���q�����{}g��d���d�&���9xgln�p�F�^�4Yr0��I�&�@>�g��|49��3:�-�"��dn�*rp%L�	�R0.�H�k��&�D&;6��d���'�`�L`��q�F�^v4Yi@&;6��d�8X�j[��4K�k��&+
3���MV
#���MV
����Z���Ja��:'k��"p���
�6Y)K�k��&+�3���MV���W+��d�q����`G��F�`	�lm��,q���MV�^�6;��4Kh�`k��&�`��lm��t��kr��h��<aF�����J3p���
�6Yi����MVZ"f�98[���K\�`�L`���`�{-��d�4`F�����J	98��v)8!�&O�&+%���sp�6Y)#'�����.g�������de���sp67Y98��v)� �&O�&� �����*���p0}&�K�+rpir��i�V��U��ln�V���p0}&�K�r������dm�������dm���`�L`�����6{��9x#ln�v���p0}&�K�;r���`O�u ����M��|067Yr������dU��C��bn�*rpeln�*rpmr��i�*rp�9����9���v)�D>�<{��9��9�X��<��I8�>�����5��Z�������������>@$�V�����W#y�;��V��TT�MV�"q���MV���{-��d��if2ZS�MV��"q���MV���{-��d����d��X��<�H��Z��&+�V����h��4aF���bm��"U�j[���c5��Z����s�������d�D���
�6Y�j$��`G���3��k���W+��de������G�������,^��S����4}(�K�8X#y�
;�����l�`��rFN���S�]���{m��e��$��ks���3Aa�X`��q�F�^��YQ�M��6� �����.
�l���6�i�Vda6^3���ax%0L��0������Sgm�l�f0�Y��Fh�>��a�����=}��4��ks��#�����]���{m�Sh��l�f07Z��Ax�>��a������=���<�ls�U�������.
�v���6���*�0[�����<\�;-��������:����M0wZ'���x��i�y�l�prtZe��Z��N����W�G���px��<��V	��Zk��i�<,y����V	'^�&'G�U��	k�U"�����vZ%K�k��N��3�N�����Wk��i�xX�^vtZe0#��`���<,y����V���%��aG�U��	k�U��
�	vix�����V�w�Hx8X;��K^�ak�U�a�{m��i�e������VY��%�����*i����aG�U�pb<l��JBN����V��������i��<�	Gk�U2�pf<l��2�pn�p�tZy8��N� ��#}P�K�y�4y8{:�y���NkE^u��A�.
���k��������W����im������>(���
yxk�p�tZ��Fx8�;�yx�y8��4�#�M��NkG�	Gs�u �:G��`���������i����h����C��H��pE>�<�=�VE���������U��Ho}ui�D�m�tZ'���x��i�����������0����aG��3^B���Nk�CD�j
[�-������4\��F�H�1����CD�j
[�yXq�F�^vtZk���c4Z;�5��������������6����xbFr��h���q����6#Un]�M�{m��i���������Z'���Wk������6������Z�
3�#}Gk��� U%����w�Wm$��aG���3�3}Gk��� U%����wi������������+������T��Z����q�F�^vtZk^���h����<�S���a����aG��f�a6o3Z;�5#g��T�ui�m$��aO�U�����h��
�p!<L�[��q�F�^���*�l�f2�Z+q!@L�[��q�F�6*��Z+1�������D�"���K���$�0xj�
�x#H<�k��x#HL�[��q�F�6*��Z;21�������L�&���K�8q#y{����-�L�b�@(>S���b�����=�VE*f[7����H��P1o}*F*�M*���:����d��N���`15o]*�������mmr1������6K^�bk��
����Q�����C2.��[[��b���rk����Q������![��-K^�bk��E�b�{�88��-n�p�lm���X�*S�����X�6*v�[�X0$����nm#p���*��[�����88��m.��Z��vk���%�V������^������f�bI�Ulm���X�j[��m�x��\�����p�lm���X�j[��m.��������$\<[��-!'��T�u�8!�6G��%��D�x��[[F.N��)�u�8#�6O����3����n��L��2]��rqQ���n������n����p1e�.�������vkE.^����x%\L��K�r�����i�6���p�bn�6���p1e�.���[��������w��������w�����T�\���8z���x'\������ \L��K�r�����i�*r�A�x1�[��.6_�*rqmsq��[��.^����\\	�o�o'r�����i�N���p�bm��?GN�����;n�H�F��vkIN�]����sD�j[��qG�6*v�[{�0$9�w��[{����Ul��z������n�����bm���#�W�����38��Q����G8�sgc8����G����?���;8��Z��h��	����N��[�~U���|��qG�6*v�[�<bH2�����>�_���1��q	G�6*v�[�0$��I�vk_��J^��l}3q�)�����n���!� ���*�q�����K#V�������_��o_���|	������������{�K�?����������.?/���w����������_�_Rnmc�oF��k���7������������_������>����3�
R�C(�u�km��N�~��n����=
o��i��NN��l�bH�u������:m�]�G�����9������^�
�;���O
i]>�����4z���{>����_�~���~�����{���9�;��bZ�������6z���{K�����3�%�c��If�_s�W��B��=rR����x?����_�=��{����Y��\��x7���|�������	'�L�%�s_�o��&�����{�{p+A�j
���c�;	���s_���7D�����Z�hY�j����(,q/�>�%��~��	gk�wDa������ ���%����n���o������k�8b�:?r<���������s����w�1"��l-��	 X�*�Z��c���~��Q~o���	�fk�uL���W��Zc�����Oqro�3���
��X�,y���-���xM~���{^��%�V���: `��lm������$�'�7���4aF���
�H��IG�G�����������&����c`k�udd��3�#B�[pF������ g��\b���C�#�A�[pA.����� B���b�H�E��G�����)xm���X+b�J0��k�
1x%l�)7�����Ojro�r�F8��{�
9x#l�)w������"kG�	s��#�:��} �m�4Yr�A8����9��9��s>o.9�hr�����[pE>s�U��������yo�9�69���L�-�D������:��Or/��������D>� ��Y&�6\���������|�H^�a�z�!�������a������X���3D�j
[��X|�H�k��2������,^��c���w���>D$��aG�U���������#�T��5l}�c��J�k��:��+f$/'�:���S%������u���N}}����	����Z��>�N�S%����ux����>������Hh�ak�Ug��Wk����|��C�����c���Q�~�����U��5lNKU�{}y�Qi�1#9�k�VZ5!'�����.
'�����'�0����<��y]����y8�GDwi8#�&?y���
#g���N� g�����.
�����'0����<\�;�y��<��j��7��8�6q���:�-xE^	s��"�:���.oH�k���<����7����p07Z�����#7��-xG��0��Y��#�������w���ts���{��GO�u ������:������to����FaO�U����\gUD����#w��-�"	�6	{��I��6�D>u~������g�'O�u"�����:�S�G�)�Z�9K�k��.�v�H88X��3K^�`�WI�,q�;��3���q���:p��U
�~���#^�&O�&����Z+��d�8X�*[��sx��<9��s��J���d�#p��U
�6Y�x��kr��h��i�������]
���%�R���:'�`�{-��d�s�������]
���%�R���:g�`�{-��d���	��{��K^�`k�u.���Z���:��	�C{��"�s�#w��-8!�6;��3!'�����.g���s�#7��-8#�&��&�����p0=��O���Y�`:������<{���\�s{�\�����t�K�+rpir��i�V���q���Z��W���t�����&��&kC^���
9x�9�NAw)xC��<{��9x#L���R����L����#�M�=M����g�v)�@>t�3�]
>���&��&�@>��{�\�����&�"�&��&�"W�����.����p���:���6{��9�$L��S0r�I^~��|�ap�F�^�SY/?=\�5�����zI��G�k^�4c���]��R����^2&��l���]
;�s5�#���?��^�������z�8CF6aC����p\��H�4vY/a*^<�y����#f$S��t�.�
��5�#2��?�0`���������)`F6�j,�^�-�������=&l^�^��Y/�N��v\�m�>�6�����0l����6���^"��,��^�4�Dhx����t��K�0b�������z��aF��JOx��p��E?[3�A�.
���k�k�~B�%�0������zI�4�t�t��K�q8�q��h�dD&[6q26Z/i�3�a�F����8��8�i�
�0���8�.
����p�{�}F.MN�JkE&k6������yx%<L��4�"�MN�JkC&s6���.
o���a�I���
yxk�p�tZ�0���'�wixG��U�.
���{����������
?i�K���Nx���wi�@>�<�<���<Lm�I�]����a�L����<\�<�<�VE&�6���>
#W��t��K�'�pm�p�tZ'�0����bti�D>	���
�y�l�prtZa��Z��N+����?�	�0T�xmvTZ!����0=���s�~+��L<�a�+���������������������O����������o�������]�����?~|����~��G���_����G��g~��)l��Mr�>)�O�|S�}�[������������������*5`�g�8����Y"]��������$���{�x����/���������|����x��P��sm��U�Z��)`F6�d-C��UI�����
�����}�������o[����������U���U���}����N��
/�S^�X�n�7�����������������_��W����}���_���o?��y��Y (~�J�oX�TVB�������_Vb<�����5}
��Gq���7$��aSY	K����=��K�n8H^�������7$��aSY�O�Hn8�cO�4�N�0����atix���������f$7��']������~@e���7$��aSY��7r��>�����x#���E�.
�p�A�^6����x'7��@}F.���h�M�.
�^��C6����� 7��"]>���C�obti�x��7��y�����p�g�ti�"Wr������a�����b�� ��<\	��O�4|"�����]>���&S��i�8�\=	��Oz4���Z��5���;	�y�
;:�f$v����"�Wk��iEJx�{m��i�pbFv:����q������e��������V�f������i������[;�S	�y�
;:�8n�Q?'2&k�G���Wk��iE�Jx�{m��i��@F2�����HU��5l��"�%���6����� #YL���wix�*y�S�-EXKx�{m��i��5�d2��[��������[;�s	�y�
;:��?���<lD����pBN��Y'����<��<G�31YM�/�w�8#g�����[qF �M ����H�d7��]����D�	?�Pzo���4�8�Z� ���z}��WD�B�����{+^��&���k���d;��_��bd��0�������&���_�B1YO�/�w�xC(�?�Szo�;B����0x�����'�7��T�#�����H�{�������b���_��R��X|,~d������&���mU�b������RqE.���������*\�)�N�b�����:��O���r�D.>.��['r1�Q��(��x��O���,��Z�8K�k���n���!	���T��%�V���p��mT�h���aH���.�5�)�V���x�����s~��~~���s~������'Z;���*��tkau�+ry���s>���s��cQ�sC~G�?�Fp<'I�"��Ox�J�j�Y��x����\���N�ARk[�	� L�/Wl}�}�y������bG#8�I�T\����_����+�6�S�O������bG#8�I�Ulm�8a��
�G_��8����mT��N�/�p?w
���������N��gA���~�y ��^��=�,�����t������_����z�/x]~�'p��;�~����4������3��H���������g�a:P��?���i��5�w|��ulx)��?%�
/` %���Z�NK���|�1GA:�C�/<����
'�����1����/R�/���2�E����O������}
�K��"��":��)#^d/������E&tA_��p�o��M���M������{^����5l-��������=E��aHr�����7x(G�j
�{�
������==�V0$9��G�nnyx#��<2�xo�;��������v���
�[7�#����O������������@>��u���Ax�����F>�<=�VE>����
W��Jx����{���U�aO�u"Wv�u�'���x��i�������N�D>��6k�5��'�a�3��xX�^��<������������y�xX�6vtZs�0$�ak�5G�a��5l���<,y
;:�9����p�O���Wk��i�c�������i�#���V�vZ�<,q�����<
x��<<::�y��J��Nk���%����������������C�<L_���<,q����\�g�a��h��i�K��:�C��4�K\����i-�����x���_���T�������:��(���&,� 1}��K�	�85���/�������t��K��8 6?�x���	��}�����8�u�o{w�� g����W��8\�8���{�-������*�����q���0\�0����{�]�W���:kE^	
�/Y���D���D���� �� L��w�wC����
AxkO�;��#o:�{6]���w�����wG��3�������2��{ ������|4o
?wK��~��)�t��"���������}K��;��\����@�|"W������D>�w�=
��|�L�G����'!�bm��>@$o�����a���!?tp�O��"q�����Z���}����Z}+������D�j��X?����}����Z"|+����%��D�j[?���^�����k��[	�lm�����
��X�X���O�u�X�4bF��[:����	$���
��X�U�^v�X�0�~�-�Z�R�U�j[{�e�*y�;��e>1�~�-Z�R�2b�����Zd-xT�{-��d-����n��J��p���
�6YKBNM~���{N��I����d-	98�k��d�����'�������u�+]
����q���*�����O��qo�9��<����\���9�49���:�-xE^u��*]
^��W����d���k���<����7���p������7����dm��[���<����w���p������w����d���{���<������w����J�����pp07Yr����'����9��9���t)�"������������&�"W��s�U��+�`z�q��qD�^�4Y'r0��� ]
>��O������9�lr���t�Zp��%�R���Jp���
�6Y)x����!���%�R���J8X�j[��*^�&?yF���3�L�A���%�V���J8X�^v4Yi�Q�`�����8X�*�s��<K�k��&+�'f$lm��4b������]
���%��`G���3�6Yi��Z��&+�����Z���J��uN�&+���W+��d�e�������d�8XB+[���K\�`k��R����`G��rp�9�`t)8!'�����.g����`G��2rp�9��_t)8#g���1�]0rpnr��i�
rp�9��_t)� �����.�������d���E�`�~���9xeln�V��������Z��W��������W���&kC��<y��
9x�9�n_t)xG������#�M�<M���67Y;r�N8�v���9xor��i����p���:�������.W�����������U��ln�*rp%L�:�R��\�<y��9��9��^t)�D>	�����|�9��d�a�K�s0���Qp�D�j[����5��Z����!bF��"�z��� W+��de������gG���������E��#|�H\�`k��q�F�^v4Y9V����K7/�<�X0�W�w)k$��`G���3������.O R%�V����8X#y�;��<��Q?�7[��<�H��J��3��j$��`G��g8O3���v���D���
�6Y�j$��`G��8O3���lm��"U�j[���S5��Z����i�������d������d������MV���d��X�����3�`����c5��Z���*��d��.^t)� ����+�j$��`O�U���f
���R��\�����s5��R��i�V�`2ZC7/��!����i�]
���{-��dm��d���^�)9xcln�p�F�^�4Y;r0����]
���w���&k$��`O�u ���z���9� LO;�S0r������dU�`2\CW/�\��+�`z�q��q�F�^�4Y'r0���]
>��O�����.�d����h�����k��E��� ,y���UV�%��aG�U���x+����p�aB����.
 a�{m��e��cF2�J�/�4�%�����*PX�^v�Y%�������>
K^�ak�U��^�����*#������Ye��Z��:�L�^����*������Ye��Z��>�L'^�&
'G�U�	3�W:~���pX�j
[�2K�k��B�,3�W�~���xX�*
�S��4�K�k��F��32�VZ%!'�����.
'��������JBN����V�����0=������}�������o[��������C��������__�����������B��0�nN�;�0�������������_��W����}���_���o?������?�Q�N����ES��q�O�t���E��d\�c'���?�����:!q���7��`\�S'B��� ��`\�c'��]
^��	�{-�T�aF��U?u"���.o���~��}��:!q���7��X���N����`��M?v��+���}���<u"��7��T���N������x������t)��x���NdS������@�:�| ���]�.�/^���l��0#2q�O�t��K�����N�wE�\��5O����
2���U?u"���.����~�"}W�K�'r����l*�>���UO������O�����(x����c�
���3�J�:��;6����R0�����W~�,�bF"U�RG��q�F�~��"]
����c��o��3�g��RG��q�F�~��]
����c��o��+f$����>�I��_�*A��q�f������c�<a�^�l>.��d��c#y��U�.���z��y�7��gx�h���|\���Zq�F�~��}
>��5�/*�&k]&�H�/�K]
���%�ti�l����+�96�"f$����.
������W	�4�K6�e�����H��9���vY+.�H���?�8e�^�l^��aD�����
��,�����1�q�f�l������pA��|�����-��%�ui�l����+�;6�"_m>��t��O�����u�.
���zY�y�t��7������
��,\���_�:P��q�f����r�c�;��e��������H�/y�O����=�WPwl�@���|�����=��%�uim�����o��W������;-\���_�>P��q�f�L�|���X��D|���bs���6��?�O1����Q���=+F$�L�|\����D��!����m$������6��01]��Rq&���1`b����Qlma�������%�������8��kB��W}��#P���*�6[[*��_��f����W�I�/�+�%�r
�~G��G�b��%�D�������������	C.�]*���%���3���	�X�6*v�[�1$�b������X�~�[s]*���%o�bG��-�$\LW<�T�K�/y��K�p���V���TI���xt�8�X1�b���rqjsqp�[[B.N����G��3rq"\l�uF.�m.�vk����p1���S1rq&\L_p�RqA.�m.�v� ��t��K���.�o�v�xE..m.�vkE.^����xe\l.0W�������nm��+�bs��!o�����\���8x���x#\L7=�T�#������\���8x���x'\LW=�T| �����]*>����=���\|.��]*����b�.l��+rqU���nU��J��{t��D.������]*>���6GO�u"�����G����O���}���|#y;��}�38�����[���o$�����b���/�7�~q�8�)��e��������7��K���R1n������8V������q��vk����%/��������#�~q�x�0�~�o��]*����S1�������8V<E�����G��q�F�~���]*����2������y���i���{t��o$��<���b���/�7�����bH���@>�T�8��K�/�R1������;V��R?�7���.�������T�8�e��{��'�����[��'p$��`��b���/8^�w�8#g������3rq&\LO0�R1.�H�F��v� ��������\\�#�T�\\�\<z����,����n���+�bz�A��q�F�6*��[r1��	������7����!p�F�6*��[;r1Y�	������w����p$o�bO��#�������x������'p$n�aO�u �!����VE,>�3�T�#8���x���_���T���������d��*�q%dL�q��2.�H�����Q�[��\L�pB2�['r����Z}r������O�Z�1Kf�`k�u@���K���S��W�I��}����0aD����l�X�~�{�]
����R�s���-8F�H�8Y{�#K�/y��K��X�^
~�����F$<����1K�/y��K�#������]�����p�vZ��`r���h���	pX�^
~���O;Fd0lm��`X�~�kV]
��%������[��bD���>����%���d���e����C��
�{^�%�r	���:a��%�Xui8�z���.�HH���p�vYGBN���+V}FN�s��
gD�DP8[��##
g�����.
gD���vl� g����fd�BX��}����,\�w�=u��0\gs��"����7]^����aO��"
���������WF���7���}s�Shm����l.�v�����������#��FkG�	gs��#�����7]>���6{*�y�`<l������0}��K�y�h�����������������0}��O������O�qo�'�p%<\����<|���ti�D>�<����6\�/!��b���"��K����p��{m��i�0#9��X;��CD�~�K7]��{m��i�pbFr�Q�vZ5N�09���s��a�������V�f$�k�UG����K^���0N�H�k��N��f$��k�U'����K����0.�H�k��N�N3��~�;#}�*y����.
����6����qV��S��V�A�J�/y��K��#y�
;:���9����k�U����K^���p���RUvtZ5�����[��VM����0}��K��~#y���8:�����Nd��4���3�a��M��q�F�^�tZy�,����i��Lx��o��a������=�VA&8q0wZ+�p!<L_���0N�H�k��NkE&�7q0wZ��Jx��q��a\�����=���<L�o�`��6����0}��K�8|#y�
{:�y������i���;�as���7������:����M����<|0�oy�h�����*�0�����������������{m��i���d�&�N�D>�7��7������:����M���9 �����s=>�a�{=���i���	k�u�a��%/�ui8K�k��N�f$<�����%���8���<,y�
;:�3�Hx8X;�3K�/yq�K�c�������i�#�����vZ�<,y����.
O^�&O�N����%�����:'�a��%�U�i���k������y�������:g�a��%�Fvix��������Hx8X;�s��_�ZU���a�{m��i���	k�u�	&<L_���pBNmvtZgBN���������a��
4��Oy��/�������-�o����<����������������
/�S^��n�7����8,������������_��W����}���_���o?������g?�#��($��G�T�A��d���(b�/�0�q���xd���~F!i/����
3"�0�_6��wE..�a�LQ���
GQH�k���
3"��Q1�ooC*^��(�����
����~M�fD&���(b���02��D��
����#^��1��t��H��~E����C"��c(��2���#��kB1�*7��<|��P��_�a<��C?���}�{�=��5���M�d�H��~E����C��O��� ���
I�������iP|E�_M� fD*&����b<d�S�A<= ������,��Z�O2����1�H��;�������J�(��}����k�k��N2���kh���N�e����<2ctk�0r������h���r�Z���h�x�KVnY1��_��yM{�w1m�Fn^C+����.����k^����
��v����T�a���H���]������J��E�Kp��7��h��;f$"�n�w�&n^�*�vmn�k��YLEf\1#��VR�~+�Kn� ��_��yM{��T�a���M������6�y�~��6�6�i����6��@F�n���.�&�_�n������"���m?u��l�Dz+�K���l�<�0wk����l�x����K�m"�������K�m���������Y<����Kvm"���������<2/wk�+�o{�f��W+�/Y��t��K��/Y�yd\��~7����M��W�/����M�~w�_�i3[�����h�<����Km"�C��_�_�h��t������=�����_�g��.���d�����[�����5����*�/Y���M�~+�/Y�yd6��~��[6��_���d�&�;4]�=����l��N����Mr�Wa@�%K6�����o�%�����
��������B0#�_z��K��W���=2xk��W�^�u�W!T�H������o���������o����~�U�;fd�k����+y�~��U�%��_G�32���Wa���J���*L#^�&�fG���'���M�~'�_���k�����5�7;��0�Jh�_kf�_���k���|��k�ov�Wa�0#�_z��K����U�5�Wa����~�UH3��wh��������L��oB�MM����*d��D����y��y���?>�7������_��{����%�����o~z���7?����V��}����y���?��?~|����~��X��_�����I�����x ���i������k]��=���=��'"V�]�
]�D8�Xd��<EzO���x��J^�o<c���]�4��h��9C����H�iu������x��)��o�k�<K1;���_Ck�Z���_�*����_�^�u4~#,������6~#,���U�56~#�������h�F��
��km�F�����kl�FX�M{��8�V�_C+��{Z]������J���o������~�������~������y�~������i��:��_Ck�Z��_�*����_�^�u4~#�������6~#����U�56~#�������h�FX�
��k���k��y�~��Xak�5��_G5���kh�_k5&�_�5������&����|q�WcF�eK���V�~3�/Y�dv��~3�o{g�x�����v��=�.��_�3����������|��W����/��jE�%+��L���������/��jE�e��M�~7�_�1������n�����0x
�
�M��[4}
F&�����Z������������<�G���	�,�?2�uk���$�0x*��
���4]
>����#{z�����������l_����RpE&����aUd���|<%������m�.���T�G��n-�Dn�����b�H�l]����Q�4�'9�;[�i��I�(�QcMx����
��XS�O������Z��������=���{Kj�`k�5E�������%�Zp��I�(�QdMx����
�YS�O����]�E�4Nx�����`G�5����Z+��dM#����]�M�4E�v�Q���h�&<�[R+��5]
���N�l�bl��y�k���`G�5�	��Z+��dM3����]�M�4W�v�Q_v4Y�-����M���I������dMxTI�(��dMx����
�6YS������dM	98�988��	���Z��&k����|�bl�����M���|Kj�`s�U������d������i���oI�ln�
r09�;�����A��A8x�,<�[Rk
���A���k��!	�
	{�,<�[Rk
���
I���k��#
o

{�,<�[Rk
���Q���k��#�m��6����J���M��dar�w�u��0|�a8z�,<�[Rk
����0L������H��M������_.�4~�"
�_iX���V;���;������?~�q8�K���OL��I����r��zz������(��|z�����L�������8�-q?���o�S�g2�>��	}4��L�O����q�[�6
v4|3�<����y=ps��b&(�����8�-q;��Q��Hw������b&'(�������-q;�R��Jw�����	�b&G(�`,�f�������')�d����a7<W���������Q�����(���t�����/#��d�X��8�-q;���R��Pw�����7�fr�r�vo��n�{-xt�{3�<�����]�.9������q�[�6
v�{sF&S�����\pF���)��(W�%n�`�g���L����t����\SL�Q0�tK�F��&kE&c��p�.���+�`��]
F^�<z��
9��uGs��!o���MuK�F��&kG&s���d���;�`k��K��Q�������^w47Yr�N8�bz��q�[�~��7_�������8�{��fw4�YQ� (LI�G�8�-q/���}o�A�Lv��*�"W���{��k��R�s_����D&�����:�O����;����������W�[�}��~q!����Z����Z��k���{���/����������k	��!q�z�%����R�s_���7NQ?�e�VXK�����k�������z��
|o�c��������ZF��W��X`-8�!q/�>w��z�#�G����j���J\�^c}���������-����Q?�t��W�<b�����by�zq�C�6��q�w�1�~��h������U��\��_����W��]V��{:Z{�es*q�~���������c�	��,L��jI����/%������m�\p�7#������\-�7��h��_d��d�'O*�����K�?&suU~�_��=����{���]�H�d�c2wW+��J���y�~q�C�^���W�/Y����������t��_�����~=����K�?&s{�#�n�)���'?$��_O}�#�����\_��;�_k}�������:����d������������{}n��_U�_��1�����[	�R<��/�}H�k����D�%����:�O�������{6����In�7
��d�c��Wi���Z���*
�������J!bF�gk������5�W)�J�k���*�3��;[���%�����J�W�^�u�W)V����l���8b��)���w����~�Uw����l����+q�~��U��%��_G��3��;[��4�J\�_c���]��U��%�����J3�����5�Wi	x��������+��~��UZ�%�����J������O��qo�i�����UJ����/���&�����'��������Z����3�_��=�������O��qo��7��������[�R<��oA�-M�}�����E�-:�.��jE�-�)���wE�]��������"��:�.��jC�]	�R<������5����7��wC��t�]��������x����wk���go�������������w'�K��G��������_��������:��������{����_U��C����_U������_U����_Ou"�V�su"��������{6�wr�Wy�x	�Z��<����U��x���<���������r0�~��b��r�O���k��2��H�k���*���������1b�d#��y�~q�F�^�u�W9��Q?�7Y��<�=��Z���*����������bF��d����T�j����4����������M��Wy{*q�~��U��{���_����d�&Y��<�=��Z���*����������2aF���d����T�j�����3������)bF���d��rB�M���U���{���_���K6h�����73�5�W�g$�����_e�_2A���UA���)����g$��_OU��M2�W+�o!�K��G�8=#q��z�����ds�"���)����g$��_O�!����l��6����/������������v�_2?���������x��_��������:���L6�W��A���y�~qsF�^���W��,�dsU�+�_��=����{���_���dz&�����$�K��G��:#q��z����l�dkU�������*����������cF����*�W�j����%�����_��bF������_���K��G�q�k�����_��+��~��U���W���_�1��k�������+��W�X��2�J\�_cU��]�GU�	3��[��U��%�����*���������1�����_��W�j���2�J�k����,f���X����J\�_cU�_�{���_��bF����*)b��)���7!��&�.���$����o��W%#�&���{���s��U���Y��b��2�of�k��
�on����*��E��b��
�oa�k��V��������V�������Z�W��������6�7y��
�w%�k��6����/���n��[������7�����x'L��G�;����)��]�0��	� L�G���$��i�$�C'�0�+��|������\��<VE�:���a����00E����g�����:��O���`.�N���@0e��8@#q�;J�u��2W6C3X[�u�O��ll�V\�����-��������k
�	"y���5��4�Z���Z#���!���c�>A$�V���Zq�F�^
��kG�HN��E�:�F���x�bz��q�F�^vY�0#9�w�6Y�U�j��Wh$��`G��N'f$g�k�����)��(gh$��`G���f$��k��.`R%�V���Zq�F�^v4Y��aFro�6Yk�*y���M��C4�Z���Zr0��	�&kM��I��H1�G��D#q�;��5#�=�`m����u��{�S4�Z���*��l�&����\t����\��i�V�`�H�M���2�6Y8F#q�{��
9�M�s��!o���M��H�K���dm��l�&���9x#L1�G�8G#q�{��9���s�u ���)��(�h$��`O�u �U�hn�*r�A8�bz��q�F�^�4Y9���Ds�U��+�`��=
�E�{-��d���l�&���9�$L1�C���|69�8��m��Z��&k��%�V�����������dma��������p���
66Y[����M�f$�M���%�V����"p����h��xbF����dm��366Y�,q�;��m<0#��hm��	8X�j��m���������i����U�6K^�a��=��%n�aG���C2�vY�$,y���]��D�xM����@aI�4<Z��m��Z��2kK^�&
���fm	Y8�m����aa��]FNM����2�p"0<Z��-#g���{4��s�����
�p&4<����4\
SX��pA.M���*�����h.�V��Bp��z��W�����a�4Z+��Jxx47Z��Jx��z��7��M�aO��!o��Gs��#o������<�+<���v�����h��v�������:���6O�u ������<|������<|�y8x:��<\�;��<\	S\��0�pm�p�tZ'�p%<<�;�y�$<Lq�G�'���������a�KHxx�vZ�"�Wk��i��Y#q
;:�=I�-�����CD�j
;�Wk$n�aG���C�s�&k����O���{4��5��������!�������G���Wk��i��\#q
;:�}�0$9�w�vZ�RU�j
;��k$n�aG��Op���&l&k��O U%������q�F�6vtZ�gl�l�f�vZ�RU�j
;��k$������������d������U�����������N#�$��N�NkO����0��
����m4�����<��lfk��g��Lx��z��q�F�6�tZy�����N� g���{4�;6�����*��l�f6wZ+�p!<Lq�G��d#q
{:�y�
���NkE^	S\��0n�H�F��NkCf�6������7���{4�k6�����������l��v����0��
����m4����a6j3�;�y�`<l��p�F�6�tZy�����N�"W���Nm$�����i���l�f6wZ'��Ix��z��q�F�6�tZ'�0������1 ���)�wh���%n�aG�u�$<�X;�#K^�ac�u�a��h��ia����k�u�a��5l���8��k������<,��������%�����:��������:F�aI�5l���xX�j
;�c���yxttZ�<,������1K^�ac�uL/��o�����5?Ur��*�#�$H�Xk�c$��Z��Z���%����s_���w	��b-���X�j�K�c ���~��*}s�'F$8�X+�#��/�ac�u$�������H��oBN�������a��=����	��}�����(�
����(�	
SR��oA�M~�K����B@8���� \SN���� \� ��m�{�]�W���\e���+�`J�=����&?wS��~7���@p2YB�F �2z�~���M��n	�������M�kG��	�R<�������o	?wG�����p2�X�A��y���Cyc��`$��p27X	� L�G�	�*H;\�+A�d��ND���Za����r?����$����|26vX7m$��`G�U8j��a���%V�D�*SF�Q0n�H�k���8i��a���-V
�	"y���-V�M�{-�Qc�mV2l��l�m�>A$�V�����i#q�;z�:N�Q?�7dk�UG���W+��cU������EV�"f��
�Zd�	<���
6Y'm$��`G�U�3����lm��"U�j����6��$����s���1�![����X�~�f����`�����MV]v��������	L���
66Y�l$��`G�Ur0�	��d������s6�Z����9�l��lm�jF����M��H�k��&� �I�_$�m�9�����`�����'�����9�,��ln�V���p0��������i�6�`2h������7���{�S6�Z��������M(�&kG�	SL�Q0.�H�k��&kG&s6����9x'L1�G�8d#q�{��9����bn�*r�A8�bz��q�F�^�Y�4Y9����bn�*rp%L1�G�8c#q�{��9�l��bn�N���p0���r����'�����s��Z��&���%�V���:�/^���<������	k�u�`��ll��,q�;��3F��8��d�8X�*SL�Qp����M�9��q���:G�`��ll��8X�^v4Y�X1#�ue��+8����o��_9�������������/A^~�_�����Oo~���������y������K�����������?��������E���[�J��i�����o����J��������3��KU�/U�g�Q��y���Y��Z���Ue�m�&>����3~����J�9��3W�H^X���Y�[U�_'|`����~�*��J�9��������<X��s�oUE������^�K��_��@G�w�+f$�,���\�[���N�����o��j��R���;7x�PBk[��s���W)��r�����o.H���o�w
%�V��������U
������/�\��=��1aF���`.��� y��?/wo.����Z����3�w�s�W���~����7\��k��'O�w"W�����D>u~`����O��������;��O����1�:�	r�����������5��`?������u06Yu�~���U
66Y/��x?@$���z��aFr�:��:�
���v=o.8Np�"~�H0?���`Fr�:���4
����f=o.x�x����`���z�� �H�Qc���f��G�1�V=o.x���H���L�K�2N�u06Y/iV(x��|`����+^<�R�����<bF��v06Y?����c�lz�\�����Q�J�~&�K���Y�`l�^�-P��?F�����/+\�E��g�^"���<��MV����Q>��ys�	9859x�3Y/����`c�U���t~`����3rpnr��g�^"!g����d���s�{�7\��K��gO�U����hn�
rp�9��9��^��K��=M�����&kE^u~`����7������&kC�Gs��!o:?0�yw���[��O��#o��������w�������9xor��i����p0}��K�r��s�S�7| M^<M��|��&�":?0�ys�9�69x�4Y9���&�D����M��|69x�4Y'r��8��d�9�$lm��,q�;��0��8��d�8X���=��ys�!��kr��h�B��J����
8X�*[���xM^MV���Z+��d�,y���MV�/^��MVG�H8������8X�*[��0K�k��&+L3�/hv)x��J��&+L���Rpr4Ya:1#�`��f���	�9��9�����%��`G��3�/hv)x��J��&���oirpr4Ya�0#�`��f��p��U
�6Y!!�&'G�rp"L_��S0rp"lm�BFNMN�&+d���8��de��L8��d������i�
rpaln�
rp�9��9��F.MN�&kE.����]
^��W�������9xmrp�4Yr�J8������
9x�9��9������6{��
9x#L_��R������������{��=M����/hv)�@�u~`�����������d���`��f��+r��s�s�7\��k���������p0}A�O���U���<o.�D�M��&�D>	�4�|"�:?0�yo�q�������d����4_Ck[��8�'��U
�6Y1x��D
v4Y1��1��E��f��|�H^�`k�C��� R����q���9E������� ����9����"q�;��8������]
��J^�`k�G��Z��������z#}A�K����Gi>0�ys��T�{-��d�����y�������L��U
�6Yq�*q�;��8o�Q?�7�4�&U�*[���Lx�P���8��������F��f��0��W)��d����H��MVL���p0}A�K�	98������g������h�bF&�5��������u~`������s�����*��d�&�4�\���`s�U��K�����Z���nM�/hv)xE^	���9xmrp�4Y+r0�����.o������y�\���59�x��
9���D��f��w��M���<o.xG��\<M��Lvk"}A�O��������d��{��=M��Lvk"}A�K�r��sp17Y9�hs������d�&�4�\�������d������a�TY'�0���
�.
�����\e��g������I�,�D��f���HX�*
[��q����e��$(L����p��J��2k���������!	��4�4Gl�����#���m4����x`H��:k�%�����G�a��h��g���!
[��q���x�]�>O^�&���h����V*�/jv�x��Z��Jk�#^�&���i�3���*�vZ�D,y�������xx�$v�Z�H,�������K^�bk�5.�����^kL#�$LL_��RqB&N:�|m��8!�6G�5f��D��������P�u(~��j]qF*�m*�f+#gB����.���S���V��bqicq�T[��,�/mv�xE,.:�|o��xE.^�\<���\�.��m���xe\l.�6������Snm���bs��!o������\���8x���xg\ln�v���pq0�[r�����i����p1}y�K�r�A�8�����hsq��[�� \L_��RqE.���������U�bO�u"W����.���'��`n�N��S�bO�u"����+�=*��9	k�5�����V��4T��e�K�]*�9"y�������6��Q������!���"}��K�>G$�V����p�F�6*v�[S\1�~�o�/r��>G$�V����p�F�6*v�[�'oNd�&�W9�T<�_��Z��vk�u�����nM��9���H_��R�~U�j[��	�m$o�bG�5���O���u�.��W%�Rq��[.�H�F��vkZ"��������./�W%�V����p�F�6*v�[S0�~�o��tv�8K^�bk�5����mT��nM�/�p?w
��?����7����?��_��K��h}����?���o��}W����z�����O����������?�������������~dr�N2���K'���7��o�G��������{�"F�=��y��y�
����yG�7��d<����~DM�������wC$������mHd=���.
o�h.�p8D�6��};����K�;��������r��m4�����BEK�������������h�S�U�2 B=K��+�Eetan�p;D�6�4}��,�<�m���O��V�M�h.�p<D�6�}'�t#"���hx���I�����o����m4����a���������0������|s��!���?|�Z�S%�[/c$��J�<so��X�j%[��9�xM$~�����Fb������/���%���������	��}����q���~����G�a���k���pX�^�}�����N#��m�Bk��%������'�a�{�������;��i��Y�(,q�~�u�<
K�K��}����������.#�K@x��Y� ,y/�>w���~�#�VYs��Z��*kN�������&�����t��O���A����3Bpj�~�����f����/�]�������d��
�on�~������05]
.���dn�
pi��4X+p�	�*�.�H�+!���`�H�����c�"��#0u]
��7�������7�~�c�;2��30�]
���w�����������`O��#�:S����!x'<�K�!�h�
��XR��S0�]
�H�����bU�������*bp%l��*bp%<�k�1������X'r�I8��c���'�`k���p����(�^���f\�z5	=
^���Z��"k���{-��d-�0\�x5	]
�"q�W/�M���!���$���Z����`�I�Rp���lm�\
����M�2F����JMB��G�W+��d-8"y�;��e0�~B*5	]
�@�J\�`k���d����h���bF�|Tj�<G,X?�0��&k���{-��d-����Q�I�R�"U�j[���B$��`G��,+f��F�&�O� R%�V���Zp,D�^v4YKB&�!�$t)8!'�����Zp*D�^v4YKF&{!�$t)8#g���&�B$��`O�U���Z5	]
.���q������{-��d���d+���.���+����d�H������i�6�`�BMB��7���p�bn�p"D�^�4Yr0�	�&�K�;r�F8x17Y8"y�{��9���P����9x'���,�����=M��L6B�I�S0r�A8x17Y8"y�{���LB�I�RpE���s��� ��Z���:���>5	]
>��O������a�{-��d�9���P����4K\�`k���`�{-��d�1#�`k��p���
�6Y)K�k��&+�3�LMB��#p���
�6Y)K�k��&+��u�&�K�c��	'k��F�`�{=���d�q��:S����	8X�j[��4K�k��&+M+f�9���>K\�`k���/^��'G��f�`	�lm��,q���MVZ^�&O�&+-��Z)��d�8X�j[����x��<9���&��s05	]
N���pp�6Y)!�&O�&+e���s05	]
����pp�6Y)#�&O�&� g���&� ����d�������d��B8��d����q���Z���6{��9x�9���.o��+�`s��!om�4Yr��s05	}
F�gs��#oM�=M����LMB��w���pp67Yr������d������$t)�@>gs�u M�=MVE>t�&�K�9���&�"�&��&�D�:S����9�$��M��|69xv4Yyx	u�&�G�y���lm�2��H�k��&+'f�*�&�K�a����b�6Y�j$��`G��������I�Rp���lm�2n�H�k��&+�
3��R����D���
�6Y�j$��`G�����{�I�S0�T��lm�2��H�k��&+Op�f&�5�$t)x�*q������8W#y//�&+�p�f&�5�$t)x�*q���MV���{-��d�e������$t)x�*q���MV���{-��d�0�~`/5	]
N���pp�6Yk$��`G��r0���&�K�98.�&+�d����i�2r0��&�K�98.�&'k$��`O�U���p
5	]
^����bn�p�F�^�4Y+r0��&�O���+��bn�p�F�^�4Yr0��&�K�r��8��d�d����i�v�`2\CMB��w���q������{-��d��d����.������]�>�d����<MVE&�5�$t)�"W���`n�p�F�^�4Y9��P����9��s���5��Z���:���p
5	=
.r��sp�MV��%��`G�U�
3�LMB��p���
�6Y%K�k��&���u�&�O���W+��d���5989����%�R���*8X�j[��2x���MV��%�R���*#p���
�6Ye�x���MV�F�H8��d�	8X�j[��2K�k��&��3�W��4<K^�ak�Ufa�{m�Qe����d����.
/6LH8X���	K�K���e����d����.
'@a��5l-�JBNM��2�$D���p�6�K�Y8�6�dd��d��h�JF�:��4�0�	s�U�s����*�E��@}B���p!4�}��4\�4�=}��4��4�P����8��BkE^�8�=���8��8�Q����<��FkC��<�=���<�16WZ;��Nx8�+�yxo�p�TZ;���x��i��;�as�u m�tZ��Ax�*�.
W��������������N�"W��T)ti�D������:���&O�u"����R��0��Ix8Z;��k$��aG��p���Vl�R���:������vZ+�H�k��Nk
p���fl�R��p���5l��V\��������x����P����"�Wk��i�8a#y�
;:�u1#9��*�.
� U%�����Zq�F�^vtZ�0#9��*�.
O U%�����Zq�F�^vtZ�tbFr�/U
]�GlX?\3Fk�������6��������_��4��T��Z��Nk��{m��i����!�T)�i�����vZ+��H�k��NkM��l��*�.
'��Dxx�vZ+�H�K�ap�ZkF f{6�)t�8#g�����)�����j$b�hC�B��q!D<�[-�����=���H�6m�U�R��H�$����H�F��^kC&f�6T+t�xC&���^m$o�bO��!�]��T�#o�Gs���6��Q��������
]*>��wB�����Q����Sm��l����>#�Gs���6��Q������l����.W������m����mT�)�N�b�oC�B��O���q������S�bG��
���Z���nmp��U*����6T�zm.�vk#�$\L�B��p���*��[[.�������$\L�B��#p���*��[[.������OI����.�#VL�x��[�\,y;��m<0$�b��T<K^�bk��M����Q�����
C.�n�O����W���nm��W�����nm3p���*��[�\,y������D�zm.�vk[��%�V�����b��Ulm��4��ksqp�[[B.N���������bk��%���p����2rq"\L�B��3rqf\ln�2rqV���n��L����.��B�x6�[����8z���\\S������.�����\���8z���x%\L�B��7���p�ln�6�������nm���b��T�\�.�����\���8z���x'\L�B��w���p�ln��������n���b��T| ��gs�U���6GO�U��+�b��T\��+����nU������i�N������n���'����n���g����������q�������Z��vk������n�a��d���.���Z��vk�	�����n��bH�K�B������r���n�8�#y���vk�;�$���-t�x�*y������38��Q�����C�UX��T~U�j[���p$o�bG��Op8�N�pu]*���J^�bk�����mT�h��N��� N�n�K�3�U��Ulm�v���������LR?8P��������*��[;��H�F��vkOC�G��T�������n���#y;��=#�M�@�B��3rq&\�X���p$���~���~���������hLvq�]Z.��������I�{����W��.�d'P������006�[��#y/?�����W�b���Z�S0b�J�8��-�������:}s�B1�	T,t)xC(�'s��{8��R�S_�o.xG$&�8�j�.���;A�d.�pG�^
~�����d'P������ @�����H�K�O�&����8LqU
]
�����p2�Z8�#y/?u����O�a2��P�R��0|N�J�p$����n�]0r0��	T'�(���O���Zhp��m�����1�������:������YG�����+fd$l���$,y���]�G�z���2����Zi���.
G@a��5l-��1��S�;6<Kh�ak�u����Wi8[��c<���o;��c�0#�a��4<K^�ak�uL�������:��	
S����hX�j
[��c����������0
]^�%�����:�a�{m��hK�����Q��p�a����h	y8�y�Qi	y8�J�K�y8��J��������N������0U
}F������*��������qs�y�06wZy���NkE.M~�H��^��W���NkE^�;�yxm��s'z����<��J�K����x��im��[���;����w����0U
]���w����i���{���;��������0U
]>������i��G���;��������T)<�p��o�<^E>~��?~�������/���y�u}����?���o���������������K�����������?��������<*�$�YX
p`�\�O
��7��o_�,��o����[�T�|.����
GXc��:��az��W#��&y���
�n-8�K�k����3�����R�8a��w�G�B�-x:����-`��#z��K���&y�����<�K�k���Nf�	=P����r��J�X�{���%���GX��u@T��)Nr��J�|
���%���#�$����L��Z��
�.p���U
~���[p���n���Np/IB+S�����K^����W�xx����?����������.g@e��������������'7\��3��b��jA.:?�
zo�9�49���N�.9�.����9����2�����k���;����W���pp17Yr��s�#����!oM=M���.�&kG�t~d���w������&kG�	s��#�:?�	zo�r���`O�u �����:����Y����|49x�4Y9�267Y9������#�&O�&�D����M��|��������g��'G�u��'yh���R�9K^�`k�u���Z���:�3�g�k�u�	&lm��,q�;��3��<�=X��3K�v�Gv@�-8K�k��&��f$Ol�&���%�R���:G�`�{-��d�c�������d�#p��U
�6Y���59xr4Y�,����M�9K^�`k�u�^�6;��s��Z��&����%�R���:������&�\F�H�^�M��K^�`k�u.���R��h��0#�`k�u&���s�#������S��gG�u&���8��d�98������g�������de��L88�����	����\�<{���\s��"���&kE^�<{��9x%�M���������o��k��gO��!o��������7��Y����9xkr��i�v���pp07Y;r��s�#{�7��79x�4Yr�N88���9��9����{>���6{���|�&�"W��������\��i�*rp%�M��\u~d����O��������:��O���&��9u~d����_�}���Z���z�t`F���`c�u��������
66Y/��x?@^��96��#�M�K�
xD�G��s�^<�y���Xp,�1�������4����
66Y�0F�x�������1A�u�����4<�m��{d�����/���o�O3d�P�~\���zIS��	�g��`c�����C�������y���S?.��d��KP�|9+����M�K�.��"����c�K���S?.��d�����O+��`c��f����H}���Y��Q�~\���:�4b�xX�G���t�����~&�%rp"�M�9d���s�#�����s�����z��������u~d����rpnrp�4Y9�067Y9���������������d���+����d���+�`s��!�MN�&kC���&kC����
9xkrp�4Y;r�F8������9x�9��q�{����&'O�u ������]
>���������9�hrp�4Yr�A8�������|������W������i�*rp%LOd�R��\u~d����O������&�D>	����|�������9�ls���
p���
�6Ya��J��&+�������d�,����MV���W)��d�8��krpv4Y!Kh�`k�"p��U
�6Y!V�xM��&+�#f$LOd�R�,y���MV��%��`G���	���<K^�`k�&�`�{-��d���������]
�G,X��G&=�-x����MV��H8������8X�*[����:\������d�e�������}
��J��&+�	/^�����
	98�'2w)8!'����D��3rpjs���
98�'2w)8#g����D��rpns���*���p0=��K�9��L%��\�\<M��\���9x�9�.Jt)xE^�\<M���267Yr��s0]��R���59�x��
9x#LOd�R���67Y;r�����i�v���p0=��K�r�N8��d��G�����:�����D�>#::)���� |4A�x��� \	�#��4\����nJti�D�M.�.�D>		�3��4|"	�:	:*���8�g��D��(�����������eV�CD�j
[���5�y�
;��&���U���]�!"y���uV�������uV�3��Ez,s��#|�H^�ak�a��5��������������`�.� T%�V����0]���Q����c����������i����"���R1����mT�(���cH���Hg�R�RU�j[[��5�y;j�8�R?�7����TZU�j[{�6�y;���dIfl"=��K��U��TL&�T6�y;�������M�G4w�8!'B�tc�O�H��I�/_+���d�&�C��T��3�b�2����X��X��E����\L�l"=��K���.�;]*.��E�bO��"�9�Hj�R��\�.�rkE.^.��[+r1�����.o��+�b�5���
�xksq��[r1������.����b�6����xosq��[;r1�����>#�����D���������n��d�&���T| ����VE.>�\<�VE.&�6������\\����\\�\<���\L�m"=��K�'r�I���Nt��D.>�\��8 �q�H�m�Q�8K^�bk�5����Q�����!	����T��%�V���p��mT�h��P1$�bzts����.��]*�����Q�����!	����T<K^�bk�5�����Q����C.��7���X�j[��q����8:��q.��Z��vk���%�V�����W�����n�3p���*��[�\,y�����8�x��\���L�p1=��K�p���*��[�\,y;��1EI�������\�[��1!�6GG�5f��D�������\�	�%�.g������i�2rq&\L�r�RqA.����E��rqisq��[��.��9w�xE..���E��W�������n���+�bz�s����W��t��K�r��p������7���@�.o���b�H����xS���n���;�bz�s��w���p1���S1r������n��;�bs�u ���*E��������������bs�U��+�b�K����\\�\<z����.�;w��D.>�����ls��i�N���p1=��G����#'�bk�5����mT��nM�/�p?w
+�����������������/A^��}����?���o��}W����z�����O����������?�������������~dr�N2���K'�S>���7�[����O������?��H��H���s]~�qMD�6~�u�4�Y����_<�#�h:0UWk���M8'"y
;��i��'2*B������J�j
[��	�D$���~���~�������p�0�~�*}��K�3�*���l��&����?�����.#�����/�������Z���o�I�{��9����4`Dr�����~������}.�H�K������"Z�U��E�~s�~���]���/�H�K��}�����cD�(�P��~�)���k��&����~��}o�e����}��O��E?�?���.�����������{�]���}��K�+b��0�\�����������{�����}��K�B�F ��u��!xC�%�sw���wG�%�"�=�.����;�_:���_����sl>���}��K��A��ut)�D$o�U.��+0��Xt)�"WB�t��K�8%"yO3y�L�D�]
>�+A`:���`\���;
����dN��_���y@>	����0����(��a��:��+�,q���%�F�x����k@�Z)��b�(X�j[[�9�x����k���Z)�Zc�0X�j[k�9�x�����&�<N�Q�`�^E��G�`��l���8X�^vY�1������.O��W{��Zd�p����h��y��:�w*�<K\�`k�5������$������u�oTt)x�X0�`�����8X�^v4Y��cF����]
N��W+��d�	9859���L�-8!'���&kN���p0]��RpFNM~�$�{����p�������p0���RpA�M~��{.��E�`��@��rp!LW9��\���)&��"���{]
^��W��t��K�+r��~��dm��������.o���`s��!oM~��{���7���+]
���w���&kG���i�v��]�`��@�����p0]��R��|�9��d��������.W���p0���RpE�M~���{���U�`��@����+�`�����9�69���K�-�D>u��
t)�D>	��/8"y�;��e��
�B��Q�2����
�6Y��H�k��&k	pX�B�B��]
�"q���M��!��Z���Z���s_��]
��"q���M��!��Z���Z����P��]
A�J\�`k���<����h������Y����.O��O��F��qD�^v4Y�t`F�$T��@��g�W+��d-8
"y�;��e�0�~*}u�K��T��bm�����M������J_�S0�T��lm������9M�����6}u�K�	98��]
�Q�{-��d-9�,��W����3�`����`�������d�`�B_�RpA.����F��qD�^�4Y+r0Y��t)xE^	���.�����i�V�`�	B_�R����k]
�1�{-��dm��d��:���9x#L�6��S ��Z�������}u�K�r��8��d�����i��`�B_�S0r��8��d�����i�*r0���t)�"W��te�K�8"y�{��9�,��W�|"�����F�����&��&+
��d��:���4K\�`k���`�{-��d�0������.�`��lm�R����MV
'f$lm�R��`����d�,y�;���H8��d�8X�j[��4K�k��&+�f�9��:���	8X�j[��4K�k��&+M3�L_�S0p���
�6Yi�x��<;��4Kh�`k��f�`��lm��2��kr��h��,����MVZ��%�V���JK����`G����u��t)8!'���.^��rpjs���J98�L_�RpF�d�}�6Y)#�&/�&+#g����]
.������&� �&/�&� ����]
^��Ym�M���69x�4Y+r�J8��dm��+�l�M���59x�4Yr�F8��dm��Yl�M���59x�4Y;r��s0}u�K�;r��sp�M���79x�4Yr��s0}u�K�r��sp�M��|49x�4Y9��9��:����\����\��x��9��L_�R��|267Y'r���`O�u"�:�Wz��9	k��q�F�^v4Yy81�~P}u�K�>@$�V����8Y#y/'G���������]
��"q���MV���{-��d��aF��^��@���D�j[����5��Z����#����p
}u�K�#�T��lm�2N�H�k��&+Op�f&�5���.O R%�V����8Y#y�;��<�y����W�<�H��Z��&+�d����h��2bF��^��@���W+��de������MVN3���W����%�V����8Y#y�;������p
}u�K�981�6Y'k$��`G��3r0���t)� g����d�d����i�
r0����)9���&'k$����i�V�`2\C_�R�����&'k$��`O��!����@��7���pp47Y8Y#y�{��9���W��#���������{-��d��d���:���9� �MN�H�k��&�"����@��+�p% �Un�H�k��*�"����@��O$�JH8��,�����=]��$��k��=.���P�Zf�PX�^v�Ye�0#�p���iXX�j
[��&�zmv�Y%Kh�ak�U���U�uV��^�uV��Zk��g�4,y���}V�zM.�>��@�Zk�Zh�pX�j
[�2V�zM.�B�L#f$;���.
O���Wk��h�	xX�^v4Ze������*3�����VZe�����V�O��x��i�e��	��N�,��������*��	���4���%�����*	y85y�8:�����a�A��������i��<��<\�V�����0}��K�y836wZy87y�x:��<\�	�4\���as��"�6{:�yx%<L�$����<���pZ������������m+���V���x����<��������|��������B��0�nN�;�XB�j��w���7o�����������w_�{����������������i�-�ul=QL�fD2���'}���E��d���'���
��^���a0�o�x�����.���;9}b�o�0^���<}"��
B���~�D��=t��@6>��S�����	������A��p|�P��C��+�q%'PL����($o�bS�!���~E��>t��D:�������xp��mTlj�0$������=*^q�F�j�7p>G�������~���!�d��?t��m$�Vq���sd�,�|�K�Xq�0$���
�>�����*��� n���m���+��Y�������p>G$�Vq	�p�f���|�O�X��u�l�|\q����J^�����e�m�������O Z�����[��n$�V���Zq�f�,�|�S�X�<bH��}�K�8q#y������7�e����b����!��G�M�.�����*��[+��������=+>1$y���
��b����Z��vk�����s��f�c�	���v�q��vk����Ulm�V\�Y/K7�;V���/{7UL_��S1rq&\<��-��Y/[7��:V\��/�7Wln�p�F�j��-\�Y/k7��:V�"_6o>���n�����*6�[�w�^�n>��u�xC.���|\�������Uln�p�f�,�|��X��\|����bs���7�W�x1�[;r�e���]X�����p1}#�K�8z#y����������wa=+F.�l�|\�������Uln�p�f���|��XqE.���|\�������Uln�p�f�,�|��X��\|����bs���7�W���nmr�e���]X����XRk[��m.��Z��vk�^������p��V*��Et�8K^�bk����^������"p���*��[[.��Z��vk��^�������C.��t�x.��Z��vk��%o�bG��MC.��t�x.��Z��vk���%o�bG��M'�$\L_7�R�<b�������f�b�����nm��!	��
�T�K^�bk��-����Z��h��e������}*.��Z��vkK^�6��vkK���p1}��K�	�8.N�vk����������2rqf\lm���\�	's�U��s��GO�U���bs�U����dn�
rqis��i�V��B���n����x%\�����\���x��[r�J���n���
�x#\�����\���x��[r�F���n����xc\ln�v����7_������j����h�4�oti�@4�����h��s_�o���c��A�����\oU��	��}���
V��J���m����X\	gs�u"�&?�u��+x"����]
>�O��Zm���#y/?�e��+�����:��[���q$�V����qg���������^�_T�'���}��K���#y�������8�e��d��&��
�����}��K�8�#y�������8�e��d��$��
�F�O��
��t)Wq$�V����qg�������[�7_��Q�~\����qG�j[�Gq��(��	.�
O;f���
��.
�(�����Y;����Q�����W�����}�*y���]���8�e��I��8�s�,�|�����qG�*
k���(�~�y����pB�,�|�����qG�j
[��Gq��(��}u��3��e���o�Y9N��|&�p����������������������O����������;ko�������]~^.�?~|����~��G����K��K>����/���
�8]wx���7����0��M~��x����Zm�����T�p'IBk*���_�v�.�#�����7��Y�^7���	3���}�K�~�:��H����[��_��b%������[��������_��~��Q�{������*�n��0�~�:�71�|���S���M�{>�k�����y:��bF�Vu��a�(��&��?V������c���Ga�1��Q�U�[]
p�A�*?�=����c����
�V��?��;}
���W)��{o�q�����`GxDx�RBk[�#*K^�����/^���<���+8Kh�`k�w�������9��>��59���O�����	��/�<K^�����O���Z���:��	�w/�<K^�`k�u����Z���:�32�6Y�,y���M��K�k��&�X*fdlm���`����������h������.�����������[pF�mv4YGF����K}
F�:?2
zo�9879���N���9��/]t)� �����9�49���N���+r�J8��t���9x%ln�V�����Our����W�����.o���`s��!oM~���{�����/]t)xG�u~d���w�����Osr�<��w�����.��������[��|49��CNn�����`��E��+r��s�#s��\��k���<���+�\���9���������g��GO�u"����M��|������?@�6;��:���Z)��q���:�'��U
�6Y5D�x��z����oJh�`k�U|�H^�`k�U��?@^oT;��B	�lm�j�O��lm�j�x����F�c����W�C�6Yu�*y���MVA�J�k��&�N3�o.�bm��&U�*[��:�H����MV�N�����������/>2�yo�3�T�{-��d�����{��X����I��J��&�. R%��`G�U�
3��-�bm�j�*y���MVM���Z����	981�6Y5!'���������<9�����3�`k�U3rp�9����{.������&� r������\t~d������K��=M��\�^���Z��W�������9xmr��i�6�����5���
9x�9����{����&��&kC��^������7���&kG��<{��9x'�w
�&�@�	���9�hr��i�����5����|������W�������dU��J���MVE�:?2�yo�'rpmr��i�N���e=���9��9����[>��������:�`	�lm��8X�*[��s�x��<;��3���q���:p��U
�6Yg����M�f$�M���%�R���:#p����h��xbF����d�������������R��h����������:'�`��lm��	8X�^v4Y��aF����d�3p��U
�6Y�,q�;��s.��pp�6Y�,y���M��D�xM^M��Kh�`k�u.������U�{N^�&/�&�L���pp�6YgBN:?��ys���������:3rp"�M���������z�[pF�M^<MVA����MVA.:?��yo�9�49x�4Y9�067Y+rp�9��U�{^���6{��9x%�M���������o��[��=M�����&kG�t~d����w�������d���;��hn�v��]��GV=�-�@���<M��|��&�@>����|498y���\	Gs�U��+�`s�U��k�����:��+��hn�N��S��G&=�-�D>���LV�a�+H88�����}�	�!�R����9�' �^v3Y/�B���9E�Dv)8�Pp����Lt)����q�����#��Q?�(F[���&�X�~�&=`�K��N�|�{-��d�����y�1����4c���~�&=`�K��N�|�{-��d�i���y��L*|B��~�&=`�K��N�|�{-��d���@F�[G[��s�
���4�]
�t��C�K���d��1AF�[�s���
���4�]
�t��C�k�n&���3d$�5�N0w)x)P���I��Sp���"��F�c�i���y��N0w)8!'���&��0�������d�D���d�&�	�.g��L&%�	]���	��Seea2\�s���p&����.
$��$����
�0Y��t��K�+�p!����.
���k����Z��tM�+�}F^��=d�K����d��i�6da�]�s��7d���J�S&�4�#om��Y;�0��t��K�;��Nv%�1]>���6
{��i���D:����i� ����>
#M.�B�"���H���4\�+YX�Mti�"�&O�u"���H���4|"�������<|6y�x*�y��D���������0�ak���3��������V�Hx��1wi8K^�az�D������6���B�0#�a����a�a��5l��B���5y�8:���%�����
xX�j
[;�0F�zM.�N+���Zk��i�xX�j
[;�0
x��<\�V���%�����
�����vZa�x��<����<bF��t��K�3�����vZa�����VXf$<L'��4�K^�ak��a�{i8�R+,'�$@LG��T�F��1=s�K�	�85�8�V+$$�D���2w�8#'F��V+d$��$�08j���3Ab:���bD����\kD��D�0xz��L\�i�.d�B���<�����4�8�bkE(^	�q�.��+�bz�D��7���	�a�4[R�F���3w�xC*���'�T�T�5�8�jkG,�����x'XL���R��X�7�8�n�@.������ \LO��R��\|(\�)����p1i�RqE.>�3(�T\������v�"W��t��K�'rq%\LO��R��\|��8x����$\L���T�\|.��P��8�9r��88��8����d�&����>G$�V����a����#�b;V2�$7��5w�8�����*��[1�z�9��6�c�q��d�&���.G���J��4�>�x��s��}l���	C���F:��������*��[q�*y;��8E����ds��'���W���n�	���mT�h��<`H���HG��T<�_��Z��v+��W%o�bG���!�3~#�m�R�2b������J������mT�h���cH���H���T���J^�bk�p��mT�h�bB.&{7�N7���8.�St�8#�6GG�3r1Y����n��\�	��)�T\��s�����*��d�&���.������n������i�V�b�z��s��W���q���Z���6GO��!���H'��T�!o����]*����6GO��#���HG��T�#�����]*����6GO��#���Hg��T| �����]*>���6GO�u ���H���T\�����|�.W������i�*r1���t��O����p1=��K�'rqU���n���d'�1�.���'�bzBE�����T���n�p���*��[�\,y�����8�x��\<:��1L�p1t�Rq.��Z��vk����Q���c������s��#p���*��[c.������8�p1u�R�\,y�����8K�F��vk+�$\Lg��T<�X1�bzLE��'�b�����n���!	�a�.����W���n�3p��mT�h��y������s����%�V�����^��GG�5.���Z���n�p���*��[c
x������~�����[/cB4N�����AczTE���S���J}o��80��]
����1=��K��87���/��\�3�b������X\�c*�\�K���:�X�������\����
����_��o_���|	���o~z���7?����oI���_o��w�����?~|����~��G����K��K�y�Y����7����������~+?��7y���������~��vt����/�&_<G����#]�:]����.v���@���p�Z�{D�CGzc�~$�������HG���sw�������PA�a��oE���)�a}�E��M�x����W�D��:S�3��{"R�)�I]�=)�&R<w���+8
^A)��=������Z��ro�I��8����1�~Z=~�K�>>$�V����pQD�6^�r,8�Q?+������W+���M8("y�4y\1�~���|s�c���S
=��K��'"y�_w����J^�R�NJ�j[[�	�D$���Z��K�bF��Tz�b���1
��l-�&\����-�4������.v)x��4$�V����pLD�^v�X��NdQ�����$���
��XN�H�k��kJf��M�.v)8!'���X�.������(���L�D�q�]
����p0=��K�8#"y�{���L�D�a�]
.���p0=��K�8""y�O�x���L�D�Q�]
^���`z G��qBD�^�4Y+r0��-v)xC^	��8��"��Z��������=f�O����`zG��q>D�^�4Y;r0���,v)xG�	��8���!��Z���:����=b�K�r�A8����`�����O�er�%���d?������\��,����=M��L�C���]
>��O���&gC$��`G�5��d;�����y����D�&k��%��`G�53�6Ys�X0�`zG��p����h���cF���&k���W+��d�8X�^_�q4Ys\1����X�>K\�`k�5�#^�&?y~���p��J��&k��%�V���������O�^r�%���%�R����'�`��lm��������'�.���f�9�����8X�j[��y����M��D��s0=N�K�p���
�6Y�,y�;��9
�Q�`z�b��rpblm��������%7_B���s0=J�K�981�6YsF�M=MVF�:���\��3�`z�F��rpis���*���p���*���p0=m�K�+rpis���Z��W���&kE^	s��!�M�<M����L�P�R���.�&kC��<y��9x�9�����9x'\�M���79x�4Yr��s0=>�K�r�A8����9�hr��i�*r��s0=<�K�9�.�&�"�&O�&�"W�����]
>��+��bn�N��������:��O�����=
^�9[��A$��`G��f��)��&v)8����
�6Y��H�k��&k	3���c� W;"��d-8"y�;��%�a�Y��v)8����
�6YN�H�k��&k�(�������<�H��Z��&k�!�{)xv4Y�4bF}
�����	D���
�6Y��H�k��&k�f��@�Q�]
�A�J\�`k�������h������a����./L��M�� ��Z���Z�3���������%�V���Zp�C�^v4YKB& ���.g��D�k��������h���L&@�Y�}
F����M�H�k��&� �	zV`��rpaln�p�C�^�4Y+r�u�����M����&kE^��i�6���p������7����dm��[��=M���67Y;r�N88��,������O��#��zV`�����pp07Y�W#y�{��9������\������d�`����i�*r0���gv)�D���������{-��d���d�����`���p0��Qp���&/�&+
��Z)��d�8X�j[���xM^MV
��Z)��d�,q���MV
/^��G����u�gv)8K\�`k��"p����h��0������.���W)��vu)x����MVO�H8��d�i��	���.O����Z���J��	[��4K\�`k��f�`�{)89��4o�Q�`zV`���`��lm��,y�;�����s0=+�O���W+��d���5989�����������.'��D8��vu)8#�&'G��2rp�9�������	���>#�&'O�U��������.��B8��vu)� �&'O��"���Y�]
^��W���&kE^��<M����L�
�R���267Yr�����i�6��M�`zV`��w���p0���R����9��d���;�`s�u ����nW��������&�@>���9� Lw��\���&gO�U��������.W��J8��vu)�D�M��&�D>u�gv)�D>	���>#�M��&+3^B���Y�=
�|�H\�`k��q�F�^v4Y9��Q?������ W+��de������MV�3�����D�j[����5��Z�������������.�#����nW��q�F�^v4Yy<0�~`/=+�K��T��lm�2N�H�k��&+Of���g�)D��U
��]]
���{-��d����d������D���
�6Y'k$��`G��8O3��zV`���W+��de����������	88��zX`���p" L���4� �� \UV��l�������$�		���.
�h���6���
�0����vi� 
��t��K��Z#y�
{���(��k�y�]^��aa����a������=m��,��k���]��W�t��K��[#y�
{��
a�����4�4�16�Y8\#y�
{��i����#�4�#����.�H�k��B�@f�5���.
���a����a������=�VEf6���.
W��Jx�x�iy��y�Si���l������y�$<L��4��5���p�V���
=7�G�e ��Z��R����Q���*��!	���TF��1]��Rq"�����V	�$HL��Rq$��Z��Z�D@b�����k��aH�����>K^�bk�U�	�^����(��P,�����V�%�V���*S�����08��2Kj�bk�U&�b��Ulm��<��kRq�V��%�V���*3`���*�V[e�x��XG�U�C.��v�x.��J�t��K�p��mT�(�J
�q���*	�8.��^]*N��I�bG�Urqb\lm�JF.N����W��3rqnsq��[�8.�g	v�� g��t��K�����8x���\\���T�\\�e�.��������n���+�bz�`��W���p1���R��\���8x��
�x#\LO�R��\�.��^]*����6O��#������]*���w��t��O���{�����:��w���T�.���bs�u m.�v�"�����]*����q�����������nU��J���,�����.�+_]*>��O��=���\|2.��[���#'�b�����'n$o�bG��;��O6
�t�.���Z��vk���{�8:��5�R?�(���T�#�W���n�8s#y;��5�!�+Y�	���.G���Z��vk�������n�#�����@��R�~U�j[���n$o�bG��N��O�
���.O�W%�V���Zq�F�6*v�[�1�~�o��v�x�*y������s7��Q���Z�C���z�`�����W���n�8x#y;��u�R?�7���T�F�X?�3���.����mT�h���\L�o=m�K��8.��_]*�������n���l�z�`����3�b����b������=�VA.&�7��8����\\���.�����V<z������z�`��W���p1���S1r������nm��d'�S�T�!o���X��q�F�6*��[;r1��	���.���;�b���b������=���\LVp=x�K�r�A����u�p$o�bO�u ��@O�RqE.>��.���mT�i�*r1Y�	���.����q���������n���d'���T�\|2.��[��\|"���?|���S-Ow^�m4��Z���k�%��2��rx��h��W�{��Y+�Zom�X�j[��-�x��`���{�FdX|���q����3��%����7����?��_��K��_��7?�{�������/����_o��w���R���w�����������$(���O����xka3|w�K�Ia������G�����=���b�oW�;���xA��C�����Y�CAl������$o;�#C�����x����/����{�MF�����.�&�V��w�	����_�~��%�s�qo�9bD���@k��o�/UY����{����*�w�_�=w_��~����=��K��S���GVB����W��w~	��M����Q�9�c���F�W�����{�]�6�������{�]w������]���&��U�}������$n�����3�/8zBc�����U
~��-x�����W����C	�l.�v��]�����{>���&?y����C`s�w :?�zs���G��<���+2������������3�#��\��k���<���O��J ������!��!����{>��&?y����>:	�s{��	"y���-�>������������M�@Oe�Rp��`���#���D�^v�X{80�~:�3��D�*[{�=�����(���aF��t�'2v)x�*y���E�>�F����M�>��?��y�}
�*y���M�>E�x�Q�&����'x�RBk[��}�*y���M�>x�P�J��&k��iJ	�lm��L��U
�6Y�\���H��M����Q`;�����I���x�l��[�"U�^v4Y{
�Q\;�s��������L��[pBNM~����FN���)�]
���I��G�A�-8#�&?y���g��L8��������u~d���rpir��g��[pA.���	�]
^���������[���69���N�-xE^	��������&��o��k��=M�����/v)xC�t~d���w������&kG�	����#�:?�zs���{���<�������p0=y�K�r�A8��d��G���<����+r�A8�������\	����\����&7�\���9���������g���<����O���q���:��S��Gv@o-���%��`G�uf$LO\�Rp��J��&����Z���:B�����y�}
��J��&��/^���<����#p���
�6YG��J��&��xMM�1Kh�`k�u����W)��dc����`G�uL#f$LOZ�R�,y���M�1K�k��&��f$L�Y�R�,y���M�1K����&��O�H8������e��	[��c����M����p0=c�K�	8X�*[��#!�&O�&�H���q���:2rp�9����{���������:2rpfln�2rp�9����{.��������*���p0=Z�K�9����������������Z��W���h�.��������}�\0r������dm��+��bn�6��M��G�>�-xC��<y��9x#\�M������������{��=M���.�&�@�u~d����������&�@>s�U����������\�<{���\	s�u"W���&�D>�<{��9�$\�M��|�6Yu�����������)����MV�D���=��yo�!�����wjp����
�6Y5�'��U
�6Y/��x�������#��)��W0�x}
��	"y���MV�/~���S�X�8bF���8X��:�I��J��&�� R%��`G�U����z�`m��&U�*[��:�H����MV�N����k�U����|d����g��Z��������z�`m��&U�*[���k5�Z��������z�`m��&U�*[���s5�R��h�jB&�5q�6Y5!'���&��^����h�jF&�5q�6Y5#g���&k$��`O�U���jM�MVA.:?2�ys���������Z���lM�M����������d����i�6�`�[������7����&]
���{-��dm��d�&s��#o:��M���5�Z�������nM�&�@�u���t)'k$��`O�u ����M��|�L�7�R0N�H�k��&�"����MVE�:��M���5�Z���:���nM�&�D>u����(����&'G�u��Z+��d�p��U
�6Y�P��5989��3���pp�6Yg��J��&����Z���:c�����M���%��D}��K�@X�^vTYg<1#ak�u�#6L��']��%��aG�u�f$$�]�9	K^�ak�uN��������:�
3��2���%�����:�	�^�����:g`a	�5lm��XX�j
[��s�x��0�u��Kh�ak�u.��Wk��g��9^�6
;��3!
'B���g�	i8�4�c'}FNmvZgFN����:3�p�q8��N�4���s�����*����p47Zy�06WZy�4y8{*��<\Gs��"���NkE^�<�=���<�26wZ��Jx�>z���
yxk�p�tZ���x��im���a��I��w�������i���;����i���;�a��I���������i������i���a��I��+��������*�p%<<�;��<\	��O�4�<\�<�=���<\	��N�D>	��O�4|"�m�sZa"^B�����z�����k^�ac������������V������h��^���p gk�'P�4#6�y/
?���bF���8;�0�&�k�GP�4+6�y�
�9��H;f�������
���HN����tifl^�^�sZ/�V����Gc������Gr�&}�K��c�������z��!#�����zIs@�9_�>���a�y�{m��i�d\ #Y�����zI�A�39`�>�����J��Wm^&���'c���@�9a�>���a��y�{m��i�!E����'c��y8���ti8!�&?��B���d�&N�N�%�p&<LA��pF�m�tZy�,����i��Lx�>�����<\�<���
�0������Z���a�J��W�����a��Z+1�����Z�W��RkC ^�@O��!�Y�8�[�
�xcDln�v$��I�a��Z;"1�������w���)�>#�M$���:����M�����L|&���t��@&>�LO�U����/G��V\�+�b�J��+BqmBq<���TL�m�ln�N���P1}�K�'R����0x�������Zm�|�a����(=*`��mT���^>{1$����m�\,y����V����Q���
a����gk�p���*��[!�x�.v�[!Kj�bk�"p���*��[/������88����|9.���V��%�V���
��W�����n�i����gk�&�b��Ulm��\,y;��0G����n��X�*��Q�T<K�F��v+,�d\lm��\,y����VX��%o�bG���!	/�v+�+&\L�H�RqB.Nm.�v+$��D�x��[!#'�����.g������h�BF.���s����3�b�LJ��rqnsq��[��.^��VA..���C)]*^������vkE.^	/�vkE.^	��R�T�\�*\�i�6���p�bn�6���p1}(�K�r�����i�v���p�bn�v���q�������6GO�u ���s�u ������\|��8z����`\ln�*r�A��>�����\\�\=�VE.�������\\	��R�T|"�m.��v�D.>	's�u"����C)=*�~��m.��v+�����Z���n�����9}(�K�0����Q����!CH2�����>G$�V����0����Q����q��d
'&k�#|�H^�bk�a�5o�bG��	C�g��dm��~U�j[��38�y;��8E�������U��Ulm�"�����V<:��8R?�7&k�g���W���nE�y�����n��bH������V\"V���C)]*�%������V\v�����ik�'���W��>���b��y�����n��\Lqb��[1!'�����.g�������n��\Lqb��[1#g�����.�������n�b2����*���p1}(�O���������Z���&N��vkE.^	��R�T�"������_���T����qC4&�8/�[��!o��s)]Z���&?�����wc2������w����.��{���B}s���d'fs�u ���3)]
>��&?�u����b2�������bs�U�k���2}o���l��l.�*"qeHl.�ND��D���J�[��@L&q~yo�����$@L�F�Q�8 �M ~�6�����d�
��Z�8,y�����8�x��8��M�{F$0\����%�V���������-�{�#.�Bk����W+�Zh�8X�6Np���4�r	��3�p0�� ��o~��w������� /��������������������y��������?~|����~��G����K��K�w9K%��v�����?����7��o�'��b�����?�3p�H���\N���B�6^�r�Km^1#�|��*���B�j[��q��)��:�XHh
��^�+$�V���S����hs,8!X$,�c��rEb\a����\�������,�t��K��"3��v{cF����O��X,�t��K���0��v{c�/����ro\�+
���)�[�
��$������[������)����
����o&����8]
�������)��3�l<�ro�;r�F����p��#�m��{;r�Nn�=����#����#8]
>���&?y���������3.�| ���#8]
���G���<����+rp%7��MVE����#8}
F�M~�\�{>��+��fn�N���p0}�K�'r����'O5���i��w0�����Z��&k�	�{-��dM!`F�\����� W+��dM8 "y�;��)��Q?�./v)8NX�~�a���t)�C$��`G�5�3�g����.� R%�&R�M���!��Z�����
3�'����.O R%�V����p:D�^v4Y�T0�~N*�\�S0�T��lm�&����M�4��Y���]
�A�J\�`k�5�l������h���/��v�[�R�"U�j[��	GC$��`G�5�3�'����.'��D8�X��	'C$��`G�5e�`�B�����3��bm�&����=MVF&�!ti�K�98.�&�B$��`O�U���f�Y�R��\��,����=M��LC��b��7���q������{-��dm��d/�n,�)9x#g�����`
����=M��L�B��b��w�����?��,�	����=M��L�B��b�������?<a����/o��������V�e����3����_9x��������9��������B��0�nN�;�2�������������������~x�������?�����?m���O��iP��.s!����?�������Ob�����+y��A�I����j ��L�����`��OD��b�G�Wn���$�Q#�_5����+��j~~C}��WM�$����L�����
bF���<�B�*��I�t�����r����'���'��������$f
���GQ^��X�$b�
3���I�{~18������Q���GQ�Obc���X (�}�~(e2��������:t����DH����������$�S0>�2�J�Lm+f�0�.���g������>��y�~s��P��~(e2����`F"���VL2n��|^��\0>�2�J�Lm+f7��R��g������>��y��?���������R���<L=�,��I�IPx�o�<���l��x��bF�E?:Mz�O�%h���x�~Y���D��F�x����c�J���A����\��,��%����u���=?��.����3*O�=g����Z���d\1�~����)��L�Qy�9��.#^����-��%#�q�e]O�RpAG�Q��,�x+�������U��|~�'AQ��(����~;��g����;���c��[�q�������������>�Rr���\}���_�Xr��o���W����^�
��~-���:~����\���O���$���+�������K$��=���4=�3������%����g��f��	�|�.��+��T"������Jf�6��R�����R���h�@	{ ��7n�fqfD"+��Y��/#�e����o��#��6�W�~�Y���+gh�!�(��}E����2)Y�o���\�X��������*�]�������1Fvl�F���`Y�*�^_m��qd'�_G}?��b������ZZ��g8��N�U&=���D�7�e�{���'[��-�Ov1��<��F�dGA^��jP,����Q.������4#������2����;
���V�aG6��G`���Y��m����eqdw��RV�`G���#����/���6��OM��yj�E>�y��_���iL�L�`�)��1�Sf�|���j�������4K2�����'��y2��A0^��}�$S�W�Q��fX�]0����������U�yT�<��L?���*/lCV,�+�
��XZ%���c������&aS�Y������/����;]�����?����
��
��k��X���{t-��/F�}�������������{e1k��d*�o,�����r���F=���8�nq;�s�a��
�Y�p�Jc$��$f��8�El�wM�������Ffb����=J��g���,7�I=��u�W��X%K�M������ne�}�dyQ�o2i�~�}�<��U��su�o2r3L3��&��]�3�����U����r��D��j�B��j���K��+��q,����y1���~�O0%�X3�!��4a��'�����O��5]G8#c�g�5]
��nO��f:��B8,\�=�������G�u��+�g1����7Z�Zy�QLGg����tp���;�J$��`�O��.�vV3�(��2��?+�1��2����,'l��N�BY�zQ,��V3�5�1L�<�~����e��5���U�=���	�\�<�r����1Q��&����,��%��EsV[�8��Mp�gm3�'[W�Yf]�C�hZm���t�����/������2��'���w;�~�������|���F:��������4����sI�����y��R��������zC<YUO�m���S==s���5����xS=
���w����v��{�m�<�I~����#�/�m7��������p���^!�+l�
	N4�}c��i��3��"�[�N��#���4��m1��&H:�Z�m������7�����!s0Z+YV]
���t�)����=~�"z���DK����a�a�r��V��l����xe����Y���&��0{�����F��0��;��vi������������|��?���s�5�L��__����{����������+��<������o����Y^.�x�����������/Ev��������������?�����?��v��Y�SI�@^X���~��W��^2�6'��T?�/A��O�+s����N��;���t�������/bX|����i����}��nL
�#�Q� �2��n�h���G>�9�2�\>���1ZpAD��������r�1����	���e�M#���q(#3.���PaD����Qp���4��t9�
��U�	$bt�#v�^&�B���41������JB�%�XB� !�!�p�j)EWA�'��U�,�L���c��e��������Tv�u-��V?����8�gh���7��X�Ip�SAy���Gz��D��M���n�����n$����}���,:���u����������o:�W1]0���&���qg�.�0��s`���et�xs�P��{�������_���p�%�����R��S�s
I�<a��|Q���J��H8�=�Vwm 5��`���0������z2
���Mr��c������DT@6�{J��R��}�����X�{���{�'	:�,�=�'������(�]���N���4�#��!��p�9?����� �E����-*(��'��O��`��Ko�
.��+m8~�
��?��q$�H9
;�N�Q2/Vg�<U��r����e���������[���L��&�L~�u/��-�\����^%KC�nA8�$4�wF��@�[��%�
]�QH��;�xe�kN}���#�Ej?�J�;���'������U�E<��-��E���,�"��LF����"���\�:jU�
��]�p]L�I����Q4��c
_`�y�}]C���t���V���|�� ��T�>��,�0����t�s��*\�_���s��OO�&�����P��x�	��^�c�V��fh�gz-�=Y�t4�B�����\��2]���rl������+��	gf�}���37�@�!�!�1�28T>��_��G����	C����_��0�
�������� 'o(Wc�7�����������x��*�Y%]K���R�	o��������
���TZ�(�<������8c���Z�n�E���f�p���C;���������	?���A����ko��g��7�
��!H��_m�����!_����'3�"�b�+Ag�����{b�{'���3�IN��S����t,it���4a����/Qhk���|�5�q�8����F������$��
I�C2�N�UV��������4*F�����j�n������g���z��Xp�X�#������W-���AgT?,�wFp����������}T�*�p)`�=Kb!`��z��]��2�)���a�����_h5�E/9L:�jw�C ��F�yJ��:(�g���_�U���x'�e���%�UL=��p�������3�q��^��p�
�Yl��N�V�S���:P�
��M�N�3�b��ms��H�1kIG1���U�U��;�Z���l��{][b`[��T���_��7����������q�;�������^�[^��+���?f	���(!`D�������@`����-E�.�^��{�2��~��$�*�S>3J�Y��M����:��E?j�M4����� �0������g�3D�3���Y�0ph;4�n�>�1����vhCA 8\�2��l]�"�n�����aJ���t����>�1]�S����n{���a����$��xj��bCt4��B��.���t��f��q�m ��B��.�:tUJ����3��*<�V1]����COp��77�tz�JN�c:�;3��iEO�h	������	M`3k�uM`��V����M��e���@W���]x�kh��5����������AF�����V�Xd��8��	t=�����D[ Q��������������V�U���t<-{���6w���x�a����/��a�x�:�Js�V��$]!�J}^��8�xl��v3�@����'����O�7�����r��U���2�4�2O����z�V�5L�=�p���%16F8L�=��8wk�F]b�\u�Ico�y���6v��]"`N�^�����������&��2!��qo��a���n�"�1]M8#�~�YG/b��1����pF���MWA�+����qL�N��:�C�A�+�����L�	W;��R��g]
���*��^��p-��2�f'�(�C
������%��k����0~�5�s�b��U�	��������Gq]�Y����7%����h
�����@U�	����F���MmS�~_���b�����W��_�[L�)V��V���c��(����	����^��X�L �d���zz��!�!������a
i� o�{���d�#B`������A� ��������o?e��AK��+��(�K:�s��t�|�a��pxe���I�;��*��/?yQCA����]���H�YDQ+"
\D�^oEj�e��#nW}SDQ��E(�Dc��{���q��r��j�&L��t��V���*D/A:(J��f�;
���6�=��C���4B�����~�4�{��2�^�pxa��|��s��U������X��b���F�m�����Q�e��m�
��j���[�Y���7��C�Up�����r8� ;���
���0z	�������k�=�^t=��4TM��CAQ]%cEE�������gj~�^���	���^*�t����h�zE���nr�3b�f��� �\�t�;�%�����M�?O�����y�����_�w7]��^ ����U:/�	��v-����b��C$�H�� ����A��
-egdE|(V_�g?6[��cU3@�=�zu�� + v�l��
��z>��B�@�b|yk�0P�l��v;[�����S>lk�~��a[;����Y��00���$��f�~�#(�0gP�Fx����x/F8x�v=���F	���[������<���qs �����������2�?|���q��Y��z�9��M�����Jf���^��"PZ5M����;"p�	���	���C^�QE/����M�( b6�Z��&�������Y��6�����k�j����za�@�^���(��pw�YVq�7o���}����Z����j���G�,PE��K�1�,Q`�@���*��^I���HP�u�F���(N����AhO�"��{Mgd��})B��I�����$b���[�(a���QL��������3,p��(�3�R�0�����G��`����x-��.7�/����I�������pt�L�[��8U�<����uC��d����l��l�<^�^G}��[���I~����,�x�gk��^�|��H�5�@a�U8���va>�����U$��J����0��n���-D�j��j�v�<�u�t#������(�������c�����#�Mh�9�=JI
�r�X��2�CJK��$���!�U8\��v=ZUH4*K�hU�W�j�-?�v��UE�f��h��V���V���3A�&#���,����M�f�����9�I��)���;v��px�	�I��N4��M
u(���I~l�4�%o���������]���u�������|���?���+���/;��o����?������?���=n
�������^�N�+Y����L(�y�����7����7fO�����!��*�Q}�Gm{]]Q�����u5t�U.t�j
�#�B{�m�kr�����n����Xp����������o�-:}�*��a����J�:~Z� ���H���*�+]8H�:�NW�]��^�\�{U�������]�X�2�Y���
�gWK^~l�����UX�:g/E$����3s4*
����8�������L��&6D88�V3]�:�:�z�l��5��Vh5��N�Z�����_������pF���=:���h\�t��5	���T���:����*������k	g�����9�Dz#K��]U�pYF8#�u��.��Up�E���#�.o��c����~��k~^T_������M}�>�/�7��V�n�~S:��&�0K�]mc�������8����4���+������R^+`X���p�����2,��O�u ����l�?�b�� $I{J��P����(����rWq�n����0�W�p�+�l�\"8�s��{�aiI#����NQ^��h������jV^������P��#p����P^8WU�������������Of��A�0�M �pc	��4���6I?��j����w��&������=`�2ZRwkY��@g��3vF��PE�}W1{o�|��s��U�s�
��b�����O��h�fu=���G����x�2��U�/���d��s�D�������U��*P $O��(oJ�<�A�*��Q�z���'���(�T�m�'4�ul�'; ��wE@6���h�#��q�1j�:��e�:����2	�g�.O�����.�RTp77����0�
��j����t#�����8��+������2��X�Kp5�EW���%���{�Z�f��2�������k���W�]t�	�:�Ya���]���j�����&�v����{�[�[5��{�j�gv��@N51����������?O�����5�Tv$4������k��p���|^���� ����5+������ng�[
g����)519J��+��8��x2����<a����h��>�0����G����3�
�������$xM8<�v=x���k��vI��u.s56W��M��#x��������
�o���-��E��-��0."B�2�zjf���A���*o9��*�E:�T��D�i��K��?W,-w�St�!M���)c��A�����cZ��>O��V��u2�r��W1#H����gO��j��q�$��|���/t��<�*aj9��aj�=����\�~��C�������Y�����I��.�#�V'�0aj����h	�T��J�'\8��o2�4����-hIgdV�
�8�IW`z�5M����!�l5�xG����-�`k�|C��)��""�������F
�$z�q����]�Y�;��F����e����r�3���;��f\�v��������(�-`�=�w]�0�a5Z�)���`�zF�
�	v��/E3����D���K�������O?������]h��=g~6t��g�Vl�%��
Z��������Y1�~�mWW��	_~l8t��i�����������B�XP�����Bh�^z�^�p?�@z�Yad���N���� ����N�����0���7��Q�{n�"�����Y�?�p������fgx�M�i�q�Y7^fc=�	�n�i��Y���K�����]�����8��'/�|�G��v��h_��a���6/��6��+Ky��VK�z���H��0k@��t�<U����9�g�}����� �~�Wvf+�;���,�%uM��D$�O8<��v��}����0��f���a�����L1z����k�s�k�eb�������B?Hr�bEo�I���.W���#\�%O���U-�h�� ��:.\-o���������b1a��i~5���8\�J�%l�f���A;��/��)���A�Z��`����[^�M!�:��]�S�]%]G�[�tB����C+$�q��B�4��o�O��7j����F]i�y�`����[������/����������������,�o��.v��]���w�=M��p-��@�y������ytX�e8��V3]�<h���\e�=���tp�
�f����I7�N��f�7����3����N
5A��8��,���Uh5���yEB:]����(�Z�t��o�kHg�.�>&���-��!�c:�.sKu���(��-��!�d:^����',5����t��u���;?��\�t���n��B#d@�8_(+������p��2��ZpAD[���,�x�{Q���n��aQu�4��j2�w,$B�B���-��\�Y�����"��B�TnyM�@�- �5F��n���[��;]h_���\����2�St������(A���"�����-�r�p���j+���BU�qF������� �-���W�j�����\Qn���[ez
@��}�)T��z��*��n�;)���o
��U�x�L�8e&.�E�kK�:����b��I�	g�_,P���k'��K6�|p)�wB{�������r<�/(G:�'W��&�s��D��g(�8"-b�e��/��q���j7'��H?F:T���8��Q�����������G�!O�Xq����tyF�1UiVe��dA�\��\b�!�W�e����t��	��h�F�X]]�cu��&�u�G#?B?��{b��u���H�!�'���0z��
��#~yt��F��V3]t��������G�����~H7��8z��u�P8�j��.�!���Q�����t����@����~H���Q�p�Ywy�p\���Q?6���Z)��^01����Z�t�?�V
t�,W�����t)���F��b��!�$��t#���)G�a:�H�b{���Lh���P�{��H�?��7fB��.z���W+��]*QL�A�P-�j�M�5Q�b��	]O:]����r�&FO����0]�`��������Z�t������I~���������|�("
G��k���,��m���\�[:���p����6iC���.�����a�j���\��6�6�s����0�h��.'�F���=mhP�5%j1	�b�@u9/��������}ok�~"��k0�������Ih��Z��HZKD\�+���y���nLg\�,� �Z��A!��w7#d!�	���1����E<��f5���f�h��">�8�&���P"�8OH�k5���y[��/�"�}�k���uim1KkEZ[���V��#���G����y�Mi���xWZ�.&�!�=B�[Z�K����L�t1���I��$�Yh�-��w�rr���x��/�8j^t�	��7y��*�,����n�������~����K�_����8���s�
m�=N��������;�
����a��o����������������W���/F�E�h2D��UeY�(YxN�5���
T_�t���F�9��J �7�z�U��0���[�5��U�����:)u���^
��&�TB�\��q����h���}W<�*#U��`H�
�:%��r5��uR������������5����tm����]U��l�Fb}i�w�T	]��Bc$��_#���t|*���������������w�����]&;B��H��
i������%�HB��	�+AG5Pg���%�t�Gg����:S��kI������jB��.���t�u�..��t
�t�7]t�#���>��yo����Hh5�E/uF:��:C
��1�s7��@f�H�������,s
�V3]�<*�A�����/X�vF�ajJZc�u�5��EQ��f]��x]����+��\�t���6�@8�d���#���JI���t��-�����&<g;iw����n��W�E��{����`h�=��������M���xQ�L:n'���}�*W�R�w����I��Mc���M��#a������s�|�@:Q�a[�Z��������Je�H6l�����A�7�	_*�|���{Z���k��^k��|-�B���|���X����k����.�6������{��l�mj�<������B�.�B���|S'� +������	��.��^;` �<S����Y_H-O8��B�\�<��[YhO)������l������^E�`����	7�v�E|�qf�����l���3��MV�BK�D-O8��]���j��V�Z�^���J�����MT��W=W�VYZ�����o
��U���+Z����B��B�8�J<7�;9��/t����~��ww�����~��_��/�?�������Rc�(������]����;��w}����
���wR�_���k~be��y�*��K�t<��W����H��y���\�^L� �H�[�������)jBG��7��7���,�	5T[��a�@l�4f���?��*���F:��\��At�5����\���qCm�Wm(!��I�D5�U���� y�C�Kh���>n�%�������^�C��k.�"��s.��������_���^?�
oL�H2Y�����N��E{����i�;B�nLW�/���tP]	�V��p�����n�2��+=�-m����_�����e4�^V��e���Y6lZ]�9��q���W��j��x��/���[O� �c����/�kd�h��V{���{�y3�b:.����1�����c��t�����\�p����(�e�/*�@�e��y�o���A�U�[D�%���u�ta���HhU��R���p�2*L�p%O�ua��^ 3�b�@���:�
�-Z�����Au"r��Q�0Au�M�AF#Fh�	����N��u��G�m�!'�B���#���ES��c��7HP�p8B�����&�o�^gK�e���b�U�y[�/�T'\����@P=���5�A�,
T���3+L?����G�\�f��p��%�������*�V�d�\���C�q�/������\�D����
��4Z%]��N?
���������Np�q,Xq}xe��.�[�M�����B�W�4�z�?Wr�U\r�z^����,@W����<��K����=�".'Rw-��������h��3L@hAW�v�j��'+ X@��5W�Qr��V�%�|A������7��h-���Z���g�l��$I~��I	7(����
h��m��2��r%���-��6sV?BC#&F���Igh�w7��B��.v�d�!�r��|K�c:���3R.�"v��]C:�r���Z�t��%�.s����U�ZP8�C�����qL��N��Z�B��We��L���z}��������.�MYh5�+�9���t�y��H�$r��AZ��~,�xu*t�m�����L[������0:���`���jT[��/G��J^�J�5[6���V1�2�k��n$���+v�@�U�pF�%^��`+^�*�!��{�������~MT�:��vM������{�&jA�,����6���k�5� ���t���w�`�<J���]nZ��1�^������~"-"N���rY����i:��B�����6�'��Y���d�r.z��wu����F���C @h�9���8�k�l����s��,[Tc��m�`�p�"��3�]i9a��"����	����*O����;�+�d���"���	��=�<UR*�JJ�^����y?���!�OA�~2 �s����x��� 2��p�eF�Bg(��\Hi����X$+��Y�
�s'��H�����2u������"�l!��"s���k�����U�b?3�:���������j��m�#
����_�|��"V�(���X�t�x/^�si�]�j�l�R���,W\�������)����pR��J�|���uv
��6���&i��ty�V
�#�5�.��v�0W�A�#���5���tt����8zt	pt9B��.��tH���:za�V3]t�x-��������wZ�t�DZ$�t8�r�����n �!.5�91L�������g]����j��!��#]K�[P��Ksu�����'�y������$(w��ra�����9�q�j.H`�pPC�wj��=js�.r�w���U�3(7��	&0G8����D�vd�hHC��,'_�qn2�R���v��������90�*��"t`./����=0y3�#n2c30W������`���\
�?��q���/_xm��]�;�8����_��.���(E��N0���������kQ��30����}KD]U�[`�"�:d	�l��������s��1�����#o��E�|�w���[m4������Y�M�#�����~���U����n��/q�������q������������or������������YQ�?��/������?������H���]����
O_v)5K^��Q|iO��?�������~`�e���~d���`�C��Sn|��wga�;�}�+P}{�U����#P�tSN�����q��P>B�	\2B�(��!��/���\�.z��pW
�rl�������:s���\��>���l2�J�fX)�Q���|�A<��CDAh5�s�.�iO��tzHaw��)�t�_jf��0K�	�b���H�k	g$]���A��I�(w�u.�B��.z�P�\p*r����/TT�����'-X�|c��pQ��o���/�*�a�E��wJh_�.����W�I�?1��b0"��r_�xc�jD���y�1����[����)Y��+��8g�%����=�x�ZGZ�p�x�������r9%\T/�]_?"��|���#n��.�����o2\dDy*��s�fS-��z�O���P.Z ��
T�^4(sz4wc���ZC�
�p��*��>������p'��om�!��� ��o�P�|q��tEn�6FY�N1a>�"���l.H��p\�;�E��;�Yq�a��b�Vi�@1��1$��U��X9T��eNH�I����m1�u\BZ%�G���Q����u�b�s���(����EFsD���J�[���� ����Y.��IM��&����&zR��oZ�t���H7�No�����/�z��k!�]M7p_�}����C8���V3]������q����cv��*���%5����#�t�Y��R��L�O�&�(����g�K�V3]����kI����o:��&#�f�H�a�:�!f���}���.Z�t�Q�C���Iw{x�B��Ch�I�B�M�����y�0��G����k�M�za%�@�~"�i�M�'��.��S�(TP����Y[����	gmm����k�y�S����u��������k������^���3k��9�����6J����5�8w���2����~1���<�x�u7�9�������|:(_���(�'�����ih�/7����g��z��r5�����a�8
F�e^,����C 2�B��z`Vn��\KELL:�FEj�6�hH7��>�����aF��� �
s"��12R��i
��;�W��1Vq����|�U���W6F�O�R 
�\J��+��e�������:q�Qb�x
�]��v\"�AIv�'�Pk+��-o�o�)��no�# ��t�]����������
�����p��U��.����4�=I����C��j��`�i}�F��_w�]�Hg((���A����Dp5�E�R�^��l]BA��tFy��m��a�Q5,���E�k�7�^�f�5� ��1���������k�'���Z^���6B������+��#wd��@`��#w�W��%������	w��O}cR�g��	9�Z��p+�'}}n����V$���_h_��1_ABK��/�@�O�!EPh�����$��%��g�pa���+3�g�$�I8]B{J�E[�q+�ZT,~�#�U\���!��\��q��Lh�9��@��@3�H�\'4�!6�V����D?	�����F?�d�~�����l������������VQf��%��
�qH��o���"�.
N��o��a��V}� aI�vk�=�)Iw�����k���3
 ��G��{so�S��� AJ�A���K
<�QV��;�Q�g�U<�C/�G)	Q���s3sE������52W�&��������]4F�U��	9T��SGH=��Y]��7%}	����|����Kp���7)���lJ)	I�(=^�#����s�]��-�iO:���9�����n ��!�Zt1lGg��j����� Hoj���j��t�'5zY]���3������Hg���K�5KO���e�+��,���Se�U	��:g���
f��lL��k;�d��Ix�yW��3N2��F��Q���t���-]��]��:�'����'�]5+���b���Fj}�9.L�p#\�B����_&k�~.v,�*���H^�
�=����3���y|3�&�S;6�Z>�������5>y�v�'xY:+o'���Q�y��1=6��0L���g��]��s�X��.xPfk�d��	�
�]M3��u��)$`�qk����PC�8�/�W��aB
@��f-��?G�C�~6�U�O#
o�2d�V���ke����5��!�I�����������]p���GTi<Br�:������Ep7���W:���Nv��%�gY�tl��c�����f�tUB�q��*�k�*^HH)�^�����*LR#���t�!b>U��I��(�����X��r��I~����+��
��B������^�tl�-��3zr��E�������=DO.�I	�z�(��P��GY.�8��Ci4��V�E��8�
gy���m@7��������%�����.z�^���32�����Qi�Y���Xh�7*��.zX����`��N���I��������X�Vp5�E/��4#�-<r��������d_2��.P�eZJT!S�y}snC����$�
�Lw�Pu��)G���O?���otp�m�T�4	j�n[W��q������r���or5�S"���(��cB���~�@D�E���X�1�Mh�����H2�����������=p3m�M0�c�H�����"�=*q�������}aj�q��Y�_�~��K�G��L��&�~�b�;����q�����W�5n����!�cfV�������;f����O����HN�GU��)����:��&�~Y�q�o�F��(���tu�}sk?4����������[4�{aj��<3��d�(��K�p�"���M0j�1g��$
�A#��N���`P�eMDC��9�6������	n�B��&�~���xfV��%���#vh�]����Y�������x��@V����3�9�pAj����N�d�s��.h
i��6�QTjE�,���QlY/L�
�0��{��.�������F�4�)�������A�d��G���g�ds�J�d���{w�Wet���������V�JS�i�#s%P>Ka��{R��q�3x!d�*�
#�b�1�K�dzs��RxmS"��\<�������+�=��CV�~sJA���t����J~�|�!�a�].bwI�E\r����]���P ��@	-��;Pp���+.��h���2��P�|�]*��t���J�
���@6<S�N0�h�
�%�x0$^3�/�0	-��W�4�����%�8������C3��V���Z<O���hWh�7�&����th�7�j��`��<m��1]��R�M,��1-������"]O:�����:t*�q5�EO�"]:�S��k6o0��U�)z:���[\t�<�
���/W�,��vE	�B�����t����*��S��n$��>�����h��l=��tP�T�Q	#����7(��l=��t��Tjt��c��7�RG�4z:��4���oP�����J�z��NH�����]�Tm��H�~W�
�������k��j����d��kR��8v�7�A5��b�wE���j�=��t�A5F��Y!��ZG:#m�p���]�Tk�-�����#���l5v�c;������*��L���t��c�5�,%��l���x1��t�A��)�R�����4�+�]�q���'�]�<��q������?�3���#P$.#B�\�"�2xs����':��{x-�c���u�3�}j#�1�a���o=�s���qx��F�T�����^m���Q�b�)E�M4���G���?�r~����:���:y2[��qSj��:��w��d�����g�Y^nC��w[��-�2�y[�_��5r[kx[#�B�B�q]����5N\��n�w"������=V�jm�u0����7�>�!����H������������Z��M��T�������C������0����FU�^���P���,
������@���^p5��o%<��xF��
��y��)a�{�����(��@[��8=��FK�
m?�4��������b\��@]=���n���jl���a���P�U��YE��Txl��yA|��0������X*a.���p���.����LhO�#��Y��v������S����n�7��.2�=�@�������(�i����4����>��0���y���po}O*\(�����7��3�j��%9�����u.�*�KR~���#:��(���G7����~<���!��W���q*����2�L����p��e��~��o	:^���4GX���l�0��9t��WgK�$
xA�qn5��]��/��t��g�5�x���[�phk86��+��[�~
�=�J�_�5���d�5Z��a�<�d��n��q���i��&$��Z+G�2��AZ�-���n�<�����$/�Z��"i���D�/My��Uk����iU6�#R�	[/,��I��a$�:��WSx�N�!]�Hg�~���Ql� '���b��,�x�5��w�y��tk,�o���������k\�v��kt=�����%��:^�[�&�3�b����Lp�2�:$N	�f���5��tF���
��[�%��z�k�_mw.���"}��~���`��y�P���1�Z�ab{ �R^;{���������f��B��p��uw=�N���"k��B>{��,�)�������?����{����A�K��������:�o���b��K�I�g4�M���X=��RE������2[�g�5��#_�4.V'I��?j	o������vv�`������eQ���9�����m/��<?�,���#�����������}r����wr=sww5����~��_��/�?������ n��}�~�G�o��W�/|u��0,��v/�A����H�G"}>���:�>�o�.>��U^�����mJ��e<��Dw��X�bb�$!V�_*�Irho�iv�(��7:`�f)LwE�����XB��n3��o/�B�w)*�������$��G�����]������?��X��d3�=^2f��]�b� �{���3�'v�X,��t�q7X�d�+@W�X�����b��m<��s���B�
�Yey��*@Wf4�����q����}��/�*]��]����M�	����yS����2����k��J?L
���75��a�z��_���
��d�3�6��U��� ]�F?E���
����#zpg�����O�c���p��]�9BS�q�:n�r*V4%H�tSS�F���]lAW�n2��Z�h���o��(�jT�b��tF�����������.v���1.��H���I��Yp5�E�A�.u��4d{�������n���:(�����y{��f��l]:����:��Y�\��u�I���:(�u��rD���@��/3�f��:(����Z���f��e��l���zQ�C��t+e7��A��<����#k���	�D����^}�iy@��� +chL�0Z�
�3�&\-��c�����Q��gxM��D��G�U���WF���GD{;"�6��>�
t�5������U\=���t#�w��V��C�E���)\�����#���G�?�3||9�����Z�0�g��t��4�O�8
�+����9���Z���'������c�-���?"�/AY����0�
?��	�z,�4���s����_�����x�w�>fW��g�gF*D�`+�+y��������.u�;OQ�+���[��n��u�Y�!��(a$�Cy�wl=n;��3����\�RS�fM!��������H3A:���D	'd�i���v_�yJS��k����M��p���2�;�Ci&Yd�4z���6y�y��N��a��x�i��?��_���������������\n�����������nF������z��X��&��}��X8#�E��?1u�B��-fG�<K-YfHSK�&:J�2CJ��Q�(��������.z��t�t�f���5	�M���k U\�v��6P��t5�nZ�[��x>�~�'W]��\~�0td`����<T�	�����Z�BA�O��6�$�8z������	^��h�rM��^?�y9Rm��f���#]�p�'E�z�@�t�	�6��)�@������-����	>����N�F�}>��%�T�>]�?�����u+������,���������?|��W>�e2&�S���k(����,����A^���kKp�c_�$y������s���An�f/�0���Nr�4�Z^�����i�(�)�P�[����YV1<ya.4�&������0����m�\'�^���e\q��&�"Ua����KYp�^y��8�W�5��H5����|V�t?O��\���������7���]8.��_���/�������{b��R�����(N��������o_����6�r�.q�|���qg��7|]&��eQ���3��e��?�������}�/y��A�[Q��(*�|�^ucd����5Db���-�+[s~Dd�-�[����*������m��<����@GUoa���v(�;�j����G��t�
N��%fI��j�����>%�������C:��W����Q�5����oQ��1�R{��M�)=Y��2�d���[/*��HX�<_{]�hUXU���*�/���wM�=���tP�
����_ax��	��^��������]�IGV\�^������'4�q��X����Uzw=���AP*Q��V>�������#n�|�&��������<a�aS�� 2#>y�����q�����<�����<����d~}��x�AXqm��	���~q�Y��H��h�]�k����,hI8�Us���uFC7�$���x���v~�*/����,
A����b(
�����J���Q{$Pp� P���Y�(�
��bV(�
f�0a ���X�����}�@��R�\���nK��`��J�mf���D4�Yix��5	��kD#K� \C�b�����hv�$\x�<�W����n��=������H�Y8ZE^,�(��#v�K8����L��t�g���\=x�3���w�O�c3L��FJ�5���^�\�~Ye4�d��E�2�r���� �e���(����Ul7!���1��xEBSZ^�mm�h���s4�H+����Ei�'���7a���q/��2�����}���u�r��o�����=��T#V�g���pE�t��� �����F���+\p��y?�Z���B�1�~lI����bP����t]�����~�[Uz�c��\RUx�y���*��NWx_Wj9��<���[���k5|a��M������g+6�bs6�(����j��'}����>l��l:8#�l�u^�-����N����*�C��fzv���U"e���y�-�~��?�C��3t���$�y�$��.bp�����
-��5.���x�y�v��(�t3�_p����KR�U��D�S��_�-�|��=�(8���=�:��vF���q_��*�!���7�C����������!BBp �Zp��5�����JR�����\eZ�0�x��[^��Jw!\G��!r|�`���zj��%v����O��\-���
#d��B�8�Hg4z0�:	��.MIg�lXt1l�"�'������I��������MG�%�+	,HPt���V���l���gP��"b����g�[�`�i�*	B�X���0���#	���7r�M� �H��*��|b�uAC���}�m�6�W+�&I:�2���d��QO���|Q���^x<kE��G�.
�]Ow���F�����Gj)%��b��<�e����xd�����o�.?"2���M����k�=e��,=����L���
I�J/)�%��2y?vy���]��2��2�7�=|�����n\�����G_��eQ�m����K�'_8��-���i�=v�&wc`��� ����S�� ��>�����+Q?Bp=���2������]F����_W�|�J2�.�_N��"2��{�
�\a]Fd|K�"2D�ZaV�#��7LD�tuJ:��[[��9w8�3����+������^�xMJS�*�,T%^�e���!��e���7�2n
�������Dp�p�"���C0Ph���;��V����q���*qU�
���Ut6�b�~��@qUB�!uy���C�����p��^�'H��"�~�����U/��Dryx�&��B���4�Ua��e��R�(H����q���Z�&v�]G:�i�����g\�v��.�r�eF�rK��v5F6���;�v@$���3�kV��(��S��Q�N�Z�v(
5�j���d��k0���;K�$���Hg$h[y�Ql���3�f;�$�0��(Ag�����(:��B��;��`�M�3�_��w��q5���/-�x��HV]����xdX%��hpHW�U����58�7��'O�48yv-�g�3������=i����!a?�P��[�� �
���F�.�gW`mj���Q4������7�^�M4�qDd�:��?�#;�y:6.Xy��M�U�5�@�X���
����_�u
�&�AG��_��O�58��v����Q��>�W����_���oS�����E=������)~��4H�+m���8���Z:E���6�����	3����|?nV���/��]���q�#���c����g9j��(�O�����_htz*�)��>N�4o�#_�6�A�~��������=�Nf\����*��~�H|�/���S��x���"�@�J"��K��a�qA��[p5Yz�J��p�y�>`��g���I��O�q��FC�,T�eL���.��O��H�U�f��,�b�U���R����O�=�:.�P,W�����J)����x����]�h<.�������<U*]9�,g�FE��JF3�W��=W��W�`W�h��'�oS�������y��^�-H�\����	�����l�F0s��]H��&_��w�l�$f�"%��5�J�b��~��l]�D��t����2#����k�@W:������I"]��-u��.a�!��HgdX��(�c$Wp5�E�$���|�=�����\�v�5I��Igh�v��j�d���3+���w5\�ym4����jH���6�F�U���n$�~��V4<��B
��Z�v
�p�U[s�y��$k-\����n"�!t�}��<�Cg�c��o\�=��ky��zKLg�c��KHg�m�n��n��l�]��f��tF���w��'Yg����(w1��e���&3JU83� ���y����l�5�C�'����~W���c��n��l�CfI�8��I6Xo��m7�M6o2+�6��F���F~��wcK:�MffD����*m��:�n��2��Egzyb���O�=�j��2Y����~�+��'�n����;��j�����]C:+�`g�]���3j�������/*)�U�6]�Hw�Q�a��E(���)�a?X�Ne��S�W��KJ)$W���"m��]c�z�N�Y=���N04r��M�~��fv�~
n����������T�P:�|��b���j���'p�bz��d�
�P�����&�}I��'�y�I(��-�@	� ���)���V�Y�H�!;Sh_��	�O�������%����E�jFC=X� )��U�V��r��Mh��">�@��/�6��+2�@��
�6���_1��H��4�-,���9)��� �7En�}/>~���2~����H����y�d����Gr�!I������{��Kg�U\��2���1����������l�O}����:#�H���"�B{�c��k
���a]������Fx�q���A��H��n��v~J���q�r"��v_�R��f����7�]���_p������4��_�����==<P���8#��u|�h��-@2UF�_����L:8P*#U��P&kp�y(�J�V�:��5����2������.�a�	������U����H�m�3
!�� B#�u�3��It��z8�W�]t��x��uw�����7�?�`"-_������.�^�t�=(������H�l5�����yt-��B���=�����4��������H���Q���[�h�1����<�F�Piy��q"�q�%����n�I6�q�k��]m7�E>'��gn���.z��#]�8��8���w�_�W�]�������;��:�Hg� j��/��@�f���(7Y�("k�����+]�hx���bSQ�bF1�@"2��D�7ExA���=�c�(��M��H�fQ�p��(�!Dx�u<=�X@��,�5�Q�������.��;��@��Ma�3��0"2�!��1�{�pADd������8Y0��
��*��yQ�M�5\���%}�}n*����]g������q����Wh��FDF:���]�7���Y$vWw0r�2�������4��6w}�MY���G������S]�S���\H�g���� �<�:�O�M���%"��{�x�p<���<��2�]�5�E|�;��P���47��a�S���5p����q��M~#~�e<��f���/�{��9�1���dT�����^o��` ��#]�p�^�lW�!���2�����mbdfFO��v���O�pK^WW�}�<��	W��2n��X�	�S���%�L�,a&:h����*�\��%�����o�i��OP��� LXt��V��.Y"B"��O��Igek�����%�M�3�^�n;��\�v����q���Q����%�Ak�Z5j��u���$!�!��n�1l�%p+�f�`�%�y�%
�1��gE���$������]��N�k���u����b�Q���tF\�Y�/ql���3J�dIt��\F:�$����N2��l��:�'���.�I&������%D��{�y��$�tdf
�b��l �q��>�r�d��k��B��c]�=�� ���&���lc��#�9��w��'Y���d�wE����e�+z���d�wE�����d{��moW������&������MV��iY�]�i��'��������&��7���6���&��7����%
�f�����(�3
%:�a���QM\fzy���'������b��6���'���������;Jc����8��F�Yq���w-w�F�����q��%�����v�[�R���T�[��]�j�����of�<"����V�bF_�m�#�]���.C������~}a�\�(P�
���p<��k��b�	���\����~F�.H�
�p�
�)�p}U��k	����k�0�:�Vb��r#��"�teN����)?~����^i�@r��n�K/��H[�A�#��o�����`�o��[����jf :.��X���!��:���H>�����o���g���1o	�QNvC�\�>���k��nXq���������O$���?)�x�gt��p5C�L!�}�V�1S�73��>m�)�/2�<ka�1�����%��^��S���P�(�����V�i�Q8,�H�Y�vM��������M :����������wo�S�*p�
l��[BdK��x����-3�w~a��9XJdK��x#�g$n�;�0�\���4�1{.�������1���F�g)��%4�.
M��_���Fp5����T���o���f��o���9���;�0��<�}!��x��	�f��_k��B�;�����3�yF�8�����Df����j����1)�g��,]C���	�f��_�y����;��&���=����h<+oj�F	��j����Q��'���vaT)�g���ra����<�]��Ws��B��W��:�����y���U�'?Z��h{�����:�x�ul��t:�B���3�c�4 2�)�Z�4��	�s�t�8F��p�~H8���[��p�X�I���i��q��	l�FJ�P�}�1+	�r������Y!h0�+���Y!h0*���!P�C�Mte�U:�:��!N�_s�u<!+��n�c�Y���nL8�C���:T�C@���Pk�
�u������f4��}EU?$6A�UJ3�#�u,�&�i=^k�f-A�V����d�sBAW#4&�Z�T�V���[p5�E��@:8�W�]����Ig���n�&��Z9��[)�w|��lg�E�������E�@��t���Yr�(�k��NJ.z]2�! +�g9+�_1���^?�t����wL�\�v�[�����H�pV�G��$�����u�@�'�3���~V�%��j��^��t
�������I�]�.��n{�N���n�I6uz�������,��1�Z��N������?�/lqZ�X�h<��[��V�|,���6�����atd�au7�N���G����u�Zf�ja��	��%�/�I�'��t'09��vb�����X�(.����5U���_�ct^_kk�5kk�����
����F��iJ�0���qF��Ox���.,"�x��/��xpWL��"5J�D2�H��
���x�W�f��2^�!+e���
9���z^�x�e���Ow�;���x�N��o�����=_�J<��h�� ]�h<���;�=����YN�^P�����s��7�x�@���(�!���"��s������*���'
�Y)��o�����xzZJZEO$����o��H��h�3�������`4��Z�����&�1]Z��0^L] �+�]c:�.Ts�B��.��SJ)�W.���#���5�5S��|;u���?�d�1��=�ou?e���-1��u>��Ci}�����Y����y��9�J���R�7%���w;��#�5t����!-�G���xL�Ue�.�a$��k`��kd>��[�������"�%]:#�UI�A�6C3�9�qY��F���q����.�����)�'�H�1�@��]%���Xz��$���(��;��@g�U����H�W���]+z��m���rT�$?O�j����.s9F��?��9�K:m�y#�!n^��Ik���I7���aZU����x��������IW��0Z��o�#[��#3���v���V�D��[�A�2�j�����t5��`�U�-������p1��%��g9+*�R�]����2���tF-�����'Y�g�f��;���3��8� h��<�j������c��tF�����'Ym�d�I@1l���k�����]���1R2�$��]���xW�>�Z�d���i&c��w-|?�{�y��$k�6�f2F���3���n��qd��+f�h�5�� �g�w<�:�`��c��t��q�������f���%���y����l�5��Qz�Mf5�2���tF���m7�M6��2��K��$�7�����l0�dV��(��&[�����5�F�Mfu~�c;zG�:�%7�b��;��{3���v�{��e2D6��'��x76���n;���2Yw�`�
?��wgX�����t����m�b�7�P�n�e�w���]f^y�.)?$?O0�����8������D�������}�����k��(�]��8�~-����h�������k7 �0�]�����;��YS���3@8�B�\�:���HhO�+s}NC�#�qx]��+@x5}�b�=��d4������\����������4<f��#�%���6����Hw���Pq(�����;��=����������U,�Z�A��G�����z{3�[��j��{�:��W3^��Q�M4���>z��e�g�,���>=����H�p�\�x��F���4���~�#��Wp5��/LC<<>�W1^����i<���0
����3:��oK:����h$�!R�:�:���Lh<C�ln*Q�W"T ����>0J8����c$��4���>~I�U��3:��;r�U�W����8���Fp_���1�t�����>0�z�Ym:��,�����t�}`��gt�7��G1^�h<��}�2p��?Op5����h��k^�Jf��?�1�yf��(�k��k^�b\��?�5�y�E*����[��v�'��������]���Q?���������g���y�c<��:��W�}`���u�Do�FO^o����������������Wx������<C�������G�`��6�_��G:���t�����5���zU����ID!��>f}���g�y�^�:b��k�k����4�����c��s����[��l��B����(sXf��W�~X:�[,��gw�������?#��PL���G#^R���yb�9$\�B{X���4zE��D�x��
�rJ�a�q����.����7�2."Zb���q?��je��
T�t%"��{�u�r<�u\����x||�o�9���bW��e	��Ln����(��9�[��#��N��5�)sH8�"�F�CM����5!*�	Q��	w;Dw�
���2�Uq]�U�d!��g���������o�����.$���_���o�����]�qyQ���?^������|���?|��Gn��o���	�k)������~�y��d�<����=��3K�GKf���t.!�U|��q=G��t���L���j�Y���6�z��L�k9���tF�y�nX�ep�
�f��UH��N���%d��n$�Q���KG�u�#��,f�k��Y	�f��5H���Y�l��g�Q�8�b�Qf]1��j���M�3�0��Y�8��IgT����(y��O��GG1���{�YG�pa����q�:V-.�����R��(Z�Y�h���8)� �+���/�I_��A��h7A��jG�X�����������y���UQ`s7�>��&�p�fT���e��0Uq����j�8��u�zd-���FSHSV�M]&g���M��pK\1���O���OH�����v���khJk�����
Qx����H�c�A�}��]�e8lK��`��L���(������7�xFc�:z�m��9�g4�6#uQ����(�������I���j��/^��xF�����q :���q���q����0�m7�y�x�g��f�(�+3�h���}`��f������/Jx5��}`T)��;���G=��*�T�W���}`����j���9D�Iit3��lv5�����U��0���4��d�����jgdf\E1^��x�8`�C��A�d��.n�]�,��9��V2K���;}�����#?�{Oss���Y^f��o�Hq��P�����y�2=We����;���H�N����c �3���z�0�������	7�A �K������~��3�z�� 0/��.
H-m@�3x#o��q3v���a��������|���'GD�A��ky�t2jy� �"�wS���O��+��,��bP�2�B�S/L�������������H
�++T��0��C���I[1�0��s8E�V�]P��s�����4�!�]�e��.c&L]x>�����'���G���M�R���1T�4��2"����-)Ut�<�����B��UF}�����b����Qm���k��%�%��I��s�/�6#��/�,EF���"�zf�����!D����KHg����F	�w��j����t<�:�������t�fh1���w����r���Mz#��z��1����n���I�?82K��t3�,��n2�y�����c:^�};��t#w�����&^�. |}�{Lv�x!�����������Y�jv�OX(XO�G��B��0+>�������~u������O���dD�����-�����1��y�h-�����P�#��=�Q��T�Z�,�>��h�i"�^����l�_*z�t��x�k�v[h���9��Zz@[���q=	���p8D���s�&������%Ik�Ao�0yj�C�Ckt$1�����B{��dK���k���J~�q!�w�Bu���'I{�{?�@7-i4@2�G��t��:z�m��-*��:�l�A6�2�M��hS~��{j� ��(� �����i�?|��1+��;.�z�����"t?�������'�"��Q��X��0��r�W��	&�\?Y	G/����d]�r���>��f�d]�����$f���L�M)����������'��&�X����K����R���B:������K�!
�Y�q��4�������=u��Z�]�3�*�Rg�e�4�����"�:sA���*NS.�:s�SDhu��F
TY�pYB�^y��VY�=�ik�3���-;#\�]��w���r��[�Ac#���b�Xpz�f�`�=_����S�w7]�8��%&�2���	t��Il�N/�Y��qL7�N���n�.'��������*	�b:K�t����V+�(��y�uz�jw���Mz����K�������}�q7�
����b�!#����n����`������_����n�������Y�_������{�q7���VN0�k���H��v�]QX%�����^q������&N���r1W�����8���*�d�7���B�����S:?{*3^s�E�n������Lg5	R�xA����
�K����t���Fc +E=�H��/�6����-��d�<���������D7�xF)�:z)6�u��3jQo�c���(�����N���{�e�M4�^����m_��<|;C�i���b��goo��f�8��������m����*t���b���~0jQ[����G������o���b?.T��R��@?f4�-M�Y������ms��_���������+�yo~�1$�o��?����yz���6�lR�������y<��A� �
���-������j��]��tl<��|tEam�����e���@tx�V`��[`�
�����Bi+������p�\�Y�d%T���P�����n<w-x�����/�����d-T���)N�L�U��4p����%n�����M M1���\e[�o"�RGO�p��>��NV�/��:5�ta�����Yx��+T��e\�B�H�����#i��+	�Y�1S>WK
x���ft�t���e|�m�����f�M����XaRH��]��`�Hj�����@:�`ChUe�@8�"��P=��R��
����<��OA�y��"m�a���� ��a����I�/�"���p�Q�f�`�vO�e)�������oZ�t����kH��v_��H8���2�b���N���n�w��L]�N��t�e���1LW$�3��Z��(�+x�z�����nReU�`q�
���� }���M,��*�b���=�����FY]�N��t�v���*�&��Af5�b:�f�,��nRW���5�Z�#��)�n���u�h��7��-k!}�Z�S���+�������^����@��p���pa�������g��Z �4�=�_vJ��1u^MVu�FZ��*nU)
���4���8�I����rZx���t��jJ�M�X��*��Q��D�Y"���{��m�Z�w���QQl������'�zW��GFYX�)mg5-��|&.y����#G+��x���s�*�x���k5X�c���na$Z��[�~O��
���z��l��YQ%��Q�5���t(�.����>+(�\�i���F���I�}VP'5�B��g����N�D�Y��8���Sp������Ih;#q��d�v
���wWP^&����U�b�)�|�
��MPFi~5K�SE�_�&��G�j�|��4?����4�,��:5��=M�{�2=W�������Q�D��
�v�����4�JL�t|z)��~"������Do�:��t�N���yS�K<.��8��m���_���)��e����'z=�>�!��"�%}���LS}xI��.�8z����������u|�y�/���4����4tiN�Q� `~�7BI��R@�V����Q��s _�
�9�Sk�g�H�	�Nw���g�4?i����yf��p�m�>B���a;��b$z����%+C��D����;���s�q���9k���=MWg���eV��(��k�km�n���}M��N�>�n�&���F���./']�F��#��!���&/��u����'��Z�%�e�-�^�Y���k����g]�3���.y]^N��t�!���:�1Z���[��0B_���n�����D�	��N����=
}/��K����������^��;����7��<!�>��gv�5����FLs��]���j�G�__Qc]���A���5�y�9d������`�&�]���;�llw����q��<�|������O�n�_Z\��iA�4��	����~��@�|�y{(>L��z�Y�\�l�5p.
�)]��)a�Fw5�j�0��q	7F��_�h��6�5|�qnZR����i��.��8G�yI:8�w]X����.������"��W/?�Gt?��l6�5y��?�5�d1���o�B?�����u�<�|�����Vm�8nNB�1�DH9ff-�o�b�(vH�����H��A ���i��8�:qW4�OR���~�q�Lz���[��R���$�].���e�%
���p�XQ��������)v�kO ��R�����8K�r����,�sUx7��B)v@G1��.�q�W7�b����g�&�l�F�:���q�h���	��!�Y�J�P��u���w�C;���C��u��<�j�2C��'�
y����=���?��<�^�tTvd��V^E���v�It�������M��RfT���eHA�����FU�Z����Zh5�E����%�����������!�$����[V��n�uc����i���`��o���a6�H'���?v��up{���/�������������v_�S�����k=��r
��4��-7NW���%���{Q&�w��`��%��dB��L�I��V��aPe��]v�G�Z�J}�K�"� ��a����0r��u(�/����C�=�k)G��^1d��I���5��2qz������z���>~�!�]���q��Y��q�_��t�������iW��v�N������K<�n���N��(a��e\�v�K<����3%7�/��@��6A��3��z����}�5�����'t�O����m��Vql7�v�YQ��8���Cp5�E/-F:8������v�K<��`��l��.�����=��2��F8W���c;���b��
H����Q��U��K!/���K�2���H|��f���������_�������O�/w���g�j�������NH#��[�Q������;
g�/�t��0V��@�����0����	n��Q[���1��E2��9����0���]��)�<����K~�w��w������u���SQ"3`)�+w������dF�Z q���tF16��H#K8n�y��;�JV(�^��yxw����p4�.�r�6����@Cp����Qu�e\�D���/��E��4�������w��>�:��!���}�u����nNw��%"VE��u��1{{]�uCF=R��V�a����Z�U����;��p
��hW���BId	�����E"����H�5�]� �����&W����N�n�������6���9����l��r�o	�v�m�Mp�~k��<�to���
#.#��I?�jK��re��d2���r��s�Lp��s�se��Dh�=W��se�N�Jv�s)�V��s�m`�5������H8}+�B�a���s�p7��M
�?JAs_)h)R��	����Q^
;JAA��=_E���*a���C\Vh_�"%��B{JJ��?��X
B]���������-%<��{)(X{���	�/%�����sti�x����=��tm��;�A7���u��y�b�n(�=L�G:��wk�>��xr��de�yr�'.��X�Hp��F��������E���{�hH�-�{�M� �v9P$�A�,����M��.A.�KA�*:��$w�*�3�2<P���c;H�W���Y�b1L��)mw� ���u��z-�l���=-?��|����N����.��.7��=N�8�n�2�"�zGsl����p,�Z���\eKz�Y�M-�p��x��J���k�g���A�V-�jw�lU.	��#"T��,���Q�qY�m�\�%o���t�c%��t��{�uL����fS�V-�j^�/Bi�@W'4����UKGF8
Z��Y�*A�t�c�Ip��1��h��C�7��mZ�/��������pJ��r��Xg	�t6lZ]�9��3��+�����m������|&��z�Xb� qv������m��0���R����r#�;��� �c9^G��k���7!�(����Q,7��/�g���������a�D��Mz�o��%M�`�:�V2�U,�p��,�&����j��j�����b9��jC�������
�_��8}Q�F��p7u�M�V<j��7����Sk!�{��iPF���g�����p-�B�RV$�5�K
�b?=��~�C��YRn�z�~mED=�jT�����C�����G�}�s�~T�4F��J���zJ8<��HG�v���R��x#Z�>�y	��uc(aL� B^��J��'J���hH��_�K:.���Y���t=%���
C'�6�8O�fh*xb�s�`�Wg�:}/
=H�q�U�G>=�u�GZ���T��L��/&���B�<uy�C��Y�Q��^,�|Z�zy���)33�1�~Ia�b���&���l>�[�y�.�7AhOr��wZ�WB�����P0��^��	�&�]�EF�1�!����`�e\"Z-�gY�%��W�tX
N�H:H��>�=�:.�!�zr����iJ=G�G�����t��K��$`�2�1g9��H:H�fE����1��H:�C������������E��q�5��u�Cu�@��t���"�A�8�c���PoX��0�j�A��u����;B�X.X�O��|zH'M�Pz�����F����E ��\�l�L�X]k�4i�j�M)������b:�
�b�`�&_���ld���1�Ph�_TbX����5���\������T���5��	w��4��F"��h���$�O���a"��������s����$�:�������� 1B��H�S�:6���W�@�#�!���]my+6���n���M��������bm�qfgE��~��3�T�tFgEWG/~A:��:Clb]@����;����w :<-:������vxZtFg�-�K:vV�����4���Y�3:+��f�Y�3:+Z��H������j��I��A��*~����bx�\���xc1:+V������;�����G�;+vFgE�7F��=dtVtVu�0:&�����AS9���uS���	�0q��k�h���4��c��c�pkX���z�>��N������X&��aV�U0��t�VY1���p���$��N4�������^����c�jlF�D:<�w��}2k"-�� ������?��c����1���=�:.�!.$u�������9?.���t(�"��u�W(.��	�eKF���������H����n"��1�":���J�D8<��J����	���
����9�t<�
��5	�hJ�������z8Bw��&��z��f:K��t���z&����c:�l�.���t�|����uaD%��?�7��%Q�b��t�??z�-���l�=��c�wo�����QL�d��H�>�t�o����E-�(=����7-S��e�|�L�h��xX[�_�K��1=��Q`+7�W�J���� 2&�A�.��t%��o?Y��@W������jYF�D:��{Xkd��aQ��A
��j�]A:������e���|�<���Lp�����/~���\���u�������|���?��7)=}9�����������R�?��/��������n#]������W�N���8\�&n�����o��|��=����mlp5��~w��T���U�����y�1|�p�	���V����4���bu{�c��������8��c[p5�=���6�D���mS��x]F�a��f�ux�
�b���9��%+����Wb
l<�dG�'k����G`y���fD�E�����U�W=���u�W���������I3L�W^����k���2��=�H�8�����^��J��S�5��Ub&�p�t�7�FL��7o�����7�i\w �("+�W��F<D�o�F���F��N����S�sO�����u\����fa>�:�\F:�Q�z�|��K:�`�����49�hJ]��S��M�����:N��J�R�2�	������%��tp 	����0
0�����)�Sj��J�!�*��p�#��_�,
�����{����������0��pH9���i��� (��N�8��gJv7]�KL�;�,a�5<�����mPFp�;���MgTP��t-������a�8��m���nZ��A���o�^"CG���^
9�m�x��z���y��n���M��}���r2��&h�d�"b�_I��7P���+Va^��	�H��p�����a	#\��?M� �0�U��v�;�{���������,t&���K��C]�YRh����@W�W��/�t�����RiVe�3�-i\���Ga����s���D�0M��a�6��fB�
������#�n����o�
K���NqC=�w<���!4���fX�{-B����e�K��Z� �T� q������A��;Q=�r���z��7����AwF���&H���WBl*�v���V=������n8��&L��D� �:rC4��X�#�(F�}��o�I7�x�j=��o�
��Z7�0�@���`t��x�K�"�QB�eB�	����i�,�3�����x��q���q������] \O8� D�k�rxdw�!���(r�=��p�I���u��@�g�v_��B�����w"\	8S����p\�t\�p �F��n�p`�,�R��kZ����P�d��/Q�#1 �y��z�Vna�H�z���Io���n�sJhO�2Kn#������@z�q1���f��M�������<��h��F�0���=%d5dA�[����:~�*�� ���Y$��5b�-n� x.��g\��gK�����b��]��'�Y�$�����3"��/[���,����gK�������UFh��4�{�:U�1��h<�i���(����W�x�������C����v��#������WU�����F��
�}���C&����/P�����������F�p���7�B��:��&j���Oh���$k���(�Z��0����Ro��zd���_�������=C��q��P�D�W�*�5���n��=��6��s������q����~��;�{Q{�5|���q���E��# ����1�A���k���IKR"j���)����R��_�u���!�G�	;,,�g]n��#Y:���;��pcB8#'�P��1U_���w�t5�t����%f����*��&m�Q`r�;���(z����c��p��tw��:0�r��S��=������v�������K���/ �������R��=	K�������*H�~9���"jO8���iO�2�*l#Y������7���6"���ecZ���=���*���Q{�����t�D��U���	�fk���*���|J�6����i����(�U�]��C�Tp��.�F���F����h<+v��� ��:��W1^t���������h�>��t�@]l���������o_���������������%j_��_|���&�f��n.��#j/�F��������C������} � �����>+0�-����pA���dH�c��^�M���S>��	�y��wX��0�>�A
.��[cCo� �8O0���X��a�8O{����2�"���3�.�����Ep�����=��c���^�`&j�,��V[a�~�8T��9��B�E��'�����JFa�w��jc&jO��pF]p���w��r?O��)=��m&\��SGZC�g�%���������,�i�( �jZ�t�3�t��F�m��t�p=��:�%*�a�4!������Qf]��YhOc:��w��4�������0�K9���r�F1�CAhOc:xw��t���nRJq��g9a�Cg�U�,D�i�!�X��9���pw\�v��]��.�Hg2w?(��\�v�^����x`��5�Ql�s��<�&�
�0�����,k�w�E��{����(x�w�lw�!&%���b�"��FY�4���1l���Eid�$��k��Hg�d��w�*!�Q�=	��������W�}V0��04�����k�Y~������j��*�$K�g���O��z���fk�d�!�J�~W�|���I�����IVo2#�g�kJ�5�I��������[��� ��k�&k�7�����'Yc����t1�]����e��<�Z�h�������u|������u�>f�����[0pvu�w-��
�e���3j;�{���o��+3(�������uD4T����k^)k�|�Jv!����"�o�W�H���a�.��<���Q���@��QAV4\��9�A�P9�&\��9��>\N��B���(����E q<���+��Y�5H��"��]%���t�hJ#���������F:X*5
�x��	�zD9�A�JD:
���J������W=O����w� �H_�o���6�����I����>�=.6d�}�RFiG}:Y��*�'@f��	�O'(��*���:v�	���p�y.adEU�5Cz�~S�N<���J3	��������[M3��[�uOB#�$�2VJ��������Lb�t\��*����,�Z2��Z�����*������!/�����\���~��_��������e}�!~���?~������|���?|��ON�����_����8��G��o��"��?�<�F�2����c���f�v���N�P�9���^4k�7�]Ss���u������
�����zQ��.��x�I�!6?�U�T�����Eu�\Q=�\C�b���/vf�ff��G�4�O�c�va�}r��=�P����l���7l�(���9��7I������]�F��t/&|��&��j����"%�1�v�%����.�|�t-�����k��Hgu���1�[$�Y�]1��!��hc�������2"���5.�n�]�]����U�K��$������k�Hg�d������J�&_��]���6"^����#�UC(�|�s��<�jC�^X7��c�R��l=-�t<��
����R��l����MHg�J�����'Yk�P��]���3N���(��I�i�F��8����i������E:�����7);��������b1�}%�3��z��:C����]�WD�Ql���H���>��oP�.-�Ob���z�����J�W�w��w��$�����S�H_���)��]��L�{����6V�,zZ�x����{K�q�i1��i1`�x?_�a���B[r�W82�m��DW����(7�p8V�vUv�o��h��������"�.�"�B�*�B�^nVX�u�3�F)@CV(7�p��t����G�*7�OYAV�O��S���Ao!�/���\��lw���d���	��BU�(��.��)�wxV/�@�1��h��*>�HS������7#<��f�Z_��!\�]�^���sn�Src���1���i�'�N��#n�37&O��o77�G�!Y0���������_��*+aq�jv�����m��/����6�|�t�n5F�@�����w���[d���3��{�eX88���KZ-����Kh;z����q��
\a>�*�S��G�d�7_M�C�C�=�2���z�������g�����*��9H�8��.o~�8T: GGH=������9����7���S��Fa�9�Cd�_�����Q%������G�ywW��a�)b�F���>�ab���2��t�.���4�5L���Pp�*z��t���f��&���3������W�]t
�p���������j?`��b��t������vy��5��f!� qi�A�!��Kgq���\c���k������dl�K��<�������e�V&D�����������{g��8���/C��h����w���/�_�2�]-�i�����XQ��8�Hw�LuF���1i�'���MY	����g��-�����I.q�l=����q��]�Z�c\���|�G\�������_S�H�dVM����d��p�����&�.��@��@�5G�U/(HQ2��.jy�'P�p�����%��O�IO��89���>�
	��d�t�����1�C(Kx���GBg�|*�'Y�C�Sk0:�Z2�cH7��>��+e0|��/c�u����(�*C:��w��[���1��B����r(���E:���0�ra�1�����J=��-�:�a���s7�����=�9"X�Xz��e%�qO�������GO$]G:������x�={���]���p<�n;�X\�v��I�����TEO�������w�"/���)���� ]C:���G/?B:^������,���b��=�x)��������,������I7��p6���-��	����.z��t�AY	����{��l��1�L:���[��~����_�9/���k:��@��@���(��H8f
�n�0��0�g��X�B�\��3��C�S:��������	(	<V�^��l���<��X�HNV���U��2g����4�T���r_<%�L<�/�w=����s�D�����"�~D�?���q{�����H��N��"���������i��72/��0�r�ba@l�C�8���JM"�F��ElE���f)�'9��
�����Dz3F8�M��;���(�
<���*�i�i���hT����4Z��:��"���#�?�|���{���2����'�Q�+TD�t|Al�!���*�$%pB�E���LAIW�h�����0m��uO��a�-���k����
7%��jD�0�3�T"L!���3z�
�*l3���<�W
&��W�]����Gp:�gE��"�F�=zv�]�����j0��7�f��!m���3�f��k�]`'��Q2��8���Pu[.�8��Ig�w?+�?��EE09���mS�>���]���j�&��O��j���Y�N�3N2���6�y����'YkT���vw��8��~1�]����Q���ql�RN���.X&���z��{�n��~G	��j���]A	�dIx�"lQlG	�dIx��1lG	�dIx�����%���p���D:+Z���n�9������v#�.�{��1f�����]��tt��Mw��t�x����O:Ve.���'��O?�8bw��=vI��~�e���&�t�p���L�\���3��>���4^�
#(^����&lUE$#^
�U'J<'�SV��"�Le�kGS�.Pgm���c��`��&r�t,��c�"+BK���Z���Y����#n�AS:V5E�g1�2�#�k�;����	_����J��\
_��/@�xcf��/��H�B�t�\#������z�3�I�E��0��:��������u0����s�h#�|�x�=�-����U����|�U�����dy^W����J���D5����p��6{/�4IhH�/���w�k�{���K���*%_d�Rg��#_#�����D��p��"_S��PY7N�gwHA�����nZj�0^W�U�eW��F/P@:�r�WN����V�?��H���Ig�nv�wuB:�SF/P@:�n��8�}��
VEmh�����
��s���]�Hgh���/�l���,�gY�
���q2;�Q����<���k��4�-���c��<�Z}G1�ql7��8���h$�u|d����t�D�]O��j��W$�U']K����U/���WT���-~��'�]���8>yX��d]r]6Q�b����Y�x������I~l�A8�}�~�T	$DK����qM�J\�N��pAT	���%��t��

����V08L��x#M��&�e�@����w[�g����F�
pD� ��Fzc��/��J�g�uUB9�JE�P�V���k��Kk4U	M��?
�DU��^,�z��3��e,��1�D�-����An\�6����t<4����������Z:�Lk���F�����f,�t<1;�S��6sa$����Hb�'�q���B�t�a�e�� H���&	���e?�v\)Vn���x�B�����H��7��kD6�eJ@H*������6M��Ot���1_@8���V��+w�&���_����8u��|7�,�&�0$��%?~L�,��eZ0H'��%C��/�q��'h7�������'���;XM
O����JS��"(���.��t�wF�bge�����p���[b��t�����l��Dp5�EW���#��}����\�v�[T���H����_�U����VPU0���z��Y�����-��lN��
�������"@ql����L�&�����\�&���\�v�
�U��
�N�uS1T*�"��
P'Q���'
xO���Q�G�<�:3�V	�0Qx��@���E�3��l�J���,��k�%'���wc��/��hV�;L��xx-
�v�n�X���4w���.
;��)��F��uGi
��j#����O	�/Ki�����z�WJ(��-����'_�<��������\2�?|/�W?N����^�c�,$�Z�j�$�G:��U�/v(�p#���+�!gX�4&��!=��7Cx��:1��L�R�P<�a�Yc3�q��n�h���^�5/�������B��k2���nIV�������.������]��v����o�
���Jk���h���|����f(��2�aB��C�!�UB�����/�������:�U������6`Y�F�5�g���J����u����Kd�,�P������]EoT:V���*>������T�t3[.E��!]���w�wB)����_�b����Hx3�n��[��~V~���z@����`� �Z�N|j�
V��9<�Q9���&X�
n���@&\��A���"��|aD��~�x���^o�)u����^��z�a�3�4�������2�tV����&N���z7�����)��8E���Sd��#.?O>�U�*�8E����f�����rl�C��������r$"��^�,7<�
����}��M�F������	�A�.�'9&�
���o���r9�nHhI]}g�����7��.��;n�����q�u<"�.��tM�$>���'��\�7��(j��2��B�����������!�&�����*9x��L�P�e��+La_���(�
��>9\�-Ph����n,�[�c�^8��Ph�6�����\�i��$]oN:xWsCF��]������v
d����.z~
�z��F]���T��l=��tp=�Y�]��Fi��L��A�
�����u8W�]=��t���FN���P���'�����|%�H:�t����wY=�����v���f���iI���o1��F��D:#�����A7��[}%���5i��m���Q��C�D�����`HC\ty���\�v����n�
j4�!.z�k��$��{�+&�F�NI��Y1�$�^��c�M-���8��}������D��HW%<���/�&Ij%I�g���������K��-$��Wm*��[�������3����|�\����	���.#@���aVb,]�R���[�Z<��-��.����h�Q�\]��=������BhO?����4�K_H-E<��^Wc8�Hg]�p����HSR�pl��f�X�}�*M ]�x���.����F��e�uqUr��*y�=?�vh������.���Q;�Z�o���������B�����������O+D��[�5��~�I3^���-�U �K���\���(�ZI��Z����j`�^2���M4�j�4���+�2�z"�n���q����n�K��[���+��\�9WJ�;~�_�9J�&Vl:���tEF�q���o�����R������Z��oR�U��#��o�N���U��i�\u����Zn �RZ�m�e�i�@�,�]���5���!���s8N��(f`��
_Z�!aPp5����,��|\�v�50��tFS�,vL�t,d�8#bm�
��.�5��t����ql��Yp5�����kM6���L�b�5I������.v��b���wx��"��Jp5����,�&����m�s��0{����fx������=t<�
�sew��1��������If�2�NB1�]���8��<�H�Ig����1�]�Hgh���z�O�J����5���%�q���f+�d���1��QlWg�3N���T;	���8��Hg�d��w
}���D�]C_@c���}���
C��oPF���������*l�]�yGiy�j-_������+�
��n=�}A�Tk�a��G��&k���2�X�Wp������t�If#�a��o��z���7���)����~W��.�zf��w�w���.���!�H7�Mv���{^B�<�%��{y	�W_^��QR�v�n2�*���$����a��1l�����I����Q���o�0)	�c��}#/�3/���L`��+�0�� y	�cE����p!�p�`���'���-=�q=N�kJ�����<=V9� y	��Yx�9�\��q]N�KU������a���;Z�e^B.yM��%����*J��<�������K(��D�K8����1qD����o��{R��a9t�� �c)�����Qj]�]����d�][���������~s������B��_���o����v�f���_����~�GQb����/�������'���o#]�~r�4��8��7N|,�1�������7���o?>�����������7���H�s���r�Dt����BJ.!^tB{�kX��^��]�N:x��os����.����ML�� �u�����C���/����(�t��{�e\q?���G{/c�w��-Tn	�&�n5E,�[��rKY���U��IRO�t����[b����������Mfc'���F����#�5�+��[��%��4�!E�P
�xF �,$$�E��tFh��������R1Hx�t�	�Y��N�+�b��q"�!���vDV���.v�����Y��4��*�]��H�'�Q&������O�W
�F�]G:C�������t����eL/J"H�4g��$"}�D��jL���B?O8���*y^UE�AX9�3�4��D�	��^h_��&|����d^���J5����x)P��x��z�@�h��i&�'����_f����3����/4:���@�h�����5�a4�������BG�s���������u��F�������5�j��+��E����}��]ZV�O��Pq ��Gf%���m��q�A{'��}:v�p��
�I���b������������7zf�:�@�B��i��.Wq}�*!������)%���X�o�H�@���sO�'=���2������V��@�B�!"��h��*-d���B2�
C�h!���\% =ZH8"B���o����T���18VOZ�M�:J-�a��
{-Na���:������Q���=Ue�;O�=\>A���a����=c�6��3�n"�e��m�HW"�$�����@���=��p[\-��?��k�+]�?��JKp�$��,�;I�uI{Iz�Z�~��4��rX�����������)�.��3�:�_��I���b,���D������w�}m��j��^i�t�$:�������#k���K4^Y�q�e��=�,/O������#�g��$�����8�~�0+�B}�e!���Sd�sg��Y2.��K��@���f�~�s'P7����@!sB�'�JT�8����W;���=.H��px��)]c#u��9-�S�@*��aChm�#	2'N2�=�H78N^i�qM���hJ#U�t��	���h�[D�!�z�;%d��W_����G�J-_�<d^%�s?B�z���$�?|/��="o�������f���������Oo��������O�@�q���!�'9P�:�4����U#�V��B�G��8���#���r�*f�W�c����I~��A�:!��c��x����S.�)�keZx\�S�q��N�P�q�M���:�Vq��8 ���z,(����	����IW�?[pA����]a2Z�Vjrcp�����kau�%�rW(�5�	�&c������~Dp�=0zuq�q�.u��G�����]Z��w-"�D:=%d�UG��^1lWA�*�gY�<����.z�"��	�t��GC����}\�v��5��I�G��NW�������*���t���[l5{���o�V�]�@�[hc������>�.s2z�4���5��K�����~�}-�6����}fV��^���C��v�4�1�J�#����%�`%�@8=���`\�0��-3�\��kC��9�*~
��k���h��X����3�9G�,aJ����i�K(�^��,=(�J����&���`���y�=��$_A\2�����*�G��s�����P����C��h=���]v��oZUo��������5��i0�*:K����Q# �����,��~�BC�k��{��$ P��p����~������������{3hD:.�Nw ����~�����W��b��]�U����������~\��;S�e���tCF��<��r�F�����u2�G�!����G��%2�5�KH�)�%v2< c�~y�H��"��!L��p5�&����UF�p|����|���o��o��laI=�[Ipa���{�����h��RtyJ:����� ����d��l,���v-������Hg�6�b���H�o������"��������]O:}G�h��v%w��H�1���]Y���w�l��4���xA���Igv�7�l;���q5��k]^�����]
�[�<���~9�i�|�,?~�04dX
�z�$
Y�pHHhD�m7L��p�I	�pAB���K[hO�H�������U,>P x#�&���m���$��{������oj���3���8�j#��`�O	Y�����Y�9d�+!�l�2����q{$�qA�d�����hame��of�C�����f�d>E&B�������^���@q��'�����*���p'R���k�W�q�S��0��L��:������h��U��d������z�������Eh�ha����+@W���Y�P��\��I�%��;T�t(�9�.��~�8T����.g���0�B��5(����a���k	�{kud�E��j���'p#�4e��]&\���'���ehOB�1I�mf0��^� �s�����x��5�FCnb�m����N:�bF=�k�M���f�`�=mGW����vFv2���5�����LF+��m�%9��J�E�?����b�����Hg�a��]��N�xV8����9�j���']K:�g���M'�wsh#���Hg�Qv_��:��l��4����]�v�#��;z9���"��~�����d�%z�i�����(7yD�(��<����?6C��*c����x y8�Y�P�ny��.����#����
��<��?����0As�!����f��	$� ^��{���x��F��4e���xE����V��@��!\ ����|�G�<�-�(�����cD��#nQS��������]T���-���e����\1m��-'a��|5����F8��V�BY�� ��A"�'9�Y�$#����8������,�������*���.W��s#�*�������[����p�T�rw�X�o�7@�����B�����k����"9��\.��tYB��W��[��d�D�@�5����o:�]W��6^�ad��O/7<.�z�lL����x1�p-�����`NB#����
t���w4�r�s��@��{���[�M� �e�M��=�o�������~�e�_�Q��}���m`Q�[v�=� ��d�yk��x���5)�/��,�P�=�M��lt|��������Lzc�:2�,���p���d��y0�n���(#=��<��t �2���u�r9{�K��\��,g�:]3�d����7���Y.�����,�n��)n��{�������������|��P��G�"�HQ�7��5M$�B�l�}��K�w
����
���ko�����2^X�1�R �,����*��[�t8�|l�U�A�[���c�yS'D�=�2fR���e�9-�?���e�����m�]�d�Vq(�, ��)��[�fA�&�Z����,���%�B/T�+wc*\y��J�0��7)���NYOS�y!��8���I:<b�]q�M�)�!!�����v,V%���������[����X�y#��e��l,���vh�>�n������s�j�neQ����EWt��H��HYp5�E��	:&�
�b���NIW��HuV� ��:����w�]� _,�8��.XZ����;���d��IK:�f�uU�c��t��e����B�e�t}?���E	�I�we�����W�K����KH�'6�o;���n*W�K��z{��!���(���[p5���+^{�.�Hw{}������x�;1 ��y���@�*"�����nSc�T���2nI8���v��;�~U2�(��[�.�=]h���~���HA�~#6"�D8=i����^���DV<�^��Xj�0�a
W�A�m����Hg�������4�/	�6���'�Hg�*WV�lc=�/�"6;0	������F�"6j������Z�O�+u��]�&SlT����-�[C+U����~�H%<�������%@�x})
!�U�7��p��T��J�R���JhOr���=�W�g��
��.����s��*n2oUH�'���.*a>�*n�ZMH�|��
!�T�{�e�r?l
!�����{�5�T�<���t���b~�8��
�}AHKHeM��H�Gpo8s�'���Ho�����8���p��*jMq?S���"�Js|�=�p����(�-�kH����r�W�]tA��<_[����@��W�6�����v-��(H_�A:<�k�}s�,�
G:�
l�E�]����j��.h!]G:]�����t���.h!.��{��$3��8��I�
��O2s`���5W�]tA�x�����c;�(�Q�Y��v����(����TtU��.z�	�!�&����8���R�5='�tMJ���r��b�<I�������K\({�Yf7������F1P��$?O�p�6�t����_�B��n2b���2�X�M� � �U��4���|bj�$A$D�^��'���Ng�Y-� � �a�
�)��
cj�SK���0B�q�A����w%A�cP��5���#�p�6�k����2�
�z�����_<E���z7�$AE2K��uIP��V��'�|��$�)���$�$����������)��t2�����^(��<�1j�uB��qc���.���������"+����=N�7U��t����s�*H����x�	�;n�%�0�c�	o�FG��?��(��\�m�XFk������"/���x	%�!n����\���P�@����=>K�#�!��{���p��V�,�O����Sq{��7���p�Ba�(����R����'�p�V<�/��<g���7��3=��~���p�\-�]r���N�>�o;��W�]t�
�:����:~��t�[C�`���]�=��
�����C�Rp5�Eo�L��tz�r�5�#� ����In<m������������^�$�����
������;�[\�v�%7���~�%7����O����4�%7���t�O2s`����@��l]rC:�d��o�y7rG
�ML��i�)%����o��;�d�A4������`2�����J:�(�!Go��/J��:v�\J��G���u�����-���q�T)����O�4�7�mZ�����yB�#Up�,���SND�\M
w ��pr	����O�f(��#b��*��]�at^�������&\��PuBhOw������P�f��0��!eXx��������t�����t�'�R��f�(#�zi}���\����O�y	��]�4�����j�W�[�'~����%�[:�:-�:�S�[C�e�~���;��k��~"�@��Z�F|.�at#Dvwf�����6�F��'�y�������{]��n �i�/�
��HE�9����,�8������N�]���&��U�S�7�*�y�5�v_�52a�VS=_�o�Bt
�F���n�d�sX�����sc�����A�_��O��9Or��[�a�_KHa�Z���m�/���9�
s� L�����3�k��a������+�][��p=�j��P�/�"��<��ob��Y���1X5x����%]C:�>����"���"�Zt�#���X]X���(1�������b��t�>�b��t�	�f�`�O��<z����b�m��lm�u���6���U��\�>e�I����3Wp_�1G2^���/��eI���xV�o�:%�^b!���Q�W�U�w�#�����/QYY���I�f�_SXTAp5�E�����af�Q����Cp5����`��a��8�v-�<��{�D.Q��kHgjIv����#����~[��3~����afx~2/���x�u��,5��8���gd'�%����Ygd��o��7�^?���cjH�t<���
������ "M�������W����_���$��p;��$�o��4��)"n�W���CENK���;�*I%���7���-����9�G���F������.���	�R��5�Hq���0oO���.���'�E�@����e���8Y|JR���fM��%V��jb�"d)�� �=�H�4�Q���ie�����-.��o����*�]���"��R�\��w�u-nZ�[]�%�<���_q���Z�������kR�y����V����
��$��	�C*3v���)�J����\=,�]��pK8x����
����=�iIV������8,��9������Z���b�j����W��'rBG1][�-eM��"��H�2�K:��:;�Zf�Q������a���C	}���o���^��
}�~��iL��O�:�K:8{�V�A����7�Vw��u�6�y��B�/�B�8���V�1�����d��4v��%����Q��`�#�]�5��4�c��iQ���x��G�C�v2�Ua��xz�6K���H7��(F�����ec&�����<��.t�����/���x��]�����x>��!��s�=����k���B�T�p<�z������p�{5��!V�U�J���
	dn3����Gqc4�����	]����=C`X���=5�d����R��9;v$��wzfe��	$n$��4�������N�g�����O��l:&�H<��^�����H���z��C�#
i�������2�CS.�I�#m)���7&�����@r�HN�@r:��W�����W�����0�EUU?�:�T��R�fA%�0��A�J���V�����0+�S���5��<~�:����*z��p�Rw��Yq8�����9P�������Q?��w������4�*�2"e��^��3B�\g<���O���;Q]4��\(�^�d�e�s��N��������+Yx�q�z�8+ *����Z��mqV��\��/�����8kX��	��0��&'T��pp�	��qV�����5r�$�6'/3��i0�a���C���4�k��Y�-X��������4~Y ���V/G��x1�-���]��xH{�y�9��x�Xi�F��X�C�5������a<���43������g���������v������8�{7��t��<��x�0�#�+x����S?�������g���:�kwa@g,���f@��
g]����.��^��@qV"B�#���?a���	�+qL� qV��p�
�)�,��a�����-K�D���U��+&�
�!��NT�����
�6�V!�(#�3�6��$}1��8+�&Z�V��q��3���8k�[�_�*�gy�Y�&u?��z(�YI��/��2/.�X�51{�,��sW��z������o����]!���_�������O�/w���g������N�}��c~B���.�$�p�����t
�[H�U���n'U��{�'|b�O�o��|�]��C�Bh��;	��&\G8�3�
�pm�;��FD�
E���w;����Dv��[��?}���_�����M�_�������/?���6���������������1e���:��V��|����!�����?v�B}^��BU�m Z�:Z�apt�z}�E���q�9=M�������	����n�W~F����������y@���$�K
�����R���l4�pE�����8i<>��q��1���|�e\�URQ`��u �	�J��b:�����s��:����*>����Z��S��������5d�WSa�K�ra�w�u�U���Ar�	��Q���Z�
n����)ST|����[�+�GhM�e��B�V�m��!�:^m����5O�N�c`������fc��0^�=�7��������Kx5�E��@��tV�����(D���}o<���'��F��gt<���^�-w��D��6��;1B�(F�K�N/�����	�H^��W����G�2�/s��V�qw
&�,B�\�P0� �*��n+�.������a��C��4-��������������HS�����QF��hJ�vs��J�O	�d�]
��#X�z(���
���W\~�|E��������I�7
6"�V��7%M�s��=L�80�K2R���}N����=L�,��R�d�
$��g�L�*3�Z��{�r�)x�)����K>�a��3�^���c'?�E�M�uc�^�T��y� �K��76�o,���W4T��hH�V-����	H7�N��H���a��k��|����z�����q��n�AH'���4�����,�8N"o������[���C�>����������?���$>��WI�Z����f������Z��H��>�Uf�u�����{�x�m�� s���3=�,ox=�����=���[�6�[����Z�+�,���t������<+�;'�^���#]�2�����Oy���������3�;�|�6���+���=�T�����R�H3��
Cp9������5�������������C�Q2<r�"7���\e�������p��\����3|�0�w���gx�l��'����9�6��7�;�Q�~��f�����3@g\�� ��83|B���kz?�������S���.�9JFE��y-��3�K!\m�{�6C��.��[p9�����������3�~2���)M��pWq�L���9��a���������p7��[��yr�����E��'�fxz����w�9����+��������9������$�,���E7`�����R��_�.�w�6�O���,?�=?������>���F�z�w�nQwqC��g���DE��@d

a�R���$�$�����\'W�Q6C/�x�KE@s�y�����yV?MOB���R���N��;�&M�{KJ������o�7��>��Ld�s�-����7%#���GJ��C��'�����K	���?"�cJ��?���ZQ���_�1�EL�/�T
@����*I���$#�Q�����m+J�\�B���:�7����!���/�1K�&�[��U��%� ;}L{����;^D1v �!�@D�J���p~�@o�><�u&�"	M�y�����J�2l�c�������|���n�4}G�%���[�(})�������S�i��Z
�>]i��0������2���|K*�O��7+b���|/�x�+wf��3�Bh��p��.L:�x]�q=d�$�+����G.�r��5i�.O[N��|9�[`�m�O_����
�(��|(J�||9�-����y��w�e<8��2�[?���7<9f�y���3��V���t�Q�������~a����g����.nooE�x��au�0R����\�D��J�����6������V����C�H�Q�����G5
�y���<
{����Q��@a��^��>#�i��N})�^.����U|CU0{1�]�>����w������f]ns�-�w���1t3��`�|�n��w���%�����L���q�t�N��7�G��a�d��Y�eq����G]��
���E[N��x�#[��}�a�qT�Gb���4���x��?�m�U�s��i��F�}��5�+>�p�DC�l�+��5�^���t%�
CRd�}������"�>�E���I�;s��\f4��<�?���[�x��v��wM�+�#��0����QK����Tb��������+��O�1L�Q�.�J�������t�j�Yh5G�\�����#�T$��Vf��c|5S����a�W%�����������Q�
����>�>��i������B�djmJ���-=7���_����]����[���������:%��]
��l��j������ �;D��t����M��P��?"�Z9D<jO�v���C�J'+7r�!�f������[�����O��v�!�g���-��>�!8���Mw9>�-T�t���s�j����F9@��mo �������=%���s��0�aJL�S�+�o������K�����B���#�ta�i���|��D��=���o����7�����V�j��}���t�Q5�*t��p���������H����./���D���B8���Q�j���r*>����t���.}d��9i[����*{�G�|��s�������u��4'���.����Gdl��A��q���w�%-���>~����Q�5sS�~O�qJ`���o����yM����p�kj�����Y�t�����&����m���1UmF�X�MV�����S;���`���>+��Z�����?
*v�v��%���Z��>+9�i������,����'v������'��{��"������3�������3x�������N�CnR5�����z����a&��"s�#����+)~�1>n.�n�����`�J�'����jM������~}��x��-?�I8F�.�����i	J�sA��q�����_�17�>�/._�byD
zD�Gdd����������?��B�h��<~D��*����?��KE���:{�.}�k+b&~�{�8�����-q�,L�U����	�	OAV�F�������d?�=����<��� �4�A��V�s1��i��q�-��lx�
��c���x�o��>��/�	|�8��C��e������8��oX����^�*�qNL����������W�\�4�>G�|��������ym���x��89�O��4�Ux-��mA��b1�*����?�
�t�Q��g�(�C�)�h�Q;B��&��.j���-���}�vT��E&��e��<�������E6��P�~�>�L��F�bd� ]�R�t4��:�1����v����z�o��A5�������rih����k��G����8����&r�h��7N|]��U>s"���]������1'�9���m$[�r�|:0���#D��%������HO��9��}�#����50Y�m�p9�O���I���*GHt�"�p�Wd��]4�K����t���am���1���l�.�c�����e�8���>`�v1�o��L)���e����,I����.��8���t^�O�W*7��/��V����l�,+�;�<�������7����r�y���#�K`�Tm��=�>s���[%�����q�:�8�eNTEp�����B�����V������!�j��ue]��� �O�E)^Nj~@�����g���8ST/�����|b�q�e�U�����[^�]�J��7�e/:n�Wy�&�������vQ��Et�K����9����35,�O��n����Wc"�37,Sd/������.� Y�8�?Q�2����t��uF��#����A����.�le�����
��iQ-�����9%9��\9+�����Qy��L/�
����5{����9e{�C�	_����9�2��u�;D�G�)!��v�}������[H�,��|��Z:�}�;f�W���<~c��^=�c<DZ^������>����M����
�����_��w�������q������������o���ep/�����(G�������O��g��L�[����r�%�W����4yb�l�[.uE�?�����Y���C�%��~�����G��%�>��c�-���t�Y�!�t����G�����o0�3Ej���|_R������s����������]u��
b��2n�
�������/���7������}�eV5��-�Wd���b���eDS�����w�<��\�w!mF�����t��P�a���7����G�K�,���%O�
��O�d��x����n-��'�����w�zi�Wk�x$�����X��g�/�+o����-��G:�Uj�<e;�Lz��]��t+��8�=����2��CO�|��
S<��!�����o�0����Zv�'x�vWV	n���,A�j{~{��$�R����z{w������j����^m���z��?����F��x�����A�����Jh_�.v�28��e9�#6�T6����0of��X���V��N���9�qft��hvv���)	�:]�<�#�$/��\�������$rF�{W'z�s�6��o�������0�7%�����]�����u�����-L�&]��nM4rz��I��S�yL����=��������<�oj���J��v�s��[�oo�t����H��=�����4����L��S��^�5���0o�:��'������nK~aaL������mA������vvw�
�Rmz��]%�yS�B~�����j�������v�\���(��9o+��9�{DP���xA}(M?av��rv���n/?a3d��j'�gnB����g�W�|�6�c��[���#�
���6��9����qy����5b�P#�&N�quz�����������M���o~Epa�nS� �Ujdx�s�Z�R�<g}r�9��Z�������k"~��j�f8��G�B�������Zt���R���-�����9�����g�V��S{��|6���-������-��i�����Y	��%]��-���)����X�S���xT�������mo���s��WW>Y{�X����������5gw����������g���������n�4���w��]>������C8�������M�gw���V��8`v7wn�'������.����!����C�Y�Y+R�<���y+�tx�	��o�{z��VB���[6��?/�}�6��g�;h�9�� ��{�n�	�����\ez?w���cA��g}�����]?�y�p����fuz
7����n����.l���U	�W�������F������b7y��������_���]4��
EC
��N��*p��-�]Y������7L)��(U|�+E��5��A�^�\~�C\�YQ0=�{D��L��Z��~&��w��.Ct������d�{v�Ta+�?���t�6�C������;����W���;�������;���|ev��nE8����.Vgw�lv����e�O4f��wx��]"Gh_����/ri.�}s^�A��a�������oQ.`Z�l������c�/���~�i��+���t*����u���Zy�.@���d����n~�e�Ez�\�
RFQ�y��}����&����u���!��������h���sAg��r~�������<��2m�v������<�����7����l��h��q
�F�Lt�>���t+�\s�Oe�����	4�W�j�M�����|��������l���;���V��z&����fMp	
�zI�'��
�3�*��Tt�)�����������6����}iT�)��P�����O�$=Mr����J��f(��su�e�l���:��O��s.Sn���R����i�}D����J�����Pi��<��jDo���
��7��k�v��G"�e�[�U`/���>��ym-�U���B�#�c��O�����W�+s�;��#Z|D��R��#�c����T�PE�_�T�����}���J����(0��%�����JoTY�^F���������I����5�:���z�S���t����E[;}������~uz,v����N�����|H��d��V%d�����&Y(�6����?���R_;��o����F~C�}C���K�����{}5j�P<��
^�����N%�u�W?����
|D��#n�z�x+vso�F��
�,��8��z|���!�^�]�>�m0D���<�7
�A'�����C���x7�v%�1��2�k���X�����R�x~��uvz%��y�-�������F������/4������[{���O�a�5}�l~�T,��h�2�2��?���w������n�3��e��~������~[�
����S���)iO�y-5�k{��c���_��p�?�yO��[B:��[�|�����������Q�7����m	!U�a����D��K.`�w�9��f\�����e����9�]��n��o�q����~�������~���)\<�!��?���ta�tH�3t�fI�(<CD�������
\��
=�<X���<y6�Cj�OpT��?Z��������	t�^z�x�&<���t����?�s1o������-'����q��I�oD�����	�U���W<_����U�_��#*�����4���[��!p��7��wA�y��wU
�#[�w�������JE���6zW��o���M�w�����a=�siK��-����~��d�Z��q�Z��M�>z�����?ve+�
`���������,tO,7�e��i.�}��]��&2	{��o[�U3��G�1!�.D�<�����
�#����Z����Gx��|�����G�}�����.�����M�u��b�O|t��G7&�����B�43����R{`�sc���)Z���V��f�s%�Gd	�[��0
'|��#��\���/�<;���r�.�����x~@�\�&��'�T����rk+���ax��X��S�Y%��J~��_��^�k��\�.~HtYJ�5!qs�$�d�?�j2h>����������L�>�Q{c��.�a2�@��t3�V7X���IT ��jk���q�_����7|D�K�|����I�����b�T����v��$<�����l�[�kC���\������8d�O�����(oG�����������������\���4��o������r��^-m�H��=���V-�Z��`�
\���V-�fI���{�6��W��������~�R���7�D6��f���&#�T��lv��6p�r��yd��l���b{������f���c�� +�u3hn����oC�%3����v�M�W]���v�n���qWJl�������^�������U��r�����������v4���
2�!����u|�w�6��(���R�n�����dk����<��y.SO��������i�E
�^a]3[��l��*�d�p*��D����
���]�KL7�������#������T���l9����M���F���W���I��������z����W��n4�\�
�1�
���uy'W�H,����N�*��'�<UG:C��:\5����H ��+:^�F
���&�
�_X���=FY�7!>Mr=��0_q��Z"�9�A�~�������7D��F'����[�h23�.�Wh?n���i&5�X��o��]l�s�������0�S���=��Ew��va��������a��*<�/�p{���k��Xx�3v�$��OW��fa�j�6�P�q5��Z-v���q�Xh���/�����\B�4���BLr�h������3��f��|�T��+�a����n�2�S��3q5��i(�h�0y�z��[�M1J�Pe�q�3 �0�=�3�>��7����B�
8��H
7R��p�n�����8r���9�q��U���?%��p���k:#�/�'�R�vi�(/_r������w�6�=q��,�z�[��Z1���.��A���e��iY�C��
X���k�-s�]0�k��2���L�F�K�[��Q�Y�M)W/�.���ov����y#�&�wi��#}���zK��������g��.-x�{��n-��wu���O3Zp�>�|��)���Y�y�$�*�S��wi�_$������S�3Q�9��(��|����!���y�� {s�n�?�|��Wq����lg�B�qg��8;�Q��\�����9�Vq�U������WI�s��*�Y��`�U������ I_�a,��w�Q��Z���8;�M��9������4��{�]Z��7I��qo4�6��,Xq�.��m�|�TPl	���d�:���+����d+;�M��&����~���j��+�7`�'���g��@+���/�"t�x,�2V����J��8�h�V����$	lF�d��'�K3�4qI�x���53zx[C��/x�^��w��>�mrA�hx�����	C�0]R8���N���������	�_��p�M�7�&,V��q���\��8n<�wa-Xr����������4��{\�.����\_���N.�\�����r��,�U\����^'��FN��8���,���	�UGW~����4�Qwt���Q�'��g�����\���f�|A�p�5������%.i���,��$�n����%|\V��K�5��sgX�\�0���2.|��W.�~��!����g��|�8�����}0��
\l�b��$���Z���o	��\�O�H�j�VN�*���o
�)������/�e�����v�
��[t��*.|������_���W��\�U�������(��&M�>a�*�o��I��k����������G?�}�l���7��&n���+h����������IQ-l�����}�����/
���c���M��w�S�@���
f��\�t0������q�	��&4Zc�(0}M��m	��y��G��'����K@vv	F�]-tT��+�
&����L��;�&�X�vVh�����z�0����B�Wry������{k!{�0�.���__�>���y��G�.�	�����|���Mh-d�@]��<��5��&&<�QW�=��,���bJ1�#�n���@N\�S�����fO`rO�����I�d������.Q6�2�Ux�&<�iR&p���'�B�g����������I�l�Z���s0E��\�A���Dz��Xp��L���wi��%%��fh��o3~Dz��������2kaA#���a`"�-�K�*)���s�?I��W5�������7X��b�"���J���o���3X���3����h��Z������,iA�k����y�ka�r�zu�����S�5�K��`U���b�#�$\��Yp�OW�	-��!��|����X���|`��P.Z�]��#�$��
��GU��dLVp�<�M�@�S.�G�$�
���G�IZH{�E\�P��+�K�&�2Z�h���f�g����n�?X�&�tK�5�[v���n������7	�[eo�%&�����p�^����G�I��^`���,8p����7�@/�`����$�
���G�IF��ED��7��U<���#�$�����w�L�k���n�|�L�e�w�T�
����I�^�j������/0�k	����I*���5����B�Xl�^��9�MR�2��Yp�7I�Xl�^��9�MR9x��ED�����$�D,Vp�<�MRe-h�L��� c������o�*��ZDd����d,Vp�<�MR��W����w~�U��
����I���j��_��n�����nb�q�.Vcu��o��LiA=V�Q�'h����&]������7IU"V'����F]q�.Wcuir���B�N�5��[U����`]��*�SBZB�}��]��O��i9ir����B��������B���|����Bn�������Bn��|���u4���wyV-����b�#_&,�!��	w��Ww�E1����_�b��+fIP+����������!�^-
jH���dhV��(��=��EP�
��@m@�����qm�\5p/b�"S>���
�f����T�[�����4 ����F���d�l���i@n�F��W���G1sd���M>���������^]`���Pnr�5`���3��B�F��w�"<��#���;{�k�������&a`�P��F~��-�.0�e	����Ej���P�ly�gA�=Zp�<�1R�����-`�+?f�g	����F��[uf��|�����.Z�������:�*���O�������U|�{�f���,����f��z�GNz���f���������f��z�ENz���.sZ�h������%�Z�j����'I	}�@k�9JRW-�Z�"=�MRA%���~�TP)��7}�����h4��)���5w�zU���|��\���Dv�7I�U\�7t?�M�@�.�����$�� �K�&a��z�~���;GHj6^�����#�$l�SMrR��)A-���z�C�;�M�q�^���[p�I��F������o��{ug�����[uO�G���vG�Iz�����.v����������&�W����;L2�G=�����o��{�`�����$#�[��w+;�M2r�
�V���d��z\�QgG�I��+���~�L�Q/�w���I��{�d�����`�@�%�K�&i����j��y6)T[�����o�&�^-��w��4)4�����o��92��z�7I�����|�4�'�!��}fn	����I��{uf(���o�M�\�]Z��7I�s���T���`��&�]Z��7I�s������-X �Ip�
��$M���02���}�
�=����If7������F��f=�8?�MRr��2���o�����G�I*���Q'`�9X�N��.-x���5��,�Q��YT{�&��W�F��fg�VS�&��.-x����*����M�}���G�p7����7I����W�������gq�~�&iy��Y\����*�x��g��o��7��8���5M�]�[o�}����*�������`�U������7I�U�[�5����.�~uG>I.��X�N~�)�iA.�a}�$���E�|;G���U�Vq������r���� 3�������	��6Vj��8��E�w�-|��,��X�w=$�Aw���w������������|w2��]O..|��,��Z��"����e��v��nq���u-�e8z�ZI��.�|� iD��9f����Z0�h�Uuy�����
!��}��s0��Kg����/�6�iA=������9w�|5��<�E��p��=�``9-�Z��<�I����@+s0`wO"a�]�z��$-���Xp�9X"��]b���@���@kg��d��'I�@]���</�#-���@kg���Zp�;X�&��he{����bbwi�#�$MJ���j����X�]��;�M��=�.��w����� ������o����E8vc�:_��Zh�wi�#%�#��C����[��
���G>J:d���x���h�9�s��V�I�#%=�qod�<�=-�U����#%Wq��b�&CaW1C��������������d(�]d����-8�
����Y��LE`��5�fvVG>J&��!�m���� �<���G�I&�r�������-h��.�&=���>�M�%(� �����G��]�]��'I�fd�k,�;����+�K� �RDr�E���(I��
�n�|�t�K���v�B������>�9�e
�/aW>����"~S�E�wi��#���������d���9�"+<�9�1+�����-�{V����|�t��
��T�h�T����qX�������X������8�>Xr�^�a���G���>�,�K�������H���F�P��`A��]�]�Z��4G>H*���(�� ,������U��"���h�����~s���Qp�<�I�p�z)o��Jv6\���*>�M�@�&����Y�Yp�<�M�r/J=�[p�}�E�wi�#�$]AZ�x�}��]��&J,x����*�x���`@��������U|����~U�z�������w�~U���&��{]��<�a���U<���49�Q2B�(���x�I8��5R�8���W��u<��ug��eG��u<���49�Y24�����u�[��=M|��	dB�O�e�>��UpWLx���OzB�����^[��Z�+�.T)��S\�D�P	���O����(��-�����Mj����-����@�P@�������n6���o��k`�n5z
���C��F}���0�����F�N��&HeXE�n[6��������Y	R�9�����-�.����~���C^2cmj���v�-i"�*��*-</��|��<[v��[e\Do��;P�1�5�������pX1~���PA�;��{^�N+��?.I�5`�Z��#+
p�]�+�u�Pj[���_W����%@�>N���u���}���$�������:��t�J�BI���+bC��'����Z�yc��7`v�!������5���~�oJ���.�~�o��q]2�yI+9���[�-�����J�!��%\��;�[P�%`]���BV^�K�v+w���R���K��C��~_��F���������o|3���?�����/?���_�����W�����������7i�}�/��/����?~�������;O�|��Wz��i_j��y������F�g�����/P���q���Q���:pb3?�
Uhw&�Fm;�h�
����;������������]_�y}q�x��A�)%-�Fg�
���,����w�L]0n�wtI
����L���;���;��)��GC��Q�����L���n;���8���;���E�M��m?������*s��������oG����>����l�QA�������$F��������54��Z�`Dr��`t���$��
#p]I��#F���c���V p]�I��?���zm-����v|S0&9Z������/I_K��,���V�f���t�I!p����1������
�_���u-X0&98�@@�I�b���G}8�
��c��3t��m�x��ib��1���xPNq���`k��o��}���1	+O��� oi��D,X2&�:ZP��#J�m-8����qq[2&�*o���qo����Y�-,���-��S�J��3����goyQ[2(Yx��pyQv��Xx��1.�,���g��Jgk��[]���Ct��v��qO����W ,�l<���G������S�yOqW2(��o�)��c{�w>���1�J%;�]y�
���op�[�{���dPr����������q��>���]���D������#W�����m��J%'��t���4�|���O�\������`D���KrV��:�Ib��1��q��x�g�[�t���$'���k�q�OgJ�T/�IN�*�!~��Z���u:3
��c���
tz�5��-���O ,��R �C�����G}��=Ng>�X�`Lrv<�m��������,��w�S\0&9{���r�
-w�{����-��$g��������S�����!��]�:t
f6 W���U�}��d�K����C|r���u
X2 �;��z�3�!99�^��,�L<����'fn�;9�@��sPJ�#3��3�����_a�(��KF#3��3����v�B���A��d0��;�

�c��k���;wOg���3�:9��tZv��%Cv���l��Iv��H��vZv��%#��G�m�d��)�s���G�d$����G����|�w�+\2��
��W����|�w�+�$��7�c����02E,�_�fT�?�?�����#eN�x(��a|_���H��2A������Zw�`�h�
��[�z:b���1~���]��GX.i��%�p#S��[����c�h�
�A��n�����Z�����7�0:�.�16�vo�X.i�����b�<�
�vO����\4����^q!(�>�M������#o�W�=@�g��pCZ�������;b�M�~��7��u
X.1�� Fe(@1��rb�4���k���H�����9[�Z��`�KZ�:�
F#M��2`�{�c��7t���k���H����7]E����x�[�)�
�#M���SNqD����w��x*�4}G*oqD��=�����-LS����ObTZ����~���{o#�T0$i�bg���e����q�x�!���dD2��!��%�5��3�T��KF$X7�:�ySLm31^���J�$��y�No��op����82��H��T�3��}C�;z�&�����S<+m�C����Yx�g���������v�sK3=�����dD��;��u��c:���o�x��Z�`��d�`Ag��7�����������-��KF$O�3��ZC��	y�7�1.��<������m����x����A��s�+�qLC��	���K�%�
�A����K�=M�-���Un}�Z"F���c�z����X�#�]#M:���2�����M
���������� /��)���L=1/�.�X��9W�_��&���9�=���L����1����/]I���eh�����A>�`t����u��/��WxB��O�������_a��.�O�
�W��v�H{�~�=�{�������A��:��j�����8��c���I�t>��Oc��G�>�����������Z�$��Y�H�[�U>���y5�l�[�N���
������o-p^�il
�������_`�s�����4 �p>����{��{���3�����#1q���������7ck��G�?���S�<���_�e�
H�z��5k�_�H�z�W�4��#<*������p�	�'���jk����g:���7pt�&o���&��'x
�����q�~���u�K"���0��e��_�L�?��.�,<�������/p�^�G�d �"e,��0�\�b���q]2Yy�W%a�[�gx�������3�*����x�7�!.�l|�7��#�7��!��t�K�";]im�K~����t�K#���J���8��G=s�} W\2amO���#V>�'O�S��hX+hAf�t���k�zf�{��)�X���`D���X����Z�`D2|]:�cx�K~������$C���5���,������,���
g�>wDd� Jl�k��1���7��}��a!u�[�����$C�c���;���`��d���OcA����-.�=��.�w�c�+]p]�I���XY����x�{�)n�$��S<�Oq�Bk��S���IF��A9��=���x����dL2���)�n���x����1�D�zRN�aLiAz����nK�$sM���-7>���%��k��!����3��'�]�����h]��H���/7A�~�E��3b��%���)}\J��~������J3&t`������pkh?���d4�aP��5g��5l�-h�����wt�'���2��<��?��+�0;(����D��Wx�4�w�hW29PR!�?�Wx�}D��&,��M�tf��
O���k����t��~������f�����l��~���|�P�6:i���Q��uO����1�k����`��dl 	��s���+p]I����i�}�`�N������`��dd2vt�u�,h8[!�lQ5:iX�D,��L�
��
G+�}�l��4�X�`P2v�G�a7�������C���1���w��es�S�f]��Z�`H22;:-�%-�n��I�>F��� �b�g���I&c�-v��b��!	���o�)�G=��v��b��1	��:`����S��a��%c���x
��)�G=�O�S\2&��O�)����|�g�[\2&Yx���[<e��������dL���^�S���^�Q/^�z(��<�K���r�8W���{���1	����?��BmlA���c���1	����X�9����3�G�T��dL����6�?���!��*�P2(�yYkS�?JL���&A��dLr��>����D=��u
� $i�����C��l��������f�����y���_~��/����?���2[��������_��o2)�������������~��<E8u�Jxr�=7h�=M;������������"�~�����_����L���+�MGK��M�+�M���@���u
X0��x����}k������u�#��5(:`��9��q���C�T��Fp3�P��
����\�tv�O��#��:��5����m-X�\��#���)�����S<�8���`�nn:ZP9�������p3�Pt�����9.~���Fp3�Pfe^|��xnyK;�'�����zZ0<���-��`F��,��=�T��-��`�]��,��=r"�����Izs"S��d�0�Y�b����aS��dD��������y	\��%c�����Xp�hA�x��dL2��T@,���`T��<a���u-X2&�Z�#�,Q�fk���k��1��nS���q��R���3}�� ��@�t����y��T2&Yy��yc�.��S��Oq��d��1|�-;��,���Z�C=��1���x��,O�{I6����-�K�$;O�~���:-��d�)���x.��<�{���x��f���{���1�������!y��[|x���dLr6�`�-nb����'���;�g.�0%+�C�qD\gj�����dc�������/�C_a�UhlB���5a��d�P��I�>�����
�������Ce(@�|�m-���(�\0,Y8�}Q�4�4<iA��?K�v��B=~�U�Z0Jd]Z���`]�K�~��y�;����J�����``�tp\u���G^.��.p=&,�,=����l��C/�g�M���	�C1<�����1a��d����&��h���	�j]�MFH�:`��c������G��PW%C�����>�_�H�NA_8�]�zlX28�x��Q�iM���C��3����7?>�x����gtp,����/1�!^�K����ZpiiA��i�����Y����Wcl@L�]���k��$���.p��y
���q�?���[I�j������:Z0\�_n4�3 ��\����Q��8#��?�����'�i���{/i����������	��9�}����&��������.prT��u���<)�;������������	���
�O�8�B�A���`��d�����������W�j_�����������8��?~�M?����W����`H�rq��,��s���\���g�c�����*������k�_��,��mM���?D�3�&d^V��&,��-����}*�4�g�������1��A��bB�qQq� '�Z��c���v���yG�>��G����1�����#l���}�q�=�M��d��K�{��:�%�/qS2$aVV@,���xy��t��H�������J_'�K����)�L����
���op�-=y��M��dnh�p�}0|I�������-�oJF$39:`A��$��KCz������L��X0�K���B��,��--��;�� ������K�$+R9:�����������1��|��X0{T��������dL�|��N���Y���W����dL���L��Xi`����vo�L[2&9x��p�L�� ��q���S|�Oq����/W�U'�0�<���S,���Cp��n�W_��������?%=�e�Em������MC����x����v���|/�\� n; ����H����n�����`��_@��m�������9��b��a��|2aD���WxBS���{1a�8n�x�O%�YE�����Q&�Y�"x]��j#F� W�#�LX� ^��#����-�C&���M�Y����IB��}�8v_�/
cSc�E��������E9X7(�]+��
J�`L�Gk��<�u�]�p��zb�
ZZ0�<9�E��,�b:ya��L�'F������i.�sU�F''������d�����q�O��~L+h�f��S�X�~�
��k������7����Q��ly�[�).��-Oq>�1�D�-�S��Oq����H�`D`bk��o�3�E,X009�bC@�-�����������a�/�a:�a�T6lDl7�Qqr���_���H��gXY�ah��/p��G�/��|��g4s�|�G�;���GF�1�G����G���K�#��1|�#R����KO^_�/����t��{��C������������Z@��#h�.��g�@���Ed�t���'7��L��5`�P��5t��������X�/��(
��1[�n��#��4�wb�P0Ern����J���S<]H��X��g�Z��~(�t���1~�Y���l�sC��5~�u-X."y�������8����Z�_��~����:�J����u�\���u��r1IWo1*['#���Zp����
��rA����a���y-x��������yWo����]�X�x�o���{���\X��O�3��)�8�;Ya���8�����%o��;���h7�"�<����\X��q��a`���W�����%H��j�Q����6������5`�x���w�<@��|���~�M������`8��3X�p"���<oXv��������i�Q�Z�q4bk�f����n,�4
�p���>vc
�vM�3���p�`�-B��������/��n�g�`,�t<�m�Ov�p���w�#\0i���#�q����[���>E��G�w�g�{����"�������8xg�O%C��Gx��(5�5��#<x��T2y�G���G��{������WxT��],g�����}�����DGz
���F���HO^GzJ��C�����������,��
�R��R�����r��Q
O�|`��h�=��Js8O��Q
�����L?�v��*�����Z�>@��_3o-�p]���Ib'3#��l
8#
"h]�Z��<@��Ea9��

���Sr�p�
�p�)��}1�(,gi���1^���`��<���/��n��y���`��<��r�-Mw�W�����`�n<��r���]cn<��� ���/�;��Sd��^���v_�1\#�e���^������)���1>�^u�q���y���_�N��<��C�}\�kk��o�3���IP��|���[1"�T�oO���Q2s���c�I����JL
�a���k��1I������d@;95���:e'b��I���7`�YN��������I��A�Ijc�f�N�������'�:d��Y���1v*O�"\�4�N��s\7�rW����;WW���c,�C&����4!_����U����yaw�s�����Q�-h=,�t=�qn��w�q8���n�1��8wX�
<�C���JF��A9�v�;�#O��S�W?����/�rD�,�Q9�v�B�'��{��94��c-�`�$�x�W��H3FA��E02��fS����K���2�����.��q'x�	��'��+ck��'x	���t�_��#�x��5O���+��������\y�W�����GxU�p��n�#����\�Wm
��+�dbu�Gx��k�����T�pD����*�������jlA
�{��5fN��'x0T��
u�H�@����[p�X4����wl]29y���*���d�<y�O�).��<�g����7=�}�S|�Oq�p��p�t�������)���#}����)���5\-��Z�`@��1�{o��X���A�$x]I����	����aLiB����%}�c���aTg����uMX0,�9�@@�Lh���&���U �t����x�;������r�=�M����� w�A�h�3>�=_���"7#�����+/r�;4�����En
�&=���	
c�H� ;#��%cN.�!'q&�";C��%��.�!F'q����[ &,�L<��V�i�D��y������y�r��d��<�_�����y�^�����y���%���y�^��Y�~�A^��-��|�� F'q&\�"���-��|�W�E���6~N6����EnKF'������&�A���dt��E����d�Nv����EnKF';_�]y������y���m���)d2a��	s��?����N�C��r�d��0�����m���I�^I"�M��d�xU���m���������0wt2p���uMX0:��y_?�0wt2����[Y]0:���cXk���(�phpU^������An��X�!�_8p���uMX0:Zdg�}"�}�-r�?����=a�V;��]��#��k������ ;���M�[�:���F'C����A�-�{/x]�N��rg���	#�RG�0jK������5a��d0�jp��?�0b2��W8��8��1e��	��&�}�����MG�
#�%
X�~%C����}�V��u&���������@30����8�������a��<)�>�m���Gx���dP�`&��~y�����0���I��I���_�`�.<����H�y\@'7`������x_2���A[<��s����;��F�w|P���6 ���x_2���A[;�q�$��q������}�@�[�m�x�d�XF���v|���K�"\;>hk�#F��Z�{�������������c=��s���_<>F�������]<e����%p]�F�
6���:�S<�5-����L-X��B@��d2� �
\�����]�����)n0it�y��JZu3�����C=�
-�-�
F$c�2Gp�?��&KQalyI��If#��ki�����.��q_ ?Z��#���v�??��#l�r���u
X0 {�S����K1���������W0ag�s�}��,h]�G�R����'~�~�#���[�>��FF�1\����9�Y��,�p����}~2�����������X2���QY>����/��G����d(2�jt�>?��2#�/p��5�JX2Yx�g�ZI�r���u
X2YP{>:s�/���~�l���KF"+����{i�����]A��d$�u4`�G���_ [v�c��d$��;}�O�;�q_ '>Z��%#�5��3����k��_ �u�k�����#���&1`��f]A��d$r�yt:v��[<�c����d$r���������x���#\0����>��K�_�T��mr��b����TW�.s�H��~�S�A��`$2�(���I�q_`S���
�)A$��~��q��`������7������
����������?��_������O��������������������Fx������o<�j���l�=��Ls8����O�o%�����~�'����B�&�����f6��������l�����s��mf��������L?Av������`�6��V:���5�h�}�l�����s��mf���4��+X�� ��g��\0|���?+}������7������?��f���J�����Av������`7��V��#"`�o�M����.��=O�����Oq�?�C�y@/��~9�3��Z�X���I��S<�������y�G�).��hH�/�$���D_k�N����A��c<�GwX�0�#�x�'�1���Q�����96��������L��a��a���<���f��c�����8�%���y	�����4!�8�%���S��d��.
�O���%#��~�S��dBC�&������W�U��d�������E�j��7���7<�������������E�3����� ������a�KV�m��GyW�i�����(�����5�<����r�g~\�emA^��w.�5����gO�������-x��:����Yp��o����oe��������-���D{�`Y�����`]���l������[0�,h�YGZ]����[*�Z��Y����cg�=����w����
��#��-�6�������jk�~�`Y0w�d�bo���L
���hB���co�tL������5`��d���.�n�'~|�m
�����5`��d���.�f�'~|��
�P��,�,CO�EB�q�q&�	^��%C��:`B�q�Q*�����uMX2&bO�n">�~�#o��+,�%c�����B����dZV��,��<�Nr6�7g���x����1��S<k��c����<�����I��9�)�� s����K�$+z�'3�l����mO�Jok�635%c�u%�p3��!��3�q��4��uMX2*��0<��#�j��������=�M��d�9��=��_a�	w���K�%;���)".�=���
^��%����I�&:�q&dBV��&,����8Y���0bC��AfFV��&,��+1��z6a�bIS����`�MV���*��s��Z�x�	h
�&+��������������C��^�1�����\��C����Qy������|�����uMX04Y[�F�����0�+ly�[�9.��-�q����%�M����r��d�x�[� Gl�=�r�?�C���A��������A���`h����t����m�P��^��-����!�W7��]�r���uMX24k�PY2Q�e�r���uMX26y�����&�~r���u��K'
�Wg���	
��H����K�����\���%uM�^
��<����[������cxK]�|�A6�
��[��&,�,Xc�:���\x�&�U�p����dt�64!��gF���&\yU����dt���D@Lh���������d���N64!��	#�"�����p�+��
M^8�D�6�
w^��w�dW2:�y�����&b���Wx� ���\2:9�.&�C&��Zh�n�b���liBe�d�p)��|��>��b}�����Q�Y1��+������'����VA�!���
�&��5a��dc�V@L8��Qm�[�v��I��	F'��h�	��06��6�S��Hb�����@L���0w��5'M�M�����h�p��)�5a�_��&L���������?t�t-e��o�<��<h���\ZzP?}���O�J��4��� \�����|��|������t���]��no�
h���	FS�
-�w�s;����#b�XF�"{��}w���������, ���l���w���k�������:dA�V��o�ohA����`0��<�}x�G����<����������N�����)x��).��O�����,��G�����r;����?��-H_���p
Z�c�t�.&�i:Hj�xM;����L���r}�,��Kl�[��;�g(���V���tcBZ��	K�%KO*�|b��m�iU��S	K�%+�U}�,����.x]�L8=`w��_,K7�U�9=`�OKF&[O�JsD�Jmc�f�U�y�#���	���	
U�����v����dl���6= b���W���z�X28���]�����������%�N���>�2����c����vmz@��J����j��6G����B��}����	Q�%x]�N���	��������Z(xN����Z(�?�sr0{+x]�N�r��$h='�&�^(x]�N��>�m�������s{*���}(;��!B��5!�n���S���`���,��c�#�M��p��������:d�����=���i��Nv���	
��(���Ns���`tr�t��0*�;��&��S����:d��I����i�L]+hBv���	
��8N<�Ns�c�ZI.����s���5a��d�Av�������h�k���	;�'Q{����+d��p����%�v�N��b���W���4��	KF'��?�D���w���9��i���N��8�����6�;��
9��p����%�����3��yxu���c�iB*�b����NYxw:R�L�����1�A��&,������z4���s���^��%��c'�p�N�D���������*��������	�>��7��M��U����x��p/b���	�
�X�zLX0:9�z[PLq�����O����*����}*��#~Z���������������|�����5!wo����uU0:9�}�T�o����w!�o����uU0:9��=���1!��W�.���E[W�����Si�����5a���I�������a�KVl��\�X�����b�������T����
���{5=�j'G+�tA2O+�rao�2�='��N'E+����I�,�z�`n��yQ���k��G�1\P�{�9���3|�����hs�4�{���F{��h�y3��V�h�����X�w���~��?������o�op��d���������7O�����������������~���fj����������������������������������?|1g������@k�����^������qt���_�\
&�Aw�kb���?�?��|M�>6[�J/h_=t���I����|&%�O����8��������?�����o����>��l��$���o���1����r���w:����3�:���Q��������������<���������g��%rW��*9����L�/_5���+�y�c��$��U��	���^�f*	�}I���}���7l�9JztP��YH��~�K����o�V`S��}����}���K�R"f1���o��|���v=��SH#��4������0.��J�J%u\j���W��4������Q;�`��K����R���P7��Z
�i���1p1%F���N"Tz��t������+%
�P[h=��r�.<��R�#�4W���V��K%
�X�@���BF�$wk�Y�<o+���F����A�ZIC�F~�n"���Q}���94� ��=*�s4��k%
�Gp����.�H��������d&�\�����������������Ru��q*>��*w-�������k%	�u
oE�������f!D�g1��Nn������Jr����������C.��3��"O.j�h/_+i�����N!�W9r���=����z@�@�^�V��;�[�.����z	Q�9m�O��;"�����4�N�yu9���y8&e�}f��������Jrgz+��
M9��^VB��6d>��������������4��zC�@0��!d&wc��)�.2+T�FW~��
�r
U��plZ�k�k�`��k�t2�{�[9�}nM9��>'B�V�g>�'��S)��P5�<�W����M��C0���n�A����k%
��Np�8�)�P5�s�~�K��x}��|��!�E��8�]��������e��j:�����4�B���y����B�P��*��
U3 �m(�ZIC���?�-�P5���)4���Y������4�N�VF�����;#�m����8�N��8W�^�V��;�[��qn[N�j(	���{��"�h(�ZIC�JW~���m9���$���Jt-o�6(�ZIC�Noe��������N;JtrF����k%
����q�����)��w��f*U��m+F����*U[�c���qM�m���%�H��H�	��7Kn����h.�����KM �����������Jn�����<.�����OM _����N�n�J��r������"h�u��r;�G _�����F��K%
��Fp�q���e[n����Jx�`"n'�������	������k����1���9��������|���v��2{���e[nW�����2�S��0c
7�+�JnWz*������l���a�]�2�O���-\�\*i����o���k����<{8i�e��j�G8�Vn�4�tUo��Zo�-��A�a���\?�U<g��_�V���U�����\Sr;�?�9`���T�U�����4�b�����\[r)�t��'�e���Zd�:G���V���"��7{sm��vBT����S]� W�^�V���#��7{sm��$��2�S��(�s��k%
�cEp�&�r�TGH0��\?�M(��(�ZIC�Doe��]���%w^	1�������q���|��!w��2���rUG
H0��Y��VF�u��!w�+����r
UGH0���~��m8"P���������o+�Pu�D��H���S��h�7�)�JrOz+��	��B�c��s�~���B��;+=���$���Jp���zsm��2����2���D���R�V����[�7{sm�mBT|���S_�������8�ZICn{��2�Zo�-�}E����Y��{D�������~&8o��Zo�-�GNf
U��< �����4���V���\[r'�	�����	����|��!w��2y�������;���Y��
U� �����4�.t�o��Zo�-�+�Nf
U���2�X�m3��~�������)T���8��_��~g��+��2+T�Noe���]���%�X	1�����`�q����������M\��5%wpD�3�82w�
FN�u�$!w���	������6!���!s
���p���Jr���x,^��mM	�$�6��R
-b������4w-��c�r�R��e��z��
�u����G�+h����r;�D�t��UT��HW�^�T�p;�_��zsm��
$��f���	����@Q�Jn������%m��[�@9���By'/(�(�RI��BOe��]��m�]W"�+c��ae��*�U3T�FOe�����e[n)	���2�S��X����.�4��t�woy�%a��[*@9`��-~��0�Q��.�4���TNou�%]������0�������
a���|�$�v�k���]���%�A�Y0���~jlg���Jr�*��fo�-��F���b�LE-3;���������n�����kK.��s�~����I�Q�PS��4��'��W����F��	f�����S��������\+i����������OM0��,N�b�Q�PS��4��-������S#��s������ c0*j�����������/'O��N�����Y�7Fk8e�\+i����l���r���>5��_��qG�`T:��k%
�]���U_N�O�	���2�O�'�QA{�ZIC�Io���]��5%wrD�3��L����+?9"P������F�+ho����KH0���~jj�N�T���$8o�{�7������Q���
��!�����4�r������kKn��r-g.��zd���k%
�?.ho����KhR�������)������4�r������kK�tb8��3���f����k%
���kef����\[r)	��f
U��]���(�ZIC.'�������n�;<)s���~��y�����������y/����KH0����j�m8"P���������_�ZN��N��G�g�3�PM�pg8W��4��HY	��������S��eV��Y�Y�PS��$��5�A{�7��\��	���2+Ts�������\+i�m���V-�P��Q���)Tq���!����4�ZICnoE�����%�Mj�9`��5T�mtV���k%
��Ak�����N5���a��Ks|G������-i���{����������\H5�(����4��tYf��K��-��U�!r3R�B�Y�S���4��PH���\[v7$8r�~�+��
�@�������N��"wIa�ew��0���U�R��@����~��a��F*p�����{2�8��o�*s-�|"�,p��,I�]*~{'����tM�]j�9d���������~��a���'p������lD�z���Z������o�4������:um��"7�-��zvY�$p��,i��P��8�J/������5�2`����5K����]-i��FX�r��um�e��`��\R���#,J��v���wj���H���kK/{�s���j����Ei[�O�L��)Yz�c�����cV|����*��ya�����t��w�W�-���kK/%!��7�`�lH�-�$�t��w����VN�Z�		��3+V��d��hBqwKz����j9�j�($�C�,Y-'2m�#
��-I�]�����W�iVk��\0��Y�Zk��������Z�����kKos�"���E���`*p��-i�m��������v!j��]`��m�������&:���r��:�|����Y�Z�������~�����kK�����4�U�uBFA�^�[��;�o���k=����!*�K��p�z��wKzg�-�	k9�j]NBT���N��;�+R
�������~��M)\����w�	Qq^�����1����w���w���1�x�������cW��&�j�=��N�[��{�o9��X��V�����4�U����8���r�$�w���	������n�D�J��dn
�j�������D��{��Vu!�2��j��Z�����=i���r�{�����n'D�r��Zm=��������A�����kK�0�Y6�U������~���w@P�9��]���N!*�e�Y��&L�����4�N3�y'�]����w^Q�,���Vu!�{�nIC��%�;{{S�W��E�.[3�*���6$p��/i(^��8����^[v�����,\m;�M���%
�;]�����{{m�=&"T��6� ������~��a���7G���k��^�t(�����{3�b�{�fI��^�q��z{m��W"T��6s��^#���o�4�6(���z{m�e��@�/s�����n�����%
��At�J�K��-��I����Y��{4���7Kv{�,�^o�-�OG��-�%�}@�!p��,i��O��z{m���N��u��}B:A�^�Y��;�g���Z/�����!*�K���j_ �
��rx:-�w����^[zWF���t����et�����^����/'W�{E����e����a��D�9i������Qt�z{m�e��`����j?wh�m������~��_�ZN�:*����t����
�C�^�[��{T�����)VG}��v���A�+p��-i�mPF'po�����N����u�%���_/p��-i��j����]�������!�C��Y=�^�{�nICo��?�-'Z�G����E�cD�+p��-i���������N!*�Ko�ZE�;������4�r	�����kK�|��>�g��:X�$p��-i�]��8L/��������8/}f��X�>&p��-i��������r����|l���gV�������)wKzw�-��}��ju<�����U��d�q(C]��%
�'���;��Zo�)�g5��������

���������"po�����T��8/}f��lP}-p��-i��B>�{�����v!D%��gV�N�2	��wKz���t��^�����G��T��}f��d-���,��;������^[z��^iO��F���#
����#
�#�z�{�����i"D%�0d��:'��������&:oJ�Zo�-�Bs��7s��� � p��-i�]��/�����^[z����tCf���P*$p��-i���R�7{{m��BTR
Cf������JT����$:��/����<#�R1����W'}�S)�S��4������^Kv����|*�����j��������#�o�z����s9v����9�n��n�F����Vo`�g|p�������D�$|����Pu-���f��,i�����{�����3*���W�zC�]��ye������{�����<���!o����F%���,i�����{����N;*~��W����IL��%
�3}��;����l��2����y����@�(�������=�zo�-�O��D���b���c��)�\�w#
���w���^����w_	Q�2�U�������
l��HC���wd���^[z�e������
}�������4���Gz������:	Q�������~_��{�nIBo]O@W�����U5j��C�;��
��Z+�No���v9���x>Ze���w
�:���V&�<i����������R���w���X�C
t�&�t����po����KQ�v��=0�dU���k�LH������w�7{{m��*T;���8�iV����{kG�����;���7{{m�]BT�)�hU/H�	��_z����fo�-�B����l@3�*��n��	��_z7���{9���BT$��L����`��+Q�������ku�k���V�I��P\�)��7tt�N��R>�$�6?���Z]��5���.�hc�����o��6�.����#�po�����l����Sf��i+�k��\�����B��7{{m��BTD��L��<��z�{��KC/��?������w�Q�'3�*����A��3W�4�z�{�����q&D��n�����GH������^�9����kK�����f���+��~�������w��2����S����C�u>���)�{��KC/��?������wc���:��j��N��J:�{��KC�N�e�/v-�Z5R
�6�|�\k�H)��B/��?����������f��y;��1�8��c�nIBo[A��7{{M�mk���9d���Vm
�^�^�[��[DG���������$L��l��������0
�-�����^[v���j�9s`�!�&p�{i����V�]R�m��T�!�e����������aw@RA�����ew��P�)��e��{�F-,�,[����S��9��;Dv^]vg���o/
�3}���R�$9����t(���*�h���<��o/
�+}��;-���l���a�oi���U��PH�^������g���B/	�����	���2KV�����
���4������Kz�-��p�!�e��*��Js���%a����	������v�L�����2+V]��!p�|i�m�����S����`0s�U�"���?�4��������U!�2`�:��G.�s���/
�=B^�{����^v�	��3wvb�Nin�>�4�'�yc�k����R�!f��	Ao�HBq_z����A���^[z�		��k3�*�r��n�M(��KC�B�e�������a�`���;�[z�J��||i�]������Zo�-�T�s���5�ng���Bq_zw����}�Zo�-���s���E��`���Bq_zO����z{M����&�C��Z��L{��M�����W�[���^[z��&�C��Z�5B�^in�>�4�b�����^[z���;���
�Y��[�����}|i�m��N����kKo����K��:�j��H)��_z����fo�-��L����Y��������^��{����kK����w��=0�j�O=�g�w�����_N��g��II)4vuVQ
���C�^�[����w�7{{m�]GBTD�&�j��������nIC�V�lJ9����^)�C���V���N�~/��>�4�b�����^[z���R�&�j�h��?�4�b�����^Sz����������U��������%�w������^������1<6�i2�VC��!p�|i���s�{�����v!D%�l2w-�Y������cS���^[z�	��3��E�@��Bq_z��������;�R<����j����0����?�4��]���^[v'�Q�_2c&������������
}/����R���v�U��]08ep���o/
�=��;8���l��������e�ae��*�����aw�c�z�K��-�;O����mf�j�z����������>����zo�-��A����f������$��o/
��r.p�����;V*~K�y�X!�����$��uMt�7�������t���2�a�������>�����k�.;�r�~����1��5�)�^v;�,�fo�-��@����Y�{�������$:/����;�|�J:���V�#��{��KC�8�7�p�������cT�	mf�j��N��?�4��t[&o:�Zo�-��	�9`�.�^5.�;���/
����;��Zo�-��N�J*��,X��U	���/
��������b5�<��K�2+V��\����������������Fv�	��3KV���CknS>�4���[N�b�r����B���t����e���
�}|I��j||�fo�-��@�J��Y�V������;58W���O������o���|��������_~�����_����O��������������?���_�w�C������F��������>�Z���������w��/��A���������LO�@"��r�4���]t��i��"p�>VSv�����������s���}���er�?��X �ewFx&ho6A������9�nfyoZ��L�~�'t�����I�����e���'�����E9mp�'g��7t�,����I��l��e�����z3q/�f�vw�`�c���]�8M�^�:�m�=7BT��>��7W�Wn����Sv�
.����m��\���-����n��C���X�e�>	��4���l�n[��4������ynt��������e�7��m��fBT�����hs��C���������!8���r��< e*�C�f���7����,�����V���f�u�!v3�O��������nf�j���L�����g[v���j�>s-�<#��v3kU�B�e�o�.�U�+d~�b7�V5�:�p�4��������_Z]N����]0���\�6o:�����E������e�n���<�2|`&��0<d.F�GxhD5�-����!���g[r���D��Y�Z*��g8�Q�bJ�R!�%h��=���P�!r3�-5��Gz"7�Z���I���z�%�����i�\���xg����������^��m��$�C�f.B[z���#=��Y�Z��$h��<���]����4d������r"7�T���I��ky�%wB��h�MC���eB�+p�fV�65	�{���R
Z���!sQ�2#�]-����B���&A{����\.r_���!�N���sg����u��
M��f��-��A�Z����j�nl�@W)	J�.����vg[v�-ZS����j9o82���5���L��f��)�+v-ZO��Y�Z��kUv)%AI�]�������5;��[o��U�g��Z9�Y�~v���3���^g[v[��F���d���!+�2���5���*�����B��-�}E��>�1sM�����v3��k?�Iu9�j�w�b7���u�G�:K����,T�#a	��������M0����T�v��J��R���i'8���rR�:��,�3�T�<z�`7�T�.�����][v��]0��5��"o���������Z��E]��f��-�lb[�E]cf�j���U�_S������e	��*�U��J��~�)s=�z0�8����z�4��t��z�rZ�V��8�����Vw3o��n���j�V���!���][v���xw��Um��.p�fV3�f&8o�{�w���v!D%��2�Tm\�.p�fV3��%8o�{�w��]�A�9�n����Gks��'v3�Tm=�]A{�w���� D%��2Um\�.p�f���.��,m�w��]�A�9�nf�j����������UmsMp�x��V�Q
�!v3�Um2X�#=��Y���,�7�{�w��]�m�!v3�Um+�go�����m���z��k����R
�!v3kU��������S��������n���k�.� ������j;t8r��������r2�x�w����l�9�n����B��+�kJYPv��!8�/����)�
��<Dqf�joy�������1���]cv[�F��5gX�w�<n�������o���w���B;/����j�y�����?	�1���]cv���T��Y��GD7�nf�jg���.i���N<��J�3��'D7�nf�j���L�T�%�����s�9�n���}A�!p�f���.��-���5����������1�X���6(
����J��5���tlJ*a�<�j�t���\�
J��A�e��.i����(���qn
�4g�d�q�K����4��tYNo���&^[zG:��K[eV�����BO�fV��.�7�x���th���j�����#=��Y�:8��p�����kL/�C�`^e��.m?E� �^~8��_��5������0�2�UG���p$�'z3����������R:��Uf��Q?w8�����������N^cz�	��*�bupi���BO�f�#�/?�u�/���KQ����W�%�cA�{8���������^^cz�
��*�ful�=Y�������	���f3�1���e�y[e�.m?]��������������n^cz������Z'cG��N�KC/��������ll;�1�m�Y�:k������%�������������M@��5S��.��A�q*MmJ�Pz[�-��fC�1���:Do����C�!p�f�5�n#8	]A��do����Y�:�����	��w�[/ho�����6�7�ju��=N��M�JC�T����ju��M@����Z�3R
�����	��w��2{S
��z��e{����Y�:������	��w�[��;��V'��t������1�PZ��������-�U��
n:D�]o`����@J�Tz��:�4������^cz�������)��=������Z1^
~����|�������������!~���zC7]��k�V(
������fo�1��A����m�V[�����y��7t#�9������v1*)�&o���
����Q+�Bi��`�\���H+Fr<����8o�������p�s������po6���;����;7y'���;�n�N����4�b����_[z�=0���;��
�t�@�Lo^��
�����-���.'!�]����^������|%�]����k���kK�����9o;�*F�xC�d������Xa����&_[z���w����l��n�#��JEXz����f��-��N���mk�^��VuE��K��R2���+�po����[�#!*y�6o�����ph^+%Ci������}����5 :�����[s��~��
��Y������������v1*��6�vUw�u���Vj�������w;}m�����u�z@�!pC�f���a':�����U=�����eWc=!� pC�f�������?VP��g��I�-�y����!� pC�f�6���{����������Y��W�n����F��wY��T
jW����Xh�V^��CbA�~~�����������<!��Q��-�zC��w��JaX~���n��)�
�!���[{��__��CO�*�aI�m�����sA���WbT��.s�US�~�!~3�WM��R�������
�������i��j������U�D���^l����;�QI�vy���
��
��Y�jz����
���k����+��.�2�7tP�n����U3�wim���_[~'��t����U3
@7�S��R7���������t���;o��`�.s�UC�H�����_5�{Gz������'d	G�m�w��:F kxwF�T��w���hC������W����f�U$�;#�=��������{����_*D:�o����@�P�(D��f��������RP�j�������_���Z��-;�m�����b��-��N�Ju]oW~�?�
"��W��K�/��?���������Q�������E�W����\=�b����_[~{TH��0���\���?�!~3��-��?������wX�Q�/�������y�nP�JuX~1��n��-�b�V������v�w/p?�����k����r<��(3�����>�_��8��A��{�{�����u!������K�Z,�{�
��Y�n����~{����^jD�9Dof����;�3��#����%���_[z)	�����d�HDO�*�Ci�=!�����zM��*�gX�o3�*��vX����7s�����:gM�����6�Ps�����]��!pC�f.��������k��-��F�J�w0S�"Oo����
��Y���&��f��-���:gY�3�����~}��C��f~��$:��/����;V���~���W��^�����vX���{����_�C��-�����U7���u�����o7�q���������R��uy��f����~;G*��B�e��~/�������,J�;�	WQ�d�1�X��7sm]�!�+p�����KmH@����;�aU�n����W�Q�E��-�'r�:�o�e�o����J�W�J���������k�o_1@?����������������3�{gY�+����6����d�v��;�c[�n����U�����-���_[~�����1s�U�uy�!~3�W=g�����Wzm��gbTz����U�}y�!~3�W���7�p������'dPJ�����pC�f��zD���y�����;m��d��C��N+�MJvA�J�/'�������.1*��1�~�/H/������#����_[~�����������_���_�D�w{m��yB����h�_E����dW
����4�r(�����k���]�������DN��U*���{��?�k%�W��9�����2�WC�28
�3�����[����_[~�
���g~3_

�[�����m��������'�U����~����7�of}r�p?�������1j�s����
��
��Y��v�6�J��-�#O���>O�{*D7�of�j�*��6�J��-�3*$t����W������,���yg�^����w�	������opX�������a�>)p������A��!~3�W��E�����_
�ItT_^��mM9>*�T4�)s��p@��!�3wc���Q��d|h!pf	k��<��W) JB�X��wV����kJ�X#,��������n���
�XoD��_�m�mvBd��3���F���!z3c�~tV����kKo7�2[t�\5rs��
����j�N����&?��;T���9s��8 �%pC�f���BI�cr���_[zG��A�,9g��G��!z3��D�e�n��&>��;#��!z3�W#��	�����q�����{������ D%�0g�;8�=n�������oY�{%�i���n#1*��9����[��g��3�Ggk�+������mT&�]���z>���J�[�T����X������p5�+1����9������+pC�f�%'n��w{M��j�!��;��;^��y�����J�P~k|}�n��-�mE���BWe���Z8�7�of�j��<�{�����n!�p�sW�iW����w/pC�f����u�n��-�j�t�����4���!~3�W����JA�jwbwouUf�j�P9$pC�fV��	u�n��-��H������,_M3�{��7�|5-�]fz�������"��!~3�N�n�!~3��ON]�+����n<!�X���\{5��I�����oL��>95M�����;�_1���MOs�������w�������y��_~��/����?����=��O������	�_��������/�;"X��o��#���n�~�_7k(�\��'��7�?�����w_��>��?�7��QY�*s
gO���Q�,�
�	�{�M����[$;t���8�����������
��TX���]��;%�b��-��F���"b��-�=\=A�7��7�x$��&i[z�>\$��<����y��'hC�f���5�n��-��I���P��mO��J����,������i[z�������mO��J�����������C���uV:@��Ir���B��!z3�|�J�e�+(���N�a�%b��-�;C�M)W*�����m������m�=x@������������H�J�UzO���W���mJ�R!
(��~,����K��A�7���T�����h[z�_$��~� 7=�on�)�E�R^���q����mK/�!��L��<�-�������k����E�+p-z�;S��c$�gV�����t5J�U�{���fk�-�l1�v���Hv����\�(�Ui��3���e���`�k�[E^���Gzf7�n�Lt\&o��5���]6	��f�U��]�.JkQ��V�a�C����h[v)-���������=]����������f[�-���e�t�>s��yg���B��f���.��-\��8��{,�v\"��������n�n���4��tY��hSv�
Cs�����Z!��!v3KVk�E�����e�>1��D,37=�k�t��
��Y�Z�,�nK�-��D�a�%b����mt��uf�j�0�E�������G�����Y�Z{��
������_��;l�bC�-��J�a�%b��-��RA�7�\����wm����d;/��m/�	q��
��Y�Z'�-��fA�j�Ob{/��m�]P%$h?��R�{�������������r^�� hC�f�#��n���P��mK��|������j�Q�!hC�f$��n������mK�������5�������7j7ufEr=��
������n�3\������n���
��Y��������
�V[�D@���Zm
�zA�Y�m�����m�my@�p���<���#[��W����,9o.g�{�����h�7�j��(��!z3k�[��
d[z����e�sS�j��.h�6�U�mDL)p�����KaH@����M���]������67D�o+�Zm2�:@of�j�.$hC�f�5����Q�^����w��1\E�����n(�!z3�W�	�������#1���������(��!z3���	�������< �n������3u!A�7w���h�����kJ�^16Wv�E�.7=�{�B:A�7s���-�y�.����� '-��fV�����
��9�������t{{m�e�����y���!�������\k�w�����^[z��&��fV����]ilk���V�P�7�{����^��	���k����]�lk����>�D�|�����)��V�#V��R<#�&hCgV��9-�{������gd�E,.�ew�g/hC�f���$:�r�k��-���n}�XYn���-��n�����a������k���bx�H��r�����T����,[�GKt��"�4g[vO������m�=�!#hC�fV��s':�V�k��)�G�������Mo�����
��Y�:j|{�#���k�n3b�G+b]���=�Ab7�fup������k�n���P&�Gl+�=�rY�6�n�Y�::��fo�-��s�����1��?M������1 ��w{{m��($��Z)V�p���#��I�`������]'M�����u����������a\I���L���c�~����D��/<I�������M�t:�~���-�{f���j�CY�Q�������
l�.��:�n�����[p(���;��r������l�.�z�^�����g�k�e�w��{V���z���e?:�nf����
���;��r������l�nsc������nz5�-�W��GQ�`Ko�E���r�����1���+�mOo�V���8D����w��.g[z5���:bc���w��5��;�i�w��m�7bTV�F,l7m�<'T��G���r������lK�������#���^�3��I��O��V4\�r��w��Q�d�������i�z?.X�������.g[z���T�y���m�^n�>�m�5
�������e�%��������u��v����_���#�l�=v���_�r���<�1\�_+��S����@�z?�j���
�{����n��%�SU/������).�7t����#������}L�@{�������F�d�LNsz!=���E�5���n�ob/�ZMU�c�v�V&����n�������E��.g[z��>Y��d�4�3�2?����ZMf�<���r��w��Q�S+�g�����)�����5���m��M��T���WbT�^e�l������z��S��mq�2���lK/t���y%��M@�CO����x�B����J��-��A�J����Mszw�[8����Vo�F\-�P�W��m�=&bT6�+�I���c�#�l��U�����r0��j��`Iq]5��������I(���C�pgV�j������l�.6�?0���,\�X1��`7�pUc����.g[v����K�d���v�6���3�V5��<���r�e���C��m��j,��
��Y��{�-���5����a&���R+�����a�!���3�V����S���l�����[je�p��;!�����NL��.g[v������2W8��]*������gw���x;%�	�������9�nf��^�S:����U��eY�ut��f[vw��U)�S:x���;������X�;]��[Fw����^4�=@����X�*5j�����X�'}��[�q��������q�=�Z�*���6"^��7�Z�T�����^[z����1e�p���48 7@of��i�
�������31*1������1����2�UM��7����kKo���)A�����r��
������G�+h�����;l��D�J^��;���z3G���E������w�Q	{��4�N{n���uV�t�7����kK/U!�7s�U� �mY����uV�B�e���E�-n�!z3�V���Cin2�V�F�e���U�f��qS�^�/���{���.Cf���������{{m�E��t����Us�C�Q�����Us�m9�
U����C�fV�Z���
��Y�jk�����{{m�mP�'�C�fV��
7@of��m��w(T��v%F�CAi�KCo�T�����U������_P�j{��.���J^���G�!p�fV��n�����kK�p����4��9�X#���7�j��p[Zg��+����N1*���4�+�p�fV���n��B���^[z�=t����V�����7�j�.t[wBA��]7bT���4�n�=�p{��Y�j7�-��=�bo�-�;��v^j�/���3��y@����Z�;�g��+����'1*
J^��{�AA����Z�'�����p�������m:Do����B��)�mcf���;��w�T�:�B:Do�����p�fV�:������M)f�[������4';�p�����U���7{{m�����������p�f���o�0_�]6�	���u�n�g�)�mSf��W��F��Dg[v������,[u3_��I���R!A{����]6�	���U�nA�B���e?�]����pMr�e�Mn�9���hyv7�����6e��
�B��fo�-�lr�!v��|C��Nio�2kV�A�e7�`l�.{�s�������E�S�����Uw�LH����5e��s�J��������5*�n����U_�e�w{{m�mbT:��4�6�P�z3+V}s��C��Z�w<����4�%���a�����3�U}�E�������_�Q�PP����
7@o���Z��w(���)�7�^��<n���1o?���P���kK���1���7�`���<n���uV�L�ef��Jo�-��H�J�������.=n���uV�J�e�v(\����wCO�l����4�n�=����9�d�ot�7�������|l�������bVC��c����������w{{m�=�l�!z3�V�I������E�{�h�����;�5
����$��P�����U��{����^[z����1�/
�
��n������v�o+�Z
�G���)
xI.�����
�S���_.�I���^[~���:�/��PC'pC�f��n��w�{m�'bT����4�wDFK����,\
\�'p�����KihP��J^��;��m��������|�n�-��F�J%����������!~3KW��	��
���R�}������n��u��������|�n��-�T�eG_����9���Gz�7s����|�n��-�'#eI_����9�'Ro7�of�j�n>�{������FnzT6��J#^��;����!~3�Wc
�^��m������Q��S:�����E�M�����_���'p�v����
��x0J^���!�&p������A<�w�|m�*b/-��f�4�w��+pC�f��F���}��)��B������9�#J�n����8AA�7}m������%�q��+pC�f��F���7;}m�]vBT|�)��5�(�!z3+X�
�T��l���wc���#j�#/��� �
����q���Q�}�����9��7s����&��Y�����)lz�������C��W+=yIJ�����$?����T�r>����gSz'�C�9Do������79��3��������{9_�m�mq9���g\M-.g��7�x5�Hm	������R�*MyiNo�����C��,3kWS��n�4���; ?-�C�f����C���;�D���W:~m�yB%�T���8W�!��7�6�����pD�WZ~m��gbTr�J_^��;#�+pC�f�%'N>�w{~m�]������������Z����������"�+p�6����m���~���4�wG�W�����mL;r��n��-��@�J�w��]M��C��6��
?�w�~M��+�ez���%���
���
��Y��+�.�n��-�l�!~���(�y�������&s��� ��wm�myB-��\{5��n�������D���W3"��`��Ks?��gG!z^k�Y��{x��n��-��D�a��Q������37�of}ck�c��+����N��t���uW�����
��Y��'x��n��-��J�a�Q�������
����j^�����*{m�]������yEN�����_�+����[VP�����c��;/
�;�S��7�~5�(��w{m�=�����F��Ks?POn�����|�D���/�_-�t�����K�^�����_-�Nt���{m��B$�C�f�\x���=��Y�Z8]��������1��7Jw^������!~3�W���������xCe&z�t��9�=�{�����_-�.p�����;��V��;/���������������_[~'�.�T�F��K�����
��Y�Z8]������w�	Q��7Jk^��yA�+pC�f��ND����)��D�J����9�+b`��8���p,�����kK��$���Fo��4Gxg�+��]f	k����?^������1��4JW��{��G�����`-'���;���mJ��8��7s�Z!Y���.���V(��7{m��OBWH4u����N7Dof�jm���Nm������N0����=���i��������A<]���zm����J�V����&�����^��Ft���k��-��N�a��Q����^�7	��rzGH��S��B��-��@����F��JszY�$p?�����8uM������T��^�&�v���I�����]�����kz���������]h���4���M7�of�j���8uM������#�!�C�f�\w�n�����u�����T���'dWj7���4�����Pj7����z�w9�aJW��t����W��6����,]muCt��������
�!~3�^m
�_��7�v�5��w{m�m7bw4Jw^����&��7s��u7�����_[~����W��Ks~{��7���9��z�E�������1��#�;/��eu��
����jg��w�J��-��B�J��t�����M7�o���m����5���k���2+������~^�
�����m����{
�W��c��i���4���M7�of�j���8EM�������7�7�~���@�������w�BA�jc����kWy5;g;�(�o��Y��8]����5�w�6bT*����$�w���������Fe�����k�o3�RZ�t�����w/pC�f����$:oi���_[~;��F�3_��{��Y��P['p����������)�yi�o�^�����O�CCt����������>�!~3�W��^��3�����wi���_[~'��Q����4���^�����_�3}���^����w�1��4Jw^��� �!~3�W�J�e�n����k���T�7�~�o�@6e5��Y��7z��w5���_[~��&�C�f�������V������w�3�x����L9f�q��k?������z��q��_No���#lK���D�2X��KB�Q���HT���F,p��������E�������!z3W�mCt���mLo�X0���\�ut�n�����mD�
�/����R!�z��4�����p�������c@�+p����;�����}f�����������":o�{I}6�wF�+�C�fV��~��
��Y�:f�-�7��$>��,�v^�=/��]0�B����,^+�������lL���K��7���cc��){q������sF����5�w?�Q�-S�����=7�of��8��������qN����Q������C7�ofa��N?�{������F�q*���;/��=k��	������^��[[w����_��	���{��-N��������������k�o��C@������jc�y��7sm���~�f��1�=O����Q�������Y����������31*��;/����
��sfm���[&po���;�
���2�;/��;���!~3�W��������k���2+��;/�����_����Y�:W��	������n#1*�eJ�V���������9�~u�H.�������.�������w(��9�~u�y��z��e�����Y�:O���J�[=�������wz��\��5�w�������y��7t��Jo��W�zs�����~5WmE�Jo�����������U
�����}���{�����n&F-��[z��n�N�s���!:oY9�j��=@�U�����a:G!z�z�W�x��v��e����wbTF��y���j��n����-�zCG�e��n���k��<�R\�t���w^�nV��U^�j��.����Z��1�+O����Jw^��y��n
��M�W�zC�e��������bT�����4�n�mJv���_��������u�z��=��J~A��Ks?�i]oU^��
}���_���k��y���(�[I�o]5@w*[ks��u�>���{�������Q�/(�[I�o]�@W+ks��uS�������5p6J���������VY[����������
������3�����N._�-���������kK��D0����9��t���6��U�y+��	����'!*.�����^�8=����,`����)nz�������c
w4J^��yF"pC�f����~����sM~��wE
D0���[~�����$?����J��)mz�����m#D�yQ����������������~����sM|���Qq^���4��M�!zsF������_Sz�����8/Jw^z�B���n����M�������l�/�!�7���7t|Gz�7s�F� ��w{m�m�����u���g/pC���|s�����p�t'1j�o����G�+pC�f��������k�/�!������~�6�6���2�r���]���_[~'�:���t����W����,]5*����_[~����8Jw^����M7�of��Y��8uM��������x0Jw^~W��7�of��Y������b��-�;O��x0Jw^��yg�u�5���fG������k��1����t��9�zn����Us�w9������B���������P9$pC�f��Z��{����k�o����(�=I�o��2[�����_�����{�����v$F���3��-"��7�~��PO���_[~������9�~����J�_�Y�j����n��-��B�a�U���w@����,�b�����_[~'�e�_�t���}����
��f�'�	��{������$�p~�U������7�of��]��/�����_[~W��%��*�i���C7�of���j�c��+�������t����U�#� pC�f��������/\�����`��l�k���4���z*pC�f��Z��{����k�o�(D�V���\�U��������UWWD��]w�����o�������kP_'pC�f����-�{����_*D:�o�����w�9
�3��������;��b��-�=��7�~�������� :V���i�H���^�����$G7"�!�3kX���R������w�	1d�J^�#<!,p�v�%�nn�����@���@E�!z3+X5"��7���-�.;Gz�����u'�p��*�yiN����
��Y��6$����_[z�����V���F��~5��~`@*DW���O������o���|��������_~�����_��\�O������	�o�������?�������������-�����JM���O�o�J�~�!|�������s���c�$�s�c�,��
\9���>��zSv������kR�-��A��E������;xr7���J�-�^A{���]6	�������#�kmD����
��m�����H0���,��#d�^k"�X��ew\�����i%�pP��)�9���n��33�X��@{�	��^6����ViSLsz����B���� 8�h[z�G$�C�f���7����A�~�BiK/V�=��m����mD�� �U����%J��@Q�fK�A�e�V(]�����]D:d�����J��?Q�fK/�=��m�6�w��+��Z�E1��j�@���eJ�P���w��m�mFb��nU(����7�.�d5p-�����lKo����,Gk� �����������-��,r�����~%F�:IQ���~��
��,k\�&h�6?��;"�0(��ZE9HszY"p�2�����7��j5L1*�������!7�.��1�t[���WZ�m�]x>f�yQ����� ��~teI���t�gNA�j�x>V%�U��4o���c��]f�j���l�������o��8/�0����=�p�TD��-������SP�����EJszO�g�j*������n��_Y^P����E������L7@of�j����N�+]���631*��"%9�#k�n������b]��T1���lKo������Y�Y�$p�fV��n#8�1���lKo��R��CiN��T����Z�*����g[z��Y0�Lof�jd9��
��Y����X��J��-�sE�a��U��4�w�d*p�fV�F.B�w�m�]b��oa(��e9�����3�V�J���cz�����
�~:Do�f�qC��
��Y�7�-k�_mwnM)�yF���*�P��`���������x�u9����`[v����
EJs�Ol��������w����cw�������}M5"_�`7�n5q�����l�n�b��U��$gwj�����e��E�+ho�:���
�����0���q��
��Y������q�5���]6�	���E�i@�;)�m}f�j�4A{�����q!D-���YM#<z�`7�f5MtYFo�{Mp�e�=n�9�n�B�iF�;)�m}f�j�w�c��Bo�-���s�H�L����W���6dV���.���w/�����7�7�b5m�:���!�b5��Y6�BA�jb�����Y���Js��Y��:-��3��\5��M@���,WM':&��m�,W������PP��k��	����������$����;�
Vss����hBI&��-"��7��e�{p��3��b5w31*et�(����;��	������[/h�����;�|�J2AQ���; � p�f5�n�����kK����MPd�4o���C����j��zA{�����y F%���BiN��t����3�3��	�������1*c�a(��]{���e�y�[�z��_����w[�QI((�Pz7�[8*3��N�e�&.����{�|�JFA��\�2
7@o�����rx3
{{m�=za��U��$�w�x@����1s��T�����^Sz�B:Do�*��F�mq��'z3��,�w&h�������3Q���C�2���_/p�f�5�v%8g~A�j�6bT�^EJsz{��7@o�J�������^[z������L��<��z��7�j�p������kK�T����V��w�_/p�fV��	)A{�����y&F%���~iN��^���M�U�e��2�;��V���:4�/�j��(�����n����v�������cU�^E�K��]v�[8��2���	������RZve�����y{��Xa������r��?�;n.�����V<�RJ��~I.��B�M����Z��BpL������R�&7�8�r��h�Y���)�r�6p����^[v[���9�nf�jm��
������=�[MwMu�e�;	Q)�S��4g�GRA����[�={A{�����a"De��"��9���`7�l�r9�����k����|U6�������	)��I��n>A{�������CY��*�_��w]z���5�u�Z/ho��������� Wd�4gwE������3kV�V�c^���ew��F�b7��u�G��7�����Z�����k����|��d�XE����n�����z���������U|=Ne����%9�[�\��
��Y��*|{��no�-���t�����[��9�������A8)h����������z�/��m���z3�U[��1A{����^*B:Do�yV[�~s$�'z3�U[���}��`�
;1*S��/�������%�mD*K������������Y��&���#
=��Y��&�-��}��d�Q�!z3�Ym��m�*�
]�/
����;��bs�-�+����.��v^|�����2��l�������h�7s���PH�����[m;=���Av������ Fe(������d�q�S�u�Y��N���
{A�jg�����Y��+����VW������"p�6����>7�7�t�7@v����2kW{��w.��_[~��&�C�f��������Uf�j�����-�����M@���,^�=J�v����2�W{����b��-�lu�!~3�W��dW���>,Y�QM'p�6����^7�7�|�O(��.����_�3}��[Ow����_6�	�����}�x�+mnu�Y���.��I��~���M@�-�)����1Q���:�~�o��7�~A�j�yB�pz�S�4���d��:�~���]vo~�b��-�gE�a�S�4��dr����:�~����Oo���N_S~��o�2�)
`~�
���
��Y�:�������V_[~�	������A�p�g~3�WGsso�����K�H@����*xt(�;��������!�����)�=OI�2;EL�c=��n����1 �%pov���K�H0����1x�H��H�Lof	�7���]S���������N���\����������?�����/?���_�������k��?���������/G�����?������������|�"/��|LN��~������!��C��;��{B{f=��p���kr��]F9��������8���q,Q�rK-��k��x[n)��q$a�-��CSr�{����txSr��>��������\LA��|����{��0���g[rx��9@����-�
LA 7��=�c��f��-��F�J���������
��q�`Kn��A{�����~ �p�H�:r[r{��
�@�����-�=�;A{������$FE��8�m���N���X��ewD������l��4c��6b�-�T%m���}vY�r:*�+M����p�T
W"�������S�[Q�4�.�ts��V.�<��KK@��8�m�.����J�\,i���=�9<��<�����N�F�"�e��xm\�xhGI����y������$�pIp�*r[vO��GXDSv��a�DA�����l��Rq��0�P����x���S��`w������vg[v1��:�n^��
�p�,�'v�zUoX6|z�w���fg[v���%�T�T]
pm�S7b��-�]�O��O)�U-U?��������-�+{��zUoXN|z����V�TcE����W�z�������U�a�����u]�����fb��"����;�7)��r{Us�Oo������ji�q��"v���������$l�E����g[v�b�}9�H�.*�h�r{U[�O/�`UN�Z�} �p0b�-��p�27���|z�j9�j������������z?bz�-���o���Jw�)�u5c8������B4.h_o�0�����p�67���@Q���4�6�m�����f[z�_��]/(W��F��$`�r[z;���6D������v>������lKo�c8����^�|=����?������p�v6����@�z3V5z�hC��>���{����^z��,���s�h�*Y�4���t���@��m�] �	���%���hC��>�R����������u%�����%�Q���e{��/�{��\�Fum~MY?um�_|�������m��7�����oX6y/��au��o}�K����$G�Y����s���44�N�a>bg����lx1��B���zM�E[���p[r���|9���\��>�^��JC.�bho�<��������E�}��/W��������M������}`��Y�k��@�r��)�-�bho6=���������}�����4��/���f��-���}`�\��\��>��\�fK.�bho6=��������2�{-�bh_�F�%}��7��m�E[�s�"(����-��6.��E[����g[v��0`fe�E[�m���c%��^��>���z��}����5�������+Zl�Ec����g[z���7�L��1��6T��; Bg����g[z��}�uKC/:ch_/X�����w�m�Ek�t���RU{2WZc��1_���7��n��)�]��C���X�nJo���N���#}����9�4���:6�vJsl��v[z��)��u�9G��;�t��:v�vJwl��v[z��)��u�$7[z���cJV�c;�=6bQ�-�l�������}9�?����^�~�����������^��vJl��>�l��
�U��
��� ����^6�vZ����6���?�����:��vJl��v[r��)����-������%����������]��v���%
[v���c*V�c;�?6b?�-���������,[v���c
V�c;�?6b;�-����������]��v����zU���Ni����n�n���^i�m2��=�c�@wlA��gwl�t�Flf�e�����1���]6������jU���^i����n�.�c{�96bv�-�����������������]���Jol�������[c/v>�����^i���\�����^��U�L�����}�5��V��5�WZc�������7�Wzc��&i�eklh�-�V�l�����:b%�-�������>�c����i�}����^���J[l����^���kXL��_nK��4G�t����<�R�CW����P�#*�/w�R�#�!hov���{����3��E��dT~(�r�F'r��f+�)�s��������A�Tf*$aw`G�����7�����A��#v������Ai	T�Q�������xMo�e�-���XW�E��=�����=�a�=���'���l�.{�'��2�V��)0�o��]6���kz�-�l
������Y
�
����a������xMo�e�M���X��%��]������a�M���)���l�.{�'P��J�.��)0b��-��	=���f[z�8(=�u�Y��8hM�-����)p4��6JS`]g��vZW`DO�-��
]���]���X����m����mi�e[�h,(Y��D�J>P)2M��X!(��7m��;�H
��]���6��t���E��AX.p_�����AFP��m����]�Q���e��E`.pC�	��o�������k�omM@���,\�=Bs��7s��#�!p�6���;��$�B�k��������K0���\A'������I���I�O�A`��s������}��Z���c����}���m��������M��4����n'��y�X�'���(I��iD�mr*����?���������	mK/��u� 
�3�l�S�����1������Nh[zY�'�C�fV��i����{��	�KC�G@�������~����4�n��M��o��>��l��n3�-�,��!z3k}��kr����vr���6A{���^V�	������D�mr����
�Ti�=�i�w��M�����L[�Y��kd�n��#���k$���~h[z���D�2d+
�
m7P����kKo�<����mKo{��gS��4�v��n�0�c����i6A{�#���~"F%��f�P�{D�7P;����d����h[zG(k:Dof�j��@b��yD�M������wZ�QI�)!��;!*�/W ��;#�&h��D���@Y�!z3�V���\�^��N�������m��z��cS���wCX.p�7���wC�C������w��Qi�k3�V���\��^�d�������h��L9>!�	������dp~j�Zn�O�=���hSz�	�������!Y�B���-	�K
�E��l����u~�9d������|,N������6�^���h[zY�'�C�,^-���S�wm��-���{�5��^V�	����ji�eQ��T�]p���;�kY�W��g[rY�'�C�f���Y����{:�����7;�m��6BT��]f�j���/�[��;#)(hovF���������jv�n��c����9AA{�3����$D%%��L������}�����
)AA{�3���}"F%%�eV����
��|,h��{ %(h�6F��{"%(�C�f����N	F����{"%(h��E���V+1*)�.�`�V�n�������5R���n[�-�
45�7�`�6�n��*�r���AFP�������=�Q�v���CH.p�V�%��CBP��m������QI����GL.p�V�]�u@�C������w��&�C�f���A��
����l����w[�m��VbTr�}f�j������l�����w;|m�]��	���E�uAT.p�t�O��T�����kK�z�����Z��r�*����n�v��-����#1*����#
�;�r��z1�-���n��-�'�5�7�n����Om��������x��M���nl�!~3W�7�MP��O���>�-�'XP���'�i}���4��OpS�cjql�e��h,(]ml��F�>�t��QpS��e~�)�:jW;7�Sp��]m���NA�;H�/[�@�`A�jc����
��������*XG,������[�W��z��Wp�z�������+XG�	�������Y�b��-�l��f�!�|��Yp��#V����f���,x����_6nZ��2� 
�l��f��e2���Yp4��66nZ���Y���,�i��s���f��i|����_6
nZ����2
�l��F�9s���F���(x������Z�Q�����Bt.p?	�{�����h��M9n��	���5��A�.p����47�
�������!*)��H�j���/���u��������!8�||7�\6�^�y���F�?}���������y~4�o�>���6�����������h�P���fs��q8:�V�9�gV�.w�����/�dJo�|���u}�9���~!D%�6f�nw������������Y��Bs�-�#4+��7��wp���}}0�-�#�	������h[z����cf���~W��7����L8���/�G��������3�}�
����M�]�I8���/�G���U���3K}��
�P*53��������h[v���s?�TVv��U��<����Y��Y��J{�-�'�*�7��wp���
h@�����H"�N�W��M�=���B�1��wr���
���n>k�Ng��+����61*u~c�*���]n�=��$�-�
R������h[z���2?��-
���*p�f������Y��J{�-��L�J���Y�:��U���s���������h[z�c��vlN�%��;6Oe�fD�-���yvl��N��<��Sf�����S����g���;6O��������r�����TJ�������c3����^��<�;6/�G������cs�,Z���y*;6���m������c�b{�-���yj;6��i����S��YG,����K6��������%���ds�,[�\�y*K6c�gm����3�e��n�V�m��R����������P>���~����{��<��m�����QINy��7t+�5JB0�����������m�oW��T�������Sr�;�m��f|}�7)x�=���~!F����JWo����57y���|}�7-x�=�����A�`�m�i�G�����%����������m����� �x�Vs
t�R��l!#���������������O�f���������������������b�������w~{?�������������a����??����������~��/��?�����?����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������9�i�U-��������q����{&�����8_7����{�q�t��9�s#�����+������o����ux����Wj�����~8�����o��$C�']~�p^�6b|���5������]��7q�e����r����=�����o�Y��@T����Q�W?���z�����p�o�����Y��$�n�����L��d�f.�O�n���r��su�_����b��������������{
����{x=`x��8�p���2���u�������o�/g������F97���Z��T
������������O����������?���j�n�&�?���O���!�g<����VV����p��2����5EW�4��nw�Ec��Wc���o���y�k����	C�F��oZ������=6?������/�������E��?L�zO|���@���\�!6#.�7l�W���/�'��Q6��7�}���]�{��{��=$<�����{8T����v�s�l����mFC���:�5�a��_x�P����^�4c����=������P��v=�{x=����������#���s��^�_����(Ux��o��>��r����=������9�~��������s�}��M�1�l�nx@zZ\[U�� ��?x��A"��x3,8|s�����:���f���E~�)j,�"��
���=E��S|�����h������)������1�j|����KH�������2'�H&�-�sG�*�ex#��-DxX�)xcX�&O�q��a������"��;���y�j��BC��0����8n4p����o�
;z��e1�	'�AmU L����;p6��!�-N�$:���|;����O�y���3�K��D�;j�/�C3�����c��
�����|GxAy�R���������1���|g�|�C����N���k,h>�f'U�r�[����V-��1�ZaC�@�/0�2�1��%�!���/��i��~"�1!�:	��X)����Y��L3��r2k��N^��="��T�_x9yL�aj�j��u�W.�X(r�9`����D�;h?�p������6�����?������<M���.h#�����2���l�����~o��wr�����!�f�x3�������y3�u���y3���s�-�;���,���"o��7�SM����z�������;�t�����R��r�!��x����$�	o�i�-���g5~t^( 
�DL���c�Sk DH����L
pSM�Q�|$���o��)�KE{S�����6�I�Q�|zv��.�0��7���7s?����!R����������?��O���c�!��y��$b��7q��CI�|�f:�����<����%����9x������JU����D
��*c
x!�����K��b[��W; ������t �@w�'8�+�|9g������4x�������U[U���K�F8�]��j��j��N���n�_�����l�&����J��t�w��f����'��Z�zsS`���V�$�NI���R�e�i"dn��K�{�&�����;�Y9�e�~o��j.���:sq�`_O��5�C�|cO�4�y���I�RP�
<���=���/����'i���(����3gL�p�s�t'W�nh?:Qu���j8R��o�.y���P�*h]����I���U��* �5��-Vmr��	>�`�,���(h]��L~b[�~�r�.y��A����r&?	B�`�/y�/�����^��������������W���rf�R�`�/y���5���Xmrf�b�`�/y�*�!,���rf������q8���~CK�ykV������(��I���Q���_��c�h�p�j�X��~#*��k������(�|��x�����o�:�Q�c�9�,�j.�O�&��#�hI��� �����l�����N�y'��a!�f��5����[x'����6g�F����p�jw��{!
Mp���owr�44�2�\���u�I�6ih�[^.J?��h0��$<�k��
��bS�a���?�R�S� �>����5\|�^�&8J��L�_N��)hn��������27o����6"�=������P�%�Q���I��5�m��K"f|��7�?��z�%��9>}0Sa�P_��R��C���Xs9H�%S��G����-	j.�J��JGx2z�2������0]����5��F��\?��+F
��� C�4�!n���;g7TsIx��o��;wj�R��K����������?^]&����	9@@�J��w�����p��)�746��I����K�;����p�����$���)����5�6<����eSs�`[�m�������l��!����;�X��:��&|����H��&Y��6R���q���L���>�V���\�
���#��z�(�����Q}j�F��3���Pas�~��'7���W��2���Pa��~Cj���e�����3v ��_�s8���������e,g�Z�`�/u��J��u��1�I�SM����!u��e���_���ee�������XP��E)g?/�J����������_��e�"9Q��+�C��U�c���/^�2f��A���!u������>����B!R�Y��
��	�����Q'�9�������C�C���+l�c������j.ph.�B���������0�}���y[]��a!�f������=����{���9�6@�*�]���w[�w��m��s�m����O��}���w�N>>O����T��^Yn��v�1�<��S��lj.x0�%����t���~�Q1�;�N}N���	�Rj5�����k��j!�����=��O!h]��T������h�vj.	����[s9��t#yr<��.�P+<z(���6%��M��J{���\���k��C$(x]%'��K"d]�@�^�hQs�`���z-����t�M��}�3�����5\��sk��m
�/���j.x����s;��n��K��������������f�O��1i���`��!��'���4��

������}��16��w\Z��eRsI�(���,��KbCU����`�\����	�U�vd���G@�;y��Q�g�.b$������G��m.���c�e�����'EA�1{�D�9s�������������3����������'�%O��������+h����������yY�*��3gL�z�g�%��;'j�����B��5%�y#8J��wN��3�I�z�p�xJ^�Kp�6o�x�����q��	��o�J�{��C�,!R�����)y���!w
����r�;(Ga9rJ^�Jp@o���3�D�A����)y���>��1�?8A0���Ds���G��?8&A0���s���:��;'~,���|��x������'hc��q��Ts�~�Y����j8�����,�K]{�;Y�����"nf�\�m!�����Z�9�6@l;�/�j=]��^HC�����[t�"���R��h�����)�4t�)�65���S�F<pu=���5�_��w�L���c�Qm ��������j�LA��/���@��)�E{7T���fu��68!h
f������j.p�2�[s9��t3>����Jb�
��Ru�|/��/���i��Gy��RJX��!s
^7����'
c�hUs�-j.l��p����5����������)<5=�Pw�b����|q��Ke�9�^n�����5���>�0��Yi�������9�������}	�����&�O��2n_������2)}
�\N
�2�_���",��K"�P\$��?X5�6T	���M����n��G~�����J.�
�[@����c�`f0����:k����Cx(%�1��T�]���(U��;'j��3&��*�Va�L[�G���0s�D�0GX��S'O��
s�U��9c"U�SQa�������vOs�Dj�g�s8����9wA��/c�����7|`<u*�$|/�=�����$����Z�����7�~�w9��1��@\`�:����~'���>�L#b��~��nPOd�f�o���3�D����n�pZ6������L9I����m8@��r}*.0`������ o�0�w�9������}7S��
��u���:���2�v����X�U}E�o��!�U^:�z���'4���?h����7��k��os���y7�)t�/>���<x��9g��#��!,^ep]�����U����!�n��U]]�_HG��ky�v-OG+#�)�c���f�h�c�9���&L�U���q��D>qC��q��^���y����]���!���.BI�Z�	�����9���KG�)KV��|DGMs������!R�\�R��L�
U_�JMs��i>U_��]3W_1c����Y��$V�Ek�M���2{*	�o��1�TZq����Y*�f�F�s��.�z���q!
�)��RW_���[�l��=��Kb�V��V#���pWD�^[���
Mnilj����$<z����F������W_���O�{����6��1��Y1���L��N�Y�����]�v����q|�+r}�?d��$B8$���eR}IlxL���������"gvS����2>����H��clbDa���Iy�M����]<���{]G������
��
@�O�����1u�@D���r�uj���{����9c����$O����m6���N����s������:�HtL������1w�@D������
�O�O��U�,(12�^k��p��������w�e]e��:gX�Iu?[0u�����/U�D(1b��g��0����������
���u�������N����I%c����&u%��r���X0cV�����J�l��������WLNx��,	f'<�z,X0"�NZ0<�nRO�&����S0��`H2S�����/�k��:d�n��1����j��~o��W����YW9C9`\yA/��Q����x5��I�u�3�#F^�k��(�Ct��WoaQ]���q��*�E��o�z��A��y�<)j+��M��m��I���vF������T~��LC�=r�P5]�����C��Y��8�9`<(u*�2(�DG��?���s*�H�S��!���*����,g��Z�2��n�T�@U���*�������6oU������yfbkS��8���������$<x�2��	[Ue:��t���KXTe!+eN������t�!8l�������$��&�����N��Ue�wy	)�8�aa��*�����[#]�/_���U�s���	�G�l��(b���Pq���G9�xc�s�Q��2�@�u`A@��L"�;�2���`YTe:��������U����"�����S�9�o�l��7�OLxnv�#)���F�gt��!���1�x�q����f�?�������1&F4s��#�&W����c��ydb<i�p����*�������Q��YpB���Y0�Ht|d&.��T������R��3*����9����e�`��8�;hA���:��#���TT�6yu0�A���L�#T}�Y,�V��_��r]Y��t��]��$����8��R-P��-�\w�k[�n�$�z�,�M��1R��+��.ya�Q�����`L�S���+{L��vY�z,X0&�Q�,�C���.���Y���`���ce�������L�C�\;Ua�jU����v���	4'���,�&g(G���O��$���][�j>��%M�P�qA�b.��j�����1����\�]�_HS]����(MM�;|��D�kg��&<D��74<HS�m*3��h�-���>Ae��?*��u���S� Fh��6�!��
t����4�mN��u�������A�l�S�6�A�-��i��T�Pe&�qLC�4���2s*W�I�����
��Kb�{�)M5�6����<�oh��
M���X�9JU��<���~Cdpc���P����XL*3�����|�+3��A���3�e
>T������H�U)4��3��L�c���IAwyg}�o��L��+��3����8{����@�����)��)�"<�po�747s��2�k��3����K3�Uf���+��?X��.6���������2�����vF~�C3[Wf�r���\2���;C1*�ht��I�~[��7�xxkG��>w����2��)�E�� ������.F��
��~������jZ�_����#�Q�*�CL�Jq���U�z,�/��b<iA���O�:�v>2�����J�� 7�OcA���n��<���A�wWj[��Uq.:��������u1R�=���>qu���z���m��%D�'��C�m�n������m��e�\�TvO��5�	)�;.n���,���w���zH\���C�,p=��Yr1���2�0<&)�����+���$'+�O�t5"������`������`�	�.:DL�3U�a�r1I� n��_��*3]t'-������Q'+|�jL����z?L�ky57�P���c��U������Ws������1����9��]��y5w~I���#/�^�����l*3]t���oWs�4��u�hIE����4�E��7Tjb7@�_���C�D��<sS��hh����z?F�+������T ��)���MtH�\�s*�x��Jgc������w6�9bD����\�gS���C���u*3��Te����������s	�3��)�M��ad6�%��=��
�M��YTf���P#x���XTf:Y� ��W?Tf��h=��!��bS���[5,�����|})!�����Wmh���[�f:�6Fk���������K3�������#��UH��LN����$��"<&q�����oh���f�|����D�X&��@x�4�+��F�����{��2��$�����op�L���A�����@��
�����~\��-�o�C����`�i��eX�����j�������$#�~t�|����C����X0g&�ZP���'S��niA�2����I&FT����+�D�G�w&��X��9^���m��-�@�����)Qb��+�CL^Gt-�����L�c����6�1y}0�A0��L�#�R�Y,�U��`��3�D��vt���k������X0gn�wZPQ(����@�7����3�D�Ft���KC�j���X�`L����R��=&:Z�_�:�I��B@�,���&� ����_�:�I���w6^����X�It(���v]���kO�5�ij3���'^��%C�P�yAO�������j�������0���'��5�Ct��gu��3�#F^��R�:]�_�S���y�v5�S+��E�S��|�<5�1�\�<u�)�6����2�\"���������_t�wU��?m}��@8�u�Jocr-��6�����q��@8�unJuk���AG�s�W��#��M�n��T�@m&��T9�o*�smfW�6�A�Xa��|�~.�|�v�#.��Z=��w�=��������j���?�6�������-�3�L��:
�Eu&�q6B��F��n��L=����u��B��6?�G�$:�C�;���x:������Ug:������z�Q]�R�:���x?|m���X������j�����P������H9����1��<x����3��]�C�����N��eQ��@D/�`~�����t���fh�����eS�IpmKpg�W�5�h]�Y��Sr����op��u���!Fr�����5�����Z�0��~�T���g����U�{����d#\)8�sr=����W����FT�
��S'Tt�p�f�&;ZP�p����@7�����c�l������4��+p=��%FN6�!���s�A���fL�:���d�g��v�����u��%FN6��%-���3��/�*-}w�ahN]�DtsE�+\���%b��+�CL]����*�/�K���)�8�����!D�Pq�������Q	���,(���I��B@�,�z8�q����+\��1	�^����^���3t(��6^�H_�Kc>EM�Y}f�~����j���r�r������Gt��w^���o~|���[#��vf2d�b����3�A��r�;xC��Wem�Q����w���n.��&V���R���5KU������M�I�&�<��gd�������1�9����f��6�<�����S)PI/eDN������hl?��X�tuE�y�[/�>���!s
���a�J3���uK3�r��D����D��%�6
��5����"<�D�7�P#j��L���)x��&�'7)���'�pq�Z�hR�IpH�
�8��3)�$�������+�3|�4Ss(�c�d�NI�si�]CR�4��P�1v����y��;����g����������1��G#�x�R����<
�X�0>�+����L��^���	@��;E��,��L@������7��4�������,��L��.r��0�j��ai��|fG���6&;kv���p��5U0-av����7�����5v��M��r��KI�ba"��2�h��p-�A�<��u�w���~H���R�Qt'��M\*F�����~J
@
�R�o���x�\\*E2���E)��n?�b�/���0����QY����He@4�����$<i�p����%�7
��e�,�������
H�`c*��O"����F��h���;���b��	%"e�=,K~
���B������W����=����d5�A��+ �����%9���o���!'s����WX�2 s��`O�@��,s���\yD^����b�t~dT�cl��A�����S
K��~w98B��%���|Dk��V�3�D�^���Y����59S�
�`���^�J;�N���U:+M�mOK*#[G-eg��v������*L^`������o�]f�~f�����w}t�Sw DD}���tMt���k��� �-
X4�#:D}�5`N���	���c�|
1�n�h�oQ�S!f]U�+1�F�26p���7x���cI�$���f�%�qR��LjP��X�����j�Z���zt5�)
��r��u�����]�������R�T��[�'��J������cu��q������mQ�JpsCp��,1+r?>T��>b <$o��U��M�X	o�i�-.b��F]�\��u�Z�ha��xsKm��`UKF�kK�Jv��^*�Z2O��F~CCm2�/T��tJ�W"6����c%Dn
�/�Yu�8>�����7����G�u��>�����c���=�7�N;�_g���=1����C��|��/������������,kX���ad:�R�~5+g
��9'�CZBr1���8'p]�L��Y���V�6y"����;�K!����2 3y�����Oe@�0�?��3��\1�w*����+d��k=c��L�`0y%!��4��=��%���T������D�jt��Z����(G����MMz���\�DlP�.�CL^�Et(G��s&����r�6y10��-
�-Gos&���`����2 T���\$2w5
�^�#���	�5`�Hdfa��&����;��[����Df&�Za��G��ZV�Ca��T����o��'�YMS��~��<�^v�%����"/�AI����n��<x�~�98B��<���dp^�����]��������������2�@7�^?Qf�XlN����h��4�1���@��[~�e�����G�quU
�W�7������>��@�P7gmBz���
a�oC�r��HuSY��!�#:
��e]N���n*���L�
��w!�O�����[��@f��~���V�F�2�kR�=����5r<?���SE���|����}_bG�Tc�^"����G�jL�C���
��&��Tc��������|�3}I:�q���M��/|w���>�t����sWc�*��X��$?�����YE12�?��(����"<��s�����3��������.UG��u��o�E5�N�`~�����$�.����f�Tc:� �	����n�&{�S����c
����ox-�hu�#;���YuVw�!�������WI�1�@����/�p�$���-�h8��@tmGz7v��D���9d������;����D&��L���}jE�A��W����Dv ��G0�4 �|�������4 k}�
���A�t��u
�1�@D:y�6 �����n�i@o:���
u ���tr~"��3���
������HD7�4�7�3�����s����YtA!p]fL+�T����p�x"NP��k����(���L
�D��D8NA0�����th�[�
b������?�|�y�����\#��y���Tc���,+�������������N����;���"/�U	��y��������sp���ySz���T�jL�����\:3M�\q �C&���;�h:;��YUc:�i>�7P���<�~�j���������_�0������41�������mbr��Hu�P��G}@wR�<�M�CN���n�J�`�|�1t6�o���j�r;�y�&������%��5���2��w^#�z,/,�~m�������v"5����A����G�jLr��2���}�jL�kj��?��K����!C&q��C���M���xw�����
�����#w�����������#jR�YE0�HA@�*�����"�����]d\�T��������_�Z�Ko�I5& �'u
"�,�jL�C�nuvD�YF��������Ki���}����6@����l��=�H�����iv�r��7����L�0��|���rQ��,
�h8g��	X�eo|������� ��D&��T2C�T
�M

��9����L�`0�"Ht|a&�t�!g��T��f7��n��0g6���(�����Nz��9����!�3���������b�3�@�3J�H�!E
H���_���3��b�.�t�1y%�Q�\��Y��i%B�4�*Cs����@�)�3�@�3�D�D�I�L^BtTA�!b����v��Jb3{$��4�7�9�Dv$6s�L=��A����u
X09(���t������D����M�QU���T��ST`�Uc�����o+��3�#D^���N���#:�����n�����U�N��.��Bt��k��!B��!^�_�L]����D���ib�#,�C&��6:��
�P��V�bS�	x�A�1o�0����Uc~����1��6�HA�}F�����O0�����i@o�7e���.s���A�B����;8OP��&3�+P�It]K~s,��1��{�C����>�c�`�k��������},	��k�i�:���r5�(�1��x�[�Q[��$D;�
-�1p���*�Z��-�1p�}��?�1���Q��T��9�cGS*��Ns�M�1xt�o�����V��-_���O����M�g�N����cU�`D�N@�*�����"���8EV���MET��{�R���z�V���Y��D:%s�j�����$�����Q�Y6��8�p�6�+���������[@f��x����Ifw0��|QB�0�fw��
]#Y��S�kW��uJ�j�f��Id�A[*C���r�m-
�*5eL";Q�,�CL�Jq��pY����D&�����R��<���@����Dv 2��+C������;Tj��
%����]*5���s�Q^;�C����P"J�s�L]LtgEz�_������d����(Y������O�}����������?������������?���~���������������/�;�s��o��#���[I����7���o���9����w������q�s�!���F��7*�omoP�-������"��s(��!�������.��s&����9t���T#A��/g��O�Oi3�����_��~^�h.���[��������������l{_�~�,��^[���	Z�~������%�o����:�N���r�KC��?h�{�~���|�����rF���������_{�;y����9�\B�����r�-7�N�uWs��y3O��������{!wOp���O��V6�@B)�����	���t?�������<�O���7��w�w����KE[{���u�D���9�
K}m����K�s�
�x�~J��h����������r1B���w���H��U	����T����U	���M
.�T���h
w������$<�E�2�"�SZmrw�Q����K���T��>bx��ZjR�Jp(K�pZ�oR�
p]����v�2t8�>D����s��� ���hV�Jx���HIg|sy?w���{�~���f��?������*��c<*��N�����EM6c��{V�F|CSU��V��:���7��Z������o�I�*��%���,�jU��	n��
�F�������o�=DHG�������!FD�:t�hn���Cx��o�C��Q��V����-�n�p�������D����aA�1`��11v
���N�8���t���u�1}�`���_�.� ���i@�[e�c�����7�{�Z�3fB�����)��<i@������
%������.�$2��T���0c.��HGv���p�i@���v�3�EH@����A�z�1��`<i���n�Nd��������
8aj��0u9������`$2�4`�/6{$2�CR�zX0��)�_����
x����su�Hdii������k��8*�K��:WS�?��?V�Xy-/~�7vy��wG�����D��7�m��W^���������y!8^���g��MA$1 o�-�����^-&�����o�r���������Z���&�i��]�YW�Y�b����7�=	��b�
����������;#��#���^������m]����1R�<�����>���yz{��OAR�<������������y~�5�Uc��1��o�$�%��5:�����R�Qi�X^]��J_c�C����Q����A�����|^,6�bC��B8�����G�5a�8\�`T���[���9Xq��P��/�1n;�R�s�5�������A�~��6U��f�L����sTK�~���	b�"*F����r0"�sj#j-n2��r�!ysvq�M���:8�j��}7�����?��fYTc:Q0*�_x�,�1	n@�����f�Tc:�Pl$hc���S�W�1k�{!���gv`��#����Fn ?���M�Q���!<�s�c,�s�tvh?(�ZO�"�7`�ab<h�psg�\N8."?����&g�Q�z*������C9��_D^79����a���<� �9J��/"���Idb��{*���p����M�l(0r��l"G���E��y����#d�S�Dn�Le@��E�u�3
��D~*������O�"����V"F
��&�!y%�q��_D^79�J�HmR�D>$/g%8�!�E�u�3�D�TD�M��xm
�E��y��D���T6�g�D8H��/"����7���&���E���"������#��������G��jL�;h�o���z���������'��=�]�����&�S�D���#��"����98b|/b=@�r^��h=���*�#6:���$����X�3���]���m��Mf��z���.�\`��1���$��k�=��7��1���?�:����;��+���������?�������'
X2�8,"��0��@������L�
Uc�v���w��s�jL@�+����s��5��s��Y�8f�X_#ey�jUf��1�����;h=��y�-fc��X0���<�Tc�nm����Tc����y|^b��!�J�����v�R���k.�M5&�Mt����i�����1���bU��g+�cN��(`���PE�7�TDO�Y�����)�1�8������[y�fYTc�B�dS��Y��8>�K�%Q�,�jLU�%R�n�n����W��{�+#$���.F���{��|
GHo�B����G7t�d��R���sh���R���QC���a�c*����r�n������I���M���N�8�z�����j<Ie@�{�M�cjE���������Od���eyv�����Q�v*2��l"�R���Iy���������L]���a����Rw�������m��jh@���.cZ����f�:`���H�����fL+9O0<�bJ]�JpuGzl�]�������0uE�*����\$Rc�����DjRx�u
���D����	O��R��v��4 ����D����Uq���1pH[�����V����sh�����������1�v�����7����;+I�3�#F��}��(��Bp��{QQ�3�#F��}��h��^�L��k��<�i+�MJ�hCTL2�<���7T`b7'(P�IxcC���o���s�rTc�����y�}N��!o��,���5�a����9ub��Y+��G}]��b�s���Y�~�f�W��]�~���\��n�E�jL2�����Kb�k4�g�7Z�������2��i����1���#�J��1
���E5&!����)
j��E5��oA����1'��}����~�|oo�~�����?�D7�{�`[����b6ekBnQNu�l�l����a�*ExL
l���?�u�'��oQ���~������Y�0|��p��i����Z��x�&���y�J�@�����E��&���xR	9�T���I�(���<������*E	n#�)�+�������>�oMm���YX&wOL�kv�#*Et����W����P)*xcXo��[���-M����J�>g���/�@��\� 8�oA�1`�706
�
�&2`�JQA�p���&F(�:`��j%�4��Rt����������
�BJ����#�rp�Tt),�U���Tt���%FH�:�	&/V&8d����9S������^v�

�/r��������uRD�(T�z,�3�E�'-���U�j[�:Z�_,:��z#��t���+V��H�c����X���j�����z$A�1`�hdDY��}��g�;�NZ�_.:G����^yH^�%:�q7F���A�;���
6;z>��a1�~vf���n���L3x0gG���e-bz��x3/���1gG����p�h]]�_�P�,�O��&V����
�Q���n�Z�h�S5����Y1:|��W�~����1�77E��Q~p0R�����El���on���1���`��������~:
���dt�(?�A�sW&WfX�f�AG������jF���S3�`�{th5��G������jF/��������w��<j�����]iQ3
�m�,����i�,jFp�&h��I!<p3�������V��P�7�$:�m���ai�Q����e:�pa��w��-���2��Ba��~\������D
����r0"����(�7��r��6��������e���[v��NW��7��.������}����.��:<�����eS�����,h#����<sd��e��
S���Q�����f���=����N�����6w���L��������.s��.U�_E5f�%;Sq�����

-�d2����dt���*:H2�c���db+ZP�d��� ����+����d#���Xp��;���YQb�Z0,��jwL
NP^�����F��	��S�;�NZ��U}��%Fnm�����mhg�Z�)g~�Q��*�
ux�|"���
7L9L����V+n���� U����~���3^1bkkD�#Z}C��-�Y��.~I���V*�JUC��d��=�����Cbk?�X���/�Lr� �T�@
��"��������V���;h������n�OQ�iV�9�%����7o������g�/�])	N�/����W`�J;����Y��g�]����|�R�Ay��w�b>�q7���QY����������h�T�p��Y��=��)D8��f�j�lM�2x`�{*E���W�:Y�2���j}]�]{{I��y��!�@.&`B>�����|ml���+���+:\R�m
�����Z��1��B%�D�B�zJ2�r%���V4��Y��`�[$�CO��l�y*	�oQ�-U~��K2�Yj������ui"�0��L@d��`~����$��xw���K2�o	��4"9X��������Gb@��J2��B%��7�I�#��Os����/����G�����1n�YY0�1jK�����,��x����s�x���dNJ�G����7��$':%�B��f��d�IqI�o�QI&�)N�}���R����C���@����-2�Z�fv�#9��rp�
��{�n���T%-����>t]��?*3c����I��9�I��	:�\������V4`�d�7�'2���e��0c�����e�2`jA�A�f
,U/g�����2�pC���u
�1�@D��`0u%��������r�Q�,�CL]��C�����4�N�'��7 �6\O%a9rsCw(�2��5H:+w��5$1�I*s2����DwR9�s2c�*S�� r*c2��� :� �-$�����VA�G"}����u
X.�+��s���%1�Iz�d6�"���ze���G��BL��}� ��j��AC2�����r�������`.v�]�{Y����"/�V�)J�����[S�����s�u�����i��x/��'3�`E�)�C&�tn��v�!����Mm7,(P�Ix���wq#2�j��bN
�����A��Sw D���6�!�x
t�����149uB���k��G}Da���chr���i�6��3S���:���4��j��N^�Y7_9��@�Bf�0d6K`�H��
��V
�<��G�'�X4P���<�SxGSk��X�������S�ZV���jL^Q;V���eu ��sX�V�,jY	n��<k�c��:����$b V�8�P-�V������W����O[���C�C���gk�/[=��e�����7���OH=Y��oUO�`D�����i��I=��'p#��n�|Cv����^�~'��w�v��eQ��@�S�+Tk��E-����fW�����A�u��>�q0_���e�z@f�{x�b}��hv�#9?��=M�y�6w�qD��T����uP�T�q�m�<!���W���}r1��N�;����q`�~�t��}�D��*}��� ���'DT�N������@W�4������'Dx�������u
�3���g���$9�;����l�����Oy=�-I�H�v��lB$����Cq���n����e�WdUDT�
�2k���?���7@,2�hG��w�5��&`�Z2!�j#�5F��&���lGw)k���
�hGON@�U��	��(G���f-!������lGw)�r����`����!��7\��!N$������D@6	��f��|^$RW��U����H]!N�k>1��hG�b/H'��$7���'F"5���F��^V�C�����z����p���e�^�P��A��	!�.e��lP[�
�k>��^��lP�����:l�y!:����e�y������^��i��^��k���4�2�4����a*���������e%<F�=�����
9�{Y[|��f'a�2�������-A���������;"����I�>�c���]0e����4���t�zY�����=�y����c�+���l���%�N�F���+���<Z�IoT/�F�`�������������D6;f����1	����r������)�y<��K�(�xM����"<��c_����1	�n������2o�����^M��z���/>z,XG0�8
�M
�S3�:�(x}�P�u1�1_k W@�kA~��
��I�EAZ���B�n�8TA�\�n�����WXf��m!\7fw=<�8DH�
k�����{V�sg�[�+��Y���8_�o�����]�=4��7�Ux�
����DT��
��*��	+t��7�Ux�5��8��F��]J!:V���*���I$�
�XU�&vFp��f�
��<��	hT���U�f�
��kG" ���U�ob����!����K���Hlr�X
���^���!��&`�j�
"�	��p!7��U	�J��:�X
���DZ�����&`���
".�	f��m�vV���i7��V	�J+�L�t���6vG�
� �f�zb$�{MgL�$�Dx$��>Q?1����:��I�XD���>Q?1���:�������B��u��C�l23k��`������f�^���P����y��E	4�Q/���$�� NT���T�y!:��i���N�"��d4��^���4�����q*�+�6g#u�G�����@s��B_!�s�������*k��8���]�
i��A�n-�)�������!~��������P��;\Cl����v1�����E����N�w Dx����
��R�1�����]W���������^�fx��$V�^3��D�4������q �F'�<�������v{M����]���\Q_�PX����r���p��1}�!h�gO��w'?���?Jw_Z��{LS"s��Z0.;E�//^��� x�N��7�W��@���?^o�=;R���n-\/~k�6�^��`�Z�H+Z�����x5�h�nE�7���A��J{Z?dO�t�"���&+H�(�5�g�����%8�e��+�������S4��Q��d��US��=��F.�����Iat�1j}�^��A���DL��' �z�7!.���f�EOu�	��}B��nBD�Y�mf]�2����]�x��,pb���F�Y=[It�0�f�Y���M��������~���IY���)��h3���������)+���63��0z�2��L�mfM�J-!2 �6��d�`�� LY�"DV����%t�dhW�B��%/Bdfr��pI����D�d���A����lgh'��`��A��Y�U������)��(��<������'F"KA������W�0}*pWl��,L�,���F��N�kt]����I;��U���Ct����^i����B���K�"��`~��#:�e��&`��g�8��y:.��k������Ad�^��i��^�.�A<�2
�.'%��yn�U�	�����_���0����HS�z����g�v��W����2'�7��m���"����I��5:$6�����k�	��f��o��r$�f�r�.������`�,���)�F����]w���o�+�r��H��l����+�Qmy�c�q����FNi]���s
o&�6�K����\AlV�G�
kG�N�58���X�f���s�u����&�-J�^�71�Y��q�����1-�<D7�
^G7�}��>o[��Q�������� ��M.>��@Q+�}I���igu����Z�����j�bc�<X7��
%���~_��sq�S����B�n�58��pItpA�1����<7��������e�����i���y��	�{��<��Y9�0�������\o\��e�c���v�MWD^CD�3��E=�@t��w�U�6]y�U������K)kt,�lW��tE�5DV{�*�qw*ia���]�"�
"���Q�OO@V���*|�����j�Q�/���pD�g������]�j�"���Y#`�~�5:$�������k�	h$��0w$�fR�KYV"D$��F���HktH��5S����I@�,{U�#�@�,p�LYV"D�L�ywe!gp3s�=/��#��}�H����&��"��!X���|�����eFn^t����%�%�����s�q����zty����e�k��z����,eG����Q������b�6�Xy�2�#F���JcEw_�����Lc�Y�����c����i��jn�U������x�1Z�uq/Lq��k��0\���+No7d���C��`�������Y�c����>��g)s��}���!A��������g)���Zxo,dH�
���B�<K�}Fnd��f�b_��0>�y��<o�cz�b#��=g�j7�/
�j���F��b�U�h��~QB��)����r`����.��������p{K��u�-w�y�������~�m���<�zWC�_G��U��Z�z#T?������/�|w.���������/��^~�������e#A�yQ�Z�S�f�������f���j~�"�����y����w������{������@�O��+�a���v.�#�/�_���]R��f<��_�����;{���3���u�^��zW���iMp�f�P����Z#8�E����=��ZwZ?.x�)�<wX�[��]�\��%x�ao��R!�|���.JpXF(h�����W��"^A�
����(�7��.h!x�Qo�2~�����y���@�G�Y�K,x�mA�
��Q��
|mA�����#x.#�q-x�a���{V�W�����W��D�m�F�:���H�	Z��0Q�D~M�*�tt�$���nZK^}X���,�|K��[��W�8�,��H�eU"yC����H6���<�#ZM���o�k��]L"������E��=+�knH^�W������1�R;�,
Z��K-y���B���#y������k+y�e��$��%y�q%�o������Q$����F$��m���-nTJ�H�@w������+y\|.�s)y�����>7�����K���3�^Kf�H��p�
�"}���2�V>�:�21�������a�o����-��g7$�8���,%��E,�*z�����0+�S8�:X����.'otS����V�>��������p%{���7f#Y���*����-h��Y�"H��e���,�%���yGt���w�;l���P������c)�+y��O��K\M|:A�������������ov�#y\�,p)y��c�����K�������,���3?Q�e��X����Fza%�BN�j��������
�;l#��yG������d9���?Q���7E�$������I8A�;F�$z�Ht�����el�.�qS�n����!K-zc�F���rA��n}�|$��LuF�M�P��l��w�f������r���[�,;��R���h�7�wi�S��Yd��� �!C.p5����7���M��Q�8�7,D��;���em��������d��o�[7�AK,���I6r����_�y�qbn�h������p�������e�1�?^l����[--��f����0K>�K\�����-��}�va/��-3�Y5��E�)+�n�0{�mi�2�<�Ak����r�~�)�����T'n��r�����]bZ������������.G�[��x�t*6[9�[����=-'7����r���-wb
�����WbN�����r�l��������,[��J������/�%{��i�����?�:q�T!]'h��<������������%���8&p){�-�M5�e���Y�*����j�xiR>ZkH&|�^g��j2NM6��/h�7������j%��86]�|�������������*���ml������-U�����u��:^l��=k�>���t�:��o��#{<+)p){�-�M��.�M^���_~���i�_g���~]�s��A�d:owR����n�h�L�7CG���#�jC�[��89&���[����-�D���@k���=�oF�\�*�/q3�43K<����o�$|3��������&������f����-�����][e�N����[x�mO�/h�s�`Y�V]W]�8�7g�u�w������Z����q[[��E>Z����'��c:�����fo.�������X����6���ag�g��2���.��3���l�Ka���������s��2A����;:��A��^j�WeD����vf}��.�������zq����.���]����)B�Zw�j+	C�jd���7�
����Vo��t�ml���fs/����R��en+~��u6���2�j��7��&���3���9��Z1��ut��������-s�x��\��nu���l����h�-�e�gL��-oFL)�2������N�[��o�,������>���|�Z�nU������#���$n��O�x�J�*�w���8����1!��qC���!���>sC���!������l��"p�V�����3���9gn�����U�d���
��������
��Vu�8ng���U��"0��2?���x���n�Y}� {K^�Q}������w������Q>h-{����q;[�b�7�M����.��9���;�M#�2,n�������oq�m�������D�|�Z�n����v�,��o4����b_����U��v�%��qS����/q}}���ekS`y����M������f}���-W.�����J!�[�+p1vz�|a���cW`�:��pW���+�<l�}���e{W`ys)�q�[.\�e���Nn\�m�1_X���������Dt]��a+�K����������v�,�^��,R�eV��_������B:��I��,p�ZX���pY���,��Uaw�moY�-p1�����\�u�m����.���"K���p[���-�<�������m�������-�.����krn\�m��O�.3�����7g����ZV�����Z��?h-{��[�a�[�,o�����w�G�{'p#��zwKg� ����9��U�����W�W���7�U@W�w��'\�;a��U��L������X�E�����Z���
������[KVqu���~T������|?�G��W����m7���kA;��Jg����~�&m��	]t���^����l_8a���K�_��S;�����8��U|�W�_����_����W��L���������@W�[���;���_�����6/�/p�$~M	t�F�zH�>��5t��M��f��q%��C��}���6�����'�O����|���]��8��n�Y=d�zX����w����Z�w��R�]���LL��i���.]o���F����q6���5@7ll@
��V��:���[��;RX�Eo�������EO���V^saH_s�77
��^77�����Q=��M|��f���>�I���7����6����%�Yw�<�������[�f&W��y�S�F�z�.����LP�f���&��Y�%/���-��S�<f��s����_I�m�9�9A��>M,yy>��5��=�AE/��+��Z�^~�G}�pVj�+~����7�r,^���9�+���i��O���Z��v#�	�Dt['�C����=��:�Z�n�����J-{�tyiL��
/qb��������g^!C�[%��k�N`f��7d/d�zX���0�yS�nu���J-{M�O����z:��G�����>��
�',����s�'0th�a���mg�qA��Ak��y�p�hVj�����/�p�:���uH�	�Cl�9aA�J�j}z����>[�u����,y�w�o_����r�f�|�����.�'[�T�q�>q�!��
zY���
��<��u����,��xc��g���q�Y��~�h�-]���S�&TW���o�E���~�dt��n��g&���s��a���<��y�>�ya��]-�B�n�w���S�[F�[��%n�.2���~��k����������y�A�C��*��9��]���;[P�V�&_�O��<�[���(�M���k�q(����R����K�s�����U��������U0A���&��,���o�s(��98��t.n��<X����{.6$���*p��W�%�b(*���R�.���{E��BA��!��U|�U����jc�s�<���R�.�aO���3\�/����hP�+j�K�"�_C����	[L
,
_f�90r����|yz�k�4Vv4��r�"w+p�1�\�l��"���E����8o��X�:��n�����N�^�����U���]��$�t���*u�70���]��{'p����������o���8:u)�&&��1O/#C��8��("���A|��LR�=sp�k�t�K\�)����
�;r�e����M��yd$lKQ`��aMV�"uf��%���w���{w�E@�o[�[��0�*�G�������@�1���rE��c
�c\>�����d9c�+����Wo��30.���OZ`�����X�����"q�946\mm������s���V I<P��@t��8���6%�Vf�e��Xe�J�Xb�����,p��y�=����#8�/����XMD�1MY<#	s2�_��j�X���x����{`\�L�|�&���0'�
t����%�����F_h�w����D7mH�3�0���m������i�#����o����+�-K�3�����&0q}Nt����0�G�H�B]������>F�Y�w�v
��t�^��_i�M+a�����UF�S��B��$�%k���u�������pD%P>i-������;O/����gk�:33F5�$��3��Y�Q�,q/������@w�I7�m���@wsi��{a.���&��)9L��B������+34���q<P��#�e6��F9t�2��v��'�����������~��V����|����'pt��������&���a�b"��cQA��@�D�|�Zo-T�s�<��H%�gk,
���ng��J��
�����n 8}�2�����f-7�[�~Z+���V��yz�Ql����x�#�~��H��=�4nYOx��5����������_6XU^LT�:�|�n������*�2q-�����Ub��.hXl��.�$n�);��vY����]P�T�'���z�f��o���:)}Oh$�����i���0����o���,s$���\s�,��e�
6'��������L�`L��K�#	��L�h�����SAt����:�N�m�bm�#�A'u�'�%�Vt����8��J���3�x	������Gyu;
V&ig�2��/I:7�F-�>rfa)ea-��xw}s5��V����F~�Q�7WzGH�T9��w���#�7�	\
]���*��nc4�>�l|���OZ���f[�������d`�#��V����7ZX��<��	`����
D�Q��<_98A�Ik����#�^Y4���0q1����U�q���\C9�$p5t�b*&U[�I����+&U��I���������Qe�%����+��F/���H��Dg��So�����_����������[.hs+���I/�,�Wk��!����u��y�C�����.qCL��S���������g����S��z�������S�qw����0�;Uw�rsuFhc��S�z�$�cAt��9	3��"���[I�SI�p�����$�&&&�����1p�����������)�K<rfF=��7����$���������F9�I������=�n�:��d�L��n�8x����	\`{�$L��J>i%���$�����X�#?R��r��I�����JCZ�*D] C$h5���c���t�-�uD��!���fL_���K�</���Dp�>\���;qu��Q���_
�V��hz�y��|����/ZO}�����<�h��A����n���7��#����>~��?���?����D<}���>�p�P*�S����8Y�Xc(<����n�u^��xW�����:�sW�����|}w������������}������O_��O/��O�g�9����|����z��G��=�/��a���csw�c����n�_�����^?V�_p���/���������
�X�rX�v���/Z�r�R��{��^`S��lh*{gC��%�����{U�^	x!n�-Z��w��}���V�&r�����}�������#��g����$�[s=����%���������
�uVU��X�h�g���w����d%?�hX��=��S������O7<a p5t�{}�0h.N|��s�A��a3q�}����c��.���wc��������W��
w�����}i�3�F(��9��.�/��4�����|�J��[�O���va���q�d�^��$�%r��v��I+Z��X@�[�HX�L/p)��B6��Ik����kVk�J�z4o����4�� u�������G}{z$lP������uN����LV��+�-�L�:k�7�v�s
ZMw�4mLg:]�N����.����C����R})�7S0�{��
`O#���#=��[�
����Vi4H�������m�#��@�1l�a����P��OZ���L�V����k���w�7�!}<���q�,�N�w����p��n���s0l%�OZ	`q3��.�.��hfc�1u����&�������,F�XO�F����b���8���X>i-�7o�<����9�����
�����m#h5L���<-p5L���-
��(����%�OZ��4Oi�}E��W�j�\q��ZA{�y����.p5L�����x�L["��OZ��4Gn�i��_��]�6��B�V�j0qL[��TV�6qL[#E+p)�N��5���Ik���)���ro�|�"���0~7�Z�mi��d��m�m%mc��I$l1z p9t�$L��i����>|�F�����/�%a�b�+��6�.u��gl��uW$�����[WH������.�����9�#�������7����`�1�A��O���<����/qL;�z����932�5n�l��|�6�vZ����O.�g�f�x�^��R���ZE�t�!��qH��X��pX����\R�:|�.�.����U&��t�����%^��e����)�2qL�))�K�;p��s2����	�#w�t����K<��qLJ���01�5'�����sRX8�9�vns����9rLW��8}����8��������E�^
��`\.y� ��hp�Vc/���n���=���$y�hr��Y�������0��@k�A���f*��)��]C=k��V��<p��g�������2V��]C=k��Q3�8W4b�Y3���i��NV_�g�L�dC$���r#p)�X�5Z�����w�b�������W��gfR6��5��12V=+��V���=C=+��V��<p��g������7���g�g��7*�U���_�B��ioTL���vP���EoUL�d_$�������������������w+c���2�t����U��U?"�-h����(oX\M��#�qcp�:p��1�,���ry+c���2�O3�R\��m�3���� ={=k�W��=C=k��V��:r�5�~�fZ����gh`��7j�u����5����&��X4��i����E�a�hZ83�h:�����������!������N.�,�F�����+T,�V�4�������^��$�.#��[����0�P�'������#�_Y�#���:q��P"-h5�K�J8�W����CCE�Zn�������R>i-7�0G����G��"���s��1����v4,�����C�zu%~�����?|������FW5u��������y/������'���������^��WY������l��x����_A~���?�����?~z���������?_������^>}|�q��_���������?|��Y���s�������/����������/��������������^��+��_��������O]{�����e}��*��eu����P}�����q�����^�i�\�����]�(������_�i~�����/�����������W��W���.����*�����/�D(���vy~�g��.���s���������\u�	Uw�	eu���.?�*/?�=^�.._[�g����~u������yw��N������/�S~��sw�����^O^]���#��q~�����O��?�~���#��q���W�[\BQ����_��Q\`q��E��y��j��_^}B�^cn�1w��/�at��]|v-��O��WO�������.?��/���W������~�]����W4�����Kv�o�|����8��.���Th�?���W����8��_]���"�FvM����I����WX.�r����o��\���;����'���E���5z��y�t�86ru���E�/��Z#�Q���6#?:^��
��T�[���r�P���,o�N�7�n'�o�*���7��,��/�T����I�����_1�HU�gy�*[W:IUn�]}������}%?�dlu�o�$������K��jQy'�cD��	#��C�����]�(� �.������R��((9��R�&�EU��t�LsvU|.*�,��M�GQ�=T��r�R�|�4�X��Ue����
��d�O���t��+���-���~_U�����x��@k(p}�F�YZC�_}'/s��JGM[��|*��+_t�9��)Y���m�kh9_��];�JA}������q0>+fq&M_��.�[��OS���7<��+C5D^�`;�
�n�/�r(V��n)`/��[y����z�*���^��z��wv��F=�S����]�3B�VB��&����7]J�#�	���8�s_���mXY�����zmJ�1�s�4�u4'��~N��D=z�
��E=�z\^+�#S�S)�h��z���G��f��(�)�8oo@_��]Q�}"�0�*��������
.=�O���
de�Bj���r���x~������/S�oB���]�/B�M>�|������=�7359m�|���+��B�`N�������]������H?}]��@"��[q,��w+|"�r,z��/�|����k�=/��3�lM�&:�N��]��yQ��#,��%�9�[*h��{^�1���`�wx�/�l����K�=/�����1w����� ����y�,�	�c�6�js�����W�$���D���|%6�	�5��y�u_��]K��*��jS��<�����u_���'�j��jS���;�����u_���/����m����cn��j]��#�Q����_�7�Q�5�������4��u�����T��	J�����"������sK�mya[�����CFR0kmE���Qp���d����Cg�`>�����t���|#�i��QH��p�z��~��Z<1*��z]��v�j�aS��'FE#��`,OL>�K�k�=1*���y4�_��r��[-
����i����&]���b���o��~��q�L�7��/������m����h���u�W�NI.T���{b��P�-��Kl}���o�V��=��O0kC���'h��{^����g]+hy�/���k�=/�X
�?�|��w)����~�>��O0��dq������E���s��K��-�7�k�=/�XJ�?c�,��-���M�W>/�X*�������~\c*h��{^��T���p
9������m����c���j]��v_j��z[�=/�X���p�R�?�	�k�=1�h���k��3�KK��nk�'F-�_�k�������k����N�	�C��-� [�'��'�=��1B�����T~�����{T~���\��c��6�_���c��t�W��]�T�����{�T��������o���c���o��_��7Q�M������L�7���L������m����c���u��R��`N������c��[��oj�e��[������%�B4������z���vM���K�_��8cV�7m����rn��=-�8!Z@�����#5�
G�-[���� �_�q�g%_NP�������i��������������������~,YI��t�W�M���Q�����~Z�qBD�W�/5�*��r[�=-�8A���t��8�8a���������%���*C��v�j����?�����%k��jC������Q�5�����GC����k���m�������k
�/��k���m�������ku�W�M���Q�u���yb��S�u���S���������������_��7P�����yb�1P�
�����OOX���M��<1���]�%��H�7n��'���h�����D�7m��'������:m��������{b�1S����K�����{b��P����K,����{^��g�����/y�'h��{^��g��Yi�K�?����������<���
�����O������#/�O�M���8�?A�������A�	f�~��/���s���}^��j1��������s���y�G^R����K�%�_������_i����G^Q�U���y�G^S�U��K�5�_�����5�_m����G�P�������GC���/u��P�5�����GK�����M�?�������t�������sG��:�u�II����4��t�����:�����B�����{]��]��*��T��"����{C��`j�aS�
@��o�\������Z�T��v���G�7���K�?���������o���t���NL�}�v��y����&]�u��3u���>�|u�l����w��[6u���#0���C�%��EV����w1(�������B����"���wF������"oA�\���%�;�|���������(J�oR����b��@�b����3�a	�2���Yb��p��wM����t�����sQR�m����$ `i2�;�EIXn��� EEXZ:0�]T����|^R�����;�EMXo���!EMX[:0��P��:�yaH�P6�L�G7�����w1,[��������:������"�%`G�:0�����6u�����	H�:0������M��0bX������ ?����u�#��:�7t`�A�b��u�#��:p�t`�Hd��u�#��:p�t`�Hd��u�#��:p�t`�Hd���u�#��:p�t`�Hd���u�#��:p�t`�Hd�\6u��3��	H�X:0q$�2��eS�;D��.��
��:���k>/qyI:�H��:P��	��H����Y#`�H���wM��E"���G"��$��|^$�u��t`�H�9�@������:�Y:0q$�J��r[>/qu`i��������m��H�U����G"����u��"WS��L���:�����N�%`CX[:0u$�P6�:p�M��l�C�`�H�%?n��l7u�����	��Y��M����}�����?��������+�a��2���sv��������"+������;	����WU����������.�Y���T����h
��
���H�;Q����G���	vB����VZ������q"���c�'����p�1,�X|�
���|�G[�]{�w�1,������:X���~C��
�R�k�8�~o��Kx���e�vM���!v��j�,�E_�����	�}��o��l��
�C��~]�i�UN�"���B�`�O��%��3�L�b��aV���,��S&8I	ZO��U������F��$��T����r�ip�|�qQ��~LL-4�B��q�5�2�6^U)cl���_�A�5�RFC�m,��
\^�~��8e4D����y�~.X���~���vM��� �G}���{���~��A��� r(O0?+"8�����}%�y����KN�2#�8�/�K
b
���q��M
�5�RFC�X���n�8��I��������J�\T���������r�t���dX�q�di�N�mD������M�����_S�~�q���#h��{b���#���n��'���������(�~-�1�Y�_�j��#h��{b��9�O�����NpH	�5��t�tz5���8p=��f�`�E�����F67���������a�70���#�EN_�1�6��}%��od��:�vq�/u�;2�7��}%�������.�x��c�������a���o�5����QN�?V���|}�f��$�pa��]�������c����~���������(�~��E�?��_��f����dP�U��E�?R�?����]��y�G��L0��U�#�6���]�K��`���s��L��������VQ�|��}�����R�}%����X*��~�$�6��.J���C��`V���������~��?��"����p�<�W��@����������`~V7,��������wQ20����������Wg��f�o�E�����������5��vM�'�MN����p;|<�� �'h��{b�� �'����"�'���������(�~-��Y�_��K�"�'h��{b��aP���o�u���8h�=���d`"X���������4����a��i���M-����A�'���a����,h�=�=1��,he����^��V�������V�,h��L��c�o{�{b��Y���
w���~���gA�'F���Y��������,h�������1��~�������������j@4�I+O.L�-����y�G��C]��_r��C������D��*�5"&N�yN"�E��y����
��3\~=�u���]��{�����G�w,C����]/�x���Y�����TA���{"��c�
��`�\gpeF��g��u��.�u3K�A@)����	�I��Gr�d�/�Ro������^Ew�4���;	�,A�!
m�����J~M4��
��=����=�q��������"L&p=��������|�������qzQ+�_�j��N�%>��b��_���������n>s�?}����������/?��_g�����_�-6y^�Pl�\�Z_��b�u.�_�����?���O���W/�����������������bFU�_�|J�O�'�Z��O������j�MU����S���J ��OQw�<�l��5e�7
x�xohyC��|S��������~�[������������Kn�/����>�3\��_���a.���&�
�)�ZE�81�uPt�-p�	
^y
��]����-�g�C^��VPuV5���Jw������?���������x�%W�}���
>e�����4 !�e�R�^�����(�P�����3X��SU���B��\����������W�������d��)"^EDx��c����<s1Q����hI���&J��Y����SD���<��)"5���1fk������qO�D+��]Sy��!�'p5Ed�����uYF��%�Nd��UD�("Vl:|�\����y0E�<�'��'�_n����:�gE�A��^#h���
F��|�3^LB��)"^Ex� �fOE�ULET�o�j��J���
��P��f��O�)�""����Y���mE���H���,zH\]�q<�VxD~���P�h�Q�Ztx��,xA�5������#�E�+E��(�����`�{��t�"D���nETdRp�A��
����
���=��tE�����_�o EDt�����X��("������PD.���fu�}%?���Q��&s����iB��qF�O0k�Hm���o�-�����J������ ��XQ[�V�].���RD��z�E��"���QD�F���lET�u��������� ����&�dfJE�<
���'y]�����~u��[+�"8����"��tED�h{��"2�RDD�\�j���F�B�
~Q��QQ��)��-h�u_a_�����UJE�5��YSDV�&GDx�E��c5S�A�-�ng�����A���W���RDD�d����/�""<����G�������������N����o{�}�-�D���
�����U!��0��I�{�(��q�f+�h���&2<�@���;�����6�&<�]�/�.�����j��|�������F������gg����(X���I8?388���A4��=_X9��D�{�W�0o&p5M��z����w
���<n'Q���������!��/����|���������3GQE�+#�zR������_V�G�C~C�*�g=��d�F��t�
WGk�������
dE�j�hG{uQ�-�a�����D)v
!��SK1���v����P��@�8�J11�bn�V�/W�x�6�#���#�����I<J�����~���}g�}g7�X�`�G`��������������0��l������b�oxgz��3�){���JU&���uy�����'U�Z���r)����F��-�Q��|�u]��j���N,����{�R�+�m��V��T���|5@��C�)��Z���Hl������j��=rr�)���D��z���������/����*�<�
�z���G:��J�������
xT��{�f�c�������������L���H������B
��H�57wt](������/�7����5G�t���������5�?��BG1��
�2[�c5���������#��b��H��b�`�-r\�t
�u�^�=���!�"�cF}��Oxm���p8��p�+30Z�z8M�[��<��N��d��#��/�s�3�z"D<\���']��'�+������M.SO�~BA{�D��:�O�:G1)�!���a���������8R\:B����Kq��bA{oI��H��Fbk��ckE1)��Az!�V^������>��.9z��=���#��z�a5E��w��d�D�����v���;��RX�C4�f��R�a��
\Op�	���EFH�?kPr��ln�zzav�	�]X)�2Y�{��a)�jB������CC��U�{�y��D�����?L�������?��dso��xD
~}'Ev�c�n��I<�����{n����b��zw>���b<�b\�}���y��vT�}	���V[���O*���]���[u��7�1�6n�v����dN��|,,$biFs4����=JPvOT5F]�Y�g9n���i&���i���}Jk��i<�>���<�h����d4W�������^��0���f�Y�?|������h�J�W���������7��|���|�_����O�~���z�q`���^��� �V����KkC��i�PXt��X���=~��;��P����	��p<�������	���IH���N@^�HJ��.��E�����r���o�C�]�np�x>���X���>�������@�j����v���Zq�=��8�������������_d��W
�
^���i��h�F����������i1�]�(:�;�V����L[G��F[UVEu1@[e����]�������r�+	��o���^OCU��k4'�:o>
��i�{EWg���OC���7��5��}3m�Y����;�P�o_�v��
|
��������q�Q�_��	�L�k�����!h��u�;uk�!�!��=�?J�|��@��{�B�nq���'��-L
��
V���6*�s��dt���9c�amz�Z|���	�!h)�sT�D��<'%���y�����6�<���;���N�o�q�0$�K�]&H?c1�Q��ZU��'�C/h��{[A=�g�C/p�������.�:����g��8F����cj�l!�(�%E��7%�������s]���C�N�S�+x��(b��Tw�����;��^A����&<d���*�N���[|��K\��V�}+P��
`���l���h�,��Fr��Y�������0��Eh��7���X���b5�q��|1�~4�<�Z2���^��
�DG�2���c{�c�!obt:�++�k���Nm>u5�+���o�	�S�� Fv-	he�J7�a�V����g��1�4r!n�m�HD>]W+���8�}�|��r���e'�H�1�Z�2�+���%�Q�R���#e/h1�=RAlh�����%����H��/��nIr�vr��
��w�{�
�P#��+b�q��r)��TxJ�C��b�
�>RAl=��=��~�c�HEY�Y���f�Sz�]�i
O1��4^Vy�����eh���H�J�;s��z�"���
���i�C<&��(�3y��x�
������������X�3��������R��v8�{�H$?����[��ej��Z���@�N��n��!���y����tH�at���=l~a�H���=���
�1��[w�"1z!���Jt_���*������x�"��#<Z��s��y��d���>qp���q���@���^�s2�u��Tp��,s(	��f�u���'e�@��/@tW;�?������UM���r���#`^�HD�������l������
��}X�!��iafC	���6a�
%������X���������af��B���xY�=��;Z5"�Vi�M�5����#������>��g�!
��w}��p��v>:Jx�g,���5�P����g�����42�������i�
�^gd����������z��%�OV��'����:���M�ni����{���
/E�[kC�6Y��w�A[W���nu�����":�3�??�j{
�I6��o�n���Q>����}S��\P�)j|AAP����eO����Q�
�[[mGp��&�[&zS���(�E���gcao�5�+td�l������6E�B���1N������q�!��Yp�xFo�"6H��=�����.'��8�3R�f,v-)V��^��]I����PMQ�X����V�!��Y���0�3��������@t��c����n!�a�SxJS����X��FjM!<���[/���m����E<�
 ��GA?���g�6HS��D��@<�xuNx�c��Et���a������=����R�H��'���*�>�� �"��[�o��y���~����8����;P���F��o�LN$F�4,V��q�$����;P��2\����������~3�T�i�"<Z���������)��[W���-����T+����r�t�(@���H +o�X���-z��	.H7
�18��<�&)��X�:
�NLx����r������(��8_m/&<pZ�np�|>�����8��2������8}�h<��Bx����V4���)x�n��I=k�Z�{��
RO���e��%���� <d}��w�����xeF���}���~n���{y�d�<�j���jb6a��1W��_�����X/Os�����|��xF��g�l���Y�f|;���<�Q���z_3��.�_�.�b��.$Nz4��Z��o�����5���ntm]�>7�`3���n9kK������q�����rw�	#�-����q�����e}1f�����j���V�;Pm�XQ�G�����7j#E�
G�7$g �l���C��������y<���b�
����!6T�
c������)��6��7����?�b����������Q��
���^���x�a�y�nrD�I���Q�M�����m�
DgT]�oFvF�j�����"��fv�>Ul�����}o�������p^���� <}����8)�T��u�;��c�U�j����S�-4g�������"���"<����II�2�R��!B"��/X��\�|Y]��<':c*<=�rd&�\pe��cO�
Dg��15r��B]��]��y�xkJ�@mj�8�C�^�j�a�o&:=c��9
��#o�L�)�N������=�F�� W&�0��J����sS#G!^�i3��/q�Q���f�F�C������e���
��Or>�x�J�7�8kMV�
DgdUL��B��Z�2�*���(����R��)q�GW�6\k�T��W�U1���qq��8�3\k�T��3C�j�K��*�����Y��Q��fDg-.L����!x5���0<��������Q�������`p�^itb<!���U1v�9��9���tV(���1�-x5���0z*�^?A���U�u���;vq�G������(�������:���V�E��7�UW�Z��1�UW%=�F@���X]gQ^�����p�	�D<��;����B����(��w�q�d�:|I�`�����z�3��y\5YNF�T�a��-g*��@wE��~�����:N�m93o;~Kn�z�YTx��y>,���E�bZ�����^��$p5F�?�t
��hK����1����
x���A]qe����cYFsgg�)�	���j������OBKe�~�}I����S����EIR�����dF0,�q�:�����E����~ �F�_Gt4,���,�Ds�Au���h�.s�RO�vFh��l5���[rF��,�&�c�BR�L�z���hX�����c�]��T�a%�B�]�+���j�6}����iY���]��Q�+������hbLo�Z��@K��=�^at��X��Uc���G��--��J��1�:�������� �j?�%�S�@�����!�h����_�+�N��hX:c��<�fw��=&�{��*�W�K��iXz��V$w�zZ�������")��K�hX��0}=���a%zt$��t�3c#
�h�]w#1z�e��J�T��V�<5��
�{���D�r��q4N��C�k�L��iZ��yn=�(��i[���2�{�^�t���B�b�
����P��eq����^�t��X������������3pZ���5�x����cu^���S�u7B����V!�5N�����R�*R\�#<�uq�^��@�om���;9�pz!)�;���8��j�{LN;�@���������Y��Rg������!�b"R��S�������s$2�+��@��{
�=��(��h\*���+�i\���2�����DN�4.�����B��5�K�V���C����������\��:sRs���=&��������9���qi�����	����+�]FR�{N=
�;��X�m-#������++��LR�{O=
�{��X;g-�������w���C&� S��@���c%���0W�	��ex�-W���+����^������
�+�&�����Z ��7�'DK��2���e��l�I����	��C�y���C@ jV�����}}����������-����a��P��"�v���
X�D�Qk,����!���] �C%`��*������]�:@���C�%�_0���C�	c_7�"z����l%��O����K���?*:{�Q����}P�%`��7��zJx�J�LW<3Mt�s�>9�s!��5z_�����Rc�C���|A���u�3��V�}8��[������e�"��wl��\z:���:
q��E}��wu�X�tU�F�*����K�������f*�5V{����z@��7�����:�ey��P�Z��z#z��+��n������Qj
o!��nq�jQ�M%�glR�Va��]j�����E=�8���va���L7��=[��������3�������&���>�lT�j������lBo�&$'G���#�
��������FHM�!�I<c�����J�!C�+xC<�B�F��A���$�u(5�rG��S���B����=��T$ptM�(c�8�`�C$'�!�4j�:�
�k"=�f��5�c���+�4�������t�
tX16\,���o����v����.��?~���������:{����?��y�_��*�yq�+�g�3������?|�����������f����T>;.�o~����{)�"��������WY���������{����_~�������������?|�������r����s���s����/�����.�������t��~���_?��/�^���'��?��#���O���
���kQgK�����*>+����*����^^:9y�j����z�����TX�kKa]?�;�Pd�W���^cW_����Z&$�<��yQ6Bf�Z�R$��&F=1o��o��c�N����P���?��&��|����q�����
�MH�$�cM�+t��A��)��h����v5�jW�,{��1l0
X���}a��/����,����	nrw�C<+��IO����r2M�fuc(�c'b�lxsA�QD��K�WNO9fMAP+�/F$\��7���`�;����0�c=a0nTgJ]YU�J&��:�^�@��{Q����J�dJ�o��e���a���@��Q�	s�o9��XK���[�C�+t�9^�4�x*G�W#^�+�^
f�����!^Ox��f^���3�0b[���;�*��5�BG�R�h+�D<���/��k���dDg���c7��U�g��B����r�U��D<8��W#^�+�~�c��ht�?�x-z��VwJ�Uvrkx�n$����#�>���?0'�;4�
^-�}��
t�19�g$���k��F�tO�7���3�9���������J��[�i<�a�rz��j���2���<$<�19����8}�q�c��?�:S$Ns�c���w����5
RD�EEx��hD*U��c+x4.�q6�����$�5N�.F���d���o("���e:���VT�����+�V�h\f���g8.���8WX�[�0�<������Q�����,��������xz�`\��i��������-���qy_;Vf�k������T����fO�sSn���-y��r1�cf�C_��}p�NXNH�	���S�5'D�3\wE�*���BT�&�Wc����9Y��	N/���B�9!���������^�D�_�����9��k���-xsFN/�u������x�����W����t��U�-'��;R���EX_����>��Amlb,x��*��TE�)c`U���*kf�r��y.r~����S�+Y��5zd����>4�z+��������l���6W���T�@���#7_4�����{��)���xH>i=E���2�1"�6w�Z=)�s����	�6������4F�>�0�!s&h�.+V&�F3����S?@���W��n�s"<$�������r�Xb��(}1n�u���(c!V�a ��h��q�^`�|�ll�L/�L����W�]'a��m��*�vF�t �� �f}+\�7�)�=��^_�g4�����������}�@/'E������wC��Q������
>AG�%P�-�a��l��s��f����O���p�C�������L�F!�bl�LN�%��j��s&��[��O�j��?IEx=��C�Z��x3��C�5��xL�.�>g�6���o���O �Hx�$�	/�H�q��+����K�Hx����	�*��ZH��a��o!��s4�X]IRu#�Q����(xw�����CRU����#)�Nx�Q��h[J+w��������9M�UNR��.~�>���T��j�3������:��hb�3���f]�F}��q����{�=�����>���V�-��	��7�^C�R[�����Ks��^+��S����-�Kc]����l�&<�v�jtY\�oW^�^��bi7�F{5���>���g�$�y�0���c��q�����������	X\w��1�����Mt#��K�'`��m tX\�N���	��Mp�9���.H�6��������Y�HHc�����Jx�ROhf�q��m�A�RY-���m`�Jb5��V�:�����=���m�&�	��sli�8��R���y�����m��A�����}���>�Bi�nC���r�����W���r��[w�/��F�ue�g���P�k&��(������~~�Ni����d�+�_���)6�3����������P%tL=����
��	�=��N���t�<�bw�k��]#c�F��l��c�(�m����s���t�QN}��0�0-��7�x�5A���=��T����.��L��z.�xD��l��r�;�V
b��L����b<QN&��sg��c�%�����("{���j���Fe�3z�&s����f���/LK6�1���BzAwgKvY�Q�,oQ�������J�X��-�72>����&z�<� ��vn���������b���~3G[����F�9PO ��m�F'�k�mW�$^Gt���6��k��	�Xn�6�pY��0�s�r�OI9^�
DgT���mI���[&���i�%:���!����g�Z��Gf9����T1�����$��G���w�r������A��7��RV��O�#�a��19]7 emtP����	���66����Q8��6g���tC���o�����	���:pc.��i��@g|��-IJ��Mo�[�7�b<��Gx4.�n.������G���f�jk���o4����`��5�"g�����-�����K�"G�U��s�O$`��u	A7pq��g�+�[����g��\k:��\���v�������:s@SW���/g�k�����������zRq.��r_t�����`r�����	����p��%��3L/��g<0���%��]4dv����kke�G^���D��KcFa6����%<p��N�{x
q&�o�J'��6|%�2�\�]}���L{�k��_pG;����S��v��U�G����I=�e��P��Kw�WK#��������yLY�7�zFb����e��#�����-��}��v�v����u��W�~��
���r��d�����7[��Nkk3v��f���1��|�����??�j�
�(��a�+�;����f��m��o����*��}Fa��oc=����:�w�ojj�X��J������	�syQ�x8�y�U$V��F������DGk����0c�0m����Z����g�8�3�^����q��Ni���ci���	�f�++��LB����q��3���`gn�6l�C����w(*T6@�^���9���=<���2���i�&6f�K�����m�U��pX5l8������,����,zM��o�&<�
����ewd���D7��5l*�8�[��g}�����A�����w��
��W��	/
��3��m�������Ze��\��;�Xe��!��*�(�����R�u��Y��.	n`�+G*�i�P��i�Ba9�Je�P���y��,�T%��q��ke�S���������w�q�70�]I�-��inW�������3�Wc�_$N�4..������~5;��jUiD�>;�lj����b��ESs}��\��2-����
T,��w��>����#DC�s�����yi�%l�����$�pa��A���\�6>��V�j>n�4�$��b�J�W��B<��/�������jD�o��-���k�DjN�I�X�����r��@J��q��'�hW��@��S��B�<#���7�C����Q/��_�C�Q[�J���P]q�7�z��������Z��+�u��+
��x�P��%����[W\m-'�\N�\3�K?�S�������+�J����N��b7���������|P�iZ|z�����s�O�v`�b�;�:]Q�k���7p�7�!W(h��p�$!h+�ll�0��a�3DG}e,�(��0]q�������RR���������"�mNp�-��]q�0�M^;�J�*(�?n`%���������O���������������������T�l���~���/�����~��O�����P���W.�5E7��
3Z�j����v���������7�|��0�1�^�������F	�{��C5$[i�����H���7F#M�F�klmV�1�����H���&���m�*p7�r��FB�u=��BZ���:�Em��u$E?7t��F<kwk��h�j��Q��m��Dg�H�'n��j���WR-SD����:Q�^l�
^�x���H�[����I��p���W#^���DG�rq����O�*��K���]C�R��v,��6��x�����}�!�"p�*S����f$^�������z�����-R�Wc��9����I��<3�3�^a�G�=,�9��vF����������j/�:��hNy
x��
a�!�v5���)�����\�w��CNR��D>�a=���~$���=�����#0�y�A/vZi�8�iX+���hY�� V4���x�
�h��������-��nY.����~t�%��,�]]I&��U�����G���UL�N��5g���Ntp����]�~t �15"�!54a��	����pA���A�������{[���QJ�]!�Z���>�G���B�m�j�X+���mC�z������t��D�j����h?:�q����##�z���uL������j������ny�?���JGu���|sz^����_�>�c��V��� �����}m�$��I�]3q�E�X���|~���}�&���W��Q��|�b]���F��cm���IW_@�0noA���C�m�D�h���:��9�M�8�`�V����y���8:F�q*���V�TSc'#V�(&����c�����+x�Dw�qV!��I�8R�&��X5P���4V��0�����a����*�xw5���q�1������Z�����%��������S�{lq�Fb���'A�4����~��/�)�[W2��$^��	���U���I�do�{�t1��D��
�:�	�Z���
�<��V��v	^�1,�JR����.�V�<$��F�`+I=M3����~�����	���x<��[Y��b�������pQ��-��a^^[���:���0.t���=����W%�1��2�|of�w�=�hf���8WXVX��t��1��0z&%���G�/0�{z1�q��MA^at����a�����k�g���x�a%z@qW��^0��
�`�1�=��8�GZ��8s+�H�	x�����W�hXF�g�9�<Z���U�~bNn����;c
�d�1�WnB�H����L����G���z$�����H�7��3������<e�I@j�Tg�m���l_�dU�_����T�+�\��E@���u%��t�vwh�D���N�eJ�ylDuVP��tyA{�]�+p(��H3fc&���,s�{n�Rl�I����`��
R���]�����^�t�k�+x�[�r`a�;�2]���"x�Y8�zcN���V�Y<H��
r��w���;��U�v����w������}��YX�������S���2�X�|������\�����6��7u�wl���<U?��+�L������Z������|P;���/XhxV]^�I������nZ����� ����nc�O�S���I	n ��8):`�Tx���7u%h5��^�G�I		D���b�CG���h����N��~R��� h���@����$2�����
gR�D���R�j���q�����ns��S�C��d9���f�s�O
pr��V���(:L?)�!g'h����dv��v�����:����L��~R�e�S�k�E�+x4�F��.Pc��D�b��>���;�W���
�It�b����G������������.~a�.q�7����**���UW������&�8��O���&oc�-S��0�c
v�>����x4g��6?���=eu{Vf�a�7����=+F9�I�eY|��MX
/p����K
�f������������;��rXN���������!W�������,��fc��������[<����(�^*-�Qez�Ii�XZ��pz�`[�=18=e0.������R??�[�bN�0.���n�(��a\�19]d$�q��rm�p����W�t��#��q�
%�yN/$�~�-�RWN&�HJk=�����8wX�vH���YSI����S�|^�	��m)�m���Bq=����Y�P �����?}����M�{��]���4��i����}]��{k;<���i�����D.�+��a��;�=�p�nf[��]�)x=�@c
��b�l4GY#�a�.�N/����)j���mf�����
�~Mx3Ii�;=�I��)^�H=%A��1bE�$��q�p�@bn.�}q��G���������BK=����^�1��1�������BSp��D����:�k�,�������Nc
�F���c+�_��_��F�f��M�@������2�H��Z�~�����"7��#
6C���R�����<H�
�
����n{�����R�����Rh����t��y���\�o2�e�8�Ik�P���<:�x�#�("�5���������Vr1�C�zz����@C
�\��@�{JJ�'����@9�uSR�;�Yb�5R��w-�>�H�
5�H�2�w-�P��3_�*J���0C
7���_�Jf�PC�u��{�a��m]���R2m��?A^X7�Z����6L�%�!���zSViU(����Bt�����+���F������\�F<k^%�F��>�K���*C<Ng
\�x������xM{�x����@���������O��������?~���O��O��f�����������������|����z������������V|l]�cW����o��������M�a�XM[�*6�S����u����m��
5l�'��`���W��m��I;O�l��=��ks���Q�m�K;���qh��<��'Q�J��9���	�@�e���(��z��m�����naj�#<�p������/HJ����J��=}��j�����qN��a��W�@��7���}q8=��V{u��7�CW���LF+��D�����e�������x��jbE{���88����w�������e:��%be�2S�y����i\&=j)���(��i\���2=��.�5N��!<�Y/��E�;-������aezA�K�k����(�^h\��U��%�O���^����	�5���c���+_�&�?n�����W��m��"m�v�/m�ehJO<n���H����%�)�g%��\�s��4�x7����1~�ug���V�c���X��u�b�91�� �#!#�n�vM=y����evf�y��<)�kI�u#��E~���7��b����@F�\�����C�n��a���A	����e�NOE!�+��:g�*��D"��Y#�����|ie��<��@����p$Dcq\i�2?tCFt��s��p~��S�g�J_���3?Kp��9U\��Y�)��aC!76 �hUt<�^��@W�U�_��G)���n�B�a�E(Tt{C�K���	��C�B��-�g)�P�q��v��9s��5e�
Y�����~�t�(��)�3�{��a�f	y����n�y�����.��l���z(���j	�{���A=�%�������s�q$�-������H�\�z�8��t�����������q�R�w�C�W������������]�8qU��/��a��[��_��a����U6C�.������m�L�7����9�k�,�g��w����:>[����O�w�.��,0bA��V�=�@��D�U+�Mx����w���Xmxe�a��.�QN�u�yu{[��=��9i�Y�8����q	�/��"�UAtz����h
��P������R���b\SN*c
���+k��2OxhWSDD���S�����������5hd
���Z�{
���3ZkU��:�Gt�
��B��~��<�Hi��Y�@�T�7�h$x�y������$8d4�F;kB3�����������iG�6����@���m����e3Ip�M�dz��z����-?��<O�v���nv��{����taev��<�8�@;��Yw�+K*���N�l��L/�M�q����5&j[��X��Fm�X���(�O�^����~������N8]g�|#Vp��,N��f<\�:��cAGNc���19��#�6Vq�E�iV����3^���'�	�j]h��X{���v���f%���4V�Z���pW��x��i�>���P���H�v4.��|3���p��qq�-��%�=��h*2�E�p��q)�m{���$
�+�r<�LW�"��tE�tE�R������$�i\���2]�$���#}�U���z���]�v�_7rQK�P}mK�n[����@�$���6�(��95
pMEp���bj���}�� A s.�B��y���65�y��k?�F	4rFt|gz���J���	�8�Y�������J~��Z���3{A	�f�Wf���n^�#gD����]��yQ0�� �����`8�aF�fV��.��������.Z�LBZ��G����|��M�3^�)��`�US�'	\{q��'�u!V#�����4n"��j��=������j�����M�a��uV��m����+sR�}�����Y�ZaIv�����|��(@����	���*��������5kkT��C�|���g�=�|�J�T�7P���yv�}P��Ty��[{�����uT��lq��^���?�t3���]3DG��������2�Bpt�����J��5���W����W�Z^��^�GGU�^q��z����������pz9��m�z��(U!8��=�	I��L9��Ual65�Bxh[�+9����#[�[�
���Av��x������JnuV�U86��F#y^�Jf��JQ���������E'���Y��X���*&ZWe����&������/ Hq��o���c��n~
�wH�7hsr� A��_�+a�����L�A�Z�v� A�M����*��,?��W9����i�N
�����c�C����>��2[!h�
����y�,U��=���3��:������n 8�t���5��>���#��64d���)���H�CRF���E��DpFq2=�Z��F.�`#q���[��	�J��02�bc��Uhl$��v�������*��{��lEG���|c���C;�������
�w�S�t�oly�Qh�#]%x�E?�KpT(���T���w�����:X\�I����]����#��>���^�����>�`�(�����mxM��bd�m�;��RF=�n�����#}���Q���}�Q�Q�p�6�h7�G�,%����&���.\\�'�3���	��&���.\\�I;*c���Be�UJ�:��A{[��GYt�I]�X��X�*��n��R�GIW|A���S��!��QB�m�6��VvYt��{W(7����.��!��|!��_�1�����|.k���W�x�c
L���`�<�Jl0��M���7�����w��X��JJ�8��tr��Q��q;�UM���.q�f�f�3��yX���cQS�*�K\�j�KV�Iz��p���$�q,��Q�p�Fp��s�%]S��[�������6A��.��`ES���[�"�mNp�
KO:4�B����v�������t3�:SXm�5���9�,��UH��n3t�Y#��I�gDg�f��&8�!h�"�=1c��K\�8�!h�%�����t#�E��NpL&
��7��~`��%�\R}=:��%t�8=�xpA�*�KM�t��s�u�Hu2�.q�:�����=����N�s]����c��(fb�:1�-X���������<��%�Lub[��p�(��Hp�����na�x�b[7�������g�]r]��D�G���0w ��r�
��X�l�f#���e&z�`6���h�)� �3pZ���yIRZ�N=�>�����oo�
��~��=&����4��{}�p�@S���8���!�&x��i���zR-��Q�p���^���o����+��������������s�#������������]�;�W��w�����4/g�cr���G�rv����<�����������=��N��s��%�qB;7W;��4���`�[�rq8��{LN7(��F�I�,���
�K���s+#���$ x������:)�,�������5R�V�,�;�v<�Lwh]�Z�q�YG��g��^$N��t�ae��HJ#�1�D�tO��[g����=�K�V�GRa�qQ'���:����h\���2��w�q:y�l�q1�����Q8��w�{LNOIi�1e���
�{��(��h\������BRaL�<G6���y�(�f���=&�glh��2y�l�q��������r�����^�q:u�l�h\�z}������Crz���#�5N���M�S�Z�;u�5���;��zb�����8�:G6�0.�u�0y�c*
R�@����Q^�t�:G60.�u����u`N���K~��U�+)_���6s���7���C�k<�~��������`|�+�P�����)2��Y���o��6*���>�H��Cx����jE:��+x��"')u71�R���+x5N����x�����vI����1�(�vi��SwY����=(�g��q5�G�t�HJ��E���\����U�p�[�����y��k�fc���q�s��r���RG�t�.��8�c�;����������(
�k�:;�L�����S�����6V��mDQ8�����ae�A����8�:�8s����*��+��_3_�{:�[ty��9��:.��-�Kklv6���p��qi���t�.o���J�W�;���O5���p���;�|���$���+u���#��W��'��p
�|�3�3�p��n��\N��l��6���p�w�����������|�u/�G���O5�(�i\������BR���	�8��h\F���0�(��	�{LN��l������q8=��i���(��E�{LN�����5�u1���j�NOs���=&�ty��:��:���4.����:�^2�����K�.o�q:u�l�`\�=c9Q8���a�S�]�^�t������{�r�p��I����.�����0u�l)`\��{�cN/��a�SW���|�u�4�����SgNG��;�����4��&u�l)i\J��;�L�4.�a�S�� )�0�:����Ke\<4�(��h\����.uFRaL�]�KM�R���M��;����?�������t�-t�-��m��7��|���|�_����O�~����\���DEv�.?n��^���Q�|d:[w��X�q�o3���I����NV#�A	����j^������B�|]@*��+�c��e�bP���������a�D������8�	�3����cS���q�(��k���AE��Ev��x���4
����s�B�A��Svg��'8�P���nu��E��+����FF!�CB��AE���D+�Y�9�8�E�3�aP��u�����(,s�9�BzyzR�[��H��^q��;���q�E��UQboug�
LN��R�aX������]������?n��K]��@���pi�p����]|�I_����[�mqv�|(X�BA��P~�����ut�+��"}u3'h��V�}4My�/�>�� W�P�����<Z�Bn[8�C�T����=�S�������ey��8t����5�
y&�m��:������`���V�K�+�1�]d��a�f	#x��5��o�Jc.)�h�K�*#���W�c��	%��Q��I.0<�r������8��H=Kr=����R�H��{&�P��A����f�\���w��p��v�@�RO�[�z��R���U�	�p�yt_t����&E��s�x����j��x�>�������x-������2�G��|�����']�����MsE}�i��6��MsZJ���e�@-��J]���m!=���}M#��`�1�y���8R���K:��c�Qh��}�o�-=�<r���&�]��G-0���&=3U�G��o!��EvK�����p5�%��K��W��HN��3���V�B<L���j���	���t�
t�w1��/�����n~������xk?�����_�z ��G��j�NA����}n���o~����O?�����L]�~���A�s1�7~���~������O���p�*�~U��\����e��w�~��������>����^�����������]�s���e�����?����/�{���.����������������|zy+
������g[�W^-��Q���])��F��h�Mm�Y[��_�yq��������{�_:���
$���|�ys���:�~�w������������_� �hV�8i��<�byQ6Bf�*�R�^aD�V@+~�Q'i�������7��6:�=��Fg��i�s���B�
���
����b�
+J�u"7���u)i5��j�����1������}�'�q���(K$����W	�����?����t��=�T�V_Wr9�:�3\��Vc���%�N�������f�n;k��x���d�nc�\kt$�E9�di���������Pn����?��U�C�tu�����y[���e-s2&�GXz���������&F�y����e[\k�Z�:��"��9�K���t��+��G{�p5�u�}��3 m�<dk��y��v+p5��A��D���L/�� g�����\�����/p����@t�oo�qh����X�l���,��X#du�F�]IKV���O��Dt��g���vA����%+C�
����2�lM���+xT0��,m��
����p!����������������5]��8��1Q��3�rv(,�������&���<����c>#0����6!�8��4�������3-�[�����_���G���<���]NRG��K'W�h\:��C���+x4.��iF-�q��
�t�U����������t�a����^�[�s���x����,�v�s�������3%����%E�G��[�=V�����������A���E*I�k�����uIi��<�)������=���t�d��?J`��9I�g�=N�?��s��X�rOg�]��l���A��3��w�P2��c5���y�0;qV�0���Z��
�%���>`5��!��,p\*��6��1k�����oM�.�o��L��Z(�R�����3���@K�����n�\�sCk��B+�����a� K�V�f��#"\��BW�������}�^��H=6���G)���j���K���u�krRO�FS<��
uvc�c���(�nP����u�=�����W�^��+x�	���������F�V��O��!��<�Qg�3{Ez���^�����~�,�!�:��Gg��_��2�Z��Bz]Cq�������=���w�wlO!e�)$~�@-��W���Z��SH~|P�
|*m�I���'9lzG:��Qa36f�^ :z���g��s�)$����+h�+���h��~Ny����d�K�W=:�x3�������O�*��H�	���������a�2�Dp��
�c��B���7E�G�(>���z�~��:�Dx`��:K|�K:��yE�:�[k�'���P�����&��A
Z
��-��Bj�[�q��3,t�#�e[����BXv�
�mRZ[^uG�tF�ln��
�Yt���
��q�(����3��~B�I���N�����M�����q���=��6��Gk���7�z���|���f!:cw��7
�ZGt��Oz���K�j���z��Ht��V�
�ZkZ��%���Y�
�d��U��A���h0v!OH��t����	�6�$
�����Z~���50�{�H}u�t��3d�����?IxMKo4^y�+���������F�A����#��`���X���#����9�GF��1��������e�����@`NO4.SvX���o�q:�$�?<k����������qRr������<��=���zb���
ytX������\��U� �������A�SS��S�R��N�2�5���k�t+����+	�o�uM�U����
�u�v��U{�1�R3��0�������\�Vm��t��&������0���iA<���R�U�����e�����:f�j�N�~�w�Y�j��=��h�6�!�$x5�E?(��7�zF��������7��{C
;a�����v�����jWo}+ee������Y��mq"��Vm����������lw���ez�u��������M��%k��W �$�������)��j3gy�3{������>����9�1�$��jT�+��m�T
�D�)p������6e\Op��+|`��������$%-��
�G��	.��]����v,9v1��������J�N�@M�7\w�XXKJ�����cn�����j�&<I��U��}2R������������5e��1�������i�8^D�+c$@��5e�Y�J��7���y�����M��c���W����0�v@7 �#p5[}�<�a��Uhgu���-��/#���k��n":=���vcAtF��5�vl�J�du���5��*b������Q�(V
>�&j���,�f�����M�Fy���MV\l������L��g��qh7�@/p����C;:��~��	�[�����.�0�@�!�y>PC�R�,��`�Y+z����5&m����]�[�������%C�$�5N��n,\��q:�Fb��3R�@T��J�q:�����,��y�s+XN�����+S�^�t����qYV��KN��"<��8�������W�G�V�8�v4.����X��<�'x���2')�h������tI�RaK���h\��N�BR���8��h\J#1R&�����:�5bEeG�k��
��z�j;{�==�iw��@�@�����>�^�z��k �]�G|������R^�<z
� �W�'w�aZ�^��������s�G�Xy��-(3	�uC��Xf<0/���D�����{�����Yoj�����3f���0af{n&8��.�l�!�;�=�1;amAH#�+�LM���AJg�B�=R���=U#bl66��3�
N��s�����
3S�����x5N{���<DJg��<�a��H��Wk�rGp���@=+823
Q�W����X������Q�W�z�{Y��(��q�R���B��T��������������8�����e2*��q�����MQU��I���~���g[mOQ����)*|E�����g���W�)�O[��:���[g�>������7�it|�M`�W�g}j����8\�<�=H�A�ju�2}={Ft�����Q�|p���f�2��T%��T��Q�N.�#��Q��i�@�T�>�3�c��DA1�V���D9���>;[�+�T�7;�2"^��95H�����
Z{��R����"�R\GpF4���
u����/������� ����h����4)|�{���0�D����X�L$�!��;k�5��veAtz�<=���-���*�0�D��>��^f�h�w��G�]��N�3�wL3�;:���l5��eNO��L���f���*����f�����<TX7���y�����q��f^C
Sht�X�Hx����o)����Z�H�n��\��?���4�����8�nG��m���;�qNw�7V�;T3��i��XNw4.�>������G�������$)�K��-�8��i\z#���
?0�{�^I����#)�f��������`L@{�D��@�24���1')��0O��G�Q��v��w�6�m��n[.���������E�%?n��^��v���������h�n��9P�6�Up���w�M��M�(�	�mZ���n�Lpzm��w�0'uF{H]\���.j�w�l[�UIx�b��@
�����9�3�
N?�.��U-�w�L)E�4� ��1��B�n� Ecx�f�&
�Zs
#��{8-�v��fg�n������"�]|E��+�;��6��H�r��h�����w�k&��(�{��b��)6JGq���
�7=��Sl;�^�(��������V;P��g�u!�H�h0���5�;�5�Ot���6:�?(T31�M�o�%���~1Y�����C�/pw��k&&��������V�g
�d]O-����J������hf.:$�&�����O/��LJZK�w��-1V�������x���~r�� �\��Zi&��uw5�1��h&v�6������+A��>U8v6��������n$:�{�1a3�	�����~�a�-Z�y;�#�p�}������L��7(�b�����^w�\�[�C�N�0��D�P�*���d��n :�9�6
���$�����)=�r��	�;6F�]�r��=���p���v��$GZ[E�EFt�K��v�=���qh��>��^fj�������Qh��������
�;���n$:���������<�3�����(>JI���y����V3d��MDG�b��j��{7F	�;�����B(T����C������$�v��)�uQ�i�mQem���`q�/�z��5J���rtG�j�w����6�Qj]���mEC�1|�2\\����(�>]�*l��9�>J.���]�����j�����':ccO.����Lt�0`z��r3���.�9�1��Z\�T�Q�tF�LW����M���Qz�l�������y�^�(]r}��}Z�j�Wx�n`���{3������W�]�C�DGK6�{3�@;���1�n�����F������Yv�	\�v��+F7Z�w71������:��N��!pC;Z�I���6����M�����	�C�� :c�JW��d�>��>���3��W�qE���r^��@�^�u�~���y�cS�G�
�J6��&<��w���*c,���s����&<�0����hNW�q�{LN�I������4�s��{G"7�s�$�19�3_^�t��F��R'�|�~��i����rz!)u_�(,���i�HJ�a�v{`N�
��=&����8IV$V���"x�h���in��.�]���y���c[X��p�{H�E�8v��q��Ar4NW��
x����7�Ke�^�������:�FQb�&
�q�Z���5�Kml��
�q8�����(J��x���z�(�nh\�;��q8���4��Zt�	x���sdT���H��qi�QX���46����
�����36�Z��8��h\�m������&�{�a9����FA��%��i\�m�!')���>���rz�q��Gs�0��3"x���1#)�0�k_aXN�4.�5�w;���#��XV�������}�a9=���F��������h\&wX��0�#�����3��d\v�n���9=����ae�=^�t�w1U�����K`NsSu�mL�1U�6&�FN��X�����:[qz>�L�8-�5N����8-x�h��O��#���in���S���nD���y>��9]���tT�]
HY�ka�����n����>�]F��7���a�q:u��v4.��a�q?�i\\X�.K�RX��2
�K��XQh���tI�Rz�(L��� )���0�/�p��q���s("�+��9�Ls����8�:GV�4.������,����BR�aLa��D�tC�R�#&��N��^�{LN7�7��-#��u�����GL<�u��Gt�-��m����^_�k=������_�A��2<���o���D����q6�+�������D�/n�mV�cE�H@j���&�!`��t��/�D"`�1!��P�&Q�����SB������@�FW�q5m����{Cw�q��BvA�8��
p�����@�B�nF���]=��Kx+��g�O����V(��U=\�[��@I����L[j����@$<J�b,5��\��Z�o�.K��]V�z�U���������o���+P5��=RH%<4��J�����N���;���s�g4s���R�a&M�j�������}�t�L�Y�o�������3h����CzC�*���$�@��@�),������@��������#p(�&:���v�/4�&������%^]�x� �����������YJ���KN���3�����Q���Lg�e��{��NA�W��:�e������������O������~�?~���O��O���U�����O?�$�=�����������k��W���ri
�������W��s�.���������g�_p��>��������#k��^�N�u7���
\A���������8��:�^>����_��_��+�m�y�����:���C�_��y����������������w����?��������-v?�)�Z���/$G_0G�]��@�W���T,�g����/�KX���tr��=�W`��|��bi��R,��>h��_��/@�R>iU+���'�q D#wi�w�<G��^��?+p��9�����n/����h���KVX�"��dH�.�:��d����������H��s��������(b��b���$��Y��y��uw�n�V
�bM�'�!��,�-�v.�������P����K�WNOA�� �jXk$��"��������w!�&�3��*�+�j����t�-�q�N�>�eN������&+�/��������9���6 ��)bN��	�C���!�=�l���+�=qI�g�}V]<��Oxa���t�$�`��=��%���Wqo71<��Ot�`�l�o��6��y���e��,~�q��jN�lv��]"��	f�l"����x�o���_���8=��8;�WX��%��l��/e������4v�7A�_����]�C�����t�|N�tG�Rv��!0�'����6�A`x��%x5��ndM=��^���������]]�[H��Q�0�s	����h���qC�w��0j�+f����H�x"��N(~�!@���]_):��t7�!3r������uY�h�6FR����1�*���.���n��y����_n�]|s�jo��1��Z�zYo����,���7O6�I�_6�'��e�d_��= �!�W�r�jZ��=�!�&pw*��\Q�q�6����-���;�F�:�I��?���������H*��b�!�|1�����!0��&���Za��X��������-�v.���X���W�w=5��?!\�
 k+e�����)"A��w:L����3rB�������x%]�v|�D�����Y{��3�k����J�*��H=c����L��+t��	�;2V�����P�r.q�G?f4����'�F<��E!�DOf2�2�5'��U&cG���#o���P*�U��B��Ze6��X3��������YY���ca6�?��=�A�%':��pzk� 
'x5�Y*9������=��[���.�>�i��kt�%�F<���A�)�V�V������Y�&+����8w��5GT)�����zy�����q�w�U������=&����4�M���Q8] #x���p��5���BR�����Q8�J����"�
���19�����8���!h2���w����O���i��'3��F�1�?Y	~+��i&�����8]��}2����W��4.���n�-q8]��Tj{'VtXx�����	���6��YAVN74.��#���n�d!�5NG���G��]�� �G��qi���t�B���8}{)Q`N�4.�Q
5����4�K;V����4�����t4.��x7W$�Z":�����\-�CK�c�G��^�6��������}@����^B�����c$���:����]�K��%Dc�>w��\��?������W�����H��*��o?	s���F�
��{]�4wH��f�o������Bp��\��C����GZaD�0����@�T�G)��{u����x��:�������r��9��k�w���pzA�K�j������:������z3�gU���{��e���a�������F�U�7�)9X���6���^�g��0���g���g}y�
�]���vb#4�`����s^��fO]y���.��y��/x��*������
^����,���]���6G��!v������\\l�c��VO�e�8K6C��@��|��cvEY�9C��u�����
��|�*��9ul�ys]0+Z����s�P�DG�f�\7b�@C�DG�VW�1�3�_b]HI=�,�����q�����x4=8DLx(
�������X��RT�
arAn�,p��-	���	���=P70�v��Z��Rr9�^v��H3�
3ELx/;���
�I�����tz�i��7E������Va��C
3Ep�q��R��)��z�"~�q��A[��#��	�����&���m�����_������k��~l����)��7h�b����W�hLZ��0�XD��������Lx�`��q��
�3�����g������@t�hqz���U&��6��8��@g��y3��ld�`c�^��	�Dt�RI��0[|��/��8�U@g�?�x=xkU1K0b��Bsf1������(b����i���N��5���a&�yyv�Mt����m����z��:�-D��=�x�a����e�C��,�J�y�
7�7���a����Q����g��,��B<l�<���.��$�HtFv7���I�3^�x�#�'u�p�C���,W%q��;*����g�JGx�V�����l��d����b,���g���0<�WeDg��NN��Z�2����F^uDg(��^$�Q�TF�sn1������T�R)��y5]c�k���0�^^MW��
����&'<�Ui�E~�k�4�.��Y���	����5���������y�#<#��&�a�-�*��Uy��UZ#���0<SR]Ft�Rq�u^W��uF��
a��%:�n���g��W#^�F���uF� =�z:��t�u�:����$�������t�{�I�
D!�@'�7�d��`��I�������"�`D����V��/u�1���[�4VZ$��J0Eokd;�h��N��~[ir�(g�:��M�3������M��?��f}���V�L�y�
s�^�>�<���p��v�@��o���6�W������_�;��pz��X{�wv�?���a�������Z��i��D�t���3�;
�p��h��19��$����Z	^������@]�Gx�G�cr��HJ�:]��1
����~;����{PN�$�1yd��(�v��4�!V�+��v4.�V�"T�q�����.i\��tN�4.�6f�|N���	x����D�tE�RY0�!F�tE�Re���
�����+�v�H��q���b��.^M�r��r4N���	x�����KmT��m;��
�K=V�tx���sdEC����s��qi����t�*���8�:GV�4.�Q�5���v�	���'44.m�)��Q�{�r�CUt%���2�5G����w���q��/R\��<.�a9�$�q[�z������fr���"<Z�>�m���r���-iM����@3X;�-_"
�Ze�!8����mIs�xN�yC��1���#����dXNs)���8�<Q6��X[QL7"
��E����
cGJa�G�����e2&���v:p�5���!oK�����p��*��i����S����9����!�������c�q:y��+J����v:,�]F����-��.�����8�:Q�2��q�����<'�B�����)s���5\��9����������� ��EER�%�I�8�.`\�&��O\�"x��i�HJ=�)���8�v4.�X1a��bDY������2]$����iN�4.�1|`���p��q)���4W�x���sd��q�V����i����BRw/���8��i\*��E�#�M#�����1t���#�����
�K���x�8	�����)+�
F��i�3
�[���0��>�Z�6;�L�Ep�������i����W�nt�K�$���|[�����-�aA��?|����������?9�����o?���?���������?���<��������~��O���Q�%��+��q��%��������q������?wG��Hw�K�����	�(z��?w���c���?k������*�y��� ����?����������Q���������>����?�R��7����.j��f��/��������?����o�\������������^��7@P���zo��<N;�k��dID�0z_���z��u�3N!	X6���%:i�}C�����5kO*������.*������0�U����+��A�G���V����e4v�%���r��D!�kzQ�������'�N�ZI�;�E9]qE� ���6���&i�s+�>�T-�v���}�U�����uf��K�)���(�����#��yq���8�������]��������b�n�js���'x������	^�z�3E��7��X�*~}��JfV�F=��#,����3F���(�1r/x5�y�����$������%<o!��#�;iSor��Q�+�SoB�N�j�����zH\	^�G����_�N������.W���k~u���%�������xK |�������gIx�T��q0���}�����?����7�������[��L�s�����oO�r����O����}���_U�?e��
���/?��������?}����>}���?��R����������y�����=��V�\���_8��w?�������O/oA�I��$�h��_���dE�dEu�j��F�Tc������E�Wj�
��^^:9�����(������Xu"�����|(��+��/�����OZ%�r��e^����3���F�X9b4Z���<Mv����/��	�mt���d��;�F� I�$m��`%�����}D��`}������r\#?(x�r����%�MK�F^0�7p�������!��@��O�S�[j�Vo�N/���$pt���UK��2����e$;�����y�����OA��J��W��	N/sZSN�-�\�
���
p4#�{�Mz�~�����X/z��J�>=c��^�3������r�#��hX���Ua��a����b�$���'��}%?n�G�[�(3a��V>Y������\(�@�9����g��:Bx(�4VN��~���R�w,�C�	�Uc�T�����n$:�T��xsNxF/`gxa�����Q�H�C	�1���.��<O�-Dg���	����5N�X�:Q��P�,���'��w��p���t^��`,��M-�m�
���n�S�D7�e0,��x\��f��u�Z�'�rK��B�'��.����g�r���&�;��`-������`�	�!$p��i�����4��=&�]NR����c�*,�j�Wct������W����'
x���W<ft	o�]�
/m�aS���3I�_�2��EatE�RZ���om!<Z�*�a���f���j�y�#
�k����;e�0��e�C��
�h`�2h��	��

�Uz5W�DatC���<��
�3��qM��+[�k<�	�c2�e���3�GatK��)�)����hY��G��2�CMV�+������hX:c��c�)0�{Z�.�M����QJ�GI��4,�^I�XS�����a��
�����zUA�����U��q�rF�b���(��O.ZU@th�����'ph�Z����q8@���f�{�����F�b�����]a	8�S�������#\���"J��l	�>�%
�����"K�q"Dk'���[�R��|�a��P�!a����W���2T��-Ds2����"��@;[�D9Y0+����fg�!�/h�dg���<^$��L�xm&�����L6�A����b�����jD������5�1+�|N3�.�5N{�r�F�v4��^�����P(x5�yT���k�gl~0���:Bx�	�F����mg�����T��OY�xmN����/����Uzf�*������WP��~�����GW?��X�\�������������|�����������-�W�����y�]c>fc����_�L�|�zp�'	68���,���a�'�;8�tz����I3Ln�7��nY+������Ey&�����L����3	�u����'��L�?YR��L�o�+��c�Y���b���v��b��,z,�/�c�xa6S����7e�G��o�G����Q�J��H�������9�VcCM����\��g�fs�
�;����m�=�n��':�U��9��'�S��A��i�f'��9^���������� 3bD-p�C<(�i����x�w�Bt�S�g<6�
^�x�w|��h��+kv2�&�������b��DgTi���=��/�._����Fe!��ki�Z���.�(b�Dg��y���W#^�]DGs��C@O ^��n�
k�~��l��9�t��X�bzc6$~�1�Q����l��
3x=��@�!�J/f0fC�Od�s�4�y�6
�yc4B���;�%�(�iX�KkcFO�w��b�l��W�����
�dm���L��hY���=�$�����'����e����u�.�gZ�����0d��D���a4�$Wct�e�G�����5���C�U�����'�����������o-x��h�v�����Db6j;o���J�����=(��R�T���sQ��z���3�Kt� �jP���-�n��M������j��������-�L�Z�J!�����F8g���	.�l���������G������<<���	}G���m[~�-e��������F��Z��j�;
z���O�����lt8z��
�;��Q/�I]��h����<�z�g��O���H=c4����Po����� �74���g�(���0�*��8aP�?�Kx�C-W����n�bdW�����7�zV����� ����zFk@���� x5���K��a��Q���^��z��p��cY��^�j��?PJx�u�����1��7�z�N=�:0Z���3NhT����!�+x5���5�`�V`6��3��H����?��n�af|�9���r;��8��^56�?���e�9��ri�-/�g��-w������~��������2��2�]��Y>��+����=���;�F[�_P#/��w��;c��L@�+��;��Qu5zLf4�[^��	�]���^^aE�j1Vn��i������4��J�2d���<T��Z��'�qG�o��N.�c�NO^��>����
�Ll���E�=�������R��\`����-�������x��q��e�hTz��b��[^�c,>�V�*[&8.��Z�E5";��O��W��:��v({���5�:�)*V���
3Dx�u���W�}�r�����P>�x���W#��m�*�f&:��P��8�s��t%S��&�=���sF��&�o$<cb����x�kx�{�a���F���+t�E��b[R��k#j�U��K��WQ�T����Z��x��Jz���*ox�h��B<d(�p#�5����,�N�8���NW*O ^C�RN��(db~����]�+�r�6��o��>�1(H�?���0����'y�X�
^	���9�������W#�=Lq=���j�F������Y�������(��VQ���t�j���0�g��;�j�V�����1;��0��a��r���-K��+�L�
�'k6�Ea�@�29�,���<Z��8��ud�2�%0��.
�Gc�za/�GZ��8�������IiEWq=�����*�i=��L���'�9')��J��a�L�2�Y�e'+x�,�q&�WX�R`����n�a��&$��^��X��eY��J��t��0u�c�@�g4,�Q�3'
bHt�],g��dt�]O��$3�c�����@��q����m��l�U,g�������@�${0T7v�
��+p����X�t������kA�z�xb&�NDF^�%�n!D�tg�0���GJN����wPl�����������W������3��]�K��&Dc>�h�s;z���7���p��:DX���J���!�^g��JO'��B��Y�����tT�� !��.���<
q��Xx�v<OGwo��o�XMx�����s�iHJ��"�����=p����NXxm�5F����dMp�W�v������]p.�������]��S��|��F��NV��������^�C�W�n�V���S��9�^�U\�o�����=����k��dLN_���z��v��k},��c������'�����s�e�j�}����gy<�<o�;��������_09��2w�J9�3�d�j�=�@��D��8����v��3����3�:bE�M�+���Gb�n����:C�����	����2rvf�'�.��_����XtyK]NthP�O�k'64��C���K���kO-�.G�U�*b��_���v��C!x�Ij?15���:u���uI$�\;�!0v��i��v����3FN�F%]��v�CT�������E���	���?�
xn�6�}�����;kX,=���;kX,�\;��Dg��7�+�x���������������3������m�f�C<�����==�Gx��WX���o@5I�Flj�A�&�b�(�3�3���_�H�2�$k/s�uDg�{��UF��d5QF!g�a�v�V���2f��I��uz�1���q��j�3�Nt����8��WX����s����a�i�"���qF/���;+C�Eo����;�W���[N;)����^4�L�`ti����;-p5F�_`xyN���9�n^at�qg��!p5F�_`xEF�h��X�x������Di���?JEx3�w��v`u%I��,���������<���eq�k�� )�J���atI�R�i������k�*')�@��?�Lt4,�1�n�P������:�\;�.$��6�����;���Ps��G�Rh��X�' �F�w����6����6��ei4�N�����d�����1��o"|�k�st��hX�w�r1:^\��W���x�����?n��Vi7w�&�����'f��&����^��2�������ZB�!I��5�2Ds���
�BR��^{���N�����;RoQ|�|V3���=rraY���"x��t��!������I&�2'��e�{:���6m��P����G-X��w��@�����8G�^E-XZS$�%�;*�F=�<G`x���J �Z�^��zF�T]����l?Y"��Q/����I=���c�>,���zF��HF�7y�@��&����Q�_Wx��Q�<��*�cgl�����7yT�&�V���fR�X�U&�5���26yx���C&��6y��c
n��:cH�c�H`���g�����=0�V���������i!<L��e�y�E�������i�WP������Wf��iy���*7���5-��q��^^��&���w�kZN"��~s=��o���5-�|P�;��_����I��]���HEbl���1���4[tKAt�����@kZ;#�A� ��Xi�������G�;\��3�y1B%���5-�F������f�F@D�����*����@{Z�!h)�u��������U�����fO����+9���{Z�QT
c��
e��O;D��V��b�7�����xA��M�Y�}{Z^��m���8�It�N��r��Zi��pM�	���W���"*lCR��=�����Nnxu��r���W�����_�7h����e8��2i��k-3�Kx(=�����Z�fH��:������q�7�5�}�-�Y������
^�x����@t�x~j���:(x5�E_�Ct�w�QvJ����#<}"���8�����:�'^^�d�����\����
������x�Y�ur�WP����Ma��E!^��O�{�-�U
c+��}f�!����t���9�<�F<#_�x=��}���G"�d��/��M����������qP������8�����HO<��R?RUX�wQ���c�{k����h8.�����VY	Ot#�����=��Z��w�xl7�����������v�x���Z��B��Nrm�1X]wQ���In'9}x��OB�*�����DmAt����k����u����n���TZ�U���(��Nz��/X��I<���������X��������u�uG"^O��3�U�F�3�������mO��#�U�����������%7]��pU��5����`�*F[b,�1�7X�J����g0�y��.
�FV	F#�W��a�=�]~��y#�*����J]���L�{�M�*����������Z��I��U&�|N�:�`'���c�;��U�V��Na��F��x<1��4E�:�`'M��0��6%��U�V��Na�K��%\���(��3dU��X�%��0�l :kyz��U��G=�9�Qb���X{c�����!�Ht�&��~^��{��D�q�}o�p����H��	�rUG=�����Fzk�;jc�}a���A<���t��Z�})�sp1�WfDgl�JO��Z�4F	�U�q����T��mI�R��z�(��
�3��������V��.)kex�
Dg(k�9�jj��%�/�G"^�"���^^z�Q���(A,��������[���A�-x5�%�������"�Z�1J�f\�1�n�Q��R*Q���x�W#^�.��E?Co��{����zCCav�� ��	���m����0��bX�n$:c�oz����g����"���S����"u�@�3���6��(��R���J�<�J�����M\1�7P�F��G7t0���js�Z�y�-��^���W����������'�������������I���S������~�2i���|����z��O�����_�\���Vx��_������������3<w����M��u����#�XN�G�K�r6X�D�1+��1���`�7K��XN�;>&oc����('��������*'���(���('v�������*'������r�`m����F"���h�AG!�BtF�Bz����5���6����-��/��;8�*�qn�0�&����_�]Y�q? y]b(�^�x�B._��DgeJR�����-�L��B�!�R��(i��;��/����;��U�KO��"o
7�ax�m�������<<�p����,��$/Y
�ly��In�[�������f":������l"x��93����Z�-Z�j�<�>��[c����x]FtF��<;<t�m�wx8k{�������T��I��(��/u���j2XW����C��^6q������{�$������c��7M�����k���.�&�����x�t��[{���*`=t�b ��E����I����Ur�>!�K���,i
��o&:}�a^x`X��+���g�)�ad������N&���W#^�V�q�������x�F��Q�8
Dg��J/�<!x����>����h��x���i0f�8�Lw!
�h0f�`$''�G�(�3�R1�-'�Gc�=�=��&
�1����T��7e4�a0|�>A�7q�]�j��������8�>]L������zL���5�����g0����{Gm������1�#x������|�9�8�.)i�
�w����{LF����Wm"q�
R�����rF;$��1��^ �FASFs]��QE������b�h�.Q_����f�"1���4:^��eF����=&�+T�'���5���
KeT��<HF��,�tX���
x���8��iXj���5pftQetC�R���h�x��F���

�5n���HtC�������$)������hN��;zc�0��e��?�;GR��5���
Kg��Y}<q��q�{LF�9I�0�aF�������(�9H>]=8��q1c�������0E�<:��\�@8�g�R`���8�iXc}@�<:�����=��Z�+�N�c3���c�;Nx5��\4c�����6)���8��iX&c��u�0���!x��h�iLF��5���4,V��uP1�Z���Gc4W�x���3c
��W�H]��32z��*�sFx���3csF\����Ws��x�et�^�0:ufl��A\����Ws��x�QU��^at���\����
.u�j���{LF����#Uk�=���C�j�N]��-�����1�,HJ=R����0��a)��_������<Z�r�������wr������UNz����W �+Z�J���[w���XsE�RU�:0��RW�q]���Ar�F|F�4/u�P�et�����Z���
�Km������tC�����%����	���ii��D���t`N��-m~X�n1\"�5N����-mKk���]������]+��K����)�����J��vB`N�4.�|X��1^"�5N'���4.�����n*��~<�L�/���'����d�Rw���0V����4�kIN�4.�����n+�G��;�LO��4�koJNO4.��T���+�'��=�L�Ii�1���8��i\fce�K^��i\���2�d$��Xivq:/����?n��qY��Jn��y����oo��k���g��D��W.��o���2$���cY����o�c�[�Xx=W>����T�(�qJ7�6EQ�K�"x��4u
b�sR����R��x�����K
�"x5���yc�R�����T$��X���p�A�"x��b�V�������t�HJ#\�O��tK��k���dNs���=&����4�kKVNs���U��Y�������;l���Ii�+���(���[��q:uI�i\��k�sz!)����(+
�����eV'�p�Gp�19����q��_��#��������A=���!�x�e���x�1:uVq�h[Fc��Y��"�m�r�WXNO����Sw�-m�d
�h�+�3M�r�WXF����
��UYQ=����&/�� �H/4-s�M^a9�-�^�t��B�bm��h�)�M�C����>a�f�����	��kF��jI��U��"�dX3}�{LN�5Hi,���JQ8�� e��<�i�
+�X3}�{LF%)����C)
���,���Xa�5�g��d�s��u�&qz����K��V�(������K��r��IJ=X��%JQ8]������2��	
MKrk[XNWI�����#
�+���X�V&�B>��m�B�m������������5�Ke�m+=b����i\��{��r��@Jk����#
������2�!kh[��{��2�@Ic�tnV�0��mi�I���wK���\���mB{�s3����,�>�\�;��6����|�Z�X;��y�(|�hW:}�y,�
���f���+,���4�N�f�)
�{��^���
���f���+,��
��}���(�hXc��9s%e2��!�y��4�~��k�N�iZ���>��"=���!�y�e�T����is0
�'����*����D�2�<���sNR���A�(��i[fk�W�f�������N����<m��Q8�����TIQ&�q�G��u��	�R��s�����<�qY����L�9��E���yv=br�p�ty�p:�IJ}��(o�8��q���t>������,���BR�S%E�xsD�%�w�]^'�HY���"QN0.�W�t��M�
R����'�-H��0�ty�p���8c���M���.i\�Q��OXk��4���������4�J����'44.�Q�����HJc8�ty�p��q����:� �	
�Ku���&�Ii��.ON�4.�1WR'�=��q��:��MAR������
�Kc���iOhh\���7y����p���D�tK�������(�ni\�����-$�1o��������5�
����'x4.�Q��O�0} �5�6y���q������ d�(��q��:����q:y�l�q���x��4�9=��G��?A�����8�<G6����A�q�&0�G�����'��>�����F�����K����x���VLx���sd���wisz�q�;5��?�����f�Y�8(<����4��|���|)IJ#�1W
D��B��3u�xz�qY;7]d��b�M�-y18]d����d:u'B��������I�s�I-�E/B�*=���\wF��O~����
])��[��D\A��o���������z����X��UU�r��^4Y�zm���
A0�)��7�����7Vz^�����
������MZ������G7���D'�z��������Q�q�$����BE��%w��'��	�'o��\�(�
���X:D%�Y!`g��@���g�+�O$ g��F@=����'N�_���P�)W�U�*B��/~T�Z��FE���E���W��:�i�{�3�s!`�~�Q������w���x|UY�>�f�s+�>��W%���!��DK���|��W�$��Ln.�?�p�������7�AS�
N���4n���?P>	�i��9��8��L���h�)I����������M�3��E�9*��@�?0�0�+x��y<���ks���������]�����rl;f@�CZ_�>��L���3j��
����cCRe5$��w�R�
IUgu��<��b��^w]���������7K��~��O�����!����_q�_h�/�A@^T�0%k�_���>������~����r���������g���+�o~��S�WdE�?���u/y����U��s����_�?|�������|����>����������8y7����s���s����/����������/�����V�\���_���������~��_>���N����T�?��z��,�������B���XG������$�+��
���t�W���W  ����EQ[.�����E�|%?���������e8��}^�����r006h9��wF6���D���U�z:���+pw&�	���A����$����cmM��E����?@��??.���+x�r�SO�%�%�X��^�q��WAg�;�7�w44��f��7|���"�8�{���xw.~�����'����Q������y����	#�%�h��MX���7�v���s���'�8zSVc��YW�\u�juWg_�������2���+��-9?���#e��F���l�Z:��6��k2�����j�Y�=i�'#
��	\�vF)$��6�1��9����v��.�ukr�4�_$��D�[7gy��h��.�7��D�;�����	\�v���(�+P�j��p����	\�v���)���i��:W��r49�x�O�*��N@G�n :�.��O�v%&�F;�5��DmMI�R��".��,�3�CxT0��w�c���\�W����N+-Ie��4��E�tE��2�Nz�|����iu�����FO��(�f�gc5zz������;l���
IJc���.
��FK
����9���4�;	��#)��*s5XN�4.���(<�N�tK��h�$�v�ZZc���� 
�;�N[
����9�r��=&����4F
���(�fAG�j�����	���?��Ib]HJc1}�5���z}�c����	7����ex�-�	��N ~�
��l����@p�,��e���P_�v�3��y��_�� ��4����^#l]G���.�0)�a�G���.�4)��h���Tt-'_���<V)?80Bx�j���ka���M��U#3�v7O[e��r��=��JN��������������W;R�������	��9�;����J���WX�5�g���*;���~������>�`��ciE���X���
��En���������K�uPA�8q������k�v��^o>������P��dC�
F��Y�.Zw���'���_@gn����
�\�CI�F��q�>Ps1�!t�J��.���!tm�%E�u,HH=)�q���b�CNT��o� <�D�Z�}vM�����2���r�5�WC{H���=�pb��Yk,O/���;�1~pH�����B>�M����b����K�!�kp]����f�^�@C����6���):~���:DLt-�����V2�3�����V�t7&�Bu/]��1������t':83WAg�~"�n :�y��(�[���KMN���1&�
�� L�1�Q������2��D$p5t�&{<�]���#.�����	\�v�&{�)���Nw���#��Q:����!���wDgh���xDG���xE��O}��Dghkt&
�j����+�M���;^-�G�w5�q���`�=������(�i7:�3�����2;"#.pC;����w�����d�5���v}���d&k�L�-��E�OO�u��������f��1�q����e����t:�X���F���h�
���.�l�����6K	�crzAI�k����Lx4-�^<*�;��p��V�^�*�}Nx��f
$����Z������3	�����q9�c~B�k��?%Jxp#��rn�t`N�w��obEm]�k��?%Jxp#zc���0F�4��	�cr��v����]r:��(���8�xc;�q8M��4�
�eER5M�)Q��q)��o�\��\+����������wJ��h\*c��*���4����a��� )���G�	�������i���M~+'Dz��\�:G�sB�o��o�p��\+�7��&���4��&u���Z���cz�y�P��U�o���`t�����7���hn�
�oK���;������b���}{=E_zM����	�j��n�Oy������h����u�ap�^����Mt���+�;M��
�@0k���@7���RwE�:�"D�,��M	F�0���5�G]�=Dk6��
�f�i�<R�NX��`X3�2��W�	�l�0gO�
�}C�VN.�]k��<���8��n,,����}`Y[`x����y�:�8\��'���,0�f��=�Q�xt	���gm�������"x5���=.<��
F��W��zSF���rv�E��[N�>���z�66L�(��������W������mL���n�_��Xoq����A/��A�
���gmn�S�g����|s�N?n��v�Eg��h������y9�aV���>����zHcN�n~��!��E����^E~W����_��a�,q��:�sM�%A���}�����N�����F�O:���W����?���������>���(��f����>���F���ks������3���s������f
�
�2��i�V���rM��DWRP�����&=�gN��]��Oz5���C@E�y�}4z=����[��7�{��hr�N����H/�l��F��0��:�y���1������� �������Z��)�
r��Vg$����!8�����Tg��?%���]�CBul�����r=�x$)[=�je�L\��a*F�j����x����>SF�l�B7���v�����
����e�{�+ttb&k�Q�;�+t���.�G�q����h{�
����\0����Qf#)���y�1��u����-�(��1�\�b+�
��E�(��,gw�������l�B���r��`���Q������sU�)�La�N	����
#x�������������+xpa����M1�9�#����t���FO}6v��W���\L`N�G�����HJv'_r:�l�
����8}�W+0�y�M���3Ii�sk���^I�����c-M�r�T����-�M%��
x���Gc	��m)�������#�mK�V�+�E�������W��Tz^��rJ�8�����uvp?��-u�-�;��ce�'^���NU��U��YkO��9�����cq��{�uDgd�Sgq����qA:=�����^�*�^�:���ah�j��s�������=
��-X�*�.9�F����`��q�8!p���M�k�8D���D�6����=��:?F+��+tXG.p7;�Ul�2�M�����M����'���z��{���������b'����	��4�X)`��L���&����`�!1���M9����G?����/�(}��	-SC���L��.�I:���.~7���
W��
�e�W��;s7��_�����:�pW,��.��0���1�j��U����4�0�Y�����H�B;�]"��=	\�v��9|i���/�w�$g�[����/�L������eaL=���[v9���N�E�4��������4�v(�	���n":������99k��KN����Uh�:I;��W�ah7�~�*���
r�8^��v�J$p��N������C��vA2s���#����)��/��~Or�)��y-G�MS�=blA�NS�lG����Y��w�����>4�B�z�l�!:C��HS���A/��M�IS����/���W���v��A���z��k/S=������*���/����k+S��h����3�^�/*:�����d�{�Nco��o�h�G�T�����
K�\�l��+����������2��F>�F���H�*ki��Y����>�S�k��:	p���<v������];6g���
����2[��@=c�7��w��7�z��D�;/_������GW�/������*�����
����_T����~�AvuL������0
�t�}��~�o���N���a��4���	����f���=�\�u���m/�s���y�\����W�Y��J���G����t��6W��^��������6�y}���W���=��\��f��/;������������t�/��d���l��$�S]U�.l������4|�~��kaDhp.��Qu��j����.Sm��W`���Y>��k��n�=�]^=h=��]��p�f
����YA�����nE�\��:c�V<%�Kt#�5�NO
�n	p%�������q+|&�`d��xD��M�j��9��[^��x�M
���r\M�Xk���q���5�[�7�l�$���V�@�k*����g�1���p���;��-1V��D�td�jJo�o�t�:+@�AZuV����Jt5���Y����V�����
�Ygm��,[�1�Ft�)u�*f�������F�5~�0���&�U+����v#���|�:/�v=8;���U���i�h���N�l�������h�7[�b��g�G��i$:����-�Az#�n��2�K����L�b,�tf[k�aW����8'�WX�_fc}�5���x�#)uSX;`m�!<j��@������b�/�\�(�>�*�g�/�*�18]d���=$������/��<')�������t��N���9��q:��9�+2���Tem�����
eS�8]� e�Oh��Y�X��IJ}T�(��V�,7��x�2f	�5*������|EM�S���R
��[�N�8M�=@���lm�"'����$�+���qG(=��w,p������m���v��uD�'����vg[=@NO���t���o���]�N����]���K�h�8���u��>MS�4l�n���~��;����wk'�N�p;��v��|��-�n�w��W�n��=a~}��E�b(��������"t1�@�>��gFJ%�N2����g�{���o��0E����E��|#]Y�"�o|�+#����G��L�)�$�lx��#�SZ���:����qh��C_�������V0��[��/����R���\F}���RO�a|@�+Bb�Uc0�98�� 
����t����v%�,�{��h8�Gyw%��ah��>�`��C����������P��GywZ��Qh�34g�
�R�<����>N� ���[�+�x�
�pp,��[	���
_1��I]?1�w��Rz�Q��5F��k���J�o���;V���*kCm�":�3�U����`;���(@X���Y�:��������G��}6�h��hgltf\d��MD�m;"��{y�������YVG���a�����lt��;�z7���,�"V�y4����s����#Eq�s���^��
��Q���zr���(����]�Ex���{R��R/�K��if��j6�bs��e
���d;�4�a�R�J�quC3M,X/�u�����W���/��7�����e���o�������x�����:�"�,�S�wn���*��b�J��A�B'�I"�2G�F>=~��+�*s������Ne�#I.hc�[={n�|&:�P����pd��2O�v���#x��N��}5����Og��g����7�]�U�}�i���
�>��V�4t�74���hG�d�_C������+�C�#��PUlk��O��/<�>���Q%eM�����l���t����F�W=��V�X��%���E)���t<6�����]�X�>so��U��
�Ea�?�u&�
�Z�����s"'�������i����+�5
��W|S1�X�AQ�� "j�y��GAl�7!GD�;J^��Rl�����+1�EW��j	�'"�Z��b �W���GGd�0�����E�n:s�!��e���Z�|��|��L����<CL�f��i���K���Y:�0��_Ri����+��O������]0�T3y�f|����s�W[}$T��>��O<
w���K��������C�Z���&Q_Z�a��@�E�Z��LK���9�������h�<l��W��m�e�3ew��G���`��W�=n	��~e_K�W�t�i��?GS	6��%���3�y��	��O����M(4�kI::�&���-��o�OK<:���}�� "�	5e�gN���E�h�������O�/*�=�)RL�$z\�xU	���a����s	e��A��200�(P����Ai��p]�*p��t���$A�0Cy������k���t-�<��Q���s9�����_�F:�d�������	%�H:��VZGvUF:��jm�&4Pvo��oj=#��'�R@��w��{�J�-� ��j<3�g�Z�f��K��t�3s����*ePe��d��=������Y�
��Y`�>�E�,b��A<�����q���k��x-O��D�x�J�UF�&�;��&L��R����qvz����������'$;
/�Nw(^��}��x�Fw|nv�iU��(I���iY�q6������l�|y���J��[���*=����k��V)g��-��hP�D�t�%����i8�E�#l�&���^�e��Ep�{BeW���4��5��T�{���t������J�����Fv
������$;���,����q�����s�4�kI�o��UF��L��]v&�_�g���j��9��\��w���9/�����
��<������H)�����K���������
e(xm�-��I`^K���-�N�TZ1]�pm��a������R�+���M+�
��k�K�^������}�'������e�������_lF_�
�.T�m�ih�+���9����t��	�,V*<��Z������qo���j,��,�h����s��QB�B��8;=�hW�O��1#��A����o�H<ZZ��N?@x�4k�/o��Sx�"�	�g��Bb$��B����^O:��b�/�J��T2�w^�������4�$<�>�w��L������4���;�t<Tl�S�e�{u��,!��X�z��GGz�WLCh���1m����JI@��J1���V��R�zOV�>��I��FtHX��)�YiG�o����c^O����rI��sePr�������.�>��a������
G:����Xu�%!z��g{-���,�J�q���N����k��(��!(]s^j���r	���m�2�bD�*l��4v9'xk;X��r�R*6�f�G��b�2��e�y�[���N)����B;�Z�e��L�����g�U�u��p�!��WA��ya��#fU����n�+Z}d�>>� �}��r}����E�Y�U�����)��3��Z�~��3��^��C�Jx��4E������4��y����l�Q�\������G����^�aM���J�q���v��)���a��8�
+����"'��z6rU��U����
�q"D|��,�a�:D��fa����O�A�6�\�(�,lt
��0���2��q��r��5���DD�_�_nX�
����-Iq "c��V��9���50Y��2����P����]������F�`��W�^� ��h�]�E�u��a}7�u���93+�o���f<P������5��|�N�T)+7j
F:�
�'���c���p<�
�����b��4
}l�M>�i
F:����&^.�����x<ug^`�� s4�W���_��W4�+�`���6j���"�=��|�J�sw=��V'��J��Q�?�54�������d��2RQ-�N�`���V�}����li�+X]��[���J �EH��n�i�/2�]����J1���	��Fa��y�8�^*W)6�A< oJ��K��_qA<
t�'N�jA�I�
�h;�����#���o<�Zo��z�i=�d`�Y,��t
�Z�Tx8�/olI�T����#�?��'<����lt�t�e������|��e�
��AY���������������m���;�0t��B7�fX�}������6������(;��G�{��Nap7J$�%���iN�^�N�o�I����Ok��.�(�������v��r^�N/�u��s�x�\���&��!��)a�O���M�3��?�wH5eC:��QF��jP��,����������+�Y��CJx�������|����_/ ����?���_������(/g�����_���O���_���������
��#}�ol,�b������~��7��$f���-��~J-������G�Cf�
��Nt�In��]B8eV��O���I�=���i�4��$;8����H[!;{�O	g9h����N�?�7������o�b����	�>q��'�]-x�X�olBG�����65>0��E����
)���L3hE��c���t�?����d���p=�S��?�jB:��\�&t����9���i��m��)��v�_}����i��Z���~������wNk�Gv#��t�w�qk�y�Z��5v\���e.������-a�����D�x�?
�I��
�Ov���9���S���:�)�����*	�{�UF�Ov{;Y�
��=��z�)q���;�<h�1����������sno�b�1���Yv&�������-�
m���i�9�������P�V[���r��@��������{�U�6j>b������V�=����z����������IN?��{��,~�4��y�*�_��V�+��g�+^;��H$�!�Ex=�[x��y�����s!��V��H��s�����M>4�<��7��u���Vu�sR!�X!O:�����i:GV����\id)��������5�����4n���JP4����*��.[�?��t��c�q{�i��tN��������2�?[�y�>��s KK��O��`��s ��XP�6��>��U���]�����q8�;�+�����I��C��R���Zuh/t�+���gV���qe^��u�l���s!���\�
W=��V�X��%��u�ykR�OD3�~��
/<Q�M��j9pB�(�q�p&	����� �������/��Ua~��\DZh������� �D|�-���JD1�b@��;a~��\)�x�u-�#k���C�K1g�D�-�~k��E�b���0��_.#��=g<�~�2��y���d��1�
����������{=82�����y$#
bz���	d����[�n�4���i����q`p���,�%P��)E�������{f�;�
=����3�^�d��iz����{��d��3�������]��k���=k����@����r}��}��s�j�V��6�p�~j��w��|�y���\C�s
���5��5G�'�,����5,�n��������G��Q�@]����"5�>hY�E4�EK�h�Z*�dU�Q-,"[,�Z��ET��i�p�������������V/��{�����������EZ��{�y��u4�
4�������s�����<j� ����lE�U�a�L�gMx,��(�'�:e�a����,�b���=c,[2*}r�|��������t<�J��M�j�8FWe��<����Y�WxO��r��m
��t����e����5�����z_=}�eA��H�\��W:�����#�����P��q��=������E�[*��X�
P�M���t�������d�K��:V(��E��9�M���BI����?����;V��Wt?U��n_��w����t��	��S&�Y���C
og?����`�n�0�C���z�A������O��
����9����]x���������d���h��j���n"���=��c��.���/�(���(���>Z��bW���x�d�R�5�3(����)�����.��'���J�.�w����Jw��|"��SjE�1dWd�S:����HV^������'�2/s��}��zd�<y����4�>Bv��K�2r{�9/����'����
��nF�Ps<����{5S��-a���;]������4���iM�Qv����v]�W��i�x�9w��3�Y���N�ny<��I���*�X���
X���;=R��.��<�}w����(�hFu�t����N��-b"�����fx/�V�Y�d��/�.=�Nwt�u�������i��������%�N��\�|�g�i��x�Nk�����\�P�X���
e��q,�p��l;=��:#p���;N��x�~�k����4i��^�=�Fs�����uZ��8=�nQ���i�����=�FOh�?(���Q;�FO�Z&�e��$����2�f�&Y�d���<��dc����=.M������+t?����_=��m�����|O�z��!8�C�^�Yg����Y�;{d���
i��F��2n s�
��u��������������%s+��w�����&���D�}��u��VU�����N������&!��8 �7)��S���:������!bz��RkW����c��p_��B�� ?��v��o�.���f�j��CpOiTM#������Q��/�o�������K�s��is����,��$�';���M�ddU�l���;}�{�_���v: Ba���'7^�����xiJ���$�A�����^����1�8�k!<e���4� �Fx#���%�~�(�s��<��"�'��7��f�����������<������9�.O.���x�YX���F�jyr��B+O�������w�����U��������>~���'�<���o�*����(>/	�/���
�M�P��
��LP��9 �,�igU���I�Q�����J@W���]gT�O:�1Ur�wY;hS��7��r�t���������$�����s
�J"���1�"7<�k�����)@��-~%���p�������z�PSe���z�RQ�mR<�6V�������==��c�
|@v�Tf���+�����']���(a�
|��a�)���Wt++���Z��4���<YQ���#	�&�W
�����{���x=EFf���������z��x=��^�O8x}�T�bb����
��{}����s)��fj��y�W��M@�^,����pJ!����&����~w�#�|�_g38|���*z>�x�e���d�'��_eZ�+���p�����"��!���@�q�Bn ��
���F7x_Bo��X��|Q-�JK,�)�!^�'*�k�R�J!��_K<Z0�RBP���������B��J(J�:�_K<^-�VPwc��Bc�{����Z)��Y��X���\f3,�w:~��r�OTMV>�k�:�_���K�B�ocA<^.��
���WK�Bk�9��t���Q
���h���X��riOTMV�EZ�Zk�i�y��J4, G�4? �x��'��&+bc��Z�e��c����S:P��nt���;Q4Y�����{^-�?�S,G��VM�n����,wU��C�d�o��$������uU���]� v�tUH��eT�G:x���j�4������v*����Zj��Y��p�
���ISfu:�,�)|���H�Xg6�uJ���E t��2%��&��oS�G:2��
�I��`9�)m���o����+�4%�r�������
��?��t�����o���0�mw�1�,�W;e��U��FH/W��@����\�UG�����	/�]�����^��W�L�^veB�)Ie��:��J�����r[�����}^U|TDe����!�����kB��eY�����(QYr�M��������.�y�n+��7So_������lsO!���q�B>�M�n�
�l/��k�|�����)�x�Y�"��	��bV�Fz�3e�a�t4��!�.�Q�D��8����$O5��������sF�?���(nz��3���~��{>I7��K�{���~=����FK����d	�=���A�����T����I1��H�T�l���V��k '^*�6IWqe��������������N����U�#]�P7&�$�C�����7z_����o�#O<D�re������&�p#��9���i����]��5��%��/W��S�Iv=��'���";��r%>�r ���o������,}�2}����&/����<�wW��S�����H����Y�h��x�UJ��d7��i��QdWg�SZP��������Ex=�rx����7�{��g}�����\+�{���F�����r�����#x�w>���4����};?��x�`�^���?�xH�����DQ*)�Y��M�u�ZZ��v��k�;d
�9w�����s���Qv����)E�!��lw�������t��q��e���Qvz���+E�u�z{��rN���|�(C=���qv���,��>�hY����o��2L����~�Q���b�x�\F�_$`���w�n��2�U�	1P�%�6�F3�#�/�=clt��j��v���"AdG����.\-���Fo��#�D�}�,wu|�c_���������t����I�����5<�����P�����Gp_�3��!����gI=Q�Z�O��_�kr�R��	��V���������n� �g;}���r�*@j�C���`�
�o�/��N^���O�� ��Y�~i�'H�+���w�#=x������1��!����Jw�X�xH��!���<������#=��
�Oz��x�-�|�T��E�B�YB���Z{��-������F�������*m������pR-W5��&�p��'��sJ����I/~��#^�8�)9!������(�>���0*9�T�`�K��	��
����Q�x
	�/���������Y&�B������(�,<5��n5�\��U�,I�s��U��6|��8|�|��l�V�k�����|^�|��^5�XE���,+����Wk�7���(dI�Z���Y�#�����B�<W�:�����*���_6*Z]	�IpO�_&+ld����-�������,�>t���F������,�����T��N�+r�H������aT�L8�4��2�������E�����'�)=&���I��0����i8jW�����(�S���[W���-�|���`�1nS�L88��v��te��s��e�XcC:Z�������if��v��hy!��]E�g��:�������7{��:0�W��H\�<�'%6ShV6%L���Hx=%L���n"��%*��(�s9�����c�LN��!�%��������]��~�e)���g��l�e�n^������R�#�\C8�����GJ��J���+�;q-�t-.�����.�ng����n<t��x��J��:�;�����R�YZ�2��
�(��W�Gvx[
���SQd�����c���+��Z�2�}W��(OuW�#��w���b�T<PJ�����]�������D����pJp|�����R���M����)Y�H��S:%���K�����6m
a�7R�J����dS�
��'L}�0R� �$����F��q$���t@��N�|�6�q���tK[��?~�t�(;��ji�Lq5-,�N���v�����(����
D����S*�������K��V�{�=:%
��G����K������Qt���������Q�ZRo�"���2(%��r���N�\�5���P�J�/5};�N��\F�F>$%�V�G^.��}�u�(�g�:�i�N������D��"�_������.����\��?��������1�.������/��Y>����_���/?����?����J��W�$��ML\�5���y]�o��f��$�-7`X^��r�)|�uzZD����W�8kF����	[��3��v9�7����Nl��9e������(h1�X�3G����Tgx
�+6b�����1�lt�Rx��4�,��W���lt��eV��.7���R��Y��z����(_�"e�^-���pvom�E:�,���r�0��o�U&YP�,���)��?:D�s��IJ�Bf]NL9�J��^=��!���L��:�%��
�}w^Jr���"�?���s��������IN���^%��R�@)�=9��R��J���E_��N7�i*��R���2�P�}����������tL!lg)����[�z��F�*4j�"%�������$\�{J��-p"
���C��h��(J�A������is-
���xeN�y|��;]��/�������x0������{@������{�FJO���i�_[;
�:N������Ux}Y���U#:	�Ox�{��I(<�W�	���xS�<]x���/�}�����L��]x��ngRJ��r�������|����L�2w?w�9���6�yw�h�p[w���Cb�Y������P����'���W��3�]#ZM�$ITu�v�	�oS��q�#K�{r��	5!#�%���"K���� �cKS���:X�
�1�B:x�����;=���[��g�����Nr/~���x���R/���y��ADIK��+w��e^�x����
P���p���5nm������JA�U5D"��~6�[���a���/k2*M
�>�zv���t��"�����D�c�"z�+}�T�C=f\��V~6
�H7Qvt��B��6D$�+��lj�mo�	t�x�+�S-`��t�����WA��WvDJ�kG������iH�I��c�
�h��B�e�U�����Q�^��5��M
5�`J��������y!���J�[sm���H8�h�d7e�Zy�v�����V���4:�I�����]�� �
IB8��������f^�������!�i:@v#��WYc��%��8�Qh�����<F�f��.m	�m�U��L����\e��l�pt.#��� ���io��l��������.��x����&+fI�+~�(���^��r���
�D����'���6:~�6�x��Jk������(<Ok�lt�S��YjN�yg��,�2�5 �`��/��9�F�%�L�-�����x�����������KY�V�������]���x�Y*e2g�x?���x�T�i5������K�����V
&��&�F��X���]�������^�q6���R�}�!y�[+R�����N��
jd�4��WK�/�	(=�Z�J:�,���rW��<V��+R	�se6�������l���C��0�lj�qbTPI:x�wcE�����J�x���8�p�
�EE�i"��q����[E��YL�y/T��
�k��4�J��Ev0Zw�Ah)�6aWa��95<{^�C�7�������J/���j�#@���p-������):���}R��!�t�������V�CBD���F�A�t��/��tsc�	��9DY]���
3T��{���� �`���1��9�*������UwlDT/��}�x��a��t9���%���9�l�pVW�m�$�P��dfTz��z<(��\���D��:�^��W��	��vzJ�������8;=�t�W��6�!��;o��Z*C�M��r�-������.K2
�o�ZV\�e�c'����t[���������;�(�n<�
���"��E��Y�r��0jAw�����
����?�T����p������+!��eU:c���)�s��|e
��?<���t����m��gt5:?Oo�:B����6 ync(�P�~�}%���{���j6�5E������v�>�"�40��l����)���
�����-"k��������^����^���{F�Cv��f�bnB"�F����G��b�@=��)y?i�|&���kx��J�T��u����Z{���\���d��c��Y��)�"�@Q6Z�T���3<4���P�M��ft�����+��0����V|Cx#<��2��5�����J����;�G�2���v��2*�����q���f�V���7�|Q���~�1��'�ni��u���._�}!^Gx-���v�//O&�ie���L�oy���<e�3VX��stQ�E�gx�>�����@�t�Qx�)K���@x�FGO����.^���%�y��g���
�G��:���o�LU����n���S�L�<�$��>��J���y��J�z�F3:^,�y���Zd��R���&���o�B)K��h`F���8OY2Y���T������3<�,����4����%/��<e�d�JR�
������x�T��d%8i�+^,�yr9g�#%��%����y�T�\��)2�Ugt�X�����X5M�U���Sg<Vj>L^��)3��\"E��SK�7�XM���.���R����m2�d	E�(�J���>aF����UO��?jR[)2�B�_���)��`��NgQ�@:�
����b+����+�
�2l���Q�+���6�1)R��M����p@�Y��!����>�t���|�6~	p��5p�Oz�����^�������~%�CkKx4j����	�.l���F�tmN�}�3�Q(o5
w��k*��\��|�Nly���y�j�BS%��5
k�Rm*b�m*�{s������+�z���>>�O��q*b��T��*x���C��E��S���L�W0������d�b�dr0��T�}�����f2��y:����(��FU!��g@pO����R��L���[��IW@��p��d��*�xh�"���>�9��S���C1������%k;w�IlT��Q&��7c��B�O��e��E��PK�m*CH7Qv�;
5�V��QSRm��>0�G:���I�6�!�C��R��Ik���U�8w�qnVB��t�1�!�!��y�dJ
�d�Y�*�`	��CT��&��t<iz���_�Kxl+T�'���=�iFK�����7�o��J��8��,��i�v��2*	�J�F�������w��&$���L�_c�/o�kTpW_�����w����J��H�H����+����O)�U:tD^���&�g9���#��fSY��7�N���/�4'��&zE���!�g9��t ����u�"<��N���]x����{Z��x������iVh��Tq�7R������t����m��$�<m�\���S�?�/��"�>�����r*�b����9�*�6�R�Gx�4���_^Qpo��6x�d������}y�gb���U�
��uv�)>k���D5�dE��R
�\}h��GL��o�E��G:�	�97�B��R
�\���v�+Z��w��U��F����z����V
����ntMs�V�>�o'A:�������v����i}��lt�����cR�q���7Ks����������Nkg�[^-�����oB:�,mqZ�n�fi�[Z��8��ji�o�,~���f���jt�����������y�t���Y��!����{���`�{����Q���Oxo�^���.�\�o�!=�J�
����7� ����i�o��#���D
���v���i�
e�G�-J����[���x���iuzb�vR�0Z�;�NO�\&�6���v���;=�6S���+��������u��t@���N�&�>oMD���Z��pZ"A��fQD�Ed�[��n������+(I������V��>��5�N��v0"���e��2)J�����WK�����r�d��2��	�;�h�[|i�Sq2e�VR6\�����y�(9������9o��4T���n���qz�Z]$���]��o~��o���������������/���"}�/������_���|���_���/?����?����J��W���S0X��m�pe�����~��������,��V9j�QeE��ce��v�h��'���F� �������!llD:DQ���r�����tmJ�}�M�zZ���������@Q�P���C���uc|Dl\AD�{�����c����;o�r�����#N��u�@����{�Y��Y,��Y�$��;#P��=�HQ�o6j
J:��
��K���@��7�0�P�l����M

P�.��L��������&hY�%��V}�������L�R�uaX������]{�9�^}��+���������;���l�J-�M}����L���t@��1�C��I/ �c������@��iG���FB��]@��Xvxx�J�Q�"]��.O)<%aS�����F����l��t�T9�
I$�����v�<�'�7���xo����e������{��6K�;}�����s���S|^�j������V�����gmq{���t����H����?��Q�y-A�>t���x�f7Kwk��U�?*�
Q�2W�Oi�����9V����k�X7k�	���}��V��l���#@:�����H��5��K:�������X;�=Z%�^�����I:*J��M�'��t�%���%�y,=�y�+���qOc��?���~�����?M����@E�����x���e�N�����Qx��[��];�����OU{�������u��=W<6vI�����|RZp�������_2��K��t�Z��
v�T��9�&%�I�h���������8��u���S�i�����#�.�>��u�^C:��I6D�8��	��k]��
G:%5U�5�^�������x���%�6{l����f�@���/6���t������CJ��#<m�y���{1�Gx���?�>������"\�{��[�!��BG�<J�����'L�)����;�;��U���A�}��N�����:�O�j�vv���`�a�
S��M:^+
���s�F9�k��r���>��U�����3�$�����'�t�U�&�����[�j�\�}�x�t��<~���V����s��J�D�V�E�g�����a[����k�n���6zH)J��E�������+��pN@��i|�x��M�=�>�	%�����y���f��r\lk��x�����]�Z�P����j���2�M^�bU����#w��8�y�Q��*D7wc���=f��g����,/���:���,z�B����d ��A��&�F�i�Kq�
�k_�Um�&#����bY����n"�2�J�3�M���
�)����Jx_)l��}c�>�������e�j����(s���2G�y<p��;��Rx�N<�mw:�CSx};`����^����x0
��c74��X�:6�\��������a����������<e����vF�H�)��'���*�������`������=�U�u�G.E�dQ�<}����Z�Qe�kcy��2(�������m%H�����l�^?�@����� ��� q<�O���Vy�Z	R�>xK��4�<��^z���.�������Q�cF��C��0k��I�D�@"\K8�Y#
u�v����?w����vk���'�6�,���X�D<�gg�?inv��<�;eF��j�������*bW �~��r���T��!�_�����%Z��Q����9�0=��@��Ke�����6H���g�_#Z7u�$�1�!��6�^�Y ������r���G�1��Buh\��h��}!���h����d �@:����cKm��	/�,j�������O4��p<��tmtm������O4����{���8�(�+0hNp�#<�0^��������H�-�_m��xJ����Ex%�}�<��}V*��Z=�M���t'*X +�����RK?l��H����0E@X|c�3�����N��5���B�G�}�`	��������}�
S��369%�7h���(����������>sl��xr�`�[GI�[J��Q������;�}pm�����V���.�$�V���e�;�*��sH�@�t�U��F������?�H�t��s�[�SFd�m-@"��>?�B�H!�L�(=�Z���b�to-@"����V�t���<�F^+���W@���$��Z?������)lBVZ��|��-|l#���OV���SA���A4��M�� @�}���z�t0��������N��y���[!���T����[#�z!O���y��X����g;������o���!L�Iq���)[��O����ti��0�c�Iq��J*3�C>����.���?&�{��c���k�F���?�x�����5hn��	��U��/�#�H�i�-�l�:���S�D�$��B�����h t���V�Iz}B�)&A�bp�!���=���*�>�i�Z�
��R�����op����U���
�,�>���0�]@x=���}�:O� �&
���K������S3X�V3�U���,+�$��������5���2�qlYu��]�pk���-?>��S3X�V3�U<:�o�Z�@�$M�k7�-�W�>>[oK�yB�=���� �J;o�3�Q��r�9���M�0*$]C�E��:B��F)j#D�j#�eT��w�����z�U^�t�`u��9�>���8�A�+�V��F��A�
�;Q@�%�?+�W��z�����x{��A��^A�����h�%/�B�y�l�I7��Tj����]�H����Wv+���*�:[�]U��r���rv�h�	�u�,��	{8�m	��e�����v�Ku��H���1���2��^�oSi��jl
�H�o��J��^����hclj~HG���J����"�!#�R�����"��6��4���W��G'����Z��(j;&�S�K�/����2�C���4>��hi�Z�4~��x���x���<9Pm��t��L
^��ToR�kY�q���lR�#�aL����Z��M��#]��:�>�'{��	�����&��t8a�C��RG�����0b��r�(����!���S�@���D����g����������z�6��y��N4��YNI�{��'c�}�x�d~oz����>g�U�M/+����_8��s�[E�)0��x�s�*������H)I�S]=��s�[��?VB������Jq��e`-���tQ��(]�Z)����an��f�)��]t��)J%�!~�7�*�+�bwt%�y+i�{��N����t�{����l�&����^�����3�q!!x��|�7�6������Lq�R�����8�������J��^C�$�TZ](�zq���
7��g�n*���� �Rp����(���:��<y�@6-�Z3���`�Ep_k�G��{lnqc�	��N�"��!�(��i*f�������GH)2�Gp7��,\GD%�'��"��Sp7������O���+�I��lB�����ca�	�o�����Hn^�����9��8sS)9��(�;���e��,��=L����}\���)�[6m�H��Xp_�3iSD:���{J'GYN��f���]��z\*�I����C��WCz�g�C��Z�*���(�v�����t�n�Ch�T5q[��QzJq���#:�4���YKx0������[�,�n��h��=I"	��)<����	�u�2�P�'������z���0�Y_��p��D���������~�	����B�gq�{����Ez-Q-R�D��h���g�Z,_�������C�����C������<���C���=�d�\uj(�>���w_�������S�~#��������jJmj��8�9������
����������$�i�0�k	w�W���6��w����Mj�Aw�JR1Q���L��J`��L�����b|P�O�����,>x_����n$����dj\�����E���)wI�=�MZ<���.$�35NC�3f-���T�h��&-ft#�2�5R+n��c�����*z��u�������
t�'��>�_akd=	�- m��� �)��"D�1���kxH7Z�����SZ�jS�L�_gt=������#�6%���>�F�E^K+�U�4x$���S�@mW�mi�JDz�u��Z�S�6�*��:�n�2�@��G�3�y������Sw�]��Ix�E~��	��SG��z^gZ+��/�"���������;�:��SG?c�3�/7�����cF�F�LP����t#
��<C�g�4bF���NK���#���v�f9�3m��<C��:��4�Xe�'^+���R�g��]Y�y�����s_�_�|���5}�����./�t���\'����Q��>G��1��� �/�E������s�Y$�IF��1���P�
����XF?��� �'�����;����J���rJRKk[�h���x�d���0cETG�=�1�r�+JX'��6M���s�s�z�DuvA���\�������/aF�{�x6=�%�������{"�����i�u�� ��$"���B���|d&eI3:$��+teI3:^�}w�;c((I���|�6I�3<d	�/�l����������vz��;�r�N���s�����z���VR�?�[m��$��	��B�8�kT�
�A��	
�Oz�'�/M(=e<y�I�3<����^�I�3<��{�MGJO����*o�DF%z��q���<���/����������r���������o?���_���V�����_��������_�������g�j�I���J��W���ylt����@�ZD��a�����WR����ly��_\�[Y����^<�C,[x}���
v��+��L�����Pb+���������Hp}��^<��(<�m�b��)<�-�M��#�
^��/�z�Xxq	�Ox{?$v�l�.���6
�x6�������$=d|6�����'Q�7��y���n��>3>Q&�f�2Y�</=OK�2Y_u7W�tsY�r�l�4��������R������?�oxG3��vL��*/�
Ou�^�����YV�g�fY�buw�>x�B��
zxvdI�z�d��P0H�h_]��
kTJ:]�?�/Urw���I���p�.Y�xOa���qka(�Fj�����n(X�6z<�:RGn���x��?*��v�c&K
�s:�5��&�g��|dmn���a���-'
�/z��X�M<lt;Yx+����iKHe��6����t�F�W��<�l
�A�2�)%p�h������{�Y��5"�O���������i~?�viIZ-�}F�q?���M���
�KH�����d�1Vx}���k$��t�
�#������g�[ PxYF:�{���c��������z�)�����<%��[@PgS�M:*��i>@xHR^�I�M�|y�H:mjE�� �+x��J���n�H)����J���ji�Q.��R
�����L�L���8���Rj�J�� ����������\v�d�����xWi�q�F��W�TQ���uEx���zwdS������7Uj�*�f�����i���������{��*V/�:���|Am��7,'���}N���-,'�'I��?����;XnO���9�>.��oEI���5
�����&�vna�8  �>����m�������D*�W��x�
�cL+��#����RR�j�|��
�idG�H�Vv��0�M<QF�A����hM��������I����F�)�-m�N�����)ef���g��W���ZW�8�H��5�a��K��d��E�{�O��,���m����#�>��=����t"���s�{�w9����������������)]��m�A���SrP4�(��|e������������|�Ce�E����v����"�H�?Q�>qd��F��WO�����i��~%�E���
�(�V%��0���(���r�����R�-��	?[{4���D�}�%�ME��b�&�m�Kx����u{��<R�J���be�}fdQp���3�J�1 ��x�Y|�+aF��g�e��jo���5�Tz%��Y�����$�����6j�	<�s����'+\��2�I�/e�^+���>������ox�4'jOV�Mx�>�ogM:^+���<������J{����s�������Q��s��wp/o�����J}w���`�S���vQ%e�{^+���|��6����J���d��Wf]�og
:���J�T����x�����g���?���'���#�%�C}�G�����x���dE���{�yw���kEI�P�Q��	�{�}����W�?4�{�}��2�[�9���qA���Sn�� �gP�A�`A��\+������x�9fIx������=�2t���)6��W����8�9K�{��v�����zo���p��T�6z��N4��YAQ�_/j��(��b��
�U'|[l��%�=�>3UcP�.�}���s�{EI�8����c�������A��v��������\pn�s�k�(O��eBI�_/��>����R�������*p�=�>O�������*�*JIx@0�x�+�*����	��B���{�yo��P�V��6�{�
5o�����C�
[�����>����R+�����
��&9�B7�+x�F��kx�4J^��a�����L���i�����}b-����f������K;�V�;TQ�g�w��u�X:��z�pF����O��=�������z^,��� d���F�f���j4�q�g�ww�q\�����?n5�f��Pp������l��^1��f�
�^���F^,w�9���SJI��/��^�����/)�g�}�x�L�Y�yL������{Q��`�������>�'����O��G�]�D�}\���?���������������e��@Y��ow��OD.)�G;��,@����0�����3-������Q�6������,���N� kDpg����0��0��[Z����C�HG5����#D�ez+��(�	)`��k���� @�Sn�w]p_��f���6'�l�����8J��uy��p��O�A�����  h6
����O�8��t�
���.�mtV���|��Y�����.t��g��D��n�?}���l���_�&���v��&x�ED������x��m��-�dE��t��s�&d(MJ��O�%]�0�Yp_oJ�J6���r����s�Xv��7�r�����KS��_��o��Z��p=���T��^�)=�B����(<�#������|S�<#����r7^��,���6K����0�U���/���*�V���n��:K���l~�!�������g����?�-��g���~F7}~~U�����a�{��6�������NG�!���!����A���
j�!�do-��M��J�!m��� h���x���)m
����]s��g��`���X�fh�$h�����o�k������{K�}��q�3�U:S���h;s�}N�k��M��'��������t���j�SQz�2��U
t'_���%9`���j�; ^*���u�m�������%�Im3�tcB:K�����n��[S^e���s�����*�<���NE9���B�-n�����
�
��2��v��H~���.~Ow�=:�o�>���N	�]�H�w��/;����dg7;%Lg1K��{��,��Ov�g���7��|w9��:K@��:���YdW�8Q���T�U�"��]��t�����
x9�BU6sH7��D
0�Zf�geFN?g�xxu�-�lr�I����s����TjX5�8]��.�/�����-��DI�`�JR�g��%���kSx_h�e������j4C$����%��kx�(1��V��f�Dp������J�$M����A�T	��=��l4�$�]��l����j��$~�-�:�,���Pak��/��DS���B��R���/�%o���Y^��e�{^,���b�����~9�y��f���r��Z���K�y������%y���<B�X���=+�]�(v�T�;�e]I^R�g)��,�!_Jpg, ����}��F%y�kq����� ��$����
�v��<�u	�O�JgR�G:xZ������x�uP|�1	�x��������J������3
������=^"��n���/���m�1��� �\��x�q9�\(�y���:O�
�
����$�,�H��W�d�u�x.�z�t�c*�mYI�Us�d6V��g��P
�����x��,A������Z~|���*�|�*���,+����x��!l���%V��
Y�<�9�ef��F�^�A��L��Z��g�1�.K�X�27�b r�2w"���x�fJf]�p�������8��6h����tYN�QG�q���g�@�E�s� �����omC&p���%������_~��.����S[re����\P[r�FI��K����������,y�~�w���2��m��{=*^�R���S�����W�2��Uvu� ����*�(el��m���Z��M�%��\�F+V�MZ4�xH+�h�p/������>V�������B����������iv�\��u�u�����Y�Q��h	*����������b�$�!#��%���j�
J�Ok�f��O��t�=/m#R���(_�x<`F��:��&1�t�N
�97zJ(I��m@$�v�'Z0�?����������e���F��4)Y�i��G�<�m�?K[��c�sF)���'��|�����6�K3�R���6�C:���s�S�P����l��R�Ri2���t� �����W��D��,�(�>��q���p��97:��T��bu�o���4-�7zk�6�r^,���r��]>di[���J�����;�*�80P�R������:��~]�q�\s����W�C[pg��u�gl8����Tm���j?��
���=S���Gr�(>B-�h��M��t��X�3I�m�"��<2���^�"�*����I�������`���
:����
�=U�v����pJs��2p��f[�Bi����I�]�(<[���jc<���1�W�V�)t�Tm��}$�O3a��#�|���;�T����r��W�'\��3J��-��r?�j�����|���|������3Y���O�-*ORv�[R6VQ"�O��)^.�[���7���
x$�,�uz�3��-�R��Zii�&���C��������QR6�8:@pOb����2B�Zv�lM�$5��[��.
��oL�]�Pv���z��l�#�g��6%��)�w���'�eB{N5f"b�4��_���P�4��1�x��u�v����
H(�n8N��M>6��-^���M>6�����lqhe>v�_e��K��;�nh��9����:a>�lve�-�rDH�}�*s����0��,Z8�?0Th)�6Y��C����>M���aw�&��g�Z�v��8��';��Iv5�����]X*��T�j��:���o���L�\OxM^��]K:�)��w�&��Oc��L���YF:������%�>��W��<�J:��������e����&��x��K�VY�m��D:0yq���(I�`%��Cx,T.�Beu\w��f�ryW�|��.A-�r�T��(]:�R�j�Qv��Ix���%|�����y���x��J��)\���x�T�uj�"-�>�W����n�M��`e�k�-�tZ����#����_�C<^.���AM����-����U�����X�
/���~��r.��,r�1\&��,��1�|k�oB�\i�8��~{�??"V� ��8qJ���	��5�Te�+�z=���� ���O����(��t������d�r0��MWJ�t���� '^v��
�I9����S�g�)	��4��6�����b�$�r��e(�'� k��Uq�L����v����}b�AN:�U��^�w��I)<������M����ov�}��������b�r���*>_�j�n����r%K\���R���M�x�4��*���O�����7����sB��B>��4��R����~�����VU�t�M2��*���M#-�����+SO=g���%��B��Y����������dJ�����}wsOgt���0
���B>���Sp�zRK�'j��x?w���f��o����A6)�38^4�'��x5����������fE����7I!��a��YI����3���iOH��N�����v�5�z����������y��R���x��{�Y��I�k���M�
�=��d�i)�&Yv���*�G�i�>���Ni���NKy�#��tJ���b��9��!]�
��e���(�>����<�C���z�Z�s����wt�>����t~����]W���dgV�*��t~'��:����?�����"������t�u<Q:��i�W�N\�u�@����\�q���zd��[F�]�K�LX8@v|I����N{g��O����m�{v�����i��M*Pft��
�9�-��[JD�E��L��������Z~�d<�����s��H�����r�$o�q:j�4�wH���.�,���4]�����>y�;�����
U3Xb�t���{�>�N7� �/4�X���������<\.����_������.����\��?���������_������|���-�>������~�������Y�������W��_���H�t�
��g�����W�������DW�*G����*G�"j�!��lz�;��g(��������s����Tl��g��|���i��|���)�kAp���cBI*���^s9�CpNx=Pri��#���<��f�#%��g�4��������P�F���7�t��L3V�`����+.��&�������(�4��6�F�)7�M��������������������snt��������2�Gx=�m�T4������h��{>+k������8�i�c��*OB&;��������$�
C��"
@p��^p��aR��@NB�S�}�,�m���u.�F��H��g�n���34df����M}2�rG:6��9v�O�1����iM��gt���l�E}2�������Ye�����P:��Lm�Vy9��"���e� �>���$����]����X%?~�KDw�Rk��r���
��]]�aT�<�C�����{Ix�k���H
��&�wuJ�)��!3�m�W#�Qx_�=G���4��'��#gx#��5���A���4�xMF�}:Y�\�����S_[�#��`,���M�dY��U��<]����R��Vn����l��8:�w-�����x�)�o�*��*z8XdY!�x��������T�a�m�%���!]��Ju���N��V������<���Ch�Srm�I�.�Fz=����������!��R�e�ak�.��Z�
z������{�M	e�th�q��Rc��$j�'|+�9%D���}3��	(��T��iz5�SGIji\+Cs�{*���p��K��c��{@���Z����\9�-L�o\�1�Xp���^�4)��V�l�<����.KI7<��#�����B�	���?]�s�P��5�M
%�� �����d��N��O����n"��5��������K���eW�lV<�Z�j$��%'�>�E��]�������yW��Ip}��������t�����3}�����U�����k��z���"O�;���v�S�{��G����^�R�Jp5�e�9�\x���d�+���,�|�q�y�N2�>�i�/{7��l;�!��k���eb����i�����21���Nx���=�F{��.�_&F<^.�6:0���V�Yd'������^��;�"x���D�l�e��wSJ����Xd'�������?K��by��|1A�p�!��	��1A~���'#�	:�����8����:�L\Y����W�oZ.x|����;���S��,f���Qj7�p��<�;(9�*���x>���\�6��������t&���CHnO�g�,��W,T��A�Q�'��W����=���P6z�0��9L�6��;=����Zc�?Lwzt�U������-]�t��	/���Lf���w�����/�P<\x��B%N��	��4�TG�^���p�E��b��I/@s��7Pz�?d����
G�)�oP�a+�	2���=�_D<����'�������(=%�6d"��������������
�Oz��Gz������Sg�D�^�RzJ8)�����*����'��o�
}������8��(=�����Ezs+�>�������Qs{A�]z���9�!}Am��9��6�V���#=���R3�q������R3�����FJO	X�4c��^�QzJ6��Ez-�U����������W��H�K(=�A�6�Vz<���
^���'�z�K���N��Rn�{��:�����Vz=�{���#�K����x�����=T�Gu�{^@�����F:��Hc���.t�T�y���*�W������={�������<�G��M]��K�]�[I;V���,+��+���)��������^<�����g-�#����9i���v��ZXO���l\OI�gR�N��p'�>
�&��{ja��[kaIE\O�3��X�N:h�;W����Xj�:2*V��j���\OI�VooR��,'�����������1��
�+�M��v����{�74+w-i'$/�\y�h���%�a�\d��_#Z�����p��	�/h��L�+i�j�.��:'\��IW?�\sDM�����	��>V9�j<A�����3�J�M�cIW�N���+D�]G:���l.p�r��H����]�x��p_H&�"��]���k�qd�cgK��]�;l���JH�����Uv�Rj��|�(�]�����_g�;[)3��l�(�]���������j�(��&sZ�G�u���(�wH���dg��$PvM:%@�Iv-v�Qf�kyqd7���b��=���Ye�����6nk��~��H��/rZE�u<QZe�W��;������(Ns\��]K:��Gq���_=J3�%PD�z!�p�"��'����i�qd�WO�� ���x���W��r;���m���h���dGePl�,z_E��FQ&
���w#�(�b�h},��n��g��Q����'��G�zuE������7�_g'�Q&����_���(���r��x�(�"N�'Cv)���pO"��o�>���+��wi����4��.�gVp}��9^��xm�Gv{��iZcgS�k��;�+��'��Lp���;�
���]�:���{�u-��XcIv#�������,#�����]��h�q�=��x�)�4���q��l"��&�5�3���K�����Z�����V��gSt����o�f�stEJ��F�Jp���|)��w�b1�pI<0���G+~��e
���r��v�K�����Uy�;]��)������;=Rz�6��v���TJ�5k0�NW�Z*�����,�NW�I
�9w�v��YE�]��t����jEvzc�q��r����4�[R%�%�,�8;��r�Z]�m���t�������v������.���Lw�
;m��-/��|���tK�H����^1qv����*%n����Nw�\�MF%+=�������^���S�(i��8;��r����4����};�D�"�4/m����5�==�r����������v:����N�\��M�im�y��iuzD���{D�N����LP^_��e�'^.w*g����('��6����/�I�Z�x�L�Yu�%��V�1j��;���S���
�c��C'��9w�Xn�����G����������lv�Xn���i�Q������G�������#��,�`F�9w:s��`-��������vz��m��/��<�N�	E�<X��}d.���+�X�eo��N��\�M?'�DQ*�bo�+x��J#�z�sb��/��^<g���;����}d���Rhs�|d�;]�r)�iu�=H���{��\��EiB���>2c��x�T�iuSJn�Q�{��\��E�R�
�����Ku�����TG���#s5/�Z�������nx����
u
��������^.�6Cb��A��ri���t�^����}d-/�V��w��ky��g�K=�.�(�gL�����������IQv�����h�6X�ED�};��������	��d���#"����!�(�g�:D.�N�\��$d���N�����s����T�1���(;=�r��f9��==�r����8R��3F�e�'^.�Rb2��V�'^.w�`����M�,xY��eR��-ot�Qj��/�����?>�\��%:�-�+t�����~��~��������(+����k{���%��������|�� ��1���UYX�lV�D�'NI@��[�{S�H2�{����/�)���8o#L�y�'�����?��H1Oq�
��3~K�,f���`6������2��8iKD�)���E�E
�Epg� ����'@��z��
w��X��c5�q�bV\��Ah94g(z5�����Z'���q��1�5`�;�� E.�[�����R�{����W��.���e���l�|��}�|���]�Zj4��xTd���fL>�������������`_1�)�F�	Z{�g�u��.��.������!#��������7Qx�$�5�2m������&�q������q�cD�K��DL�.�q��R
��}�_m���	/�Ii�;Ax=���M�f����e����6����!�Ux7xM���b
��P�Y���)���O����^7����H���3����������FJOi P��=���F����(�O�����o�����h+���������a����?�������������'S����~��w����_~��"M��U��d_u<~��S����~��7w���?���7
�I�?���gUZ�����o�������?�������x��w_~�������z�������������,���nq������y�V������_����|y���/�*�@�r�?�:�:z�G�m�}���@�!�|B��;w���z{kd^OCo1WA����K�B.�|��!��A��.�����|\'��������.�D�����SKF'Ke�ZZ�M�*��>t@�gf�zG:H���q�$�p�iB{G-Y���ij!�m��V�tL���tju�?�v5f���e��"A��H�sPr�wW����P�Y��_H`����Cm��Z��B������q&j�p������'L�gF��W	_^��@�<,��W	��w�_~�u%��X�W������Xq��u���o�J���>9e��S�r��>�b���YCX��h��l�c&�����3i���Ni��]!q������I~����N����������O�3j:�+������S�*#P�3i3��t�����k���P�:5k�&��xx/	�'�~9��5��t<b����]N}��S_n��'�@����=� ��a���?-d]����J~t�	.�jV��B2��k���O����,R�!5�~�N�e3[e���^����af�,R�9G:��S�L�HI;OpOy��w���"���H��%���U;���"
��m������x�F��"%�DQ��{�!�*7�7�tyF�}������GT�|�Z���Q���Z����
�K���zy��Q����s�������E9���)��gCG�R)��r��A�+�H��(���
��A�7���a�������\dEHF�=�\N��]ME��A���M��tp4�\����qdT����qC����m�����w���`m�(�2�|w5n�(�r������$�p�w�u!�N�.Z	H����WF+��C�����)�M�p}B8�����V�J���Jp����m�p�BeR~%?:,X	�V���K���f��9��fZ%J��Q���I������E�(�E:x.�'<%�$���)M@��K6V�
�S��/�O(�]t�#��-�=���{���8D�H:� p�/�e�[�s���1�<CKp}��R^��'���rZ-�MhtYB���&+^%���o?O<�J��gR��G<�1Y{���s�R�1Y�o?O<������.Qv:G=Cs��>�N���W7�U������R(���.Qv��[Ix������o����'/-|������%/��8�N�E�U��o?���K�j��(;]�r��{l���b��������W�r��,�����M�����v���aG�?����r��qG�^�I�%����n�K���j��V�i��M� x�<oq����Jj�4cT�Mam�IG�^�3Ij|�kvS���e%���r��7�#6�UJ��AI�Zc&��t���4��<]������6:~�B���^�F���G:���'��
������ ~kL�!!�>��oPH<�#�w�cD7QxJ<B���#<f�����o��y��JB��/��x�����5&�
^n���P��^K^x}��C
���%^����'$�H�)�!!)B^H�"�����OX�E��"���5X^dR�������O����������E6��������~��y<���?E��)����]6n�.u\���3�G���z�K]�>x3���4<f~%���{f���E_�}�~[�����l�A��]��|4�=������[v���&ctMre�t����������$5nT�� ��������"�u�#���D���:�8���-�k�@��$��L��X�A<:���e�EX�X��@�|�
JF��f���t��
�A]��6���~�]Y����4��d�)���Vp����Q�����V�,��owE<��SFx�"z�:�u�;��r�����rHGS7�<��
�)����JxM)fVk��'�6R+��"<&kv�s�i��W�]m]���N��L��8�C����gW8&�����6o�ev����gV8��eC:�����}"�D<�'����@]��nznW�z�*����T��!
����x�m�l^�(���;]�B��r�* n��5/�Z1Q�	�+w:����]�Pz��������6u|t
�Ed>�[@��v�d��/#��j���D����m��mNQ*��������
�jm=��6���7Lk�j���.�(���\�o���S�lR�I����`�R�����",e�)�]n�?<W:>J������uS�e�d>!��&m�t��Z2�Jg���Z������D��<x_zU�^��Cx�W�G�������M=�)�7<�:��7�u������x�GgM���T;mM�$,�^������8���%�>[:�ts�
����WG�G��������$�oL�$|��]'W���ys�'��X�7�p'V�O�tb_���>]��E���P�Y0���>�T.�|����}>jR_]d�I�TG�:-��)M��Sp��|��^��+�d�4)2�x����]K(\�&�������*a��M���\�{[{��3�����eS{c����Tp_~�oLw����i��������k,�g����~6���N�b��8��j��`leD=���E�Gn�����l�w��!�Px�-��N�;r�����ZI��wTd6\_�;r�#�����
4����Q�����1��X��wi�>�!�2=)���LR0fx���������$��.�H�����Ex�����Y���;d�z�i]a���(��q��Ox��g_��;���kp���^K<����S6��|$�eGWSKk(��%���.z��
�������w��3�t��N���T:8(ul�v���Xx};�w�����s����|�|�����J��RjF��
I��{����Z)�1gM���y�TZ�E@C�mIS3<^.��r�;]#�(����^.�?����6I����ni>�����<yL�j�|^���,@�\iXg"����RDd)�0���h�/5��{u�j'U:�|)��IJ�������5(��\��
gx�h�}�0	���<���.M(<�F��o���A�}�jk��n~��lt�~�3:8�'���gx#�����	u���u)��i%�q��B�Qq]�9b���K1j��ZIj��	��O��_m��\����Z������b�$�q�7Rz�	�v�"=V����R���9��hX���#�1-oi�y�<�1k��f�uY��
?w���L�:y�"���$TR��n�>���|�1����f��>�����}������lp���B>���/v��o�{\AM��z�}2y���q���3���O�M��u3:t�\_>�r��������X�����#�DI*�'�}�[�@�f���~2 �kc>&����g�qGs���{�q�����cj�1M�1	�rw��h��<;����j�#�Gp}���k�&�x(��y��}�19���k�'��I���}��R���cn�-2h
(��[��Y%�\�*a���K=a���|�G�)�(G-��5��I�",/��%vi��&���H�b|,���%���Y�@�9�F�4_���Tx}��.j��	�,!����eR�^�@����g�C1���x�dJ G���$��xJ@�m�M2+�8�KpOiDO9^#�6�Ky+Y%���G��P�.�$��p��e@��.`s	�o�������.���^1��f�K�&��6�g�����eH���-�������g�'J�<������v:z�/�J����Y����:��kb�d��f5M@��v��cv�B'!�Vlw�=f���g��&�(���[dl/+�/g�lM[&�����wi��!m�����sw������g�s�a�B�������$����l��I�]���t:��e��@��j �IBm�A�m��D�����>�S[U��-��q�o�'I[�K��mt�N�3����j�j��G�5�S�Tu�x�
��	�C�(�2G�)W�VXGxY	�e~�G�1�� �L����M$�M��,Vm;Ex��u��	/~��jO���&���n����\���(�C����vV���WBzw]������e�i�ZY�������c�
�>��������Q�����Z^��|yah�p[.s��]U�(>Oc~t��G�yr���r��
Z3�ghQ���S�^�e�od�������'�����F9�`lR0�J��X������]��JJ���$H���;Q;��Bk�Ih����5	t-5��[hj�
�\f��@k�#����z���o3�P�=	J�k@���D���%�7]s7X{�G��;�kqO����8��lLe&
����x�]S�9���+^�Lq��Le���t������$�l�d���2��:��Nb=n�!]:_&s3�9L�i��X�d�z@�d����������kr
��0p�}!�Gx�0p��	/z[^���K��yh�z��	��-o������
�4_^�O)5�����2�IW���2Sv����xZ}x[^�-S�i^���<4@����gW����s���`6G�D<�����D�/��H��v���/���Hx=��2���J�d����{[�O�e�To���J��[���
��6i�1M���kh�j��y@oc�7����s�t���Qz`T�[��DQ*����L.��ny����8�N��Zf6�w:~�j���&���^1s�f�;G���"���	�o�2�lw����)��B+9���=/��DYdE����v:~N?�x��JEVH���������(��]�V����x�\�����x�'���H������*<��4��;���!/��DY`�R�Ry�����x�LJE�r�E�����o������2����~�B������b���rW�sW.�?��UA�b.)����?*�K�8���H/��r�:�i�i�������s���g�5��W�oo�|b����y<�;O8R�#�i<��+�:^�__��N�8�1��Z,��0�����`tmB:��P�L
IG�m��ZU�E$V�}e	����z��C���j"}���=�]�Qx�s�*;~�;�(���

l7���'����_�D:�|��^������4B�b\��D�)�ju�I�
������Q����%���P~���?/}��P��U��*x���\jJ^�����J�*�n+(?�	I�]�K�� �<2fI�II�PZ���.�^p}�<~��h,�pQ
�IL_�v�d��5<�[�@���1���% �8�����qu�g)����z�~�7��tJ�M�Z��P9�kG{65f"v��L�_�1�������X�C<�e�Qo��{���(	��4����X���%�W�������-R(I�V�<����H.f�
��>Fp�3y�b��}�(��_�Q�'��������xMr�A��.V���Y�Y���Q�,:mt�M%�x�����/~U�����\DW�UB�}ymF:�����G^�S���e]^	ec�=����	���GL��ixFY��������k�����<�N�4j:��	����4��o���P R����������'?+S�b�����W&��g()i�{��f|@�W?Tb����e����"��6�q�����V�G�]G����{z��2����K��['����n�K�+������[/������+���_V�K��yA�z�:o(w�M��`V�+t&�K�����)��wn�����m���:WF����l���n��N�o�uBV��f]G�h&�
�g���['L�|��{/��-��7Px~+M����q���T�rG]�����1�C 1�\�jS�8��(<%v�����g�t�L�qQ��v�������7 g����[�(s���:#����^��2 gsc�!�hXu���?��.�g^�`�u���Ud��*x�t�
��"��sfzS�����?����V/7�9��SO?������x�Z�Lwk��U��������WS6/�V�oW������@o��q�{�q����Qk��?)�Z��n�H�<L�-h��I:�A�$oy��0)^�I�U&�#^�PU&�;@md��I:<w��aM��(r�fd|�{VE.Rx5�����W��'G��p'*�����i��QS�r���r6fd&����t�fd������t.�����{�P:Gk�ul22�����T��[����W�]���tHW�'�LuDF&`k�r��|��P�h��.�����n��4��8���S.�<~�\�M���
��4��\���%S+�����Y�����0j�-�t��t���<&���n��#��m�����/��Z�m���m���Z8"���%����j��Q���S��^x�f#��PQfOp�q�T��O�T�%R�������!.Y����Y���^_�)~�k�
)�7�v�^&�R���.#�4������2 �m��#o�;���vz��2*WK�M*���Jx};��5�FJ�=�NO9E��oK�lwz��2)Ie�&����2�g��2�NO�X�4 ��t�/�~�i���&S�����s�t�(Jm����f���Pg���Ex���.�(��.�_�F<���;��7�&��=�NO���������K��S�����:��_f�[�&�������krM��p�7�]�N�X�S���d�����~^��F��F�%��*EljtH���R������>t�=�IG�z�8�S�3�Q".���Q*uu����,���d���S��.�O6�>~�������Z�8�&����W��d��O:�cK����E%��&
����RtL'.��Z�8�c�r��c���������]jy
q�7�I4����a0Q�G��������x|)��5I�Ft#��ZW��GS�K����20���2)�j�d��pQ*�w�m�$���S�K������z�PY�k��
#2�y���(����
��	�/<��d�*>����h������aQ�������~�Z7P}>nouY��.�v�.�*2����~�M����JuY�>x�R��wY��	�'{��1�����k����RH�\p}���R@W����;'��B�A*��Ir�9��*�xT�B�uQ������}��w�����\��/����kr�����oo=���s�qEE�?��z�>E�������2��OQ5�S$FO��I��2@�Yx��+��]�T���J����6�edk��w�(	�V�e������;����L�JoW��*�xL>^_��Y��@�����t�4�
��������4��M���i�Q�or�S��4�������Rp}���T���n��	��&4Lm9�]p�r��	�����{������m� �"�gQ�:�����i>�_^�f�S��y)�D��^xM����fs�=���fs�Zi���}���������+&)��4���w�A���YBQ�/����4��������X���s��n�y�dJ�m?�xyFQ*wK��$����O���t��Q��\r%���?��x�\
wZ����Z�j��/g����QdH��t���<�l���%���v�F�����;��2~�?�*^.��;�%
����R�����W���~�y]��[���%G������p������y(9J���#�������~^5 �%Guv���R3��(�&�2��b���#^�U���J���G�f���o�@f-GE��{w��B��
�}���^�U�sd�
���L1\l��H�����BgR��1/�=�]���/%��	�Q���JbV��M�$�H�y���w�,�����cqv���Px�gZ%�u����^��A�U9���(W������M��d�q	�}���$:7�g�sW�����4K��3��f�_�~��]�����������s��
�H������{-��ZKk��IRZ��������*����o��Mi}�%]��Na�4��}2�����'�u�J5��Kz�3�1��x}BQ*�V�O�Ir��V��krv�&��J;��5y��Hp��������7���t(O��,Vof��UdV�7Z�zHO�m��3<�Jg��b��L7�N'�TR)Z�?����0Mf���>���0IO\�Z��_�t�]��^%��_�:�m�	���6s�U�
��sfxps
��3���&��3��t����>�x�*%��6@�$�uFk���;�����Z�f �����F�)����$������]UI������	/z������2�%�U%&Vt[L�;O���L�x_JJ�~�3<�f�J�LZE�V?��S6��i���o���;��!7�U2f�*z������;�����t@C������V�����gxx���y���$���s���fx�\%���^�1���r�w�t;=Q�J���^�A���K�$�kSjm���x���I���"D+����:^.�?��^����:�Zv���wK�,;�H�3����E��*����seb�o_��kq��t��L�t`�����Z���K��^5I���!P'���Y$������S�(���U�}����gx�������m��k������M���V*�v:wdU�a�	q���q:�O�f� 7���/�������D�)�{kRl����S���6�Q�W Ox
N#<�	����H�+SJO�?�_sK�p��qRkIz��J��S���o8���ifj��q����V�h`�+��J��b$��q�U��u�{�2S���U�N)�O_%���[Zu�x��K��j)��YD1[���3P��Ug�%�����l�B�����]���]�d�Ti_9�{����
�s}(?������O�����l<t�����>�u�Z?�4�\�&���t��%K�'��uo5Jtc��z�^o�ta���=�+	���h��N��t�����7dE����RWf��
����+Uyj���u�!?Nx����G�G���?KnM�t�M��>�F)��w��|d���N��z�"s�U���
.�1e�x��\��S�����'|�k��r�-m�P}F��Dp=ysJ��M�:���p�{��
��u�A9�,)��e>���ojMTm�7�����.�L+��IY'�@:��*�#<&�Oxv}��N&�Z������%������8��F������\�L@E��J*Z���_S���'��}�IW9��g}�o��EvZ�$�)��L^_�"z\��	�w�����.�����u�[��u�����=pgx��I\9�N79E����B��;��ni�1YU@�v��@���;�f�2�&���t���U| �Q�w����V���.�(���������K���d2�t���;Q+�2%����z^.J$�^�����xF������>t;.�lf��gp���������c>}�O������C��zz<���3��qH�r�`�f�������(�������	T�{��np������6&{��J���5�5���N�ra�38�����<~��=Z�};�[������V������Ax}��_rB<x2���dp���Lx}��_�A���S��vHg^�(=����p;��J45^������!^����q�J(=%D�&��O
��I/~���^#��M��$�����X&������dp����s��YK~-�"�9������e2����+�wL2x����8BX��3O2x�[28W�C�
,�(J]�d�&h�)�9V���,�����4��1fpv=9�f^���(�tlm-���.���(��t��;���#8cE�����|��#%��W
��Nc6	��rJ�Z�N����m-�gQ���g���������k-��T��z����_�'���y�\L�������r)�d�&��)����?)����.�I	'��]��F�`K�is���[����W��@���Q#����0wi���<�AD��K����x�T��A$��L���&��^�f��C@@x}�3�d(�����������Nx}�S��p���S�v��-3���'<�N�a�cf���=>@m��<*����(6��']G:%����2�Yx}�3�#
<�j*J�rZj�q������^Gd����t'Jik�����,����M<�?������>�x�4�iw�y���t�~���sl�y1���e�[�f���;��R���8�>�Nw|{*�����C�x�X�uW!+���o�:��e�{^.�b���{���K�N��=�c�{z�����c��������2|�-w���C&���2�]R��|� x�|���^g�/���;1�O�=_�R�]g��q���[�^�l.?tH��f�{�����Rsa�P)�^)�B�2
�e�O�iVj.��=�X����r�T+��)H ��:���!$"����&�@�)����x�c����ZU��M�"�i�}��n���Fs�X��L���&%��Ysr��|������U������b}�-��R�����l2���#�U�\�I�q��3������(H7QxZ�8~���z���{��t0��NI>R���Iy��C:���)�)�`-�Gx=�����r�!4�C��������x���s���k|1o
��|xCF�}6QA�x��-�?��p������	�r�%+�/|YT@�xUWj���l�6�.S������qk'�
��S$��l�w��8%	�\���lum��'��t�����b��?2o��W3�����y���iNI*#e������k �TI�Q�a�$�o��R����������7��(�A��vD�7��&#.������z��D������8!�L)����1�x���Z\q![%��qc�x�s�\�<���X����S�����@��F��e�b�P�t�<^�5T����z&Je�a�eW����J�4���������9S+b*-�:���{���e���i��K��t���J���"<d��x}�okms�����*~�<�h���>?�VY�~y-��V�^���q���Ti�&~��^l���]g�ekEw<b:��Y��6��7������o�N<�1��lw����W�i��"�4]H�=~Cu�
�����g�������Z�q��x�JzR�2����Qz�iuz� �QI�^�qvz��2*%d!��;=�r-�a���TB��2C�F��������P��'��
v���d9�t�����I���E�&�\��������5S�t�[w��^<f��3��&���$<E�*��H(�1�r��&���JR3�Yj&�
�����L��gP���u��1JR']�����=���8PI���T�b��N:���
�I�:�x�i��a�$���S����uo��ZI�*I=��a��Z�Jh����n��iY�b�;�-}��v	|5�bW�*m��H<����'=�UGzg�Dg�HK��K���}�Bq���>^�S����R%�M�E���K(=������`+�Oz��5�cAx}��_q@���S��\x��s��IoE�BM.������ ^�)�tR�gJ�M��R*�V(F�^�SzJ�Qp��z�.���+�Bj]�!�Hx}�c�+�����
�)�����}l�6r��
�����O���Q
6�$I���R��RgQ��0�+��x.��B�����O.�����%
�O�;P�k�5S
��|re���J��7���
x�TO3��=3��X�D�fIhm�MZ�����Pp}�0���Q)��������J�Lqb���lR��GMi�Y!A���0�ki�5OgI�*r���fI���<r��)�Y�	���p-�,�I��qGE��a��qOE��az���x|��T�zlU
���J�=f���#A:��g��������n$��u���XY
sy%?:�H���)���(���(������=���I���K����t��	�OxZ�N��_"�>����:b�4%�V���D^��<��	/����-��-����2Y
[F�}����l�������P�x�e���;�p��o����^�(J��r��:�R�s�t���v:~�m���[2�����v�s���{����Q�����( �����`���e��[�:
�%/W��YX���e��Lz�m�B�\)���C��f��@l�p!�/d4�����Wp�b��M�(�h���i�
V�
�/�?u�x��NkO�"%n�gpsuk]/"I]��d��h���(��:.~�(�h��J���&�x�ex�Sz�E�}���4b�!�x|+�K��cIo����)T�c�|���;5/8���?��,���^@UyX��D<�fw)���(?22��I@�uF����J~�5L<}��h���d��$ �N�uW����z{��-�Y�){��3�>>��ybO�[b�@o~W��Fy�������KqQ��.��w!=�gM~��/��//���'����oX����*v?�L
�:�-�4��O$������!�e��d����kp�D���O$K�k�a�vM�~v��<���n�`����k�����SD.�+�����W�������S����,�G\����V�&/����J�Z�%���$y9(��(�+rY��5�����K�AWQ�F�����L�;��sW���������mQV"�J�rWB�d
~���/�EQ_�����=����o��Mh�!�Ky�����{�+~�6���RVpC���'�7��W|iV~%?�IA���q��\7�0K��kA#����t��a�(q�F�r�������������>K�D���=�7��}��9\����n��V�=���RM��F�j�'�,e�T��A�W����W��JUT�����C@��v�nKy�q����j~��1]e!�QN&�t2�(>�Y�'
zy�c�-�CF���/�_�j67���B��bA�
�P�]��0�b�<���������W���/�������_ryD���?}�����5�,���T�t��d�cY�syj�g�{-.5��H���8".EV���T\vy�M(^y�l����	;z$�������[x�GO���(GO��[i/�U�;z�$��J��<����������_|��o�nZ\@.���������?���5lY�����_.�������_�������G���I�?������y�����{����a[bIZ��gA��~���������lq�����<+:�X��&`U�&����t5$�(�a���Y��I�X�i�;��5OG��a#�"���'��m�E���^A����K���������&?��|��S����)�T�z���x�}��4y��{�&��,��
ov��}����
I��0'H��'8(������o|�qG������r��n�g��#�y8O��k���{�|1;c�	��z�f9��U������f��f�U3N��yE%^�}~,���.��c�v�]BA*exj�m������`
�s���Rk��8���.M):�Y���i,������3p\����s)���z���B�"�'�8ub%|�zl�U�7���7�s��}:\��^���)	B�]~Xv�s����[����������0����n1���Gq>v���&��$8	�/���Aa��+���h?��h /\(������|�k����7�d����h���J��i^*s�l���V�+�Y`k��?=���;���P���4��G�I/�%l����kf����@;��*��u�+��+��q��f&k��bHoI��(f��oO�O3��#[��L���n�GzY
�� �~��������lx�	�Lz�q�s�_A^�@Y'���-t37�p�
�Lz�q��j��\-�"��fpT�Lz�q��ah]���*�yZ���.�y�)9N|EGD��F��o��p��\~J��+� ���b���@]]�eN?�*��YJax�Y$�=G|0�r>��W��f���[0k^O��$��&�2�������p���#�o��"��.�zu�N���7�2��Sv�&?�}0��d��_v���L��r�.�k���w��#�q�3����^Eq��.
�����!�s�������rX�=��j�]~�*�Ul=)\�=>���0{�g��h�g��>������:���,���a��\�%&��Ae�!�Bh���m�GF�=>g�'���
�"�`���M�U������+�6m�����\>�+�n��:��o��uR�y�!]�@&^���x��g+>���������~����l*�"AnV��������'��n�h	�4#��I��?[�9�����(�u���8������+�S�o��g+>&#�G|fa���e��^+fC���m���pd����a�K��p���g[���\�\��iVH=Q�(p�	�F����JT<�G~V��P��xX
�F�����;fO����#T~���q/��F��P|�t������t�iQ#j.�p����o#��OM�� �[��������?�
�'����b;\K�h�W��;8=����%[������*����iuKE���?����������������$����e)�����������_�����ur�z�}��O����Sh�����cW���9�a�=�r������7��n��|�?p6���u�����C�������~��-�&�Y�w��I��E1�'��h�xY>"���)f���QEF�e%��j� ^2��8��@������������D8<����ckOO�����Vf�i
�_�D��h��_���h���"��fB�1�h+?���#?3_S��J��K��;N~���d�:�E�_�B;2��l""���� �g��_��ic8�����<be�b�D[���p<\n�������i�M3��56�v�u�x��x���G(T�=��r6y�u���Ch��;������������*���_���;��1�:�T��h��!��"m_w?�
�k�<cU^6��3�p]2������r��ur����nX��k��h"��Z��k&��&�*�jO�����K�B���Y��Jp%���N�PWX������������&o+CX��w�&A��4��8������(�Ud���kO�ku�9��1��w���gqN����[�kz�{b������!F�/��������
����������|�_b��fd����~�%��<5�s�9����b����<����}M�Y�=T+5�v�g_[�!0#���m�W9����\������c�v[�����!��D�<�r���J]#� ���m���������L	������o`+����)�k�����#U����lW[�
�]�Y��n�@�
�]�v[����h�	rt�����`�����UAK[�MH�������Mz!���v[�����|��>goi�`;7���/$�����K�y���D{�/�f����y[�9����#��9/��`W	��y[�e���G~�s^���{>L���G��O���_����pOc��r&m���O���_����������L����S*1��9/���Mh7�L����S��ny�������9���kx����6E�����+�s&m��ja���������px�6��������~������n����;��G~V�o��h�?���.g�V~���5Ka��������n�������w�7�+�����kMh7�L�ia���v'?����@pSJ���X�wc�$��T�^�����Mh�L�s�E�,�B7�����#m�3E`�l�e��v��������C~n{7�XKA�\SU6����V���k��}�k��O���o��i�����`��G�1�z�������n��H����gE�B�Z���4�@�u��#���&F�JY�|%?l��w��8/$��~}]7�p)����X=�z�f�vc�����$���_�h3���Sh7&���o�OT������m�� �%	�\~{:|�8q�G�\�����L���P#�s����yD��T��#?+�O�\<��8D��v�)������.�������g7��y7�lO�3\q����_�����i�l����Z�d��i��2d�B����n���i��~��p}�����
B�=��s\��4���ef+>v�d����]=)7��2�=
9�z�����H�=��{������Lh�%���SA�����&>L���U�7[�1^�+���.�vu0^�?���z�����"z%\ZE�v%^�lJ��da[������������2��/)����m�7�������C|/N���l�(���m��`_?�]����#M�����G�c���M'~!Y�T~C�a�D������is�%������nL�����Y��;�=<����}�Y�C����Nl]����F7Q�l��p�U~�?:\�Th
|���n���.)E���;<?�����O0J�m�
*=j��o�Uz�?l�����o����dO����B����SM`
�lll����&5E����}�iy���R��/&��}p��<��Z���=�#�b���&�z���8��;�dL��J�����h�]�r����Q����|C~.���������7�m�S[�!�������%-��+�Y�	���s��bz��H��!{������s�.x�.l���m�r;�~|c�n�����AXr�����G���v���V|eMB����^&A�p��2�Ung[�U�q��G|fU��q\��\������V|� tC���n�'��p�
�C���L��18������Z3m|��<�*7���v��6��p+�p���e��}������3WK�/*��9��i��Y��_&pWP��M����N�������i%tF�b�a���%<tF�T�r�{���K��n�������`��G|�'�v��n{���31o��Ye���Lw�5R&\
����Uot[�!�pC��/zu��!��GV�2m��N�7���k��s���N�7�m�L[���
�#��� ��73��h+���tBl��sB��o8����4_����� �Vt��2����m�M��s%	�WGcV�^�s��8|}B�1��V~��������#k�pY���*���M��+^f��������@xAh7&7���DhU�=��zxd��o���h�v����d+�.�|���N~����n��h+��Gt���7���n��h+����D�
A��l��H7��}�]|��#��#�?�8M���^���p���^���y��FD���6��+�Z�BG���M��!�
�o$a�	�n�<A��'��3p�>z���1^����Y�5��&�MOGp�k�h*�"�8�Gp�I�~��Kq�f�/�C�`�W�0��8t.%��g�����D~���'���A����!{�;��`iJ�����U�yF����{�O���!)M���&� ���E��K�2�?
r�n�y%b����G��������K$��*�� ���P�
��`��	��5v�C�`(�x
^u�����(��4��V.�9�'�M��i���{�V~-w���J��Yk���K=W�Z���-�V~���R(��f�L�	��M(�,�m���c�@1s����%RU�����?V�+V]���+����%l������^����`+?���'?�w�/k�t8���x�]��r����mo�s���h�S4��1��b�6�2��B�R���lr��])�������g]YP��Z2y�>�9B��m}�NJ?�_�'�?��/�����?eyQl9U����/��n���S�{�?9U����O��w@4��5�RCkx@<���_�/���|������O�<�\����#�?s�+��i#��2�6^� l*O���?����z-������O�Ua*[�u	5�EwM����Ap7���
�G$M�}��zd�h'���f����|*a�	0��`��`�����;�)%�����1��'���t9SV@uc�	0z��tHf����3���1���/�H3�>�A�H��+��l�`�
�O�V�@+�rp
���9[f���.L���b������E���L�0�^/F:d�	���9[��
�O�v���X�G+��lX���0�h�	��K�����9[VT������%RUH���	s��;"*)���/���CSp7&��
�����l�;�D.����M|��<eZ�N�G�]���y��_"R6��'��)������l����)�>��D|�f��*_p7&��
p�8�����K$T�t�	�\��DF>�f�;V/�`��{�l�n����qf��^"��h���m"��^"uBw�����V/�@�	�Y�;O7<�%R'�D��'��=:A�f�{z���li+���0�h5^&��-v�Z7cj����%���+���`�>���aH����y`��h
��N��-'/�}:��Fh_�����8�W�s6�����MM��D����*�4<_.��VW9s�7��&��r�}�wl��s�[�&�k��}BVy���z��������,�TY��5l=*��\��S;c��5�-�����r���=pk�"b��L���t'1G�����������$����8��� ��{��k���'��mpI����n+������'?���@�1��1(�����-������tx�6�{�����Z�^i��&?��6�1����l��#*��rp����t��
���=[�1 ��Rp��=�t4�������i�x@=�tL��m����x��p��=����M���m��k��I�}����@:$>��&O/TH�
�����'������y���<�P!a+@vzf��'5�����t[�"�U������H��9���<�P!a+@vzf�������t>.�t�hgM�^���`3CT���n���+]Y/�!�Ap7VH�
���4JRCe5�5��p�.�pG��n��0`G��0�h�WFrd���C�J75�B������O���H��G��X!a+���n���^�f]����!�+$lH3F�}���@:����sT
�2oLjZQ�z��L����o��T��|���i��?:\�M-?�B��E�G��_����������~�S�-�<~'
���l,��xz��va���V�@��:w�.��n�e1Z[
����Z��*z�7�p�����U�[��x��n���_�w��n����@�� ��=J:��w[0�V~%����_=J:d���`����W,�>��Uy���y�}�4��a+����V�Q��`���RfL]�H��>o��V~����������o��c���n����si�Y����|��[�g�VI����`�U.S�
	�e0������|�}I�Ep7Cm���9����**��y��1j+@N�f��^ ur`�,�=��=�Cm����M���� Y}���Z����f������f}$�h�����U�2pV��n��
pH��C��G���t2����Q���;|f��.���o.���~�M�����c�1�n�-o��8&x���{4{���)�.E}��n�-�
�1e��{Z���k�`���k�1b�����4fy����!4���Z��_�N��������0�U��w�k�V~5LWA��/�i���i�Hx~A~5�87�V���2��������������U�����"��9l��I��n�����a�9b�&�5�����}�����cS�M)��Y��=#f3:\����cl+?�kQ��G����p-
�6����2\��;bV9������E���1����9v���b�S�<�o���V��	s���/�H:����!�uc[����K�,�
���7���|��|}�cl+@Y��=h��2h�t���Jf�3���A���P]`Q#UD�����/��s��F�����/�^q����*�F���(���t	[?
�O�v��!_����.��n���
0}���}�]K>��A�>_���k����W�Z�
R�
�%�t�	�
���|lse�KA��mm�6~@,ZH{�,c�X�\;�5M�@7��0(��`C}/�d$��cEu�����=��l��k6IS)�98[v@�1|�L��2���t�q����U����GM���2K�>����������Uf�����3).r��c�:�;$�p���H�G�=�>��������� Lg6����+|���`�������2`=C��@;'[-*\�tM��\��Qc�)e����c/��HkZp���6z���"C��$k����2��~G@*�T�Z�`K��M���@�svx��Xn��K'����8�f�����tq��=�0��n��K0�'(�>	�=�%����c	�x{�O�fU�r
��S�Ut�����o20����'A�7Y#��f��$]��y����20���J���9lI~-s�*]	�>l�D���Tc$a
u�Jl.~$���H��1���##z�����<.��W	��������1�b,�����6�'��.K(���w}z�A��I0vwO��)�����4��F�)L�I�.M����s�{>��@fPa�	0z� �r�e���(������d��E�y��ia����V��\������0s&+�*��^`[�x\�O������*��O����mX�,�m�]b��i�8��X=�~�5��+f�Z����>7�ia�m�/H��Z�0!i\�|�L�f�/H��{�|*���\�����v�
������Oa�C�����n�6���F�����2&d����k�b[��)��Y�����?'�b�e�����w���j�M�el�'��'�R�.;Ur�,7�t�I�7���[�p�
s���2����g�n]J��+�[	�C�
z{z��?OR�YJ"�� �g���~0���;���7D1{C�)���������kxD:vV�����:�w��n
��J�A� o��YFg�[�1�����0vx�	t��N)Z�fE���+Ep��5l%��\���@f9������]��Z��le\�V�#�D��Y%uz���x����_$�D�kT�b��N_L���H��'�,l%X$xv
t��N_l
thmq��K��7I�t�b�����N�Wq�t��y:�����*�t2��TaD{��\��I
���Y��)����W��@���x��s�I��P���3Ki���:�U^��P�;���o����Jw>��FwM'��,�Q���Z|���h�_-jM��24$����jI����%x���h2*�)�Kaq�fKt�Vw.��$E��Q�f9��hT��]����%x���`��O�fo��f]"I��i��K��7	����`��DH����p�Y��53��:I�St�>��OX<�L�l=�,Cm��Kf�
������O�:�����/v]aQP�r�Z*����t0f�|���dv�����g_���4�"���J���W�}R4kP��2��+Fp7&�
��-�>F�UH:X��1��V�
r��Yx�^��T��
��1��V�mKD�4W�y���-���m��l�iP�02���!��Y7���m��*�5b�������
:��wc"�����G���\m�,l��|hyg}{o7�4l��=���h�dy�=
pf
�KpEx��x����b
^y�T_�EU�� i�v������D�&��|�V,t��'������2���T�-���KL����7�'B�ZC����D��B��/��r��������UnL��x����F�c�gQ�fU�!�%�S�m�qD7�����bO��:��OZ��m+�}l:r��K��3��g������n�'�&��U��w��u���TI8���������q�������{�������?:[�B`��	�jo��������7�p�������{�mh��=G[$sI�3(���G8��v�T��0�J��M�<���X��<���w"��U'���Iq��Z�]e�y/�k�����F��Jp�V��J�y|������������Y�TM��-��2�^�:�� �'�O�V��J|����N:��53W^�:�� {�7�)���s�{r�I�N�����+U'���o?���@	v����U'��<��I0�7�b�D���As7OA5Q���|l��@]3���<�J�3�4z1��5#�&�����H�uv��(�ed�[��)%'$
���eVT�kT9���4=/���c�6Ej�@�$hU���ftH�\���T�X;kq/E3�g}m���t��W���!e+��'��;����q��.��)�O����9Nfh�����xmn���Gh_�n�B���WqS����n2��Q�m�`u��,��67Q�>���q$���^���b������V>�F\&���x|�O��u.[���;�+��X�CTRp7��
p��-�>�y8�8!p ��M�%x�O�f/�R2�7����������[a�	��!*@��������������J�ub�(�L���b-��GlX�;�0�h������pB���[	�9wH~^�QVW��ZZ��!^(�w^���������F�M�8��c���y������[�p]�o���E�F�Fgt����6��`����l#���6�W\�@UA/� A��l��`V�Q���C,�f�a��`�	��`�������Om���}���n
6�J�C�I�}4k�$�J9�ftH
\�xn*��-���Y���1�4y�I-�=��a�	�O����ft��w��u^��y��FW����tN���G������������{%R`�4:\�M�z�kzSTU����]��C��e!���v�WeZ?����D�]�� r��0{�\��=�
0�:&��+�V��
�O���M����4�O�1��/c�A�}�z�
�U��*�u�p[x�
J����`�{��]�
� o
�O�V/�P�(�f-7_p��
�����'���ft���!�/����:;a�	��� ��	�VW��k�Z5��1F=Kp"��A����������U8&T�
���Y��W���da�@{$h6�!�E���[�Z�YI�+�`[	v�`K�k�Q��(����|��lA�}��9����.�#�#l
5�f4��*A�����]Y|d,A��Zk���@+��V-��)�>�}��U�������4g�h����;o���_&�9c�x��Z�#j�@�`��mB�kR<�}k�FMcZ������}�qfl�_�<�����LchOP'v�'�8�g����R�d+���q6��S~�ob������W]��������;�6��y�]��`,�&s��8�/��^'CRy���E,�!vL���vL`j&e��4��*���u�?�]�`��D���N��N:<w.�]�`��1���P	���\��>���9R�����&N�9R�l�'���5��C)��>yc�iW��r������@���#���Z���l�z�D�I
(@�V{
���BpWW���c�����O�ijO���S���8�i��!��;�z��8�[���y�D7�69��O���O��|7L����_t���m��I`����'���4�;�tL�#?v'���v�I���t�f=JBz������<�pW��q8�����]VAR_g�L��y�a��S��?i�f�'}�?���4=�����|cQ�QIW2s���~���^h��������h��J2{^m��\�r��!m\�=�p57���������}�����������_~>g�����A��H|~����c�c�����e�T{��m����v�y���y-�>	FOn!j}w.�]}^`�lm��I0<���oM-�{�IHG��n��zL��E����U��T�����+�n<��}������)��+����]��?:�7�;������,)h~+���E�����F���%�����Ay��I0��t���-��]}`��r����\t/��U��*	�z!�X����u]���!������{��}��;h~|c}��Uf���kG|y���?�<��/�p7���<OO0]��]���{��]=vV���z�}�E��(je���m,�g��#p���g����(���f��.+���V#/��g�
0Mr(�,ru/@3���F$�c��
wc#[��f���'@��u��)�Cp76� �7f���U��j�e�.^c���Z^��.�������V7��K�I�����Wp���f�W�����`Y`{g��^hA�Mu�X�,�!��N�]�Y��ZP�
p���w������J7��-(L�~�<"N�D��.�l�����V��ch��|�GdF�[Dp7�����1-��"iZ]���?�/�����V���r������3�t]P�@����D����zm��.%�5<���U�*�:�b�b�����������8�:��^J��?�),���m�G�w<���jY��e���>�7�i�R���u���ue_c	��%��]#�������.�mq�?g��7,��t����]"#�s��}�]�;�����r����V�_��F���oF��gv����G�,A0�)�C��m�ft��
��~�|���A�$�����tO�oVv��� &���}��6�fF7��	���$I/R=���D��&7����;��D[��l�x����h���[9���*�"]�`��.{��feC[	3FC�,�]�4�CnJ������"�,a*eJ���0�jq	G��n��a+��'#����+�
�`
#Ip�v���`�k�V�M��P�kR���$�7����S	�����O����d��p��6y.���F����}�m�eT$Gu@�������O����m�|�(�	���ml6Ed�u8�b9B�=\�������~
0��t��{�Gd�������9�l���r�!sKp���0�`����}�`����y������:W�bw�']�HG��+}9l%��&����`	N�{^�����7�@)$n�����V����ijv�B���t�IrO���a4��/��) �cp��:��O��_��WrS��!�E�&���%b�����Ou���M���Y^!~#��A�v���Y^�x���7���7��}=�/�������s�����	���[x[�u_y�y�1�7��d�O���������h�W���x9aKS!v������4�Me�7�}��2ISqT��S+����	dC���k�q��U�eN2\�H5������r�%��Y$�����x��J~t����XPk+@���	g��/���p(������PP!����|}gt������D��s�t�B��b�D�����F[�H�(�>�v�f^o�*������\qo���Y���z>�l��sMx 5��`t\h����,�{��=���S`�0��h`w�(}����",��d��#�hL1E��}��'�!h+�y����}����������w��VX��d�k�7�&@d��0o���D��Z z���X�]X�x�
�,y,i5�v�f|�����V�����V�5�>a�%���N
���/�k�m� �+�>�n?���Qp��x�J���4����x�P	�T	��rT[	��h��3�pd�������x��3F:<Ke�{�b��B��\����E\����gfe9���1S��I���O�����k�b�L����p����H�q�@�g��nt��
p�=S���{F�������_�������l�I�|4b@���\�M8���v!��"E%m<u�:��%������9�g�6������.����a�y��f5�l��[
im��������s'LV�iT���-�!('��S�xc>a�]�*�<#�S�����p	�a�����&�cJ�,�����a_`�����F� ��	s��UI�p����D���>�unT[������+^
�k��w��V�MED%,\X��J�k|3��$�87�H������M��oY�����hk�a��
u��Ze��;�����l���[������.o�����G�[V�D��'���@�qwy����Py�T��3�f��z��3fG���<�����N����%y7IE��y��F8'U\��((����|��T�iG��+�ugr����y���K��4�������&����R V�6��c��Fv�K����?:]��Lp7e�<�AK!�	����\�~{���	��DJ�� r�����L���*����������J���!\�z:����0U�S�o�>%�����Jw�Y���V���UcC%�4�4��������:*H�t�g��<�
w�HB�`O�E��t������BB�5����h�hV��K'��,�Jz��s�w�'���H�����%�k���:��I�*3���q�&������%�s	��c�$1��I�,R��-!5�y^g^��h|���Dc���.���4O���i��dE�q�_�(��
��,�5���g��}�V����z1��}aI����Zd���R�7Q�=Rl����$��������:��V�7z���^�f�Jy6H�t�	��$S�,�f��&K�}>��K�������'[�SZ���7�'���6���=}B�u������l$�x�W���������H���K^P���{��86&m���X���k��UO�2����:~>�S��:�V��Qf������}�������^H>� k���'��O{�Q?f�i/$�
���.�>FtL:�n��1Lf+@��	�O�V���+��J:8�����uE#/w����]��z���q���+1��G���7|��y�"����M_��qD�Z�}_����)�g��g�����5vd*��Q�^iz�kx+��R����f�W��d�.��I���^��T,��@�7�Z���`>c�[Hy����K�}171��*������V�D�\�T���)��/N�������������1-"�O���g������~�/_������.}������O���-U��������]���y+8e��������/X���$S�,�#��������Y���>?��t����������jQ}�,vB���q���D�|%?:/�G�e'��vbq�V�IO��
��tz
�m"�����B���,@��"�.���%r*%��4ux�2�O%}e����.�9y+]"�B���\�k��.�h�!�����!�*�������	a�������i��.������0���'o�He�][U.��/���TYf���| ���pyW"~'Pv���a�r���5N_�~�e����C�2�t��-@��&�.�����������r�L�t�D�Mw#�n��B�����U�=�.�����iM6��t���-@��,�.��*T�$y[��.�����m((�]���m�d$.�r�KFH��,��e��JR<�����<����TE���e�Z�w��>�)�U
����}�|?�I�A��T��:���,����-XJ�/q[g�>(i��/�<i|8����_��-�C��
��bi��j�5��5P��|D�I���i]"=����,k���n�>��R�gt���p�I��&����0��eY���f�����Nm�SK�A��&�����[���Z�7\j��N����@��X�R�[:LRz4�u�}0}L���}[�w�$��1�%b^�������<n�������c���~���?]���o���_������/o�?����������������?������E�������O��o1��K��w�&�id��������a
E�i7�9��g�OtR�����=�����.�[Z�4����0gF*��t���1�M���b��e*����}����x�;kx*���]���G]Y�4��R�7��x��5�ed%��Xp�����X���UI�[�Y��@��d��`�	�q��b 9��oB`'��{9���3���^N����k��:��k9�J|W�����Vq.�Z�������W�s�!`����\�8c���6_�w��������*j��@�������
������K9��8�e���Z\���V5�M�"�^��uQ5
���iDZ���j�I�]FZ��?�jS�I�?EZ��o���_����j����)��JG�2���k�O�� ���'�&�-*t�E����SgZ5U���	A��6!lQ��0uX��*�=`LSj���-�%�T!���B�^�]�-.�O��n��@�R���j�W,��e�Q,�C�Y�e���O��6�u�w����YPU�+����C�.p=�:-%���mRo+��s��|�W�!lY�����u�������8��
��P�������H�!��t���������3�CQnP�!����6�������u7e�{���%�f�d �5�&��]������E���Vw��x������`�&z��e��a�:�zh	6>���]��e�U�;^k&V	����e_�����)�+	�M��;��K��������i�"h/�-������UP#lvI�$���,n�]rdj�Q4	uA�����'����&��.K|)%5�(�@�F�����1���U���s?X&��RD0	:,d���'�ZE�~�Y�8�\���J��
��6��|C9��\dZ����o�[��=p[����(���\Y�1V���4��WE�8�f������%��wY{���P��#���XY�Kh���kv%p}���&a�]�A�U�W���������7�K[�eM�H,�����;tMfs������:}n�+��}�jB!�1���#�n���y��1�O����y�V�_����
�,��h����r��~AP�����5����J�F��'w���
�K�H
��� m�����]���EZ�,��vb����"�19���f���<&m?����Px?�X�d��z>�����E�S%l������h�go�~?��R�+��(�9G�]�md��L��d����%���eO�w�y4��C���h~_���L�/��o����ZG8({���a���x9j��d�`��AY����5���5U|E�����Ocs>�����,�x]�k2Ms\j����d��7�H��E��&�����|Y��k2���kjX�i��XP��#�����XP��#����f,�O��dZ�2���}2-�K�Sq�>��M�%�<B�l���U�Q��cI�*�P)�����N�����1�
���ekMT������z+�Tu�N���5u�:D�l/��:U�S�����S�:�l/��:U�S���m�S�!�	����N5������P��Ct���m�S�!:e��o�S�!:ekQ�������(Z�T{�N�Z-u�=B�2[���N�G�TfkQt���'��E�Q��#t*��(:�Tw�N�Z=u�;D�l-��:��S��e��/�����S�!:ekQ������(��p�N�6
]uj8$�kkQ�����m-��:5�S��E1R��Ct����S�!:ekQ�������(&��x�N�Zuj:D�l-��:5�S��D��IK2�(&&��*w_��E1%��)9B�
S�bJZ.��
�����:D�L-��s����2�(��:��
��(S�bJ�S�!:ejQL)u*=D�L-����e��/������yrG�TikQ8��B��H���(u��S��E�Q��!9��EF���)[�"�Ne����E��)Y�����(X75R7U�Z,��)�*m-
VNM�TN��K��CJ�*[���S�!�S��E������)[���S�!�S��E����������`��tH�TekQ�~j:�~���(X?5R?U�Z������l-
�OM��OU����C��j[���S�!�S��E����������`��tH�Th#��EQ����m-
�OM��O�����C��j[���S�!�S��E����������`��tH�TmkQ�~j:�~���(X?5R?��Z�����jl-
�OM��O5����C��[���S�!�S��E����������`��tH�TckQ�~j:�~���(X?5R?��Z��������j�**�!T���VE�:��������XB5RB�&�Vk��Cj�����`�tHU��������J[��eT�!eTibkY��j:��*MlMRM�R���m�J���J������R���R������Z���Z������b���b������j���j����d�$Y�U�W���eU��@n��U���eWU�*K�������Y��mQ$i�UM��������z��W��4/��^����i'��"�W�!ze�J�H�*=D�L{i^VE�r����m��W����-���W��EF�r����m�Q��c������W�1zf[T��J~VE��>�j��8�?��������.����2f��P��~���,��O@��Lm�B��B7�J���:m7���iz|:�%�7���a�
��6����\#l��~��s]�w#�2�F�-+t#���s��5(����jQF;����i�bY�u�n��
�����F�6"lY��J��:m7��lO�����%�7"�����(�U��a��H�	�N�U��iD��B7�����:m7��q�v0�e	���]��[V�F�x��:m7��=�N0�e	���bmD��B7b���)1�S��s���K�nDM#L_�]�n�4�����+p�9�%S��\Vy�'������*���)
�����q4����$��.p]�*Q�l��������up��>�<���ok��XW�X_��M�7� K��DQ��	����kL�u��q��p��;QF�	��u����������:C���;QE;�L����j���������]��:�N����
��,�v'L��Y��,���0}`gm�u���N�>��.Y�Jb���;�������;Ox�
j�:kb�:��y�<�Kj��s�mgoK����X;����@���Bmw�������r��l���b��e�u���N����7�,��.�N���������\'L��y��M����,��d���{�n�Bmw����O5��^Mw��XN��u������u!yK�i�N���������:QD���uu_�����u��W���.D�e��u��o�?�~�����������������{����&W���
����������='���?�������_��������7�|�O_���o����}yK���O�]������w�o��?���7��|L����u�����[\Tb*������ ������>2�|G�7�_��*�J~�E9G���]�sa���.{�>����T8XB��{�������rY&G~������4����7�h���}E�r�l���/�����?>y7�%4__-������_|=�������x���w����o?�������O���������t��/����������|���������__���]�a�5�Y�b�l�<,,�e��G�6}������^��a�Q�pb�B����&�Gh���!��{M���*�&��iM���H����5�>1��$��{M��zUP��#���(�
�Sq�>�i���T�O�����>�G��i��*�O��d����*Ty�B���)��U�Q��_.��JUG��m����NU�����[Q��Ct�����S�!:e{��������{k�T}�N�^�5u�>B�l��T
u�>B�l��T
u�9B�l{�T
u�9�7akQ4������(Z�Ts�N�Z-u�=D�l-��:��S�EK�j�)[���N�����E�Q��#t��L�Q��#t���J�Q��C���EO����)��UO���)[���N�����E�S��Ct����S�!:ekQ������(��p�N�Zuj8B�B���`�m�`��S��~GJ��o���KuW.��]�i^%?���qU�F��k{NHA�������r�d��/��6�:.J-9��(��p��(5+?��L/�:AY���'�O�:AZ��r�E�>E�����#e�������X��S�N�S���ez��L��U��(�{�N�S�!:ezO��:��S����Q��!:e{�:��;B�J�{�Q��:U��Su��S��=�Q��#t����2�Tv�N�>��:��Sa�o�\�~���mQ9u*[��=_t?���j���,`�M��W���:��^�)�Zt����E}��MqU��YIj����EF�U���2��mX�*^�{)��mX�\T}��lo�2�����X�
�
K)-.��Ke�O
��O�%��������,�Q5�|�*�V��{Bd��j����*����z���i��M����
T�
e�����a
t��[����z;]~�5rY��mH��0�����p����-��U�9�e����4|��j��4p���'lY��a����T��p�f�0����/�.#�����u�t<p:}�_�cs�w��P��x�t���}���{���:F<8�~��_�D]~�e
�
���6��7�~����L���<av��g�p�i�y���<Mr��,��������]��U�����������rV�8K�}��o��n�C[b	g��9:r�^�th�"�"��<����?-Wq6a������?v����W������r�}��g_��
��$�r�V��BU,-
Mqe��������3�wB���o;po�y �(^��x�@�6�zh���$����+����gn��$����;�z����7_�7��C��C���&�	Z{AC�\u���4!h�
l���������s�fh�}���IH�>��Z��"�L��&(��+�uWS��a�A�R�t��0H�{���]V���85}{7�%�>�-R���J�����\��h��m�6^��{t���,�&�^V���m���_x����:��x�vGf���-_�i$����g�K���
<R��"�|U��Q�&�����Pb	<tQaGJ>qQ��/�4��a����~��.*�!S�/6|�����#�iV��
��Eu����RJ~��uM����KS-xiJ~���/�6;�)y��G����
;�K����3����+~��gx���^��6|��Y���^��/*��h�W�p�4��vd;�]TX�oS��R�
7-�kj����K�%��E�)5��z�nk�7<�k��%p[;�se�/
<0�+X����#���E�y8��ih�7��s�&�h	uQ&�4�H��m��>�#�}�c��g��F�����j���A�dZ���
{���_��h(���M����{�|V}9�2��:G[6��^:Z����k���!!n�W���$+pgi5#��E��-��z��M��n@�,�x]�k2��w�|Y��k2uPw�����Hk2uIv#��d�{�����-�T�&S�Z7R��#�����M���}2-���=)��{M�3���
5�P�3���5�Q�y0}��%Y���2�%������ejL�I�EUG,���������X��9��ebY�(S{�O�S�!:ejP�)u*=D�L-�>�N�G������Q��#t�v�T��S���<�;��;B�lO��:��)[�"�N�Ct�����S�!:ekQd������(2�Tv�N�Z9u*;D�l-��:��S���zf�*w_��E���>?B�lO�u�$�x��l-��:U�S�EA�*�)[���N����EQR��Ct���(�S�!:ekQ0CZV���l-
fH��:e[��W�)�������(*�Tu�N��F�u�:B�l���:U�S�EM���)[���N�����E�,pY�����(�������E�P����X���(�Ts�N�N$��Ts�N�N$��Ts�N�N$�[�Ts�N�N$�[�T{�N�Z-u�=D�l-��:��S��*�*w_��E�Q��/GZ��E�Q��Ct�����S�:e�����S�:e;;���S�:e;;�gi��r�E�Z=u�?D�l-��:��S��@��)[�b�N
����E1P��Ct����S�!:ekQ����r�:#[��������m��������m��O��������O������(&��t�N�Zuj:D�L-���S���ejQ�����m�3�~j8�~�v�������)�n;���C��l��
������`6�~j8�~�6�(�O
��O�������������X?5R?U�Z�����m-
�O
��O�����C��j[���S�!�S��E����������`��pH�TckQ�~j8�~���(X?5R?��Z����jl-
�O
��O5����C��[���S�!�S��E����������`��pH�T�}��
��P��T�]UH+�D]������M��%z�w�Q!��;�0c �r����B1YB0q�Mt� ��s�*����M�e	����r�����#u�[[gIK?���]�uu��o'd'lm��e	G�D���K��B����je��;���*�m��[W�J0�bV]YA*f��re�W��`��0����������A�����Y�o'p]a3GW`]�Y��{�E�Z�a'����^hMOS�xt���_I�+	\W.��r��9�Uz�����o�����wK����������}\���<����2l�s�DTA����S��)�	ZzA�b�
Z1��#�&C+��Y�K}[S�T�T��t�+)xF�;y(���$[���U"�jA���s�4p~�
4�+I�qp1�?g=�]��@SM@K���W���KL����.[�w�u���G_G�"���B������.��a'���_#i�
�V�j^#��^���@��.�s�{��;^#?�)����/|%M�����Mb�x��`���z���yek���5�2*�^8=��k���z�����6'W�a_w�M��XS���u������J���C������]�z����������G�^�M���
��9v<T�-�J`0!T�=����"]U��{����r��F�����^\M���z��*p����1���C���Y�8VLF5�CO��m�I����;�m-�4�v'}�E����"Z��qEkf����H�?M������&Kn#K���+��m��K�"=�u�6jR&Q��9/2���h&�:b�������*�v��NwD��ik�dK������~f���&V�&��o�\�R�����g�6�"ubZ[��L������i�	�78'��,{=_����(�h=mW��	:�4����6{�M���$vU+�������3Vr��f_�S�v$�,_���u�>J0*�V����sV�Q�d3�V�zF���
c$��bd��1�o���bd��]�p�O���3�G�V\}@\���"+.gW���R�n��8��}�b��7`8���s�-�7	��-���$��W���,�)ax%T�������W���/�c]����1j%p���?���
��_.O3
�F��z&����
���j�zU��8�4U�S��	�����1F��4��j�85�D�4��C�xN��R��s���rg�����vr���wf����2����r�<uf)/�e��9q�9n�@J&��9q�m"r�/�D{k��t���hf�������0������3P/�?v�"�}�A��1������*���=\���.�^bV�X+[^B�t{���!'bn;���3�������v`
�NB�0���Y�=!�����P��r*]JS�Ki����[��*M�����*SH��g���#�v�O������g�3�L���]N�)��������XSHg-pz&��k
�l@N�N���7
r�>~���g��'{����6z���S���y�o���S����y���S����j�9��S��DM�����rW|PT��J
�(w��xS	������R�Sa;���c���C��p
�/o�g��8�q
>�I�����?_L?'�Mx�K���u_F��HGt\��6<zu��K��
�8��o��<�y@L�h����V�����?U\!�O��<x����.���]N�7��E7Lp�^������>X�����0�r�%��8��Z~�Z&X��G�C�qo$^e��S�I�S�0O�#wx�]j#	+�ty}��N7��O�����WD����Dx��G����������F2v�#�L���]N����zL"����m$����S�D��3w��k��`�N$J��F2�|�&����h��Mho�Q���n$#��	�;�H�>���*�+��M�HF��GK�S���)�j�^�(�er�}�#���)�b�O,������c��w�^6�������{w�3{A�#.�sM���k�����$��}��>���������sI�F���>���~�o�����D���]N��=+>)I$[sb=�Y����8��Y�9U�qb�7����D�5'��������"�����L�O2'�(�H��$`�S�qb{H���[G��!'b.�Bu�Lr'e��3�&����������H���!��3�]�q-��(]h��66!���� d�w��R�bS��4�g�Z���"���e}Ut����������N�����<�(3���8Sd�UY�:�l��3E�8y����8�CmF����t�?8���x��4%�l�����G�t7N������Vm���2q�g)��0�d`��.���P&q:a^��-�5x�����e	��k��	H�����r��)'��e���%�/�,��
���������%2��0X�X ����}c���c��z���>��8�[1�?���+�����3��y��	�q���6D6����f��l�,����^w�P�����Gq�V�v�0@�� ��=�� ��,H��w���y;:vl���C�
�g�#��#[3����b<c�RW�	��qMl+uV��T��T1���c;c�23���NU����Sy7�l�?���X�L���2I�����r��qawKyL�I�,���)���[�����;���4f�>f���%a�4�y���B��
v}�F���<���o+�����������f6��b��v�z�Ia�@�����^�����J�21��8Ql�(F��7��1:p���R?]�A��6� >�u�<b�~��o�6[���K��o��"�_���?P�?#eX��5�j&��[����+�:��><��N��o�[:Rg�8���"�S&yr�N,B[����C�\���� 2��8���p7��O7+������'��Wbpw�I�����FjK��H?���Tpgbp�/�\���>F�p�Z��w@#E]��| �d\�8o_�8�|��Z��21 V�&�`�����l��c�YepC�r��@�Y�@h��1�k��%c8�"np��'��0!���FJ���@�;��� ��T�Z+���r�q�*�d��yge�@ce���2�����y|U��M���2��q�my�>�3^(7��RI��;
>.�//���c#�^�R�>�f�R��m'�"%������V��&=
�ekqO?t7���Y�!v�8-�X���J;t���bf����5)8������yP�(%�������oE��E���X�,
� -�������;�L���q"�����\8N$*.gY�A���!`��0�s��-��6��K�����Cq�^/R���d,^*b�J���
:�ys8o��.2���po�$7�	*�t�1b&<6IL���*M�����4)S����%b<L���1�y��a�J��%4���|���������ta
�%��1021 �.Pc0#)�>�/pYO��u���w>��27RHE����.LL���8���1 �.c0h$��~���:?��X�21��"�`BR��;`=\�F�$��7���@�F���X2H/pY�&<�J�+n�LXu�4�Z42�E���k�T]�,�t�|h��1��hb^�x�����I�z�@�����|j5"D�W*�����Q����BV�n^��+���K�8��Z^&d�������R=asB[3�5
+���&gx���~��uB���J�t�B����N!����p|O�^V�<w`%�Q��PY5������;�vj FA�y����j��G�&gXe��@�%��I�S�Q7��5�b�l��@j4��D�����Q9���YO���j��^(V�<\�tU��c"+��`pE2�+�f��3VBL�� ����9����Z���H�U;�.�'�Q�B��uE�8�����W$�����G�����K�����g,��hr�H��y��Z����x?��	Q<�$��]���K�x���}�^k7Rk�y��pv�S/k	_�z�P�.�\��Z�x���
�;�E�W>���\�~&.J^$����~�q��~
VjQ��gW��%^�h*��A�Y%����qDZ���D�Wy4��I*���2%^	=����~��H^	�Ww�J��"-jF\��E��jh���\��y�Ei<�(��+����<�Y��2%"-j&x`3���^������z=������BxU4e��<�����u�6!�*z�3�D��0���
��TiBxU����R��c�P�J�E�
zJS��OxyU4��I*a:�!��~
+.J+������N#���D+��@XU����J<9�V�t3���3^J7���E)��|q����E���D����x����5!-����UE/�D��0�E/X�=�d\�,��^4.J��(����*z�J��'���������/Jba`U���E�p/J�*z��(�z��N���5XO&����^�7�b������5iQ��+�u�B=!�*z���a"P	���["-rF����V�88}K�ZS��0������[��^���-� ����!-��7���=��%��WE�i1����*:`����oV	]�!�����o�'�|�yU4�SJ*a�����_�SZ��)��*�)-�{Jra�U�xOi9wO�^=��T��$��&.J.J�������R"p-dfiQ�����s��a�U�#���=%k�A���a@�6��o�0���	=��.����iQ��	=���S�yU����T����@T�������t�S:n	�	/����s"�����WEcM����k�U��^�j�a�K��dm��`Q����|�v�^��`���,U������D����#\'��Sq��%/���k\�K��N��V�k�����;��N����?������^;�J����{M�����W�O�����V]F�-$�������V����_7��4s��U/m�����t���'�^�Mc�t�'.����n��f��V}���={���yR�O�xy&����7��:/����v����m����~=�����w1�w����D��5����m���M`
������:����7�����d�}�A������2,��@�KZk�5DZ�$H�����������4N��j��M���������r�TZ��dkN��zA�!d&���	�����A�'����B@N�ZB�8�n6
�=�+�'������������	���������(��4\�=q�����+�'�vA��A�{�H���$F�����R�xS�?���O���������o�7����/��x��	����o�7�����.��x��	����o�7������M�"��Q��M�W|S�E�7�M�W|S�5�7�M��x�����|�7�Z�y#���r�7��Q,�M-�|S�����r�7��Q��M-�|S�����z�7E�(�y.'���)����������
B��.hx��)��VB��@�h)�|���G��f�'q|�����ht�t�Q�X h���@�N'�B X�2�N0u�Xrb� ���t�ZO�$�5�4}�0"S� $Z�@@����7�����v��� �"bX��0��)��,"^��"H����]y;>��
���P�#S� 4Z�>_��z9h����\������*#\/�I+��@�������G�V�@+,g�����U��[Z"p�j�I�Iy��q�oc�_y�������U��}������`�(��r�
�����w[7`�D�`�/eO�m�=�	v���
��������U��-��>�g- }��f�4��:���G���y�5X���r�����t�uC
������Kx�Z���x���
���D�'oM}1�X>`��5�2I�������\W������d;N�Yr��8l��)��e����6!}�
1�]D`�>�C��|RI�P_ =��X��pyC"�}����������{��*�-������L��g��b+FF��^�b#F��Xc�+���u������M\��������#����:G��;������������HnK<�n��T���x;#�S�N*��9������V��Z��'�'r�s���r�zz{�*{���N����{��	+�l��KS/�u���B�
�������U�D�B����������W��U1Ql�H�R�n�T���,+0(I��>���Db��U������.1�a���w��}��UX��U�Dh%�G��Kw&/�~&��W]�_�FK����� 0�c�nI��@K�����h�C�������bqi#?���XS�q*�2d�,����}����%��8�Y�(,�W/�p�����C�6���9���<��(��������C�,;8�>.u����������<3�p��t>��M��_���jK����(u(~U��uG�����b���>��_W�`j��o��9#������M��Ne$'xQ�DXAQ�@��2�%����2��A�]'a���rY�=� �������Gb�:���� 8���H���v�:�����j853���$k8o���z\����@�N�����2I� p�
����Z�����I���JxTZ���W
�5J��m&���Q��!Af�:�Z!*HQ3I� p�7�
R���uh��A��� �������ve&���q55�N��SR�X�4����>�Bs����7R3�:���N�
d��B�0p������?Me��
����<�F�LT
��Z�0Zm��*�5V����%oX������)4�v��RQ�/J����L��_�(�������7����|��$_��"��^ ae�=&��5	+���1a�VV	�l@��$������gf�V�F����a`U�n����%�*��c��(4?ncU�V�������VI�J#E&��?ae�t=&�����F���2K�0���� ���G5��~z9[�r3{XUt��K�����������\�8JXUt��5QhV1a��	+k��1a������UEGLX�@�����#�j������]V��,y����(g�)?7!K<V=D�^������p��>�:z��u|U&���$��1e�)�T����q��u��YY+}�s�������UI�����I+k��8���K��UJO�|��i���UJO#Xa�B�8�j�i�����%V-=c��(���>�tX���y�����V��3�����U��UM�����y+k���t
����^�����^��	g��V9�@E�L�}X���
�zUN�+�zz�J��B�8���:f��q`��+������Rq`��+��+�jY���y�z'o��9����y����C�"���R�9����|d�i���SO],�L�}8���*�x�K%�zzP��f
�����7Ve��i���SO
��L�}8��� o�4y����lx�)/����������V���mG@\�[���(�5��o�3M�8p��A��#�)O] �JE��%�6V3�?�fP��0�4�i�S���ul|�	,}���1qV��hN���T��	���+V[)9�)�7Z�h&���H8e�`��!S8D/���h�����x��U[�v�)�}4Z�@X��:vA��
c;� K�������,��
�2�
(�D�8Q�V�4�-H���7���@�%
��L���F������7���)H/��@h���4Z�@8�,��
�8v��D�8����| X����O�@��c�:�:a�.M��fM�����Y��;��8!�$��W�=�i���3g��&��{����Mm�l=^���3�W6��~��/�Z�~�V�����"�IV���+$@yX��w���?����|�����_~������O��L�:jb�h�F����H�1Ru
��+f�6`��$�,�|T�~s�3U��.E=��5RF���zK��{���S�8�&��������m�s�N�����G
��R��$/����W�6��� ������F
g����p��
��|�Zx�-����d��!�i_�po��_t��:M���O�C�����G&o�SY_�m���`�=Ql�H����0���FV�D��&�tq�
g����[�x��3C`�%�;Kk�!Fjx�t�]5�y������6�?��i}b���(.\�q����wl����r<i
7F��$�;��~cm��
G���2l��@z�I1��C|u#RxR���t��.Q��i>��%����Tvg���{�����c����d����mG���N�W�G�iq�U�Z�@"���L
��LK��ji�� -eW�L������>�y}"�2�k�@Jp��`9���<_������Ox�w\���yg��#r�������'�q��&x����,|���T�>���m��WI�����Ux���U��O6�4b�R�����	,d����4���� 0��l#H<�OC�����]%�����}�n"���a�a/J�+o��W�z��0��5���|���.k%�E�3�V���A�z�/�3�����WoX���������4����%�
�����u��D���w�/��W}a����n)��G}�8�M#F�v��,���\��e�!�?>�w<�	�E�����y[b����;�����XkcT�
�b+F�}g��W12�GD[�<��������$������M��f�o�3��b�l�d�=��?~�e
yH�MZ?7�+�^��3)��6�����?���hx���9q6���Ls�6F���L��oZ+f�h4]��f�;��������Ik����F�g�+�w�9A3����o��m�Ne&��\%X�s���V�������o/r:�1�q]�
����e�X�����15�#^�����������n?��z��d7���9N#>��|9�})/3��7_���m$�FAq.9}Kh��s���x5/70Y�����'qlD��3W���h�z���`��8}���
��G3g9������]`��?�j�B����S=���4�_�;�3g���C��<bo���7	>�i�����C��U^>��0���Ey�j[�������(18v�H��nCq7$V�0kV���g�cWlT�{����������Z6��:�	�N�ICw?�����`N*	 ���a��D��*��3M�l�F{?���RT��r&�PV�sf%jqf�;YIh��D�q���u�Q���a���h5P7�Aaw����_a���D�Gaw�����o42��Ki�q��Q`U�����g{XAQ���+�f��(���@��8>�e8V`>"�����vI����PB���yf�=B����+l[��/~�������&W���)�V����������4t��I�����=2R����X����#��c��m�%^�����w�y���U#����H�|� a�_���g$p>O��&��r���8�p���>.r���	��	�aH���y��.��m����������b�<bo[q�#^p������|�Q�5uxe�u�-��W%��;7�������'��7��N�9u� ��k�����:�mocT���b+F��c6�H=Zj���{���W������~Q������������/���|��3R�o����*�~���=Ex�����x��c7Z��g�����,��`!���|���.t�\ihd���>�|�
�]�f���������W�����������<�+�B�t���&������{�+��W�����#�ki���������D��)��2N�we�,.��,)5�W������W�o�6B�P�]+B��IN]G�"4�/��;��%�&=�4�|0���^}��:�f�"�f_�U=�a��?�y?w1�G���g��ef;���{��������2�_Fk�?�,_�Na�/�g.�Q��Uc���)��w�4N�UNs�eRY��8l�iI�t���m�����O"Q��A�������f�,�d�jr��Ql���M
�{��|����b��	��I�^r��3��
P'���^��o���Pr>
���D7�&�UN@K����8j�2x2}����E�����#���]��������l&���k���O]�����WY�y�q�����RI�6����'��}V�$��'����I(�:B@`���
$o���M����AK����,Mz5$B)b�<,��IN9��]%�����O]���������{���^8{�"9�1�_W��(b�>�
�F�f8�z?����O?�H��~.1A)y�*M��9�'�To��H�3���og�b��~��O?��������#q�v�^����A"�T"a���(���tdo��k������|�eE>�����/1���T#�|8�RM��d�<�z��;�F����	$�;�LC��#g��F`J�-	��M�\���_��l������&7���p�.lu����ar��0S��;���e0E�3R����uR���U��k�����RxP�)�L����M���'-�F�U��	n&��fq���8����m�n�@P$�<s����[,"m��s�r��:u�X"������B��b
�,�R��6��i54��,����N�7/*��O�����uU�r�XB��t��P���.C�cT�����t��&!o����n��(Y�_�����N�����	T^����D�nh��Q0p�8������l=h+j��W|u�����S��&�W��ZF����M�(�m��h h+j"���&g���Q�9j"�>
4V�(�p��hrF�����r�	���5
P�&����g��
�~|U��eh��Q�z9�&gg�+���5RQ��"Fa�����^��e��Q�N6�@�(�XQ�``E��������������������5��y�p{"1� ��y�p��x���U@�O%��UA����5�z�T?1� �z��I<Y��*�<�J.���fph�W�fLq`���
wI������<���5�BzTp�+1� �JzDM�x���UJ�no���N�8�j�UQ��V1=�pP8�i�)V5=�,J<Y��*�G7��W��iX����(�d=c��c����w/;�c��#����5�zz����]������G�E�'kX��8������iV==�,J<Y������L��O�8���eQ��V==u�.��n%bq`����u)�d����4�K��q`����u)�d����,�K��q`��S�R��V==�C����8���	_�M�T�dJX���%�'_��.-�j��;5��v����2�������Y��4��UbpAX�sN�*N<Y��G}�ej���<�F����!'�����!'���	���G^����SqM�����m	=�8_�L���A#6B!
�#`Z
�i�gz�����Wy�P?��i����-8�#�4b�J
����������.���O���^�.|[�@��Ws�k������Q��y�E\��V�D�vRV��z+8���V+��Z=kR0�������"P�`��I��X�,��:}4(��gQ!z>����1���|��`o�t
~���	���NQ��~��}o������#p�V�h��@��K\�W�fB{����T����\3A�4�|�|�)���0���4�
Nx+�U;(�(�bt�����l��#%4�S�5�=���E��AgVk�O"4)*��^�*�����!0�G�v\VXji�Y~����e���h���M�!#]�b��Dq��h^�}��l����p�I���	����7!�	p��b�b+Fu��	�����h^�{����.�&x3�����7!Pp]��X�_���Rg>�HX�� ��^�
v��6����� ��H?j��-FF��u�����w.�e���v��r���RH����%����m���:�s������#x�	,�d<�Mu�� ��G��ve��L��p|��	0��Y����~ H����������kT�k8u�LUZ�~B�y	|6]�H(S�"$^���Hl?��*_	e��HT|�O�9����q���`$�;�������x���Ht���'���g3��x�($^���=��y_����DOD��is^�m��X�r)	/�>a�Rjf����e����U�L��H�x)����|��2Qz�t?���g���������v{���7^�E��_DqK�R��U�Y(���2����d���
���Wu5���F�����5�>���O�����&2+����4?�e��(FP_��y������?>��9M���t
��z�qDl��h:v�O&Z	:8f�k�6�Hk�?�)n����F\�*s���������ksc��&Ce��8�fW�3�f�0o���ywt�����.�n�-�������gW�����J$�'��Z�\S���Z��DG\����;��<��2�W����E��.�`�'�L3�5�+��	{�����q^��|��9���a�:�f�<�"N"Te�g�H8M�%��L�f����~���pK�Z[�N&��Q���3��*LL8���s����FL8G�E��Y"]�b��F[>J�X�>7��s�p��7[�2���g��������&Ce�D[�?k��G*t����W���)
�0�!��=����^��!,�wU�)�+!���?*x���w��.��������o�X}^\w?�b��O)��ecf�W}~��o��Z�v>�vU������b~�/bX���A%�]!��7��M��L��>�r��0��w_}��W����6L���������{����>~��������wL�����7�����S�M��
����M��W������VY�3��������"O��L���_��7����_}�������`�s����/���=���?��_��������/�����_~�i�G����������?�E����w�D�SF������O������/~��O��?����?|����W������������oi0_��������.�����o���?w0���~��q�q��L��l��O�_�����N���O������ mB�A�-��>!�z{&C����������o����6�����nv��Go?��8���O_���n�����U���J�����v�������o��_~������O�?�u������'����7������/(��������<a?m�j����O@�������N��b^a����!�E��������Jp%+YL.��
����;���t��TJ& �&�8��~x�i����7�����@I�L�0����Im��6�`��1�*�p4�����6��@��������6��>��r�p�z�	�!�~\9�'��r�����0���qfn�?��E�Au���M��D������������$zqI�����8-��������[o�K�M8��UoU�^Y�/Y~�Jr	bF����j��;�����2�r!k�pV��V�>4�w��f�Fb@Vl�:��'��S�y�n�b+F�+��p�9_z�D�~�f��8�����\���p�8�m����x�O��Ty�2�d�	�o��n�}&�������=f#���0�}<�	wQN�����}�pd��}[���e\a����2��k���\I�b�<�9�-���-�x|B������|BbyH���3�����P�'�!L����cB>(�p��WE�j�j���	�Pu�Ro�`=�� �!�i��$��m�7��aNlD�����/Z�M��9I?���d{���������������_�����)�3�3Z^������?������?~$����fs'o0w>�Q~���7_9��sE��~��o��������nw�_��q�{�R����r&XZb��/���������m4��R��]�'
�o
�:���r�h��G�����F}2�v��GTM=�qD_iut��e��e�$�b��dy},�/��;������/�:�[����}�G�n���I=������������X
m_��_MirXe�0��p���`��S���~��`I�_���B_}����a�0�3����_��x�����I����?�Z~����������_�*y��������2��Nh&��o��w��Y�<�	��w^�x>���w�n�v��>�����[�����v���j���� �B����;�������;����N�#t.��������Cf�qw�r��e��P��P��'k����G�����3��D��[��=)OSj�������A&�h<4���iU�l.��:�Y)���3��L���G:J�R�(Q&�oL�$d����@�\��dD� �!b8:��D�����j���h��X_�B�x7�N�I��^��Q_-�������4�7�A��8#����^f����
����� ����vp��0��A\�P��u�Hh��u���J�f��j&*�d�:N�/�Vt�53Q�3�����sY���"�%�l���#�B��L��j�w����sV�������0�7�;33�.&���]c(Anu��:�������e���������L�HG��=_��~�Ri������]g{+��������u������o���v�>������t*umW�cE�����6�t�,����w�
��3�W�?����n�"��+�����z��A�8�Xq��B�������8O��i��cC�l!'������i�E��s�v@g"�{��[x�|c���{�b�M�3���Is+�c���b~/m�o��;� }�C����3#����zu��sbH����:X����;VY��hw���&��|F	�Q�xeZG5��g��Os��i�5t[0����R{e���5�,�'��hKh������Q�����9���";#� ��������oA������z!�F4T���V3e�u$/��>+�p��{�����-'��#�`�A��5��h~Z�I�Ju3U}J�a���'����-"�?>~'�a/J�|5����p������UHb]Q�.$�C��h�H"E4�xC>L0�5��F������z�d�\�������}�/h����V������X���F>N��z�_n,���7��
�eB�n��Zzej��7������EZ�n�� !BV�03�Jf��g�f%3���Cz��."���,��k���g�����5~=���>p�_�>�l��=���J���##�FQ���������gn;W��;��%�uWs6 4���&r�&�o�b��Cn*b�����Md�M�c|����:��Y�}t���������2�����#)�nj D�������w����"����r�u8^���G"�8BN� 
b��W����h���F�"���kq2���s�7� NN���|���%�G�x�� ���r�d�2�-�2��A���H���:W��x'�Dp���A���Qd�W�h�aW�|4�����bD�����!��Y�rl�{o���U!�����0�A\1[�b{�5�� ���L]4�����1�eU,{�u]�[�Z���^&�?�O���� �*� �����+��dEQi�Xy�u����
���fb����� �*� ���r����� j�+�m,�b!��P��d�	�8��l�*� ���+��'�����vS���q@�����hp�1��gU,�A,�@�@>�6��"�8��h2=�b���+�q��������N�AdU,�A�{@�Wn�t��8=�8}����B��"�=noo�n��8}�q{�bq���}I��p�qg�?�X.�l�|�?/8������������^���]6/D\~�qm
}����R��/8�����/������4����_0�C�=�tW��W�������^���W����j�}8�-wZ��~��D\r��G�s����z|����]�:�cb�������W�RQp��O���s/�~�mF�EGP��/���EG��$o}��
qT V�{f��%���+���X����#	�N������ �J�Bs�L�'
Q�<YP��G�:DX7��Q��cO�bz�i�O#��0��['�A������O��|��+���'Gm���O�Q�Wn�)�@[�\"��C�� 7�}��QS[��.{c�s�wb��}�:���l�������
��U���v���0u��C=K�����/���H����Sp��nN�N��9;%h��Sk��C^����w�D��j�
��%�M�zwS��e�p��{u�,��U��L�>M�z��(����h��������Rr�DKl�9;����t%��ea����Rb��uS�hX��8�g8��)�g]���>����:���,&�R�����W�'����}�������3�=�I���W��C��N*f����6��0�a>��RA����&�+����Pi�Uw7�~��FQ��0]Y�fC5t��>�����z7:U����{O�SL����+�z7O�p�����F��n�v�>j^��	����Z��>��w��./&��7�~���UFMt�yC>�uW���;�+yb��CP�,|���l�;����!�q.��2�I.pf������	93
����g��P��`;�{�UxW���y�������{/8���4���[l�1�]<�@���3�^p����V���U�P/�C��X��m��������3:j�E�~o�}[��	��C������F���������^�F�����h���o��Rj���_5D���P�8��a)�Z)�yo�s,�P���h�y�R���O4��9�#�����#�z��f�0b����^��:�3�p�.�����`�u�xp%�r�g���]��6���;��l4p�#�����6H���[��l�4#����w�E�G{��w�G�u����k��l����������;�%-\�K<nU�;�%�F�q����x������l���~�2�~g�$^����1E}��4����kd?��HY:�:���F���Z���w
Gz��~,�:{]�Og�O?��;��9}�;^p]����J��{W7�S=AD�2T�0�y�/r]������=�^�����^M|�zw��S��`Z��������R����?�^����������T�asoZ������wOx��&S9w����������T��h[�ZP<��,���Sk*���V$����^��Y*�����8��l�V�x�J}�{E��R=ADs`��&�����k���m||����;a�	������������f���c��������?���?��c�2����������~H��6���������_�V�W�9���z�-��?E-�������~K�"x����������>��&f�{c9Pxu��.�ge"�����:og��E��q��������ER���N���:����v}(�u��eAQkDx��y�����u5$A	���kS}��EY��VO#h�{*V�����@�d
�F^��H0Q8���(�;��8�JE��y��'@"���A��J&�G�����BHD���H�A�*a>�;�� ������h{�q���sw�4�A��
P���N{��A�����/�����VW���A���r��:����/	�����>w\����h�C�����"��M����:�����VjW]Q�R�	�� ^PG{V���{I�� \q��'a\�^�O�FDX)zM��uw��A����A�
�j���9�� F�X�}�U�PqF�����8&������*� �l�d���eb%�����:�+"��8��D���0
��e;~�^C�$Oq�+��|�^��	}��x��h'L��J#/�b�:,	�� ^�&N�l��Xy=�����������8c�=}N����>����|�>s��y��g�������<��)�<���8���y���@<���e#>�jq��nTp81�z{��6oXO�F5#���	�/��:j�+���}�x�PC���h/t��;Fx����~~(�|�A��!B���<�x�
�bn����rz�,�����A�Rn��	�C�0��W{���p����+GO�LC|� ��'Oc>��WN�.Y
{\k���S�@���C���W����U����N������/B\k\EV�BsdF�ae�!*[�1�p�/A>���F?"�Jw�k��k��p�%�1������k�0�� ��9��r�}"������c�t;7���:��t�#�?%�G����D��!<F���{�Q:�J��w�F{.$�G���=�ei"<�K��U��zaGj"�;����s��#��o��?�Dx[YO������u���l���O���L�qO�4R]��(g�l�}�b�����`���7���h0����`�R���_?�����|�a�������Lt��XR�^�]$�r8G�{� ?������{�A&��v���l"p�A���"�����x|#C�w�����y������z;�[�q�;��:v�O�zD'��z!����3Um��B�8�(_�#���*U�v���q?��2],E�Y���<����iB�.lg=O�!�4A���]}�*��h���;�>Xbub�4%��o��������O?��rp����`�%�	�������Dt����������E������Y�mk���o~�������|���?�������������C����W�o��������w��������D����������{�����'���|��g���'���gG�?k��_���-�sr���������>~xV������������x�_RE:)�������L��\�W���U5S�|��$�^���6��#gBR'�u�+
����f�$O�[uN��Z�T�*��J�!�p�����3�$S����~Ta�����y�����u�>��)���O��~�QC;�Lc�nW���LBL��f
��q��mioe�='lg������	��[��C6m[�������_��!����$."�s_Wa*,d"�:��G����n��}�C�LD7��>�����H^�����{��=��n�^I�IfWSf"�9�b�+gx[�yH7�f�@��LD7�n���zM&"��S�..e"��s�����3	�����}��<����]jc����n�v�!��G1A�q[�>���U~��$�l����+��d
�������z��������4.=�LD7��],K�e"�97x�C�� ��������;B��n�
>����H8��e������z8�u�Xsn=,��$��5'����D$p�r�N9A/�L��4�
^��|��yH7��t�}�LD7��@��LD7�r����/��6���r�n*�p&��r�&��I?���9H5gRb�-Up&"��3)1��d"�������T���n���]ivg"�I;<u)��r��Dx�������Uhw���}(}�LD7��\��6���������T&"��3+1�-�e"�IY���'#��Q���n����e��G��xH7�?A]�LDw���������H�f��]����nN
o���_3�+_��R��jO?���ON�������H���v��]��97x�t)'3	�����<Y�D$psn�V����D$p�h��YJM��\��Y�K�k2�����ma~�Ah�q�;�uP�-�����[�����n��6@��LD7� ���[|&"���_=;���/a��Njbh�[�9�'��u�u����nG���wb���&����I��'9`� ��;RNB��3�e"�5%���j�!1�YS�J�g"Dh)	qz�R����$�Oo����k))3���LI�n��;������j.�w&"��3%��X���oJ������fCM{�h�q?�������3�C���-�s����O2�o���}?�'��H����{�^3	���������Kwp��
�+-�����u����ON��p�.������q(�M&"��5)�F���n����������L_$-m��#�P���s:�)������8(��yx��l�����&���I��;�W����)��!�	��@�
m���j�K���n�m�u��R��H��L��R����H���v���{u��D9
�4�m�[��LD7��<���3s��g"���"g��*��d��i�8���3	����\�w&"�����V���y&���S)Z
�|W:;��@
97x��ap&"1CX7�0*�-�08�n�g"�Y7��d"4:�~�����p�SB��������	�%F��}����D����`LLD�s�;nYK�83a�(y7���e
"C��K�N��23�yX����LD�sN���+�LD�s&'^/_��b������f*eef�/+k�ho�RWf""�9�o�RXf&"�i�	M����d&�<Y+Kz�������sz�����p��3���53��q���A���'^!�-����31X�Y�K��C����8M�����*\f������	j�e"�M�d���Vw���������+kML?Cu��C�3��
�(�(�Ty
�Z�/+L��D8�V�.�iZf"����fG�n�%1��������O� 2��3�&�RZ?���&�Z3h��"e�jcn��i��QnTy����m������M�x�8����3	�����g�C��d&"��3�
}(7��D8��'���J���p��$xWn:��p��'X�8���5B4�0�L��M[R���+��LB`�d��S�-�DD&	�{F�;��p�e������O�z'3N���Y�z'3��Rh�2��������������e�M'q��$��=�
A3��9b7��`f��[����|y��I�6gN�+���D8��M_����pZ�B�����wf�<�Y���we�LBd�9�����H�LD��.(�/d&"�9���D3��������G8����;�5�b�M�.m�(�BT���f���Ff"�0i�I�Il����o�Z�>Cy�>���i���'c�`�����XR�|��c&&"�Y��������g���v��D8i���%5���W;fb��vo�,Y�u�M'�lZ;�u2t#l:���u�ZXu�6�xf"2��Se������Hg-�:8x�LD�s�V�	Jf"�s�,T`�LD�s��C����2������[f"����\����k����Ea�j0�P��$D����/��d&"�Yw���iJf"���*��l<��L��l�J����Le3^iL���Sd�)�8HLb�U�G9��S�-%k��a��^��p��d��^��p��d!����{�J�R��|���pN3b�d���p��~T��d3����ve&�����������p�w%���V�	�B��`���-L[�g��8��9�]�Vj�����tf3��������Rg���J������������=M;�1L�U&!���V�c_Vq�LxE�v�X�Ne"�5=X����a
LLD�s:�7�2�]����fL���^�[>J�>5��-2�)�Zt���Ef"�5�Z���$3��Q�C)/3����E�+��N��e��T�LD���b*8iW>{�L�SA�f
�q���I�6���W���Wu��/W��d�=���s
�l(��Ad�93���29��p�}~r})�2����vCv�P&'3��!�YK�N~(k�f"�i%M�I����~��$�41L�n������JS\`�*�Y��N�R���LD�����T���p�4pKY����<������D8��3-��2���4�dZ�8[f�n�hZIS�x����������Q�������o�F�����+
�LBb�Y���j)
��D8���5t��LD�s��������pZ�u�:8[��������UXg;�D��9��3��&Jb����n:��+a���`sf'��+���pN�d�t�2��S%�}��D8���[f����Y���)]��D8�>��U��a%LL�*�:��%�2����������p��~��x��p��~���qf����fVKgK%�l��~Q��'3N�"bJ���Z�d&����Yko-�/��LDd�9OJc�S�����Z�t1C��f"�Z�t�1�A����4%�VKv[f��Z��'O[L���:y��:�D+b�`�e&�Vk��
v��g"�M;t�]�_�Z���D���&�4�6�/��*�U"2������U��e�0�$Df	��;1�:�c_
��D8��L�&3��Z�t�u�V*3�iE,�*�Je&	!�<(5=Y��Z&����&�+4��$D&	�}����63�����2p����<�����Of"�����UO����Db=���W��K��������n��V��ff�z������Z�#���Xs�'k�K"3�N�hJtc�MN��f7�U\�^��`&!2������2�LD�s�TkX����o���e�iJ~���l�IH(y�:�+�v�LDf	�w9��q����V�uK�����|R�i�����&�:�����Df"2��I�a�LR�'4kM�u��3��p�e����L$�s�4�]�g2�����i�N�Bb�0��4��
sY>����`3���������}���a��4�����^����l��R/D&	)AQ6<[6��������voX�wx��e��"c��Sm����/LD�����a����kZ�X*p_V#za"�1��]u	�T#b��S�.FX	����|7X����Fo��2H���B��m~�!�JLx�y�
��a� 2���gab"�����H|�8X�#�����v���?!�2��Z�'/Ln�rV��pcr���'��c�E��U,��U�%�K� ��L$�%ga"�t(s��Db�9����o���'&"���ze]��d&"�9�M����*��p������������8�������'�6�-�A��Uf"�r��*�������8���r��LD�s�d5���^�H'�%���j���G���r��51TS��H�6�a��-vb�|XB�=D�����DB@=�J�>�
�"���^��su�y\f�*�=�h����z(��7tx}� �=��T�����p��Jw>J�6��V��
\�2�LD�s�9Z��]�&"�idi�������]������6��+3�7���6��J33��Eh��&Jf"�����R�(��p��^���83���ut�[�"cM��c�,t�U������d/��oX�9�*fl_�����&>0&�J'���YUr�n�z0����`��T���NLD���%��->1�iS����������b%��z1��'&w�
��)qAYf�*�	���y�����R}���p�b����;1�����X�Q���������6e����tP���;�&"�9c����LD�s������*��p�����.G<1�����
�����A1��M��!��O&"1�������������;5?!�u�ar'"c���G3��$1���:����{�X>�~a"�u����/LD����X?��p��u��3,������Y;,,����X����4��rP��-
�y�_G���fZM<���;�ma���;���T������+�2�����_�a��p����E�U�F�!��Ym�L�%��D�j�c���u���Dd�I�	Q��������4Z5V�n*�;7�l��3��[a��<��S���I�LRJE�,}������|������|[����8�a�
�Jb"�u�GS%Hu�0��X���/LD��n�c�5���pN3�N�4e3�����K�����4#����lf"�����Z�V��pZiS�+k����2^W�5��;a� 2���}�t�f&"�ig%�[��.[P�0��uo8K�n�5���opZiS�W�U.��	�W�:�M�����X�����Co�����A;�*������Zf��m{�gI_vt!!2Kh�zi6D������
6ga�
�R�v�DD�u���4e3��W9�0�N[f"����]�����P:m��!p�������Waf&"#����=����p����da5LLD�sz��!KILD�sz��lf"�U��`�f&"�Yw�u��s�fY�W�n������9����33��}�K���������}f" �i�+����p����4�z%u��
|�n��I{g�l��wv������!���*i7���;d&"�9�z���!3�������p�^O�r��;d&W�h�+���p%�58�vq���|��9����dV>I=�f����X�C�LD���<S(5Of"�����}�y2�����W-=����@^E,�I�������H�[L�DBd�p�'���01���xe��23�Y1b����03a>�b=1�z���b� ��)��K�>3NJP�I��c��3�$�����uyD���8-?��:�A���y�amX�=<��$$�X��
id&"�9�J|�G��p��Gx����'%(D[��/���#�7���%7��42��|��'x(��0���y'����W&!2�����<5�LD���~�e����y��9���j�0���@RE�lJ�$�������$�LPB���P2����iPsy%3���=�S<3����lf"��A	6��P2���v�-���f&w�,��&q����LDF�v�C����*3��,�|%�d*�������kK�:X��9�����<R�LD����q.��e&�i�>����������af�3���]Y'���f9T�i�Y��z�d&"�Y��i��r�7Yyp�#
�)`���d*3�?���6�<�DDd�Y��e��$���k,��D8�e������P]��;��+����x��o�v���FZ-avY=���R&!1Ih5B��
<��LD�s���B��D8�^-t@�LD�������R�|�L$=��&uAqcY�>3a^PXO����P�$Df	g����LD�s&(1�R<d&"�Y��{e&"�is�����+3YP8os�q,��3��)��!�q��������i.%C� 1�Y���y��NLD��&U���LD��&Uk,�qd&"�9�w�.�����p�zBt�%2^��������E� 2����������
\C���do�1o�o8
���rbg"�M�lJS����u�	�Z �Q�.e��LBd�Y��s��)3���o�2����xJ<��t�2�Sb�b�CP0��g-�:��xb"�3��ZV}�LD���T�g&"�Y�q*���D8�R��4c3��;3�3�a�������
���0/���L�W�������E���%�b%������3��f]HVc�8��5�$�.rf"�V?��"�rw�i�X���.�(w��:��w�G������T�xy�����Nw�����]d���#�E��E~p��'/����2��E�����	��)q��*��Dd�9��F��G;������)�&�&X���x��M���O""1SX��X�(3��qbu�Q�:�e-l:bu�Q�:�e-l:bu�Q�:�e-l:bu�Q�:��6%������Do�����d�d�Qu����m���q�����	ks�q�R�������S��x��p�gS��3��D8�c	�Lp�p&��0�	��L�3	����O&g���pZ1�Z�,d����Zc-�:��|�����8g~29[����p����7�����lY2]�V�L$�1��)-C��Z��d&�
k��)�Y}&!2Khf��d@�e&�G&��a�a,Uq� 1��d�q��NLD�s(�KU���gMP�P���D8��2a���D8�1�Z���t��2+b9V���k��(3q�e�
�W��G����}~VS){2�}��2����{&!2���
�v�LD��nA�|��Bk��D�gc-m:��tP2�g-m:��463�����|Y�13��F����#2�=��Lc��=����x�����,y�kc=��C_�g"��3?��-���D8k~2�2?�LD��N���g&"�Y��	j�e&"�if�I7#�=�P�,39��:����^�s�A��7�2f��1�ky��IL������@q��D8k~���.�-�s�K7�gj��p��dQC�f&��	�����kS�����}���JS6�#���b����LD�s�'��e�����LO����lf"���aq�4e3	������j�]i�f&y�J(�pj���g"��S�}oK��9����d	z�VH�����T�Q�j'3N��A����+m�����fu5�a��$�l��d�j���p��d��K��D8k~2C5��D8g5�eq�U������g���,cyo&�p����
��2����4�~�By�130�{ZeS�0^�.���W���Z��T��I����L��2B�����K763������^Df"�s�_{]z��pZ���\�*���D@`���R�A����L�wd������:�Y�����e&�Yk���/3��D8�I�m��g&"�9��u�e����5Y!���*��2�u�V"���lEl?���x&�{���BH4��dR`���k���p<���gMOf8��LD�s�4]���|x>�������5�v�H�6cN�mN�����(�i�F7�s���p�}4J>p�,��Sn���;�7,��m�2�C�����H��i�%��,�p���U���x|��|Y��C�;�pj)V���xb�<��M2�������H0c��o�M���	�	�(B��XN��D8����xb"�u���wb"�1���aw�b'����T����{;��������{<8�f�x{c^��}a"�Q-�n.���0��Y�5tK�O���p���������_�Z��}a����7L��V���g�j��s�
J�r��LD�sn�Jw���������^��'3���+��r������S��d&"�97{�������������'3���?��.�Jb"���QP�O%��D8�YCP��r�$&"�i�&��RPC�K����
%�
�����Dd�Yw�q���:��d�S!�xb"�u��G��'���=�h�B[PK�-?1�������p����*���N+�J;��p�K�;8������\-���n����'��h�k�Oy�D�6��V}9���n�]S+X�3��B�5��i�|�Z�0�����t�%�8i�$�vk��/LxO�YS+m�2�D&	�F�m�t���pN������3��Y������Y����	����E���}����� �D(���,��B���,�t,;�p�#�v��e��&"�Yw�a�����-�9E�����LD��D=1����"3����UMI�i��r�$&��iXe�^<�����,a�OV�eb"�3?1]�eb"�s�1���;3�N+@+��._L�0a-���V���|�  �i�X�j2|�~�qO=������
+ ��l�b�$6�9S*c�r��LD��j���nc����Lx�n��A���43��������Nf"�������eb"���1�+�v2���	�\N��D8kF��c�LD��fT�[Ob"��^�7�[Ob"��R��"l=��p����9H��=��91K[O� 2���W�z������r���)R��`�	�����|��b%���Rg"�r������S��Ad����4G��Z
�Z���t���4;�����;�q��
��2;�L$f
�t,���V�wM3f��]]�}W�����`�_��;3�)���'3���X�Of"�3=�|��D8�a�P&���p��~��������"��K�>3N���:�N�<.�Lxug��
2�>���X�bf5����HdV��c�]���If"1����T�k�T���p�����
�/LD��6{���UY�������,�����*p�A;y������]=~��8����(�DDd�9����e:�������������e�!��:�'}���
�aMILvK�=���.
q�8�;���%��XC�{����p����r�xb"�u���Tk��p�����;�]�������I]P�5�H�*7�Sy`�����$Z��Y2XP	�YBJP�g������9�:���G����X�N���u"2��I��J����g���fwb"�s���@R��Hg���������l���<Xsw��<^'����tz,_fd&"#�y��}1����D8�C-�Eq6�o�3�V������k���Rcu~���L3	�I���;������p�����4�3�����L�2�4���\�����R���$����yf�+XK\\#@�ku��2Ih�6�������C/�Z���Sy�-3���Lcyj���'���Sc7eE���������-6��Ad�9/s�U�����p���X�u��$&I,��&q���-�q&���p�y�A���Ad�pfT^������gqm���D8k}Po4���D8���v���vu����d���YI�������2sk����=���D8gF��)w��D8gq6�5���D�p�����k��3��L}X`�ILD�s�'>���Cf"�u��Gf"�������Cy���d���r���w92���4����/Rw9hu>�TZ��>C=������ ��U�q�gx���0���bYP�D�y��G�o(�{����t�2�y������f&"�9���M�S����LO�����D8gz4�f&"�9��`� 03��E���pZ!V��=f&���v E<I{�vWB��G�o8Ic}�\_�����$��3�7e�����"���Lb3���}��Lb3���OB\��*3a�bi�X�:��k5�z\[����@�DD&	k~2������g�O�V��D8k~2X�	��B�T���<1����V��D8�;�#���'�����+W�LDd�i79h���A��af"����mO��Z����	�)=��dK�H?���*���a/=�9�!�'��t�J�I�Ll��$��2���I�����6�����-3���D�2��V���w��-3a�;���c��o���`s�T1��Q`f"��@��./�e&"�Y��Q�'���pN%N]y�����<-��R��g&"�iwMc:��w��syB��VAy�E��EB��������,���-����LDd����k��'1�N+JjC�����D@�yZ�M�!��T�if&��<���P�F����1h;f�������`L�@d&"�YG�����LD�s�'C��>Df"�3=zxZ����4#O�2��jm���.3�����e&"�iwM��e��u�	�v���h�+��(������U�0,
�������Z�t�R�g""N�
���$��S�d�+V�������*�B#�H
�������b���i)��d""s�����!�4��/��f��
��2�����LBd�Y��^6d&"�9G|�"L�U�i�g-;*_N��D8gF5jh`�����|F��b�d&�YK��g&"�9�����s�40fN�O����T��g&��7�^�����>���Xs>9������������CW^��$D��T��1��9Cf"�����R<�U���8k~�U�2���	V���@yb%�4���)�U��;U�v�y���'�SE�
��UbU���!�JL����V��:�K���8�Q���0���pN3b\���ff"���d�&�d�������;3��qN[�]OLD��6N��dBi�f&������p���R2���V��xJ?Y[^��DxO�y]��7���LBbv���R�;]^i�LD�sn���Jk63���O~-���D8��Tm
p��������������3��)���)�[��Ad���'����[O+jJ>�[��D8����X����pN]?��!3�������dq0U��fo�OX��i�0����,a-k:w�Nb"������J�Ylf����6J�X+XJ2���L�f^_J���R}0!�u����;3�[J���p���	e6�9��5���>� �S�Vb�{W���LD����N]gB>3�=u�y&D�3;\]U��A�����=��DD�-�%Ss�f�	s2E4�����r&!2����\�f&�Y���T^��LD�s
�yJ!���gM��X
��D8�;��Tg��p��dq��$&"�i�	M��k�Ub"!�i�X������TIL�$����d���Y� 2I8�E
�y������h(r�����������pZ�X*p73��g73�����L��d&"�9�����^of����6�Z�)���Ad�i��u������3�#�;����<�x,u��>����s�>Y"�>����Z�u�s�&p��~�`�LLD����M�e������M�:���2�g���L�.03�����.03N���>j��3�C���Q��B��_]ipf&"#��o�]gb"�x�@JTVeJ{63HThB�'��S��w"�{b�z����l��9����~�k�Uf&"�9��j����L�ZMS*p;�W������4{s�����L��@�J���*3�����V�I� 2I8O�-�,'��*[XK���d&"�Y������D8��lAf"�V���W��\e&�yU�=����E�Q�
7�2��uP�A������g9J]V
�uX�Y�g��H��a�_|���pN/b]�aFf"�V4,����Ki�f&�����X �tg)v],O2�;K�V[��/�"��1A��v����g\�cg���a"�1A��-"�0NKPH&��u,���6Dx��$�j���
�`J��s����&v�v����$aLPbmG_�H�5����/LD�3&(����/LD�3&(���������$�n�r��z���I�����n�S	9q���x�7���
�K�����f>��P���Y�4vsY����p��j���,U� pV5�����*��p����e��&"�iw9H�}T���zX&�
����
�R��/$���kTj.\�&"�9S*��r��LD���
�0-*3�r�$&�i������Jb"2������X�xb"����Z�E�z�*����[��
��X��LDd�9�z��W�/LD�s��*xW����{�PN����+�Jb"p�F+J4�TJ�0�5�����I2��Y&����WT���21��N>��D8�^?k�,��Jg4�J-]y���HV�����~�C��d�R�����8I�&I� 2IX��u)m��D8cO���������&	gY��������-���I��JA����(���D8g!�����#�����O��J�>3����~,m��D8��k��{�w���-����^������6�Sy���8����C�2����:SB,���Db�0>��p�K9S�L�%�����"s���c	<����|I�X��|a"����|��=�����4%��zZ^�����V �*�I��^����#��9��Ad��j�e-m��D8kz���r���S�tSi�d&"�9���R�g&"�i��hy��Cy�73����6{�|s}�Q�=��8�����BHl�@�'�J��I�a~��$������`&!2�9s*����53�N�J�����`f�=�9\�W��$"��i�����2�����K�����lo:���R;��l$�l�D��������]��g&"�I� ��������Lx����2��50qk��F���501�k�6d�_� 2�����Rg#��c�Ymy6���'���K7	�:p����wfr�{���,�������s��V���LD�s�*V�r��LD�sn=��2�LD�s�'��r�LD�sU�/K��0����3�:������4Yl�.��3fYL4�������$D�����)z��������7l������_��X�Z�M���������W^��p��~��W���p��hZF;��F�L$2Z�3����_�u���g&;K�[B��r�
"���$!%(��v�
"���jZ�[���3L������sJ������
g����L	3����Sm�xb"<rV���	����D8�f�[��3���}������D8i�'>��l��	���H��J��S�LD7����R*�LDd�p�����3��p�
YR:��93�t6������5%H���X�4��1w�����5%19���pni�M����Y�Lxki�~��Af� 1I8���~r�{���H+�J>�e����t��������p�^O���UC����I~��g]W�;qY9����
���L���)[���LD�s�z�uy23���8�����D8��wO'���D8��)�{�|)��d&����diuM��J\��Vx&�����&t}_Z(����LO����{)������.3����U{3��{}�����p���.������QI�����3n������x��N=�%1u�P�#s�#���X6�{a"�5;��{/L$��j���	�rd&�Ox�X7���LBd�9�������g�OV�������O|�Of"�f������8zW�2�����wKZYS��?�?(p��y����B��p�Q	�R�7��f&�:"��)�����|@���^�|�>���{��+x&!2Kh�Xi�$�_�<3a=%�=J��/���Ab�Y�4zo�,63�:���I������i4���r�$&��u��R�r� 2��)��fn��oZ�X*�.�g&"�i�6i��p�>3��h��=A�LBd�Iy ����L��Z���.{�V>�:�KW���DD�u�_���Ff"�����\�g&�Yk��n��$1���5�.[f"����n=��If"q��V��:����wf"2���O��<m�LD�s����KU����4P��������^�Ym��R�g&V��)��	��'�����C�l�]LI��0C��3��n>��\c�5C�H����f���[O�z���X��x�����<,	c,o�e&"�ioHCZP���@�L����*K�������92�2�k�Y����l&!2KXWB����gMP�3L�i�X��#v�	G�a��2�+����k���
�xhuB�w���e�����#�4�8It(jg��X���@{��D8g��+m��D8�i��������������4v��e"c�
��Y`f"��.�6������Vm���C���+Y����������+x�'3���A���v�������*���D8i�S��	^�f&����"^V��-�B� pY�V��:G&�d""1GXk*��0�Nj�d-l�db"��4���_eg��W]�9�Lv�J��
��P'��t�3��&Vg#5|��Yb�3��7|��O0ts��/sk�I2(h�������=�7�2���`�
cf"�u��P��LD�s�����������O���	2	���Xo��U��p��d��O����<F"<b�LD�sZ>���3��;���3����x�c�cf"p��X��v-l�Li�d"��heM�'���J���H���5��<��LD�8�����OB�rT�Z�tXcy�'S�A��u�](�[d*2���MI"F����L��B�u5j���I��6��?���� ���GW3��by�U��d*2�9����+/Ed*������i��G��M?39�V��7��]�C�\��N���� ��]���%p�5�CQ��Dd�����*��LE9������Td������[�q)�D�"p�jCN+hN;�W��d*�g4%A�l0C�f��
X���#TC�$d�6k�2A�LE9�i-���8C�L���k��q�����`�N����^��M�Y�|����LE9��2�k��.S�A��]M����rZMY*r5���2��������U�"���<b2Cy�*S�A��OL6���2������r��Td�kv������o�"��o�9����R,g*2c��
v
]�je*��'�U!zSX�;���7�Z�u�
���Df������e*"�i�Z����������s�����4U2�!g��'
�g�"��u��UyI(S�AN���F�4��$&*"F�L��������I�^�P�7�<Y��L<���'�����&s�"��S���T�g*2�9��Y��z��� �l�4��<�Tn�<����7���n?��M(}�Le/�}�����l��{f!2QX����-}�LE9g�2;Sn���r�Mh��Z9[��d%�n�w^��
/f*���[����	����;���B�����aUa�~�p���<�LV�ar.�S�y.S�A�:[F8W�Td����S_^��TD�����|�3�2�T=�7h7buQb���3�,������X��m�Ys�.#d*2�9s������r���E�e�LE9�<��e-^d*"Y�.*�n��c��6Sa���|��y�Q�
�6����b�R�e*2�9W����v�Td�s�*KK���� g-���Pj�LE9)Y!.��g�����!�:*����cy������d>�Z8B���<a�U�)Oi3�����P�"���m�2veN��� '���[+���9y�"rk�V#�x�v����;�fK����d���LBf���*�P�e*2�Ys�D~�"���N�����-S�A��{���V"OTd��jd�������J2��6���*�g�A���2��{oY9��U���LBf�����A�j���D�����E��~�f(O2����d��8�a��M�lX����*�Z&!3��^�������� ���V�D@�������T�~.��LE9g~�h7��� g�@����i3��+�
g2��3��b�;.�:�RGd*����7i=�c>��[�"3����:��[�"��u]��-S�AN�U�{�����2�C���j�����.M�+�Dk���-�&i52ih���T��
����8t�|��BBf�3��C��z/TD�sV�����>^�� g�������_�� g�@3tv�%rsT��-n-m=yz�E�Q���s"���-%cY�'�3@^���r��f������b��9�v>H��C�c7��+���B$��,V;t�|��BEf
�5("u:_�~���=�e
!�P�\1�0/k���~�C�~�C���+����T��L_�� �%�V�Z{w��!�%�XO]x��B;�M���{���!�MT���A.pV~���#������{r"�z��8K���\ITd��������� ���6���N��j�;��a�Q���8��n�-lC����3:n��Q �R�����;(��m(S�A���l������r�j�j���k��3����
(��nLWR��M�n.�<19������749���S�LY�����;�x��>U���o��������O?���!~�~��/��U����������U���M1��������\�0��Z�����A|��h��K�2�_-�W��������C���6������_��������������_��w������_��?������n�?g��O�-���u�(�_��c������t��}�_>t�8v���?��o>�����O?~�����������5��~���p����m�QYC�����Z��Ok��,����_~����/��f��<�(�i�����������7������������_~x^{~a~��������~���������������>~�~���l�����|����������?���������_���~���������������<������?����J`~���?�������e?<��|���`���/��F��������y��'W��������:��s=���_~8X��pJ�������`��z�4��d��� �R���z*$+I{��Pg� � iO��� E�d:*$%�j���:)H#@����^j��Z
/	_�6�� ��U��;��F�9�4��� iH�Q!=���.�!���V������G)��_0��������B|R��w�i�B�Z*� E��"`�(�� 
m��(����_0�%�T
7��UK��(-�RN�DDRa�f@4Y�LR*
A*oi�`���V����}QG$%���V��JE�|���0Fb�d�����1�������8F�e�����D� �G��<�P��B_$=/i:I����g��7e6�0��d����aoKO@:;��h�������m��L�mg0������>Jp?�#a�����V����$H�7U��z�D��6HNf��������s����;�'F$�	��^Y�D�'^ �%u��"���\��T&�' ��%
B a$A��F��(i���.%C������d���7�QzP�8]_�{J�H��F��(Y�������8J�8J^	y�}�Q��m����{_\�Q
���F)���0����,��)a$@�N
������f�w!���&�$9 d��#8�	#	���O!�wr�!�(d.������wKy�����DS��GMA[7s����~r�l��(�T.�������3�_��B���q��hZ��MO@b����"a���F��uxo)a�\Y�B���{K�po�R�[r�{Ki��P�[r�{K��~T���������������{K�po)CJN�[r�{K���������6�������R����N}�sxo��-eH��=n�T��^��������v�*�����${�	�n��5a<���E�_0���N��s�z�q��� ��s��(e!p	�	H�|����X��	H�4�X%�����u��Z�U��r#`J �`:�X��M!@��x����~�������A��t���>�&]��f�g0�^��a���Iy��5��MT�N�5�����x�~jkU`J �`:����m\y�+�<���2~�����A�����k��
8�<���_����`J �`:����1�������x}}��-�L���qZ��QCyw*n�	T�.�<���:^��Qky��A���@2^'3���A��tv����O����������6A��sk�g�'0q_"4��6A�x�sa|���#	R��sQ�L&o�A��sq���yo�xw�k��t�3���W��d�' �_,��l��d.c<�|�{�6���1��t>����U�����������qo�xf]:I�U�&�@�[�yo��{G�����������u����$G���}/s���uH����@:;J��e4�;�J\�|/s������1��t>;Q�Ty5&c�L�����{6��,�	�	Hd'�ui��1��t6;�����p�1c<�lv��w E�L���	��=��_0�����\6}�H�������������~qJ���~��%���I�Nq�V�w�by �1���=�7H@�����e����i0�j���h��3@�K�cw�l���!��I�d^��&��@�x��?�s����>c$A�It7H��%�' =���jW��8C��d�
���q2�z3z�D�Q��^o���/I�����{_\�r�#	�������D���	��Q�?�� �i&+��.����GH���N���iH���2Oz�z�D,{���B���/n%'���K���������1R y�������	H��4�g��=��������%�' �O�~�=.a�<*2B�@?��0R =\B��Q#$��Azt����$XF�#����'��VN����{�p�&�R��B�����1��t�>�):��lyeH�w�@My/.c<��Jc?+P�	�	H�7�e��{VT��!�?��Cr�X��f�' �?��IC�������A�}�	d�g�%���m�aJ �`�^,��w��L����Sy&�<����lc�a�c�x3�3�N������	^e�'0q��n����	H�����qx�H�$��o�"@"<��M�����A�g����^��� �(�^@��\�f�y�d|�
RyN�1��t�����Yk�D='��]��?Jls	�	H�O�b_�Qf\�F
$'c2����#���A�i[�����[	_\�$c2�u
�����7_�n�������A*&����Q�q�}�,B��K���iH�z�S�����CH��y�p����AZ�����N��cK������T_*=�$���DF9�c�
���-���s�������]Z�H��$tw������,�$�"�~K�JH	#ix����w ���������{�`�4�z�$C����J�x�gu@H�(NFZ����w�x�i9���4l�`z'�$H2���P�p�	H���bY�.c$A�����
 Eb��H�)�!p	#��x��d���eHf�w^m�&�4�\vNdx��g�Dk��	��Q��������I����+�K	�	H�o|���[��R��+�;��J ���������'��	H�o����;z�	H�_�;����UO2����P���~
��N�x{������O@bM+�f�$H�>l�X�f�D����6�{J�)J�x��E�>�B��2��(tP%=�2���.N�+D�0��i�x���0t�T>�<��O@�^��`K�$c<�;�C���:'�6s�iH=U��2)\�AH������}�>c�L���c����U_��	V���$�/n�=@����pz��v��H399y�dv��R���$�' q���a&�0���=��SE���2�������@����	p��@�Z��\����%6E�x�\2��3c<�{]�zpf������]H=���O@:;�z�����1���]z!��4�3����w�+c<�}zGey�;���	�a)ES�x������2c<���]�P��1���>��p�1��t������@����I� u�T���	H��d=B"��2�k!g�' ����}q�
����{����*������A���)2��'MV=\�$m�}�"C�y��A���oS<C��'p8'#��0X�k�K�JpNr�d:o�����T>�R����+c�����
RH���Ijp!�L�
��"�F��h�_$���-B�~m��6�n�H�������CH�f��H��p!6c�@�R���#!p�J����J�kz���$���������x�����%b�����B�&��F�5�
��7a�4�N���o�C�1_�h��*����.�/�4i�A�
����C�I*p+�K5_z���	����/	�����5@��KVfzo�J�"c$A���C�c2F��"s�z��H��1�(�|q� i��@��=t� $������,�	 ��@�������ag����R6U]��H@����O��L���_��7���������������?m4�O���_���~��������|���������?t�0�����J+����������������a�;~������������0���>�n����_���?���~����?~���������O�3�O������������~���?�����Gq��t_��Q��/k��g�������������]����w�������&TP/���z������_}=���A�`�/���������?������{������_����~���?}4�����[g�������@�|��~��y�f��/����L�����n���_~�f���V��vwY���/F0�,�����J���3��B���D;�����.�����Z�5����Qz{St��e�3�}���z��2�=t�^���O�4��o��������O?�!�������A��9��_���n�Xw���j��������_X���76�0���_>�����w�b��i���_���?����?��������~lL~�������/>������e������������+�p_��������g�[�������K
m����l�qlg	i���7�������ys�������~��[�����|�������?�������?����`���������Q���{����XM����"����K�
!=x�E����S����iI������o?~�����:��v�X����#��E����7���m?����~�����}~���?���F��&"��w{C��F���d[n��;���u���U!���(j����U����(-�$����}CF�I�]�1���vI�����aI����-	!!
���H��W��:A��H�W	�����sWu����L0_��j�����o���?���O����M�i#����w������A=��j��u�Q�wG�
�*���T���-F����3��FQ����D=�q����i�9I�� ��8�5l�5�?%�7�5�E�v�p<�C�%Yk!��{�Dd-���&����.�0�^�i�l�1��C�$"�c�������E��d�?����uD�����M"�Z{Yw]d�����;�(R�] �nx�Dd��q[�"������y�]e���	"��C�$"����p]d��A�^h�N�N"���
{���E6ZD��^�0M$��l�a��lD=w�������6ZE��x���*^�ja
���v���J�������v8����B#�CQ;������v���B'
^������&�����m-~&�����UzQ����|�6�f����m-�@9�����n���v>V���5�����m�4yAi;�J[u����]���jmH-(n�cq[�0$��w���^hI�(o�cy�Z{RxC!�}�HpQ���W]�J����;V���-���3����������_�:c*(�q�x5~����/p�w�*[FP�e����V+�����Hl5l	��$��a�Hho/[\gNh��1�hhlNc1��c�$�k�Mho�{�9��+/ �S��e����`���h����`G������6v���h�Ip{�EC��h����5�2���6��B�hxUM��=Je������
�}��(�a�Hp�	��$��;94F����A�&�����
e�����W��G��we����
e�?����A��p,s[���:7��\}�AQ��c��[Tun<��Up���s��������scE��6����X�6����������P�����Q����P(��s�]�k.t�F�����=~^-�	u�X����
&�����5:T���X�����:w:����
f�����5T3���X�����2w����[��2w����B�jA���\���ZP�.��:��r�]�k.��VT����5���U�z�r��+��uW��������]�E�ilOE((���������]�k�s�b�"�c�{\uD(��bl�5n�3��@�&�������X�#a>�mcs*b����%n�Dp5H�xS�#�����zD�������E,�}�Dp
H�h�%�u�T������56������m��Z�#��q�u�T��H�Aq���T��q�=����\h�����:s*b��k\����=h��k�*8��.8r�"�^�NEg��������@�&��+�u�r���^�NE���������Q��c��Z	yT�~W������Q��c�k�S1����G�T�aW�����*7�\�����rC� ����Q��]�k/��"��x�rmk{j@�+*��P��*�^�O
�r�c�{��@*��r���m-�FT�������Q������Q���*�
N"���q_�^�OM�r���m�OM�r�ws�'�����/��f�����[�S3���X�6w0f�����/�������[�S���X�V3y��.�r�]��_hO-�r�c�����VT����m�e��+s���e�z,s�����������w&���=#��
�u������P����	��U�U�g$������������
�A����>��%��-��i��3�
%)���66�
{FB�>d��=[���^gP
jR��-}c�j0`�&������m[���^gP
��z�to�T�kt���(��D�����5�p]gP
�A��J��
��U'���.6oz�F�5����)�X)u���X�	�;�r�KB{����������C5x��=�G����.	�mp�s��
?�c��;TOe����f{��..	�mp�s���:�����v���p�s�/���%��
��UD�[���Z;Tun<���GL��V.	�mp/t�����.��C5���un�[6�rIho�{�C5���4tq��u�Xi(��<w�^.	�mp/t�&����.��C5����un5����:w���:T3����s[;T3���X���7`7���6�:T3��JO���ZP���:���P"���%��	����ZP�V������:w9����\l�����B�jE�[i��[;T+���X���s�u���s�u����M�����;��	����1*�#��s�u��@�&��m�P�
tnB�>����������:�j��s���6v�F
:7�}�a	��#��s�u�hB<����C5��	��Dp
����6��9T�U�X����hA�&�8,���s���^�P�vE�������7�c�[uX$����Mho�{�C5�3B������@�&�8,�u�s���^�P�nD����������E"�������p�C5z���X�����Q��c�[uX$�P��]��s���:7�������p�s��Dp#����s��UD��unh�PE���X�V������:7\�P
�s���
��u�p�s��Dp�����
:T#���X�����:w<��U�E"�#��qW���u�x�sCk�jB�;����"�	u���s����:w:����C5����un�a���:w����B�jF�;������Q������ZP���:�B�jA��Ttnk�jA����j�'�u���s/t�V��kE��v�V������f{����KB{�x�C5uP�r�4v�����=#�} �	��#�{F���IY�X�y�����	���Dp��KB{���Ik�x\
(6v�&
{FB�@�'\l�����:�j2B<.z;T�o4�} ��.6uIho�{�C5�!��������$��M]���^�PMvB��Eocc�j��Mh�G�	��$��������!�����o4�=nk)�M]���^�PM�SN��.��C59�F�����B��%��
�u��Q��Z�4v�&�:�����I&������:�j
�sk�];TS@��un�`�Dp��KB{\�]hQE���.�=��J7V:0��1��KB��M��n����qx��C�Ck#[�$�;����P�V:�l@�wD�;T�0�/6wIhw�{�Q5����x��6��zw�4bh�Ta{��v'�ZU
�Z����W5���*�Z���%��	��f������e�8�3j��������=^���^hW-(z+�^6������]�U�j�Wa���v'�V+��J��
h����{�c��Z;V��%��	�u�������{Q]c�j�@�&��$~��;�	�N|�s�f�!���ml[�
�o��H�'_�7����������+����X"��`|��o=����������:�j�b�H_����
H����O"��o����������}��_D��7�}$����58v��W]g]��o}����lA�&��d������U�yWs�7�>�oc�j�A�&��d"�]q���������E��[U��u �G�?��:��	�N|�s�f�cE������Q�����f������U��Ws@��+�W5�����7T�o��s@�����U@�j���Q����o��7�����B�*���5����P����o��w@�;��_}�{5��*�W�v�T�CE��>]�GT������W#����~uk�jD�;V�o5������w�W��B�jB�;U��n�^M�~�c���G��i_������T���y5�����o��jF�;�k_}�w����+�W�����K�uo��.(}�}��/��V��KE�������w���m�;��|�}��/t�VT�kE���������VN~���@|l
�����:�j��x\Qh�8�
�����O"��&����u���&�x\T�~��j�<�GR?��b��w'��YW��q��
h������>��I�{�$���5�yW��Z�K�U�2�����q����k�jy�.1	�Nx����.�J��
h��Z0N���6���`���v'��9WKo�q�
h�����&��m|mc�N1	�Nx�s���q!�
h��:�M�������{�$�;����Z|��K�n@����Mp��Z�b���v'��9W�G�[i�m����K����������:�j	�|+mc6���Q��c���6��c���������1>a�1D�[����C$��}���m]�j��1	��|*u���o�w�����(|�c��|u��1	�MpO%���7�����QU�!�e�x,{[W\�mLB{�Si3��M(z+�cTUxHwB�;����2��Iho�{*i��%o�w������(y���m|�j��1	�MpO����������Q��T"�
��"x[���6&��	���^��C�[���9�DpW��KE�����mLB{�S�����b��;FUs������"v�kb7��	��3^��aE�Vs����Mp����U��#�S'����@�&�G�m�S�
�n��>6�U+����<�U��M������Z5(��}���^q��x�3�VcbM�66�VR7�}'������!\]�bM�6v�VZ7�}'������F�:�j�;�X����nb7�=���z��A�&������Z�!V�n���Dt������MzWj7����uF��&�X���7��� w�����v=�]���:�j��w}E��������������P��}�{�U�����w��VU@���n�bkD�����^UD�+z�o�UE���X�V������z�\%
��P�����[{U���X�V���w�]�{������w����6�����zw<���[�Q���z�\
���P��5�����P�N�z���HDwB�;���sE4����T�������t�w[w�Yg�����=WC�y�P����Z{U���X��nn�.�w�]�{������]*z������KE��>EXQ�.���/��V��kE�V[�JDwE�����������1	�mt/��6�ey���(�m��
L�od��m�U�4��ho�{�W�A�b�s�k�Um`��:�k�����e���m#E�2�j��A���A��W��]}\��q��
�C�q�HOL.����(�X���zU:�5���m��e��3h���^�Um�V�X����zUcg-F��v���n1�mx/3�6D3B��um����5��>��P"��,&��
�en��hD���1��[5v�����v3�/���po�{�]�!���0����60��������N1�mt/��6�(yk�b|[�j���W$o��9������\���(yk�b|[�j��7T$o��9��
���\hWE���V1����"J�Xk��8�%o����UJ�J��[�UJ��"y���P����B�j@�[��[�U#j��X�V����(y�]�k/��F���>1��_5���%o5+�����w�U��B�jB�[�����%�;����o5+�����w���B�jF�[i��:D���w>����]P�����^�V-(x+=b�o�V-(x�c�[��$����]v����ZQ�VZ�<?~o��z,x�)�HtQ�����^gV�o�CL���@tU�7�=�n�[��	�mt�3��R�"x���$��@�&������nB{���*�V�X����Y����V�nc�Yi��	�mt�3���bE���f�2�w���66������F�:�J�!V�nh�U)z7�=���X�*z7���n�W�lD��{U���Mp��X�^������:�J��w���6��Tz7�=�n��[�C��w���*�@�&�G�m�U)z7�=�n�S��]��_�U)obM�6���G����n�v���~W���yU*����{U�F�
�z�yVP��]��_�U����wck�*��
�;���O"�o����fUD�+�7�6���X����������/����CE���^��zw8�����rw���ZU#���"wck�jD�;V�nk#rB�;�����	��T����U5������R�������w��^��zw�������Q���z�^�]$�(x�]��.4��sE�Vo�H�wA��Tn47�zT����u�U+*���x[�U+*��r�Y�>�]Q�����]hW�(y���mlW����X�V�4��j�
���F�:�Jw+B<.�k�D��`�Hp�E6>H��&����uv�V3B<.���v���q$�G�U��B[��6���UZ���V��>�	/l	�Qxi������:�J�+�at�������`mn]����F�:�J[+�at������� ���5���ho�{�c�� V��lia�����&��m|��/LF{]�a��A���ru�����V�����4��f
�a2���^gXi��q�\]�
%^�7�=
ok��Q��]���3��G�[i����$�P��G8H�7��
���_gX�����FWkCI�7��
�vp�oD�wE�����(z+
b�;��
/��Xk��:����+z��������!F������w��ph�8��z�]��/��FT��1�Z@H"�#��������;��we�����P�Vz�h����P�N��������w���zV3��J��Z{V3�������0�Q�����B�jA�[��Uk�jA��Tto���Dx�����
�V��J��Z�V+����{���%����]wuo���ZQ�V���j�z���u�z�{��s�k:��	�mt�3�L7"���mlZ�do�{����Q�nW���<+�@�&�G�m�Y�7�=X�Wk�]��s����0W7v������k\����*�p�_e(���(���*c@�&��$�����
��U��X����[e,���]�4�n{���*�+�XQ���WezP�	�>��74LZ7��
�uN��W�X����Se���k��_������:���!V��n�SJ7�=zq���4������:��x���"uuc��x���X�6>B0���U��:��T���t���$�P���������t�����T�n�)��&UD�+����@"�j���u��.��Zw�i��.��Zw����n�lT������T#����vMk�jD�;VNw[wJ7#��qW����	��X����S5���j��k�O"�*�iW����	�TQ���W5���*����'�5���y��n���w�h^���ZP���[��3�5���y/����KE���~���w��j6��E�U���z/t�VT�kE�������w����~0f�?L�{^�]gY�j[�J�m[V���#�}$5��/v�Ipw�{�ke����>1��J�W����>���w����#��:��j�����
(_
�G��N
�X������:����K����Y���M�G�I���$�;������C���su�����4�}�D|�SL�����+k�x\@WWk	I��7���ut��^1	�N|�3�l?!����66���4�}�D|�[L�����+��x\CW����u`�&�����/��Ipw�{�}e=��J�m�W�����[E'_������:������1�6��l@�*���N$�����U�W�o�s���8��oD�k�����o��������O?��s����8����������������U���J���a�?�����0���_~������/~��O?����?~�������O�~�<�K��>����������Q	���y=�}6D�Jx�\ �^e���7�crt[�l�u�M���w������2�m����=�TK�
0N��o���������PO����3|����M���`�QO��C�����P���C����c�M�����bD|�E�ut��5@�
d�}t��=b��C��}L�nKw
1���i"�:������1	���w�{�������[C��~oz��������P���W���}gq�v/)��YC��}����;k��o�{�CF��4����m��!F��	�Qt�}5Dz7�}�n�;�}��[�j��n}]qW
���Mp���W2El������yU�1���w��B%�k@�&����/�"6��	�Nt���z�cM�6��zz7���2b����D�:���+b����^U��n��]����w���^�U���+z�5��zz7�=���/�!8�	�Nx�3�z7"�����	/�� �����[�}���s�z���Wo��Dx=*^_y+����J^�/y�uvUP����u���>��
�#��ysD�4��~UD�+��Z�["�5o���h^��@�^hX
(zcE�V�tK�w@�;�:�5���w�W��B�jD�;TT�k�X��z��)ok�yD�;��^s�e5��+�����&��c��]��N�{�}�k.��&��SM����f��SE��6�g�����5�V3����{[�V3����{[�V��y_��]�u�R����k���]*�������]�u����ZQ����[�V+���������wLB���\+��w�B�ux�V��$�G[G���8t�s���_}�c|&��u�E��72��q���L�{��q�����i �p]\�a�@�ol[9� ���k��:l �n���}��t��R�76�v�Ip2�������2�n���]a�4�olY9� ���k|������i ���]\;!�J]���r�A&�=@����aw�@&���.���+E!|c��a��]��^�
d�M�t����:��n���nc��a����V��bw�@&���.���M���hc��a����!j�����i���]��:������66���Ip��Q��c�M��|����F�7]d^G��O�
d�w�Sa�w�?&_��.�*��&2�������1	�;���}��i�o�\]��7=d^G��I��c�wbRa�w�=&!\���M��������1	���.6�q7�c�����;���� �:��m*l����nmSa�w�;&_	�.�3���2�������1	�At[�T�:�����7�����r������6��uL�{��Fv�q7�c���������i�:���*���D�����c�M��|������M���yKc��w�w���6�!}z7����u^�WB�������
�n�{����+��	������������-��������7��������cC���������O���H��������~H���[���������_>��B��	�mX�H?�d��=�Od�Z��o����'���u	���������DG�l�"��s�Spo0��:���W�|*>L���G{&��~�~��zx(�_�S�h�����MmG�5#�r���A>��nG`$�<"9���������\V�
!�j�qP>��.�� �c����D"�?�x��7�@p`.&��������B��c��Dpx�������[Lho�{����!���#�-���o���ZLho�{����!�������mPB{��G�~g1��
�u�����*�i��*^p3T�Hh��UK�Jwc1��
�u���Qt���4��'38������ly�8rX#��w�3������]�FB{����sW�������u�]Q����4�/�0�C����j7t����]wu��2,��:4��ZC���
�	�����49t�g$������
� �Z����U�g$�_n�+zA������:�*h�k�W���������a�Hho�{�C��+��;T��q����o4��
�uU03B�Oj�P�hB{��6��,x�	�mp�s��b�tRc�*X�F�w�P�Gn�r���+�������������Mh���v^pGn�n����
nH%��]��o4�}U���n�$s�C<����������s}E��N�<�\��s�s�B@���un�n�Dp��p�s��L%�P��]�k/t�"��p�sMk�*����:���T"�un����B�*����:���Kw@�+�`[w@�;��\{�C5���un�����:w8���F��Q���:�^�P��s�c�[�oE��:w������aB�;��\{�C5���*:��C5���*:���0���vu�����Q�������Q����:���yW���u�r�s���Dp��KE�6��������:T+���X�V�[����s�c����cXQ���:�:�*v�s�c�[�o�;��	���c:7��
�uU�V�x�s�	�Dp�������cT�s�����9TQ��X�Vs����q_�uptnBKz��9�z��Y���|5�
Y#5D��it�H����^~�Ng9�Mr~C��7����p��7�!����x�0��Nh���7��&��
�u��0����M5����;�}��0�����6��z�8"���7���7L������f���MB{���a����M5	.(��� ��=�a�8r��o���a��0?��Kw������3,������:CoX@y'�\���;�=����Gn��M��7�!���&��]Ay'��?�V�2����:Co�^�	�	�@p���Xi"�76��tnB{���;	&�$��U�[���
�Q��Mho���3�Fl"�0?��JW��+�]���������:�j�&�	�	�Dp
����?���;��	�mp�s�F,m�0?���t�X��|��GnW�����&�|���s�J���{n�����\w�C5b�����C"�=����?����/8r�:�]�P��D0a~�����;V����B������:�j�&�	��Dp=��J�@��Th��s���u�9T#6L��8$�P�V����Bc@��u��6L��8$�Q�V����BcD��u���L��8$�;���tt�O��u���s���L��8D��:��<�5>G������:T�A0a~�����:��;��v�&������:T�@0a~�����:��:��v�&������:T�?0a~�����:��9��v�f������:T�>0a~�����:��8��v�������:T�=0a~�����:��7��v�V������:T�<0a~������Qi�;T[nR����6��9TS7#���7��C"�
����\c�jR�g$�����������LT?�������k�PM����V���9T��*	��Dp5�	����d4��n��p�C5�2�0?�qH��7���k�PM�����2�s�&U&�>��Z�F�p���.8r�U&�u���x\e��qH�o4�=����z�F���^�PMN!��*��C"�����\c�jr��&�����������LT?��z��=�2;T�RNho�{�C5y��7���Dp�\�sCc�j
�s���
�9TS@��un��	.��p�sCk�*��
�:7\�PE���X�V?��F���X�����:7����u�p�s��Dp�����
��u���s/t�F������~�Q���:7�v�F������:T���X�V?��N�s�c�Z;T��iW���u�t�s��Dpg�����
��u���s����:w>����C"�����s[;T��eW���u�r�s��DpW��KE��v�V������:T+����s[;T+���X�������]wun����;��	��@p�tnB{����4������9T���0?�qHW��Mh�5v�f������x�C5k��	��Dp5����\c�j����������A��:��qH���Mh�5v�f:7��
�u�lB<����C"�tnB{��C5[��	�MpUw�E5�1���!��`t��nllQ�=��v'��yTs?#�c�[�<$��@�&��{T�����D�:�jv#b<����C$� u�p�M��[�]����\������Z��yHD���������j]��uUw�M5��"v�Ts@�����
�Hx#����vUw�QQ����mmTE���X�n�K������zWuZU
�x,x��D|T��������P���Wu�U#j��X������(z�c���0��;��T������w<V��/D"����X�nIL��N�{��{�g5����uo������w:�[�8�3*�y_��]���|�|�_�H|Q����wKc�wA�;�k_u�o���]��o������w9�[�8�+��e_������z�~�_�D|W��kM�6��l������:�j��x�R��R�B��t�{$�G��W�}Ipw�{�{�(�������*�=�t��}�`��w'���W�����bP������#�=�oc�j��/	�N|����!�����/D"����]c�j�0	�N|���� �����/D"��`|�kXniL��b�w'���W���q���"����]c�j�60	�N|����~@��Ur�_�H|�=Mp��5�������W_�_-*Z.��0�/D"����]c�j�f0	�N|����������H��������W��Ipw�{������0�/D"��o�������Ipw�{�Q�V:�����F����[�W�&��������������H�w@�;T��n�_ac�w'��W��J��"���P������a���^�_��+-b�_�D|'��cE������Ipw�{�5���t��!"�E�;U��n�_a��w'��W3��J���"���\�����Mb���^�_-�+�b�_�D|��KE������Ipo�k.��V���v1�/D"�+����uk�
[�$�;����Z;����1�/D �k�7�=B���Z;��	�N|���V�!����~!�U��#t���U��Mpw�{���1V�o����6���m�_��o������UO����W�����3������Mpw�{���1��oc�j5����6��Vkp���������Q�h+����H����Mp��5���^������/��2�L�
� � ��G>�� ��#t�-��_q�v%���7��"���~"�u ��#t�
���Npo�{*}������"�_�Dt=�__����}�z��~W��J�y�P�����~�
(~CE�����P��]�{*uf�.J�P����C"��o�H_����(}���=�8�F7����[�:$�;���5����P������/ot��CE�V�����j���m5��ve��C_���(z���mmZ�(z�����M�	E��{�{���7�����w[[V����wmk�jB�;���:��
���w����!��\���c5���^�^��\Q���C"�*���xmk�jA��\x�.�+J��"y���DxW��kE���v���w=8��0��y����~��������ym[�jCWn�mx/3�6DB���~�U�����kkXm�<����#����M�Rn��}H�Ww^U)�i�:V��N����]fYm��X��[�>D��@xu��mkYM4��po�{�g�A��^��}H��L^S)�i�zVS�e2���^fZm@�4������V�`�mM�
��c��iv�k5u�E��R���C"�}����2�}[�j3������[��VS�4B�T��~�u��*U0����f��sh���^�ZM��b��n�����^�B�m]�
�^��{�U�`/��J����!����Wto�������
���\�
�����.3��C"�uo�����kQ��]�{��ox#��Z����!^����{������7���s%6x�;���5��~�P����v�F�����=Wa�7�#��Z����!�u�X���]�u���{���
�����b��}H�wB�;�tok�jB�;���]�uo��L������w��^����Q�����B�jA�[k0S�>$����]*��yx�����=W]�9��{k�e�(�u�R����)���]wu�����]Q����TP ��C��Vt�klJ�to�{��\+�
��{�(^��	�����R�nW��+��^�7a~d%��@�&�G���J+�]�{��ox5�����������klJ*������s�5x�k,B����J����Mp��56%�������:�JY�+��:����{��'2w�kY�kA�&������R}�+��56�T�7�=�J�8�=����6��yV�_bM�6���D�[���8�DoB{��,+�&�X��-+�A�&�G�Z��z��~W���+�Q������+�Q����m|�j^��y�u��
�yCE����U@�j���a���y����:V5o�h^�����ycM�6>T5o����B�j@�+���v���CE�V����y�]�k/t�F��CE�������w�h���!�E��+z������w��^����P�N�[�:$�;���vU�����P�N��[;V3����z�[�Dxg������ZV3���"{}k�jA�;Wdou�����w���zV����{[{V����{�[�DxW��������ZQ��5����ZQ���[�:��;�:�]��_�Z��,w�1`h�Z������C"��A&��
�u��V=@���	�]+�`�Hp�:D��������{�k��A���B��k�5l	�#[�Dx�L�{��\+mB���
�]+m�2Mp�:$��c2���^�Zi�"�J1������bx+�.�[�Dx�{L�{��\+mg�X���V��4�}d��/t��po�{�k��!V���������W�]V���B���6���V�E�X)��V��e��>�uH�z�d�������uo��Lh�Zi���Wtou��o@���u�u���{kdBc�J����{�[�HxQ��]��.t�"��Z������{cE�V���F��qW��]�uo��Ll�Z
�{���m�Z
�{�]��.t����&2��k5��j���k5��wu����Q����������w�����!�	u���{��������F&�v�f��SE�V�����{�]��.t�f���62��k5���+���uH�wA�;��^w�k��������]�u�R����E"�+��eW��]�uo��Ll�Z��{�����-"�E������\+��������]+���MpY[�k:��	�mx�s��R��{�VF��MpY[$��@�&�7����VF��X��:��j�������"^
�7��
�u���3B<���k�Z�7�}dm��������:���!�^�5v�����>��H����Mpo�{�kelD���Ww�]+cA�&���-��5�������V���0
`c����{�G�����nW���\+�@�&�G���2to����"��nW���\+�
B<���k�Z�������"^�����^�ke�^�{u���2uo8����E"�uo����Vuo�����UD��uo}m�oD��u���UD�k���k5��������H�w@�;���p�k5��*�W�v�F��CM��v�F�����
�V#����{Uk�jD�;�tok�jB�;���p�k5���*�W�v�&��SE�V�����{�]�.t�f��sE�V��J�wF�;Wtoum	/��yW��]�u�\������]P�.�[][$����]vuo���ZQ�.�[��*�u�Z���Z���]Q����7\�Z��{���U�]+����Vt/��3kx-v�Ipo�{�ke�!����kel	�#k�Dx��L�{��\+�f�x\ZH������u$���-��2	�mx�s���qI]��VV����>��H�;�$�7����V�@�K[i#�uc���L�G���b��6���V�B�K[i#�uc��Z�L�G���b��6���V������GF������2MpY[D�����e��{�ke�A��%u�n�ZY�i����"^l"�����:��z��K�j����to����"^�"�����:��z���V2Z7v�l@��+����H���$�������uo�����]���7Ttoum�/v�Ipo�{�kQ�VZ�h�����{cE�V���b��6��V��J+�[�V����{�k�Dx��L�{�]�uo�����]�u�X����E"��E&��	��.��&��^2����&�SM������L���}��o���6�}���\S����}d���^h\-(}+�d�im\-(}���m�Kb#�w'�:Wj�J;mZ;W+j���}���D|��L������o���6����C��V�ou��o���Mpw�{�w�w#b��_����;P�	�#��D|����U���������h�W����>�{H�Wk�]������^��M��F��{�k��	�#��D|M�cw����z�7�>���Uo@�&���"�]p���u�Uo
b�����UoA�&��G���M`o���s��^!�����������>��H��������:���W�XQ���{�;�������F�@�&�;�������+��6v�z�7�}du���G���������=�__Q���{�{T���~���D|�_��~�u�UP����������7T�ouu��oD���������~cE����UD�+����H�w@�������P��k[�W����~�/��7�(~�}��.4�F�CE�������w��6���w<P�zW����~[{W����~�wB�;����	��T������T���Cb��Q����W_h^�(~����[�W���&~[���e_������R�}k�jA��T�ou�I�wE����_}�y���]+��om^�(~�����>��:�+�����:�j�KK���]F���+�����>2�$���e���^g^9�0]�����WN����>��D��������{�y��E��zC}c��i�=�G��D|��L�����+g4b����W��u������ao�w'���W�v��Ri�o�^9�i��N�g��e���^g_9� �J����}�z���T�l�?cw�w'���W��c��n���r�������^&�������rn@��b������	�#�M"��_&����u����k]f\c��y����_}v�`&����u���kmf\c��������M$�����5�W�o���k�_E������M"��b&�����������h������CE�V��D|��L������o���k�_���c�K��z����LB�����o���km_M(���mmOb���5����/s�����"*�Z�����QO�
�P���>3	��|*}�
�����k����f��sE�V7����$�7�=�<�FwA�[k5�Z�W���X��=�~��d&��	����7�+*�Z����ZQ��5����{�$�7�=�7�F�w�{k}f|c��w�{�t���X?]���Mho�{*k�
����"z}c��+�	�#��������&���|y��;DX����e�5H��}�G�$oB{�S����]aE���~�7�[����O���Mpo�{���7�fB����U���Mp��[#oA�&�;uT���bE���f�� v�G�p�o�78v�g��U���0���Q�{P�	�#��u
�����u�u�w���6������>rN)��������z�k���W�=
^_����z������^gV����WohlV���7�o��7��
����U%o�H�����(ycE���.��Q���S�����7V4ohmW
�y�����������w���|�]5��*�7���F��CE��>�#��q_�^hX�(z���
�
�E�X��/��	E��/z/t�&�SE�������w:�����k���w�����k�FwF�;W4oh�X��y�c�K���]�����=W[�7�J��"yCk�jA��K^BUv��.(y�]�{��otW��KM����V�����%�d�����w�U���j�F7t���x�U��}#�}�(`7���6���UAu�RW(6����}#�=�n�[�{�$������
jA���B��[�����$����.v�Iho�+�VY�<~���	!~�<~��_}����������~������������������������������������OO�&|��������B�G���7������_�z�M�-w����y���)�9���������������C�Pi����fp�<%������������S����,B<.N��kfp�;%��m|�0`G���6���v�k�x\����P"����T�om������������C�)G�U�Dt��P����s��#����u�]�*-9��$�Q>�J���sM��b/��6���v!�~�5���x�
p�"�}�E�Dt�G�{�}�a@����.\�Hhy�+]l����F�B�n�����n���`W������;��I�;���IBA�����A�RA��Yv���N��8�4�7�/���W��6�f3���"�����p���5��N���.��A�D�=�A����S����C�}o��������8��V��*�����A�pP�+]�����J�8�������_��AWpP�+]�����J{8����������ApP�+]�����J[8������v�w�3�|��^���uUy91����]Uv����3�[����w)���]W����U�������y�z]����n����������rW�=�.�����3����w�]W�W�]���U���
�Ki?�^����w�]W�C�����w�g�
����3�����w)���]W�7�y��������R���J?���Kq�t����/��]�n�t�_��	��O���R��.��/;�������/�}�Sn�����k��/������=�_��=�������#�������`��xQ�2�]�	���
^�<�+r�9��V���������)G�?�.����t�;r�y�s/����^��u{^����x�`�oh�%���1��A�(���f��xU�2�]�)t�
�C�$��?��M�py�f��xU�2����	��<�Kr/����n������7�n���r����g�����!\���{,����L�k��xU�2�����$:�Kr����7�m��p�����*G�����Q@������nA�-C�������Qf��r�w����%9��J�{������w7�n���r����|�����%9���}�}w3����ef�jwU
}W�$�^X�|/������k�U�U9��������pI��[�t;�n��aW�W�(3CW������%9��*�[�WCq/tw����U�"��	�]UY�w�pI�m�o�K��P�+]����U�"��������w�pIN�;s�q5�J���*xU�3k�O�t=�n.���*8���^��uU������_�*wUe�-�%9����{�����J���*xU�23t���V�+���|�[�.������
^���]���l��E�$�^�4x/]�Dq�t����W��0bIt�)t�w�pIN��p���������[�K�rWUv�]J�5��?�8^��^��uU%��
C�D��A7��F�w���+Q�+]���$�]a����U�����}a���t�w��w�aW��w�!K�s����w���/���.�W��W��]���+YW���{�����0��^�8^��^�vU��0dIt�t��!���(�����(���aWU�w�!K��tO����n�.3p����5��N�]a��8@k
\��S��Q�K�+Q�+]�����
3��
�3�V��*���/f��Dq�t
����+�X�c�����}a��tq����5��:��0cI�R:�nG�����vU���(���]Uu. �����	t�>6(-���|��\�s��^��UU���_T&��A�����N�O��B7�UU�_0"��L)<����
J���*WU���
�{�kWU��aD~5�X�����H�������
-)����k������fnq���JRJ���&e!:���J���:�����b�7�.����;9�?��p/w����
hQf��rUunP�RZ�������G7������s�Z����\U�;����;)"������NvU�F��r�3gg����Q�]���u7u7�UUgB�����U��	u7	��]D~�X���kXUe�����8sv����%�U�Uuf��<�]��*��f^w��o�u7���_D����w�aUu����jWU}�|������-��e�����*��E�]������w���}�}7vU'����n���N��S�]1��}��n6��*�n�}W��f����U�]�&������f�����V�w�vW��w���b�t�n�n6��:�n�}7iwU}��+��A������f���.����]q��u���]���.���J����K����&�����
�+��A���R�+]����#��������w)-GW���|��^��uU������UU�Ki9��]U]W|tC�u�]YUW^
��U.��
�Ki9��eU
�Px�b�V��K���mU
`������V����
��-vuU�f��7+�Uu���^1��(/�������1#��Y���;8/���*�Uu����v�U�f��7+V5��FAz�t3�F��8�^��5V5��F�z�{�3�&��(X������z��z�bXY%���ko���2jo�WL7oF��C�u�ag��{3��Y�����Y�^1��zof����:�{�{�viu������f�-������UA�-��f������{�tS������:���D�-��j�V'z�)y�vku���c�u��UE�=��n�*zo����:_oE��c�u��UC����:)��
�����m�m(�m,����j(��_�h�V�����m��h�}l�����h��7_'��L��������E�������v�U[N�(�Bf�u��Aq9��r�pA���k��;0�0HhQ����O���U�������v�U�0��I�b���3�z�������g\Cq|�������&�����BqJq�����&�����W-�(L�]����9��_������{������y�(��Y����AuJq9���U�U1w����j�����r�v�N).�W��U�e1w����j{���]���7z��O�t�=�[���J;�kW_���+-�q��UK��Q�_������;�kW_���+��q��UB�M����5�Cq|
����+-�q��UF������f���1w����:P��1N��:PA�tS���c����UA����8�����A�t3����;�kX_������������WL7�/�������UE��6��2�oE������G����1��w5��*���C�i�W
������t3����;�kX_5�_i�����:�o��k�/.������UG�����Op
_��.�z������������W�q�f��_���/�����|��;��n���]��/���*�W���R\��r��]�g7������>`F��'8�����_�~�{�_�;�k�_��cF��'8��
�Kq9���F_�)���~���~��������)(��g ���C�\q�
Lq/?�o}���n�����o��#]A��r��7`�{�����{�n'&�W|~3�������\o����^�����^���	%�U.���Kq���������[_���Q}�����U���Q:����M��q��o}q��nB�M�����UO(�I_�{u=������u�{/�����]�k�����c_m��7���C�{�(�Y��U��:PzAz�{3�(������#�{���C��U��*��E�]�#�^�w����������AxW���D�-�����f�=QxO��_;�'�)���VU4�S0��]HV4��\x��[Qy����v]UQy������x*oe�{��6t�&8���W5t�&8������QzG�m��^�����v�y�������U~��wT�>>�5����l��$�����������]�}d��s�#���Y_U�bDa�n�����u�L/~�������g��s��F;��aDa�n�-��v���	�^��7/l���{�k�X=u�(��
��U]��x�	�^��7/l���{�kVY=U�(��
��U]��+?��_�f���2q�W4�*�G����A������~�����[e>�^��UV�D#
3v�Rh
�x7~�����[e>�^��UV��"J�e�ne�s������[e>�^��UV��D�v�����7��+����7�����M���n���Y=���&�{���3�&��4����k��7��J�e�vi��{3�����x3zoz�{�5n���+����[��7��+����@�=����t�{����n�M��*�������xzo{�akU�{����vku���{�/~3������{
[��W�-�i�V'z�)y�vkU�{����7Z�^��W�-�6�����V�{�o3�6��:���&k�����
�e���Z5��&�����E�mC�}o���x;z��Y�m��UG����>��{O�;joj�{c5n���^a����K+���R\���.]���R�+]���-#J���Y9��`����^����^��UV�U�(I�re�<H/�e>x�k������W�v���#
��+7Vn������;�k�[�y)��]c������+���R��\���7x|vc��k�\���^���p^�����m�g7v^�����q�wWn���Kq?sT9o�g7t�`�X=�aD�yw�������3�>�����R�+^���E����+Qz#/����_�#JoJo�+�\D��������K(���^�7��	�7
�7V	�7	��kV�7	'���	.�������*��f�z���7��}O�h���z�aeu����jWVZ�!��*o!����C�
��UA�-��F�������W\�7���[��;����7jwV'Z��[�����fu���c�5��*J�)Ho���*Jo��W��5�nE��c�5l�:o�7j7V
��������{�6t�6t����j��Mp��]Xut�&��+�����Qz�Pz7�����vAz�ra�����I��n^�c>�^��5V~��'��rc�|rP\�r��ao�G�+^������yB.*WV��G�e�)���5�#���]c�}�����+�����r��Lv�|����+��!��8�E������R�q��
��.���H{�k�W��ADag�/��T�(K).#E�����6|t��]���o+F�G���\W�
�R��}�U��|��������0"?A�%����P�R\�sW�[���H{�kWW��cD~��K�u��+��'\��
�^��7�w���|D�v���\W����U����n��n�V���+��qI��J��������nF�MC��
����+��q���jK)����t���W������������G�����?���?��������������O?�����_������O��������_�������	'����h������{������_��������s�a����%�q�.)W{���l^�*�����)���]��-� L�������1��^�~3���?e��]��%� vI��+|����^���.���W�v�^�w��0k�e�j/����z�8ln]�2Li�t������a�����^��V��a/\��.��W�v�^�7��0i�e�j/�+�����^���<<��a�{�k��|C,��]V��B�^9/�����/��������X�&
g�r/Dp� ����S�+^�v/�;bA�4�����Py�����j��8d��^���{�����|-dt^��0/��7/JoJo4,��� M������+�����f��!�������w��4i8k7V�Wx=��o����C�)��ae���a��������+�����f��!����������4iXJ7oE����u�xq�0���5,��-� M^�K���+� ���T3���a�{�k�Z�kbA�4�h�V
�WxC���f��!����������0i�/��UG������	x7�2Lq/x�]k�-���0j�/������R\�r����a�{�k�Zm.`D��E���x/���*����W�v���=F^A]�[����R\�����W�v���.Q�����Z%����I:�^������sw9����/?�o�:��Ws)�����:��_�_���0���|~�����I�����`��m�cD������m�IE��I���,�J7���_���]���#����\�m	�H%������K7��������]�������;�-�����2�������5*��(�kW�m��������t���W&_x��^�~�:�����5|�q`D��l/���BN(��_(��nY������+���MRf��r��8<����w/�������_re�~���&)3GW��;����~z���t;>:<: ���^
Qx![�%6�nE#��+���n�^�}�}7�{
}�
��������x�]�W���m��m��������M�]�|%m���]�mD}�}7vU}�K���U�~nt�w����[��y������������bD��Y���A����e~3+7����
J{�k�U��`D���+wU���
���Un"w��J����}�����8r
]������o�������v]���}H���U���zR���U�]���pG�����!)3GW�����������y
�p�[���}[1�p�ZA6�E)�e~x���
zRJ;�k�V�����Uk��V�;4����|���P�R�^��j�;f�Z{������7!_X�|/��������j���Qp^����	�7����H�{�&t�4t^��V{B�M��jV�7�����{�f��<�^�6V�7K���Xe������{�h�yh�n1����C�^����j�����{���c��n1��
zo�W��2oA�-��������{
K����+�r���D�=��.�O����^����������\f����U�^��������:�����V�{�{.3�6���{�C����{��{�ak��{����E�x;zo�����������}��������]�^q���qA����n��U\�{)��]k���/CL��Kq���Ut��{�]kx/���*�V���R\�rk���n��������Bsx�[���{).�W������{��k���bF�{�#�xW�^���Un��
�Kix�Z�f�W<R��7��R\�rkx/���k�b��Q�^�Hu�- ^�{�[����R�^��*n3
�+������R�O���&]��{)���k��^0����������~����x#zo{��k�bD�����G�S���F�{����������Z���{�������	�7	���k4f��4�^o�Ze��,x�x�:oF����>/%o�������
[��7K���Z��������@�=���
[���{H���Z���{��| zo{�7l�
zo�W<R���D�-������D�=���
[����W��2oE�=y���+zoe�������U�^����
��
�N���~+�����5l�zo�W<R����	>�w������m���ak��{���b�7oG���������x���}���]k�uI�9���UZ����~z&��x���?9>���V���K
��Un������}|sN����O��v�U�+f���G�3�z����^��V��'���k���0#?F��G�3��P�R\��m��BcJix�Z��v�����b�7oX/?������
��R�^��*���A�^��f���2��^��i����~�7?�������}�c��t��f
ahM).CX�T!��������0��"sp�k��CgJq��^��{/\\Ci/p���|/���+������Q{#��/����7��J{�����{�&�^is��\Y����x�����Kc(��[_����Qy��1�va�Qy�����I��nK�4��^�����^���8��R9����{���������o���}W��E��������o������1����S�{��]am��r�m�����H�Ci/p�:�����+l���KN���{����g��?��0�������h���/���M����}�9��J;x���nC���xQ8f�m���W]���	�P���;�]W�����3�vt�����n�����^3�yA���x�{��y������y���W�v=Uv#
��{��@v)����9;�]J{�kWTe�1�`�Q���~E������f��`���J�����bDAw�rQ�W�]���U���W�]J{�k�T��`D�w�rS�W�]���U�x�C�G7�]��*�]���U��r���]�{7y�����k�U�
|�2st������R\������/�������{��������������R\������7|tC�}o���t���M�]U�����]����}7}����M��Q����U����x�������w��w���q3]��$�n���2�n�}W��7�nF��C�}o���t3�n|7iwU�n�}W��7����{}�����=�w�w�vWu�������f�-����"�aWU�w���I��*����]����'�n��{�3��{�����&���D�=�U>||H����aWU�w����]UE������Xf��V��:�]�����V�w��������n"�n��{�3����w���Y�����]�]�&�������79�f���]����U~nt�w���W�P�+�	]UXy~a}��F����?������~��_��#�#�������O����}���?������_��������������_�A��O���x�M���G������2��?��~O/v=��>���u?����[�����7(����]sw�0#��n����[��
��e�*������W�v��`B�!,������w��\�V��m��
���;������t�p7��(-W��=p���������cD~��8�n�Z'J��U�d��Ai�p�Z�#.Q;�\���A(-W��=p�����+���� ,���u�^�iE��(�����e��^��uvG:1"?r�?��{�f��(-W��;p���N����|`D~��~C�f��������7lP�+\���8�s�5���{������������W�v�����+,���;�{����{����(�e(����:Qt�^��:QtO^t���Q�v
�{�k�QU4]a�����*�n�M�-�%.���W��%UC�6lx�����6^u���R�n
�{�k�R5t]a���n�:�n�]�-�5����W��5UG��kx���,(���]�(�nY�v)���]OU�#���*�Te���]e�-n�G7�]����?����*U���RZ�������
}w�k�����]���x�]J��u��[|�G7�����*k������UUY�w)-GW�w�
�Kq�t���<F�}wU��J���]e�-|��^��uUe[0"�����t7�]J��U�����R�+]���l
#��+�	�Aw_��������Ki�p�������]q���t��������^�m7mw�k�JD����*7U%��F�v�_��nB��C������Pv� ��EUB�M����f��4�]��*��f^v�vQ�Qv�$��%s�(�y,��E����y�
�E���{���?ut�c���aOU�u�u�vOU�u����y�|/���[����T'�n�U7h�T'��)���5�r���C��
k�U��U7h�TU�TW|�i���[����T]����k���[y���g�bn��m���aK��u��A��j���w]��y��������T]����[����%�U��q�B
�{�kWS=��|��j���\�C��rt�/e��P��^���T��a���U#(�T��O
J��U��q�B
�{�k�S�>`D~����S�>6(-CW|-q]\�Aq�t�z�s���2*n��Aw����rt�/e��P��^�F���F������f�
P�RZ�����jP�+]���
#
[$���s�H�����f����J���:�#
[$���s����rt�{�jP�+]�����(l�Tn��JRJ��U�!O\�Aq�t���3��
[56��������]��'����W�vU��Pw���rUu&��$��g�����>
�{�kXUe�]a���]Ue������.��iP�+\���@�vjl�M���{H��M�iP�+]�����
;5v������v_8!��.����W��MUA�vj��M���[�_L�A�iP��d�T�h��N�]���h��`����3��:
�{�k�TU�]a����TU��*���b���N��^�6U
mW���k7U
m�	�����3��:
�{�k�Tu�]a����Tu��.���b����}���������ScWn��c����]��.���J�����cD�w���f�u������\UU�Kq�t�����(��rUU=�.���*���|��^��uU�7�(��rWUW�ty�_M�p�PW�]J{�kWU�����
I����]J;���~+��Ka�l������nT.�j�����e���n+>���f���n �����\T�
d��r�2�K��;|tC��vEU�Av)3CW���;�.���*��u���������F�e7*U5��FAv���g��(�q(�����	e7������Pv� ��k�3�&��4��lXTe����n�.�2�ndW|�x�������
�����y���E������]���t��ch����:�v�v�����{���{�3���2��lXT��"��vQU�w������3����e���M���{������}��|W�d�����w
����[y�M�]UE����jwU}�}�-�eUC����&�����6Ax�7�g�m(�m(�n1l�:o��7i�U���+�Z<oG��C�u�]]��O�W��\W�>9(-3�Hy�`�%0�v@���jK������\W5����Py�`�%0�v@���j�bF~dPR�����
J��jV��n����v}U�3��q�r_�V�J)-�W�kn�����Vm��������BWJi9��es�=0w����j&Y6aLRn�Z����rx�����`(��]e�6�e��}0Y��j������\77�Cqx�:���������;��C]Ji9��}s�]0����uV-:�������U�h���^'�����P�^���E�^a)LV��ZB����j�����VV	�W�
��+����x�U/5p��5��2Z��&kWVZo��W����>�;�k�Yh��Z���Yh��`��t�xq#��5��
Z��&kwV���+����w�P�^���D�V�d���D�=��{L���{���vV�W�
��;���[�|���[a(��ag��z��0NJ7�oC�m���#>f���0w����j���~�h�V������!3��n�{��
[���+��Y�k����v��W�1�o_@})���]m�������ro��/���*�����R�_�����y�u�rs��/���*���{|vc��v�U� �����]u�Kq�����>���z���� �����]����~�s_>���z����3
�Q����_���vVn�{����v�U�f��W����/�e���zf���~)���]y���%�Un����`����|w�_�;�k�^��bFiA�r{�#�/���*��=��F�~����~�`�N���	�7
�+N���7������v�UOh�I�_��^%��$��8�g��������W�7����������_qr���o��j�^�����N��:P��W��3�/��1�����*�����N��*��E�_qz������w5��N��"�����N��S�_���D�=����W'��)�����*��)��vU���W�����V������[�g�������o~����A�}���MR`�
��7^���:p�[���������^�����]�_qJ��?�m�
2�B��o�w�}$�v��Gd��n{���g�G\&������������o}u����P�"�u��G�p?����f�������o}q���� ��E��W�0�z~��pM�������/����|/�u���`]�[[=�E����/�8k]� ��B��C�{��	���^��z���n&_>��|��.���H{������p;&��z���-��p���N�6�GV�|���}���^�[���\]�'g�������N�6�.����;�b�w/Q�+^H�����{���j3����������F�]i�����a�w������x
o
�{36����x�U2�nY�����������x��x��q/���+��Y���������L����������{����2�U��:�y�y�>3�����y��q/���+m�Y����[x�u��xZoZ�{C6n���+��Y����|r���N�D�=������{�����:�U���������|�?������������>�U�����U�^q>��
�������j���>�U��j��M�^�Ktm���m���M��oG�������UG�����^�inA��C�}o���t��K�9����[�z).���{C�}
�����x�{��#J+T�;+��z).W�*��:�^J{�kWY9�0��BU��r���2w#��j3~x=H/��������Q���\Y�uE���zq���+X/�������Z1��DU��z���+o�/�x����Ki�t�+
F���*7V.��R�q:��c�-��:�{�5�����Rf��rc�6p^����jK���������r;(/e��*Vn������I��>����V.��F�y���3�Ft��;�'^N�������P�{�&t�(9�ra�:o����/g�M(�i(�����oF�M��j7V�7K��|��2JoJ�{#5n���������{��f���80o���J�{5��{�������g�-(�/�^�w9oA�-C�}o���xZo�W�p=/Zo���������e���������{
�+n����D�=y�����x+z�9����i�����V�{�
�3�V���{�v���z��zW�����6�z���3�6���[�����������6V��	�+n�����v������K�������V~�����[O�������\:]���|�������[0��@U���>6(.�����{������W�vu�w
#
C����3���
.��Ty����J���������T����P�R\��^e��:�#���]Y��#J�S��*�BSJq����tas�G�+]������1�]�P�R\��P�{c>�^��UU~�!��<F\�;��=)�e�*����5�#���]S�������M���&��]�{�v�|������|�QZ��\U���y�G����w��w��*��w��1�R�t�n�}W�7�nB�Mc�5�����4F\�;�nF�M�������"��w��w7��*��J+c���3�������U�K�@�=���vU���0F\�9�.���������[�w���n�]UA���hwU}���|�����e���aWu����b���}�|W���?�w���n�]UE�W�hwU}���+~��A������n�]UC�����4g�m����]���
}�
}w3��:���#F^�9�nG������Xf����}���aW��w�%1������n|W�|w]�w)���]W�.'F�V�*wU����]������R�+]��juF��*wU����]�����������uU����]��j����y_�|w]>����v]����Rf��rW������������ww��j
#
�+���A7��R\������w)���]W�n#J�Q���u�����m�u���W�v]��/Q�]q��;�.���?�Aw���W�v]��7�(-EU����"]�w��Og����q���]W�F��(���{o���y��>�A7������v]���w����z�)t�w�����3�f��4�]��*��f�w��l3�f����������n��aWu�������f�=�w�w��O��E�=��
����{H���U���������}�}7vU'�n�|W��:�wO�w�)�3������w�aWU�wO�w�vWU�w+�����t+�n�n4��*�n|W\�9�nC�������f�m��m�����j��M�]qk��}���+�M�A������F�����v�w���S���v�w��I��Ci�t�����0� .�Q�������|7#�ZJ{�k�U�,��F\�9����
��}�n��0��J���
FYa7��Sq]������[a(���]W���)��J�tW�I).CW�73.�������
�cDi�rW�����U�5p)��������`Di�rW6�I).�f(�����^��uUakQ���U��#]~����n]\
Ci�t�����Q���U�=)��>z��;a(���]W"���F��
}7����3\	Ci�t�����w��0�]UH����]q������^�vU}W\��Ue�������n
]��<��d�U���Vy����������n]�Ci�t
����+.����
�n�}W�e7�.����W��]���+�����N��S�]��
��P��l�U����J��������jwU���^�vU}W�#/��A���V�w�Ev3��6J{�k�U5�]a%�/�G�t�w����\Ci�t
����+���N�����]8�U���}�}7�uU��K�9��]����R�q:�%�)t;>���f��js#
��������R\��r��9�]J{�k�Um�cD�w��g������xp�����J�����#
�+���Aw�����;��
�Ki�t���mmQ�]q]���#]�w����.�������pbD�w�u]3�n������m����B�-ve���Q^��j�@x)��q)r�W|tC�u�][��`�����Vm;/��>nEn����[���-��FAy��3�FT��+���k�Et�8t^��V[B������%f�M(�I���|��%��4�^�6V�7	�+����7��f�z�5�3�f��<�^�VVjo�W�/1���{��+����@�=������@�=�?�f�-�������	C����[���������|�vku���|�E�3~|O4��1_���D�=�������{��+n����������V��
�+�!�����V�|�U�3�64�:6_g�[54�&��vo��|o��.�)xQ|�X|�ao�Q|�$���UG������{�^��������V����W�D0�������^��y��0�v����������q��>:(�8���r^\Cix�j��u�(,�w������Z���g���0�v�����}���VT��j_�3��^��y�1�v�����������rm��L)�w��7�P�^��j3�ss�8�q
^�L).�W�t�qE���k��
�[���/�g��w����2x�K�w�P�^��j�a��.l�����xw�L).s�/�?1�o�g����M����3
�Q��3�F�(ls������P�_��jOh���/���7��&�|�v\Cix
{���+����,�x3�o��W��=/n������UF���xq���o��W\�=/����������+,���4�x��!�������b(��aoU�|��1^6/�o�W�P��P�^���D�V�xq��'��)��v���b(��aoU�|��1^6oE���������E�����V
�WX���`3�6������{^�Cix
{���+l���H�x;zo��W\</.���W��am��{��1^�	6o\�{;������Kix�Z��T�(y�rkx/�e�*�Qt���v������`F�{��`3�z�^���U���{)��]k}�����c������^e1���G7������+x/���*�Vq���^e1�a�G7��������Bsx�[��{)�8��fv
���n���]k�3
�+N��w���^������R��������������g�;�)��8ah����2��O���Ki/?�o}u�n������f�����+���7���������^��7
�+��7��F^{�M�3�&��4����6�7��&Iz�+����x�����Qz�Pz���|/����%��.�2*o��W�3;��������W�{�(�� ����p��^q�����
�[����-��E�]q���u���]V��2���y��{��Av��$3��(��p��
�D�=���o���������#If������\����{�V�:>�}���f�h�U0]q$��
M�����-�3�6T����k����6�u��$3�vt�&��6�������vt;�ndW�H2�nZ�������5��&\Cq�fx�R0"?N��I���O���Un�����W�vUUr0�2	�c�8�b^�����U%\Cq�x����a�e��xqd��>:(.�W��J�9��^���Ui�Y�IX���3����R\�r_�pu����+�RX1�0GWY1o����rx�K���c(��]e�6��1�^Y1�m)���*_�J�;��^���Vi�����W�g��W��O�t���xqw�����+��^1"?F�������{)�w2.%���{�kWZ���+,���+�S���F�{���$\Cq�x�Z���{��1^|�}����������c(��ak��{��1^|�}�����7�����c(��aku��
�c�����z�!x��rv
^��c���M��oA���������[�{������xqs���5l�N�^a}�_y���D�=�������c(��aku��
�c|�n�*z�)y�vk��c(��akU�{��1>i�V
��J���Z���{�k�Z5�^a}�VL�����������c(��������
�c|�n�:zo�W�9;o^�{��{���q+����Rf�rk��^���Un��[��
���i��u�������Ze�Kq9���Uv
���{���q/^�bD�{�y$3�z�^���Un�����W�v�U^F��W���+x/���*�Vy���W�v�U^;F��W���aE����+gg�
���������bD�{�y$3�n������Z�
���^���Vy+Q�^�=�)x�{).�W���{�g7��	�UXy�a}�w�^�L���o��������<r<����o��o?��?��	�_����~�����[�����������G��?��b�_KJ�#�Y<���7�Z�������*��������cO����������#��#�:���#����[�8_
��������Q#�P#�]�����k�x�8���q!���A�@�8��-��-B<}�A��D�D��wg�-(e(���+(����q��!.��A�D�8�����B<{�B�B��;�n����P!�a}WQ!�pt�\
��[����rt������
O��a{����	'g���^�
��pp&n��A���Y������Y���Y��nG������xw
]��>��`��K�(��=��r+�c��
J��U��\�Aq�t�.��cD~@�x�8����
J��U����Aq�t����/��"�:����c��2t���3���
�{���uU�o�G*:����H�����3���
�{�k�U���y�����jRJ��U��\�Aq�t���#�H*9N�5)���*wUn���W�v]�����CX�!�����AMJi9��]��[7(���]Wu�07�Vo�gl3��P�RZ��rWu��
�{�k�U1`D~"�x�6�nD������vg����J���:���|C<c�A7��&�w�e�3���
�{�k�Ue�]a��x�6�nF����jwU�y��^�vU}WX�!����{��f�w��*\�Aq�t
��}W��!����[�w�w�M�3���
�{��vU}WX�!��M���[������7(���aWu��
8�3�tO��S�]q����}��^�vU}WX�!����[�w������)t�w��ww�����
8�3�t�n|W��;�.����W��]UG�p�gl3�v��.���aw]��Aq�t������
8�3�	t��Ki9��]UY�w)���]WU��y���f�u+�|W��;�����W�v]Uq'F�}W<c�A���RZ��rWU<�.�������?0"������������U�u�G7�]�����������U�|��r��)wU%8|tC��v]U	�������U��Ki9��]U	��w�]WU��y���f���w)-GW��*�.��������1����]U��w)-GW��*;�.������J\0����]U���Q�]q���}7}7�uU%��F�w�3�t�n|W��;�nB�MC���]UB�M���gl3�f��$���gw������
�����y�����E�����kvg�=�w��w�aWu�����gl3�������]UA�=��k�U�����x�6�nA�-��jwU}��}���:�w�����'��)���cw�}��n2��*�����x�6�nE�����+vg����u�����j����]��m�����7�����w��w�aW��w����]UG�m���vg����}��������]�]���\�c��+���@��E�J���:�#�C��3�t|lPZ��rWu��
�{�k�U������ ��m
]����]����5�J���:=��<�]���>6(-GW��:q��������FY���
��m�jRJ��U��N\�Aq�t���3�����f�
P�RZ��rWu��
�{�k�U������\��m�
jRJ��7����+6(��n����}����\��m�jRJ��U��N��Aq�t���so��+����=��6�{ug����q�����:#�n|W��:�n�v�i��&��4��l�U�	}7	���U%��$���4y]\Cq�t
����+,���f����YZ���D�:�{�k�U���R��m�}�|W\�<�.��1��l�U�]a)�x�6�nA�-����g��u0�J���:�w��0���'��)��v��`(���aWU�w��0���}�J���D�:�{�k�UU�]a)�x�6�nC����j7����^�����j(��V��m�����^q]�������U�WX#��M������%O�[4�>4^���Uu���^���.������\FV���
��-v}Uu����{S_��%����p������6���f���7����/n�����������?���v?���k/Y]^�ym_6���e��q(pK��>�����f��	��3~���m��r����z�5a�;�k����aF���x�1o]�pO8+7|��=a�;�kW���_*QX<�������*\��_m�b,�����j���3V<���pJ��U��j_��
��u�]�W;t����\��8���*�|
E�����|
E�	")�_M��P$�(��-_C�l�H:����H6A$��xQ$��O��������������|������'X3�z����^���y�����v-_[=f��O�#�xW8>��^����p|Jqx�Z������gX3�8?��^�[i-��)���k�Zh��?@��f��<���/��U��S���v�U�N����gX3����RZ�rk�v�L)��]k��3�������RZ�rk����n|���Z��{#��Y��j�7������%���x�]k�zo��W<���7��&�{�[�����5l�2zo��W<���7��f�{�[�������
[��7��+����{����:���@�=���
[���{��+����[�{���N��*��e�����*��E�^���D�-��:���D�=���
[����W��������N�����u����������^'�L���[�u��UC��c����UC�m��:�Tf�����u��UG�mc����UG����:�Xf�����u��UG��c��v�U_P};��N<����/��w�N\��yt����/���+�����W_'������}).������x�/���+��_0#��N<������R\���r��=�/���]����f����33���J��\<������UW}=1#/�N<���7��R\��r���/�����z80�d���U`����������������W}���_���o`�����=������j�^���B3|���|w�_���U.�������w�k�z�Q�_�tf�����_��>��������W=��FA���|�o��W��Hh�	��7?�������>���hf�(��������pF��C�}����p�~�`������ofF�����t��ch�o}w�����{�+����[�}�}���w�nA�-C�}����p�o�W<����H��|��O�2���6�K�D�=���tO��S�^�C�^Q{�������^���J��]ZU���K����[�y��y�:��nC����j7V
��	�������Px�x!�������p;�nn:{��������d+�}Y>?�u�:�~��t�~j|�����>�|���w0;�o���l!���������g��t	������4;��bDa��X����=��%.�W����n�g���������#����xu��������K����{�����5��I��5cD,K���[V=�4���/��{������aQJ����zD�1`[�5^�������x�W�s��l>;lJ����U��D�����w�x��n��K���>�4|v���c3+����Q��+~7��wO�w�'^�U�l~�9���X��c3���Ff���Mg����Q��U�m~�A��c�5+���{����w�xzo�w�-���p�.�����J��I�^�����7	��j�V�7���������Y�^����zo��W��:�{����7[�^�z�!x���t
^��C�^�����C�}o���xzo�W�n:oA�-�����D�-C�}o���xO�^i����t����7h�V'z�9���fk�����J�d���3�V��*xo�n�*zoz�{�5����{�]2�w�xzo��{U�j<�������7X�f����*������I��L�������7V�^��W�$#~3�@�-h�]�^���p ���J���rK�����_Lg�u ������������W�v��s#
�+~/�B���2tu�)��{|tC�}o���t=(/e��*V���R\��������x��q/���2st��*���R\���6�f�
�Px��q/��bDAx��Q3�^���}^F�K7��R�+]���m#
���*���R\�;��-
���R�+^���m#
�+�
=�� �/�����Kq�x��*�W�(��������rx�oi�������$�{�FT�()�r]�*o����At�~�&T�4T����r	�7I��]W%T��+�c����Qy�Xy
��������������}~�{/��7�����:PyAy7���@�=�}~�{3]T�c�����*������v]UPy���������������D�-��n�u���{JW����h���x�a]u�����n�uUE�=%�U���*oo0��*o�w���o��W�f�kh�mh����jh�M0�M���h�M8�}|��������������������S������/�������*�|;��#3�W���|tP\�����fKc>�^��V�E�(l�q�ra�|tP\f����f+c>�^���U�oQ��v���{�����t���<���{�kWW�u�����]���+T������N��u1q/x7�������nW��|����rx��I��-�#��]a�C����\�+V~[/?���u���,�#��]c������nWn��m)���*����+�#��]c������nWn��u)�e���.0��V�|����k�|D���<�(����Qr^�+8>�����nv��O�����+7V>��&�y�X�����z��z7��*��
�b~YE��7��f�z�X�N�������6Vz��.f�n���C�^����c�5��
z��/��6PoA�-��j'��2�^�����
c\�n�N��"x�X���{���C��
[��WX��vkU�{O�{��t���[����V�W���vkU�{+��^�Lg�m��u���ak��{��1.j�V
��	�+V�3�v��6�����������[�����+�	x����w�k����2sx�[�u����Q�s/���\���n���]i��#
��K����R\��s-������W�v���F��W��Z=X/�enj<��{�z�^J{�kWY��cDIz�+�u]�./�/�����
�Ki�t��u�Qp���X����2t�;��t(/����+��P0���I��Z(/�e�>W�{�n��x�]_�n`������W�/�e�>7�{���Px�]]�� �����\W�;/�e�>?���n\��
}7��UkD����&��j���Q�����f���q�����Z�n|7)�UkB�M���p�/������
������M�]UF����jwU}7}7vU}7�����}7���U����w�aWu����jwU}��}���{���2��h�U��"��vWU�w��/��K�D�-c�5��N��S����U���'��/���K����c�5��*�n|7kwU}��������t�n�n2���n|7kwU
}��������t�w��w�aW��w���Y�������]��A������&��*,����Y��
|nP\����n�1��J���
n�������U�w�NyF�1�
���
�aDih�rU��p����tqE�������?1"?4�e��*�P�R\&����+b(���]U�#�Cs����5)������+b(���]U���������&��]��]\Ci�t�����d� ����M��AMJq�����n���W�vUU�F��.�UU��&��]�q��P��lWU��1�03wQ��BD����*���0�
���
	mW����*$�����������a(���aS�Pw�1~�n�2�n�u���S����0��J�����������@�����0H�^����^�VU���#f�����������K��P�+]�����J;b�����Aw���v
{�k�T�h����E��:�vOa���KU7�E�=���
����+��Y�����[����73n���W��UUC��V��?3�6��&l-T��p9���5��:���!�iWU}����}���a(��[����+-�q�U����v�wu�n�.��������������3�:�]�����L���R�]��jsf�v�*wU�����������������j�������Um|��~�j��������
�[���m���^��j[�x).�nU����
��-vu�f�W�B0�o���L:����Kix�
�m��Qr^��j��y).�N{�����R�_��j��(Y�re��`����<�u��{)���]g��
3
���;�-����^���F4����]k�E4�(��Wn����y�U��%t�4v_g�[m	�7	�+��L����x�����|3�o��3l�2�o��k7W�7����
Y3���y�����:PA�vwu�����+���E�=�������{�+����G����m������W'�o��k�W'��)��j���N��s�����������^�������_��f�V����aU������UC������Xf|�6��6�_g�_5��&��v����b�������3�k�_u��.����_u���������{b(���]{�/0�r���U��������oge��qS����v���`��.����r{�;�����og�7w\Cix�������]X�W��j���Aq?}!�f�~r|�����5`FaM�x9b��S���\*��e1�v�����������U�����{�B/n����v���-�QX��*7W��)��Zi��}1w��������=��rs����s.���p�wg�Cq|���}?1��(uUn�Y���O�k�?��2����W{D���U���#�o���m�������;�kW\�	�WX��rq�'T���������P�^��*��
�c�8l�������[����{��6W���=����f�=�}a�����7�P�_�����
�c��2�������������1�v����:Q~�2^�6���{����F�:���6W'���@����f����������qy��5��*���B���f�m��UR_��v\Cq|
����+,�����)|�}�t������|q���5��:���F������v�}�/]�������������n��)���s������S\����)q�������������������)�wr3':�_�{������z����x=�/��N������o}���`DA7��*����������xW`�{�������6�(���\^������/^��7��R����=��7�Q��M����/�e������x7�_�{������x�#
��)�Wq���^��*�+>����u�{3���2sx������R\�ry��g7<�}���f��7
����]�����<I����?��������������������O����������O?���~	�es�����������_�M���p�?�����O"o�������~������t���[��F������W�(4������^AN�%:��6�|+����n�o>��|�.���*�|)�+�I�E���y
���n�����$7���t��\��� '��[�|�������t������� '��k�|3����5��^���_��/+��������{��Q�+_��/�e:
��U��R�\I�F���y��Fq�|
�����(4�W��KFp%����|����oQ0��/�}:
��Un��	����tN��g������
�����(4�W��K�W�I���y���[��k��%�OG�9��w�RC�n�9�l����
���	%7���t����_u�_�&���|;�o��{#J����>���*�Wy���-:'���f�Dq�|
���w��8�I���nE���*�W�3Q�+_��*�e�,i��������f����|q>���5��2�����&�m�)|��p����`�^�8���^��W��eiL��6��+�on�����'4Q�+_��*�}�,�i����7��f�*���|qD���5��2^����&�M�|7��,��s/,���o�g7�_��*���,jR�������t��3���M������x�.���������t�sh2�h����x��Q�AM��3�&��(���e����M�����J����&�e�|3�o��Wy�L�	M�J����(���&�]�)tQ~3/���G2�g��W������+Li�_��A�@�=x�M���3�g��W���UA��4��R��[�|o��y1y/^�Di�x-���W���vqu�����f��3Q�+^�����JS��voU�{+��Yy�_��L������j������][5��&���E��|q<������z�4�)i�V��I���X�^�8���^�Z�V�W���k�c��.�Oya/��|�><(�u@�aou,'f��%���p��Aq�t��]�[�:����W������(���r
^����L�������W|t��}���:<������r^��I��������
�����Xa����*W�
�)��&j�����;����*��<��>y�!`�_��'C"~9b�fH�yH���a���
�'�ZR" �D�cC �y}5��'H# f�c���������?�J(J{��nX�{���p��x����"x��<B�nD��c�0l���y�p������"�`�K�{�&��4���Hh������.JD�%�-���GF�Hc�0�����y��/���Q"2/nQ>�>��<��
�8�"�"���3�(/ny���f����Z�f����C�f����[���e�����x\���W��
��1#��x����������g��=������l�����������������[�z��z7����V�z�
t���[y�u�+�3�6��6�������P{�pz�����x;jo����od����{��{7�����v��L�����]�������,��}���aiU�^
���o����RZ�����>���n��Uq���������rx�[��:>����V��(x�rkU<x/���*�V���R�+^����3
���Z����rx�[����R�����*a�������g�
�������<�^����^��V%4��{���Z�mE�������^�x/���5l��vbF�{W�����������Z����^��Ve?0#���rkUv�^J��Un�J\��
�w7l�JD�������U���Q������7��������UI�����U��*	�7	���Z�����������UF�M�����UF��������^��7�w�l����{���Z������`n����k�eiUP{A{�K���[x�_�A������ZvV�����Y�h�E���to��XN��s(����:QzO^z�veUQzOAz��3�V��:��hYYU���Ko���*Jo����)2��jn��u�����j���w���X5t��;�Cd���Qy�Py�ea�Qy;��A������W�f��L���7�U�����7(�U���������K9(���a]u���-A��:|lPZ���;�'����W��m��=f�'�������Ai��/������^��UI���dR���\�(������&t�'����W��m��6���&����<��:�K������^��Ug81#?�T��>�M)�e~7+���2J{����s;0#?�T��>�.4�����|�p�*J{�k�V�;�<���>�twhJ)-CW� ��E��J���:#�)�������x�`�����L�7�7�UgB��q���g�Mh��7^'=�)xq
������2*���C\�>oF����|�f������^�Z�U:���C��>���{|O���8(��eau��
�8�E�3�t�Cp�����J�pP�+]�����
�8�5�3����E��/���0���=�����:�y�m��)x�yOaT�8$o^��Aq�x-���+l�����[Qz�0)��V���=��7[6V
�W��!�p�����6aE�8gk
^��6��lYYu�^a���}�����q/�&���pP�+^���.���.q���u�����>/�n�[�^�{�kXZU�`F^{��3�:�^J���*�r����^��V�5��k���}^���#N��;����W���U�'f��W\�>�
�Ki9��K�{������������y��`M��Ki���V5������
[��{)4�W������rS���n��{
[����Rh�rkU7�^J�����������k�aiU���U.���Ki��������^�>����C��+�X�A7��F�z��'��7����������	�7��+�X��7��&�z������������*��&�z��3�f��$X��/���������*��f�z��3�h�Y�����@�=������@�=x�g�N���{��+^������C�u�egU�zo����xZo��W�=���[������D�=y�g���{���������E�=������������3Vg������^�����2�k�Y5��*x�vg��{���
�xzoc�������M�^�����v�{��3�v��>�^g�Zu���{�8cu���'G��W��=o��1�v����jK���<!q���>9(-s�]{l��1w����j�`H~��8du_����l�
��P�_�����!�)�I��j>;(-�W������;�kX\��]6a}�x�:��
�)���j����;�k�\��.��?&)7W-@kJi9���

�P�_���m+��G�&���mP�RZ������9���vWmw��+�9��w����r?��G
W�P�_����C��t�A�3���|�i�N|�m_�Cq|
����2I��j	�7
������P�+_oX_���+,��a��������]�|q{�����2���EF��=�/�o�W�l?�/����������+��'b��{�������g��2w����*���"q&�����+^��������[�W'���JF��=����{J������P�_�����
�d���3�V��*��8G`_�"Cq|-����+m�����o�W$0�/�������UC����h�W��	���
;�k�^u�_i��r{������������R�]���/C
���]����2Ws��:�nl��as��/�f>����3�:P_�������/�����W���Rj�rs�=�/�����{7|vc�]
����RX��(WW}���L:q��������VW=8)�Q]����})�w��~`�v������cH�|��\]�- ^��W����/�6���V1$��nQ����Kq��ie�;�/��5l��^0$��nQ��z��������F������~�����{�"p�
�-��U���Q8�����������}/���$���p����Q��P����|/���%���2
pX����8������=P���N��:PA��x��c���}y�oA�=�?�f�-(�E8������o��{_�o���[�?�f�=Q~� ���_��}���{����=�|O�|�8�nE�=�[��fTQ}�P}�;���nE�����p���[%�U���{�����C�{�6T�&(����E�m��ge�����}�;��oG�����Op�����U������P���FVx�d�f��BsxU�/a����W\n�2�o���+��J�!^�AFa�����.^��t�G�_�4|t����u��_1��SU|�3��x=?���s���v����^��UV�H�����]'>�x�
���L�z��%��n�����%���1�N|�3����C0_�[u/�o���+��Ye�%R����]�U+�G����������V����5���D*�����jg�%L�?S�o~d�v����^���V_2f�(l�q^����������9�W�_i�x�Z�/�{��2N�/3oD��������zoz��S6����{��2N�/3oB�M����_�zoz��C6����{��2N�/3oF������_�2zoz��36��{��
�e���x�����U���K��c��o���/z��^���^f�-������i��p��e��oN��oA���8����'zo��wU=����z��6��{��
�e���e
^�����U��������C�}s���x+z��^���^f�������U���������9^�^�
�WX/��o/3�6��&x�vk��{��{-[���+��q���x;zo�W�����}�����[�{��2N��2�[�{)����;�����^_@1l��s�Q�^�������2x�{��xx/���5l����Q�^����~E��y�r��<x/���5l����Q�^���ab�����}���]�nz���5����(y�rk�V�^���U��]������t�{��^
�����Z��Kq�����<>����9[�^�x/���*�Vn���^����>����9[�^�;x/���*�Vn���^����
��{W����3
�+����7��F�{�r��"zo{�ak�zo�W��7oB�M�����%��4�^��*��&�{��3�f��$x�r��2zozo�l�2zo�W��7����y����Z����{�eku���������E�=�U>Rp��zo�l�
zo��W��*������7e�'�o�o���N�S_���D�=�W/��{�PQ|��������VA|7���������7�E��C�
��UC�����Sug�m(��_����_�
��
�7X�V��	��i�V�����;��K�>�`Y[u�.���\[�?:� ���n���%|rP�+^���/
3
�����3�:�����O����w��Ai�x
k+�N�(���k+�����2x�O��OJ{���V��Q��)�V��G�e�*�V~]���'��wC�k���>�M���+t����|"���G������!��CFa��/WU��L).�W�D����+��
C�[���6���o��R\�r��7�L)��ak�w�����rk��_�;?�R7��)���5l�|\0�0RW\s=o����tQ��7�����n�������q���	�7
��|b�zoz�f�Z���+����[�����U���3zo{�ek��{�E2���)x�{����_���<�^���@���������{��������C��-[���+-���[���[x���M���[���[�V'z��Hf�n�N����^����'z�9���������&q�����
���9W��:�����j���*�]��j����^����
��
�w�l�z��K&j�V��	�
�v��Q|�P|w�������d�k�uA�����_�&�]_J{�kX[�����������R\�rm���P|w��ju ����\[����2x�k��;|tc�5��V�K�9�����A|).�W��Z}�G7_��j]f�W<���w������rm�� ����7�Vk��Q��\[����2s������)����^��V��`FA|���f��@|).7�L��\70_�{�k�[�[����*�V��"_�|���u���W�������Q2_��j�`�����Hp���q�����Z#�o�7)7WkD����z�M�kB��C�������}���I��J���w_��kn�(�i(�����(�Y��tSu�� �A��$�o�U~���ox�{����������������~���L�������O����?���������������_�e���p�?�����7�[h5L�Z����{�w��o�>���|��)����8��Bs?�e_�a��2������Gm�5|v�V*�5l�#��_��/�4�p�Flw<|��1�����8��Bsx�������e�]WV�*.c��������)4�W��8�8\��u�!�7�pCLx
�����)4�W��8�8\��u�a�/��2����}�Sh�r�pq�L#�
�rWv8�
�1�����8��Bsx�������e�Wx���=>:��Dx
�����)4w
L��8�8\��W�qH(��1�����8��Bsx�������e�Wx�o���{CLx
�����)4�W��Z�i��2��+�����{/c�	�em���)4�W���i��2����x8�{/c�	�ek���)4�W���i��2���c���n�[�{/c�	�ek���)4�W���a��2���KL���^�'z�e
�/��ek���)�g^������0���>�{�V���b�k�Z�,b
���n�pq�#�
���V��m���)������Y�����Z�0�pF���G�������)������Y�����Z�0�pF�k:����o���2����V�����+�R�x����2x�K�m���W�����fnp.�����{)�gN�g�u �������\���
�E���|@���E�q�����^��V���Q���(�V�
�Kq?s=��
�Kq�|
��m-��W_�(W[����9���7��R�+_��j3�����j���3'�3�n��P~�b�]m�/��+wW��Kq���O���V����nh�n1,����Rs|���m����t�|�����
��-���W)��r{��i�Q�_�[��C�u�a}�%�(	�r}�%���x�~���������*�'A��o
���xV�72�o�����!���v����yV������[,���iX��X��o��[,��\v�VA.������[��,�N��S�_�]`���'�����|+�����e�U������3�V��*�����V����e���4�G��j����_�R��
�����Y�W��	��������y�oe�������e�����������).�W������/c�?��W;N'����6�/�'�/������o�><��\��������)�gF��������|���*���=|x�������b��S���X��>=������*�W������_��j����3#�f��	��eB�W|���=x|tX�~�5��v�PL�9�����#�������*�W���������a���bJ��U��vQ�_FuAG��=p�g���`�k�����\`�8�x��(��r���P������6X;)��`�k�!��eH����+�=�_�6��v�RL�9����S�������m�����/��?vX;�)��`����1�_����|P�����9����]be������~E+�������-[�-�,X��0��|����OpA
>��-k��\
7��\P���N|�f�=��=�[�X'z�)x�8�b�=�<8h'z�9�`oYdU��S��U�����U�`����\�l�zp<x�n�zp�<X[�zpc<���j��M�`q[��=�I�]Uv��>��������]�`q��qA������`�;l�d��`H���iDS�S\�'X���.��{�j�dEL�9��MVt����	�����g7������<�Rs�������).X������n���a�W�`J��MV\��).�+Zp�g7������a����&+�`��Vn�b����MV��<8(7Yq���������l�x0��:�o~����b��}�s
*�������Wa'���C��
S���{_����W�(�pP��b��^�[�1�����%�^�58
���Q��t�|�jpj�{_����P�� �A��J(���`�i��(�i(��}��oF�����3�fT��+�/�b��=P��P����|/���X��:P�A�w���@>���1��x��!��v�UP�p��9��2������{��A~�S�xO����_�*��=Q~��!�{G�7�E�=��hf�����p����f�������;��oE����n��UC���M����o��P|�:�!�������)|�|�p�k��1�
�vT�.��X����Q}�p��=n4�&�;8\������}4~Sn������|�2�*�{�kX]%#3���F~�k_��;���p
���5����Q��*��5���O���T�	W�P�+_��*�3��x��\^��S���b|_\ECq�|
�������Bf�
P�R\���8�|_\ECq�|
��f���������|�Y�N�U���h(���a��3��x��~��S����*.$�DCq��6������������������'��=����?������~��_��#���������������������O����?��x?>\������O������/�_��c����E�'��-����������?�����������x�OD��M����D6~o�ea��������m����#��G7Q�+_��/�m�,p��r��w����E:'n_��'7Q�+_��/�u�,�o��r��#|�f�&��/L�����l��5�����4�iWn�r��9W���}a_��Dq�|
����4�iWn�r��9w��8��__!o�s�(��a���J]�7���3P8g�6��2L�s�(��a���R]�7�]����#`�>��2L�s�(��a���Z]�7��B�*�97��8�a
`��Dy��
[����0��G��/�����:'e��6Q���<��_��uY�����3W�`�R��2L�s�(��e��w��0����fnh���:'�0�aI8���^�Z�Xx�.K���v�����[uN��3��6Q�+`����uY���r�u,��q��^h)��X|,��Aq�|
k�/�Qh��r�u8��8�kuN\B8�������^��X^���_����������p_�����:�r���*�X�
%�!\�s��|W(Q)���a�u��:
��U.���!]�{�����*���5���\G��'��;�#@�z�����S�n��p��jXax��Bs|�+�c�����"H��~�|v�=����:�r���*7X��!\��/L���>����`X`q������\`�7������{��#�������H��Q�_���|�o��W|kp
������,������_m��7��&�_�}/����,����m��@�������|�c(����:P�A��v�UP�^�_X�w3��\�,��\$�.�

p�X|-t
��8XX'
�)	�v�u��������|+
�9`���WA��v�UQ�+/�/u��/
p�e��P�� �Y��j(����:������o3
�������	v���?y�������m����n��?�����F��?����"g�����O���"���[����8��"��/����^p���k7���+�Q����
x�_���<��e�j��Qp���5l������	�>�������]���Cq�x
����Ka�xh�T��2x����p(��a�W�D���<o���$(-�W��+8���^�6ye[1�0�yp/�
D��������zPZp�
���5����0�p�������9�����Tp�
���5l���1�p�����nHW8E���T"�Q�+^�����C���X����z�p�T��Ih�il��^Ih�I8C{~��^��7����$���f��<����Z�h�Y8B{~��f�h��������@��C��-;���N��;���n�j��Q
Z�1�����*h�E8@���
Zo��W��R�z��zw���D�-���vgu������������{�w���*j�)�U�[Q{�����m3�V��:��������U�^�����V�{Em�����������UC�m����7����{���������{��{w�����v�{�����~rt�{Em���\����^��V�R0#?�eUn��>9(-�������|t��h�aku:�1H����������rx�G�����D�����a� �f�*�V��OJ��U<r�>��6�h�Z�+���^���\�1��^���\>��6p���+f�����-g�
��RZ�rku�L)��akun3��K���3�n��RZ�@P��:qq���5l���cF~t�8�r�}E��L�W^��/����W�����W��.]�[�3��RZ�rku���{�k�Z��WX��[�3��F�{_�Lp/^��Aq�x
[�3��
�;�vk��{���/�%�/.���W���UF�Vw��*��f�{_�Jp/^\�Aq�x-[��WX��[�������7�E�=���,[���+����UA�-������^�����^�Z�V'z���#h�V'z�)y�vk��:(��eku��
+;�=�3�V��S�^��
WuP�+^�����
;�vk��{���������:(��ek��{�uA��j��M�^Q�f��=�������������Zu��.x��m�����7�Vu�����%���.�������ZU���zo2l�����^���:�^J��Un��k����k�ZU�bF�{7���z�^J��Un�����W���U]f��wSn��
�Ki9���U]�{)�o6l���1#�����x��x��m��Kq�x
[�*f��W>��Ki9���U��{)��akU��y��HO��Ki9���U�>���f����������Z����r�o+�V5z|tC����U���Q�^���F��(x��m3�&��8��l�Z�����Un�jB�M����6/zozo�l�2zo��W =oF������6oF��C��������y��G��{��������^�z�1�^���@�=x�&��[�{�{_��t/���[��k�Z���{�80y��������{������{�bY[�(�'/����)|Q|OA|_��s/���{��-��UE�����#�g��h�U2_������������j���W_qf��
��I��]\uT�6T_�X6W�����k7W������������������jK�G(��ru�����_���-��Aq|
���<��'���Us��Ai9���U�E2w����z|�bH~�PT.���J��U.�n������U�
C��u�r{���
����3��*�;�kX_�����p��\_��)���*�
w�P�_����C��u�r�t������o4\&Cq�|�a�6����2Q��j�������o4\'Cq|
�����&�����U��<��_�~��B�;�k�_�0$?`7*�W-��F����3��F�;�k�_���+l����UK�����~=��p��J�;�k�_e�_a�L���2�o����_�7���2w��������n���_�����~=����P�_���@���$�������f���
��P�_�����
�e�vU����y�|3_\+Cq|-���WX/��������7ko[o�W���Z�W�W�/������[y�����.���W����j�������_5����o~~�p3_�,Cq|-����+l�Ohf���������p��j�;�k�_��WX1#��L���_J��}~�p/����R�_���/
C��+�����V�+��v��/��5���;1�����U��������_u�Kq|
���)��r�=�/�e��g7�����7,��
L�?����SZ�v����g76`o�`�L�?Q���)-X������c����[����-��(0��kwX}����V�=��X�g���)-X���;H0��^
K���cH^��p���K��v��#Zp[�j�b��y���ZpnA���N�P��X�W�+�'^��&p����k��K�Sg��<����������`�
�=8,��:�����ZYz�!x�v�u�����N\������MVA.�k7Y=�,��=��=x�l�N���{��� |����7��>Q�O�����>0�y��1Vt��wa����WA���bS W��:����H����
W^��Bp��.���M���������}3_4��������Q��������V�E�E��/��������`�����#?;����{�;�>�}�����B��o�w�}$:1�0�Hlg�u�~r|���%)���3i/t���|/]w`Da���a=�4���1��y�q/]�<���B��S�{����3�n��s]�O�|�E�[�W=��8|x��A�_��;D��,���#�|W~J�+Gw�����a}J��!�0�0�w�m���
���W���g>�����<f&�:����n�?$����{�����������f&�:����.��������|a��G��K�
3
�x�nm��:��/?$��S2g��h�qh�o����oD��������	�7
�+N���7������9��^�	�W�B#vCS���&A~�)l3�f��4��7�p��7��Jkh�vh�����%��{������9��^�����F��f�=PaI����#��1��7�p�����J�h�v}U������pA.c���N`i����N������������{���������&��_U��*��8�|�����[���������J�h�v�������|�o���c8�����M4^���������������������9��^��W�D�������y�
�/�|9��g7��7�p���K��MF
��U������7(���KH7��7�p�����Rh��r��/�e�*�����:>����9��^�>`F��r�<�/��L�2����W���[=f��+Xn�����_�^��)��a������
�`��3�����^6X.4�()�r��6���)�7p`�{l�a�����+wX�oTx���M\:��S���)����(8���a���~���{��������q/��[�|#:p�@��+��_�	%8%��!�N(�I��U��r	%8	w��/�s����9��^�-8	�j�X-8K���_}�A�C~s�����,X��]ch�o�/������:��#8��[����W�������!�+h�eh�o��/px���N4�"��
d���
�jYa�(�� ��v�UQ�OI���V�:`���WI����\�K�����\�lY`5�&	�v��P�� ����|;�o�o�,�:�o�7hX���+�*�����7X~��	
�+~C���/��Aq��6�������#���a�����CA���>=(�8��7��=4q�|
�+�f��)�W����e����������|���5l����Q�+D3�����1_���~a
�G�+_����3
Sx�{�3��N)�g^Q&��V����#���a�C���^�������3�(��Kh>�^��W~��Q���+�A{Jq?�������#���a���CFiMP����)���Wy���4q�|
�+����&(�W>��F�Y����7�w3��|B������	�7������{�&��4����������M�����Y�����7�����n��UF����l��������/�������{�w����_i���_����_�pzJ�Q���7������7���D�-����X�'��9�����:��4�vu��������S�V��s���eU���3�vU�+������
���w������}f����o������w�E�mc����:���}f���:�o�W�|?pG�c6,��XZ@�)X�Lq?s�~�u����a��.3J�X���,�x�~
`
Ly��
+��U�(-bU��V
Lq?s
`Ly��
;���(8����+80���
�)�W�`�{lXb�k�����%���S��\��8x|xC�
[�5�Sh�r���`���u
�m��7�����Z7�`
�V���
4����y�QI����
=x7���}������f���).X��\w�`�{lXd��aF���}C3G��(y�:���l�d�=8J��d�	=8
,�sM������-����$�n�2zp<X<��8���G�&+�g�����3������R���@
>�-��5�4X�?�/j��k�W)o�[����G��������f�-h�E��}��h�eh����:��O�����f>��O�0X��D	>�-k��|
,������W^����S�Vt�:t�h�b5t�*8�8�b���xV�m��m�����j��MP`q�����
,��������G���w��E��7,���yo���p
���5���R1�4�H��
>=(�g^e���P�+`�
+���yD�Vp��Aq?S�O��h(�p2������A�J#��5�������|
`�GCy��
;����� m����x���2�����P�+_�+����4���|4��3���n���B%��V�V�����3oP�R�q�����P�+_�+�3
#y�r�vhP).7���m�x+_�FCq�|
;��w�(��Q��B\�/?.��;O'��p
���5��BD�v�$�+$t�(8�S��m4��
���
	X�I��K���v�-n���W��-VF�v��_bf���Yp�F���P�+`��@v����b����1B�����h(�p�l�
J����e���ie�zM�i(��e�u�K{i�v�u����u>����g�����g���Wii��U��;i(��e�UQ���4Y��j��U��}�#�R�{l�c5�`i5�8�����`u��4��
�������n��]du��.x��d�mA�C��M���S��t�ox0��k{��<>��g�&ks�����dm<��r���8���o���M����)4X���<x0��k�q���o���M����Q�`�&k[��).X���V�`�{��*kC�"��xSa���\���0�6����1$o�~Q���mE��	�"����7a�;l�em[���	�E���v0a����+���o;�0�6����`H�����em;�0���t(���b�g7a�vY[D��	�E���"�p�MX�WtB�Cv�a��%4����_���-�	'��_�*��Q��P��b�ee4����_����&�y~���0�p��[,��M8�&��.�@>x�^y��v��[vYE��DX��*(������V�5�0lYe��"i�v�u��@X����D>��,��=�<�iWY=��=����{?�+zp{��l�*zp<X�\>0zpN��7�f|7��:�`g�d5��&x�x�|����a����;zp{��l�:zp<X�\>pG�����j��;.�����M����]�W��r��/�Bq?�n���~�|6l�v0$?��;�&kw�Bq?�r������6Y����R��r��{����y9n`\TCq�
��}]0$?�W>��x�"��~^����j(��a���
C��z�Sn���"`a���r������VY{81$?�W�v1�E*����q3���{�
��};0����+7Y�M*���W�]���j(���a���0Ms����&f��I���t�B�]���j(��a��Gaaa���U�Q�#/����9�Q��X��a��'aaa�<�f��"�_`��!��j(��e��Q���5�kWYE8",�70n�����U��",,��^��:P�A�_��v/`\UCq�-��EX�X#�������o����j(��e�UP���5�kWY'�p�DX���]5w���:Q���5�4���Q�Oa���v������[VY=X�Y��v�U��+������q[
��^-���,,���v���������)������W�&��[k���du���{�|�w`�WCq�
����kk���d�<��~�Z��q����MVt�<xUn�������;�����MVt
C
�*7Y����`�V��<��6Y��R��U���+x0������W�`�;l�d������3{������;pX���������A�-����@�)8�X���T��~�b����g7T���F��w��^�*+n ���w:n����
E��/����F�4X���;h0�����xw�`�{���W�{�F�	�`��Q�� ����x#JpJ�{_����P������x*pX�8oBNC~����xQ�� ���x3
p�X���8��c�{�f��,���n���o��W�����1������{������z��E�=$����-(�����#�{���"x�8�w���[�U��=�{�����{��(�� ����|O�S_����D�=�W�
�V4�S0_qF����
���p4V4��\�6��P}�����UC�m�����g�m���9�5���}�����UG����j7W����-�������������G�W��;�o�5�����JK���X"�)wW������
�|qC
���5,��;1#?��o��U���Aq?s�w_\PCq�|
��������r{�<|zP��������P�+_��*�0;3	[j��\_��S�����3��v�{�k�_��3����o��U
P�R���������������!�-`F~4������A{Jq?syw_\MCq�|
���{�(,������C{Jq?sww_�LCq�|
���(�������)�g������i(���a�"�����o��UJ��Q�_��������^��W)��
�i���_e��$�������p/
���,�2
��������F��k�����^�ZX
���f�.��C`����P�+_����i��]`�"	�vA�[i(���e�u��i��]`�(�� �/�'��/����W��VE6�xq���
��v�{��J�{}3���j(��b�kX
��������+i(��e������4�����7��_x���u	�P�+^���ki��\`�����������/���5���r`FI������R\����{����~��q/^�K��Q������2x�����;|tC�}s���x=�/���*�W���R\������v|tC�}s���x������U^�})�g�k��Fy���W���U3
�����})�g^l��7��R�+_��*of�7*wWy����y�q�
���^�vWyk�QP���]��#_��W|�q����^�nvWy?1���Q������~���|#�o�o0��rD��������(�Q8�_m��7�������*'��$��vw��~�p�+��8�oF�MC�
��UF�����T^}�:��O����_��?���G����?9��?�����������?����_����~��������������/�����_��c�*�22��4�\
e����?��c�=�ty�W\�����h0���>��������&�I�}_��)MF#�:�o�a4�������;��h�v���S��4�e�	|��qLN�	�����1�t����c�8F~t_<�9��1���;�<���c�r�w�y�!���/����2��@&6~���LRn�<�9��e�)|;>���L0l�<�9�����x"sH'2���3����1>���Od�D&)7~������2��x"s�Od6�����C:�I����'2�t"#�:�/�������;�D��Nd�r�w���!���/����'2��Df3l�<�9���|]���C:�_��Od����f�_x"sH'2Y��:�D��Nd��Ag���c|"��W����LV��<�9��]�|�D���l3��������	�������y��=��p����g��3���.)�$�e���#_t������5����������v�W�&��&,��m��6!�-z�_���P&NA&^�Mz��M��6q�m���;�&N�&��E3�V��S�	���?�e��e����(��	q���
]�
.!��<oC�hC��-���.�x�7�L��*��xa�����;�D��n��ut������d��*���]���{������K��]^Y�%(4�F�oY�(������M|��n�'7<I�
���fN����up�Fi?�b��?��(��a�W����A��{,���`����c�n��A})���a�W�3
i�����w������v3����^�^D+k���A��{,��
�
C=�{��7��7��R�+^����3Jk��n���v��[n���Kq�x
����Q����������0�f����nl���U��|)4���2����2?���Ho��P��'7��h�[����;��t#zo����y�7��F�8�hX[����U��JB�M����M(�i(�����(��_qc���7�������x3zozo������{���h����������z�1��h�[�������|z��{�8j��oA�-C����UA�-�����f�=�{�wt�[N��s�����:�{O�{�uES������Q��sJE�=��-[���[y����[�{�tyT����P|�X|-[����x�Oef�m(�MxwRs=/�o��ek�Q|/��������N�c�g��(�}(����:��� ����������~'�{.��Aq�x
k��9���n[�x|rP���V�V�>:(��amu����-b�;��������k�>;(���aou����+�����BgJi�p���W(M)��amu�3bu��T����)�e�=�5n��4��W����2f�����)x�2��L�n:��w����3%������dA
���x7�L)���w_��agJx
k�s����Op�*SJ�������7|t��^����+f���+����Q|#/����)��#�o��amu&����8�{����x���L��P|�P|�em�P|� ���UF�M����0N�52zozo���2zo�W��:�{3��/������{�7[�Vz��{�X��[�{�{���-��e�����*����^q�������^�
�)xO��2��l�Z���'���8�xO����^�����V��zo�l�*zo��W�&=oE�����V��:��l�Z5���{�8Lz������~9���tP�+^�����
�:�Y�3�v���{�+�qn���k:(���em�Q|�e�[��������^[=>��}t������K�������g�u ���{�[{�Fu`�����-��UuC
��\\U�Ki��^�zP_�;�k�\U�1�����U�������=[����}�bX]���RB@f�]A~)-7�G{BN
>����������RBAf����{�
�P�b�^�m�������g���)-3�N��d��)���a}Uw�!y������SZ�lA�Ly�
��w������1 `��_Xso�U#p�[�Q�#�����3�&T��+��bn����c��
VMh��7`���|3p�
xW����3c��VF�����h��7��}~T4�<6`g�`h��`��
��|���=��|��Y6X���`���A]������e�u������3�h�'o�.������OT�s��������'��Q�����Ux���_�����u���������W`q���
�
���;��
��
�,;��
�x?�f����M:���Q��X��e��Q�;���g��m�O��+p~���_�������V[
����qS�������)|q���5������MX4�+������~'t�
3w����jfb6a�LT����J����n��m�a��^�z�
��0�	�f�E$3����RZ�����+f(��a����!����VP�RZ�X�G�3w����j�������\a�
TJ������;lXa��cH~�nR����"`~$�{���_�p��6���^1$?w7)WX-�S�O|���7�P�_�
�ET`a�LR��ZD��������U3w����j	XX9�n����<�/��$*p�U����oxd{���������O�����/��3} ?�q��O����?���������������_����q�����o�\8���7���������=�;�����~i�A��2���g�������2����	���/X�t��a�������=��5���R0$_�'���;(^(���������\�����_wC�7���W������2|�VS{��n|um5������R����=/����i���.���W�V������P�O�5��
������������\[
k�V��\_���7@�Bi??��^�.�Q�_���oC���r��7�](�����n����5J;�k����cH��ZV����pmM�����S�`����C���K�A�)-�������8�x5,�zD��g�{k=�G^�������P�
�o~����B�������Y��J���w�W���8������^�8������y~�b��t�<���>�K�@�=x�o���{����[/��7�E�=������{���C�_���������4�K����������^�'�o�W��:Q}Oil�6�����{_�o���{��+���������F����������w�{/���[y�u�vq�P|+/�^{_Eo(�m���oC�m���E�����M8�}���{�v��>�Wa����v^y��][ut�.��*�V~���w0����#��W�>Bs|uk�G�o?;>�2|�k+�����������/s�����Y=������^9V��/L|��;��c��o��2��k����#L�^x]K��z�i���ok��V~YW���������.��[�+�V�0'<������,C��aF�e-��6W�t�
��Z���#���2���<��o����Zn������?�������#]�gw��q�e�w���U�9���/0��#.�W��z����]>g��f�_�rN��z���w���Z��+������W�v��##��e���|u��G������\_�%��^�=i�M�����_����a����z��/��?��f�������j�W�7����������^�=�j�=�/S�����_�����zu��^�=k�-�����_����
�o��wU��
��e�����%_�������j�W'�o�W��:�/��?��������_����*��)��zU�/��?��V�������j�W���������{��q�e����^F>�f�v����A������a�[�|;��e���|������y�
���[�/��?������Bs|��+���R\��v����n�����s+f�W��6����������n���)������P�(��x�m_�Kq���ueS~~=�/���5�����Q�_�
����|y�}e����u?���R�+_����3
�+^a��7��R����9v�����^��W.�(��x�m
_�_�����[�n�P���q/�
��Bsx��+���R\�������=>����9t�^�;�/���*�Wn���_��A|vC�}s���|#�o�W��6�oD����j�������W.��FA�l3�&����oP�������kY_e��$��x�m����y�
���.�����Z�W�7�+���o��7h����o�����C�_�������w�>t���7X�W���+�`����������[��,�����W��6����{
���+��9��`Y_U��*��x�m���[y�����o�o����o��W��j�����M��j��m��������M�_�����v�7�����������/�����
�	|������_y�8�������n����]���>=(.�W����q�#���a��}�����
�|��|����l;��/,���{�k�_ybFa��x�m��S��]�z�|��+g>�^�n���_�(��X���������{B��������W����	2
{g�x�:�o����2��^��|��+g>�^��W~�!��w��G�3�n��R����}��+g>�^��W~�QX<#~����C{Jq�t���n�~�a��G�+^���G���3������Q�_��AQ�P7���'�_i��x�:�oB�M��������P�P7��*��J;g��|3�o�����������y���e}�Q��3�	���o�����W��=P���Z�W���wF<a���������9��-���X-����+m�OXg�-�����W�����D�-C��-���W�=���|O��S�_������{�w���*���|��'�3�V�����+�s��[���w�����
�g�x�:�oC�m���2��^�
��
�w���:���~��'�3�v�����+��������w�����
�g�x�:�����v�_�{+�u���W�������Q�_��ju��������{�:�_�{�k�_������������)�w�_�~�g7�����Z=�/���*�W�����I�����
��u���_��j]�).3=G���u�����k�_�!`F�w��j
���������)��o4����cF�w��j��).�W���u���W�����/�Q��]��Zw�_�����^���������Z�������5����_�����7�7�WkD�����g�M����_����	�7
�7�WkB�M��j�W	�7����x�{�(�����F��*��f�������y�}e<��|��<��h�_�����Q��:��_�t3_��c�����*�����Q��*�����W�#��������Z�W'�o�7j�W'�����+����{���c����*��)�o���*�o^��>�]+�o�o���*�o�7j�W
��
���?�
��
�7Y�W
��	�������x�}e���|;�o�o���:�o�7j�W����}#���{�k�_�Fda��L�����_��7�P�+_��*8���3N|�z_����}#���{�k�_#2�������������2|��o�<Cq�|
���������G��
�)�e���_�<Cq�|
��<f�����_��)�e�j��
�y��^��Wa[0��F��
�����B?y/_\=Cq�|
���5���u��|w�|��������z��^�f��*�'f�����_��)�e�3h���z��^��W!��
h\R��BD������[S����{�k�_���+,�qI��
	�7	�!^XOw� ���{lY`e`a�K�VF��v�`�

8
8[6X����%��@>����G��P�+`�
��;h\���
*p��#��1���{l�a������;��Dx�C�?Cy��-K�%X�B��v�UQ�OaC�W?e�4��
����h����[��\�^��7�P�+`���{h\���jpv$z�{�W�P�`�XYEX�D��v��Q�� �^������������0aJ�V���L��r����oK��74a��Y�RP��\fmT��r������
S�a�6k�C
.������S\��v��ypa�; lXgm��!%V���d��2�/�o+�0�6����aHI����-x�������\���Y[81$/�^�7�2Lq���|o�0�6��������E���6�a����s��+>;��
��m��`�:k���).X�R�>;F�
��-�
G^���\gmU8
*��g�z/`4�86ag�fm	M8�&��6kKh��7a�N�����"��"�,���"�x��v��Q�3/����)�3zp{�������{�_���=��=X�s2��|�=�YVYz��{�_����|�,�9�����;�&�������=��,�9��D>��,��=��<X��:��O�P��C�{�EW��s��������U�`��dU���{�x2�'����;�&��7���v�������I������`�&��7���v����;���I��=�3l�d����P�`�,���w��R\�3X<
�Ax��4��J�VY�s��Q��/23;���a�W�v\OCy�
���u�O)�N���}@��M�0d
a\PCy�
���W����N���W�R).GX���5�w@������!�I��)�Y{�2��r���������Y{������wq��6��r���K������Y��4wa[�_��Ax�:��r�
���E5�w@����w����j��6��;���#��]W�P�a�F�C�{��:��}8
>,�1S���; lXi�	}X�Y���qgN�����:��V������Z6Z	mX�Y���qg��h����.v����P�+���������/��;���.�~������q]
����taak�_��A����r0|/a\XCy�-���.,������S����>u
a\YCy�-��]X�\���qg>��O���/X�����[�Y]X�]���qg���Up���{�h���;lYg5Taay������
7^�_�������P�_�2���k��]fu����c����[k(���~���~��������.,����r�t������nEpaJ{�~�[��t�R1�`��r��0���ci���L��^����^��`D��W�&+z�`�����^=x0���}���|}�����MV�`���\��:�������|/��2st�[���S\��W��C|��x���n(��}{�o���^�
+�_���8����74|xC�}� �^����]�����R�����Ky/|�;����0�d���U��~)���*��|w�_�{���1��|;F��W���1 _�R�����������8��F�~���3'��(���/���������UL��I�_q����7I���:��f�J�!������/O����S���F������3`C�
�!��}y��������W
�[�W�
,�_���A�_�~3`T�2>���Nt�"8p���Nt�Sp�W&���D>�g��%VE	>	�%VE	���2��^�%��oC[�X-�
�[��\~e����Zp[�e�����d��5VGn��WL��h�}l��=VG��+�Xi��.X�x�d��+k(���a�����)E~S��� ����Y��5��
���J�i&ao���{�����r��_XI����^�X��4�$����r��<|�P\���*	��P�+`�&+�0M3	[k���d�jT���n�����W��MV
+f����M��J�T���n�����W��MV�f����M��J����d%�WCy��
���u��O���r������&S���{l�d��bF~Z�������).X��J����^6Y)�[k���d��o�L��j(��a��z����o�MVBN���M��}5�����e������5~�n�2zp<X�m20����W��M��,l���v�u����M�F>���\�{�`ak������\��L��j(��e�u�[k���d�������}�)�q_
���l�N�`ak������|
,�7���P�+`�&��[k���d5��*x�x�d
`�WCy��-���,l���v��������M����W��MVG��<��2���%�n�����l�d�<�Bs������S\�x�d
`���{�a��x0��+7Y��S\�v��]��7��`�de�bF���r��=x0��{����x=X0���5����0�`�Q���+X0��{������S�+^�+�3
�[�V��;�|/�Li�x
;�*f8*wXy���t/���x7�_J{�k�`��`F��r��7�_�;N�����w���������Rh�r�w�_����g�����}�a{�#�o�7*�W9��F�}�|S't�8t�`�^��������UN��Ip_������i����UF�M��j�W�7g��?�)�3�o��e{u��f�~��������~S����7���@�=�g{�\��X��7pA.C�,���\N����\�3�F���D>��Y6X':�)8p�n�Nt�S8��M\����o�VE��'���W�X��7pC�C�,[���N�-VCn��������m���e�������I�����]�`������}���a�u,���I��:���`�&���4��
���:����p"��������k7Y����W��M����'�I��:<|�P����>0.���W��M��f�G��tW���/��!�[W����?�������x�x��?�����������?��
�����?������������?��/_��+���q���c�3d��W����7�������/�������LD�&�/t���
��#��{��r�wD�&)�g���8�����$�����`*%��+�G�j��~�-�)������$�Q����G�'�0�TJ
��������/}���_>�^����� �N�?��EO���DD���-H$_�[����>�L�������"���L��^�kz~M�
������E�!��Hy������k�)|M�L|���s�5}7�B�����&��E���+~M?�!���T~/�
�(���az�3
�4��(7�m(��q��;���m�m��MhC�h�&��5��|Q)���R~/��F��FaY�v4�.,�x��f����F�����-8��^���e�(�)�_}�y���-8���2|������r�N|
k��f��h�����|q�9�e�jR����2����1�����Q8�z~�f�8���~��c�������e�9�5,���`F����U�����s�����T�����e�96��W���c��W�n���).X{�Z����2��6X%���`q���8���r�_0�{���r~N�
���Q8T�n�
�>���;�/4�������2���6Xe.��_���G�S\�X{�Z����2��VX%�_�}SD0�>��`��[g����sl�a��|�����6`}Nq�#.���g����slYbe����_��Ir
`}Nq9����q�y��>'��-��|��`�G�S�OR�����|q�y��>���g�-�2��+��-N>�������'����s�kYc���������X8���~/�,�|^.��	�e�u�_��X������{yg����r�|N�-k��|�`��S���������e�9���Z�e��W��k,|Nq���/������e�9����:J�e��W|�k,�{Nq�cj��~|^.��	�a�u.� ��5������^N��>@(��a�u:���)��)�|~P\N��{�����6��N�`F~v��Fr
` ��	�>J:=|�P�+`���
3��S�5�S��C
���o
�jT�{�
{�s=1#?;E\#9p���r�_��{�Q)��a�u�3��S�5�sC�Jq���X������Y�#�(�'���x���~7��w��TlXd�;�����x�g
�zT�����:���TlXd�1`F~������=8J�}�F��8��l�d�	=8�,��3pBN��_�:zpzp�l�2zp<X�����Y����{g��<��l�de��,x�z�u�g�����=�{�e�u���k$�.�������)�zp{�e�U������9�������6����D
.C
v�e�u���o�M��|���{������P��b�dU��*l�To�*zp<X��9�WtE�Cv�e��P�+/��z��P�� ��"�)��p��[,���&�x��N!����`��.�)�;�p��[����
w^��wCf�8��r�����s��e�a�6�.
C�.,�2�0�A����JmU�8�^�6���;1� ��uV�A��q��^�8	�^&�6���?0�`��}V�I��!�����W++NB���a�>��`��:������}V]��).X���>;��
����)5X���l��~bH����X��a�U��!y�>M��S�O��x����}V�=��]X��4�.Lq��`�7��.Ly�
�����x�i
��.^�_A�]8�]��Y5�G����OS't�(,}{������p������p�]X��4�pFN���W���K8���;�>+�g����Os�g����/Z��|T�<Vag�f������m��*|�*������oA>�&�,���&\V��
�p�MX{K-(��a�*�D.��w���=Q�O^�_�}/�=�d<������'�����)|+zp�=���Y��~�h�ul����jh���`����
-������{�6t�6v`o�c5t��;�xib
���x~��~+�����-[���y�L���������'�m�����vXm)��T�;������~���������6X�e�O*��
Vs��Aq?qm{_�UCi|
���a�fV�D���y�������=�/.������U[a�fv�D������R�O������������a���!�a�Q��z�
�M����������Wms��+^H��w����~����������Wm�RXX��_�= _~��������j(���j�_��bH~T�8�y
��Kq?qW{_\TCi|
����}5�$�)|�o�������/4�SCi|
�����u5I��J�����^���/�������UF���$��*��f���Gj����[6X���&�7X�����!�|�x���
:���&�wX������{I���;lYb�(�����^b�(�'/�����0����_��������[���OEXXZ�����"|�"��M�{���{�!~�{��x+z���&��X
=������{����{�����{�6�`aaMV��:jp�5X�}���j(���{_����Q��u5Y���(�]8V����>����>�J�/������]a���~����t���n(��}w������]��;�_�����f�
�P~�;����_1"���>S�zP_���z�^����^��w�{/��aD�{��{��]�{).�N��
�Ki/t�;���n����f�����ty�U����	�.��~�;���o��QP^���o���;���7P^�;x����V0�����U��y).�W������R���C�{����:)�$���������~�s�k8��F^|���Z�����_���'T�8>�5��zB�M���c��N(�I8�Uo��o�ZVW�7��+O!�8��f��zy�Q�������:��3o�n�����A��$*���������H��_��#��������������������������������������_�����"T������~gx���q�.�G�q�W��l��X�����X������_��#aW�=2n�q�>��;�G�o?�>�r�t�=�4|x�5��ou���5���/�]�PS��aNxx��C���[]t�Q�PSn��v�^�+7�0<�8,v�Zr3���f���8]�) `������#]���������G���j�-��������v�r��H�����n���%��3����?�>��r�+w�t�1,w��[r/�#cF���?�n���]���+���}sp���K��E(w��)��	�_�j��_��\�����{���������'z��{�W��a�����9��^�=�<X<���W������G��:��7g����W����)�zp<X��j��m���MVCn�� Sw��&x�z�������-����v�M�_����j7Y~��{}�����K����5�&�;���`�&�;���W��M�w3
���:`����?l�s���}��� ����>CF/,��)�=|�P��6�x�����6Y~��qv��u��+4�����
�><,R	�a�����jM�����R��6�����"�6Y~[1��u\�����I���?l��E*��6l���0��t\�����I���?l��E*��6l���1��s\����+�� �r�p/���l�d����)�zp�=����{'��4�`�&�'��$x�X����x~���^�=8
=8X6Y=8K��de��,x��
�>������e�u���7Yz�!x�z�U�����&�����:
��\x~���f���e�����:�����b�?��|���a���O��s������������z�U��+��b�)�+zpzp�l�*zp<xUo�zp�=���&�n��m�����j��M�����1�/�������_=�������1���c~��p/+~e�*�c������1_������L������v��0,��p���Lh�F���� �{�^�$���_�	��9���_��y??�^������<	�a�`��Gh�	j�F���� ��w|xx���`�a�`|�Gh�v�`~�G����p��|�2������k�&���� �{78�������0��#4�;P��0��#/O�|&t8�������0��#4X���`��G���5������v�N�
��
���k��r�����4�x�v��N�
��
f���k�Ls�����4���o���a���8���`�klt�����4�V�o���a���D���`�&k���y���������=����`��Gh�v���T�����M�-�o�y�����`��Gh�v���X�����M�m�.�	�6Y�u���n�6�����;�i�����e�;6l�6�����dm0��#�wr�x����������"zp<x�n���|��nx�xK���������zp<xSo�z�e���M�-�_&�`�&+�g��7�&+�_���4����Dwl�d������z�u�_����4���c���e�U����7�&�����oo=�=x�l�N��"x���d���'���7��=�{�e�U��O��7�&��W���{�SW��:�`�&��W��7�&��W���{�S7��6��h�d5��&y�z���������)�;zpzp�l�:zp�<X�������`�R���� }������x��Bs�����}�O���n�v���
g�G�&kw��#��k7Y��O���n�v����P��M����G
��n�v� ����d�����P��M����Q���k7Y�
M*��/�N�B�Jq��
��=8�(�P����=@�Jy��M��H��W��M�:ff���M����P/�N�A�Jq��
��}��Q���k7Y�M*�ek7Y�E*��6l���`Fa����d��T���n������p�X2l���%�n���y/�N�������a��'��$y�v��'���{�x�w
�������W�����+���8�� ��"�$ ��#�����rc�P7��?%E�hk����'�������:����<���r��4Y980��MV@cf��)98t9�k���v�&+"G���MVD�]��&+!G�����J����`q����S�����J����`'n�2rps0{�wJ�98w9�k����v�&�D�cf�N)�D>��5M��|2��MVA>����RpA.}�4Y9�0��MVA.cf�N)�"�>k���\v�&�"�1��zg�������h��L�GK�,�S�A��&�-/^�����rf��K�,g��)��`i��p0�mV4Y���p��6Y�S�A��&�Y�`���h������`/m���a�K�,�S��`E���32��M����)��`i��6�`���h���0#��^�d�8������z��S��`E������&�����wP���r�������h��L�GK�,wS�A��&��/^��M�s����`/m��Cvcf��)9��9X�d9����&�y�`?�����[�������f�4Y9�s,n�rps��Ah��C���i�rp�8X�dE��0�`�X��_�98v9�,�*+"G����J�q����)
'��a�h���$��.+#	�1	�+S��[+������f��YY83,�mVF�c6W���[��0��0lM�u"
�
q�u"
�c6W�'�[qA>�8lM�U����A�h��2�ase���#�.�E�iU$��qwZ�����}In����H\H�(����%d�8HK-��m���~4�q{
��4�h��1��a#m�����4,�l�����6l��7C2�\����v���s5����4��k(n�aE����!�m�A�k��*���c_���0.�������_�d��p�&5b���~<�q�
��4�����5=��f��Z~�Jy��.��o}��q�
���h���5=��f��Z~�Jy��.���-7�P�N��N�0_�s{li�����w�%��]���^<������w+�d�,�J�;�a����p��a�aCq;
+-����M6����i�3K&.����a\bCq;
k-�4���Y��V@�������m��P�N��F+ 
s�lq����nQ�a\cCq������H��2����
7�4�=�
���iX�h%�af��]��VBN���O��m�P�N��F+#3�l,�#�4|8�M�x'�p�����o�~�{�������������~���_?�;���������O�������������~��+d��1�?���ed��������sM������p���w��C���o��P(J���dnl�U��k/:��Q���Y�_{�ox�76E=��(��ai=��(��I�t������5`pc�����5`pc���oV�
�/^_�ZE
#�^J=jXZ�������7\���E�U��1���,�Mi8�����x�0&�������`HF��7�����~��|77�A�R�N��0��!����1��s�������|77|����m������!������ 3������ �>��0�������y��y�Jk�X��K��WE
+�pex���)
W��:�a{����
�y��yxUtZi������VZ��)� ���Jf�����U�i%<L�G
K;�d��)� ���J����������]1$��,�Li�S�~�U�i%<Lq;
+:����0�#S^��)��ai��V�a��6��������_*��{+�d��E�)%o+�<F�UZk�
���6���L���vbD�Y ���@Ly�JK��S�����J����0"��,���p����VZ����uq��/���{S�Q��B+��w����J������k_����!
;��uVr��n�����JQ�uQ��/�����=�,�L��#�1��2�#�.��X��~b�g0���)����`���
������=����f	dJ�!82,.�"Bp�>~�����"�F�Y��oB��c���5VB�M�G��=�����fdJ�8�x�X8a(���3C�,��)	8�	x7X'p�V,�D>f!dJ�'"�9F�M\aD�s�<X���\f)dJ��0���,�p�6\�K�y����H���`q�U��+�8��&��F�����+/^B���=V^�By?�zg�y�[�mVY�X�8�SoY�R��{�|�w����P��`E�����c�-�"S
�p����Y�O���;�mVTY��8RoY�R��b����������H��m��.+�3�G�[E���J������%�
L*�m�r(���E�8Po�_�s
�Jy?��vk���U�����wX�D�GK����K���O����|�x�R�O�>`��,���.��
�~\���U�/vf/l��gdJ�9��9x�~^�r��r���:�-�#;���UV���~��������}��_�qo�9�s,n�rps�.��0�����gu�\0rp`8���L)8"�1_y�V�#rp�r���:�-8"G�������rpd(��F��pBN}�TY	A81 ����� �� |EF�[pFN}�TYA83 ����� �� ��U3��I8wI��I�6|"	�	��.�D>�$��W3�aD����/N�����(|2(�����(\�(|������ 
�.
�8����+�paPx�YQ��Q����{A�"	�.	�8���~�I�2$�~Q����	S�����d�l�\�)o����:��9��Y�Y�af��{�w�����
S��`E�u��9��Y�����������-�0�mV�Y����!�CZf�H���	_����T?��^�WE�u���z����:W@a�;��������������:7 a
�9����	S�Q������x�� �(��}�������S���������;�0�m�t(������!�CZf��0���p��V�q���-X�e�n��
�.�t��n��W��[�Cv]�]����C����:=��cH�]3;�&���}��7M����=C����
H��!av�����p�������p�HX�e$�0&�o7��oD]�4UVD������,�@�L��������J����`'n�bpb0X�bp�b��)�2bpb0�}	wJ�183|��{�H��O��"�D
�����|"�c
��e���O���O��"� �;q�U���@X���\��kz��\
v��"�1K�:+Bp�B����*Bpe �Ik���
��!�������Kk(m����*K����"'m��������`)��W�P��_E�UL����"'-�����1�����+k(o����*Fjfo�OKcd�p����/|���a\YCy��=VYa�fa��X�P���W���w���us��jTjX�d�m���W�T���7��w������6�k(o����*����W�����wP��w���o��6�;k(o����*���=����)
�R)������m��P��aE�U���=�^Zfg���@Mse���
����4|(�������5�K����������
��6��k(o����*y�Y_c�������Y.!=�������)��0���zq���\B�TG��5�-X�hE�af����F+"
Gf�������k(n[���J����Z�������w�!��a�����G����� ���/~������������������o������?~���w?���odo~����������w��-�>]�_���o�)��z�e}��x�gb[�_��=�F�gBO>2��3M��|���Y�g��]���������3���2�F� li��q������x���z��q���Yh��#M���7.��6�r���������������+���\Ax����������_~1��7��40w��1�~`~���?��n�J�78�����p��)?�p���7��_p)���G��9�N?�z>�������*����tp��w���H�G��]sv������G����L���V��9���_�
\��*������}dD���c�"��~32Es~��e*�����L��\�~�T�##2��<���Q���D�h������������D��[�z�D�##Ea��^P��[(���of����_^�S�T�����<Q�����z���3�g��zo�5��k�S��F�,3����:��z������q?���[�5�/��>���*�<�T��<��p��z�����\8�wo������*�<cN��<��p��z-�/����b����R��^��|�H	32q/��^ _���/��[���������2+�/���CS�]|)�h��t���k�_�(���K�?���~7_���s!��w_��u��+�+��R��1���@����B��o�k�E_�(���bF}���9})����������m����8���6W�!��1��~�����WTW�!��1���	���~�~�Lu��_������5��G��c�e�O�7 ��1�^�ro��7t��k�������>y��/�o�/�XzJ��7t��k�������>:��oD���^�WwNe�LB�}��W	8�x�W	81,��3p������y�������`q���s����:�3s6Q\`��'���8��g����*���Wq�U������,���AS`��������`v?������k�������`i�e�{T����s��#�=(n�����K����������w��Wx
�#�=(n�����&b����MZ`Yw�;z<-}�v���]�
��2����M�`Y���x>��j��uW?E�e�2������)���O)�g|���o�k�����6�8���I,��?������]o�wJq�~������6i�ew��wp~R�	��A�R��_�(���r��a�6X�JqG����*��4����Q0�x��&���[����vH���2��2�Y%�u���`i�e=B�c X�!�����fQ�X�#{���-�G
���7�|�R��R�����p@c��=V@cfgZM)8"�.�ESdE��8���.��w����N:���3�3*�Gdy3�'�ziT��_��1ro~�DF�����hN.���������n�L�~��o��L(��B��}a���_zk��%�����W�.�S���[k��c��K��������g��m�0�,���:�����,m��������S
6�]�x�Y��f@�Q�A���o3p����tpJ�v�k�=�h����,6J=(XZ�����Ms�����v���(��m]1����.m������u��[����E��iXQ�=~�`���]Z�m6�;jXx��#
R�������U9>��K��m_�a����S�6��1E��iX��m��!��i��`�(����m��7�(o�aE�	C�_�c���i��P����p��6�v�W��Q�Y�Cvc>�m�������oJ�a��a�(���#�1�:k��~���a?�aM����q���������
#
�
k���4��8�}VD�cf�ZN)8"�>[M�����q����WN;��pBN}��B+!�1��M�4�����Ggd��ga���2�pfXX�g����a�+�a�m�D>�,l5}��,|2,,��Nd��a����-� �}��:� �1;q�U������o�Q��Q�j���(\�(��mVE�
_8r|k���(\�(lm��
S�A��6k_�)��&�e���x}��6k7+�����Y��������
�0���h�vk0������-�0�}��Ii����������m��cv�6k_Wlx�����)����-xU�Y�zb�1
;i��o��w���"�o�����������!�(��m��
S��?o�����������w@aJ=(X�f�;�0�}���g/^��WE�����z�����`a�;�K�������������������Y�Cvc�Ga�(��(�*���#
�1
{i��{Da?F� �Tx���������
��~�����)D�0FayH�I�W_���g�/u����a����)G������C�="�.��=��z#�p�0{6fJ�	Q8�QX���p���k_���7!�1��&��������S��_�
}o�)8�)�}�>�����,�'Bp�B�k_����D>��>Q�R��|2kL��7���|v������[��C��� �i�"�)"p�"�k�����"��VE��K�����H����S��c�x���>������������VX���������{�5F��YES�5p����~���:�>(og�f�3�g�J�v���3\��6X��������X���q<����S
^��R�Q����XA�R��a�����3\Y�?�`��wT���:�/^����:6�J�?��O)x}JqGK+�c7x��3\���LM
�
J�;T�;*XZb{����e����{>6�8�e�J�)�P)�h���:p���-XQc�b��2V�O)�!;�Wi�u8�`��f�������X�G�_vwo�9��9XSdy�`?�`^�Oi8 {������� � ����p�0/��4��C�W����pD�]~qD��
G$�8&a^��iQ82(|e���
'D��E�Gt��pBNc������pbXx�YY8uY���6��������lS�����U\ge�����gt����0��0lq�u"
�
���i�����C:�m� 
�c6���*����a��������
k
��8���1��������a��������
k��<�������h�nA�c��T��Jn��m��F�-3r8,�����_�+��S��aE��L��i���0�5,�E���^������z����rp��~)����������s:�mx�������[�)��6,~���^�_��qo���f7�Nix�������
p���
+*-�[�����VZn������~k�;�0�m�UZ�X0#�FZh�`��~�+���{
S��_E����6�:������/Y�����]��_�qo�I�1$l�e��H��!����-�#�.�8����=���@X�eya?����o@�]^5UV@�����|���7"�>k�����"+"G�����`d��g`M����#��V�c%d��<������S�7M�����V\ceD�<F�+/��[pF�]�4-������D>�|�q����g�7M�u"���ZO)� ���`�/�)�t)x��X)�0��j=���\�|�
�{�H��K�����H���`�.7�`��:��+Gvn-����������4=������(�/p����/�~��`\ZCq��=�70L�3�k�W��l�ByK�������+�,oa���V���ZO)����
���qg
�mV4Y~�0�xX/�����W��wP���h�;k(n[����������U�)o`R)��`i�qe
�m
�M���8���j=��L*�����]���5�-X�d��`Ffq
�v�����jn�.������h���1#3��%�);0��w`��E�����h��Cf����Y�)9��9x��k(n[����9��[��f=�`�������lx��a\YCy��5UV@f���YOi8 �1��0�iI8tIx�tYI�Y[��f=���$�$���<�a�YCy��5eVBf6�6�4�����W��4�kk(o��������������3�p�0�
���qs
�m��Ya��_cX�����0��0���:�a\^Cy��M�u"
s+l6q�U���1
��?Ni��P��aM�U��%6���*��e�����S�6��mX�hU�an��&n�*�pexX��� �.�J+,��z����
�0���7\�4\��uy�PtZ�l����M�i<Ly?��)
�a��6��������aV�Ni�S��y�uJ�x���
+:��.���ai�V�a��9��Nix��m��N+�3r<,���f�a����G���)o����
[����N+����w����W�[�p���+*��G����.���8LyK����K�N�h�h�B�
�6Z����������������S4Z�!
;��wi���ch���[Gf�4��4��V�H����]�h�4�f����=������4Zi�34����4��E����p����4Zi804����4��M���#�p����4Zi824����4f�����p����4Z	i8q4,n�2�pb���|J�q8wq�i��8�97Zq83O�������y8�yX�h���'�����:��O��Yi>���<|�yXSi�����!��
�p�xXz|(�����^�iU�����!��*�p��!��������^Qi�e�+���!������9OEf|�#����m��J+��1������!��s�Liw�P��aE�M���B�CZiE�a���M�����q�
�mVTZ����Yh����4��S�����g��Z0����m��F+�	32�|i�7P�������l(n[����[���(�CZh�
�*�<���"q�
�mV�Yq�Q���fci�w���y�?�&�������6#���8i����wP�����l(n[����n���Q��I���������{�]6�)8(�������6NZfE�$��$|Eu�[0����m��2�#3m�=uJ�A��A�����`\fCq��5]V@f6�'��"rps��qo������k������q�*+!�1��?���l(n[���J���J'n�rps0{�sJ������k������1N�de��<�`�����q�
�m�4Y'r0���8q�u"�cf�)9��rp�4Y9�Yic���*��e�����)�6���i�*r0����U
�W���p����m6�-X�dU�`f����&+-��u�����O��Lq�������rbH����J@�������qk�8��v
VTY�$����VY�S�A��e��[�`J�)XQe%0$�^Ze% Ly���u"3
^-^�.�EQe�@�R�
�VYi�����w���-x��lE��6aJ=*XZe�
@��
~�U�\p�k��`�(�����a/��� LyG'N��9�@��vVtY�0�#ai�� a�;21�
@������JG��
K���6l�9}�u���CvV�Y�!
;����JQ�1(,=u'yda?`aE��<��gX8����,��,l/������0�0l4uV@q�������;�6��C������H���� ��"�p�������p����Z	q818��VBNc����SBN}6�F+#'��������y��Vz|������FSi������ ��N��s������{>���>M�u"�q�U���1[q�U��K�����*����aq�U��������������F�iU���������D����i3�wd�hCq;
+:��$9�\d�x��������7�P�N��N+����6v�vZ��M���I[��m(n��UtZ������������n"�w�xX�Zf�hCq;
+:�������������+HU���Gx�n���C��lX�i�m���I�v�vZy�Jy?���
�F��iX�i��`��$_�H;���T���}����q�
��4����^1�x��]��V>Vlx<as���w�P�N��N+'�O������x�����w�P�N��N+;�af��]��Vv��n����������vVtZ�#3�m�"��<����*m-3������5�V@f6�X#���p�0;�`J�����v�tZy��lc������q���`�9
#�>��N+!3�m�wZ	y8�yX�a�iCq;
k:��<�l��F�ie��<�av����q�
��4���2�0���q�u"�1�7�;m(n�aM�u"3�m�wZy��0;�`J�����v�tZy��lc�w��4�<\�<����0������5�VEf6�X���)
W��:�av�����y��yxUtZ�<L�G
K;�s�������i�x�����w_?k~�d��z
 1�,��NHLy%K����x]$~������#2@���5�_@Ly�J�8-1�m�}������#28���5��p��~!_��p��6���E��~+Fd`�}�kJ�����aX�k�0Lq�~_�}s���f_����(Ly�J�8w@a����������Fd@�}�kN����K�}lx�� ��c���=�)��_i�u����K���,^�.��P��~B�c �}�kJ�!�1,�P�����P��G�7���=����^S����~���+�s�E���G�/=�����9�X80,�D����DX�`E$������H��!`���gD����#G��7�������3E3�&="p<V,8!'�����������������5%VF����)!8�!�=36�|"���`M�u"���M)�D
>���RpA
>��55VA.�oM)� �1�\�K�l��������`�%�)W��:��+��o.9��9XQd�e�+�p0�����w�;(�&�Zp�m6�-X�dc1#3��}hJ�� ������l(n{�C�d�`Ff��*m���;��J����P��`E�Ul����U�d�u����5�!�S
�m6�-X�d�5cFf��&m��&��~E��b�4��l(o����*[����MZe�
T*�5,�<��>��6����#6���n�.���R)���������l(n[���*L�,�N�I��r�K�����mt�m6�-X�e�aFf��&���Cv	��5�4��l(o����*Q�Yic7i�U<��gP��9�a�fCy��5mV@�V�l�6+ f�;ZsJ������
k���0�����uVD��	yV�m6��}sE�gE�an��&���p�hX��p�
�m�Z	i�[i����4�_nXp�
�m�4Zi�[i����4��4|���{:�2���)�N�av����:��Of�;w�G��P��aM�U���6���*����a�W
.���m��F�"smvq�U�+���g�.���m��J�.���F�K+��S�A��t�u��m��J�.328�K+�jVl��avv���
�0�mVTZ�d����.������x��g����-�0�mV4Z�F���0�[pN�@���s��=�6��x��4�)��
S�Q��F��@���s�Mix3x��8�)��S�Q��F�n����s�i�������h���aFn�����;�0���$��������mXQi��bF�i�U�a�;jX��C=�)o����z:fdp��VZ�!;���^Sv���������q�18|H+����tX��R���������������C\i�a�=�>�W�p�������p`x���=�a���=WZy8�yXSiE�����!��"�p����N��
'����aM���������J���y<|e���
#�.��N+#'����VF�_y����3�p������N�������:��O��aq>���.��N� �;q�U�����:�)
�����]�i�����wZy�p������<\�<�k:��<\v�Nk_���1�cT����~�~yy�m��3Z�H3�GYw��:�c�5���g~yy��x���_?�=���|y������O?|�����E����������o������?~���w?������������{K����Y��\
������7��W�����o�@���o���P�����H3���Y',w�~���wtK>�����(o���|D�����',w��W�a6����������;����H3���Yvi���4�l�5���)
�+^=��L
�	�GF���r��������af���g��z����d��|d< c0����)
�
3�f>������H����
��}�5,,�<4�l�5�
�)
��^��H�������%�0����
�n"�w�����G��P��a=�[c0#�_�M�S6p��_���G��P��a=��T1#s>���8�a�a�����]�5�a7��6���=1#s>�}]}J������9���xonx=���8��VtZvM��9���[����@���9�aweMix�Jy�����f�G����9
�T�����i���JUjX�i��A�}|��;�4��T�����mYS>�z(U�aE�e�2���]�7���*�4�����p���R��dN�iY�b��y�n����Cv[|�Av]v�N������ai���/@���a�c��4�����N�iy�a��0�pbJ�y�s<,n<�p����tZy80<�n���pD[|�C�]v3����t	���K�<�a:U�����D�=V��sE��q`N�<���cC�S%���������z��;64�G>#\d�}
y�w"\�.\8M�w"\��,���o=�fOd��avK����-�>[h:��lq2g�/��{.��A�+S~�-� Z�>Zh*��hQ�W/��{�H�!vK���+�E������H�y������uA��X\��tk��`Ay���
�<�������`\�2�<��!N�l�K,�m
��~o�u���r�@
�l�1��,�4���)[x�Fy����
�<��_07O�Vf��aw�M)x�x��O����[a��3����]�-x^�E���7��m����`�(�V���=(��Y�{���Wf��a7��)����r�W<���2�g�A����[��2k<
�@lJ�;p0�mV4Y+,�|�,m��8xe�xv����`���h�VX��="]���`����A<���s]��&ku���y�&m�V��l�4���){�`��`E��z�`��7�.8 3K<������C��5MV@�������4���)G������i�"rps0{�sJ�9�Y�i��aS
N�����A�d%��4��U�d%�`f��aW��)98u98h�����������,�4���)g������i�N��<��U�d����O����R��|v98h��9�s�*n�
r0��S|��#rp�rp�4Y9��9x7Y9�Y�i��RS
������A�dU��:�`�T����o ��N�.��Q������+��mI�q<�=�6�`��P���@i���
/�A�`E���XH�K����
���
���x��B+�����B
=(X�dmn wT�����/�A(�����R��5d��Mix�JqG
K��m-x�P�>VtY��b��LT�\���7P�w�����6p��������v�!�3Q��mS���R�Q���v�d*��4�h���b��LT�d�����*4�F�)
`S)o�aE��'��D��u���)��ai��9�a��a�(���!
�1
���4�4��4,�*b������fQ�Y�G�cf�.N��#{fp�����~�����Y4mV@cf�.N�7 fl�����~#�p�����H��!aq������/��_��8�`M������ ���)�&��4�`����~q'�m�5�&+#3�A�s�S��H�yL������FJ��W�ced`f/{lqJ�'2p30{�dF����v���X'0��=�8���|�	�=n2�_�Bi;�j:�����a-����pO��n����5VEfv����4\��+�8X�a�2p�3�QtX;������������N�nE���Y���)�(Z��S�A��k7@��3NM������S�Q�X�]1����s�S��@��3���S�N��k_
�d(X�b����/����`�C��
Ly;
+z�}�����<������|�m����wVR���o�����/-�6o��h+�3`����u�d8�B����x���Y�o���Cq����?;�XE�w���������k���q7<�I�D=px��g���;pz��L�c�Ni����8�e�	_\�w�g����w0�����s����3<����{���qGt�������q3;�=�;�_�w0���?�89��O�3VQ�8:�`F���x�����ft��	�7�[��u_�7VQ�89�`&���x�����fr�x�87����3VQ�88�`���?�����fp��:pl��g���;pn����c�~L�����8i�{����?5�XE�w�����>���/��;��q����/�;�C��U�~N�;��q�9��/N�;��q���qf���gVM��C�fh�7X84�`��]��~o�82����3�����q33�U�S���q73�I�J}����?3�������8�Ni����8'�*��C����8�j:,�w0S��K8�a�w0S���
m�������?3�������8'��ph��
�wq����?4�������8'n�pj��M�wq����?5�������8'��pl����wq������������J�u�����ft���YnA�F��O�p�0�m>��}���_�������r�0����i�{�i9c��ui������k��)��^i���0���������^�.
��5��z-�0e�_@/������z���uw��]��_�}o������M�[��)�����`�\�
Lq�z_�}o����c���m��������
��6�����z+F��vXn��^�9�x�;0�m�}�1����'F���VX����_J��/�m�}�)���	#���K�+�|)��R�C�u����=��_���������s�n�W��vk����+�+��|��|����H�~L�W����$_?8��o@�
�������}������o<V�7"��}��UD��c�������Fd������o�oWW	�7������{�M���X�]%��4�� ��2�o���	5����~s��������y��A\^���y��W�������{��Ak�����o�W��������[�K�5�UA�-c�
��� ��1��g���[�K�5�UE��c�
���"��1�^�pk�'�Q�������8 �3�����8 �3��r��_�����^��qo�8�3������8�3���q������;��)�����<3.H�+���<3�=�=�_�����^��qo�8�3������8�3����/x�����^��qs�3���.���q:�_�S��'��
��o&�Q����o'fI7����;�S�;xMTZ@��)�mVX~O�q<%�,����O)��`i��
/^wJ��s8�-��!�zT����T�;(XZA{g��u���8����"�#�Y��w��n�����){d`�g`E��=2�3�Y�%���~�$����G�]~q���`?�`��[����.���	H��K�/�������lq��#������c��_��qs�H���`q��������))!�.�8����bp�0X�ce��4���tn�g�����'q�[pF��&7�`���%a������ �{>�O�����|"�c�p��OpA>����{.����`�5�)���`�����������������`�E�)W���<��]��k��=VX��+C����3�
P0���!��`������1���`#���
���=����
`0�m�p(z�`*fd0�H{�`W,��`i,`0�mV�X�����`v����W�`����f|�+`0�mVYaM���`i�V�`������mx���)���S�Q��"+l����s�Mix�x���)���S���i�v�`��9��4|,x�� �)��pS�Q��*+���sN�i����������[1#��V�e�(�f�Mi�!�.o�2+xda�����Y�#{���3ES�����:�#{����
�~����)
����aM���C�V�gE��0��+/�����c��wM���#C�V�gE��8�a�����pB�]�5�VBN[q��������CFN]�5�VF����8�9w�'�p������N����aq�u"��K�q�������
�����*��
�p���K��8\�8�k*��8\^��VE��?��H��K�����H���avT���������������i(n[����K�����UZhE��;�']0����m��>+���-5����� �wOz�Y�
5�-XQgE1#��FZgEw�;�w�%�{�5�)�P�Yq�y���T�J����N��_J������+����@����1�����T�;�'��a�=5�-XQf�}�����UZf�l*���>qS
�mVtY����Y��J��x�L���x���[0����m��*+�32�Z7i�p0����;���������
+������5f�VY�#;�/����a�WCy��]V�H��������$��pv���qc
�m��YQ��[�����(�(�����W�P��`M����5f�YQ82(|�p��a\ZCy��5mVBfV�v�����p�0{t�����o�����6;M������5���1���,��p8���0����m��:�Df��vf���O�������nn7�P��aM�U����5�}%wJ�i�0���%����m��>� 3l�&��*�p�0�=d�����k(n[����������QpZ��+�^Q��lZ�)n[���JK��
��:+-����y�?�/^����z`d4
��6+@a����������%a�(�������eV�@���Ky�?��W����6+�fdPx��Yi��_�+�i��m��6+m32(�K���
S�/����
S��a�����`F�wi��v@a������v`a��6����^0#�����J��
s��_�O�0�mV�Y�����ai���0�<s�0��Z�Cv]��:+9�a�����Ja��a�^2|o�a�ua�+����=������~����{���^Sg�����!���p`�c��`o������^SgEd����!��"�p��e_e�QpD�]��:+!
G����S
N���Ca��J)!
�>
k���(�>�uVF�
K?5LQ8�QXSgeD����!��ND���0{����?����(|vQ8h��Q�dP�]I5���(|ro_x�����p��p��YY�0,��,��0�pa^f�pOi�"�.M�U�+��:�"W��4{�{F���P��aE���������i�����p^�&By?����q�
�mVZ�����-�q�B+��P���,���{�d������+
�l7��L.r�B+[��P��9�?�#�m(o���������9��I���Q���sJJ������
+*��-������V�@�R��9�?�a\iCy���V�
fd�����4�[l������0����m��J+�32�|����8U��9���4�+m(o��Y�V>"�d&�:i�������
,��]W�P�N��N+;�an���vZ�!�1��f�4�q�
��4����G��8i��=���0��`N������f�tZ��[l���V@ c f�LiW�P�N��N+"3�m�wZ�8���]G0�a�iCq;
kJ��@�m���R+!�1_8�ss�����v��Z	���l���VF Nc f�Liw�P�N��R+#s�m���:����}S��6�����:����6^\j��������S��6�����*���f/.�
�p�0��`J������
M�U����6���)
W���<���Km(n�aE�u.���j/����_6Ly��oZ�<Lq;
+:��X�����:
�0�4,��N<Lq;
+:��.��ai�uZ�a��9GAg<\:-1��T�(�N[0$�AZj�����'��Y�)�@���S���:��!"�V����)���R�HLy;+j�s��A� ���
���~�i�)�+^�>E�u����zT���:w`b��9�A�T|�z(V[�PL�GK���(���s tN��������6�Pq�6[�C*v��i�D���b��c�UT[�G,v��}�T��=���[ZN�X��Xl5�V@,���}�4�������{H��O�VSm���Q����H��yL,�������VSmE���A���J��yL,���L�����V�l%d�4fb����02qb_[�6��S�������y����;���H�������
�H��O�V�k�H����-;�wJ�'�9&bv������>[M�U��1[v����qa�MK�9�p�������e����;���<\�c���)��"�+Z����c ������"�wT��s���n(o[��h��R1$3���>7�b�a������=�b\vCy;+j�bN�L�eN���}���*�~N\p�
��T����M�������������>�
b��R�?|�������������s����O?|�����k��������o�Fo)>�����?}������C����|}{C�����V
�Y����?}�M��sD�������������o��X(�����*3�.�2���V���W����((���X�V<�W��P�H��j��[�cxWN��[1������u`��x��e���+�{+w����{+�aP��S���x�2#�����u���;�w����+.x�p���������_j������*3�i'Xw��]��xW����e�Ey��kr���x��
e�o�S
>`v���]y����q�m
~���W�b���Mk��`u+����pD���q�m
~����W����H(#��l���'dn.�AQ�����L�|���PFZV�H����v���0(����W�{� ����@(#}��b����17���(oS�kO����x�r�����������cn.GAQ������{�^e�A��0B���0���3N��]0�pB�)�k�����x�2���Z9�9~we]��� (���t��0���4(k�}�� ��������q������0�03
���:���$����L�����@Q���'���^e�AY+��*�0s��],=�`Eq;�x��e����H���;v�����e�;H�?�sY���<�=*X�e=�����;(��=�������P��(�^A8}�=*X�e=��P0s��],=�`k��u�	�8���+g���G��G�3�����s
�x���|�_��u����^�������N���/��{^O�x+���7��7�������)o
����7c�#L����J}���X��`F��ovY�x;���?��0�����oG��<��Yp���S�,����X�`|��M���t8�x���c�������-X�d�3P���3�)X����I}~wQ,�!;���cOs
Fvc�0����=r��r��3O���9�3�{�R�G�cfw�N)8 �.�8���+�������)��0�`vU�����C��_�xr������`�����#rps0��tJ�98v9���'�^��97Y	98�9��S:���������{�`FN�����7Y98�9X�de���p0{�iJ�'rpf8X�d���g��5M��|2�{�RpA>��.)�RpA.]~q���W9�0��z�S0rps0��tJ�9�t9��A'�^��\��MVE�cfW��(�,�����/�9��
�8�p�6i�e�`�;(X�d������h���0#�����28��
�6Y�<=��+�,c-fd8x�6Y�S�A��&����g��`E�e�32�I�,�S�A��&�����-X�d��`F���M��V,x���v�)o���-X�d�-cF���M����)����]��� Ly��U��#fd@x�VYf�������4�����*��zT���2�0�,�*�3x�� �)�,��7�XZe� �� ����S0���������Gv��ci�e<���0�yvJ�A�wAx�TYA�sS��UV@cf��N)8 �.o�*+"�wq�������S
����������av�����p�0�svJ�	A8uAx�TY	A81 ����RpFNcf7�N)8#�.o�*+#g���UVF�cf��N)�D�]�4U��|r,��N��s�����)������&� ���1S
.����`q�U��K��5MVE.�c0�\��+���&�"�.��&�.^A���13
��A(��i�lvF�v�;�mVTY�X���	d�`Li��-��~��h��Z0l�y�mVTY�.�������R��[�}��e��6��m��.����C{�!���j�af���.��u��t�R)n[����k�������vYv�Jy���0l�y�mV�Yv��q<��q���JyG
K����5��m��6��22�k,;�hJ�;�T�;jX�����5��m��:���22�k,;�hJ��T�;jXZwX�]���6�����0�xl�e�Mi�!
;���}�uH��O��B�z�af��eMi�#
�1
v����=������i��0������4����6�)
�����C�h�af��eGMi8"�1v����#�p������"�0����3��4���#������pBN]>4�VBf��Xvh��������Y3���8��8|h*��8�l�����)g��<�aV�L)�D�]>4���4�,�����)�H�����'��a�����)�
�0�������\����'���,\�,|h���,�������)Wd���0��mJ�Y��YX�g��0����S�f4�.���w����^`a��6�����`F����ES6fX�]�4�a,Ly�����ZM���s��4l��)��aiTZ-�0�mV�Y����aavp�����)��a���������S�Y�
0L�G
K��u�����-1S�^�.
;E��n@�z����Z7�a�;jX�I�[����a�(��}������4�S�Q��Nz���)o����Z�f�Mi����!K�0�mV4Z�[0#���Fku��n����XV�4��4������G��Fk�H�nL����Yn��#�>k�,�,�f'�L�7 �1��L��~�p�����
H��!av���~�����/��to�98t9��pY�����w.`D�?s��������?���|y������O?|�������������o�F�?�o���?}���������?bd����=U���.>����/~^���7��Ou���`}�/p�|F�`��/~n������^S���y������y5��<a����g)���+��)�)po���0���� R�.RxM�W)�)�'po���0�����"S�.SxM�W�)��)�'pk���7��<^����F������%a��s�	�[���,��|�� ��-XQ�m&`��{�n.n wT���
7�P��`E��Y�V�1kA��`S
�p������o����+z�m�i���=6����,�b��A(o[�����3����#B���������O�l���6�Sj�n0�x��p����w8�AqG����l����+��m��q<
�=�9��c���s
����
�P��`E��'fOCe�qN)�S�Q��&k�� ��-X�dm9��
b�M���;����wn����+���#3[A��������`���.��m��&+ 3[A���S
������o��>-�p�m��Y1�Y
����oD����_��������R0�d�X	)81|a�����6������2B0�d�X!83�����~q�m���X����D1��83�������] ���,��Df6���PL)� �cfS�����*J��WSbD`f!�*.�*"p#0�xF��	��v��tX	����;��\�|as�����o���Y��S�A��
k_�)������~������fQ4X����~�
�n�)������~^�.��EQ`�v��K��S�/���n�)m�_E���C�x�X�
Lq���W�
�Ki;�*
�}�r������
�eX���S�N��k�N9�M�`�;0���������������!��^�)��w��}Cyo�0�m�5�k?�0{��Lq?����_������Q4X�Cvc��
������]����]�����="�#�&��v��������v���l4V@�c��V@����[p@}6�+"���VD�cf���7"�>M���#���+!�1��]f���S����J��i���%��oFN��v�pF�}6�+#�1����|"�1_X�|s�'B�9�`M�u"�cf���)!�d X��^��kZ��\��>��RpA.K���W����`���*BpC�.��*BpeB��p�+Rp�S�U�X���5S�.���� w0�L�(��;?(n�`E�u�C�'���0p�����G�����v
V�X�5r<�h��X?���e:;���Nz�R0n�����E�a+�O;��E��;* �x?��&���}P�N��"�XO9���K��c�Jq���Xn����~E��%9��qH��c�Jq���X�����~=��������qH{�c�Jq�tH��w}P�N��"�8`|��l�8�E�q�G�����M���>(o�aE�u8���Y��~H�4����/�0r��s���������VY�G�c6�����Ay;
k��� �l�`?$S�a�F|���?(o�aM�������dJ�I8�I�����
����iXSfEd�vS��
����,�-���
GBN}^5mVBN
����4��5N�h����S��WM����3���>+#gn���C��P�N��F�Df����)
���'����V�TCy��������Y�K%�{"1�����L)� �������6���L�{+1�����L��"W��������6���U��+��afc
����[�)��_i���a��������`��cf? S�5+������g�)o��k_�o��'F�0�������~�u���������/�7_��� �~@�� LqG�J�,�nx�� ��c�{��
L��J�,�S�Q��*�m/^�_{(|���)��_i��6�`�;�W|����x����=��
����y����r;�/��+���^���	��D��Kx��q��'dJ�0�,m��Ly;�')�f0��R�Cv�/Zq	�
�Fk����~D�������V�G�����{d`?f`�#2������+ ���`M�����������^\bE����i�"RpS0��RpD
�so��I.!���`M����������bpb0x�^��2bp�����X98�9��{���^��%�����)�N���p���:��O���uI�D>��i�
r��p���*�����E�%W��K��_�q�%D.c�&�"�����]E�]~qJ���9��98H�,��
�2���,���=.���m��&�/3�gi��
�@(��`�)��P��`E��M���YEA�dy7�;v'�4������h������YZ�M��p���Yh�<����m��&��0S�3[k�YTS
^A�R�/c��u5���W�c�m������$�)�n�Q)��1����J���h��n1�x^o��X~�Jq��!,w�P��^E���3���i��P�wP���Q��j(m[����G���Y�A�`y�b�����1�[/.�����*���;�_f]
�nJ�����Wz���=5���WQ_y���l�1����H�~L�������J���i��/����:�����M�?`��_\SCi�~5�UD�e���Y���}#�HBx���55���W�]%d_fY
��uJ�	�71{$�w�x\SCi�~5�UF�e����X����~3C���
��P��_Mwu"�2�j�'�S�=O��.���m����D�eV��X��[��1���g��;j(m����*��������~+�o�/;�xF�������j�����-�Y��UE��c�e�O�7,��������
�/��k��UX�)��_a��k���M�_�K�G�J��`�)��_aL�k���M�_�aF����
�����W��R��_EV��5��*����w����
+�/�m�U�Wa[0#��F�_�
�����Wa���m���*l32�k��U�W���_av�_J�������1#��F�_������W����m���*3r�Z��U8�)�`����
n�k��_E����W�_�����{a����z�_��_E<����W�_�����{a����"��.����* �z����
��a��F}��o@�
]��5�UD�
�Zq���/����������k��������*!��1�^�}o�	�7u�w��W	�71�k��UF�Mc��0���~3�o������2�of������7������{�=��.�����D�=�����D�=���W��������
�oa�������[���W��t�w��W��2�k��UE��c��0���~�k��U\���J���������W��P��_E���	DV�_E��;�W�_E\CCi�~E�����U�_E��;�W�_E\CCi�~�U\����]��U\A�R�A���*�J������Z0#3�w��Wq��/3 S�_E\CCi�~�U�2fd�����*��O)��_aq

�m�U�Wq�����J����>���~��U�-4���W�_�FdFn�*��������W��P��_E�o�V����*:�_������������*�����M4���������_<�_\ACi�~5�U@������* ��1����g��h(m��������v<��~#�o�/;�xF�����6�:M��54���J��q��������J������/��f�W�7���]<�_\?Ci�~5�UF����l��*#�ff=�����3���W�_�����M�_���'�B�_��J�����
�/��f�W������]<�_����_���*�/��f�W��2�+��p��m�U�WiA���l��*-���w����J�/�m�U�W�,����M�_%�KyG�}�V2��-XQ`%S0#��+Y����_<�`Lq��
V�3r,m��
LyG+��S��`����1#���
�9S�Q��+m+^�.{E��6``
=*X�a�
���
�Xi7x���%V��)��`i��v�`�;*X�b�����R�W�X��0#C���)@��wT���J`0�mV�X�Y��`0��bJ�1��1����{v�����^�c%��f7YL)�#{���EV������^Sdy�`�p0��bJ�9�s,m�rp�r��4Y980����RpD���g��c��5MVD�����f'�(8!�>k����87Y	981��2�QpFN]�&+#g���uS
�����`v������s�����:��3���>�)���'���0����g�����*��'���B�)���p0;�xF�9�t98h���\f7ZL)�"W���q�3
������A�dU���p0��bF�y�;He8��g<����h(n[�������#���bJ�� �wT���������+��lf�$2�R�)[��P�Q��&+�>���h��
�q<���[-�w�;�#l�2.���m��&+�0833[i��bJ�+�T�;*X�de�HCq��MV�`rff��v����70��wT��������6�EQe�}�������l1��T*�5,��2.�����]V>���5�n�)
�R)��aa��q-
��4�(��Q1�x8�a�[Li�m�07:SXfe\LCq;
+�������4��o1�a�,����6+�j��iXQge�0�,�1���)
�a�����Y����v��Yi�YQc�sF
K�,\OCq;
k
��8�,�1���)
G��������5�����J���������pBN�C��4�<�<���2�0�����.�4���3�����
����iX�i������������<|2<�>����qM
�m6�N�Df��v����������8|s�����v�tZy�YWc�}S���e�����)
����iX�iU�afa�a7^�h�\�������3>�a��iX�i�K���;/�4<Ly
��E��������a���N<L�G
K;��S�A��?<��a������QtZ��������i��)������p����a����u����/�4�S�A���t��������:7�!fw_Lix�����i����)n�aE�unCr<,���}���<����<Lq;
+:�s?1$���N�<��)�������<Lq�����:��!f7`Li�S�A��?<��a�<��<l���������W�������{
����<��o~��#�����G������>~���w��S��_8�������������������W�������o�v�G�l�����������7��?�u�l���_���DA�_&�*Z��&�p&��2��^A�_������0��20�V�4��3����)
��/���������/�o%`A�_8����QpE�_8�/\pE�_�*:���r��2�`��R�e ��n�E~�|�(+����|v}���Q�WF�_Ius�h����[EX��W���D�T�&���L����4��:0�V�V4��3���)
�������a����������������g��LiM~eL��c77�&�L��h+����|����0�����[�nnM~��U�V4��1���#2�a4��1�����0��:0�����h�+c�-�HdJ�h�+c�/l��a4�u`�WE�U��W��[v������G�����+�H��YV�h��G"�c"��.�){$b?&bvY���������q�e��Li8 �1����4�@�@�jZ��@�@l�m"S���b�gK5"G��_}����-���v�EL��q���](2���H�$��8!�.��]��z�����N+#'�M/���5#�.��M��~3�p�hX�h�H���a�zO�����}����Q�dP���L�� 
�cfFO��U�K�_�}o�A�0 ����/�p�0{,zJ�9�t9��o���[��+C��&�)�V��:�`�~���)n��k����������G�
��G�_�>�y?�q���0���i�z_{"|o�f���Rz����R�	P������������?���������w���������������}����?����������fs��n?��*��������������}���o�������������]��~�_��������k����?��A�f;������
�e���o#��&lnm��?�v&�(������M�����
�E�w��'�������"�X��bFF���N��K��y?�����F�g���"�zw����9�R/��������?�v��h�[1#cP�-'S�������{<��za�3l[��a��'fd*��dJ�����w��p������WT�aF$�f#��z�6����#P���M���m��~
3"7����;��a<d`?��^����������zE�fD�m����w�^�x���y���!�[��������~#�o���m����C�����G������B�|�A�����������JH����$�oB�m��?�+��}�U�o�W�73����UF�mv�?�R�_d�f��~��������C���D�mV�?/�b�'�o���m���� ����$iwU�~�
�t�4�UA�m����W�]U����L��W��Y@O�MS^U��f
��~�u&s�E���{4���,����y�l���,��z����2�/��+���Y��u����!��k�)��_i}e�/��./�o�k���g����]1#�����2������k�)m����2������������w��R�������*�+�V����*����a�c������~7�_J��<����vbF�Wiev�_�;�'���Ki�~���fd�w��W�����x��������W�_�#`F����9�)� ���2�������sB���!�:����q���9�,���G�u]�}qH���z�_��/;�cJ���3�+��<������#B��7 �z��!S�
����_i�C�_ro��70�����������F�����U�_E�����&���od�W����S�5�UB�M�n��*#�&�����7��W�_e�����&��N��������D�=���i����d�w�W'����������{v�w��W��0�������[����>��oE�-]��4�UE��������[���U�����M�_�e�����������w����#ki�i�~��5+flv��Liea+�3��_��Gv�<���*�+��H�_d�{��~�����4���~��YXH�L���������!o���W�<���W��<���*�+�����~����u4���~����e4��m����n	3�C}���������w�����������W�_�=@�f!��~����U4��_YXD�L���+����26�h��+��,,�y��B~?��g��_Ee��m����W�_Y�����{e	���"�6Kh�_Ee=�o���M����z�_?��++@n��#�6h�_M��=4o��W�7���=}0��������~5�U@�m���}�.��"�o�/{�`F����>C�j�����,�y����J��q������&��f������o���m���*!��1���f�����3���������������������>���������~5�����l�y����:��1���f�[���3����*�����������[�>e�o�{��\���������������[�>e+�o�{��U�W����l�y����Z�_�����>�����R��_E�.3r�+��V�b�c�eO����R��_E��3r�+��V�Ky�
����R��_E����u��j����w����Z�
�]�E����z����ZW�_�;�W�_���k���C�_��/��+���
�����W�������������B����W��Ky�
��u/x�������c���:i����w��0���/�m�U�W�3���_'��V�������C�u]�u��ju����_'��V������>����G��]�u���#�z����
��~��������_����o��W�_��������5"��.�:M�#����*"�F���_%����_����ob������������.��oF�M]�u��*#�f�������y�����)�"��.�:Mu"�f����:��1���{"��]�u��� ���zqU�����%3�-�������� ����������_i?Y�k�5�UE���zi�-x���
��
w�P��_����%cFf���W�����+������m���j33�Y/��6���e����g(m�����,����4^�_mn���}�5�_�=Ci�~�������[@������>�������_�=Ci�~���m��������>��������
w�P��_E��32x����v���w�����
w�P����j[�����<���C��7����������� �h����O?|������q�������o�F�?�o���?}���������?b�����T����+9�q��������a�S��{�=�Lf������e����Wz�G��6z\�7�C��c�`O���wyP��^E���	f��PzJ�q"|A8��<(m[����"������3���4�4!}�a�M���7h���4���`�IO�7!L�1L��\�Ai�z5e^F�`�y�������%��%���=���W�����2�tps:8�Aq��������m��*�,����q�����X�x�>;�hF�������j���O��U�*�)�V���<H��^\�Ai�z5E^E�e6y�������[��+}Ni_�{k�{��9�}����z/c�9p/�p��1���t]�
��j7��zP����
p/�|z���n*^�>�*Z��n��3�XN���R�/���n�{)m[����W�?s���zW�^��e�1�W�^J��kEm�o���-�S��|)��qm�|)m�_Eo�oC~��)��+�;&_��
��Ki;�*��}��3�XN�����_�������~��~D��[,���Kq?����~������fQTW�O+�tc�e�XN��!��/����~]~����v������n����G����u���G��]�5���
��~����)���0�_�
������_�h�������n���oD��c�5���RpD���W	8��]�6������M��p���JH�iL���)g$�4&�i
��s��������A`q�u"�1?PS����3��tX'2��0���:���1K�q�2��g`���
2p30��rJ���Xz��^��K��������u���&�)�Vd�:f`�=n{E�}6��X��cf���X��Aq����������:��!?s���~
�=(� ��3�wxP�N����C~�&�)�Z�{P�/�_��Ai;�*:�c]0�gn����
���	�:p���������`���d9���b��1��{���Ai;�*�c��37YN�w�Jq���=:p��m�����#���M�s�Jq��	?b8p���������
�&�2���)��+����Ai;�*�����&iu8�_7�_�=������~�����M����G��c����J��W�_�_f�{�������0����v���W����!��"�o����wxP�N���*"�r�<��UB����}i��;<(m�_M���M�&�)�f������wxP�N���*#�2�<�M�s�E����}�~q�������N�_f���pJ�'�������W���������� �2�<��aS�-���Y3'}������������&v���~+�oe��I�������r�/��C�_����~���u�/�������Y0����RS�5��������/�������)r�����)�Z����Wz�����������r6cHf����r+�/��2F�����v�U�Wn���d)���
�Kq��+n[��!�����}�,����[/�L�?�C2��
���	+,��t]~��������3>"S���)�g�^1�������}}���c���"Ki}���_�;��+="�����i��/����,Fd�WZ^�x�~����Wz��s����}u��]�����VW�#�z����W+����������E��c�eW�Mi7 �z����g7 ��.������vboc/;<lJ��7���IcoD��]�}�����F��8�^v��vz�z��>����}_{�{o�	y7�y�]6�������+�����������'����x�x��pS����^�oF���7~�=�x��x�{��zO$�sL�N�V�H�����b���#/{s�RoA�-�J�[y��y�b�������|L��"�V�q���������WSXU���@�����:�z������J���h��rbFf�����nwP������J������I�q<m�K++o��Aq��O/n���m������������[�uP�~� �*��M3���WQZ��azf���KZ��������aJq)������p���?A�/~�������}�y|����_>}����_��������~��O����'�����?rkY���tm����������7\����y8���>��AQ�<>��L^Z��������>�P&J�kQ�|O�f4���|a�{m`���/+g2Q��^E���\`&3�������60G����
8�����*j���3��Kk�����������Nd��m���/�����ebYmJ�����!��=8�����*z��g�3��U-S�u0x:0���"��'2Q��_E���\`�2yi����9c.�����D&����h����\� m��8��9c�]P��L��WQ�<A��L�L��o@�e�#|�%�D&���������\� }@-D�_�����p"�m��tWx�.0s����JH��:c��?�D&�����)��]`�2��9�����������D&����i�� ]`�2�vwJ�'�/s��HB8�����j�+<I��LA\_�_����'�Nd��m���
��f.��������3�cgNd��m���
��f.S�W��9Eg������=j�_�Jrk��Q��x>3�����#2���4rF�������{q*����i:
=2��+�}D� ��kM������*
����(��`i�-�?"s��H��-�?(n[����x��B�
�VXq���tFz�f\A�R��`E��3����Y���A�����)n`P)n;�D�a��`���]�HK���X0�����=��*�mV�Xq��q���,�+�P)��r��8T���h��1�xw�Y�5V<@�R�A<��~��x����7E�b�c�Y�=Vt����`��_�#�.o�+z�`�q����9�3,�*z�`���MSd�`�q���
����`v����rp�r��i�"rp`8�=�6���f���(8"�.o�&+!G����lS
N����`v����rp�s���J����`�4���3rpb8���0������i�2rpf8�=�4��98�9X�M�x"�]�5E��|2l�E��|2�N��QpA>��k���\6�"� ����������������`#.�*bpe0���1�`�����]Qd�1�2l�EVZ�)�Rp��M�-XQd%c1#���"+�`�;*XXd%��Dq��EV�f�0XZd%Ly���qr�mVY���`��Yi]�`���3
��M�-XQd�5cF����J`0��R
���)n[���J[��[i��6�`�;*XXE�}����`E��v�`
=*XZd�8��~)/^��E���`
=*X�d�8���
��x��|(���6��p0{�iJ�9�q,]�Cv]>MV�����`���){�`�p�������}��M���=��V�d���p�x�98t9��4Y98p,n�"rp`8�-1����|h���97Y	982,^pBN]>4MVBN��W�)981,��?e�����C�de���p�*n�2rpf8X��98�9X�d���'�����:��O����C�9��s���*��'�����*����`��rp�r��4Y9�0�����\9�9�v9�)���X����&+/p��_H�y��mV4Y�,��R$m���;���������P��`E��M����"i������#4���4�-X�de�1#3��C5��L*�,,:2����m��&+�32sz�9Ts
�Jy���qA
�mV4Yy�Q��YS����R�&���
W�P��`E��w����E5f�6Yy�Jy���+^���{�h���aFnT�����T�;*XXtd�RCq��MVv32�z7i��r�s�|�����6{E��=r0����$7�`��9������k�,��m���MV@�K��j(n[���
����vT���#rp`8Xz[R�M5�-X�dE�`n_�&n�"rpd8X�`\UCq��5MVB��l�&+!'�����d�UCq��5MVF�6��M����3���#�.{M�u"s+k��DS
>��O���	3
�m5�-X�d�`ng
;rJ�9�0,^0����m��&�"sKkvq�U��+����������i�*r0����9��sA�K|.���)8(��s�����]�d�8���
���m��&�43r{[�M�i��)��R�]��u98(���S�Q��&�����wP0;abF��������h��8�B�
�6Y�
Ly���+^�.E�unf�8X�d�p0�,,:�
8���+��s����`i�u�����K)x��m��&�<��p�!m��8���
�Lq��M�y��p0;p{J��b�����]��M���������:=r�c8��01�`����h�N��>�M�G����}�������p`@�WYA8p ,m:"�p���Y4]VD�	�.+"	G���F�]6���J���Aav=����p����3!	�.	�ESfeD����!.�2�pfP�21���(��(lM�u"g���m��,|2,�N�����,|vY�,�:�D>9�Ya�d`X���0\�0lM�U��C�N�gU����0;gbF�i�vi�,�B�"W���������a��n������VY`�f���8i�U��P�A<i�Qpu
��4��������[`���V1p����0�EpF������
E�U,L�,�'������}��.x���lXQi�u����^'���
N��>����
����iXQi��`Hfv��VZe�JyG
�)����vVtZe��[�*����a�����
����iX�i�����6Wi�U���w����(����vVtZ�H���������Jy���q�
��4����Cf��H;�������-;qbF�����vVtZ�#s�l���S�����a��q�
��4����0����;��<�<l��SF�tZy�[e�����pD�K7�[l(n���tZ	y��e���VBN�)����v�tZ	y�[f�n���pFNK7�{l(n�aM�����m6^�i�����av����q�
��4���N�an�
��wJ�y�dxX�a�dCq;
k:��<�����N� ����3�U6���������Bvs���+�pexX��� �>[E�U�aJ=h8H;��S�Q����./^������f���jWi�U
�0��R6���������`Hn�����x���6�S�N��N���!����N��6���x�+�0�m^�V]O�mw�vZu������G���)n�aE�U��!����N������Kix�����V�����J;��S�A���
/^��WE�U�aJ=jX�i�x��~)
�/^��WE�U���xX�iU�<�fgPLiy��yxUtZ�#;����V�����a��=���������������i8 ���3��y�W_���g�/�|�{����E�SJ����Ab��#"q�"�k_���7"�1�E\j%��1;�bF�	�8u������������5�S������a�~3�p���k_���7#�1�E\he�������8�s�_�}o�'��9Fa~���~OD��Ca�~���E���D��oA.c����*��av���~�K�_{,|o�1��1�_�;���\��"�.��P��~���x9Y�x��}<������0��{<�6���H��~����#v���~�����M�~a��3ng8�f�3r{m�-�_������J�g���J��3r�]�
�_V���M�N��Q0��y���Q,xM����*��i*���lZv����a��3n�I�b�[���^v�����
��S6���6��m�z���AFn���X�4	
��C6-;rbF�����-X�b=2����k�.��R���c<cS�������b�n���~Wa�����fN�(�!�.�8����=r0���]�;�`��/�#�>k�,����1�"+ �1[v����rp�s���
���Zv����#rp`8X��������{����Vq���#�����'������u�[pBf���|�������g������u�[pF���Xq����3�����������/����9��i�.��R��|2,_0r����gu�[pA�V�Xq�U������� �.�8����+r0���]�;���\9�.�"�.�8��������6V�d�9�2���1�,���-X�d�����z��L�����|<Ly)��������?���|y������O?|������=������O�����q�?����������9�{�4��'L�O���f����
�3��E_����{*������_���������~$���
fdNi��a�����K��������^�����SQ��`E�g���c����)�������������������8~M�x'|����.����������Q��4���2�7�����/���/����������?��������>����������O_�X��'�AP�zE����D%%f����8_RB<�b���WW~o����+��v����{�u���1������y�v��O.l���_(m������	32�O��~�!�������
�]����W��7�3
=�w���x�����}����F��������+�����;_Pb<x�@y����~���������+����������L�7!
�����7�[��u0�8t��~3�pb0���)�f��<~�pa����fx�@i�~E�$d<�3�|���L��D>����/�����{��WT�aF�������
���s�����oA�-}�5m���p�;��A���[��{a����V�����M�_U����/�	��/�o��&����7����M�_���s���G�J�+�������WV <���*�+k<d�� ���)��}P�A������g��_Ee��-�'dJ�n�w�����������W�_�u���N@i��F���ql����������W�_=~�bFf�#�	��������WV<���*�+�/����~B����>���~�������m�����32G��O��~��%��Q��~a��3m�����G���I"�2�_������������g��_Ee�/�������������6�{��������������{�~B������wi�}�wM����'dJ��7����&���E�
]��5�UD�����)�F��8��]�_E�����]�_%�_n��	��oB�Mc���E��~�o������2�/�����L�7#��1����*#��.����*#�r�O��~O��<��d���D�=���k����[x�~B��[�O���UA�-]��5�UA�����9�"����UE�-}���W��[x�~B��[���a�.�������j]�)��_i�.���w����Z���������Z������j5���w����Z
�/�m�U�W����[�'��V�Ky�
����R��_E��f��I��u����~�����R��_E��3r���������/�����
�����*��u���[�'��������W��Ki�~���G���/�	��/�/��+���c�k���C�_��/��+��������W�3x���{(���!�:n����Z��c�W�_�����W�_���q�+��V���������G��}���W��s�+���o���u����C���������_�2���������UD��]�u��*"�F��O��~�o���u�����S����J����_�2����������UF��]�u��*#�fn�������y��N�_������N�_���'��^�_�����/,�����{v��i����[�e?!S�-��e��V���/�o�����W��0��~B��[�+�����"��.�:E�-^@��O��~�n�w�����p��m�U�W����[w/��6��������f��Ai�~��f��m���W�����+��67J�����ff���I��m���x<��W�
�����*��m�����'���
�)��+��6�TCi�~���E������Wn����~����{h�f���N��fdn�6��k�����h(��_a����YC���S������-���W������W����m���jsf���K���!��1�^X{o��{����*���#�2h,�	���G���
��
w�P��_M��4�
�)����������3���W�_�_f�e?!S����a��A�_��J�����"�/���_�<������������M�A�_%�_f�e?!s�E�Mc�
��
w�P��_M���4���L�7#��1�i��g(m����?]�m}����o������
����??��fy�����~^��J<���X�����������m���_(��Wi���<(m��(������a.���?�W�OP�A��>o_�'(m[�������<a.��{�5�epBX��p����*���d�8�	s��[�����z�m�n�&(m[����m��c�0d���LP�A��2o_W�t}�P�y�
0A��^p���KP�A��.o�^�>K(��}���V�@�����4�;���.��~+^��������}�����*��~wx�FqG�
��}�gi������X�a1$�0��Y�{>})��`a�����S������!��i��[�C�uc�5����������'O�`�_�<N�p����=����Y�����}�?y�{`�<O�W���,��* �.?~����y�&.�"p#�Y�
VD]~��)�#�DM\aE��8�`�H;������S,8!'�H�t�	18q,m�bp�b��'O�����X98s,��2rpp���:�����Wq�u"�i�u"��4Y9�s�*n�
rpa8�H���\�l4MVA.c^�MVE.i�U��k��������u�����:��T�����:p����h��%a��d�U�dn wT���:p����h�0�x��*m�7�;*X�d����v
V4Y������c�6Y���,l�\�Aq;+��c�����c�6Y�
"���
6Y������M���r<�t�6Y�"���
6Y.�����M��9o�J��c�JqG��7{P�N��&��+��7��M�qlX�x��aO��(W{P�N��&�8N9p�I���S�Q��&����-�*���!3>6i�ux�`�p0{dlF�����v
V4Y�GfV|l�&�#{���#c3
���S���
�����M�d���p0{dlF�����v
�4Y9�Y������f��M)98�9�j����l���MVBN�G�f�>(n�`M�����5��������`�����q����i�2r0��c7Y'rp�8X�d����)X�d������M�d����`i��;>(n�`M�U���M��������`�����q����i�*r0��c7Y9�2��P�[��k��WE���`J=(X�d�8���
6Y�,x���*�,g��)��`i��p0�,l��)x���*�,gW9��]�d9LqG�,g��)n�`E��V�!��K�,�S�Q��&�����S���rk��c��M��6,��`�����7�`��)X�d����c��M����)��`a��v�`��)X�d�=aH���M�;��)��`a���`��6��������_���{�dPXZf�P���:�Y�Y�v]~�k���:a7�CZe9� �f�����#�.��%��z=b�c�!-��G��'��������W�{�
�~����
���`����zBp�B�k_���7"�1�+"G���b3��������}}��^�8�C\a%��0{VlF�	8u��������q�����I��f�������[oF��c�=�������e�����D�=��_{|o�'r�9��C\^���'���)��������'���[|���� �|��UE�-�7���H��!_qoU�|+G����"���Ah�~������W~����������4��pA�_�b��\"'m������+l�<n���m����[��c������w�����������*�+o+fO�u����+�;�i��a3���4��WQ^�������NZ^�
�)��+,�<.���m�������q<��I�+��:���~�����4��WQ_�8p���5NZ_��)��+��<����m����09�3j������KH��Nd����W�P���������3j�����a*���W�_y�LCq�~���fd�W�_=�@���_a�q1
�m���W��YO���U@�
����f��{i(n����
���v/��"�o`��=6�_\KCq�~5�UD�e��xq��#�������V�������/����������e������P��_M����4^�_e����/{6lF�������j�����L������{2����/����m���� �2�i���*����_�t��~�K�5�UE�e��xqU�+�������B����������������*,��w����
�/�m�U�Wa����_i���r�+������m���*�3��7H��`�)��_�x��~-�/�m�U�W�&�8�� �������~��UX7�v]�}q�������z����
+�/��+���f��u��������R�A���*l��w����
������/�������B���Wa����~��U�^�.����*+f�o��W�����~��U8�)n����
�`�1�i��c��=6�_���������C�uc�
��*x�_��/{<lF���w�w��W��3�+������W�_�����M�_�������
����_i�C�7M���
oN�82���QpB�]�4VBNc6���JH��!`�����3p���i�2p�Y�VF��'������i*�8��,��D>f���(�D>��i:��|��,�� ��3b3
.������*�e�f�X)�0��QpE
�}
��X)��)�,�+.x����&q	
�mV�Xq���D�H{�h�ByG{��Kh(nS���������D�H��h�ByG���Kh(n[����&eFn�"m���;�,l�".���m��&+�0+3r�h����+�T�;����Rp���"�
V4Yq�0#3��H����I�����MV�%4�-X�d��bFf��6Yq�JyG���Kh(n[�������i�F�d�L*�,l�"n���m��&+32�x����n����2
{ZlF������+������M4F�dE��f���(��P��`E�=r0�����,��f���(��P��`M����m4F�d���p0{`lF�����6�&+"s�h��������`i���h(n[���J���F#n�rp�8X�d�6���i�2r0���������l�#c3
�}4�-X�d����V+n�N��s���=26�`�HCq��5M�������&� �c�����J���i�
r0�������\�l�#c3
��4�-X�dU�`n3�7Y9��9��G�&������C�d�8�B�
�6Yi�����MV2/^��MV2��zT���J8���
6Y�T�x}V4Y�n���`+m�������MV����)�)���Z��q���J+p0�,l��
Lq��MV���q���Jp0�,l��Lq��MV�
fd8x�6Yi_�`���#c3
���)n[���J{����&+���wT���Jp0�mV4Y������U�d�8���
6Y��x���MVr�����U�d%��f���(�#�.;E��<r�g8x�6Y�#{���#cS
F�]v�&+ {��Wq������������`M�������������`�����#rp�s���J�����U�d%���p0{dlF�	98u9�k����87Y98q,m�2rp�r��4Y98s,n�N���q���:���.{M�u"�o�&�D>f���(� �]��&� ��7q�U�������W����`�i�*rpe8x7Y9�2��R0rp�r�W4Yy9�
2�I�������
6Y��P��`E�����9E����� �wT���������+��l-fd�m�&+[��P�Q��&+�����h����y�����+�T�;*X�de\UCq��MV^fd��n�&+o����������MV�2fd��n�&+�`R)��`a��qY
�mV4Yy������I����I�����MV�m5�-X�d��ifng�.m��&��
f���(��P��`E��pp�����&+;�`�p0{dlJ������A�de��m���MV�����`�����qa
�m�4Y9�[[�����f���(7�P��`M�����5��������`�����qe
�m�4Y9��[�����f���(W�P��`M������5��������`�����qe
�m�4Y9��[������f���(W�P��`�h��A�[\����A��@XZe����iX�e$ans�.��
�p�HX�e����iXSfUDanu�!.�*�peP�=56�a�ZCq;
+��sA�v��6�\��)��aa�u.�������:��!>�u�i�)��aa�u�a��iX�g��`H��i�uZ�
34����������i3�dp��Z�/���ep�=96��p��vV4Z�1$�����:W�a�;jX�h���o���J����)��ai�un���w����:w�o���N����)��ai�u����w����:�����F�i���!9�vZ�<LyG
;���������,��xX�i�y�q<,��N�<��<l�������N�i�y�3<�����G�}6�N�#{�����
����a�����p����tZy80<���VD�'�f4��c����������a'��"�pdx�=B6���<�<l4�VBN;q��������
g����a���2�pfx��;��<�f����?����?���~����{������w�!��y8���������������_��e������+�s�W���_}����_���w������������~,������\�2v�O<��H�(bH$��?���7��h|2�'��n����t������0FT�aH$����p���C4.��	�����+^���	cE���H��@���7��h\�A��y�
W�Hq;
���_�,���Lbt������5<]�a:���f���aQ�!����^�������4��w��0��)�N�g���
B�C2z���on"�w��t����R��6��E��,���~�|�x������.�0���l�y6,*�0d���^������6�w��t���@��f���aQ��!#�d���/�0�U�;jx�|�t���4{m�
��7	z�4�m�6<_�a<���w���e���f���aE�U����o��ai�Up�
�5,��
n�)�f�g��N��
C2�����*�����vZW��f�
]�U�i�<�l�y����*�����vZw��f���aM����7owZ������vZ���4�m�
k:��<���y�pwZ����f���h���f���aM����%7owZ������vZ���4�m�
k:��<�l�y�����7�w������6��o�lX�ie��f������n�������.�)���g��N�Dn���mX�i���;jX�i����l�������Y�K%�[�bA$nv��-Y\k���;*YZk����l��`��V�f���~��n����~��.�)�������U��~��8�l�y������0��+���8Lq�~_�"}s�#r0,-����/��B��a�������{�5#r(,�����_������P��6���%��~m��c�\�I�S�A<����~�/^�_{,|o�+`0e�+���
LyG�
����x]~�����n��y�����@0��+,��V����(��oq��v��Xu����~�5V��)ng��b����c�����0�,l��Lq;o*)��8&`�H����C����;$`78 �Y0"�#�]�V����A`�����="�<V,�#�1�E�ad`�00{jlF�8�kJ��8�X!8p,-�"Bp�?
��X)8r,n�"Rp�(X�b%������bpb0��k���f��M)18��Fkz���6�+#g���c3
�������"�D���DV8�����C>��?|��������������������~���_?��������O��������?~���w?���������qca�!����E�������������7��?�����^��="��`�6{a�)����xW�%�S��q��-zf�)cF�����|�;����g��`=���1#��F��=�(���eY����g��`=����!#3��a��H��`f���]I�#��q�����#��	����G�3���J�������/�.��`��=*X��=�y(��eS����g��`=����=*X��=�P03�����{�����m�zf/,0��zP�6{�x�����'���=rp|���Kn.9���o���K@f��_Y�to�9�?����%�������
QKDf��_��to�9�?����%����������������$���rpv��SK�-8!3���7Y	9��eG��g��������[pFf&�[��O)8#3����H��`�����g��[����[���:���1_��to�'rp3��
�4Y9�����`q�U������,H��������5MVEnF��-X�dU��:��+���-�"7���`M�U�����o�6YfA�c������Lq��M�Y2fd8x�6Y�S�A��&��`���h�������U�dLyK�,cW�x}V4Y�S�Q��&�X�`�;(X�d�����s���2+p0�,m��
LyK�,�V�x]�M��6��p�*m��LyK�,�S��`E�ev�^�M����)o?��}C��S��`E�e�32�J�,sS�A��&����-X�d��`F��Wi�e����|e���;�`���M�d��8�6Y�#�1_Y6to�9�w9xS4Y�#{���M�G�c��k���r��r��i�rp`8�=Z>����|e���G�����M�dE���p0{�|J�98�9�����F�}�4Y	982�-�RpBNc��h���rp�s��������`�h���3rpf8X�de�����]�d�����`�h���O����`q�u"�]�5M��|2�-�RpA>�|e���������i�
rpa8�=Z>���\�|e���W�����]�dU���p0{�|N���u��Wv�Z�]�R��+�,��_f��|��K�,���yK�,���q��M�526��,m�,��,m�,���mV4Y��������`�h���a:�3��`i�ea8�3n[�������6��`i�ea<�3��`i�ea:�3n[��������S�,m�,���,m�,���mV4Yv��u����M��������M������M�������Q��-X�dY���;(X�dY������h���0c3M�M��&����g�~�++��-��?��+�,����)�o�6Y�!�1_�1to�9����<j�X�Gn���-X�dY���|e�����f>����b�9�����`q�������l��`��f>����b�9�����`q�������l�������5Q,8!7S���-�RpBNc��e���rp3��y�D�`��fJ����MVFNc��e���3rp3��y�D����L�[���:������l���9��s���:�����o
7Y9�d8X�d����`�i�
rpa8�=Z>�`���p���������N�dU���p0{�|J�9��9����[^����`�h��8�B�
�6Y�LyK��u)x���M�jV��p0{�|J�8��
�6Y���m��&k�3r,m�VLyK���S��`E����9�6Y��a�c�&k]��)n[���Z�32�-�R�LyK��u��m��&k�fd8�=Z>��8��
�6Y�Lq��M����p0{�|N����wP���Z�����&k=��)��`i�����wP���Z�����^�d�9�1�-�R�CvK���!�.{E��z�`�p0{�|J�9��9�pWoN�A�wA�k��� �f��Oi8 �1�E�e$��%a����p`H�=\>���$�$lq��c��������Caq������"n��p�����Y	Y8q,,n�2�p��Y�uVF�]��:+#g����sF�c6���:��s�����:��O����S>���1
�E\h������B� ���S.��e��f7Zy��yX�hU����0{�|J�y�r<,��*�p��pPTZ���%dx�=c>��m���5,��6\^Cy����ffO,��!�)
��P�A�F�im�����
+:��T�8Yd�S�S�+6<��i����p}
�mVtZ�=1�xv�e��Oix�JyG
K;�
��P��aE���	3���Z�����A�R�Q��Nk�6��mX�imL���-6�=h>��
�*�5,��6�`Cy������x��Ycc���S�A�R�Q��Nk�6��mX�im����=6�=j>���*�5,��6�aCy��g8�m��n�;�����g���o~��������?A��_>���������z��������������?�����������|��#f�G�k?1�S%���z��5|��o�)�����p}�/p��|@������HK�
w�P��G^Q�m��Yr�G��O��t�"pl!��6�	By����)�"����-�i�"rl!��p)��4�)�����-8���l�������P�N���/#\0�A�_�S���a+��p-��4�)�N�f9�kpJ�'�����w|���v��|�������p�gm�y�f�.����5%_��m�z�����+>k���6+��p3��4�)�*>lc����g4�/���y�f���S�N���o_N�<l�p����
�0�5,��v<Ly;
+\�M�����g^nnx����VZ����
xX�i�x�R�vZ�����_pZ�����������������|����������������o�v������#�o��7��_v��}�*��������������}���o�������������M���Q^e������o2aHn���EH�S����|����U��iXT�a��!���2�������
��/^�UcD��4�����
�@�w����3o'�X�������dw�6'�N~��_G�;?����	1$�>s�%l��K
w��8�b<|�Oy;
KZ�&$Br�L���!��zJ�^j�����[B��
^<|�������~�����S���?�5<�6�*^<|������~���_�S��?�5<�6�P�|����y���������#�qd���-a\D&��y���1s.��58���d�����tK��C����}�G�aDc�\
�kpJ��81G�K����6l%�[��9�������d��O�~K����iXR�5!���s)���9
#�o����)�����|kB"3�R����I�<\���|�xx ��v�tZy�9���;��<\���H�������Dv�\
�kpF�.9�"f�vZn9�D�UtZ�9�"���)
���� "�>p���_!b���:p����a/���q����Q�����C�XE�u���Y"�^�)
����!b6i/}����D�XE�u����"�^�)
���Y"b6i�q����E�XE�u���Y#�^�)
����"b6i�q����F���N��="�G���s�z0kD�&���#r����U�i�H�`���pJ��G�`���m����E"fUtZn9�M"�%��0.9�E"f�vZn9��D����\%r0�D6i�u�&���$����0n9��D����p�������n9�M"l�)
�&���I���NW��*�����q���m��-��D��&�j:-\%r0�Dvq���Dn�oJ�	y��$��������J�^FD�4F�]\k�2��[&���R2.9��D^�2}o��K�`v���RW��*6��~q���_%��W�{��M"�IdWZ�H���������D��"���H��/�9�="����5"�F��7�_������F��/n9�-"����%"�D��7�_\"r�����%��~�� ����e�[�)��_i]�a�����c������`i�����r,�����M��=��_sb�1�"�Y�`�;���7�_Ly�~_{$|o�6a�1������w����r+�/����Q,x
�q����r+0�,m��f��
P(�S�A���m@�wT���r����@XQa��B
�VXn��_�'x/x���>V�8f�C�a���~1�����+J,�fC�!-��Cv���]�i���r)��)���X�#;��q
�H���0XScy�`�`���
����`'�I18��Fkz���X980���dE����`M��������������`'�%+!�>k��������RpBN;�'�.#�.�8����3rps0�;pJ�983�����������{>��������S
>��O�����~w"�]~qZ����s�����)���q�x�9�t9��a7�\����RpE.K��x@9\����gu�[pE�cf�(�������,�n|����:n-����,�q�&����-������'u�[0����~'m�<����~q��q�����yqP���z���q�&��z�����x�]�����{^a��o6��|	��������~)���N�����M��`��o��)X�dy�hCq���IW��f�
���h���b���^/m�<.����O0�fJ����7m�`E�����{�����T���|��-6��-X�d��b���^/m��[�`f����h\bCy��M�w���*/m��Gv���6��-X�dy��l���&�#{����E�
���i�r0�������8�~\�q�
�m�4Y9��c��MVD�K?M������k��������&+!'��YU>�`����`M�����-6A�de���q��������i�N��<�� n�N����`q���k(o;�C�d����� n�
r��p0�����k(o[���*���
� n�*rpa8�U�S
��5��-X�dU�`f�M7Y9�2����9�v9xS4Ya�����MVX��)��`i�������M�dL�K��`��)��`i���������
8�B
�6Y�S�Q��&+��������
���6Ya�����MVX��)o[���
���K���S�Q��&+l����-X�d��bFf�+oN���
s ,��� Ly��U���!#��u�vY?n�x	K��p	S���]�e�#aFf��"-�~�	�fm�����W������
Q��Q�,�6��W� ���.���Gv]�mV���~��f��Y�#{�Y_>���0��0�k���0�0lq���C��0��0�p������"�p��Y��VD���|J�q8vqx�Z	q8�q�,�F+!'��Ye>���<��<�k��<�8WZy81<�:�)
g�����]Sie�������:��3���4����<|�yX�i���'��F�i���'���N� �}�tZy�0<l��VA.�;��<\�<|h:��<\6�N�"�1[V��h8����6�����5#���H;���M����vZ��P��aE�����EF�iE7�;jX�iE\`Cy���V�32s�����n"�w����������
+:��.���k��V\A�R�Q��N+���6����Z0#3��H;�����x��e����q�
�mVtZq����k��V�A�R�Q��N+���6����1#3��H;���T������V�56��mX�i�flFn���vZ��JyG
K;��{l(o�����y��fc��Vt����ai�q�
�mv�N+z�an���vZ�#{��Ym>�a�dCy��5�V@���Xq��������:������
k:��<�-���N+"G��Ym>�a�eCy��5�VD�6�Xq����#���6��0.���m��N+!s+m��������aV�Oi��P��aM������6V�ie����0���4��l(o����:����6V�i���'���6��0����m��N� s[m���*����aV��iy��yX�iU�an��*��*�p�xX�i�F��6�����<���Y��VZ��)��ai���a��4��V2fdxx�vZ�S�A��6�����m��N+��^��V�+6��0���4l��)o����J6cF��Wi��V�a�;jX�i�x���
+:��F����*���
<LyG
K;���x��<��V���)��ai��6�a�;jX�i�������WtZi������V���)��ai����W���^�i�c��K;�tS�Q��N+����mX�i%g1#���N+9�a��0���4���]���V������M�i%�<�9�vZ�#�>k:-�<����V@��;��<�<4�V@o�N+"��Ym>���<�<4�VD�o�N+"G��Ym>���<�<4�VBNo�N+!'��Ym>���<��<4�VF�o�N+#g��Ym>�a��������N�����&��N����aV�Oi�D>�<4�VA>���VA.��|J�y�ty8h:��<\8wZy�2<�j�)
W��������*�p�xX�i�o"��aV��h8����6����R0#3�h�vZ��M����vZ��P��aE��M���x�]�ie7�;jX�ie\sCy����(�������KK�l�.By��|J�����v*V�Zy�����w�K[���V������V�U7��S����������]Zk�
�*�U,��2.������V�7������V�A�R�Q��^+�����XQl��bHf��.-��f���*�[��P�N��f+�C2C~wi��P1�U,m�2�������Vv�����]Zme�X�,f����q�
��T����G.�����n+ {��Y}>�b�xCy;k���\���9��V@.��-\yCy;k���\�-�9��VD.���-�yCy�����J�����C�n%���p1k��T�\��\l4�VF.�V��v+#g��Y�>�b�zCy;k�����}s�����d��U�S*��7��S���*�����C�n���p1���T�{o(o�bM�U����7��������bV�O��P�N��v�"3�o�!m����2\�*��p1��T�h��%bH������S�Q��v�4+^�>E�u�bJ=�X�n�����*��[�5x�\�h�N\L�;i�uZ�b�;�X�n����p���:�
C2\�����S�Q��v�\��)o[�U�[�f1$��N�n�p1�T�*�)o����S���:�C2\�����S�Q��v����)o�bE�u�C2\����yX���bV�O��.������yd�p���[�.����������]�����:r�c��I���!;��Y�>�b�\��\l�����=��N�ny�b�p1���T��}�����
����bq������B�S1rq�s���[�8p\,n�"rqd��U�S*���q���v+!G�����J����bq�������5�VF.N�+��T���3���v+#�>��v+#g�����:��3���B�R��\|��x��['r��p��[��d��U�S*.��������*����b/n�
rqa��U�S*��������������b/n�*rqe��U�3*.���v*V�[e������c���*�G(��bi�Up��T�h������Y�c���*�#�wT���*�
��v*V�[��r<��xi�U,�G(��bi�Up�}�W_���g����.�^��`��`�o\�n���+��x���_��?��������������~���_?���������O���~�������>|����~�~�#f�G��m0�����h�O�|S~�T��
���������7j~���7���#�Q�i�W~yr�s������:������O�^����#�9�i�W<~s��C�:��~=~q�����`/����V�8�p�M_	���3O�.��{�
��)�������7�N�8&p�5_���)�]�zo��/E�g�S�����~c�����&H;���e�7r3w��M^<�f�S�����o��E�y����+	&�S���������l���,��������~3<+���~��^�y��w�>�t���'������7�{��"�<�W\���������7���{v���1'7\�O���^A._�������\pE.KZ+	��	X�*p��kN��	�2���xS��p���.@����E������y�H+�j�)� �������+:�jfd�f/��``���8�j7�x]~m���[�`
=����Z�`���we����/^�_�lrs�+P0�,m��
Ly�.�E���m���������\�L�GKk��S��'XZc�����c�������#�����;`0��B<e��)n[����������EZd�0���]8hzo�p0�mr(��zT��q����n���,n*�Cv]~m���;�`�q����9�1,���z�`�������\�G�q����=�����j@�]~m������p�7Y980���5�����$�������`#n�"rpd8X\U&���������\pBNq�����8X�aCBN����&+#'��������y����2#�.�6����O���p0{�mJ�'r�9��U\U���g��5M��|2��y�RpA>�,�*rp�s���*����`�L���+rps�*n�*rp�r�k�Kn.�"W���MVE�c^�MV\���.�6����9��zT���z�����wP�����Y���
�y�P,�x�h����3S
6'lp����MV\����7���C�`{@F������G�[����`a��S���
�y�P,x�0#�F�,l�������]Y�~o��	oE���w(�Y��:�m��&��A��xj��e���%�x����C��}���S�,l��v(x����J����oG���wh\0#������+<��se���.��"�
�3Y�H32���'�S
v
>��r��Q��`���s(R�`=�����f���)9��9���{���������zdD���G�`?��++��-8 �.o�&+ ���MV@c��@�����C��7M�������)G��8��+���-8"�.o�&+!G���'�S
N��i��W���[pBN]�4MVFN�O\���������N�������i����f��N)�D�c��8���O��������:��O���'�S
.�������M����\��i���\f���)9��9����{�������&�"W���'�S
�����`i�e����`E�e�`
=*X�d�8��
�6Yf�x���+�,c6��q���28����]Y�~o�8���+�,c-f�8X�dLyK�,c��)n[���2����M�Y��)��`i�eV�`���h��Z0#�����2���9����{���)n[���2[��o�&�����wP���2;p0�mV4Yf�����M�d�8��
�6Y�X��u9xW4Y������M�9��)��`i�e������]�d��f�-N)�!�1_Y�~s�������&�x�`�p0{nqJ�9�3,n�<r��s���
����`�����rp`8X�d�����C�dE���q������q��WV��[pD�]>4MVD������|e1��'�����C�d%���p0{nqJ�98�9�����������������`��������������98w9��4Y'r��p0{nqJ�'r�9�`'�%� �]>4MVA.���\����������\�|h���\f�-N)�"�1{�/Y9�v9�P4Yv��
2��[�Q�]�ByK?.�����-X�dYc1#7�W�dYw�;(X�q���5��m��&��32�z�s�S
�p�����ZXY����M��32�z�s�S
^-<���E���g��`E�e���y����)o`R)��`�_�����-X�d�-bFf^/{nqN�`R)��`�_�����-X�d=~�BFno
{nqJ�;�T�;(X�D���5��m��&�d������|�I�����OtXXY����h���0#���=�8�`���,���:�`��`�h��G�������������6X����4MV@f�������,�������`M�����5���)G��0�`��
6"�>k������a�-N)8!�1�?l�	98u9�k������a�-�)98�9X�aCFN]��&+#3{k,{nqJ�98�9X�a�����5M���������)�������6���g�����*������[�RpA.��`q�U��K�����������>��RpE���`q�U��k�����Z�`fo�e���(x]��)��`i��.���-X�d�K����Vi���3,m�VLq��M�j2fd8�}^3�`LyK���S��`E����f���)8����i���+^�>+��u�����M��S�A��&k�^�.E��n��zT���Z7�`�;(X�[��U�x]�&k�7��q���Zw�`�;(X�K�Lq��M�zX��p0��fJ�p0�,�%���m��&kufd8�}^3�`���l��7�a� �� U������)
{a7a����H��K�A�ey$a��0��fJ�I��I�,�O��(�(4eV@
��l�4�(�(l�G�kD]�6+"G���g6S���q��f�~f�&����aM�����C�)
'��4�a�H?4\�p������H���a�����3�p��Y�}GF�]~|�W��D���y���Y����g�_�+.H�'G��N� ����VA".]"~|�����0H�>��RqE$.�k��H\�H����XqE&��OofT�-x�i������x���������w
���n��o~��������?A�?���?�����~��g�������<�o���?}������G��?b�]����:��_�6�4�:���7�����������g��G��F��yi���J����WT}�
7f1��`	.��^M�����6}�����U���r<������7�Tw�����p)��4�����`��HTs���������6}n����U��W9��j.H�{>6lx<���7�)
�Z��iXQ�m��!�CQ�Gpo�����Y��0���m�F��m���b/���
{�Tw���g�P�N���o�C���������QQ�Q���~�� ������������ ����{��a<��XiY��j��iXQ��������J��+��;������\�G@��d��0�L`L"a���H��EE�
���\K@58�`=���D���V�a2�����W����p���'���
��__�6�a�Boe����7������pD�6{vZ;�0���2]���;������u�� ��i���d#���t!|����G�^�A$o��g�u���z+��pE>����4��H�a�N����z+����>\����4�H�a�N�D&3!�V�a�����h�i��������i����n_Cz+���<�K\��u�5�/^���c�5�aI�����>,q5����*^��G�Nk�#��}���t!��%�B�N~w!��%o��c�5�C�>Loe���%�F����>,y�;�y<1����V��iB����{�y��
����<R�az+���>,q5����<�K�a�Nk�7��0���Bx��a�^z^��%o��c�5/C�>L��C|X�j������"^<��;�9�'��������������3�pR|����3�p&>l�i�}8���}������VA�����.�����9��>\�><zvZ+�p�}��5����>�2�~�0���k��G�NkE^u�H����W��t���
}xk����im������I�;��F|x2����m=;�}x�}�^�.������}/}�m=;�}��}�^�>�������tE>�><zvZ}��>L/a�}�26��O���>��7z���)����x��������J|%������l*�s7���]�� b�Rk�CD��V�.�"y/|�����o1�~:�d]i->B$��������!������{�����af�Bk���!q5�~���f����}�6�f�'F�K����e��~��}%��d����}�&�^�����R���w�2U�j|���C$���s����;mQ?(�^�>|�J��_�*k���{���C�{��p��BFC���w�"U��V���B$���s������������jT�����������Y'��l��+�pBND�g�k����xS�pF&�!�
v���31�����������#��
LC�������n�H���O���d0�^�.�Wt�Bx1�8p*D�^{�X+J0��W��
%x%�X�r���{��bmh�d.�^�>���7b��y��C!��
����Q��Z��]���;��������{��c��d+�^�.����x�b�c�H����,�*z0Y
�W���\�/�EN�H�+`�&�D&;!�
v|�����&B$����MV���J��=�<X�j����4�K�+`�&+
'f�=�^�.�����[7Y)�K�+`�&+�3�n�R��`�&+E�`�{��d��aF���MV���W����4Nx����Y���%t��+��,q5��MV�"^��?yT���'�`	��n��,q5��MV��xM~���{���Zl�d�<X�j����4W�xM~���{/#f�=�^�.��`���n��,y�����f�=�^�.�zp"�������S�����������
v�����d�d������)����Y�`z�.���xp2o�
zpiz���t�������=�06o�V�����'������6o�V���y�y����M~���{o���`�&kC��g�&kG����	����w����xG��g�&kG��/{6Yz��{0��]����l�d��G���<��^�=��=�^�.�+zp%�����\�<z6Y=��L�`�'zp%����=�l{�g�u����+�p��$������5��
�������C���8����[7Y�k$��t�&+�3��+�0|�H\
�u��q�F�^;6Y9�y��L��+�p����n�2n�H�+`�&+�p�f&6�
v<B�*q+w��k$��c���	3��f�&+OP�J���]t���{��d�9bF���b�d��T��������{��d�e���q�������7s��5��
����K���i�����iD���w�8[#y��������xM�n�rFN�����q�F�^;6Y9����b�de���<��yp���{��d�`2]S����\��{�.�q�F�^��M��L�k�y�������=`���k��g�&kC&�5������7����`\���W��M��Lvk�y�������=`�8X#y��=��=����&�@>��{�.�q�F�^{6Yz0[�a���(�az��0��H�+a�*��������:��+1az��0��H�+a�.�Df�5�y�u�
�D��m`�e@>�*<;�Ye��a�6����W#l�f����]���*\XBk����@�%�F���*�����a�:��	3�����*lX���Ez#��p����c�U�����`]h�tX�j���2�K�+a�B�Lf$+��u�U&�a���n��>,y���2U��|���*���u��F��|X�^	;VZe�1#�a�N�,���W#l�i�|X�^	;vZeY1#��`�i�|X�j��;��F�zM^;������`�i��>�t��F���>��>�8vZ%�g�����*}8�>��`�������g�U��3��`�i���|���*���������>\��NkE^��wZ+����a�NkC^��NkC����.�7�����������7��������7���F��}xo�p���v����p0������0��B�@>�>�<;�}�`>l�i���az#��pE>�>�<;��>\��wZ}��7�]���������:��O�����:��O���F�a��������Z�/!��h�i�|�H^��u�������v���0aFr|Q����"�W#l�i��d#y��;�5F�H�/�����CD�j��;��l$���c���f$�F�Nk�T��a�Nk�-�{%��i�c���$�h�i�SD�����v!�c6��B8;vZ��cFr�o����JU�����V\���W����:������;�u�RU�j��;��l$���c��.p���Fm�u��.P�J^��u�������v���>��U�h�i�	}8�7�}���g�Nk���l�f�����>����.�q�F�^	{vZ}������VA.����`�8i#y��=;�}�
������>��7�]��������V�a�l3�wZ���|����Q�{%��im��l�f4��v�����y���6��J���������h�i���;�az#��0��H����i��l�f4������0��Bwm$���g�U�����h�iU��J|���!�>\�>\<;�}��������>|�7�]�����v���}�������6�K^��u��
����J�������O�����%�F��������v���P1#������bD�����`�|X�^	;vZ[�1#������F�a������|X�^	;vZ��bF���u������W#l�im��W������6�Kh��u��M���W#l�ims����a�Nk���%�F����f�a���7�}�x��>�r{��x�0$�����b��!�.���X�6;�Z[���d�jm	�8#���]'4��4�08�Z[F%NL��k�-�g���^���J��J�^+�g����VA'�����`���4�8��VA).D�g�bkE).D���`�+J����0x6[+Z�J�x6o�V���X1���xC+^�V�jkC-�������Z�-�w�]���[S����m���;��������w������^�+^�Yn��;�����:��������^|(^��nU���x�l�nU��J���
vA\��k���g�u�W���y�u������`�'z������n���'�������9�����w\���
����>�l������sD�j����go$o�c���
C�������#|�H^
�u������m vl��X0$��]���=�����[�[;�H�b�vk�,���������G�W%������q�F�6;�[��q�d�&,���>A�*y5������7��������C�A�����g�W%������q�F�6;�[�0$Y�]���}�~U�j�����o$o�c��/'�$���u���	�GqFz7�1��H�+���n�	��l��D�F����bz7�1��H�b�vk���d',��VA/���������m �l�
z1Y���1F�^\��#���@��n���d',����^�/N��.�H�b�vkC/&;8!��[z�F��j{���[���g����!������x'^l����8������:���NH��[9N��|&z������?������������������?����|��?��������S������~x�������G��_�_���qxgt\���������~0}�w0~�7p���1�����?��u�F�?����;�;I�����G�{'��@�X�1`H������wA��I���= �V���$m�c�w�C������qD���)��{�p�$i��G����k;$������I���=�\�^��5I�`����6�g;$�����i��m�{@-�<Ox��Y�+`��������Zl]�3<K���x�d�x�x��I�+`���X�CI��.���$H�v����8
x��9�+`���H����Vg���H`��W�����LU8�Uxtl���*��
g��������Y����{	g4��6����;
�p&&����v4�B^,|����pA.���{��7�������h���p6o�V����������M~�V�^�+��Jd8��Y���������
oM~�N�^���F\8��Y���^*����oM~�F�^�;��NT8��Y;��N�(4o�t������F���@>�	g�.�@>�1;�eVE>�*��M��|+�pe"l^eU����#��7�E�M~����|O���4���:Q�O�D����D
>�����[��!�$\���:�������f����!q/|�{|/�0`D�[��X�X5������nj�7����m]�	�bF�;��X�X5�X���#s�����!qoo9�;f����u�UGhQ%���aR�D���o�8W��;�
����J�v�G��<�x��@}�NO����[wXu�
U�*��%�9�����<u<���Zl]b�:T���~�T�/V����#�e�����X�Xu�U�*���"�:T�{�Xc�1��~��7���jp�5����{'�����'2�pFN���{����������8���{Y=8�w�Y�>�zp�=����{����`�&���f�`�d���E��G������6=��#L����������Z��W���M���6=��L���o���������7���M���5=���K�������������w����0z����'/��������&�@>t~d �^�z����'�.�pE>�9]�y�U������������?yp���O��JN����=��=��q�{���g���<��f���'�`�&���O�����9�K�+`�&�v��<���:x��U[7Yg��W��M�V�H<����0x��U[7Yg���=���:#x���[7Yg��
`�&�^��?yB���G�`	��n��<X�~�_0=�Q:��^S��<��^��������@�%���
���&,y����s����0}u��LX�~�_1]�����J���:�3�/�u!��
K�/�+��\X�^	;�Y�R1#qa��^�iD������|/��2��2��)�N(���0}����2����y?�^�m87m��S:�%���3�a�>+�
g���W�
�pn����g���l���*h�E��G����
��
{�Y+��Jl8��Y+�����#C�7F^�2��gm(�+��h�gm(��.�t���
]xk����g���q�h�g������t���Uxo���Yg��;Q�h^g�����t���M�h����fh�1azF�M��M��^u\Q�kS�'�2��W"��$�.�O���0���D>�<yvY'z�I<���0z��{0���x�9�<�UY/}��kh
�q������ �y������y�{��d�d�������0�;�I�t��`��y�{��d�d\ #����,�.��
��~�&�v����� �����q���i������������_�����%�Wo�&U�UY�0E�����a]O���4��]�p�k������^n�0�~bo��at!<O@x����/`t!�5�y������H3�g�FzF�KD�����
�.�a��5���_��i����������p������_��B�k^�^	��Y/�P���M�b�!�2�t��`t!���S��g�>�%#�0���D�.�3�p&����r/��:��:<{Zu����.��p!����r3a��������Z���z
�c�BxE^���#o��KxE^�><{VZ�0����P�.�7����KL�wZ����a�NkG&6�������>��>L�����;����a�JkG&6������:��:<��.����i��g�u�
�
�HO����
�
��+�pm���YhU�a:bc^hU�����l���D�M^<��]����S1�>��O��g��a@>�*�8�Ya��`�:+�������K�/^���6+�	3�eB�LX��6^by	",q����#f$"L��.�#����m���<X�^;vYa0#�`�.+����W9����/a��%��c����[WYa�X�`���	<X�^;6Ya�1#�`Z%t<�K��H�f�`�{��d�y����i��0x����a��5=896Ya��`�&+,����7Rt���5=896Y!�'���J�8�'���EGBNMN�MV����x0������x��&e�������d��L<�V	]��B<��M��0��������Z���`�g��=x�=x6��=xmzp�l�V���x0�3����������oMN�M���16o�v��M�����w�����������w���M������{����=���:������H�z��{�b��=�h{�g�U��+�`�g���\u^�=����g�&�D������.�O��S�������|6=8;6Yq�
�Fz�|�H����w/a�D�^;6Y1�H���F��	"yg�����{��d�pbF���H��t'��i}��K:���W��MV�f�O����H�#4��Wyw�����wW"l����v����aF2dC��t!<A�*y�?��]e�	���W��UV�
f$;6��U��U[w�l^�^;VYqN�����K��U��U�>��*#����v��^n� #[������T����*#�����v��b1#������"�t6?�0&����Xe��"�6l�%�8�g]��O5�E87E�xVYE�L�Dz	�.(�Ya�7�cA.M.�UVA&6�^�.�W���p2�*W��������Z����M����
=x�=8�w�z�����Yem��d�&�K�0z��{p2�*w�������������M����=x'l�d��{���g�u��	�H/a�z�A<���:�����&���	�H/a�=�������\���d���d�&�K���|�����=�l{�g�u��	�H/a���|�����q���ap������D��5�B8�K^��u�5a�� ��e�a�����5�B8�	K^��u�5F0a�� �Xf��`H����!*,y��e�8F�xM�c�5����Z#l�f�#���U[�Y�4��k�p��q��a�:k�@�%�B������)�ap���y�����5�Bx��
a�>k���%n��c�5.C2�.��tX�*���q��
���������u�5�		�>\���{�xI�a�JkL����0��]g����p�����>�v����>���k��pA���N�������4�|	��s�}�������o���7/���y�����?����������C���?o?|�O�x�����x�������?���������OL��$��.>�����~b�����!�������{�7��(���|������Y��(�.��~����G��[��[��oG���n<;��b��"<P��@�8t�(���jq��"xV|���������Y�,���fQ�f<��fQu���>Q,*���D�8�b<�����"<�
�
x��$^a��M�"q���i�0�~L|�n Wl]�M�"q���)�Y���4��"q��_���C�@$o��c�7E8�p"� ��o��K8�'���[�{��H�a�zo���������r/��)�����&��W���+k�4bH�8����]�%<�W5$�F����pD�6;�Y�0�~j�n����!q5��u��� ��A�����C��F�:kZF$�U�>k�M�� ��gM��!�Q�u�5%�a���.�&��
�����P��4H�.���:�t�u�5�*��mvl���>L�A�y����3�a�JgA$o��g�U���8�h^i���|����]�� ��i���dd4��V����p0��pD�6{vZ�0��;�
}x#>�;-\��
�����>L�AF�NkG���N�A$�����i���d d4������p0��pD�6{vZ�0Y�;��>|����H�a�N�������������0��`��"y�=;�}�l������>|���Ax��������<�Kj��u�5��W#l�i�a������������V[wZs��a�Nk/^��G�Nk�#��}x����>,q5������%���~��Oo^1?y��2�s�J<Y�Z�J,q����] ��������������Q�������!����w!�����J��w:0����u�5���W�k]i�3�����}�F�^���u���y��_�Bk^&�xM~�6�^���dV�Z�Y�*,q5��u��"^��
?w}/��"�t����9�'"���]�f������7�g]�'�*k����h0�~`�������=��oA	�D�����\��ov�[P�K���s����������5����2�5��V����H��'�7F^u��[�
xel�bm(�[���g���o���
������xG��/H;�Q�w]�g�
kG���/v|����`G�:��;�l�a��q`���.�+:��~�YbU���K�l^bU��J$�~-��%���{�X'Z��[�l�b�h�'�`���>������`�k&�����5�2����[�Xn�H�+`�k	3����=��D�j��{��A$��c���3����E��D�j�����A$��c�����y����Z���5�7��a�{�&�c���;f��A�&k��H��`�&k�]�{��d-���q����Z&(R%��~�`���W��M�2����Y���e�"U�j����WA$��c��,p��B�A�&kY�H��`�&k�Q�{��d���1�~~�b�d-	=8���7A$��c��d�`2�X7YKF�������I�{��d�`���7Y=����A$��g�U���3�6o�V��B<�~!��=xm{�g���������
=x%L������=������7���M���16o�p�F�^�Y�l�v�`�c����=xgl�d������l��`�c����=� L��0z����'���pE&;6�������x0�N`��`#y��=��=���$�&�D>���v�6��
���Jz0��I�MV��%����Jx���vl��P1������JaD�lh���J<X�^;6Y)��Q��d�d�,q5��MV�����
���Jq���'�&+E�`���n��8��k{�c��F�`	��n��,q5��MV�^��;6Yi��
`�&+M��Wl�d����������J��u��MV���%����J3x���vl��1������Jx��U��v��K�+`�&+�3���������`���.�zpjz���d���t��MV����x0�N`�=87=x�l�2zp�=8�7Y=8��	�����O�MVA.�g�&�����;�]�������g�����g�&kE^���v���M�<��
=x�=8�7Yz�F<�~'�`������M���6o�v���x0�N`�;z���`�&�@���7Yz��<���:������MVE>t.�MVE�������\�<{6Y=��\���=���	��D>�<{6Y'z��{p�n��� '�`����3�H�+`�&+;f�**�MV�"q5��MV���{��d��bF���b�d� Wl�de����W��MV�p�f&�5����>@$�����8U#y����<�y����&+�P�J\
�u��q�F�^;6Yy�0�~`o�n��E���[7Y�j$��c�����{�u��g(R%������V#y������Q?��X7Yy�"U�j�����s5��xql��R1#9����C8E$��������{%�Xe��"�fk�.+g4�DL�~+�a����W��]V�h�l�f0/�2�p&*L���0��H�+a�2��
������*����0�^`�8[#y��=��]����u��2��_�Cexm���Ygm(�l�f0��6����0�f`�8\#y��=��m�������:��_
�B�k$���g�u�������:�������]�t����l��a6`3�WZ}� >L���0n�H�+a�J�������:��+�a�N�k$��p���N�a6a�;�}�d>l�i�}�l�pr���>,�5���V��%��~?����5}89vZ%�Kh��u�U����[wZ%�x��>�;�'�H|8XwZ%�K^��u�U"����v���1#��`�i�|X�j��;�2�K�+a�N�Lf$>�;�2�K^��u�U&�a�{%��i��bF�����*sD���������%���c�U�3��VY��%�F���*����v����bF����VY��%�F���*i����a�N�$���|���*	}81���JFNM���V�����p���JF����;��>��>�=;��>��G�N����#��`�}�4}8{vZ+�p!>�;�}x�}8�/
v!���M�����>������>��>�������g�NkC��G�NkG�t����]���{���g�������y�u���G�E�.���������:�������:����#��`�}�h�p���*�p%>�;��>\u���W�'�pm��g�u�����;�}��}8�G_}��mv���a�K�|���Z���a���W�������Z���1F�u�����a�'+.�H�+a�Nk�3�s�F�Nk��!"y5��OV����W����O�H��;�u���~�f��[��i#y��;�u<0#9�w����	JU�����^q�F�^	;vZ��aFr��h�i�3���W#l}/������v����`Fr��h�i�3���W#l~/��6��J���Z8sse�6�u��.P�J^����4��H�+a�NkM��+[��;�5�'���r�C}8�}���Z3�0���;�5�g���r�B�m$���g�U�����h�i��B|�Vn]������g�UP����d^j�(��1��� �q��@��j�h�l�f2o�64��1-�� ����������P�7���y���oD�i��1�H�b�^kG'f;7�y������i��1N�H�b�b�@)fK7�y�u�D�i��1��H�b�f���������h��X1-�� F+�M+�g�u�������:Q�O���y���n$o�c��
��l�f�����X�j����m/��
����6��y�u���	3/�.��^,y���-�y�u��E�b��!�n��^,y���c���
C/����m/��
bZ�uA<�K�b�vk�$^<[�[�^,y5����6E�zm/���6�Kj
�u��M���WCl�nm��W�������f�bI�!�n���X�j����m�x��^��m1$�������b��!�n���X�6;�[[
�x�l�nm	�8/��[�	�8��88�[[B/N��g�vk����x1u�.�3zqn{q�l�2zq&^<��[�8/�N�qA/.�{�[��0/6o�V��B��:]�+z��x�g����������x%^L���
�xm{q�l�6���x�b�nm���b�t]���[���g�������vkG/��S����xo{q�l����x�b�n���b�t]��G���g�U�����y�U��+�b�e�����G�v��W���y�u�W�������^|��8z�['z�I�x�n��?GN�����;n�H�b�vkIN�]���=�����[�Q�8�#y���=l���X�[{����!����qG�6;�[{��9w���X�[{����!����qG�6;�[�'s�lg�n���U��[���qG�^����>���;[�I���>A�*y+w�;�H�b�vk�GI�p�u�����J���5.�H�b�vk_�${8�����W%��8[?L�q
G�6;�[�rbH2�C��)�9N���xiD�����������~��_��K�����������o�������T����?o?|�O�	x�;�_?������?��#?������r+���������_�o^�?�;?���g~�{���>����3�
RB��u�km�{�MlD�Y�G���:mx���d/O�C����.�w�u���F�y/���v�s�x��#�}�����@%����v���#E�K���o�~��Oo^1?y��*��SB������N������"��\����3�%�#�
O�$�������@����9)�^�'>O��<��`����|O�:�d���}'>M8�/R>rN��|�a��~�����|�a�����@��c�G	�W����<I�����F��7D��?����;�����k�TX�^�>w}/�8`D"����;"���U�>�:��|#�����}�q��|+F$����v�#��5���!��;�K�������w�1"��l]dH��U�ZY�,q/|�{P~/�i����u�uL���W�k]c�����Oqr/�XBk��[�c��
`��X^��?y����0`	��n��X�*���c9��5
���M��&�����:*p���#!��P�SS��<��^�81������u~�@�{gt��~�Yb��L$���X%����q��.(���4���*h��Xp1o�V���[�#���xE^��=k�5x%\�k�
5x%l^Sn��[S��<��^�z�F<���Xz�F<��������{Y;z�N<��Y;z��{��_�z���`�&�@>��&�@>t~�����M~�8�{W���xp1o�*zp�=��S>�\��k���<��^�'zp%\���=�$�����=�}�(�gS��<��V�u�x	�[WYu�����~���"y���������u�U|�H^�����5�g���v,�j��������!#���?��F���W��mV�;f$o'�mV�M��a���m���v����bF�r�`]g��T���>��N#^=�S_���Hx��t$�F�������W#l}B�^=�S_���Hx��t$�F����3��W#lmKu>��a����OG����V���u�UhT%�F���hT%����J�����]�u�U�p">L���B8���?y����3�p"�u
��V�����0="���>��>��	&7F����;��>�����.�����O`r/��>\��wZ+�p�}����[<�uxm����u�xE^��JkE^u���]oh�k���<��^���Fl8�7Z�����#����oM~���{�(�;��`^h�(��.��<W�0���t����:��w�����:����y�t/�U�h��g�UQ���������UW�G�*���	��	{�Y'�p%&���M��M���J�>Q���O�e��"|�e�9���?�L�V��,q����s�1#��`�e�<X�*��_%=x���v����bF���U���%���U�3�x��<96Yg��`�&�����Wl�d�c��������:G�`	���M�9�K^�u�u�'^��O�M�9M��x0=���	<X�*����s��W��M�9G�H<�����,y��M�9�K�+`�&�\�H<����,y��M���K�+`�&�\*f$L��8E�{�#O�����S����3�'�����.�3zp�=�����������c�uf��L<���0zp�=�Bw\��s��g�&�������.�zp�=��Aw������M���26o�V��U�`:�0z����������W���M����L����������M����G�v�����!�.�w������g�u�������]�����t��=�hz���d���`zxo�=� l�dU������������x0=���=�6o�N������M��|�����|����;_m�����W�~U�K�_��Z#l\e����G�k^�4��c`��5���We�dL��
���{�;��������?��^���J���z�8CF6aC���B8�@8��5����0/~�������3�)Wz�k�c��~�f|�����0�����+��a
��M��Y/� <�'k:�g���k�+a�6�%�����q�������5c2��
���W�~u�K�3�%Wz�k�K��~�f���]���k�+a�>�%����+=���4�E?[3�A�.�a��5���_��	m�L�����zI�6�t�t����:��:��h�dD&[6q2n�^��g��t����:��:��h�a2f�q]����p�{�}���'�JkE&k6�������>����]���k���g����9~�z���F|�n�w!��oMN����>L�l�I�]����a�J����>�7}8yvZ;�0��'�w!|�����.}��������i��d������pE>��e�.�+�pm�p���*�0���'��!�>\����.�O�������i���l��������>|���=�}�l�pr���>,�5���V��%�o�a�x��:�Xi�0bF���X���8�^���x���W����?������������������?����|��/|���?o?|�O���z�����������1�_~Ih��O�:?�Cu�	����
�_���~����g��g�7��7������*k�0��q&[��D���7�����J�����x�����`�������u�����x�<P��sm��*�{�X�0#�y�.C�����a���������o�����|x���V�e����3���*�r[������7����4����?�������)���81���?���z�����_���������w�������
�����A�+5���iY	3�a%v�����xx����5}
��Gq��p���J�����%`F����z��p��W#��_6�.��A�^	���������=���uB�d�������
$���iY��H8�sO�������?Pe�Kx���J�����(�y�@������Z��qk�"F�;<p��W��e%fD-���:P���;y��������58d��3���}[�����8�&F�u���|��M�7��b\�z�I�����M�>���k���i�O��J|�~����>|�obt!|��M.����3�����0=���8�����?���V�v^�^	;vZ1�H�Uz�I�>D$�F����0����J��������t�N+�	������^�^	;vZ1�Q?&2&�N+�P�J^���u�a*�5���c��
3��D�d�i�JU�����"l%���v���T #L��������W#l�iEKx�{%��i�9AF������Bx�RU��V�-EXKx�{%��i��k�d���JU������"�%���v��^�XbF�e#�n}�	}8~d��^�	}85}8��V�(�d5��\�qF!�D��'�qF!�M!�g�����n����F��?�Pz/��F\�F�Z�����z}�+*q!J��F���WT����a���Vtb��������x%Nl�km��k����Ylm(�d=��`���R�)~d��^�;J����0x6[;Z1�O�o�wA�������h�{����Ym��dA��b���Z|-~d��f���GS����mU�b���������W��������*^�Yn���dE!f�r�D/>���['z��x�g�u��z�B���^|/~d��V��^,y���c�5�$^LR��8�K^
�u�5�b��@��n�a�����]����{��g��K�O���v@���������?w�'?��9��Ti��[�������O���������E��
�5�X86��9aH2�����7�$��7��h�'~n�����	o$������a�� |���	�4�������+b�Fp�I� .����7���S������f���"vl'�A��b�Fp�"&o�>��z/��#����G#8�?_�i��5<0�/�&�;��'9��U����@��^��=�,L�-�4]�\^���/|�����u���������3o��M3��(y?���4C)�����?���g�a:� %�o���i��5�w|��u$�@)��?%��h %���� ������c���F���hV�%��/;����3�_��_D�~t��I��>�o&�Q/2��H��"��":��SF���^�:�{	��L�����p�;�������M������{	������.������
��E��aHr�
���7�R�����|��#y�={��`Hr�_��0��F��ydb�^�;������Y����;��&������O���������{��>|�>k���A|�����	�m���VE>�����+�p%>������+�pU|���:��+;����>|26��N��S�a�N�D>��6�Nk��O���gx�����;�y80$�a�Nk��Wk��	�a�� ��i�a�����;�9�K\��u�5G�a�� ��i��`H��G�#}�K\��u�5�/^��G�Nk��%�B����G�a������i���������'�aI�����	|X�j��;�y�x��><:vZ�<bH�����]���W#l���y��
�������0=$��|X�j�d~���K�O�������b~
�|�e<1����{] �	!%�/2t��P�SS������oB!N���.|3
q"Bl~���Q�sS������oF�������-�����d~+]P�KS������oA.D����2\��w<�(��)���F��wE^�
��Y+��JT���dm��kS��������"��"L��w���oD������"�������������M�;j�N4������{{&������L-��%� \�?����P��G�7�E�=t����oE�=��������#������W]���t|�W"����Y��|��{6X'��0U���??Nb����Z�������^�
3������>��D�j������	/^��[�k	p���V[wXK����bc���%F�x��oK�%���Zl]b->@$���[Y�8��k�{��b-#{+���-�2B�*q5��-�2V�x�Sok�e1�~�-[�x�U�j��k�e�U�^;�X�0�~�-�Z�x�U�j��{�e�U�^;Y�|bF��[:���2"`rb�`]d-����
���Z�3������.�x���[7YKBNM~���{'���{�l�d-	=8��&k������O�q/���u�+]g���<���*�����O��q/��\t�����\��7Y+zpiz���u�xE^u��*]���+��`�d���k���<��^�z�J<������7����������?yT���w���x�y�������y����M~��������a�.����xp0o������O�q/�=��=���t\��������������MVE��/�MVE������]�4����l�N�`�B�A�>��O��������|6=��S:n��`	��n��,q5��MV
^��?yH���x��V[7Y)�K\
�u��B�����'���p1���t��,q5��MV�����
���Jc�����.�G�`����w<�K�+`�&+�'f$l�d�iD������]O����
���J���[7Yi��`�&+�����
���J��uN�MV���%����J������c���`	��n��,q5��MVJ/^����������t������#���������MV���Y�`��pF���c�0zpnz���d���{0����������.�zpiz���d���E�`�~����26o�V������g�����'�&kC^��7Yz����������7����E�;z�F<��v����7=x�l�v���x�y�������a�]��{��'�&�@>��7Yz�A<��u�pE>�<y6Y=�������\�����>��k��'�&�D>u��]���'�`z�q���g����<Lx	u��=�>@$�����8Z#y����"f�*��]���`�&+�f��������TDG/���"q5��MV���{��d�X1�~V/���x0�W�w��5��
��������z��E��Wl�de���W��MV�V��������<A�*q��3��j$��c��g8O3���v��E���[7Y�j$��c��8O3���l�d��T���n�2N�H�+`�&+�	3���&+'��D<�|n%�V���vl�rF&�5����=86�[�8V#y��=���L&k��E�=�6\��V#y��=���L6k��E�+zp!LO;��j$����d���d��n^t������i�]�^����l�6�`�ZCG/�F���7Y8X#y��=��=������.�w���y�y���5��
���:���n
]���@>�����F>��x6Y=�����.�+zp%LO;�'k$��g�u����z���|��w��5��
���*z0���=�DX�j����2�K�+a�*�3��V�{��p�01az�q�LX�^	;vY%��������.�#����[�Y%�
K�+a�2��3�W�|��0����[�Ye��5]89�Ye��a�:�� ��W#l]g�)��k�pr���2,�5��}V���%�F���*��W�i����*����+��Bx��a�B������J���*K��d���_t!��K^�0=���|X�^	;6Z%
����u�U�p">L�=�B8���'�J�$���|���*}8���o�����?����oY~/��L<������������?m+�#��O�*�?���?����=~��������w���������������������?�u���~#�S'$��G��|���8��N��q��"�C3.���U����r+��NH�+`��
3�����wooE1.���U�.�W8uB�^�Vo��x�O�t���
�x��������
��y�����~�D�K}�o���]�.��	/^���lZ�aF��]?u"���.�w��]?v��+����5O����fD)>�S']���@)>�c'��"]�/^���lZ�aFt���:�RG�����N�wE��x���Nd��
2���U?u"���.�OT�S?~��+���|6=8��n���X������n>A$��+���;6�e��U��3�V�.ut�;6����wl������y�����t��`����_��H��c�^vl^��p�1#��]��wl$��J�0�����Ws<���|��.u�M����W	�����c��o��'���z���u��������W	�����c��o��g���z���u��������W	�>��5�_T��u�0#�~]��wl$���J��0���!�W�s$�"f$�/�S]������W	��%���d�jp��3��e��S��]��K6��7�g�l������yF���|J����)����3�[6�e���}G�]�2h�)a�6�l$�����0����1�WKw$��_m>��t��a��U�a�:P��f�^�l^5����6|�����y��k6��K^�B�l������;�Q�/�6�6/�p�F�~��@}�_�l^E����>|����y��{6��K^�Bm������|G���2k�)b�Nm$����1N���I������O4�������[-������?�8j�^Fm>��{"F%�L�|�����T��)����m%��
����6��81]���8�K���N,y���-��I�u���b��%onvAG�zM)~��wD��%������"X����W7� ^����%8"A�%�r
�~G�#h����W"� >��5���#��4aH��t���	�X�~�;s]O�����������!��
�.�g�b��%o�uA<�K�b�vk[I���xtA��K�/y����X�^�vk[*�$^Lw<� N#"&^l�uB/Nm/�������b���qF/N���������������2zq&^L�<� F/�����]�������n��B���ytA\���b�l�+zqi{q�l�V���y�y���������xm{q�l�6���y�y���o����
�xk{q�l�v���x1����xG/����;z������n��;�b�����^|/�o�vA|��{�[z�A���ztA\�����]�.�+zqU��������x1����D/������]���g���g�u������G���'�b�>l�;.�H�b�vk�����)b�vk����%o�vA��7�e����/�����_p>El�n��}#y����.�q�f�l�|���q�s8���������o$������W?G>����x�0�~�o��]������ �����~���G�S���Y���{tA��7��K���1�������?|���C������1��H�/�&���_�o>�u���bH���@>� ���%�tA�8�e��k����C�'����1.�H�/9��b\��/8��wD���/;8�"�n�v����_r�A�8��_&p>�x��8�g���u��g��L���`�1.�H�b�v��������[��/�G�A�^\�^<z�[+z1Y�	�y�������]����m �l�6�b���vkC/���?�����@��n���d',����^�3/6�>pG�6{�[;z1��	�y�u�����?����m�,��b2��y�UQ�����.�qG�~�wo�����S��{/#�1Y�	����h���1}��e\����?���Q��D/&k8!��['z������8�������O�
���%����:�b��%o��|��kZ�sw��F$N����#�K�/y/��N,y/�����p��q����F,y��}�.�#���~�V�^����'�V���%���M��>,y/��{J|3���
'�N��"&O���V]O������g���v��d���:f�a��%�Yu<�K�����x^1"�`�>����%���d��2��k?!~����a	�\�l�g�����w��N�^��c�u$4�DL8[wYGBN���+V}�	'�{���3�p"*����#�
g�����.�3�pV;.����p6o�
�p!.L���B�����a�:kE.D��y����D���7]�(�k���g���
����y���
�����oh�[���g���oD��y���oL����uxoe������w��������w�����.����������>|06������0}����>|�}���������y�U��+�a��M������O�q/�}�.����>|���t!|��M~�D�[	�a�KH|�XwZu���%o�� \qG�^	;vZ5�H�6*��V
�!"y����.�qG�^	;vZ5����lT�;�'$L�����t!�8��J����������b�i�JU��%��t!�8��J�������y���������K���Bp$���c�U���q����>��T��_��M�8�#y��;�:�A�����N��P�J�/y��a����W���V]���Fp�u�U(U%���l��p�����v��j1#9��XwZ5�'���m�.�q�F�^_gq��jF&8���C8�g���u�.�q�F�^	{vZ}�,�����*����0}��a����W���VA&8q0��V��B|��p��0N�H�+a�NkE&�7q0��6����0}��a\���W�����>L�o�`�im���a��M�8|#y��=;�}����������w������H�+a�N�@&�7q0�������=a������g�U����M�;��>\�����z#y��=;�}�L�����:��O����q�F�^	{vZ'�0Y���u�u��'�a��\��>,y�'x8vZ�p`F�����:�����������J���:����N������K^��B8�K�+a�N��3�����%���8�����5}xr���|XBk��;�s��_��\���W����c�uN��Z#l�i����������x��><9vZ�<bF�����:g�a��%�Fv!<�K�+a�N�\f$>�;�s��_�ZU�����v���������u�u�		�/�t!���S��;�3�'���������a��
�����{�������Z��������C����������|��C�����)/���0�����)������o��Wo���o��������z��o�z��>|�������q����hZ�A��f���(b�_�a<4��G����|F!i/|g��
3��0��6�����0�G�(n���Q�����x��h��~E���7�����Q�Lp��w��($���i����7� ���n�x��xd��V�����y�lZ�aF4�]?�"����C#��c(��et+�#��kB1�Vn�}������������G�E��{��kA1�n���
�1�/�0�p���x�����($�"��A7u���A�;(����h�bF�b�E����]��O�F�����D	�����2����k(�N�w����$�y�TF7�}������W��� d�������� ������<2ct+_�yM{�kZ�AFX�y
���_�a�����GV�n�7�i/|��
2���kh�/]8��Fn^�*|�m���kO�,�Ef����t��_��y����^�a����p��m�q���H���]����k^�o��
��p��7�i��W�H�T�(��
|���#d���}���W��Ef�����D�(�_��y����^�A8X�yM{�kZ�a�2�u�H%u������#s��E�mo�,~��1d�_�m���.|3�/��yda�V����l�x�W��,�D�(����K�m���oA�m��,�����Kvm"}������Kvm��������^�Y<������D�T�����KVm���������I�����K6m"}B�����K6mf��jG�m/�$��jG�%�6�>�����,�<2x+����g�<������D��������<2x+����^�I��UE�%k6�>�������5�Gf�������I�����K�l"}B�����K�lf���D�m/�$��*��d�&�'4=���W�*|���0��J�+_��*�3��Oh��
��������[��_I{���_�P1#�_������������7��J�+_��*�32������+y���U�%���c�32������+y���U�F�vM������'d����'4]�N���W�k�_�9��k�ov����+�5���U��%�����
���������
�����'4]�.���W�k�_��W�^�:�W!E�H��>���7��&����oB�MM����U�����/}B��y���?>�7������o^�����������?��������A��_���?o?|�������x������W��W�������Q���J+h��r��_���~����������[�D�
�+������/�+9O�>���7^� ��W���������y�bvl��9C����H�iu�{��J�v�G���[��5�R��������5�������y�������i�|���_Ck|����_�*|��v�_�^�:6~#������Z7~#����U�7~#������-����������V��:��W�k����9�������as�5�����as�5�����aq�5���c�7���kh��u�7���k^��q�7���k�+_��o�����_��o�����
_��o�����W����k���5���Xam�5����k#l�����u��F��
��������K��^��oB�m/���j���li�>���7�����Gf�n����;�������lg�>���������GF�n�[��+����*��le~1��V�_�2�����|W����|���V�_�1O��t�������G�n��������Y`m(�lb�>���L�?��v+��=0�kGf��M�;0Y�d��V���4�0xVX*0��i�>P����#{z�Fn���������l_�>�����}�l�aUt���|<K�%�����4]�(��T�G��n|�������b�h�l]�>��x�����[�i��I��XcMx����[�XS�O������Z���|~H�`�k���%�����"|�L�`�G�o��C�6;Y�-�5��E��d"'{�"k'�v���
�����|oI��n������]���i�x��F�������oI��k���I����������������	O���`�&k��I�����������{�W��M��G|Kj
�u�5-��N�t�b�dM����������oI��n��<����q�5%�������dMx����[7YSF&�{�&k������������oI�6o�
z09��X7Y=��=8x6Yx�����7Y=������BxE.m�U�-�5��U��"L���u���	��	{vYx�����wY�09�;�e��*�)*�Yf�a��Z#l^f������0X�Y;���v���f�q��Z!L��t!|�����`]g(�G[��g��~Kj��y�UQ��Y�a���*�pm�p��gM���p?w	���/6,��|������O��?=�y����?�8�%qx�'&ga��ow�<�����y>��J�<�?��r1���a0n�f����y��o�S�g2�>_<��h:p������o�un������x��L6������GP�����o�yn������x��LF�������`39A9�
���������� ���t���7�@,fr�r����������$���t?pv3��b&g(�`�����-q����R��Nw��)�x���-�zo��n���X��x��L�������'x�6�S�C0n�f����W��c�7�a�3Y�����������1�!�{3�tK�`�ro���d�;~��.7����x0���q�[�6;~Wm.��d�;~��.7.���x0���q�[�6{6Y+z0����w�������w���=x�l�6�`�����
=xcl�d�P��m�l�v�`2����=xgl�d�R��m�l�v�`�����=x'L5�`���������?�y���t�UD&��������Qaj�=�\����!~�6�^�E�Lv��UVE�D������k�������{����d�{4/�N���h0��x�������B�����������k�e�����5��\������@��7��Y��K�%�G�����XH���n���'���2ZWXK�����5��������=��1�~��h]`-#��W�k\`-8�!q/x�{|/�i������u}�L��J\
�q}�������}���x+F�>���e�~$a�Z�/�~H��y4�|�3��������@u*q���{�����xE����bF������ZhN%�����Zp�C�6����7��������Z�o"�K��_������|3�/Y�����%��f��T���E��M�}���{��_��1�WW����n��/�~H�+_��jE�%��yw�����~������������P���d^^m���_j�=��������l�6�_2�1��W;��F���y�8�!q�|=�����~L������3����p�C�^�z�W�/��������`�k�_�����~o������d�c2��*�o%�K��_����W������KF?&���D�=��R=����l���g���7
��d�c�����+q5���U�%���c�B�������U
��W�k�_��+q�|������l�_��+q5���U��������J�bF�g��*�#�%�K����W�^�:�Wi�1����u�&�_���5����+q�|��4��Q�����J������Wi�������J3���V�Z�Wi���_��*-�]������Jh��u��_���5���r��k���'p��7M����u��o"�K������������������u�2�o&�K�������������-��Y�����*����/��|�oi����o���������W+�o!�K����wm����o��wE�]u�]���
�w%�K���
�wk����o��wC��t�]���
�w#�K����wk���go��wG��u�]����w'�K����wo����_������yu�����w���{������������yU�+�_��������z�W'�o��w1��N�����uu���M����<D������<����U�R=��7��!q�|����=�X�W9�������WGh$���c�C����C����1"_�A��_����W���U�;f�O�M��U�=��_��*�����u����bF��d�_��S���5��2.�H�+_��*Op>f&;4������W�k�_e���W���U��l�Lfh�u�ghO%�������?#q�|���L�Q?}7Y�Wy��T�j|�����3������)bF���d�_�������W�g$���c�3�/��I��U������q�q|F�^����UF�%4���*����/��|q{F�^�z�W��,�$��jE�-�������3�����Z��M6��V����/��|qyF�^�z�W�/�����������z��/�H�+_��jG�%�3�����w��T���E����;{�W�/Y�������{��z��/n�H�+_��������l�_U��J���y�8:#q�|=����L�d���D�=��R=��Wg$���gu�����l�_���d�k�_��W�^�:�We�1������*�W�j|����%�����_��bF����U	��W�K���8��k����_��+����U���W�k�_�1��k����_��WB��`�����+q5���UO�vM�]��2M�Q��b�_�	�W�j|���2��J�+_����3��[���2��J\��qUf�_�{���_�e�������,��W�k�_��W�^�:�We��Q��b�_��/�_��=�&��������*	�7��[������_��=�f����_���d����o1��2�of�k�_����_�������yU��_��jE�-M�M�������5��V����/��.|����&��jC�]����W��F���y��������_���������xG��S?�xG���<�x�8�
��|�����|4
8y6X��p�+��
|���pE�MN�VE������:��+q`��=���g���g�u�������:Q�O"���;^q�F�^;�X�e�l�f�n��>A$����Zq�F�^;�Xk��2W�C3X�Xk�O��6��V����W��5�����
��=��D�j��{�7h$�pv���q���$����ZG�Q%o;^���0��H�+`�"k�f$G��M�:A�*y5��M��+4�
���Z�3��x�u������T�{��{��d����a����ZhR%����Zq�F�^;6Y��aFro�n��M���7Y+�H�+`�&kM��l�&X7YkBN�G��=����vl�����h�u��f���{p���0N�H�+`�&���A�`�d���{p���0zpi{�g����E�`�d���+�`�&�h$��g����I�`�dm���`�&�h$�p�l�6�`�I���=x#L5�`����W��M���Fi�y�u��������{4�
���:���*M4o�*z�A<�jz�8H#q��=����fi�y�U��+�`��=�"����l�N�`�K���=�$L5��m@>�\��m��`�&k��%�����������������G�&k���Wl�dm<X�^;6Y[��xp�n��,y5��M���%��c���3��M�6N�y�q������
�����3��M�6�K^
�q��M���8�U�6m���u��� ��W!L=��DX�6;vY�\0$3a�.k���%�F�������i�ap,��TXR+�G�2k[@�%�F���������apl���.����m����qa��]��������2�p"2<Z�Y[F�D���� �Q�sS����g��Llx4��
�p!6Le���6\�6�B�����y�������{^Q�������Z��W���y��������� ��o�{VZ��F|x4��v�����u�����{vZ;��N|x4��v�����u�u��m����>|06������0���+�������iU���|��������0��.���k���g�u�W���y�u������� |��m���>�x	�O���>�����wZ;n�H�a�NkC�c�&�Nk�!"y5������5�A������!��E�u���	�'kF��=�n��mv���x`Hr|�d�i�#���W#l�i��\#q�;�}�0$9�w����JU��6��v����
����>��;����;�}�RU�j��;��k$n��c���p���Fl&�Nk��T��a�Nk���{%;�}�C6w6c3YwZ����US]�B����N��{@����!�)��u��'��D|��z��a#q�;�=��)�����3�p&>Lu�a\���
���VFfc6�y�U��3�a��=����m���
�0����;�}�����0.�H�a�NkEf�6�y��������� �[6�A���������l�im���a��=����m���v�a�i3�wZ;��N|��z�8g#q�=;�}��������>|0���p�F�6{vZ}������VE����;-���W��g�u��Y����:��O��T�{�E�� ��i���l�f����}�$>Lu��c��
����1���b�i|X�j��;�#�K�a�N��$>�XwZG��a�N��^��������%�F���:"����wZ����}xt���|XRk��;�c��a�N���xm;�c��a�N����%�F���:��}�wo����S���Wq1'Q����:fPb��A6����X�^�?w3}/�%`D"��u�u, ��W�k\j����}�V�f�'F$:�XWZG�/�a�J�H�������H��7�'&�����Q��a��=�f������n����Q�3Sa�:+�
g����{�-�������D����"����*(���0��|W������wE
^�'�*kE
^�SK��wC
^���C�{�n(���d^dm(��`��]��o����=�������M�5������z�������	?�D�^�
�N8��X
�A��y�
���1�	
� ����|���pE���WT�J8�WX'*pe
l]a�����<���|N���|26��*n�H�+`��p�f%�6!Y�Xu�O�����0n�H�+`��8i��a���[��D�j��[���6�
������d���� [�>A$������i#q��{�:N�Q?�7d���P�J^
�q�Uq�F�^;Yu��Q?�7d�"�N��J^
�q�Uq�F�^;6Yu0�~�o��MV��H��`�&������~�����s���1�![7Yu�~�f���0�H�+`�&�.;f�O�
����	�T��6n�*��H�+`�&�&�`2j�u�Uzpbl�dU����W��MV���d�&d�&�f���<����5�{��d�`2i�s�`����T��F.M~���{���d�&d�&kE^�SM��l$��g����A�P���
=x#L5�`����W��M��L�lB1o�v���x0���q�F�^{6Y;z0��	���:��w��T�{�!�{��d��d�&�&��������;6����g�U����M(�MVE�������36�
���:����M(�M��|����9��M~���[�x���[7Y�,y5��M�9�x�����f$\���3�K^
�q�u�`�{��d�1bF���M���%��jz�<X�^;6Y�8`F���M�9�K^
�q�u����
���:����+������?x�iD��x������o������/A^~��������o�����~��w�y���
��K���x�������?���������E���[y%�g�.�������7�%�g��g����HxS���J�L8�g0#���`]������6���x+��7Uo�$�c�w�����u�w������,|���MU��*	�X��e��������;W��*���|�x���o��@���\W�H^Y���s���U���}��oxS����X���S(�5����������|�{3�=����������B	�6/�vx� y��/w�|�������;&�H�Y����.H^������pA�^{�5bF���`^�U4���������+zpmz��Y�����y�y�w���?0�y3�=�lz��Y����'��`�5�:�	r�������_����5��_������u0n��~�	��Wl�d��[����`~M�K�
3�g�����Cp�=��y3�8����"�����H3�g����zISp�=0�y3�1�������~M�K�G��:7Y/iv<�_�|`��f����T��d�d�!�D�Q�&�%�
�'�k��z�
����"U�5Yu�G�H������NI���5�6=o<�p�f,R�_�U�%`F�]�`�d��[�����I��/+\��T��d�D:1#��v0n���&����E��'��������z����7Yu���I��=o���s��g�&�%zp&�����u~`��f�=�4=x�l�
zp!����\t~`��f�+zpi{�g�������y�����?��y3�
=xm{�g���o���y���o�?0�y7`������g���o���y�����?��y3�=xoz���d��;�`���.���C���<o|�M^<��=� ����|�������+zpmz���dU��J<8�7Y'zp%l�d���g���&�D>�[7Ya@>�[7Ya��W��MV
fdl�d�<X���=��y3���5=xql�B��
����
<X�*�����xM^����%����
<X�*����+^��;6Ya1#�`��f�#x��U[7Ya��W��MV�f$L_��x��
`�&+L���896Ya:1#�`��f����u~`��f�3x���vl��|`F����.��`���n�^��p���'�&+,f$L_��8�K^�u�zpjzprl�BBN����}�'���MV���������
=836o�2zp&l�d�������d���<���*��E���<��\��<��=��/hv����?0�y3�=xmzp�l�6���x0}A��
=x�=��9��o��[��=��
=x#L_��xG�t~`��f�;z���`�&kG���4�>��w�������|4=8{6Yz�A<����pE>t~`��f�=�6=8{6Y=��/h��\u~`��f�'zpmzp�l�N���x0}A��=��=��9�{�?@��g�&+�>O�5�����|�H^�u���?@�c���~NQ�/hv�D�*����*^<���MV�#f��)���.�#|�H�v��<o�D�^;6Yq�Q?�7�4��I��
`�&+�P�J�+`�&+�'f������.���Gi>0�y3�	�T�{��d�����y������M��U[7Yq�"U�^;6Yq�0�~^o�/h�M��U[7Yq���a��s���d��@�E?�7�4�^�I��
`�&+���T��d�����4�N��I���<o���S���c�3z0�����.�3zp�=��9������&�����H_�������MVA.M.�M��Lvk"}A��=x%l�d���k���g������H_��xC^u~`��f�z������dm��d�&�4����7��������7=�x6Y;z0�����>���w���y�u��m�l��`�[��]�����������G��=���Lvk"}A���\u.�M��\��*�D&�5�������"|�"\���E�l�p��q@&�5������8�	K^��u�5`��A���C��D��;�]Pa���.��*,q���1���0}I��8"a���m���%n��c�5�C2����dX�*����q��
��}�8n���u�5�`���/����4��k�p�q��
b��f�����[WZ���5�8���8�Kj
�u�5�`��WCl]j����WOQb�Vk\@�%�����Pb��!�������S������!���5� N��Iw���Vk�	�8��88[cF)ND���]g���K��}�5��V��V<���V���W6� .h�Y����Vk�����8xV[��-�/mvA��]�_�[����k���g�������k�}�������
�xm{q�,�6���y�y���o������xk{q�l�v���y�y�������y�u��m/����^|/�/ovA|����y�u�m/��VE/>���7� ����xq0o�*zqU����:��+�b�g�'z�I�8��['z��x�g�u�����+�=O~�����u�5�����"����4T��e�K�]���b�vk�]��@��nMa���iF����q����!�n�&\���
����W������}�����[�[n�H�b�vk����,�D�*g�#���WCl�nM�n#y���i��7'�q���]O��J^
�u�5����m vl��y�������������UG�vk����@��nMK��������������[�[n�H�b�vkJ��O�����.�x���[�[��H����4�|
��s������?��7��������_��D������������O%�}�������������?�}��O����_~IP~Ix�G&ga��o�\�\<�/_]�����������/�E�1^n���q6D�6~���iE� �!�ky�G��th+1�h���n���=��

�������
c#���>��
��e���A�Ch�����~�3�0��p9D�6{v}���EK������������ �Y�U�2 B{�.�+�Eeva���v��m�l�*�Yy�n�f�'>t���[4/�p<D�6{}'>t#"�e�Ax���I����=�<�37�� ������!�3���r3a�a������0��C���?�y���r�e��\���`��@�%�����c���T��n���A�%����o���7�K\��u�5�/^S�������8aD������G�a�������tX�^�>w#}/�)bD������'�a����.��	dX�^�>w}/�y���I�u�5���W�k]g�3�����}�&�f�#���Z�]F�KDx�.��DX�^�>���^����[WYs
��_�*kN������=&��oB	N���_���$����3Jpj>~����|3�o����]�f��L�w2��
�on?~�����
p��6]�Bx2o�

pi?�l�V4��0��^��Wb��y�����No������C�xC��O���
�)���������D�xG��O�����{�X;J��K0m�>P�w"��y�u�����-��|�Lk�.�+Z�A,x2o�*Zpm?���*jp%l^cU��J4x2��N����n�g�u�����{�=�dl�c-8"y��������3.d=�6	=/|�H\
�u���n���vl��G.d<�6	]������M���!���M�&k�f�O��MB�>@$����Zp5D�^;6Y�1�~F*m��H��`�&k���{��d-���Ri���E���[7YN�H�+`�&k�*f��G�MB�sD����a�n���W��M�2��Q?�6	]/P�J\
�u���\���vl��e������I��T���n���W��M�����bm�N���x�l�d-8"y����%����$t���3�`�&�B$��g�U���Zm�.���y�y��3!��
���Z���Vm�^��W���y��#!�����g������$t��o���&'B$��g������$t��o���&B$��g������$t|�����&�A$��g�u����$��|^��,��W��MVE&!�I���W���y��� ��
���:���>m�>��O���y��� ��
���Jz0Y�MB�i��`�&+
����
���J!bF���MV
��Wl�d�,y������{0m����Wl�d�,y����+f�=�6	]�N�MV��%��t�&+�;f�=�6	]O��Wl�d�	<X�^;6YiZ1����I�<X�j����4�x��<96Yi��
`�&+���Wl�d�%��kz���d�<XB+������K\
�u���/^��'�&+�	3�L��.�zp"�������S��'�&+e���{0m�����xp�n�RF�M�<������7Y=�N�MVA.M�<���\��7Y+zpal�d���k��=��=x�=�6	]o��+�`�&kC����dm������I�=x#����=xkz���d�������I�xG��g�&�@��<{6Yz��{0m�>�������:������MVE>t�MB�=���MVE�M�=��=��L��.�O���xp6o�N������c�����P�`�$�����`�&+�\���vl��pbF��"�$t&L��u��q�F�^;6Y9�Q?��6	]G���`�&+�V���vl�r�0�~`/m��H��`�&+�X���vl��X0�~`/m��"U�j�����k5��
��������f
m���H��
�b�de������c��g8O3���$t<C�*q5��MV���{��d�e������I�x�"U�j������5��
����)`F��^�$t�����b�de\���W��MVN��d��6	]g��D<�X7Y'k$��g�����p
m�.���xp1o�p�F�^{6Y=���&��=�.�MN�H�+`�&kE&�5�I�=x%\��,����W��M��L�kh�����16o�p�F�^{6Y;z0��MB�;z��<������{��d��d��6	]������]�>�q�F�^'�&�����$t\�����q0o�p�F�^{6Y=���&��=���&'k$��g�u����$�\��S��8X7Ye��W��MV6��{0m���Wl�d�,y����
f�=�6	}�K\
�u�Ub�������d�,���MV���Wl�d�q�������d�<XB+����2�K\
�u�U��������*���[7Ye��`�&�L����
���*s��d��V	]� ��W#l]e�DX�^	;VYe>1#Yp�]B�����	�.�,`���B8;vYe90#�p�eB�	TX�j�����P�SS��c�U�p�U8�6���.���6�dt��t���f��.�u�N�Ce8�uVA�M��uVA.��'t!\����`�g�h��i����Z��W��-�^Q�W�����ZQ���g�BkC^u�Q�BxC���FkC��>�=�}xc>l^i���;��`^i���{���g�������;�}xg>l�i��G��=;�}� >L+�.�+���|�����������VE���i�����>\�G�N�D>�>\<;�}�$>L+�>���O�����Zq�F�^	;vZ��k�l��V
=�|�H^��u�������v����k�l��V
]���a�Nk��{%��i���\��
����!"y5�����6��J���Z�3�|i��������[wZ+n�H�+a�Nk�f$'��J��	JU�����V���W����:����K+�.��	��k�h�i��b#y��;�u>0#9��V
]/P�J^��u�������v���e���_Z)�!����[wZ+��H�+a�NkM��l��V
]'��D|x���V����ap,���B��lh��qF!�D�G�R�l$o�g�U����
-� .h���h�j����m ���VTb�iC[�.�WT��(�h^k����m ���6tb�jCk�.�7t��8�h�k����m �,�6�b�kC{�.�w���H�h^l����m �l�v�b�lC��.����X�h�l����m ����b�mC��>�Q����y���6���������l��V]W��������a��@�Yn���l��v]���'�b�rk��O����m/��b�vk��%��x�n�����k{qpl��0bH���[��8�K^
�u���b��@��nm1`H���[��8�K^
�u��E�b��@��nm�����i���8"b���u�������������C/��B�x���[�[�^,y���m�0$�b�-�A^,y5����6Ox��^��m/��b�vk���%��������W��������bI�!�n���X�j����-
x��^��-�'���������b�vkK��I�b�vk����x1�� ����y�y���������VA/���i��qA/.��g�v����G�v�����[��xE/.��g�vkE/^�^=���x%^L��.�7���x�l�nm��[���g���o��i��1z�F�x6o�v�����������w���[��xG/�������^���8z�[z�A��v]����������G���g�U��+�b�-tA\��+��������������:��+�b�v�D/>������^|��8:�[��2/�n��>G$������qG�6;�[{0$����B�>G$������qG�6;�[{��,��n��8"b�P��X�[;��H�+�������!�&,�� �_��b�vk���@��n���!�*,�� �~U�j�����p$o�c��Op8�N�p�� ��_��b�vk�)��@��n�3����A�@��.�g�W%������qG�6;�[�2aH��@��.��W%������qG�6;�[{�R?8�n���^��/����k8�������3z1��	�[��8�g���u������4������+�g(O�������Z/t�\P�3Sc��'q$���S��7.(�d'�r����016��pG�^?uC}3�����Z-��Z�-N���H���n�o���Q�@��.�7���Hq2��pG�^?u3}3���l�Z+t���D��y��s8����[��(�d'�R���� B��k-\����O=&�pE&�8�V
]W��Jt8��Z8�#y/��zH|3�e��Z(t|��D��y��[8����G�wF&{8��	=z�I<8YZ�,y'��>�32����",y5��}�@�%o�-&G�a�������#�	K^��u�u��^��c�uDPa	��eB�TX�j����cx������Gpa	��n��\X�*��u�u�'^���a�:��&�Hd��	]O ��W#l]g����v���9bFb��O�Bx��a�>����%���c�u,f$:L�.��a���.��tX�^	;6Z�R1#�a�(t!�F$L|8[7ZGBNmv����>���J���>��g�J�������������3�aZ)�!�>��g�N����?w�����pa>l�i��B|8�wZ+�pi��sGz�LxE^��wZ+���|���Z����?w����7����0�����7������>�5}��=n&��o��i�����>�.����>�7}���<n&|����i�����>|.����>|4}���<�&�>|���S�s�~/���*�������?������������������?����|����}��������\������w������������|��Q�%�N`5��mr�~�/_]�y�f�����=�����s�]�T8��5��Kz�5L���j��$o;�#[����#����v�k<1�����0]����Y
��v.q��[�:�QW�@K�.�'8�M�*��y�<��K�+`��Nf�
=����r��
�Z�{�������cX��uA���Nr��
�n���D�xx��s���$������&y�t��N^<<�����p�gIZL�.��n.y�T�7�x��X���?G�y�����@��.�3���U?���8���?w����zp&\���Z������l������?w��������b�������Y����6=���Nn������y�����?�z/�
=xkz���dm����b�d����������xG����d���;��b�d�������l���@����d����b�d������,����M�<���\��7Y=���������k��'�&�D������=��=��5�{���g��'�&���O��m��s��
`�&���%��c�u'f$�����3L�x�u�u�`�{��d�����+��u�uF�`��������#x���vl���aF������:G�`���n��<X�^;6Y�X0#���`�d�#x��U[7Y���5=xrl��	<XBk����s��
`�&���xmvl��<XBk����s��
`�&��+^��;6Y�2bF���`�d�x��U[7Y�,q/�g�&�L32�n����t~d��^�	=85=xvl�����[7YgFN�?��y/����<{6Y=8�MVA�������\�<{6Y=��M��\��7Y+z�������Z��W�����Z��W��������6=x�l�6���xp0o�6��M��G?���oM�=��=x'���=x�=�������M�=��=x'���=��=����{��G��=���|�MVE��?��y/��\���dU��J<8�7Y'zp�=����{���g���&�D>�7Y�0�'��{�#;�w~I�����W�~M�K�3�����������e��g�}���zI�����z��8l�?F>����4'xD�'����s�^<�y��sd��1�)`�&�%��#���	`�&���?@^���	2�X�~
���zI��h�%�#����xX����9�f�8a��)`�&�%M����	`�&�%L���E����#�y��X�~
���z���|9+���M�K�.��E����#�%`F�S?l�d����������z	���[�H}���|bF�S?l�d�C0V�	`�&�%zpj{�_��	=8��M�9d���{�#�����������z�����7Y=8�������zpnzp�l�
zpal�d���{�#���^��K���g������G�&kE^��7Yz������dm����������7���M���5=8y6Y;z�F<��������������w��������:��w���D�.���C��G�=�|�MN�M��|�'2w\�������pE�MN�MVE������]���U��G�=�|��m�l�N���x0=��`��S��G�=o������MV��%����
x��U[7Y!D�xM��MV��Zl�d�,y��MV�^��g�&+D�`	��n�B��
`�&+��������
��������%����
#x���vl��0#�`z"s�x��U[7Ya��W��MV�N�H<�����<"`������,q����0��x0=���<X�*������:\�������
��������
`�&+�	/^���c�zp"LOd�8�'����D�=8�=���
=8�'2w������tQ�������d��B<����pA.��E�>���K���g������M����L%�^�����&kC^��7Yz��{0]��xC��\<��
=x#LOd�xG���7Y;z������d���;�`z"s�z�N<���:�����&�@>����F>ttR���"|4E�xVYE��G2w!\Q��.��nJt!|�	��	�.�D>�	�3��>��O����A8�r6U�8�Yq������5��eV�CD�j�����5�y����&���U���]���a�:+�n�k�+a�:+�����"=���"�W#l�gE�y�{!�r��x0�~lo�3wA<B�*y5���V�����
���V+�����h�.����E�-�1����m v,���cH���Hg��x�RU�j��[��5�y�k�8�R?�7���� �ZU�j��{�6�y����dIfl"=����U�� �]���k�b�f+&�b2d��]'��D��nL�A�V��V�r#��8��)�Hi��8�g��te���Z��Z�r#�����1�H�i������tg���^\/�,�V�b2g�A�]���+��`^n����������^Lm"=���
�x%^L�&� ������vkC/&�6�����^�/�k]���{���g����Q�H�k���x'^L�&� >�����v�@/&�6�����^|0/6o�*z������nU�b2l���]W����������������:����M��6wA|������D�'z������n�z1��������X�j����q/��
����I����q/��b�vk��������C�������]�/��]G�b��@��n�q�������]����WCl�n�#x��m vl��q�������}�K^
�u�5N#^��G�vk���%�����'�b��!�n��9��k{qtl���XRk����q/��b�vk�O�zm/�����L�x1=����X�j����q/��
�����"�$^L�q��8�'��������S���c�5f��D����qF/����E��8��8z�[�8/�G9wA\��3�b�E�qA/.m/���VA/.���a�]����x1]���xE/^�^=���x%^L�s���x%^L�(� ���W��=��
�x#^Lt��xC/���E�.�w��M�b�vkG/���#�� ���w��t��b������g�u��������� ^LW)� >�������VE/>���[��/��]W��������:��+�bz�s�'z������:���������^|/�G;�@<
�9r2/�n�&���
�=��i��N���a���|����?���������������?�����������J���?o?|�O�	x�����x�������?����������L��$��n�0����������������������GR~G��<����3�k"���3�X�M#�u8�M���s?�����J�j����	�D$o��c�7Mp��DFE��]OPTI\��u�7�����4������+�� ��W�<aN�@U��E�3TUW�l]�M�)"y/���{�.#�����/��]����_��o�I�{���]��7
���@Ep/�r!q5��E���"����9���/�Y��]t��#����t��_�����F��7�Q?J����o�zJ�j|�+�	�D$���s7���-+F�7E�}�����@�:���9�{�����{����dR��m�����2
6/�pMD�^�>���^�J0Y��Zt���oD��ZG�(�J����{R~/������,����w��t��_����sl(�dP��e���|�c]����m������A��E�
��[]����m|��0*0��oXt|�W��t��`\���'
��Ot`2'B���x��O��t���y��W��%�<��Q�`�vE� �Wl]b�a���~��b�,XB+��[�9�K\
�u�5����0����#h��V[�Xs
��`�k�'^��?y�����	3�L���x��`�k��%��c�5O3�L���x���wM���y��W��M�<�Q�`�NE�3x���[7Y�,y���pl���bF���]/��]/����
�����3�L���8�K\
�u�5'�����'�2�pBN�����9�'��t��������I&�����x�y����3�`���pA�M~��{���{0}q���\��U�>���K���<��^�+zp�=��7������]���k����M����L_�xC���7Yz����'O0�����L_�xG���7Y;z���`�&kG�u��t|�����G�z���`�&�@>t�/
t\����t����\����%����U�`��@����x0]���D�M~���{���������.�O���x0���x���{��d-W�����@�� Wl�d-8"y����%�a�Y
�/t�D�j����'B$��c���3����7���"q5��M��!��
���Z����P��]�P�J\
�u���<���vl������Y����.��	�����0��H�+`�&k�����J_�x�"U�j�����A$��c���f��A��t�@�*q��C����A$��c��,3����W��"U�j����gA$��t�&kI��d��:�pBN����F�8
"y����%��e��@�=8��}���O�MVA&� ���.�zp!L7��A�{��d���d��:�����{]�����l�V�`�	B_�xC^����.�qD�^{6Yz0Y��t��o����F�8"y��=��=����W�>��w���M�H�+`�&�@&k ���>������M��H�+`�&���-��@�=��+]�����l�N�`�B_��D>����>�������MV���}u��4�K\
�u���`�{��d�0������.�x���[7Y)�K�+`�&+�3�n�R�0��b�d�,y�����H<���J#x���[7Yi��W��MV7��{0}u��	<X�j����4�K�+`�&+M3�L_�<X�j����4G�xM���4�Kh�u��f�`���n��2��kz���d�<XB+������K\
�u��������MVJ#f�=��:�pBNd��]�>�zpj{�c��2zp�=��:�pF�d�}�n�RF�M^<����u��t\��3�m����\��x6Y=��L_�xE.d�}0o�V������g���������
=x%���y���oM^<��
=x#l�dm��Yl���=xkz���d���������.�w��]��8�7Yz�������:������]�����q0o�������g�U������]W���<����������g�u�W����]���'�`�&�D>���d������������ '��`�de����W��MVN��TD_�8����[7Y'k$�prl�r80�~P}u�� Wl�de����W��MV�f����� Wl�de����W��MV�<�L�k��]�P�J\
�u��q�F�^;6Yy��43���t<A�*q5��MV���{��d����d���:��E���[7Y'k$��c���3���W�^�H��`�&+�d���vl�r
�Q?���:�p��`�&+�d���vl�rB&�5���.�3zpbl�de����W��MV���d���:�pA����y���5��
���*��d���:�0zp!��,��������Z���p
}u��=x%��,����W��M��L�k��]o����h�d�d����l�v�`2\C_�xG��G�&'k$��g�u�����@�z�A<8�7Y8Y#y��=�����k��]W�JD8�WY�Y#y��=���"��k��]�h���p4��p�F�^	{vY'�0���o� \T����u�UPa�{%�Xf�a��d���>��0����[�Y%Lx��.��f�.,�5��uV	 ��W!<Z�Y%F�zmv��J��a�>�D�a������8��k�pq���6,�5���VA�%�F���*c������Xh�i��d���B���>,y5���V���%���c�U���[WZe��a�J������J���*���[wZe�0�����*����v���r`F���-�.�����[wZ%����N�$��D|��F��0�p"><ZwZ%����N�d��L|��G��pF����;��>��>\<;��>\��	�.�����y�����{vZ+��J|��I����>��������o�����|x���V�e����3����_|x����_o���(�����)_���a����g�/�(���������������W�|���?|�������?|��'��o?����n�c���bZ�aF4�M?z"�w��Q�xh�9{b�_�A�}���<{"���D5���'}����x'�OL��7�W��5O��i�!t�]?~"��� >��r����~�xp���m 6�� dE9>�(}����r\�	S��
��	��������h�U?�"�w� >��+9�b�_�a<8�Q�6�6p���c����W������
������k��!��u80$)Y��]��������0|���e��O��
C�����1|�H^
q�����z������q��u�,�|��	���sD�j���p�m���������G�Y��������pzV�� �������z�������E�zY���u�������[�[+.������O��#�$�<�/BtA�7�WCl�n��q�^6n>>*vD�I�zD����Gn$�����Zq�f���||V�������G�U�.�q�F�j����wn���������z�e��S�����C7�WCl�n��t�^�n>>-vD���/{7� �/C�A�^�����n������Oa���������-���b�v�n���������W���������-����b�v�n���������7���������-���b�vo���������w���������-����
�������/�7��:">��w�����.�q�F�j���-\�Y/�7��z"F/�l�|��������!6o�p�f���||
����_�o>El�n�������[�|�^�o>>�uD|�_�o>El�n�����[�[��^|������6�Kj
�u��
���WCl�nm!��k{qtl��^,�����.�x���[�[[����8:�[[/��b�vk����WCl�nm���k{qtl��q������]����WCl�nm#x��m vl��)`H���u�.�'�b��!�n��	�X�6;�[�tbH���u�.��/N���6�K�b�vk�I���n��^,y5������K�+������
C/���A^,y5�����&�zm/��-�'���u�.�zq"^����-����������3�b�vk����xq2o�
zqn{���n�������*���xq2o�
zqi{���n����x1}����x%^�����xm{���nm��+�b��A�z�F�8��[z����������7���u�.�w���y�y�������{��7����|�eD5���7�P>P�w�����j|4���[��� ��A���o�0��A�8��[��h��s7��^��Z\���
�����hq6/�N������n����'J�I���k���R|)������8������[��>,���_�q>l]l�8�#y5������8�e��d��J�{��~Q?�(����]�����v���/�8?'{�1��W0F��v�[]�,���[�Z;����Y���=����+8?E>L�1�Wq$�����qg�������G�7_���X��u���(���[Z;����Q��\	O;f���
��.�qG�j����Gq��(��[L���3����~A�P�J^��u���(�~�y�&�#���/�8��.�v���
�b]f�8��_Fq^;8N���e�O	[�Y;��H^��u���(�~�y}��H8�_�q>%|[����{��g���_d��_����������� /���o|������������������?���R�����������/�$(��������{�mx�t�����_�o^�|�7�����*v������U��T��$IBk*�;�o�v�)�#�������j�;������0���:��1�>�����"=�jz/�o����������G�����p���?Ezd��^���*�W�u���3���}����N����l�������1�u�����G������1�C�S�Z�#���>x� q�_�q��a�����@���8�C��~�>�^��1H�+`��+f����;}�C��~���p���3�X�V)�5���A�%�����^�c�����'?��
���Zl��#x��m�{d��f�'^��?y���Wp�0#�`��E�x��U?���x��W��M�1G�H<��{��,y��M�1�K�+`�&�X��<���:�`���n��<X�^;6Y�R1#�`�&�H���<���zpj{�c�u$��D<��t�pFN�?2z/������d=8�/]���u~d�^�=87=���N���=��/]t\��������xE.M~���{�����/]t��������=xmz��G��{7���x0}���
=x#l�dm��[���<���+��o���K]�������L��xG����1'�^�=x'L_���@>t~d�^�z����'9��
����K]W��C��G�@�\��k���<���+�\��7Y'zp�=��1�{���g��G�&�D>��7Y'z��{�#S���~��mvl��oJh0}���:�'��U[7Y5D�x�����p�7%�����>A$�����q��� ��Gx�PBk�����D�*����+^<�y}P�x1���r(�MV�I��
`�&��P�J�+`�&�N3�o.�b�d�	�T���n��E���vl��tbF���P���:OX�����{�P�J�+`�&��f��[����4��Wl�d��T�{��d�e���k��X7Y5A�*y��MVM���
����	=81�n�jBN�?2�y/����<96Y5�g���MV���Y��Gf?�\��s��=���\�^,^�=����������K��=��=��#��&kE^u~d��^�+z����������Wr��`�dm������~�xC��<{6Yz�F����=x#l�d���{��g�&kG���]�y�u�������=�hz���d��9�k0o�*z��{�#S���������g�U��+9�z0o�*zp�=����{�������g�u���(����:��O������9��M���s��`�&���%����:������c�u�32�n��,y��M���%��c�u����&�����Wl�d�<X�^;6Yg<1#��`�d����u~d��^�#x���^��s<0#��`�d�x��U[7Y�,q����s�0#��`�d�3x��U[7Y�,q����s.��xp�n��<X�*����s�x���86Y�,�5��M���K�v�GV=���xM^��3�'�����:zp�=��U�����/�M������`�d�=8�������3zpnz���d���<���*��E��GV=�\��K���&�����M��\t~d��^�+z���`�&kE^�G�&kC^u~d��^�z���`�&kC��G�&kG�t~d��^�;z������d���;��h�d��������z��@���<��=� ���=� l�dU������������xp4o�*zp%l�dU�������d����xp4o�N��S��G&=�|��MNnMV�a�+H<8�6Y?���'���
`�&��0����
���z�f��)�t ��0���I�����5�^�5Y?E:1�~NQ��M�K�8"`�(Mz�D������
����)����zc�m�^��G�(Mz�D������
����)����z�T2|�Q?J�0���'k>��vk�~�X #����m��S�O�Q����.�=Y�1�pvk�~�� #���t���y��~�&=`��_O�|�{��d��q��d�&�	�.����(Mz�D�/����3���F:��pBN��m�������g�&�%RF&�5�N0w���3���'Lt!�Q�sS��g��Q��pM��]�L6%�]4��4���e4a�\�s�+�p!����.�WT�������ZQ��tM�+�}�
�dU�2����.�6]8{�Y�0���t���
]x#����.�w���-��u��2L�k"�a�BxG���=f��mxo��g�u�
���H���>��2,A���Cu�h�p�,�*�0���t����:\��"=h���>\�>\<�}���D:�����>|26��N��������:����M�[�=��#a�������������v���p`F��t���>,y����.�����v��B�0#�a����0����[wZ!Nx��>\;���%�F���
|X�j��;�0F�zM.��V��%�F���
#����[wZa��5}�8vZa��a�N+L���W#l�i����k��c��3���]����W#l�i�|X�^	;vZa	���0�d�Bx��a�N+,����B8��VXNI���2wA�FDL���9�qB!NM!�c�q"FLg�� �h���u�2qnqk��Q�3Qb:��1*qfJl^kT��T�0x�Z��'���]t�B���<���N\�N�bkE)^��q�.�W���H1={��
�xmJq<��
�x#VL��� ���7b����>����������Q�7������Z�-��OtA���M-�g�u��������� ^LO����@/>/�,����x1i�������]W���x�g�U��+�b:����^\��S(� >�����v�D/>����>���O��������#g���c����!#���t���8�����[�[1�x��s��SlG�!CH�p�Xs�>G$������1���������B���H��� ��9"y��4�>�O�z�9��9�#�q������6wA<B�*y5���V�_��
���V�"�����t���	�U��!�n�����m vl��<`H���HG�� ��_��b�v+���J�b�v+�C�g�F:���2"b���@O���x�~U�6;�[q�1�~�o���]'�W%������	�X�6;�[1����H��� F/N����]g�������n��^Lob�n�bF/�����]�������n�b�y�|s���0/6o�
zqi{q�l�V�b�z��s�+z������Z����G�vkC/&�7�N8wA��o����]o��[���g������HG�� ���w���t�.�w�������������M�3�]��;�bz<E�z������n��d�&�!�.�+z�A���O�qE/�m/���VE/&�7�N9�A�^\��*� >���������^Lp"s���D/>��*z ��S�b�vk��%������b��!�n�������������!��A�.�x���[�[c/��
����#�$^L'�� ����WCl�n��X�6;�[�8`H��t����X�j����q/��
����8VI���:wA<���x1=���	�X�6;�[��cH��t����X�j����q/��
����8��x1�v���X�j����q����xtl���XRk����q/��b�vkL�z������+��(��^��j��[\cB5ND��Q}(���?wK}/��b�����.�3�q&bL��8���?wC}/��Z�����.�jq!ZL�������?w;��i��
N�g���R\~��?��7��������_��D�������������$�}������������x�������?��������s"��v��������������������{�w��p?�S;�����{�/���{�J��.v�.����P.v&�E��r�7��9���
����$�.|4����y�W�,�������{+JE������oE���)�a}��S��S<����+x�ST�)��]���'Q
zRG�'*��T�����z�a�+�+=���i�O����.�&�����l����b���]����`�jo�E��x��p0�~V=|���Wl��M8("y�i�\1�~���|3�1"`�T�@���D$o���#�q��������.�'��$�����pND�^�����+f�OO��.�_���`�k�5�{��bM3k8�Iz�b�3|IC�j��[�	�D$��c�5-p��DE���]/P�J\
�u�5�����v���4aF��Tz�b�	=8��rt�C"��
����2z0Y��-v���3�`z(G�8#"y��=���L�D�a�]��B<���0��H���[<���L�D�Q�]����x0=��`���W��M��LvD�A�]o��+�`zG�8 "y��=��
=����c�F����8����{��d���dC�������Gqt��!��
���:����=b��=� L��=�hz��g��{	+z0��,v\��+�`�&�C$��g�u���z�b�'z��<������{��d�z0���+�<��W�>�u�5����
�������[7Ys��x0=���,y����9���x�u�5G�`���n��,y���86Ys\1����X�>���%������/^���<���K8�Kh�u�5���Wl�d�S�����'O/��N��Zl�d�x���[7Y�t��kz��g��{	�	3�LT�x��`�&k���%��c�5/3�L�S�x��`�&k^��%��c�5�3�LS�8�'���M����S���<���K��t�G)v����`�&k�������g�������� �.�zp&LO������{6Y=�6o�
zp!LO��xE.m�l�V���x�y�������y����M�<��
=x�=������.�M���5=x�l�v��M�`z�b�;z�N<��7Y;z�������:��w�����]����b�d��G��'�&����������xp1o�*zpmz���dU���{0=7��=�.�M��|6=x�l�N��S�`znb��� '�`�&k�A�{��d-���c����]���`�&k�9�{��d-�`F��"zL`��"q�#b����@$��c��D8�!� ���.�#|�H\
�u������vl����\�=(���T���n�����c��L#f��@�I�]OP�J\
�u������vl��9`F}���E���[7Y��H�+`�&k�O���K�
�x�09��n����W��M���Q?����p��`�&k���{��d-	=�L��������,�
�M�����
���Z2z0��g�����7Y��!y��=���L&@�Y�]���<������{��d������_�7Y+z�J<8�7Y+z���`�&kC^��7Yz�F<8�7Yz���`�&kG���7Y;z�N<8�7Y8W#y/��&kG&�5���.����xp0o�p�F�^{6Yz0Y��gv\����������{��dU�`2[C�
��D����y���5��
���:���n
=+�`���x0��8
��g���&+
��Zl�d�<X�j�����xM^����%����J<X�j����*^��/�MV�#f�=���p��`�&+E�`�{��d�1`F���Y�]���WLw����%��c���3�n��4!`��t���	<X�^;6Yi:0#�`�&+���Wl�d�<X�^'�&+�f�=����,q5��MVZ��%��c����u�g�,q5��MVJ/^���c��zp�=���pBN���nW�=85=896Y)�g���Y�]g��L<��v�����<����u�gv\���`���pA.MN�M��\t�gv��������=xmzp�l�V��U�`zV`�z��<��������'�&kC�t�gv��o���nW�;z���`�&kG���7Yz�N<��vu|�m�l����x�y�u����nW�=�hzp�l�*zp�=���pE����nW�'zpmzp�l�N��S�`zV`�'z�I<��v��|6=8;6Yy���L�
�8�"q5��MV���{��d�0bF��"zV`�>@$�����8Y#y����f�*�gv�D�j������5��
�������������.���'iF���0N�H�+`�&+�f���gv<A�*q5��MV���{��d�i��������>��H��
`���0N�H�+`�&+�p�f&�5���.�g(R%�����8Y#y������y������^�H��`�&+�d���.�MVN���
����N(���0��CE85E�8VY9���zZ`�M8��]]�h������
�0����v!\P�Qa:���0��H�+a�2��
��z^`�+�p!.L������{%��f���l������2���]]�n������6�a�^CO�Cmxc6l�g�p������v�a6_C��BxG���Z�\#y��=�u����3�>����t��a����W���VEf6���.�+�p%>L��F�m���N�a�`CO
�B�D>���.�q�F�^����*
1�����@\b��!�.��B,y�[�2��1=9��0"bb�t���F,y�k�I����q%��b�Z�DPb��@��k��aH�����>���%�����*��W���ap,��R,�5���VA�%�����*S�����086[e+��b�f�L`��WCl�l�y�����08V[e-��b�j�����WCl]m����kjq�����x1=E���X�*���W�x��m v,�J
�y�u�Uzq"^L7�� N��I�b�v�$�������*�8/��^]g�������ne��L���%�qA/�����W�����8x�[��/��	�A�^\��e�.�W�������n���+�bz�`�+z�J��n{uA���m/����^�/�'
vA��o����W�;z������n���;�bz�`�;z�N���{�A�^���8x�[z�N���*���^|0/6o�������������bz�`���2/6o�*zqm{q�l�*zq%^LO���D/�����W�'z��x�g�u�������u����x1����x����@��n���!���=]���#�WCl�n�8r#y���c���C�gz�`��9"y5�����37������Z#�����@O��8�����[�[+�H�b�vk�����z�`�#���WCl�n�8u#y���u�0�~�o��vA<A�*y5�����c7������Z��!��~=g���U��!�n�V����
�����R?�7��� ^�_��b�vk����@��n�K���y���5�q�~g��_]����m vl���^L�o=m���^�����.�q�F�6;�[kF/&�7��7�1zq&^L��� ����@��n�b�~���]��B���uA��7���x�l�V�b����]���+�b���1z�����������N��vA��o���X�8~#y�=����l�z�`�;z�N��n�uA��7������:���
N�vA|����
X�8�#y�=������z�`��� ^Lw�� �	��@��nU�b�����]����y�y��#8������:���N�g�A�^|2/�n����D/���?�y�������
��\�l]pm���U(�A�.�C���T��n��@�%���������[�[[8��5����{�	#2-����q����3�@�%�����|��_�y����%���������������/����?o?|�O��r)����o�}���?����_�_��'WT~I���Nr�~�/_]�y����o����{�P,pw%�������?��(��?���.�-po%y��
]��{���[���=���MF����q�]�&��J�;������7�MU�����='���#������.|3�Te��GfB�����*�=����{�~/�2`D�E�@Oj����=U��>|d%�^�o�
>i�9�s�o�[1���s��4v��F���z��H��|Wx� q/|�{�~/�u���+�������$������^�<c����no+f�_p���>�����g��8����o�T��Y�*�3���EA�+B���4I������O~i���|"��#��3H�����M=i~0����b^e�=\��<43���7.���C��8y�o��<�5�>3B�.�Dx���w�A	��]��r���&������
��t��Mxg��<��,8���t�a�g���v�g������J�^���lvf�����Ew�}f��]��N������t�����������1x�p������Xc�Dp���0��-d������1��%XO�L
��9.�]/��Xc>�Q�O�fO�(�p������X��"��~c kt��tnvd�������,p�@�X �*��~c$k,:2������g�H^e�SG����x��J�������R��N�KDR�WY������h<Re���+�)Z[�����B$Ux�N����c U�����.���s�c��I�m<���a�F Up���H���d������1�7����
v��������I���~���1�������v�[�������I�n���l�`�����V��}���]��~p����uv�;������,pO?���`���a���o��;;��]��~po��f��8L?���`���ax��o����d
���6�/FY��~����>A�.�H?x��������l�^���#��Q��}��^`�������I�����lv^���������G�&�������I���O�l�]���3������G�f�������I��<[~p�H�B?x��`�I�ax��l��;���]��~�b���#YSF?x��`�9�Ax���z��������lv\���9�`�U8u$k���z��������l�[������WY�����9o����$�;���-p�H�������#YS��x�~p��H�T�hm�SG��~��*�:�53����1�5�
?���e�K����,p�H�T����1�5U9
?���e�+����,p�H�T��uw�7F��j!���]�,p]r�
?8u$k���z��������l�X���
�`�U8u$kj�7�~p��H���n,?8u$kj�7��3�3�����M?�|c$kj����<���nu?�g�g�����~p��HVG?�3�`��b���w��3�3�����M?�|g$���~��Z1����{����x����~p��H�@?�7��.y$k�<�~�����<�6�������~�`��]�H�H?x��`�Y�ax�<n����d���G���G�&�����L�����i�~g$k�<~p�<�5��t?�g�g�����~p��H�L?x6��.y$k�<~p�H�B?x����wF�����w�#Y�����SG������Wo�d��i
����#Ys�Dx��|&|�]���x�@.55o\��4Z[����9�
"����d�n\��������OS��-�,�8�p�����#Y��i<^ ���7.pQ�Qo�������@$Ux�N��Rw��o�d�eNF�_��RG���T�U8u$k.H���1�5��~�.K����������v�+Rw��o�d��DF�_��RG���T�U8u$k���]/�#Ys=�Q��������F$Ux�N��9�FpW\�1�57����5.K��������d��W#��~c$kn�Ck\�:�5���[�N����]/�;#Y�`cj���G�:������������M?�~g$��l��qY�HVO?���`�Q�a�#kw����d
����5.O���l�M�,0G��z����sk\�<�5�t?���DY`�����3�5�6���<y$k�<�~��7���Y#��~g$k�l��qy�H�D?x��`Soe�9�Fp���H�L?��[������~������$�sd��������~�1����#Y��E��M�I�^2������1��d��Z[����%�,����d-�L�m���#YK^��������%�,����d-9�`�]/�#Y���h���#Y��,�����DYaGXx�+��P��2Z�p�P�R\ac���8���<a�]��cYK1����]�X�R�^m�S������W������h��.u0k)�
�����YKU�z��p��h�R�hm�SG��
���j+�:������t��7�����@k+�:���p��W[�����gN�m{�o�g-
�����]�x���nto87e'qV��p���1���t��v�ZKKw�������DY���p�����hu��[�v�#Z��������:����?��3�����%i���;�N������p���VO�����1���po����$�
���M�}gLk�?<X�p���@x0�aS{e�G����?��3�5�
�H����?l�O���Dx����w��&�����cZ�����M�I���O��p����Lx6��"yLk�?<��)?������M�}gLk�?<�p�<���^���DY�������/��g��	
�H�:��_"^m���N4����w����i�Y��Qo\���1�^������%�
c���w����bZ'���z�"W$�i��+��FsMS�e�1����^����NH#���H���"�
;���)A���cs�]���bZ'���z_W$�i�h�pa��4%(QVsl.��~_L�����f���1���.����%�
c���w����i�k0�l\�8�u�����`����Y���cP�Rj���K2�m|]�8�u������a���DYa�����W�}1�<k�>��L�:��n���DY���p��w��i��K���@W&�i�����?lJP��pK������j�m\�<���n
���DY���p���3���6F��2yL��?���)A���=��~���w�z:��PW&j�t�{�!N����q��3�5�#6���2yTk�G<Xq���H�x������a��.�1�����Z#]��p�MJ�%�K<n��y����D��m���q��>�d���%�O���M�8������m�-��.�L�x6�bS�e�g:���S�g��l-����6�J�Z�/�Wl
Q�,�B�x���������n�1��U�C[�K�Kl���%���b��X�7��Nw/!
��J��s����-q��V��/��%~cp+�{B~q�:������W[���������1��;��B�-q��V�������[�7<����o�n��|@�_\��n��b���8ut+/Zo�/��������_\��n�%�b���8ut+/����1��W���_�:��W���WYbS�e�+������o�n�uFH�/N��k����-q��V^�/��%~ct+�gB~q�:��7����MEJ�%n�7�~q���V��/n��N��[�������(K��/n���������_�~q�<���/n
����DY��~q�����nu��;�/��G�:�������(K��/�������~qo��u��VO��7�bS�g����_����@��7��:ytk�_<~�)J�����a�/v��n����/��G�F����'�n����m���3�5�/
��N���O�_�<�5�/���b����D�x�������~�d���(%�����m���3�5�/�-�8ytk�_<~�)J�����e�/v��n-���/n�G��������K�2�#��_���r�}W������[~��7��MQJ�%�����1����� ���n����jK�:��0�����o�n9W������-�p������[Sp.�K����+JB��]�:��
�W�W[���-�18��%~ct����z�_���n��U���8ut�a��w����[���w�uM����_^m�SG��\x7����-W������&ut���K����MQJ�%�$����1�����z��s���K� �*�����(K�Q8��%~ct�5����8�I�r
�����MQJ�%n�7�~q����k�q\�:��Z�������(K��/n��������~�1����[�����MQJ�%�_�m���;�[=�bc&�k�G�z�������(K��/����_���u���UP3t���8�s<�*t��56u)QVy�k<l�����ax�cl��qm���H�x4cS�e�G:���c��Ax��Sq\�<�5�-
����DY��n����{N�]��N�1���C[3���r����f:���S��1v�g���L�&l�t�g�%N�Z���.���t�^�#q�u�ix�C���F���EF�x�t�����.p��fm�S�����j�:�Ud����K�]��$��w�CZEgXx�N�*r8���Z�})���
?�K�*�`��8u@�p���w��K�.��	���	���WG���/~�������z9�����/?}���?����y�?���|���?�p��������?���?������+��g��meIZ��2k/�������#_�������W�+
#�����(�|�Bx7���x�U=�a�������_!�����uA�)�7.p
�B�5�,���+W[������i<%���n�X4�ca�a���
����+R����~E��f{cp�h�X4�ca�a���-����+R����~E�->}cp���X��caNa�������+R������n��xcp���WtF���S��=�k���/�c{=�k��^�w����F��#2v��6�k�'���	�z���F2	6�K��F~���DY��~����3�7�����%��
?���DY��~�����mv�'����`����]��~�d���'�����M?xgg��<���[�H�L?x6�`S�g����~���&ax�<	�����~�b���'�/���M?xgW��\fMh�`&^�2�"����d�!"��~c$��s2�}a���Q8�"����d� "��~c$��2�]a���Q��\`��anJp�,0���z���*�DF�W�9w1��
�HM�*9<Dx���HVYd�;��S�,p�@��j�:�Urt������������I5g.�Y`RW[������C�w��o�d����s�b��H\m�SG�J�
�u1�#Ye����1;���e�kRW[�����CC�w��o�d�MAF�C�9m1�7����RG�J����1�U�����!���(��n
?�K�*90Dx���HVK?��bNZ�����������,����3���6f��s�,pO?������,���3���6&��S�,�@?������,�
���3�5�6���3�,0�����o/�sP��������~�1-���e�G�����?K����]/�;#Y�`cV�9_1�O��'��#�������~����������W�?��x����<�����_���*����������(���k�,/��������?��_���?�������O�����?���c�f���X��r\H�r��S~�d�K��r�%�����lh����|����xR���\��7.�B�x51�f����HG�x1�EfD��QC����:��Q�����y�4w��'����2il��p�+C�b���%�*#�}>�����D�Q"�_�����^P�7�J�ry����8�Q?u���a�D�!'����G)Ju#E���*�{&v�y�-J)�F[�8�Q?u���a�D�Q�R�������_b��(����I��d������Q�����<�^`�R�mQJ�4�J���F0.~��t�U�(�q8=�S�Rm�R���V2"W�s�g��(�2E)����>�GQJu#J1E�\����Mq�B�j�L���	��cOF���M�K\�!,W��)O>����4���l-�6��QT}������[��_�G2���9A5���a�����r��,p�����8eXx���QO��S�,0�r��Q��q^����6�qU������q�����Q�c0�����K��3�y����&�]��`\�`���������������r��y����ML���k<�W�?�����������(��pg��W���7���������=�j���?\����C�{�z��I�< ��b0�B���n)6,�uE����M�|_�z����}��+�^%��-��2V��T"����,��T����GY�����MJ,�+;1;�]���V�cFY�"&^Y��V3F��b�����!y��qey��z�MO%��.���yb��X����e�����p��]x�,zjg�E���u�w���'[���3�Ov���"��V��DA���fR,��"�Q������X�� �f��Q�2����;
���6�aW6��#���b�������<
YF\Y�S�����4X��u�z�����X�f������)#���������_�'X�'X��r�����>V~5��o���DZd����������
	�`<A�I��d��Ul����8aV�����������h��7�e���w6ee�a�\AV���&+W�K��3��3�2	�Q���Q���_�����t��o����������F�+P���c�W^����+:x���D�K�>���:v�vw����] d�� ����.n��qg���|����{���Xh���Yj*�G��"+�Qd�S�Qyn�B6�}�ut����&�:��_}`�Q]=�,�g��M�����-�J��jYZ�:d<m�Hw�j��38�(����������8<e��P��!#/���?jN��[,<�����v)
��,�l
0����������w�0�Z��E���\��m�1�')��	
���	Cn�1C�Ep����/����>__P�����b�}��/�������#��i��~���sy��(�s��Gc$�U��t�	�aL�p�h���B�(�����2hg
s�b�� ����*�����Jh�r�#��'�U�e���Kh5�Y�t��Wu\~EpQ���%�:�:��1�D:�@���a��wXix����
a4��_�e�V=��(�����1�h����h��<�8�Zh���������ViL�����O��?�\)_]�����]��_�z��|������ ���_r�qy��	����p�?�<`��f�b_F��E�#�������R�����p]b9[����E�4�>��aS���N��������
Q�}*n�s�=�7e��F�'��*�^e[o�p�	�[��#l�����u��(���7�.~N������s��'�~��w�����;�cN�h%��ka��	����=d�pr��'#�QEo��[hI]���0��EI�]�m����,s��1+:<�WYf��[?�b�	����JG�]m��_��w�����v�<1��?���};5����__����s��9��=Yc[�W7gy������D��&=�G{�����������?~��*n�����]v��wS���������s��?���������S� ��_S?���W��^���.r�~"!/A��Oz(s��������'���t�s�X��^1�����#+W�p��g����"���-Bn�9�2����x�x�+%���������sC�h�1�b�$b�+iHC��|;������"F�!�#�On�P"F0�(FPg%���I��*�k$h#�J�W�bH���G�.?'>L8�)�v���b�=����^+��FAR>�CQ�l�R���"�H8���Yq�(��Q�"���PE1]���7�$��z�m�~�Y�qL7���Y7o��k��*����4����<X�r�M��������n&���K�aG>V�����Q���������7����.�
��t�t��3Kb�n*�����:�
�p|9Mz�#�Y7�!��*��WA=)�;F	-�<��������S�0�Y���L���'\j��yo�6���l0
�sZ�}Bo���^����s�K�yt,�#��\[lADd�e*���-l�-���(����k���|����F�K{ �Y�Y���u����[hIC;bI��
������y�
�����T�EUy�	U��' V����7DE�Um��� j����~/��	!?�����7J���/����k�Lw�%����/]�����w�o����nc����=�j���/�^\
��jY2u��&��3�FJ��(�U�r�FR��	H�'��p���	�:�b[�����z�uy���	<[��3��B���>s�"m���d�c��7��H��*�Q��U�=����b���O��B��1��	�~�/��k�^�_�.w����A��o��d\�����U�F:W�N.7V�� ���������D��/���9Uun^d���k������<�������^�L:�r%i�m��p��g�.z^�t%����������33$���	[���L�������29T�%��_���������
���a� �����;�A6~���\��� ?�����}<��7�nP��*�Xr�_w�r Lz�pL7�6Xgx����r4�,�\��3�B���a���a���BP������F:(\T�hL��-����'x�0(������
={���B�b]as�y���7G����ab ���C}
�-( F�t�����_�	w�<���&+&�\���g ]KSj,�&LP�p�%
�j������g���a�J]p�z�,zU!�pI����
������l���%���>������`�r�������Qm0V�)V�H���������5��$�f������+z?�}8�4����B.�,�G),,�xB����AW�0e�\�"Lx�px��f��-�I�Vp���n&�Q������������b�/@�~���;���(	�b��%^�[�{F�M�\X����5����l�v$��m��x��s����M�I�\�t����#�Q~c���b:���U�M��;�z��:�mI��������tj���O��	��S��^s��}������GN���>�{>��;�������h!`d�������@`����-G������G�
��~��$J�`P�0Z�Y��]���9���<j�-4����l �2c��~��)�2����!���a�0v�B����t�"�������+� ��|�d����w;�)a�*G���;���to�J�_�C����1v��N�8���Q����0p�3
�b��J2��=ZZ���@px��b���,�59M��$�(�k�*
�b���UI�<��*��n���4�U��t�wF�������3�M�����	l�5�y�����Zac������E�G�o
�ae���DM��g��M��t�!�#j��pM�?,
�=$j������o�H�D:��� �$����p�Ul�>"o����/���&�xY�����e��]<s�LF��p�XK`����U�>�gd�M<w�+��Yj �G����1�������D��U�p��.�]N�xYf�,F�t+����t�C���+���t�����a�.1��������2/w�w�L�]"`+N�^�
�w�'*�w1L�puF8���l��t5.b��E�c��pF�}���Q���(b�59��vK�M�@�+����qL�N��:sC�A�+�����L�	�:��R��_]����*�����p=��6��$�(�C	��n���%�������1~�u�s�b��]�	7�������{q]����>�7e����O��YVq]�����UN?���5�P�����z��Q���_��Ov�	��bU�l�p+��0&����A�<`C@`W����(��3��Y�����>6�lHh��z>��CicA�C�$�{��@�X�����lA��`s"�!����-+��o�(q��a�
������0�\d4�um�8��,s|�"���\e���'Oj(7�t�'<4y~Q����Q���[��Wu]����)�h��o���a���_��v�N��|��h�dZ��P[m�m����A���"�6BmV�c�T+�k���=d]hI#�_p:��jC�g-��%�^�+�+o�����[��J��Yz[��m�NN�CqF}Sy{�M�4�^��~�H�
��B/�%H�4���w�O�pz	@�)��n51a����?���9�W/���`$
U���PP5g�X�P/A8�~c������K�2��R�[%����Y^t�l�G8#�h�a�r,�UL}B�z��j��_���������*�{����p��9�����UL���y2�H��p�g�5�������"f2l&!vM�z�6){AV��`��=��c�u���	�����k3H7Y��`dC�W`W����*��+�{���`d��&����$���G`���L�	��+"�c�:���H�Y��0	0���$��\f&�~w (�2P�Fz����x-F8D�v;V\`��+��i�?�������#�3�5��}&��\���i���B����a�Y�g�cAB�D��0���<�!�����a���+b��@}��Y�?D��U�+:��"���y�_��!����61[��F����E,�5Z���FMT�����=��i��p��ew�y;=������D��n��6���>��`�*B��*�Q�`��$�VtW	��N��3G��n�(�5:��O�@y��B{�<a'�k����K"�M:�����n���
�������s)����������+,Wp��,�3�R�0�����g��`���[�,X�)7�7��g��?Z�
���T+8�N����{�����T/�����r20J�d�V��c�po������-eU� ����VU�����Z�G=jg��>P�l�
q*�]��g0n�l	xi��7S&[�b��S`����V���-�����n�a����E���Fn���8���]��nB{�e�JR��{�2d�e�rZRo%iNu
��Z���'����J�QE�d��T������#��A+[��E����VYeU�keUE~�0�n�R�F�����n�0k�n��&���jB���*��
��\d]hHC��%P�e���������F���_��w�_��	����������/_������~:��~��?�����o_�������j�����q;��)�Jr��}���~�q��%h��7���=�C�?4,���0�u�
mMD]����Z\���<���(�G8��������4�s�e��I����*�=�����=���pXM��]����d��bM���A�I��R�U�/V�p�:4�
x�
�f�@��&;�����=�����S�Z�2�]���
[gK����3-94��u.��H��2~���i��$�qO7f<����arC�CPh5������C�o4��v�G[�c`�V3]�����������\�u�3J]���QL�@��*��]�I8�g��&?�<�UL�^s��(uM~�9x"�Q�����N�� �Q����+�o\�t�5?���[��u�~<��;�����!�6�?��/�;�E�b����!�f��]U�/J@8�$�f�~��,>O0���bA�}�L8����u�`��l�����V��%��PyABV��������[��M��XlA�d�$I`x�*\a��A%�8qX��*a�}S�^_f���nf�m�k�'ct��x���3-i$���C�b�)��5Mw��Py�\����hS5�]�<$�Wy(/����>���U\�X���C�O��g�"aR�@��f%�iIm�q,�����o�@�M�!�%��{�:����B3����d��3�����b���V�X����v��}b������+:�0�1��zcO�p�a7��m2�c��o���d��KkD�������]�%(�7�l4�7%A�}���dt���0��!32M@�j�����>��]��d���	��!��#�;<e����g$�N:�2��|��+AWf������+���B����{$�eG8���3'�F1�L:�G�#���U�tF���g�v��%�����LH���JZ��������.��tuA:+k�z��y��j���3!�@:+m���k�\�v�B�'���C�Np��v�y�W���!�rOv
���\��%��������u�|����8$�����A���	��u�1�z��p��ve>�6T��
����gE��5��H�~� �k��V�!�R��~��)JPji���8�j�&yM����n��-3g�-�y~~w�e�_�Ylfg� �k��y���uwI^�����B'�K�V�G�*�����H^WmV��������/6(���#�����=��0	."B���zia���A���*��|��"<�e:Ps��Q6�����t���9�e�C��e�;0H��pPr,����
��]�p����#�.fIpw?�l���X-���M\d�#+���m���2_p�4�����45��������~��C�������Y�����I7�.�3��$�0ij��_�1���UFO�p.�>d�e�	����hIgTV���IW�#��\k�E/7$]G:#�jv��b�	+[Y�������s�MD�wu����hY�&���I��8��w��XY�"7�<��]�Hg8���;��.�����'_U7Y�k���KV���a&�f�fW����.b�Yk@&��k���/���5_��g�/����[+��Z<��6@���9������8n���F2���a�����tuX�!�tAV��_`����;��?6&Z_h_;��o���]������f�	�Bh�Qz��^�t?�AF��0�P��� ���	� 	�����?��0��7��Q�{n�&�����Y����_h���3�������H���n6���~���R�v��)�_R����w�S��|���<�����H�w]��WJ������6�^�6/������Z6[�z��$����0k	@k�t�:U�!�]8=f}|�:���y �q�WNf��;�����%uM�YD$�O8��B���>>f�=�*��Q�0��.��L1z��������k�mb������I�_$�G�������$��]����d��2jU+#��/����k�W�[�$A���c.Fp�\L�,~^�M���.E��v3������|��f�� i-�5��d�������`�����9���n ���P&!���2	�a����f!}��opN���h=�������<�<��2�J�s���.�,?�����k:9��?A~��5���;rK����j���]}O���3B��t4Pn�t3�t��{\�t.+��L��t��W��w�l:�@�V3]�~��[H�G@��zX���Uw�sCM�t%�u�=�� `Z�t��o��D��NW�&7e�B��.���t��e�k����R]��8�����T��MG�ei�.
�@$���d�.����\�����;XO�AG?���\^u���n��F#d@��\)+��^���p��1��ZpAD[����\��{R��n��a��4��2�O,$R�B���-��:<�Y�����"��B�Vny}~��[@�[�pg��c+��p��>D��1�=dN�pP�EIQ�:��M<���5-�r�p<��j+���DU�uF�����A�[�C(��f-��(�JE�U�Vn��9Y����bRE~�c��s���Z������T/6���?���r������<�G<_����#.�}��\���-\�����"+�)�\������*t��dyn�:_h��
%�`A�M��Mr��H���W{9�^Z �� P�c��QG�?�..fZR;��<�c������+���JUVR� +B��4���	�PP%�Z-s�a%�C�Op�f3v�����k&��nP"�;�c��x&V��[FOG	?�����G�n"���+�~7#�'����~H�������y�Z�{.���t3���7�W��Z�t�?�C��6:Z�����z�h�5]t���=	Su'W��jd_���QL�d�J	����qLwRh5��hZ)�Q��d�;��t9���F��b��#��$Ho��p�V��#�0�s��/���D���	�V������s�t�,����	�f����c]����D1]}C����5]0o�m�t���t��!��J�&�L����0]�d����(�Z�t������Iy��\������~�)"*G��{���,��c��}.��$n$���f��]����k+�"��sh�����
�8�
�
�<�<m8-�4��F��	�i�}M�|]�^L���/P_��A�q}�yM���v�5���P�5v i-�(t������$�%"w�UBn�<�Hk7g�3w\i-���C�������V����n�&�����KqR���um��O��hg��u�p7��o��N�����s�����Hk+EZ[���6��G4���HB
7��mY�,����,�}�8��Z;�~�s����GW�tnB�
�v�����nwN��s2�}���@M��.5��<�M�w�����������������V������>.��>��~����?���s��_�w�U�[+��c���Q
����z:u����stE=�W���@�2�����,�@�l<'��@TOK�/H:D\z����K%���p#���<��Z#�������e�q��zX�T�QyI*�]o��}��i�h��I���E�Q�at���]���@�d�>i�������Fi������^Ty�n��6��]�T�
�ni�����K(�z�:���2�aT�����?�dj���)�*��|d:�n���O��*�{�!�H��,5�4/��FZ�M]�:��C
dm�(�s�?S
���". ]O:��Hn:��	�f���G�!�6��0��:�1�vk���G�M��c�����aMG5��j�����tP
�(�5Q�4��@f�H����������B��.z� i�Z������Qj����gk
�j���}_]]��.Lqa���.W1��~��M7�h�e
����kr���D������V3]0o����$�������k�$^���5]jo����(���=��C�����xR�L:'����J��{���}X��ed���_k��R��p��J���9F=W �(�p�	m�m������|�3C$v�[�kZ�������O5��b���W��5�mX������F��1_�Zh_;��ovx�b�@]�}�7;��6��!0�1�H�Q��O-_�g�|��O�y��]h_;��o��d�|��]t�<����Z����b��W�w�k��	��Wh����g+�!e��U�����TQt�>�����@�<��������lX�����Yq��y���Qh�W���	��x�IQ��\4����o�7�n�R����j�����~�*+��Q��5��V����i��J^_���U��\n�������?}���P�7���?�������e�����;�����U%
0��oxe�W��v{g������l�n����;���|��'����q�����j!Y��~j���#j�ww�s% {���t3������^����E�^l�����n��PC�G�Fq
���0k������V6��/Sp����CRKp������s\�����&
�W���c��M9.�]���}�x��h��H��G�����luo.�&����cn��������o����I�l��w�Md��b��I� ���=��R��	@�!�0����/���tP]	������y��n�2��+=	��l��?t��9�/�c�h����nu�Xw	�&l��9�s���\f��7� na%���\�!v��2C���'l�}]#C�{s^h5,�l��t����*���b�u�'�8��I��k����	�`]�:��_6��2tEA�k�������Y��M$�P���]�K�v
����0!P�/u~�
�9���7P��_��|�rAV�����T'\��(����0�ND!�@#&���'�l�-� Iu�5X���~����<�M0�b�B���\��;yX4�^9f��A����"��\�<��-/��:[��(���^e��M��b�)Iu������$����[��T/��I��:�1���c��;��k����4Y���'���rc5dk��i���b��%(���\���l�P�
�AnT`��0�VIW���ogT���%�����c\+V<�^9o�K�Vt-i��,�	!�U%M�=}�/�e��'�^��~��j������a7q�k�VB����BC������)hI�E���aB+��k6�`>U�B�l�S��s��R.!|�]�V�^��n�������z?��g_>�eY�������p��8VoH����|�N��4V(9D�o��Y�
�P����%��On:���V3]�a��C��w�+!�����(������Wt���}z�!*���bK&]�H��C����Vp��
��+���'������1��B��.\����(�+��O��_]����j��2���+G��O��7l�aK�zc�����X���T���&�����L[������2&����u�u5�-Z����u5�N��M�����x��F���M����3�q�nH��������Q6l��S�dM~��=��V3]jo���������h����S{-� �{���������xN"H�.#����]"Xf�A��m����qLE�����������#�H�����z�Gi��x�.��f��i��x�-���k�������^����[]xwWx�i����c�3z1^��u�dPQ�9�uV��1����y�_�m��
���n������Li����gYpS���`���i�d���2{Y��G\�nA���k���.)�k�>>��O��b���4����/�Z��*-"s]��_a�*t��:���t��A�E��Y�����w����[hI=*�������)�)V"�=2�(���>Y)q��������Mg$z�lb*p��^?G���LC�!�������*b5��~/��H��������M*Vd�����$g�����H%���oOF�F8���^W����w6/h�s��-���@������Z5��|��0�:e�D\	]��j�`"_�1P2j���%�-���f��"��Pp��1
+�����H�g�b����d�Uh5�!h�t��J+��k��'+��p�����0]��N?N�u9r:B���_��db�t=��I�kb.�K���_b�����~\��H�:ab��C�vt�N��_���0��$�5Dy��8�S[2vQZ��\j��d�Pi/�"Lb�px
���*������h�YA�(��4��n=J�^K��a��N����\�$������:G`�������q�����t��z���)������~'������
_�������F2����������������w ��������N���QW�����UE��%����A7�|��\udENA��x3���H���ddB
�������6�y����b6u����8����M��n�MW�����8�����z�8�����/?}���?��7yu�V��N������(������?���?�����7���&e���
�Xv-=k>���QM�������~�q��j`�e������_�6���y�U3����w�����}������`G�%���������	�����3�d�ZKPZ
+B�W_�!&#�
]�%� �Z��PS�;�Us�V
���c
��8d�w$([`��F������<��"��j���=�F��)���+s��j���0�a:��\�t����(�4�i�$(I7�NOP&��*<��V3]�.�����2U��SE�_���?��0�d`����?�Ea/��#����0�I�)�}.H�p�Q�'����'n����:+|���'��^����1����W�4�����
����e�(�<�L4<]�J�."���z2]T_�ENI5��m��Q�~�R�G\�e+]Tf�i��.�EF��1��k!��na��#�l���)��b��@��M�
�gsw&Z:��u���o����S}���+w��Y�k���0W������C�c���EN�1�'�e����(��t�3�],� 9�qc��8=�"�,�G������YZ�q�HgHp���o�r�� ����K����}9�}\CZ%����{��;3�����r�>��yP��8�)���9��L=io5Z���7�`� �5���������EM�C�Eh5�E/j"�B:}$W��n��<����`��n��<��r�2�pH�	�f���UA7g���h���1L��R�UL�+j�5Fyi�����B��.���-�(����_�K�V3]�����I����7_N��V�F$�0]��3�KS��-�K�V3�V���2�F�]�kj��K-w�_j��>�P0,d�U%�u��$lWV2d�7B����p���|>��B%�I��M��-;)O��p��;)��'�=d���Xx-Y����{��������:�7��s�l[�5L��Xc�����*�����NI��W�pU�3)�^������B'����#����K���mh&�]������Q�@OO3���=,�?�!A�.�y�&a��,�f��U����R���QG���� �M�k����g�X�"�O���H��F����=
� b�B�l�0�.�8�S���������i�@
���	w�w%Y�M�Q[�|;��_%���@�m�-"�,����Q�Z�Xi�}u�~���IgL{�aD�C�Zp�3P���,l�c�?�<��	Wo?�2�����F�'�>s�t��\-l4�/�L:c�kr���t�����$IA:�MW�]�,�5\�v�%�[Hg��Kn;v
���a��6,�������>4��l�:��hv�[�O����N���������n��6��[n������
��e������^�;�����?xj�b�;�B?�w]���w�L��x�����]��]�*�]��"|�}.}�|	-
��Ee?	�A�]�/f?I��K��#�8��d?W�3�..H��p���������s+�ZV,~�#�5���!�7\��u�K&��\�q��r���$�:�Mi���u*�b�)�O�!q(����2�d?���g���|����}�n����(3�YtU�_)�i�!��Zz��_��~�p�3��.�Dj?�YKoX�	�4�%��������$�e�{���#���h�_E:����O����$)	E~�-5�LoD���0Fo���xB�^p���$DQB{�M���?�&�`���\1�l�JR�J�~5Mv��$�PIJ@.!�ZogM�
���t�%,F <~���n��/��+������s�����$T$C��xm���lY����Ya� A{��:\-h�|�t��
����a;SW�]��=MA:DS�U4����IgER���%�L:#9��vuA:#9n�\��YFz�(�]�$�`�v���(�]��N�s���k�`\�v�-���M����w�L:�&3�n)]�Hw})_��m�e���e�������_W��.�R$���p�k���0g����nF�Qh�����+do������B�~������@�K��O�l^�W0o�=u���7�����J��f���1���� �2Xu;�����o����i��ar��t#{5�v0����`��'�k-|�c�g�x���LVy��+%�$?^
�?|-�P�/��'"k�l�2L���C���tw$P=�g\�M�0���-C��l�qn��Pf	�U�a.�q��z?���;_H:8�����>��H���R���o�
^������v���<�.f`K�������V��+��|!������]�7�9T����R����
�*LQ#���t�%b�*a���CI�������l|z�� ������
�;����z-�?/�8�[p�8f��2���6u��v<�'+���t&%�O���n��d���B^qlGGi6��V�E��8�
gE���m@���������%�����.z�^���3*��Y���4���|�Ml44�fs},��Ae�F_g�s��Hgt�O��MlB+������]^�����Z��\k�b�/�Z��*-������������P��|
��U���:����#AV���ZQ�7;}�6@�y�5b����+F�/�8F�qA�k��a������-Q�WX�-����v�_?Q��J��c?��	�kg`P�UY��v1��J=`�~'���B�����%��(��J##�z�O�A��#OyaV�h������>�|�}�k������\�8�k������A��P�qaV�������;.�!A�������z��J��Tnr���~�j��*�8�/ic�j��z�}�k?��0+�K����F����=q�_�z���b�(�+k�p�����C�j��g��$
�A#�xN���`P�UuKDC�����C����^�B��!�~�������/�'���#Nh�]��k�Y��b��Y����0�+��g�s4����#\��]�� �����h�m=����:[��1���^���a���]#�u���je�����z���/�R�B:\���]�R\*Wj�r�>�+?+���TF��'����mU�Tm��<�+T=Ke���������B����6����Bo�S��-�J��C�t�J]��s��w�*xW{�����)
����PW�x.f��0�,�C��w��}�%�6q�mb:���^tMA:C�lxY�
ZH?Pp���n����|��(F��.	U�B:d~j�[�������c�y�f�}-����	&LA����i&���}-����c�a���V���\<����j7�w�
��6���a��W��km�i��tcL����5�lgZp5�E��E��tF�E�$t�Tx��l���t��I���l�aeK�S�r*�M�3Z���y�U�+�?���,-���t����?�������*��S��n&�Q>��v�Qt��l���tP�4��	�����/(��l���t��TnL��c��/�ZOG�<z9�4���
_PF����Z�z���H��������5ZJ�����#��25���������,��a�.'���#�����������'�5x-z�-������e�B���tF����c��/��([6!D��@:�l���v|A�m���7L��
�AG�=�*%��l��W<Y�M:��n���%��]�w�������������VuHg��	����c<g0���F�H8<F��	� E����7s��tlY�(�Z���]#��H��F�cn%�AWf4�v��]�	*��%���H]"�'��B�����S��[h�k��������-P�C���������*�#�J
K�Xg��G�(P�%��%|<�������k�������C�c����^k���:�����P�Rn��v������{5���AdT���4g�p���X.�k�p���\�����]��K<��!��]�r+}�����|�|5_�tH�t7]���������-t�A(����V
�n���a����\�x�G	��4��"���a|��$Lp�y:^[hKZg���)�c�mw�K'�?���*6��q�����xo��^cWl�
�����V�k������/����b�`�31
���U�<7�]#��z !2�=��HV<f^;��o�iJ�����f�G����=�1;�2��B���2��x����HW�xS�	�O���W���7����
|�L��I^B�U���uw!�&tHR[�����<�r���a�'�A��p��~"C���-<
R?H��&�*�a0��Wt|�-zQ�U�Y?X�t%����_��\	`�3������B�FX���\e�-�g�2���_��������_�U����h��|+����l��w�k���B{����Fo�5��d�5z#�a�<�T��a��q�\z���&$��z�F�1��AF�������:��8����z��"i}��B�/]}��Yk����jU��w��]YRo�S)�HWt�W	����]^C������Z����CNp5��.�Y��v��o������Y����5���������\�v��kVt#����1%��>�{�'�3�b�n@�Lp���
(�\�v��kVt��X��
��{#$��y�s	�������_��'�j�_Q0|�y������/�0�=9���1Q�8v�H�	��b�'�B��Vp��
73�0"���|R��"�)���������|Z�=�BS� ��%��R��BSZ���d|1�����+��rg^����rE������������W��*������~�%�[�n�C���y��$�����/-���Zo����r�y���w�6Y��#�������p����,�;��y����it������~�?���2��w����+������
����U���7L��p}��"��|��Jd�+�?^���:�~��i]}����b<?�E�e�����u�87��X�ba�$!V�_.�Ivh�yq�P��ot�:/ RXn�$��q���P��9�O���x��{U�����}����ED��z�e'��������=v�k	�h����SNW�\,���z�����(�*]i��
V Y�*�UW��_�d��I*�5�E��Y�q�X
���<at����D����q����c���qS�������]�b��p�����d�6i����wq�}���I�Q8����t-��nN����Q�4��x��F_����h*H����o�6���p3����������������zG�y����CS�y�>��v*V6%H�tKS�F����lE��n1��Z�h�����b�{5�F��B:��"�w�0f����.v���1.��H���I��Yp5�E�A�.w��4d��������i���:(�����y���f��l]:W���:���p���:�&sEt��Y5��uP�����f��:(����F�$���r��l���zR�C��tm7��N��<�����j������m7��������� +kh|�a�<��g8�&\-��k�M�����Q��/���#z����3���<��t���zEm��>�-t�5+����j�F�C������@+Q]R�U����\�����GT��1����2o���<1u?�jc�<�5h����3�k���C��|�V�R���u?�?���\k2��Qx���,xR�����	?_�	�~����	9��'�&[+�2>�Wm6%��0�zOX�Bm�^!^��������u�U^�V&8��p�#�q���X�/x-��uK<����iME	#��C^p�����b��t������Xz
��):L_����]i&H��`Q������s�B�m\�4�^�Vy�./j&H��������mJ3�� �1;�l��+���SWt���M�/��K��������7������������%;�0�������~�o_��1�T
�P�Kc����<H��NO������e)b�������c�x������d0��Za�����0�d��(�B:�+)����'�IM��j��.�]����t'�]���*�3����O�kIw��^�O�}���K>��<E����@�i{����O �W�F��*
�|"/��I� �'�1�$��|�/���8�s)`�w�B�r1�����0��{�2�B/���]2�&��B[.R��.)m+�x[nM	
�|n����������S:�tr-~�?~�[�M$�vWe���'���Ni����y��0Z&k���}&������@hD���j���&�-�U�}���\Yn9�m@V��q��T����>)���y$*�����Y��C}�.f|G�����)+�q�!4	�'���&�s�m\s��z��7l����7a6�
�'B������������ly�4F�Qch��D����������]���������~s�_�����_�������/_�������_����?�������}��>����}����)���s���7d"sXV�K��Q�B�\�����?����z����%d���jpsT��>S���33P5����"�������|Gf�=����n[���DhI����j��ex����2����^p5�E/�#]K:}�u�����@p5�E/������IWG/�!����������
�:�]����J}�Ui=��f���"cIF2�o��K�����9��QW=Z��dU�p�
�pA�*��[Sh����Q����;���8���+��o���*��#����g��k}6;����4�Q��0Y��K��ngU>+j%�����G_�"1����#��|��&�����i�>�y�����Adf|����������?|-���/L����L�7�,L�
�f��`E��wF��s�t(��m��q��������t�����4�����?����j�W������
�z���}��
jC%�~��@mt0z�J��#u +2��A �.f��� `���c�u��]�L�"$��rl��p_q��3lVa3Ke&�A8D�j#jlHh��3E���:�U�A
���`'~����g��0�Q��<�'cxY�����V��.�����z�g�E�I7����^#��]d�p�z}�� l��G�L)��������[�o!���Z����^\����>$�L8D�������&^�:�����hJ+��o���y�{��fic����H#-�BS�&�2�0�e�Qf�T�����r�^?��p���p�V���s�[S�C������"���k-��{c7x�6��yl�����c^����_~���n^K���]�����ckj�ylEUJ�
�1����
������Z/��(6�5���x���C
��CK���S�V��s�g���6�(w@h�k���9ly���{B� ��mV�m��y�A����5x�+��%��0�D�0�Y�*[�� =H���`�.OIz��I6\0�M���oO�v�v4�p���PoO�!�-������O�]��~�]�b�)IQvq�Q/�O��{(�wJ#Prt"�{�}<�<�1D����X��*�!����C�3���KK���!BBp �Zr��5�o���N�r�����\wZ�0��x�LzX^��*w!�@��%��r�.a���K��=��!�'�Z��F :�4��&,ql7���`�u
�X]���*���b�.G�Op5�k"�b��#���?���g�-�+�,HRt�������������gR��&b��e��_���`��*	B�X��dpa�����:��&\�|$��C�c[��FC�&��1�<�Z�z��a���C(Sp���]AK��[K�e�;���W��vt�|$����r������r���H��?��X�U���9����|d����_�]~ddn����
0����Sg����c�S���-�A!�8@�%��$wYg��.O|s����J�������Foz�._-�]��c��w������sz�e��_8!�-?yo��{�2�n��&���Ep�c."b��M��$0_J^��F���8C���'/k������B�S7�!u����}.#�+�Ek��uF��Y
��Y!��f�1�0��9��8nk��B�����g
�1�+V�^k�9�����;T�E�N����C�Cp���gjo�m�;"1������Dp�t�"���C2Ph�����V����x��Lx���G����+:�w��k?}D��*!������<�!j^uE�W���o����p/�Q���D�����l&�<|�J��8e�7�U�a����J�,H����~�\p�M�6�+��t�����+��/���b�\���+�a��B9��Z�l��/wF��H�Ig����_QlW�\Y����(�������.v��������i�,5S�|��n"�Q�m�F���_p5������tF���wE5`WT����c��n!���J~������.�~iE��5@�����n�����a����!]�T}u��kpN>�����48eqnP�vb(����tI�$���p�H����x^
�&>FF�u�B�����75G����o������t�����"�}}^_����t���+V>AgctSk�t���h�r��z_o�/���t���:���L������
o;\��Q��~��� �&����S�����E=����_S���� �{����6��|�Vk�(~<�&{?�8a�?���/���wQ���/��������#�������j����}�w�}��b�������@�>������f���+�_P�?|��t��>�s�����Y]�UX�����f��2�]~�:�3�<T&�EMD�r�0"�a� ��p~�&K���`��?���gpQ��<�����42��0�nc��w��}f�D����va>�6�f�YM�H E
���c����
����5wJ��&��c���t����I./���B�Vit�����;5~;�.��4�����N+�p�(��}���u����p#�������u�S�����\���h�f1L��t8k���|�Q��ArV��r�SC�2�(����\�v�5I��Ig�������l]����n6����$�5X�ZW8��FB��tF����b;frW�]tM��*W9�w�
�p���.�&�t#�-\����M�Z8�J���E��l��mt]
�x�����kQ����o��wE���h����E1l�AWZ�5�wo������{*���B���]���3�p��1�w�����|w=o�^��L�c�
��������\�v��
�=;t�3jl����d�hR�hwq�=�y7�'3ZU8�� ��y���O�z����	�f��~�T���9��v}�IOe�-y���7�d�d�m7�'���*��b��>�5�/�y7��3|2�� ��]��Ti��tO�Y�.:3��v}
�QbPO��*F�W�����6^��qj�UN��l����]G:�� q���f�=�����v����jj�.w���(������*�d��p�,k�������v�e�4��m�B��d��q�z�N�E{���0����h��H[t�������B�V#\v��n������G����]F���?�<�C�XhW�W�H�k�
�b?���e�/y�� ��#��6q�H���F{j��,L$�P�)�O�)�\W���v0�`��`x��b
����y����`�*`kfs�w�g4�um�{��^[h�����=����-����_:��t3�wM��h�R�T����"w���1�7�j���,�����#��o.�|K�hi����=�����).{i]�Q',� "2����{�9�@�S��>����(6��q��������'+���U{X�0�8��^m���d��-����������m��q%��J�����Dp���q���~� ��c����%�b����@�Sx�����"
gw��o����$Ke����X�>��C�1Je�ea�����B�Tm���\�S;�A����<�?ev3�
�@;���Z Z�`�D�x�F#dSBDhD��tFz6�.p�����j��.�"�1�nz�������6�H��v#��7���7�{
�f��"-�A2�L���,�p�]O:��m���M�-'��1�]1�Q0�V;�w7�U0e�����7�l��`"-��n^Hg�dY����[x��z��))��z��q�%�+(p\�v��?�����v�M���k3�(���.z��z�Y~E�����3�:��I���t��*"+�Ed��"22���73^
�C�w��5D�?1��G �p�
��"���������j4�����
k�j�
8vx�"<�>��F� ��V�o����Dd�C�[h�q��"2��GWM��s8���p($���&\�p�u7�=������4���g^�dF�p7F�jaI�"d��^��s����4����4�B����jm��aDd��}���{������n�F��_���[��������f��)"k������a�S��_S]T����]��_D�	U@y�
z��0����K:d��]�)������S���w��D�����F1����x��O�����=r�����9��3j��o����5�'�x
t��#����zw��i+�>f��3��Vg�@��{�>�B������)B���'*�����}fTfFO��~��O�p;[^7g�}�y7��>e����n���3�����E�Jt��=i�M�K����^��J���g
_~��o�aa�2�c
��R�]t�����~=H:+{+��E�,�n!���*����Fp5�E�WK:��z�G���K�H�uo����������t���z	����!� ����I����!�Hg��R�CoIp5�E�+�<'���J~�
L���[9�(���F^�Y�/ql��l0Z�Yt��\A:�&K}W7��j��>�t���,�wW�&\�v����"H�=�wW�&+tda
�b|w�D:�&K�����
���0�|1l�1��{�A�?Ct�� ��-g�r��o��7Y���,�_QA�$�G9���t�p)K�W���*�'K�gk��\�v����%�>��
��OV��iE����]��l5����k��5�Of��d;�d����>��,Qp5�E/�Eq��(�Y������bh�
3��v#��R��1(������Q����66Z7��v<Q:�ml��Ql7��������<Q:��~a��A��H�(O=Q��K�]�R�jl2���7�o��~�r�qtt�{�3����q��E>���
����_a�W����-�U��,�;_�V���� +g�q����\���h�c���!�U�=�n��
x� #~1�qW�X��*�#]����[�2��.i��&�#��_����k+m5H���=j��W[i�2�~����\�x��c�]�����������{c[*�8���{��pGu_ :�����*I�c<�������0tcN���g���o��}�^#\$����(�x�gL���4C�J!�}�V��Rh4+�R���W�B����o��aT	����x��)�O4%�d<��GcTf^ztK7�xV����R�xz\//����C\Op�h��xHz��9���1��a��%D��Q�7Q�<�2�2��1qZ�d)�-=C$��4�Q�Y&�0&�\����4�1g.L����K�aL94��1n�Y��8�s���B�*��19HiW3^jcrP�
�f����a��/��1��3�yUbc*��'R����x��j�K�aLL�	���8�+K���p��D<Op��E2�y��/��1U9�g��,]C�U��	�f��F�x��>!��d���3�y���8�����J�a���	�f��F�x��j�K�a49�g���va����<����WW������N6:�?�gOs���]�����G��<:�X�+ktl�����~��BW��Kd&a�4 2�)�Z�4��	4s�t�8LF�xp�~H8�R�5��v�X9I���i��q�1l�F��P�}�1+	�z�������!h2�+����4�r#���!��2o:m/<#��~/��
������/v?���3.�����������.#�Z�C#rft,����Fwc�H�����!(�JkFueC��%�B8m��s�c_�%�f�:1�"zM(�Z��W���>J�tb�f���H� ��j���?�t#�������r��U}�"���\�v]���/���\����H��<�%��b���������%#��{�����Q_Q���H�W�Q_���cy��j��>��tH��Fy���?���7�5V�E�K�1#�1�4�]��,���.z_2�u�3�����7�ht]��d�����F�������l2��8��A�����1�z�]o������?�/�	Z<��h���k�����o�7�6o���?6�������n>��Pe���K��k��k�q��)�'�.�}.HY>��}-7���h6�[,������]j�^��e.���:�B����F����p{	��B���k����4.3�yg�;���W[���"���'����+Q��p�b�+r��O$��4����q��x��j��.�%�R+^a��#�w���]��!��������q�7�����!A :�����s������kh��<
������n����e��^x�r����
��w��u#�B��:z� ���������u#2z����^(H:T��f������xzYJ�D/$����/��13f0��&z� �4��>�V��8��`��L�7�����Cre�L����R�P+�m���Z����&�<{n��Z���u��Z����?�d�3��kZ����i3�������t��"��/�J�����@��IW��(�����(�'�@�����82X����^1�%�t}��)K���5�;�d�t�Wr�\���mcd�.����"�%]:#�]I�A�1C�c����%��Co��uS��h�'���d�t3�����J�	���Z���N�����:\e��s:�dpmI8=�����'�/NW���\���>eN��$���y����N[m��HkH����j����s�-�3d�V��(���#\�v�e��k@W#���n��Vz���
|G��1�5.����vP�\p5�E[G��tF2�j��v��q��`���%^p�rW4!���D+���kz�����w
o�F��-��w���-Hgh����Ql��&k���2���#���o��(�4��b��+A�%�����7Yg�d�E@1��n$��W$��z�d�Q�ic���z�~�(�]���7�t��Ql7������v���
W���{v@,@p��6x�
F,���v��c��n�O6�����e����F�'K�g�	'�h�d���(�����h���v}�Io.PX�_���7�d�d�mG�l2|2k�K����Vus�<��t���Y�_��������k����n��2�����������%��DY����b;���>k�m�2�Q�m�������FqV����;�M�3�(�i|o�'��A��t\�y7wu�u�U����C����.�jAw6N�r|=����'fTp�_������5���4JhW���h��[�(o4n�}���s��y�	�x�����&�3�ouA��e����>��� 7�C���X�����CW�
^M�_Xc/t'���2�t��P����|�JYMS�s�y��.2H{�W[��U@�C8Op��8�xyI��u�=����������],�Z�A��G�����z�����+Ax5�����s����l�x�gM����tEA�Y2��e��CLOx5�Eo�@:��W3^��Q��9�gM�O}a��|W3^��4���!������%�L�YQ���i�W4�1�>�XX�A�%�O�D#����!'�l
�:���y�D1^�T��j�K}a��	���H��i<c�}����k�gL�7O�(�k�1&�[�Sq�!��>!��c<����j�K}a�����t��Y�u0^k��L}a��gL�7��G1^�h<c�}�6p�C<Op5�%�0:��:#�������x�9�<��z��:#������x����c<��V�����@70���<s�y�1�'���R_�yF�����8�c<o0�yM�cd<o�$z�=�������5�/�������%�0(������c<���:k�c$�1�7����'{������/{�u�z�v�&��C��$��F@�~���g�F���:b����s����h���s�l�w���W���}^�������hsX�?|�?Z{�uJ��:G_��	���@|F�5��~���F:xR���yb�9$B�B{X���4fE$�B<�m�Wye��A�m\�m+��m�#��������5�6��\���������F�Up�����G���k��J��OL��6��c?�]��&O����pgJ�-��E����Nn�tu�5�)L�C��i�4��j���0/�Qy�*�"�H��%r��8fv�9l��Fn�y�9s3����/~�������z"9�����/?}���?�������G�����x���������O������#��7���V���.�������#'����A��*��%�G+f�>�t.#��|��q=W��t���j�����t-���{�M��^h5�E�Z�"'��Ez\��t��B��.z��u����f�(��	g�s���Q�����(��5��J���V3]��Hg�����f4..��t����Bp��Qj�����{VF:��F�]�R_5�����X��(��ZXp��Q,\bak�G���]�+C+����T�2�V.�{2OJ:������y�'�v�'�U�w����w�h��v��y�>�<`���P`s^7�9��&�p�fT�������tM �]B�\��	����h��=k��d5�B���a�:�:��n�4�{��e{n}R�l}B:,��n-�{�J����V:�P�x8�W[i��DP:��'��1^��������$<F���_(L���3���m��,i<c�����b�^��*�����&B���/�PxUN���;�����x�V��k�n�1/����Y�Y�-4�q��s���.h<c�v�����\�x�K��X��j�K}a49����9G=���T�W{���08�Hp5�%w�(9��iFg�MR�q�QmHN\����8��g���U'�5�����b�.��q�NG��A�T��!n���,i�KeI�T����%v�F-=�UF��=�5n�oTe�r���%��Z���w��?��������zg"2�3��j
#�H����h4F����e���@ tB�/��_��O���.	�a<��������7�e</c�_Zf/�|�|_���������|//�.Fo"���B���n�77��q����e7L
5FR����] �RM����3���������A�����] �x5�N��I��]��-"�J������]��s�B�Q�B88BB�q���S��LX�� }Z�-Y,I���k����b�s� ni^CdD�"��ZR��y�M�3L]�8�Gk��h�U-�t�;�?Zz������%�%���I��s�7l_N���"#��z>z=	��t#��f�%��2�z���Q���Z�t�� ����`���M��d��0C��t�#�~����c�n�i25-���tt8F�8In�����;����b�	���{��4�����Ra�1���~�$7���d���������C�Op�S]@4>���������q/�%��y���'-l��=b��RO���~���i�k����Rho�$&q��2��	�iD����]\�q���]��������Q�#��#�Q��5�Z���>r���~�BD�Y��2�e�\��ZOq�s������o0rP�������m�yh�/�p���`��C��N-h<��H��*�4|�0uj�C�CoL$1�����B{��d����k���J~�q#�w�BM��]�7I{?�Bw-i@2�GY��t��:z�m�!,*��:�����d�L�����������,�Yy������K�����������^<'�j��O��p9�����8uD��>V2%��kE�>���m�I4�oV�1J&���YW��$��������YWx��fc.��07�:�tKN�1�'`>
;"m�����hV�z�#����Cj��+��CzJp�����eyNS�E�>�^Sg������:��C| u&!]AHc8Xkh/��3Wt��4��B�3Wp�E�VQg�j�@��	Wd�?�������H���)��nl��:�2�~�V�s����UL[���C�Ch5�S���n&�^���t��������p�'X�!).����@8�	Pa�7�1�B:]c��tCI8=�]4�{+:t\�t�&.��&����Q�QL7���Ur��<MF�+��K�������}��4
�����b�� �~�$7���d2T�ml�������'�M7�41��k�k���Yp�b:�&Va�5�	�{NQ���Iw=N�+
��^Q�x�+.>��l���Lq���+��c���b�W�uD����%�O�������}	�!��#������w7[���
A����W��CDGp���~�aW�hJc0�U�g�{���W[����Vtp��r$�!�,�����M4��������x����^�;��@tpW3^���8@�)�G���B�����S��o��;"Lk�L���{G��5�x�1/���Em�mc���W����m�Mx�������u�xpW3^�f�+���3���P��k	��\�x�2�Gl?������~l�[���p����Y���S����������5oo�3f�F���90�E��Tx<��A� �
���-������j�����t<��|tEam�	��1����@t�h&k���-��&���h�P�J�j�t�3��a�B%U	M�T-���V?����j�;�����S�����5Mq~��T��o�g	5�@�����oi�I����*���	T8F���H����dE��d��s�M��I<���W��B
���-��"x�>5���q���0e��Sp����%>/f�H���M����1�
�a�q_��z�����4�t��ui�_�P���p2���0��Cv2��VW�0���-bh+5��4p#}��z��4��v^E
F=�SEi[d6��8�o']K:}�T�5��C�Bh5���{���I��(�����Mh5�E����#�.pK�a��pF[U+e�t�#��hIn�o��L]�N��t�c���1LWe�3��Z��(��x�Uz�]z��4����V�8��&������>��j�&V@�JG1]
����t<Mj�����o'�B:�8In���ImT�Y������Y�=��x�4�����&�k|D�6'��8I�y��q{��\�����6��Z83|�y��/������j��r,� +%�\���{�%��?s�L� U���&����.�?���)�
� �LKS��.�a�@����G{G�`��B�����]@E)��B�z�!�,���<D��m��v��2��teA������,mT���<'�o���E�������,�������GW>��<�Ul�Q��v�v+=��@�J:^��~�Z������[������C�Sp5ACr��Q/���R�MF��^��|I�F����.�]A���jA����i;K'����Nj1�����(�k��]�����8�C�Sp�{�ql�e��Q8`M2�b����N����
��W����_:E�O����
�(�o.��\���������'��C�_4]��4�(��67��k�^w������V�W:���,�f�g���iz����z%��~#������@
o�:�����N��yQ�K<n�����}��^����)��m�����F=�9�!��"�%c���s}yI���N�8F���������� ��Ds/_��*�|����|��%�G����M�%����[�G���Ni���|��@��H�%�
#�'\O8=�R�1�����;K�����f�)����|�6���A��+���p
,�j�.���t<��Y��M�������&/�4][�N��Y3_���m����R�&/�5�H:=���t]�um�TA]^N�t��*0�wG2]G8K#L^���!�w�=�Y�;l��h�o)��|u}
�^�}K�����z=�Rf����[H�_b�M7����@Ki��a����%6\���B_���7�U���������e�����������Y��7��3
����eFN�#3����V���F�K��]y�^=�#�o��������8�C��B���<��*�.����d�.����s8���p�+���UE��o�}DaV��;����Wg�t^Q)M8�n�#��/P�Q�qA���S�@�pV)���p��B{�P��j��C��$���t�������Zg���um������2�p�tp�W[��=/I����nk����mk�,���������G�5�l
k�6�YXJS���%/����]p���|/z�O���5@[
��!$L�R�����D1A;����Pr��kH�C��p���7\�`]x*����(��L?��Q�t��#�C)vH�`����q��m\d���p�XQ������WS����@���HO�!�q�#�*�G��EwUxw��B)v@G1����q��7�b��x��&��F�:����*�#�F�C8H9�����;��l�2oQ����W�q����k�(aG�k�i:*;�(���l;�,zR�Q�Q�zYy]@8�
C�Qf�ub��H�����Rat/��mHA����]�&z/M�!l-������H��N[;�������yZ�{0�������|0y�p�����������<�����?v.�cWI����;������B�}�����@�}�T�[������s�}-�N/�Ho��p���|,9����2�{�����X�**�dB]���)��AS��w:��j����Be�A� �.��s�a2��C�Ph���!'"�B{��R���x����&�
��5����2vf���Y*��-[<�wc����3����s�O����4��N/�
���t���������tmgLj��E	CG-��*�����t�4��Q(��|	D�Ji�	���ql7���9������c4\��-�H��c4��[�<��n�����2��qlG���j���Z�t�+������x""����.z�]��9m�G�M9d���b;+�v�[\�v����i;��w�7��J<����K�����$?����?������_�������/�/w���)�����?~��7B�o^k������-���p��N��
c��+t���r-Mn�_1��U��de���>�i�*�g��To�U��I�.���p�}����yd} �n����5q]y��T�����	�uD�+�2t%�Q�H\�� ���Mw�id	���,�c����+���u���u��M�K�\�/��6�����6�Te�%�4F�m\�]\M#�/o �,��f������bmi���c&��ww�s(�,�����M��_���t#��L��F}��7O:�jWy��w��?�:^"�1�Z��BId	�Uh�"���TPe������.�L��������xZn.�'��[n�5<?��c9���5�����[B�?f�r�E���Jo9�g�-�"�a�e��u���Yk��#X��x�,�u�X����3<����\��(Z�r���A��:��%����B�X���6��:��u�-7N?J�Tw)(��#�5�r����R��W
Z��~��O�1�(^CB)(;��k�)��^%��p��
�pA���CZVhA���G��_��R���KZR�Nntl)(����HA�:����L`|)(��f\m��K�H��v4������h;��M g���v�#���-��&���m�<�!�$�{���l���<%���n��aD�L�(�c�#�}]�q�z��
S��v���!A���Ql�@�,���@�l	����XD��v���/��k����Q�����@��"�� A\�v�w���0A����U��f����,�{a;t��i��p��oz��+����f0-]i���D8���x�����	E8@,q`
�&���jAD8�C�^p�#��d��t��LhA+�j�ip<��58��Z�Y��n���\FKG:DhVB5�~�%�l��%"�"�s�|Y������J -�D?����b5�?�>�Z�Y���F_������h<�1%�TKGF
Z��Y�*A�t�c�Ip����h��K�H7��}Z�/������p��v������j�l��9/s�<Xf�7��	�]�q,��='�L�����NA����9'�j��5aT1�c�2�=��f^wF2+@�r|��e�E�nA*Qh����XnA�_h�b9>�=�o����������;K��rm��d��X���k��Mh�q��T��FG7+0�rT����/����k
�_��8}R�F��pWu�U�V�k��������J�����������eF#��N��H>�SUX���Q/)�����W�u��n[H�o�iX��
�����{���!���p�����E,�Q������h�)��v+��p%���R����n�a���C��3�0&\!/��$���B�uq4��B�/�%��b����a����g�M����s�q��04<1�����������'���:�����=�m�GZ�Q��Z>�T{zL��<�E���4i���5��k���~i���+S��,a.���������(L:(�W9|�|��\�h����!+�����K���`�!�!��%JM������c�C�����(��F�Z����k	�&����t��}�{�}\�@����7����)�
e����!Y#�OU���t������l�@#� �	�����F�A8^"�>�H����tt�9/�����+�l�w$KI��+I+�$�86��
���.�IV�����r���b�`�/<-7�
���N�Y������������@���6���o0ru�U{L�������3��V�?��Xz(����)�|M�g�Qy���c��������@�Ko����������4���'5�	wM�\5��F�8y�~}~�����a!/�����g��s����GfM��#$�I	�pAr��kQ�$���X/���t�rG�C�u0&����V�j�S��z�?6]��vJ)��������~��3�:Sq2�]���3����c;NV���{B����Z�dE��?���Z�d�=�K:NV����4��8Yq0&+�����8��Wh$��	hLVt���$�� �Y��
��b1"d�����t|����MW@����1Y�Y]�����c��9#������]7���t3mwu��c�/:�z[��$�1�',<vn�/�:����g�N�GX����	 ���s.��3[<u��2a@t@�"�0����C�@p����uL���(��w�u�!-�����E�����4�9k�i���	�z�T�D��eED��K��K�W�1YC����H�Dp���+�+I�[�q�ZL��]J�D:�}��>�kJ���'����Y��atL��s[p���atL���Nh�V���1���(���c,c�B�e��O�"�c#�j}�a4%�	gtaKn������b�uB���R�D1�0�^	`Ei���7��K8����Fc����.���p������<�$jQL7����G��E8>�����:{�F�-�-�t,��b�7�n"����>�e�������ej��L����-���{k�+����@2�{����4l���F��B>�}.���p���!�S��*��o�@�#�59-i�'�F���1���D�����D}X�u�P� ��:G�D�!3�}"&��vE�>�!b&�B��?�����oN��=�����������������>�������������?���������=6����������N�W�~�s�p�VC������<��|�{��~ns������o�([u�;\��Y=��
�4�/�3����*�����3�^�i�q���B�m<S��xl�f�����[h<=�m���o(h<#�c��b����*����#B����q'���cLv6b���/��F$�g+(k�@���������W��������x��Wi���:���Y��[�����5�H{��������oJ�9S�5���b&�p�t�7��L��7/������/�e� �#PDVd�^��x��_��u����2��#����>^rG�����z�>^r���|�}���t�S�{�|1�K:�`�����0�(hJ]�����E����>���J�R��,	����5�%��t 	����0
0��)��)�+�S�d��o�1���N)����,
�r���g��������_�0��p(9_��y}�� (��A�8�[gJ����#���pV�0��:^m��K�a;�����(��3������s����Vx0��p|
����U���iq����Kd��K���K!����^��'���-���)W�oW�?N.��	�"����X�O��
4��p��MA����@�0�;�dEseDX��W;��n�	DF�k[_t�
��F��g���$�@�p�z�+7[
m��^_�����|�C;�B7L��%�fW�8����C��&k������Hd
���6l�����L���;_9�{p��~D{
��y��(��JyC=�wZ<���C����/�%��F�~�#��������AX��A��+A7���zl��@� ��z��Ax(�_L#o�=�"�\�| �ZXo�l���K�m<�)3Z� Ro�����~�[��M����Q���}<��bt�����b:�t�7o�����q�t  !��Pk�@��&H:F�N���py�[d1B��L�t ��5������Lz-Dn8�aB���u���3�=�d7�h�G�Z���F�b:����tx���h�6�T �M�3u�7,�\�t����)}Hn:<W1�$H��p���5���k����\����f�s2���,B�LG���^�UK&C�p�~��pA21����Czf��cd�CU��(@O:#F_��l�+s:w~�?��z��-t���^2����#FH���j�f�x���,����Z���0d<��3�Q���I�kNp1����9��5{�D1^��xF�<��u9����/~�4���\�x�Ge�6�L���kRu������f�9�"L��x
���%L��K��SR�E��=�w��������K���y������n���L��)q_�t	+�gYK���F�t���/�J��:��&k���Oh��S����l4�-�<L�o�����G���/f�Wxm�U�<��P�m�t$�+�o�f]cxCN�t�d�I����1�q��*K��[>O���>�!_�����k�n����>��_A��4���������w�3�'-IA���
��H��_j.P�~7�z��=kO�ieI����j���Z��:�����E���3�5��B-��������8�k	��t�`:>bf]�aE���n��6
&�o��A�U�s��U�u��$��M�����1��NA���+2���k�{������.{-k�b��G�V�:�K���$�q���7�� Y���B�\��=�0��B{H��hp����6j�������j��eu�����^4J��7d���fxe����� (�n.�����/z�)�����r���+<<��W1^ta���S�}[�t�7�xF�4���tCA�Y�S��a�7  �����mVt��f�=@�����G��b�����6��2�b�mg�Wx|V�Od����|�)Y�*U�~�#x��Y���y�U?g�q��Z�/�_.���=�R�J��p�D�X��������t����_�!��{{���x�Oy�Zf\���a=��d��)��j����"A�q�a��w����m�2I��o�m\:d2W+g��z{E�w��s;n�G���7�{r�Q��=����������PY{@�x����7\��Y{������m:k�Q��=�:�}��Kd_��5g�}�y7N���v3����]�*?C/(�uOWe�O=�`N�d	�T��j��]1��Cf�2��Xa�}���	g�)(,QA������4����8���0��,��C�qL7����� ��\����V�4���B{�!z �����L�������B{�3t.�
������(��V3t�y�x;	�f�`�.���XHg2�_�/W�]t���x2���V6��x�����_���c�|�=��e��j�;��v�]����p'/��9)��l������2�������a;���j�
'�Tx��z �q���(MF:��{��������W��+X�W��'�t�����������G�7Y�j�tt�Z�%K�g[�d�!��S�-}�������;�d���Y�8�]W��3n��o��>Y���
%A����O�Y>Y��]���3|2s6]����LYp��g{�d������x��t}��z�]�n�������y+~]��S�M}b]�h������k�������}��D,�

U�~~���W�����SH�����H��q���$��x���+8(���)mT��9�fT����j�p�,�F��	�j�px��q����a#�zy2cHO<����Di�h
2vp���{s���h+�;������+qV:�kAx����J-� bz��]Q_� r��	]�g%����#((�_�QQTu�jD�������R����kT���?|M����24��fi��P�B��k*�(�v1�������������c����7�FV�Q^3�G_�����>i�2�`����Yh��2��}��Ih����JK9�u|�V�I���+:����t���E���|$vW����/N�<����r�����_~������o������������?������O���>5)�%W���L������H��U���������o�.�q����oz���.�hw3Ti��kW��/�r��@�'i��q8giq������;�]�$��~1��0�9���'�
����P�j����G��Wm�����l]���������A����D����Lr�w�9�A�l[���<�o������C�ggNx�._#]G�'>����j��^�*'���%�%����.�|�t=�W)����Bs>f���#�(�C1�5!��h��c(�3C1�eD�c,�3z\���I�������8��M�X=����H7����������*�&_��]���52^��l;���!L���g[�d�!b��T��C��j��^C:�dV����C�Tp5���+��tF��N}����z��Bj��oIg�d���Ql���7��IqlG�i�7Y��tSu+1�oQv�u�3�'����b1�}��3��F��C�|���.�3"�(��IgOX]����/�Q���'1��c���J�g'����1�;Ng\�v����nf,��T��+8�Ip���c_����TD/�!_P7=q�e1��,�{�,���1L��9[hOm���AV�oP�(�JZY�V�����������["iy���W�Qe��Pe�F��Ph_��
k��r��hh����O�!�T5��2C������d���x;���!�B�\���pd�����e,`�'�*E�V
���*a���fI��!�B�]w��V�b����x��,5�5�2Pm��nz��6����8�6�^��/�.{p�T�5�a���.��~kc~��yKLg�����������*;a�����A��������_H>O:>�:#q��"��`�q�Cw��Y��
��x�+�����iIk�r��
m�������]L�0e�9���G1��^���Pp���G�����0�6��~���������t��
�:����C�srv����������o���g����7
S�A8^"����jBpg9G��Sn�>�C��M���3��Y�������?���:k�9��W��D�0��C�U���9.�!k.����k�H7����'���f��&��3Z���n�h�0�F��B:CAo���b�����S�g��4���\�����t���1/���������d��K��<�������e�V%D�����'�����w�x�8��62�!�Z��qQ����1�1�b����N��y-�!W4��1���S��8�fLDZ���4^S�D�@y-���w��#�ur�%�Ul��\:�U�s^�t�k�G x.��#������y������p)��d��=��������M�� r��@�0k�\�_P��d��[���.P�t�:���y%������vz�/�q�����d1<]k k�t�����.��P���'�
�Av��������V��@��M�k����N��Xd�m��O�~�-�C�cH?Ip���]*��#��-V@!Lw-��&@p������I��t���*���tL�����s���C�^h7�����r���k�.�0%Hx�t<O���2z� ������C�yZ7p��)�v}A:#���v��$�����	����5c��^�:'+XF��E:>�
-S�Do�A��t�����~�t|<[���,�'��b��=��(�
�����!�,������I7��6���-������.z��t|AY��m����j��O�?�~&_P�5uM?�����/�\Vgg�\d1P�'P�U��<��RA������>L�p%6��>$�L8�P������D8@��|�qC�G��o�W�*[xa2����?WR��g�l5�����Y�:�)
=U�s��O�<���ng��%�\*��"t��*�?�*���?�������j^���[�<�!������\Xu�p��|�\�O;�P�0 v������8��&���f����&��2��������IdE<N��
�q#��
#��f+gMI	��P
�z������Iq6�P���,�V'E��w��6��D��������;���Db�]��W��6��AL�!���.��$%pB�e���LA
I�P�l�����0m����H�^a�/���s���n���"�Za�g��F�B���g���58fWyF�L:�1�f��)�aF��*t��� �E���3f�$�][����k0�p6�f��)m���3����{�S`k
��2��:���Pu[!�8�kIg$����,V��*��s��9���{�����Yp5�����7Yo
�N}W������3��v^��e�M����n��27�9�#�w7��3N��r�����j�V��i��o��z�>�(�\�v��
JxK�c5a�b;JxK�c��a;JxK���vH/�����v��lq���\re
�9+%��f$]�(oc�W���_��tt��-7��t������O:�!��? �_Vq0	�&���Y��~�e��{F:F����B�\�������>'���4�������)iJ���"��������u�)���,SFY����z�Y�a ��X���(+/��J��U��cMynZ��lZ�1�G\���t�#	�R6��Yf�����c����/����J�os-|�
_����Y��Wc ���r���"_�A_hr/���!W������_��n�!'����D��k���q�)�����pE/�G��pE/�ZC��}�^tdHW��[����<=i�z�YFCs��*_#�}��������P�5@�9!�dpa}~a�k�C<Bp���#_#.�U�k��!��)��������e6����<L�t
N��������}"��v����O��)|�F�����]���x������[k(N�wm�]��:�"�t���������>�%��:<��({����34N��� *"��Q`��Jn��'Jg���1���7Y��(f =��&�7���d��NF����pK�
�T	�f;E��Yu�������Y��>�^{e�Ol���y���k�=��������B.�+f"��X��lm���1�~5?��DNh��_ U	��d%�o<���We����&\U�pk	�!�y���B�������&�LS��	gY/�*xuA�]w��V��kE����QV��$��J�����ST	�C���w[�P_T	��Jh�5��������5����uV���&�"���������b.��:��$�%eK����4�F;s��YE:^�f�RlE�xe�T-��N�P��F�����b.�t�1=R��1sa$����*b�|����#7���
nc-A:�4�m��M|[��a����b��$��7��?-���@���|YN�#r��m�P�B�R���Xa���i<xa0e������A�,��&@���4�C�|����e \�{�Xw	5��!k>,����-2�/���A&�O���E��O~����^+K:���E���������2���)��A\�v� ��wg4/vVJ��2)���=�%��jG:�2I�gk�&���.��t��*�7�j��l}D���t�|:��mZ�lc��j�)@|m7�N��No;��W�]8��\P�U�-ge����#���*zO
�M��GA�<zO
�Q�%���� O�H���j��bh�TU����>��0td�;I2�	����eta��Ta�����*�O����r��q�2GlYh5o�� ���w���_���\w�-��-
�v���X�r��t��.
���)��V��uGYi
��j+�s��OI���i��������o�T|�,���O~�G*��M�s*>f*������k9���3��8��b�������@������-Arx���Y[��b��	7��|���N+��^1����b
�t�'F��X
��'2���j�B��m��D�R���q��ek���pz�T<���tz[��;�3R���q��b��64��R���s�n3_�m�P�xB�R��T����W�����a���j�&O8�Z%�������9[�jYn \��X(���,������@t3R)��P�
�P�s���
g=�������nW�U��]|J���3��ql�T����K�E��HW�o�����T��j��<�����2��k*���h���_��>_y�����<H�V���A�� d
Oet�f>�IV�A���u��R2H8Y���F�@�QY��_-T��xM��<L�X�<�����NKa��|xm���O��f�����f��0y
�u���F
��8y���h��E:OQ��q���G��*��#OQt��i��HT�?|-���/��
xY�u�1Or$"�����4"���n�{��M:g�����	�A�.��&�
�������
9�n�hI]}g�����Qx����o������~����6]���p�	�1���q6�Z&��=�Eo�>~���9 �k������P��{��gC�I��Rp�i�K:W�3��0���8�V��'�������U`�p8�v����:���u;���Mr����C�@p�0d���u������ k\�v��kH7��P5��Z}��x�
�f���5�C�Yp����Hl�F��z���D:=���v��)������5����6�p:g%����>��l}�+�f����w�������4��c�Ep5�E�NK:���x�9�7����=E��/���+,E�ICH�h����2�C�iH�nt3_P�!
q��
�C�Op5��+<���/������3�I��l�f#��+�f�OI���Xx�-��F���-=���8������EKi��"I��k2�d�5p�$u�����|������_�@�ZH�k���
�3����M��S��q_+�2;o�s_C9�]g��h?�����X,� ��	��v�r�%,�P�WDc����S.�.�p��pAtq��!����5cFC����
��"����1���3�.�xx�
�AWz�)���86�J�s��>��&�.�x��o��R�.��N���uqMv�M��G���K���UMQ������S-���������/i�>N�����x�B/3�V��96�0kZ!�Sf���S[p��-�p.#�p�p��G��k-�bk�Vt�'��]��f��nc��x�������H�������o�/m��_�F���C�Wp���K��R����%7J�_&Vn:���tUA�q���o�����R������[��>��*���D������J�.��4�9[�5-7Ni-�v�2�4��V�����ZXY�q~�9\']n430����/��P0(���bk`Vt�
�f����H:c�`;'L:62������QlW�����Y��8���,����i`�����HgT�������a��l�M��9���;���(��\�v�50+��t��*���`�Vf���Q�l��Ug��]{����7Y�G���1�;z�{����/��$���;�7�Q��v3���9Y#�w�8���2�^rE����3��d�(��Ig�d��l����C?f�:����t�M�����Ip������@:�&K~�u�J'3u�vc�Ho;�:#`5��c;������������jl���|��|A�V, �y�q���Lc�}���k_���uX��(}��xAY�(��
�Q���'�`�df3����
�O�:n<��Sp5���+FFG�����m�e4��feg���M��n���K������|�.a���j��%	���z ��p��T���'�o�y
[g�a_�����M��x��Z8����O�q��$�#���������Fl�0q������8���%�1z�El���KX����obL�������8��)a��+<n����X����%�d�=�J%��s9�UqVz@VTx��q��%ot��5-���R��L�K�B�%t�Y�v���G`>��*����rM������?WL��b������kR��n;�� �c-�����Sj�T�S���"��������/�����������������o�����v>f���?�9_�����������O�����YO~�e_��|����������|q��R#�^~����������Ewx>����7�n���^������Y��T\B8xtB{�gX+��^��]�N:D���hs���!.���gLL�� �
������wB���/��_���t
�b�=�6nx6V��������U[B����,+�vq��@�#!uDai����&3�������0�%��%b$����9�������f��p����V����N+K��*z��t��'#�d6���"�L:#5]EO��n�L]p�i�$�J:���(��N�3
�b|w�B:Cd��vDV���.v�����Q��2��j�]�tO7f<Q��u��n���g�F��@:C������t����eLOJ"H�2g��$"��D��j����B0���7��yu��a�H�a�&M8\�B�\�l4��o���
�-w�1�5��K�r��Cb_x��C�F���t��R��r�������3�4:���@�h���7��a6��d�s%���F�����>�n���>�lt��^��c�fV�^t�������|v|K���i�*���(�����|1�@8h��V{O���^�=�5CV>lWZ��s<z��t�����S�([<���.n���gHFcrF�]���3r���E��tH�
�1����p����������.F��U��9�]g�vq�l! sGH=RX]�dI�^p��\�l!�p�����;����U`p��&�^��u�0[h����������ur��9�<�z&�Yz��<O�
g���\�z$��������S��$�D��t��b��"]�<��j��^I:��0��kAp��V�H��+�t]���*-�������o$��-�%��nhU��o�aO��g�Z��O?�8�FG�uao�Oi�����9�-�6xH�P�x�}���v���f���fH�Cb�C,�m7�\Y�>�_��d��t��.S��.eyr�^��&�����R���
�qf�taV�B}
�U!W�9�Svpg.QY2���K�����M)�����N�*n�!m?�.6�.�R�$��O����qu�I��u���{&\��9����!Cc3u����S�D*�:�aChm�#	�2'n2�=�Jw�N^[ikpM��^hJ�T���I��/h�kF�)���2wJ���2������?Oj�U)��{��9e���O[��������E��y^
|�=�%L��)�y���I�=��bZ�p(������J���=���9�!��F������'*<%�����]�����bfx�9�.����8�Rg#��{l�=�{��)]�=�6^2x+�*���m�dXg��	�'�B�Qp,��o�J�2	���
��~��8�8�Tp���$9N8�ci�f w&����o>7V7�z�)o���f�V3a����a���r�����vF�.N:�����h��v<�kk�C��E�[H�����]Spe����v
���{�=� r)����O-]��N\zl����l]ZC��tz��
�C���j����<�[]���Z:q��������*�+�[��P�=A�a<f�e.�L�N?��&XKI�>���_h����d?r�0+��/�@	V�a���v��%L����
��!l�/�$X	7N/�4��$XW9�my��8Vx������n�����n���f?���0	V�a�����+]�0�1
������5/�ZoJg��	�`%�B�]/$X���`-��e�?���^AB2��������s����:Q���� �K���\;f��hO�������m��Z���_�����0XzI[&���)����K�����U
�\������@�_��������C���7WW��I#�q�z��(�K<��W�*d��v�v������'����Q�;s�m��s�� �|����(�11�6��O&�*1��r�����N�"�&�Is����2[b'#�3������t�-b��~	�n�����Pm�	G�����m�}s�~��+K����*��'�}<�������� �1AW������"�cI.�����7���'������
�M���
��Gsz�U8QW�]����I��(~����R%5F��8��+�������D��i�&^��9�f�������-x/�����.O��IW����5o^���[�����>R�0td�L�z�$JY�p�Hhd�c7L��p�I	�pAR����-���
��LC�~wn5���������u����,�����s�g�>�������qV/��J�l����SR����s��)KwIY�J��H�F�?b���:If^��NV�/���-l�J���J��ni]�Z�������D�<9a������	�g �8�UN��CWW��;�2��x\�r�{�2/�H�m"�O��-$�B�m�b%c�]\�D�+����
>��j���CWIW��:P�r�����sW�'�~�j�P�B��!�w�-�������lx�}9�������A�������'�l����-����>�<��	�)�v�2������=qFo/C{*�I:3������	��n.H����m7���
�����vJ%:���������[ 7\�v�::{����=����bH��j�=��DY�QB�mWd%��N�U�?�p��b������Hg�a���]��N�xVV8��P�y��l=�O��tz� ����osi#��+Hg�Q��Y�D��j��>e�t�����d����������F\��Ko;�(��F�>e�t3��'�UQ��#Oy��������}U0���r<�<��y��D(�c7�<�pP��pA��C�Bh-z�_����|A��9��R+z��F��G^��s��g��:0Me�>�c:�5�(�<�xH��<���#*EQ��G��9n�c��1���fLyD]�����]4�?|-a[�23����.��i	�@\x����j�%v&l�c�p�	������Ad��&Dhr}���YAVC��q{���%�Yp��+���]\fXh�]�bw#�..��������Z��p�T��v���/��s�t�q^�d�Fq�3/�6�HNpw7�%�]��v�]��vq(�!�&jMva�A���a�U��
o7���p���F��U���E�E~>�"F�'�����Cu���Q�Z����
�/�Zt4�r�s��A��0��^Z
�M� �e�-��:���r}Y�r���+���s�����5�j�-�[��2d�Y	�I�0�e���&��	� �e�!*��|��<������9T�x��h��D�@�e���4v��|5O��M�����3���9��G�,J`���,���r�D�������?��=�\g���b��,7eW��D��������k��������j��xW>W|�h�=b�A�(���X��&��U��1Y��8��Wo?��
���k�~�`���,��5)PLxT�	�z����8U�|,�..����@S���_|����s�(S����������q��Wc���f[p�1Y�]*&H�e
���V�Y�������2*1kc���d	�K�������Y
W�c��-����-��5(�iJ/_Y���3I'�2����q����2��>lz��Y��j�VV�k;��^Vc5��d;��W�]��O�a,�w��6��f�k�Xt��:��x������xG�D����.z�L��@Tp���tJ�tF����ql7�N�&��vu�|���tk�`e5~��3�(�{�=[g=���%�S9��f����������p��~��!������|$�1W�W��g;��N/lHo;���a*��+����k���@o����\�v�~��b�����U����=����1�Z�S���Q�5�w�������yK���$�������d3�V`��h01�r���ve?��g(�	������0b#�-��3�&\���M~�Ld�{L�5	���	#A!�pc]d��~��t�h��.>�Js���k+m�y��t��rc
`*v�s�b�)b#�q��n������Q�F]�2���������:��fP�)6���/���=���V�2��k���C��hV3����%�`����6�TV�� ����B*�=$�\!���R#+{�$�=����.���lr��.�
oSHUf���=BT�|�]�#{+�����6~�!�T�{�m��<�
!U�m<���
!�$�"��������.%��X�RI�0B*��	�`n��V��
!��7B��TNRE�)�g���R_)b��'�]�9%���t����l��9��l]�:��V�||1�h��yg�E�]O:=��e��pk�on���]�H���&\�U�o	�f����
���@�mWg�3�@MtA��`����7�1��Y�L��n"�~���v�� ����ZH�����`.l��Di����t�X�[H��(��F�]��a���v��O��5�U\4ka���'Jkd��R�Pb �u9��'�U�����,{QD~]=/	����#v�nf%�o��b���A�<���������/~�1b���EP#��Pgu#4��H�@� ��m�������9zA�_pF�6#��f���H���+���w��uFN-7���E��Ml&���_��I���"��_�����]�MuU����^m�w�0�b�)� �����F� 	���$���Uy�������z,	*���
����oU}����������O����Z�|^z�d@�����Qg�	
$ b��5;6��p3\!�=��EV�m^I*{�^/�H�rg�	��S>��x���6J��]����|�]�g|�Q�H�Pp������(M���"/��x	%�!^����\���P�@����;���#�!���.��p
�YV]����s	{���7���p�Ba�*����R�j�?`6�5�D*��+y~�����/�������
��3Vp��Bt�
�zG:]���v��W�]t�
�����6~��t<{C�`�����3��
�����C�Rp5�E�L��tz�2���_\�v�$7���L�Z�����g��w�smt�
�&�������-�f�����m?��sa���7�dHn�����I:�7���Ql�H��j��.�!o2#�����y�����&������N?Q��n���e]0���v�,FS��=QI�e1����_�����n�$Z������z���������Y1NJ�����'�g���O�U�����J�g�5�RQ�Ws#�H�E:�\��2`�S�J�u�8r�
���h���=Fcb�	D�E8t��C�]�<�!�&��q'���x(^-�s2��+��! �]��������"�J�_���13W��(���St^�C��x�"�:/w�yu���H���?b�����:��n��u^G�o
������_������R��|Yk���0�nd���.������N�HW� ���bsq�YD����w�����A�o4J}���d#k:.scd��`�S}w1��	�z������[^�F�����E%��j�����%/dE�qk��Q��kV���m�q�;c������z�pk������������
�&�2��}�/��<8�s�$L����c0�k��a�����G(��G��p#�Z��P�S�vb��H�w��������<]dQ���#���
���"���"�ZVt�#�~�XSX�������1����b��t����N����l\�v�D-���<Uz����b�c�&�6�6����c���w
�%WyOYo�(�k��'^����Rx5�EV���F�nez��9����JF1^�7T����a<^f���*����5�L:�2K�LaS��ly�������F!�u���j�K�Z�����`��v=�<'��{�EnQ���Hg4j�����^�x�}�}&#���
t���Oa�����e�������x����,�d~E7�2������B�����<��tM��l����kHO���H����!�}��a�}�/_�@q^��F�#�_��4���)"�Wa�g���SCNK���;�*I�������-����9�g���F��u�����p�	�Z���	����ca���
!�]�q/��X.�w
�7�|S�q�$��e4��`����!�k<�b���,VG�R�5� �=�J�4�����ie�����-��9o����)�]�!�"��R�R��o�m-nZ����%�y�+F��kD�����t�jq_�����}��7�:<�/ux<��~�%d�����������@�P~!�������
��C�Kh���qW#� ��-����6b����@���b1F��2��r�]�Y-�����}'�p"'t�1�%�V����k� 2�Do�����h���ef�({��:F��:���x|�v�e�U�T�H�C^�Lcn$|B�y\�!���z��}�p|1�z�G�����c{�~iWB_�1U�����-:_���I-F�,�cw�X���:��"�?�<��Zpc<��^V=�o�]D:�l�]�;�7O��yt����Ro��6f1�}���#�Dw�\p5��W�o!�~����w��]0ey^pc����r�}�z*L:�t#�6���}:���Nk�����}-�B���2���^���3Z�W���]	����	=C`N����=7�d���r�1y	$L$��zfc��I$n&���4��$�7��3g���b�o��:&�H<��Qws]iU{�I$o�i�i��=�JC�t��V�
XEY�i�)W�����
a���3Z��n0�\&�s%���N$��9*x���WT��U�a&����~n�d�S��J��
���"�;e���[�,CCD\����Nu�wo�Uq~�;����&z��p
�rw��Yq9�����P^L��������6�wc����)4�..
"m�R����U�3��E�t#��
�%7J�7:I��K������9T��x���w�gm��YY�R)����Je������
/��}�Y�������19����CNhS�Y=7r���Ya��9�����H��E�g��]pc����������#��H!���"�����vT���x�r\p���"e�^�x��_�1_V����3���g���gsmc�at�=��7�QeD�sm��YI�G�x}T��Y�]���Z�L��F>��q�2Mx��*^��%��o�}�s���������Z�]�G���=���P���YA7��.��<�W�?P������~�'L��p3�t%�	$�
��\�=d���-9Z?sdI�����Gc�`e����Y�7�������/R��V�j�e��������)I_<%�J�����`�����:%��%���W����gy�Y��m~����Tg�:����wqZ�6o����"��f�'�y���%]��������_��|��e������������?�E����y�c��*��.�I~��N�?7��3�f#�v��F��;�����|�O���7ki���m�!y!�����	mn �1�V�[����K'"��"k�-����	zZ��������O_�}�������C�����������?�_������)s��M%%��}����}t�[����/����:�����)S���is�*4���e�K�uX�����7X������Dk](��pp��v���3K]���]���?�EVn�Ro)���~1KM:��1��U�&R�n�r����{�bmcf��� ���WRY`��u �	�j��j9�sLV�9j}����5����>�����x��p�]G��zs������TY���\��]�C@]p:��@��~�qs�z(�U��;�&Usve����� o���B��	`���V����
�:$R�����`�����M<�z�7o��u0���x1�7���i6.~q0� �^�x�g;�n$�5$5�����V]�o��_Y���	]���W�M��.���M���h�����v#F(��~E������y1�����0|�X�eN���1��aR��C�Eh���
&�Vuq���`e�E�����9L��x�]�F��U;����%"��{���iJ�w��9�JWMi�n�vv��b�)�`���,�����{��N�������=�����b�����\�E�w�
62�V�g4%��s���-Lu�0
�K�R�������Rw�y�?/5O�_�B3�Y>�W�����%����K%��������Pq�Ob�������������wQ{Uv����w��${#��T�r���o��}#**�O4w���o���H��v�V��0G���z>{��7#���p��8�p7� �\E�`�C��
'�7�����h{$�W�N�"p:��O�k,U?��������J�����~<���>�����t��\�+��������H<����J]�����_z������_�����������}�=OK��Z���,H��t��������'�>��~ ]������{�����_x��������_�}����~�#�T��^]�R�H_����/������/Z���/�qw��}�S�U2"r�"7�>��\��3����Op��W����������}����p����j�<,:����\�\4���.�� ��8_��g3���*WN�����dt�h�B	��9D��}��f�/|��\~��a�����������^=.iz������i��S<�p}��j_��NIa�p��nX��ev�/�]����2{���������{f���J��_x�W�`�,�H��� �,����4`�����R���+[�4�pcp��Z6���|���$gU���?�`������V}w��|�yJT�O���!�Z����w�.��%v��['w��6Co�x��E@s��y��o��nyW�N�HB��Xf�5����w�����s�����G��Y�o�5��9�����s�#���_v53��DDJ��K��']����������G�����x���7�j�o�/����"�*Wb��O
�S���E��KV�h�hMT�w�Y)z�Gx
�G�k�������X�U�c�,���S�����/yA����F�Hq�V�H[	�vY�����g�_g�m�P��!N��V*����sGW����)�?�y���K,}�n}���k
����M������3�������������y}�������}���1U����J<8���|�d������K�0���s����!��|�~���	K.�aK�������s����
�-�86�g,�d��������P����������>c9w��n���	��G��j�O����s>�����3��V���t���������?��B����������wdT��K��6���{��+�IT��D��_l�MU�����t�+)=���G<�M�GT-
������
���|�Q��@�a��]��>3�y��I}Z)�^)����U����`�j�z�}&O�*Eo>�����u�/��z��6����O�
��������v|d�v�}���v�<<������pp8��cs6efU��;�w������[���?�'�x�=[q�}����h>�*���yh�����!	�������������	xjhO<����'�g�]�����ja$����I��yb�vZ�w����m]D����o���.h�i}�J�����._�����sQ^����
��]~�Z&��+�z�8���+��m�'�X���IWX-/��3��$�Vt
�Z�-���|����{��p�&6~;�-��-��R�'k/�a�W%����=��e+e�S��a��t�>��y��w�w�g1��I�7�%�[{�m[��?	���Z��h{��-������I�O�l3������"�#���E�w��������r|��?�Y���%��{"�%��8tX��P:Y���.��8�w�?�pD�����{��*~.��EW���4�_ #�c�M�NU7���6���:��{�S.�g��~���f���I�Y�,��k���Ob��b�������ly����s���v���+�/�=8���2������T���������������g��&��B]p:KFx9��������I��������%o8�O��:����(�?�G���.9w���l��9���^��r���h{���7�QN���:���������S��=2�]~�V�����,K^��%}�1��Y������O���8%1��w�����������Z��(S{&>�J������v�<>����3 ���R��������/����i@�W\~en���K#�.���?*v/Wv��-ZV]~�Z�����)C�����[�~���?q��<]~���o��{H)7����VSA[tA�+�x7���]������Zt��������_�s!2W��M\������S��B�&�~@��,7y��0���S�3�y�����w����?���F�./���e	J�sEw���j����� �}"���q^8�"�?+FD�{dT�_~��'H���/*q����C��H�oO���/]��w�x_�v�V�L���>�t��Z��w��t{�Le����p\����0�G>�f��#��ped��Y7�	���}���6�s1��mX�u^���l�mv30�j<�o��>��#��&�#��Z�#������W���������M<N����k��ob)7���A�&��v�hi�\�����'�l_%�{{�{�����9�D]K�[���(�Vt�%\���
��y���>���9.��-�R4��]!�E�-��`,�q���]���qQ�q�g^��������E6��Qj��?����	>��.�qA�
t�����bWtHc.7`����������q4�&����{w[)MK4u��	������q�l���������`�_~��7Q�W�x�8����P?�	�Fu�d���o\!��"����
��r��2�\~�^6[(r�J��W����b�����T�?|�&r@��\!�c���x������5GjE�B0����]�������f0�����Z�s�z\��<.����3cY(�9�����?������l�^��qA��(�'�3��������Ul��{K���]���7l���r���,�=��`�\�����p���[%����?��'�<��U�=�.y��y"����6���m^�C
��`����VA�/�Q�Z����F|e�y�|*�E��_���Ol
���,�:�6wz)j��k@��Y�.��eE����k�W�y��'����q���Et�KQ���9�����4�H'{Q����m7s"��6�Pd/;������C�E�Zq<vQ�*����t|�
F��#����A���W]\������E�$�.������r��o���D��������7�����7'~��Ov��D��a�d�!����[,�%R��-�6�����T�Q�w�B2eE��p�-��c�g�c�z������o�s���w��H���Ytm��G[������
��������o�����_O��������o�����vNO���_����r��������?���?{���Z\�
�,�S�WJ�Z�!���F)f�r�[)J�����\dL��������{�#���W�����m���N��yVH6�ki�������7���"���d�.)�����K����������w�Y,��e��x]�o���w���~\���/�-��V�}[�E��������D����������F4�^�9{}�=���x�R���kV������6�o������G�K^l��G��*<�>��E���o��|���<����~��k�?�C��������U���x�zG����z��tO'�J���l�WI��y���FE��~�����\��!��H����S=��C��8����.?Z�e��o^���&�kW��-��m������g������y-�C�Z����^�#ZM�Z�F��7������e������PB�tw���xS P.�l����������-�����Zr�Y�o��>.�i��~�%rJ��MW=.���Wp�W�=��#w��?�#�
����59Z���_�������2�7e�����]����ct���-�[X0M�&'��h:��]z}{~��}1���Z�S|��Oq�/���w-Rh]�WT�������;��v]�OF?�}�����u�w>q�e%j�O��^�3���W0o��y�>o�Gx�����+��~,�
�y�=�z}�u=��~�"���t�N�u7����^�� ����u{WY���G���Z���5����GdP���xAc(�������4N��u{�	���u7'!>
z���g�r�'k_w��r+:�wW�������g~�����2K�\��F�WjD�������y������b1�s��O�o~Fp���s|A��������
(�?y����sx���s���j��M~�����Z��*�U
}	��������U��.�[j������Wn:N��Z�RN��*�9�^k��_X!. ?Y��"�M+6D���J��.�j|����Ma�o���8q��b�7��������J�m7���O�K��a��CTWp��x������lDu�w|��|����u��_w����/3J�yw��[#��8���zh���3���nS���������z���I�������7�����4����r���5�}�r�<���
+:�t����S�cA���s���[��?�c��y��>������i�8�o�pCh}?�	�O�U>��!����\�nC�����n���>xy���R����4���^����J��M���+<t%^�������^�5Bi��������N������D��S4��ES���N��:p��#�]�J�����oXr��T�I�4����z�k�r�����cG��!�f"�8��pfr������t�c�-��a� _��e'�
G9��Q� ?H�j_w��|�����]�e���\�����]_�G�2��]��.7���
_�"\����6�����2=���;�D��~�����k���p����\^�l��}��q�]�k�!���r/���?�p�}��e������w���O���S?�-�#�Q��P,��
�v�h7�e���&|�66�����(��~c�M~��V7�[;��C�"�J8�ct�k
��M����}�������?~O����f]������}�I�OW�1��9��'42����2�m4;p�;>�\>pzI������V��<d:>�>�����������=O�������Js����{����L2��*a�n�v�1W
����
K�~�����v�EF�2H�A������Y+�d����V��N��<��u�$Hp�#I���NL����c
��]�7l���]y������Ka����C���
�|L��h�����>_��Yx�~r�{l���z���~��z�e�},i�?�t�����������a���������iD#a�
v���g������
�2M�u���O|��s�����\?��=��{�~���_���������?b���R���~Dv�4�G�/U�P}�U�J����0�;�i����'?`��<]������mU+��u$�o������z~�w$e�����ntBY�t"{��t���P-������X��O~�I�V �Y���O$3�d��=6�!��=�9$G���?Y�G��y6���������a�����0<�
�#�t��g����0>�
���:�C�4�Y�����/&(�G���W�oc5y�
�^Y����pN��ld����W�-��s���w�V>Y��t"�
��R=^F�E��-x���\h�}3����{S�wx�}k,+�+�:~���<���}�|��"���j���
4������}�C�-���?��5+���oX�r�����<������|����CFw�������
�~������
v���������Hg�O4����a<x�k�>���w��	�0���E\�N�+�iAC��+��?�������e�#�v�D~��������,���p�����}^�K��m����}�iq���nz��Wv�Q�s�g�f���e����\:�&D
�����~E>�2Z6U�o�8�.���+�����}�����8L���h�>�D�@7�����1��>zDw$N���>�y�g��<	���O���?��T��4��+F�y'���E:�<Q�K��h1N�h3U��}�.���w��
�f���.��{�p�j��{�m����&�
��F�)R����)�o���l���/r��~�L��%p-a���9�d������m�X�?�����9�KO�Bl`[�����}c���<������Ps)������yv�t�9�An�~[�d��v��������$�=sf���?t{�U������8)������G`���\���l�>��F��A��t��|�zn����������������Oc��/15����VtD�A��}����#��^�k��v������r����%���khr���(������Z13�4��V�<}�L������?��W��� �Ipt�S���7�.UHZ|�=}�O��j>���Lx�}��LT��a���7����xt���������y��|�Gv��yv�������?��#�~U��k
������-�v�M4�*�I�ns|uw�����~���s���:����s���������_��_
.���\7��/R������"G���u��h���u��"���U��VXu�
\�)��:����K�n�;�Gl��R�����\/��K�*��Mfc;��I�J0z�vL	f�v���	2����lX_� a{���mR�m��Ax��������B���8����.������M�4�p�����m������Q2�-C��������,o�>:ff_��-�l�d��������I}&�YS���q��eN+�����O>�eGl3���#O��e�i&�?�eOcs���Q��5e6��l.�K3�A�T�r���>�7l^>��]������{�mx��+�
�oot�
�m�n,~��6�,_���an�������yG/f 	l��e��i�@���56�@�Nt�z<����E����E����@�[uG1�������C�h�o(�
&"���Cn��{s��op/B\�e�|��gj~��
�62���|3B�{���������F�s
�����i�M'�����d��6��oh?<�Ga���X��oG����{�zC�A��(��6B�{����w���B�x���qG�-o���~���eC���x����s`�>B���_�6iU�?���9��@C��	�s���7�X!���?s
��n a�����%
�'5�f����a��ml���������0�:�P$�=1�
1
c��E���L����3���8�P������q�e}����96H��h~����

�#F�)\hY/b�\8D�������g5�>��Y����
�!�sIh;=b�k:G�����R	ml�"I���>��u�����}���p�f����@3��t
��%��a42���6�����-��66`�h$�1=xL�����WL�����p9L>�m��$�+\�?@�9e��A���"���#k����&F��(��kw1��-�0Y��&���Z�(\M�L��m��d5h���$�^�xk���
#�����������7h!(&���$+n� ������ows�6�O��1�����>m�������I/�%��^�K^�',�y��^<$��o��z� y����g��xHzq�0I��h���_���o�1�
c��
�����j�B� l����-�2&q���n���=��.�o�2&�P�E��~%i�y/�xJ�d�V�2&��&���j�$>���<�HH��o��2G��d���d�N�#c�o�HT�g���������S6��z��G�c3�Ml7�x�Asf�P[5��o���\w�qu���iG����w���P�
�v���9d�v��
c���[���0�+70��L���9t��O���N�������]tr��~��q�C]7���.�����Ftc���4N����}���E'�xc@�^l$xe�x���SR���'7H;b��.�3�Hxbq�ml�v�F������;����}8�}�]��v3�p��e�����.<�]�]W�
��,��s�?(�X;Y�xN���0,�<���F��c;�o����
�0(�xVh�������d��!�
��&��
����E&��c����YM�����I�y� ,����-�0"�K��-_�5h<��dT<6�H��N��Q��u�?�]����Hz�e���d�`D/^����������Z?���G6�����9�7�Ml�_y��}6[�������MF�$z�=�}�+�/��R��o�[���)���r#,����P����aFK��m
M84��;�3��Y�8;0��e��F��&\#��,��P�+\:`xN:r
��q�`�%���`��4��W�,`�����pEG^�A�YE��&\����#�����#��#gTa�:������aH7n�����y:e�#oiGn���EJ�����u��\;�nd��A��������++��a��u��f�����a���f��Q� z��������z�����v�"��@_%��	�&�i�@3}���<�LJ3�ad�����`�o�@��E}���������`������;���
��uw��_3y���;���
���`A��.g��!�Mpc6�J�0�����7���C���7J�j0��(�������$n1�@3sg22u�<���Y��aP��C��XMW����n��0t�2(�zh��z�ay�#X�c�Il�x�	4g��-��MZ0���1	����f,�1S^�� -�h�W`S��$X�� -dL��� �d	nl��1I��%f[�$��%��[�$3���(/��������-c��G
+C;�i�y\P\����2&��-�Y�����t��K���1	�n�U�K�������S:*�"��I6���/��<�,��oi/n�l�o���I0Kpc��Iv��(#�2&�������IT�w����$���c�C���@XK]=&���%���$��G�G��xo-�[�aL�a0�4g��k^n� ����C����d�;h���c��X�K�$��
������b�LB.���l��~D
+s
gT-��X�[�aL�P�}��}�k[s�7�`�����(#�h��Q��\,��-�0&�#��|��}�b�5����6��)=&su�aL��A����q=��f��C�%Su�k�x�:B�}��_�Oi�����eP�!YG�9V����i�L���eT2)��ZwC����l�1]��dBG���[�Q��'��[�%9H�\�M����-���	%G����3��	n��-#�A�9V����'u4L�W������X��T��c5xy+��(��}4P���S�����U�xTGI���N]��D?^��n����
�8��R�rCbb�0s�<��o���R�T������%�f.�{d=�#���xL-�YT�b�����S��ta�E����t���S��'�?y�|a���'�?y�K�-
�#Di�de�z���)�kN)��4P93	���W^���+���l�L�G�B�����<Z8�	nl����d7�(��)����`�,�[�a42�xT�B�[�������C���l�Lzq/�9�IT-8�i/n�L�$�@s�\{4���)�#�4H&��3�;r*$����+rL��drZPX�����jA�o-��UaZ�$��4g��Y���h���
�2&�PE�9��I<T)�X�n�Lb���LQ�������b�-c�	�x�����Iz��^��2&	P�N���c��@pc��IpI��_x�`��������2&�%9��$��LQ� v�N�
9�eL��Y��>Z�r�dZ�E�$_��eL��Y�/��r������&%j�2&Y��^�z��%�6���d\l[�$������$j�[R��-c���M����1�����T���1��g�.�[c���@�zOj�}��{x	4g��1��u��Kl����C��}�o0tP�Epc6�IB�!F�j�W����-�[�aL����`��L0P�Apc6�I���Q(��*�$�B���-�0&	vE�B�V�o���-�[�aLz<�{�r�W~Q�z!nl��1I����V����=M7�`��$xVBKSu���Dp�
��1I�������Fp�3��-�0&	�a����������n1Z�$�j��x����0'���l�x<��0'��7�aN��-�2&�����Xp�i!��Ll�LxVO���P�v+L0����l���I������i!�����If����V�W��g����]�2&��.�����Y0������]�2&Y�E�w��\�<���2��1��^�/����ZpE/^�^<��IV��U�����N��7t�5��c��dC'�'��s?�L�oi'n��(nm�??u?�_Z{R�[F$�ZL�_�\�{bgqHw�-������`e����;6Hf����%������w�����a@2cs�,,��oAl.����c��d�����\�QD���3.����w���l{�(�_�Y0KV�-���x�G��d�PDM�9a�y���-�,�v
���V��������S�O�B���<hA��).!�������lhr
#�y	�@�-��	*[p������aH2��g�|��k�3-
ks4���5�IfL�h����Am�s���/
-��	4w?o&��I<$��h���9ZZ"O����-8uh��:�Z�$������<��c"���l����A_�&�D,������I��s��}�`F�N����%��[�$3�GQ:����\�I3�6���-���"F�]����-�����-���I�(�XwT�\��^��$�eP���B7��e�iA��5��-��
�x��8g���c*���l�`��%d[ZS�s��{g5���2p��}�`��
e�ckOvv��A��2p��='-��8����l�����=?|��o�����#�B�aL�t0d�@3�`�9�����
C��������*�\�m���l�,29K��{.K��Z�L������b��-�n��T�@�.l�.�0Y�
���u�_2��H�'�C�	nl�������%��h��/�{x@'���d������X�Y��E�lAxg-Q�,�0Y0K�Q!c5�j��2�!�a��
�������_�����S:����#����Q�A���K�������������`�����S�'kfB����{ap��0�opB/�I/-#�	j*4gA�l{�78Ae#��-�2$	��?��f���~��8���eL���@s�}��g�[�eL2�G��-X��!�7�`��d����>|k-XEl�,����,�X;��
���K��[�$+��h����j�xY���&�WC��dC/^��U�!P�~�z���b��Jv(p$�\`\�#����ci���-���x�7��	k�-;����c��K�M(8r��������,D7]��d����P����L�vP�Jp&l���� ���9{
T?��@��M��ah���"��
k_(��jt���a��d�A
�*rv����aMx6l��vA�������6���Ex�����~{7�)3U3�xn�|o����{����"���x�e�k��^���[�k�(����F��xb|����l@PAn<��G<��V�G>/I�5�ok���hh@�g�(��3�R��A�Lp�����c�	��<e�l@�	n\������FK�
X��k��s�Q/U/�4 �^P�26��p����RkCb��0�
X�|�oZ�YcsNf��f�W!k�W�g?�����i�<����saF�~3�}��~-����������P�E`c���B<�g�v�v�@�%���W �]��~_��#���[�������7�����qr��������������������������R{���o?�����_3��o��a���O����Q�s�f���������w��Y���~q������k�m8��@3[���P��hR�a�����6�b��5�c���[4��>���q\�&
���^}y\���A�)--�������,��`r��i�mtI����T��l��[r�m�m�E��(r���~�;L'���n.'��8���.����m��m;���I������v@,��-�0~��-����t��f���[�ai��(��<�It-h@�!��F$�
�@s|�([T�[�aH��1Jt�u,]���[�aL����=�Yp�Q��8;~O���
c����Z�_�&���Epc6�I���^�f�}�0����%1
c�}��z6@T�IF��nl��1��3t��$+&�GxQ����`��d����`F���zq4��,�2&qx;���siA���b�����1	V��cA<����`��d����:��\�����d\���Ip�7�.o���8`�-�&��I�h��3Z�s�sf����,/�[%3�q�������n<���eP2��5n\��>����5�Jph��,�W��w�,xG�
��-���x.���\����-��/�U����<�^��e�&/��eP��e�	������
nxo��xh��#ZP����8+a��xJ��b��ePr@�
���������S�H6�-����4�
>?U'���G�i�aPr���Y0��H�&9:��:�Id��1���
�yQN�#�S@l�8��@��X3-^|DS
�z�aLr���Y�yL�kAo�#�Q@l�8��@��X�,��]|D�	��
c��h�E��=���>z�=�h>Y�aLr��=��j�^�R���!��
c�c��x�X��y^<�]<&���aLr�x��]\��x����aHr��q���
��������eD��&�V�W�!>p�=��
�2 �xG�z�+�!9p�=��
�2�������Rw��B�Ai�t�hR��k��8����l�t�hT���$�<��66`�`dF�f44 ��'��[�"��{D��Xy���S���e��2���#�m�0�C/;�i@|HG-�d�����.��0`�����in�lx����C�
o�-}��D6��7�k�r��[�.���
���FL�W������)�78R�Hg�]�h���}-���#��f��7����;�x�`�h��1������?���7,�U���E#��z��72e��5�6�[����Fn�v�(���l@�pG�]4r�8�h����#����=����E#�9����.����o�<�{$W��v��
����>CP���m�'������#7��+���?�5l;8�	ml�v�Ho��������5pB����#7H;b���G��{k��&��	#��[�@ss���Z����C��F�F#���0��]�9��
��	nl�������{�5�e�������O
�;�U<^�Q��lA����]<5H�8���8�	L����-LS����bZ�\]}��O�1��85I�C/�f?�Z&��M��������eD�������ob]z������2"�u#w���M1�v�x)�ndj�@5�ty�}����G��I��Bb�}�7txF�d�)��Hzq�]�������!�4�eD2�`�Y������/�9���eD��G�u��1����:�����,�2"Y;�`4����Aq~w�7��SkM�{����^
~8���mBt�5��-C�
�x:�r��5��n������Jv��M��s�uM��#�iGn���p���~�/-�h�d�ehW���k	1
����^�rk��B�ah2��=Sz���j�j@,�������������S�t������z������khB<�����T;����:p�!:���Z��xd.E�}�:��8r��d8@�"��	3nd������&L�0<;t�C�*�#�v��M��ax2v����.iO��p����0a��d4��cT��P��#+���&L�0<�� yG�H|*�+|�#�_}��o�v<eE�k�q����8Q�"V���C<���5`o�1*�y0����w����&����it
8������_��~<����4 ���������]xH������G��G��3&n)�#^�c�2>���5�C���W����@�.��.|�-�l@|Q;��3��)�_�.]���]��i�
Wy�G�I>����o�~�c����8|bM�|�9'�*=x��M��b�~����.�e �z��>/���>���zL�@dFf�d4D�~�3���v����)c]��y_��O�%�06-�]x����������DV��E(��h�����N����e(��=�
u���
/��J�2��)-�t�oA|K�W������Ga�K�N���s�#�+n�`m�(��3V>+�zqT�soXkhA�h���k�F���L�m�8X�r�X0#Q���V����l���K��a�W������<�[�aH��
4X��`���Ag;����`���Y-�8}���nA(�%���$�G/�Xg�`A�B�<���}���$�_#�����d�[�aL���	��� ��C�.n���������1���.w���$nD/V�d��P�z�����aL�z���8c!����]����1�G/v�WQ{�b����eL�������-8�����I&|QO�+�$����|Q�-c�`���^���o�����66`��$�`��G���.|�����W��[F$3��%�/7A�~�3�3��%�H�D��T�D�\<p�1�w���a�$�f�,�����W��K��[F#+�%�\sv��[n�Q��6.�n�`�.��zbk.��A����������b�0���$:u���G&G�-��J*���
wh!��	[�#��&:�����	ol����v�r��7��
���
��X�r�j������Gi������fD�|�������)Mpc6�H���@3�=��c�.��-�0$��8j�}�`�NN���7�`���c2�G��T����
�P��4,u"6�J<&c	4cA��
y� ���(
Kl��`5���`�78h�����aL�G���Z�{16����
C��X���� v��(
{����xG=��H2)[��(
Kl�`2�@�-8UQ{|QGiX�`������`���^�a��-c�	�x��x����������I������o��wqH��-c��8�w�T�E=�����-c�_�����_�3��������I���QO�G��xIz�k��X~���+�����>=����Ip,�������<�x�����eL�S��4�����C�}z*�k�lxXKS��%��~�D��
�2&���������zB�@H������C���bM��o����������������?��������h�����������?��&E������O����/�������Hxx>Y97��=Md�}��������w$�>����_���MT�������!������T���^5��v(3"��Fp+��j_��b:z�`z�x�n��X0���k��o�@'��O��
#��E(��D�o0tP���`�.t;b���sm��4��7�`�.�b]����`��	nl��\�ZP���N�������a�
�@3�P�u-���Cz\�o��B	����wq�����O��
-8�hA~0��]�g�d�[�aHFPS	t��8��#��7�`��$��!��.�`2'25�I ��.����0��I<4�a@���C����l�x�4%���S�L���Z�$��h����\f���	�=���-c�`��8�����n�0����l��6%��-��,�-�}������q�����8 ��L-c��X��k/p	z�����1��"F��5;��,��[kI��Z�$+��+?�C�<!�&Y�.^�wqh�l��+�uZ�7��^�%�8��I6�����������xKzqh��x����S� ��{�.-c����������	<���t��2(��,�����N��s�:��%6�J�t~�}�G��	A�'��	�%3�����W�����q(��
�%3���v|�����sz(@h��8�}�X	^h����%s�����o��Wu��D�����F4]��d��J��W��G����y���&L�00�x�j���G^�8���&L�02�Gx�����GVz9�xv��0a��dvM�&cx��	7a�����@�'��M������	�j��Z�&$B��p|��Q6!��>)1��eh2�#G������c�)�3�h'�	�N&��hT{�E�y&�!��������w;��b�j�s4���K�oF�	o�%�{��Zp����
�Y��g@������^5��)�s��}0��O����	n<8���������>\{+����	o<����-�W���y�a�7��ki@(�������`F�S��i�s�{Oi�����s4�������9�7����k��~amv�SG��Xkmh���h\{�� ���DT������
�^\[��A�7�`��d���s4���#���^pT��^�mF$.�^����<��U?�g/����aH����EX�=��[pq��^�m�$��g����j?��-�0&Yz���e�gtM�yY���aT����Qv�� SmtJ��t�>��
c�e�@3��z���NA��Nhc6�I�}8��^���Gt�1��
c�eDy��G��A�N<&��6I�7�n�����7�K���eH�YY�X�v������t��H��!�C���J_&��|�����H&��h������op�SzJ&�m��$X� �sw�7I�7����~�2"	��!��o�<�-����-�29��`��d��
�[�eH��hA~���=AjY�����l�,��!��-��\{�`r��m���o'���Gu+��k2����I0K���$y���Kzyv�2&�v�(L��Xi��������E3}��dG/������ ��y���^����@L��������H�����i���a���w�����4��:7
�!9h�����b�=���6
�����4tU�]7T����>��A���C�_o"1����;h1�76a�(n�|�zD�	���$�5j�'6�V��'��	3��t��4�5j�'6������]�0��=��V����
��[�������<pd���a$���	4g��`X��p#����H(7�7�~�r|I�A����#'��������c� A���0���np�sj=z��p���=]784��nD�|�����������
SL�G4����Ok�o��i.GtT�F'��G4����/k�o���I}�
�����/�xX�~��	nl������[��7g���{��>��
C��G/�y/�%�lA��>��
#�G�h��������Y.d�����+6t����U+���q�7l�
3Ln�8�
[�UgT�`�H/�F$�Cl(0�t��.��c����E��<h��x��=<��G<���������_�G�in�L����g��u
8�[zJ�����Hm�@3|�T�v<�CR�[#$j���CP����I�zl���i"��+On<f�3���-C��A��~H/�~8��5����E����Q�fT2�A&'���)�c��}�T���x:�"���`>��d��k�f~�AsV|���9�����nl�v�
���}u���N��K�F'����T>-�<�S���.�'�k�f���u2cI����]�a�k�� -������k��]�q�k�f��z�v�>��Z0�U}C7�[R�r��������8��G��$S�d�@�[7p��{����%7HxG���7�"�<�&��7q�������a`
����#Y���%H���Q������}�tG�a<b��8w��p���/��L6�����5h���w��x��
h��7�a4bm������]�	���.:�0�}��]t���`�s������6��
��[��y�����/�G��>�0��p����w
�}����v����v0� �����8�h�d7�o��]x�����#���v����uPp��_����.9;~j�8ta���(5�5�GvI�Z�"]�.\����}���������\X/��3����������������3J�t
�!=%�S�H�w��5��	F<���,������Y
�����+�F)<|��(��=�~AsDW��(��'>������H����O�a��Cy�4��Z9x��>�7�`���N"F>�����k�iB�a��C����Y���nh ��G%'�'UC���A���3�Bs��
���v��\��������	t�%���a�/������&�s�yI/�o��+:�"8�{��Q6����&94������������&l������������������0�����;�����*�8��u�$hh�o��w��y�������_�N���������y��~�M�%F%V���(���D��L����
�0&��d�F=PON�3��`�����0"���@�
8V�Sk���A��k�X}B�?Hm�`W�7�;���a@2`�	��LX9+2���Q����eKn��cck;�`��>�;g���0�eL�9��he�o�!y��aH2�x`�u\��c����&,�0&F���o���xd��aP28tc��q��xp������Q�G/v��Y0��=z�G/������n�SF������G���8�#��#�{���kQ�q�	_�Q
5c4���f&c�1L!�0��:����[F����w��0��g�����sO]���3��9+�t��]xN������t�Yp�����\�����{�(]x\8cR�������2��U]����<��A��D^�.|N^�5�����:�u�
C�-��j����D�z��_s�t�~�;�J[Z�n��P�K�����A�op�3zO��5-c��x�W��&����^|���e4r�����W���C/>�^�0;�b�X�v82v��7�`�xd4=ZP�����h��Epc6HF�#F��&k���	-�K�76a��d����oc7�bL�iB�c����A������c�)F%y&��:&��	�%#�+ ��	����d��x�F�<�0.t�A(��j&���<$�6L�/�Ap���;eG�F�7�m��#���p#������F�7�m��8��@s&T�M2M���, ��Mpr��L�������
- �Npv��L���]'����2a��dBG��BL��$����S��[F'o�Ir���I�9�o���I�9H7r��d�9�o������<K7r���8�#�IG�[F'�������I�	��������N���F���V�NV��������NVt�U��3*��M�����et����
�l�G'��[�F�[F'���p#�����7�������	��	4g����!��r�2:��(�����;�$��N"�-�L"�B��������Ng�������=F���vt�p�=��M�0:qf@�x^?��vt���7��n�8�#F~��,N�z:G5��M�0:q���X���.t8����&l��9�z_��y_a�����at��L�K�\�i�p�=��M�0:q:r4������7�#iGn��q@J�\[�w8����&l�����h���	3�Rg�0kK�����76a���9�x����&��L��:<���OjhB?�	��~��|j@��z���D��eh���	4c���j���n�S:}2���0��@3|�"��'<���@��eX��'a��������C����A�3		���?t��y����c��dF�
����_��.<�]�e@���	tq�}��x����-�\<�����]�������e0�{���w�����k�����v����y�\��r�u�����-�:�����ms-��r���q�^;>�Ep�����g���� �w������w���������8���������ZPX<>���Y���nl�����`��~=Q����� ��gjhAu��$��a!��-�0���K�_O��z��)H>����gjiA��!���GT���h�d��k���	4��~.kM����������F$~�������.��y_ ~&��F$~@��??���~�8����l���)|4��TL����gB��k�x�.
.b��/�>���-��>���`���������U��e4���=_����q�3��
�2���>��`�������}z��o���q/,��\8����>�|��E�B�h������~��X����-#�]8�S����@��Lhc��Df�=����S52�_ �����-#�]8��=�rM���]B�e$�h@��3t}�/[v	md��e$��G}��s��/'>���-#�
j�}4�����5i�/�u	ml�����.��1`�����66`�Hd�jdu�>��x�kO��L-#�]���F2�J�_��.|�]�a$2E���w���%�/p���m���d����d:����e��T���@���
�0���h��z�~�h;4`�Bf*����b�/�x�\�@����oo�������������?���������������������}��o?�����_3^�o��I��#�l�_	��S��#*������Gy��GZ��'��l� v�r
c��������
j����n�
c����Ah���v�� v��t�h���B���\���`�7���!��Fo����?>W���A������0|������2U���?���C��-`���5-��
b�Hw���\��� t�gD��� 6��t�h���Xh������A�^<���a����C8�o��[�aY�a6)x�b�/�S+:��A�^��^�2$���F�_I���	�Z>9��t-��	�x�Gwh�0�#�������eTF4����o���0�k+��v7a��$�#|t��pz.�(�pFG�#��Kft��w�I�E�iBt��q�����rT��`��O,>!�	��L|WGE(&T|���p�w��|W��eh������I�F�j�
+��k2<6]��dCG^��8(��y&���7t�_}��o�v<e�Q��x)o�`<	^3b!
����s�]���Q9����ki[�=9���F�����������-x���HO�kg�|f���o�,��z������hiAho!����y4-��-y6� .�&��_���.�9��M��
-��Y��YP�a�gA=�s����jK���03�hdW�`o����sj��{x�f����&3.�&�����	�M(�0=���I�q�7��
�0&�x���n�>wb]�RoB�aH2��b����|�������l��nD�"����<:P�ol��!��[��Ps\|�J8c^���&l��1���m��g����)����i�L#Z�Wl��g�o��7�`��$�G��2�`�zqH{q��$����k��^��C��[�$3zq���y��,��%��!��Ls��}����j]/^���$��l��dY#���u�����n\�@���&l��M�O�6>�Q��7�W<��dO�m�l��+������pCG����2.���7�����D��1Kxc��Kvt�()[���L�	Y���e`r�h�9��>~�bu3��76a���X#��M��XR��K����l0�
C�gh�
)��]�/�!�ah����E�#r�Z�,�)}��d1b����q*[�c�[�ah��1
������x����
C��G7��>���0��y_a�~����ah���������-�mBt�>��
C�e@G�%G��6���:��v����2�#�#g<
uM8�#�iGn�,#��	4g��m����:4a�]�7M��j����U<��B��Mxc�M�A
K&3*���B��Mxc��M<:r�������B\�Mx��������K������ga�	��5%��
-��`����:��WC���!��nh��1�[��}�AV�
q�7��M�2:�a��m�~\p��e���7��	[F'�E�y�h��P���K��dh�,�dB�j*5yg��G��l2ZF'+4!h��c������5�prh�lM�/�������
��-�qrh�l���q�f��R�
wt�-��-����4g��O���o���2:9z4��t2c���#xT�~��etrl�Q�Y�1I�+\��%O�
���Y�@s&��.\;h7!��	F'+�i	4cB��.�j[\
���Q��L�0:Yq�;�N��g<s��y��:����Dl���$�}��C��h�dol���C�	<�S�k�t���@pr�������?d����0����}��<��v�/�"�������z���X��j~T��p�L���zX{����|���g�Y����]��n��$�i��	F��{�L?�s�u'��3b�\f�"[�
t'`
��m����<c��j��6@4Gpc6��6�N�9����}��E&�����6������Z����c���r�C/%/~�z�C/vi/n�m��	^��%���G/vi/n�m8��@s|�)[�Z�@��#��q�;�f��r������	��h�;��a�i����@_(KW��B�&L��q-���*��P��lB�V	ol��a�<�	�I>9e���<��Jx���-���U}�,]��8����&l����-�~�,]�Wq��[zz�o��#b�#2Vj+K4+�k�9��Mpz��L��r�}�8=`KO�-c��I�2�{*�8=`KO�-���I�2|*��l���et��6iz@��OeG��[zz�o����M����R�+�;�����at�wP�E���PQ��4!Tp���
����hBa�w��d7����S��d7���r����%��	F'��p�����L�^Hxc6�Nv\��G���	&g�����at����]��m\���kB\����nO
��;�wa���i�P6!��{��O&l����O�9f�]�&A/���|2a��d�}��PQ���wz�5��	F'���@W8���h���0��N�C�@s&�]��{<��������&�}��P1:�3���5�����4��%G��a����&l�t�(Q{��K�:�-��M�2:��=J����R�
1G�G��d���	v��Q��d���W�9�=j�'��N�C��'��u�B���Qs>��et��{��}�N�b�q�W����9�L�2:YQ���?��]S�oM��0��et��,�E)&�]S�o0����&l��(o��kj���;�����-��}C�|�N�D�^��<������N��|O��y��'��L���atrt�����X��k��?&�	6�N\�M�f���|���#�y�t
��wo�������&G>���M�0:9p��!,��3j�tM������m�5�N��}��sBd���o����k���=���9!��W�]�G���t
�����F��3�k�O�(E��o�������t��Z�XQ�]�g��(KK*RCb��03������r�tJ74 �i	3#��*C�u��h��R�DmK�-X[d8<�.YQs�E�kA�N�������>��>|�9�k?l�%������w
b��n�=��Q� ���Ekszv~�����~������~H�s�
�'� v����_���o/����4���1������
�������?��o���������?��O�����������o��3�j��_�?�����Zi����atd�<�����R��A	7�j`�u���o����>k���f�C���7D��|������V��t<4Z����7>���?�����?������<f~���L�l2��krpy�[��G�r�AF��1
����>�k�#bCmi��G����A�2�C.�����.�������<�D�,�SG��=��d��Q���� �d�`����c�A�AN[���*�����~{�<)��
�l����b��;����R�"��
���?O�0��/���})\*�,�>�CN[�����0�x
i�yR�Yh{��})�+��� B���W���p�+WEj����]W����5���<5j�j�R(���V����~��"=.�������^0V�.t���rG{�H)�-�-w��Da;rgt
Ai1|�X�H�77���p��!��������2�]{�-�{��U�sW�V>3(+e�]��&7�fr����s���+���{�"�'�X)C�>�=�hc�)Rcw`��Ksy*�{���Co�X)C����#��g��R��s��EM��;��y����=}�!�x����v���3B�,j�T��(M��=}��!��\�2��4e��	3c?5m*�s�������R��^+&*���jG��!Da�deu�8H���Jr�VmLn;}�x����z�T��
B{�X)C��!�d���S�L@������*��hO+e�
�ZI�m��*3/Q��P�sgH���Jr|�����m�P�����P����UvQY�2+>��d���S�����Je������M��S��_+{����S��1!Diexe�=0�8�r��
�����z�����k
����_��)]�w����2��
�%�\�N��(f�~�K�,�x��=}��!��8�F�]�����I���U�����VZLZY��c���q�m�PY�3S�]Y���\�@Y�Jr����qn;���D��N�)t,{���H�:V��;�k�c>�����\�����)���\B{�X)Cn��JH��};���D��N�)D����D��c��>��d���S�,�@���L�B����F$e+e�����&��v
����w�g�����h�`��R��_+;�/6[U�Q"��
�T�<��;�8��y�U���������mo"�-�E��@b���>Y�pk��@sJ]����2c��UT=l���=}����.9������-������
������&*e���Bh�u��r��� ��W�oh�����R�[�"����S��.�~C��s��(X��	�
B{�P)��/yB{�3W����1�i~�a�39@�AhO*e�����i�S��.���d�|���~�0c���C���T�dG�)]Y��uA��se�\?��f�|q�p���v�G��,�;���K�����I��r�T�c�����p��!w����L����%��"�`*�O
:�����Jr��<B{�7W��������45���;���Jra�����\]rQ��%��\?5��Q"�'�X)Cn1.�����K��!D!��\?5�����JrGr	���\]rQ"�������� �"(�X)C��\�	��<5�D�r+�O
�
��u��!w����,�;���KnX"�f+�O
�\B{�X)C������s�	Tj@���_e�jX0��4��c��>��t��N�P"���*�O
F��u��!w����nk�P
������������o��2��Z��M`��vz�13���P�Dc��3�X)B��-.�C�\o�.�������_�T��hc�P
�Jr-�V���\]r{��7K���/����z�2N8V���.Yw�7W���C�����B5�m���Jr������s����:t��O85�*�Xvm���Jr=�V���\]r'(�#�����	�
B{�X)C����)Yw�7W���!D���*+T���=}��!w����L����%wA�����SS�2����E�6SY�W|�,���v
��A}af�W��j�0����d��q������;���K�� D���*+T�����'�c��>��d��\o�*�.�>q�*w��FN�H�:V���:�����\]rm��8�U��r����>V��k�C�x�7�W%� �����J�z�u]$e-ez��u�q�:Af�W����P#�"(�d)���.��������!���UT�C�KhO*e���^!��zsu�E� 3�V������T��C���Cp�@�����-�@��VM��<�g(�s��u���v����,�;%-�r�,�����%Tn�`c6�V���/�%��R�u�E	� 3���O�
c�H�:T�p��#~K����u�E� 3�����3"(�P)���/�#YwJWV��w"��+�r��� � ���"�zc\�8�\o�.������_��)o!� ��O�2�Zx��������+B,z�T�2s?�.JhO+e��Oh/�����}j���_��)?B��j��R���@p�����)�}j�9m��r����Z�j��R�\yB{�7W�\�S#����)?A���5�X)Cn�\����:��O�03�VV��/t�	�Jrg|�����v��_6�������_1�X���p��!w������o�Oy�S#���*w��
r^�P��2������]��*@qaf�W�~������Jr|����s����N�t�o���B5x�O��u�!w2��������D��U���,��S$5$�.�����%w@��B�[Y���s	��;��8}��^���%w\�p,W.��F�X���Jrq�8�����K.�@�0�<T���<���H�:V�����	���\]r�!��d�<�j
��"����2��J��������D�r��L��!e5E"P��R�\�@Nh/��������I�C*w�M+�s ����2����_q�������D��U���6�6"(�X)C����-�Z��B5����%T.����>��2���"�{sU�
��F��UV����Z:��c����k��^���%��3c��
U��Z5�i��R���"��j�v
U�5���OM��;���F���c���V���\]r�I�03��\Ch�A�O��2�:x�Z���A�`�T#�i]��r�KM8[�0���Bh�5���:D��[LW��*("����2�|����S��.���F�9r+R�B� ��I�JvPH	���\]vWHpd�~�+��
�@���R��-kr��)�Y��mC����t�K��ur���R��4R�{�GW�����|k���T���3�=�aw���;0�|�KW�����A�9�UF5x���'Kv
|{�Z��.�vE�|���*kUsz�{�d)�nU��Z��.��C�|��B����K���R��J��X��^]]z�o�0s�\P5c��,��IGKz���\��n]]z�s�034�K�fy�YhZ���2�N�%	��uu���5���[Y���ni�������,����K�������+��*e��r����:�����>*Zz�gW�^��3Goe�j^!�6G�P��Q���Ct���v����a�XY��wH���&�w���w�w��^��N��Q"��+KV���9����"�.�����W�iV����0s��Y-�����R�^Z=�����K��� �������`Jp��-e����Bp/v���;LQz��5��;@����?[��;D�^��N�Z��(=^*�V������?[�����Bp/v����W�(<^le�j� �@p��-e����2%3
�zxu�
!
�[�p	z��gKz�[Bz	k;�j��(<^��j����������[�dJ�\�.�k@����VV��C��v���2�n�nY1�x��W���c/��j��z�B�p���w�w��^��N�Z�
!
�[Y�Z;��CH)gKz�>>�{��W���LQ�{m����@�Kp?
�� �t��N�ZQ"���T�����C��F�P��Q�^\Np/v���;lQ:�+�V��^�{��(C�A%�����K��Q�,me�jE]���?[��� �\#I���^]z�!
�e_Y�Z'�VAp��-e���KN�;���Ko��Y��k�V�������s��Pz��wT�xA����WS�2h��������]"Y�|k�.�����K_Y�Z7�6%����2�n�t����|o�.�����K_y�����=��a���(t��W���C�����?�=��b�{�d)�������^���e�,�Px���k�6��=��a�B)������.��d�~�K��*�6��M8Y�����.YIwJq�ew8��n��Ym#4���'KvGx��k����:��Qz�T��61�=��a�C>��^���ew�tAf�7TV��	�	���R��	�,SzU�)�Y���"D��2T���f�K	�Gq�-sr����^]z�:f��2T���(�#��{|�,���vr��uQx����m��c�'�I�2�n�l����������n����r���c�!5�	gKz|�����������/C�:��� ����"�������c���Q�z����n!�%����2�Z(�#�{{u��'�(��
�%���w=�=���w0�.YFw��W�������f�����gKz�����v����?F)��,Z��^�{�l)C��w�����K����x�T�Lz'x���gKzq	�����Ko8��>6V��������?[��;��%*`z��W��% D��2VV���������+�[�t�X;�j��?V��2VV��
C�M(���2�n�n���c�T�}G�����XY��=va��p�����w����~��W����Qx������:�����G��{��W�^�!D��2VV������R�^\�Gp/������QH)��U�K������������^����w���!,�3ce���Z&��Q�7D�uL/������?F�=a�[���{x(�&����2�zx�������NBR
�r��1A�Ap�_e�
�%S
�z{u��!4'���k��R
���R����s2�p��W��eE��D:WY�:V("����2���R �{{u��BR
��jul������:�����]�bo�S��@��������:�m�t��Q��4{�{��W�]�ux>�n���[������p��%����I�����J�s]���ntV:���V70�3�w��z{u��D($|]]��uC�zA3N�2����;�k�����
����Z��m�n�������`�����^]v=z�4���-�������^�d)�.L9���������!B����jV��M�`*�,e�
�f	�yt�g]vg��w��[huC��YH�Vgw�}�����ewE�X����)V9��
��0�E�7����poDr�����nBF�����
>�7�[�8����.92�\o�.��wa���[guC�o�����-e�=v8["-���^UzMw D!��+�U������=����	��t�X;��@��3g��S�o��Uo�2�������n��������|�)�7t��7R��pu��V���^����5!��{4`e��8�"M(��(C/��������K/�B&��h�������7R������V���^����U!��{0���Ye� �5�*�����7����^����w�� �O�E+3C�����������p/�����Bhn��w�TS�2�w�l�=����w�w�����N�2���~RS�2��1����\�������jO�8�S���O�]xZMug�������V��W�^���w$�V�z{U���Yi��T�;���^�By_za�����^]z���~��Z��tV������=���bo�.��C��h?��V��;���������C��p/�����:�(����j�I�������8�����^������(��Mz��y����������c��p/���� 4����P���x���_z�[BzlJ;�������P�;��R
���W�^s~�{��W��Ci�y������*�������[��b�v���!�`�Y��r���!�@p?
�0���bo�.���4�<�������:�����}z=�����Joo 4'��+�Z������R�^�#:|�����U)��:�B������=�=�����r:�{��W��! B��.T�������^vG����t�Tg]v$2g���U��eOp�{e�u�T ��z{u��+"r
��lu;G������U?��eJ�Ni���������a7@J����������)�S��.�z�0��v�E�~������������eIN=�8����������f��P(Dp�{e�����&����u��!�F�9�U���c���*}{e���E�'g����u��7����rw��a�+4�I�^v��=�{��W���������X
��������k-�K���S��n���r���C�Kp�|e��WD�nk'W
(f������rYC$�}|e�!�%�{{u��7���rw�� ���6��+C�;]2�=���K/JB��3`e�j� �"I(��+C�]2�=���K/jB��1�QS�2���!���>�2���n	���v���@�K�9z+w���
_z|�,���\o�.��
f���5�a��#R��>�2�n�����c�z{u�EY�0s�,Z
;��,�������w��Q��������F�9VV���LG��M����;v�n!�{{u��7����j5=F��M�������p/�����nc������U����c����������������;��|	�5�U�q���=����V���^������(=^*�V�������������p/����;Ah>F��
XY�'=�G�wZ]�3��j5��IH)X�:���q�����?[�����p/�����x�(����j5.��_��)��R���Ct��)�T�q��J�����Ze>�6|�o��J��+C/��������K�� D�T�VV�������������bo�*����#�}�h����C]��������p���$�z{u��B���X[Y�r���������c�	���^]z�!
�����z�g��_z�Bp/������a�X�5���H�����;����/��N��
a�=Z�VV����=�=��������^���ewB�����0v7A�Kp�{e�
�t����)�Y�]T�2c�^O������H�����;��eNN9%:���,�Px���e+�`�������aw����|Oi���n�����U+�a�����o���Y6�:��������Px���E+w`���h��+�.N9'��z{U�����wK_y�� � ����"�zc��{{u�����_�1��B�Ap�{e���f!��z{u��7����r�� ��Rs����aw�7�����K����p��X���{��+C�x :8^�������B:���VyQ�=�����D�L'�����wB��B:��,W�	�	���W�����)�N8���K����p��W���{��+C����99��\o�.����T�PY��+��_zW|������+���B.a��X�
r	���W���-[z�k;��c�a�XY���Rs�������w��^��N��"U�/C�:��@���By_z'�����K�uQ�{-�j"���x�d�?.���w���������?n8n������O������������������m���~�������g\�o��I�6������b�'_�3�c�<������_��_~�7����)���
��7:UOpH�Kj'�M~A��AWY��<h,�A�\!���N�K����&\�N�9v+�QN$�)Z�����@��n����^l��e��f��������2E���=�t��&'B{�Z�]\�>I�NC�.�i���wC�Q���.�8��-�����R���&�e������2�>����-NS����h]v�!
�����:�W.��sq@�������^l�Ve7��w��&�e�k � ����]v����I�s�����B������w2��������E���,��b��.�C@�B��X�-t\����,�����W������)a����?�a�y9�.�nEp�������{�	3�n���0A�����V����O�)�0=����n�Q��+���A�e���U��,!����V��	3�ne�*,t,|�4��E���Kziu;�*�Rw���[�-�tDK���e�������e�p�������3A	7���\�v<v~hF5�.�;>[v9��=��{��PH$��r��a�{����ZUr�rX��Z��*�3�A�#�r!�l�Jx��r+�U3�6�k]����6�Y�or�����9���@ne�j�W�xO�����D�9r+��#��s$=�[Y������^�y�%w��Rs��,U��s������R��mM��Z��.�D�����*WU�D��!��R5cS�����K.JA����*U���9����,T���Dh�5<�����g���U�����9Z��@ne�j��&B{��Y��uG�R�[��j�0�X�@W(	*�.�3�������
4KMM�rM��c��@�V��flg"���U�]pa�,�4��"���aa�PT���[\r_��fg]v���J��5U�e&��]��%��B��.�=z�*���L��2d����a�����
k��2�������!Da��\S����'���E�e.����P��w���[y����E�DK���,T-a������ba����T-��[��5�$������+��IUK����W��Zfx�\���R�2�>Oh/������	3���V�y2/���6�?�[Y�ZpQ������.6�-��._Y�ZpQ�"��	�@e�������j�U-�����S�z�e��c��S�@e�=�A���S����/�CXO=�iUy'��r�e���f�|zk$���������N�����\���j�j�K���zwu��g�(��S�����\���j�:�.�����e� ���[��j!��Fr���k���]B{�wW�]�#D!��*U�����2�V��VO�5Z��B��.��f���Z�����Hz`��V�����n;�jE5�0s�V.�Zg�`����ne�j���2'���zwu������c�r]��`��m`��V���dY�����]]vQ
"�����u��#����	eAe���A�a��B��.��fn�[������#�����U�>Y7^��Uew�6���[��j� ����5�,������{wM�J��<4�(�,Xm"��P\Y�����0�8����n�.b�-X����m����2�V���-��Z��2��C�������U���e��,Xm���0�8��������J���C�Apv+V�.�J8�5+�;�wx!�*��&�<.�ne�j�d����SZ�2�3��f����U���e��,Xm3>Y�d��)�Y��eG�B*!T��#��O%�Ae�]�A�&S	��fev7��UH%����
�������2���d����SZ�2���ff�����t|��PT���,G�t�\�.�{�	����*+V���w�D�z++V;�.'��x��E=h��w���w��� �@oe�j���{����6^ezQ��	�]e�j���{�5��������x��EEh�F�w���}��w�$�z+��;N/'�y��EIh�f�w���C��iB�V�#w_Nh/v�*����.
1�*+V;.m�#Q����z�����h]������(�KS�����>C��G�������������*�Kc������b��B�VV$w�`Nh/6�*����.�1������K��Hz���$����=Z��B7�2������TV��c�HzC'��������������c�{SY�:����&���0��'��y����6����Z����������2���l!�z�� M�9z+w������q+�K��5T��m#���U��A�qmmB�Pz<�	���^ez���@s�VV���!��	UBe��:���o�Z��F�9z+�VG���!4�	eBe�
�l	�����^ez���@s�VV��b�C�l�������~Nw�7T��o#���U�c��Chm�N����5���P�:���@s���f�~=vH)Bo�PV���zB{��W��# F^��3U�����>f����w����_��U��w���|��[w��
��:�V�����w�{��W�_�#F>��m�j+��4t���[W�����.�^��U�w�����u��n�V@7����������p5�{3����3�Sq�����
��_�l���2�x�;��
����!
�������y~v�J������p/v�����3Go��V7t�E�#�u��|�|�����K�| D�	������������%�>^�k����K���!�9���z�#o��a�J�o]��w����b��.�{��w����luC����F�+C/l�������K��!D~�v���WyO+������S#������;��m����������\��-�����J���;��p/������m�{��n��
��	.Goe�����w�W}u�f�($~����v@7�a�j���;����^�����ApN�9~+�V�A�Ap9~+�V�m�.�}��pe����B_����	r����pe&|�L��c
�+�C&!�������������,m�r�j��.������te�+\�����Y�����4���� F!�����������(�n�K&N�������lBGY_����#���(3BaX~w��	��~_U~-�C��w�[{uC_����~���"��nFt����|e����y�\{e
������|e-���j��.��h����W������G~+�W��]2�{��W���@�B�w��4�-*D����~eG�-m�
������C���Pw��
(D����~e=�]l�
�������i��[Y���t��6B�P~'|�L����_]~���L?T����\�������uiC���������|��uW
��a���3�P9T���.�6�J��.�[���WM���w�d�������s��^m���"��[����P;d#�������=������4��z���f�+�W}�u���V���[]���d��.�fC�Bu��W~��?�"���+��������^���������+�W}�_���[�z��1�w�W{u��B����c���~��S���[Y��a����_]~�����X���������_�������p�����;A�������~�O��'��_��~����kU9�%�L��T��5���rW����{�{��W��eF������K�zX�w���[Y����a����_]zQ#"����~��}�=�[;�0�������K/JD�������G��B�Pz��hM���������NM��������r�V����{��W�^*a����=8X����[��j��K�������+B��NM�����������1���;�������<4D����\|5���"y������0���/�����;�(�~]��������r�V�{X�w�{��W�_T��h[�#����a����C��V|���)��=����/*CC�.�����W���!R�Z�;��eN�~O��������B�����,]rX1�X���rm��B���^�����!��[�wp�Uyw���k��� :��_]~��h����o��q�_�r���~	���_U~��C�����W#,�������]�8}������������(LF�}�������r�V�F��>F��^�����?��[�+�^��.�����z5�L�1Z��J��.�c@�Bo��,_��/�����|5:����������z�',��������r�V��F�>F�^����wZ��]�������MBvA�*�/ND'�W{u��b���~5��^ �����G��������b��r���B~��~~q&:��������"LF���~��O�F �PX'���������������{_Y���\�_�r������Z������hw��Se���)D��V��n�#�W{u�E��E����\|�,d�\������N��W��=�����~�u��������>�8�	���_]~�1J�s��A�
�����_9��.��^�������8��y��;�P!"����+7u���Wzu�
P!A�9~+�_��-��Q�
3�K�=���������T�o����'����I��>Ip�������>I�9~+�Wn���r�V���z :T_^���U9�;�)h�S��A��FIp9�+w�c�=�Q6���x�B�����y��W( *B������{��W�^o L�zCe���<���[Y��fEt��9Z�^�!D,�|��r���y������{x��hu�����!
�EC��+���.Go��+?�.9[����K��"/���r��w��"�����[(��0��B��.���	�%C��+�a������n�	�->�Y����Ko���0s�V�<��#����
����{��W��yG�Bn!T�;�=.Goem�/�nY�{%�i����1
��Pyn���y����3�}�5���_]~�������|�z<���z����ae��gD����P�������>T{�Pw	.�oe]r��y�j��*���;d�v��Yp�9�'o{���+T�����Gp������w���+]������=����,]M�5��^����w�#_�<tj�U����'�����i��:�{��W�_�u����x59x�\������VD����P����������^MT\�����4A]������o����������uOp9~+�W��o����Wzu�] �%���{'�n"�����	�OQ]�+������!�X���\{5au�����oL8}�j�^������_1��	FT��������7����w�_��
�������������/?�2���?���?���D����o?������3��������BB����n�~l0H�������~�/���/?���a`�����M���S%x����\��,\�j���QzHvh��{id����t����e�*����/�.9%�d��.�����"c��.�#<�-Goe�/�pI��M���:t��/��o�Io�����Gh9z+�|�A����#�K�?#�*c����N RZ���2_��<��^m���7����gl7�����������-A�CZ����4C��$���. QZ���"_X�����5���!F�����\��
C�U(*������eK�������wG���K�js]zw=vA�
���{��~OJ�'��U��;Hh�������;wP�Ah9z++|s����K/�h���	rU��=��Yd���2�Z�{	���h]zQ"��j�U������.��
�+Coq/����T)�#�P\Y��G�}g���
Ve(!�%�[�u��#����&\e�� ����"+�W�a�[D����.JC��aWM��<�'(_�#e������<��eJ�/��u��#����&[e����,�Y����8t��^���e��Y�<���\��C�Hzd��j5��i�{�-Z�]��fa�t�>s��y��#����,Z�>Y�d��9�Y��}F���%c�����x�|S�����{��eWh�Vew�`haf��,Y-���c��d�t�d!�{�u�5;B�.��U}w��n#���������^m�����#�r�Xf���=����TV��F��������3A�z+�U�-������Z��3�K[=��K�[#�v��e�K����r�V��? �����z�2��x�����\�p� � �����e�g��^��P�Z����K�&s]zg�"����R�{�Z��C�������\�p^�C��r�V�#��-K�C�d3�.��;4Co�:�e�J
B��[Y�\6|�l�J�������� �z�Xc�{8z�|��5������^m�V�w��9�J��-����v������$����'�5T�V�f���Z�������kgD��{O6B�����X>���a�Ko��������r�V���g�{�Z��������j��PFGh9z+k��x :�����1��e�s�����-��2������!�$�W{{u�Ea�@3�V�\'��[#]������,�K��5T��2�����j��.Dh9z+����5R�^����w�#_E���\�{W("���e�W�������n1��������nPFGh9z+�+nE#�W{{u�=�A��h��ug��-Go������"�Jo�*�[����-cw���n�Z���q�fzD�,�;���K���4�f���ZmBB��[9�������t'{{u��7��[y��6@��	}m��\k�
��'�W{{u���6��[Y��FHgmBc��+�Zm� �d��do�.���F�z+�Zm�����f�����D���W{{GU�'t�+���u)�v#�����-@N��^���ewF	|�Z��r]vgx�Z�����6�.�\��������1���+�U#�m������m_Y��VX-Bp/��������,���\�w7�5%���e�m�]r��9�Y��rn�9m�������!Ch9v+�V��!��V�s��*�{��������UO�e!B��[Y��
|{{$������
����XW����� ���5�g�������py�����m���;@.��2��%�}����^���eE!���[Y��<��Hzd��b�;�w	���^]zQ"��Z��D���C��?hBOv�|-�|�ub���v���_�������L�0�$t��L���1���}���������'e>�?�hs�+���;��&���^Y��q��.����kT����e6{7����a�r����]�����]vq�7������.������k�u}�z��Z���{t�Ko�n���~4�ne��0�Z�����.�8{��^�r�e���ob7;�U���������e5�������^�r��w�#�r1+�u�w���2�>u���;��j��.��a��������������A�^�B{��Y�^�"Fa%k��v�F�c��j����<*��g���]����a�����{8Px��7.Y�p��Y���C��&��u����@M�e�}^��K/n�&�W��u��m�����dlk��{q��!l���i��w����,�n(Y;������e�����������(j��w�\���d��.����b~#.A�����e�}^��I�
�{����j��&�Sgf��Wa�p����nt��:2�t���c�;��]����=`��&;a�p�a�7�.��A��~Ep�&�v���
b�k�0Y�� ��2��U�n����W��u�u�#Ya�p���2��2��U��f���^�r��w2�Q�c���e�w��w�ue�|�L�&�v����1
q�0z����P�;\��������l��2����K/�Bw��u%o�&@	C�����a�gK4���.g]z�1
q�0z���n{�|�;�U�n�<-�P�W��u��'�(lpf����}t;�l0�U����g����W���&����S�c���E(6��!Zw����++��h/v9�����9v+WV���2�V����������n?"D��ble�����|>z��[��sG{��Y�]�-���[�Ur2�\��a��leFx���n�s��.�. D��b���e|�m���	���je�Ep�N�s��.�S=�n1�`�2�;A�Ap?��N ���]����!���F�+\�w��>�Q�wg|���N�s��.���v���[Y�2�������de|�,�:�sz�.�z�"��	<eN�
���m��X�
�,[���d��.���v��[Y�2;Tj��m��X��,{�R�d_�*������_.F�*\�{m/�e���V��=B{��W�^s F�}L�*\�{�!����*k!�%�W;{u��bb^���=��7��U���`\2�=���K���1A���W�p!�%����^;B�Kh������V�(D�B^����'����^���Bh�����;9�(��B�Vz'{	.Co�:+;.������U!��[������Hz��r�����2��������;h�����]0���\e����lY�qoC��n`\��Wh�+���?��UV�����-9�do�.���v��[Y��t(X���UV�����#���P��a��4Goe�����w���U��@�P�^/��W�^�~����j�[�P ���U���.���P���1

B^z{�L	n���Z�������
U�~D�������#�����j���l!�W{{u�u;b:��2�k��pz+�V��gK�{��W��iB��D:�����
�;\����U���{��W������r�U?Cw�e���Z�3>[�twBC��_V�(�'
xe�]1�X��_Y��W|����������n�+�x1B^��y��cCy���j�o�l�������K�~ F�AAh�+��4(\����U���H6(���U�w��6��[�3p� ���6_Y�������
U�u!��[�5p�Ebw���U�����j��zU���mV�������;�4���r5���;���������;f��������pv+W���w`6�7d��3�ne�j��������n5��%#�s��.�����w�,[
_��A|7@�������.6�f�����0C�� ��U���,s�K�����.6�f�]5�*�wW{��m�,Z
+
������b�a����:��z��m��Y
;>Y6�
���b�a����:��Z��m�,Y
�	����������� 4����@6�e���X��,��jo�.��!F�CAh�+C�����[Y�����

��q@��B����W�l;n]��V�<Z���^]z�1

B^��C��2�VyG�#�t�BC�j��� ������C�Apz+����\�C�do�.������#���1@�Apz+�Y��-c�Wz{u��=b:��2�;C�Apz+�Y�>[�d����^]zW����|Fh�+C�������
�%�q�g��A�+����n�+������rVC��a���Qyuzw�� �W{{u�= �F�9z+�V�����/��E�����^��U����	B^���p���[Y�r����^�����.�Qh���k����2�VV�\? �t�XC��
��PF'4�9�
C�A'�����E��+�����;bj���2������r�V��n�#�W�{u��b����2��!�Ep9~+WW��������4��}F��+����.�����\9��Gp�����;��Q��������t����t�p9������/�CNX�g�.�2��B-����G~+���������:��}Fh�+��;T��Hz��r����|�j��.�F ��>#�����Ro����z�q7�������7�����>#4��_o����r�V������^m������Q��:�����!�Fp9~+�W����]���1
/�
����}#�:SY�����j��.��C���#4���_
/�����_y��Gp5�|'U���8�W���S��=�\�����@A%�}u�
�f���� �\�����U}�b��.����7�TY���\���
�_@?%�[}u�]1Y��#t����$^���[Y��>^Vw_����w�a����/�����~zqY��
�^h����@�6��'�Hi�?09����,ON�G�|����J���a���\{5���Hz���:9��%�s��.�=�������������r�V��R[�b��.��f��BS^� �6E���2����4���n�4���� ?M�9~+kW���!��Q�u����W:~u���!N�-���"��	�!���[Y����<"Q���_]~C@�B�W��+��r�����.9��s�{��W��r��0���ye�W��iWxe�jZ �Kp�6������Q��
�[e�w��/�����mL�~	���_]~w���o��]M;��w!�kk�8���^m�U�7t�!�t#��9�C�{���[Y��]���_]~���@s���WY��` ���7[��*X�	���_]~{�+���k�B�/����,_�~Ct����~P!"�iZ^��y��7D
��Z���F�uOp������&����V��+��:g.�oe}#x���s���_]~'��	4�o���0A���r�V�7��{�{��W��� F^��Bw^�
�\����Wa��KHV9�����1:�����_�p����~|�/�����UX�����Bw^~7PO	.�oe�*lP�Ip������c����V��+s>���\����U8�K��7����4�o������=�����_�����CEO�����
�����;8[x���B��oe�j�a��j��.��G���o���2������r�V��f��Np�����;�23����W�Gx�\����~5�8t�{��W�_� F^��Bw^�u��'�������������NP�:S����W��	2p����~5�@t�{��W���"�E�Bk^��y����r�V��f��Np5z�*���8�X��+���������5�Xt�{��W��
�p�0�

\e\x� d:�������e�����_]z�!�o+4p���:|.Goek>��r$����U�]��0s�V.�Z:A��m�,`-G�������!��T�\����r�V����%�mz��W�^��#����,pZ�����|� �.Qi������f�^����b}�e�+�W��"�d��9�Y�^�!D��b���2���M��x��t�
�^����wr����B�V���&��Q�w�wKT��J��.�s����������.�oe�j�A9]���Wzu�]0����+t���_�n"���u�e��KT��J��.��?4�o���e��
���[Y�Z6|�l���
��eG���
�;���|`���ce�j9��r�7�6��V�#���k�V�nZ�����t������
����B�9~+�^��_���[Y�Z-T�������+b�����W�����r�V���5�kz��W���!F!�������/�e�u���u���{��W�_�!F�:�
�ye���.�o����D���Wzu��f�(��Bw^~����r�V��Z�]���Wzu���C��
�ye���_���[Y�Zg|���������l���X�;���be�����_�+�]���Wzu���7��[Y�Z7�@�����������
����4��^�U�����D�|3��>��Pt�{��W���[�PY't��������r�V�'7�u�j��.��!F��N��+����=�����_m�@t���������!V�+_m��	�G�w��:�{��W��1 F��N��+��#��	.�oe}rs�%��N��������@s�V��6�{����+���_]ri���_]~'�/��Bw^��9����r�V����o���O����;{���`���W�g�@.�oe�j[��2'7������w�T��[Y��V�@Va5���ol+����j������b������_mF B������m����������S�;�8�q����,�&4�_[�8��r$��O��.�{$�x`�?���'�#��!�����^��U���(E�����\���v{o]2>%@+�;@L�9z+`��������+�K���gezQ!"��B�O���A��G
�������� �%��z���!
��XY��=<�	.Go���}�]2�=�>+� �%�����=����r�VV�������~O�����3B�/Vh�+��3L� �����}�w��\{J{V�w��K���[yn��b��
{q�����B���������#F��L��+��;t�\��������eO��5���cB��^�;���P9Dp9~+��#�{u�=D����
�yE��0P[Gp9~++��]���\��2���F�9~+��[B��W��*�=���b��2����WO����=�+\����9��#�{���C��~V��+s>;@�G������^��U���(d���2��A9%����6yL�[Fp/��*�����2�;����uOp9~+�WG���������������W�|^�u?��PY�:�-#�{��]=bz����2����~z�Be��� �@p/��*��Cv�@s�V���_���]���c�]2�p��W�_�#���������C�|3��~���#��\��*��3���w��u������,���n`D��-k�_�����[&to������Ba]u�����w�{��b�����W7t���������{���W�����W��*����H!z�zYW���Y�tq���v�U�������n�U�&�����n��
�]����s�������:�;��atA�Nwu�����v	���s����.�!��
�ye��et����~u�o�%����B���Q(��������n��]]�*t[_��,�;�������&����2��>:�����_����eO����*�{��Qx��[E��t�����������p/����k�G�B~A��*���,��kk���v�����U�{8�Pc'4p���]/���}F�~Ft��u
��Iz�������;� �����3����^�����AB�
�ye��@�����,�vD���;'@����(<a���2�B��.Goe�L��7Qq����������B^��9@Bp9z+�Wf�wKH��9'?���@
�0s��-����d��vx���%*mz��W��uE���E��+����P�gjGG�[��f�s��.��C���Eh�+��P�t���[;0���6����J����������W��[(�����\�a���{��i����:D�9~�������F��#��k7�����^�������@s�V��l/{���[�w�fGt�������(���k���/����,\�B_�{��W�_��4cA�{���� ���6�����re=�]���_]~'~	4���t����/����,]�	*����_]~����8Bw^����.�oe����v���^����wq�Qx��ye�] �%����+���eI��'{u���C�#t��9�7�@��7[Y���.�������1
�Bw^���w��r�V����o�=���P��;�] ���k��*�.�oe����~w�W{u�5b^0BwO��-Tf\����U;��p������{�(�`B�������r�V����S�{��W���C���!*�W�8�Q������v���^�����������2�:�] ��_��w�{��W��	=D����y%f_��ABp~���d?A~��^����7���/�Bw^��w�������_�3���d~�d��.�z��w�B�G��y��!���[Y��W���v���_]~7��	4�oe��� �@p9~+�W����-�_8������1����:?����)�����_�����j��*�C�	[���r���A��)D��V���!���������Z�C4�o����B}�����_
�[�j��.��h����WC��!R����_
������N����;�B�9~+�W��C���;����^����b&��db`�?���1x��	.�qe
k�_������N!�Af/���q�	R���w�,a
�"�d
���K�**a����`
�\���
�0Ct9D������.B�C�^��+��+$�	.GoekX!Lp/�����y���{�?��S���S����\B���~����w����p����������������/��?������O%�o���o?������3N������Q��;|�R��~���;:�����W��G��������h!�F������7Zx�\�,{������
�%si��x]v�!��<z�Y��Cd�%Gpv�+y��p��}���b3a���,��#<�F���6�tZB{�
Z�]l%"���e���L;JMD�UZ]v���4��u������B�b������r=�����hw�W��u��F�QX��m�e�w�v[�*�;�N�Z�^�#"���{(���Q� ���P�����h��@���mD�� ���x�%J��@�Q��K����-Y�t�Z�^�""��+O��P����4]za1���hUz]�����Z�x�3� �A�\�R�������g]z�G����^P��x����'�������h��j��.��/�����2�;����2�*�n�\r����g]z�1
�I�rP�{Gx�\]eY��R4B{��Y�^�'�F�����bi�e�U�5��\�7��j��1
�A9(C/��\]eY�|�DE!��>��;���"4���w������e�%�����~Nw�4T�����q� ��{W�=V>�*�Vn�g��n�i�Z�mE���E��x�����WMeT������~O��4T������#Ce��������2��t�=��r�W�7T�|w F��"CE��c)�e���Zy�1����K�
�Q�a���z�e"���U+���@U1����K�)7��[Y��X�Dpz+�V~X�1����K��!F��[��x����2�VV���J!B{��Y�^�#=�[Y��X�Dpz+�V���^�x��7t�����0T�{H�����j�q�����K�<#F~$|/Ce���n�XY��>[�:�W��u�]���@s�Vn��+a\�����_���b
�����*����?`zA*s@�l|��XY��;>]����s�����P�!hCe���
���[Y��:����<�v�N����[y��d �%���u�	7��������!���������=�e��,[M=���b��.��C�B�+Ce� �%���U�i8\2�='9���Mn��c��h59{'��m�,ZM���^���e��Q�z+kV��=�e���YM>Y|2�='8���=n��c�r�� �������d5�
�a��Bo�.��	f�H\M��<�:&���UV���,K2�=���K/��h������b�!4��������eMw(4T�&lq#�����i��Chns���i�G����o(WM��F�9z+�U�
����*�U��W���Ph�W�~���r�U0x�B��\�3��`����|A*295�y\���r��e0��������Ub��Q���(�#����0����^�������B2AP���� �@pz+������^�������Q�&�P��w����2�VV5��zB{��W�����Nt�2� �@p��|eY#��3B{��W���C��X!A*��������|�/���'{{u�]g�($a��+�+����F����&
'{{u���?6!� Ce�2
���v����eOfN����{`�����^P�x������_9��;�����^Uzg��4Go�*��@�m���z+�������^��������Y�z���eVs�z���[Y�����;��V��"F!���2�;B�Kpz+W������^�����9�(t�;5�*�{��	.Coe�j�Eg��jo�.�S���WM����	������j5O�R �W{{u�
1
)A�+����7�n��Z�3>[B�3��j5/0��@s#�*�V��B������eI�b;���K����q�������+�N�E���������.4o��A�+s��0�b���z+�V����=���do�*�K��q�t��W�p^:��\��������m����c��(��\-�x��m��\-����bo�.�=����c��p����\�������.YMwNu�ew8�PL'(e|w���e���[-#<�	���^]v���i���W�w�a��l��r>B{��W��	b�E����_v'H)��.��#�{{u�
����^��������e���I.3����bo�.��G��
rA*��4��4�PY�Z��a�����n0��0s�V��l����
7�r����VOh/�����c\���}?�)V����$l���[Y�Z����Wz{U�];�=a����q���\/�e���X�|{��jo�.��h������Y#A����j�j!�$�W{{u��br���W�{{�e\���r�:@������K/*B����<�u�W�IB�V���qEp�������6�(La�2���YOpz+K��T�����K/jB����b�N��_#Q������:��eJ��5��V�4Go�:�u�qtk�
��3����;��eN��;������2����9�>>�5]�R�u�����|�V��h��[�?p��P��r�V���
_.[���d{�.�����t��W�����OE���r���?�S�*W��h������A��	
n��,]m�.�j��.���F�9~+KW��d:�LWY������s�Nv�����n����v���lB���*�W�o�{��W�_�t#�����m�R�M�q3]e�jwD���;����/��h������!��&��KU~=T���M���b�����,_mmB���*�W[������;����/6�h�����6�x�	mn�T����.s�I��~�a��N[p���w�D�s3��~����_�]�
��mCY��� (�e��
#��O/SY��6|�l����F_]~�1�/�AP�������SY��|��>��������!?dh�"��������~���%��������BD�9~+�W���)D��V��v�#:�������/*D���r��>@i�)D��V���bK����;�r<��|�9*`�7�>B}��8��a�2\�b��.�(f������$��D��V��v�"�d��9:�^?~���'�
!�e�~��o������������������������_~�e�������_��/������?������a��F�u�y,����������+O��O��~�����>��z��z�������g��$<�_��D5`�����Q���=����u�E)`������.����P���i!���J��������Ur����6
�>W�U�=�0	���g]r-�0	3C���A�\LB��[�s������Kn�"D!��<z�%w��e�}<��;@m�����K��"_ ���\���b	-��}�\�%w���^m{�e��Q����u����Z�����.��n	���g]v������u����*Ah�O���b����4=����+�P����\�]�[9����W��&�����=�����E�v�g�u��i<��R	KvWH���WZ�u��F��'E3v�����x-�v<�AI���y��Y���@�|Ip�*r]v�w^Dv��a���`B{��Y����a<�1`]����{����	�K�;w������j��.�0���a��Ru�\4��������>=�\+q��Y��~C�����T5w�p=�����X��a�OoHOi�U�����p��U���n�T�}U������B�vZ���1
��Z�
����������e�O���u����n
��O�e,!�ew��$l����
>�)]`�N��������e� �ew�n���$t���;��-���B�������PQuG�����ZG����vZ��m1���
���n3������}w�����[P�iUs����f, �e��`|��3����{L��E3�_�nV��t1�)�������qB�zs�*������^mn�����F�OBe���Z���yo�.�v����{��U�_#��X@�K��8���}^��K�0��7$��'[�u�G��g3���=_w�\=���H]za2����f]za2�4Coe��@��-Gom���@w�W�u���@w����2��\�;Z�^!KY�����t��Y��d5��[Y�2������������0���W���*���8���K��(���e{������A`Nh��6����6���aV��/�������L������=�o�%���:�K�|_g��3����\�W��l��g�lW=��
7�=]�����J.����^��%�b��Og���m�w��+���}�w�{�u����;f���"����;���Iu����;��M�����{���[Y���/����rCUr{��������K.���13�V�z����=-O�!�b�h/6=��}�w��k���}�w�/����}�w���u����;f�~����b�h_�F�%�b�h/6=��m�w�LEPei����;Z\m����;��M���B[�4c���^m�w�\��s%G�^��������K/���A�.�,C/�����^��K/4���^m{��c��z+�T=4���r-�"��������K/t��A�������w��,����w�W�u����;h���RU`4.����1_��Bo����gUz��76cQ�*���Bo����J������P��9v�c3��������kl�������P��;v�c3��������k2&��������P��=v�c3��������k���3����������b� ��f�i���c�?����d�A��j5`�� 4�f�i��d�A�)�V�\����������������]�\�����MC�]����������������]�]���
��%
]v�?v`�c*V��Bl�~v]v�?v�c��,]v�?v`�c
V��Bl�vv]v�?v�c3�*]v�=v`�c�U#��B{l�nvUvGl���X[�d�;vd�c�U#v��Bwl�fv]v�;v�c3f������#��P��9v�c3����������1�\�]������b���������]�]��������;bk��n�=����.���Bk�T�R�^����Xa�Tz�5vdZcjU#���Bk�����K/���Bo������;2��
��[cG�5�d�d��{cG�7v������1j�}��Y�^l���X���]�^��^L��_�K�
i�1�R}����R���F���!��x������U�K��B{��W��}G���xd��h5���������B{��W�]�
���c��h��#�	��L�"�:�t���sz�.�����@���]�]l	tBK���Z�]l	t���sz�.�����@�U��:�'Ph{*�.��tO�9�Y�]�	tBO��*�V�����7��.6�tS�9�Y�]l
tBS�1�5+�]�N�
�9�
t���sz�.�����@c*KV���(��a�]�)�����.�:�'P��*�.6:�)0c��.������sz�.�����@c*+V��������/6:�)��\��)�	M��T��v:�+0��W�_�
tLW`C��aW����,X9ltR[�������P�����|�PdZ�_�APNp_o�V��H��]���Z��4g����������u���$�W�zu���(dMe����\�?����$�W�zu�A[#����+?BhNp9~+���jc�.�nG�BBP(?7��������`VB�!8'���&]����I���������p]������O����9����;��&]?�&�O�V����[�~��NhU����@�?Q��w��$�U�=�O?�J������	�K/����2���MQ����c*t�
� �W;�u��?��[Y��fH�MQ��C���3<��^h]z���@��S���lS��������B���^m�����4Goe�o���5E�}};��w�D���
�K/V�h���R�t@�m�����u�2��i#�W��U�
���L�����6��tvT��` �Fh��C��kG�($��![e���h#�L��sW�^y6B{�!Z���@�B�Mx���w����2����]zH�������b�l}�
�0BTNp����wop�e#�W[�u����h����U��\�����!�Fh��D��;-�QH�	!��;ATNp_�@��7@���^����we�@s�VV��Q9�=��]��rl�jS�.�����0���+���|�X~W�x��]���nb�����U� .'���0���C���j�EO� �p����U808?$i�6��=���hUzg,�#���������Q�_^�V�������^l�����3g����l�?������s]z-�^���h]z���0s�,^��������s]zx�������b�af(U+C/e�Q�����*�^-s������K.��f������!+8�w�[�]YAB{�3Z��iE�BRp��\�����z+]v$	���h]v�!
9A!�Z��r����y�[��;CN��^���ew9���]�aw�� �}��N��R���jg�.������PY��7�	.S��\���w�� ����K�)A��[Y���>%�Q��K�)AB{�/Z���[��*VK9�e�}��W�w1�$�W��u����h�����b! '�L�s���BF��^��������*V�!9�e��*K�	AB{�)Z��qB�BBp�,X-#��������Z�:���h]z=�j����d�x�	.�G>����!�Ah��D��;-�Q���5�e�����\L�Ko�T�����K������,Z-3D��)����3�:��_]z�1
�������BTNp�b����
��{��W���#Fa�|��w�����^L�����{��W���5��[Y�Z��i���R
]~�x��M�����&H�9~+W+�	�B��Ti_���W�O��r�b��*�	
[x���}���'�S���/6
�L�`C�j�F�Uj+KW+6
�B����,�/v
�L�`C�j�N�U�t���;W�SPz��[W�U��x�b��*�
���������*h2|�����+�+�P�Z�Wp�z��{W�W�d�	����t���V_]~�Yp��]e�j�f�Uj�X%��/6��f������b��*5
��������,��LF�_l\�f���������,�*�W+6�R�`����,�F���4��������((,�,�/6
�R�`�\��b���n<������-�Q������AtNp?���� ��h�
�[��8�qe
k��\��Y��[�c9B�{��W��~G�B��)IX�������:�%t4��w��3������1������	������1���7�|�p��}���6��y��|���;�=$��\l�Vu�}��0s1ye�o������>��&Uz�'��^���u�g�($�|e�o����K�>�o]z��h������z��3Goe�o������$��z�&��f���u��6�(��������\���� ��G�]_����w�Q��+�};.x%���������I����/�G���vQ��+K};nw%�\*�2�+��h������n3B��~H��2��nW���h]vw�"��R�W��u�=@�"���u�W�\Fz~���{@a�v����J��m�Q(���%�7�\���g�a �pD+]_i����:�(����Uj.v%�L{��$�.�RG�����h]z�1
e~B�[zq�+�e��|8d�h��+�����1
U~Se�������~�M/��<�}���G���;6i��TY�:p��!����@��wl�������;6i��TY�:p��!���3���;6������������C��)����wl�����w]zq�����y�=Z�^��yH;6�����;6a�fx^~�K/��<�;6O�G���;6i��0?���c�vl���������Y��P�:p��!-��*�V.�<�%�9�����������N�Z��i��P�]���3�=���>�����
�������h]~�G�BBp�+\��-��
	����
�__���d{�.�C����0�����!'���\��!��7$��'��u�g�(�`B]���nt�������t���7&��'��u��=`t�F�vX�_��
�3�����W��|2/x�=Z��iC��J������&�r]�B��������?��O�����
�M�x�n��/�%��������v�����p�?���i���&k�o����}���������?�����?�����?���/j��?����������������?����������������?����������������?����������������?����������������?����������������?����������������?����������������?����������������?����������������?������������y#�����y��y�W9p���Y�9��id�d�M4����Cw���
v��u��
�ty����C���.�;^^����3_��o���-c����L4ty������F��M��X���a����y������?��������������Y�5�(l�3�(�����_�Xtl��Mx������Y^�$�[B��O����N��4��k�@�
�pu�������
Y9��}�y�g��8��~z/��G�������{G����a����Hy	�1�����/g��G���l�1�7F�7w�o�e��_��o��~��o~������7�����h��tm�>b�]��q~Q�u��U�.<��	/��E@G~b{Ut�G�	���.+e<�0�u�=9���k��t�	��f�����p~�����o~������_���7_<(�4�f��{�������yqMm��8�o��W����'��6���o����w�t�x"<�	����u����D�s��;�����6#�
/���}
�`�p���u�����i$GyB3�[�N����}�Xa;�,�]�p����C=P���#����u���H���R�or��s��I:�]x����3��y�SG?��������cLn��e�v�D7���U��N�'��s��'�X��=����S��^���&�~�����j\E��U�x����I�*|^E�����{Q4@|xM]��8��t@����2!�&;�&@�/s��.��<�c���g�o�U;�,�$��fR9�����\Q$����7g�>�����{�l����c+���u;�����[����!h��1�t��w�t����6G����N!�mx�oo>)�)b>��Ih_�<2�n�|�����!�Dh#�em�-d�����-��2����S��Z0[�|G��;x��	�2�;P2;p}�W\���P5;P5kg��3h>���E�2�[:��K���s)�A:����8�2����32�}�2&d�(!�+�&e!)cCm�ANf1����D��i?������9����,�q�6�_��c���f�~���B���~�������_o�~��}�B�'�y��������I�����������7��gr���M��
!��<��\��p#��C2nj�lO�O����g��g2��f���d�d~�	;���O0#8�g��v&�N0GX!�$��j�"x\^^��|�3�����]p�p��^��^( ������~]��5��R&an%S����P��'���o-�0������6�_M�!h?3�5��:��z�����������T��6|�������_���?��7����%"�� ����/J��7Q�G��E)�D:%���&
BQ``];�(_+�����9'��L!�TUe�D�Rg^����1�-�%�g; ~��T����]�|x�z����V����$x������U[�A���x��v���<������K���p�������h���#>�7��f�����>�j�o����z��};��%	KT�p��:U{�1�17�%�]X�����0+��Y9�e����k5���@uf�3?�/��Uj.����=P�����<�)�L�)<������2Y�]�=W���P(%���S3g��E��.�"8c�~����C��g�!E����'O����~5s��@����Cq����,V�5s�������^��6�_��'@�
��/W�W�!8�x	ml���O�B/af�W���h�d������C���V��o��*���W3��A�%������������f	!��K��/YEp��~5�HqG���1�I(d?����5�}���A}a� ����(B��a��;�_�:�����Ce����0��PE�/�/�\"��2���g|�:K������	�d�u���~�� <�'~�B�c����L&\5�6��'s�kV�?[��grH���5�6��'�������������Ln��F�b�|��%�\'

�/g�RJ4(�\"<0�>���83�J��?���"�����W4����Z��P�\Q�$��T"
�+_�Z>�pJ�k2���T"
�����.�������I��5�}��KD�����o6�(��7�&���L��E���&�Q�|�(%x'k.�\b��������5�SG�b'#<0��2�Y����0t���k.�������a�p�*�M#<�/�Q����j.���7��;}��C�\R^����Yi���I�2Y-�j�O�gh��I�tJ�x��0@��B�hR�����@�(r�8sai�\"���)����5�6�L	��K��2�6#6��	;I�Z^���t� ����N���uYM�ZO�)�d<�H}��'��d�7�ug
z5�����ewQ�^��m�?���*BTBO��3� �
C���N� 8g�~If��3� �
C���s�U�^/.�[�b�8�x��������=��{-c;�y�Z3c��5o8PZml���O�8�/���5�8((#���*&?#�PVF�?��v���kQ���6�x���9��A���.^*f�"�P��	��t�*����-]�0T�"EQ�\���
sR��3
�B�B��c�h��H86�?uB��������:ml�����r�������Z�e�K	�s������As.��a��g��luk�mO�M��Z��Cpx&o���c��
 �*�M���� 8<��d[�X3lC�x2���)w��;��Fp����ICGX1�<�|�����#x^��)�z:5�<0�9��C�9������h�Hv8�5���an�V8����WSm@��� ���=o
B�����w��y5����Dp�����5��Y�e��'�����%b���.Ji���E	��M�������s5��S��"A�+9��\"B�k ���5j.#lh=��A��5j.#lb>����]�.
,���5|����>�Z�e��=sk�3�����3���������=�g<k�Z�b�1i��� H��N���i�7�&�qsl���v��[�cr\Z���Rs���� ���Tj.Tu���R�%`�z�vd~�Sj�}�9��d�c�d6k�������h����#��u��K�)�ukl�;V��r�P�������f�!BYaf���*����{4�����������+�<Ap������{-^C��h?~N�/����9����9c�B/a�(�C�wI��r5��qE�w��DM�k�J�krN����D�(��|�x*^���P#X��cW3�	7�CW^'�n�
U�-�<v5�H���OO�k���:��B��(���v�#w^�����"8@�d����EB�(������x��;P�����k�x��A�����h>��a��c3�����
��n@�%���v����C�/�/�\"8h�#�9B��bK�������|?�0r�l5�5�6�h�d&���=g2���W3lC�p2�V�w������f�����ZO����������[��B�I��R����x�ES
i�NR�uj.��7������A�z5�_��w?�L�u��WT�������ju�LB����AA�07�����~��U_Qm� ��I������)�\F�@�$�q�ehVs!�������/J���&r�B)3�K������6�c_��k.���?a���Ix�Lh��KD8a����U�A�Qsa�ha�����������-X�h>@,>&~jz���<��	/Ws)��Uj.#x(K��z������������v�?I9����Z�OF��g^�7A�TJ���q�|dL��%k.'@1�_���2/,��KD�BqA>ai�\F��������tj.#l�L^��Op�����j.;:x:��d�c�u&'�v��-�\�[�ty�<J�o�c_t��4PTa���(_1g�wTa6^����R�0{Z���3� �
��*L(�<Ap�0{Z���3� �
s*Lq���r$;���9�"j��9\�~k�9wB��b�3���mx��\u"�"|/�������D���y--�.���9��I.g�*f?#�3�������w���C���i$�h{���V���N`@����j���
�|�������4`��f��HB�#��d����8��d���,�!���|�M�d��������� 7��7�}7�W�Kp����Y�vc��o��!�U^F�F0���O�����Y?@�e���i|o6�����B��
!����)t�>���K�W�f�=����*<]�>�^���B��������}�/������;����+F��c~��Z:�a�9�Q��������a�9��W��^l.P��t�Lph��v�PSt@��;�E(�Ukw��B�d=��<���%��C>D�����w���BDasJ�;5����tj�����P}�Nv�\}��1FX����W%b��h���
��K��Dxx-��)�I��'�/Un��z���]2�0�-�B4�*�+]}	�6<�����S��Dl�o��(���W�	��(�`.���ES�-��H�q��K��/����Q|��.c���/�[�'����'��M�&�V�`����V�����
^���I���]��j:��H~�X}��AB��_X*���
.S{��R��l�Gl����/�[���!4��}�6GV;x#Rn���lM����0�nL&���)�����PxO�t�=TLG!�n���)�# :���t�=TLG!�c��;�fS����1��{��;� �h@>�nLi)�a������b�8�Y#%��<&�|7]�,(b������|�V���}7cr���*�A#�,��-X�
8B���/]�D(b�w�������?��4��t��KcK!!:����/MW1�a��^X�hKW�F�@!�	V�*E7���0kK�� ����-�]��&'�A��f'��&,�0"�� ?���S�]���)��k��h���s�&y�3B�k��#���`��m��9$�`��f(<�g>kT��Ctx4/�I����#�_WT�	���h^��E������"T�s���u�������#�v������*)j��a�),[�����TdF�0��2�a��m��"3X�1(rF���_S��;J�� �
J6�C�3=����
bD�S�P!�t���Y7�lg��Na��j*S��C��H��|�K[�*3B����qfbV����fb:i���u����a�9
�/������6=�!S����D�X�`�9
R�J�*3���*�SG�*�Y�����m���,��Ex�" �����VU&��;������F��gb��2C@~zL@�f+G!FX"p�GI��JqT=0w��4
*�����0P��YP�*���gZ��4�2#lx������U���e
��Lb��W���Z�+�����	�����;>3f%xJ����e}�����{���T4{�g}�b����@3�L_\I@tP�Np��GF�Z�/[�zWU�����=t&k�w!NP�L�9�^2.�\*������Vii���7a��	Q�����`��8D���jLV3G!�=ZPP������T}���`��(bU�@.Z0��g=]Ygh��C��$D�����\-���;Z��l�����nEIdINY6�ff	1�.��+��P�0�������aL��:�
�W��d��e���`��d�
f�}��"�����w6�Ip���*��I^��DtP gs�*�����������G33����#���\R��{����h>��%�f(���&���0��f�[���!�
-(4��������X��JS#V;	<Wj"���IS#<�8	/7<HR�u*3���zk�5��>��W�������I�.��5�Zg/
i(�e:����4����A���)
��?D*g���`��
b������AM�*3�i��4<VfN�*31�
������%b��h�j�4�Y��x8���7X#�<Y�����?��g�����hl+G�
(Lo�r,*���
����|�+3
n��>��<W�Y����"�^X�`��3��L����&��Fq�\��Lz�w���g����i jr^(jR�9�+����)�9���
�JVf~�{,�1�4�Zef��|	��K�23�=�}�< ��R�����=b;2?�1���+����
@�;vN�P�J-*<1F�|��V+]�*Oo�����NeP/5�;�P�J�qp�<r��\	��w����[
Z0]����#����@s,�J��Am+�MX�^9�x�����������6�\*������@���6�����wT}7��u,\�C�wO�����1FT}w��u,\�C�`O�������]�m�n�5�#]�:��,�Q�=��V~R����&,X/�cV7W��5F�2�MX�^f)�x��y����B4Z0=�ph�8Y�@��d01
�l����$�X ��O��A�4DS�l��&}�&y�23Fw����z;t�d�Q��U�i�����f�����`����y��?D�G�������b�z������!-i
5C9���(HZ��*��������8MauZR����QJS������r�&z����1<H���kn��4u��L��#2�m��Gk*��St3-�AB��&,XS�@�;ZP�l,�������cM1B��>]��S�����Uf��23F�����L��������&m�4�L��Dxx�����L�23�
5�7�����Bef�����G���ZO�z��TtJ3#pF
���F������/�����44Sz�k�fF�V����������Z�i�������9��Z�`� �3��F5�+�&q���m����J�f:���-�����TJ3���)_)T*�DlP�A`O�XJ��nEpS�78t��T���t8��Mo���v� F���/��wK���A���a�KN����t��1��9��$#F��!����Z��z���`�L2b���B��/�Lt�G&�q��f&1B���,X\Dtp���d�����Y��F��]�����0�L�"F�}	4g��uq�nG��q�5S����hAa�/^��@0 �	�L�"F�J	�G������\��bm�@s,^���@�$�	��-!�
-((�S��V@7Z�`z���[B� �h���KC�!7a��1�x�����1�����V�0&�������[��P<5�tu�k����1�x��M�bm&�����a��,�L�����_�f�'0Nx43K8\�P1�=	���~���)�����c�z�[�?a�!]��j�r�� T�N������n��9��������Y�S{i��N��a�9yj#)�:��o��s��S������u����*�����**F�:�������VT9�to���@DQ�\�����_�U�5]��+*F�:W��uRS���LD����������C���1�
���������}�	q��W��Dx;�G�P�cNL�{R[@��y�m��~��&�x�(�� b�t�yH�4�3�F�����Q������a���X�Bc�6?��b
������2��?1�����0Mxs^����=���3{�������9��E���A�F*����HI��J�T�8�7�r���L����Y�vLgt2�,���"����,���t�8+4�w�N}&��{wd~�CP������r�A����=9�������������>{���	sY���.{��L3P�s%��h�b69�O)��w(�'������b69����`��J�*\	n�����-(T���� �sx���
W_1�a��@��Kp��E�8��@s,]���E3
����0������,]#�����
W_1-�q���&�� �4p�L���UZ�]7	�P(]���B�LW�N5�K�4^�Y�t�k�U�hx�����Di$�`�=�.At3�!�����.�Yp�2*�Qb�
�n��
c�~A�9����p�����S���^�h��k7�k��:(�r/D	���?g������V<��US�P0�X���Ctx4ox4����~{7�#Z]#��d���Atx:G��q��~;��_�*�mS*����������S����](u�;g�R����s�CNk$�_�@3��1�������h:�1(sFU_�|��x���#�J��P�R^�Ft r��~������ 7����~���So]��9	���0Z���N��f�v���xC{����/J�j-ZWj�+_����&"��E�F�j���O�G6�or��L����/n�UJ3�I	-N��TJ3��������X�A���L�AY���$�G%���z
I\i&��j?d��z��w�3���g��1�'Y�asrLj�Q����{�HW�Ny��z�P� C���EK3'����h����R�	=d�|T��yg��f"8H���w�Ri&��\���)��I�X�2^�>96������=�q�8���MK��=���7��`]"/�W�i;
�Bq}� �Z,��ES�y+��kh	:���~�����)����t%Bw���)�S�H������C����z��S.N�")���Y(��n?��@p_n�)a������A�Q����Cp_~�1���[w�M/���P���XV��F1]���Q+X1%V�'!����FX^4-d�
�
7��JD�%7^����5 
!�m�e�v�Q�����h��wT@���0�����!�4��.L�8����!�4�
�R������09P�9�y=g.��*1��a�t�	2���S����,R�i����Xd�����!D��s�����5���ekpG/L�����D
�M]�kh@��3c@{�<����h�7	�uV��#ZR�����JV:��0�=}�hUaF��&�������DF�n�}?3dF�ur}���; D��s3��A�Gpc������F}��>�����!�#�����|1����uh������t]�JLci-�}�9.u����,m���"��-wP�,Nj��I
�s���<|jD��;�>5�)
��r��u�����������T������!N��
G)��Q����y�K��F+����C�E��X!�C��:��������X�3Z������fF�U��u��j�<� ?s2����Z�d�q�������J��,����y��1:c��:V;P�zI'b3�,�:V��[�w�Fk/�hi@���S��C�u��>�`&�:V�k:�����i��7� @gO���v� F�|��������������MbD�b����i�'��V�j��"t�fNK(.� :h�#��k�������}�D��L��\
�5L��1�w�<~)�
s�3y5S��!�3y����m��A&����3V����#���W"�
�,F�j|)d@3��j��x55��jt��Z�W��P�N�?��A&������h��0s,^����������C�P(G����G&����I9��a>���2 � 76`�H$
(^�#���	76`�H$`aB�
��C�#t;0Y����D&�0��%�b-+�����P� ��8�?��������\��%����!D<���.*�:���K��kpg�/y��xAtx.�����f��p������_�L�	�e��2����I���o�V�L#<4'!��z�/�ZV�0����;nt���*���6���~_Sw@��niBy���6����0��"���2�
Q�Ca3�a��; DT7�]vPS��ZV@����.�w����G�1LX>���+�F�0�k�)]�o��(ZH�xYJ�NN
��<������_rG�Tc��C�(|f<�Tc"8(�!�8i��J5&����6~X7�I���,_��p�@����G����3u����cWc�:4���t�@~�!����(��1�!UDI��NE�C<��o�O}Cz��_��t��^��ygiTcF�QB�_��4�1��'	�=}g�TcF�@�#�9_�7�SE�{��{4"$�
�%���������:��'�!����/�>t&������-E���}��+&�#��R��K�	�������C�$r�W���t*%B�WK��a<TL"#�/�^�y���`�B^��b9��>����@b��b6!�=k}
X�.B�d��b64���Y��0��Ft������b64���X'���BQ��bZ)����t�X�	��
��A��i�"hB��3`�r��� ��+������1|�x!N�<���
#��@�?J$2�h�� ��a$��3�������9�@l���#��/���1����<�k^�T��c5f�~l����<'���B��yF�?���Kr$�X3�C�x8/�H���@����${���B��yz��|�R5f�����\n��F�����s&���G�0��vd
������a����@��&�|�h�~T�����^��j���]hb,/^#:6�d���; DT7w���|��6�d���; DT7����)_L5f����M�|W��n�;@^:�7���e�X�6"��eY|�{n#��]�'�C���=������v25��!�
5�1#p�]�F��5�1�5n�8o^�
��3d��<��X��	C�����V�!�y����3���?\m�#~�EY��*�#)h�"J��t*����!�n�]�jL@�I�D�
��,�jL��=�KT��yg�Tc"8H�-����;K��-��}�����l�����}�����^��v� F�\*��H���An����n�?���Y��6���J��f:"<��UMmC�4�e����E��6�2v}���r-d��|"���t����c��*�8����=j4|��0pQ��Z �p�"2!�0�.���N :T���`�"2!��Q	���R��-(��J@���L��fM��3�D�����Z�,"b�Q��t����
#p�LY
%D�!
fE�Mt.�M��t�:e59�`X
1�`t>0�1Y��_ LY
%D��!/ �������e%@���7��6��HD����9��IYV"D�&chN��
t�R0���S���	����[Fg�� �!"�F"�B������(���f��HdBaS0k'0���:6�Z�/�Df�f&c:��K�A6&��t9$e��G��i6��0,���f+I�2�#D:��h������~y�l�kRp���I��h���x!:$��Z�)8BDK0k<v�L]^P�I��W������&��6���������ac9����k���l�����c��+���}���
"�>����5��������y�D�.����:<,�Z�	�+�hD}m�����$��Q��[6f��vY� ��"�p��r���Q����S��^��W�6*�m�qfc62��v�! �kf�gDb6&!�� � <�`c���w,��r�!��+p=�}����q���h�B�k�������4j��$��\��3��(�o��mlz=s{>]y?\ml��fsb����P��F������� ��<Z`���m3d>���,�[����n7���wV6�
"%��j��
��$��jg�Q���0l�8����)t���?��,���dFH�fn�ksR0��u�!���`����|�^�S"��1�@��6+m�"�
�LYC������9T�MXD^AsY0k�]JY�qY�����L�SFC���<���@��������j�d�J/@z���Rm�j(!���L�P�.6n����ys�T������`�N`l>0�-����F��6��#��c"(��Y ��7�������_����������������O�*����}���?�$����������o��8�#��~�;)�9�c��� ?�j�������y��O��g�����(��F��M��������G�`wf�����"��\A�m.��R��n��9���C�H������F��g���a�W���f��{]�6���
fE~��?��P��k��.`����3f���a�W�B$h��{]�6UH`	�����(�+p����2SC���������Z��V�XO9��]�(YS���Zt�Gp���f�M�2�%Dz�U�+���Z��f�w���q	����yW;�o��@������������^)(���`�{�C(>���o)8�j�
_u��M��}�5E�r���0���(��F�.!O}�_����b�M�C�w��%v)�
�8S~�?z�pCA�m������bD�W@+��~���5�*�!�+h7���ulUBf�0|d�_~U���h���������$<�E�1�BS������D��y����� lU@�B��X��� lU�-I�*��@?[�f>���^ae�0�o�\����9�|Z� �����Jxt��_J��
���l��M�����������s������8g �L����g�5�a�����9CU�1��U[_G�?|ga�b^R�:_�����U	OA{��
�V%���:�S�v���
S��=v.!��fb��	���bD,�5�c=C���C,x=���]��Z������.�h8a�x����V�����8D��vC�	���Xf�>���]FY���RnNn�����F�0�~����+p��f	���X��&`r���`�J�
#8>Z`����
psrc�%,�c]R�z)�T��X��,h7������l������)��'�%�~�d��"���8�����V
P�7�
���:
p3as?�#�[L���c�AV��y�|a$�����<��!)h7��H�Cs��VN�����)���s�#��Q������cD�8f\{��k^�f����`D��~��<�-���_��QA�1�;�D����F���n�*��1�;�������[7{�s�D�;�z���F����7�-�n����V���j��V��L��1�������$<.?�w\�5�.�\����0��Z�~���ybdzs�[�'�na^s�l]���ybdzs�{�G}��������)������7/V�2_
���y��#�y���_��\AF� �p���Xq-+n��ei��sY^�S�F_���r|vh#4�fR��wm���K�M��XP��N�3	�!��+p�_���u�C 6�
\Op��?Za������]IQ}���$��\�C� x}��ui��=S��R��[8!@$�fD���C1�VQ�Y��7aD���x������+7z���1��n��r��v!���
��\AaT0?pg�`c\
���=|g�ac���l$h=N����?�����0B���lM�������#7�/�h�Bo��{��K������}��Y(X���"��HYD&�����;�����"�e{y^�,"#�������^J!8�Y��E�y����&����=��Q��"��HYD&F�}cyzN�6��HY
Fn"_�M�z4I�\D�l/"����PbD�w16������d��"��HY
Fn"_�M���E���"��HYV"F&v�M�ut&�q����</R�����Icy��JpL�l/"���e%bdF��D���7���|�^D��F"�D����G"��l/"��#n"_�M���"���"�e����F"3s3���]"�1	n�?�2f�����L��#���c."9n�����)�&���D���}��vC�)8b�Ob]A���pXD~E�!��16����c���lL� ��#����4�b��F0��n��L^Q����L�1Fa����Cz��l�qe�`�A@6f{�1XD~��
�O�w �76��O^\����k�g,.�+�>��"�+�
��;c�z���|ilL�!��#��ccv�ccr�Q����������4��5q,�eIx���=���Xf�����J~���)������C��$�z%A���$<ac]��������1�q����K�-bct ��;�o�(��	��$����������r���z6���3��;��Yme���I��Fl ���QV��Ex�����[m��	��|{�����M������I�=%��j��
��\�����O��
��\�c���PWu������{�#����On3��Ya��=B*
������:�j���z86f]����^D�{
a
�06������NX�!��E���$�H�&�+hE��K)+p���<�j<�%@�{�M�M���
o��E��{>�g�{�M��8�����<�zl� �=�&�66�������^/�H�&�+hE����+p�l���e�j�
�D�3*R0�

p{FE�����x�Y��V���wOV���`���
�B�3*��tV��K
ps�v^&,+�0"#"��f���!"h7��H$� �+�sD"9)\��X�.�T��B�D�����P�,[_��H$w��Yq.����+p([Z��G�:3�u
f06f���V�-�mu�2�#Fz�R���|W�-���$U����+�T��Bpt��6��J�#�s����c'�xe��j���<��V�^+�XCT�T�W�g
^�`nN���$����&�;��^���.�1�k��m�}��1"����'���h7�2�@�Ho��,��Q�!��+���y`�,�+�mv�2_
sy��f�-�n�EZ6�
2����/�,���Q���/�2x���z�F����Y�;�1������)OeL�gJ'�zpcJ�Ix��\�C�[�j�/��1�'8�����=^`��������7H�b�-�
��.f��[r�E9��Yu)�v�PL�<�����o\{����[���^�J?����a0�0���&�rSVL��Ex����<C�;}2Ek����*��}�)
�3!��j�>
�%8�<�5�K.S��F�k=Oagg��mQ��[S��2�e�{|��`���������0�����Z�D�A|����d�����U�71��,��H=z���`��vC�)��Xd���{#	�ST��X�,p#2�Z`�l%���6S�NY�FWP�:S4�R��vC�)+����\@+0]	�%�M�S�j�)U���de�C�N�n0e��'
P/�%`UP��T�:e���
h������Q����`��1.���f���@W���6Y�NY�"F���&����I�nH���H�S�:[4y4���$h7��h�-I@kG0�������6/GZG	�t�#��|Q�C:N���>���o��lPp���q�������y5� �����y5��*��a1�?��Z����g��	�M�0���{�0�g���j����{�
5�2���-X�U�	���`1F��j0�(��8O�h�6y���������0�9n3z����F�9G�1=�Mp���6c�I�~Xad�s�iG�C�:&8�m�h�0�@�3���1�8�S8�+tLp�
g�zgt���|��
+�����F�Gx��������)�d�]���c�s��a|�C�����X%]J�.gt�����b��
\Gp�Y��e���?!�7�D2c�;�RO���� ��<8l�����m6��y��p�@�i�G�����7�4^5Bq�V�h�e� ��<Z`��O��.�_����7�;v��UW��;+/s�#��>��e\�U�����2W��Z�>��f��^�LA�0�q����&	x��	�{����Kk���
�{d3�������,�����'U����IXK^a�)L�)�GO(]]P�JJ&a-y�)�I0vAe�)��!���dbl2J�H�����D�K��^��&,&�0� �O#������&��c[P�z�%7�cbH�E�E�nH0aYt��3�I06?x�n�����	�����
�,$��u�k����%b����\�=I�$78����,0#�
�"7����$������_�������"�#�Aol�$D�\��y��f(
VC��d��=������$��8cA k�/�L�:�AVS$�B�1I3kk\#�q3W�f���/����=8���Dnfs?J�Mt��f������c�3�dP���=��S������v��Q�O�v��Ny�S�Ay���B���n��S Z�
��r�5�2�\��N�
V���W���h�Zd����M�7T�����&�e��)s}e����P�I�'B�|�e	l�C�'pW�;��,���{i�t$;�u��P�:��,J�����^%��������u�L@vz���+����vUZ��0W%��.r�Ru�l�d6�p��x3��y���� �L@$�A0?�zB�$8�n����	p�#��4"���: �5Jfr3�P�%3\#�F������k�zs�=wrJ��������z{���3/-
�����V��Ex���k����,�bc���(u�l�����P2����1Tm�YA(���5�$����Ip3�y&����"0%��C��]�e���$�y-g�{��:�,:��
�{����W�m�A�
G�l�{��O�n{Tf���
"&e
f�%�/�NX�Y]����zL�CF���\o:�$��e��`���
"x��Y`���
o�AY��:��O�L/��e��`�J�
"X��Y`l&�ML������	piY0k�M^�]Y�n��_(���'�� �6�
&����
�l�,cs�V�@V.�[�E�h��,csY�na2d�����WC�"�1&��MY�cdy*A�U����gA�G"U����]�u�H��v-��h��"�����Y�.�8I�2&)�D#b���n]�
Rh2��"���P������"eG�p���e�����]0eG�t���������)8B�sv��<v�W����_v��L��"����J��L��!����EnX���$<�d�J���;�y=�-�1HlV��
"��yBDv���1�O^�1T����yBDv���1������j{C�2����PY��`�/���B��fu3�������l��x��{�	�aB��,^pYkK�7��Lk�p������� ������O�V�Q��8��S������ \V����h7���	�\�DJ����f�Y.+����;kzld.�
���$��� �5.�E��b��7T��}�}\.�
��9���x������|�j�~V�	���d�C��VA2���:CA�d+x����<C���������&�z�\��{g���� �Q2����\�8^�F����Jp3���g��l����\��dF��fQ��9��|1R��N�)��J�{�C���S�U^l�_��5��I�=���,�"h�1�?��'c�n�7g���%�{�5;�+�S?������:c'�0e	��L�W�����O��Q��tt��O�x)
��E��`�Z2 h����LB�C�&p�LYK&DTm�&��lj��)�M:�KYKDWP�=���w-��E9BD�F0k	��<.�+3
p���R�y{��	0:��!��;\��!N�AG�W
E Iu���/_����zU�a$RW���Z�/�D��4��U��DW��&�|a$R��(���D����'�Q�K�N�_
�e��Ps�A��	!�.e��lP[�
�{>��_��lP�����Zl��Bt����
�� r�Am�5����*�DG�|�����ibe�i�7���a*��G����9�����H���`�q]]�����c���7��e�� �n�����k�cbs`bS�2�@��n�n&����<��`��!2�i���t���D����������n��
2���#����X'�F�5�+���<�F�NT/t�z06&�1�9m3�=#� lL@$�A0k���$8�n��`�����)�y<���XQ�����Ex��/�4�&��Wcc����d��l�e1�ec���kV�e{�������A��P85��Ex�@��s��&#Jcc��@��B����;+����4Tm]!��+p�P�apa��+p�5~������pl���y�q������'����0R���[�W����gh�|�����+��o{hX�o���^�E�+���7V^�J'���
�lW������DU�&v)��X�o���^}'��*|cU����:�0�Ux/�|,.�Q�O.@V���*��[;�Y�o�*|��B��ZSo��z0D`�S��P�&6x�s��Z�	��+�>$�O#���
W%,+b�(@c(\���B�iw-��e�Dl4����tV���i7��V	�J+�L�t���66#d��Y�n3R�0����3�r�G"\�l/��_�pIDc-�h��x,���l/��_�p�Bc-�8p�<��\�C������4[�TN��������4#�����:eG�t��^.J����~y�\'Y��q�s
RQ����/O���:eG�t��A*j�����i������T�WXl�F�<���}������>B6s������qm^���l��~TH�Y�uk�O�w Df7�Y���D����,�:e��b�Y�5�!~�GtxX�����yB����f1��2_
��8�����p��|���dx��f6��/Kb��C�k�e����)
�1��(,��a����'�4��c|w&bc�Jp!D}LCaw6&�9�����1}�!h������.����� ���.��{NS"s��(�L����W��~�S4��<> ���=^�����N�Z���V+�l&?�j���Z��[�2���j�����h�q��g������i��}�)J� 	��� LQ�k
���5���%8�e��)���qf�f�{���5��kvE
�/��=��AZ�=V>)��!<C����b��
�m��v5O@"��nB\(K�f�EOu�	��y"��nB����Y��Ct����1����n@�s
���u���D�����5)�����`>��,�7ifM�J- L������#:���Z�)+����`���t#��&��IY�%D��A3K/@�VL`��!����3�
0:K
��dhWL`��!23��3�
0:����Y1D�)K^�H:C;e]����"�F"3f���D"�Lnn^�,h�b�_�C���]	�}a$�05���\"2E��uYF~$e��G��7�A���4�r�e�������Y0������]0eG�3h�R��x:��k������Ad�N��i��_�n�A��2
�.�$��yn�U�	�����/7'S��i
��;.�\eV�0E����~L�S��U�6]�a
�M������w-�ty�5��dv3a��BW9
p�����;�!"�)�5�|m3E�����k�h�rY� ����|�e�����6����i\kx��j��SZ��C��\��)�����t��v� 6+	�-\�5�#St
���1�Y���\�k�}����q�����M6K3nQ��z��`c��u|&��o��������������~��I.>��@����$Fc����!Qkx����;C���Edc��P�������Y��+�%��j�Z��\���:O\6��p����C�fn���[S�������A��#u>!��r6a|��:�j���cc�����c��������k���wF�����U�n�
��+"� �
�YU�<r)e�����*|������j�Q�7�N� o��*|������*|gT���U�n�
�����!��cT��<2�������9��KW
]CDR_0k��^�CR_�������P�FR?�sGn&���e%BDR_0k��DZ�CR_������EN���UE�$���]0eY�3	����X�)���}��H�w�42��#��s�Z���Dz�`�w��5c
J$�����{]$�������Cl�5:�I�#�Q�U��������}E�\npy�2�#Fz����w}@W�1W�Y�<K�#�sm���?_�����Lc�Y�����c����i��kn>\������x�1Z��q/Lq��k��0�rL���	�+x������k�*l:H���1��o/l����b�<����� �
t���o�c����bD-�72$���~{ C���>#'2���8��2.yyZ��������w3��Y�� _���������(�;�h�:�(!c��|�I�r`����YT�/�]Nx|���������r'������w��������
q�?B!+��j^���O������x.����������������?�"����~������l�/�������=�:�	�J�K1�������'�l�/n���������������������0~%?l�h��=�F��Z����/g�S������O|�{�O��������u��Xk�������*��Z#8^����_de�fZ?ox�Z�;��-|���
n��^}Z�2P*��8�A���a��Vc��^Vr�x�6�N3���2�����g5�!/��e���=��~o�7���f�9/��xm�mp���7�P��-h���8q�e7�
�:��q��|����=�k�kxe�O��vi���^���U�c�&�����	Z��.��U9�Mk��Oky�e�oY^�gy�y-�-�����Y�J� o�A:��d\�c;���,O/��������N��,�9��q��|�����k��Z^���1�U��&K��Vy���<�k�{�3��X^���M��'�kOky�e��,����������D�p[e�(��
���h
#��q��`�7*�q,o�s�f��O�����8�\�������_}}%�����s��o������!3Q�od8��V�����	�o��K�d�HL�������7�XN����g;�W���X��o�"�`=O�c]j������r�Y�M�''wt7]�������������e��=wZ���*�Ow���F�����,l,o���������#��J������2�7T>hmy{<����WL�D�p������M'h��6�rpV{.���XG'\Z�iy,������|ky{D����W��D�p��3�c���}4�kyrpV������������YF�;��-o��r^��~�~�K�7��$��r���I8A{8F�dz�Ht������26<���iz{\�����1�j���<���!������G����Tgm��z�d�����Y����������,hd�mo`4������cli�k��Gt��\�jI\����I��R�8�7,D����O�gGF�&y:�#�`��6����QZ�`y?&��A��V�����p�A��_�Lg�
\��i-��&��f
����QZ�d����0K>�C\�����-|�-z;�~a/��-3�Y5��E�)+�n���NKi�2<y�����Kg9/�e�k~��p�S�����v������|!:k�l�D��v0�����&n9��M*g�W����i�<���:��N�n�8S�>����8sZ���
�g[&v�M���8myo*y.K�9�_�g{���LU�o��w��G=UH�	Z����utNP��HT	Z����'��	\��i|S�sYoR9��_~^V��M���!1��y�:DU��j��7��!��U��V����qob[�t�\���N[��Z7�c���W���Kl������-U�����u��:nl��=��>���|�uF��X����VR���N[���;6�l�����_~^j�4�]g������������gR���������O��d{cGt������7�sL>hm{{�����i����@k���=�oF�\�*_b2�43K<��S���f>��z��N[���;&�6���y�-�����][e���9��n���#%����9��"`����d�czs6]�az�-��9�<�Ak��-����2�Y���x/�x2O�+��#h �F���b 8}��Ey�m�X�n�U�N��>;������pw{���l�Ka�������{r�%he�Vyr&ft�%��V����^���PNw�������6�r���������.���^����%B�Z��V6����ZmXo��s�7[�1�����27<���\N�Gl)�Kl����hM�M��lS�:�����0�v&8}2��G+F2����vc2�;-�e�ot��9���8/�e�~������1U�S���*R�e�����s:�oE2����w�����[�Ak��������#v��I<\���qm��U�%f���8�������8!p���N[]�9!p�������y�-3G������VyfcB`�x:��	��Q�qz�*��qB��5!����>sB��=!��U���2[.��������{�W-���3��lo�K�3��U�����@���N[\_r������W\/��lY�����&}�]$�sh���M#�2,�:A�=�_|���n�V�N[^_��Ak��+��e�,��o4����b_����U�o?���8)P�j�����pR��5)�<m}}���e{R`�[_?/�e����X�S�"�|g.��@��/��qV�b�
,R�:�
\�f��-�/��l�
,w������pX�bL����������5��;cX`�gg7���<m�}���Z�^������|��:��H]hX�Y�b|��������$����ekX`y�
��a�����r����KoY8-p1�����\�q�m����.���"K��\8-p��X�vx��i�����rox�;/�e������xL��i��1-0���eaF�����,��]6�e�Y�-��n��Ak��c����[�,o�����g�G��.�F��uvKg� ����9��U�����W�W���;�*�+>�-���.��fwy���?���Y�E�����v�Q�X�?����m�[[Vq����~������1|?�����cs%��&���������Y��;�����]�u@W�|�b����p�2�p�:_��S?*P��������W�\VA��U{w �����������8��MA�]�O!.�gR�5�&���i^N������
�z�'}X�k��o6���|��Z^�}�?����.���o��|���9���o��|��E���F�AV�Ukv���&W}��~ ������_hdb����:>�zc���F0��
���3����acjH�zX���6��1���R��8���
i��^�-@7�T^s`H������h>��&7���TITky���IT���H������������/���������>������w�����AS�Rky���l���H���[^��A��O���q,/����J~%�k3������������mm��Qjzy~_��~����=�������W,�D���7�r,^���9�+���i��/���Z��v"��Dt[+�CR���Vh]?hm{{��Y�m�B�./��>��'��Y��������W�P�VI&������
��Pk{5f5o��C�@kVj�k
|b�����!t�8
\���yz!	�,����}�0|�4�:��OKg��A��Ak��]nx�5+��u���7{��r�q�uH�	�SL��`A�J�j<���^�7[�����|���������rY�Kf������"y�e`L5������A/��<��72O5l��?-�%o����w�����O|��F����<�oBuU�*�{�-2��M|�M�,5�3����6����-��3����:�|w��yY-�������-������@�/;��F]d�}3�����)2�U����s,���U�u�?d#���i\lA�[��|UL���x��"����7��O����,�+
ZA�?.\��tx\\������uo��	Z�.���S�Vo���������(���bw�dX�P`�+[~���pY�&��V�}UW�Z�(1����7*J�u�%&��mTC`��x4�r�q�Gc8��<���R?�.�bO���+\���v��\4���N���H�����lt��-����'��l�-�Y_���ZF:��M��\���
�s4)X[uE��_��r�1��6��-����'��\p�_�	�%
lX]u�����H��/@g���R�#�^�q����w�._AK��.������S����1yd�yz�b
�r6�@��&4�\��:���8�XS��_��N1�Wn����/O��n����������73���E���!KW+�$�l��Gg�E2@�o[�[��0l�*�[���]ayEa
����0��\�8�X�rF�O}5��rY���J=���=��x���q4���r�yz,~��&�H��q�f����������C�%p�I����k6,��9�x6��i�{9�#���[`��+�e��K���Y�n��X{�	����t^�Em�
���n���xE�r%?�/�Qc�OZ����3s`\�L�|�f���0�
t�1��%�����Fhwt����D7mX�+�0���l������4��y0��o�3��p�R��@�O	\�7��>':k
{b"���$��@t�@�Gh�7F�Y�w{3�l:Oo�C��4
��-a��c��UZ�S��B��$��j���u�������
pD%P>im�{��G���7@�[��5L����u�������Y�Q�,1��|���@w�N7�l���@�;4��\���|�f���0%���Q(���Tte�~��u�x,���6&���}�a
��0SN>im�{��G��'7�2_���X9g�Gx���yWA�O�+:n���&f���Dt[���NS
l��P����
T=��<��H%�gk,
�I�ng��J.��
���V�E7��G�|�NY������n?m�
��I+��<��(��gkG<�f��FK��=G7nYO8������
S�YJ��O\�/��*o:��a>3�lk~�1J�L\�/�-%p�p�	�����
;��0e���]�O���OP�T�'�
p�	zf2L�7�Jc��>'4��|���j��d�r`����Hr��9���
\��9q��d�6;��������L�`t��C�#��L�h,�����SAtF��>:�N|�L��
������!�����4�����-p�����ig��83=�S��j?
�&igc3���d�7�F-�>sfa)ea-�cyw�;���
��VXe#�����#�#�b��x�{���c�'�	\
]bFL�wD��X��7���
�OZ���.-��X��H�3��H��+����}|6ZX��<��`bBL������'n��A�Ik�ceH��7@���5L\��*������fN��a�lL�������I�VcRs�����I�vcR�� ��Y4���$3���������F�?�6=���������G����������������^x ��Y4���01!����������N+6M	\
]bBL��S���������k����S�^=�@WRz�����;���I�����S�9:#��c��S�{�d�cAt���9	3��"��6��$�����8��u��k�V	�q����1p�3����MI
�=S�x�$��z|5o����$����������r|�:	��)�{��u�'��2������%��G'pa����0u6�|����$�����X�#?RgU9s	C�$L]���
!-q�.�!�������j]�'���>2Dw������SWx����������
ps'�6���|~����J������>���9\��E����[�}��m�=�u��#?��i��|������w?~��w�����������q��?�����<B�<O�R�4JceAc��Dx�UNt����e���]v�;��	\A����������������������~��?}��l}9����/	����������o���_������;��{����|lW�c?��_�������7o���p�]�7�F��7����CyC>�\������5�s��������z���T�����K��o������	����{��an~M����FXs����}(^��.�������YP�>��F>�$����Y��.1��^2���*,�<��"�X�h�g�sU��vA��4Y��4+V y��x�_�a����x����+��.1���
��f��O���1��5$7�k�����\����5����[/�G2?n�n�-����6�Kc��6�@���!-pa~y���a��K��V����?�s��`�+����z�.���A���HX��)�����+��.
��Y��B�Z>im��i��\��X�����Gs�n����'�s6
���hz���G2�uN�K<q��iP��OZ�n�*0�.���d��YX}�1�C�S�j����t�c:���3}n��4�g`�%��fK����`s��`�K��KGz��z
�|MA�
R�@��Z���#����c�����93��!�����L`�]X���k�������o<c����,�N�{����p��nk��s0��'��������5���f6�S�`��Z�j�:	��,�b���m$\x��R�0��`ZR��������5T0�S��h�j3��*\��ls�1�V3��O�����f��G��EAtE���9��\b������y	a����_��qs�}��u��
����%^�W3��$����!pi�'���%bl������93
��Z~�^t�i0m����n��4���SY)��4��F�V��O��ik�������)�L�i9�E>[1�`I�l-����q�d��m�i%mc��I$l�z p�t�$L��h����/>3��~�~��pI���H:A�
�K�%��t���z�l��-�g������'��o7sfL;L�J}�o����9�
zG}��������f�i0���c�7���)��)�q�ek��i0���+�V�2\
��������e���8�E�*��?"�����A*���������F�CK�������_�������]R�V����6�<����*�`:vI	\���0]�S�����&`����
����K����MJ�����b:�OJ�G2@�I	\`y�L������F�r7sfLW��qz'���5/p�-��o?v�!� h�&�o�� �� ��hp�Vc.���m���#��o%y�x�����7��+��Z�"8��5S��a%f
����[5�����5�~�fZ�e���YC=k��Q3�XW4b�Y3���i�xOV_�g�L�dC$��A����g���1�����nl=3i�oz~�N=3��1��A�'h����Y1���%�����[������~�bZ��k=3g�g��7*�U���e�g��7*����vP�q�EoUL�d_$����������������������rg���x���*q�����e(��;,�f��)C�������\�8c��h\�OZO���X�3S��i�W���u���~F>[������f*p5L��Y3��j���30����5�j7sf����io�L�����5����&��X4��ib������U4�N��X4VE���W_s����e#��!��Q8���a�
��U8M}�HtF�T�yE2B�������y��C(�����.s���WV�H�y�NLJd��f���C�����/1sh��X��U����0gP�'��o7sf��~��*�N<>g�1C�*�����a%�dg,��+�+�������������_~X�����J~�����|���_��?_oEVd�#����S^�"�~Q6��)2��O�����7���������?|�����o���o�����m����?���|�?^��?���_|��������>���~�����������������������������Wd��,�y���������eq�����U~�������C���P}������=���O�����=��F�e�������O��?��d~����Y�:+�~��~�����kn�r	������Ve~��.�o���
������^[��t���\u�	Uw�	eu�W�~BU�~�%z�]���:��U����l�������]���_V���;L���������zo<yu����8�?���!���?m�������8�?�E�_�}oq�	E�_���Fq���������?�����������c���_����
>�7����������Jy�w�?��C�~zQ����nu}�?x�Uv������������+���r{��;�q��������]���o�����lou��.����$n��.��o�a����Ww:����s���o�{���$m�7��Oo���d��%��������N/r��!���5��)mh3��������W��'�>U������m�V�i����$�U�������������t��$�K���WL9R��Y������*7�������K�y�����2���7l
�'�J����[��QT>����f��'��.]�(� �.������R��((9��R�n�EU�|X+�M����/E����,���(*��J#�P6X��o�F������<VTZ��e3Y����zw���JGtzsK��?VU�����x����m(p=�F�����B�����u��FM[���T��+_��u�w�d�W�����U�|I>��w�o��z�B���cga|V�b&�����.��p]��������\�4�y���d�*��?��A�������v�������*���^�Qz��w}��Lz\�(�����g�8��8-�b�o�Y��@��+�+�����L�-hXY��C���:�)-�(�1�����:���sz+o$������Z������9��<�r����������7���u��E��
��
����Jm�Y!�%��������k��2�q��@V&,��h��Hb����:�M9���/S�ooX���!���|�������=�7359m>��C3FD	fE~�}�/�?�Z~/�G�����q����c�$�k[����c�C�c����of���]��u1���@f�{4q�1�x�
���^u�9���Y�_b��s<K�Z~��;f�u���O�e�m���x+��s��|6�N���+(>�"��E3�s������6�js�����W��>�D��G|%&�	���^y�}_��]K��*��j���<�����}_�����j��j����;�����}_��������m����cn��j���Q����_�;�����w_��}H3~�_�r���ZA)�}aP�V��1U5q�wni�-7l��^u�H
f�V�X~
��LI/�:0s�I�_�WKGn��1/�_�B�`>������7���������_���@�7lz?���h��������q�v-�FE�8:���KUNt~�A�_�}�L~���;?}�T,���M����0.���&����<fz�y���0.Z��f���S������^{,t�����KF��l����K�'���������k��.�X���3�.��<����	���^{,��`>G����v-��K�'��A'Y\A�m���u��������?���	���^~,%���t���-���M�W�.�X*������X~c*h��{]��T���p�O������{]�������R?_j��z���.�X���x��v�(h��{a�����g�������~/�>Zz�V�~��/KG��n;�� ����-� [�;���=���B�����t~����^{t~���\��c��6�_���c��t�W��]�t����^{�t��������o���c���o��_��7��M������L�7���L������m����c���u��R�8`N������c��[��o���B��l���EK�5�h�������f�+���^~,Y~?b��Y��������9]C������h��rv�����W8�o��_����q��
���*�r��@|��E|/?��5����L-?G��6�_���c�J�?���2m������t����"���p��W������e��"�_�������_���^~,YM�W�/�����[����,�X����6�_����_���^~4����-�_���^~�����K��Z��v���0����Z��Ui��p����k^~��������GO��o�����GO����/�����M���0������i��,����k^�������o���������o4�_��m����������o��_����d3�����^�����R�3�����^,����R������^���b�����<���k��.��3�?������/N�m���u�G���	fE~���y�'h��{]��
����&-}��O������#w��Y�_��K������k_���h����G^���m����#/��J��%�?��������?����4�_��#����m����#���*��%�?��������?����6�_��#o���m�������k��:�h���m�������kt���~?������^t����������o�\�����;O}eH��>�Mm�=}`��� a�����lS?az��~��@��o��
��3���PV|#�j������p����/}����.u�`����/��D�7���K�>���������7��M���Rgf��y;�}������}�o���o��}�b�����[����-���6}��%�A�Wd�[����%����+���^wy����.q�Q����v-��EQR~�*��DC�E�����A+@�A����8�?�(p�|]�Q8z@�{�<K�|.J�@��_~\L,�E�Y�tQ���>�uHQ���L��.*��j��.)j�������EMXo���!EMX[>0�3����}������l,����6�>��J��l���~H�����<�1�;�������p}`����E,@��������,EO�m��c��
���
�x�}`��_�����S7b}���_������SG"#}���_������SG"}���_�L����SG"}���_������SG"3}���_�,����SG"}�����!,@������#��.�>��"��t|�`V�x��|��]�u���K
���E�H����w-��E"����G"���k�.q|�`��8q.��}��"����G"���m��H��������#W���>�u����K�&�D\EXm���E"���,�8q5}`��_���>��|`�H������<��0�������#��>�����v�`K�>��D��+����>������ ���y[��7�����������8W~%?lp]F�}0g�_��?���"+���_�_w1�_d�/��6��.o��w��h�0D����;4�>e@S@T���h.B��E"������`'���;i���-`�'-e�F��G�v������/�����c�M0+��2����������a��1������2��Z�o5�P��2^#��{���/X��S~�/�k������V]f1f(��o���Wp��V~���
�p3=�7��<m?�Sk��>3���/X��S~sI���LZ0S�j��C~����'|)����K�n�
/�����,9E��ul����$D^�w�����+?&�^�"��q�=�2�7^U)cL���_�����RFC�o,�_
\^R~��8e4D����y[~.X��W~���v-��� �G}����F	�������)�!@dS�`~U4Dp�;��=y�J�������\~eF��c_��2"��+���?���k������)?N����S~U
�U���-�,?<Q�r�>,�����c%���C'K�tn"���F�o5n��%}������#��A��������-�p�=����f5��F���kQ�����Wc�A������Q~z5&�Dt�CrH�������c����1et����t���c%���g������������?�m�+�������6r�������(V~#�������~��������(X~�?F=����S~lc,���m�+?.}+�6����rb��Z�v����73����#y��;�Z~/�?f����7�Gj�]�������a��0�X��#y�ea��l��6J�_�1�X��#u������^T�`��������;�Q2��r���9��U6��]��u�G��������CE�����6J���1T4��\I�m��m�+?��`V��������Z~��?����t�A��V��+�?�k��.����)�_��%8�����c%����������:��6��6J��_���`V�7��Q#�'h��{a�������7��S~
��v-��
��y[~�6�y���)�������a��"�'��%��T-��v-��l�����)@��V����VJ �����~�
Zmw��(V|���n����f�j��{a��f��hM->��V�������VV/hj�e/h����0�`/he������+?f��{A�F���^�p;�<��^�j��{a��^���M~��Zm��v/�>�Z�����������^},���D������������^~�_����K.�:CrH���{p�xV�x�
nM����u�S�|����u���P��{��8�u���]��{������[�#����]�x����Y����%8<P�����C�M +��'�<8����������,������Y
J���'T&�=*�#'�|��Pz���C������\)��h���Z���7��?T��R4_����Y[�����������z?s���Lf]&��P�����i���>�/oh���E���|�
��6K|T�M�?������L�7�U�����'~Rw�}��O?|�_��������l���/���8z��i!4��Y�f6�������|������~������?}�61���+����Q��W��R�S��]�h=fsyQ��[O7Z���)r����[c$������LDv���������xoxy���|��������]~�[���������|�����?}����|�����(�m�;��{��$`TZc!�>C��'�z]}\�C��W������w�~O���P��>�����Jw������?��_>z;^n����j~@�@�@����D0��CE�z����u�#�y!wO(����������*�F|B��\���^����=�8"5����WsD�0����������)b:��}�o�R���L��q��������
y�YsDj��b��h�������O���+/�����9"�C�O�j�����������K���-���(G��M����=�3������r������"�Yk��2�#8�k�I��`���7>����!t��#���qD��

o�sDU�EuDe����|�d�~����}��m�}�O�!V���Z^g�h�8�<������������E�����?:�*�#Z����[
:�uD� �������|Uu��tD�8�z��r|��y�r�b�MgB46	vDE&�	�Hm���V��\�?2/wD�:�R7����
�����2����o,xa��[V�z8��5eTG�t_�|��~�n��9lv����9"@�Q���#R�t��-��f��g���8"�Q���+j��j���#2���=��s����,xa�A���d$�u.jhv�tR5C��p�d����$��L����A���$�����!��������B9"�s���o2/wD�
���W��.�#":D�WsD�0���
o�{5.��E����wGT��V��
���|���R:"@��p��#���09"��]T�9V3���Bp����6 �x��@����L��#���qD������qDM\GTu������35��V���!���c�3����V�<�������/���@���S6[aUG�+��x��DD��a0�>����<�q�B3w��Dm^GM�����%���0�XMe�tRz"`����3�z�`$k�MDx��������'�D��������'���^�C����<Qtn�
���6l���EL&Q�H����{N��������|���g�����3GQE�+-�zR������?�������UJ�z&�������"��>�/�I-��>�:����|�zuS�.�a{��_�D+v
!��S[1���v�����6�	���8�J31�7bN�V�oG�x�6�-���!���CX�-�h�sV���|}g���v�X�`~D`����o��o.����f����N>�F��7<�3=]P����
�?�*U&���u�#�/�S�]-��z9�Cc�����jK�,�j]W�R�"H����S�K���_�v����j�+�#���t8$�r\�u����>���T�R����O9.�&��������w?����	��Wh����h����#Sy�c.��W�c]����������ps3��|��/�x��M��D�I���.�@q ���c�����y71����F�5P����<����*bEnv0z�������L&N����A
c����h"Z8�X1���$V���;e��$]Cp�}Tw�f�,a��X�����^�s?8��!�}
�����2sy���#�#��3u����>���="�`V��nV������s��g������O(hO����3���N�s4��jb8�_��I��vE�������Nn�%z���%�'#b��9�X+�I��
�1��
\���)<�� <�%G���e������o���������{�U2�w"D��f�;�����I)��!W=�^��0�i�'���@��"#$�_�(�BG5�z=�0z�g��9LV�>�g������dr+�@H��z��c�%2��et�i"�V$��Y����{�w�)��N��:�����)<�N�����#�&�s6��>����"�`@���{>/�������8�V�j�]��Ie�^�����y�P�M���9�q{���i����z���B"f�f4[#[����U�DWc�e���q��&��2�Dw�+�E��U�wi��1�g�g_)�+�cf�9����1s&��&(�a���?A��w�������i�J�W��c�b�HP���������������v��; ��2��������~���[Y��$'�
���UBa�=Jc�^*��������d$Lp��3���L$�N�M(L�LAtX�=UPx��(��tQ�U�2
����}�E�Yw�������nb5�z����j�����iz?��<��/<Pq�#��8�������������Q��8j��8PT�
<�N��F{����J}�;���N�����F�I����V����t3u�,n�mk16���*�i��gu��������7^��/�����B��hN\�#r�<����x���+C
����0�k<
~�f�"w����-�������_��ld����W�R��8u���_��8���/���!h��u�L��H47#d�'y�+�����^���-.p�����!�i�����Qq���^'�
�������5�����SLC������Q3����������@��h4+x(^��D]Z�Z��h>���G�I�O�X�h��,�J�Dp���vp�����s��I��5)�_5Kj�)b���3Lc�eA�15|�!_h�%M��'%�������s]���b��=�WxM
���1�R	����XV��/�A����&<d���*o&���-�F�!��(U���Zll0���9��� ol|A��/��q�:b3X���Zxc[���Y?l!FCG��7��gs�#�%�jj�����Ht�*�Q,�=��?7��&F���c1�?WW�YGC�I/0q���?�lb$kI@+=U����k��y�_>���@OH�[x7�$"_�������X���|��v�/ s�N��
�c���2]+��3�%�Q�R���#e/h3��RAl c�SZ���N�I�x�JR�Irkwr��
��w����P-��-b����zRk���b��b�
��RAl=���\_�q���,e-{�'�������M�i����*�y[4XV��)������3�=��)���0�����8�c2l1��;S�����`�����/��ZoKv&� }<@�8�;Q]�XA�����Dz�p��b���Yf��x���iNDt"V�9���8��<��"�aH�Qt���=m~aaK��?��I�/��?���ER�B�������(�Q��]7�5
\-��E>��Gx�Yn�5�t��w�y�_���EV���o?l�J�z�������V��Uf�C)H���[w_�Y(���|���a��ce�H�jB�G�[��1���DTl� ���M��_]>Lo(��������7���{lV��P����<�����)H}��������h�
K������7����+�J#ohzH�����2[�4}?���G��h�~p����������P�� =ch����"���7_�j�������������|�����uF�-�O��%�����,�}���>Ynw����'�xJ��){z��#?g^.�"�}�U��G~Wo�u����u�V�*x�o�C���1���p�d]���{�����9F����P��T6E�/�`�������q��6&����`k���o��`�D'E����rY����l��>{��j�
q���~�Ex�����q�a���0�����8�2�[��3:)��`��V�gC���$��<�(I���8XL��X!E^��we�~��C������Q���C�9�W\a�gb�������@t��c�HQD����Rx	)
`K�ya��u��QS��,u���`���(���Y�3hq�w�
��&<K�AHQD7�����9��^R�U@W��}��x�������1�BI��#�da����'�$V$�s������ ������,������o��mn�����H�ny�X�7c�I$Ew�w"��2\��o�]w���b��s�����7�
���U���:�q��z����0��[Y����9��Q�p�H +g���Bp��jd��F!8G7��'�$EV�C�a���	z�ZNz�N��F����jz1�A��wC���5����i�tXM�~����K�Y6
�!���S[�����
P�	o����k��!�+(=�����	7������!�[��C�� ������H����~!a��\�.���@�S~TMLFs���\������<��
*������u_�Q�����dd|��U>��2g�Zd?5�,�_������.������y�m�u���&8���[���f�$�����"'`m���=m����`����zX���[>[>���n�Fr��I��I����z4��l=o��D�bEmD����{�F�����'�PPx��82y>�� i)�c#��y<Lvu1��AC�a�<��jRa�5��cl�2{�)���A��������������h
V�3�G�H����8�a�<@79���$wF�(��&�����g�6���3����7#;#x5�Y��p�����l������>��=�Vx����'o)O�4���Tx*��Z������*x5������^g�������"����"<�>{_��Rxe�"p�#<�D�W^0��l�����	tyNtFWxz���L���<��p�cO�
Dg��1=r��B]��]��<#��5�U�6=r�!o/x5��0|�7����M�Ex�Q�z&�n�}�����=��F�� W&�0��N����s�#G^�n3��	/q�Q���f�G�#������e���
��Wr�@x�J��^�5&+���3�*�]D^M�RYk�T����S�6�*�]��*��T�OE9y5�*��Gx�#<��b���"<23�&��)��	O��E��"�6#:kpar�G>����.���*���W1��9��������`b� ����b��s�9���T��P���G?�����:���Tz}�+���J�{g���#<:��x����"��O��z���0>U�}���
|��S���1��2O�����S�b�E9y�k���}�%0��X2�;�Y'��&�F�dF�Q��9��jA����E�l+�����
���q�d9,��?���-g:��D{E����Yw1�:�������wKn�z�Tx�-�|ZE/�K��zt��U�����M�=�*�]�|0�N��*�sU�+��h�
���#;������(�3;�L�LxE��V��7�����p�T���w�KbE������.J�R���$�(���R���,��.p��s*�����������5� Kn�~P�?8������S����Q4�&W�uK���7�
��t�^(J=��R75V/k:o��a,��+�,UyZ���a����/G�����>K���y���i-��Q�+�����^,�AbLG7�Y�
e&Vp���������9��h�9�����[�,7#9��h����Sg�*�A��|�[E�N�Vo�B���a���W�<3��b��i�E�8���{NE���UW�K��y��Fm�H��y�����T
E�0]�����e0������7�����GGQ�L�<36�b��+c/c$E��Y���=��$O���!xO�1�x���6��ir8�&�����W��!4���E�3���:�Ms_���4�<9��n1V��y�m(���eq����@�i:uv�������u��������t��^�t��X������t��!x��in����S��j���m)���uqZ.h]��[�+l&GM/�����bG�
"x��i���b��h��rq���������N���X�)�)F�t���|�%2��+^.��6+�
�GRQ4]�r��U��T�H���R���iN����&�h���bL���)Tq4]�r����4gx�GRQ4��r1�x�����!x���6�(�0&u��ny��zSI��������Ok�]FQ>�N=��;^.�1h�FG�/��<�Mw3E��>�(��y�t��9k@TM��\zwZ���d"�O�E[�[z����7f8��n>���-�����ym/.��W�c����D��}�����7� M���	�r'�
���Y%�6��]	�|��H0�y��������W__�8���7��b����ZFd�jQ��rm�D��x����5��ZC
�p���]- z�`��*�|��E�]�:@�j�z����7�`>��G���nGt�]_�l%��w�����{Tt����	M���#+�����c�)�c�+Y3]q�4������q��=�����*6:���w�t��#8]�&8�����e�"����-����`������Q�	���zpY����������}1jU��I�!��[�._�j��^S�G	/��TNz#������Q�����A�q�7��%x��t[ xx�^Mz����J�`�[[��Ho*)=c��5
3������_Z���+�zI[�0�Ho�7��#S��7�9kf$�!�!x5�����o���������coBo�&$[���#�����C�[ou#�������V{p0�
o��
�����	/uP4d3�g�J-��QxF��|�G^��\��Fx 	\]�:��1X����n��Z���2����j�H/���3�FM�c����X�zDxv6�S�	�nF�
7�+��������f����O�O����|�������w�um����w^\�������7������������+.�-���c�+�|nf\�������OEVd�#�������"�~Q6�����r���}������o����?�������~������w�.��������7�Y���/���������Y�~���������������?����~��B�O�O�����*�����/���aw�vX�>u���������������:����~@E�|%?���-1v�����a"����e#b���)�@b�kb�����&�>��){xV���z��X��d�.(�*��-w�1��:��!����$}�d�BG;������6����1kW��v%���1�a�Q�Jn���
+^�����?W�'���y����P&=i���'��d���"�FS�e�N���������\���=a��5A�P_�H�."�1wV
FE�(w����0�c=a0vTkJ]YU�N&��uo?v�1�^�1z����\%�3X��y{�0���Q �(��Y�����h�%pV�-��������U��#�
�#��	/��k/3V��
���'<cQ�	/���	�{�����=�*��5�BG�R�h+�$<��W^�-�~'�����0��ll����Ex��h��Ixx�
^Mx��\�	�L��`��@x-�sc�?J�Uv�kx�n$����#�oR�a&N�;v �
^-�}��
������3��`��|�(���D�
B���X�=o��<��WXy���z:LXM|�9���>ul	�{NM3�.�5MG�EEx������I�����L�]ae�b���gQ���e4"�*���<^.�y&�����$�5M�.F�/���9��PDx3/��<WXQu�����(Z���2e�#�qa4��r��3�w��Y��c���Q4�*��}bUPMO/��<WXA��g�������4��6���������\>����������c�=���i;A��S����[���w`JG��oZ���������ON�	+�	):�|<p
3�����K��X�s�B���dl�j��\�1'+p3��;\�1'��}+h�y���!��*@��<��KZ��K���hlq��3jzQ��/���w���4�_}��9����l�
2���rG�Y���
�+x0c������?��������vWEy��(3�
�
�UQ��d�*���s��+>����h��}�
��W�������T3����[���''`��V_�m�4����V_���|C���m�6=�EP���'��|�R�" F��fcP�'vt���W�sUz��H�j"8d��I�����I�A&�[�d��8�S�jo��t���@�����=���������'1�Y���D�5M�m��+�cgczfz3frm^����:	�Dx������Y�f ��[����V�v����{�C�>x� ��i����lA}���f�OG����A>���p2u�f �%`9�O�?�q	��%<����|�z-��g:���$\�o�1f�9S�Q�G��=�o��N5f�9^�-�'p5����"�����g�x�#����Pc�*E���1�����!<��[�,��7��Ie���t���J-����R ^��|E|�>�����0�,Dx�w�����J�����D}�?Q�n���i����=��KGQLx��Ox�[J+w�����O\��,�&�*�(
&��O�'<^.��~5��D�t���:��hb�3��x���D}���RK��N
z^�5/��<K�WX����'�^����f��o�!<^.�y{���N!�O��ny�4��h�����m����nm�.�;�v����:�vsk�y6��b�e(����|����{���������J��X�3�������o�ty��D�BWA���H�r5a����3VhZ����	n�n]w�gK����4��[��@�T���zB�09�a���7Bz�2Z��m`�Jb5��V�:������9���g���7Az�q['������vh�����o^
��R�`�/<�B�o��y����-��c����o�`��,M���������s�Jw���7J��r�Ql�E�P��d�l|E��+����>�Mev��lO=�\�_@��1�$����6�{>�:�����@��	��^36Q�	���D�x`xw�5�}�O�s��v2�m���@C�&��[Q���`�8f<���T��f<20����A(�7�w���JC������x��L��`��2c��Mx��M4�#kVBQ�r��2�=����pKp�~��/%����[��^�=H�.�w�������[����[9�*!%{'���?��M����x����������[�A��~��`���]?AQ~kd�q	g37�l�	7]�Sx����3�	o&<c@�����f�+���!����%�LxQ�7�QeNo�%��3v���c0�������|��������#�������Y����'�'<^�(�m�#�����O!�	�����:��G���+�sj�n ��`P��I�����6&����Q4��6W���t�����&/���	�������G��\������(��l�{�������F�'i����f��
�����=;� X5�WS$l��!�����{�E��iU��}���+�"G�U��s�/`���	A����/�pW<6<8�:5��5���(tLi�|s�����a�����M����eo$��;��j�!����)��$N������8�D�+W������P^ ���+d�(a�a8�W������Kp=t�����k���,�������D���KcFaO�px	�.3E�k�a�����tr*���������W�~\y��=u����/x ��h��S��t������c�+rJ��l[�8�c�N�ji�����!�Q��;�.���fJ�H�����P��9J�#��l�}������"��u��W\~�|���H��<�����;)�����]=9��W&2_5�}��/����aE26�@y3��<^�+�i�O�7k|�Y}D�>������X������,��!������
A������O��	�syS�x:�y��H����^�/�o�F��3�
C������8!�|��c�1���1|:�w���F��X���Mp�f���f���1�8���;���
��F�ax�����P4l�h*����9�h��
���2����a�
�&v}��Av�����C��"����+H�������8�dl�m�\Un���'c�Dt:k�t�q���G�z/�3uCx�������O�|;^�-Dg��������U���7��2v�W`��(pO�
�2��F��� �XG��M�%��X����h�%�i�c�PXM��RY%���p��4K(�M	�l�.��ZY��2~�-�-����{l�
�iWRz�im�������TW�������1�/��K^..������|5�{�������}f�?Ij�����H�Rs}Gj�}g��W�cK�*�t�'i|�89B4��117���������lQB�H�d%�e�C�#8M��pAh|����|��i�)Hc���4
�W��F<��/�I�:F����7���/x��H��t�Q�����1+>��������_����t��H
'�����3�{x�P
L�&��	�GmM+1Z�B��o��>B����R����d�8|E���I[��*�����������I�{�p��hj�x�_�W����d�8|g��7�A���������zP�4-�\�z5v�J�II���!F�������&���]~��C�P���p�$!hO+�lL�0��a�3DGe�(L�}V���Y��[J
��>�c���I���	N�%�GpS�����to���c+��~�,���/����������������������O��X��N���w������������o��h��q���Wn�5E�g��<f���$��[�7�o�/���t����53����z��5���F	�G�����I*Mc�����CDBO����1�4������� 6��W_�w�H��w��;k�D�
�
�\��H��'XcRHk(:#��P��#)��y�c�'p5�Y�[��a�5�G9S�Q�7�A�J/<�(����n.��Z�����ZQ��l�
^Ex���H�[��`��?yXJ|��	/�\^��S��I|�M��{g�K�PX���S�?��'���
2/^yzL�<����y�Z�)�O�k3
/����ny��z���V�-R�WS��:����)��<+�=�^Q�G�=�����vI�cLR`Ew�`�7}�gS4�<��h�@XE���]5y>�
�yE��Yn�;���!�(�~".CXE�Xc>������x����3(�y�A/vZi�8�y�V$~�	��fO4>�XA��gyuO�XF�oL_���Nx�Y����������}�lW2�w�%� �VVd��?�G���UL�N��5g��G':<��J�]B>:�����	�0|t�=T�>.��=�:�B����k0�U�?�����50b��qO�y����%������1V6����X����M������4��	~��x�k%x���^�tzg-��`�?��&<t��m�k����*��&4��|�������_���cR^�����dTb_[3I�'g�v�Jx���Ql��Na_������1�|��Q���)y�}�m���t�t	��4�p(�&1N|�z�^g�C��_�C&h��~��a_���a4��b@��m�J55v2b�fb+<f>I�^�C%�[�����V���b��:c�X@+��i��1`�����a���g������l+�3d��F�?�;��x�HLxyI�1�}�.D$&Hy�
����M$����L����a�7�x�'8���V-� ����E���b���Ny*T/`l��Q0:y�V����1,�HR����.�T�<$��&�`#I=�f�{#���1���	/���"��������#�7�"8���l��(pOs����t����'�<�[��9��L�x%P�hCk����f�`3���f�����e����N�7f[cE���Q����Vt�WLw���)H�+�N��Xz�9����=��tZ�P���DR���e0��.dy^�#o��<}+�H�	xE��Y�+t�XFkg�>�<�,�i���������?�&^,����o�	��\���2}�,�*��H6�3{k�H�;Y��neb`�.�2!G��9����8���HVe����A����]	�gke,r<�`��;�0$�:��C�!���t:�)!v���YA]��
�2��p!X�+p(�7l��]fc&�����"{n�Vl�I����I��
R���,Sb��@�i:�6�<�[cs`a����LW��n����"�1���T�M�2]�C�U�nS��+����Y�.�2k/��}�YX������#��Nm�i��s�|��\������6��3u�7���.O�']}�G�n��p��I=��2���/Xx��X^_D���v�q�H7���e3���0�m���u��1���������A��W=qCppW�V{��%x�OJxH 
���,:�e�EC��L�pV��I	�A��W�����Id,�3�{��I+�@KA��I�=�U>)�-��fs�����d9��F��9���\����U"-#��'%8�����W��A>iW�����D�]��d�W�I��OA���
���:6������n&:�"6Y�q������\ag�6%�����r�/����)Mx1N^����/��K�
%�����,�p�:�`�&<��Gx��9���m�e
V��FxL����C*MxQ���l���/�mIOG�>+3��0��b���x���V�q�sY���Do���G&��aI����4�V�3����w�QX������Z<}8�
�1�y�1#���h�i�hz�.���!���JKwV��2GQ=��(��2�-���CMO.�{NM�E�����bM��\�#l�(��q��sj��(Jc�����i��^M��[���T()�3hz�(�}oy��r29GQZ=��{����s��i�D��?I�5��[�A9����P <�-���r��P�w(�Nq�:�~�dx�_���+I���M�LcO��Oq�{>��o�;���c�6w==��\�+��f��9���p�n&-J�����`�6BD�x6�QVKr�6��3����&� m
�Z��=��6�}$�y��_�LQ�N�l��m
�W8JOI��M�X;	�G��Q4] 17��8�l��m
��JJ����t!���C�Q�>/L���2�����c�P�\�6����_��Z>��1�����7jS��`��n���6��V�5�5�Ml���P��4��Z���GN�>�M�>���$�� �2���~�AB2406|�F>�x��i:n(����)�zI��=���X��mAF���G;i���g{�s�M���|��t��Q�Jn�=c�^O��c=PS�uWn�='0��������f<�Nz�*)����,3V��y��6c�q$��r��2<�-LS���/h'c�F����	�`����9���g����~��&F[7;)��L���������Q�����Yr?K���J�B��Jt�Y����������*&:r����~�8�	���n��?�8����)p5�cG7����vGx���MC��~�������^���]�\���������������N�/V��w������,�}�����������=�G>�F��7����c�����/��������������t���b%_;��^���_aU����zr�@�g��Ud���=e�������9wmNxz:������c:J��Gv=���C����W���,�Lp',�LG	x-���Ex�/V&�����Gx|�u'�Wk_P����JG�=�8�E�>8��yM�|��'�W���{o���yq4=�j,zu��7�CW��T�L�J������e��������x"z5��^-�5M�o�<f$��#�hz��2�h��2j��.�<~s���\&=j)���(��y���imzF]�k���Cx�\f���������e^Nk�j]^���D����e��]�y�D���������6}�z��+�����������x�����J��������w���j���_�67)���d���D����V/�����M���o|�w�p�l�~��w���k��nCAl�Sv=b;��1������'ov����_V��o)�Y�~�E`��O���
���YR�h^�kR��\q���@�1�|�{1�]>�1����(t�}Q�
�IGV�H_1k��(��??������j�[��p��8�18������!#:��5bK�?K��)�+f��hd8����DpzN���F��p�P��
9Z����/�����;�h���j/z�nB��;
��KJ�p�8�P(d�(A���H	�
��g���g�q�N�~o�6?o�rP����������w���%<�1���O����']Z�l��Ez(�\�j	�s���!=��m���Ho���
�9�8��J��d{)���KJ�h��������U�w�����N\*��u�v�*������
���#�e��]W��������O.���^e3��f��m���VJ|��_�#����8�������=������dq�����>��x�����g��Y��������$�@]��
�;Q|K��6�2�0zI��h'�8����V���=��9e�Y������q	�/��b�UAt:q� g��'8c�9����TzA&�������+re-3V��	���j���q�� �)��{�#�k5���'8���V+����'���*b�:�P���n!�a��u���!+Q}|VF(P?��(	^��j9��=������dguh��2�w^��\Xv��F}�d7�~����2���$�
�&�2��N=���a��Gv|<O�t���nv�������tamv��y6�q�@v��f��\YVEv|��.��6��*3�VU���DmKy��mak1�E�n�{x5(�W�Z�(~��A�uv��7b�����t�nV����+�t��4�o]��S�99�1�+/�w��V]�j����Nxx����:����(k�_�nV�[(Jc��58,���������v�����2��F�������7�]+��K^.�������.
R��.E�%/�R��W��O�h���R����
,��(��+^.�N�/��'q4����Ok�uIQ<�GY5/�Z'��������E-��z����n/�~u�gi�T��FQ���Q�k*���Yn�F����g72��*D��g��/kSc������{�@-gD�s����@�^P6�L����R���t�W��F��@,p���*�6C�Z0k��Rm9#:$�����K��Z�1��J0+$�q����p�
��i9#8\�m~���:S�V8��+|��x��x������Hy�l$<Dp�����l$��X�p��G���x��iz����)����5v"�6q����Y������-,�W���G�?{�/�����lc#?����V�����76�U�66�Onll�U[���,r���r<��V��
Vj�
��.������u��N�'���_����OZGMJ�;0�|���L��R��k���,n�gqm���t���������gqktK���]�Wqk�������_��fp��q�c�=-��_�����k����F� P�
��������PP��R^i��@���*��f�zU�E����.i�
0�J�4���9����_R�[�Jn1+������A$�+��kU)��V��;��"�a��;�u��u��W�D����p���D��t3��)�����~������{�t�|��'g5���^��Y�*���k�NG�j��	��n"<��T��d�����	�`����W���c�#����Fz��4	^Ev�Z�<m�.Z�������z���Z�|e7�Q:H�����7�1�#��6��=%SX��H�CRF��E��DpFq2��Z^e�\��Z�ZI�L�J��46�bb��Ud�%�Wv�����]J�s�����o��z[��8�������u������t(��6�^�Qd�#]%x�E_�Kpt(�NW*���w�3�{c�d,�����EoL/,zz$���2���:u\1��2Xo�������6�&u\12�6���Bvt)�n7�Fm��#�(��FI�6��F�7Jn����&�Q&����a��Ud.���������q��Ud.����1����7����&u\�9 ��4w��7���Q�����ok[er�
]�b�Q�C�7���j����!�x���+����������-��Pv����n��� ���$����e*_���M)�\�,���t��
�j���3���9L%��`�5��3
	n"8�������X��
%X��)�
���(j�<;�UM���.q�f�f�3��y��aE����UD��z3���,�Iz������Iq,�����Y����#����������Et
�	ZEt��	V4����(����a�E����UD�8�����;,�(>�Lt����V�;�jfH�8a/��UD��n3t�Y-��E�gDgP�SG���g1�������%��������������K��>���L��o������x�sI]����'��?�����"�����'��n!���NF�I���&�$#h�r�Nt'���.q�f��A{�kb�;1�-X�������r�<���Lwb,[��p�(��Hp�����na�x�b[;�������g�]r_��D�G���0{ ��r�	��X�l�f#����'z�pm^m���U�A4=f���=������4���}�������'~�t�w��=�����4��s}�h�)K�j�������F�����)J=��[t�8�v�\�����]����Nk�l����������������4[��95���������{ ���b����nT~^���-x��in���������;{�vg��(������f��^�����
���G��\�Inu���4&����nP�
�I�,�E�
/�F���VF,���I@��S�-���R�YFE�-/��H}Z%�8��x���im�uQ�k\��9���Kg�}�*z�4���Nk�}EQa���&��{^.����:�Q4��r������(J#�16�D����e��>&{�\���6��w�i:y�l��bt��K{�h�]������2��c��921����Q4=�rQ���B�Ei�1e�����`l����h��
�{NM���4Z�2y�l��2?8�)��^.����+�:^�t����rY����sdS��E��R�S����4�:G6�O]�jy��Q��;J�D����^�t����r��u��+SQPz'�^O��������9����2Y�=V]���(����]������V�����_jc<�����x�������>��_��0
��<�n�^"s�(���c��5Q�
����:��+_��T�(�1�0^�{J?89E�?�*u^q.`��W�tj��\�e(x��i�Q��3�^FE�-��W�tj����2�'��LQ-��2�(�.Ei��H�W�K^.�����T)�i:u^q�X��+uxC�������f���4]��=�s�}g�4]�r�tbwa���h���Rg���,o�i:u^q�y���H1�FE�
/�z>�M7`yxM����3�=	^m�R�����5�����i��{6����r�8�ny���dg�FE�/�v8�Mw`yxmT�����r���T�FG��\�����}IQZ��Rs�f.��ZM?y��c��������{��p[k��h�{�gk�I#��i��������cNQ���R�8�y��F��`������x���y\(J�?�Z�G�/�Q'v��1����F��S��G3�hrk�`M��\��4v[NMs#��=��g��gcAMn�G������l�����$x���,����[�#i���b�S��K��e9m����-�5M���-.��H[NM��w���%�[�k�N�#[r\.�����(�.rJ����K��������-.�����cM/��i�SWQ�F���4��/g�SgN�����?u)Ei�1M��R�r)-bwr�.y����O]���4�k�kMW�\*c���`�����Ku�����(J#�I>ku�y��z�	�uWt�������OCW
�r����n�������������������w@�������IQ�]����+5��w���L�b��{?-�MF^�0)��������yPr����������H1?$EP�.�����~m�o1�xAw�^���a�Bb�����8�
�+�����cR���v�(���G����0�����x�|��4�����s���A��UvW��;8�H���n���GT�#����7FF�CB�
�IGV��D+�Y�9�8�F�+�'aP��=����xKZ�9�9��z6yzJ�[��H��^q��;��8q�GT�UQbo���&txR�'aXb
�����C���M�o?v��I]��@>��
pi�xR=?��v'}%?v�
@��mq}d�H��E��;��Xg5!�	,k�rW��/D�����}�[)��4�^��i�������o�A�9m��Sm,
�;�$OYf^�.�wM�����(��wK�kU�LU�`=}N�.�+�5Xy��G�fX#/��F+v�y����7��}��g3��+������VzUF�M�&c��	%��I��$m���\s�H�M��e��������3�4���(��kH�6����+0<�]��u��B����w�TZ�5|p�Fs��3�����-c�I�{p���-���������p5�y�x�
�E@W}�>S������������D�Cx�GD�3i���'����=6i��KiS��������@��1r�7�����i�?����G����c�C��~l4
mo������F��%�&����kxp��~l�3S��t+��
�d�1T*��0K�
W^�����x�.���!<cz~az�(�C���.������t���AWAx7
|�����x�����u����o��N?����O�����<��K�]k
�R�7�����������FY���>����G���t���������U\d�#������Y�����MWuy�i��7�������|������~������?}��r7��}�w�}�w�����������w���.����w������O����(pqz�B������ZH��`���s�M
��x�Mo��[_����yq���������=$��1$�W �&�����2�,w~��C�5_���/x{��~A�H�Y���h�y����lD��U&�����j��V�%F�����&?t������aI��6:c�N�]kLO�W��n���-�+&���$�X+r�7^]WP�qt?���s?o�X�{����d/����Q�Hn�=��W	�����?GXY�C:J����:D�����1N�
WQ�EL�j������x�4�6�������'�!3w�s�Z��T�xD���2�F��'�����[d4R,��TWV�/���W�c��w��4�^�r�\a���o3��
��y�i\���j#�u-iq��j�b�]M��9�+���t��qd��=W����:�1��] m�<dk��y��@������A��D���Lo���f����x�D�Y���=��s�Yo{�MGv��k�m��%�c�,m����J����MDg��,-d$lk+�de���A���B`�VF���>tr��2���.� �o��x����/��X��x���j���6�8xt����L���
�iRY��X��D:�������z�g�4��mr�CXM�
������i5��ri��[���+x�\��K�j��)Jc�C}��
/��Z�}��
/��
A��4���X���:�����������r�>����V��������'���_��A��V�n�~��+�)I?�u-%�^J�A�����a��kq���8��$�G�2S���K� S�A��]��X��S����,�i������X�����:\��s:��~Ng���������C����������������B������j*V�CF�zw�E��#����}r�PP�(��	0�|�O.'m�<�A���a5P���Ba�Q�W�����
]��j��Bk��B+�����0.� C�V�f��#"\��BW��'hO��j�B�����.z�i�V\[�����C�4�:�59��l�)^���>�1�1fSyM7��	���:����`e��I/���<pk��G�c�w�i-{+xxO��&����Qg�={E����^��u�g�~�G�G�\@?���k'��h���T���[����
7��q@��������T������@�Q�3h�eYi6�]H~zP�
|*m�I���'9�{G>���fL�
��@t|��}����nUW���eL�|/Mq7�:�:>�&���?"��.$���\��\;��Q���i4};^��5,pA��y\A{N;^����@�����W��|C�����v!=��_���v!d^����j�	��DpX�"h��	��Dpp��V��v!���p���]��n��2�+����YA�-Jk�k v4��@g�fskFnf9��3+p�Y�Qd���W���	�:i��#:}��d�g���dg\oQ�g^���l�h~��]X�q���':��'��k�3f�Y�q���uD������_W���`��clG�;X9*D�k����%���Y�
�U��V��A���h0v!WH��t�Q��
�6~'
��	�����ck`M���������g��!S���^-�A���WX�������v�A�A������`����X�#/�Q!rM���G�g���Ix/�Q�s�u�5=�r����4G~xM��:i���r�F~{l��i��'%!wM���X����g^.��q�]!�6���e��[n���f�*sO6������f���������)F)�����s
en��l��d�@Xv%!����IQ��OV���j�	����#�)������j�s��pA��G��O�L���Ia�#CA<6���V��Mx�jN����
�6���Z���o�]���,x5M��7?K�&<d��&���V�fJ�H y�|��
xSA�}R��m�0a�m����S��w�JY�o�i�g�,&l��?S�u���#����H��^�o��c�5����v�7�I��%#e�+�\���8���"e��A%s�w_0��&��&s���#sc�N�yET�+�%s*_���)pR�>��IR6��w����
,����:@W������,)����k;�i��e��"F�������W������Mp3�u��e����8kaj;��[�{|�G(R6��Ij^������
G�H��J���=#e��1�������!e7�����������{���t�9��������
�=�9
z�hg1w���n@�G�jw]�1�D�a�W�����#;���>�<����'����Oz�����%*��H�J�d1w������X�<qd��h�=����#��e4�#��
�HAt|�M�Gy�������(X�����}�����������}�Gv|(�����n!:��l��4����D�$b�Y����F�D�y:�M��9�����[�������%C�$�5M��n,�0�W�t�����g����+��^�t������X�����`4=Sz'Z��L�xM���>���J��j:~+��rY�5�+��	x�>bQ��h��r1����`�H���?�{NM�9E�G���^4��K^.���[���Ky"�$�.�A�����t���4#er��x�T'�B���xM����GC/Vm�����5���R�h�b�b�v���GC/��
d���l���ni6����
>�n!�����k�V���#D#+bP����+����2��]z^&�2��y�|������
�����g�]��B�f]1+<
����Cp3�k,pAz{���/���4�������Y ��t�(��#e���S5b�&����]�nh��^���FTW���(�F�t��i�#e�do�!R������p
+=DJW�q���y��Y���Q�"�:����������"���?�:lG�����JgT����}e��������(7��(eq�����Q������?|����W8VZ_O������j������vQ�+:���Yvm��)��zr�E�/�C��@�c�,>:0<��Z��}C���������z=�S�7X�N*����+��D�Z��V;0o�g��gDGc�����';�o��h#�CUb��H�?��f<2�0��NO�j�8�T�h�i�
�`��7��v2Y�}�,3V�ovmD^=~�q�F*�\x��:o��c�����/�-b�7L#�ugD����P�-�����m?�n��3��1��o��!I�������X@t��o�)IvH���Gc�=��]Y�^/O/���fKc��5�'Lc��D��*��Y&��|�(����y����if���;��V#��Y����q�	�8�aZ���:?k!��_��C��S*J���Ei8j6�5�0��Z��i�i:~��M��:��I�-�07�������(�=����+����l���N|^�]F������L�h��.G�/�N���]�vD����������(�M��.�8��y��F�c~`M��\z%MsM��������-��^.������������������W����=�r�h�_�{��Nt�[������^���s��Y����A�22<��@)�������hq�u���
t[w��nr�	�9��-@k�X�6�����LpA���>�+�S���w��
��I[��$<X��}���^�C�����_���X�T-��m���h�y������P�m�c�h������"����H}���g��������q��g��>.�d{�]���`��4���?�e0H����!r/Cs���7J�A��Q,��Fa������|��g���xp/��Tb�/�KX�@���
�B��o��h'2��d!j.����mt:?(��&�7������x���dr�l�!���y`�����Px���c[���LC�������I��d�,pA���k��!y63^��X�T|z3^fJ��0}l��B&���2G�m����8� 1\��Z![|�Cdb?�dbgNS�M&&8p��v�T�8H&������jD7���=�2!���\���~�a�-Z�y;�#�p�c�g������4�
�K1�p�{to3A��-�"	k�@.%��q(p�Y$�8���xZ�p)�n!:=~J/�6�����(��Qn�g��Oj������6+���v�e����N/���jg�uD��{�����0�=�,|�9Gt�Gi�/C :����8��N��7VS@����t��"�Ey��|��</��(�E�������Q��QM�~���(���,��*�B�10���qd7�A�J�Qd�N���^v�U�FO�W���':�����Y��\Mv�6���
�(��Q��wE�7Jc�Q�pq���k�F1��Z[a������x����
?���zZ�T��_�Ht=�{�pq���f�����,��	\Mv�����y��������3�(e�����N�(m�\@O���e����GNt����G�����i���.X\�)���v�������P-�&���`��7����x���6��vkWL7�m<�o��6K6���d},��"`���������W���Qlv���{��&��I�}OI��4�~�Y��8���3����q���l�{����@t����?���+���N��X����;��_6Ext0��`�dc��j��[�fO��4]e����\��;�	O��@j4������=������c��^G�9���@"7��s�$�95�5_^�t��F����2V|�����12���g�'��BQ�o����&����(-��>�=����L��S�QKe�$+�7+T���(�q4����
��l�.���9��5�8��9�D�>P4�sOW�\nf��M�2�^�t��������R���L^���:�DQb�$
�i��E�5/����ad�h���R�h�(��z,�5M[���h����<X>�����Ks�&���M�k�N�#�HP��#i��K{�������1Q�g�mXMw�\:c��U������Kw�����;������o7��{^.�Q�5�E��z^.��&���S��DQ���a5=�rt���jG����sjz�(J=���WV�#/��j���{����e,Ok��LQ�a�������x����cCG`MO�\&wZ����#����V�3/����^���kz��2���ir:����92�b�fc��.����4�����*Nc��iL�
�8���b�c�RW8�l����6]g����4�:GVg���}��%��sG��W��"%�5M����9�u����0k��)�����.�����'E����*|M���;-7���a�i:u��v�\���&q?��y����6]���&�2��K^.�1��j3�����K�=�0��������$_F�t��������8��x�T�im�SD����9����b��g"��8GD��T�E��1�I������K�����:ql�sE�95����6������[^.��b�����v<����~�-7�����x��v��m�����+-��n�V�=���g���\1�Z?i�V��J����f5=VL���B��![�arv��M���{�J$�l��uoE�m��x{�%t#@�����
�h�z��i��\v�;���tx����*�	W�W�h�X	�+�ff���]�]���c8�<YkrF�]��ShT�LpAv��'���f��e��Q[�?Q�}r"���c���������|�tY����������^�]�����|T�]�����T��BzrY(��|#x�(�����W��
���2J� s���J��'M�j�;@�NZ�>Q�o���	��g/0�����>�������J��������+P�>Qa
+�*���w�57��*P~�E���sX�*���~��7QxW��VxuA��(��
�FF�>QZ,<d)�/��
���b6�F�2�Q�1���%_��t(�t7e�����_�������������?���?���OT�����?�g��E����?���~�� ?�J��Wno�B�W<3Q~��Y|������o�������~c����d{�"}���Si��N�u;�p�
\A��������Oqx}���
��=��|%?v���W|���������w�.���������]���n������e�w������O���=v1?�)�Z���/$G_0G����@�W��t,�����/�K��|���r���1�#���|K���c�?��A[G�`�}���I�ZI�p=!�!�K��qp�2x��Y������YG��{Y-����{<O�d�$�%Cb�xV�h'�������5��Qx�����1{�Y��e�~��IF��?W�\���<l�V�bu�'6�!��,�]�e��3v;�P�kM�e��GOC�� �jXk$��"�l��������Hr�
wz��Uu���"�|Ot����y��er=��si�X��F�]g�v	����EYX����N��	�S^'�C2{0��
s�W���-����u�$�����&x���I���g{��K����@�'1<I�':v�	\������_8/^fo���; �WV}j�k7����O0+��aAx��5~��k���.W�P����_a_K�+^�:�?����3���!�x!~�K-5�������t�zM�|��*�l��X�����l<���a�����Od-=��^�qup��'�vmto��>ZIX�h�%�&Sj�����_�j)a��W�|"N-Y�E������4��������|H����������1��z}��������[��V��v���On������7�����3:��c��y6�,���y�AM���A>i�^�K�J�b���5-7��J��i�p�R�����gm�
+��^���O�[��������x<Y{<�Sx�I�����D ��b���5=� �@�7�C�x��Y+�4�� �W����K���%-3Vjo�����]w
��OW{��������[Ajo���=��S{#�����P���c���(�D��/�4�-D�L@�b��<����h�.��k��o�7��X�5�&d��
�k���U$���g$���K��3,�������	����o�Kf2X�A��$<z���Q�;�H��3�3�JfU��o�W��5*V��1�y������,}z�1�0�k�>�!�%':c�p��vAN�j��\r��V�{���,�g
�3��������M$K
\Mx�C*���^eZ�%o�g�gAHVD7�y��k��R�ky��zy������"xxV"Y"K�{NM9Eit��C��h�@F�>�������=�����l
��iWR�����)V�@#���4��^�t������������8�f~��t6M3�?����;��	��J�[�@M3�?�$����
�����&�<��y�T���[�h���R���N�`XxM��i�����6��YAVM7�\jmF��5��d!�5MG������1X�� �G���������P�iz(Q`M��\Z�j���i^.�pZ��*���>s��r����9"1L���n�>�������i�yn�A��+����c[3��������[���1f��Y��B��u�����a���h�o����+���|%?v�������
p��
���O��{ ��A��6a����	9b�����Wt��C�[���`��wpb��L#������a����h���������wX��T�6�����X�z����u�8�^�����=�(����"x(,G��L�YU���oaY~�fe����[8�h����>� V�@3[��Ey���	,�<���Y���+tw�&���Fh�������~a��)<u�i^|��,���/o��m�U����Wp��|�G�e�4�[r�O�]�K�1���bwJ�0���M8�_����PZ��d=��
0?��<s���a6z����6��_P!<�OZ��>��5"w�f�+3�6jw��J�V�1[�&b���VW�1�+�_b](I=�,�����q��Afm<GO6���w�}�3;+�!�4�B���[���6:������x��'bk�^k,_Jn����XiF�a��	��e���:!0i1@�4�N2�����=��8/h9�0]�7�G�.��".��.��;��(����6b�6a�����o�|�a��2.��k���<wu>����x�x����0�U�7]�V�2L/�uDgdg���l�7���m����uz�����W^��q���h-No�3��d�i���]	tVkq��7���Fv��6��������p*�Oz��x5�Eo'�
������n�*fcF�]x�YE�<���{x9��W��9mQN�%��G�[5��>/���DW���lGO�$�[&��n!:�N����y�{��Gx9���*a��'�����}f�.�"<������g�E�a���&�p���F�3���/�������8���R�
�<��	�z�$�0rG��zCx���^���*�.����J���*��Hx�>X��)�*#:k�ur�U�*�A�jGy���T�]{��G�Rl�6�`*����S�2�J���W��b�r��p�����T��Bt�w^���Ti�E~�k�4�,��Y���	����5���������y�#<#��&�a�-�*��Uy���UZ#���0<SR]Ft�Sq�}^W�>��*A,��^KtF��%�:T	�&��5���u�E�����H����}�Q|^�Gro=����=���H�
D��Gro<�]�c`�=�d�G�l	#�N/<Ri�&�����wn1i,Z$��J0Eo�e;��x�YL���<Rirk)g�:��N�+��\����N��?�A���Y��D���u��y�
s�^��]�l<�-:\��o�7Az�Y	�U�0*7&���(�^��Y�9���kzaX�|�cN�����i��Z�h�@k��D�(�.���{NM�9Eii:��V��+B�j��� ���#<���95]d�^�.L�E�����{:��<#�I5=S�F����h�9����X��8���rq��6��
xM��sLk��������h���Rjmf��t�,���4mMMW�\J#f�(��x�T�im�B��0z�
��I��\*k�X����W�r����M�5�y^�t�%F����6�yn������K=���0����9����������5��ri���'�t�*���4�:GV��\Z��k>#��N4mN��������6}m�D�!�<TEWR�z,SX}$q�M���}��/���|���/��a��t_P��nI��%��{�0���g����C����!�(���V�NM�ak&�������7�2
��^(Jc��9H<��I��tx�����e�[2��9E�k�N�(�x�XSQ�gDMs*��=��'4j������E�3/����*��������e�[2��gPx��i��,��y���4�r�������rIXM/ xM��eQ"x5M���a5�2^.K���A5�2��	xM��e.��"x5M����5���^���a5��en�����h:��"x{���B��$���tQQ��nI�2��\.�W����W�r����s��V�fM;^.�1a��bDY��rq�im�,(J=�)��8�.y��F���������KY���9ZD�k�N�#s/k���.����l�{RM/�����������Ke-�HM1r�4"x���M'��;R��(�nx��z�������nx�4�im�A+��W4m20�h����XfR��]����Nk�-Z��6����#i��Kk��+S�]���]��t[���jK{����� ���~�������^���]�\�����?���?���O��?|�_����r.�����������k��W����nW��+AG8V�DDw��_~����Wv��G��ol��9��g&���A���y���?g���!/?���X�sV��#0
�Y�s�-�9���U�K�g�g���G��uWt�������OCW
�rk�����_������������?��E���\��O7g��&�"����o?v@����z���<V;�k��dHD�0z_���z��u�5N!X6���-:����;"��s������
�x�������J~��*VG��z� �`��+WFQ��4	�S^�����F"p���`��=����8�je)��t����\�IV�4I�[)��A���[����V]NA=����/OO+��G+���~���K�E�����
&<�v�����k����	���t����}"�o��O�j�����Z��U����*m x�Y���<���sJ�h�7	TQ�7��^�j���KIT��x5���<������3iKor��Q�+�KoB�N�j��g���W�W��ACr^��OM'�v�$&�����?��-�:����U�>������=����Pg���-�,	�B��z1o,������������_~�����l^�=gg���������K�\dE�?����.��/��e�?���7���}������o����?�������~������w�*w�������7�Y�������������Y�~����������������Hb��C�dE!����������G�tc_�������wn�
��>}�d�N�
 ���@���)h���(,7v��C�5_�|A�/�B>i�4�}��yQ6"f�(S�c������y��Z3�C�-^":�)�����j��w�L�$A{���r������yD��`�������v\#?(x�v����e�MK�F^0�7x�\-�a�+C���O����[z�V'}�7dne�
�� }�2d'��b"�u�G&��y:/C^�{�Xr����VJ%���������9�.����q�~��c���#�&��_�����
g��D��s����N����G��7����5��_�oc����>D���/�O������[�(=a��W���W�-kO�P�,s�������ZBx(�4VN������R��#�	O��J�v��q�HtF�&�����.`g��,�%:��������pc���.��<O�-Dg����	����5V�Xl�(�[�Tcc����w��p���|^���X��6���t+x�G��V
�Ht��ay�(��x�63���`��<���Y�5z����x�^Mx� ��n"�My��Q�z��<��O2L�Y ��%L�M$<���9�r�R��t]Ua�P������L$<������f=Q�+���X�%^���Vx���c[�������)J}3��M-��+^,��*�����R�\V�,���^m0WwDQt���(���L�(��y��!�B�U4�^i4�`��Ut���*��#e�(�����\V�
�3��q���1:2<F�<��xl��Tt���f�
����Kk�H<��+�����\
V�j�^Qt�ID���3z�=��+������	V�=J)�,	��K�WR<��?;���x�������~TA�����U��q��G�b��b��;��* :�}��]�B
!Z���j��7����Y���8&����H���Z�������R������*�G<Y���0���%���-Q8�H��'aX�!Z3���q-u�&��6�	5P��%���"/�����l!:\'�jo�8B/C4�K�����5�af�r���pAf�j��M��d�������z�=j�O�d�x��,&��l��F����+�&��f�^�i&���i�"cXM�(��F�����W��G�.,��Qz��s�x��#��7����2��v&x���K�}2�)���)=u�C����z{�C������������
���s�C[����~,`h�?|n@szTW�\l�/g��ol��d�����|sW�����8���I�OZ7�D ��������8��	�6+Lo���6�s��+7����D�������UJ��<q��P&k������L�j�����B;���'k@j;����������b�eP3^rb;Q�?��P������1J�0��a����MYF��D���7�#T�?A�R�J��H�l��2���9�V1c�Mi���\��g�zs�	�������=��D��B�oc����T�� ��1�V�d�6'���P�Z���<�G�����y�'=���
/�,�[��x�T����dZ��	/�,��p2��ye�N��DxVS��y�l����*Mz�1�'x5���+<�n�QYH��Z�g�~��,�(f�Dg��?y���W^�YD������^ �>#<�>+�I�a:����Y����J��!�	�DG�/fsm�& ��b�O�B�|�FoH��l�c|n��0W�FQ4WcL��zC�����'���E�#/�ci
b���)��N�B��
���=xa=�b��)[��io��?�E�%E��d���D��e������.��g�,75��)za�2��`+���hVI�����4�7�r�}��Xgn�V5�E���&:(z���zPW���$<(Z��S�,�xE��;��/�����ONj�3�;����^(J=RMG�EII�	v�_<L�.��!pW���]�n��S<o�76����*#���A_z[��+���*��B����m!8�p��rU\����q�
�sz�=���<^�O��	�#����-����|�tY�hz���k����tGA��:�J]�����
�������P�������%<�	����h�[(=�5���R�fG��A��9��f:��h
2����G'=[Ka4 ����I��
�"�J]�ch�n����Gx|.Fv����Jx3�g1�0���[2G���"~C)�� x5���5����W��G�!,�<���n�*��e��{��I/~C)�a��b��O�$��L�u��\��h)
J�X�Qy43��������:�X���Z�!X����x.��>R/���it�43�����{�U��y�������������hnf��\Z{������m����+�d�l[���vJ�r��m�_��|��������eO=h��o�������'�������� (����0��+tt]��d�0m�+p=�}�����+�(V-��m���y����ZJc,��6C�i[^�C�J����~�w������v�1�����������W�fb;�6-b�i(���Ho��"pr�Y���������D���wj[&���J�W_,j]���8���~�XE� m��a��V�����������+���������^��|���r�����rBa����/Q^�j�@�w[��U@W����\�j���m��\��Dg�j#�Gx���d�<X����\t�(#�V�a���gt�[�[�{
�pO#<�8�����c~��#:����lKzc�aaMD�"�� :�����U�*��e�����@t�S%��jz�w����+���mM�b$'�)Gx��N��k�Uj��l��t����@�|8�se].�<���g��0�����i�I?>���H�+x%���gm�
+C�V�`r��(z�$��D����������B��(�t�(��x�t�h���(�g��;�h�V�]{=c2��(����[#��DE�Y���FXae�m�_�&�-��^,��s��;Y���2�g4��Y�f���(z��b�Y/,��Q���e<�hb���+�mQZ�UEO�X�I�������x�L���'�9�(��J��Q���e6:����NV�x�����_a](J=����F ���l��<�z=9c�7�R�����=���/��<���5<�� �E���r�{JE��}���I2c9F�\�*30�
��{z��lk�gs�b�����/�~u�g���>c7hH�
�X�CU%���1����t�^:���+3A�v"6�ps/!v!�;���@��z���J��6p`A��`���\��>��%?v���V�pW<��;�����8��fw�
]t�p3�0�u����O +�K#Cd��
\p��N0������_����R�i�p�������k�b�U��\��3���������._����(u�E�����8��Dm',�6�����O8Y�	N�j���<z x|.��E�p��7Sz�S�\�GzX�q��I/���<������g�����W�����M������m���wW��{��������f����[��������������������o����9��c���,R����58�,�#^]�����A��-��`r0�Ue��d��g:��������Hq�U}��W�\n��_�+�o^i��p=�t
e��z�{��k'<f���1�:;v}�b�4h���[�r�A]������@���4c���������]����U��g���}�����]'���8T_;@���-��&�0}����M�����-��h9�Ut����Q�s��k�A�3:P�:~k6�u �
^�e'z_;��IwV�Xz��KwV�X��v�����7�S0�������������`��M�O��	�`w[���������^x�#<��WX���o@5I���lz�A�&�`�(�3�3���O�H�2�$k.s�uDg�{���UF��d�(����4f;��X�V3���H��uz�1���v���r��k':dv�|�M�+���g������Lt�0F�@��
���������������,����D����-���N��2����;+]{D����DE\M��^�Sx�Ut����W����������0�"��N��N�R������D�Di����JEx3�w��v`u%E��,��;��/g$W���7�;Q_;��E�W���>��K^,����o��D}��Z���6�����Ke��[3��(���R����X�R�T����@���x�X��v���R����X������;]���6����wt���9Q_;���"�O�+[^,�������S_����D�����XnZ�����*�j�������z�v�q���9P�).<b����/L��=�*C�]�>.H�)��*hO�H���� ��.��������^s���N�����;JoQ����f/�5U{�����|eE�>���C_9���/I&�2���a�G����a���U�Wzd���,����L x�����|8G�^E/XZ]$�-�3*�&=�<G`xxgU��@�5�1,�:���T\��1/x��~�D�W�^�q�7Sz����>,��QzK�$�H��<����0���&y���'yT�$/VE`x��Iy�<0�$�����EUo����_e�X��<*c��W�?0<d"+k�G�<��$��3��<��^�Qz���*y����)x����y��x���C�����aQ�_fX�cZ�,��~�O��[l��h���yLK�1-Un��scZ��� �^N��$���w�cZ."��~s7}��7U���O=����/�\}���x�.�xb�#1���F����]tKAt�;��3���fF
���A�����1�7�����w�GWgT�b�J>O�'��-xWv\d�����};�sdj�4��w�i!8���=��ENA�����TA�b�&+>�����B�������iHGS)�q��(�CsZ<�ZeN���0sZ�����6�f��i��d�M�M��N�Cu�.�5����X�	���`��{�����6e��	���uy�W�An| m]%?L�m���|��(��d�/ ��V�A;����0}����Sk�H,�A�a����#:�=�Gx3�Y������R����\x�@��	/�0���j�Om����W^�a8D��p�e��'��:��;���Gx�U�������Y�Cx9�x��Uu��s!�������wq�����N��
z�\o�),�]�`~
���mA�RS,�]���@�r������������|Q��D��>s+`�$<<��&���6��}�W^���F��j��wq�7���H/<�g������wQ�G���=�mK�qg��xw��UF��Ht������y�UF����E���4�-��u���hwq�������^�Q����\m�.��>����><k�����,�]��-�����\x-�*��]�����$::��z�X��(��Lz��	/X��)<���������X��������u�ug^O��=�U�F�3������o��^�7Z.�p5����S�7�*]�c�S�7�*U�����`<UZb,�1�7XO��5����`��Z]����F>�J]�{�3X~��y#�*�1��J]���L�{�M�*���w�ZZ��Dg�N�H��U&c}N�:� �F�>��Ix�*���SGd����+F;�JS��#2i���Q��)��G�bPi�:q���-�3�p�SS����U�Wm	��K\����������������8����!p���������� ��F�3&Y%��l��4ID���FGnM�$�����J��������H���^��p_�{�b��/�,������/��.������)V��W���F+�5�=��:�3�Jz�-�UJ���oExUAtK�K��+z��`IY#��o :��X��q�W��TF+���<��j	�v���^�6Z	�`�gxVODg8��BEx
Bo��	/1K�oPz����$<z��(=��(�c�����T��s��&��,����7���Bx|��:��0p1���x�4FZmoL�+LW����������s�3h�m�����t*�1��H��{fUzc�����"<:�����#���n���I��!��Ne0p/����U�Q������k�|�*�
W�w����p��o�������������Y�}�G���������O����?���~��E��+��W<�x�n�������o����i���@������[���Mk1B���D�{����)g�UN4�Y����|��9�������c�6��XN�r�9�=��XN�r����"����rb�:�XN�r�Y*���XN��p�6�H�Ia���&
:���38
���J�� i�4����-��	/��wpx�����,�^W%?lteAt����u��DP#x5��|�7��)I��*��42%f
1��VH�������&�����`V�.�����5��]���lk���&������&�`�����j�z��������6Y�o�f�LDg�6��Z�M�6<g��1N^��EkTM������ck�7i�1��eDg����CG�v:��Y����m��Tg�����d�����RG=�&��%�H�0�=��eg6^���L���t���iR���V���
�7u�w�^��9M�s������]���S�.��*_��`Q�����q
\%������	���`Q���f�������������q�����8"�#p5�y�����������j7N9���oB�����8*�����P����#�"�<q�g�Q��/8y3/�Y/8��Ex�0f��H.<v���R>g��b���x���<��/Xx�0��wg��"��)����O�'��&v�^Mx�QY�=r;���������r����n��|Y!���C�@�>PA��#���st���*z�(�>��&��GIZe�FQt��C��S��� �E�HE���4���[9�������v�xE�F�G�lD�TQ�(���r��~6E��/�mQZ�T����4�V�2���BA��S�����O�������KeT��<HE��Y���]#6���
tq]�b����V�U�ET�
o�z<�E�A\�+�6��8�nx�X��V~)�E7�Y�������X�q�nq��7&��[�,7��gSt�(J=����(�����6��G����Tt�S�zc��Q4��8Gq�F��f���M��d�����(����`\E�����f��=S�zc�f�Q���e0��S�#o�����G�������1�1���q���7�
�l��������Z^�(z��2��%�qMj��=���������I��X,���P1���,7�	��h�����g�^,�\�"u�j���e:�E�-�E����-p5E��^�yN��W�9�:^Qt�����!p5E��^�EF�
gu�3G|xE��3cs��lM�p��W37�s*����Z��q�yWSt����x����8������#U�M?��K^,����5�(�����Rn�@���_}���=I����r�SW��q�]�v������w=J�5W�^�*�YV�BQ���5!��k�.�p���G�5���xQ�Ut������G�
�����i-������KS���L����S'���WKcl%�����5��ni���t���i:u�lny���>��re`Mw�\���6���D�k�N�"�x�tzCI^�3k���������%^�t�Y���7�����y��������%^�t�$���e0&����y��2�����(�0�EG�#/��r�R����������'GQa�57%��'^.�1T����/��=�M�Ei�1���8��y����\��:=�r������Q�FcM�9���,��������e�h+��G�f��s����������>��_�Q��}y��!���0��}�1�m��b�}�b�����8�
7�b�����CQ��R�F�Z`�:��9�w�pe�q�xM����K�E�j^j��R/��i����(J#\�f9��t�pE�ji��T����#x����Q�F�b
������Kk��2��Q4�1������
��W�)Yq4����W��fu2��;^.�i����(J#\1�dE�4��
^M��K�K���9�+����������hz���s���dMs	��=���w16���+�hz��2�}�>t�"��G�-c�9^a=�)^�k�N�U\&�-�1��,CG1��w�r�WXMO�����S3���w�d,
� N�5��W�r�WXE�������QYQ=�j��I^&� �I/�Z�����j�S�������w�5e��"�������}�z��+xM��d4��������U��&�d3}�{NM�5Di���JQ4��e��<�!c�5i����=�����������E�EQ�n
.VXEc���9�%i��I��������m&U,��v�Z\��ma5]������(�.y�����2q�
��2������2�RVssGMW�[*cl[�����wKrl[`M�����,�(��y�T����#�
����Krn[XM�Di
�6�qD�t���6�_{P��>��-M��ma���1x:7�Q��ni�N����7Krl[X=�=i�����r=�fi�F�����^iCNm���� �����g�����J���;�a^a��Z�B�
����$�����}�����J�����A�*z�����V�CIZ����SE�Xc���s%e2�bBN�
�i�����4�<96�j1�~�dL�����e9�+�����4�N���Q=�j����*�IO�Z��K]�jz�)Jc���E�3�������A��e>�(����4&O�O�(�^x��zWIQ&�q���e9�,���4FO���6�������w�e��x�\�)5�g�-&W����'OM�9E�w�e��x�\�95�en��2�Dq4�P�zWIQ&���EI��u��kQ�,/�HE�.��i:���&w�w�����tFc>y�h��rq�,/��4�5]�rqgm��`�!��c�'OM��\J���J�H{A���<ks|�WEi4��O�(��x�TF[I�������Ku���&�Ei4��O�(��y��F_I�������K}���&o
��h�7�<Q4��ri�v�:q#�
/�����M�f��o>y�h���������(�ny��gm��@[(J�9���E�/���7�w������e���L}�u_�+��^u�vo�fQi$UU���(�������Y���O���rF|�������l�j���G���<.�Y��/h�>x�r{�������!�!��+������:������F�p����7��#��8����e8ku�
�����>��������4�#=�p�ZaE���k#}��l��2��}i�Gz��2��<������F�p���e�BD_���y�L����g��6����f.�^q"��x�4���e��R���3��H2����9�O/<\���M��#�u�fJ^��FZx�5}t&B�0��{����R���%r�"W�~��PtW�_�������G�+��|F�K��
���v����w�{�_}���_��������d���(d�[���O B�*ULsL�����2��p]~#?l�>#�qn��n��;^�j��$�{K'�z��6Y1r��Y�9�L�V�f'�bA��]M����{"�����Kc��R�]��<�^%������,pg���O4 k��Y3��I�d��H����'t�����W7���/qV�
�
	�fE�F���o.�o��:l����4�s1`�k?��	�c�Y:�]�3����*���4�X����}U"�\hOy��J�d���I��W�4��Ln
�_�pY�H��}�/?��a��#]�H�W�~G��w�������tD2�3���H�	I��5%��g ��IE��b�PG%�;����C���>���x��ks�����������[_x5��'<���w�/��z�g����E��1!���b����cBR�Y���}1�:�����ju������[�����,n�����������zC��/������F����Cu}�d��+~���~�������������2����
���g�W����������_����/y��������m�t!|~����������������_���?�����?���/����>���>����������w���~������������������w���o��/������.��4Z�����zVw���B���������z%��I��+Q�|%���k��O�����+Q[4�u%���/�C��o�������6��u.����3���A��@o��l2y|�|��>^�U��;���;��������
�6�!u-��������+��?������1�s�w��c����q��b����������Yp��u]���D5�`E�+�Y�1Z�^q�F�Wk����@:$u����r�����������#��3v�:$X�,���pF�����H������6ud��rU��Vwu���xB�;y=*e�M�&s9K���l�L�f�#���3��VA�>�U���k2��W��h�u	G�.n�4��\�vF($��(��q���f��y��tkr�hl~�l��N?�
����v]-���	�L:�x���J��j�3���. ���p��;��	�f;����f�M��M�"���=�vl�'�����I��b ����'Ic�������������)���'j�CV���8���q�)
�����\���w"�I��$��IS.�HW��V��d����H���V'��$+=��$#�D��J��������;���2iJCw��K2�
�F���I��nx�4'��k[��FM�)
�d�[.������#��piO�;	�������4�	��t�����-!Bw�y���s�t���FI����d��^-��^�x<\��N�u�)�R��_Y�^�OD���(��d�c�x�g�x�����"����A����e�8Yn��;m�:��v����F~<���u�����TKzO�����Zt>���C����B�RM
�	��{���e���k]��������������o�&��Fj��l���h=��k��#]!�$�;�4���P�.��_^�V��.h=��j�3��	��.�d�� �$�;\��k2Z����";Nei���^x�`w_s���ei!���.�T,���
������]ey������*�u�Q��p_�@s?��hd�N������P�����|��g�L��0'�^$9jrq�/�en��1���rK.�P��H�5��;%�OW�UR&-8�"����'r��u4������7��t��
����"��'*��u�5�jO\)��=|S\p5��E��x{&p����5D��_��o

�&b�, �B�Q+�k���E�\�R���p��	��u�+��03t)��]J�M\$py��?��"&]K�I��M&|F�h���z��Qq����Yc���Yx.����eFp:����v����"XxIl����K=�v-w����Ff�O�1��������k�E�Hp5:����y����5���w.}������G� ]O:��g<<R��;J��1
��!����;J�j<�qG��j��V����#���*�Ib��;JoT�����y����{��n��b�),
���X���3v��m7�3�����kv�G\pOc;��G�^�W��n�I6Z5[G�n��x4N2sh]*�H��l�^�����&�/�~��u��`����������o{����f>Q���3��:"��w�^af�u@�:��H/P��s�����k#�>�x<Z=x�
�.#�g��^����#-��H�1�#�gi��"������$//i���t��	��F:}�(�p�^m�y���G:Z�D��dEl]���N_%J<\#zCD��0&i��s�t��M�j*v;���D������7��1�H�p)NT�
���)���&}�(�x��F��.I3����U~��*hJ���I_%J<.�Q�mw��4eE���I�}hJ����&����R[Y�������U~��"��L�9�G��B�o��o+p�f�)+�7'��&�BS���hYOY�U�1#��\3�{�����L{��n�r����b�4UE�W��+�����I���FT�������/����������=N�?���=���D�ZZ��u[c��x��=dh���VpW������
��0k��MN=�I�D)�]�>P���x"���`8
}t@��l0m:��4�{�
<��4�p���O��8�b�{����ps�}zWp��
Y-�\����C=��j#!7��7�!'�;������^�����Z�3�p
F�\�����f����K���h=K2}gk�!�Ex���A=�	�r��+�\�����zz���p��z����?�����0�$�+E�-_�_!�V������}��R� o��6+]�����+�G'��P�O]=��7���v�����,:S{����'q�3���6S��O����Hc����q;�Z��/���R4�ZI�
����Y1���E)��G�����?�^�m;�����F�O�~�/��1������oF�����9��gt�o���6}�W���3V��O�csy�_7�g(���+
���=�Gg�����-�b��A�_���g���B),�LD4i��
��]���j�u�d�>�:f��������Y���Y������m3�c42=�_�L��D3��EgE�<�q�>F�cq���dp��P1<:��&��e���*�
��<w��!���r�d�e�G��MF�����Cul�����r#��HS������T\��P#�Z���I�;��u0ere��L:�5]��)l7��A�2y��/1��o�����n ���Zq���W�]j5����%.x�������S�0|�il�����(����;�l(��b)�+:��}G9��e���j�FF4�E�`EG��r���NTh��
�^)�+<D��L�`�%�������#�����)��&o�����p�^m��'�8�t�����s�CNS	<m���2B�W������G�s�t����N�����+<.�����\-��f7�=�H�4����M^K���Ka<�#di\�aS���<m8l*!�*��@'/�%^����UY���I��+�-U~�%]�-"��H'/�%^�����"��)m��x������j�-u�xMo�GO�����I�O�y�:n97]�z�#m����w�*�����=��:����8S�d��� }���@:=�J�����NpOc;���?w��������j������m7�*m�������
�=��o��f�C�y�x�M��V>/�(���V2�Wt�#����*��D��*�Wp<��5����.�������Bv�
b����^e7��L��H�Y�3e���4QJW���jc���g�$�L���"��"K�bM���Jh��4�����������[>���C������
[d�7�����M+�k����_�U4�����K�;f*b��\mutT}�=��Fa�����R�Ulg�K��nO����-�#�v�������(9�F�����^�,�Y"�n�2�
�	�������f�)s'�g�`xEgC���:���n�{�M��Cl���6�����]����*�;�I;���
�il7�No^u���G�h^u���J$����v��.���C��v.��[H�q�_{
O����?�����)��c�s�7�P��1����3�B����F7��F�+:��g#��~
7�<�=3���J[7E��}�K���+:�g����������A�X�Li�Y�����Vn�/���44�_,U�4����1[�/��z�p���E����$�-�8��w�8	�l�NS��$E�?9I�K�-_re�V_�������$\��'�������V���'l�92��o?L�k���	p��bwZa����������VDh$��2[�u��Q�����d��i=C#1������_?���[����Rkyan�m���W��o�E��_���2�]�)�k`n_/L���a����'�WE�m?�`����K�F��_�
�nt`)�u��z{=�+�E��r.._��+��H@�X���S��#��!�i�6%�.3�����	^���
�U�m�\s��-z}E�O�b���c����
�m�&���0��!!�~U����?T!]��y���Fi�.������9�p����j��P��[��Q���
�p^?+b��/�Eu�n�wy5E����I�w9N�T�����A�#�9R���>F�4C:c�*���%�:#��N!'uK��\�G��o�d��I�_(��Q�#�m��]8#��T�^��x�M
Y������X�����:'��5�[��.����1�jEx������Rh��u���+��n����Z�J��tpG���$�m��M{�Y�BZqV+��g%]
�vW��wly��V�U�7�Y�����d���n!�g�R�Y#�yX�����O���d�b�~roq�����V{�D��1����������&�L:�$�I���� ���o�������gY��H:=��0S�]r#@7��2�������;�!�Y�i�.����Hw���+V�/�!_d��9^��4���K�I��x�a��������/���IF��V!��_dES�t�0��{��FZ���N/>�<�)
��u�I3�9^t�{����*xm����/d4��Te���P�zAQ�:�H��z�Vn��J5�3M�����MX-�z�]y�Rf	���P�I��?�B�-�6j��\
��[H��8Mz��5%F�6j���]qO��
����#t���w,����il���`���:�����];ad[��|��:��[];�I_�C:^�;=���v>���W��Dz�d��������4�����[����W��tH��G�d���4��s���|�)�
���NM2Bpz���:',./02���6������B���r�<3\*>�d�����������o��0!S���A��|7]Y>3��������/��7���e~S�i������7��7�Y��%���vo��qC7�Il��!+x��[xC_�zHuq=o���x�9���(P> ��"���)�(pa��l0E1�N��[����-Kp�b�	��{�yW�jApOc��tz���(����#���o�
Q]�=�����,�g���\q���,������v.���nIW�����P0�#0��N�/B��xX@R����/������<3����E���*�~.���`�Ah�G�������)Z%A�S���Y]K!�>�&PW\��upx��9
�&P��M"��"�0�]���E��tT����@�+�~hftE������������3��t����^������D�����p�E�i�_���Q�������^�c���j����Xo�O�0�4Bx��h���x�NN�g�^�D��4�KwW�q���z��D�����)���\���^�������nba�y�H���|}�������~�����������������}A�K�����2��}�J������*�r{@�H���
*7{B~������OOn�zy�9|��r���RY�p�m�pkd�M����nu����Yw��(��#��[�.o���]�����Y�H��BIm��?i���w��{]g�bC���ek����M�F��U-����x+����M�X��/��5l�W
�Ea���)���������s!'�������y���#�-/:+/���RX��E�Q�(�+�2	b'�<	��"��Q�b?���s���J��*qX=C��e-�G)�w������,ha^!F��mE�n�r�!��g���Z���\�"=�@d>�0�����GZ���3F��U:�0�8_r�W�W�Jd�Skx�`���'j��<V>V�8������	����o���-F�������g	jT}�8X�j��J�E5}Z~��oh"-z�&��O����E��D��'i�]��M�yU�o#/���a(��?z�Z���_�V�FQ�F]K�+A:�4�Y��4�
N�����8�4?������Y�>Y
�t-IG��b8�����{�i�G���Pg���C�Y�U��������*C�Dp5����������S��*G����dW9^U���~�I�t!��>�6VF�E.����`P�&����"'��"�$��(Z-IP]�^����I���'����zeJ���K_�F:�dWIt3��\dBI7�N���J����)HgH��n2���kx�5�=��Ld��tF�Y���v����+� ��Z<3+K3��gsI�%]G:��y�~�F�����0k�\tO@�xDu���l�����*0q��b)���`���N�`Bi��������Yy�����Yz���
��JKS5�H/�^��P��zBr������� �U����z�ss�N����������L3�#��Q�������Kz��26�]���^�J�4#=�l�G��$�G��x<[&���)!��u���'z-�����7��!�v-����K��H:�R	�Ylr��������������v�����Hd;���,�+��8�����p����v=�t���0���f���s���eA�������V7���4u������y�B����%=�U9��q����T�z,�NXB��TM�[�(oM&�y-�;Q����PmH1�'��Dy�"	5�����W�)�M��W_�U/���+���ZI%��W���A��Yx���b������@5��).#�����G8���n ����b�������?~���ck�[��T	X������{��;tF	��giFz���p?�����O��J�^�x�i��=��7���c>�8>��,�[P{&�/�!&2o���[��7��(�8|�5]�F����k2h�	�O�D���Sx�����0���I�_��O�CC���&�^u<��N!XB ��Yi��G'z�7LChm�~L5"��5�	�VP)���a���h[rug���%�L:E��St`[�gC�H��M�������6c���R%�ai4J��~�6%R��W3��&_T��j��
�c
zt��,	��"���VV���,�j�q�.�m�mR��T+H�G���7AQ�yI�t]�5\�Z����KmjX�!�Zi�����r��C�ncTl����zx�5F��P<���+�6��>�bO�`[���,�x�����U�v����C�����&Sa��"#fM������+�>��Ro��V���.���!���+���������T�O�g\���a��g���I<���7B��hB�����~�'-�Z��!r���_�/��o2�4�D�������S�w��e�HY��+������.DN�7��9�&��M�����q"ND|�y+X�
QF�{2�yA��j�����e��'��e.�/V��b@0N�_����jQa~Y�rb��xf�����o�L1���]	�l�L1j�����+�_Z#��
t�
�l��Fh�E��-2lo����^�>gf��v��6��rDD��^�``�V��� �QV�$
F:�
�p��8I��[Z�Y��Q��W�J��-��G>�`��_Xp�7�����������:���&Z�
WJ�����^���d�G��$���Q$��\�-F��<|�H�\E��H^p��]��|�P�;�����AF.����3�G�t��*�/���=��F���t�?r���(����?n�O6�,a���J����+<`^
�����,z�\��j���)�-�"}��h�IO�*�������0Y�K/G<��'��PZ�.>�z��y{����z�Y*��t
�V�T�>����{� �/�������p)���7��Y��{oeR��kA����AY���ee�7�����3��u��)G�c��[�nn�a����'J�
���3Y9IIF��G�{���q���`%��iv�^mM��$�L�y����P���0����j��������{5����Ex�jr}R]�V���j�9���?�!����-�he��x�A���	���N�����7��	R�+x����?��o~y������������������?���/{������~�������/?|���~Q���7��cg>�/���w��}���K��?�/���N��W�m*Y�I�!3T�W�}�$��!#��+��'yG�����v�,G�qId;8��Aw�m���}x�	��h��>���oF7��;�o����g��&>q��'�M-xs_^��#|gB���u���Cv����R��!;��t�U�j\`|D�H��g��X"�>u��	gx�r���K�t��\/:��h���R�	G�E�GV����yO|���Z�vG?�{z�z�;g�����L8C���y����k�/m��Ez�z���9�]}���?��"j�C�QxO��0�Th5���#rJ{#��x�
�3����w
.	�{�5F�f����}�`����v#��8���������p���<��!>�v*�lS)��m������p��\��o�������s�7�;����P�V[�������@� \��=G:h��F�F��G�7��5�[�s����=G:>gzO�9�+9��B���"�|����
�������9
G�kgi�$�R^�W�����.������*���{)���s��i�Y�]��@7���,�9�n��\�
��
y��58?V���9�r�
qrC�4Qt�����j��]k}�f����Q��zpi�F�q(��������i��d?���� :G&8�����i7���':��&Y��L������.bA}(:�|�k��]���T��������)�<�,��P�4����i?Q���o��<���7B3�n��'�����O�s1�rmi��5��l�_6�����8��/].�D�f�����O�.}�V6�X�8��$U_.
"o=��V���rI�Y�W��� ������/�q$�Ce�H}���r�x"{�	���rI����7�t�l������r��� rs�����/���������\F89z����������k��5=��fLs�D2�d�}�*h��c=2Ry����LF���1�!�8��U1�R��y����w+�g���SW	�$v�@iG�0�����<g�#�����$����MFz�����y���,�k�O|���Z�C���9��f-����S[���/�9w����7ne8o������n���|����SF~C^�>F��}C�Y���T>��7����i��D��a�����_����>u��U�?���h?�#����Q=����>�W�U�?�y����R������7=�����>����U�?�x�a�G�x��#��o��s�+.<����$����w4p���W^��M�?�����>�������s�]���,>��BAI�z�2z���T=�E���Go{�X�d4tr�|��z����k:�p�Q�f4yu�_�5�>��O���Y�Wx%g����>��5W�Q����W���WxTV��O�"�}�h!���
E��rH�+��".��k8xH��������u�s���M�2�%���C�@p_�f8U�� *��Xa�?��5�M��Xa�_y(���xt���UM�c�JT�����f��6ci��h��R���
����9��j�%�e�x�^et�]���D8]�07����9����.^v��v�]��Q�	���-TV�v�-����s+96����xz�EeT>&�]����j�K]�����R����s(�[��9��������Ox��F1\�yW���J_��B<�S[E�)lW�3�[��w�U�W��s�bg���3�eo;�w�b����k8�,&C��3l��q�+h���Q�p<�n��O�k�����jN�Pk<��&���~M}�m�+U���;L��v���xm�-S&��7������H��Cx�9�l�9�j=nG:����o$�ofh��j�����"�'����U���p����Kg���h��<�=��8���xm�S7pZ�
<\z�f9����H<\���kz��m�_���M3�t��6���%�H�<\n|�giJ@	�6��)��4C*T���}M�Vxl0��@�m�'z^WmnG:�������{^#�,��)H��
�9��&��o�D[������wPF��}�����@�2�KQ;�@/<ZC�c���@�dYN�O��s�h�����9�@�v�K��Ak:��
��z������o����-%���
��B��Zd[�$+#'Y�;{f��l5��c�-����
Ha��c��6��+��$��7�4:D�[I���8{�%�T���0k���M��4���65����&1��8!������|���y%53kfH�����$
���u���A�j!��@���r�.s ���m����}�Z���S^�������`��R�K�v��p�zo�������Y�H��{����<\I���H��=�]�d5�l���#}���_��j#�p��_'W^�z^_�<���u� ,#sDb�*/7RX��D��0��U/4�O�t'���3�M?����3��f�������	^���/�����������s�]�\�����'_���F(�*On������"BP�'aZ�w
�����}��~rT������)^|��A��*}�V�������!aO�6/^�����|������b�<��4��
w�Xs#���#FT��]�5�j�c���*�I�kL���]G���y��S�K:���Jv����$����kK��Dr��c���q�o��-�/��]����l8�
|����U�_�'X�WJgt�:|�\(�~������ka����g�y�U�����J����a�
|�u��c�C8U�����|nU�m�����
��{b�1�N��j��I�<k��G��L_�O�����W)2r+����B8#Vw���)z�Ul���p����u�I�Z{�7O�����r�Ybj��y�W/�W@�^,��
=��B�O�N6�Ul�V�9��@8#�z��-��^E*y>�x�z��'�����eV�+���p���a���#�^C`��|
�	7�D��`���^K�M_K<�/��Bh��r�����^u�Bh��9MiB������
�6J�����#]��^}�Bh�6MiB��c�����
�#�n|G�AhLxO:���6F!t��<x-�U���N/cA<.��
����qkB��c���pi�B��2��������|�tF!�%��f�{.�Q]=�&�-�%��D��d�_�7
�-A�D#���7�a9�������?Q4Y�
i�P�/�%���P������G�p�:h�"�#��yM�<ZF=�S=� ������e�8Yn�&������Y5In+������&wV[�#�
A��PU�;���T�G:x���j�v����S�goK�Z+5k��f�t8{wg����:�Q�>NE�C��X�:%O���?�k���3���S�G:l2��
�K��ps�S�	
H�_�����[�k2JQ�4�����
��?���,�')�+�^��������4cfE�W���W��fX�4��@�U��c_�M�#{��H����j���kq6��L�6�d����3Z�H*3��I�W��%�������[�G<L��qET��"�P���6��\����!T�]�P��~��P�YU�E�S��O!��5o���B��~��U�:O����-�B��m��
��)�~V��m.d��E��Z�S��},V�ER����V�Fz���an(:����[�����w���B{��Y��0��V�9���q�n�`�3:���~�bx�I7���j���
����x�c���R���B{�u<q�LF'������2��I�����tH�(VR���C����P��N��+����t|�/�1�&��#�H8���j:�:�{�2��X�N��R�Xt��k9�V�O�<��*������OM�f��9��`;���b��Fk.�KIg_i$���?(��F��;��Ob;��J#>�r ���������G#�,}��}�3l�������-x�y���3��f���W��[�h��x�5���'�n!�~�Y��Il��3$����Il���"��U9�~���[�#���>y�.`on
�^�q�S�!�����j��-�����}����^��9���
���m��x�C���t���HQ,�Wlo����=����j�d
�9Gz��u�sm��$#=�p�"��1��y����kz��x�����z���x��F�x����x<\���������-��f�y��2�o������u|��y�L�i��L��luSH_�I<.������]�[x���i�������A�d�����)��x�h����*CdG�����2-���@���#�B�}�,7u|�}_\���i����~�y '�u`�[x�Y��06�����Gp_�s��!����{I���V�O��_��J������]���)���.�'#��A,��F�C=��5
��2�$C=��*��PG/9���*����w�� ����~��'H5���wMc=x�+���a�q��&=�NuC�<��&n���I�r'n��!,m��X����Y/"���������>�$�cBh�J��^���3�BV*h��l�x|���-���o)h==��[��i�� �#�����)%�W�^���{�:�3rb������(����~�l�Qm0��%�����������s<��W$m���b�)5���SHx�_�?+�f�;�f�_1�+"k���e?�,;�,[�G���G��/f�*�f��:m��5��_U���(�T������]jo�,�l>�����OZ�:����j�X�d4���sc��v>��[WexE
��S�2�j���$�e���,�J0��
~o�#�pE\���s�������Y��O\�
�J��v:~!��t�.R��S�2�x��'�#+���u�e���fhLx-�ya������+Zd����S����V�9�=�|�����)Z&�|B��E��h9����XcC:�����.��v�0a����j�n��xb�e�8?�M����2��T��������/Fl��
�|J��?��*%L���n!��%���$�%�����m�\v�& �%��������.yy?���p����F6��
d7	�b;�����H��#������[J�W%Y�������Z��W���]�]	���*��ki;n(��c6�Nb;
�6�?��T&�]�;Jc�������oK��.9��v��h,I��mW��0$9�(e��]���>�YQ����
+F����pC�
����w
�������d�5�����������O�.�]���lZ$�	�)��M����3���M�B��4�Q!o�/�������6��t#	�+)�IF�CIx�����������#�t���yW������d�{-��)n���i>���kz�hJ+m<���x�F�|D��t��p�����~�����i�IFz��2y�f�b�5=�p����)��VRoz��p����y�����x�L'�����������d�g.�Q#����g.���������3�l��i��"H��	�D��"�_}�����7������r������������~��������}����(�����?���������c�����+��"�I�����e�}��K��o��)�c�����hs�4���.�6��-����[F��W��=����@���[�z��;����H2���U��"
Z\3��"�x�u5�^��1�@x
���I��i��z�Zz�+��I�����������ViK�,�i=MmU�����$��GK�{�"����Y���R}�,7�Y��`V�Q�Y!��R��~�5���$)i���������Q�v��C��If����&���:	��.%�<vuCD=��=��Hv5�c���������&+F�BDZq�i�e���MV|+.�F~�t����.��<�� f���E������6S�U
��(�@�@""S�7�s��N����r���&��t ����S���
;��k��������z���=�y�^v�a��%���>����~��F:�z�p�^m��k@�{����^��x3�gx�"��k�_�O�]z�6���*�Z�f����_��/�v�������bv�;�OQ�!������I����4�UxB��3�E��^I��+��tub������7?����wU�77�����}���D�Y�Y��C��ZE��8L��_���F��\eh���}b�A����Mp�����85'Q2B,���Yn$�8��������I<W�B!<u����AO��y�x��������^�\��x����^��22�������p����c�y�������*@1��y"
O�q��
?����V��� �0��U�n��b������n�h����T���t�>�N�H����X�(zLVD�GC���9$Y���������G�tmG��5{�  �_y�zS[o{A$�Q�j4:*�V�G�t���+��(u���HY����u��e�:�)��mJ}����UZ�S6V��O-+����������&���*�}k��:/��n�h�-�f����[|����C���[�O�9�x�~�=��e'F�Ul���e�)�g�m>��'��*���y��]G8#��	����e���K�~7�%���e�N���~��f�y����_y�^��x�����+�n�.�;QY����M��m���,��<L^���;L8Q/i�������L2�n0���/��2��N�K��x"	�6�������4��#2{�z��i�tU��z/�`i����'Ket��;�t����N�����4:��n���x<Yj�m"��}���R7�]�MNK�/�P�/=&O�������w�,M}�M�@��:}�1�x��F����$��K[�vE�3-��_��5�f�;�,��s����[�J<�,]q�%��FF�O���y�tz�LD����T��d�?N������"��Y�J�+��//T���d�G��e�Y�S���SA%�������2"u����p��+�����Y�fE�[����Y,�~/T��p��hpe�a���.-��s#�4`�Q�D��7���o��}H���s#�5�X��B��W{"������,������r���\!�t���+������SFD���'W� ]	����6BW4��2k�������w���������}
8�?������C���H��5[�@q �z�����
��8�J�YuK&��8�:�tVW�m�%�P��d�Tz���x2n�f�s�8D��B6�\.x
�7+��
PS�������[)qiFz��Ux_�{��C�g�b��T�4�[h=��{.%�W�����
O��VV\��������b�����/p��>.�.�tw��A�]�]��[e��[e�����B�������I��I��5�pW
��3�v��Fw��WB�;��t��m�0��rC|c
��O�� ��m�@���]�]�'��b�a�R���H��YJ:T�_q_�r)�^���Z�j�e!�U��Y�Pi�B�e!��`�l�>�|��Wpf_}��Edm�#�z������kPp��k�s��F�������Y�MHd]��#�x�n+��\��:#�'����R�M���Hk(��mL�s_&�{�QWgO���.n:��m3M�bn�P��M�Y�R�����L���5]��Vt�����+�������*�La�����������������V����3�2F�OX�o/��gfH���y��V1��3o���(�7��S���������U�+<���B�,��z����3���Ye��Z.��2/Hw���+n��9:"�(���+<��%{�.� ]4�y��W���
�6����Wx8K�W�;z����;OY��Q[�W,�X��$]�d)�VE��Vt�w��d��%-i��Y�+i���R����Vt<X���%��*hI�,��&J3�O��(KN.4����R��,��uNKe�M���O�Z������R��,��MFK�AM���O�F/K6�c������'�s�:��VY�����'K��rFt��Y������~,��yvW���l�������a�b�L�1�����Vz�S�j�wot�{�(���W!�l@�PT�Q�j�9}�Vt�H�U���i��F!��"�*���K�������;��tE
�C��+�)�
5Wx��6���/x����^S���Ha���z���������F:y����)��"����"^�z�����^���Ai��U����a�5Oe<^j:�MnD���L�Q ]_�x��(�������5
�w�B)gb��L����y�f�B��O5
[�r�+b��+�������x�U7;����	�q������q������=A��{�+b�8�����&^�F>|$��:2��,:h-�\�k}:�����S�F��Q��TB:x�$�
�.9-�gF���&']K.z�2[d��*�xs��}�9�Z��/S�f��\_�5k;w����2p9�G������o�?�Z�s�-j���Yz�SB���{�(�Z����[m����K�?�1gGp_H*��!��j#K'oU�m�	��2$�Ue�:�)m��O)
����0j����n�����Kx��h,�L_�q����D)��(+T�'��K��iE��L=��`��x�U&7�������Y�3w��H�7���jH���J�?|�-Hp����^c����5*���d������������x���6}E�=^��%��BG�5|m�{�=���n6����x��x����K�Y�0�+�H���=�������Ke ��BN:���p��*A����4��Ig��Y��4���o��(/�=�)
�����m���*xV��4�Ig��7^����j�;�����TJ��r��-�Ui���V��4�[HgyU�yU��5�*V�1�~�+:�W�y�{b���Ui*�d)�����5DMu��d�"n�E�I��m��-���-����H�"�=�@7�7FAQh"��}��
�a��f�7H5;
�L�}\P�6�-��FA�{�����������$H�7p��vES��1������f�;�,�.���`g��O���)YMO�G�_e�%�f�{-���(����'K_�vI�|��F�-K0+�@<Zz��R�!O��<�� �-��@G������e������!���2*��'���/�cTh��Io��2�/S�"�!=�d���.����I��6���x�Lz�.FN�y�g-����
�W��F�z�$��g���Sx�<���y>��^�]�7��N3��E������t�q���f���v%��H�kY�f�HG���4k"���D���h���`%�iE�FQD�^��t�7�u�nCEKj2V0�@�"��1^i�t�t�%Bp�9�EAK���0y��.x���s�(�V�@�eN-4w=�R���hW��d�Fk�l��hY[�x1r6J���dY�<]��qY�
t�7N����*�%?��_}�����7������r������������~��v������~�G������/?|���~�|��\�+7���LFV�E���l1�����o���\������wq����=^>���y~B{���5d_��k�9�'�N� �!�*�����;�^MK��9m�7�������NMKB��N�V��1m`����P�P7R�7�1����Yp��)�h��'���3V�6=��y���~<��^,�;�,�b��i��=W�h�7;���)���V	8R��x����>z��t}V��Vu�E��J:�2�{�;A��,����"P;�����L�Q�ua�����t�Z}!P��xx��7]��F����xc�F�V������G��j#�>����Px5�Eu|�����7���*��,6Z�vag�����F��tq�2����M��Kc<V	��t���J��{��(X2$�����4��~""t_<E�xO������g�U�3<��-2o��6{������X����8�M������R��da�Z%n�����nk�a�#Q��-��m�Q�q,a�}][��c��"?Lf_A��|V�����E���qP�9K|_s+�i�c�M��=��������Q�S� ����<2*~�TvI��}��9r�m����Jofn�(s��e�s�N�>*��Cr����<O��Gn�F���x�eu���F~���.�&>����������2�������u2���!�Gaxs���F�
��*�����'���4�v#��g�ly�
����.��\[��'C�c����������.�F�)��Iv����r�-F��5�N����m�d~��j]����t���p����f<7��X�u�3���`C"���^�xn�u������T+���x^�����H�1^O:������%zX��5^r]l�������/[6)^�xV'�4�I�b�5���g���>�����_��
�=��m`�R�A��'��t�a}�)��"��-h����vP�
��3�F�2�&��?uh=��|��CC��j��>/�t<V:6����B9��3������8��U�����3�$������!O���I���%�[�Y;�d��*��!_���!O��;�z�Z�F4f�\�qf�\�}=����x<Vn���m������.f�^��f^�U�9�����a��r���l�<g���t9�a5�X�u1��y\lo��x����M�ZyW���j���2�M_��Ut�8�3GQ�K�!��T���M��Y��k@F�Y3���l+�*����������P��j�)���?��!��T��g���6�j���4a�������6�t��nW&�Km�V����:0i���F<�w&��Xx�&"Q&�6-��e.?l�"�z�����.p(�6�Ov��.��^m�#���x8��W�^�C��B�U���6;��@G�������5;�Lk�����e7':�yLF��`5�Ld���3��#v���U�������
�����T��
�
�Rn��E����x]�7e�[^��Z�W]����+A�����gK���-�N�J)A*+A�Wph?<`�
Y�b	R�8����t�<�'���u+]"���Yy��1���!YrZ	'}�u�+��������:Xxh�����]���vo���N�]Y�Usg���]E�D�����0z$��GH
�VV���p������|����2������u2g��y�T�D<�}��A�"n{U r��2��q���O�����c�RS�)@B��d���*@"�[�"9�)H��sA����<�N)����Bx��hc���d �D:K	�p�QR[x5�%�EM:\dfCQ���&2�����n��Mc��t��l�D��*8��m��Mb�
���<�CS����V7w1���tF����m]����2���F�����x<�j������)@]���Dd����,���'O�t�a}��"��;�A�f��p�qn���J?��3K�2��-j"��w������+iI�Bc�~$g��\e�#������s�r�`��@K��f�G�q�y��zbg�A�g�{�*}s��<���~�5�6����Se��C������2�66|�zg"���d�G�*���0"kmo�x���i������d�'+����{o�x�L��z������a5�X�t9��B��H���2+7H�}R\���	�����d���T��<yU/�#.}H�����>����:������T���/��x����
��-/�Q��D�q�e����%����h���j�i�^���a��+�b8jBD�������f1�{�<}{�Q�~1�3�������M=���������P������Q�f������a�����P�����#Bx�J��z��i=��#B"�o��7d>�J�D�xA�B���3/��T���Yo�h=�J�lh\���G��n�AOe=d�
�f=�PKc���3*C��7�M��32������`���w��h����*�����_:�f�t���.����kIV������+(�#�Q�uy7�T3��f�j[v�-kn�v�2��'h�u�6J�`sX� ���|���	Z^������m���/�����OZyB�#���2 ������TlD�tA�"Y�)��I���D�3��XL�P�)��Sm��%��v�#t�:.�x�~���u\�D�}<����]i��Z�.E���w��X+.�RV��+�#�>7���
o��*������E���y�TF��#�S4H�	t�Q�l��O� ��@:=��w��6V
���������tMx|]�W��u��j��-2�p�����'�c�����_���_�s�)"���x�b���x#��!��[|
�H��9Z�z����Z�V�����n=Z�z��&1�T�(�����o��a2&��U"��	1�jK�>���3��%�7�\aW���in���1oZ�9M_�G<�g+�[���'G.�%'�~����4�[j�-�<��E��x<��?�������h����������#nq��z�a���y|r�I�Fp��]�@���D��d�%F�_(�I2�9������j���v'�^FV<����t�q8VW��H�p���;Q�2�%-�k��;c�q.x��7���G�3�O��D���
Q�+�;c�q.y����������R��yX���������d�+�*��X��n�[$J<+�������hJ��bn�I���R[��������S~�]t���iJ#�!}�7��+�b7t%�y+y�s�)N���,/���J�#����&����\��n������!!���|�Dn�5��G��Q4��[��N�Io����I������^��e�4�.�\�4VD��+�jn���j�"��h\�����E~_gv�]'�|����F�Y��si���"���"�1`��-����wR��D���]S1��&�W�!i��������
�L���K`��~L����b�����W&���U��6BW�����P��o���In^g����9���KW+V9��(C����2��
��&^2E@�q����[! #s�G��t8��:�"���*��tr��BKZ���5�k��k�8i7(`��d�x-��(�X>��2X[<C~�%�H�Y#��H�W� B���������u��3�s6T�8��N#���%���K���,����2�����'I"��%�g��>���6Y&����q=z���U����O���IU���Y��}��:��b�_\(�(.uu��\,_��%�Un���/c���c��y[�?�9�h<���}���O��x����k�{���g�i<�+���*n�^��/j<D��V��K�~���w�����q5�>��D\���uoFn��}j�Wt�����N��\O���"W���,�����w�
�exhI���n��sY�M�+����q�y��a|P�O����U|��n=���
n&����d�������e��`�%��w�xX�!]HxW�8����I<��	i�X��.+�t�~�����E��pL�ZMVQ�-lSxx���F~<�k@W*�u�'�%�E���� �S�H�1L�����|F��&�Y�������..��������F���	��x}N<��>�Z�%1^�[`oX>�D���g\�~\I�m�{`oD��7����7�:�WI�7�t�.�<��x�b���#3��E��+����D����W3��RG��Fg�����������:|�����<u�+Vn1�~���.�+:�0Fg��j������ya���T{��K��_��n�I�y��|��n[/G�q�f>OSm�.|&�/��%�������b��|�y�+k9�,-X[:�����������|���r\���0�mv�q�-i�sr]�n��]�q�q{�s�3�^�dr]�n��h[O��e�+<\����������H�����%����+�y��+�y�?�X�xe��c����b�ubvn�$��a�=�8����FT��t[�\)����_V;�Vt<W�G��Cv���DvO��Q�~<���R=�����U�D����������,iE�Dr�}���,iE�wN{fL-i����'�}���#��2�6�X|�=���z����x�NZ��	��y�B���5�P/�y�Fj�{�O�P��u�v����5��������z��!A������+����3��������&-����wr]�a�����|�����������ePf>�h��m�W���g���//����\~����_~��w���i�nq���������^^u��������x��qk���%W���j��5�����
��}���K)|y����o��qJl�����x��X��j����T�����gt�(���Pb+�
^�0����0\�x��Wx����F,lg�5%�g���Ti���k ���"�������j�;�!�Q��3T<���(���Z#��jA��z���V����Q�/�����B�}d|�L6/�e�!{\z���e�Zu7�����Ye�U�O��N���������~};�������uV^�Ju��	�Uw������i[��(�Q�7jYh������u=Yvd]('$�	�V��a��BI��k�S�r#w����t|�M'
��NP�W
C�;���n�J�t����
�g�t��\#�x�'���{�l�����,)����K�S}7���8S��=k�q���q�2���Pp��i�3|g}7�0���e�����n@�=!�V�VoT��n��\���x��x�.�3J��h����}�{������>�gB������w���=�����k�{����^�l��Go��BF:#�gE%��9���/�G���:��4�a<8��W3���@����t�z���c���j�K�-@��t����=���ghX
�|*�I�M�4<��`<$)	��@2��If^9���Z�^xw��P��v��BJ����x��TFN��V���`�K�}!� ��j�*F�����Nc<^Uj���^�x���,��4�c����p���3������^U���u�%1���������rS����_UZ^UZ��r���U���*��+8��U�������Y>Y�|@�����w����z������z�����3w�;�����H	����b$\��M�������'��'DW��?��:x����MF4��{qE�����ocV�W���������Mr�`@TpOc;^��Ph�������e�"������b�(V�1����Z,}��m7��xmY}tR�n���`��n�����P��-U�4��Hg�5D��|m�����E�sv���,���������\�v~O��y�/�3t?�>g�P����l����5 �Z.����Hg� 4�e�AW��3rP,�$�ce��F��H�����������;��U9o��qgEY�N�Q,�4�+yG)�WO{��b,yG)�;J�D���*�QJ�J*�]��:V��Tw��e��o,�~c����W�	t�&
��p>*�����&�x�q��=xe�#����y�%
���be�qfdQp�9�3�F�1"��y�Y|;aF���f�eojo�6�-�TF#�h6YN2���$��K�z;�e�����D��d�u4�;���I��������uc�c�;�<=X�6]��qN/gM:+�![q����J���q���t1w�$���J��m���y�f_�q8�n9X�����.�%���ce�t��_��z��2�H���t��F���r��c��h���$W����yk�G�x�cKZ~�4�<�\1R<�~�q�y��'�-'+>^��]b�#��|�'g&|�9�y��h�X��D��Se�%�����8�'��)z���3� V� �@O�����	�<�l�$������-��t�=�)6�8W����4�>K�{����OF���h��p��T�z��N���EES��S->�@<X
]P�t����Ml�$��g�jLF�%S�>�8�<W�T����y��fIp�9�L����K��m�q�x�Tzri���<����>�z�3ZR��G�����J��%DD'���U��{�q^hI������*FIxD0�y��*�"�u�qn�`,��8��Z�*�!cxt����TiO�8���xe����MO��(�=<�d�x�t�it��r�W�p�X�c�3��CO=��n9����f.��@��y��z��Y��f�,�t�=��Z���>�'6�`�*���#O�a<��Q^ ��@�y��zAAL�=����2��]���xe�w��]�d�q��x��t(8�@�_��+}�W����_Ad�K������F��l������~���-<W�� b=;���se����������������,�J.���U��x�W?���������J�+��a�W�~�����������������2��@E]�_n&��D!��Z;��x1�(�����-�s��vng"Z�G�al������|3����C����X|�g���Y3��`�d�/y%M�*6]#��LG��1��kvd��H.HfM.��!u���>������BW��w�i6/��
�)O�%���
e��pg�O�a��T����{�����t�
�����
tQ�o�|�a��-��}�&��������j�?������~~�+V��k We�e�G_Lt7�n:�G�C�������|��8""��z���������dy��S��uQ�H)�X����+���!g��Wd^q_���[��.�i;�3���k;H�]q���L��c�	�����'����R�z>����_<�8��R��+x��|y�^{)<3�Z������e��}���'_�������K�+�vo��5��k���\-�������?��-h
����=��z~�	5_7�W�]C�";��;�b�W�(��P�t�5t��ty�-�!
�d���G6�&�FCg����tp3^q:C����;��u'*z&+/���[d��v�]����v���SCw����s�\'�'���{~o(S��!;s�}LWZ��]�n$��Dg�:r�z���e<r���abu�pj�N<�lW�K����c�����x���76�i�N�t����;�OCw���tI�\Oo����KW������n.A7+��M�~�Q��r���b�-�����^����y��z��m�9:�_q���t'��S������wJ���@:�)���K������wJ��E/�+�Y�,z	\q5�%��:�_q�2�J8ds���5�)�,
���g�]�cG1J�s�V9���
t��tr���x�Uzx9�BU>}H7��D`����#'K�3J<�:��	-��`���.���&�%�V/�@7x��ZI��
�9Q8X���4�3Y�[���)�/Hh%�������+�!��:}�-�:�,F����J2����9�1�����Y�[�1H�ASC+�@3H��I�6�=���,����o����n��
[��x�'��E����,}�-�x�������d�G,���b���Q�|��j��2����eloI�&,���rS�W����;K��mezd/��(�G���Q�R�m%yY������	��we��
��+�f@};v*�]��.t�c�����<"��*�/�}J�@7d�3<�&�KI��i�Sga�D���,��jg>�����a9��������OQ�
�?�#^"����;�^"���mEH�8��� �;\��x�q��Q�sw��b�)�*��h������k�x��R�����K���g�:�"]?�y�x�\/vW���VR�
���b������
7-�8A���z\�PW����& �3A��~��!n���_��
��u�s���-��h�r��d&���)�t��+r�^lT�;U1��tE8����x�Ff]Ds������J	������Y������Fd�8R��{�@�e�xA
�2����Z�P�g��	������/~��Z�]WK��RmU_�WKi�(yD�|g)������4?���5O�J�z����O)���&�����b��2�n&�����=o,eh�w����5�tJh���R��H�ze����}R,I��jm�|��I�M�E�{�l�P��n���J�%�h#��	�CHRp5��kI���������fY�(������bm�����~���@�w����vSA:]��x�M-�&#�g	�����n$������cF����p�s�!7�Y��6�q�$��I�=�@/-i��FDR}z�
f�CXf?�$��y�xfi;4L��������+��@�Y�f?�]2J!���2�@��x��@�/�^^���@�/�!�������"��@�/�^�iJCd4}�
�p��st�D�_��I2�EFS�>S�8�@8X��]�e*�g�u�O�B���zo�6�J,���r��]�eiW{���J�����GpS�qd�8��\�
9�.uF]��L��{��j:�^�al�]Eo����5���w�R������}OW17HpW��L�&"�Uf���O�6�f�Y�b��%Ut�CW�g����V���W�UyqK���J<�c�U����������C�O��h�zU�7�)�h�zU������'UtE��tY���jg<\�W��o,��b�)�����Hpf����L��q�v�S�������+��_���23a��4���s�j�y��%-_���o���qR~$�r*����Q�������5���b�b����#�AM�l��j�]���L�c��Qm��6V��K2'��2.�ZR�~`:%e����$7`���4Z4��:{9I�����}s/����L�]��v\#�������8}�u���32�tG���<��.�s.c&"V�(�����8�����^��������F������d���R�	�
}��I�l��l`��|��IGw�hd��Q����e�n��|f;��n���3�j����c?�-�MYOL9#
$�Z���8&�<����u����*+E�'+�t��\mj�	k�m�u��N�����$���o�f;����v-��
�l�{am��s�S�O&/�BN:�^x��ez��*�5+x��v=������.,��w�`i�$Y�EA:=��x���\�v�3.����n�=�s�f�r]�� ��e!n��Q�l���IZ"7��:�@/��Q�����k�P�l��d�Y�\��)�m�+DPk�\9��L���Mi�P�J�$#]��$������F:}"�-��c��%��GKsZ�f�&��������g��Ct��]��ny�4�i�t����F:}��x������&�d��h[x�9��`����'�yw<\�V����\��Y��c�LpWY��}�^�oBp_��8Y�#����PQ�N�!}�1��x75�m�&�^Op���O4 ���Y3��;%������Xz��A����PK7�9�r��e'����d���i�=�y�PLI���A�y�37�x\�/�'9e��.C�=I9X�����0���@��W	�v��r��Z%���"�3�x]N�Yo��u�_<%��xx������k�n���W����+z~��k���m���)�����p_
yw?����#W�S��:;%��]x^M!�W )�1��3���}��o���/`�U3<lw�����J=%�����u������Se�_�AXRp�r��#�|E�'�T��
L�9�%��N��w�3�tE_��*����})�+:8>w��c��S���+e6��������E�`-�h�O
�
����v~�2n���z�����eE����wI!_�a��UI�u�92����HH}��`�p[
y���
�p.)�+:��ws�������r��~<�kI�I�e���M��=�W����g�,;��t���V��%�sE�]Zp�Y)�il7��P��).��+:n��~Q=�v����.��������F���4�I��
���v}F:��x�~��� ����*Pbm��Nw"�f��t��(X~�$��t5��m7pGtL��7�N\�m��n ���T\�����*���-��n���5:,|��������zg��w�Q�v;���J����K���eE���������dDDCr}d��|����&�������KRx�9�3�.��#*$H&����l5�H�����Y�x68�i��^��<����w1dC��#�e|����O6�[.�b�F:4��1���	����������~��_^���z���?~���������O?H��r�|���������k\�/���}���_W�������2sn�JP����GZdX
��<��o��)������~b�\����.�E��B�!�6��xw
�g�(�����=�HO9Mi�BDZ��HO���"��|c+]S<�	��=�@�-i\B����s��tD���@�<{���gZ���������L��^x�����3L4�O��<��V���
�6��+.��g�U�����(�t�>�@�)��0��
t��k��s�����{���q��st��������3�Gx��uUt��]������|T��]em��?�
��J`U��L,%b���-I6�F�G�������*r��Yq9���`���X^��oz�}�-�[������W�, � ���c��>�te �~�����W�8-��|Z����B:K�����O&U���<�*+V�������q_��
��2=���'w����y2P�k�a����Ftg�-a�����@7����2
���2����D���Fx�GRD0�5qhs�������k�����J�9��NxP�^�z�[��fZ�����TQW-�4�x]A�}8Y��\���L)�o�������X�O.����z^�\�e��T|�}mum��um{s��N�����$�x�u��J�}wT�=�b��E>+f����%������|j[������)�R]02r0?����������J:��#���ZQ���n��c��?�QGV�p�R������T�tt-��@ov�Yq�%��6m1��T���9�>�23�����"���w�f�PhO��G��	�I���Z�J������RqO<���:Xw{U�2��r������mq��&�������.�X�a�H���ic��&{/�k���EW��������,�>�zM_
���Le��[�J�!@p����n �Qo�'��'�B:�5r����
�t����#m�po6<�V�j"��%'���������H��%����h\�v���>���#]��`;����i��.����<���VOV�C�>�V��s�t>�H���h�{�E��:��9Mi�����$#�F��{��f#��hd�������G��y��N+<x���N�g����jh^�/#��
|F�?v���Ev�{���4:ZwE�21��p���U%�k�Ev�{�������O��M<\&=2Q?���W���im���Np�!��/.�<t�`y��|1A�p�C���}����S+>Nf^$�pdf�=�T�T3
���qeSfr^�{|����w��n)�+nk=�k�	�a��_�R�I�Dp���Q��^��`���4YwT���I�&���R<��sI�&Br�|"���V�_���d�y�o}U�K).�������N�x0�E�Yh?}������4v���u���SEx����?��HW\�x�;���pe^��3�_�y������*q�X��h=C�l��z%�1���a��z8��W�^��u��D����N�����g��]DY���*$���{�� �x]�f��Ag�-���I����zuI�-��"��|������Y��X�X��6<~f��$�krZ�'�(9�Z��+Hx5�~j4���W��Xo��)-3�3����Vx5���`���hs{A9�z����>�1����c����ske�������Q�#�l=�v����������L��1F_���gd��xI���[%�;��w������zCF���@_�
���+xi�������s��{���3��5�;���
�/F���z#�{����%�Y@O<��������kuqx\@��7�.�F�\�H�+&�?�M���.���?Uoy�j���}%���p���L�1&��9u�w<.i�a%��
����b&]��K�wv�/�<xV!�����Z�{�%�s��O������J���l\����s)i'�B�u�k�+��+����{kaI��"�J�3�����t��	�z��E�Z�a �qK;|8�W)i���]J�W��;Qc�r�����eL�P�}���S��2�xuC����vB�P)������X�����t�1bE�|J�	����jA;52����h�����>�&�H���m!t�Q�~G;e%Bx������S�'��p����U��RK�tFf��\!���Y5�n}�����B:��p��������B2Y��
�j���*�Oc�#[5�����tMF:��~�~�T���i��=����#��;~�63F�1z�[�I�]�����m����;J��d���Hc��t��r��C2�W����I���
tF.��(��z�lg����<��n&��bt�9��Y�������n����u�'�n"��_�$�$����F/���;���g�w�`9.���'���1���l�W�!���$����,�������Hc;�zFC������e�_=���Hr�N��L��be�&��(�qG)��*��w��p{��n�e2�(��E��|�����5;��3�(�VW�-�t���kv�e���~��v��,��l��H	��T
��M����v9_q5���+��wy6�N�Q��m��3+����W�9^������s6�[�l���Cyp�"�G��e���.�Y������<�n,�gY��'�q76�'��L:��}��+
�YMn���59�+�il���P�����w�B:�$k��g�AK���]Y-��J�d������JW���jN����r�}i�+������2������%���T�\�U���e
��w�j8�H�x��6�Uy�#]�
S[}c#rY�Gz��>�0g��o��(M�n�iF����b*��Y��n��s�thJCY�������Kk��F��N�q��pi���if��FvKn����t�����0e�����������F��K��z�i������]�=��|���tO�Ho�vY��4#=�p���e��;���D�Q�J��`<c���A�7�p%���f�G.c~�5���Wxm���S����b5T7\����q9���=xm�#�|Gz��2Y*7���o��2��]�32�^1��>�H3AEx�
V/�H/<\n2T�6�K
S.�3��O2���j���[�x�,�Y�t�V#m<cL��#2�t0tXl��#��r�=�HC��
����>�)�+�6���|FZ,W�s�t(hJ��Z�#���^Y�#���p��s�thJ��Z�#��F����y�.E}�5]f4��`�������Ki(������#]�p)O����Mi<X��}d���RB��s���HW<\n�x�6��w^��}d���RY}�"|d�#]�p��i�45H^��}d���b����s���nx�4�i�4��\�S�G��B����R�
����KsVI�kS�-K������Kk4Y3��$yOw<\�����UT����>���Kg��8:c0�<\���k�����k#}������[-���=�����SJ��x�����.�^v`�LJ2���D���J��F�p���������;���s������3�l"�d�'.�Qb���w��+"���9�)�g���.�H�<\f���{������y���i��<���3�l��d�.�Qb���wM/<\n��m����Y*�����b��=��k���~����������BW>���"�B�����/������W_~����~*�&�r3��h&
Y��������|�H#��6o��M�,�`�h{"��I0���*�j�I�{K�_~�����MV���g�2��^�5+��r+�9N_�]M���W��2!a��_��C��\5��~%�g�*��h�B��IX�������'��U��P�^o2��*�+0Vo�X��G�ZW��z6���[��kV��T���W���b;F��LpW�0�Z�u~U����i�	q�~! ��;�\�*>���b5��o�_��y_�_���b�TK�����x����]4�
����y�{�=�7tpJ4�u�m=�����@��w^e�#be�t�H��twKc5��OOB��.��������n���15kCq��D�Kmh"���j������/�/��k��j��pR:��� ���"���t�g�"r�|����3���?=�Nx�w�^Sg���Bxw�dV�xeN��1Z`��+�&^-��|�g���*�;����7�z��LDIB�8��tB��tUA�}8`�����o������,�������������z���/������7���u�<���?������~��O���"�������}����S}�������g��.7��+��wY��US6��+���`~����������������_���?�����?���/����>���>��������M����?����q�����������_�����* Q9��<�A<����~��P��o*P�	u_7���]������	}��I����b~����.��	uucmB���qY������_�ku�0`b"y(1s�MS�����������U�����m��l�H��$;���d����pH���8j�JG���a����Q�[E�1�Op���5����1��*��	��e<��99��/�bv���^���s��������ULy!��Q�"�q!��������O�2^]z\�q�����V�a��q�!m\p�����-A�H��8CV��������
�L��7�x��7�����L��\���$�vz[t�5<@�����=�pe���~N-m@W�2=���x%6i������x=��H��3�"��=����
��{l,
���G�bS�@Kg���
�x�U'��k���2�:3k�'��xx/	��S�<��7��t�b����MN}}�S_���'�D����#� ��a�����-	�r��F~�t\���B��dfW�L�f��zj�S)���>N�������H���^k���af�,R��@:��g��d���<�=�y����E��g���hJ��5a6e��t%�=�@8{^��Y��[hJ�zo
�lrC���+��z��^Y}����S��;�W����x���������mV�M-8g�����/���L�`e�j:*7���(y!��`�I��P���kx!���!��5���� B0B{�c����b����{��k�P=c�I�+IG����q����d4���/��7��z���Vn ������s�tF����q���gI���h%���+�k���:Y�h% ��N�_�����[��������}���3�����;�����C���F�+�����'u�Y����a��J���R\^
�F>4#g��]��i��ON��{�.��c�7nKE�)�E:x.W3��f��x����O��t��6�/�Jx��/G`KpO�l��"����7��(<~���ck)�Xc�b��h	�f<+�%��F��7�`�����AWd�;�T5Y�*x-��^~�xx��v�N���x�c���#]�4��1����'������K��.Q���x��6�U�)����I/?O<�-�����vI2��J�{��fE���N/?O<.V����I2�5��:������BO/?���K��hN��nx�4�=6g�1G��F:��<�Z.������S��x<\�p�5�"�(���{w<\Z=�h�}�jI����8[n�j����6N�:�������'�WK��QZ�^I�`\V��~b-X��F�q
,���$5���7�e<�n���O��\�����@�F)��(i�4f�KH�����sO���:��%��@�($��U:�����\�x�
�W�4�!L�^�t�G�f����C<Bx�o1Nt�g�#�Z�4�c�o_��|�/���[i�Z�|�����4������x���<�^Oc�
7y��|�:��K$�����o���P���T1/$��xuA����U����y\DP�K��U!��;�����q��U����	�YD�Sp�Z*u�N���~[����>����Tl��]�(�:~���#����yh��T�"�A���������+I��=2c�=B��e��wI'y+����A��*u�C>����gBV��{=;�F����+��\:�W�����Lx%�e�}�2+2y��/��X��T���k�x���`���zf���x�?l2[b:s��� b��2�*N3����3�`���b������[��$�:�-<Cf����t7�}t�{�iW3��tP��}n��Eq�����:�����[F�P%W�#�@�S��}_x5��t�1uSp�c<�p���y9!�����`f��F�Y�!��$�c��`8g��E�� �h*�&V�fn�x�1��W3�_�X��jn*�l����������p,r����{����x�MX+R�S��� ���^������+X��,�������P�(���#���3�xm�����t�jk�36p��ny����� �q�i��>t����L��_nW���![D�@s�E��}��C���j��U���-�^���}G�/iJC�M��L<�0�%��U�3e�x<azOW��HM����a=�����Y����N:0��s������Wq)�]��r{������G� �#�)m��q92�O�_�k�I['�#���g�������*oJ}O���t	��^�^��x����(B[>2m=��c�ye�`�*����GG����Z��:�/����R��j��)���
k4|5���>��p�^�.���9�&Z�x�����X�:���� ��;S8��x������k�\��pV����������86�~�W�x1�/.��zm��_*v���n3�}l>fR_�7?��n�:��?��&��)�Z��e�W�Ev`�{<LF��n%nJ�R"�x2�F�PA���^���%���k�X����{~���(E:*�
�������+:��F��d����Y�lk,�gY���������t�'�q��1yj��.��\�e<s�gK�:"��/�q��TB�]K6���p�w$��������7�;F.d66\-��8�pS��a54n�������	���`�y�-o��4n�������[Iq.)+<���W��n��J����t��:�������Ux5������!S1��R�������#�����g_��]�q�)�8y��
�'�Q�R��)���r&�����Mk���%��Q�\�s��1������{Wx�c\0��thJC���cK4�5<����tr�����{��n2����k��nx�4FN��P3�H7H���4�����p�$���Kc�_D�K�Z��pi����t��������x��z����vI�Z��l�>�����2�O��"u>���~<������D���K�����B��K��������4�<��@7g9���n&s���k��Wxh�}y3����<��6]��x�@��?�N��:"��w�����tr�����/���
o��t���P�]����*IMc<����r��D�\��*t�JR���h<=���eK���j�K�����5p6\����K��
o���+����z�t�-w�7�Is\��buS��4����9���4����,���(�g_����{��IX�m���Ih��u��R�|�r���C������s�w(���B�����+�4����^UQ�/�O�����������y�>Y�����������Z�����G�nE5���1��O���$���S~r���-i�O>���M�]_����dD��|L��,��u\|�:x��-����x@z��*���6�K>&��B�SM���`�O��Gd���Kh��}�1��K�]�O��	�������4|.��+:��&C����cn�)2Y���6�c6�{�T�1W�t�%�J���|�{�%�)g+�b	v�$v7/����tQ�|L�M�{1>��x�������i�����f��J�W��tQ�|L����-+�"��
r�W3���b��WpS)�@�U��x�@K6�'�t��%���D/%^#����x+y%���GiH�M}��WZ�S�w�+��^��2�+<x��W�
��|F��iR=�<�H���x��]D �w�kHL	�6����f�Z�<
�detC���N������X
�kzg2+�x�4�uv-��,�!V�E��}G���:����;���]n4f�6�]NS����(/+�/g��M[&��u����p���qi�ex�z,���g�}��J��H�L[�R�E�+��e�q���M���L:^��^�,�j]�����'7�x�}�}�gJU��-��~���'I[k��j
tr��^��z���T���H���=�l$��x��;AH]h<�(�
����a�Bw{4Og��+���
�$2�B��e���x��?�W3^�j��0���kK"���Y���6�I���+�9��Y���a�Ue�����q��;�����r�����S}\�����-�������������r����j*���c7��k�N�B�en�e�W�6�|��I�Y�Z.s�8�9����<wV�8y����u��c���5�����H%6O�
t�������$H���;��YyC��$����{o$�z��N���Z>�������u\}�:����5�q+	J��@7�i"��e�F�����M��������x�{��7."�7;S����H���x�CS�9��9^��p�lLe�;��t��W���u�d2���Z&���l$�V��5��2�����q���f&�����G����+������e��0p�}!���xP��j�K.�K:p��0p���8��W3��,o���C`��{��W�3JM7Y^-��t
�*+3���WM��r��ey}�m�����>� �z����W��l��x�}����x��;_��If^S�����K_��'��*��2���Jcd����c���J��|�7H�M�
�o���7�[�I[c���T����Je,#�x;3��/���s�;&���Q��=�Mi4f�"2�|G��ir��q���y��6nG:�@5��m^m�7����!�z'��"+|G��tD���H<\�[TY%IFz��2��"��Hxm�������hTd�h���� ��D	�`�������U����2�������e:QEXg��&C:���H3�L��{�oC<.��*����4���9����pY����IE�sZZ/~Y�^$���&����
��E��/���'�M)�M�Xy_.�D����~�_��0!B����FG��b�����\�����&��^W�����V1X��_�t2�:{��y<��N�L�D��xB�/�m�����6]H�{��*X$"�a~A���`t}F:��0�\
I���gg�U��X����������C���j"{����ul'4����������z@�B����4��w>�U:}��p�\�x�[w�`��
�
��Z�pV��L�Xo*h=��`�>�J���,-�}\����~�����aCU�EU>�
n?�G6�Y��]�����J����T��`A���u	@��S	�=c��`\�TC���t9�������W"����A)�'���u�%s�����-&W��oK@:<q��������q���x����G{�}Lgm:���������1�C3��e�VoW�����<�CAY�j������Z@V5!
M������% _������S����He$�z�\���#�Z�*H���}���)�y"�����/�B�$O�!�[��Ck%���f���Yl4_������c�,�u�O%�������/}U���)�\���UB���� ������������n���WB����t��
����[Lo�YxNY���x��oh��3����>�H�����&��;�^m���P R��u����LS���FW�T#=�l��U�
�CJ���s����T#=�pY��oo�};�8���e�O��g�]g���	����e�����{��I��e�8[n����&qz�U�V����	�����/���{����z��7�3�'}�t�V�+t.�K�C��+�)7��w��ZjAzn��V]�w��@>z��[h�������j<����$��]�U:��:�p�/W	���K/N����o�[B�>t]����)���xt]
��-�����r]���i���xF���eK5��P���vI�G9�r%�y�����t���=^����i��Hb=�+�W{QF�l��:$/V�.����u�8�������}���}��~�8��:�C���u����=�?���������a�������u�\������0iu~\�Mj�=���}IZ=v�<���f^n&z;$��=2���|���l��S:I��n)Hg<L2�t��$� �{��<Y�X��!R���u�We\*��0�|2I�g���r�(s��\�_S�J���^M�U2��U���n$������P�4�8p��8�	����$����Z�u84#�T����|��I�ze(G[�:>��+s�Yi*��6fdv�������tHW��L���mi�U�����1�N�]��F�j�V7��8���3�2�Z.��YI�n:���5�:�dZ�3w�����/�����Q�\�M�3����yL��V��
G$Y�=��+#_4/�d�4������V8"��2�Y��V�m�����j���iv27���'�yl?U
���j?�Dj���T�	��q��|CuK�"�:������\o�i���#=�0����w�h��^^e������H�<Mn|�g��G�l-Yz�T�A�Jx��N/rM����O�����4���I�#��pY���:��5�x�,�Y�t�q���G���:����i��|���)���H�9G:4�5��S���k���P�f���"������z�A�������v��"���5BxO:�M�+[�����Tx�2���}�"�q�����r��"��v�'rM��p'�M�Ns_�S������o?�@pz�J�� ��0kU0�
���!r�k��I�R�C:����;���P�-e�D\�!��6<�f��M5:E���Sv^OM���>�������^�TT�4E|kC�������O:�ckK��RQId������TJ�����%�k���1%|�I��v�fg:�W&#���SHc��O�IO'3��$1���/}i��"2�[�V��f�h�n��'1S�k����f�D�{�bd�e�i����Q��i�d�g��J_ZG<<��W1^De]\��ZF:d������x�9�6��'T��	�d3��#a�,�)�����aI���?�W]��m��|>6n���U�������7�����'h��/V����Z����y�OZ9�����0�-u������(�t���VK��*tUN���s�3�PdE�J�5K>wN��J!�Je����g>�e������Wr��+���_�����&'����7�:n��s����1�d��c�	�Y���e��NQ��)�KOL�I��2@R,����,�k��2����Z��>�S\F��l���H��*.#_\��7�)�e��V�4�]�z`�tw�1�Tx�tw7��H���h�t���
����YOM�O����t���������Q�O��W�Pt)�Zu@�*���[x5�����-[�g���ym�k��q����jB��m�!�"�gY�m���7�|�)f^��3����N"���_��|k)"��|��i
q����y'����7tR�i���7� g�"�)��$�i�#M���j#���pEmo\��i-�Qz��Oe^Y����R���B<$	�9G���D���N_0
���Kid�������KN�������Z��F��me�o��#]�p�O���pt	�2�!}�(�x����+�������R�H���(i����.������Xr$��'������|�-(9R���#��3"�������(��J�BV����~<���j��/9j��
p�,u+��i"
�.7�U|D5��&{�k�gt�=]�r����D=g�������y%y_��HG����
�%�v�Y++3..>Eo�Cp]p_�s)z]��������*D�^KFI�}�x\��!���U��	���i=Ep%|�H�5Y�@�%<�f�k��w{�W">�P�,������)i=�F��G^_<%�x�K��D��k�s�������_��0��.4?e�o������?�;�+��U�q�/o��vh;��:���e����Z��m��IRZ���}RZW�Hihmw��c[SZmI7��3ZX�r>�OVt<���$��X�L��~�����J�1�)
o���������Ux�+����<2r"���	�#�}LW>_���}+8>J�����������.dV�wV�z�&����_��ju���tw�N'���(Z/?�������C�}LW��%=p=[huF~��B�1=��2q�fO��	����>!=��E ��mX%�����Sx�ihya]�
Wt�7g����"�7JR���K������4��O0^O<��UX����L:��0P��W!�_x5��U���<���f���+<�*F�L��W�����j!�y�'de���k))���Wx�������I�V���Sw�i���6����Wx�������I�V��C����s��?#��HG���4�������$W�^��Y���I�'k����+/$O3[��p����&y��
�������Fz�)�������x=��H������%X��p�����bE�V�Os#x��z��<J�c��k��+:�-����*��������-U����+����/~&����Hf�+j��*�>~y0��.	r+:��:�9����{�e��
�K�w��CU��n�mo�������z&�B���RI5�e �q�"�IF���,�
��0�%An�����nW5Ke���3������U%�g���2�I�W!Oxv'<�	����D��sZ��?:~��<�jCq��Hd=�p�q����X�'�Q��kj��q9����l�p��-z�J��b"��q94�5�R�{�2�b�=N�&^��z�J�UW���*S��k��j)�(YD��
�?�G��L�n�����VmdCW�z�J=o7���R��r��:�;4��
���P]N�{=��(=��Wp��?dE����.MO=����D�p�T������q��N��`�V/���m����Po\�R�I����9�����DO�_�+��t���2Uy���O�:��'������f%���'=K���<��<�"����S�:�&��G����r5z������j��\�4���N<Vm������~9f|�[��J�-�"����I"�J���y����� �~������N:,�=K�:`��'�Z��%����I<\��Rw�V��O�:�&����X�i���a�����k��0qx��?�x���a?]������q���S�-s�G#W��PIf^�M�J>~�1UXx5����&]H7��9<6<�=�,�$�)���*�Z�"�.����;Q�
Y�Vxm��+���p�W*|�#�\w���zJ��	F�+iJ��D����gKg��j"�h�#��"�����)��6ED��w�{.����Fu���K��vM9M��B�U �f�.��3���<���DR`e J�Os#y����y��N�����&Vz�v\�lnj�+8�BnBO7���>������������8�Fz<df�J�8�|�OF��������.�(�������	T�{��n
�i	���8�v&{�R%���b��fC�>��~2���S�����?�T�xm������p�,�h��OJ)�*x�W�^�����)���N<�	�f��e��i=�n��tf����3�L��$��!j&���"����!^�z��8��d��"��l������j�K_�A<�5���~���S������M[&��_�_��'��+Z�?�B�V�k���O���������S�'����$��h=�#��I2x�$�w�%��+���q�M���Z2x5j
i�/��^>�����4��1fp#9
1/�I��F
:J[�����	��HI��i<O�+
�����O)��\F�P�T�I�T�z\%���T����|��<��lH[�w�4����{�e<s�X���/���d���.�����CU���9���D&��-�9��1J�K�]��N:�%��u1;e��-��f��W-�1#�+�o��:��]o52
7�����W�����|��"�^�x�T�� RX">z��C@@p5���&���M�<�x5W��D�JZOb�n;���g\|��I������l��,�������������=��e�d��Hf.�G�SN=��Q���-s��W3�[Q���rS1����*�Hc<���W3^|��;nn'��(��]�@�Y�H��M<�?�WKtL��O<�1]s���C^���N��M<�0����Z�IIF��oFxO:�|*��o&���IFz������mz
}���:�H]������5�n�$#=�p��k�^C�x<\�p�5="<&��9�'.�����*���g��q��d��w�����Y���}��������Fe����4W���>Wf�Q����q�Z�K����\~<�C��������Od@���b@��{�+�����A:<��U�����,Hb�cc1��s���� �tH�W�\
H������L[�x-R�^��x\���lE�� AM�"�i�}0�a5����H?a�Y�?��]N�����,_���RX�c��d���zN��f��b"�f�,�Lb�q��
�3�>���G�zyL����t�g���i����x�w�+H�K�2�Gf�B��3��u�IG�����l�s�oD���j)GBg<��f���O�[h=����<����b�)���
Z�CD����l��q�D�O���{R<!����-�/|���d�P��?S��O�E(�?��w[��W��r�D����n��,��K����n��URHw�Z��j7V=��5�6�{5��~s��z��w>M������R&�r�7��xL�	?��O=�&X/�oI�?q!�����,9���=��/�N�W��|a>�:.�#FB�����a��(�����3�xe��Z�p {%��qcix�KcnL��[��X��j�)c��M�L��*#F����T'�D:%��5A������nW�4�6Vv�O.�x������������Lk4�i���$��Z���W�V��K
.�F���+�:���w���/k�s�����&}�<�x}�u��w��Cg^�k~o�^���i�7pW��+~�^|n�C
��3/��=p���"��6��p��������=�U8�w�G>�GCX��N�h��B2�����7���_?�HO��N���*:N3����HOj#^��#=Zo:����r6�r���y��F	YL���H/<\f�v�#��0�b��0���Fz����0�k��N�#��e�l��:�y���b��8�F�g8\�WI�y���7S�t8[w��^�g��;3��g���$>E�+��H(�2k9��a[�u#���*5�t�V���A�T,�N���Z�D���I��n|����$u N\$FANnu�IR'6a�}��%I�t�������4���m?���>i]����'�?m�$���^4�a��yr���/�F�����%+7n����O1�!��&7�U��vJ$����Y�z����!����R|��@���V("��r������8�
�^n��Y��4��g���r�
��Y/}��pY^�z�+�7�z�� �/���\y5�m(bs�C�)V?����`=��Nnj����B��Bf�b��%�gdug��'����z�Q+d���r��W���^�DW6�W�����_|-��l��Z�~w���Ocl�M��g*�0�,Z���BZ�s}?\
�ud�N�����w������P����L�P�
E�ZC��QP3�|��a}ud=���V/	K��E�t<������o=�R��w-�'�����3��m�#�I�'WJg���	*�,�^��Y���D��y���[�$�^�<r����<�	���p=�<�I����e0�I��G.��j&��w�������d�:�*���Se�3���� }�+i��f&>�0��I���
M���0���7�����������3Ja�0
0~�&�&�=^�!ISx����R��C,Op5�Y�:i���j������b�<'�U�e�$1^��<���/��r�)��t�Y�2E����k���e��J�����T'�2�{��8L^��2��+Mi�/w��������s���^��2��+y��C)F��w�K�����#]��$�����( �J���`���e�U<[nn������"Nf;��M&�67!��T_�1�i��Q �H��2|RGI�#�1��'u�t����i�
V�
�`N�:J<����'���D3�{wk�D&�����H�\0X���4z��������e4t��J�4�M���#��
��z�]�!�p@��86���'���L���R��������f^p�1��Ysk�������D<�7)�����fd4����������a��������������������j���&��wCP�&S���4j�N��qbO{Xb�����r��F��-���|������]�_��t��k��x�e~q���Q�p�!wc�����3U��|3u��|��O��x6G.{�l�Y�)�VOS|C���0�H�X�L������m�~�qOSc��M���_KO����"r�_����$����^�{�?����M�'h���k}q�k�����a79^��	q�e� G�Uu��\W6rK�;�9	9j���������D������+���������mU7b����Pc��7��/��(
��}Wx�a"�|��78��:.7�A����\y�y�>�06$(���:!L��|�������	�E5_^������AZ���Sn�XXd���`������������Q�4�����?�������_�����L6�����8r��"��U>Ey�=����H�v�U��V�X���^>e�U���@_R_�Z^	O�T���=��	h�]O�})�+���V�Y��P���<Iy��)<��Z	�*�����<Y����!#��ZK�7���uyG��Jfb����P�M��4�|�<����?��/?��������w�����.����������������!��!�O�$������>#�kq��B��W���K���G�����]���&�����?v������z$��^���[x�[Od��$[������*��m=e�]�J��<����o���������������r������������~x�_������w?\6��u�6���}���_����������J��W>�-���������A��-���*��w�~;��z�>����wzn�op���E'�/h����+�=t|�ka��h�=���n������}��`��a+�<��R�
����d4�������W�U�B3d��uU��������B���s%#��`�RE��������+������G�dMeq�W�x�3g�c4���VI"P�s�G=��X,_���G���w��z�Q�N�IV|>�y�0O�^��Y��sp�[`������'c��*�\r�Z}�Yx�������/�8��}�l�����8���4�����0��_��z(������z��C�=����������4�Mw_���v���o08�BN�|��~���B2"�X���>k;���7Ih�7I�7|8\��^Y�V�Pq�V������6��m�W�T��~wy�$�[�b�������_������f�����`T�����0��cg
�u��+�u�s��"��=a���6~���
���q������6���X�MV�������p/�����zSKB=i���l�^&����qEO,���� ����c�W����f�Z�^�d���f��l)�Ka�e&�<1�a���V��{�"����q-���zE�� o~�l�^�u��lx�	��z��Y/`|y�e���woaX����3W`W�k?�zEKB����-R���j�]Y��<���X*V�x�����E��9e�g�j �!�q�w�}\�B��_��R��j.��HJqzo\��]�uI?���UJa|�Y"��G|e�r>�����V���[��^O�Id��%�2>x��xs���c�����X"��.�zu�A���o��`aN�5B�i�Cq�W����m�+��~ua��J�.ok�n��y����Q���7��zyT�{�tU��p��]����eS�2���GU���.?��5�k(=)\���(;���Y������Ug�����r�D���<2�#���s���������4
���s�5�0������ AJ6����||��t�5�xJ�c�A�h>y��WN�J���������y[J*~!q �O������t��5����BNh�KE�s��wv5_�!7�2���~�6�I�eX%Z./���������	s]��j���|E'����
��U���o����|LFd�|na���eU�\�VM���}�W��"�����q����Ehw��}�Wq�K�������JT�D����&�;}����Q� �������������g_��w �J����#�~�T����^U��ye����O_i/T����E�\h��}��~��\T7�E��(�k�EX���+V>S
�#WPt������W��8;�i�����8�����RQ���3IE�Q��������?~����f�������[%�_�~\>E�Z�U/�T
��o����9��|����������*V����s�Jx��v��U�7���$��=Q���W`3�5�����?�����g��_}��Z4�"�#��j~��������h�yX�#����V���VEN�e#��f� ^2��8��@�����.n���8���V]<~l�ib�Qln��H��H����F_�U=�DK<��*$�	��@����f�~n��H��4����5x�y�k���z��R6Kb?��vd<��DDn1w�A��-�i�.'�Ca�p�����b:��b�D[���p�\�����_�-��E3��5>�v�
���\x�g��PaV���lR�u���Ch��������o�����#�~���������	�i��N���=)����7�����L$���\8��i�P�K�G=sL�ur�=`r�,��5S/�"���� �L��g�&��^n�����}c��i�&��,���;/c]a���+~�����?��n�z���<�
���{���l�%>
~����u���-�:�����������8�9�vG�o[n��W1��DF��"���Ot��;3�A>sC0�{���Q��wA�P2��l\<3���3��xZV�
sb�s%p�S8$������w����{�5jt�|������}	���k	��z?����� ?��#���}�������\��R?9W�a��� �k>��
rj�s��eJH;<\������xc���;(~?�qi�������&�]���S
�s��&�]�v_����x���^gE��p����o�����[� ��?7����B8�O��yW�u�|��>g�4�p�;w+���}�G�Ra��svY�]�q��-}!A��~1saV��<�p�UB�3A��~|����/y����p���}������0+�K���*�a�|[������$�������.�0f�-g��~
�����'�y!�nB�3g��~-��F���s^���������_�-���m��9/���Whw�L����8����O�A)0%�]��@�����_�Urm���'�;s&}�GeaV����Ps����ce�m9�������,���#�~�B�3g��~3��I�������kMhw�L:�ia���vc?���V��%'��D�Z��*1U�����5��-K��)Y]�������#}�=E`�l����v��S/��F~�\�s����j
b�_���.<.����V���[�����p��P_�����<���c�s2�v�Y��r��X�qewrY�u����	�����T�miV���!G�I�d�����O���V�q^HRw�}��Q�T~�f%V��Y���)�k�	waV��<�L8(y
��d9_����
�c��	�^�A.Ih��;����C<�}�k?E�X<�C����w���q��Sf�~^�"{�\~<�C4Hh��rG:|�H5waV��p�[�#����j��� 8�FC�]/��:���@��&@88l��!Y8��m�
)\(��
�:�)N[�U���+��������� +�Ks\�0���e�k>*A�b>�lW%�pMA��!�M�__���	�b>�H��Z���v_����0d�|~��8�1`:>�nz���������6~��������q�t����|l1��&y�+���W]"�'��o����q�6ke:��_Rh�%��oZ�9yc>����^��{)�(�;��}��`�8�������g���{�a�1�7����,�j��@��q�{��~N���{�%���	��B�3Y��~��Vz�7�szx�������8$N����%��o3�&�N/�������
W�b*������B�bC������7��	����e�L}[����F�S��y����'l��	�ko�4���-'�J����b�����&�*;��0�,��H��������#8��#�r���\a��}���+��=p�^%�����B�����gG����m�|/���\	����#��r�������z�^�\M���|���8�5�K�����|/y�����'p3��zn���n}97�����9z�\�O<W�
l��66��]'_@�+�2���������	��[�J����k��%��7m��In\���}����|�}\������J��&�On}�������5������z`*I���� ���d�G�����������h�C����J�>\��'��nznC��]b��������8s�T�"o���>\gH��k�g�L��4��n����W�J�Zi@}?'g�'e�o���,2n:�qU�r��ot����W�}ot_�5���b��w	�{���{���=1������s�R�;���	��}��l���|�.\��%� <D�����W�����xE~l��/;'�|PB���{e��J�Wd�|�� ���pPB�5��6�;�����o�Nh��2]�W�<:f]
����S*���Ch�%7��/�$�����0 �]~<������M��+�f�~^N��{�+�'p%n�B�3���~������* ��-+��vgr���j�V�Y������d�vO�/d���;��|���E^���n���.�pp��N%D_�u��[�G�%/ ��B�S	��~��!^5��i�b���E�n]�8���^��5����y���P��A���W��Z��y��ZD���6��#�yr�L�t����!��o$a���^� ��'��=p�>zA
���h/xe��h�<D�t�����]
Xe��w�%��]�=�Z������k��8a���8t!'��g�6AD_"?���0�"6��![)����
��*#E�}rj�� �c���{�Tw�RWH������CDpwJt���.S�Q������pU#�)�;5�|
�+�f@��H�l��^�C�]��H�pkF����rVW�C��b_�u\'F(8����+y��0U���{X+����_���Z�<w�����qyg��*TK]q��"��o�?�2
���- R�7���	�E��/��~��V�[�y�D��}�5�������q���C��~u���:��"j�;����}���c8]�5���C��m�aw����7Y��E�c��U�s���h�C4��X�����
��R!})c{69����W���d������n�f2yUx%�;�����~��MJ���������_eU��U�|��g:���S����n�v�_�������G� ���{:���q�������6�������W_�%��uVF������Qo@��������y����Hh<m
/�D�w����~=��?|n
S��o�Hh�/�kt#��3W���#"i���/P�8�@7��4>n�y�s�3���Y3`������i~,eu�w�KND]���1w����t9W6h@ue��<PJ:$37����G����D��%��O�9�ir<bwg���.�����Ayl����3a���
���y��Z�t4`���G���Xr�)����H�l4���0�k�
>Za����g�
>Z���0�k������%y
�(%��	s�l�Hj�����H� eSpw&����h�l��D�M���0�k�n$���Y���7�u�E?�%�s������L^9�!'�c��O|�H�f���S6A7�=N�������Ma����B��cU���L��5��=pU�k@��H��l��?�%2��������z�Dp$��d�mm-}
H��0k�z��p�5�l~�K����Zt����z�D�����u����D���0kL��	�� ��Cd[gK_�8D�Y3�W{��}��-[����t���^"m���0kL��	�i�}���^�t:��ql��!�����A�p=�a�������#�}��sgc�^��nB����o����������dn5�f���6"_����@�����R��n�������WUs�
W���N����~�x��u��i�^rz��T�q��������|�nRD���CnAG��X"�����noA^��V���Ur��J\������-^���1�.���}�{��c�� k�s+���3\;��=_��x��2\��jT��K�s(��������j���8�1��[�1�^��k�Q�n��{k����CTTp������n��{k��y
�c@�{����WNg���i
�c������������n��{k��Y
�t}g�����p�_O�'A���<��tH|�W"O/TH��JO��0yz5�p=�W"O/TH��JO��0yR�j�y4K�5 +r{�Yz�&2`���~%��B�����$�����J��|�.�t��W"O/TH��[!����mkC����n��!�ApwVH�p�"������ek�������h�����f��n�����X�� rV�U��*$|
 �/���'5������B���\��J����n*T�,������5F�5&Oj v���sT��2�LjZU�y���,T������,��U�::�]�w�~�a�5��cU����r�H��������o�w�����U�/����A
�8;��v��@��]�����h[��]o�'d������m=�8��pK��I^�M:����3|�'��~%���y��y""�W�(�������P�(����CIW��������CU�������CF�������y�������;�~�+����M^_��x����j���� u�d�u�t��69!|�7�	!�����u�~O��/w_0��~�K;�*0o����(En�\����������\���2�_����K����������5`G���tk@�`h��	��`����C�5z�@����m�����1=���-�k@>�'��G��)��#�h�#x����z���5��`�����5���h���������
wg0���SFD#��?Bl�g�va���t��#��ry���Kqy��c��6�����wgly�|����.��|t{�U���2�.G}����-�01�D���^u��uO�p�\�j�j����*����\���!4���Z��_�^A����p5�~
n]�����k�WWA�����O���$<��~-�87�T.��r=������gu�9����.k;�D�9q�L?I��������a��8b�g�{�1���?�}�����cW�-9��������E���1��_��(��#fq�8w����~�EAN1k��sb������������M��:bV	]��K�8�o������	s���r$Cf����6������3+�J�u�	����W��/x�}
�K�0��=yt�t�O5�W����e���s�u�UD�TAM�-E��#�b���������p������N��O8!?Ppw:�=
2J?
�f@�R��x��?K��;=�����#Wf���k�Wt#�����#_c@����f]O��\�������e���G�>�Pq�)��~�����s�Uk��R���w���������
�|
�q�WF2�[���y��W
o������!l�g�VKp�T@H�|���uF�x�����n���gl5��;�-!D����z�%�n~��t��5`���,�������B'��B�w_�������b@��cy����������g{����
f�0kL��@:��f�F����5��l�,����
���*m�28����]|74{�GD:��7�aPg]w~���(��0����������{��#5�^=����N���	�����cS����!_0����p��V�RO^���p/ap��oq�`�)(����e�,1wg����5���Y��JXv��dM]�8du���-,��,��&��Q�����@�>.9�Q�1����������|/sx�L�tc\_���k�t�����k���IR�q�7�����$`�6�z���r����e���������8[p�-u�.u�R�-�<���OO2"h!��S�{�.�I��K�c7+��r�fE�4A��H����'��Rf����IW��x�l�
Xr�z�L�����@W>,L�v����K�5��-���^�����k��ka���o���]�P�x�Q�k��{`����-=DX\�qlw?T�7���.	C��\�w�M[$���	�qU�uH��_��������v��~�]�����mn��w��S���
4��z������Y^(�\P�5��,���}������r^�`�����p)�V6������(���kA��/��5`���_�J��T�
��@��'�_qw�n|
���*���S��}	_~<��@����J����P��B�OO}�����r��H:,�Ri�q�����B�N���
Q���C�i���%t�k�Q�N��J�D��D�����{C7��9(;�#���k��{L�8�}�+�d�<�S�V�U�*��J��q
_��.�&�[Ng!gq��,fl�|\��1��k������y%u�
gVt<���g�'�H��7��8���:���=]�!�OpwX�Z������i�Zl
t�����-��o���d�J����N�Wq�t��q:����,��t2?]�8B������'�I*�����E���������'I��U>�MR�H���W�[Jc)������tH���?�MR�\����������.?��q��W�'�I�����V�[�����UZ-��_��?�MR�
����gaq���p[��?�MR
#
�`����H�F�
���������&�&��Z����DT"�J%�tH���?�M�w�@k����2{�,\~<��mf�Hw���W�~�yJ?q��:��qV�Y�4�t
H������yJ��(�����n�QX�*�T6�C��`,p�
����v����-W_��84�#�8�Z���W�5+�	T)�YVtp���$b_��E�f��Z����Opw&��C�Q�
��0�@�P� �;��}
��D�%�B��m�4`���L"�5��=����B��d\��!�����I��y��o
��kS��A�����L��5��=p���5���M��&��;�����z���am�6=F{JV�����`���W��a��{U4���ob�����B�%
�/����|w��������n��B��z0i��P��nS`#m��
����C�jD�l��?0�zJf��&Z�1�����}���g�|��T��G,�i�9u�q!�bQ%�Y��3U���hGteN_n�{��Y�����Tm_v������!�����O��'���t�2�#t�_��;]�N�m�o�TI8�^����,��=s�X��mT�[O�{�����-p�~�ln��L�u��#����]{��{��>�����7���h�c��d!�~E�����F<�������o���W������,��;��:�� ��G~k�5^��:{0���f-:V����������V����\�U��4��K�tp�v��W�N|-H���,��{o����|��C�Y�0s���_Rs�[u������]�&������+U'�����]i�TW
���_���@k��
�(�H:Ht7��+JSU�[����MpzvwZ	7W�-B/.��n��DX��U�>e�����|��B�}����Zyo�kB�+:^����tGz����H
h��nQE����Cj��zdH�V8�����������Bh�'tx�
��)_#uu���+Fq�����Sp=���9NVh����d���	W��#�/���C%�C���k8������2�yW~Rp�/X]�)��w���&j�{;����w���}��s�n-��������	�+:n����{�����sEDc����y�[�������\p�f��~�8.���BW�����%PK�?��+:\owgz����V�5z=b
��Cx����5`��H����U[����K�X���_6Pgf��no%G}E�Zp�&��Z�-�h�C����e�~�~/�2�/��w�5�|��|�����(�i�;p[��l�]�9y���7t� K��(�����x<��p���3Z�7.qz"��@_��j*z�H
��`�������b��a�X��'�{����
2�8=�9�*+x�wo�����L�Y�MVI
�J*���.�����R[\��[�9�e.<Y�vj����5����0kL]����]Np�������#4�R���s������M�%�9\_��I�A��p9u����.�M�w��t7WxvW��w�*�F_�2m��mO�jb�������QL��4�v�,8CW��^p����Ba������YLS�0����l@� �f@�7@�Y�0=�B��
�5`���d!�u{�6�D����m�p_RxS�5z�b
X�TbZIn��
�5 [��f��Z+:D{�U�\��D��0k�����}�w�+���-�Z-��)Z=D[p!��F����H�W��,����`�j�i%���?���,h��n��V,�>�`_��*	x��k����qM��!��-8<��g>GX� ���~��la[�3�#���V=S�z�� �}�������-�+�%������<�F���'tsN������j����g,��^�[w��7x���Ki��!&�zD]�l;9M�}-A�g���-������Wd���^��&��b������C�`d�@+A��I�`cC�y���J����
���U[��%?��Vd{�*��t��~,����K�$�B��:�����X�M<���8�/�$�N�<�l��b��X`#�1y������2�B�Pi��?��F�s=-}����A�S�;���tx"����>����c,����l�1��}���}�:��S��&7N�>R���N�>R�kPI�Rh�}���"W���"��-��6pp�Z\�$�<O��&%(�u_�)�&�
i�Y���kO����M���jO���Su��o�4�H�����C�cd�1f�d|l;��`[����;�'AF�f�~�/����m��I`��;�'���e�w�QLMc?����~��$�pu]V%1��i�G]�]'��#3��:����+H�)���p�Y'�:%�H����8tk=�]�	�l����{q���UCF#]��-���	��{�}p�O/�K4f�	�+��e�?�p
�����Mp��L{����������?l�}���WE��U��Os&�w�Y:��������>/0��v:��=������S���Q������@kL��B:�������������Y0>�fo�_�V��t���W�����6Y6�K�dd�%U��-�y��/��z�8�d���
����^���,������Fp�<��p�Xd������=8����]q�<���~��BkL��!�����|q��M�Q����"$���n]CuTI88����(7����`���f������#p�����,�������wV]���1��W[�e���x
����������O�]��]X�Y���M=v��(w�D>C��r�u�6G��:�����3��U��f;*���E�NWT����f�/�g�0�J,�U����n^Q�D$�}��w�����k��Y3���:r�9�����5 �Wf��^�����t-�
E�E�,��(�V6D{U�����r�`u��8����Zbo?���_u��"ow�[��w�������K��3��C���"+�t+��$(|
8/D���}"�C��w������{�EO�O�Y��n �;%(|
�������Y��������9�C$���=����I�������� TP����p�pEW��N������hmE��U�M���D��{_[�
���N�X&�X�p=������iyy�������������U\�����{����j����s[��c����:�`E��?>Tf����lA��:�k$����y�����k�	��0�9�~��h��{���H����
�Y0u-��O����������f���\�oE���;��W�=c�!����Er������WO�����7Wh���u�H�g�{�}�QQ����{��,������n"]y����-o2i:���H�?= �%��+'�s����eS���Sz9�����U���E�����FA_V+F]��(S�?����R<��()�k�W��.*7/Q�*�������lF2��kA��8��$	�^�
_�<�Z#��J]E�.'��I��q�}~�J���.������{*7���g������7rP��{�}3�������.�~U����w�/�m>! !��W�f�VDF�+����-��pz|�����@����ZpF6���U����B��le�'���[��W����%�:u�=��%����U9�-ti�/�V�']HG��+���q�t��{��=.P>�q���D�?-RH:�$��W�����.�nj~�B�aE:�$�����=��������!p�.�W�8��) ���7����9�Ud��,^��>��*k�~�fw�����._�
�7b�+H
a'�/���cs�������4�/w;W{w�])��&��{����{x[��X{�e�1��7���+�{�������h�j�MF�����������<+]m��+��s���������Jn�i��n�6�M��|�v]�Y���e8Q�����z�M������'����B�����r�KwgA����0�N8�,����U@����,��5`��
aN�o��4���G#�;j}
��+s�t�Jf`�lB���������5�!*C��/�L�F����^p�57��/��A�r�k�7{~�]| 5��`t\h#��MVf���[����
��W�*�q7�����R��1�F�a��$[�1U������c������
G�qWw]X��U_��SSu�^����
��:���5�;O ��[��g���]�^ z�a�������v5`]s[�j����h���k��wg���[}��%���NF��}_pw�x��CW�5���_���(�{k�}-�s�tz�����v�{�wo9��y�h��^��B
8�U�P�P+-�������h�^lh��D�����>����;=��l,Gu�`S"f*����~�,���o\k�j�����'�#	��:>w������3���k�����>#���:�~���%��F�Ht��+�����$�*R5"�i��.X��ut�6�	r���mRV��Y[��*���y��e5��z.��@��`��#��+�<�ST���L�
3����G��W��)�<1��0�.`�5`Y���f[L���
�����WI��Mpw��|
X#j#���W�f`�����F�5 U��9y���w�Uz�pEh��>�mnT_������+^���-�������k��!���z@��{|3/�$�87����6O���z���F�o^��b�}�uh�vE=:����2�����/��v���[�u��;���l���|`��`�i"�|���XwH��g.�Iizsxl���3�ao��d��]+��[2�\��e
����w\nD���'�E+_�Z>}�j�| ���{��\�Q�uy������N�w����4��&�;��;��@lpl�r-m���!{O�|�a����wGP�-3I�4b��i/�����w.p���j��T��
�!�Xh_��1=����O�o2_^�Wz�����E����-?�u���~���Wt��t�O�����c��C��`��HV�����!��o��:.��ak�(y�%<�3	�����x�� ��`���voz��hm���h�����oXE@^I/��`	��@kL��D:<_wm�C�4`�p�	�fA����|��w�}�*\�wm�C�4`��$&���"�Zn	��B��u�uL��W�����h����s����QY
�EU�l���[e��T2K���qD�Y��)��-�w/FYQ�t���GV_�jEz\�b��������k���m�'_.��������,�U#5�!�&�;�\\
8�t_�5�u"��r�c:����K����|
H���*��Rw"^�!mx�5}b�m���voY1�l�;���TZ{{�7�a�Z��5��N�#��;��vNl V�.�VA{��IQ��[���:N���wi�����Qf��no{-e�tp}������|
�5a���iO:��Uu��G��qIf����w7��&�5 ���Y3���>o�my������~n[����d#�vS5g�UQ|���~o����_����o�~B���co�h��^1��Q�6����]���^~<�Cj�����Zpb�4D�Jo��]���6]����*��J�����h��n��J.H�3:\����]��,W��
��K`����s#��=6x�a�U#�>������g�Pjo_�A�����������eZL _��r����o������?���������.�����_�����������xej���m��G���?����������NfxY�Z"�����/��Ga~�������/+�Zd�/[.���g1VO���L�HT�7���e�H>�����x:
q_�����
���&�1
VG�+op�o9�c�4��U!�])�w�e�P>3~W�����p��$oc��D��Uy)����(��������GC�Q;n��� �}U!w��~�!M���g�����[���<���7�:�(�}U)K�|��r�g��7��q.�J����Qh��B�W�NR��`�~���_�b��(@!���(tiF!��B)/����._�����+R�|Gj]G-����B������{�]�j�W�tk�y�u���W���Q(��B�W��$I^?�s-�����a�3,����������Y�-^2B�'�����6��O�W`��s�5�K{Sj�C�g�V�w��qhs|V3m:"����\f]����8�����
����'7%�K\�3~������/�2�+L��~A������C�gU2��q�;|V_mY���W`�Gt��&N���!��!����z��Z�Y��e=D��r�gt���8�b��.�u)���{����7w��������!��������/E��#�����Zz�7\�������~�1�����t�z�����y4b���c:G����Pe��K��V"����P��>���>����������}��O�|��~��?���~������d���?���;���������_~�����o��b�����[���f���4��������	~��W4;�.Z�7NP���Fq�]����?�}���'��(��Ht���"�!I��������<��'����W[�_V�V�{�\pk������=o�������Y~#?�/+��r�����o_q]}E�����������@<����4�/��56���'C���� ������)���}"�$������Uq���r��X��?��Xn��>�����j�]GH���cY�'\�p�7��;CD�E�c�j����2_����������U�������G,�<�M�����7�q�P��,��]O���|k:�&�#��&����:~������\}�M7��L�e�or��6}�o2�O��������/y�7�9�*IM����4t�7�F�+��?��@��t?N�A����A�>�FZ�g\�i���w
� D��^�����e�G-���#�51������(K�"}9q.�6����(��q!|\�\��m��[���,�����c�gU�Q=��h����)?H���z�m+����8QU��C�gEnJm��Y��sS��Ki!�z������C�2q�;�p�~��8��)Z���~�>U�q�,��|��I>D���n�M�������bS�����|eJO�f;pv��E����������;��7�$�C������t��#���V�xS�����`<&F��s��f�
:�v�	6?�[�n��������-���S���}�o+��W�MI�ekr]�o�7)Z;�o�d��y�^�-^?����WP#�wI�e
�nUw�.�2��]�M]��E���~������_J@�]'d���lP�h���_�\tn�$�T�W������)�B�D���U]��Bo�T���U\�C'�+��q����b�:2}����~f�����L����o_��N�E����m���_��S�^�Cy��{����}�z����\�@������/i�}>._s����+�<���"/�C������B��Lo��^�k����<�X���m�^��[2�cI�{����/���0��~`5���\�+�I�WW�c.�eQl��G�P\!C�XVN����E�N�~$��-o�2t�3h�J����%33v[ !����;z[�����a[����yQ���J<)��Lp�yO��>�J�MNG�����>�I�i>���*u���&����1�<h����K�g��y����{�eYn#Kp��+�}���K�"=��[��Y����KbW�L�d"����'2�}vb��g�{��1���>:�Y�;�;��ic��{�w�`�nB������s����
Kr�������L�U���)�a��s��x�}P=B�N�I9J��O+g�/
S���4(�C�w)��3P��c4s\�2���5�	��W�h�|���4���2hg��2����zup���%����z
o�p�6�|5'�+m&��Wsb�6�	9u'pb-��Z�'{�=����Z���{b-��Z���{b�L�Z���{b-���S{�=��ML
��aP�E�C�rgX�����I�3L��z�����)6�+&�CCb�rR�j��M�Sl�w��hS����{��?��x7��6��)�����p�Mi��7�M�3lJ�n�m*�����|#�T<��x7��6O�)��7�M�Sl�7�����)6��(:�����U�Tw�M�*�m�;��������3l��*�m�?%���(z����2���G��O�)^E1�M��������Sl�WQ�������x��65�bS��bD�N�)^E1�M�g���(���x�i/�����3l��*�	mj<��,������Sl�WQLhS�)6��(&�����U3��t�M�*�mj>��x��65�bS��bF��O����(f���X��������9��ZVE17�:���]#��&$u�M�*����Sl�UQ�
m��V�)VE1+�)u�M�*�Y�M�Sl�UQ���9�|9)VE1c_�Y�aS�WQh�����B�x�F��g���UmJ�r'�WQ�)s�M�*
�6eN�)^E�eS���I�*
���O��r����S
���������)��(�tj>�t��*
���O��������s��xVO��TOy^E��S�)�S�WQ`��|J���UX?5�R?�y�O���Oy^E��S�)�S�WQ`��|J���UX?5�R?x�O���O^E��S�)�S�WQ`��|J��
���)�S�WQ`��|J�T�UX?5�R?x�O���O^E��S�)�S�WQ`��|J�T�UX?5�R?y�O���OE^E��S�)�S�WQ`��|J�T�UX?5�R?y�O���OE^E��S�)�S�WQ`��|J�T�UX?5�R?y�O���OE^E��S�)�S�=T�X�Q�R@��|+��S*����������*���
���O��R
���"���"*���
���O��R
���2���2*��*���O��R
���B���B*��j���O��R��&g,��O)�R��&g���O��R��&g,��O)�R��&g���O��R��&��1X�cW��baU��i����XH������S[,$fd����S[��2�j>���XX�]�S�����B�J�bW��4hW��bm��6�J�bW��4VhW�����J�cW��B�]�s��W[�+}�]�j�ve��+^ma���9vE�^���g���y���������������>=�vi+���!fm��6nhq�f���
4Z���
�����^�X:7
��&�F�:]���n��la��(lN�uRA�E��Q�ad�^A9��tFU�'��h����n<y'�U+����'���-�D@%~��;��]�������D��4Z��ph��E�F*��t\�QU/f4Z���h�x�Nkp�z����D-54Z�� �M<y'�5�S3�Da{"��D�hQ'b�@kn�-�5��5�j7
��,�5����)�d�����naW���LQj�&�r�����Zh��!���Y��)Q�N55R��$��D��$XCk�C2 Q��qX+5����-�������x�'�$
�3���`
����I��kpm����pb3�]���Q��`��
t��g��y'���@#�L�w&X�k�A:�z�0�f�5�6�S"�;���� #�(�1���<���M��f��@�P9j�f�5�6#o'��3�a�w��ztm�T����8��%�D�u&X�Qh-�������� ���t��Dyg�5��v6[o+k���%�������s�6�c�;[��=Zl&Xcl{�=�M���v��-Q��	#��Xcl;���D�w&Xcl;X;C���m���D^��fb�����[�(y&e&Xc��A:U�h�l��W�����v��s_��/8�OD3�n���u��O�������%�������O�\�����]nH=
g�e��O��x.O85}��a������������o�����o��|��/��/�f��?���o�������]���b��E�������%���
0��������Gxn�%�/�X��E���������^�����/W[��n��Y�V�JP_~����e��6&�|�C�GR�2����/�a�\��oo���~���?������VB�Y	�$�o����������_����+�?~���������x������O���?_���������g������_�e��o~L�Z����2�_�s�a�-��qg���o�px�r�����"�����i���-�8��$F"��k�k�-$0�Wsb
���S5�!��50��BN�	�XC��=%����*�}����aO����hO���zH��S{�=�wx�����'����������f����0(��6��hQ��bm���B��g�o�����)6���z�)�M���m��bS�[o@�
�������)6�����p�M�v}�m*�aS�M_|D��g�o����)�	^E���)6��(:��x�M�*�m�;��xE�6��bS���C��N�)^E��Mu��������3l�������3l��������S����b@����)��~@�N�)^E1�M
�������Sl�WQ�hS�)6��(F�����U#��x�M�*�mj<������`��S0�'����~G�z�7��}���ez�p����e*�J��h	�Cea/�n8��D����w7���Yb�rR����#�j��)��p��T�V�)��#4�� �|���P44p�7�|9)�P44�
g�b
E�j��p)�P4(������X7��W����b���B�R���>4��:��X������)6���j�)}�M9�}J�M�3l���SmJ�aS�w�2hS��r���A�2��k���9��h��jnU?�ZR#e���C
��n�����"�D�������I���GJ�vq��H�=RgI�y���S������ ���'�}���aU����K!xw�v@R�R���k�T�j^�q7t�\��l��&�+���u�4���������
M��GL�q�]��4��3����$G������-�aC}�jS[_���%��2�D`��,�����F���mwZ>;�&��=2
��=�4��7�p��]:\7=�������D�YB���">������2I��=�S%�tY�������3G$�7�����������"-����p��ax������>#n�N=>DZ��$j��i��
������~���7w������F���N����u���m�4
g����Na�����E�<���j���/�~�����	qn��zl��-����s��s���J5�d�n��'�'���u��4�>	~�#��q���U��a��\a��������\��v�!WfE$�&R�)h��X��&��J�oX����nj�@���;�7�8�q{A?��5�����<n���@�>����r?	�s{XJ��D����7���t��t������@�&P��M@5k���:l%6k|��@I9����u��1������1�#z���y�a���qH���>�5����A�
�t|�0P�0`I�G
=���Ib�{G�!��mB-'��4W�'$�=<���FQy��k�TR$E
������]�W����:�?>��N�#
�p��
g=	�W���p�'�"����Xp�S�h!���K(RN%Es)vFR�+���O�'	��}8�-�iq��O�p��b�#�3�Y�I|FR��w�*��
o��k���)K�w�4W�{b�����}�;���I�|�C�����w�{\��N&Ep�+�?����4��:������h>���O�p�k�1h�v�������s)A?1���p1��\���SI�\J@����:<�U.5��:�L,8��y�Q��3|xA��I���O������9w/��.�����	��w�^����6b���3������9�f/������^A*��V;7�#��K?�����x�6u�w��p�<�&�q$�2�m����C�tjw�z{�x:=6�n�B*;�����G<Q9J��A���������#\�MD�y�rb���#��D���X����S���'��d?�m�D���X�~���;�kb�����3��5��g���{b-����d"�jN�o4�3�|�A�����hQ��{fh�v)�|9)V-14pq=�|9)V114=��g�bUC3#��R�rbPIq�<L�UO
mJ�bS��bPhS��bU�B�Rg���S�F�Rg���S�F��g���S�F��g���S�F������0hS���Um��bS����M�Sl�WQ�)s�M�*
�6eN�)^Ea���6�����������Ux{x�g���SC�6�r��aR���E�jO�)^E��M�����h���Sl�WQ8�����Um��bS��oH'�/'��(������)����M�\�~����hS�����<��?��x��6�O�)^E���)6��(�T8��x�O,_N�WQ�-�!�bS��"�M���K��Um*�aS�/�
m*�aS�/�
m*�aS�/�
�T<��x_$:�����U�Tw�M�*�m�;��x�UN,_N�WQ�hS;���H�*�m�?��xE�6��aS�
�m�?��x�������};n�������x��65�bS��bD�N�)^E1�M��������Sl�WQ�hS�)6��(&�����U�P=�|y�������t�M�6m&�����m�2�hS�6����0�M���������Sl�WQ�hS�)6��(F��J,_N�UQ�X?5�R?��4g������)�'�F��O�����3b��xJ���k#�O���O��`6b��xJ�T`U#�O���OVE1b��xJ�T`U#�O���O^E��S�)�S�WQ`��xJ�T�UX?5�R?x�O���OE^E��S�)�S�WQ`��xJ�T�UX?5�R?y�O���OE^E��S�)�S�WQ`��xJ�T�UX?5�R?y�O���OE^E��S�)�S�WQ`��xJ��j����G���
#P�wT�V�M�[BL�*��U;�gG=����(
bB���&lz@��< 7zh#�(�����o�i;�M����
lb�(��w�U
�6�C������4^�>i��3������e&x����3f��+u���t��[m"J�	�D��%�P1�[�
N��$�N�8>�e�L�&�l�����55���8=�eJ�zV7�C��������Z;D^�7'����\������&��L��'���UOz����U�V	��M/��������D�n����������-�Z��������:������oG{���4T$�J��I�s���M��}�&%>Z1a�'!gy�����.u�D{\�U��VI�>�>���O]%��Ur�i�������zB�T�/�@i�D����q���@��Y7���3PK�P����h�m��!����L^�O�_gw�����N�O�>=�H��7��7��!u����vR���6������]�m��;�!���fw��^��|�D������U��������s���d���/���=�.��Bz*)�x�8!��''I�pwh�������<muw�.��_��T6y��A���|��	z�t����X�<��;r����G�R�[r*+�+�S�N����C>�s7	������6�J�A?�XXO��3IC���!�gu�dE|�s0���C�{��?�VX�j����w�^��gdU���K�����k�����I���#o�RmbB���%Da�l�<61�ML�6�����a
�f<�I�_�,�Q,���s}�;��_�p�sQ��"��������@�������7A'��l�i��^�a��~$vV3�������
+����8��)
W;U��{���(��\Z��k9g%��l��*F�#���/�#	;2��i_8G����!��nu�#\����vCzX`���5�Yq9��uK���
��
s�(0���`����
s�M����A=B�_d���Y���B���.PY6�����'W���������m�^������u��_.O38N�
��LQo0�wb����eQ�
^@��#,����������w�4�����=!�gM�85�B4Wz���9)4^��B������c�H`�>.�g�������o���.'�#Qg��R[&�jN�g�'%�Ws�<�[(D�����Vk��t��{43�����!���4���,�q��e���H��80	�7V���]#�'�p���]�~]bf\X3�.!q�x�����(�mc���2�������� �IHs�Z�*��-�H�j]��t)M�/�9�{��iC�;�����O���<]q�x �3lw�!	�1����LyF��2����*!�/9%����*!����F���X%��9�8q��/�T-~���3]��d��'�����S{�=q^�[(�=�g�g�B��=��8�f�shO��DHTRhP���&������x��C�rg��2���hS����~�_ k�|y�<�|�G��6�������<������&\�%VpP��������l�����,�����!|��A(��L�-y����=������+����O�'����K��k��f��t��O�����Tm�[��[���ap��K$_��c����:���#��6�I�j���8���<�
��:r���6�0��N�G
�t#����Om�1cF�H"Tu�{V�?t�_=T�@�H��,b�D�y�rb�Hz�cI�k��n��
NA��qz�9�W�
|u"yH�;����#���&���Io�j���(}�X7���	�'�H�&{�SqX������Tq���o�C�b��A���+�I����J0�������.�~�����}��{�a�(k���[W���wh4`DG;�I�`�v�c��6	�gw�����������c��&����V?�h?���}�@�&���v9����XR�H���a��E�������������uX�������Wsb��;�hO|�E^�}��H�O2'�(�H���@zx�'��@'�~�(]69����2�����XE�<j�~j�_)`�SBz(��)~��C\�*.��4���M�v�f�@&A����"�M�S��.2���$���%�|�t��������OsKd���!O&��k��D�Z���3�Ws���'��9��u��B��<��n�~�Q����k]��L�U��C��h�����<�u���
�m�T\F#�u���	��	p�u�By0�3����Y���6_�V�-H8����G@��={��P&L=�	s�-��[��n�}�hxSN����[W6���7���c�;	���+�[_���.���,��q��*F��>�z�st�R�a60�V7a0�_�����U`�v��������N��u���O(�}go%o;�����X���:pH�]���
2�!��wl;
�P�e =������l�a�^����4+�C
���u��<uU�-&���b$�����Q���s�C����T����G��k���tSy�!�d���*���#:v7��t���c'4L�t.nV�]�e�#���1i�L}�|�%a=U��G�M��&��y,^�l��xL��f�YE��8�0�Y\�mV�p��=<���dQ#��a���l5S����(#����0�������9��(���RMze�/� ����u��~�E��/s��Z	�o�&�F!��/���F�)��7����h�nA��EW�3tz�{��F;�1��t���E�L`;N���"!�L���:��Rg����L"~��z�D��=��<������I������/pY�>���\�['34R���*}vHu@*�G�`���/p9o3�-��js����F����| �d�E���}� |�����2s@�fM���R�zdc���.�:����9�7k��u�Zf�8�]�p��jL�2s@#��m?�zg?�'$�=$Pkm�^�6�>Bg�L`;o�X�Y��2�i]�����x����f��?37��q�my��/��h�T���N'�������D����2}�-����1�F�#Cf�S�j'J�!�O4���&�6��]�p�?�5��&�X#��O�5�.3k��)�I���4X!k �"����x2��
Tx3��;�V�X�,u� -�o��/m���C&Np�8�|'��
p�8�<�\�����3�C�h/���:<����	~u�;��p��+ >�E�X\��E��"*V��\�sA�#o��[0�����o�
����B��.<F�8�$����*������4I)}���9 
%�xX\�%������F��o��������x�@��������XO�(���#3����H����7���Ca��o�)���p�����@*^;`=]"$���9 ��<>���tIM�v�z�0t�'������H��`@R��X�.�$�/�)bi���Cb��@z��z�0��T�_����k�6��zf_�z�0����/�������F�<��f_�{�0�����3����qF�F�C��0����}"��Y���'���yA��`y��~�&��f�7Z�d��5�
�g����	�������0C�;�����y��~�V�:����J�t�B����F!��[��'�/k�<6�:J�gA*��3�����sG����� y��~X��QA�(�����yT�%��I�S�1n&�����9f#�RgAC��<yM��,#gZ�b��z(j��^(��y4��t5jB�:DVT[0���G��������Y������G2y�}��Yc�����D`s���@dE�H��}����G��������zc>�t�?����
3MN��;�-\��z�k+�i �D��p�k�G6�Kb
�Gu���k�N��Ob=o�.�Pe-�x�g]����)��>{���cvJ��s�>��	�@���N)@%@����x���1N�Uk�RN�7��������x�GS�@e�2�DZT�{��qJ��A���D�rIJ)���nyw�{x�F���xu'�L��5iQ��G��1;%�C���D��i`=�{tJ�CN�0
�A4����$������0@��x��gx�h��ON��#�������	��EcS�q��_lx���CZ�F"Lo=��y"p�4�F�&,��Z���7��0�4U{�'$X���q��9���[���Q4��I*� t�C�E�������X��������h-�Lk=5��ONk`���fD��[b�K�
�Q���b��jY��I���D��FI��X��I
H����e��'
N)8aX��'l��x2:%�EO���;� U��EO�i=����(z2��L�)�Mk=tJ��)�F��E�d�
���bDZ�i�~2�'�4�F��M;��S��PY�uZ���PO��(zj��a"P���["-�4�H�3[k=98}K��)y`X�����[��9
�Q����D��i`���|���O�,o���-8ax�h�#-����7�(�}���*�2DZ��-��[�����Q4�SJ*� ��#��Z�S���)��Q4�S�������7��{J�c����Ew��������E�R�N��vJ�Q4�SJ��A%3����������)��7��1|��S�F��H�<
���o�i����)���M���uo0�40��Z�(z���P�)�M1��=	0��S�)m?	�/o=�k����O��({%����EO�nx���m+�_��Y�	�%�,����{���)vf�R?M���Z�7�[�|���kFK����=�M��K�������|�:��/��������O�sM�
t�NY���#��E���g�'Q|
#�x]F`������	�Y�0G*�Z7��i���g=!��y���M�i�eap���e���G^�':���B7vu3R\^��(l��������|����(,��	�K���x?<�N_����!�{�������X���]��9\�������[F��&�Db��d�u���M���_Af��
b]?� 	)��\����=M4�H��IW���8��2��O��x6�����?�]N����2��I����^Pp�I���	�����A�'����B@N�^B�8�n
hO�{�<	�C{�g�����	��;��8S����{��w/���3���9��z4���8R�x�D�U?��"�+%z4���b}{`��6��bS�bb@��O�)^51�M
�������Sl�WOhS�)6�+(F����IR�x��65�aS�M�hS�6���z��65����U��x�M�vd^H�MM��������Sl�WQLhS�)6��(f�����U3��|�M��2�v���)�������T��P�bV����9S��Z�A�������S�G����}�K�U�h���zQ��D�h�'�v�{�"�*��<���I��M�u"L��������`���-��N�-�D@����w"X����r�L��� �"OD7��g�V�n���s,�D�:�)o�g���fXh��)�04Z��.y[�����V�X������Y##&\o�Ik�s`����xj��iE
����<��i`��l�--���qRwR�hq��[X����}���V)�[������`�DF��������w[`�&�+�6+e��J+�	��xM�t�:�w?5��h�-���c����zX�C�:���G�W�q^k
��g���U\���.H!uj�j!2���]k��4�����a���H����-V����Q�I���j��1���'&N��&�����������f�)���%�6���P
Q�&"�q�f��qRK�Pw�tg�/�pyBH,�z��*dE�i�^Cz�������j����QYV�)����`I�D�E��}��R=��8G����/�����B;a}qM\��G������!�6a��������I��������-o�����vR��<���}�n������b}@s?��
Is��Elq�l��5B]�����-��	+=����D� ��s�����]��Kt�M������_��b��*F)��f���N��e-�3�C�ZN%�`w��`�$o�#$���,�z�S�U��K���������=���f���L�{E�~5ZB�NU{��<OJtH���@�=:��0��C)���r�}������v9�J�~(�2d�,�t�O~Q�c)Q"�:N�M�
��]%�8��W{i����:���<M�2Ww�
Zjf���Yvpx��6�v��k���zn��<3�p�1��zN����hPe����S�9J�:?��E��!]\Q������0jX~i\��S�������d�=���6��;<�H�E��)�MDY'�5/3�Zb�9��N��$���'an��r�+� L�
���������@�N�WI�I`�>���M^=	����I!I�H�N����X���ib�I�]�M�����e����y+<6�"&3x�$�8�':�d����y%<*�a����M�u�.���$�$p^�*�����'�3V�
$j&�:	��M����zh��I���I������Q�RId��Zq5u|��c���`�3�5���)�<Z���R#�z�m�4p���J�^>
�Q�B
d�����]��A�jN��4R�i@�j��*k��h�A�g(U)�4X]�:g����:�Xf�2��Ok�lc��bwJ����'X8�=�)�F�-����wX���j{�^��"O
�V@���-
����A�(X[��B;�)��5�v�,��,y��5�v=����Ok��H���)�va�k����6�(��`�����ol�(X�)��F�<
(X=�`e�t=
V�`���NC�S�%�4�F����w��^8
�Q��r�$�F�i`���Y�Das��4�F�a����X�8�4�F�k���i`��#
��/XY;6���5����(:�`���5��t����5Mk���CFf�;
�Qt��2��rb�����5���VwM����5���p���y`��{���]�`���qt����KV�y v���j��_��v��=j���Y���5��Q�������wl���m����5�lY��i��k(=��
K^?���������~�5�Q�&
��@��}xX��u���[Y�|�u���[��<�F�#���_��v��S�q]��z���pzj��L�wX��	:�d
���xz�X������xz�N������5�����L�wX��u���,��<���3���_�Z�xzF�:��V�y��"����_�Z�x�k�C�u�*U��O/��"�L�w8����eF,Sx�<p�����c�Q��3����L����O/�J��i��g<�)�������3����L�w8�������H�g<���������3����q]�:�sQ+�<h[�g����Ow�/3b������52������ha5��=k��	#N�1m��.�~������Ft�������`4��}UsF��	e4�)lw��R�gX����x�v#��;3�����D�B~�F�<3x���w"X�b��3����BA�E��  ��= kYc;B@�(lOD�������%����"�Da{"�T�$�����%�����d��vH&u�I�E��t^��;���S /����BW�i���e�'�D��.��H�'���y|"X�c *K<y'�5:v�����kj�6k�����Z>;��8!�$O���@[�����V�\=M ?���<i���������e���.M�������s���������ktX��A+$@yX��������?}��o��zb�������?}s���|z1P_��i���HDj�����~�b�����L������J�?.������=�����)�q��j�`�uK~��B!�	0���Ub��|Fg�O�����#	��R4�Iv����WSmB�� u�$E{ua!���������z����Gh��3��/c��N��t�m�G���m�j�Qu��N��?Mw�D���{�����T�����_�#X�����s��io�,�c&�
����c~p��~��>�T�g~p���b	���#�c}@��'5�?��������x�|Y�_~��'V;�:�8q�q���[�?����i.� w�(������5�6�fdF��
/�Y���F�����=�*,�E
����]��c�R�,��m�q��:��5N���H���e��E��}������bY�?���+&�	)�� &�i�=��V{
�$�2�Hv�H����{<�ODY{-%�n��@C�w��������x�;���.<�ug��Fd7(�������q��
P����8�����dL��?��w"}������d�������V�I�����X�?�F��mxh
c�fA�A|�����]%����Z�L}���U���^��Wj�����`}$�'����\��b�f���������=
�
V�g�+[�~����=�W�e�/h��za
����`_��:+a��z�?�E��v�w�l_�O}�:8�M#F�V��x=rrI���	���������D��~�oz�m�)��;~Ti���0*�B��*F�}gX�W12�#A[Q��<�! ��`4�z��7�`����n_�3��d�h�J�v�7�����!�n4�.�g`=U���$�����>o���h��D_s�l�#�gZ�haT������V���4��hW�z����vm�/4u_hTyf������@3EzgY��+����L�5�*����,�`�2ww/���~z�3��c�U�@�v��qc�9$����uL�k�W���i��7��Z����jm����B4�-#��������/3�����r]��L����t9m.4��9r;7^��
LV}���{�Q���+iD7��gi>(�g��o�`��rq�S��~`^�#\�a�F�0 ����y�����t]����������)+���;�&��?M�����\?U^>�����iQj�Bm�3�[^�`D��v��y��T�N�u���h�Ng��U�M��p`hU�F�z�,�:���D�>
��4p��Q�&�T ����4p^"XX����&�Z���+��/��*�3�C���T%zqf�+�$�:�Mh���_�J�F���iz#Z
�Md�����F�a�tT"�a7�r�o��L��`)x|���Y`��{��U�VXA��0{W�f�/��daR7q<�e8V`>"���^F;�$�e}9���2�a��@:c���-~j��x
���k�nr���n����=o&].�k����7G�.{d�,7G��%M�=z����m�%^�����w��G�~���yqf$p> X��6���N���j�xh���8�!fB{\�>�'�	��	���Jm����:����+~��O����q�	�<b�y\�����Gon^?5^C�WF����������n�_�����%��?L��$p��C����6�v���o{��g��b�=f!0����F</0�!��mF�b����8���:�W��4�>�vw����|��#R���V���:�og�?�"<�;/pq>����q�
+}Ff,�T�8����g7~hB#���	�L�U�>F>���+�a�x������B`G��gBr60�Q<�����5�0 ���$�q5�����O�����#��4/�2Z��R#�k���%��e4t��HY�������{���K����^���-��Q����-r��{��~������������.�`��wU:�.�-bx�EX���,��$�u�bE���gB�2��X��s��tb���w��m��#����f�M>r���&g�3�~0OY��n�4��g��������U8,��$e��Y��&��:`���
"TV���������5�m���bke��(�n���
F[X��-mO`$�'
����e�����
.�"���B_���4xA���l�[�bicq���G��L�.�\���;�;b�i��bG����F���B`�U��2zd��:?�p��S��,�:����vga)��:��h�e&aU��M�������u������sH^� k���d�ZB#F�<����DHB"F�a��.r��
���p����a����WKvh����*�����N�G�����Pz�.�~`�aK8��~V�w=��:��E��-&(�!��J��C��E<���V��W���1SZ_��Se�,�D�>���_��^�t�d"P�	sh&vg��,��#{S__��V�y�6��|���#`A����2	��O��T���2�&����{����^8A��6:��|�a.h�i��0Zm��"�	*�������o�|]���:���D�UG�7

3��kg��o���tF�s���.�^#R����������T������xuT��������H��jn���	��Vs���������-�]pA@����	�Cn���eOu.\��N�S�U>�UOA9!��s@dq�SH��A����\f��,y�����N�7h���Y����K`	)��hkB��3u�s���%�������"�y��GU���������_���S�)���*���>�fbwh���`�Rq��9����g����g���:X����yf����=��xW���Y������Q�&�,�6���h x�,�XQg!��L49g���#qz(GM^?4V�Y���7����k�Y�W�2����u��M��9�uf������+g���:�/'�����9�B����Fjh�������Nq{$b�6�,�K6���g���:<Rg�=�"���ih�%%'�m��s��OJ<Y��5|�<��HN�����p��x��k�Eh?��0�t!;�x��k��p���0�1t�C~&�d�� ��c����y`���24����<����wI���5��f��$����H�
�v%'�k$�cL�x��k(������;/��X���(�d��`�o����y�SlX������uX�������.�y�<���=�E�'��k<�(x�}��r�8�x���(�d��x����H�����k<�cX�x��k<�p=��x^:��t�aQ��:��t?A���.�y�<���=�E�'�<���C�~i��V"6�����/%����O�Rbp�<������x��k<=X�K��	��O-����uX������5��op=�L��xz�����vo��-�z����C�t�p�S����f�;`�xz���*18aX�s�*N<Y��G�[����2��S�6��/��V�"�lr"xN�H���5���P������7�8+q�d��������CQ��%��y�����t]��?Y��Q�{U�@��W�9��(��k���v���#������d�}56����:��Q�>R�E�Pc=Q��(6;pH�
��Ed�U��WA�*
F,�J,_�Uz�Lb�+�z����9&�<N�����
�� ��`�h�`ky)�������NQ�����}k�AiO�.� ;7�����DO>[��	�Gp�
����-h��T�yW
�����X��`{Mc����
X��0���=�B�j8�[�x������f�������Vs@�/i*|��V�+��$�F�a��
�=B�n+,�����
��$gb����xps��&:�BFq������xy��_d�����{'�������6!���]��W1��4h��M��1�<�M������&�W��@�yB��6�_���RW�L$�/_A�����u���t�v�!��W�Sc4.M���3.�k��@��2$���U�[�/H UUCl�W�u�D>�agp�Z����cL`�I���&^2��*7���,y2������W�G������2�'��k��������W��{�n��<��1�%��4e�P�p�L�x)�o3�|vx�UB�(}&*y�/�9�����q�LHp&�;���^?;�&��v�D��
A�y|4�����f��K{��o�}5^p+}`&�6�U��6��+��3A�E�'lS���(�>�y|�my(S8c&h��M�r;6a�\.�K��y��>Za��^;�����~����-��%Hi���Yh���2e��d��G@��������B�?����,�Z0���/�����Gd2V����2?$��3�����ankb���rs�������5�����������L�����/8f�>xY~$�x)n�������������������\_��d�L��y5:������
����P�5��n�S���n����������e%��� %�tm���njp�Q��������p{zI��+��ue�jWfH�'�L+�Uq��r��*W���q]��,��?�J$��."�P�����@�D��"��Z!8M�	���~3����gx��^�Zsl&z���k��A�gxLp�p��6���
.���������,J�X���Uq�N���a���]����]~�uo�d�L���V���z����K�;����u5��sgi��������M��yWe�b��+!��P������Y7�����/~����X�;�U�(��XJ��o��u�!�t����`�a���>���t�U������3��/�������j!����-��&[��-7�O�?����������������o����m�z��?.>s��_����J��dW�������}�/�7���W��,������~���Z����}��`���=�<��i�����/~��~��_����2����������?wY��������o�~�������o����B����.�����_��o���������N�(QD�}���H���
��������������|����������_�v����}��=
��_�������o�8�����?���k��b��S���5p�L�q��^��_���/���y'�����O��T?H[�t��B����g2�����,������?,���_�_U��=z����7��������mG/��Q�����?k�����{������[��/?����H+�t���-����	}��~��~���jAi����|���e�T�~�~������6�:Q*�q�!��S�������	���d%��A�1�w��-��,k��p�YJ%��P ��X��:��m������o���9k��!S��obu��h0!�1�5Y�h��@��h8]����^���i�$E��C0!rH��G��C<r�����0�#�men���m�6����0e�}4g���������/��$��R�����` �2�u�/��z�m�5��	3"����{��~��VR��3��OT��A_����)�Y������2�����8g���D����ut%�X�'8K)�	^��_���N,>�d��������������ZHY���p�8�}m1��:��: U^��,�������{_�	�u3���	[T#���0�m��n���yB�7>�~5`+-���2�ZZ�i�\Z�{
s��;	V�2�?GL�����q<yB�����	yBb{H���#����,H���������� �H8���]��J�������y O��t��A��0�!<�Q~	��(?lD3�9���b�7�hhsthha�!#���:
�3�k���o��z�������/�*��C2��{������?������������������n�P�u�g��������b�h����w?�������[��n��o��o���]����}��	�&��U��B��O�����h�
���.�����`�?����4�f��
��M�����.������=��]��.3��LW�,��T�'����>�����;�����������/+������n���I-���mh�i��A�bM,����C�US�?���u��B�po��{0�
�%����-,	�=�|L!d�����C�0�3���I�`��
��n��I������Z�z���d�u�C���W�����z*��xo�	����G���qG�	���W�����v�n�6uW��7�~v��`*b��6�Z����P���6[W������������/d�����t�P����������zc(}u(�m���57��|�(�����ao	��sZ���L�/�$��7��%�h[���@�}T���sT
`�m%b��B��(i�~P�L��LN2�e�D��5�[�k0����2��A[GS������xM��m}��(�@���C��u����q�g�������f�����V��P�2�87���O4�si��3��������S
����J��������?� B���S�D!�����I�8#�Jv�J��������s������K���������e�6�c99�b��Q��G���	s{3�Y�9�b"�*��5����.�>�N �������p��?��Tg����2��]�\>;@�DZF�{����b���o��������X�����}?������7�9�J��+����E������$�i|�����w�
�g�\y����>�"��+q�������N�8�X���B�#�[�����p�v�����x�BH�m���
an�Q���D{_}��#���,#~���9����#��� s+�c����|O6���;� m�C����3=���+���A�`Rmw|���5��:��I���E���>h�9�%�[�qe������D���9�UG��8�������2�����5�����h.4�2����Q��\q�OO{�e���0�������V��8��l����"laDCE5m>5SN��dG�-�	;���2���/�<����3�M��|��h~��$�J�����$�0���'�wN#��E��������{Q"��Wc5r*�	F4n�>{^H����7���S�!Q_	�1��;��#Z���f�H���]V���J��uO�x(Kt�=ZP���w^s�����6�l�����!������E�����3$.�Ok�#<��	����H�X^���n,�T�}� !�*J�n%������(#^��%�]D�BU�Y����9
|�3����F��8�d��Go_�Qv/��v%����q�Q�h9O]G&�e��tv��������F�zVs4 4���&r�h������858��R�����n"���:��\_?u��f	��y�>~�����2��VD�R2��@�0�	��M
�w����"���4��m�"�Wt 2�=h�yk_s�
!�?O���%����+Q�9�8��JU�y�7� ���s�y���yk� ���+g�qG��"<A�1o
���H���y��{���D��%���W�(2�S�����4��`W��5�{�7"�a��6��@!�
���*��y�A�"���qO����*l�.�0v��Ed;DX�L�4�����BcY#Jz�5M�[�\�������+����a�D���:�#"�T~�=%+2�J#�J��^�^d�T��O��z�7�[���PqF���?{G�2��-B���X���8�:B����z]��q�B����x���l��z>Yj;DX�8��D��T$N���|�
�� ��.!�����&��F,�Aa��y��^��q�PD���8�m���������i+g,�K;!�Zq����"�����gD,�BW�l��zW�l��E,O@�A����]<��-zk��p?{z�K]6/Dt?~����+S[�B�0���'�n��oU���=�&3�e���u��r�/w�V�#@��J�����*��\��ek��~���OHD�0�:R������Wo�F5����-�����[!�KE��.>-({[���(��MY���<���/�}B��;0�D���mV��
����K��]b��u�o��J����!A�0������O���J���(3���Y��,���#�:D��	��(����b������+�F�r��8���8/>����(m�q �o�l=����>\�=�����l
.[��?� ?{������"�D���3&f���o��u�Y����C�Q�����mn���������%������
�=i}7��v
x�����ju]4���e����$h�.���T�h,��d-A>�(��C�'/�4����
X��mEu�u]�;�Z�Eu��Q����y��-�h�m=�.)��1 W�Uvg.Z�%u�����6�@�j��M=�aBK
��-*�0��������b�%uw6N���0x��.�}�~������3�-�$�~��=���B�J��=�|��=��aK��F�y����~��Pi�U�o��HcP��0���fA�5�V�st�`�����Z��+D�)&�����@��+ t_���'���};���^�������V��h�O8��\�������N��v�o_e��2��p��U^��
�J�����!({�a^[nGl�3#���?��2#�����vB����@H?	i�	e����������:vZ���3i�	��*c�io��F;y���xV�z����FZ5�j�g�C=����B���]e�=��Dgt������>�c{+&�uXj��F����@�F�7Gz^i��F�73%|#��r�P�E� *�%
�q�;���j�p����>���C
��D�-g)�����C��X�&��m1r�gk�F��8���X�O�n�%\�Z6�n.q-{�����Z�ip�����d���+��G��l�4p�9���������������H3�h������H�����}���d���*+w���'�%-\�K<>F5�l��{��G��l���~�&��d�$^����1�'�%�:�_��q������;��D�1?"����l��&���k��:�)��<�1��u�&\�D�����N,>�����'\���+��/p�����TW��t�Gv��E���e~����������.���:0��K���eI�3�����R����}�+^LV�������P�a��,���Z���������i�S�z���T��x�f4a�8VZ������T���w+��k��T��'�?��j��hF��*�����	<Ku����
���<��C�zc��a��o��u�������������/���q�������������������1��EY������Iy�e4���~�����L�w�9����S�z�OQ'��w��������������?��#���f������
w�^>����*���$c~<~\wN�&�8��Z�������x���TPT�*h���C���^4�F��*h���U/�� ������z�����V���7�{D��=�y���C^���H0Q����h������JG���/�\
�0T�)�h�K&�[�����A�$��T�� B�*a���
[fGD���:i[��\yR��$�D��+@	��D8�I����>�];!���[��h�9�+O���hwn�$��j%:���v�>�N����V���D���0o
�	}�;�[_���:�-~��v��A<��v4"�4�U{"Ldz����0��o�^����,���}w��A<���.B��U����sv�A���9���:�#"��8G�t(�c�!/���C�����)K�#�����ugDX�����RJ��5�gD,=����5�Stb���<��_�V�h�<S��pN���Py����`�ykO����=V��3bq����Y�#���]l����d����������x�������s�N��n�z�4��job�@Wf��X��^��'�t����������u�zj��nN�[��V����5��3�1��z A���^w��m#<eg�����|�A��&B��dB<M�����`�����rz�*��jj����P������%�!DOc���	'r��a����e��q	���p���������)��E_�V��	a\�DX�a|�:�5�r�N8v�]D��H��!D_�*qp`�Ph��kDX�5���w=��K�����3��������9c���og�M8��\p������1�N��������{D�����7���r;l?���^�yM��p��0o���U"J�!�GT��}�Y����n������o.$�[��+�eyD��J������#�����n��a����+z|���P�~����>���C|��c4���C|z�2Z0��=�������XE9z��&�*V�/�=<���p�
;���zt�e0I�������u�xYi��a?6��>mM�g�c���2{-#t1�,�p�p�>A>��|�����1B � �=p��d���Nh-�����}������'��y��2���I��oo�g����:�`�0*�z�z�A������6;��Qq���{hb�*�s���q�wo�W,E���}�Dl�G���;�9�q�
��#��eWXE%G8�N�7�C�.��}��o����?���_�_k�����g!����p���~�D"���Q���ey��if�?��	6\��}���w���o�|������.���?~���v��������7�������w?���w�l����>����V������y�w���$vz��\}�������/���xm��S����������/����X��M��2��L�������h���W�S��k��NO�U3�������W���6�G��u4����(L������I9I"l�D8mH<`�zIRa�P�W2����e�:��MJa������6my1#����?�����������_Q_?u���v���nW��q&!�.�3���8a��Loe�='lg�$3����Z��C6m[o�fvh����cv��$�ND���K����A�����Ld����S��O�f
J�U����H��B���U�`�f&"��U��P����,yq�����2	������Ivp��<��D�p�����k{=��~����cMF��#�*H�X�d+�U���<z�D$psJ�8�q	�����r��D$�_���
��S��m��d"���������jc�#�����Ld����
1u�S:�LAb�pj�e\�DC&"��S�,��LC&"��S��:Vd"�93�Mp�5���M���q_�5[���2���l�>��H��mn�g����J�5)�;@NI�\��$�$���)���*I:x�/�Hls&t�k���n�$q)��vpP ��l�^1K�'1��]����=�7�2�5O�iVI2Bk��Ab��J����k��nVI2� 	����4��C&"���tH���H�t��7�Np%���_�������{.�T&���>�Ih��+D�	�B�d�S����d&"��S�3�{d&"qj��I�g�=�o����L:�v(��LD7����������e0��l&�;@K����%��O�\�g�	�����B|��Y	�NMbBC��H�f�$zVd"�9BL���t��n��mJp���+���&n}8,��^�[�������3�W���4�&Z�kz�Cw��IF[��f"�[VM2P���nVM2�2���H���:��)��e"�I;�E'-��p�(�D6qv�-m����l��*l� �
arQ+�D�#��I���3���I��`��,��ZNMb�P����n������F&"���In����J-��lf��_�&m�:9@���w����j����mNMb�Rd��95��PL��H���$6@5E&"��U�D(��D$p���$��Iv��pg"���aQ�hx\s�R����U�3��<�G�U�`�LAb��j�A�m�*A�&UY
��H�f�$�\��d"�9�v�"���� O�&��*���";��p��������6�F���FW���Q����cMK/b!B������N� QS��IZ��-�2	������>d&"���$�5p�?��M��u*��;%��
ex��lg��e���/����zQm���vF&���>��SWH��3���I��o�^HzNM�z[j�LD7�&i�)5I&"��3��F]j�LD���VX��X.;E,m��b�Ld���Q�|�i��S���K��j����B���^��w2���I�y*�:����I���7"�9����;��M�$��V���4��D�p��QY m�Z��T�{60��F��K<>���d���������$������BNI�4��D$psJ�[]S�[E!�iI�$I��$q��y�Ld;�}X�D���VW{�Tq[S�e&���>,Ih��+�����$V�$Y��Rlg"�9%�5+q'"�9%��
Vv""��3��BS�8��n��R��)bqa�'�Lpw�����VX{�TaG(��<V��= �&�Sy�9H�VM��=����"�&��2n�D$z�4�'!n��G02��=^��Z�SZ��Xbg&��W,������+}+�U�^\�&���o����c��K�X&�3�E�*LfxG.3��L|�:g&"�9��Wm��3����m�a3��
�T�r��f�F�"63�~��E5����[��������f"k��x93q�X=f���������.�If"���S�x��'���p��w3���D8M��:[�Sg���$1��w����n�M6��;���D����4"d�	cy�8sY#��$�ex���g�']W����pVy���g&"�i��$O��<B`����3��cm�?!���
�z���v53Y�'O�5�<=��(U��X[��������4�f�'�-��g&"�9�Ih�x83���J�<3N��U�oQ;�-��(��f&[����(Z�Qn�-:��[����Ld�/p!b�.��,u��X;�3����D8�>	v�LLD�s���v�����'m�:�{�t��L���5ZR�)`�������%��j�}S��`�$���qjP����g�'+�LD����^+�LD�s&#B�d&"�i�����S�x� 3�L����V���%��O�+�?��j��#dm��1R&!�HX�	vF
b��k;�����Xk$���4bo� �I���T��w�p#6G�{���Gj���*����?&��f{�g���'QA1C� �HX��F=:.U��hmT������D8�>��+/�D��K�-i�'fG��6��03���(���Kl�����q���"�LV�$kN}����8�,N}=���D8�>�R���pV}!u����LF�R���pZwR�
`�NL�!u��lf���AZwR�b�jZ/���/+\3���qG��Q5��s&!�HX�����3���d��4Df"���$N��g��zi=Ju���;��q��c3�M�O�yKkR��=�ks�*3�������}U��/���Ad�p��Nu�6�����'���6�����'���6��Hg�T�YW��2��
�Ts������<��L��?Q
ClUj�-�|�����Ld���c��O:��?i�lS���D���W2����p�>3����"\��LD�{�$a�sB�up�>3�����hKUP�W��/�d&k���k����&����"a�'�`����*Z�U*���f&�Y��vc����h�8-�����'SW��d&���Z���r�*}���[Ob�vU��P���9�1q� �F8�I���G����k�
\��&3�)Oz���0��p�\D���R�LD���I��Q;�0�5�!Of���RZ�R���N�^
��P��2��8��Z���}���2�Y$���w��(3�Nk�J����g&"�9�Jz�r2���^�R]�S������l'���i���x����z�nc)�3����8���j�'���"a�'���LD������I��T��L�kf&"�9s����R�5���%�����ff�����z�������X���DV�O8BV}2����+b�U��i���D8�>�)���p�d��uy�������=9U&�3�M���U������u��:px�33Yq(��%B�.�Ly�)N�E��O;����D8�>���������'��@-3���|_�9d&�'���~]�j�LF\��5b,�2���}��2��D8�f����!3��C[^��LD��6�TX�v
K���G���f:��S������J����#�d�����G=D��E2�#���"a��g]fQ2������2��������f.�(��p�f�
_�N����r��L6��V���^���������x2��r�Z"d�"�c�3�E���t4C�E�LD�s�����"�LD�s����e%3���.��03N+|M�%�������@f��x]�&6	���N^>u�x"�&���P1I���LBd��������pV}�Y�z�T��f�:�P���H�u	���U����������<���u	UmLf��uz0��d-�|<Pcml:�
|`� �HX����i��D8�>��2
���g�'�X�`�LD�s&#�f(��d&"�I��%�\v
K&�����d�n��������S���%�X�U��J���kD��f�I��Ny2�X�vg&"�9��dC�e&�Y��N�/O�3�4y��J�N]����lf��xY�����%=X/+�4.�DV+=1���d�my.�I�,Ny2�������'S4� �LD������d&"�i��$O��<���`73�N�(�&�����z�������d-~\���5��v�^�Z�f�k:
����n��O���\$��p�&����ff"�31��
��pZ�k*,����
�gd&�	��~��#T�[|��q��Ld5~���5�U4����ad���d�;1��Of��xf"���d���af"����T��w
_���	��d��Gj5�I��!U��+_���3��r��Z"d�"q&d�z���������D8��)x����pN}2������LF�n�g&"�i������SX2w(Pb��q?H����Z>u�#��6D�j�r�X���~�E�H�,V}2�����pV}2v�[R��j�&����f&"�i�$W{��].�������M�J,�����<���f��j�}M}�@eF&!�H8���j��zc"�Q��F��oLD�3����2���pZ2"�����o��%p�Q����V���^\�Z�V_�s[.��d������H�����E��O|�Wo��hZ_S2�Y��$1��O|��F?oLD�3&#|_��~���M�0�^����r�$&�7���Ab��F���S�=�w"�&������k�����"I$$	��)x�r����d����g<,��XV�1N��u����Z]�L�\���_���.���vs��Z����r�$&k���gcS��-h��Ad�p��X�'��pN}��.�If"�S�(�J}����LF�EK%3�N�zI�0�z-�|�OL��X���&��&��O�mJa���f��;B�����%�7"��S��v���/3��'�>3%��D8g2By����p�>I���^��U(���1��j�&�Z����~����
E.���f�'1�r� �FX�I,�R7�i}M��{W���D8�<����H'6	M��������RIL����	�I���Ju��*�I�q&&k	����������ND	�<�5���D8�<�M3�����D7s��3����,��>��q���F�ka��C��d&�	�'� ��i���^?U����#���r�m���8�Y$��D�>�A�������mWF���p����_��/�'&"�I��N���^�����iwf�	��#����T�[���S`��LV��7j����$�2��9�,V}�'����g�'�-�lf"�U��Vwb"�3�UJ��D8�V7��\��0^�
H��d��RClk��-�|���F�oD����Z*f�"��0K��5�V�T�3���D8g_S��	�Ib"�3a��Ib"��OR�����z����d&�	������5���
8�T���F�R�g"k	��q2u�,{L	9qY#����X���pNybl(��D8�<1��������"�<1;��8W���&����Z[��	�bA�T�_���1Y�'O�5�<���%d/U�j8;�.(���j0�pZ'V*�������pVy��qqf"�3a������p�f�R)��)�1�TJ��d��JC�j��������T-Y���Ka����d��,�5�����q,3m��pV}2�`���p��3w�����^'�z�m�>?oL���5Z_S�I�U������%��j��X��\$���"�l�������D8�>��|
���pN}bm��������!�1N+�M�0��R�����l&���Ab[�����������Ld5~�r�b�z*��Y$���BO�7&"�9����JoLD�s&#,�Tzc"��K$����R]=���l�T:������S���l��=��fS�'�����2�E�������\����Z�R��c�oLD����)�~�������4���Of_tg&�������Zo�U����M�01Ym�t|�9�I����}� �H8�I��wg&"�9�I�!u�����'���}f"�3�ZH�g&�i}MU��Q;�0���}f��?�imM�WF�J�*��-�^3���qG���u�<�i�LBd�p�����F�1��OZ?�i��D8�aI���>3N��u*��;��m,��}c�	�������T565�����T3f&+����D��E�E���z�3��U�����D8�><l���pV}2���'&�Y����-Sm��pZ�n��������)Sm���'Ja�mM��e��Ow;O"�z������'�1�Of����+������D8�>q.�g&"�9�N����D8��HV;'������d;~<R��5UA��-���/��1Y���X[�:�X3�E��O\;��Zf"�S�8�X3	��}M���v����%#�>1;���P��d&���Z_����W�Sl=���U��C�*O�/c�LAd�������zZ'V*����0��pVy2��&3���p�.�^3�4y�ja�N-��Ty���l����T�!5��������Ld-N{�������ru'"��U��3x��D8�+�o�5Qf"����+h����'m�:����R]��]Nf��?����^��V���_DO�T2����8���7]�O2�E��O��.���pN}��P���D8�>Y����Yf"�3����lZ_�K~���ff�����z��������7�2�����S��h`�RW���X��;S�e&"�Y�I��,Df"�3���<P�LD��z����\����Zf�	�����������W�S>��w�1Yq(���%B�.�q*���Ad����i�|��0i�X�����������'�� PKLD�s&#��e�Cf�p�?����e�-3q���4W�9d&"�97�E�e��p��>��,s�LD�sF����bDf"������SX�*��3��t�a�bi=B����\?u����oDV����"f�"	�B&!�H87��2����g���Tn���p���#����,�Ih*|5;���`�OL6������^�������=��d������H�� ��e�k����d&"�Y��@&&"�Y����,Jf"�3���E���������NaIT����l?^Wb�MB�����Ow(<YV�K����DCq]&!�H8�I4P������'��r��LD�s&#b����pZ�P�
_�N�kl��53�N'��h]BUS�Y�|�.�q�[�����%B�.7�LD	�>�~�M'1��O�U����$��
��D8g2"v]y}&3N��/����SX�Pf~2�-�O�A�Vo��p�Ov���x����u%D��52D�,	�5�*OF�eb"�U�L���2	��MB�������p�<Iu%j���k��lf��xY�����%=X/+�h\���6Vzb�9�I�Ly.�I�,Ny�i�������'�Q��Tf"�S�tf.af"���H������B���d;~\����^�J��u�]��3���q}����k�r��D	�>����Ql���'����23���$��Ib"�3��P�
��pZ�k*,���t�gd&�	��~��#T�[|��q��Ld5~���5�z���w���Y����`'&"�Y��h�xf"���������D8i����U��v�*�^3�M�����&���T�[�|�f8��LV��7j�����ol:��=k_�^5����D8��)8�`�LD�s��^�
��D8g2�7p�=3N+|M�%������@�L�;+������	��S��n�!RV�����S��m�$�Y$���w��nf"�S��>��ef"�3�x]73N�'	���RXe&�����G(����Cyy&Y���X���Tfd����i�CeFf"�U�P����g�'#Tfd&"�i��d�f�.����g&����RkiMB/�I-p����4�e���C9�H-2u�LsYR�9�,V}2O8��TI	��)��ec��D8�>4��LD�s&#���92��GjS-�������X*���M��~��#���@m��q�e�>YVO����5l,?���"!�5%o}���LD�s����2�����<,<Td&"�I��N��z�Vw���3����H��%t��n����u�0���2����@��������E<���C�J}���g�'}�$1��O��L�d&"�9��0�>IL$����^R-�e�f�2���l��:��MB�MX-�:�	DJ"��?�Y��d�I�,V}2��;��pN}26]y�����LF�
4xf"��OR�����54�L������I�V�7���:�\o4��'��S���;�<��Ny2ZW��d&"�9����R|g&"�9���Ly�73�Nl�����'��e-Lf��?�OhMB��J�:p�{�L����	k_�1�29�9�,Ny2�����pVy�R|g&"�Y�I7�������E��Paf&"�io��Z�S�D7��$&�	�'� ��i���^?u�������U��]y\�I�,V}2���83��O�P�d&�[���S��xb"����T��wju�e�,�Jf�	��#�-�����b���|.�Xe&+���D��E�m�G�D	�>�<I�����'�����LD�s����'�2������K)�������Z��N-��&����=^
����pK�/�*n�d3�5au�����H���K��m��X����$1����t����D8g2b���Frf"��OR��������$1�L��ZZ[S�����M�
�iP��D����4"d�b�g"k�U���03���dre����g�'s�;1N�E$ybv����2��L6�����5�>S�U�T�+�{�L���c�)Of����D	�<������O�ub�7M�)>3�)Of3�!}f"�31����THOkk�R)��)�����������0-����J�������Z&�����1S��,���Z���u��eb"�S��!�Y&&"�9�J�`y'&"�I��N�����d&�	�����)�$p�Uyu=3YK��X[����E�8H,�V���
��pV}2�k��pV}2��gAf"�31��Bf"�V��Ja.;�0��!d&�	��~����������^d�V�{�1���h�X3���@O�7"��Q�,���JoLD�3���@O�7&"�����JoLD��z��R]]/�

�Tzc��S�x�F�k��N����u�i�������Xs�b] ��
o$	g+�����T}CKk�J���1��OB\(�������&}b��$4�5�RIL�3��
���[��r�R��tF�#���6U:>��������8�,V}���NLD�����L��1��O�2u��D8c2b^����H��5U�F�kaB3����j��x)LKkk�]LWM��0���\��i#s��h�<���dC9����"��'�)�~c"�S�(��z���g<,	J�����'m�:���z�nP�|����&�����������T�V7([V3�1Yq(���%B�.��m>sY$��D����3�����XY	<1��O�7�6��H��kT�e�-3N��M�0�z-LPQ����d��0�����2����������^�zb�Y�I���D���Zb+V*��2����//��1���PCy����pb/�$��'�A����7&�������UM�>U�S������@������=I���r�b
j��@-3��Otau'&�9��}}��xf"���H������+�'&���Z_����W�Snl)e3���J���S��tq�8QY#��D[�x+����ub�ou_.��D8�<�N�xb"�3��6��kf"�&OR-����,����53��D)���nCj6\-�	:�2_����iO��pvb]0O�Y&"��U��<x�jM��:�R�wx��D8�Y��;��]�5�S�I��N���^������v9���mimM/�V�{�T�/�\*�F����gu����d�O�E��O&�;1��Of�d����r�5
�)�l�1���0��X*��pZ�n~���.�oL6�O�A�^oZ���V�f��%n��dS=Q���5�-`n��X[��/aY	<1��O���,Df"�3a��L�g&"�i�DH�I���@-3�~�]����T�[���S���;���8����!S���2sY$�������T�Ik�Jcy�-3��O�Pj��p�d��}Y���<��OX7������D`�g_�`F[��2����d�2��D8�f?���!3����)/Fd&"�i�}*,Q;�%������d3�|��8Z�Pmou%�O�*�~#��N>�1S�*����Y$������R����)���>3���[��Y��D8m�O��f����]��g&���?R�hMB/�V�z	��W���x���8��o�!S���"�$	g_�`}(�(��pN}b�+af"�U�����������mgKE���������Na��u� 3�~�����j{K'/�:n���	���%T��E2@q]&!�HX������pV}25���R����K�|��'1�N��S���)|�3�f&������K�jc�0���m��8�����o�!I����D	�>iU_n:��pN}���LCd&"�9�Ikby�=3���hm(��d&"�I��%�\v
K������d�n��������S��a�$k��x]	3u�8_n������'�o��23�)O�`�8-3���$4�������p�<Iu%j����l�����e%��#T��`�����qA&��X���f�'�*��2	�E�*O�����g�'���LD����qA8H��w�&�I��=y2�-���l'��Z���W��c�����rrf��?�OX���s��,u-���5uMfb"�S�8��23���$t��?�LD�s�"�T�
��pZ�k*,���8���f��$�U��_>u�pA,YM�w��}M]kg����02pN}��
0���pN}��.���p���'���'m�:����W���53�~��ZGk�lH���W��>3Yq(���%B�.�8��!2�E��O�q����Z_S*�n�g&"�Y��7�3���7�
��D8��5�\v
K��e��`?��=BcsV���;�iC���/'�5�>�,�DBd�p��x��D8�>���Q���D8g2���u�7&"�i�$W{��)�Uf��?��z������3��j�x�����[���$$	k_S�BeFf"�S�x���pN}�Tfd&"�i��d�f�.�Tf�2�M��_�u�&�������
<�e�Cf��P�?RK�L]$a,sd"��U�Dh����g�']W6��LD�����d&"�9�~ec��D8���T�vja����x2���J�� �Gh�o��������}&�&����a�k�'W&~2	�EB�kJ>�e�'3��OBc��Of"���$(��LD��6{�ju�N�n����3����H��%t��n����u����x��Z�x����4�r/u���i03,��D8�>	v�|�J��v	
�X&~2������R�d&�i]B/���S�H�2���l��:��MB�MX-�:��)��j��#dml�d�I�,V}c��Cf"�U�t���d&"�9��
������T��vju��D2�-��x�Fk���
����{�6�\�C�*O���A��������0��pVy2k���pNyU���L$���&ybv�ITMY��l'���Z������^l�T7*�{�L����	k_��f
��*^Y��F=N|�����T�f(�wf"�S�D��[Of"�3�Xaf&"�io��Z�S](���d3���]5��Z�����`"���r���Cy\�I�,N}�/�2���$���$3�Y����%��D8i���VW����������&����zZ_S�o��J��uc?�W�2��r��Z"d�"ty��9�,V}2��d��pV}25�9wf"�U�LH��D8g2"�#H��D8�V7��\vja�f)��l?^
��mM]�%��O74��D����Z*f�"��P��LBd�p��N��?�L$���5�L,�If"�3��P�H�LD���I��U;��]�K��l&�j���T7�7���:��L�g"k	��q2u�8W������'�o�33�)O�`�33�)O�h�33N�E$yb��������M����������z�n����kf��O�kVy�70����"a�'�\���pZ'V*�a�|���Y��v�P����p�\D7����D8i�W�F���ts<1�~������p����^	��p��������0D��E�7��,u��Y;��*�f�����'���Yf&"�9�Jz�J��LD��6{���=���d&�	�����)�$��p+93YK��X[����Eb��#{�V������D8�>�=�������'}��2����>�k��pZ�n*������^C�L6��� ��i�o	��S�=���3���qG������J���"a�'�S����Y����S����Y����S����i}Mu*��;��=�T��z*��h}MU�)s_���!��o6Uzb�Y[��3�7d�������K�7xZ+V*p|,53��Om�� �b�'�5M���������;3���(���Kl����Ku�JE���6U:>���d���n�9�,N}2���3���dh!u�����'���}f"�31xH�g&�i}MU��Q;�0C��}f��?�imM����i�f��e����f��;B�V�C��4D&!�HX�I�Fg&"�Y�I�{���p���a�����D8i���TW���#<O��l?�����5U�M�����������C9��.2u�LmYA�9�,V}2[�����dlt�j�LD�s��Q�r��L$���5Sf�xb"�V��ja.;�0���T[f���Rb[S�n��S�m�
�Ld���c��OF3��|&!�H8��h���Rw�Y���-\��LD�s&#F��3��^"IX����.�g&�������
*5oQu�^��L�2��5�V�c�V����"a�'1��Zf"�U�t��53����t�[�.��^��i���O��>lYR��l?.Ph}M�'�_�O��A�&&kW��5�<Mg
"k�U�Lj�F�g��ub����&3�*Of(p�LD�s�"�fj�X����J�0j�fRCy���l����T�!5���LZ���Ld-N{������5Q&!�H8��d���g&�i�X��-�&�LD�s��L-���LD��6{�Ju�N����]Nf��?����^��V���������Z�x����uZ��r��E��O�]63���d��I����Y��Nt��LD�s�"�^�?���lzZ_�K~�>4����d3������5�;h5>
��a���&��p���dl4`6RW���X���2���g�'��$�g�k:�C��LD��z�������<P�L6�W����*+�U�^�;+x�33Yq(���%B&.�Yuep�9�,N}2�hx'a�Z�R�_�g�LD�s����2P�LD�s&#��-Sm��#����s���-Sm���������e�-3����A���3������bDf"�3���T�{e&"�i�}*,Q;�%s7z>������Z�Pmou%�Ow_g"����Q3u���<�Y$�����\�x��5�;�������,Jf"�����W�S�:�6��d��Gj�I�%�
_/�Z�����LV��7j��i�d��E��Ab�p�5]�������D8�>���]	<1��Ob������g��cc�*�'&"�i�����R/,��������l?^W�MB�����O��OD�����*f�"qeq�	�E��O�s(�IU��.���e���������/U�h]Bu*|�����������v:�x�F����"�j�kl:��*_��QK�L]$]>0qY$������$&"�Y��|	<1��OF������gLF�fj�xb"���_Ra��^X���r�$&[��p����6�7���:�J�������1��j,l������'J�r��LD�s��N���'&�9��Fe������p�<Iu%�^W���r��-���J�G�6.��jYIT�l\�Fd���c�)O�-����Y$��D��;SoLD�s���>?oLD�s���Rf&"�i��$O��<�>�TOL���
�I��5����
<������%��������e���8��F��'��pV}��2��L$�s6	�jh��$&"�9sj�e����������K��$����xc��?��=B��%��OwyA���j��#��k��G����02pN}���/�'&"�9��N����g&"�9�J�*�8|c"����T�����Q������?RhMB�
�b�Z���c��d������H���cm��9��Fm���RW"h}M��������D���������oLD��
_Sa��^Xu���lwV:��=BcsV������!RV�����U�D�$�Y$���ka�������[vR���&�Q���oLD���I����
��P}]�x]I����-�Cyy&Y���8��F=��o$$	g_����2���pV}2��oLD�s����oLD����.��]5���d��Wj�I��5�n��5�xb��P�?RK�L]$�&S,��Ad�p�c"�ub"�S����j�8��F���~����LF�T	��h����Hm��Q�Z�h�����l�T:��=B}��Ow(3�����z����i\��e�'��X$���D��r������e�'3�yXbz��LD��6{�juu�Vw���v�x�F���k7Gh����1��j���Gj����d�@�$"��U��c���LD����i}���g�'s_&~2����D�'��pZ��K������X�,Jf�}����6	�7a�|��c)R2���qG���4Z]�d�FBd�p�k|�������ZW�O2������LD���I��U;�����D��l��5Z�P�no�]?u���h(r�O5�<��h����Nyb�*��d&"�9���M)�3���$��M��D8�Ih�'fO�t���j�����Z������^?U�=��f&k	�������y,�w� �HX���|�����T�c�;1�*O�[Ob"�3ag_�d&"�io��Z�S�6���d3���]5��Z�����`&���r��V���8�Y$����m��g&"�9�IkLyL����}MckuY����'m�:����Z��U�iwf�	��#����T�[����b����+V���C9�F-2u���<��D	�>i�\��3�������doLD�s��6���LD�s&#���R63N��M�0��Z���J)��l?^
�mM]�%��Ow�H�����:^C�L\$}����!��X���X���L$���5mG�$1���h'W�g&"�i�$����Z�vn��$&�	���Z��5���
����{(���Z�p�F�L\#��e0�9��Ny���|1���pNy��.��D8�<q�)��D8-�����'���yZf�	��#�����bB�XP/�uv,�^3�5}��Xs�g�2��D	�<q�X���pZ'V*p7�����pNy�|W����p�\���#���'m�*����RC)�3�-��+a"����J��0.��Z&�����1SI�,���Zd���zf���g�'Cf����<+q��LLD��6{���=����L���5Z_S�I���Vrf��?���bu��E2I�G���X}�
��pN}��o�LD�s���5��D8g2�kx
!3N+�M�0��Ro�5��d3~������_>u�cy�:YM�w���X=�T�$D	�>��S���T��}M=�T�b=�"k_S�=��XO�H�k�S���)���S���T:����^;
~�>u�����M��k�V�>B}C� �HX[�������D8�>��R���g�'�.s�^���H�k�����'cStg&������t�-Ss�z����x*3Ym�t|�Y��8�Y&"��U�L�����d��}f"�S��R���p�dDP���L$�����T�vja���}f��?�imM����i�&hh���f��;B�V����ub&!�H8�I��<n�LD�s�����^of"���$�������'m�:����R���y��d��wu#����}�W�S�����C9��.2u�SV�g"��S��%h.�:1��O��L�e&"�Y�I7�6��Hg�k��<��LD��juS-�e�&C�j�L��?Q
Clkj�-�|���
�Ld���c��O����3	�E��O����D8�>���}f"�3�t���'�I�j��>*�t��lg��Gj���*���E��kx�'3Y���X[�F
�X3�E��O�qe������'�B+��D8k_�%^-���D8-�����'���%��d�q�B�kz=Q�*}��}SJ��d�������'���1q� �F8�I�s�d�LD�s��E�x>Ke�X�����p�\D����'3N�'�F�����+�^3�-�O������6�f��R�8��L��ND���'jaX;��Ze"��U��<� ��(�:�R�O��(3�yVgh����'m�:����R���v9��v�x�Fkkz���U�T�������Z�x�����S��'���"��'��.���pN}�U���D8�>�,t��LD�s�":�R��pZ�n~����"�L6�O�A�^oZ���V��k�;���j�	G��O:7�j���"!�b%�C��LD�s��.�e"3�������\*��pZ/�s�]���d��wu#�����b���
���;3��r�Y]"d�"�C\f"��U�^� a�Z�R��m�j�LD�������Zf"�3���L�e&�'����o��D`�U����WM�k�Td�sn������LE9�~��q��P����3���P�|e*2�i;~�.Q;�%�����Le3�|��,�i�7������o����d5�|8��������g2��s���-PJ�R=����~�C��g*2�9��>�2���� ����������-��Le���jUCkz	�"�������y2��r��Z*f�:��Rf"����i��6�h'*2�Y���A&*2�Y���@&*2�9C�~���J�"��V
�JM.;�&�4�>LT���4Y���}mo��S>+������:^kBM\'3�f2��S����T5���S�
�a3��9�A�����rZ�P�
b�NA�`� 6S�N3?�����6���^;X]�3��<��k�����f2��S��/w�LE9�V�+���rN�2,�{�Z��9�!��rM�"����_R��e��d��L	e*[�����]�6�7���:nk%YY��N�������m&2��U��
��DE9�T�2t�TD��6���2�4���O�N��0�e'�Le����8�v�qI��O�	�d&����mV�2A;��Bf��J����Td�sJ����@��rN�2^�Y�G��� ��(�T1;Re���?S�N�?!Vh
E/^�������E�Le-A��Vam�:_�����:��*�mg@���MN�2��:3��MEGg��$*2�9S��e ��� �U��R��N)���#S�L�?��mE��%��O8�)�LV�O�C�^�clz��}2:rV��2A��� g�*���,� g�-:��2b�"�����T0�w
f��/i3�M���]���}eC*�����#�g*+n����T��u���r�G��|����;@��]���D�"���{�"��S�L
\�Td�s�(&��3����T�r��K�4��Le�1�qwH�1���Z>u�-��e��9}�9��d,���Bf�pj�������rN�2���73��9������r�VI��.rx�7S���?��:���&��`"3Y��?���G�<�wd"���?���#S�A��U"�wd*2�Y�J���rZ�"��3��+sY��&���.�i��&����N�+K%2��r��[*f�:b��#��Y'�Ze��A��rV�2���G�"��U���8(S�A����3�����A�i�����SR3+]^j�T6/7=��mG}���O�+S�����z����W��u��,D�	�Y*y:z�C��� ��*��K��Td�s���^��Td���}���N���B�A���!"x��]���?4������_���!"vcm�:���*���:��*����P�"��S���+�J�"��U��Pf�2��9����U��&��TRs�)��{W�?�T��ew��&�����O�����f������S��J�,d�	�V����LE9�V�l�W�Td�s�(�5y�"���UR�����vM�J2�-�������T��Ks�Ox(�����W��6�T�����
�TY���E�7*2��J����Y�"6g;��1�*WK�"����4IS�*]c��D��l'���*���{���~��������Z��	���Du��M%�V�����j����NL����R��`���� g�*��/���� gLQt�
��DE9�U�TR��%5]�Y�����3��vK5����:pt���j����Uz��+����Ze0��'*2�Y����r�$*�g7����P"OTd���}��u��wA>�r�$*���?�� '��J����*�9@>o=>��h�j��|����:��*�
 �z
mA��U�*�C{�"��S�(���6S�A����S&��6S��T���R����|��7����~���b�W����J"�p����~q��t�_��q�Q?k������k���w_�F1]�Rp��r4]��3����S��ed�����R�fmc������O�~�����~����_?����O�~�����~����_?����O�~�����~�������nD��p
#183Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Bharath Rupireddy (#169)
Re: Parallel copy

On Fri, Oct 9, 2020 at 2:52 PM Bharath Rupireddy <
bharath.rupireddyforpostgres@gmail.com> wrote:

On Tue, Sep 29, 2020 at 6:30 PM Amit Kapila <amit.kapila16@gmail.com>

wrote:

2. Do we have tests for toast tables? I think if you implement the
previous point some existing tests might cover it but I feel we should
have at least one or two tests for the same.

Toast table use case 1: 10000 tuples, 9.6GB data, 3 indexes 2 on integer

columns, 1 on text column(not the toast column), csv file, each row is >
1320KB:

(222.767, 0, 1X), (134.171, 1, 1.66X), (93.749, 2, 2.38X), (93.672, 4,

2.38X), (94.827, 8, 2.35X), (93.766, 16, 2.37X), (98.153, 20, 2.27X),
(122.721, 30, 1.81X)

Toast table use case 2: 100000 tuples, 96GB data, 3 indexes 2 on integer

columns, 1 on text column(not the toast column), csv file, each row is >
1320KB:

(2255.032, 0, 1X), (1358.628, 1, 1.66X), (901.170, 2, 2.5X), (912.743, 4,

2.47X), (988.718, 8, 2.28X), (938.000, 16, 2.4X), (997.556, 20, 2.26X),
(1000.586, 30, 2.25X)

Toast table use case3: 10000 tuples, 9.6GB, no indexes, binary file, each

row is > 1320KB:

(136.983, 0, 1X), (136.418, 1, 1X), (81.896, 2, 1.66X), (62.929, 4,

2.16X), (52.311, 8, 2.6X), (40.032, 16, 3.49X), (44.097, 20, 3.09X),
(62.310, 30, 2.18X)

In the case of a Toast table, we could achieve upto 2.5X for csv files,

and 3.5X for binary files. We are analyzing this point and will post an
update on our findings soon.

I analyzed the above point of getting only upto 2.5X performance
improvement for csv files with a toast table with 3 indexers - 2 on integer
columns and 1 on text column(not the toast column). Reason is that workers
are fast enough to do the work and they are waiting for the leader to fill
in the data blocks and in this case the leader is able to serve the workers
at its maximum possible speed. Hence most of the time the workers are
waiting not doing any beneficial work.

Having observed the above point, I tried to make workers perform more work
to avoid waiting time. For this, I added a gist index on the toasted text
column. The use and results are as follows.

Toast table use case4: 10000 tuples, 9.6GB, 4 indexes - 2 on integer
columns, 1 on non-toasted text column and 1 gist index on toasted text
column, csv file, each row is ~ 12.2KB:

(1322.839, 0, 1X), (1261.176, 1, 1.05X), (632.296, 2, 2.09X), (321.941, 4,
4.11X), (181.796, 8, 7.27X), *(105.750, 16, 12.51X)*, (107.099, 20,
12.35X), (123.262, 30, 10.73X)

With Regards,
Bharath Rupireddy.
EnterpriseDB: http://www.enterprisedb.com

#184vignesh C
vignesh21@gmail.com
In reply to: Amit Kapila (#181)
6 attachment(s)
Re: Parallel copy

On Mon, Oct 19, 2020 at 2:40 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Sun, Oct 18, 2020 at 7:47 AM Hou, Zhijie <houzj.fnst@cn.fujitsu.com> wrote:

Hi Vignesh,

After having a look over the patch,
I have some suggestions for
0003-Allow-copy-from-command-to-process-data-from-file.patch.

1.

+static uint32
+EstimateCstateSize(ParallelContext *pcxt, CopyState cstate, List *attnamelist,
+                                  char **whereClauseStr, char **rangeTableStr,
+                                  char **attnameListStr, char **notnullListStr,
+                                  char **nullListStr, char **convertListStr)
+{
+       uint32          strsize = MAXALIGN(sizeof(SerializedParallelCopyState));
+
+       strsize += EstimateStringSize(cstate->null_print);
+       strsize += EstimateStringSize(cstate->delim);
+       strsize += EstimateStringSize(cstate->quote);
+       strsize += EstimateStringSize(cstate->escape);

It use function EstimateStringSize to get the strlen of null_print, delim, quote and escape.
But the length of null_print seems has been stored in null_print_len.
And delim/quote/escape must be 1 byte, so I think call strlen again seems unnecessary.

How about " strsize += sizeof(uint32) + cstate->null_print_len + 1"

+1. This seems like a good suggestion but add comments for
delim/quote/escape to indicate that we are considering one-byte for
each. I think this will obviate the need of function
EstimateStringSize. Another thing in this regard is that we normally
use add_size function to compute the size but I don't see that being
used in this and nearby computation. That helps us to detect overflow
of addition if any.

EstimateCstateSize()
{
..
+
+ strsize++;
..
}

Why do we need this additional one-byte increment? Does it make sense
to add a small comment for the same?

Changed it to handle null_print, delim, quote & escape accordingly in
the attached patch, the one byte increment is not required, I have
removed it.

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

Attachments:

v8-0001-Copy-code-readjustment-to-support-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=v8-0001-Copy-code-readjustment-to-support-parallel-copy.patchDownload
From 67c99a6ad1559af2a760651a1b4d550b5ba094a4 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Tue, 13 Oct 2020 18:29:58 +0530
Subject: [PATCH v8 1/6] Copy code readjustment to support parallel copy.

This patch has the copy code slightly readjusted so that the common code is
separated to functions/macros, these functions/macros will be used by the
workers in the parallel copy code of the upcoming patches. EOL removal is moved
from CopyReadLine to CopyReadLineText, this change was required because in case
of parallel copy the record identification and record updation is done in
CopyReadLineText, before record information is updated in shared memory the new
line characters should be removed.
---
 src/backend/commands/copy.c | 335 ++++++++++++++++++++++++++------------------
 1 file changed, 199 insertions(+), 136 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 36ddcdc..f6a63ac 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -95,6 +95,9 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
+#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+#define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
+
 /*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
@@ -224,7 +227,6 @@ typedef struct CopyStateData
 	 * appropriate amounts of data from this buffer.  In both modes, we
 	 * guarantee that there is a \0 at raw_buf[raw_buf_len].
 	 */
-#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
@@ -288,7 +290,6 @@ typedef struct CopyMultiInsertInfo
 	int			ti_options;		/* table insert options */
 } CopyMultiInsertInfo;
 
-
 /*
  * These macros centralize code used to process line_buf and raw_buf buffers.
  * They are macros because they often do continue/break control and to avoid
@@ -401,6 +402,12 @@ static bool CopyGetInt16(CopyState cstate, int16 *val);
 static bool CopyLoadRawBuf(CopyState cstate);
 static int	CopyReadBinaryData(CopyState cstate, char *dest, int nbytes);
 
+static void PopulateCommonCstateInfo(CopyState cstate, TupleDesc tup_desc,
+									 List *attnamelist);
+static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
+								   int copy_line_pos, int *copy_line_size);
+static void ConvertToServerEncoding(CopyState cstate);
+
 
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
@@ -1518,7 +1525,6 @@ BeginCopy(ParseState *pstate,
 {
 	CopyState	cstate;
 	TupleDesc	tupDesc;
-	int			num_phys_attrs;
 	MemoryContext oldcontext;
 
 	/* Allocate workspace and zero all fields */
@@ -1684,6 +1690,25 @@ BeginCopy(ParseState *pstate,
 		tupDesc = cstate->queryDesc->tupDesc;
 	}
 
+	PopulateCommonCstateInfo(cstate, tupDesc, attnamelist);
+	cstate->copy_dest = COPY_FILE;	/* default */
+
+	MemoryContextSwitchTo(oldcontext);
+
+	return cstate;
+}
+
+/*
+ * PopulateCommonCstateInfo
+ *
+ * Populates the common variables required for copy from operation. This is a
+ * helper function for BeginCopy function.
+ */
+static void
+PopulateCommonCstateInfo(CopyState cstate, TupleDesc tupDesc, List *attnamelist)
+{
+	int			num_phys_attrs;
+
 	/* Generate or convert list of attributes to process */
 	cstate->attnumlist = CopyGetAttnums(tupDesc, cstate->rel, attnamelist);
 
@@ -1803,12 +1828,6 @@ BeginCopy(ParseState *pstate,
 		 pg_database_encoding_max_length() > 1);
 	/* See Multibyte encoding comment above */
 	cstate->encoding_embeds_ascii = PG_ENCODING_IS_CLIENT_ONLY(cstate->file_encoding);
-
-	cstate->copy_dest = COPY_FILE;	/* default */
-
-	MemoryContextSwitchTo(oldcontext);
-
-	return cstate;
 }
 
 /*
@@ -2698,32 +2717,13 @@ CopyMultiInsertInfoStore(CopyMultiInsertInfo *miinfo, ResultRelInfo *rri,
 }
 
 /*
- * Copy FROM file to relation.
+ * CheckTargetRelValidity
+ *
+ * Check if the relation specified in copy from is valid.
  */
-uint64
-CopyFrom(CopyState cstate)
+static void
+CheckTargetRelValidity(CopyState cstate)
 {
-	ResultRelInfo *resultRelInfo;
-	ResultRelInfo *target_resultRelInfo;
-	ResultRelInfo *prevResultRelInfo = NULL;
-	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
-	ModifyTableState *mtstate;
-	ExprContext *econtext;
-	TupleTableSlot *singleslot = NULL;
-	MemoryContext oldcontext = CurrentMemoryContext;
-
-	PartitionTupleRouting *proute = NULL;
-	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
-	int			ti_options = 0; /* start with default options for insert */
-	BulkInsertState bistate = NULL;
-	CopyInsertMethod insertMethod;
-	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
-	uint64		processed = 0;
-	bool		has_before_insert_row_trig;
-	bool		has_instead_insert_row_trig;
-	bool		leafpart_use_multi_insert = false;
-
 	Assert(cstate->rel);
 	Assert(list_length(cstate->range_table) == 1);
 
@@ -2761,27 +2761,6 @@ CopyFrom(CopyState cstate)
 							RelationGetRelationName(cstate->rel))));
 	}
 
-	/*
-	 * If the target file is new-in-transaction, we assume that checking FSM
-	 * for free space is a waste of time.  This could possibly be wrong, but
-	 * it's unlikely.
-	 */
-	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
-		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
-		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
-		ti_options |= TABLE_INSERT_SKIP_FSM;
-
-	/*
-	 * Optimize if new relfilenode was created in this subxact or one of its
-	 * committed children and we won't see those rows later as part of an
-	 * earlier scan or command. The subxact test ensures that if this subxact
-	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
-	 * that the stronger test of exactly which subtransaction created it is
-	 * crucial for correctness of this optimization. The test for an earlier
-	 * scan or command tolerates false negatives. FREEZE causes other sessions
-	 * to see rows they would not see under MVCC, and a false negative merely
-	 * spreads that anomaly to the current session.
-	 */
 	if (cstate->freeze)
 	{
 		/*
@@ -2819,9 +2798,61 @@ CopyFrom(CopyState cstate)
 			ereport(ERROR,
 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 					 errmsg("cannot perform COPY FREEZE because the table was not created or truncated in the current subtransaction")));
+	}
+}
+
+/*
+ * Copy FROM file to relation.
+ */
+uint64
+CopyFrom(CopyState cstate)
+{
+	ResultRelInfo *resultRelInfo;
+	ResultRelInfo *target_resultRelInfo;
+	ResultRelInfo *prevResultRelInfo = NULL;
+	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
+	ModifyTableState *mtstate;
+	ExprContext *econtext;
+	TupleTableSlot *singleslot = NULL;
+	MemoryContext oldcontext = CurrentMemoryContext;
+
+	PartitionTupleRouting *proute = NULL;
+	ErrorContextCallback errcallback;
+	CommandId	mycid = GetCurrentCommandId(true);
+	int			ti_options = 0; /* start with default options for insert */
+	BulkInsertState bistate = NULL;
+	CopyInsertMethod insertMethod;
+	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
+	uint64		processed = 0;
+	bool		has_before_insert_row_trig;
+	bool		has_instead_insert_row_trig;
+	bool		leafpart_use_multi_insert = false;
+
+	CheckTargetRelValidity(cstate);
+
+	/*
+	 * If the target file is new-in-transaction, we assume that checking FSM
+	 * for free space is a waste of time.  This could possibly be wrong, but
+	 * it's unlikely.
+	 */
+	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
+		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
+		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
+		ti_options |= TABLE_INSERT_SKIP_FSM;
 
+	/*
+	 * Optimize if new relfilenode was created in this subxact or one of its
+	 * committed children and we won't see those rows later as part of an
+	 * earlier scan or command. The subxact test ensures that if this subxact
+	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
+	 * that the stronger test of exactly which subtransaction created it is
+	 * crucial for correctness of this optimization. The test for an earlier
+	 * scan or command tolerates false negatives. FREEZE causes other sessions
+	 * to see rows they would not see under MVCC, and a false negative merely
+	 * spreads that anomaly to the current session.
+	 */
+	if (cstate->freeze)
 		ti_options |= TABLE_INSERT_FROZEN;
-	}
 
 	/*
 	 * We need a ResultRelInfo so we can use the regular executor's
@@ -3342,26 +3373,13 @@ CopyFrom(CopyState cstate)
 }
 
 /*
- * Setup to read tuples from a file for COPY FROM.
+ * PopulateCstateCatalogInfo
  *
- * 'rel': Used as a template for the tuples
- * 'filename': Name of server-local file to read
- * 'attnamelist': List of char *, columns to include. NIL selects all cols.
- * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
- *
- * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ * Populate the cstate catalog information.
  */
-CopyState
-BeginCopyFrom(ParseState *pstate,
-			  Relation rel,
-			  const char *filename,
-			  bool is_program,
-			  copy_data_source_cb data_source_cb,
-			  List *attnamelist,
-			  List *options)
+static void
+PopulateCstateCatalogInfo(CopyState cstate)
 {
-	CopyState	cstate;
-	bool		pipe = (filename == NULL);
 	TupleDesc	tupDesc;
 	AttrNumber	num_phys_attrs,
 				num_defaults;
@@ -3371,38 +3389,8 @@ BeginCopyFrom(ParseState *pstate,
 	Oid			in_func_oid;
 	int		   *defmap;
 	ExprState **defexprs;
-	MemoryContext oldcontext;
 	bool		volatile_defexprs;
 
-	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
-	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
-
-	/* Initialize state variables */
-	cstate->reached_eof = false;
-	cstate->eol_type = EOL_UNKNOWN;
-	cstate->cur_relname = RelationGetRelationName(cstate->rel);
-	cstate->cur_lineno = 0;
-	cstate->cur_attname = NULL;
-	cstate->cur_attval = NULL;
-
-	/*
-	 * Set up variables to avoid per-attribute overhead.  attribute_buf and
-	 * raw_buf are used in both text and binary modes, but we use line_buf
-	 * only in text mode.
-	 */
-	initStringInfo(&cstate->attribute_buf);
-	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
-	cstate->raw_buf_index = cstate->raw_buf_len = 0;
-	if (!cstate->binary)
-	{
-		initStringInfo(&cstate->line_buf);
-		cstate->line_buf_converted = false;
-	}
-
-	/* Assign range table, we'll need it in CopyFrom. */
-	if (pstate)
-		cstate->range_table = pstate->p_rtable;
-
 	tupDesc = RelationGetDescr(cstate->rel);
 	num_phys_attrs = tupDesc->natts;
 	num_defaults = 0;
@@ -3480,6 +3468,61 @@ BeginCopyFrom(ParseState *pstate,
 	cstate->defexprs = defexprs;
 	cstate->volatile_defexprs = volatile_defexprs;
 	cstate->num_defaults = num_defaults;
+}
+
+/*
+ * Setup to read tuples from a file for COPY FROM.
+ *
+ * 'rel': Used as a template for the tuples
+ * 'filename': Name of server-local file to read
+ * 'attnamelist': List of char *, columns to include. NIL selects all cols.
+ * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
+ *
+ * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ */
+CopyState
+BeginCopyFrom(ParseState *pstate,
+			  Relation rel,
+			  const char *filename,
+			  bool is_program,
+			  copy_data_source_cb data_source_cb,
+			  List *attnamelist,
+			  List *options)
+{
+	CopyState	cstate;
+	bool		pipe = (filename == NULL);
+	MemoryContext oldcontext;
+
+	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	/* Initialize state variables */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/*
+	 * Set up variables to avoid per-attribute overhead.  attribute_buf is
+	 * used in both text and binary modes, but we use line_buf and raw_buf
+	 * only in text mode.
+	 */
+	initStringInfo(&cstate->attribute_buf);
+	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+	if (!cstate->binary)
+	{
+		initStringInfo(&cstate->line_buf);
+		cstate->line_buf_converted = false;
+	}
+
+	/* Assign range table, we'll need it in CopyFrom. */
+	if (pstate)
+		cstate->range_table = pstate->p_rtable;
+
+	PopulateCstateCatalogInfo(cstate);
 	cstate->is_program = is_program;
 
 	if (data_source_cb)
@@ -3889,40 +3932,60 @@ CopyReadLine(CopyState cstate)
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
-	else
+
+	ConvertToServerEncoding(cstate);
+	return result;
+}
+
+/*
+ * ClearEOLFromCopiedData
+ *
+ * Clear EOL from the copied data.
+ */
+static void
+ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
+					   int copy_line_pos, int *copy_line_size)
+{
+	/*
+	 * If we didn't hit EOF, then we must have transferred the EOL marker to
+	 * line_buf along with the data.  Get rid of it.
+	 */
+	switch (cstate->eol_type)
 	{
-		/*
-		 * If we didn't hit EOF, then we must have transferred the EOL marker
-		 * to line_buf along with the data.  Get rid of it.
-		 */
-		switch (cstate->eol_type)
-		{
-			case EOL_NL:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CR:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\r');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CRNL:
-				Assert(cstate->line_buf.len >= 2);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 2] == '\r');
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len -= 2;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_UNKNOWN:
-				/* shouldn't get here */
-				Assert(false);
-				break;
-		}
+		case EOL_NL:
+			Assert(*copy_line_size >= 1);
+			Assert(copy_line_data[copy_line_pos - 1] == '\n');
+			copy_line_data[copy_line_pos - 1] = '\0';
+			(*copy_line_size)--;
+			break;
+		case EOL_CR:
+			Assert(*copy_line_size >= 1);
+			Assert(copy_line_data[copy_line_pos - 1] == '\r');
+			copy_line_data[copy_line_pos - 1] = '\0';
+			(*copy_line_size)--;
+			break;
+		case EOL_CRNL:
+			Assert(*copy_line_size >= 2);
+			Assert(copy_line_data[copy_line_pos - 2] == '\r');
+			Assert(copy_line_data[copy_line_pos - 1] == '\n');
+			copy_line_data[copy_line_pos - 2] = '\0';
+			*copy_line_size -= 2;
+			break;
+		case EOL_UNKNOWN:
+			/* shouldn't get here */
+			Assert(false);
+			break;
 	}
+}
 
+/*
+ * ConvertToServerEncoding
+ *
+ * Convert contents to server encoding.
+ */
+static void
+ConvertToServerEncoding(CopyState cstate)
+{
 	/* Done reading the line.  Convert it to server encoding. */
 	if (cstate->need_transcoding)
 	{
@@ -3939,11 +4002,8 @@ CopyReadLine(CopyState cstate)
 			pfree(cvt);
 		}
 	}
-
 	/* Now it's safe to use the buffer in error messages */
 	cstate->line_buf_converted = true;
-
-	return result;
 }
 
 /*
@@ -4306,6 +4366,9 @@ not_end_of_copy:
 	 * Transfer any still-uncopied data to line_buf.
 	 */
 	REFILL_LINEBUF;
+	if (!result && !IsHeaderLine())
+		ClearEOLFromCopiedData(cstate, cstate->line_buf.data,
+							   cstate->line_buf.len, &cstate->line_buf.len);
 
 	return result;
 }
-- 
1.8.3.1

v8-0002-Framework-for-leader-worker-in-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=v8-0002-Framework-for-leader-worker-in-parallel-copy.patchDownload
From 421c4b191410a141ec95132c38d9a63fb2695bd9 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 7 Oct 2020 17:18:17 +0530
Subject: [PATCH v8 2/6] Framework for leader/worker in parallel copy

This patch has the framework for data structures in parallel copy, leader
initialization, worker initialization, shared memory updation, starting workers,
wait for workers and workers exiting.
---
 src/backend/access/transam/parallel.c |   4 +
 src/backend/commands/copy.c           | 235 ++++++--------------
 src/include/commands/copy.h           | 389 +++++++++++++++++++++++++++++++++-
 src/tools/pgindent/typedefs.list      |   7 +
 4 files changed, 468 insertions(+), 167 deletions(-)

diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index b042696..a3cff4b 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -25,6 +25,7 @@
 #include "catalog/pg_enum.h"
 #include "catalog/storage.h"
 #include "commands/async.h"
+#include "commands/copy.h"
 #include "executor/execParallel.h"
 #include "libpq/libpq.h"
 #include "libpq/pqformat.h"
@@ -145,6 +146,9 @@ static const struct
 	},
 	{
 		"parallel_vacuum_main", parallel_vacuum_main
+	},
+	{
+		"ParallelCopyMain", ParallelCopyMain
 	}
 };
 
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index f6a63ac..99f7c9b 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -29,7 +29,6 @@
 #include "catalog/pg_type.h"
 #include "commands/copy.h"
 #include "commands/defrem.h"
-#include "commands/trigger.h"
 #include "executor/execPartition.h"
 #include "executor/executor.h"
 #include "executor/nodeModifyTable.h"
@@ -63,29 +62,6 @@
 #define OCTVALUE(c) ((c) - '0')
 
 /*
- * Represents the different source/dest cases we need to worry about at
- * the bottom level
- */
-typedef enum CopyDest
-{
-	COPY_FILE,					/* to/from file (or a piped program) */
-	COPY_OLD_FE,				/* to/from frontend (2.0 protocol) */
-	COPY_NEW_FE,				/* to/from frontend (3.0 protocol) */
-	COPY_CALLBACK				/* to/from callback function */
-} CopyDest;
-
-/*
- *	Represents the end-of-line terminator type of the input
- */
-typedef enum EolType
-{
-	EOL_UNKNOWN,
-	EOL_NL,
-	EOL_CR,
-	EOL_CRNL
-} EolType;
-
-/*
  * Represents the heap insert method to be used during COPY FROM.
  */
 typedef enum CopyInsertMethod
@@ -95,145 +71,10 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
-#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+#define IsParallelCopy()		(cstate->is_parallel)
+#define IsLeader()				(cstate->pcdata->is_leader)
 #define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
 
-/*
- * This struct contains all the state variables used throughout a COPY
- * operation. For simplicity, we use the same struct for all variants of COPY,
- * even though some fields are used in only some cases.
- *
- * Multi-byte encodings: all supported client-side encodings encode multi-byte
- * characters by having the first byte's high bit set. Subsequent bytes of the
- * character can have the high bit not set. When scanning data in such an
- * encoding to look for a match to a single-byte (ie ASCII) character, we must
- * use the full pg_encoding_mblen() machinery to skip over multibyte
- * characters, else we might find a false match to a trailing byte. In
- * supported server encodings, there is no possibility of a false match, and
- * it's faster to make useless comparisons to trailing bytes than it is to
- * invoke pg_encoding_mblen() to skip over them. encoding_embeds_ascii is true
- * when we have to do it the hard way.
- */
-typedef struct CopyStateData
-{
-	/* low-level state data */
-	CopyDest	copy_dest;		/* type of copy source/destination */
-	FILE	   *copy_file;		/* used if copy_dest == COPY_FILE */
-	StringInfo	fe_msgbuf;		/* used for all dests during COPY TO, only for
-								 * dest == COPY_NEW_FE in COPY FROM */
-	bool		is_copy_from;	/* COPY TO, or COPY FROM? */
-	bool		reached_eof;	/* true if we read to end of copy data (not
-								 * all copy_dest types maintain this) */
-	EolType		eol_type;		/* EOL type of input */
-	int			file_encoding;	/* file or remote side's character encoding */
-	bool		need_transcoding;	/* file encoding diff from server? */
-	bool		encoding_embeds_ascii;	/* ASCII can be non-first byte? */
-
-	/* parameters from the COPY command */
-	Relation	rel;			/* relation to copy to or from */
-	QueryDesc  *queryDesc;		/* executable query to copy from */
-	List	   *attnumlist;		/* integer list of attnums to copy */
-	char	   *filename;		/* filename, or NULL for STDIN/STDOUT */
-	bool		is_program;		/* is 'filename' a program to popen? */
-	copy_data_source_cb data_source_cb; /* function for reading data */
-	bool		binary;			/* binary format? */
-	bool		freeze;			/* freeze rows on loading? */
-	bool		csv_mode;		/* Comma Separated Value format? */
-	bool		header_line;	/* CSV header line? */
-	char	   *null_print;		/* NULL marker string (server encoding!) */
-	int			null_print_len; /* length of same */
-	char	   *null_print_client;	/* same converted to file encoding */
-	char	   *delim;			/* column delimiter (must be 1 byte) */
-	char	   *quote;			/* CSV quote char (must be 1 byte) */
-	char	   *escape;			/* CSV escape char (must be 1 byte) */
-	List	   *force_quote;	/* list of column names */
-	bool		force_quote_all;	/* FORCE_QUOTE *? */
-	bool	   *force_quote_flags;	/* per-column CSV FQ flags */
-	List	   *force_notnull;	/* list of column names */
-	bool	   *force_notnull_flags;	/* per-column CSV FNN flags */
-	List	   *force_null;		/* list of column names */
-	bool	   *force_null_flags;	/* per-column CSV FN flags */
-	bool		convert_selectively;	/* do selective binary conversion? */
-	List	   *convert_select; /* list of column names (can be NIL) */
-	bool	   *convert_select_flags;	/* per-column CSV/TEXT CS flags */
-	Node	   *whereClause;	/* WHERE condition (or NULL) */
-
-	/* these are just for error messages, see CopyFromErrorCallback */
-	const char *cur_relname;	/* table name for error messages */
-	uint64		cur_lineno;		/* line number for error messages */
-	const char *cur_attname;	/* current att for error messages */
-	const char *cur_attval;		/* current att value for error messages */
-
-	/*
-	 * Working state for COPY TO/FROM
-	 */
-	MemoryContext copycontext;	/* per-copy execution context */
-
-	/*
-	 * Working state for COPY TO
-	 */
-	FmgrInfo   *out_functions;	/* lookup info for output functions */
-	MemoryContext rowcontext;	/* per-row evaluation context */
-
-	/*
-	 * Working state for COPY FROM
-	 */
-	AttrNumber	num_defaults;
-	FmgrInfo   *in_functions;	/* array of input functions for each attrs */
-	Oid		   *typioparams;	/* array of element types for in_functions */
-	int		   *defmap;			/* array of default att numbers */
-	ExprState **defexprs;		/* array of default att expressions */
-	bool		volatile_defexprs;	/* is any of defexprs volatile? */
-	List	   *range_table;
-	ExprState  *qualexpr;
-
-	TransitionCaptureState *transition_capture;
-
-	/*
-	 * These variables are used to reduce overhead in COPY FROM.
-	 *
-	 * attribute_buf holds the separated, de-escaped text for each field of
-	 * the current line.  The CopyReadAttributes functions return arrays of
-	 * pointers into this buffer.  We avoid palloc/pfree overhead by re-using
-	 * the buffer on each cycle.
-	 *
-	 * In binary COPY FROM, attribute_buf holds the binary data for the
-	 * current field, but the usage is otherwise similar.
-	 */
-	StringInfoData attribute_buf;
-
-	/* field raw data pointers found by COPY FROM */
-
-	int			max_fields;
-	char	  **raw_fields;
-
-	/*
-	 * Similarly, line_buf holds the whole input line being processed. The
-	 * input cycle is first to read the whole line into line_buf, convert it
-	 * to server encoding there, and then extract the individual attribute
-	 * fields into attribute_buf.  line_buf is preserved unmodified so that we
-	 * can display it in error messages if appropriate.  (In binary mode,
-	 * line_buf is not used.)
-	 */
-	StringInfoData line_buf;
-	bool		line_buf_converted; /* converted to server encoding? */
-	bool		line_buf_valid; /* contains the row being processed? */
-
-	/*
-	 * Finally, raw_buf holds raw data read from the data source (file or
-	 * client connection).  In text mode, CopyReadLine parses this data
-	 * sufficiently to locate line boundaries, then transfers the data to
-	 * line_buf and converts it.  In binary mode, CopyReadBinaryData fetches
-	 * appropriate amounts of data from this buffer.  In both modes, we
-	 * guarantee that there is a \0 at raw_buf[raw_buf_len].
-	 */
-	char	   *raw_buf;
-	int			raw_buf_index;	/* next byte to process */
-	int			raw_buf_len;	/* total # of bytes stored */
-	/* Shorthand for number of unconsumed bytes available in raw_buf */
-#define RAW_BUF_BYTES(cstate) ((cstate)->raw_buf_len - (cstate)->raw_buf_index)
-} CopyStateData;
-
 /* DestReceiver for COPY (query) TO */
 typedef struct
 {
@@ -402,8 +243,6 @@ static bool CopyGetInt16(CopyState cstate, int16 *val);
 static bool CopyLoadRawBuf(CopyState cstate);
 static int	CopyReadBinaryData(CopyState cstate, char *dest, int nbytes);
 
-static void PopulateCommonCstateInfo(CopyState cstate, TupleDesc tup_desc,
-									 List *attnamelist);
 static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
 								   int copy_line_pos, int *copy_line_size);
 static void ConvertToServerEncoding(CopyState cstate);
@@ -1117,6 +956,8 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 
 	if (is_from)
 	{
+		ParallelContext *pcxt = NULL;
+
 		Assert(rel);
 
 		/* check read-only transaction and parallel mode */
@@ -1126,7 +967,35 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 		cstate = BeginCopyFrom(pstate, rel, stmt->filename, stmt->is_program,
 							   NULL, stmt->attlist, stmt->options);
 		cstate->whereClause = whereClause;
-		*processed = CopyFrom(cstate);	/* copy from file to database */
+		cstate->is_parallel = false;
+
+		if (cstate->nworkers > 0)
+			pcxt = BeginParallelCopy(cstate->nworkers, cstate, stmt->attlist,
+									 relid);
+
+		if (pcxt)
+		{
+			int			i;
+
+			ParallelCopyFrom(cstate);
+
+			/* Wait for all copy workers to finish */
+			WaitForParallelWorkersToFinish(pcxt);
+
+			/*
+			 * Next, accumulate WAL usage.  (This must wait for the workers to
+			 * finish, or we might get incomplete data.)
+			 */
+			for (i = 0; i < pcxt->nworkers_launched; i++)
+				InstrAccumParallelQuery(&cstate->pcdata->bufferusage[i],
+										&cstate->pcdata->walusage[i]);
+
+			*processed = pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
+			EndParallelCopy(pcxt);
+		}
+		else
+			*processed = CopyFrom(cstate);	/* copy from file to database */
+
 		EndCopyFrom(cstate);
 	}
 	else
@@ -1177,6 +1046,7 @@ ProcessCopyOptions(ParseState *pstate,
 	cstate->is_copy_from = is_from;
 
 	cstate->file_encoding = -1;
+	cstate->nworkers = -1;
 
 	/* Extract options from the statement node tree */
 	foreach(option, options)
@@ -1347,6 +1217,39 @@ ProcessCopyOptions(ParseState *pstate,
 								defel->defname),
 						 parser_errposition(pstate, defel->location)));
 		}
+		else if (strcmp(defel->defname, "parallel") == 0)
+		{
+			int			val;
+			bool		parsed;
+			char	   *strval;
+
+			if (!cstate->is_copy_from)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("parallel option is supported only for copy from"),
+						 parser_errposition(pstate, defel->location)));
+			if (cstate->nworkers >= 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options"),
+						 parser_errposition(pstate, defel->location)));
+
+			strval = defGetString(defel);
+			parsed = parse_int(strval, &val, 0, NULL);
+			if (!parsed)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("invalid value for integer option \"%s\": %s",
+								defel->defname, strval)));
+			if (val < 1 || val > 1024)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("value %s out of bounds for option \"%s\"",
+								strval, defel->defname),
+						 errdetail("Valid values are between \"%d\" and \"%d\".",
+								   1, 1024)));
+			cstate->nworkers = val;
+		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_SYNTAX_ERROR),
@@ -1702,9 +1605,9 @@ BeginCopy(ParseState *pstate,
  * PopulateCommonCstateInfo
  *
  * Populates the common variables required for copy from operation. This is a
- * helper function for BeginCopy function.
+ * helper function for BeginCopy & InitializeParallelCopyInfo function.
  */
-static void
+void
 PopulateCommonCstateInfo(CopyState cstate, TupleDesc tupDesc, List *attnamelist)
 {
 	int			num_phys_attrs;
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index c639833..cd2d56e 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -14,14 +14,394 @@
 #ifndef COPY_H
 #define COPY_H
 
+#include "access/parallel.h"
+#include "commands/trigger.h"
+#include "executor/executor.h"
 #include "nodes/execnodes.h"
 #include "nodes/parsenodes.h"
 #include "parser/parse_node.h"
 #include "tcop/dest.h"
 
+#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+
+/*
+ * The macros DATA_BLOCK_SIZE, RINGSIZE & MAX_BLOCKS_COUNT stores the records
+ * read from the file that need to be inserted into the relation. These values
+ * help in the handover of multiple records with the significant size of data to
+ * be processed by each of the workers. This also ensures there is no context
+ * switch and the work is fairly distributed among the workers. This number
+ * showed best results in the performance tests.
+ */
+#define DATA_BLOCK_SIZE RAW_BUF_SIZE
+
+/* It can hold 1023 blocks of 64K data in DSM to be processed by the worker. */
+#define MAX_BLOCKS_COUNT 1024
+
+/*
+ * It can hold upto 10240 record information for worker to process. RINGSIZE
+ * should be a multiple of WORKER_CHUNK_COUNT, as wrap around cases is currently
+ * not handled while selecting the WORKER_CHUNK_COUNT by the worker.
+ */
+#define RINGSIZE (10 * 1024)
+
+/*
+ * Each worker will be allocated WORKER_CHUNK_COUNT of records from DSM data
+ * block to process to avoid lock contention. Read RINGSIZE comments before
+ * changing this value.
+ */
+#define WORKER_CHUNK_COUNT 64
+
+/*
+ * Represents the different source/dest cases we need to worry about at
+ * the bottom level
+ */
+typedef enum CopyDest
+{
+	COPY_FILE,					/* to/from file (or a piped program) */
+	COPY_OLD_FE,				/* to/from frontend (2.0 protocol) */
+	COPY_NEW_FE,				/* to/from frontend (3.0 protocol) */
+	COPY_CALLBACK				/* to/from callback function */
+} CopyDest;
+
+/*
+ *	Represents the end-of-line terminator type of the input
+ */
+typedef enum EolType
+{
+	EOL_UNKNOWN,
+	EOL_NL,
+	EOL_CR,
+	EOL_CRNL
+} EolType;
+
+/*
+ * Copy data block information.
+ *
+ * These data blocks are created in DSM. Data read from file will be copied in
+ * these DSM data blocks. The leader process identifies the records and the
+ * record information will be shared to the workers. The workers will insert the
+ * records into the table. There can be one or more number of records in each of
+ * the data block based on the record size.
+ */
+typedef struct ParallelCopyDataBlock
+{
+	/* The number of unprocessed lines in the current block. */
+	pg_atomic_uint32 unprocessed_line_parts;
+
+	/*
+	 * If the current line data is continued into another block,
+	 * following_block will have the position where the remaining data need to
+	 * be read.
+	 */
+	uint32		following_block;
+
+	/*
+	 * This flag will be set, when the leader finds out this block can be read
+	 * safely by the worker. This helps the worker to start processing the
+	 * line early where the line will be spread across many blocks and the
+	 * worker need not wait for the complete line to be processed.
+	 */
+	bool		curr_blk_completed;
+
+	/*
+	 * Few bytes need to be skipped from this block, this will be set when a
+	 * sequence of characters like \r\n is expected, but end of our block
+	 * contained only \r. In this case we copy the data from \r into the new
+	 * block as they have to be processed together to identify end of line.
+	 * Worker will use skip_bytes to know that this data must be skipped from
+	 * this data block.
+	 */
+	uint8		skip_bytes;
+	char		data[DATA_BLOCK_SIZE];	/* data read from file */
+} ParallelCopyDataBlock;
+
+/*
+ * Individual line information.
+ *
+ * ParallelCopyLineBoundary is common data structure between leader & worker.
+ * Leader process will be populating data block, data block offset & the size of
+ * the record in DSM for the workers to copy the data into the relation.
+ * The leader & worker process access the shared line information by following
+ * the below steps to avoid any data corruption or hang:
+ * Leader should operate in the following order:
+ * 1) check if line_size is -1, if line_size is not -1 wait until line_size is
+ * set to -1 by the worker. If line_size is -1 it means worker is still
+ * processing.
+ * 2) set line_state to LINE_LEADER_POPULATING, so that the worker knows that
+ * leader is populating this line.
+ * 3) update first_block, start_offset & cur_lineno in any order.
+ * 4) update line_size.
+ * 5) update line_state to LINE_LEADER_POPULATED.
+ * Worker should operate in the following order:
+ * 1) check line_state is LINE_LEADER_POPULATED, if not it means leader is still
+ * populating the data.
+ * 2) read line_size to know the size of the data.
+ * 3) only one worker should choose one line for processing, this is handled by
+ *    using pg_atomic_compare_exchange_u32, worker will change the state to
+ *    LINE_WORKER_PROCESSING only if line_state is LINE_LEADER_POPULATED.
+ * 4) read first_block, start_offset & cur_lineno in any order.
+ * 5) process line_size data.
+ * 6) update line_size to -1.
+ */
+typedef struct ParallelCopyLineBoundary
+{
+	/* Position of the first block in data_blocks array. */
+	uint32		first_block;
+	uint32		start_offset;	/* start offset of the line */
+
+	/*
+	 * Size of the current line -1 means line is yet to be filled completely,
+	 * 0 means empty line, >0 means line filled with line size data.
+	 */
+	pg_atomic_uint32 line_size;
+	pg_atomic_uint32 line_state;	/* line state */
+	uint64		cur_lineno;		/* line number for error messages */
+} ParallelCopyLineBoundary;
+
+/*
+ * Circular queue used to store the line information.
+ */
+typedef struct ParallelCopyLineBoundaries
+{
+	/* Position for the leader to populate a line. */
+	uint32		pos;
+
+	/* Data read from the file/stdin by the leader process. */
+	ParallelCopyLineBoundary ring[RINGSIZE];
+} ParallelCopyLineBoundaries;
+
+/*
+ * Shared information among parallel copy workers. This will be allocated in the
+ * DSM segment.
+ */
+typedef struct ParallelCopyShmInfo
+{
+	bool		is_read_in_progress;	/* file read status */
+
+	/*
+	 * Actual lines inserted by worker, will not be same as
+	 * total_worker_processed if where condition is specified along with copy.
+	 * This will be the actual records inserted into the relation.
+	 */
+	pg_atomic_uint64 processed;
+
+	/*
+	 * The number of records currently processed by the worker, this will also
+	 * include the number of records that was filtered because of where
+	 * clause.
+	 */
+	pg_atomic_uint64 total_worker_processed;
+	uint64		populated;		/* lines populated by leader */
+	uint32		cur_block_pos;	/* current data block */
+	ParallelCopyDataBlock data_blocks[MAX_BLOCKS_COUNT];	/* data block array */
+	FullTransactionId full_transaction_id;	/* xid for copy from statement */
+	CommandId	mycid;			/* command id */
+	ParallelCopyLineBoundaries line_boundaries; /* line array */
+} ParallelCopyShmInfo;
+
+/*
+ * Parallel copy line buffer information.
+ */
+typedef struct ParallelCopyLineBuf
+{
+	StringInfoData line_buf;
+	uint64		cur_lineno;		/* line number for error messages */
+} ParallelCopyLineBuf;
+
+/*
+ * This structure helps in storing the common data from CopyStateData that are
+ * required by the workers. This information will then be allocated and stored
+ * into the DSM for the worker to retrieve and copy it to CopyStateData.
+ */
+typedef struct SerializedParallelCopyState
+{
+	/* low-level state data */
+	CopyDest	copy_dest;		/* type of copy source/destination */
+	int			file_encoding;	/* file or remote side's character encoding */
+	bool		need_transcoding;	/* file encoding diff from server? */
+	bool		encoding_embeds_ascii;	/* ASCII can be non-first byte? */
+
+	/* parameters from the COPY command */
+	bool		csv_mode;		/* Comma Separated Value format? */
+	bool		header_line;	/* CSV header line? */
+	int			null_print_len; /* length of same */
+	bool		force_quote_all;	/* FORCE_QUOTE *? */
+	bool		convert_selectively;	/* do selective binary conversion? */
+
+	/* Working state for COPY FROM */
+	AttrNumber	num_defaults;
+	Oid			relid;
+} SerializedParallelCopyState;
+
+/*
+ * Parallel copy data information.
+ */
+typedef struct ParallelCopyData
+{
+	Oid			relid;			/* relation id of the table */
+	ParallelCopyShmInfo *pcshared_info; /* common info in shared memory */
+	bool		is_leader;
+
+	WalUsage   *walusage;
+	BufferUsage *bufferusage;
+
+	/* line position which worker is processing */
+	uint32		worker_processed_pos;
+
+	/*
+	 * Local line_buf array, workers will copy it here and release the lines
+	 * for the leader to continue.
+	 */
+	ParallelCopyLineBuf worker_line_buf[WORKER_CHUNK_COUNT];
+	uint32		worker_line_buf_count;	/* Number of lines */
+
+	/* Current position in worker_line_buf */
+	uint32		worker_line_buf_pos;
+} ParallelCopyData;
+
+typedef int (*copy_data_source_cb) (void *outbuf, int minread, int maxread);
+
+/*
+ * This struct contains all the state variables used throughout a COPY
+ * operation. For simplicity, we use the same struct for all variants of COPY,
+ * even though some fields are used in only some cases.
+ *
+ * Multi-byte encodings: all supported client-side encodings encode multi-byte
+ * characters by having the first byte's high bit set. Subsequent bytes of the
+ * character can have the high bit not set. When scanning data in such an
+ * encoding to look for a match to a single-byte (ie ASCII) character, we must
+ * use the full pg_encoding_mblen() machinery to skip over multibyte
+ * characters, else we might find a false match to a trailing byte. In
+ * supported server encodings, there is no possibility of a false match, and
+ * it's faster to make useless comparisons to trailing bytes than it is to
+ * invoke pg_encoding_mblen() to skip over them. encoding_embeds_ascii is true
+ * when we have to do it the hard way.
+ */
+typedef struct CopyStateData
+{
+	/* low-level state data */
+	CopyDest	copy_dest;		/* type of copy source/destination */
+	FILE	   *copy_file;		/* used if copy_dest == COPY_FILE */
+	StringInfo	fe_msgbuf;		/* used for all dests during COPY TO, only for
+								 * dest == COPY_NEW_FE in COPY FROM */
+	bool		is_copy_from;	/* COPY TO, or COPY FROM? */
+	bool		reached_eof;	/* true if we read to end of copy data (not
+								 * all copy_dest types maintain this) */
+	EolType		eol_type;		/* EOL type of input */
+	int			file_encoding;	/* file or remote side's character encoding */
+	bool		need_transcoding;	/* file encoding diff from server? */
+	bool		encoding_embeds_ascii;	/* ASCII can be non-first byte? */
+
+	/* parameters from the COPY command */
+	Relation	rel;			/* relation to copy to or from */
+	QueryDesc  *queryDesc;		/* executable query to copy from */
+	List	   *attnumlist;		/* integer list of attnums to copy */
+	char	   *filename;		/* filename, or NULL for STDIN/STDOUT */
+	bool		is_program;		/* is 'filename' a program to popen? */
+	copy_data_source_cb data_source_cb; /* function for reading data */
+	bool		binary;			/* binary format? */
+	bool		freeze;			/* freeze rows on loading? */
+	bool		csv_mode;		/* Comma Separated Value format? */
+	bool		header_line;	/* CSV header line? */
+	char	   *null_print;		/* NULL marker string (server encoding!) */
+	int			null_print_len; /* length of same */
+	char	   *null_print_client;	/* same converted to file encoding */
+	char	   *delim;			/* column delimiter (must be 1 byte) */
+	char	   *quote;			/* CSV quote char (must be 1 byte) */
+	char	   *escape;			/* CSV escape char (must be 1 byte) */
+	List	   *force_quote;	/* list of column names */
+	bool		force_quote_all;	/* FORCE_QUOTE *? */
+	bool	   *force_quote_flags;	/* per-column CSV FQ flags */
+	List	   *force_notnull;	/* list of column names */
+	bool	   *force_notnull_flags;	/* per-column CSV FNN flags */
+	List	   *force_null;		/* list of column names */
+	bool	   *force_null_flags;	/* per-column CSV FN flags */
+	bool		convert_selectively;	/* do selective binary conversion? */
+	List	   *convert_select; /* list of column names (can be NIL) */
+	bool	   *convert_select_flags;	/* per-column CSV/TEXT CS flags */
+	Node	   *whereClause;	/* WHERE condition (or NULL) */
+
+	/* these are just for error messages, see CopyFromErrorCallback */
+	const char *cur_relname;	/* table name for error messages */
+	uint64		cur_lineno;		/* line number for error messages */
+	const char *cur_attname;	/* current att for error messages */
+	const char *cur_attval;		/* current att value for error messages */
+
+	/*
+	 * Working state for COPY TO/FROM
+	 */
+	MemoryContext copycontext;	/* per-copy execution context */
+
+	/*
+	 * Working state for COPY TO
+	 */
+	FmgrInfo   *out_functions;	/* lookup info for output functions */
+	MemoryContext rowcontext;	/* per-row evaluation context */
+
+	/*
+	 * Working state for COPY FROM
+	 */
+	AttrNumber	num_defaults;
+	FmgrInfo   *in_functions;	/* array of input functions for each attrs */
+	Oid		   *typioparams;	/* array of element types for in_functions */
+	int		   *defmap;			/* array of default att numbers */
+	ExprState **defexprs;		/* array of default att expressions */
+	bool		volatile_defexprs;	/* is any of defexprs volatile? */
+	List	   *range_table;
+	ExprState  *qualexpr;
+
+	TransitionCaptureState *transition_capture;
+
+	/*
+	 * These variables are used to reduce overhead in COPY FROM.
+	 *
+	 * attribute_buf holds the separated, de-escaped text for each field of
+	 * the current line.  The CopyReadAttributes functions return arrays of
+	 * pointers into this buffer.  We avoid palloc/pfree overhead by re-using
+	 * the buffer on each cycle.
+	 *
+	 * In binary COPY FROM, attribute_buf holds the binary data for the
+	 * current field, but the usage is otherwise similar.
+	 */
+	StringInfoData attribute_buf;
+
+	/* field raw data pointers found by COPY FROM */
+
+	int			max_fields;
+	char	  **raw_fields;
+
+	/*
+	 * Similarly, line_buf holds the whole input line being processed. The
+	 * input cycle is first to read the whole line into line_buf, convert it
+	 * to server encoding there, and then extract the individual attribute
+	 * fields into attribute_buf.  line_buf is preserved unmodified so that we
+	 * can display it in error messages if appropriate.  (In binary mode,
+	 * line_buf is not used.)
+	 */
+	StringInfoData line_buf;
+	bool		line_buf_converted; /* converted to server encoding? */
+	bool		line_buf_valid; /* contains the row being processed? */
+
+	/*
+	 * Finally, raw_buf holds raw data read from the data source (file or
+	 * client connection).  In text mode, CopyReadLine parses this data
+	 * sufficiently to locate line boundaries, then transfers the data to
+	 * line_buf and converts it.  In binary mode, CopyReadBinaryData fetches
+	 * appropriate amounts of data from this buffer.  In both modes, we
+	 * guarantee that there is a \0 at raw_buf[raw_buf_len].
+	 */
+	char	   *raw_buf;
+	int			raw_buf_index;	/* next byte to process */
+	int			raw_buf_len;	/* total # of bytes stored */
+	int			nworkers;
+	bool		is_parallel;
+	ParallelCopyData *pcdata;
+	/* Shorthand for number of unconsumed bytes available in raw_buf */
+#define RAW_BUF_BYTES(cstate) ((cstate)->raw_buf_len - (cstate)->raw_buf_index)
+} CopyStateData;
+
 /* CopyStateData is private in commands/copy.c */
 typedef struct CopyStateData *CopyState;
-typedef int (*copy_data_source_cb) (void *outbuf, int minread, int maxread);
 
 extern void DoCopy(ParseState *state, const CopyStmt *stmt,
 				   int stmt_location, int stmt_len,
@@ -41,4 +421,11 @@ extern uint64 CopyFrom(CopyState cstate);
 
 extern DestReceiver *CreateCopyDestReceiver(void);
 
+extern void PopulateCommonCstateInfo(CopyState cstate, TupleDesc tup_desc,
+									 List *attnamelist);
+
+extern void ParallelCopyMain(dsm_segment *seg, shm_toc *toc);
+extern ParallelContext *BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid);
+extern void ParallelCopyFrom(CopyState cstate);
+extern void EndParallelCopy(ParallelContext *pcxt);
 #endif							/* COPY_H */
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index c52f20d..5ce8296 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1702,6 +1702,12 @@ ParallelBitmapHeapState
 ParallelBlockTableScanDesc
 ParallelCompletionPtr
 ParallelContext
+ParallelCopyLineBoundaries
+ParallelCopyLineBoundary
+ParallelCopyData
+ParallelCopyDataBlock
+ParallelCopyLineBuf
+ParallelCopyShmInfo
 ParallelExecutorInfo
 ParallelHashGrowth
 ParallelHashJoinBatch
@@ -2224,6 +2230,7 @@ SerCommitSeqNo
 SerialControl
 SerializableXactHandle
 SerializedActiveRelMaps
+SerializedParallelCopyState
 SerializedReindexState
 SerializedSnapshotData
 SerializedTransactionState
-- 
1.8.3.1

v8-0003-Allow-copy-from-command-to-process-data-from-file.patchtext/x-patch; charset=US-ASCII; name=v8-0003-Allow-copy-from-command-to-process-data-from-file.patchDownload
From 6c8018b00a8455f02d9db65ddeb8a72f5a89be98 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 14 Oct 2020 12:48:22 +0530
Subject: [PATCH v8 3/6] Allow copy from command to process data from
 file/STDIN contents to a table in parallel.

This feature allows the copy from to leverage multiple CPUs in order to copy
data from file/STDIN to a table. This adds a PARALLEL option to COPY FROM
command where the user can specify the number of workers that can be used
to perform the COPY FROM command.
The backend, to which the "COPY FROM" query is submitted acts as leader with
the responsibility of reading data from the file/stdin, launching at most n
number of workers as specified with PARALLEL 'n' option in the "COPY FROM"
query. The leader populates the common data required for the workers execution
in the DSM and shares it with the workers. The leader then executes before
statement triggers if there exists any. Leader populates DSM lines which
includes the start offset and line size, while populating the lines it reads
as many blocks as required into the DSM data blocks from the file. Each block
is of 64K size. The leader parses the data to identify a line, the existing
logic from CopyReadLineText which identifies the lines with some changes was
used for this. Leader checks if a free line is available to copy the
information, if there is no free line it waits till the required line is
freed up by the worker and then copies the identified lines information
(offset & line size) into the DSM lines. This process is repeated till the
complete file is processed. Simultaneously, the workers cache the lines(50)
locally into the local memory and release the lines to the leader for further
populating. Each worker processes the lines that it cached and inserts it into
the table.
The leader does not participate in the insertion of data, leaders only
responsibility will be to identify the lines as fast as possible for the
workers to do the actual copy operation. The leader waits till all the lines
populated are processed by the workers and exits. We have chosen this design
based on the reason "that everything stalls if the leader doesn't accept further
input data, as well as when there are no available splitted chunks so it doesn't
seem like a good idea to have the leader do other work.  This is backed by the
performance data where we have seen that with 1 worker there is just a 5-10%
performance difference".
---
 src/backend/access/common/toast_internals.c |   12 +-
 src/backend/access/heap/heapam.c            |   11 -
 src/backend/access/transam/xact.c           |   26 +-
 src/backend/commands/Makefile               |    1 +
 src/backend/commands/copy.c                 |  245 +++--
 src/backend/commands/copyparallel.c         | 1343 +++++++++++++++++++++++++++
 src/bin/psql/tab-complete.c                 |    2 +-
 src/include/access/xact.h                   |    1 +
 src/include/commands/copy.h                 |   54 +-
 src/tools/pgindent/typedefs.list            |    1 +
 10 files changed, 1607 insertions(+), 89 deletions(-)
 create mode 100644 src/backend/commands/copyparallel.c

diff --git a/src/backend/access/common/toast_internals.c b/src/backend/access/common/toast_internals.c
index 25a81e5..70c070e 100644
--- a/src/backend/access/common/toast_internals.c
+++ b/src/backend/access/common/toast_internals.c
@@ -17,6 +17,7 @@
 #include "access/genam.h"
 #include "access/heapam.h"
 #include "access/heaptoast.h"
+#include "access/parallel.h"
 #include "access/table.h"
 #include "access/toast_internals.h"
 #include "access/xact.h"
@@ -116,7 +117,16 @@ toast_save_datum(Relation rel, Datum value,
 	TupleDesc	toasttupDesc;
 	Datum		t_values[3];
 	bool		t_isnull[3];
-	CommandId	mycid = GetCurrentCommandId(true);
+
+	/*
+	 * Parallel copy can insert toast tuples, in case of parallel copy the
+	 * command would have been set already by calling
+	 * AssignCommandIdForWorker. For parallel copy call GetCurrentCommandId to
+	 * get currentCommandId by passing used as false, as this is taken care
+	 * earlier.
+	 */
+	CommandId	mycid = IsParallelWorker() ? GetCurrentCommandId(false) :
+	GetCurrentCommandId(true);
 	struct varlena *result;
 	struct varatt_external toast_pointer;
 	union
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 1585861..1602525 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2043,17 +2043,6 @@ static HeapTuple
 heap_prepare_insert(Relation relation, HeapTuple tup, TransactionId xid,
 					CommandId cid, int options)
 {
-	/*
-	 * To allow parallel inserts, we need to ensure that they are safe to be
-	 * performed in workers. We have the infrastructure to allow parallel
-	 * inserts in general except for the cases where inserts generate a new
-	 * CommandId (eg. inserts into a table having a foreign key column).
-	 */
-	if (IsParallelWorker())
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_TRANSACTION_STATE),
-				 errmsg("cannot insert tuples in a parallel worker")));
-
 	tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
 	tup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK);
 	tup->t_data->t_infomask |= HEAP_XMAX_INVALID;
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index af6afce..d6d449f 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -764,18 +764,34 @@ GetCurrentCommandId(bool used)
 	if (used)
 	{
 		/*
-		 * Forbid setting currentCommandIdUsed in a parallel worker, because
-		 * we have no provision for communicating this back to the leader.  We
-		 * could relax this restriction when currentCommandIdUsed was already
-		 * true at the start of the parallel operation.
+		 * If in a parallel worker, only allow setting currentCommandIdUsed
+		 * if currentCommandIdUsed was already true at the start of the
+		 * parallel operation (by way of SetCurrentCommandIdUsed()), otherwise
+		 * forbid setting currentCommandIdUsed because we have no provision
+		 * for communicating this back to the leader.
 		 */
-		Assert(!IsParallelWorker());
+		Assert(!(IsParallelWorker() && !currentCommandIdUsed));
 		currentCommandIdUsed = true;
 	}
 	return currentCommandId;
 }
 
 /*
+ *	SetCurrentCommandIdUsedForWorker
+ *
+ * For a parallel worker, record that the currentCommandId has been used.
+ * This must only be called at the start of a parallel operation.
+ */
+void
+SetCurrentCommandIdUsedForWorker(void)
+{
+	Assert(IsParallelWorker() && !currentCommandIdUsed &&
+		   (currentCommandId != InvalidCommandId));
+
+	currentCommandIdUsed = true;
+}
+
+/*
  *	SetParallelStartTimestamps
  *
  * In a parallel worker, we should inherit the parent transaction's
diff --git a/src/backend/commands/Makefile b/src/backend/commands/Makefile
index d4815d3..a224aac 100644
--- a/src/backend/commands/Makefile
+++ b/src/backend/commands/Makefile
@@ -24,6 +24,7 @@ OBJS = \
 	constraint.o \
 	conversioncmds.o \
 	copy.o \
+	copyparallel.o \
 	createas.o \
 	dbcommands.o \
 	define.o \
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 99f7c9b..e613fc0 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -61,20 +61,6 @@
 #define ISOCTAL(c) (((c) >= '0') && ((c) <= '7'))
 #define OCTVALUE(c) ((c) - '0')
 
-/*
- * Represents the heap insert method to be used during COPY FROM.
- */
-typedef enum CopyInsertMethod
-{
-	CIM_SINGLE,					/* use table_tuple_insert or fdw routine */
-	CIM_MULTI,					/* always use table_multi_insert */
-	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
-} CopyInsertMethod;
-
-#define IsParallelCopy()		(cstate->is_parallel)
-#define IsLeader()				(cstate->pcdata->is_leader)
-#define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
-
 /* DestReceiver for COPY (query) TO */
 typedef struct
 {
@@ -83,7 +69,6 @@ typedef struct
 	uint64		processed;		/* # of tuples processed */
 } DR_copy;
 
-
 /*
  * No more than this many tuples per CopyMultiInsertBuffer
  *
@@ -181,9 +166,13 @@ if (1) \
 { \
 	if (raw_buf_ptr > cstate->raw_buf_index) \
 	{ \
-		appendBinaryStringInfo(&cstate->line_buf, \
-							 cstate->raw_buf + cstate->raw_buf_index, \
-							   raw_buf_ptr - cstate->raw_buf_index); \
+		if (!IsParallelCopy()) \
+			appendBinaryStringInfo(&cstate->line_buf, \
+								   cstate->raw_buf + cstate->raw_buf_index, \
+								   raw_buf_ptr - cstate->raw_buf_index); \
+		else \
+			line_size +=  raw_buf_ptr - cstate->raw_buf_index; \
+		\
 		cstate->raw_buf_index = raw_buf_ptr; \
 	} \
 } else ((void) 0)
@@ -212,7 +201,6 @@ static void EndCopyTo(CopyState cstate);
 static uint64 DoCopyTo(CopyState cstate);
 static uint64 CopyTo(CopyState cstate);
 static void CopyOneRowTo(CopyState cstate, TupleTableSlot *slot);
-static bool CopyReadLine(CopyState cstate);
 static bool CopyReadLineText(CopyState cstate);
 static int	CopyReadAttributesText(CopyState cstate);
 static int	CopyReadAttributesCSV(CopyState cstate);
@@ -245,7 +233,6 @@ static int	CopyReadBinaryData(CopyState cstate, char *dest, int nbytes);
 
 static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
 								   int copy_line_pos, int *copy_line_size);
-static void ConvertToServerEncoding(CopyState cstate);
 
 
 /*
@@ -645,11 +632,11 @@ CopyGetInt16(CopyState cstate, int16 *val)
 static bool
 CopyLoadRawBuf(CopyState cstate)
 {
-	int			nbytes = RAW_BUF_BYTES(cstate);
+	int			nbytes = (!IsParallelCopy()) ? RAW_BUF_BYTES(cstate) : cstate->raw_buf_len;
 	int			inbytes;
 
 	/* Copy down the unprocessed data if any. */
-	if (nbytes > 0)
+	if (nbytes > 0 && !IsParallelCopy())
 		memmove(cstate->raw_buf, cstate->raw_buf + cstate->raw_buf_index,
 				nbytes);
 
@@ -657,7 +644,9 @@ CopyLoadRawBuf(CopyState cstate)
 						  1, RAW_BUF_SIZE - nbytes);
 	nbytes += inbytes;
 	cstate->raw_buf[nbytes] = '\0';
-	cstate->raw_buf_index = 0;
+	if (!IsParallelCopy())
+		cstate->raw_buf_index = 0;
+
 	cstate->raw_buf_len = nbytes;
 	return (inbytes > 0);
 }
@@ -969,7 +958,11 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 		cstate->whereClause = whereClause;
 		cstate->is_parallel = false;
 
-		if (cstate->nworkers > 0)
+		/*
+		 * User chosen parallel copy. Determine if the parallel copy is
+		 * actually allowed. If not, go with the non-parallel mode.
+		 */
+		if (cstate->nworkers > 0 && IsParallelCopyAllowed(cstate))
 			pcxt = BeginParallelCopy(cstate->nworkers, cstate, stmt->attlist,
 									 relid);
 
@@ -994,7 +987,15 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 			EndParallelCopy(pcxt);
 		}
 		else
+		{
+			/*
+			 * Reset nworkers to -1 here. This is useful in cases where user
+			 * specifies parallel workers, but, no worker is picked up, so go
+			 * back to non parallel mode value of nworkers.
+			 */
+			cstate->nworkers = -1;
 			*processed = CopyFrom(cstate);	/* copy from file to database */
+		}
 
 		EndCopyFrom(cstate);
 	}
@@ -2624,7 +2625,7 @@ CopyMultiInsertInfoStore(CopyMultiInsertInfo *miinfo, ResultRelInfo *rri,
  *
  * Check if the relation specified in copy from is valid.
  */
-static void
+void
 CheckTargetRelValidity(CopyState cstate)
 {
 	Assert(cstate->rel);
@@ -2721,7 +2722,7 @@ CopyFrom(CopyState cstate)
 
 	PartitionTupleRouting *proute = NULL;
 	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
+	CommandId	mycid;
 	int			ti_options = 0; /* start with default options for insert */
 	BulkInsertState bistate = NULL;
 	CopyInsertMethod insertMethod;
@@ -2731,7 +2732,18 @@ CopyFrom(CopyState cstate)
 	bool		has_instead_insert_row_trig;
 	bool		leafpart_use_multi_insert = false;
 
-	CheckTargetRelValidity(cstate);
+	/*
+	 * Perform this check if it is not parallel copy. In case of parallel
+	 * copy, this check is done by the leader, so that if any invalid case
+	 * exist the copy from command will error out from the leader itself,
+	 * avoiding launching workers, just to throw error.
+	 */
+	if (!IsParallelCopy())
+		CheckTargetRelValidity(cstate);
+	else
+		SetCurrentCommandIdUsedForWorker();
+
+	mycid = GetCurrentCommandId(!IsParallelCopy());
 
 	/*
 	 * If the target file is new-in-transaction, we assume that checking FSM
@@ -2767,7 +2779,8 @@ CopyFrom(CopyState cstate)
 	ExecInitResultRelation(estate, resultRelInfo, 1);
 
 	/* Verify the named relation is a valid target for INSERT */
-	CheckValidResultRel(resultRelInfo, CMD_INSERT);
+	if (!IsParallelCopy())
+		CheckValidResultRel(resultRelInfo, CMD_INSERT);
 
 	ExecOpenIndices(resultRelInfo, false);
 
@@ -2910,13 +2923,17 @@ CopyFrom(CopyState cstate)
 	has_instead_insert_row_trig = (resultRelInfo->ri_TrigDesc &&
 								   resultRelInfo->ri_TrigDesc->trig_insert_instead_row);
 
-	/*
-	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
-	 * should do this for COPY, since it's not really an "INSERT" statement as
-	 * such. However, executing these triggers maintains consistency with the
-	 * EACH ROW triggers that we already fire on COPY.
-	 */
-	ExecBSInsertTriggers(estate, resultRelInfo);
+	if (!IsParallelCopy())
+	{
+		/*
+		 * Check BEFORE STATEMENT insertion triggers. It's debatable whether
+		 * we should do this for COPY, since it's not really an "INSERT"
+		 * statement as such. However, executing these triggers maintains
+		 * consistency with the EACH ROW triggers that we already fire on
+		 * COPY.
+		 */
+		ExecBSInsertTriggers(estate, resultRelInfo);
+	}
 
 	econtext = GetPerTupleExprContext(estate);
 
@@ -3016,6 +3033,29 @@ CopyFrom(CopyState cstate)
 					!has_instead_insert_row_trig &&
 					resultRelInfo->ri_FdwRoutine == NULL;
 
+				/*
+				 * We may still be able to perform parallel inserts for
+				 * partitioned tables. However, the possibility of this
+				 * depends on which types of triggers exist on the partition.
+				 * We must not do parallel inserts if the partition is a
+				 * foreign table or it has any BEFORE/INSTEAD OF row triggers.
+				 * Since the partition's resultRelInfo are initialized only
+				 * when we actually insert the first tuple into them, we may
+				 * not know this info easily in the leader while deciding for
+				 * the parallelism. We would have gone ahead and allowed
+				 * parallelism. Now it's the time to throw an error and also
+				 * provide a hint to the user to not use parallelism. Throwing
+				 * an error seemed a simple approach than to look for all the
+				 * partitions in the leader while deciding for the
+				 * parallelism. Note that this error is thrown early, exactly
+				 * on the first tuple being inserted into the partition, so
+				 * not much work, that has been done so far, is wasted.
+				 */
+				if (!leafpart_use_multi_insert && IsParallelWorker())
+					ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+									errmsg("cannot perform PARALLEL COPY if partition has BEFORE/INSTEAD OF triggers, or if the partition is foreign partition"),
+									errhint("Try COPY without PARALLEL option")));
+
 				/* Set the multi-insert buffer to use for this partition. */
 				if (leafpart_use_multi_insert)
 				{
@@ -3218,7 +3258,10 @@ CopyFrom(CopyState cstate)
 			 * or FDW; this is the same definition used by nodeModifyTable.c
 			 * for counting tuples inserted by an INSERT command.
 			 */
-			processed++;
+			if (!IsParallelCopy())
+				processed++;
+			else
+				pg_atomic_add_fetch_u64(&cstate->pcdata->pcshared_info->processed, 1);
 		}
 	}
 
@@ -3241,7 +3284,7 @@ CopyFrom(CopyState cstate)
 	 * In the old protocol, tell pqcomm that we can process normal protocol
 	 * messages again.
 	 */
-	if (cstate->copy_dest == COPY_OLD_FE)
+	if (cstate->copy_dest == COPY_OLD_FE && !IsParallelCopy())
 		pq_endmsgread();
 
 	/* Execute AFTER STATEMENT insertion triggers */
@@ -3272,7 +3315,10 @@ CopyFrom(CopyState cstate)
 
 	FreeExecutorState(estate);
 
-	return processed;
+	if (!IsParallelCopy())
+		return processed;
+	else
+		return pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
 }
 
 /*
@@ -3280,7 +3326,7 @@ CopyFrom(CopyState cstate)
  *
  * Populate the cstate catalog information.
  */
-static void
+void
 PopulateCstateCatalogInfo(CopyState cstate)
 {
 	TupleDesc	tupDesc;
@@ -3562,26 +3608,35 @@ NextCopyFromRawFields(CopyState cstate, char ***fields, int *nfields)
 	/* only available for text or csv input */
 	Assert(!cstate->binary);
 
-	/* on input just throw the header line away */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (IsParallelCopy())
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
-			return false;		/* done */
+		done = GetWorkerLine(cstate);
+		if (done && cstate->line_buf.len == 0)
+			return false;
 	}
+	else
+	{
+		/* on input just throw the header line away */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
+		{
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+				return false;	/* done */
+		}
 
-	cstate->cur_lineno++;
+		cstate->cur_lineno++;
 
-	/* Actually read the line into memory here */
-	done = CopyReadLine(cstate);
+		/* Actually read the line into memory here */
+		done = CopyReadLine(cstate);
 
-	/*
-	 * EOF at start of line means we're done.  If we see EOF after some
-	 * characters, we act as though it was newline followed by EOF, ie,
-	 * process the line and then exit loop on next iteration.
-	 */
-	if (done && cstate->line_buf.len == 0)
-		return false;
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			return false;
+	}
 
 	/* Parse the line into de-escaped field values */
 	if (cstate->csv_mode)
@@ -3806,7 +3861,7 @@ EndCopyFrom(CopyState cstate)
  * by newline.  The terminating newline or EOF marker is not included
  * in the final value of line_buf.
  */
-static bool
+bool
 CopyReadLine(CopyState cstate)
 {
 	bool		result;
@@ -3829,9 +3884,31 @@ CopyReadLine(CopyState cstate)
 		 */
 		if (cstate->copy_dest == COPY_NEW_FE)
 		{
+			bool		bIsFirst = true;
+
 			do
 			{
-				cstate->raw_buf_index = cstate->raw_buf_len;
+				if (!IsParallelCopy())
+					cstate->raw_buf_index = cstate->raw_buf_len;
+				else
+				{
+					/*
+					 * Get a new block if it is the first time, From the
+					 * subsequent time, reset the index and re-use the same
+					 * block.
+					 */
+					if (bIsFirst)
+					{
+						ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+						uint32		block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+						cstate->raw_buf = pcshared_info->data_blocks[block_pos].data;
+						bIsFirst = false;
+					}
+
+					cstate->raw_buf_index = cstate->raw_buf_len = 0;
+				}
+
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
@@ -3886,11 +3963,11 @@ ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
  *
  * Convert contents to server encoding.
  */
-static void
+void
 ConvertToServerEncoding(CopyState cstate)
 {
 	/* Done reading the line.  Convert it to server encoding. */
-	if (cstate->need_transcoding)
+	if (cstate->need_transcoding && (!IsParallelCopy() || IsWorker()))
 	{
 		char	   *cvt;
 
@@ -3930,6 +4007,11 @@ CopyReadLineText(CopyState cstate)
 	char		quotec = '\0';
 	char		escapec = '\0';
 
+	/* For parallel copy */
+	int			line_size = 0;
+	uint32		line_pos = 0;
+
+	cstate->eol_type = EOL_UNKNOWN;
 	if (cstate->csv_mode)
 	{
 		quotec = cstate->quote[0];
@@ -3984,6 +4066,10 @@ CopyReadLineText(CopyState cstate)
 		if (raw_buf_ptr >= copy_buf_len || need_data)
 		{
 			REFILL_LINEBUF;
+			if ((copy_buf_len == DATA_BLOCK_SIZE || copy_buf_len == 0) &&
+				IsParallelCopy())
+				SetRawBufForLoad(cstate, line_size, copy_buf_len, raw_buf_ptr,
+								 &copy_raw_buf);
 
 			/*
 			 * Try to read some more data.  This will certainly reset
@@ -3991,14 +4077,14 @@ CopyReadLineText(CopyState cstate)
 			 */
 			if (!CopyLoadRawBuf(cstate))
 				hit_eof = true;
-			raw_buf_ptr = 0;
+			raw_buf_ptr = (IsParallelCopy()) ? cstate->raw_buf_index : 0;
 			copy_buf_len = cstate->raw_buf_len;
 
 			/*
 			 * If we are completely out of data, break out of the loop,
 			 * reporting EOF.
 			 */
-			if (copy_buf_len <= 0)
+			if (RAW_BUF_BYTES(cstate) <= 0)
 			{
 				result = true;
 				break;
@@ -4208,9 +4294,15 @@ CopyReadLineText(CopyState cstate)
 				 * discard the data and the \. sequence.
 				 */
 				if (prev_raw_ptr > cstate->raw_buf_index)
-					appendBinaryStringInfo(&cstate->line_buf,
-										   cstate->raw_buf + cstate->raw_buf_index,
-										   prev_raw_ptr - cstate->raw_buf_index);
+				{
+					if (!IsParallelCopy())
+						appendBinaryStringInfo(&cstate->line_buf,
+											   cstate->raw_buf + cstate->raw_buf_index,
+											   prev_raw_ptr - cstate->raw_buf_index);
+					else
+						line_size += prev_raw_ptr - cstate->raw_buf_index;
+				}
+
 				cstate->raw_buf_index = raw_buf_ptr;
 				result = true;	/* report EOF */
 				break;
@@ -4262,6 +4354,22 @@ not_end_of_copy:
 			IF_NEED_REFILL_AND_EOF_BREAK(mblen - 1);
 			raw_buf_ptr += mblen - 1;
 		}
+
+		/*
+		 * Skip the header line. Update the line here, this cannot be done at
+		 * the beginning, as there is a possibility that file contains empty
+		 * lines.
+		 */
+		if (IsParallelCopy() && first_char_in_line && !IsHeaderLine())
+		{
+			ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+			line_pos = UpdateSharedLineInfo(cstate,
+											pcshared_info->cur_block_pos,
+											cstate->raw_buf_index, -1,
+											LINE_LEADER_POPULATING, -1);
+		}
+
 		first_char_in_line = false;
 	}							/* end of outer loop */
 
@@ -4270,9 +4378,16 @@ not_end_of_copy:
 	 */
 	REFILL_LINEBUF;
 	if (!result && !IsHeaderLine())
-		ClearEOLFromCopiedData(cstate, cstate->line_buf.data,
-							   cstate->line_buf.len, &cstate->line_buf.len);
+	{
+		if (IsParallelCopy())
+			ClearEOLFromCopiedData(cstate, cstate->raw_buf, raw_buf_ptr,
+								   &line_size);
+		else
+			ClearEOLFromCopiedData(cstate, cstate->line_buf.data,
+								   cstate->line_buf.len, &cstate->line_buf.len);
+	}
 
+	EndLineParallelCopy(cstate, line_pos, line_size, raw_buf_ptr);
 	return result;
 }
 
diff --git a/src/backend/commands/copyparallel.c b/src/backend/commands/copyparallel.c
new file mode 100644
index 0000000..436df40
--- /dev/null
+++ b/src/backend/commands/copyparallel.c
@@ -0,0 +1,1343 @@
+/*-------------------------------------------------------------------------
+ *
+ * copyparallel.c
+ *              Implements the Parallel COPY utility command
+ *
+ * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *        src/backend/commands/copyparallel.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/heapam.h"
+#include "catalog/pg_proc_d.h"
+#include "commands/copy.h"
+#include "libpq/libpq.h"
+#include "optimizer/clauses.h"
+#include "optimizer/optimizer.h"
+#include "pgstat.h"
+#include "utils/lsyscache.h"
+
+/* DSM keys for parallel copy.  */
+#define PARALLEL_COPY_KEY_SHARED_INFO				1
+#define PARALLEL_COPY_KEY_CSTATE					2
+#define PARALLEL_COPY_WAL_USAGE						3
+#define PARALLEL_COPY_BUFFER_USAGE					4
+
+/* Begin parallel copy Macros */
+#define SET_NEWLINE_SIZE() \
+{ \
+	if (cstate->eol_type == EOL_NL || cstate->eol_type == EOL_CR) \
+		new_line_size = 1; \
+	else if (cstate->eol_type == EOL_CRNL) \
+		new_line_size = 2; \
+	else \
+		new_line_size = 0; \
+}
+
+/*
+ * COPY_WAIT_TO_PROCESS - Wait before continuing to process.
+ */
+#define COPY_WAIT_TO_PROCESS() \
+{ \
+	CHECK_FOR_INTERRUPTS(); \
+	(void) WaitLatch(MyLatch, \
+					 WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH, \
+					 1L, WAIT_EVENT_PG_SLEEP); \
+	ResetLatch(MyLatch); \
+}
+
+/*
+ * CopyStringToSharedMemory
+ *
+ * Copy the string to shared memory.
+ */
+static uint32
+CopyStringToSharedMemory(CopyState cstate, char *srcPtr, char *destptr)
+{
+	uint32		len = srcPtr ? strlen(srcPtr) + 1 : 0;
+	uint32		copiedsize;
+
+	memcpy(destptr, (uint32 *) &len, sizeof(uint32));
+	copiedsize = sizeof(uint32);
+	if (len)
+	{
+		memcpy(destptr + sizeof(uint32), srcPtr, len);
+		copiedsize += len;
+	}
+
+	return copiedsize;
+}
+
+/*
+ * SerializeParallelCopyState
+ *
+ * Serialize the cstate members required by the workers into shared memory.
+ */
+static void
+SerializeParallelCopyState(ParallelContext *pcxt, CopyState cstate,
+						   uint32 estimatedSize, char *whereClauseStr,
+						   char *rangeTableStr, char *attnameListStr,
+						   char *notnullListStr, char *nullListStr,
+						   char *convertListStr)
+{
+	SerializedParallelCopyState shared_cstate;
+	char	   *shmptr = (char *) shm_toc_allocate(pcxt->toc, estimatedSize + 1);
+	Size		copiedsize = 0;
+	uint8 		len = 0;
+
+	shared_cstate.copy_dest = cstate->copy_dest;
+	shared_cstate.file_encoding = cstate->file_encoding;
+	shared_cstate.need_transcoding = cstate->need_transcoding;
+	shared_cstate.encoding_embeds_ascii = cstate->encoding_embeds_ascii;
+	shared_cstate.csv_mode = cstate->csv_mode;
+	shared_cstate.header_line = cstate->header_line;
+	shared_cstate.null_print_len = cstate->null_print_len;
+	shared_cstate.force_quote_all = cstate->force_quote_all;
+	shared_cstate.convert_selectively = cstate->convert_selectively;
+	shared_cstate.num_defaults = cstate->num_defaults;
+	shared_cstate.relid = cstate->pcdata->relid;
+
+	memcpy(shmptr, (char *) &shared_cstate, sizeof(SerializedParallelCopyState));
+	copiedsize = sizeof(SerializedParallelCopyState);
+
+	memcpy(shmptr + copiedsize, (uint32 *) &cstate->null_print_len,
+		   sizeof(uint32));
+	copiedsize += sizeof(uint32);
+	if (cstate->null_print_len)
+	{
+		memcpy(shmptr + copiedsize, cstate->null_print, cstate->null_print_len);
+		copiedsize += cstate->null_print_len;
+	}
+
+	len = (cstate->delim) ? 1 : 0;
+	memcpy(shmptr + copiedsize, (uint8 *) &len, sizeof(uint8));
+	copiedsize += sizeof(uint8);
+	if (cstate->delim)
+		shmptr[copiedsize++] = cstate->delim[0];
+
+	len = (cstate->quote) ? 1 : 0;
+	memcpy(shmptr + copiedsize, (uint8 *) &len, sizeof(uint8));
+	copiedsize += sizeof(uint8);
+	if (cstate->quote)
+		shmptr[copiedsize++] = cstate->quote[0];
+
+	len = (cstate->escape) ? 1 : 0;
+	memcpy(shmptr + copiedsize, (uint8 *) &len, sizeof(uint8));
+	copiedsize += sizeof(uint8);
+	if (cstate->escape)
+		shmptr[copiedsize++] = cstate->escape[0];
+
+	copiedsize += CopyStringToSharedMemory(cstate, attnameListStr,
+										   shmptr + copiedsize);
+	copiedsize += CopyStringToSharedMemory(cstate, notnullListStr,
+										   shmptr + copiedsize);
+	copiedsize += CopyStringToSharedMemory(cstate, nullListStr,
+										   shmptr + copiedsize);
+	copiedsize += CopyStringToSharedMemory(cstate, convertListStr,
+										   shmptr + copiedsize);
+	copiedsize += CopyStringToSharedMemory(cstate, whereClauseStr,
+										   shmptr + copiedsize);
+	copiedsize += CopyStringToSharedMemory(cstate, rangeTableStr,
+										   shmptr + copiedsize);
+
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_CSTATE, shmptr);
+}
+
+/*
+ * CopyStringFromSharedMemory
+ *
+ * Copy the string contents from shared memory & return the ptr.
+ */
+static char *
+CopyStringFromSharedMemory(char *srcPtr, Size *copiedsize)
+{
+	char	   *destptr = NULL;
+	uint32		len;
+
+	memcpy((uint32 *) (&len), srcPtr, sizeof(uint32));
+	*copiedsize += sizeof(uint32);
+	if (len)
+	{
+		destptr = (char *) palloc(len);
+		memcpy(destptr, srcPtr + sizeof(uint32), len);
+		*copiedsize += len;
+	}
+
+	return destptr;
+}
+
+/*
+ * CopyNodeFromSharedMemory
+ *
+ * Copy the node contents which was stored as string format in shared memory &
+ * convert it into node type.
+ */
+static void *
+CopyNodeFromSharedMemory(char *srcPtr, Size *copiedsize)
+{
+	char	   *destptr = NULL;
+	List	   *destList = NIL;
+	uint32		len;
+
+	memcpy((uint32 *) (&len), srcPtr, sizeof(uint32));
+	*copiedsize += sizeof(uint32);
+	if (len)
+	{
+		destptr = (char *) palloc(len);
+		memcpy(destptr, srcPtr + sizeof(uint32), len);
+		*copiedsize += len;
+		destList = (List *) stringToNode(destptr);
+		pfree(destptr);
+	}
+
+	return destList;
+}
+
+/*
+ * RestoreParallelCopyState
+ *
+ * Retrieve the cstate members which was populated by the leader in the shared
+ * memory.
+ */
+static void
+RestoreParallelCopyState(shm_toc *toc, CopyState cstate, List **attlist)
+{
+	char	   *shared_str_val = (char *) shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE, true);
+	SerializedParallelCopyState shared_cstate = {0};
+	Size		copiedsize = 0;
+	uint8		len;
+
+	memcpy(&shared_cstate, (char *) shared_str_val, sizeof(SerializedParallelCopyState));
+	copiedsize = sizeof(SerializedParallelCopyState);
+
+	cstate->file_encoding = shared_cstate.file_encoding;
+	cstate->need_transcoding = shared_cstate.need_transcoding;
+	cstate->encoding_embeds_ascii = shared_cstate.encoding_embeds_ascii;
+	cstate->csv_mode = shared_cstate.csv_mode;
+	cstate->header_line = shared_cstate.header_line;
+	cstate->null_print_len = shared_cstate.null_print_len;
+	cstate->force_quote_all = shared_cstate.force_quote_all;
+	cstate->convert_selectively = shared_cstate.convert_selectively;
+	cstate->num_defaults = shared_cstate.num_defaults;
+	cstate->pcdata->relid = shared_cstate.relid;
+
+	cstate->null_print = CopyStringFromSharedMemory(shared_str_val + copiedsize,
+													&copiedsize);
+	if (!cstate->null_print)
+		cstate->null_print = "";
+
+	memcpy((uint8 *) (&len), shared_str_val + copiedsize, sizeof(uint8));
+	copiedsize += sizeof(uint8);
+	if (len)
+	{
+		cstate->delim = palloc0(sizeof(char) + 1);
+		cstate->delim[0] = shared_str_val[copiedsize++];
+	}
+
+	memcpy((uint8 *) (&len), shared_str_val + copiedsize, sizeof(uint8));
+	copiedsize += sizeof(uint8);
+	if (len)
+	{
+		cstate->quote = palloc0(sizeof(char) + 1);
+		cstate->quote[0] = shared_str_val[copiedsize++];
+	}
+
+	memcpy((uint8 *) (&len), shared_str_val + copiedsize, sizeof(uint8));
+	copiedsize += sizeof(uint8);
+	if (len)
+	{
+		cstate->escape = palloc0(sizeof(char) + 1);
+		cstate->escape[0] = shared_str_val[copiedsize++];
+	}
+
+	*attlist = (List *) CopyNodeFromSharedMemory(shared_str_val + copiedsize,
+												 &copiedsize);
+	cstate->force_notnull = (List *) CopyNodeFromSharedMemory(shared_str_val + copiedsize,
+															  &copiedsize);
+	cstate->force_null = (List *) CopyNodeFromSharedMemory(shared_str_val + copiedsize,
+														   &copiedsize);
+	cstate->convert_select = (List *) CopyNodeFromSharedMemory(shared_str_val + copiedsize,
+															   &copiedsize);
+	cstate->whereClause = (Node *) CopyNodeFromSharedMemory(shared_str_val + copiedsize,
+															&copiedsize);
+	cstate->range_table = (List *) CopyNodeFromSharedMemory(shared_str_val + copiedsize,
+															&copiedsize);
+}
+
+/*
+ * EstimateNodeSize
+ *
+ * Convert the input list/node to string & estimate the size required in shared
+ * memory.
+ */
+static uint32
+EstimateNodeSize(void *list, char **listStr)
+{
+	uint32		strsize = sizeof(uint32);
+
+	if (list != NIL)
+	{
+		*listStr = nodeToString(list);
+		strsize += strlen(*listStr) + 1;
+	}
+
+	return strsize;
+}
+
+/*
+ * EstimateCstateSize
+ *
+ * Estimate the size of the required cstate variables in the shared memory.
+ */
+static uint32
+EstimateCstateSize(ParallelContext *pcxt, CopyState cstate, List *attnamelist,
+				   char **whereClauseStr, char **rangeTableStr,
+				   char **attnameListStr, char **notnullListStr,
+				   char **nullListStr, char **convertListStr)
+{
+	Size		strsize = MAXALIGN(sizeof(SerializedParallelCopyState));
+
+	/* Size of null_print is available in null_print_len. */
+	strsize = add_size(strsize, sizeof(uint32) + cstate->null_print_len);
+
+	/* 1 byte is be used to store delim information. */
+	strsize = add_size(strsize, sizeof(uint8));
+	strsize = add_size(strsize, (cstate->delim) ? 1 : 0);
+
+	/* 1 byte is be used to store quote information. */
+	strsize = add_size(strsize, sizeof(uint8));
+	strsize = add_size(strsize, (cstate->quote) ? 1 : 0);
+
+	/* 1 byte is be used to store quote information. */
+	strsize = add_size(strsize, sizeof(uint8));
+	strsize = add_size(strsize, (cstate->escape) ? 1 : 0);
+
+	strsize = add_size(strsize, EstimateNodeSize(attnamelist, attnameListStr));
+	strsize = add_size(strsize, EstimateNodeSize(cstate->force_notnull, notnullListStr));
+	strsize = add_size(strsize, EstimateNodeSize(cstate->force_null, nullListStr));
+	strsize = add_size(strsize, EstimateNodeSize(cstate->convert_select, convertListStr));
+	strsize = add_size(strsize, EstimateNodeSize(cstate->whereClause, whereClauseStr));
+	strsize = add_size(strsize, EstimateNodeSize(cstate->range_table, rangeTableStr));
+
+	shm_toc_estimate_chunk(&pcxt->estimator, strsize);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+	return strsize;
+}
+
+/*
+ * PopulateParallelCopyShmInfo
+ *
+ * Sets ParallelCopyShmInfo structure members.
+ */
+static void
+PopulateParallelCopyShmInfo(ParallelCopyShmInfo *shared_info_ptr)
+{
+	uint32		count;
+
+	MemSet(shared_info_ptr, 0, sizeof(ParallelCopyShmInfo));
+	shared_info_ptr->is_read_in_progress = true;
+	shared_info_ptr->cur_block_pos = -1;
+	for (count = 0; count < RINGSIZE; count++)
+	{
+		ParallelCopyLineBoundary *lineInfo = &shared_info_ptr->line_boundaries.ring[count];
+
+		pg_atomic_init_u32(&(lineInfo->line_size), -1);
+	}
+}
+
+/*
+ * CheckRelTrigFunParallelSafety
+ *
+ * Check if the relation's associated trigger functions are parallel safe. If
+ * any of the trigger function is parallel unsafe or if trigger is on foreign
+ * key relation, we do not allow parallel copy.
+ */
+static pg_attribute_always_inline bool
+CheckRelTrigFunParallelSafety(TriggerDesc *trigdesc)
+{
+	int			i;
+
+	for (i = 0; i < trigdesc->numtriggers; i++)
+	{
+		Trigger    *trigger = &trigdesc->triggers[i];
+		int			trigtype = RI_TRIGGER_NONE;
+
+		if (func_parallel(trigger->tgfoid) != PROPARALLEL_SAFE)
+			return false;
+
+		/* If the trigger is parallel safe, also look for RI_TRIGGER. */
+		trigtype = RI_FKey_trigger_type(trigger->tgfoid);
+
+		/*
+		 * No parallelism if foreign key check trigger is present. This is
+		 * because, while performing foreign key checks, we take KEY SHARE
+		 * lock on primary key table rows which inturn will increment the
+		 * command counter and updates the snapshot.  Since we share the
+		 * snapshots at the beginning of the command, we can't allow it to be
+		 * changed later. So, unless we do something special for it, we can't
+		 * allow parallelism in such cases.
+		 */
+		if (trigtype == RI_TRIGGER_FK)
+			return false;
+	}
+
+	return true;
+}
+
+/*
+ * CheckExprParallelSafety
+ *
+ * Determine parallel safety of volatile expressions in default clause of column
+ * definition or in where clause and return true if they are parallel safe.
+ */
+static pg_attribute_always_inline bool
+CheckExprParallelSafety(CopyState cstate)
+{
+	if (contain_volatile_functions(cstate->whereClause))
+	{
+		if (max_parallel_hazard((Query *) cstate->whereClause) != PROPARALLEL_SAFE)
+			return false;
+	}
+
+	/*
+	 * Check if any of the column has volatile default expression. if yes, and
+	 * they are not parallel safe, then parallelism is not allowed. For
+	 * instance, if there are any serial/bigserial columns for which nextval()
+	 * default expression which is parallel unsafe is associated, parallelism
+	 * should not be allowed.
+	 */
+	if (cstate->defexprs != NULL && cstate->num_defaults != 0)
+	{
+		int			i;
+
+		for (i = 0; i < cstate->num_defaults; i++)
+		{
+			bool		volatile_expr = contain_volatile_functions((Node *) cstate->defexprs[i]->expr);
+
+			if (volatile_expr &&
+				(max_parallel_hazard((Query *) cstate->defexprs[i]->expr)) !=
+				PROPARALLEL_SAFE)
+				return false;
+		}
+	}
+
+	return true;
+}
+
+/*
+ * IsParallelCopyAllowed
+ *
+ * Check if parallel copy can be allowed.
+ */
+bool
+IsParallelCopyAllowed(CopyState cstate)
+{
+	/* Parallel copy not allowed for binary option. */
+	if (cstate->binary)
+		return false;
+
+	/*
+	 * Check if copy is into foreign table. We can not allow parallelism in
+	 * this case because each worker needs to establish FDW connection and
+	 * operate in a separate transaction. Unless we have a capability to
+	 * provide two-phase commit protocol, we can not allow parallelism.
+	 *
+	 * Also check if copy is into temporary table. Since parallel workers can
+	 * not access temporary table, parallelism is not allowed.
+	 */
+	if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
+		RelationUsesLocalBuffers(cstate->rel))
+		return false;
+
+	/*
+	 * If there are volatile default expressions or where clause contain
+	 * volatile expressions, allow parallelism if they are parallel safe,
+	 * otherwise not.
+	 */
+	if (!CheckExprParallelSafety(cstate))
+		return false;
+
+	/* Check parallel safety of the trigger functions. */
+	if (cstate->rel->trigdesc != NULL &&
+		!CheckRelTrigFunParallelSafety(cstate->rel->trigdesc))
+		return false;
+
+	/*
+	 * When transition tables are involved (if after statement triggers are
+	 * present), we collect minimal tuples in the tuple store after processing
+	 * them so that later after statement triggers can access them.  Now, if
+	 * we want to enable parallelism for such cases, we instead need to store
+	 * and access tuples from shared tuple store.  However, it does not have
+	 * the facility to store tuples in-memory, so we always need to store and
+	 * access from a file which could be costly unless we also have an
+	 * additional way to store minimal tuples in shared memory till work_mem
+	 * and then in shared tuple store. It is possible to do all this to enable
+	 * parallel copy for such cases. Currently, we can disallow parallelism
+	 * for such cases and later allow if required.
+	 *
+	 * When there are BEFORE/AFTER/INSTEAD OF row triggers on the table. We do
+	 * not allow parallelism in such cases because such triggers might query
+	 * the table we are inserting into and act differently if the tuples that
+	 * have already been processed and prepared for insertion are not there.
+	 * Now, if we allow parallelism with such triggers the behaviour would
+	 * depend on if the parallel worker has already inserted or not that
+	 * particular tuples.
+	 */
+	if (cstate->rel->trigdesc != NULL &&
+		(cstate->rel->trigdesc->trig_insert_after_statement ||
+		 cstate->rel->trigdesc->trig_insert_new_table ||
+		 cstate->rel->trigdesc->trig_insert_before_row ||
+		 cstate->rel->trigdesc->trig_insert_after_row ||
+		 cstate->rel->trigdesc->trig_insert_instead_row))
+		return false;
+
+	return true;
+}
+
+/*
+ * BeginParallelCopy - Start parallel copy tasks.
+ *
+ * Get the number of workers required to perform the parallel copy. The data
+ * structures that are required by the parallel workers will be initialized, the
+ * size required in DSM will be calculated and the necessary keys will be loaded
+ * in the DSM. The specified number of workers will then be launched.
+ */
+ParallelContext *
+BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid)
+{
+	ParallelContext *pcxt;
+	ParallelCopyShmInfo *shared_info_ptr;
+	char	   *whereClauseStr = NULL;
+	char	   *rangeTableStr = NULL;
+	char	   *attnameListStr = NULL;
+	char	   *notnullListStr = NULL;
+	char	   *nullListStr = NULL;
+	char	   *convertListStr = NULL;
+	int			parallel_workers = 0;
+	WalUsage   *walusage;
+	BufferUsage *bufferusage;
+	ParallelCopyData *pcdata;
+	MemoryContext oldcontext;
+	uint32		strsize;
+
+	CheckTargetRelValidity(cstate);
+	parallel_workers = Min(nworkers, max_worker_processes);
+
+	/* Can't perform copy in parallel */
+	if (parallel_workers <= 0)
+		return NULL;
+
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	MemoryContextSwitchTo(oldcontext);
+	cstate->pcdata = pcdata;
+
+	(void) GetCurrentFullTransactionId();
+	(void) GetCurrentCommandId(true);
+
+	EnterParallelMode();
+	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
+								 parallel_workers);
+	Assert(pcxt->nworkers > 0);
+
+	/*
+	 * Estimate size for shared information for PARALLEL_COPY_KEY_SHARED_INFO
+	 */
+	shm_toc_estimate_chunk(&pcxt->estimator, sizeof(ParallelCopyShmInfo));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_CSTATE */
+	strsize = EstimateCstateSize(pcxt, cstate, attnamelist, &whereClauseStr,
+								 &rangeTableStr, &attnameListStr,
+								 &notnullListStr, &nullListStr,
+								 &convertListStr);
+
+	/*
+	 * Estimate space for WalUsage and BufferUsage -- PARALLEL_COPY_WAL_USAGE
+	 * and PARALLEL_COPY_BUFFER_USAGE.
+	 */
+	shm_toc_estimate_chunk(&pcxt->estimator,
+						   mul_size(sizeof(WalUsage), pcxt->nworkers));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+	shm_toc_estimate_chunk(&pcxt->estimator,
+						   mul_size(sizeof(BufferUsage), pcxt->nworkers));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	InitializeParallelDSM(pcxt);
+
+	/* If no DSM segment was available, back out (do serial copy) */
+	if (pcxt->seg == NULL)
+	{
+		EndParallelCopy(pcxt);
+		return NULL;
+	}
+
+	/* Allocate shared memory for PARALLEL_COPY_KEY_SHARED_INFO */
+	shared_info_ptr = (ParallelCopyShmInfo *) shm_toc_allocate(pcxt->toc, sizeof(ParallelCopyShmInfo));
+	PopulateParallelCopyShmInfo(shared_info_ptr);
+
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_SHARED_INFO, shared_info_ptr);
+	pcdata->pcshared_info = shared_info_ptr;
+	pcdata->relid = relid;
+
+	SerializeParallelCopyState(pcxt, cstate, strsize, whereClauseStr,
+							   rangeTableStr, attnameListStr, notnullListStr,
+							   nullListStr, convertListStr);
+
+	/*
+	 * Allocate space for each worker's WalUsage and BufferUsage; no need to
+	 * initialize.
+	 */
+	walusage = shm_toc_allocate(pcxt->toc,
+								mul_size(sizeof(WalUsage), pcxt->nworkers));
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_WAL_USAGE, walusage);
+	pcdata->walusage = walusage;
+	bufferusage = shm_toc_allocate(pcxt->toc,
+								   mul_size(sizeof(BufferUsage), pcxt->nworkers));
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_BUFFER_USAGE, bufferusage);
+	pcdata->bufferusage = bufferusage;
+
+	LaunchParallelWorkers(pcxt);
+	if (pcxt->nworkers_launched == 0)
+	{
+		EndParallelCopy(pcxt);
+		return NULL;
+	}
+
+	/*
+	 * Caller needs to wait for all launched workers when we return.  Make
+	 * sure that the failure-to-start case will not hang forever.
+	 */
+	WaitForParallelWorkersToAttach(pcxt);
+
+	pcdata->is_leader = true;
+	cstate->is_parallel = true;
+	return pcxt;
+}
+
+/*
+ * EndParallelCopy
+ *
+ * End the parallel copy tasks.
+ */
+pg_attribute_always_inline void
+EndParallelCopy(ParallelContext *pcxt)
+{
+	Assert(!IsParallelWorker());
+
+	DestroyParallelContext(pcxt);
+	ExitParallelMode();
+}
+
+/*
+ * InitializeParallelCopyInfo
+ *
+ * Initialize parallel worker.
+ */
+static void
+InitializeParallelCopyInfo(CopyState cstate, List *attnamelist)
+{
+	uint32		count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	PopulateCommonCstateInfo(cstate, tup_desc, attnamelist);
+
+	/* Initialize state variables. */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/* Set up variables to avoid per-attribute overhead. */
+	initStringInfo(&cstate->attribute_buf);
+
+	initStringInfo(&cstate->line_buf);
+	for (count = 0; count < WORKER_CHUNK_COUNT; count++)
+		initStringInfo(&pcdata->worker_line_buf[count].line_buf);
+
+	cstate->line_buf_converted = false;
+	cstate->raw_buf = NULL;
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+
+	PopulateCstateCatalogInfo(cstate);
+
+	/* Create workspace for CopyReadAttributes results. */
+	if (!cstate->binary)
+	{
+		AttrNumber	attr_count = list_length(cstate->attnumlist);
+
+		cstate->max_fields = attr_count;
+		cstate->raw_fields = (char **) palloc(attr_count * sizeof(char *));
+	}
+}
+
+/*
+ * CacheLineInfo
+ *
+ * Cache the line information to local memory.
+ */
+static bool
+CacheLineInfo(CopyState cstate, uint32 buff_count)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	uint32		write_pos;
+	ParallelCopyDataBlock *data_blk_ptr;
+	ParallelCopyLineBoundary *lineInfo;
+	uint32		offset;
+	int			dataSize;
+	int			copiedSize = 0;
+
+	resetStringInfo(&pcdata->worker_line_buf[buff_count].line_buf);
+	write_pos = GetLinePosition(cstate);
+	if (-1 == write_pos)
+		return true;
+
+	/* Get the current line information. */
+	lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+	if (pg_atomic_read_u32(&lineInfo->line_size) == 0)
+		goto empty_data_line_update;
+
+	/* Get the block information. */
+	data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+	/* Get the offset information from where the data must be copied. */
+	offset = lineInfo->start_offset;
+	pcdata->worker_line_buf[buff_count].cur_lineno = lineInfo->cur_lineno;
+
+	elog(DEBUG1, "[Worker] Processing - line position:%d, block:%d, unprocessed lines:%d, offset:%d, line size:%d",
+		 write_pos, lineInfo->first_block,
+		 pg_atomic_read_u32(&data_blk_ptr->unprocessed_line_parts),
+		 offset, pg_atomic_read_u32(&lineInfo->line_size));
+
+	for (;;)
+	{
+		uint8		skip_bytes = data_blk_ptr->skip_bytes;
+
+		/*
+		 * There is a possibility that the loop embedded at the bottom of the
+		 * current loop has come out because data_blk_ptr->curr_blk_completed
+		 * is set, but dataSize read might be an old value, if
+		 * data_blk_ptr->curr_blk_completed and the line is completed,
+		 * line_size will be set. Read the line_size again to be sure if it is
+		 * completed or partial block.
+		 */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+		if (dataSize)
+		{
+			int			remainingSize = dataSize - copiedSize;
+
+			if (!remainingSize)
+				break;
+
+			/* Whole line is in current block. */
+			if (remainingSize + offset + skip_bytes < DATA_BLOCK_SIZE)
+			{
+				appendBinaryStringInfo(&pcdata->worker_line_buf[buff_count].line_buf,
+									   &data_blk_ptr->data[offset],
+									   remainingSize);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts,
+										1);
+				break;
+			}
+			else
+			{
+				/* Line is spread across the blocks. */
+				uint32		lineInCurrentBlock = (DATA_BLOCK_SIZE - skip_bytes) - offset;
+
+				appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+										 &data_blk_ptr->data[offset],
+										 lineInCurrentBlock);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+				copiedSize += lineInCurrentBlock;
+				while (copiedSize < dataSize)
+				{
+					uint32		currentBlockCopySize;
+					ParallelCopyDataBlock *currBlkPtr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+
+					skip_bytes = currBlkPtr->skip_bytes;
+
+					/*
+					 * If complete data is present in current block use
+					 * dataSize - copiedSize, or copy the whole block from
+					 * current block.
+					 */
+					currentBlockCopySize = Min(dataSize - copiedSize, DATA_BLOCK_SIZE - skip_bytes);
+					appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+											 &currBlkPtr->data[0],
+											 currentBlockCopySize);
+					pg_atomic_sub_fetch_u32(&currBlkPtr->unprocessed_line_parts, 1);
+					copiedSize += currentBlockCopySize;
+					data_blk_ptr = currBlkPtr;
+				}
+
+				break;
+			}
+		}
+		else
+		{
+			/* Copy this complete block from the current offset. */
+			uint32		lineInCurrentBlock = (DATA_BLOCK_SIZE - skip_bytes) - offset;
+
+			appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+									 &data_blk_ptr->data[offset],
+									 lineInCurrentBlock);
+			pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+			copiedSize += lineInCurrentBlock;
+
+			/*
+			 * Reset the offset. For the first copy, copy from the offset. For
+			 * the subsequent copy the complete block.
+			 */
+			offset = 0;
+
+			/* Set data_blk_ptr to the following block. */
+			data_blk_ptr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+		}
+
+		for (;;)
+		{
+			/* Get the size of this line */
+			dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+			/*
+			 * If the data is present in current block lineInfo->line_size
+			 * will be updated. If the data is spread across the blocks either
+			 * of lineInfo->line_size or data_blk_ptr->curr_blk_completed can
+			 * be updated. lineInfo->line_size will be updated if the complete
+			 * read is finished. data_blk_ptr->curr_blk_completed will be
+			 * updated if processing of current block is finished and data
+			 * processing is not finished.
+			 */
+			if (data_blk_ptr->curr_blk_completed || (dataSize != -1))
+				break;
+
+			COPY_WAIT_TO_PROCESS()
+		}
+	}
+
+empty_data_line_update:
+	elog(DEBUG1, "[Worker] Completed processing line:%d", write_pos);
+	pg_atomic_write_u32(&lineInfo->line_state, LINE_WORKER_PROCESSED);
+	pg_atomic_write_u32(&lineInfo->line_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+	return false;
+}
+
+/*
+ * GetWorkerLine
+ *
+ * Returns a line for worker to process.
+ */
+bool
+GetWorkerLine(CopyState cstate)
+{
+	uint32		buff_count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+
+	/*
+	 * Copy the line data to line_buf and release the line position so that
+	 * the worker can continue loading data.
+	 */
+	if (pcdata->worker_line_buf_pos < pcdata->worker_line_buf_count)
+		goto return_line;
+
+	pcdata->worker_line_buf_pos = 0;
+	pcdata->worker_line_buf_count = 0;
+
+	for (buff_count = 0; buff_count < WORKER_CHUNK_COUNT; buff_count++)
+	{
+		bool		result = CacheLineInfo(cstate, buff_count);
+
+		if (result)
+			break;
+
+		pcdata->worker_line_buf_count++;
+	}
+
+	if (pcdata->worker_line_buf_count)
+		goto return_line;
+	else
+		resetStringInfo(&cstate->line_buf);
+
+	return true;
+
+return_line:
+	cstate->line_buf = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].line_buf;
+	cstate->cur_lineno = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].cur_lineno;
+	cstate->line_buf_valid = true;
+
+	/* Mark that encoding conversion hasn't occurred yet. */
+	cstate->line_buf_converted = false;
+	ConvertToServerEncoding(cstate);
+	pcdata->worker_line_buf_pos++;
+	return false;
+}
+
+/*
+ * ParallelCopyMain - Parallel copy worker's code.
+ *
+ * Where clause handling, convert tuple to columns, add default null values for
+ * the missing columns that are not present in that record. Find the partition
+ * if it is partitioned table, invoke before row insert Triggers, handle
+ * constraints and insert the tuples.
+ */
+void
+ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
+{
+	CopyState	cstate;
+	ParallelCopyData *pcdata;
+	ParallelCopyShmInfo *pcshared_info;
+	Relation	rel = NULL;
+	MemoryContext oldcontext;
+	List	   *attlist = NIL;
+	WalUsage   *walusage;
+	BufferUsage *bufferusage;
+
+	/* Allocate workspace and zero all fields. */
+	cstate = (CopyStateData *) palloc0(sizeof(CopyStateData));
+
+	/*
+	 * We allocate everything used by a cstate in a new memory context. This
+	 * avoids memory leaks during repeated use of COPY in a query.
+	 */
+	cstate->copycontext = AllocSetContextCreate(CurrentMemoryContext,
+												"COPY",
+												ALLOCSET_DEFAULT_SIZES);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	cstate->pcdata = pcdata;
+	pcdata->is_leader = false;
+	pcdata->worker_processed_pos = -1;
+	cstate->is_parallel = true;
+	pcshared_info = (ParallelCopyShmInfo *) shm_toc_lookup(toc, PARALLEL_COPY_KEY_SHARED_INFO, false);
+
+	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
+
+	pcdata->pcshared_info = pcshared_info;
+	RestoreParallelCopyState(toc, cstate, &attlist);
+
+	/* Open and lock the relation, using the appropriate lock type. */
+	rel = table_open(cstate->pcdata->relid, RowExclusiveLock);
+	cstate->rel = rel;
+	InitializeParallelCopyInfo(cstate, attlist);
+
+	/* Prepare to track buffer usage during parallel execution */
+	InstrStartParallelQuery();
+
+	CopyFrom(cstate);
+
+	if (rel != NULL)
+		table_close(rel, RowExclusiveLock);
+
+	/* Report WAL/buffer usage during parallel execution */
+	bufferusage = shm_toc_lookup(toc, PARALLEL_COPY_BUFFER_USAGE, false);
+	walusage = shm_toc_lookup(toc, PARALLEL_COPY_WAL_USAGE, false);
+	InstrEndParallelQuery(&bufferusage[ParallelWorkerNumber],
+						  &walusage[ParallelWorkerNumber]);
+
+	MemoryContextSwitchTo(oldcontext);
+	pfree(cstate);
+	return;
+}
+
+/*
+ * UpdateSharedLineInfo
+ *
+ * Update the line information.
+ */
+uint32
+UpdateSharedLineInfo(CopyState cstate, uint32 blk_pos, uint32 offset,
+					 uint32 line_size, uint32 line_state, uint32 blk_line_pos)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyLineBoundaries *lineBoundaryPtr = &pcshared_info->line_boundaries;
+	ParallelCopyLineBoundary *lineInfo;
+	uint32		line_pos;
+
+	/* blk_line_pos will be valid in case line_pos was blocked earlier. */
+	if (blk_line_pos == -1)
+	{
+		line_pos = lineBoundaryPtr->pos;
+
+		/* Update the line information for the worker to pick and process. */
+		lineInfo = &lineBoundaryPtr->ring[line_pos];
+		while (pg_atomic_read_u32(&lineInfo->line_size) != -1)
+			COPY_WAIT_TO_PROCESS()
+
+				lineInfo->first_block = blk_pos;
+		lineInfo->start_offset = offset;
+		lineInfo->cur_lineno = cstate->cur_lineno;
+		lineBoundaryPtr->pos = (lineBoundaryPtr->pos + 1) % RINGSIZE;
+	}
+	else
+	{
+		line_pos = blk_line_pos;
+		lineInfo = &lineBoundaryPtr->ring[line_pos];
+	}
+
+	if (line_state == LINE_LEADER_POPULATED)
+	{
+		elog(DEBUG1, "[Leader] Added line with block:%d, offset:%d, line position:%d, line size:%d",
+			 lineInfo->first_block, lineInfo->start_offset, line_pos,
+			 pg_atomic_read_u32(&lineInfo->line_size));
+		pcshared_info->populated++;
+	}
+	else
+		elog(DEBUG1, "[Leader] Adding - block:%d, offset:%d, line position:%d",
+			 lineInfo->first_block, lineInfo->start_offset, line_pos);
+
+	pg_atomic_write_u32(&lineInfo->line_size, line_size);
+	pg_atomic_write_u32(&lineInfo->line_state, line_state);
+
+	return line_pos;
+}
+
+/*
+ * ParallelCopyFrom - parallel copy leader's functionality.
+ *
+ * Leader executes the before statement for before statement trigger, if before
+ * statement trigger is present. It will read the table data from the file and
+ * copy the contents to DSM data blocks. It will then read the input contents
+ * from the DSM data block and identify the records based on line breaks. This
+ * information is called line or a record that need to be inserted into a
+ * relation. The line information will be stored in ParallelCopyLineBoundary DSM
+ * data structure. Workers will then process this information and insert the
+ * data in to table. It will repeat this process until the all data is read from
+ * the file and all the DSM data blocks are processed. While processing if
+ * leader identifies that DSM Data blocks or DSM ParallelCopyLineBoundary data
+ * structures is full, leader will wait till the worker frees up some entries
+ * and repeat the process. It will wait till all the lines populated are
+ * processed by the workers and exits.
+ */
+void
+ParallelCopyFrom(CopyState cstate)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
+
+	/* raw_buf is not used in parallel copy, instead data blocks are used. */
+	pfree(cstate->raw_buf);
+	cstate->raw_buf = NULL;
+
+	/* Execute the before statement triggers from the leader */
+	ExecBeforeStmtTrigger(cstate);
+
+	/* On input just throw the header line away. */
+	if (cstate->cur_lineno == 0 && cstate->header_line)
+	{
+		cstate->cur_lineno++;
+		if (CopyReadLine(cstate))
+		{
+			pcshared_info->is_read_in_progress = false;
+			return;				/* done */
+		}
+	}
+
+	for (;;)
+	{
+		bool		done;
+
+		cstate->cur_lineno++;
+
+		/* Actually read the line into memory here. */
+		done = CopyReadLine(cstate);
+
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			break;
+	}
+
+	/*
+	 * In the old protocol, tell pqcomm that we can process normal protocol
+	 * messages again.
+	 */
+	if (cstate->copy_dest == COPY_OLD_FE)
+		pq_endmsgread();
+
+	pcshared_info->is_read_in_progress = false;
+	cstate->cur_lineno = 0;
+}
+
+/*
+ * GetLinePosition
+ *
+ * Return the line position once the leader has populated the data.
+ */
+uint32
+GetLinePosition(CopyState cstate)
+{
+	ParallelCopyData *pcdata = cstate->pcdata;
+	ParallelCopyShmInfo *pcshared_info = pcdata->pcshared_info;
+	uint32		previous_pos = pcdata->worker_processed_pos;
+	uint32		write_pos = (previous_pos == -1) ? 0 : (previous_pos + 1) % RINGSIZE;
+
+	for (;;)
+	{
+		int			dataSize;
+		bool		is_read_in_progress = pcshared_info->is_read_in_progress;
+		ParallelCopyLineBoundary *lineInfo;
+		ParallelCopyDataBlock *data_blk_ptr;
+		uint32		line_state = LINE_LEADER_POPULATED;
+		ParallelCopyLineState curr_line_state;
+
+		CHECK_FOR_INTERRUPTS();
+
+		/* File read completed & no elements to process. */
+		if (!is_read_in_progress &&
+			(pcshared_info->populated ==
+			 pg_atomic_read_u64(&pcshared_info->total_worker_processed)))
+		{
+			write_pos = -1;
+			break;
+		}
+
+		/* Get the current line information. */
+		lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+		curr_line_state = pg_atomic_read_u32(&lineInfo->line_state);
+		if ((write_pos % WORKER_CHUNK_COUNT == 0) &&
+			(curr_line_state == LINE_WORKER_PROCESSED ||
+			 curr_line_state == LINE_WORKER_PROCESSING))
+		{
+			pcdata->worker_processed_pos = write_pos;
+			write_pos = (write_pos + WORKER_CHUNK_COUNT) % RINGSIZE;
+			continue;
+		}
+
+		/* Get the size of this line. */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+		if (dataSize != 0)		/* If not an empty line. */
+		{
+			/* Get the block information. */
+			data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+			if (!data_blk_ptr->curr_blk_completed && (dataSize == -1))
+			{
+				/* Wait till the current line or block is added. */
+				COPY_WAIT_TO_PROCESS()
+					continue;
+			}
+		}
+
+		/* Make sure that no worker has consumed this element. */
+		if (pg_atomic_compare_exchange_u32(&lineInfo->line_state,
+										   &line_state, LINE_WORKER_PROCESSING))
+			break;
+	}
+
+	pcdata->worker_processed_pos = write_pos;
+	return write_pos;
+}
+
+/*
+ * GetFreeCopyBlock
+ *
+ * Get a free block for data to be copied.
+ */
+static pg_attribute_always_inline uint32
+GetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	int			count = 0;
+	uint32		last_free_block = pcshared_info->cur_block_pos;
+	uint32		block_pos = (last_free_block != -1) ? ((last_free_block + 1) % MAX_BLOCKS_COUNT) : 0;
+
+	/*
+	 * Get a new block for copying data, don't check current block, current
+	 * block will have some unprocessed data.
+	 */
+	while (count < (MAX_BLOCKS_COUNT - 1))
+	{
+		ParallelCopyDataBlock *dataBlkPtr = &pcshared_info->data_blocks[block_pos];
+		uint32		unprocessed_line_parts = pg_atomic_read_u32(&dataBlkPtr->unprocessed_line_parts);
+
+		if (unprocessed_line_parts == 0)
+		{
+			dataBlkPtr->curr_blk_completed = false;
+			dataBlkPtr->skip_bytes = 0;
+			dataBlkPtr->following_block = -1;
+			pcshared_info->cur_block_pos = block_pos;
+			MemSet(&dataBlkPtr->data[0], 0, DATA_BLOCK_SIZE);
+			return block_pos;
+		}
+
+		block_pos = (block_pos + 1) % MAX_BLOCKS_COUNT;
+		count++;
+	}
+
+	return -1;
+}
+
+/*
+ * WaitGetFreeCopyBlock
+ *
+ * If there are no blocks available, wait and get a block for copying data.
+ */
+uint32
+WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	uint32		new_free_pos = -1;
+
+	for (;;)
+	{
+		new_free_pos = GetFreeCopyBlock(pcshared_info);
+		if (new_free_pos != -1) /* We have got one block, break now. */
+			break;
+
+		COPY_WAIT_TO_PROCESS()
+	}
+
+	return new_free_pos;
+}
+
+/*
+ * SetRawBufForLoad
+ *
+ * Set raw_buf to the shared memory where the file data must be read.
+ */
+void
+SetRawBufForLoad(CopyState cstate, uint32 line_size, uint32 copy_buf_len,
+				 uint32 raw_buf_ptr, char **copy_raw_buf)
+{
+	ParallelCopyShmInfo *pcshared_info;
+	uint32		cur_block_pos;
+	uint32		next_block_pos;
+	ParallelCopyDataBlock *cur_data_blk_ptr = NULL;
+	ParallelCopyDataBlock *next_data_blk_ptr = NULL;
+
+	Assert(IsParallelCopy());
+
+	pcshared_info = cstate->pcdata->pcshared_info;
+	cur_block_pos = pcshared_info->cur_block_pos;
+	cur_data_blk_ptr = (cstate->raw_buf) ? &pcshared_info->data_blocks[cur_block_pos] : NULL;
+	next_block_pos = WaitGetFreeCopyBlock(pcshared_info);
+	next_data_blk_ptr = &pcshared_info->data_blocks[next_block_pos];
+
+	/* set raw_buf to the data block in shared memory */
+	cstate->raw_buf = next_data_blk_ptr->data;
+	*copy_raw_buf = cstate->raw_buf;
+	if (cur_data_blk_ptr && line_size)
+	{
+		/*
+		 * Mark the previous block as completed, worker can start copying this
+		 * data.
+		 */
+		cur_data_blk_ptr->following_block = next_block_pos;
+		pg_atomic_add_fetch_u32(&cur_data_blk_ptr->unprocessed_line_parts, 1);
+		cur_data_blk_ptr->skip_bytes = copy_buf_len - raw_buf_ptr;
+		cur_data_blk_ptr->curr_blk_completed = true;
+	}
+
+	cstate->raw_buf_index = 0;
+	cstate->raw_buf_len = 0;
+}
+
+/*
+ * EndLineParallelCopy
+ *
+ * Update the line information in shared memory.
+ */
+void
+EndLineParallelCopy(CopyState cstate, uint32 line_pos, uint32 line_size,
+					uint32 raw_buf_ptr)
+{
+	uint8		new_line_size;
+
+	if (!IsParallelCopy())
+		return;
+
+	if (!IsHeaderLine())
+	{
+		ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+		SET_NEWLINE_SIZE()
+			if (line_size)
+		{
+			/*
+			 * If the new_line_size > raw_buf_ptr, then the new block has only
+			 * new line char content. The unprocessed count should not be
+			 * increased in this case.
+			 */
+			if (raw_buf_ptr > new_line_size)
+			{
+				uint32		cur_block_pos = pcshared_info->cur_block_pos;
+				ParallelCopyDataBlock *curr_data_blk_ptr = &pcshared_info->data_blocks[cur_block_pos];
+
+				pg_atomic_add_fetch_u32(&curr_data_blk_ptr->unprocessed_line_parts, 1);
+			}
+
+			/*
+			 * Update line size & line state, other members are already
+			 * updated.
+			 */
+			(void) UpdateSharedLineInfo(cstate, -1, -1, line_size,
+										LINE_LEADER_POPULATED, line_pos);
+		}
+		else if (new_line_size)
+			/* This means only new line char, empty record should be inserted. */
+			(void) UpdateSharedLineInfo(cstate, -1, -1, 0,
+										LINE_LEADER_POPULATED, -1);
+	}
+}
+
+/*
+ * ExecBeforeStmtTrigger
+ *
+ * Execute the before statement trigger, this will be executed for parallel copy
+ * by the leader process.
+ */
+void
+ExecBeforeStmtTrigger(CopyState cstate)
+{
+	EState	   *estate = CreateExecutorState();
+	ResultRelInfo *resultRelInfo;
+
+	Assert(IsLeader());
+
+	/*
+	 * We need a ResultRelInfo so we can use the regular executor's
+	 * index-entry-making machinery.  (There used to be a huge amount of code
+	 * here that basically duplicated execUtils.c ...)
+	 */
+	ExecInitRangeTable(estate, cstate->range_table);
+	resultRelInfo = makeNode(ResultRelInfo);
+	ExecInitResultRelation(estate, resultRelInfo, 1);
+
+	/* Verify the named relation is a valid target for INSERT */
+	CheckValidResultRel(resultRelInfo, CMD_INSERT);
+
+	/* Prepare to catch AFTER triggers. */
+	AfterTriggerBeginQuery();
+
+	/*
+	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
+	 * should do this for COPY, since it's not really an "INSERT" statement as
+	 * such. However, executing these triggers maintains consistency with the
+	 * EACH ROW triggers that we already fire on COPY.
+	 */
+	ExecBSInsertTriggers(estate, resultRelInfo);
+
+	/* Handle queued AFTER triggers */
+	AfterTriggerEndQuery(estate);
+
+	/* Close the result relations, including any trigger target relations */
+	ExecCloseResultRelations(estate);
+	ExecCloseRangeTableRelations(estate);
+
+	FreeExecutorState(estate);
+}
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index 561fe1d..5bc0d65 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -2353,7 +2353,7 @@ psql_completion(const char *text, int start, int end)
 	/* Complete COPY <sth> FROM|TO filename WITH ( */
 	else if (Matches("COPY|\\copy", MatchAny, "FROM|TO", MatchAny, "WITH", "("))
 		COMPLETE_WITH("FORMAT", "FREEZE", "DELIMITER", "NULL",
-					  "HEADER", "QUOTE", "ESCAPE", "FORCE_QUOTE",
+					  "HEADER", "PARALLEL", "QUOTE", "ESCAPE", "FORCE_QUOTE",
 					  "FORCE_NOT_NULL", "FORCE_NULL", "ENCODING");
 
 	/* Complete COPY <sth> FROM|TO filename WITH (FORMAT */
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index 7320de3..42d4893 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -386,6 +386,7 @@ extern FullTransactionId GetTopFullTransactionId(void);
 extern FullTransactionId GetTopFullTransactionIdIfAny(void);
 extern FullTransactionId GetCurrentFullTransactionId(void);
 extern FullTransactionId GetCurrentFullTransactionIdIfAny(void);
+extern void SetCurrentCommandIdUsedForWorker(void);
 extern void MarkCurrentTransactionIdLoggedIfAny(void);
 extern bool SubTransactionIsActive(SubTransactionId subxid);
 extern CommandId GetCurrentCommandId(bool used);
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index cd2d56e..9b19dcb 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -34,7 +34,7 @@
  */
 #define DATA_BLOCK_SIZE RAW_BUF_SIZE
 
-/* It can hold 1023 blocks of 64K data in DSM to be processed by the worker. */
+/* It can hold 1024 blocks of 64K data in DSM to be processed by the worker. */
 #define MAX_BLOCKS_COUNT 1024
 
 /*
@@ -51,6 +51,13 @@
  */
 #define WORKER_CHUNK_COUNT 64
 
+#define IsParallelCopy()		(cstate->is_parallel)
+#define IsLeader()				(cstate->pcdata->is_leader)
+#define IsWorker()				(IsParallelCopy() && !IsLeader())
+#define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
+
+
+
 /*
  * Represents the different source/dest cases we need to worry about at
  * the bottom level
@@ -75,6 +82,28 @@ typedef enum EolType
 } EolType;
 
 /*
+ * State of the line.
+ */
+typedef enum ParallelCopyLineState
+{
+	LINE_INIT,					/* initial state of line */
+	LINE_LEADER_POPULATING,		/* leader processing line */
+	LINE_LEADER_POPULATED,		/* leader completed populating line */
+	LINE_WORKER_PROCESSING,		/* worker processing line */
+	LINE_WORKER_PROCESSED		/* worker completed processing line */
+} ParallelCopyLineState;
+
+/*
+ * Represents the heap insert method to be used during COPY FROM.
+ */
+typedef enum CopyInsertMethod
+{
+	CIM_SINGLE,					/* use table_tuple_insert or fdw routine */
+	CIM_MULTI,					/* always use table_multi_insert */
+	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
+} CopyInsertMethod;
+
+/*
  * Copy data block information.
  *
  * These data blocks are created in DSM. Data read from file will be copied in
@@ -194,8 +223,6 @@ typedef struct ParallelCopyShmInfo
 	uint64		populated;		/* lines populated by leader */
 	uint32		cur_block_pos;	/* current data block */
 	ParallelCopyDataBlock data_blocks[MAX_BLOCKS_COUNT];	/* data block array */
-	FullTransactionId full_transaction_id;	/* xid for copy from statement */
-	CommandId	mycid;			/* command id */
 	ParallelCopyLineBoundaries line_boundaries; /* line array */
 } ParallelCopyShmInfo;
 
@@ -242,12 +269,12 @@ typedef struct ParallelCopyData
 	ParallelCopyShmInfo *pcshared_info; /* common info in shared memory */
 	bool		is_leader;
 
+	/* line position which worker is processing */
+	uint32				worker_processed_pos;
+
 	WalUsage   *walusage;
 	BufferUsage *bufferusage;
 
-	/* line position which worker is processing */
-	uint32		worker_processed_pos;
-
 	/*
 	 * Local line_buf array, workers will copy it here and release the lines
 	 * for the leader to continue.
@@ -423,9 +450,24 @@ extern DestReceiver *CreateCopyDestReceiver(void);
 
 extern void PopulateCommonCstateInfo(CopyState cstate, TupleDesc tup_desc,
 									 List *attnamelist);
+extern void ConvertToServerEncoding(CopyState cstate);
 
 extern void ParallelCopyMain(dsm_segment *seg, shm_toc *toc);
 extern ParallelContext *BeginParallelCopy(int nworkers, CopyState cstate, List *attnamelist, Oid relid);
 extern void ParallelCopyFrom(CopyState cstate);
 extern void EndParallelCopy(ParallelContext *pcxt);
+extern bool IsParallelCopyAllowed(CopyState cstate);
+extern void ExecBeforeStmtTrigger(CopyState cstate);
+extern void CheckTargetRelValidity(CopyState cstate);
+extern void PopulateCstateCatalogInfo(CopyState cstate);
+extern uint32 GetLinePosition(CopyState cstate);
+extern bool GetWorkerLine(CopyState cstate);
+extern bool CopyReadLine(CopyState cstate);
+extern uint32 WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info);
+extern void SetRawBufForLoad(CopyState cstate, uint32 line_size, uint32 copy_buf_len,
+							 uint32 raw_buf_ptr, char **copy_raw_buf);
+extern uint32 UpdateSharedLineInfo(CopyState cstate, uint32 blk_pos, uint32 offset,
+								   uint32 line_size, uint32 line_state, uint32 blk_line_pos);
+extern void EndLineParallelCopy(CopyState cstate, uint32 line_pos, uint32 line_size,
+								uint32 raw_buf_ptr);
 #endif							/* COPY_H */
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index 5ce8296..8dfb944 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1707,6 +1707,7 @@ ParallelCopyLineBoundary
 ParallelCopyData
 ParallelCopyDataBlock
 ParallelCopyLineBuf
+ParallelCopyLineState
 ParallelCopyShmInfo
 ParallelExecutorInfo
 ParallelHashGrowth
-- 
1.8.3.1

v8-0004-Documentation-for-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=v8-0004-Documentation-for-parallel-copy.patchDownload
From 16755acf139da5fb449daac2e0baed0a647b4086 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Sat, 1 Aug 2020 09:00:36 +0530
Subject: [PATCH v8 4/6] Documentation for parallel copy.

This patch has the documentation changes for parallel copy.
---
 doc/src/sgml/ref/copy.sgml | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/doc/src/sgml/ref/copy.sgml b/doc/src/sgml/ref/copy.sgml
index 369342b..328a5f1 100644
--- a/doc/src/sgml/ref/copy.sgml
+++ b/doc/src/sgml/ref/copy.sgml
@@ -37,6 +37,7 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
     DELIMITER '<replaceable class="parameter">delimiter_character</replaceable>'
     NULL '<replaceable class="parameter">null_string</replaceable>'
     HEADER [ <replaceable class="parameter">boolean</replaceable> ]
+    PARALLEL <replaceable class="parameter">integer</replaceable>
     QUOTE '<replaceable class="parameter">quote_character</replaceable>'
     ESCAPE '<replaceable class="parameter">escape_character</replaceable>'
     FORCE_QUOTE { ( <replaceable class="parameter">column_name</replaceable> [, ...] ) | * }
@@ -277,6 +278,22 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
    </varlistentry>
 
    <varlistentry>
+    <term><literal>PARALLEL</literal></term>
+    <listitem>
+     <para>
+      Perform <command>COPY FROM</command> in parallel using <replaceable
+      class="parameter">integer</replaceable> background workers.  Please
+      note that it is not guaranteed that the number of parallel workers
+      specified in <replaceable class="parameter">integer</replaceable> will
+      be used during execution.  It is possible for a copy to run with fewer
+      workers than specified, or even with no workers at all (for example,
+      due to the setting of max_worker_processes). This option is allowed
+      only in <command>COPY FROM</command>.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><literal>QUOTE</literal></term>
     <listitem>
      <para>
@@ -953,6 +970,20 @@ COPY country FROM '/usr1/proj/bray/sql/country_data';
   </para>
 
   <para>
+   To copy data parallelly from a file into the <literal>country</literal> table:
+<programlisting>
+COPY country FROM '/usr1/proj/bray/sql/country_data' WITH (PARALLEL 1);
+</programlisting>
+  </para>
+
+  <para>
+   To copy data parallelly from STDIN into the <literal>country</literal> table:
+<programlisting>
+COPY country FROM STDIN WITH (PARALLEL 1);
+</programlisting>
+  </para>
+
+  <para>
    To copy into a file just the countries whose names start with 'A':
 <programlisting>
 COPY (SELECT * FROM country WHERE country_name LIKE 'A%') TO '/usr1/proj/bray/sql/a_list_countries.copy';
-- 
1.8.3.1

v8-0005-Tests-for-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=v8-0005-Tests-for-parallel-copy.patchDownload
From 3d72c381b024c8eb93324e250c1e628aa78965d0 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddy@enterprisedb.com>
Date: Tue, 13 Oct 2020 14:23:10 +0530
Subject: [PATCH v8 5/6] Tests for parallel copy.

This patch has the tests for parallel copy:
---
 contrib/postgres_fdw/expected/postgres_fdw.out |  49 ++++
 contrib/postgres_fdw/sql/postgres_fdw.sql      |  52 ++++
 src/backend/commands/copyparallel.c            | 369 +++++++++++++++++++++++--
 src/test/regress/expected/copy2.out            | 326 +++++++++++++++++++++-
 src/test/regress/input/copy.source             |  31 +++
 src/test/regress/output/copy.source            |  27 ++
 src/test/regress/sql/copy2.sql                 | 368 +++++++++++++++++++++++-
 7 files changed, 1191 insertions(+), 31 deletions(-)

diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index 2d88d06..474c5e7 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -9033,5 +9033,54 @@ SELECT 1 FROM ft1 LIMIT 1;    -- should fail
 ERROR:  08006
 \set VERBOSITY default
 COMMIT;
+-- parallel copy related tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+CREATE FOREIGN TABLE test_parallel_copy_ft (
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+) SERVER loopback OPTIONS (table_name 'test_parallel_copy') ;
+-- parallel copy into foreign table, parallelism must not be picked up.
+COPY test_parallel_copy_ft FROM stdin WITH (PARALLEL 1);
+SELECT count(*) FROM test_parallel_copy_ft;
+ count 
+-------
+     2
+(1 row)
+
+-- parallel copy into a table with foreign partition.
+CREATE TABLE part_test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+) PARTITION BY LIST (b);
+CREATE FOREIGN TABLE part_test_parallel_copy_a1 (c TEXT, b INT, a INT, e TEXT, d TEXT) SERVER loopback;
+CREATE TABLE part_test_parallel_copy_a2 (a INT, c TEXT, b INT, d TEXT, e TEXT);
+ALTER TABLE part_test_parallel_copy ATTACH PARTITION part_test_parallel_copy_a1 FOR VALUES IN(1);
+ALTER TABLE part_test_parallel_copy ATTACH PARTITION part_test_parallel_copy_a2 FOR VALUES IN(2);
+COPY part_test_parallel_copy FROM stdin WITH (PARALLEL 1);
+ERROR:  cannot perform PARALLEL COPY if partition has BEFORE/INSTEAD OF triggers, or if the partition is foreign partition
+HINT:  Try COPY without PARALLEL option
+CONTEXT:  COPY part_test_parallel_copy, line 1: "1	1	test_c1	test_d1	test_e1"
+parallel worker
+SELECT count(*) FROM part_test_parallel_copy WHERE b = 2;
+ count 
+-------
+     0
+(1 row)
+
 -- Clean up
 DROP PROCEDURE terminate_backend_and_wait(text);
+DROP FOREIGN TABLE test_parallel_copy_ft;
+DROP TABLE test_parallel_copy;
+DROP TABLE part_test_parallel_copy;
diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql
index 7581c54..635fcc2 100644
--- a/contrib/postgres_fdw/sql/postgres_fdw.sql
+++ b/contrib/postgres_fdw/sql/postgres_fdw.sql
@@ -2695,5 +2695,57 @@ SELECT 1 FROM ft1 LIMIT 1;    -- should fail
 \set VERBOSITY default
 COMMIT;
 
+-- parallel copy related tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+
+CREATE FOREIGN TABLE test_parallel_copy_ft (
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+) SERVER loopback OPTIONS (table_name 'test_parallel_copy') ;
+
+-- parallel copy into foreign table, parallelism must not be picked up.
+COPY test_parallel_copy_ft FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+SELECT count(*) FROM test_parallel_copy_ft;
+
+-- parallel copy into a table with foreign partition.
+CREATE TABLE part_test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+) PARTITION BY LIST (b);
+
+CREATE FOREIGN TABLE part_test_parallel_copy_a1 (c TEXT, b INT, a INT, e TEXT, d TEXT) SERVER loopback;
+
+CREATE TABLE part_test_parallel_copy_a2 (a INT, c TEXT, b INT, d TEXT, e TEXT);
+
+ALTER TABLE part_test_parallel_copy ATTACH PARTITION part_test_parallel_copy_a1 FOR VALUES IN(1);
+
+ALTER TABLE part_test_parallel_copy ATTACH PARTITION part_test_parallel_copy_a2 FOR VALUES IN(2);
+
+COPY part_test_parallel_copy FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+SELECT count(*) FROM part_test_parallel_copy WHERE b = 2;
+
 -- Clean up
 DROP PROCEDURE terminate_backend_and_wait(text);
+DROP FOREIGN TABLE test_parallel_copy_ft;
+DROP TABLE test_parallel_copy;
+DROP TABLE part_test_parallel_copy;
diff --git a/src/backend/commands/copyparallel.c b/src/backend/commands/copyparallel.c
index 436df40..add4dbc 100644
--- a/src/backend/commands/copyparallel.c
+++ b/src/backend/commands/copyparallel.c
@@ -102,6 +102,7 @@ SerializeParallelCopyState(ParallelContext *pcxt, CopyState cstate,
 	shared_cstate.convert_selectively = cstate->convert_selectively;
 	shared_cstate.num_defaults = cstate->num_defaults;
 	shared_cstate.relid = cstate->pcdata->relid;
+	shared_cstate.binary = cstate->binary;
 
 	memcpy(shmptr, (char *) &shared_cstate, sizeof(SerializedParallelCopyState));
 	copiedsize = sizeof(SerializedParallelCopyState);
@@ -226,6 +227,7 @@ RestoreParallelCopyState(shm_toc *toc, CopyState cstate, List **attlist)
 	cstate->convert_selectively = shared_cstate.convert_selectively;
 	cstate->num_defaults = shared_cstate.num_defaults;
 	cstate->pcdata->relid = shared_cstate.relid;
+	cstate->binary = shared_cstate.binary;
 
 	cstate->null_print = CopyStringFromSharedMemory(shared_str_val + copiedsize,
 													&copiedsize);
@@ -438,10 +440,6 @@ CheckExprParallelSafety(CopyState cstate)
 bool
 IsParallelCopyAllowed(CopyState cstate)
 {
-	/* Parallel copy not allowed for binary option. */
-	if (cstate->binary)
-		return false;
-
 	/*
 	 * Check if copy is into foreign table. We can not allow parallelism in
 	 * this case because each worker needs to establish FDW connection and
@@ -656,6 +654,7 @@ InitializeParallelCopyInfo(CopyState cstate, List *attnamelist)
 	cstate->cur_lineno = 0;
 	cstate->cur_attname = NULL;
 	cstate->cur_attval = NULL;
+	cstate->pcdata->curr_data_block = NULL;
 
 	/* Set up variables to avoid per-attribute overhead. */
 	initStringInfo(&cstate->attribute_buf);
@@ -878,7 +877,11 @@ return_line:
 
 	/* Mark that encoding conversion hasn't occurred yet. */
 	cstate->line_buf_converted = false;
-	ConvertToServerEncoding(cstate);
+
+	/* For binary format data, we don't need conversion. */
+	if (!cstate->binary)
+		ConvertToServerEncoding(cstate);
+
 	pcdata->worker_line_buf_pos++;
 	return false;
 }
@@ -1034,33 +1037,70 @@ ParallelCopyFrom(CopyState cstate)
 	/* Execute the before statement triggers from the leader */
 	ExecBeforeStmtTrigger(cstate);
 
-	/* On input just throw the header line away. */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (!cstate->binary)
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
+		/* On input just throw the header line away. */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
 		{
-			pcshared_info->is_read_in_progress = false;
-			return;				/* done */
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+			{
+				pcshared_info->is_read_in_progress = false;
+				return;			/* done */
+			}
 		}
-	}
 
-	for (;;)
-	{
-		bool		done;
+		for (;;)
+		{
+			bool		done;
 
-		cstate->cur_lineno++;
+			cstate->cur_lineno++;
 
-		/* Actually read the line into memory here. */
-		done = CopyReadLine(cstate);
+			/* Actually read the line into memory here. */
+			done = CopyReadLine(cstate);
 
+			/*
+			 * EOF at start of line means we're done.  If we see EOF after
+			 * some characters, we act as though it was newline followed by
+			 * EOF, ie, process the line and then exit loop on next iteration.
+			 */
+			if (done && cstate->line_buf.len == 0)
+				break;
+		}
+	}
+	else
+	{
 		/*
-		 * EOF at start of line means we're done.  If we see EOF after some
-		 * characters, we act as though it was newline followed by EOF, ie,
-		 * process the line and then exit loop on next iteration.
+		 * Binary Format Files. In parallel copy leader, fill in the error
+		 * context information here, in case any failures while determining
+		 * tuple offsets, leader would throw the errors with proper context.
 		 */
-		if (done && cstate->line_buf.len == 0)
-			break;
+		ErrorContextCallback errcallback;
+
+		errcallback.callback = CopyFromErrorCallback;
+		errcallback.arg = (void *) cstate;
+		errcallback.previous = error_context_stack;
+		error_context_stack = &errcallback;
+		cstate->pcdata->curr_data_block = NULL;
+		cstate->raw_buf_index = 0;
+		pcshared_info->populated = 0;
+		cstate->cur_lineno = 0;
+		cstate->max_fields = list_length(cstate->attnumlist);
+
+		for (;;)
+		{
+			bool		eof = false;
+
+			cstate->cur_lineno++;
+
+			eof = CopyReadBinaryTupleLeader(cstate);
+
+			if (eof)
+				break;
+		}
+
+		/* Reset the error context. */
+		error_context_stack = errcallback.previous;
 	}
 
 	/*
@@ -1075,6 +1115,289 @@ ParallelCopyFrom(CopyState cstate)
 }
 
 /*
+ * CopyReadBinaryGetDataBlock
+ *
+ * Gets a new block, updates the current offset, calculates the skip bytes.
+ */
+void
+CopyReadBinaryGetDataBlock(CopyState cstate, FieldInfoType field_info)
+{
+	ParallelCopyDataBlock *data_block = NULL;
+	ParallelCopyDataBlock *curr_data_block = cstate->pcdata->curr_data_block;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	uint8		move_bytes = 0;
+	uint32		block_pos;
+	uint32		prev_block_pos;
+	int			read_bytes = 0;
+
+	prev_block_pos = pcshared_info->cur_block_pos;
+
+	block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+	if (field_info == FIELD_SIZE || field_info == FIELD_COUNT)
+		move_bytes = (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+
+	if (curr_data_block != NULL)
+		curr_data_block->skip_bytes = move_bytes;
+
+	data_block = &pcshared_info->data_blocks[block_pos];
+
+	if (move_bytes > 0 && curr_data_block != NULL)
+		memmove(&data_block->data[0], &curr_data_block->data[cstate->raw_buf_index], move_bytes);
+
+	elog(DEBUG1, "LEADER - field info %d is spread across data blocks - moved %d bytes from current block %u to %u block",
+		 field_info, move_bytes, prev_block_pos, block_pos);
+
+	read_bytes = CopyGetData(cstate, &data_block->data[move_bytes], 1, (DATA_BLOCK_SIZE - move_bytes));
+
+	if (field_info == FIELD_NONE && cstate->reached_eof)
+		return;
+
+	if (cstate->reached_eof)
+		EOF_ERROR;
+
+	elog(DEBUG1, "LEADER - bytes read from file %d", read_bytes);
+
+	if (field_info == FIELD_SIZE || field_info == FIELD_DATA)
+	{
+		ParallelCopyDataBlock *prev_data_block = NULL;
+
+		prev_data_block = curr_data_block;
+		prev_data_block->following_block = block_pos;
+
+		if (prev_data_block->curr_blk_completed == false)
+			prev_data_block->curr_blk_completed = true;
+
+		pg_atomic_add_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+	}
+
+	cstate->pcdata->curr_data_block = data_block;
+	cstate->raw_buf_index = 0;
+}
+
+/*
+ * CopyReadBinaryTupleLeader
+ *
+ * Leader reads data from binary formatted file to data blocks and identifies
+ * tuple boundaries/offsets so that workers can work on the data blocks data.
+ */
+bool
+CopyReadBinaryTupleLeader(CopyState cstate)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	int16		fld_count;
+	uint32		line_size = 0;
+	uint32		start_block_pos;
+	uint32		start_offset;
+
+	if (cstate->pcdata->curr_data_block == NULL)
+	{
+		CopyReadBinaryGetDataBlock(cstate, FIELD_NONE);
+
+		/*
+		 * no data is read from file here. one possibility to be here could be
+		 * that the binary file just has a valid signature but nothing else.
+		 */
+		if (cstate->reached_eof)
+			return true;
+	}
+
+	if ((cstate->raw_buf_index + sizeof(fld_count)) >= DATA_BLOCK_SIZE)
+		CopyReadBinaryGetDataBlock(cstate, FIELD_COUNT);
+
+	memcpy(&fld_count, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_count));
+	fld_count = (int16) pg_ntoh16(fld_count);
+
+	CHECK_FIELD_COUNT;
+
+	start_offset = cstate->raw_buf_index;
+	cstate->raw_buf_index += sizeof(fld_count);
+	line_size += sizeof(fld_count);
+	start_block_pos = pcshared_info->cur_block_pos;
+
+	CopyReadBinaryFindTupleSize(cstate, &line_size);
+
+	pg_atomic_add_fetch_u32(&cstate->pcdata->curr_data_block->unprocessed_line_parts, 1);
+
+	if (line_size > 0)
+		(void) UpdateSharedLineInfo(cstate, start_block_pos, start_offset,
+									line_size, LINE_LEADER_POPULATED, -1);
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryFindTupleSize
+ *
+ * Leader identifies boundaries/offsets for each attribute/column and finally
+ * results in the tuple/row size. It moves on to next data block if the
+ * attribute/column is spread across data blocks.
+ */
+void
+CopyReadBinaryFindTupleSize(CopyState cstate, uint32 *line_size)
+{
+	int32		fld_size;
+	ListCell   *cur;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			att_num = lfirst_int(cur);
+		Form_pg_attribute att = TupleDescAttr(tup_desc, (att_num - 1));
+
+		cstate->cur_attname = NameStr(att->attname);
+		fld_size = 0;
+
+		if ((cstate->raw_buf_index + sizeof(fld_size)) >= DATA_BLOCK_SIZE)
+			CopyReadBinaryGetDataBlock(cstate, FIELD_SIZE);
+
+		memcpy(&fld_size, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_size));
+		cstate->raw_buf_index += sizeof(fld_size);
+		*line_size += sizeof(fld_size);
+		fld_size = (int32) pg_ntoh32(fld_size);
+
+		/* fld_size -1 represents the null value for the field. */
+		if (fld_size == -1)
+			continue;
+
+		CHECK_FIELD_SIZE(fld_size);
+
+		*line_size += fld_size;
+
+		if ((DATA_BLOCK_SIZE - cstate->raw_buf_index) >= fld_size)
+		{
+			cstate->raw_buf_index += fld_size;
+			elog(DEBUG1, "LEADER - tuple lies in he same data block");
+		}
+		else
+		{
+			int32		required_blks = 0;
+			int32		curr_blk_bytes = (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+			int			i = 0;
+
+			GET_REQUIRED_BLOCKS(required_blks, fld_size, curr_blk_bytes);
+
+			i = required_blks;
+
+			while (i > 0)
+			{
+				CopyReadBinaryGetDataBlock(cstate, FIELD_DATA);
+				i--;
+			}
+
+			GET_RAW_BUF_INDEX(cstate->raw_buf_index, fld_size, required_blks, curr_blk_bytes);
+
+			/*
+			 * raw_buf_index should never cross data block size, as the
+			 * required number of data blocks would have been obtained in the
+			 * above while loop.
+			 */
+			Assert(cstate->raw_buf_index <= DATA_BLOCK_SIZE);
+		}
+		cstate->cur_attname = NULL;
+	}
+}
+
+/*
+ * CopyReadBinaryTupleWorker
+ *
+ * Each worker reads data from data blocks caches the tuple data into local
+ * memory.
+ */
+bool
+CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls)
+{
+	int16		fld_count;
+	ListCell   *cur;
+	FmgrInfo   *in_functions = cstate->in_functions;
+	Oid		   *typioparams = cstate->typioparams;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+	bool 		done = false;
+
+	done = GetWorkerLine(cstate);
+	cstate->raw_buf_index = 0;
+
+	if (done && cstate->line_buf.len == 0)
+		return true;
+
+	memcpy(&fld_count, &cstate->line_buf.data[cstate->raw_buf_index], sizeof(fld_count));
+	fld_count = (int16) pg_ntoh16(fld_count);
+
+	CHECK_FIELD_COUNT;
+
+	cstate->raw_buf_index += sizeof(fld_count);
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			att_num = lfirst_int(cur);
+		int			m = att_num - 1;
+		Form_pg_attribute att = TupleDescAttr(tup_desc, m);
+
+		cstate->cur_attname = NameStr(att->attname);
+
+		values[m] = CopyReadBinaryAttributeWorker(cstate,
+												  &in_functions[m],
+												  typioparams[m],
+												  att->atttypmod,
+												  &nulls[m]);
+		cstate->cur_attname = NULL;
+	}
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryAttributeWorker
+ *
+ * Worker identifies and converts each attribute/column data from binary to
+ * the data type of attribute/column.
+ */
+Datum
+CopyReadBinaryAttributeWorker(CopyState cstate, FmgrInfo *flinfo,
+							  Oid typioparam, int32 typmod, bool *isnull)
+{
+	int32		fld_size;
+	Datum		result;
+
+	memcpy(&fld_size, &cstate->line_buf.data[cstate->raw_buf_index], sizeof(fld_size));
+	cstate->raw_buf_index += sizeof(fld_size);
+	fld_size = (int32) pg_ntoh32(fld_size);
+
+	/* fld_size -1 represents the null value for the field. */
+	if (fld_size == -1)
+	{
+		*isnull = true;
+		return ReceiveFunctionCall(flinfo, NULL, typioparam, typmod);
+	}
+
+	CHECK_FIELD_SIZE(fld_size);
+
+	/* Reset attribute_buf to empty, and load raw data in it */
+	resetStringInfo(&cstate->attribute_buf);
+
+	enlargeStringInfo(&cstate->attribute_buf, fld_size);
+
+	memcpy(&cstate->attribute_buf.data[0], &cstate->line_buf.data[cstate->raw_buf_index], fld_size);
+	cstate->raw_buf_index += fld_size;
+
+	cstate->attribute_buf.len = fld_size;
+	cstate->attribute_buf.data[fld_size] = '\0';
+
+	/* Call the column type's binary input converter */
+	result = ReceiveFunctionCall(flinfo, &cstate->attribute_buf,
+								 typioparam, typmod);
+
+	/* Trouble if it didn't eat the whole buffer */
+	if (cstate->attribute_buf.cursor != cstate->attribute_buf.len)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+				 errmsg("incorrect binary data format")));
+
+	*isnull = false;
+	return result;
+}
+
+/*
  * GetLinePosition
  *
  * Return the line position once the leader has populated the data.
diff --git a/src/test/regress/expected/copy2.out b/src/test/regress/expected/copy2.out
index c64f071..08ce743 100644
--- a/src/test/regress/expected/copy2.out
+++ b/src/test/regress/expected/copy2.out
@@ -301,18 +301,32 @@ It is "perfect".|
 "It is ""perfect"".","	"
 "",
 --test that we read consecutive LFs properly
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 COPY testnl FROM stdin CSV;
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+SELECT * FROM testnl;
+ a |          b           | c 
+---+----------------------+---
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+(2 rows)
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 COPY testeoc FROM stdin CSV;
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
 COPY testeoc TO stdout CSV;
 a\.
 \.b
 c\.d
 "\."
 -- test handling of nonstandard null marker that violates escaping rules
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 COPY testnull TO stdout WITH NULL AS E'\\0';
 1	\\0
@@ -327,6 +341,15 @@ SELECT * FROM testnull;
     | 
 (4 rows)
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 1);
+SELECT * FROM testnull;
+ a  | b  
+----+----
+ 42 | \0
+    | 
+(2 rows)
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -396,6 +419,34 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+SELECT * FROM vistest;
+ a  
+----
+ a2
+ b
+(2 rows)
+
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+COMMIT;
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 SELECT * FROM vistest;
  a 
@@ -456,7 +507,7 @@ SELECT * FROM vistest;
 (2 rows)
 
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -467,6 +518,8 @@ CREATE TEMP TABLE forcetest (
 -- should succeed with no effect ("b" remains an empty string, "c" remains NULL)
 BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 1);
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
  b |  c   
@@ -477,6 +530,8 @@ SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
 BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 1);
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
  c |  d   
@@ -533,6 +588,31 @@ select * from check_con_tbl;
    
 (2 rows)
 
+\d+ check_con_tbl
+                               Table "public.check_con_tbl"
+ Column |  Type   | Collation | Nullable | Default | Storage | Stats target | Description 
+--------+---------+-----------+----------+---------+---------+--------------+-------------
+ f1     | integer |           |          |         | plain   |              | 
+Check constraints:
+    "check_con_tbl_check" CHECK (check_con_function(check_con_tbl.*))
+
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 1);
+NOTICE:  input = {"f1":1}
+NOTICE:  input = {"f1":null}
+copy check_con_tbl from stdin with (parallel 1);
+NOTICE:  input = {"f1":0}
+ERROR:  new row for relation "check_con_tbl" violates check constraint "check_con_tbl_check"
+DETAIL:  Failing row contains (0).
+CONTEXT:  COPY check_con_tbl, line 1: "0"
+parallel worker
+select * from check_con_tbl;
+ f1 
+----
+  1
+   
+(2 rows)
+
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
 CREATE ROLE regress_rls_copy_user_colperms;
@@ -647,10 +727,248 @@ SELECT * FROM instead_of_insert_tbl;
 (2 rows)
 
 COMMIT;
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+COPY test_parallel_copy (a, b, c, d, e) FROM stdin WITH (PARALLEL 1);
+COPY test_parallel_copy (b, d) FROM stdin WITH (PARALLEL 1);
+COPY test_parallel_copy (b, d) FROM stdin WITH (PARALLEL 1);
+COPY test_parallel_copy (b, d) FROM stdin WITH (PARALLEL 1, FORMAT 'csv', HEADER);
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) FROM stdin WITH (PARALLEL '0');
+ERROR:  value 0 out of bounds for option "parallel"
+DETAIL:  Valid values are between "1" and "1024".
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri FROM stdin WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1) WHERE height > random() * 65;
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+-- temporary table copy: should perform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+COPY temp_test (a) FROM stdin WITH (PARALLEL 1);
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) FROM stdin WITH (PARALLEL 1);
+ERROR:  column "xyz" of relation "test_parallel_copy" does not exist
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) FROM stdin WITH (PARALLEL 1);
+ERROR:  column "d" specified more than once
+-- missing data: should fail
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+ERROR:  invalid input syntax for type integer: ""
+CONTEXT:  COPY test_parallel_copy, line 0, column a: ""
+parallel worker
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2000	230	23	23"
+parallel worker
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2001	231	\N	\N"
+parallel worker
+-- extra data: should fail
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+ERROR:  extra data after last expected column
+CONTEXT:  COPY test_parallel_copy, line 1: "2002	232	40	50	60	70	80"
+parallel worker
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) FROM stdin WITH (DELIMITER ',', null 'x', PARALLEL 1) ;
+COPY test_parallel_copy FROM stdin WITH (DELIMITER ';', NULL '', PARALLEL 1);
+COPY test_parallel_copy FROM stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL 1);
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a = 50004;
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a > 60003;
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE f > 60003;
+ERROR:  column "f" does not exist
+LINE 1: ..._parallel_copy FROM stdin WITH (PARALLEL 1) WHERE f > 60003;
+                                                             ^
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+ERROR:  missing FROM-clause entry for table "x"
+LINE 1: ...rallel_copy FROM stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+                                                                  ^
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a IN (SELECT 1 FROM x);
+ERROR:  cannot use subquery in COPY FROM WHERE condition
+LINE 1: ...arallel_copy FROM stdin WITH (PARALLEL 1) WHERE a IN (SELECT...
+                                                             ^
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a IN (generate_series(1,5));
+ERROR:  set-returning functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...lel_copy FROM stdin WITH (PARALLEL 1) WHERE a IN (generate_s...
+                                                             ^
+COPY test_parallel_copy FROM stdin WITH(PARALLEL 1) WHERE a = row_number() over(b);
+ERROR:  window functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...rallel_copy FROM stdin WITH(PARALLEL 1) WHERE a = row_number...
+                                                             ^
+-- check results of copy in
+SELECT * FROM test_parallel_copy ORDER BY 1;
+   a   | b  |     c      |    d    |    e    
+-------+----+------------+---------+---------
+     1 | 11 | test_c1    | test_d1 | test_e1
+     2 | 12 | test_c2    | test_d2 | test_e2
+  3000 |    | c          |         | 
+  4000 |    | C          |         | 
+  4001 |  1 | empty      |         | 
+  4002 |  2 | null       |         | 
+  4003 |  3 | Backslash  | \       | \
+  4004 |  4 | BackslashX | \X      | \X
+  4005 |  5 | N          | N       | N
+  4006 |  6 | BackslashN | \N      | \N
+  4007 |  7 | XX         | XX      | XX
+  4008 |  8 | Delimiter  | :       | :
+ 50004 | 25 | 35         | 45      | 55
+ 60004 | 25 | 35         | 45      | 55
+ 60005 | 26 | 36         | 46      | 56
+       |  3 | stuff      | test_d3 | 
+       |  4 | stuff      | test_d4 | 
+       |  5 | stuff      | test_d5 | 
+       |    | ,          | \,      | \
+       |    | x          | \x      | \x
+       |    | 45         | 80      | 90
+(21 rows)
+
+-- parallel copy test for unlogged tables. should execute in parallel worker
+CREATE UNLOGGED TABLE test_parallel_copy_unlogged(
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+);
+COPY test_parallel_copy_unlogged FROM stdin WITH (PARALLEL 1);
+SELECT count(*) FROM test_parallel_copy_unlogged;
+ count 
+-------
+     2
+(1 row)
+
+-- parallel copy test for various trigger types
+TRUNCATE test_parallel_copy;
+-- parallel safe trigger function
+CREATE OR REPLACE FUNCTION parallel_copy_trig_func() RETURNS TRIGGER
+LANGUAGE plpgsql PARALLEL SAFE AS $$
+BEGIN
+  RETURN NEW;
+END;
+$$;
+-- before insert row trigger
+CREATE TRIGGER parallel_copy_trig
+BEFORE INSERT ON test_parallel_copy
+FOR EACH ROW
+EXECUTE PROCEDURE parallel_copy_trig_func();
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+-- after insert row trigger
+CREATE TRIGGER parallel_copy_trig
+AFTER INSERT ON test_parallel_copy
+FOR EACH ROW
+EXECUTE PROCEDURE parallel_copy_trig_func();
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+-- before insert statement trigger
+CREATE TRIGGER parallel_copy_trig
+BEFORE INSERT ON test_parallel_copy
+FOR EACH STATEMENT
+EXECUTE PROCEDURE parallel_copy_trig_func();
+-- parallelism should be picked, since the trigger function is parallel safe
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+-- after insert statement trigger
+CREATE TRIGGER parallel_copy_trig
+AFTER INSERT ON test_parallel_copy
+FOR EACH STATEMENT
+EXECUTE PROCEDURE parallel_copy_trig_func();
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+-- transition table is involved
+CREATE TRIGGER parallel_copy_trig
+AFTER INSERT ON test_parallel_copy REFERENCING NEW TABLE AS new_table
+FOR EACH STATEMENT
+EXECUTE PROCEDURE parallel_copy_trig_func();
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+-- make trigger function parallel unsafe
+ALTER FUNCTION parallel_copy_trig_func PARALLEL UNSAFE;
+-- before statement trigger has a parallel unsafe function
+CREATE TRIGGER parallel_copy_trig
+BEFORE INSERT ON test_parallel_copy
+FOR EACH STATEMENT
+EXECUTE PROCEDURE parallel_copy_trig_func();
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+SELECT count(*) FROM test_parallel_copy;
+ count 
+-------
+    12
+(1 row)
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+-- instead of insert trigger, no parallelism should be picked
+COPY instead_of_insert_tbl_view FROM stdin WITH(PARALLEL 1);;
+SELECT count(*) FROM instead_of_insert_tbl_view;
+ count 
+-------
+     1
+(1 row)
+
+-- parallel copy test for a partitioned table with a before insert trigger on
+-- one of the partition
+ALTER FUNCTION parallel_copy_trig_func PARALLEL SAFE;
+CREATE TABLE test_parallel_copy_part (
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+) PARTITION BY LIST (b);
+CREATE TABLE test_parallel_copy_part_a1 (c TEXT, b INT, a INT, e TEXT, d TEXT);
+CREATE TABLE test_parallel_copy_part_a2 (a INT, c TEXT, b INT, d TEXT, e TEXT);
+ALTER TABLE test_parallel_copy_part ATTACH PARTITION test_parallel_copy_part_a1 FOR VALUES IN(1);
+ALTER TABLE test_parallel_copy_part ATTACH PARTITION test_parallel_copy_part_a2 FOR VALUES IN(2);
+CREATE TRIGGER parallel_copy_trig
+BEFORE INSERT ON test_parallel_copy_part_a2
+FOR EACH ROW
+EXECUTE PROCEDURE parallel_copy_trig_func();
+COPY test_parallel_copy_part FROM stdin WITH (PARALLEL 1);
+ERROR:  cannot perform PARALLEL COPY if partition has BEFORE/INSTEAD OF triggers, or if the partition is foreign partition
+HINT:  Try COPY without PARALLEL option
+CONTEXT:  COPY test_parallel_copy_part, line 2: "2	2	test_c2	test_d2	test_e2"
+parallel worker
+SELECT count(*) FROM test_parallel_copy_part;
+ count 
+-------
+     0
+(1 row)
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy_part_a2;
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE test_parallel_copy_unlogged;
+DROP TABLE test_parallel_copy_part;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
+DROP FUNCTION parallel_copy_trig_func();
 DROP TABLE x, y;
 DROP TABLE rls_t1 CASCADE;
 DROP ROLE regress_rls_copy_user;
diff --git a/src/test/regress/input/copy.source b/src/test/regress/input/copy.source
index a1d529a..cb39c66 100644
--- a/src/test/regress/input/copy.source
+++ b/src/test/regress/input/copy.source
@@ -15,6 +15,13 @@ DELETE FROM onek;
 
 COPY onek FROM '@abs_builddir@/results/onek.data';
 
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+
+SELECT COUNT(*) FROM tenk1;
+
+TRUNCATE tenk1;
+
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
@@ -159,6 +166,30 @@ truncate parted_copytest;
 
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
 
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
+
+-- Test parallel copy from for toast table with csv and binary format file
+create table test_parallel_copy_toast(a1 int, b1 text, c1 text default null);
+
+insert into test_parallel_copy_toast select i, (repeat(md5(i::text), 100000)) FROM generate_series(1,2) AS i;
+
+copy test_parallel_copy_toast to '@abs_builddir@/results/parallelcopytoast.csv' with(format csv);
+
+copy test_parallel_copy_toast to '@abs_builddir@/results/parallelcopytoast.dat' with(format binary);
+
+truncate test_parallel_copy_toast;
+
+copy test_parallel_copy_toast from '@abs_builddir@/results/parallelcopytoast.csv' with(format csv, parallel 2);
+
+copy test_parallel_copy_toast from '@abs_builddir@/results/parallelcopytoast.dat' with(format binary, parallel 2);
+
+select count(*) from test_parallel_copy_toast;
+
+drop table test_parallel_copy_toast;
+
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/output/copy.source b/src/test/regress/output/copy.source
index 938d355..a5dca79 100644
--- a/src/test/regress/output/copy.source
+++ b/src/test/regress/output/copy.source
@@ -9,6 +9,15 @@ COPY onek FROM '@abs_srcdir@/data/onek.data';
 COPY onek TO '@abs_builddir@/results/onek.data';
 DELETE FROM onek;
 COPY onek FROM '@abs_builddir@/results/onek.data';
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+SELECT COUNT(*) FROM tenk1;
+ count 
+-------
+ 10000
+(1 row)
+
+TRUNCATE tenk1;
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
 COPY person FROM '@abs_srcdir@/data/person.data';
@@ -113,6 +122,24 @@ insert into parted_copytest select x,1,'One' from generate_series(1011,1020) x;
 copy (select * from parted_copytest order by a) to '@abs_builddir@/results/parted_copytest.csv';
 truncate parted_copytest;
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
+-- Test parallel copy from for toast table with csv and binary format file
+create table test_parallel_copy_toast(a1 int, b1 text, c1 text default null);
+insert into test_parallel_copy_toast select i, (repeat(md5(i::text), 100000)) FROM generate_series(1,2) AS i;
+copy test_parallel_copy_toast to '@abs_builddir@/results/parallelcopytoast.csv' with(format csv);
+copy test_parallel_copy_toast to '@abs_builddir@/results/parallelcopytoast.dat' with(format binary);
+truncate test_parallel_copy_toast;
+copy test_parallel_copy_toast from '@abs_builddir@/results/parallelcopytoast.csv' with(format csv, parallel 2);
+copy test_parallel_copy_toast from '@abs_builddir@/results/parallelcopytoast.dat' with(format binary, parallel 2);
+select count(*) from test_parallel_copy_toast;
+ count 
+-------
+     4
+(1 row)
+
+drop table test_parallel_copy_toast;
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/sql/copy2.sql b/src/test/regress/sql/copy2.sql
index b3c16af..b3c9af3 100644
--- a/src/test/regress/sql/copy2.sql
+++ b/src/test/regress/sql/copy2.sql
@@ -171,7 +171,7 @@ COPY y TO stdout (FORMAT CSV, FORCE_QUOTE *);
 
 --test that we read consecutive LFs properly
 
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 
 COPY testnl FROM stdin CSV;
 1,"a field with two LFs
@@ -179,8 +179,16 @@ COPY testnl FROM stdin CSV;
 inside",2
 \.
 
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+1,"a field with two LFs
+
+inside",2
+\.
+
+SELECT * FROM testnl;
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 
 COPY testeoc FROM stdin CSV;
 a\.
@@ -189,11 +197,19 @@ c\.d
 "\."
 \.
 
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+a\.
+\.b
+c\.d
+"\."
+\.
+
 COPY testeoc TO stdout CSV;
 
 -- test handling of nonstandard null marker that violates escaping rules
 
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 
 COPY testnull TO stdout WITH NULL AS E'\\0';
@@ -205,6 +221,14 @@ COPY testnull FROM stdin WITH NULL AS E'\\0';
 
 SELECT * FROM testnull;
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 1);
+42	\\0
+\0	\0
+\.
+
+SELECT * FROM testnull;
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -249,6 +273,23 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+a2
+b
+\.
+SELECT * FROM vistest;
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+d2
+e
+\.
+SELECT * FROM vistest;
+COMMIT;
+SELECT * FROM vistest;
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 x
 y
@@ -298,7 +339,7 @@ SELECT * FROM vistest;
 COMMIT;
 SELECT * FROM vistest;
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -311,6 +352,10 @@ BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
 1,,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 1);
+1,,""
+\.
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
@@ -318,6 +363,10 @@ BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
 2,'a',,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 1);
+2,'a',,""
+\.
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
 -- should fail with not-null constraint violation
@@ -353,6 +402,16 @@ copy check_con_tbl from stdin;
 0
 \.
 select * from check_con_tbl;
+\d+ check_con_tbl
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 1);
+1
+\N
+\.
+copy check_con_tbl from stdin with (parallel 1);
+0
+\.
+select * from check_con_tbl;
 
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
@@ -454,10 +513,311 @@ test1
 SELECT * FROM instead_of_insert_tbl;
 COMMIT;
 
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+
+COPY test_parallel_copy (a, b, c, d, e) FROM stdin WITH (PARALLEL 1);
+1	11	test_c1	test_d1	test_e1
+2	12	test_c2	test_d2	test_e2
+\.
+
+COPY test_parallel_copy (b, d) FROM stdin WITH (PARALLEL 1);
+3	test_d3
+\.
+
+COPY test_parallel_copy (b, d) FROM stdin WITH (PARALLEL 1);
+4	test_d4
+5	test_d5
+\.
+
+COPY test_parallel_copy (b, d) FROM stdin WITH (PARALLEL 1, FORMAT 'csv', HEADER);
+b	d
+\.
+
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) FROM stdin WITH (PARALLEL '0');
+
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri FROM stdin WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+10
+\.
+
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1) WHERE height > random() * 65;
+60,60,60
+\.
+
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+60
+\.
+
+-- temporary table copy: should perform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+
+COPY temp_test (a) FROM stdin WITH (PARALLEL 1);
+10
+\.
+
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) FROM stdin WITH (PARALLEL 1);
+
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) FROM stdin WITH (PARALLEL 1);
+
+-- missing data: should fail
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+
+\.
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+2000	230	23	23
+\.
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+2001	231	\N	\N
+\.
+
+-- extra data: should fail
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+2002	232	40	50	60	70	80
+\.
+
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) FROM stdin WITH (DELIMITER ',', null 'x', PARALLEL 1) ;
+x,45,80,90
+x,\x,\\x,\\\x
+x,\,,\\\,,\\
+\.
+
+COPY test_parallel_copy FROM stdin WITH (DELIMITER ';', NULL '', PARALLEL 1);
+3000;;c;;
+\.
+
+COPY test_parallel_copy FROM stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL 1);
+4000:\X:C:\X:\X
+4001:1:empty::
+4002:2:null:\X:\X
+4003:3:Backslash:\\:\\
+4004:4:BackslashX:\\X:\\X
+4005:5:N:\N:\N
+4006:6:BackslashN:\\N:\\N
+4007:7:XX:\XX:\XX
+4008:8:Delimiter:\::\:
+\.
+
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a = 50004;
+50003	24	34	44	54
+50004	25	35	45 	55
+50005	26	36	46	56
+\.
+
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a > 60003;
+60001	22	32	42	52
+60002	23	33	43	53
+60003	24	34	44	54
+60004	25	35	45	55
+60005	26	36	46	56
+\.
+
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE f > 60003;
+
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a IN (SELECT 1 FROM x);
+
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a IN (generate_series(1,5));
+
+COPY test_parallel_copy FROM stdin WITH(PARALLEL 1) WHERE a = row_number() over(b);
+
+-- check results of copy in
+SELECT * FROM test_parallel_copy ORDER BY 1;
+
+-- parallel copy test for unlogged tables. should execute in parallel worker
+CREATE UNLOGGED TABLE test_parallel_copy_unlogged(
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+);
+
+COPY test_parallel_copy_unlogged FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+SELECT count(*) FROM test_parallel_copy_unlogged;
+
+-- parallel copy test for various trigger types
+TRUNCATE test_parallel_copy;
+
+-- parallel safe trigger function
+CREATE OR REPLACE FUNCTION parallel_copy_trig_func() RETURNS TRIGGER
+LANGUAGE plpgsql PARALLEL SAFE AS $$
+BEGIN
+  RETURN NEW;
+END;
+$$;
+
+-- before insert row trigger
+CREATE TRIGGER parallel_copy_trig
+BEFORE INSERT ON test_parallel_copy
+FOR EACH ROW
+EXECUTE PROCEDURE parallel_copy_trig_func();
+
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+
+-- after insert row trigger
+CREATE TRIGGER parallel_copy_trig
+AFTER INSERT ON test_parallel_copy
+FOR EACH ROW
+EXECUTE PROCEDURE parallel_copy_trig_func();
+
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+
+-- before insert statement trigger
+CREATE TRIGGER parallel_copy_trig
+BEFORE INSERT ON test_parallel_copy
+FOR EACH STATEMENT
+EXECUTE PROCEDURE parallel_copy_trig_func();
+
+-- parallelism should be picked, since the trigger function is parallel safe
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+
+-- after insert statement trigger
+CREATE TRIGGER parallel_copy_trig
+AFTER INSERT ON test_parallel_copy
+FOR EACH STATEMENT
+EXECUTE PROCEDURE parallel_copy_trig_func();
+
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+
+-- transition table is involved
+CREATE TRIGGER parallel_copy_trig
+AFTER INSERT ON test_parallel_copy REFERENCING NEW TABLE AS new_table
+FOR EACH STATEMENT
+EXECUTE PROCEDURE parallel_copy_trig_func();
+
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+
+-- make trigger function parallel unsafe
+ALTER FUNCTION parallel_copy_trig_func PARALLEL UNSAFE;
+
+-- before statement trigger has a parallel unsafe function
+CREATE TRIGGER parallel_copy_trig
+BEFORE INSERT ON test_parallel_copy
+FOR EACH STATEMENT
+EXECUTE PROCEDURE parallel_copy_trig_func();
+
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+SELECT count(*) FROM test_parallel_copy;
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+
+-- instead of insert trigger, no parallelism should be picked
+COPY instead_of_insert_tbl_view FROM stdin WITH(PARALLEL 1);;
+test1
+\.
+
+SELECT count(*) FROM instead_of_insert_tbl_view;
+
+-- parallel copy test for a partitioned table with a before insert trigger on
+-- one of the partition
+ALTER FUNCTION parallel_copy_trig_func PARALLEL SAFE;
+
+CREATE TABLE test_parallel_copy_part (
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+) PARTITION BY LIST (b);
+
+CREATE TABLE test_parallel_copy_part_a1 (c TEXT, b INT, a INT, e TEXT, d TEXT);
+
+CREATE TABLE test_parallel_copy_part_a2 (a INT, c TEXT, b INT, d TEXT, e TEXT);
+
+ALTER TABLE test_parallel_copy_part ATTACH PARTITION test_parallel_copy_part_a1 FOR VALUES IN(1);
+
+ALTER TABLE test_parallel_copy_part ATTACH PARTITION test_parallel_copy_part_a2 FOR VALUES IN(2);
+
+CREATE TRIGGER parallel_copy_trig
+BEFORE INSERT ON test_parallel_copy_part_a2
+FOR EACH ROW
+EXECUTE PROCEDURE parallel_copy_trig_func();
+
+COPY test_parallel_copy_part FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+SELECT count(*) FROM test_parallel_copy_part;
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy_part_a2;
+
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE test_parallel_copy_unlogged;
+DROP TABLE test_parallel_copy_part;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
+DROP FUNCTION parallel_copy_trig_func();
 DROP TABLE x, y;
 DROP TABLE rls_t1 CASCADE;
 DROP ROLE regress_rls_copy_user;
-- 
1.8.3.1

v8-0006-Parallel-Copy-For-Binary-Format-Files.patchtext/x-patch; charset=US-ASCII; name=v8-0006-Parallel-Copy-For-Binary-Format-Files.patchDownload
From 93042e3cab8e9a4f067e5f74b0dc67b0a6df2886 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 21 Oct 2020 11:33:36 +0530
Subject: [PATCH v8 6/6] Parallel Copy For Binary Format Files

Leader reads data from the file into the DSM data blocks each of 64K size.
It also identifies each tuple data block id, start offset, end offset,
tuple size and updates this information in the ring data structure.
Workers parallelly read the tuple information from the ring data structure,
the actual tuple data from the data blocks and parallelly insert the tuples
into the table.
---
 src/backend/commands/copy.c | 126 ++++++++++++++++++++------------------------
 src/include/commands/copy.h | 126 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 184 insertions(+), 68 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index e613fc0..5894b28 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -222,19 +222,14 @@ static void CopySendData(CopyState cstate, const void *databuf, int datasize);
 static void CopySendString(CopyState cstate, const char *str);
 static void CopySendChar(CopyState cstate, char c);
 static void CopySendEndOfRow(CopyState cstate);
-static int	CopyGetData(CopyState cstate, void *databuf,
-						int minread, int maxread);
 static void CopySendInt32(CopyState cstate, int32 val);
 static bool CopyGetInt32(CopyState cstate, int32 *val);
 static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 static bool CopyLoadRawBuf(CopyState cstate);
-static int	CopyReadBinaryData(CopyState cstate, char *dest, int nbytes);
-
 static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
 								   int copy_line_pos, int *copy_line_size);
 
-
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
  * in past protocol redesigns.
@@ -448,7 +443,7 @@ CopySendEndOfRow(CopyState cstate)
  *
  * NB: no data conversion is applied here.
  */
-static int
+int
 CopyGetData(CopyState cstate, void *databuf, int minread, int maxread)
 {
 	int			bytesread = 0;
@@ -581,10 +576,25 @@ CopyGetInt32(CopyState cstate, int32 *val)
 {
 	uint32		buf;
 
-	if (CopyReadBinaryData(cstate, (char *) &buf, sizeof(buf)) != sizeof(buf))
+	/*
+	 * For parallel copy, avoid reading data to raw buf, read directly from
+	 * file, later the data will be read to parallel copy data buffers.
+	 */
+	if (cstate->nworkers > 0)
 	{
-		*val = 0;				/* suppress compiler warning */
-		return false;
+		if (CopyGetData(cstate, &buf, sizeof(buf), sizeof(buf)) != sizeof(buf))
+		{
+			*val = 0;			/* suppress compiler warning */
+			return false;
+		}
+	}
+	else
+	{
+		if (CopyReadBinaryData(cstate, (char *) &buf, sizeof(buf)) != sizeof(buf))
+		{
+			*val = 0;			/* suppress compiler warning */
+			return false;
+		}
 	}
 	*val = (int32) pg_ntoh32(buf);
 	return true;
@@ -658,7 +668,7 @@ CopyLoadRawBuf(CopyState cstate)
  * and writes them to 'dest'.  Returns the number of bytes read (which
  * would be less than 'nbytes' only if we reach EOF).
  */
-static int
+int
 CopyReadBinaryData(CopyState cstate, char *dest, int nbytes)
 {
 	int			copied_bytes = 0;
@@ -3539,7 +3549,7 @@ BeginCopyFrom(ParseState *pstate,
 		int32		tmp;
 
 		/* Signature */
-		if (CopyReadBinaryData(cstate, readSig, 11) != 11 ||
+		if (CopyGetData(cstate, readSig, 11, 11) != 11 ||
 			memcmp(readSig, BinarySignature, 11) != 0)
 			ereport(ERROR,
 					(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
@@ -3567,7 +3577,7 @@ BeginCopyFrom(ParseState *pstate,
 		/* Skip extension header, if present */
 		while (tmp-- > 0)
 		{
-			if (CopyReadBinaryData(cstate, readSig, 1) != 1)
+			if (CopyGetData(cstate, readSig, 1, 1) != 1)
 				ereport(ERROR,
 						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
 						 errmsg("invalid COPY file header (wrong length)")));
@@ -3764,60 +3774,45 @@ NextCopyFrom(CopyState cstate, ExprContext *econtext,
 	else
 	{
 		/* binary */
-		int16		fld_count;
-		ListCell   *cur;
-
 		cstate->cur_lineno++;
+		cstate->max_fields = list_length(cstate->attnumlist);
 
-		if (!CopyGetInt16(cstate, &fld_count))
+		if (!IsParallelCopy())
 		{
-			/* EOF detected (end of file, or protocol-level EOF) */
-			return false;
-		}
-
-		if (fld_count == -1)
-		{
-			/*
-			 * Received EOF marker.  In a V3-protocol copy, wait for the
-			 * protocol-level EOF, and complain if it doesn't come
-			 * immediately.  This ensures that we correctly handle CopyFail,
-			 * if client chooses to send that now.
-			 *
-			 * Note that we MUST NOT try to read more data in an old-protocol
-			 * copy, since there is no protocol-level EOF marker then.  We
-			 * could go either way for copy from file, but choose to throw
-			 * error if there's data after the EOF marker, for consistency
-			 * with the new-protocol case.
-			 */
-			char		dummy;
+			int16		fld_count;
+			ListCell   *cur;
 
-			if (cstate->copy_dest != COPY_OLD_FE &&
-				CopyReadBinaryData(cstate, &dummy, 1) > 0)
-				ereport(ERROR,
-						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-						 errmsg("received copy data after EOF marker")));
-			return false;
-		}
+			if (!CopyGetInt16(cstate, &fld_count))
+			{
+				/* EOF detected (end of file, or protocol-level EOF) */
+				return false;
+			}
 
-		if (fld_count != attr_count)
-			ereport(ERROR,
-					(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-					 errmsg("row field count is %d, expected %d",
-							(int) fld_count, attr_count)));
+			CHECK_FIELD_COUNT;
 
-		foreach(cur, cstate->attnumlist)
+			foreach(cur, cstate->attnumlist)
+			{
+				int			attnum = lfirst_int(cur);
+				int			m = attnum - 1;
+				Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+
+				cstate->cur_attname = NameStr(att->attname);
+				values[m] = CopyReadBinaryAttribute(cstate,
+													&in_functions[m],
+													typioparams[m],
+													att->atttypmod,
+													&nulls[m]);
+				cstate->cur_attname = NULL;
+			}
+		}
+		else
 		{
-			int			attnum = lfirst_int(cur);
-			int			m = attnum - 1;
-			Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+			bool		eof = false;
 
-			cstate->cur_attname = NameStr(att->attname);
-			values[m] = CopyReadBinaryAttribute(cstate,
-												&in_functions[m],
-												typioparams[m],
-												att->atttypmod,
-												&nulls[m]);
-			cstate->cur_attname = NULL;
+			eof = CopyReadBinaryTupleWorker(cstate, values, nulls);
+
+			if (eof)
+				return false;
 		}
 	}
 
@@ -4828,18 +4823,15 @@ CopyReadBinaryAttribute(CopyState cstate, FmgrInfo *flinfo,
 	Datum		result;
 
 	if (!CopyGetInt32(cstate, &fld_size))
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("unexpected EOF in COPY data")));
+		EOF_ERROR;
+
 	if (fld_size == -1)
 	{
 		*isnull = true;
 		return ReceiveFunctionCall(flinfo, NULL, typioparam, typmod);
 	}
-	if (fld_size < 0)
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("invalid field size")));
+
+	CHECK_FIELD_SIZE(fld_size);
 
 	/* reset attribute_buf to empty, and load raw data in it */
 	resetStringInfo(&cstate->attribute_buf);
@@ -4847,9 +4839,7 @@ CopyReadBinaryAttribute(CopyState cstate, FmgrInfo *flinfo,
 	enlargeStringInfo(&cstate->attribute_buf, fld_size);
 	if (CopyReadBinaryData(cstate, cstate->attribute_buf.data,
 						   fld_size) != fld_size)
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("unexpected EOF in COPY data")));
+		EOF_ERROR;
 
 	cstate->attribute_buf.len = fld_size;
 	cstate->attribute_buf.data[fld_size] = '\0';
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index 9b19dcb..49f438f 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -59,6 +59,109 @@
 
 
 /*
+ * CHECK_FIELD_COUNT - Handles the error cases for field count
+ * for binary format files.
+ */
+#define CHECK_FIELD_COUNT \
+{\
+	if (fld_count == -1) \
+	{ \
+		if (IsParallelCopy() && \
+			!IsLeader()) \
+			return true; \
+		else if (IsParallelCopy() && \
+			IsLeader()) \
+		{ \
+			if (cstate->pcdata->curr_data_block->data[cstate->raw_buf_index + sizeof(fld_count)] != 0) \
+				ereport(ERROR, \
+						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+						errmsg("received copy data after EOF marker"))); \
+			return true; \
+		} \
+		else \
+		{ \
+			/* \
+			 * Received EOF marker.  In a V3-protocol copy, wait for the \
+			 * protocol-level EOF, and complain if it doesn't come \
+			 * immediately.  This ensures that we correctly handle CopyFail, \
+			 * if client chooses to send that now. \
+			 * \
+			 * Note that we MUST NOT try to read more data in an old-protocol \
+			 * copy, since there is no protocol-level EOF marker then.  We \
+			 * could go either way for copy from file, but choose to throw \
+			 * error if there's data after the EOF marker, for consistency \
+			 * with the new-protocol case. \
+			 */ \
+			char		dummy; \
+			if (cstate->copy_dest != COPY_OLD_FE && \
+				CopyReadBinaryData(cstate, &dummy, 1) > 0) \
+				ereport(ERROR, \
+						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+						errmsg("received copy data after EOF marker"))); \
+				return false; \
+		} \
+	} \
+	if (fld_count != cstate->max_fields) \
+		ereport(ERROR, \
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+				errmsg("row field count is %d, expected %d", \
+				(int) fld_count, cstate->max_fields))); \
+}
+
+/*
+ * CHECK_FIELD_SIZE - Handles the error case for field size
+ * for binary format files.
+ */
+#define CHECK_FIELD_SIZE(fld_size) \
+{ \
+	if (fld_size < -1) \
+		ereport(ERROR, \
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+				errmsg("invalid field size")));\
+}
+
+/*
+ * EOF_ERROR - Error statement for EOF for binary format
+ * files.
+ */
+#define EOF_ERROR \
+{ \
+	ereport(ERROR, \
+		(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+		errmsg("unexpected EOF in COPY data")));\
+}
+
+/*
+ * GET_RAW_BUF_INDEX - Calculates the raw buf index for the cases
+ * where the data spread is across multiple data blocks.
+ */
+#define GET_RAW_BUF_INDEX(raw_buf_index, fld_size, required_blks, curr_blk_bytes) \
+{ \
+	raw_buf_index = fld_size - (((required_blks - 1) * DATA_BLOCK_SIZE) + curr_blk_bytes); \
+}
+
+/*
+ * GET_REQUIRED_BLOCKS - Calculates the number of data
+ * blocks required for the cases where the data spread
+ * is across multiple data blocks.
+ */
+#define GET_REQUIRED_BLOCKS(required_blks, fld_size, curr_blk_bytes) \
+{ \
+	/* \
+	 * field size can spread across multiple data blocks, \
+	 * calculate the number of required data blocks and try to get \
+	 * those many data blocks. \
+	 */ \
+	required_blks = (int32)(fld_size - curr_blk_bytes)/(int32)DATA_BLOCK_SIZE; \
+	/* \
+	 * check if we need the data block for the field data \
+	 * bytes that are not modulus of data block size. \
+	 */ \
+	if ((fld_size - curr_blk_bytes)%DATA_BLOCK_SIZE != 0) \
+		required_blks++; \
+}
+
+/*
  * Represents the different source/dest cases we need to worry about at
  * the bottom level
  */
@@ -236,6 +339,17 @@ typedef struct ParallelCopyLineBuf
 } ParallelCopyLineBuf;
 
 /*
+ * Represents the usage mode for CopyReadBinaryGetDataBlock.
+ */
+typedef enum FieldInfoType
+{
+	FIELD_NONE = 0,
+	FIELD_COUNT,
+	FIELD_SIZE,
+	FIELD_DATA
+}			FieldInfoType;
+
+/*
  * This structure helps in storing the common data from CopyStateData that are
  * required by the workers. This information will then be allocated and stored
  * into the DSM for the worker to retrieve and copy it to CopyStateData.
@@ -258,6 +372,7 @@ typedef struct SerializedParallelCopyState
 	/* Working state for COPY FROM */
 	AttrNumber	num_defaults;
 	Oid			relid;
+	bool		binary;
 } SerializedParallelCopyState;
 
 /*
@@ -284,6 +399,9 @@ typedef struct ParallelCopyData
 
 	/* Current position in worker_line_buf */
 	uint32		worker_line_buf_pos;
+
+	/* For binary formatted files */
+	ParallelCopyDataBlock *curr_data_block;
 } ParallelCopyData;
 
 typedef int (*copy_data_source_cb) (void *outbuf, int minread, int maxread);
@@ -470,4 +588,12 @@ extern uint32 UpdateSharedLineInfo(CopyState cstate, uint32 blk_pos, uint32 offs
 								   uint32 line_size, uint32 line_state, uint32 blk_line_pos);
 extern void EndLineParallelCopy(CopyState cstate, uint32 line_pos, uint32 line_size,
 								uint32 raw_buf_ptr);
+extern int	CopyGetData(CopyState cstate, void *databuf, int minread, int maxread);
+extern int	CopyReadBinaryData(CopyState cstate, char *dest, int nbytes);
+extern bool CopyReadBinaryTupleLeader(CopyState cstate);
+extern bool CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls);
+extern void CopyReadBinaryFindTupleSize(CopyState cstate, uint32 *line_size);
+extern Datum CopyReadBinaryAttributeWorker(CopyState cstate, FmgrInfo *flinfo,
+										   Oid typioparam, int32 typmod, bool *isnull);
+extern void CopyReadBinaryGetDataBlock(CopyState cstate, FieldInfoType field_info);
 #endif							/* COPY_H */
-- 
1.8.3.1

#185vignesh C
vignesh21@gmail.com
In reply to: vignesh C (#164)
Re: Parallel copy

On Thu, Oct 8, 2020 at 11:15 AM vignesh C <vignesh21@gmail.com> wrote:

I'm summarizing the pending open points so that I don't miss anything:
1) Performance test on latest patch set.

It is tested and results are shared by bharath at [1]/messages/by-id/CALj2ACWeQVd-xoQZHGT01_33St4xPoZQibWz46o7jW1PE3XOqQ@mail.gmail.com

2) Testing points suggested.

Tests are added as suggested and details shared by bharath at [1]/messages/by-id/CALj2ACWeQVd-xoQZHGT01_33St4xPoZQibWz46o7jW1PE3XOqQ@mail.gmail.com

3) Support of parallel copy for COPY_OLD_FE.

It is handled as part of v8 patch shared at [2]/messages/by-id/CALDaNm2UcmCMozcbKL8B7az9oYd9hZ+fNDcZHSSiiQJ4v-xN0Q@mail.gmail.com

4) Worker has to hop through all the processed chunks before getting
the chunk which it can process.

Open

5) Handling of Tomas's comments.

I have fixed and updated the fix details as part of [3]/messages/by-id/CALDaNm0_zUa9+S=pwCz3Yp43SY3r9bnO4v-9ucXUujEE=0Sd7g@mail.gmail.com

6) Handling of Greg's comments.

I have fixed and updated the fix details as part of [4]/messages/by-id/CALDaNm31pGG+L9N4HbM0mO4iuceih4mJ5s87jEwOPaFLpmDKyQ@mail.gmail.com

Except for "4) Worker has to hop through all the processed chunks before
getting the chunk which it can process", all open tasks are handled. I will
work on this and provide an update shortly.

[1]: /messages/by-id/CALj2ACWeQVd-xoQZHGT01_33St4xPoZQibWz46o7jW1PE3XOqQ@mail.gmail.com
/messages/by-id/CALj2ACWeQVd-xoQZHGT01_33St4xPoZQibWz46o7jW1PE3XOqQ@mail.gmail.com
[2]: /messages/by-id/CALDaNm2UcmCMozcbKL8B7az9oYd9hZ+fNDcZHSSiiQJ4v-xN0Q@mail.gmail.com
/messages/by-id/CALDaNm2UcmCMozcbKL8B7az9oYd9hZ+fNDcZHSSiiQJ4v-xN0Q@mail.gmail.com
[3]: /messages/by-id/CALDaNm0_zUa9+S=pwCz3Yp43SY3r9bnO4v-9ucXUujEE=0Sd7g@mail.gmail.com
/messages/by-id/CALDaNm0_zUa9+S=pwCz3Yp43SY3r9bnO4v-9ucXUujEE=0Sd7g@mail.gmail.com
[4]: /messages/by-id/CALDaNm31pGG+L9N4HbM0mO4iuceih4mJ5s87jEwOPaFLpmDKyQ@mail.gmail.com
/messages/by-id/CALDaNm31pGG+L9N4HbM0mO4iuceih4mJ5s87jEwOPaFLpmDKyQ@mail.gmail.com

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

#186Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: vignesh C (#185)
Re: Parallel copy

Hi Vignesh,

I took a look at the v8 patch set. Here are some comments:

1. PopulateCommonCstateInfo() -- can we use PopulateCommonCStateInfo()
or PopulateCopyStateInfo()? And also EstimateCstateSize() --
EstimateCStateSize(), PopulateCstateCatalogInfo() --
PopulateCStateCatalogInfo()?

2. Instead of mentioning numbers like 1024, 64K, 10240 in the
comments, can we represent them in terms of macros?
/* It can hold 1024 blocks of 64K data in DSM to be processed by the worker. */
#define MAX_BLOCKS_COUNT 1024
/*
* It can hold upto 10240 record information for worker to process. RINGSIZE

3. How about
"
Each worker at once will pick the WORKER_CHUNK_COUNT records from the
DSM data blocks and store them in it's local memory.
This is to make workers not contend much while getting record
information from the DSM. Read RINGSIZE comments before
changing this value.
"
instead of
/*
* Each worker will be allocated WORKER_CHUNK_COUNT of records from DSM data
* block to process to avoid lock contention. Read RINGSIZE comments before
* changing this value.
*/

4. How about one line gap before and after for comments: "Leader
should operate in the following order:" and "Worker should operate in
the following order:"

5. Can we move RAW_BUF_BYTES macro definition to the beginning of the
copy.h where all the macro are defined?

6. I don't think we need the change in toast_internals.c with the
temporary hack Assert(!(IsParallelWorker() && !currentCommandIdUsed));
in GetCurrentCommandId()

7. I think
/* Can't perform copy in parallel */
if (parallel_workers <= 0)
return NULL;
can be
/* Can't perform copy in parallel */
if (parallel_workers == 0)
return NULL;
as parallel_workers can never be < 0 since we enter BeginParallelCopy
only if cstate->nworkers > 0 and also we are not allowed to have
negative values for max_worker_processes.

8. Do we want to pfree(cstate->pcdata) in case we failed to start any
parallel workers, we would have allocated a good
else
{
/*
* Reset nworkers to -1 here. This is useful in cases where user
* specifies parallel workers, but, no worker is picked up, so go
* back to non parallel mode value of nworkers.
*/
cstate->nworkers = -1;
*processed = CopyFrom(cstate); /* copy from file to database */
}

9. Instead of calling CopyStringToSharedMemory() for each string
variable, can't we just create a linked list of all the strings that
need to be copied into shm and call CopyStringToSharedMemory() only
once? We could avoid 5 function calls?

10. Similar to above comment: can we fill all the required
cstate->variables inside the function CopyNodeFromSharedMemory() and
call it only once? In each worker we could save overhead of 5 function
calls.

11. Looks like CopyStringFromSharedMemory() and
CopyNodeFromSharedMemory() do almost the same things except
stringToNode() and pfree(destptr);. Can we have a generic function
CopyFromSharedMemory() or something else and handle with flag "bool
isnode" to differentiate the two use cases?

12. Can we move below check to the end in IsParallelCopyAllowed()?
/* Check parallel safety of the trigger functions. */
if (cstate->rel->trigdesc != NULL &&
!CheckRelTrigFunParallelSafety(cstate->rel->trigdesc))
return false;

13. CacheLineInfo(): Instead of goto empty_data_line_update; how about
having this directly inside the if block as it's being used only once?

14. GetWorkerLine(): How about avoiding goto statements and replacing
the common code with a always static inline function or a macro?

15. UpdateSharedLineInfo(): Below line is misaligned.
lineInfo->first_block = blk_pos;
lineInfo->start_offset = offset;

16. ParallelCopyFrom(): Do we need CHECK_FOR_INTERRUPTS(); at the
start of for (;;)?

17. Remove extra lines after #define IsHeaderLine()
(cstate->header_line && cstate->cur_lineno == 1) in copy.h

With Regards,
Bharath Rupireddy.
EnterpriseDB: http://www.enterprisedb.com

#187Amit Kapila
amit.kapila16@gmail.com
In reply to: Bharath Rupireddy (#186)
Re: Parallel copy

On Wed, Oct 21, 2020 at 3:19 PM Bharath Rupireddy
<bharath.rupireddyforpostgres@gmail.com> wrote:

9. Instead of calling CopyStringToSharedMemory() for each string
variable, can't we just create a linked list of all the strings that
need to be copied into shm and call CopyStringToSharedMemory() only
once? We could avoid 5 function calls?

If we want to avoid different function calls then can't we just store
all these strings in a local structure and use it? That might improve
the other parts of code as well where we are using these as individual
parameters.

10. Similar to above comment: can we fill all the required
cstate->variables inside the function CopyNodeFromSharedMemory() and
call it only once? In each worker we could save overhead of 5 function
calls.

Yeah, that makes sense.

--
With Regards,
Amit Kapila.

#188Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Bharath Rupireddy (#186)
Re: Parallel copy

On Wed, Oct 21, 2020 at 3:18 PM Bharath Rupireddy
<bharath.rupireddyforpostgres@gmail.com> wrote:

17. Remove extra lines after #define IsHeaderLine()
(cstate->header_line && cstate->cur_lineno == 1) in copy.h

I missed one comment:

18. I think we need to treat the number of parallel workers as an
integer similar to the parallel option in vacuum.

postgres=# copy t1 from stdin with(parallel '1'); <<<<< - we
should not allow this.
Enter data to be copied followed by a newline.

postgres=# vacuum (parallel '1') t1;
ERROR: parallel requires an integer value

With Regards,
Bharath Rupireddy.
EnterpriseDB: http://www.enterprisedb.com

#189Heikki Linnakangas
hlinnaka@iki.fi
In reply to: vignesh C (#184)
Re: Parallel copy

I had a brief look at at this patch. Important work! A couple of first
impressions:

1. The split between patches
0002-Framework-for-leader-worker-in-parallel-copy.patch and
0003-Allow-copy-from-command-to-process-data-from-file.patch is quite
artificial. All the stuff introduced in the first is unused until the
second patch is applied. The first patch introduces a forward
declaration for ParallelCopyData(), but the function only comes in the
second patch. The comments in the first patch talk about
LINE_LEADER_POPULATING and LINE_LEADER_POPULATED, but the enum only
comes in the second patch. I think these have to merged into one. If you
want to split it somehow, I'd suggest having a separate patch just to
move CopyStateData from copy.c to copy.h. The subsequent patch would
then be easier to read as you could see more easily what's being added
to CopyStateData. Actually I think it would be better to have a new
header file, copy_internal.h, to hold CopyStateData and the other
structs, and keep copy.h as it is.

2. This desperately needs some kind of a high-level overview of how it
works. What is a leader, what is a worker? Which process does each step
of COPY processing, like reading from the file/socket, splitting the
input into lines, handling escapes, calling input functions, and
updating the heap and indexes? What data structures are used for the
communication? How does is the work synchronized between the processes?
There are comments on those individual aspects scattered in the patch,
but if you're not already familiar with it, you don't know where to
start. There's some of that in the commit message, but it needs to be
somewhere in the source code, maybe in a long comment at the top of
copyparallel.c.

3. I'm surprised there's a separate ParallelCopyLineBoundary struct for
every input line. Doesn't that incur a lot of synchronization overhead?
I haven't done any testing, this is just my gut feeling, but I assumed
you'd work in batches of, say, 100 or 1000 lines each.

- Heikki

#190Ashutosh Sharma
ashu.coek88@gmail.com
In reply to: vignesh C (#184)
Re: Parallel copy

Hi Vignesh,

Thanks for the updated patches. Here are some more comments that I can
find after reviewing your latest patches:

+/*
+ * This structure helps in storing the common data from CopyStateData that are
+ * required by the workers. This information will then be allocated and stored
+ * into the DSM for the worker to retrieve and copy it to CopyStateData.
+ */
+typedef struct SerializedParallelCopyState
+{
+   /* low-level state data */
+   CopyDest    copy_dest;      /* type of copy source/destination */
+   int         file_encoding;  /* file or remote side's character encoding */
+   bool        need_transcoding;   /* file encoding diff from server? */
+   bool        encoding_embeds_ascii;  /* ASCII can be non-first byte? */
+
...
...
+
+   /* Working state for COPY FROM */
+   AttrNumber  num_defaults;
+   Oid         relid;
+} SerializedParallelCopyState;

Can the above structure not be part of the CopyStateData structure? I
am just asking this question because all the fields present in the
above structure are also present in the CopyStateData structure. So,
including it in the CopyStateData structure will reduce the code
duplication and will also make CopyStateData a bit shorter.

--

+           pcxt = BeginParallelCopy(cstate->nworkers, cstate, stmt->attlist,
+                                    relid);

Do we need to pass cstate->nworkers and relid to BeginParallelCopy()
function when we are already passing cstate structure, using which
both of these information can be retrieved ?

--

+/* DSM keys for parallel copy.  */
+#define PARALLEL_COPY_KEY_SHARED_INFO              1
+#define PARALLEL_COPY_KEY_CSTATE                   2
+#define PARALLEL_COPY_WAL_USAGE                    3
+#define PARALLEL_COPY_BUFFER_USAGE                 4

DSM key names do not appear to be consistent. For shared info and
cstate structures, the key name is prefixed with "PARALLEL_COPY_KEY",
but for WalUsage and BufferUsage structures, it is prefixed with
"PARALLEL_COPY". I think it would be better to make them consistent.

--

if (resultRelInfo->ri_TrigDesc != NULL &&
(resultRelInfo->ri_TrigDesc->trig_insert_before_row ||
resultRelInfo->ri_TrigDesc->trig_insert_instead_row))
{
/*
* Can't support multi-inserts when there are any BEFORE/INSTEAD OF
* triggers on the table. Such triggers might query the table we're
* inserting into and act differently if the tuples that have already
* been processed and prepared for insertion are not there.
*/
insertMethod = CIM_SINGLE;
}
else if (proute != NULL && resultRelInfo->ri_TrigDesc != NULL &&
resultRelInfo->ri_TrigDesc->trig_insert_new_table)
{
/*
* For partitioned tables we can't support multi-inserts when there
* are any statement level insert triggers. It might be possible to
* allow partitioned tables with such triggers in the future, but for
* now, CopyMultiInsertInfoFlush expects that any before row insert
* and statement level insert triggers are on the same relation.
*/
insertMethod = CIM_SINGLE;
}
else if (resultRelInfo->ri_FdwRoutine != NULL ||
cstate->volatile_defexprs)
{
...
...

I think, if possible, all these if-else checks in CopyFrom() can be
moved to a single function which can probably be named as
IdentifyCopyInsertMethod() and this function can be called in
IsParallelCopyAllowed(). This will ensure that in case of Parallel
Copy when the leader has performed all these checks, the worker won't
do it again. I also feel that it will make the code look a bit
cleaner.

--

+void
+ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
+{
...
...
+   InstrEndParallelQuery(&bufferusage[ParallelWorkerNumber],
+                         &walusage[ParallelWorkerNumber]);
+
+   MemoryContextSwitchTo(oldcontext);
+   pfree(cstate);
+   return;
+}

It seems like you also need to delete the memory context
(cstate->copycontext) here.

--

+void
+ExecBeforeStmtTrigger(CopyState cstate)
+{
+   EState     *estate = CreateExecutorState();
+   ResultRelInfo *resultRelInfo;

This function has a lot of comments which have been copied as it is
from the CopyFrom function, I think it would be good to remove those
comments from here and mention that this code changes done in this
function has been taken from the CopyFrom function. If any queries
people may refer to the CopyFrom function. This will again avoid the
unnecessary code in the patch.

--

As Heikki rightly pointed out in his previous email, we need some high
level description of how Parallel Copy works somewhere in
copyparallel.c file. For reference, please see how a brief description
about parallel vacuum has been added in the vacuumlazy.c file.

* Lazy vacuum supports parallel execution with parallel worker processes. In
* a parallel vacuum, we perform both index vacuum and index cleanup with
* parallel worker processes. Individual indexes are processed by one vacuum
...
...

--
With Regards,
Ashutosh Sharma
EnterpriseDB:http://www.enterprisedb.com

Show quoted text

On Wed, Oct 21, 2020 at 12:08 PM vignesh C <vignesh21@gmail.com> wrote:

On Mon, Oct 19, 2020 at 2:40 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Sun, Oct 18, 2020 at 7:47 AM Hou, Zhijie <houzj.fnst@cn.fujitsu.com> wrote:

Hi Vignesh,

After having a look over the patch,
I have some suggestions for
0003-Allow-copy-from-command-to-process-data-from-file.patch.

1.

+static uint32
+EstimateCstateSize(ParallelContext *pcxt, CopyState cstate, List *attnamelist,
+                                  char **whereClauseStr, char **rangeTableStr,
+                                  char **attnameListStr, char **notnullListStr,
+                                  char **nullListStr, char **convertListStr)
+{
+       uint32          strsize = MAXALIGN(sizeof(SerializedParallelCopyState));
+
+       strsize += EstimateStringSize(cstate->null_print);
+       strsize += EstimateStringSize(cstate->delim);
+       strsize += EstimateStringSize(cstate->quote);
+       strsize += EstimateStringSize(cstate->escape);

It use function EstimateStringSize to get the strlen of null_print, delim, quote and escape.
But the length of null_print seems has been stored in null_print_len.
And delim/quote/escape must be 1 byte, so I think call strlen again seems unnecessary.

How about " strsize += sizeof(uint32) + cstate->null_print_len + 1"

+1. This seems like a good suggestion but add comments for
delim/quote/escape to indicate that we are considering one-byte for
each. I think this will obviate the need of function
EstimateStringSize. Another thing in this regard is that we normally
use add_size function to compute the size but I don't see that being
used in this and nearby computation. That helps us to detect overflow
of addition if any.

EstimateCstateSize()
{
..
+
+ strsize++;
..
}

Why do we need this additional one-byte increment? Does it make sense
to add a small comment for the same?

Changed it to handle null_print, delim, quote & escape accordingly in
the attached patch, the one byte increment is not required, I have
removed it.

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

#191Ashutosh Sharma
ashu.coek88@gmail.com
In reply to: Ashutosh Sharma (#190)
Re: Parallel copy

On Fri, Oct 23, 2020 at 5:42 PM Ashutosh Sharma <ashu.coek88@gmail.com> wrote:

Hi Vignesh,

Thanks for the updated patches. Here are some more comments that I can
find after reviewing your latest patches:

+/*
+ * This structure helps in storing the common data from CopyStateData that are
+ * required by the workers. This information will then be allocated and stored
+ * into the DSM for the worker to retrieve and copy it to CopyStateData.
+ */
+typedef struct SerializedParallelCopyState
+{
+   /* low-level state data */
+   CopyDest    copy_dest;      /* type of copy source/destination */
+   int         file_encoding;  /* file or remote side's character encoding */
+   bool        need_transcoding;   /* file encoding diff from server? */
+   bool        encoding_embeds_ascii;  /* ASCII can be non-first byte? */
+
...
...
+
+   /* Working state for COPY FROM */
+   AttrNumber  num_defaults;
+   Oid         relid;
+} SerializedParallelCopyState;

Can the above structure not be part of the CopyStateData structure? I
am just asking this question because all the fields present in the
above structure are also present in the CopyStateData structure. So,
including it in the CopyStateData structure will reduce the code
duplication and will also make CopyStateData a bit shorter.

--

+           pcxt = BeginParallelCopy(cstate->nworkers, cstate, stmt->attlist,
+                                    relid);

Do we need to pass cstate->nworkers and relid to BeginParallelCopy()
function when we are already passing cstate structure, using which
both of these information can be retrieved ?

--

+/* DSM keys for parallel copy.  */
+#define PARALLEL_COPY_KEY_SHARED_INFO              1
+#define PARALLEL_COPY_KEY_CSTATE                   2
+#define PARALLEL_COPY_WAL_USAGE                    3
+#define PARALLEL_COPY_BUFFER_USAGE                 4

DSM key names do not appear to be consistent. For shared info and
cstate structures, the key name is prefixed with "PARALLEL_COPY_KEY",
but for WalUsage and BufferUsage structures, it is prefixed with
"PARALLEL_COPY". I think it would be better to make them consistent.

--

if (resultRelInfo->ri_TrigDesc != NULL &&
(resultRelInfo->ri_TrigDesc->trig_insert_before_row ||
resultRelInfo->ri_TrigDesc->trig_insert_instead_row))
{
/*
* Can't support multi-inserts when there are any BEFORE/INSTEAD OF
* triggers on the table. Such triggers might query the table we're
* inserting into and act differently if the tuples that have already
* been processed and prepared for insertion are not there.
*/
insertMethod = CIM_SINGLE;
}
else if (proute != NULL && resultRelInfo->ri_TrigDesc != NULL &&
resultRelInfo->ri_TrigDesc->trig_insert_new_table)
{
/*
* For partitioned tables we can't support multi-inserts when there
* are any statement level insert triggers. It might be possible to
* allow partitioned tables with such triggers in the future, but for
* now, CopyMultiInsertInfoFlush expects that any before row insert
* and statement level insert triggers are on the same relation.
*/
insertMethod = CIM_SINGLE;
}
else if (resultRelInfo->ri_FdwRoutine != NULL ||
cstate->volatile_defexprs)
{
...
...

I think, if possible, all these if-else checks in CopyFrom() can be
moved to a single function which can probably be named as
IdentifyCopyInsertMethod() and this function can be called in
IsParallelCopyAllowed(). This will ensure that in case of Parallel
Copy when the leader has performed all these checks, the worker won't
do it again. I also feel that it will make the code look a bit
cleaner.

Just rewriting above comment to make it a bit more clear:

I think, if possible, all these if-else checks in CopyFrom() should be
moved to a separate function which can probably be named as
IdentifyCopyInsertMethod() and this function called from
IsParallelCopyAllowed() and CopyFrom() functions. It will only be
called from CopyFrom() when IsParallelCopy() returns false. This will
ensure that in case of Parallel Copy if the leader has performed all
these checks, the worker won't do it again. I also feel that having a
separate function containing all these checks will make the code look
a bit cleaner.

Show quoted text

--

+void
+ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
+{
...
...
+   InstrEndParallelQuery(&bufferusage[ParallelWorkerNumber],
+                         &walusage[ParallelWorkerNumber]);
+
+   MemoryContextSwitchTo(oldcontext);
+   pfree(cstate);
+   return;
+}

It seems like you also need to delete the memory context
(cstate->copycontext) here.

--

+void
+ExecBeforeStmtTrigger(CopyState cstate)
+{
+   EState     *estate = CreateExecutorState();
+   ResultRelInfo *resultRelInfo;

This function has a lot of comments which have been copied as it is
from the CopyFrom function, I think it would be good to remove those
comments from here and mention that this code changes done in this
function has been taken from the CopyFrom function. If any queries
people may refer to the CopyFrom function. This will again avoid the
unnecessary code in the patch.

--

As Heikki rightly pointed out in his previous email, we need some high
level description of how Parallel Copy works somewhere in
copyparallel.c file. For reference, please see how a brief description
about parallel vacuum has been added in the vacuumlazy.c file.

* Lazy vacuum supports parallel execution with parallel worker processes. In
* a parallel vacuum, we perform both index vacuum and index cleanup with
* parallel worker processes. Individual indexes are processed by one vacuum
...
...

--
With Regards,
Ashutosh Sharma
EnterpriseDB:http://www.enterprisedb.com

On Wed, Oct 21, 2020 at 12:08 PM vignesh C <vignesh21@gmail.com> wrote:

On Mon, Oct 19, 2020 at 2:40 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Sun, Oct 18, 2020 at 7:47 AM Hou, Zhijie <houzj.fnst@cn.fujitsu.com> wrote:

Hi Vignesh,

After having a look over the patch,
I have some suggestions for
0003-Allow-copy-from-command-to-process-data-from-file.patch.

1.

+static uint32
+EstimateCstateSize(ParallelContext *pcxt, CopyState cstate, List *attnamelist,
+                                  char **whereClauseStr, char **rangeTableStr,
+                                  char **attnameListStr, char **notnullListStr,
+                                  char **nullListStr, char **convertListStr)
+{
+       uint32          strsize = MAXALIGN(sizeof(SerializedParallelCopyState));
+
+       strsize += EstimateStringSize(cstate->null_print);
+       strsize += EstimateStringSize(cstate->delim);
+       strsize += EstimateStringSize(cstate->quote);
+       strsize += EstimateStringSize(cstate->escape);

It use function EstimateStringSize to get the strlen of null_print, delim, quote and escape.
But the length of null_print seems has been stored in null_print_len.
And delim/quote/escape must be 1 byte, so I think call strlen again seems unnecessary.

How about " strsize += sizeof(uint32) + cstate->null_print_len + 1"

+1. This seems like a good suggestion but add comments for
delim/quote/escape to indicate that we are considering one-byte for
each. I think this will obviate the need of function
EstimateStringSize. Another thing in this regard is that we normally
use add_size function to compute the size but I don't see that being
used in this and nearby computation. That helps us to detect overflow
of addition if any.

EstimateCstateSize()
{
..
+
+ strsize++;
..
}

Why do we need this additional one-byte increment? Does it make sense
to add a small comment for the same?

Changed it to handle null_print, delim, quote & escape accordingly in
the attached patch, the one byte increment is not required, I have
removed it.

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

#192vignesh C
vignesh21@gmail.com
In reply to: Bharath Rupireddy (#186)
5 attachment(s)
Re: Parallel copy

Thanks for the comments, please find my thoughts below.
On Wed, Oct 21, 2020 at 3:19 PM Bharath Rupireddy
<bharath.rupireddyforpostgres@gmail.com> wrote:

Hi Vignesh,

I took a look at the v8 patch set. Here are some comments:

1. PopulateCommonCstateInfo() -- can we use PopulateCommonCStateInfo()
or PopulateCopyStateInfo()? And also EstimateCstateSize() --
EstimateCStateSize(), PopulateCstateCatalogInfo() --
PopulateCStateCatalogInfo()?

Changed as suggested.

2. Instead of mentioning numbers like 1024, 64K, 10240 in the
comments, can we represent them in terms of macros?
/* It can hold 1024 blocks of 64K data in DSM to be processed by the worker. */
#define MAX_BLOCKS_COUNT 1024
/*
* It can hold upto 10240 record information for worker to process. RINGSIZE

Changed as suggested.

3. How about
"
Each worker at once will pick the WORKER_CHUNK_COUNT records from the
DSM data blocks and store them in it's local memory.
This is to make workers not contend much while getting record
information from the DSM. Read RINGSIZE comments before
changing this value.
"
instead of
/*
* Each worker will be allocated WORKER_CHUNK_COUNT of records from DSM data
* block to process to avoid lock contention. Read RINGSIZE comments before
* changing this value.
*/

Rephrased it.

4. How about one line gap before and after for comments: "Leader
should operate in the following order:" and "Worker should operate in
the following order:"

Changed it.

5. Can we move RAW_BUF_BYTES macro definition to the beginning of the
copy.h where all the macro are defined?

Change was done as part of another commit & we are using as it is. I
preferred it to be as it is.

6. I don't think we need the change in toast_internals.c with the
temporary hack Assert(!(IsParallelWorker() && !currentCommandIdUsed));
in GetCurrentCommandId()

Modified it.

7. I think
/* Can't perform copy in parallel */
if (parallel_workers <= 0)
return NULL;
can be
/* Can't perform copy in parallel */
if (parallel_workers == 0)
return NULL;
as parallel_workers can never be < 0 since we enter BeginParallelCopy
only if cstate->nworkers > 0 and also we are not allowed to have
negative values for max_worker_processes.

Modified it.

8. Do we want to pfree(cstate->pcdata) in case we failed to start any
parallel workers, we would have allocated a good
else
{
/*
* Reset nworkers to -1 here. This is useful in cases where user
* specifies parallel workers, but, no worker is picked up, so go
* back to non parallel mode value of nworkers.
*/
cstate->nworkers = -1;
*processed = CopyFrom(cstate); /* copy from file to database */
}

Added pfree.

9. Instead of calling CopyStringToSharedMemory() for each string
variable, can't we just create a linked list of all the strings that
need to be copied into shm and call CopyStringToSharedMemory() only
once? We could avoid 5 function calls?

I feel keeping it this way makes the code more readable, and also this
is not in a performance intensive tight loop. I'm retaining the
change as is unless we feel this will make an impact.

10. Similar to above comment: can we fill all the required
cstate->variables inside the function CopyNodeFromSharedMemory() and
call it only once? In each worker we could save overhead of 5 function
calls.

same as above.

11. Looks like CopyStringFromSharedMemory() and
CopyNodeFromSharedMemory() do almost the same things except
stringToNode() and pfree(destptr);. Can we have a generic function
CopyFromSharedMemory() or something else and handle with flag "bool
isnode" to differentiate the two use cases?

Removed CopyStringFromSharedMemory & used CopyNodeFromSharedMemory
appropriately. CopyNodeFromSharedMemory is renamed to
RestoreNodeFromSharedMemory keep the name consistent.

12. Can we move below check to the end in IsParallelCopyAllowed()?
/* Check parallel safety of the trigger functions. */
if (cstate->rel->trigdesc != NULL &&
!CheckRelTrigFunParallelSafety(cstate->rel->trigdesc))
return false;

Modified.

13. CacheLineInfo(): Instead of goto empty_data_line_update; how about
having this directly inside the if block as it's being used only once?

Have removed the goto by using a macro.

14. GetWorkerLine(): How about avoiding goto statements and replacing
the common code with a always static inline function or a macro?

Have removed the goto by using a macro.

15. UpdateSharedLineInfo(): Below line is misaligned.
lineInfo->first_block = blk_pos;
lineInfo->start_offset = offset;

Changed it.

16. ParallelCopyFrom(): Do we need CHECK_FOR_INTERRUPTS(); at the
start of for (;;)?

Added it.

17. Remove extra lines after #define IsHeaderLine()
(cstate->header_line && cstate->cur_lineno == 1) in copy.h

Modified it.

Attached v9 patches have the fixes for the above comments.

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

Attachments:

v9-0001-Copy-code-readjustment-to-support-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=v9-0001-Copy-code-readjustment-to-support-parallel-copy.patchDownload
From bd57d168b440aaa57ed63847f932477bf4a87ddf Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Tue, 27 Oct 2020 13:36:54 +0530
Subject: [PATCH v9 1/5] Copy code readjustment to support parallel copy.

This patch has the copy code slightly readjusted so that the common code is
separated to functions/macros, these functions/macros will be used by the
workers in the parallel copy code of the upcoming patches. EOL removal is moved
from CopyReadLine to CopyReadLineText, this change was required because in case
of parallel copy the record identification and record updation is done in
CopyReadLineText, before record information is updated in shared memory the new
line characters should be removed.
---
 src/backend/commands/copy.c          | 503 ++++++++++++++---------------------
 src/include/commands/copy.h          |   5 +-
 src/include/commands/copy_internal.h | 198 ++++++++++++++
 3 files changed, 395 insertions(+), 311 deletions(-)
 create mode 100644 src/include/commands/copy_internal.h

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 36ddcdc..10f3e4c 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -29,9 +29,7 @@
 #include "catalog/pg_type.h"
 #include "commands/copy.h"
 #include "commands/defrem.h"
-#include "commands/trigger.h"
 #include "executor/execPartition.h"
-#include "executor/executor.h"
 #include "executor/nodeModifyTable.h"
 #include "executor/tuptable.h"
 #include "foreign/fdwapi.h"
@@ -62,176 +60,6 @@
 #define ISOCTAL(c) (((c) >= '0') && ((c) <= '7'))
 #define OCTVALUE(c) ((c) - '0')
 
-/*
- * Represents the different source/dest cases we need to worry about at
- * the bottom level
- */
-typedef enum CopyDest
-{
-	COPY_FILE,					/* to/from file (or a piped program) */
-	COPY_OLD_FE,				/* to/from frontend (2.0 protocol) */
-	COPY_NEW_FE,				/* to/from frontend (3.0 protocol) */
-	COPY_CALLBACK				/* to/from callback function */
-} CopyDest;
-
-/*
- *	Represents the end-of-line terminator type of the input
- */
-typedef enum EolType
-{
-	EOL_UNKNOWN,
-	EOL_NL,
-	EOL_CR,
-	EOL_CRNL
-} EolType;
-
-/*
- * Represents the heap insert method to be used during COPY FROM.
- */
-typedef enum CopyInsertMethod
-{
-	CIM_SINGLE,					/* use table_tuple_insert or fdw routine */
-	CIM_MULTI,					/* always use table_multi_insert */
-	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
-} CopyInsertMethod;
-
-/*
- * This struct contains all the state variables used throughout a COPY
- * operation. For simplicity, we use the same struct for all variants of COPY,
- * even though some fields are used in only some cases.
- *
- * Multi-byte encodings: all supported client-side encodings encode multi-byte
- * characters by having the first byte's high bit set. Subsequent bytes of the
- * character can have the high bit not set. When scanning data in such an
- * encoding to look for a match to a single-byte (ie ASCII) character, we must
- * use the full pg_encoding_mblen() machinery to skip over multibyte
- * characters, else we might find a false match to a trailing byte. In
- * supported server encodings, there is no possibility of a false match, and
- * it's faster to make useless comparisons to trailing bytes than it is to
- * invoke pg_encoding_mblen() to skip over them. encoding_embeds_ascii is true
- * when we have to do it the hard way.
- */
-typedef struct CopyStateData
-{
-	/* low-level state data */
-	CopyDest	copy_dest;		/* type of copy source/destination */
-	FILE	   *copy_file;		/* used if copy_dest == COPY_FILE */
-	StringInfo	fe_msgbuf;		/* used for all dests during COPY TO, only for
-								 * dest == COPY_NEW_FE in COPY FROM */
-	bool		is_copy_from;	/* COPY TO, or COPY FROM? */
-	bool		reached_eof;	/* true if we read to end of copy data (not
-								 * all copy_dest types maintain this) */
-	EolType		eol_type;		/* EOL type of input */
-	int			file_encoding;	/* file or remote side's character encoding */
-	bool		need_transcoding;	/* file encoding diff from server? */
-	bool		encoding_embeds_ascii;	/* ASCII can be non-first byte? */
-
-	/* parameters from the COPY command */
-	Relation	rel;			/* relation to copy to or from */
-	QueryDesc  *queryDesc;		/* executable query to copy from */
-	List	   *attnumlist;		/* integer list of attnums to copy */
-	char	   *filename;		/* filename, or NULL for STDIN/STDOUT */
-	bool		is_program;		/* is 'filename' a program to popen? */
-	copy_data_source_cb data_source_cb; /* function for reading data */
-	bool		binary;			/* binary format? */
-	bool		freeze;			/* freeze rows on loading? */
-	bool		csv_mode;		/* Comma Separated Value format? */
-	bool		header_line;	/* CSV header line? */
-	char	   *null_print;		/* NULL marker string (server encoding!) */
-	int			null_print_len; /* length of same */
-	char	   *null_print_client;	/* same converted to file encoding */
-	char	   *delim;			/* column delimiter (must be 1 byte) */
-	char	   *quote;			/* CSV quote char (must be 1 byte) */
-	char	   *escape;			/* CSV escape char (must be 1 byte) */
-	List	   *force_quote;	/* list of column names */
-	bool		force_quote_all;	/* FORCE_QUOTE *? */
-	bool	   *force_quote_flags;	/* per-column CSV FQ flags */
-	List	   *force_notnull;	/* list of column names */
-	bool	   *force_notnull_flags;	/* per-column CSV FNN flags */
-	List	   *force_null;		/* list of column names */
-	bool	   *force_null_flags;	/* per-column CSV FN flags */
-	bool		convert_selectively;	/* do selective binary conversion? */
-	List	   *convert_select; /* list of column names (can be NIL) */
-	bool	   *convert_select_flags;	/* per-column CSV/TEXT CS flags */
-	Node	   *whereClause;	/* WHERE condition (or NULL) */
-
-	/* these are just for error messages, see CopyFromErrorCallback */
-	const char *cur_relname;	/* table name for error messages */
-	uint64		cur_lineno;		/* line number for error messages */
-	const char *cur_attname;	/* current att for error messages */
-	const char *cur_attval;		/* current att value for error messages */
-
-	/*
-	 * Working state for COPY TO/FROM
-	 */
-	MemoryContext copycontext;	/* per-copy execution context */
-
-	/*
-	 * Working state for COPY TO
-	 */
-	FmgrInfo   *out_functions;	/* lookup info for output functions */
-	MemoryContext rowcontext;	/* per-row evaluation context */
-
-	/*
-	 * Working state for COPY FROM
-	 */
-	AttrNumber	num_defaults;
-	FmgrInfo   *in_functions;	/* array of input functions for each attrs */
-	Oid		   *typioparams;	/* array of element types for in_functions */
-	int		   *defmap;			/* array of default att numbers */
-	ExprState **defexprs;		/* array of default att expressions */
-	bool		volatile_defexprs;	/* is any of defexprs volatile? */
-	List	   *range_table;
-	ExprState  *qualexpr;
-
-	TransitionCaptureState *transition_capture;
-
-	/*
-	 * These variables are used to reduce overhead in COPY FROM.
-	 *
-	 * attribute_buf holds the separated, de-escaped text for each field of
-	 * the current line.  The CopyReadAttributes functions return arrays of
-	 * pointers into this buffer.  We avoid palloc/pfree overhead by re-using
-	 * the buffer on each cycle.
-	 *
-	 * In binary COPY FROM, attribute_buf holds the binary data for the
-	 * current field, but the usage is otherwise similar.
-	 */
-	StringInfoData attribute_buf;
-
-	/* field raw data pointers found by COPY FROM */
-
-	int			max_fields;
-	char	  **raw_fields;
-
-	/*
-	 * Similarly, line_buf holds the whole input line being processed. The
-	 * input cycle is first to read the whole line into line_buf, convert it
-	 * to server encoding there, and then extract the individual attribute
-	 * fields into attribute_buf.  line_buf is preserved unmodified so that we
-	 * can display it in error messages if appropriate.  (In binary mode,
-	 * line_buf is not used.)
-	 */
-	StringInfoData line_buf;
-	bool		line_buf_converted; /* converted to server encoding? */
-	bool		line_buf_valid; /* contains the row being processed? */
-
-	/*
-	 * Finally, raw_buf holds raw data read from the data source (file or
-	 * client connection).  In text mode, CopyReadLine parses this data
-	 * sufficiently to locate line boundaries, then transfers the data to
-	 * line_buf and converts it.  In binary mode, CopyReadBinaryData fetches
-	 * appropriate amounts of data from this buffer.  In both modes, we
-	 * guarantee that there is a \0 at raw_buf[raw_buf_len].
-	 */
-#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
-	char	   *raw_buf;
-	int			raw_buf_index;	/* next byte to process */
-	int			raw_buf_len;	/* total # of bytes stored */
-	/* Shorthand for number of unconsumed bytes available in raw_buf */
-#define RAW_BUF_BYTES(cstate) ((cstate)->raw_buf_len - (cstate)->raw_buf_index)
-} CopyStateData;
-
 /* DestReceiver for COPY (query) TO */
 typedef struct
 {
@@ -288,7 +116,6 @@ typedef struct CopyMultiInsertInfo
 	int			ti_options;		/* table insert options */
 } CopyMultiInsertInfo;
 
-
 /*
  * These macros centralize code used to process line_buf and raw_buf buffers.
  * They are macros because they often do continue/break control and to avoid
@@ -401,6 +228,12 @@ static bool CopyGetInt16(CopyState cstate, int16 *val);
 static bool CopyLoadRawBuf(CopyState cstate);
 static int	CopyReadBinaryData(CopyState cstate, char *dest, int nbytes);
 
+static void PopulateCommonCstateInfo(CopyState cstate, TupleDesc tup_desc,
+									 List *attnamelist);
+static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
+								   int copy_line_pos, int *copy_line_size);
+static void ConvertToServerEncoding(CopyState cstate);
+
 
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
@@ -1518,7 +1351,6 @@ BeginCopy(ParseState *pstate,
 {
 	CopyState	cstate;
 	TupleDesc	tupDesc;
-	int			num_phys_attrs;
 	MemoryContext oldcontext;
 
 	/* Allocate workspace and zero all fields */
@@ -1684,6 +1516,25 @@ BeginCopy(ParseState *pstate,
 		tupDesc = cstate->queryDesc->tupDesc;
 	}
 
+	PopulateCommonCstateInfo(cstate, tupDesc, attnamelist);
+	cstate->copy_dest = COPY_FILE;	/* default */
+
+	MemoryContextSwitchTo(oldcontext);
+
+	return cstate;
+}
+
+/*
+ * PopulateCommonCstateInfo
+ *
+ * Populates the common variables required for copy from operation. This is a
+ * helper function for BeginCopy function.
+ */
+static void
+PopulateCommonCstateInfo(CopyState cstate, TupleDesc tupDesc, List *attnamelist)
+{
+	int			num_phys_attrs;
+
 	/* Generate or convert list of attributes to process */
 	cstate->attnumlist = CopyGetAttnums(tupDesc, cstate->rel, attnamelist);
 
@@ -1803,12 +1654,6 @@ BeginCopy(ParseState *pstate,
 		 pg_database_encoding_max_length() > 1);
 	/* See Multibyte encoding comment above */
 	cstate->encoding_embeds_ascii = PG_ENCODING_IS_CLIENT_ONLY(cstate->file_encoding);
-
-	cstate->copy_dest = COPY_FILE;	/* default */
-
-	MemoryContextSwitchTo(oldcontext);
-
-	return cstate;
 }
 
 /*
@@ -2698,32 +2543,13 @@ CopyMultiInsertInfoStore(CopyMultiInsertInfo *miinfo, ResultRelInfo *rri,
 }
 
 /*
- * Copy FROM file to relation.
+ * CheckTargetRelValidity
+ *
+ * Check if the relation specified in copy from is valid.
  */
-uint64
-CopyFrom(CopyState cstate)
+static void
+CheckTargetRelValidity(CopyState cstate)
 {
-	ResultRelInfo *resultRelInfo;
-	ResultRelInfo *target_resultRelInfo;
-	ResultRelInfo *prevResultRelInfo = NULL;
-	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
-	ModifyTableState *mtstate;
-	ExprContext *econtext;
-	TupleTableSlot *singleslot = NULL;
-	MemoryContext oldcontext = CurrentMemoryContext;
-
-	PartitionTupleRouting *proute = NULL;
-	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
-	int			ti_options = 0; /* start with default options for insert */
-	BulkInsertState bistate = NULL;
-	CopyInsertMethod insertMethod;
-	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
-	uint64		processed = 0;
-	bool		has_before_insert_row_trig;
-	bool		has_instead_insert_row_trig;
-	bool		leafpart_use_multi_insert = false;
-
 	Assert(cstate->rel);
 	Assert(list_length(cstate->range_table) == 1);
 
@@ -2761,27 +2587,6 @@ CopyFrom(CopyState cstate)
 							RelationGetRelationName(cstate->rel))));
 	}
 
-	/*
-	 * If the target file is new-in-transaction, we assume that checking FSM
-	 * for free space is a waste of time.  This could possibly be wrong, but
-	 * it's unlikely.
-	 */
-	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
-		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
-		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
-		ti_options |= TABLE_INSERT_SKIP_FSM;
-
-	/*
-	 * Optimize if new relfilenode was created in this subxact or one of its
-	 * committed children and we won't see those rows later as part of an
-	 * earlier scan or command. The subxact test ensures that if this subxact
-	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
-	 * that the stronger test of exactly which subtransaction created it is
-	 * crucial for correctness of this optimization. The test for an earlier
-	 * scan or command tolerates false negatives. FREEZE causes other sessions
-	 * to see rows they would not see under MVCC, and a false negative merely
-	 * spreads that anomaly to the current session.
-	 */
 	if (cstate->freeze)
 	{
 		/*
@@ -2819,9 +2624,61 @@ CopyFrom(CopyState cstate)
 			ereport(ERROR,
 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 					 errmsg("cannot perform COPY FREEZE because the table was not created or truncated in the current subtransaction")));
+	}
+}
+
+/*
+ * Copy FROM file to relation.
+ */
+uint64
+CopyFrom(CopyState cstate)
+{
+	ResultRelInfo *resultRelInfo;
+	ResultRelInfo *target_resultRelInfo;
+	ResultRelInfo *prevResultRelInfo = NULL;
+	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
+	ModifyTableState *mtstate;
+	ExprContext *econtext;
+	TupleTableSlot *singleslot = NULL;
+	MemoryContext oldcontext = CurrentMemoryContext;
+
+	PartitionTupleRouting *proute = NULL;
+	ErrorContextCallback errcallback;
+	CommandId	mycid = GetCurrentCommandId(true);
+	int			ti_options = 0; /* start with default options for insert */
+	BulkInsertState bistate = NULL;
+	CopyInsertMethod insertMethod;
+	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
+	uint64		processed = 0;
+	bool		has_before_insert_row_trig;
+	bool		has_instead_insert_row_trig;
+	bool		leafpart_use_multi_insert = false;
+
+	CheckTargetRelValidity(cstate);
+
+	/*
+	 * If the target file is new-in-transaction, we assume that checking FSM
+	 * for free space is a waste of time.  This could possibly be wrong, but
+	 * it's unlikely.
+	 */
+	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
+		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
+		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
+		ti_options |= TABLE_INSERT_SKIP_FSM;
 
+	/*
+	 * Optimize if new relfilenode was created in this subxact or one of its
+	 * committed children and we won't see those rows later as part of an
+	 * earlier scan or command. The subxact test ensures that if this subxact
+	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
+	 * that the stronger test of exactly which subtransaction created it is
+	 * crucial for correctness of this optimization. The test for an earlier
+	 * scan or command tolerates false negatives. FREEZE causes other sessions
+	 * to see rows they would not see under MVCC, and a false negative merely
+	 * spreads that anomaly to the current session.
+	 */
+	if (cstate->freeze)
 		ti_options |= TABLE_INSERT_FROZEN;
-	}
 
 	/*
 	 * We need a ResultRelInfo so we can use the regular executor's
@@ -3342,26 +3199,13 @@ CopyFrom(CopyState cstate)
 }
 
 /*
- * Setup to read tuples from a file for COPY FROM.
+ * PopulateCStateCatalogInfo
  *
- * 'rel': Used as a template for the tuples
- * 'filename': Name of server-local file to read
- * 'attnamelist': List of char *, columns to include. NIL selects all cols.
- * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
- *
- * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ * Populate the cstate catalog information.
  */
-CopyState
-BeginCopyFrom(ParseState *pstate,
-			  Relation rel,
-			  const char *filename,
-			  bool is_program,
-			  copy_data_source_cb data_source_cb,
-			  List *attnamelist,
-			  List *options)
+static void
+PopulateCStateCatalogInfo(CopyState cstate)
 {
-	CopyState	cstate;
-	bool		pipe = (filename == NULL);
 	TupleDesc	tupDesc;
 	AttrNumber	num_phys_attrs,
 				num_defaults;
@@ -3371,38 +3215,8 @@ BeginCopyFrom(ParseState *pstate,
 	Oid			in_func_oid;
 	int		   *defmap;
 	ExprState **defexprs;
-	MemoryContext oldcontext;
 	bool		volatile_defexprs;
 
-	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
-	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
-
-	/* Initialize state variables */
-	cstate->reached_eof = false;
-	cstate->eol_type = EOL_UNKNOWN;
-	cstate->cur_relname = RelationGetRelationName(cstate->rel);
-	cstate->cur_lineno = 0;
-	cstate->cur_attname = NULL;
-	cstate->cur_attval = NULL;
-
-	/*
-	 * Set up variables to avoid per-attribute overhead.  attribute_buf and
-	 * raw_buf are used in both text and binary modes, but we use line_buf
-	 * only in text mode.
-	 */
-	initStringInfo(&cstate->attribute_buf);
-	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
-	cstate->raw_buf_index = cstate->raw_buf_len = 0;
-	if (!cstate->binary)
-	{
-		initStringInfo(&cstate->line_buf);
-		cstate->line_buf_converted = false;
-	}
-
-	/* Assign range table, we'll need it in CopyFrom. */
-	if (pstate)
-		cstate->range_table = pstate->p_rtable;
-
 	tupDesc = RelationGetDescr(cstate->rel);
 	num_phys_attrs = tupDesc->natts;
 	num_defaults = 0;
@@ -3480,6 +3294,61 @@ BeginCopyFrom(ParseState *pstate,
 	cstate->defexprs = defexprs;
 	cstate->volatile_defexprs = volatile_defexprs;
 	cstate->num_defaults = num_defaults;
+}
+
+/*
+ * Setup to read tuples from a file for COPY FROM.
+ *
+ * 'rel': Used as a template for the tuples
+ * 'filename': Name of server-local file to read
+ * 'attnamelist': List of char *, columns to include. NIL selects all cols.
+ * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
+ *
+ * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ */
+CopyState
+BeginCopyFrom(ParseState *pstate,
+			  Relation rel,
+			  const char *filename,
+			  bool is_program,
+			  copy_data_source_cb data_source_cb,
+			  List *attnamelist,
+			  List *options)
+{
+	CopyState	cstate;
+	bool		pipe = (filename == NULL);
+	MemoryContext oldcontext;
+
+	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	/* Initialize state variables */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/*
+	 * Set up variables to avoid per-attribute overhead.  attribute_buf is
+	 * used in both text and binary modes, but we use line_buf and raw_buf
+	 * only in text mode.
+	 */
+	initStringInfo(&cstate->attribute_buf);
+	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+	if (!cstate->binary)
+	{
+		initStringInfo(&cstate->line_buf);
+		cstate->line_buf_converted = false;
+	}
+
+	/* Assign range table, we'll need it in CopyFrom. */
+	if (pstate)
+		cstate->range_table = pstate->p_rtable;
+
+	PopulateCStateCatalogInfo(cstate);
 	cstate->is_program = is_program;
 
 	if (data_source_cb)
@@ -3889,40 +3758,60 @@ CopyReadLine(CopyState cstate)
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
-	else
+
+	ConvertToServerEncoding(cstate);
+	return result;
+}
+
+/*
+ * ClearEOLFromCopiedData
+ *
+ * Clear EOL from the copied data.
+ */
+static void
+ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
+					   int copy_line_pos, int *copy_line_size)
+{
+	/*
+	 * If we didn't hit EOF, then we must have transferred the EOL marker to
+	 * line_buf along with the data.  Get rid of it.
+	 */
+	switch (cstate->eol_type)
 	{
-		/*
-		 * If we didn't hit EOF, then we must have transferred the EOL marker
-		 * to line_buf along with the data.  Get rid of it.
-		 */
-		switch (cstate->eol_type)
-		{
-			case EOL_NL:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CR:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\r');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CRNL:
-				Assert(cstate->line_buf.len >= 2);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 2] == '\r');
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len -= 2;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_UNKNOWN:
-				/* shouldn't get here */
-				Assert(false);
-				break;
-		}
+		case EOL_NL:
+			Assert(*copy_line_size >= 1);
+			Assert(copy_line_data[copy_line_pos - 1] == '\n');
+			copy_line_data[copy_line_pos - 1] = '\0';
+			(*copy_line_size)--;
+			break;
+		case EOL_CR:
+			Assert(*copy_line_size >= 1);
+			Assert(copy_line_data[copy_line_pos - 1] == '\r');
+			copy_line_data[copy_line_pos - 1] = '\0';
+			(*copy_line_size)--;
+			break;
+		case EOL_CRNL:
+			Assert(*copy_line_size >= 2);
+			Assert(copy_line_data[copy_line_pos - 2] == '\r');
+			Assert(copy_line_data[copy_line_pos - 1] == '\n');
+			copy_line_data[copy_line_pos - 2] = '\0';
+			*copy_line_size -= 2;
+			break;
+		case EOL_UNKNOWN:
+			/* shouldn't get here */
+			Assert(false);
+			break;
 	}
+}
 
+/*
+ * ConvertToServerEncoding
+ *
+ * Convert contents to server encoding.
+ */
+static void
+ConvertToServerEncoding(CopyState cstate)
+{
 	/* Done reading the line.  Convert it to server encoding. */
 	if (cstate->need_transcoding)
 	{
@@ -3939,11 +3828,8 @@ CopyReadLine(CopyState cstate)
 			pfree(cvt);
 		}
 	}
-
 	/* Now it's safe to use the buffer in error messages */
 	cstate->line_buf_converted = true;
-
-	return result;
 }
 
 /*
@@ -4306,6 +4192,9 @@ not_end_of_copy:
 	 * Transfer any still-uncopied data to line_buf.
 	 */
 	REFILL_LINEBUF;
+	if (!result && !IsHeaderLine())
+		ClearEOLFromCopiedData(cstate, cstate->line_buf.data,
+							   cstate->line_buf.len, &cstate->line_buf.len);
 
 	return result;
 }
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index c639833..b9331af 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -14,15 +14,12 @@
 #ifndef COPY_H
 #define COPY_H
 
+#include "commands/copy_internal.h"
 #include "nodes/execnodes.h"
 #include "nodes/parsenodes.h"
 #include "parser/parse_node.h"
 #include "tcop/dest.h"
 
-/* CopyStateData is private in commands/copy.c */
-typedef struct CopyStateData *CopyState;
-typedef int (*copy_data_source_cb) (void *outbuf, int minread, int maxread);
-
 extern void DoCopy(ParseState *state, const CopyStmt *stmt,
 				   int stmt_location, int stmt_len,
 				   uint64 *processed);
diff --git a/src/include/commands/copy_internal.h b/src/include/commands/copy_internal.h
new file mode 100644
index 0000000..ea4bfca
--- /dev/null
+++ b/src/include/commands/copy_internal.h
@@ -0,0 +1,198 @@
+/*-------------------------------------------------------------------------
+ *
+ * copy_internal.h
+ *	  Definitions for using the POSTGRES copy command.
+ *
+ *
+ * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/commands/copy_internal.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef COPY_INTERNAL_H
+#define COPY_INTERNAL_H
+
+#include "commands/trigger.h"
+#include "executor/executor.h"
+
+#define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
+
+/*
+ * Represents the different source/dest cases we need to worry about at
+ * the bottom level
+ */
+typedef enum CopyDest
+{
+	COPY_FILE,					/* to/from file (or a piped program) */
+	COPY_OLD_FE,				/* to/from frontend (2.0 protocol) */
+	COPY_NEW_FE,				/* to/from frontend (3.0 protocol) */
+	COPY_CALLBACK				/* to/from callback function */
+} CopyDest;
+
+/*
+ *	Represents the end-of-line terminator type of the input
+ */
+typedef enum EolType
+{
+	EOL_UNKNOWN,
+	EOL_NL,
+	EOL_CR,
+	EOL_CRNL
+} EolType;
+
+/*
+ * Represents the heap insert method to be used during COPY FROM.
+ */
+typedef enum CopyInsertMethod
+{
+	CIM_SINGLE,					/* use table_tuple_insert or fdw routine */
+	CIM_MULTI,					/* always use table_multi_insert */
+	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
+} CopyInsertMethod;
+
+#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+
+typedef int (*copy_data_source_cb) (void *outbuf, int minread, int maxread);
+
+/*
+ * This struct contains all the state variables used throughout a COPY
+ * operation. For simplicity, we use the same struct for all variants of COPY,
+ * even though some fields are used in only some cases.
+ *
+ * Multi-byte encodings: all supported client-side encodings encode multi-byte
+ * characters by having the first byte's high bit set. Subsequent bytes of the
+ * character can have the high bit not set. When scanning data in such an
+ * encoding to look for a match to a single-byte (ie ASCII) character, we must
+ * use the full pg_encoding_mblen() machinery to skip over multibyte
+ * characters, else we might find a false match to a trailing byte. In
+ * supported server encodings, there is no possibility of a false match, and
+ * it's faster to make useless comparisons to trailing bytes than it is to
+ * invoke pg_encoding_mblen() to skip over them. encoding_embeds_ascii is true
+ * when we have to do it the hard way.
+ */
+typedef struct CopyStateData
+{
+	/* low-level state data */
+	CopyDest	copy_dest;		/* type of copy source/destination */
+	FILE	   *copy_file;		/* used if copy_dest == COPY_FILE */
+	StringInfo	fe_msgbuf;		/* used for all dests during COPY TO, only for
+								 * dest == COPY_NEW_FE in COPY FROM */
+	bool		is_copy_from;	/* COPY TO, or COPY FROM? */
+	bool		reached_eof;	/* true if we read to end of copy data (not
+								 * all copy_dest types maintain this) */
+	EolType		eol_type;		/* EOL type of input */
+	int			file_encoding;	/* file or remote side's character encoding */
+	bool		need_transcoding;	/* file encoding diff from server? */
+	bool		encoding_embeds_ascii;	/* ASCII can be non-first byte? */
+
+	/* parameters from the COPY command */
+	Relation	rel;			/* relation to copy to or from */
+	QueryDesc  *queryDesc;		/* executable query to copy from */
+	List	   *attnumlist;		/* integer list of attnums to copy */
+	char	   *filename;		/* filename, or NULL for STDIN/STDOUT */
+	bool		is_program;		/* is 'filename' a program to popen? */
+	copy_data_source_cb data_source_cb; /* function for reading data */
+	bool		binary;			/* binary format? */
+	bool		freeze;			/* freeze rows on loading? */
+	bool		csv_mode;		/* Comma Separated Value format? */
+	bool		header_line;	/* CSV header line? */
+	char	   *null_print;		/* NULL marker string (server encoding!) */
+	int			null_print_len; /* length of same */
+	char	   *null_print_client;	/* same converted to file encoding */
+	char	   *delim;			/* column delimiter (must be 1 byte) */
+	char	   *quote;			/* CSV quote char (must be 1 byte) */
+	char	   *escape;			/* CSV escape char (must be 1 byte) */
+	List	   *force_quote;	/* list of column names */
+	bool		force_quote_all;	/* FORCE_QUOTE *? */
+	bool	   *force_quote_flags;	/* per-column CSV FQ flags */
+	List	   *force_notnull;	/* list of column names */
+	bool	   *force_notnull_flags;	/* per-column CSV FNN flags */
+	List	   *force_null;		/* list of column names */
+	bool	   *force_null_flags;	/* per-column CSV FN flags */
+	bool		convert_selectively;	/* do selective binary conversion? */
+	List	   *convert_select; /* list of column names (can be NIL) */
+	bool	   *convert_select_flags;	/* per-column CSV/TEXT CS flags */
+	Node	   *whereClause;	/* WHERE condition (or NULL) */
+
+	/* these are just for error messages, see CopyFromErrorCallback */
+	const char *cur_relname;	/* table name for error messages */
+	uint64		cur_lineno;		/* line number for error messages */
+	const char *cur_attname;	/* current att for error messages */
+	const char *cur_attval;		/* current att value for error messages */
+
+	/*
+	 * Working state for COPY TO/FROM
+	 */
+	MemoryContext copycontext;	/* per-copy execution context */
+
+	/*
+	 * Working state for COPY TO
+	 */
+	FmgrInfo   *out_functions;	/* lookup info for output functions */
+	MemoryContext rowcontext;	/* per-row evaluation context */
+
+	/*
+	 * Working state for COPY FROM
+	 */
+	AttrNumber	num_defaults;
+	FmgrInfo   *in_functions;	/* array of input functions for each attrs */
+	Oid		   *typioparams;	/* array of element types for in_functions */
+	int		   *defmap;			/* array of default att numbers */
+	ExprState **defexprs;		/* array of default att expressions */
+	bool		volatile_defexprs;	/* is any of defexprs volatile? */
+	List	   *range_table;
+	ExprState  *qualexpr;
+
+	TransitionCaptureState *transition_capture;
+
+	/*
+	 * These variables are used to reduce overhead in COPY FROM.
+	 *
+	 * attribute_buf holds the separated, de-escaped text for each field of
+	 * the current line.  The CopyReadAttributes functions return arrays of
+	 * pointers into this buffer.  We avoid palloc/pfree overhead by re-using
+	 * the buffer on each cycle.
+	 *
+	 * In binary COPY FROM, attribute_buf holds the binary data for the
+	 * current field, but the usage is otherwise similar.
+	 */
+	StringInfoData attribute_buf;
+
+	/* field raw data pointers found by COPY FROM */
+
+	int			max_fields;
+	char	  **raw_fields;
+
+	/*
+	 * Similarly, line_buf holds the whole input line being processed. The
+	 * input cycle is first to read the whole line into line_buf, convert it
+	 * to server encoding there, and then extract the individual attribute
+	 * fields into attribute_buf.  line_buf is preserved unmodified so that we
+	 * can display it in error messages if appropriate.  (In binary mode,
+	 * line_buf is not used.)
+	 */
+	StringInfoData line_buf;
+	bool		line_buf_converted; /* converted to server encoding? */
+	bool		line_buf_valid; /* contains the row being processed? */
+
+	/*
+	 * Finally, raw_buf holds raw data read from the data source (file or
+	 * client connection).  In text mode, CopyReadLine parses this data
+	 * sufficiently to locate line boundaries, then transfers the data to
+	 * line_buf and converts it.  In binary mode, CopyReadBinaryData fetches
+	 * appropriate amounts of data from this buffer.  In both modes, we
+	 * guarantee that there is a \0 at raw_buf[raw_buf_len].
+	 */
+	char	   *raw_buf;
+	int			raw_buf_index;	/* next byte to process */
+	int			raw_buf_len;	/* total # of bytes stored */
+	/* Shorthand for number of unconsumed bytes available in raw_buf */
+#define RAW_BUF_BYTES(cstate) ((cstate)->raw_buf_len - (cstate)->raw_buf_index)
+} CopyStateData;
+
+/* CopyStateData is private in commands/copy.c */
+typedef struct CopyStateData *CopyState;
+
+#endif							/* COPY_INTERNAL_H */
-- 
1.8.3.1

v9-0002-Allow-copy-from-command-to-process-data-from-file.patchtext/x-patch; charset=US-ASCII; name=v9-0002-Allow-copy-from-command-to-process-data-from-file.patchDownload
From d4145cc06b44f395445b0e39d95c7aaf2b2bd476 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Tue, 27 Oct 2020 18:26:01 +0530
Subject: [PATCH v9 2/5] Allow copy from command to process data from
 file/STDIN contents to a table in parallel.

This feature allows the copy from to leverage multiple CPUs in order to copy
data from file/STDIN to a table. This adds a PARALLEL option to COPY FROM
command where the user can specify the number of workers that can be used
to perform the COPY FROM command.
The backend, to which the "COPY FROM" query is submitted acts as leader with
the responsibility of reading data from the file/stdin, launching at most n
number of workers as specified with PARALLEL 'n' option in the "COPY FROM"
query. The leader populates the common data required for the workers execution
in the DSM and shares it with the workers. The leader then executes before
statement triggers if there exists any. Leader populates DSM lines which
includes the start offset and line size, while populating the lines it reads
as many blocks as required into the DSM data blocks from the file. Each block
is of 64K size. The leader parses the data to identify a line, the existing
logic from CopyReadLineText which identifies the lines with some changes was
used for this. Leader checks if a free line is available to copy the
information, if there is no free line it waits till the required line is
freed up by the worker and then copies the identified lines information
(offset & line size) into the DSM lines. This process is repeated till the
complete file is processed. Simultaneously, the workers cache the lines(50)
locally into the local memory and release the lines to the leader for further
populating. Each worker processes the lines that it cached and inserts it into
the table.
The leader does not participate in the insertion of data, leaders only
responsibility will be to identify the lines as fast as possible for the
workers to do the actual copy operation. The leader waits till all the lines
populated are processed by the workers and exits. We have chosen this design
based on the reason "that everything stalls if the leader doesn't accept further
input data, as well as when there are no available splitted chunks so it doesn't
seem like a good idea to have the leader do other work.  This is backed by the
performance data where we have seen that with 1 worker there is just a 5-10%
performance difference".
---
 src/backend/access/heap/heapam.c      |   11 -
 src/backend/access/transam/parallel.c |    4 +
 src/backend/access/transam/xact.c     |   26 +-
 src/backend/commands/Makefile         |    1 +
 src/backend/commands/copy.c           |  300 ++++++--
 src/backend/commands/copyparallel.c   | 1351 +++++++++++++++++++++++++++++++++
 src/bin/psql/tab-complete.c           |    2 +-
 src/include/access/xact.h             |    1 +
 src/include/commands/copy.h           |   23 +
 src/include/commands/copy_internal.h  |  226 +++++-
 src/tools/pgindent/typedefs.list      |    8 +
 11 files changed, 1876 insertions(+), 77 deletions(-)
 create mode 100644 src/backend/commands/copyparallel.c

diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 1585861..1602525 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2043,17 +2043,6 @@ static HeapTuple
 heap_prepare_insert(Relation relation, HeapTuple tup, TransactionId xid,
 					CommandId cid, int options)
 {
-	/*
-	 * To allow parallel inserts, we need to ensure that they are safe to be
-	 * performed in workers. We have the infrastructure to allow parallel
-	 * inserts in general except for the cases where inserts generate a new
-	 * CommandId (eg. inserts into a table having a foreign key column).
-	 */
-	if (IsParallelWorker())
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_TRANSACTION_STATE),
-				 errmsg("cannot insert tuples in a parallel worker")));
-
 	tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
 	tup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK);
 	tup->t_data->t_infomask |= HEAP_XMAX_INVALID;
diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index b042696..a3cff4b 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -25,6 +25,7 @@
 #include "catalog/pg_enum.h"
 #include "catalog/storage.h"
 #include "commands/async.h"
+#include "commands/copy.h"
 #include "executor/execParallel.h"
 #include "libpq/libpq.h"
 #include "libpq/pqformat.h"
@@ -145,6 +146,9 @@ static const struct
 	},
 	{
 		"parallel_vacuum_main", parallel_vacuum_main
+	},
+	{
+		"ParallelCopyMain", ParallelCopyMain
 	}
 };
 
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index af6afce..d6d449f 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -764,18 +764,34 @@ GetCurrentCommandId(bool used)
 	if (used)
 	{
 		/*
-		 * Forbid setting currentCommandIdUsed in a parallel worker, because
-		 * we have no provision for communicating this back to the leader.  We
-		 * could relax this restriction when currentCommandIdUsed was already
-		 * true at the start of the parallel operation.
+		 * If in a parallel worker, only allow setting currentCommandIdUsed
+		 * if currentCommandIdUsed was already true at the start of the
+		 * parallel operation (by way of SetCurrentCommandIdUsed()), otherwise
+		 * forbid setting currentCommandIdUsed because we have no provision
+		 * for communicating this back to the leader.
 		 */
-		Assert(!IsParallelWorker());
+		Assert(!(IsParallelWorker() && !currentCommandIdUsed));
 		currentCommandIdUsed = true;
 	}
 	return currentCommandId;
 }
 
 /*
+ *	SetCurrentCommandIdUsedForWorker
+ *
+ * For a parallel worker, record that the currentCommandId has been used.
+ * This must only be called at the start of a parallel operation.
+ */
+void
+SetCurrentCommandIdUsedForWorker(void)
+{
+	Assert(IsParallelWorker() && !currentCommandIdUsed &&
+		   (currentCommandId != InvalidCommandId));
+
+	currentCommandIdUsed = true;
+}
+
+/*
  *	SetParallelStartTimestamps
  *
  * In a parallel worker, we should inherit the parent transaction's
diff --git a/src/backend/commands/Makefile b/src/backend/commands/Makefile
index d4815d3..a224aac 100644
--- a/src/backend/commands/Makefile
+++ b/src/backend/commands/Makefile
@@ -24,6 +24,7 @@ OBJS = \
 	constraint.o \
 	conversioncmds.o \
 	copy.o \
+	copyparallel.o \
 	createas.o \
 	dbcommands.o \
 	define.o \
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 10f3e4c..f485505 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -44,6 +44,7 @@
 #include "parser/parse_expr.h"
 #include "parser/parse_relation.h"
 #include "port/pg_bswap.h"
+#include "postmaster/bgworker_internals.h"
 #include "rewrite/rewriteHandler.h"
 #include "storage/fd.h"
 #include "tcop/tcopprot.h"
@@ -166,9 +167,13 @@ if (1) \
 { \
 	if (raw_buf_ptr > cstate->raw_buf_index) \
 	{ \
-		appendBinaryStringInfo(&cstate->line_buf, \
-							 cstate->raw_buf + cstate->raw_buf_index, \
-							   raw_buf_ptr - cstate->raw_buf_index); \
+		if (!IsParallelCopy()) \
+			appendBinaryStringInfo(&cstate->line_buf, \
+								   cstate->raw_buf + cstate->raw_buf_index, \
+								   raw_buf_ptr - cstate->raw_buf_index); \
+		else \
+			line_size +=  raw_buf_ptr - cstate->raw_buf_index; \
+		\
 		cstate->raw_buf_index = raw_buf_ptr; \
 	} \
 } else ((void) 0)
@@ -197,7 +202,6 @@ static void EndCopyTo(CopyState cstate);
 static uint64 DoCopyTo(CopyState cstate);
 static uint64 CopyTo(CopyState cstate);
 static void CopyOneRowTo(CopyState cstate, TupleTableSlot *slot);
-static bool CopyReadLine(CopyState cstate);
 static bool CopyReadLineText(CopyState cstate);
 static int	CopyReadAttributesText(CopyState cstate);
 static int	CopyReadAttributesCSV(CopyState cstate);
@@ -227,13 +231,8 @@ static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 static bool CopyLoadRawBuf(CopyState cstate);
 static int	CopyReadBinaryData(CopyState cstate, char *dest, int nbytes);
-
-static void PopulateCommonCstateInfo(CopyState cstate, TupleDesc tup_desc,
-									 List *attnamelist);
 static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
 								   int copy_line_pos, int *copy_line_size);
-static void ConvertToServerEncoding(CopyState cstate);
-
 
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
@@ -632,11 +631,11 @@ CopyGetInt16(CopyState cstate, int16 *val)
 static bool
 CopyLoadRawBuf(CopyState cstate)
 {
-	int			nbytes = RAW_BUF_BYTES(cstate);
+	int			nbytes = (!IsParallelCopy()) ? RAW_BUF_BYTES(cstate) : cstate->raw_buf_len;
 	int			inbytes;
 
 	/* Copy down the unprocessed data if any. */
-	if (nbytes > 0)
+	if (nbytes > 0 && !IsParallelCopy())
 		memmove(cstate->raw_buf, cstate->raw_buf + cstate->raw_buf_index,
 				nbytes);
 
@@ -644,7 +643,9 @@ CopyLoadRawBuf(CopyState cstate)
 						  1, RAW_BUF_SIZE - nbytes);
 	nbytes += inbytes;
 	cstate->raw_buf[nbytes] = '\0';
-	cstate->raw_buf_index = 0;
+	if (!IsParallelCopy())
+		cstate->raw_buf_index = 0;
+
 	cstate->raw_buf_len = nbytes;
 	return (inbytes > 0);
 }
@@ -943,6 +944,8 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 
 	if (is_from)
 	{
+		ParallelContext *pcxt = NULL;
+
 		Assert(rel);
 
 		/* check read-only transaction and parallel mode */
@@ -952,7 +955,46 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 		cstate = BeginCopyFrom(pstate, rel, stmt->filename, stmt->is_program,
 							   NULL, stmt->attlist, stmt->options);
 		cstate->whereClause = whereClause;
-		*processed = CopyFrom(cstate);	/* copy from file to database */
+		cstate->is_parallel = false;
+
+		/*
+		 * User chosen parallel copy. Determine if the parallel copy is
+		 * actually allowed. If not, go with the non-parallel mode.
+		 */
+		if (cstate->nworkers > 0 && IsParallelCopyAllowed(cstate))
+			pcxt = BeginParallelCopy(cstate, stmt->attlist, relid);
+
+		if (pcxt)
+		{
+			int			i;
+
+			ParallelCopyFrom(cstate);
+
+			/* Wait for all copy workers to finish */
+			WaitForParallelWorkersToFinish(pcxt);
+
+			/*
+			 * Next, accumulate WAL usage.  (This must wait for the workers to
+			 * finish, or we might get incomplete data.)
+			 */
+			for (i = 0; i < pcxt->nworkers_launched; i++)
+				InstrAccumParallelQuery(&cstate->pcdata->bufferusage[i],
+										&cstate->pcdata->walusage[i]);
+
+			*processed = pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
+			EndParallelCopy(pcxt);
+		}
+		else
+		{
+			/*
+			 * Reset nworkers to -1 here. This is useful in cases where user
+			 * specifies parallel workers, but, no worker is picked up, so go
+			 * back to non parallel mode value of nworkers.
+			 */
+			cstate->nworkers = -1;
+			*processed = CopyFrom(cstate);	/* copy from file to database */
+		}
+
 		EndCopyFrom(cstate);
 	}
 	else
@@ -1003,6 +1045,7 @@ ProcessCopyOptions(ParseState *pstate,
 	cstate->is_copy_from = is_from;
 
 	cstate->file_encoding = -1;
+	cstate->nworkers = -1;
 
 	/* Extract options from the statement node tree */
 	foreach(option, options)
@@ -1173,6 +1216,31 @@ ProcessCopyOptions(ParseState *pstate,
 								defel->defname),
 						 parser_errposition(pstate, defel->location)));
 		}
+		else if (strcmp(defel->defname, "parallel") == 0)
+		{
+			int			val;
+
+			if (!cstate->is_copy_from)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("parallel option is supported only for copy from"),
+						 parser_errposition(pstate, defel->location)));
+			if (cstate->nworkers >= 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options"),
+						 parser_errposition(pstate, defel->location)));
+
+			val = defGetInt32(defel);
+			if (val < 1 || val > MAX_PARALLEL_WORKER_LIMIT)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("value %d out of bounds for option \"%s\"",
+								val, defel->defname),
+						 errdetail("Valid values are between \"%d\" and \"%d\".",
+								   1, MAX_PARALLEL_WORKER_LIMIT)));
+			cstate->nworkers = val;
+		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_SYNTAX_ERROR),
@@ -1516,7 +1584,7 @@ BeginCopy(ParseState *pstate,
 		tupDesc = cstate->queryDesc->tupDesc;
 	}
 
-	PopulateCommonCstateInfo(cstate, tupDesc, attnamelist);
+	PopulateCommonCStateInfo(cstate, tupDesc, attnamelist);
 	cstate->copy_dest = COPY_FILE;	/* default */
 
 	MemoryContextSwitchTo(oldcontext);
@@ -1525,13 +1593,13 @@ BeginCopy(ParseState *pstate,
 }
 
 /*
- * PopulateCommonCstateInfo
+ * PopulateCommonCStateInfo
  *
  * Populates the common variables required for copy from operation. This is a
- * helper function for BeginCopy function.
+ * helper function for BeginCopy & InitializeParallelCopyInfo function.
  */
-static void
-PopulateCommonCstateInfo(CopyState cstate, TupleDesc tupDesc, List *attnamelist)
+void
+PopulateCommonCStateInfo(CopyState cstate, TupleDesc tupDesc, List *attnamelist)
 {
 	int			num_phys_attrs;
 
@@ -2547,7 +2615,7 @@ CopyMultiInsertInfoStore(CopyMultiInsertInfo *miinfo, ResultRelInfo *rri,
  *
  * Check if the relation specified in copy from is valid.
  */
-static void
+void
 CheckTargetRelValidity(CopyState cstate)
 {
 	Assert(cstate->rel);
@@ -2644,7 +2712,7 @@ CopyFrom(CopyState cstate)
 
 	PartitionTupleRouting *proute = NULL;
 	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
+	CommandId	mycid;
 	int			ti_options = 0; /* start with default options for insert */
 	BulkInsertState bistate = NULL;
 	CopyInsertMethod insertMethod;
@@ -2654,7 +2722,18 @@ CopyFrom(CopyState cstate)
 	bool		has_instead_insert_row_trig;
 	bool		leafpart_use_multi_insert = false;
 
-	CheckTargetRelValidity(cstate);
+	/*
+	 * Perform this check if it is not parallel copy. In case of parallel
+	 * copy, this check is done by the leader, so that if any invalid case
+	 * exist the copy from command will error out from the leader itself,
+	 * avoiding launching workers, just to throw error.
+	 */
+	if (!IsParallelCopy())
+		CheckTargetRelValidity(cstate);
+	else
+		SetCurrentCommandIdUsedForWorker();
+
+	mycid = GetCurrentCommandId(!IsParallelCopy());
 
 	/*
 	 * If the target file is new-in-transaction, we assume that checking FSM
@@ -2690,7 +2769,8 @@ CopyFrom(CopyState cstate)
 	ExecInitResultRelation(estate, resultRelInfo, 1);
 
 	/* Verify the named relation is a valid target for INSERT */
-	CheckValidResultRel(resultRelInfo, CMD_INSERT);
+	if (!IsParallelCopy())
+		CheckValidResultRel(resultRelInfo, CMD_INSERT);
 
 	ExecOpenIndices(resultRelInfo, false);
 
@@ -2833,13 +2913,17 @@ CopyFrom(CopyState cstate)
 	has_instead_insert_row_trig = (resultRelInfo->ri_TrigDesc &&
 								   resultRelInfo->ri_TrigDesc->trig_insert_instead_row);
 
-	/*
-	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
-	 * should do this for COPY, since it's not really an "INSERT" statement as
-	 * such. However, executing these triggers maintains consistency with the
-	 * EACH ROW triggers that we already fire on COPY.
-	 */
-	ExecBSInsertTriggers(estate, resultRelInfo);
+	if (!IsParallelCopy())
+	{
+		/*
+		 * Check BEFORE STATEMENT insertion triggers. It's debatable whether
+		 * we should do this for COPY, since it's not really an "INSERT"
+		 * statement as such. However, executing these triggers maintains
+		 * consistency with the EACH ROW triggers that we already fire on
+		 * COPY.
+		 */
+		ExecBSInsertTriggers(estate, resultRelInfo);
+	}
 
 	econtext = GetPerTupleExprContext(estate);
 
@@ -2939,6 +3023,29 @@ CopyFrom(CopyState cstate)
 					!has_instead_insert_row_trig &&
 					resultRelInfo->ri_FdwRoutine == NULL;
 
+				/*
+				 * We may still be able to perform parallel inserts for
+				 * partitioned tables. However, the possibility of this
+				 * depends on which types of triggers exist on the partition.
+				 * We must not do parallel inserts if the partition is a
+				 * foreign table or it has any BEFORE/INSTEAD OF row triggers.
+				 * Since the partition's resultRelInfo are initialized only
+				 * when we actually insert the first tuple into them, we may
+				 * not know this info easily in the leader while deciding for
+				 * the parallelism. We would have gone ahead and allowed
+				 * parallelism. Now it's the time to throw an error and also
+				 * provide a hint to the user to not use parallelism. Throwing
+				 * an error seemed a simple approach than to look for all the
+				 * partitions in the leader while deciding for the
+				 * parallelism. Note that this error is thrown early, exactly
+				 * on the first tuple being inserted into the partition, so
+				 * not much work, that has been done so far, is wasted.
+				 */
+				if (!leafpart_use_multi_insert && IsParallelWorker())
+					ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+									errmsg("cannot perform PARALLEL COPY if partition has BEFORE/INSTEAD OF triggers, or if the partition is foreign partition"),
+									errhint("Try COPY without PARALLEL option")));
+
 				/* Set the multi-insert buffer to use for this partition. */
 				if (leafpart_use_multi_insert)
 				{
@@ -3141,7 +3248,10 @@ CopyFrom(CopyState cstate)
 			 * or FDW; this is the same definition used by nodeModifyTable.c
 			 * for counting tuples inserted by an INSERT command.
 			 */
-			processed++;
+			if (!IsParallelCopy())
+				processed++;
+			else
+				pg_atomic_add_fetch_u64(&cstate->pcdata->pcshared_info->processed, 1);
 		}
 	}
 
@@ -3164,7 +3274,7 @@ CopyFrom(CopyState cstate)
 	 * In the old protocol, tell pqcomm that we can process normal protocol
 	 * messages again.
 	 */
-	if (cstate->copy_dest == COPY_OLD_FE)
+	if (cstate->copy_dest == COPY_OLD_FE && !IsParallelCopy())
 		pq_endmsgread();
 
 	/* Execute AFTER STATEMENT insertion triggers */
@@ -3195,7 +3305,10 @@ CopyFrom(CopyState cstate)
 
 	FreeExecutorState(estate);
 
-	return processed;
+	if (!IsParallelCopy())
+		return processed;
+	else
+		return pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
 }
 
 /*
@@ -3203,7 +3316,7 @@ CopyFrom(CopyState cstate)
  *
  * Populate the cstate catalog information.
  */
-static void
+void
 PopulateCStateCatalogInfo(CopyState cstate)
 {
 	TupleDesc	tupDesc;
@@ -3485,26 +3598,35 @@ NextCopyFromRawFields(CopyState cstate, char ***fields, int *nfields)
 	/* only available for text or csv input */
 	Assert(!cstate->binary);
 
-	/* on input just throw the header line away */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (IsParallelCopy())
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
-			return false;		/* done */
+		done = GetWorkerLine(cstate);
+		if (done && cstate->line_buf.len == 0)
+			return false;
 	}
+	else
+	{
+		/* on input just throw the header line away */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
+		{
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+				return false;	/* done */
+		}
 
-	cstate->cur_lineno++;
+		cstate->cur_lineno++;
 
-	/* Actually read the line into memory here */
-	done = CopyReadLine(cstate);
+		/* Actually read the line into memory here */
+		done = CopyReadLine(cstate);
 
-	/*
-	 * EOF at start of line means we're done.  If we see EOF after some
-	 * characters, we act as though it was newline followed by EOF, ie,
-	 * process the line and then exit loop on next iteration.
-	 */
-	if (done && cstate->line_buf.len == 0)
-		return false;
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			return false;
+	}
 
 	/* Parse the line into de-escaped field values */
 	if (cstate->csv_mode)
@@ -3729,7 +3851,7 @@ EndCopyFrom(CopyState cstate)
  * by newline.  The terminating newline or EOF marker is not included
  * in the final value of line_buf.
  */
-static bool
+bool
 CopyReadLine(CopyState cstate)
 {
 	bool		result;
@@ -3752,9 +3874,31 @@ CopyReadLine(CopyState cstate)
 		 */
 		if (cstate->copy_dest == COPY_NEW_FE)
 		{
+			bool		bIsFirst = true;
+
 			do
 			{
-				cstate->raw_buf_index = cstate->raw_buf_len;
+				if (!IsParallelCopy())
+					cstate->raw_buf_index = cstate->raw_buf_len;
+				else
+				{
+					/*
+					 * Get a new block if it is the first time, From the
+					 * subsequent time, reset the index and re-use the same
+					 * block.
+					 */
+					if (bIsFirst)
+					{
+						ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+						uint32		block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+						cstate->raw_buf = pcshared_info->data_blocks[block_pos].data;
+						bIsFirst = false;
+					}
+
+					cstate->raw_buf_index = cstate->raw_buf_len = 0;
+				}
+
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
@@ -3809,11 +3953,11 @@ ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
  *
  * Convert contents to server encoding.
  */
-static void
+void
 ConvertToServerEncoding(CopyState cstate)
 {
 	/* Done reading the line.  Convert it to server encoding. */
-	if (cstate->need_transcoding)
+	if (cstate->need_transcoding && (!IsParallelCopy() || IsWorker()))
 	{
 		char	   *cvt;
 
@@ -3853,6 +3997,11 @@ CopyReadLineText(CopyState cstate)
 	char		quotec = '\0';
 	char		escapec = '\0';
 
+	/* For parallel copy */
+	int			line_size = 0;
+	uint32		line_pos = 0;
+
+	cstate->eol_type = EOL_UNKNOWN;
 	if (cstate->csv_mode)
 	{
 		quotec = cstate->quote[0];
@@ -3907,6 +4056,10 @@ CopyReadLineText(CopyState cstate)
 		if (raw_buf_ptr >= copy_buf_len || need_data)
 		{
 			REFILL_LINEBUF;
+			if ((copy_buf_len == DATA_BLOCK_SIZE || copy_buf_len == 0) &&
+				IsParallelCopy())
+				SetRawBufForLoad(cstate, line_size, copy_buf_len, raw_buf_ptr,
+								 &copy_raw_buf);
 
 			/*
 			 * Try to read some more data.  This will certainly reset
@@ -3914,14 +4067,14 @@ CopyReadLineText(CopyState cstate)
 			 */
 			if (!CopyLoadRawBuf(cstate))
 				hit_eof = true;
-			raw_buf_ptr = 0;
+			raw_buf_ptr = (IsParallelCopy()) ? cstate->raw_buf_index : 0;
 			copy_buf_len = cstate->raw_buf_len;
 
 			/*
 			 * If we are completely out of data, break out of the loop,
 			 * reporting EOF.
 			 */
-			if (copy_buf_len <= 0)
+			if (RAW_BUF_BYTES(cstate) <= 0)
 			{
 				result = true;
 				break;
@@ -4131,9 +4284,15 @@ CopyReadLineText(CopyState cstate)
 				 * discard the data and the \. sequence.
 				 */
 				if (prev_raw_ptr > cstate->raw_buf_index)
-					appendBinaryStringInfo(&cstate->line_buf,
-										   cstate->raw_buf + cstate->raw_buf_index,
-										   prev_raw_ptr - cstate->raw_buf_index);
+				{
+					if (!IsParallelCopy())
+						appendBinaryStringInfo(&cstate->line_buf,
+											   cstate->raw_buf + cstate->raw_buf_index,
+											   prev_raw_ptr - cstate->raw_buf_index);
+					else
+						line_size += prev_raw_ptr - cstate->raw_buf_index;
+				}
+
 				cstate->raw_buf_index = raw_buf_ptr;
 				result = true;	/* report EOF */
 				break;
@@ -4185,6 +4344,22 @@ not_end_of_copy:
 			IF_NEED_REFILL_AND_EOF_BREAK(mblen - 1);
 			raw_buf_ptr += mblen - 1;
 		}
+
+		/*
+		 * Skip the header line. Update the line here, this cannot be done at
+		 * the beginning, as there is a possibility that file contains empty
+		 * lines.
+		 */
+		if (IsParallelCopy() && first_char_in_line && !IsHeaderLine())
+		{
+			ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+			line_pos = UpdateSharedLineInfo(cstate,
+											pcshared_info->cur_block_pos,
+											cstate->raw_buf_index, -1,
+											LINE_LEADER_POPULATING, -1);
+		}
+
 		first_char_in_line = false;
 	}							/* end of outer loop */
 
@@ -4193,9 +4368,16 @@ not_end_of_copy:
 	 */
 	REFILL_LINEBUF;
 	if (!result && !IsHeaderLine())
-		ClearEOLFromCopiedData(cstate, cstate->line_buf.data,
-							   cstate->line_buf.len, &cstate->line_buf.len);
+	{
+		if (IsParallelCopy())
+			ClearEOLFromCopiedData(cstate, cstate->raw_buf, raw_buf_ptr,
+								   &line_size);
+		else
+			ClearEOLFromCopiedData(cstate, cstate->line_buf.data,
+								   cstate->line_buf.len, &cstate->line_buf.len);
+	}
 
+	EndLineParallelCopy(cstate, line_pos, line_size, raw_buf_ptr);
 	return result;
 }
 
diff --git a/src/backend/commands/copyparallel.c b/src/backend/commands/copyparallel.c
new file mode 100644
index 0000000..0ddd4e5
--- /dev/null
+++ b/src/backend/commands/copyparallel.c
@@ -0,0 +1,1351 @@
+/*-------------------------------------------------------------------------
+ *
+ * copyparallel.c
+ *              Implements the Parallel COPY utility command
+ *
+ * Parallel copy allows the copy from to leverage multiple CPUs in order to copy
+ * data from file/STDIN to a table. This adds a PARALLEL option to COPY FROM
+ * command where the user can specify the number of workers that can be used
+ * to perform the COPY FROM command.
+ * The backend, to which the "COPY FROM" query is submitted acts as leader with
+ * the responsibility of reading data from the file/stdin, launching at most n
+ * number of workers as specified with PARALLEL 'n' option in the "COPY FROM"
+ * query. The leader populates the common data using
+ * PARALLEL_COPY_KEY_SHARED_INFO, PARALLEL_COPY_KEY_CSTATE,
+ * PARALLEL_COPY_KEY_WAL_USAGE & PARALLEL_COPY_KEY_BUFFER_USAGE	 required for
+ * the workers execution in the DSM and shares it with the workers. The leader
+ * then executes before statement triggers if there exists any. Leader populates
+ * DSM lines (ParallelCopyDataBlock & ParallelCopyLineBoundaries data
+ * structures) which includes the start offset and line size, while populating
+ * the lines it reads as many blocks as required into the DSM data blocks from
+ * the file. Each block is of 64K size. The leader parses the data to identify a
+ * line, the existing logic from CopyReadLineText which identifies the lines
+ * with some changes was used for this. Leader checks if a free line is
+ * available (ParallelCopyLineBoundary->line_size will be -1) to copy the
+ * information, if there is no free line it waits till the required line is
+ * freed up by the worker and then copies the identified lines information
+ * (offset & line size) into the DSM lines. Leader will set the state of the
+ * line to LINE_LEADER_POPULATED to indicate the line is populated by the leader
+ * and the worker can start processing the line. This process is repeated till
+ * the complete file is processed. Simultaneously, each worker caches
+ * WORKER_CHUNK_COUNT lines locally into the local memory and release the lines
+ * to the leader for further populating. Each worker processes the lines as it
+ * was done in sequential copy. Refer comments above ParallelCopyLineBoundary
+ * for more details on leader/workers syncronization.
+ * The leader does not participate in the insertion of data, leaders only
+ * responsibility will be to identify the lines as fast as possible for the
+ * workers to do the actual copy operation. The leader waits till all the lines
+ * populated are processed by the workers and exits. We have chosen this design
+ * based on the reason "that everything stalls if the leader doesn't accept
+ * further input data, as well as when there are no available splitted chunks so
+ * it doesn't seem like a good idea to have the leader do other work.  This is
+ * backed by the performance data where we have seen that with 1 worker there is
+ * just a 5-10% performance difference".
+ *
+ * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *        src/backend/commands/copyparallel.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/heapam.h"
+#include "catalog/pg_proc_d.h"
+#include "commands/copy.h"
+#include "libpq/libpq.h"
+#include "optimizer/clauses.h"
+#include "optimizer/optimizer.h"
+#include "pgstat.h"
+#include "utils/lsyscache.h"
+
+/* DSM keys for parallel copy.  */
+#define PARALLEL_COPY_KEY_SHARED_INFO				1
+#define PARALLEL_COPY_KEY_CSTATE					2
+#define PARALLEL_COPY_KEY_WAL_USAGE					3
+#define PARALLEL_COPY_KEY_BUFFER_USAGE				4
+
+/*
+ * COPY_WAIT_TO_PROCESS - Wait before continuing to process.
+ */
+#define COPY_WAIT_TO_PROCESS() \
+{ \
+	CHECK_FOR_INTERRUPTS(); \
+	(void) WaitLatch(MyLatch, \
+					 WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH, \
+					 1L, WAIT_EVENT_PG_SLEEP); \
+	ResetLatch(MyLatch); \
+}
+
+/*
+ * ESTIMATE_1BYTE_STR_SIZE - Estimate the size required for  1Byte strings in
+ * shared memory.
+ */
+#define ESTIMATE_1BYTE_STR_SIZE(src, strsize) \
+{ \
+	strsize = add_size(strsize, sizeof(uint8)); \
+	strsize = add_size(strsize, (src) ? 1 : 0); \
+}
+
+/*
+ * ESTIMATE_NODE_SIZE - Estimate the size required for  node type in shared
+ * memory.
+ */
+#define ESTIMATE_NODE_SIZE(list, listStr, strsize) \
+{ \
+	uint32 estsize = sizeof(uint32); \
+	if ((List *)list != NIL) \
+	{ \
+		listStr = nodeToString(list); \
+		estsize += strlen(listStr) + 1; \
+	} \
+	\
+	strsize = add_size(strsize, estsize); \
+}
+
+/*
+ * EstimateCStateSize
+ *
+ * Estimate the size of the required cstate variables in the shared memory.
+ */
+static uint32
+EstimateCStateSize(ParallelContext *pcxt, CopyState cstate, List *attnamelist,
+				   SerializedListToStrCState *list_converted_str)
+{
+	Size		strsize = 0;
+
+	strsize = add_size(strsize, sizeof(cstate->copy_dest));
+	strsize = add_size(strsize, sizeof(cstate->file_encoding));
+	strsize = add_size(strsize, sizeof(cstate->need_transcoding));
+	strsize = add_size(strsize, sizeof(cstate->encoding_embeds_ascii));
+	strsize = add_size(strsize, sizeof(cstate->csv_mode));
+	strsize = add_size(strsize, sizeof(cstate->header_line));
+	strsize = add_size(strsize, sizeof(cstate->null_print_len));
+	strsize = add_size(strsize, sizeof(cstate->force_quote_all));
+	strsize = add_size(strsize, sizeof(cstate->convert_selectively));
+	strsize = add_size(strsize, sizeof(cstate->num_defaults));
+	strsize = add_size(strsize, sizeof(cstate->pcdata->relid));
+	strsize = add_size(strsize, sizeof(cstate->binary));
+
+	/* Size of null_print is available in null_print_len. */
+	strsize = add_size(strsize, sizeof(uint32) + cstate->null_print_len);
+
+	/* delim, quote & escape all uses 1 byte string to store the information. */
+	ESTIMATE_1BYTE_STR_SIZE(cstate->delim, strsize)
+	ESTIMATE_1BYTE_STR_SIZE(cstate->quote, strsize)
+	ESTIMATE_1BYTE_STR_SIZE(cstate->escape, strsize)
+
+	ESTIMATE_NODE_SIZE(attnamelist, list_converted_str->attnameListStr, strsize)
+	ESTIMATE_NODE_SIZE(cstate->force_notnull, list_converted_str->notnullListStr, strsize)
+	ESTIMATE_NODE_SIZE(cstate->force_null, list_converted_str->nullListStr, strsize)
+	ESTIMATE_NODE_SIZE(cstate->convert_select, list_converted_str->convertListStr, strsize)
+	ESTIMATE_NODE_SIZE(cstate->whereClause, list_converted_str->whereClauseStr, strsize)
+	ESTIMATE_NODE_SIZE(cstate->range_table, list_converted_str->rangeTableStr, strsize)
+
+	shm_toc_estimate_chunk(&pcxt->estimator, strsize);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+	return strsize;
+}
+
+/*
+ * SerializeStringToSharedMemory
+ *
+ * Copy the string to shared memory.
+ */
+static void
+SerializeStringToSharedMemory(char *destptr, char *srcPtr, Size *copiedsize)
+{
+	uint32		len = srcPtr ? strlen(srcPtr) + 1 : 0;
+
+	memcpy(destptr + *copiedsize, (uint32 *) &len, sizeof(uint32));
+	*copiedsize += sizeof(uint32);
+	if (len)
+	{
+		memcpy(destptr + *copiedsize, srcPtr, len);
+		*copiedsize += len;
+	}
+}
+
+/*
+ * SERIALIZE_FIXED_DATA_TYPE - Copy fixed data type values to shared memory.
+ */
+#define SERIALIZE_FIXED_DATA_TYPE(dest, src, copiedsize) \
+{ \
+	memcpy(dest + copiedsize, (char *) &src, sizeof(src)); \
+	copiedsize += sizeof(src); \
+}
+
+/*
+ * SERIALIZE_1BYTE_STR - Copy 1Byte strings to shared memory.
+ */
+#define SERIALIZE_1BYTE_STR(dest, src, copiedsize) \
+{ \
+	uint8		len = (src) ? 1 : 0; \
+	memcpy(dest + copiedsize, (uint8 *) &len, sizeof(uint8)); \
+	copiedsize += sizeof(uint8); \
+	if (src) \
+		dest[copiedsize++] = src[0]; \
+}
+/*
+ * SerializeParallelCopyState
+ *
+ * Serialize the cstate members required by the workers into shared memory.
+ */
+static void
+SerializeParallelCopyState(ParallelContext *pcxt, CopyState cstate,
+						   uint32 estimatedSize,
+						   SerializedListToStrCState *list_converted_str)
+{
+	char	   *shmptr = (char *) shm_toc_allocate(pcxt->toc, estimatedSize + 1);
+	Size		copiedsize = 0;
+
+	SERIALIZE_FIXED_DATA_TYPE(shmptr, cstate->copy_dest, copiedsize)
+	SERIALIZE_FIXED_DATA_TYPE(shmptr, cstate->file_encoding, copiedsize)
+	SERIALIZE_FIXED_DATA_TYPE(shmptr, cstate->need_transcoding, copiedsize)
+	SERIALIZE_FIXED_DATA_TYPE(shmptr, cstate->encoding_embeds_ascii, copiedsize)
+	SERIALIZE_FIXED_DATA_TYPE(shmptr, cstate->csv_mode, copiedsize)
+	SERIALIZE_FIXED_DATA_TYPE(shmptr, cstate->header_line, copiedsize)
+	SERIALIZE_FIXED_DATA_TYPE(shmptr, cstate->null_print_len, copiedsize)
+	SERIALIZE_FIXED_DATA_TYPE(shmptr, cstate->force_quote_all, copiedsize)
+	SERIALIZE_FIXED_DATA_TYPE(shmptr, cstate->convert_selectively, copiedsize)
+	SERIALIZE_FIXED_DATA_TYPE(shmptr, cstate->num_defaults, copiedsize)
+	SERIALIZE_FIXED_DATA_TYPE(shmptr, cstate->pcdata->relid, copiedsize)
+	SERIALIZE_FIXED_DATA_TYPE(shmptr, cstate->binary, copiedsize)
+
+	memcpy(shmptr + copiedsize, (uint32 *) &cstate->null_print_len, sizeof(uint32));
+	copiedsize += sizeof(uint32);
+	if (cstate->null_print_len)
+	{
+		memcpy(shmptr + copiedsize, cstate->null_print, cstate->null_print_len);
+		copiedsize += cstate->null_print_len;
+	}
+
+	SERIALIZE_1BYTE_STR(shmptr, cstate->delim, copiedsize);
+	SERIALIZE_1BYTE_STR(shmptr, cstate->quote, copiedsize);
+	SERIALIZE_1BYTE_STR(shmptr, cstate->escape, copiedsize);
+
+	SerializeStringToSharedMemory(shmptr, list_converted_str->attnameListStr, &copiedsize);
+	SerializeStringToSharedMemory(shmptr, list_converted_str->notnullListStr, &copiedsize);
+	SerializeStringToSharedMemory(shmptr, list_converted_str->nullListStr, &copiedsize);
+	SerializeStringToSharedMemory(shmptr, list_converted_str->convertListStr, &copiedsize);
+	SerializeStringToSharedMemory(shmptr, list_converted_str->whereClauseStr, &copiedsize);
+	SerializeStringToSharedMemory(shmptr, list_converted_str->rangeTableStr, &copiedsize);
+
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_CSTATE, shmptr);
+}
+
+/*
+ * RestoreNodeFromSharedMemory
+ *
+ * Copy the node contents which was stored as string format in shared memory &
+ * convert it into node type.
+ */
+static void *
+RestoreNodeFromSharedMemory(char *srcPtr, Size *copiedsize, bool isSrcStr)
+{
+	char	   *destptr = NULL;
+	List	   *destList = NIL;
+	uint32		len;
+
+	memcpy((uint32 *) (&len), srcPtr + *copiedsize, sizeof(uint32));
+	*copiedsize += sizeof(uint32);
+	if (len)
+	{
+		destptr = (char *) palloc(len);
+		memcpy(destptr, srcPtr + *copiedsize, len);
+		*copiedsize += len;
+		if (!isSrcStr)
+		{
+			destList = (List *) stringToNode(destptr);
+			pfree(destptr);
+			return destList;
+		}
+
+		return destptr;
+	}
+
+	return NULL;
+}
+
+/*
+ * RESTORE_FIXED_DATA_TYPE - Restore fixed data type values from shared memory
+ * to worker local memory.
+ */
+#define RESTORE_FIXED_DATA_TYPE(dest, src, copiedsize) \
+{ \
+	memcpy((char *) &dest, src + copiedsize, sizeof(dest)); \
+	copiedsize += sizeof(dest); \
+}
+
+/*
+ * RESTORE_1BYTE_STR - Restore 1Byte strings from shared memory to worker local
+ * memory.
+ */
+#define RESTORE_1BYTE_STR(dest, src, copiedsize) \
+{ \
+	uint8		len; \
+	memcpy((uint8 *) (&len), src + copiedsize, sizeof(uint8)); \
+	copiedsize += sizeof(uint8); \
+	if (len) \
+	{ \
+		dest = palloc0(sizeof(char) + 1); \
+		dest[0] = src[copiedsize++]; \
+	} \
+}
+
+/*
+ * RestoreParallelCopyState
+ *
+ * Retrieve the cstate members which was populated by the leader in the shared
+ * memory.
+ */
+static void
+RestoreParallelCopyState(shm_toc *toc, CopyState cstate, List **attlist)
+{
+	char	   *shared_str_val = (char *) shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE, true);
+	Size		copiedsize = 0;
+
+	RESTORE_FIXED_DATA_TYPE(cstate->copy_dest, shared_str_val, copiedsize)
+	RESTORE_FIXED_DATA_TYPE(cstate->file_encoding, shared_str_val, copiedsize)
+	RESTORE_FIXED_DATA_TYPE(cstate->need_transcoding, shared_str_val, copiedsize)
+	RESTORE_FIXED_DATA_TYPE(cstate->encoding_embeds_ascii, shared_str_val, copiedsize)
+	RESTORE_FIXED_DATA_TYPE(cstate->csv_mode, shared_str_val, copiedsize)
+	RESTORE_FIXED_DATA_TYPE(cstate->header_line, shared_str_val, copiedsize)
+	RESTORE_FIXED_DATA_TYPE(cstate->null_print_len, shared_str_val, copiedsize)
+	RESTORE_FIXED_DATA_TYPE(cstate->force_quote_all, shared_str_val, copiedsize)
+	RESTORE_FIXED_DATA_TYPE(cstate->convert_selectively, shared_str_val, copiedsize)
+	RESTORE_FIXED_DATA_TYPE(cstate->num_defaults, shared_str_val, copiedsize)
+	RESTORE_FIXED_DATA_TYPE(cstate->pcdata->relid, shared_str_val, copiedsize)
+	RESTORE_FIXED_DATA_TYPE(cstate->binary, shared_str_val, copiedsize)
+
+	cstate->null_print = (char *)RestoreNodeFromSharedMemory(shared_str_val, &copiedsize, true);
+	if (!cstate->null_print)
+		cstate->null_print = "";
+
+	RESTORE_1BYTE_STR(cstate->delim, shared_str_val, copiedsize)
+	RESTORE_1BYTE_STR(cstate->quote, shared_str_val, copiedsize)
+	RESTORE_1BYTE_STR(cstate->escape, shared_str_val, copiedsize)
+
+	*attlist = (List *) RestoreNodeFromSharedMemory(shared_str_val, &copiedsize, false);
+	cstate->force_notnull = (List *) RestoreNodeFromSharedMemory(shared_str_val, &copiedsize, false);
+	cstate->force_null = (List *) RestoreNodeFromSharedMemory(shared_str_val, &copiedsize, false);
+	cstate->convert_select = (List *) RestoreNodeFromSharedMemory(shared_str_val, &copiedsize, false);
+	cstate->whereClause = (Node *) RestoreNodeFromSharedMemory(shared_str_val, &copiedsize, false);
+	cstate->range_table = (List *) RestoreNodeFromSharedMemory(shared_str_val, &copiedsize, false);
+}
+
+/*
+ * PopulateParallelCopyShmInfo
+ *
+ * Sets ParallelCopyShmInfo structure members.
+ */
+static void
+PopulateParallelCopyShmInfo(ParallelCopyShmInfo *shared_info_ptr)
+{
+	uint32		count;
+
+	MemSet(shared_info_ptr, 0, sizeof(ParallelCopyShmInfo));
+	shared_info_ptr->is_read_in_progress = true;
+	shared_info_ptr->cur_block_pos = -1;
+	for (count = 0; count < RINGSIZE; count++)
+	{
+		ParallelCopyLineBoundary *lineInfo = &shared_info_ptr->line_boundaries.ring[count];
+
+		pg_atomic_init_u32(&(lineInfo->line_size), -1);
+	}
+}
+
+/*
+ * CheckRelTrigFunParallelSafety
+ *
+ * Check if the relation's associated trigger functions are parallel safe. If
+ * any of the trigger function is parallel unsafe or if trigger is on foreign
+ * key relation, we do not allow parallel copy.
+ */
+static pg_attribute_always_inline bool
+CheckRelTrigFunParallelSafety(TriggerDesc *trigdesc)
+{
+	int			i;
+
+	for (i = 0; i < trigdesc->numtriggers; i++)
+	{
+		Trigger    *trigger = &trigdesc->triggers[i];
+		int			trigtype = RI_TRIGGER_NONE;
+
+		if (func_parallel(trigger->tgfoid) != PROPARALLEL_SAFE)
+			return false;
+
+		/* If the trigger is parallel safe, also look for RI_TRIGGER. */
+		trigtype = RI_FKey_trigger_type(trigger->tgfoid);
+
+		/*
+		 * No parallelism if foreign key check trigger is present. This is
+		 * because, while performing foreign key checks, we take KEY SHARE
+		 * lock on primary key table rows which inturn will increment the
+		 * command counter and updates the snapshot.  Since we share the
+		 * snapshots at the beginning of the command, we can't allow it to be
+		 * changed later. So, unless we do something special for it, we can't
+		 * allow parallelism in such cases.
+		 */
+		if (trigtype == RI_TRIGGER_FK)
+			return false;
+	}
+
+	return true;
+}
+
+/*
+ * CheckExprParallelSafety
+ *
+ * Determine parallel safety of volatile expressions in default clause of column
+ * definition or in where clause and return true if they are parallel safe.
+ */
+static pg_attribute_always_inline bool
+CheckExprParallelSafety(CopyState cstate)
+{
+	if (contain_volatile_functions(cstate->whereClause))
+	{
+		if (max_parallel_hazard((Query *) cstate->whereClause) != PROPARALLEL_SAFE)
+			return false;
+	}
+
+	/*
+	 * Check if any of the column has volatile default expression. if yes, and
+	 * they are not parallel safe, then parallelism is not allowed. For
+	 * instance, if there are any serial/bigserial columns for which nextval()
+	 * default expression which is parallel unsafe is associated, parallelism
+	 * should not be allowed.
+	 */
+	if (cstate->defexprs != NULL && cstate->num_defaults != 0)
+	{
+		int			i;
+
+		for (i = 0; i < cstate->num_defaults; i++)
+		{
+			bool		volatile_expr = contain_volatile_functions((Node *) cstate->defexprs[i]->expr);
+
+			if (volatile_expr &&
+				(max_parallel_hazard((Query *) cstate->defexprs[i]->expr)) !=
+				PROPARALLEL_SAFE)
+				return false;
+		}
+	}
+
+	return true;
+}
+
+/*
+ * IsParallelCopyAllowed
+ *
+ * Check if parallel copy can be allowed.
+ */
+bool
+IsParallelCopyAllowed(CopyState cstate)
+{
+	/*
+	 * Check if copy is into foreign table. We can not allow parallelism in
+	 * this case because each worker needs to establish FDW connection and
+	 * operate in a separate transaction. Unless we have a capability to
+	 * provide two-phase commit protocol, we can not allow parallelism.
+	 *
+	 * Also check if copy is into temporary table. Since parallel workers can
+	 * not access temporary table, parallelism is not allowed.
+	 */
+	if (cstate->rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
+		RelationUsesLocalBuffers(cstate->rel))
+		return false;
+
+	/*
+	 * If there are volatile default expressions or where clause contain
+	 * volatile expressions, allow parallelism if they are parallel safe,
+	 * otherwise not.
+	 */
+	if (!CheckExprParallelSafety(cstate))
+		return false;
+
+	/*
+	 * When transition tables are involved (if after statement triggers are
+	 * present), we collect minimal tuples in the tuple store after processing
+	 * them so that later after statement triggers can access them.  Now, if
+	 * we want to enable parallelism for such cases, we instead need to store
+	 * and access tuples from shared tuple store.  However, it does not have
+	 * the facility to store tuples in-memory, so we always need to store and
+	 * access from a file which could be costly unless we also have an
+	 * additional way to store minimal tuples in shared memory till work_mem
+	 * and then in shared tuple store. It is possible to do all this to enable
+	 * parallel copy for such cases. Currently, we can disallow parallelism
+	 * for such cases and later allow if required.
+	 *
+	 * When there are BEFORE/AFTER/INSTEAD OF row triggers on the table. We do
+	 * not allow parallelism in such cases because such triggers might query
+	 * the table we are inserting into and act differently if the tuples that
+	 * have already been processed and prepared for insertion are not there.
+	 * Now, if we allow parallelism with such triggers the behaviour would
+	 * depend on if the parallel worker has already inserted or not that
+	 * particular tuples.
+	 */
+	if (cstate->rel->trigdesc != NULL &&
+		(cstate->rel->trigdesc->trig_insert_after_statement ||
+		 cstate->rel->trigdesc->trig_insert_new_table ||
+		 cstate->rel->trigdesc->trig_insert_before_row ||
+		 cstate->rel->trigdesc->trig_insert_after_row ||
+		 cstate->rel->trigdesc->trig_insert_instead_row))
+		return false;
+
+	/* Check parallel safety of the trigger functions. */
+	if (cstate->rel->trigdesc != NULL &&
+		!CheckRelTrigFunParallelSafety(cstate->rel->trigdesc))
+		return false;
+
+	return true;
+}
+
+/*
+ * BeginParallelCopy - Start parallel copy tasks.
+ *
+ * Get the number of workers required to perform the parallel copy. The data
+ * structures that are required by the parallel workers will be initialized, the
+ * size required in DSM will be calculated and the necessary keys will be loaded
+ * in the DSM. The specified number of workers will then be launched.
+ */
+ParallelContext *
+BeginParallelCopy(CopyState cstate, List *attnamelist, Oid relid)
+{
+	ParallelContext *pcxt;
+	ParallelCopyShmInfo *shared_info_ptr;
+	int			parallel_workers = 0;
+	WalUsage   *walusage;
+	BufferUsage *bufferusage;
+	ParallelCopyData *pcdata;
+	MemoryContext oldcontext;
+	uint32		strsize;
+	SerializedListToStrCState list_converted_str = {0};
+
+	CheckTargetRelValidity(cstate);
+	parallel_workers = Min(cstate->nworkers, max_worker_processes);
+
+	/* Can't perform copy in parallel */
+	if (parallel_workers == 0)
+		return NULL;
+
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	MemoryContextSwitchTo(oldcontext);
+
+	cstate->pcdata = pcdata;
+	pcdata->relid = relid;
+	(void) GetCurrentFullTransactionId();
+	(void) GetCurrentCommandId(true);
+
+	EnterParallelMode();
+	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
+								 parallel_workers);
+	Assert(pcxt->nworkers > 0);
+
+	/*
+	 * Estimate size for shared information for PARALLEL_COPY_KEY_SHARED_INFO
+	 */
+	shm_toc_estimate_chunk(&pcxt->estimator, sizeof(ParallelCopyShmInfo));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_CSTATE */
+	strsize = EstimateCStateSize(pcxt, cstate, attnamelist, &list_converted_str);
+
+	/*
+	 * Estimate space for WalUsage and BufferUsage --
+	 * PARALLEL_COPY_KEY_WAL_USAGE and PARALLEL_COPY_KEY_BUFFER_USAGE.
+	 */
+	shm_toc_estimate_chunk(&pcxt->estimator,
+						   mul_size(sizeof(WalUsage), pcxt->nworkers));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+	shm_toc_estimate_chunk(&pcxt->estimator,
+						   mul_size(sizeof(BufferUsage), pcxt->nworkers));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	InitializeParallelDSM(pcxt);
+
+	/* If no DSM segment was available, back out (do serial copy) */
+	if (pcxt->seg == NULL)
+	{
+		EndParallelCopy(pcxt);
+		pfree(pcdata);
+		cstate->pcdata = NULL;
+		return NULL;
+	}
+
+	/* Allocate shared memory for PARALLEL_COPY_KEY_SHARED_INFO */
+	shared_info_ptr = (ParallelCopyShmInfo *) shm_toc_allocate(pcxt->toc, sizeof(ParallelCopyShmInfo));
+	PopulateParallelCopyShmInfo(shared_info_ptr);
+
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_SHARED_INFO, shared_info_ptr);
+	pcdata->pcshared_info = shared_info_ptr;
+
+	SerializeParallelCopyState(pcxt, cstate, strsize, &list_converted_str);
+
+	/*
+	 * Allocate space for each worker's WalUsage and BufferUsage; no need to
+	 * initialize.
+	 */
+	walusage = shm_toc_allocate(pcxt->toc,
+								mul_size(sizeof(WalUsage), pcxt->nworkers));
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_WAL_USAGE, walusage);
+	pcdata->walusage = walusage;
+	bufferusage = shm_toc_allocate(pcxt->toc,
+								   mul_size(sizeof(BufferUsage), pcxt->nworkers));
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_BUFFER_USAGE, bufferusage);
+	pcdata->bufferusage = bufferusage;
+
+	LaunchParallelWorkers(pcxt);
+	if (pcxt->nworkers_launched == 0)
+	{
+		EndParallelCopy(pcxt);
+		pfree(pcdata);
+		cstate->pcdata = NULL;
+		return NULL;
+	}
+
+	/*
+	 * Caller needs to wait for all launched workers when we return.  Make
+	 * sure that the failure-to-start case will not hang forever.
+	 */
+	WaitForParallelWorkersToAttach(pcxt);
+
+	pcdata->is_leader = true;
+	cstate->is_parallel = true;
+	return pcxt;
+}
+
+/*
+ * EndParallelCopy
+ *
+ * End the parallel copy tasks.
+ */
+pg_attribute_always_inline void
+EndParallelCopy(ParallelContext *pcxt)
+{
+	Assert(!IsParallelWorker());
+
+	DestroyParallelContext(pcxt);
+	ExitParallelMode();
+}
+
+/*
+ * InitializeParallelCopyInfo
+ *
+ * Initialize parallel worker.
+ */
+static void
+InitializeParallelCopyInfo(CopyState cstate, List *attnamelist)
+{
+	uint32		count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	PopulateCommonCStateInfo(cstate, tup_desc, attnamelist);
+
+	/* Initialize state variables. */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/* Set up variables to avoid per-attribute overhead. */
+	initStringInfo(&cstate->attribute_buf);
+
+	initStringInfo(&cstate->line_buf);
+	for (count = 0; count < WORKER_CHUNK_COUNT; count++)
+		initStringInfo(&pcdata->worker_line_buf[count].line_buf);
+
+	cstate->line_buf_converted = false;
+	cstate->raw_buf = NULL;
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+
+	PopulateCStateCatalogInfo(cstate);
+
+	/* Create workspace for CopyReadAttributes results. */
+	if (!cstate->binary)
+	{
+		AttrNumber	attr_count = list_length(cstate->attnumlist);
+
+		cstate->max_fields = attr_count;
+		cstate->raw_fields = (char **) palloc(attr_count * sizeof(char *));
+	}
+}
+
+/*
+ * RETURN_AFTER_UPDATING_LINE_INFO - Update line information & return.
+ */
+#define RETURN_AFTER_UPDATING_LINE_INFO() \
+{ \
+	elog(DEBUG1, "[Worker] Completed processing line:%d", write_pos); \
+	pg_atomic_write_u32(&lineInfo->line_state, LINE_WORKER_PROCESSED); \
+	pg_atomic_write_u32(&lineInfo->line_size, -1); \
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1); \
+	return false; \
+}
+
+/*
+ * CacheLineInfo
+ *
+ * Cache the line information to local memory.
+ */
+static bool
+CacheLineInfo(CopyState cstate, uint32 buff_count)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	uint32		write_pos;
+	ParallelCopyDataBlock *data_blk_ptr;
+	ParallelCopyLineBoundary *lineInfo;
+	uint32		offset;
+	int			dataSize;
+	int			copiedSize = 0;
+
+	resetStringInfo(&pcdata->worker_line_buf[buff_count].line_buf);
+	write_pos = GetLinePosition(cstate);
+	if (-1 == write_pos)
+		return true;
+
+	/* Get the current line information. */
+	lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+	if (pg_atomic_read_u32(&lineInfo->line_size) == 0)
+		RETURN_AFTER_UPDATING_LINE_INFO()
+
+	/* Get the block information. */
+	data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+	/* Get the offset information from where the data must be copied. */
+	offset = lineInfo->start_offset;
+	pcdata->worker_line_buf[buff_count].cur_lineno = lineInfo->cur_lineno;
+
+	elog(DEBUG1, "[Worker] Processing - line position:%d, block:%d, unprocessed lines:%d, offset:%d, line size:%d",
+		 write_pos, lineInfo->first_block,
+		 pg_atomic_read_u32(&data_blk_ptr->unprocessed_line_parts),
+		 offset, pg_atomic_read_u32(&lineInfo->line_size));
+
+	for (;;)
+	{
+		uint8		skip_bytes = data_blk_ptr->skip_bytes;
+
+		/*
+		 * There is a possibility that the loop embedded at the bottom of the
+		 * current loop has come out because data_blk_ptr->curr_blk_completed
+		 * is set, but dataSize read might be an old value, if
+		 * data_blk_ptr->curr_blk_completed and the line is completed,
+		 * line_size will be set. Read the line_size again to be sure if it is
+		 * completed or partial block.
+		 */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+		if (dataSize)
+		{
+			int			remainingSize = dataSize - copiedSize;
+
+			if (!remainingSize)
+				break;
+
+			/* Whole line is in current block. */
+			if (remainingSize + offset + skip_bytes < DATA_BLOCK_SIZE)
+			{
+				appendBinaryStringInfo(&pcdata->worker_line_buf[buff_count].line_buf,
+									   &data_blk_ptr->data[offset],
+									   remainingSize);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts,
+										1);
+				break;
+			}
+			else
+			{
+				/* Line is spread across the blocks. */
+				uint32		lineInCurrentBlock = (DATA_BLOCK_SIZE - skip_bytes) - offset;
+
+				appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+										 &data_blk_ptr->data[offset],
+										 lineInCurrentBlock);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+				copiedSize += lineInCurrentBlock;
+				while (copiedSize < dataSize)
+				{
+					uint32		currentBlockCopySize;
+					ParallelCopyDataBlock *currBlkPtr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+
+					skip_bytes = currBlkPtr->skip_bytes;
+
+					/*
+					 * If complete data is present in current block use
+					 * dataSize - copiedSize, or copy the whole block from
+					 * current block.
+					 */
+					currentBlockCopySize = Min(dataSize - copiedSize, DATA_BLOCK_SIZE - skip_bytes);
+					appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+											 &currBlkPtr->data[0],
+											 currentBlockCopySize);
+					pg_atomic_sub_fetch_u32(&currBlkPtr->unprocessed_line_parts, 1);
+					copiedSize += currentBlockCopySize;
+					data_blk_ptr = currBlkPtr;
+				}
+
+				break;
+			}
+		}
+		else
+		{
+			/* Copy this complete block from the current offset. */
+			uint32		lineInCurrentBlock = (DATA_BLOCK_SIZE - skip_bytes) - offset;
+
+			appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+									 &data_blk_ptr->data[offset],
+									 lineInCurrentBlock);
+			pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+			copiedSize += lineInCurrentBlock;
+
+			/*
+			 * Reset the offset. For the first copy, copy from the offset. For
+			 * the subsequent copy the complete block.
+			 */
+			offset = 0;
+
+			/* Set data_blk_ptr to the following block. */
+			data_blk_ptr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+		}
+
+		for (;;)
+		{
+			/* Get the size of this line */
+			dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+			/*
+			 * If the data is present in current block lineInfo->line_size
+			 * will be updated. If the data is spread across the blocks either
+			 * of lineInfo->line_size or data_blk_ptr->curr_blk_completed can
+			 * be updated. lineInfo->line_size will be updated if the complete
+			 * read is finished. data_blk_ptr->curr_blk_completed will be
+			 * updated if processing of current block is finished and data
+			 * processing is not finished.
+			 */
+			if (data_blk_ptr->curr_blk_completed || (dataSize != -1))
+				break;
+
+			COPY_WAIT_TO_PROCESS()
+		}
+	}
+
+	RETURN_AFTER_UPDATING_LINE_INFO()
+}
+
+/*
+ * RETURN_CACHED_LINE - Return a previously cached line to be processed by the
+ * worker.
+ */
+#define RETURN_CACHED_LINE() \
+{ \
+	cstate->line_buf = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].line_buf; \
+	cstate->cur_lineno = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].cur_lineno; \
+	cstate->line_buf_valid = true; \
+	\
+	/* Mark that encoding conversion hasn't occurred yet. */ \
+	cstate->line_buf_converted = false; \
+	\
+	/* For binary format data, we don't need conversion. */ \
+	if (!cstate->binary) \
+		ConvertToServerEncoding(cstate); \
+	\
+	pcdata->worker_line_buf_pos++; \
+	return false; \
+}
+
+/*
+ * GetWorkerLine
+ *
+ * Returns a line for worker to process.
+ */
+bool
+GetWorkerLine(CopyState cstate)
+{
+	uint32		buff_count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+
+	/*
+	 * Copy the line data to line_buf and release the line position so that
+	 * the worker can continue loading data.
+	 */
+	if (pcdata->worker_line_buf_pos < pcdata->worker_line_buf_count)
+		RETURN_CACHED_LINE()
+
+	pcdata->worker_line_buf_pos = 0;
+	pcdata->worker_line_buf_count = 0;
+
+	for (buff_count = 0; buff_count < WORKER_CHUNK_COUNT; buff_count++)
+	{
+		bool		result = CacheLineInfo(cstate, buff_count);
+
+		if (result)
+			break;
+
+		pcdata->worker_line_buf_count++;
+	}
+
+	if (pcdata->worker_line_buf_count)
+		RETURN_CACHED_LINE()
+	else
+		resetStringInfo(&cstate->line_buf);
+
+	return true;
+}
+
+/*
+ * ParallelCopyMain - Parallel copy worker's code.
+ *
+ * Where clause handling, convert tuple to columns, add default null values for
+ * the missing columns that are not present in that record. Find the partition
+ * if it is partitioned table, invoke before row insert Triggers, handle
+ * constraints and insert the tuples.
+ */
+void
+ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
+{
+	CopyState	cstate;
+	ParallelCopyData *pcdata;
+	ParallelCopyShmInfo *pcshared_info;
+	Relation	rel = NULL;
+	MemoryContext oldcontext;
+	List	   *attlist = NIL;
+	WalUsage   *walusage;
+	BufferUsage *bufferusage;
+
+	/* Allocate workspace and zero all fields. */
+	cstate = (CopyStateData *) palloc0(sizeof(CopyStateData));
+
+	/*
+	 * We allocate everything used by a cstate in a new memory context. This
+	 * avoids memory leaks during repeated use of COPY in a query.
+	 */
+	cstate->copycontext = AllocSetContextCreate(CurrentMemoryContext,
+												"COPY",
+												ALLOCSET_DEFAULT_SIZES);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	cstate->pcdata = pcdata;
+	pcdata->is_leader = false;
+	pcdata->worker_processed_pos = -1;
+	cstate->is_parallel = true;
+	pcshared_info = (ParallelCopyShmInfo *) shm_toc_lookup(toc, PARALLEL_COPY_KEY_SHARED_INFO, false);
+
+	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
+
+	pcdata->pcshared_info = pcshared_info;
+	RestoreParallelCopyState(toc, cstate, &attlist);
+
+	/* Open and lock the relation, using the appropriate lock type. */
+	rel = table_open(cstate->pcdata->relid, RowExclusiveLock);
+	cstate->rel = rel;
+	InitializeParallelCopyInfo(cstate, attlist);
+
+	/* Prepare to track buffer usage during parallel execution */
+	InstrStartParallelQuery();
+
+	CopyFrom(cstate);
+
+	if (rel != NULL)
+		table_close(rel, RowExclusiveLock);
+
+	/* Report WAL/buffer usage during parallel execution */
+	bufferusage = shm_toc_lookup(toc, PARALLEL_COPY_KEY_BUFFER_USAGE, false);
+	walusage = shm_toc_lookup(toc, PARALLEL_COPY_KEY_WAL_USAGE, false);
+	InstrEndParallelQuery(&bufferusage[ParallelWorkerNumber],
+						  &walusage[ParallelWorkerNumber]);
+
+	MemoryContextSwitchTo(oldcontext);
+	MemoryContextDelete(cstate->copycontext);
+	pfree(cstate);
+	return;
+}
+
+/*
+ * UpdateSharedLineInfo
+ *
+ * Update the line information.
+ */
+uint32
+UpdateSharedLineInfo(CopyState cstate, uint32 blk_pos, uint32 offset,
+					 uint32 line_size, uint32 line_state, uint32 blk_line_pos)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyLineBoundaries *lineBoundaryPtr = &pcshared_info->line_boundaries;
+	ParallelCopyLineBoundary *lineInfo;
+	uint32		line_pos;
+
+	/* blk_line_pos will be valid in case line_pos was blocked earlier. */
+	if (blk_line_pos == -1)
+	{
+		line_pos = lineBoundaryPtr->pos;
+
+		/* Update the line information for the worker to pick and process. */
+		lineInfo = &lineBoundaryPtr->ring[line_pos];
+		while (pg_atomic_read_u32(&lineInfo->line_size) != -1)
+			COPY_WAIT_TO_PROCESS()
+
+		lineInfo->first_block = blk_pos;
+		lineInfo->start_offset = offset;
+		lineInfo->cur_lineno = cstate->cur_lineno;
+		lineBoundaryPtr->pos = (lineBoundaryPtr->pos + 1) % RINGSIZE;
+	}
+	else
+	{
+		line_pos = blk_line_pos;
+		lineInfo = &lineBoundaryPtr->ring[line_pos];
+	}
+
+	if (line_state == LINE_LEADER_POPULATED)
+	{
+		elog(DEBUG1, "[Leader] Added line with block:%d, offset:%d, line position:%d, line size:%d",
+			 lineInfo->first_block, lineInfo->start_offset, line_pos,
+			 pg_atomic_read_u32(&lineInfo->line_size));
+		pcshared_info->populated++;
+	}
+	else
+		elog(DEBUG1, "[Leader] Adding - block:%d, offset:%d, line position:%d",
+			 lineInfo->first_block, lineInfo->start_offset, line_pos);
+
+	pg_atomic_write_u32(&lineInfo->line_size, line_size);
+	pg_atomic_write_u32(&lineInfo->line_state, line_state);
+
+	return line_pos;
+}
+
+/*
+ * ParallelCopyFrom - parallel copy leader's functionality.
+ *
+ * Leader executes the before statement for before statement trigger, if before
+ * statement trigger is present. It will read the table data from the file and
+ * copy the contents to DSM data blocks. It will then read the input contents
+ * from the DSM data block and identify the records based on line breaks. This
+ * information is called line or a record that need to be inserted into a
+ * relation. The line information will be stored in ParallelCopyLineBoundary DSM
+ * data structure. Workers will then process this information and insert the
+ * data in to table. It will repeat this process until the all data is read from
+ * the file and all the DSM data blocks are processed. While processing if
+ * leader identifies that DSM Data blocks or DSM ParallelCopyLineBoundary data
+ * structures is full, leader will wait till the worker frees up some entries
+ * and repeat the process. It will wait till all the lines populated are
+ * processed by the workers and exits.
+ */
+void
+ParallelCopyFrom(CopyState cstate)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
+
+	/* raw_buf is not used in parallel copy, instead data blocks are used. */
+	pfree(cstate->raw_buf);
+	cstate->raw_buf = NULL;
+
+	/* Execute the before statement triggers from the leader */
+	ExecBeforeStmtTrigger(cstate);
+
+	/* On input just throw the header line away. */
+	if (cstate->cur_lineno == 0 && cstate->header_line)
+	{
+		cstate->cur_lineno++;
+		if (CopyReadLine(cstate))
+		{
+			pcshared_info->is_read_in_progress = false;
+			return;			/* done */
+		}
+	}
+
+	for (;;)
+	{
+		bool		done;
+		CHECK_FOR_INTERRUPTS();
+
+		cstate->cur_lineno++;
+
+		/* Actually read the line into memory here. */
+		done = CopyReadLine(cstate);
+
+		/*
+			* EOF at start of line means we're done.  If we see EOF after
+			* some characters, we act as though it was newline followed by
+			* EOF, ie, process the line and then exit loop on next iteration.
+			*/
+		if (done && cstate->line_buf.len == 0)
+			break;
+	}
+
+	/*
+	 * In the old protocol, tell pqcomm that we can process normal protocol
+	 * messages again.
+	 */
+	if (cstate->copy_dest == COPY_OLD_FE)
+		pq_endmsgread();
+
+	pcshared_info->is_read_in_progress = false;
+	cstate->cur_lineno = 0;
+}
+/*
+ * GetLinePosition
+ *
+ * Return the line position once the leader has populated the data.
+ */
+uint32
+GetLinePosition(CopyState cstate)
+{
+	ParallelCopyData *pcdata = cstate->pcdata;
+	ParallelCopyShmInfo *pcshared_info = pcdata->pcshared_info;
+	uint32		previous_pos = pcdata->worker_processed_pos;
+	uint32		write_pos = (previous_pos == -1) ? 0 : (previous_pos + 1) % RINGSIZE;
+
+	for (;;)
+	{
+		int			dataSize;
+		bool		is_read_in_progress = pcshared_info->is_read_in_progress;
+		ParallelCopyLineBoundary *lineInfo;
+		ParallelCopyDataBlock *data_blk_ptr;
+		uint32		line_state = LINE_LEADER_POPULATED;
+		ParallelCopyLineState curr_line_state;
+
+		CHECK_FOR_INTERRUPTS();
+
+		/* File read completed & no elements to process. */
+		if (!is_read_in_progress &&
+			(pcshared_info->populated ==
+			 pg_atomic_read_u64(&pcshared_info->total_worker_processed)))
+		{
+			write_pos = -1;
+			break;
+		}
+
+		/* Get the current line information. */
+		lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+		curr_line_state = pg_atomic_read_u32(&lineInfo->line_state);
+		if ((write_pos % WORKER_CHUNK_COUNT == 0) &&
+			(curr_line_state == LINE_WORKER_PROCESSED ||
+			 curr_line_state == LINE_WORKER_PROCESSING))
+		{
+			pcdata->worker_processed_pos = write_pos;
+			write_pos = (write_pos + WORKER_CHUNK_COUNT) % RINGSIZE;
+			continue;
+		}
+
+		/* Get the size of this line. */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+		if (dataSize != 0)		/* If not an empty line. */
+		{
+			/* Get the block information. */
+			data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+			if (!data_blk_ptr->curr_blk_completed && (dataSize == -1))
+			{
+				/* Wait till the current line or block is added. */
+				COPY_WAIT_TO_PROCESS()
+					continue;
+			}
+		}
+
+		/* Make sure that no worker has consumed this element. */
+		if (pg_atomic_compare_exchange_u32(&lineInfo->line_state,
+										   &line_state, LINE_WORKER_PROCESSING))
+			break;
+	}
+
+	pcdata->worker_processed_pos = write_pos;
+	return write_pos;
+}
+
+/*
+ * GetFreeCopyBlock
+ *
+ * Get a free block for data to be copied.
+ */
+static pg_attribute_always_inline uint32
+GetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	int			count = 0;
+	uint32		last_free_block = pcshared_info->cur_block_pos;
+	uint32		block_pos = (last_free_block != -1) ? ((last_free_block + 1) % MAX_BLOCKS_COUNT) : 0;
+
+	/*
+	 * Get a new block for copying data, don't check current block, current
+	 * block will have some unprocessed data.
+	 */
+	while (count < (MAX_BLOCKS_COUNT - 1))
+	{
+		ParallelCopyDataBlock *dataBlkPtr = &pcshared_info->data_blocks[block_pos];
+		uint32		unprocessed_line_parts = pg_atomic_read_u32(&dataBlkPtr->unprocessed_line_parts);
+
+		if (unprocessed_line_parts == 0)
+		{
+			dataBlkPtr->curr_blk_completed = false;
+			dataBlkPtr->skip_bytes = 0;
+			dataBlkPtr->following_block = -1;
+			pcshared_info->cur_block_pos = block_pos;
+			MemSet(&dataBlkPtr->data[0], 0, DATA_BLOCK_SIZE);
+			return block_pos;
+		}
+
+		block_pos = (block_pos + 1) % MAX_BLOCKS_COUNT;
+		count++;
+	}
+
+	return -1;
+}
+
+/*
+ * WaitGetFreeCopyBlock
+ *
+ * If there are no blocks available, wait and get a block for copying data.
+ */
+uint32
+WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	uint32		new_free_pos = -1;
+
+	for (;;)
+	{
+		new_free_pos = GetFreeCopyBlock(pcshared_info);
+		if (new_free_pos != -1) /* We have got one block, break now. */
+			break;
+
+		COPY_WAIT_TO_PROCESS()
+	}
+
+	return new_free_pos;
+}
+
+/*
+ * SetRawBufForLoad
+ *
+ * Set raw_buf to the shared memory where the file data must be read.
+ */
+void
+SetRawBufForLoad(CopyState cstate, uint32 line_size, uint32 copy_buf_len,
+				 uint32 raw_buf_ptr, char **copy_raw_buf)
+{
+	ParallelCopyShmInfo *pcshared_info;
+	uint32		cur_block_pos;
+	uint32		next_block_pos;
+	ParallelCopyDataBlock *cur_data_blk_ptr = NULL;
+	ParallelCopyDataBlock *next_data_blk_ptr = NULL;
+
+	Assert(IsParallelCopy());
+
+	pcshared_info = cstate->pcdata->pcshared_info;
+	cur_block_pos = pcshared_info->cur_block_pos;
+	cur_data_blk_ptr = (cstate->raw_buf) ? &pcshared_info->data_blocks[cur_block_pos] : NULL;
+	next_block_pos = WaitGetFreeCopyBlock(pcshared_info);
+	next_data_blk_ptr = &pcshared_info->data_blocks[next_block_pos];
+
+	/* set raw_buf to the data block in shared memory */
+	cstate->raw_buf = next_data_blk_ptr->data;
+	*copy_raw_buf = cstate->raw_buf;
+	if (cur_data_blk_ptr && line_size)
+	{
+		/*
+		 * Mark the previous block as completed, worker can start copying this
+		 * data.
+		 */
+		cur_data_blk_ptr->following_block = next_block_pos;
+		pg_atomic_add_fetch_u32(&cur_data_blk_ptr->unprocessed_line_parts, 1);
+		cur_data_blk_ptr->skip_bytes = copy_buf_len - raw_buf_ptr;
+		cur_data_blk_ptr->curr_blk_completed = true;
+	}
+
+	cstate->raw_buf_index = 0;
+	cstate->raw_buf_len = 0;
+}
+
+/*
+ * SET_NEWLINE_SIZE - Sets the new line size.
+ */
+#define SET_NEWLINE_SIZE() \
+{ \
+	if (cstate->eol_type == EOL_NL || cstate->eol_type == EOL_CR) \
+		new_line_size = 1; \
+	else if (cstate->eol_type == EOL_CRNL) \
+		new_line_size = 2; \
+	else \
+		new_line_size = 0; \
+}
+
+/*
+ * EndLineParallelCopy
+ *
+ * Update the line information in shared memory.
+ */
+void
+EndLineParallelCopy(CopyState cstate, uint32 line_pos, uint32 line_size,
+					uint32 raw_buf_ptr)
+{
+	uint8		new_line_size;
+
+	if (!IsParallelCopy())
+		return;
+
+	if (!IsHeaderLine())
+	{
+		ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+		SET_NEWLINE_SIZE()
+			if (line_size)
+		{
+			/*
+			 * If the new_line_size > raw_buf_ptr, then the new block has only
+			 * new line char content. The unprocessed count should not be
+			 * increased in this case.
+			 */
+			if (raw_buf_ptr > new_line_size)
+			{
+				uint32		cur_block_pos = pcshared_info->cur_block_pos;
+				ParallelCopyDataBlock *curr_data_blk_ptr = &pcshared_info->data_blocks[cur_block_pos];
+
+				pg_atomic_add_fetch_u32(&curr_data_blk_ptr->unprocessed_line_parts, 1);
+			}
+
+			/*
+			 * Update line size & line state, other members are already
+			 * updated.
+			 */
+			(void) UpdateSharedLineInfo(cstate, -1, -1, line_size,
+										LINE_LEADER_POPULATED, line_pos);
+		}
+		else if (new_line_size)
+			/* This means only new line char, empty record should be inserted. */
+			(void) UpdateSharedLineInfo(cstate, -1, -1, 0,
+										LINE_LEADER_POPULATED, -1);
+	}
+}
+
+/*
+ * ExecBeforeStmtTrigger
+ *
+ * Execute the before statement trigger, this will be executed for parallel copy
+ * by the leader process. This function code changes has been taken from
+ * CopyFrom function. Refer to comments section of respective code in CopyFrom
+ * function for more detailed information.
+ */
+void
+ExecBeforeStmtTrigger(CopyState cstate)
+{
+	EState	   *estate = CreateExecutorState();
+	ResultRelInfo *resultRelInfo;
+
+	Assert(IsLeader());
+	ExecInitRangeTable(estate, cstate->range_table);
+	resultRelInfo = makeNode(ResultRelInfo);
+	ExecInitResultRelation(estate, resultRelInfo, 1);
+	CheckValidResultRel(resultRelInfo, CMD_INSERT);
+	AfterTriggerBeginQuery();
+	ExecBSInsertTriggers(estate, resultRelInfo);
+	AfterTriggerEndQuery(estate);
+	ExecCloseResultRelations(estate);
+	ExecCloseRangeTableRelations(estate);
+	FreeExecutorState(estate);
+}
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index b2b4f1f..5f8856a 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -2356,7 +2356,7 @@ psql_completion(const char *text, int start, int end)
 	/* Complete COPY <sth> FROM|TO filename WITH ( */
 	else if (Matches("COPY|\\copy", MatchAny, "FROM|TO", MatchAny, "WITH", "("))
 		COMPLETE_WITH("FORMAT", "FREEZE", "DELIMITER", "NULL",
-					  "HEADER", "QUOTE", "ESCAPE", "FORCE_QUOTE",
+					  "HEADER", "PARALLEL", "QUOTE", "ESCAPE", "FORCE_QUOTE",
 					  "FORCE_NOT_NULL", "FORCE_NULL", "ENCODING");
 
 	/* Complete COPY <sth> FROM|TO filename WITH (FORMAT */
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index 7320de3..42d4893 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -386,6 +386,7 @@ extern FullTransactionId GetTopFullTransactionId(void);
 extern FullTransactionId GetTopFullTransactionIdIfAny(void);
 extern FullTransactionId GetCurrentFullTransactionId(void);
 extern FullTransactionId GetCurrentFullTransactionIdIfAny(void);
+extern void SetCurrentCommandIdUsedForWorker(void);
 extern void MarkCurrentTransactionIdLoggedIfAny(void);
 extern bool SubTransactionIsActive(SubTransactionId subxid);
 extern CommandId GetCurrentCommandId(bool used);
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index b9331af..2c2b9da 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -14,6 +14,7 @@
 #ifndef COPY_H
 #define COPY_H
 
+#include "access/parallel.h"
 #include "commands/copy_internal.h"
 #include "nodes/execnodes.h"
 #include "nodes/parsenodes.h"
@@ -38,4 +39,26 @@ extern uint64 CopyFrom(CopyState cstate);
 
 extern DestReceiver *CreateCopyDestReceiver(void);
 
+extern void PopulateCommonCStateInfo(CopyState cstate, TupleDesc tup_desc,
+									 List *attnamelist);
+extern void ConvertToServerEncoding(CopyState cstate);
+
+extern void ParallelCopyMain(dsm_segment *seg, shm_toc *toc);
+extern ParallelContext *BeginParallelCopy(CopyState cstate, List *attnamelist, Oid relid);
+extern void ParallelCopyFrom(CopyState cstate);
+extern void EndParallelCopy(ParallelContext *pcxt);
+extern bool IsParallelCopyAllowed(CopyState cstate);
+extern void ExecBeforeStmtTrigger(CopyState cstate);
+extern void CheckTargetRelValidity(CopyState cstate);
+extern void PopulateCStateCatalogInfo(CopyState cstate);
+extern uint32 GetLinePosition(CopyState cstate);
+extern bool GetWorkerLine(CopyState cstate);
+extern bool CopyReadLine(CopyState cstate);
+extern uint32 WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info);
+extern void SetRawBufForLoad(CopyState cstate, uint32 line_size, uint32 copy_buf_len,
+							 uint32 raw_buf_ptr, char **copy_raw_buf);
+extern uint32 UpdateSharedLineInfo(CopyState cstate, uint32 blk_pos, uint32 offset,
+								   uint32 line_size, uint32 line_state, uint32 blk_line_pos);
+extern void EndLineParallelCopy(CopyState cstate, uint32 line_pos, uint32 line_size,
+								uint32 raw_buf_ptr);
 #endif							/* COPY_H */
diff --git a/src/include/commands/copy_internal.h b/src/include/commands/copy_internal.h
index ea4bfca..73bb5a7 100644
--- a/src/include/commands/copy_internal.h
+++ b/src/include/commands/copy_internal.h
@@ -17,6 +17,42 @@
 #include "commands/trigger.h"
 #include "executor/executor.h"
 
+#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+
+/*
+ * The macros DATA_BLOCK_SIZE, RINGSIZE & MAX_BLOCKS_COUNT stores the records
+ * read from the file that need to be inserted into the relation. These values
+ * help in the handover of multiple records with the significant size of data to
+ * be processed by each of the workers. This also ensures there is no context
+ * switch and the work is fairly distributed among the workers. This number
+ * showed best results in the performance tests.
+ */
+#define DATA_BLOCK_SIZE RAW_BUF_SIZE
+
+/*
+ * It can hold MAX_BLOCKS_COUNT blocks of RAW_BUF_SIZE data in DSM to be
+ * processed by the worker.
+ */
+#define MAX_BLOCKS_COUNT 1024
+
+/*
+ * It can hold upto RINGSIZE record information for worker to process. RINGSIZE
+ * should be a multiple of WORKER_CHUNK_COUNT, as wrap around cases is currently
+ * not handled while selecting the WORKER_CHUNK_COUNT by the worker.
+ */
+#define RINGSIZE (10 * 1024)
+
+/*
+ * While accessing DSM, each worker will pick the WORKER_CHUNK_COUNT records
+ * from the DSM data blocks at a time and store them in it's local memory. This
+ * is to make workers not contend much while getting record information from the
+ * DSM. Read RINGSIZE comments before changing this value.
+ */
+#define WORKER_CHUNK_COUNT 64
+
+#define IsParallelCopy()		(cstate->is_parallel)
+#define IsLeader()				(cstate->pcdata->is_leader)
+#define IsWorker()				(IsParallelCopy() && !IsLeader())
 #define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
 
 /*
@@ -43,6 +79,18 @@ typedef enum EolType
 } EolType;
 
 /*
+ * State of the line.
+ */
+typedef enum ParallelCopyLineState
+{
+	LINE_INIT,					/* initial state of line */
+	LINE_LEADER_POPULATING,		/* leader processing line */
+	LINE_LEADER_POPULATED,		/* leader completed populating line */
+	LINE_WORKER_PROCESSING,		/* worker processing line */
+	LINE_WORKER_PROCESSED		/* worker completed processing line */
+} ParallelCopyLineState;
+
+/*
  * Represents the heap insert method to be used during COPY FROM.
  */
 typedef enum CopyInsertMethod
@@ -52,7 +100,180 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
-#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+/*
+ * Copy data block information.
+ *
+ * These data blocks are created in DSM. Data read from file will be copied in
+ * these DSM data blocks. The leader process identifies the records and the
+ * record information will be shared to the workers. The workers will insert the
+ * records into the table. There can be one or more number of records in each of
+ * the data block based on the record size.
+ */
+typedef struct ParallelCopyDataBlock
+{
+	/* The number of unprocessed lines in the current block. */
+	pg_atomic_uint32 unprocessed_line_parts;
+
+	/*
+	 * If the current line data is continued into another block,
+	 * following_block will have the position where the remaining data need to
+	 * be read.
+	 */
+	uint32		following_block;
+
+	/*
+	 * This flag will be set, when the leader finds out this block can be read
+	 * safely by the worker. This helps the worker to start processing the
+	 * line early where the line will be spread across many blocks and the
+	 * worker need not wait for the complete line to be processed.
+	 */
+	bool		curr_blk_completed;
+
+	/*
+	 * Few bytes need to be skipped from this block, this will be set when a
+	 * sequence of characters like \r\n is expected, but end of our block
+	 * contained only \r. In this case we copy the data from \r into the new
+	 * block as they have to be processed together to identify end of line.
+	 * Worker will use skip_bytes to know that this data must be skipped from
+	 * this data block.
+	 */
+	uint8		skip_bytes;
+	char		data[DATA_BLOCK_SIZE];	/* data read from file */
+} ParallelCopyDataBlock;
+
+/*
+ * Individual line information.
+ *
+ * ParallelCopyLineBoundary is common data structure between leader & worker.
+ * Leader process will be populating data block, data block offset & the size of
+ * the record in DSM for the workers to copy the data into the relation.
+ * The leader & worker process access the shared line information by following
+ * the below steps to avoid any data corruption or hang:
+ *
+ * Leader should operate in the following order:
+ * 1) check if line_size is -1, if line_size is not -1 wait until line_size is
+ * set to -1 by the worker. If line_size is -1 it means worker is still
+ * processing.
+ * 2) set line_state to LINE_LEADER_POPULATING, so that the worker knows that
+ * leader is populating this line.
+ * 3) update first_block, start_offset & cur_lineno in any order.
+ * 4) update line_size.
+ * 5) update line_state to LINE_LEADER_POPULATED.
+ *
+ * Worker should operate in the following order:
+ * 1) check line_state is LINE_LEADER_POPULATED, if not it means leader is still
+ * populating the data.
+ * 2) read line_size to know the size of the data.
+ * 3) only one worker should choose one line for processing, this is handled by
+ *    using pg_atomic_compare_exchange_u32, worker will change the state to
+ *    LINE_WORKER_PROCESSING only if line_state is LINE_LEADER_POPULATED.
+ * 4) read first_block, start_offset & cur_lineno in any order.
+ * 5) process line_size data.
+ * 6) update line_size to -1.
+ */
+typedef struct ParallelCopyLineBoundary
+{
+	/* Position of the first block in data_blocks array. */
+	uint32		first_block;
+	uint32		start_offset;	/* start offset of the line */
+
+	/*
+	 * Size of the current line -1 means line is yet to be filled completely,
+	 * 0 means empty line, >0 means line filled with line size data.
+	 */
+	pg_atomic_uint32 line_size;
+	pg_atomic_uint32 line_state;	/* line state */
+	uint64		cur_lineno;		/* line number for error messages */
+} ParallelCopyLineBoundary;
+
+/*
+ * Circular queue used to store the line information.
+ */
+typedef struct ParallelCopyLineBoundaries
+{
+	/* Position for the leader to populate a line. */
+	uint32		pos;
+
+	/* Data read from the file/stdin by the leader process. */
+	ParallelCopyLineBoundary ring[RINGSIZE];
+} ParallelCopyLineBoundaries;
+
+/*
+ * Shared information among parallel copy workers. This will be allocated in the
+ * DSM segment.
+ */
+typedef struct ParallelCopyShmInfo
+{
+	bool		is_read_in_progress;	/* file read status */
+
+	/*
+	 * Actual lines inserted by worker, will not be same as
+	 * total_worker_processed if where condition is specified along with copy.
+	 * This will be the actual records inserted into the relation.
+	 */
+	pg_atomic_uint64 processed;
+
+	/*
+	 * The number of records currently processed by the worker, this will also
+	 * include the number of records that was filtered because of where
+	 * clause.
+	 */
+	pg_atomic_uint64 total_worker_processed;
+	uint64		populated;		/* lines populated by leader */
+	uint32		cur_block_pos;	/* current data block */
+	ParallelCopyDataBlock data_blocks[MAX_BLOCKS_COUNT];	/* data block array */
+	ParallelCopyLineBoundaries line_boundaries; /* line array */
+} ParallelCopyShmInfo;
+
+/*
+ * Parallel copy line buffer information.
+ */
+typedef struct ParallelCopyLineBuf
+{
+	StringInfoData line_buf;
+	uint64		cur_lineno;		/* line number for error messages */
+} ParallelCopyLineBuf;
+
+/*
+ * This structure helps in storing the common List/Node from CopyStateData that
+ * are required by the workers. This information will then be copied and stored
+ * into the DSM for the worker to retrieve and copy it to CopyStateData.
+ */
+typedef struct SerializedListToStrCState
+{
+	char 		*whereClauseStr;
+	char 		*rangeTableStr;
+	char 		*attnameListStr;
+	char 		*notnullListStr;
+	char 		*nullListStr;
+	char 		*convertListStr;
+} SerializedListToStrCState;
+
+/*
+ * Parallel copy data information.
+ */
+typedef struct ParallelCopyData
+{
+	Oid			relid;			/* relation id of the table */
+	ParallelCopyShmInfo *pcshared_info; /* common info in shared memory */
+	bool		is_leader;
+
+	/* line position which worker is processing */
+	uint32				worker_processed_pos;
+
+	WalUsage   *walusage;
+	BufferUsage *bufferusage;
+
+	/*
+	 * Local line_buf array, workers will copy it here and release the lines
+	 * for the leader to continue.
+	 */
+	ParallelCopyLineBuf worker_line_buf[WORKER_CHUNK_COUNT];
+	uint32		worker_line_buf_count;	/* Number of lines */
+
+	/* Current position in worker_line_buf */
+	uint32		worker_line_buf_pos;
+} ParallelCopyData;
 
 typedef int (*copy_data_source_cb) (void *outbuf, int minread, int maxread);
 
@@ -188,6 +409,9 @@ typedef struct CopyStateData
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
+	int			nworkers;
+	bool		is_parallel;
+	ParallelCopyData *pcdata;
 	/* Shorthand for number of unconsumed bytes available in raw_buf */
 #define RAW_BUF_BYTES(cstate) ((cstate)->raw_buf_len - (cstate)->raw_buf_index)
 } CopyStateData;
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index ff85363..70be094 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1703,6 +1703,13 @@ ParallelBitmapHeapState
 ParallelBlockTableScanDesc
 ParallelCompletionPtr
 ParallelContext
+ParallelCopyLineBoundaries
+ParallelCopyLineBoundary
+ParallelCopyData
+ParallelCopyDataBlock
+ParallelCopyLineBuf
+ParallelCopyLineState
+ParallelCopyShmInfo
 ParallelExecutorInfo
 ParallelHashGrowth
 ParallelHashJoinBatch
@@ -2225,6 +2232,7 @@ SerCommitSeqNo
 SerialControl
 SerializableXactHandle
 SerializedActiveRelMaps
+SerializedListToStrCState
 SerializedReindexState
 SerializedSnapshotData
 SerializedTransactionState
-- 
1.8.3.1

v9-0003-Documentation-for-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=v9-0003-Documentation-for-parallel-copy.patchDownload
From e160bd11971b315f36455785ca488c61035087c7 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Sat, 1 Aug 2020 09:00:36 +0530
Subject: [PATCH v9 3/5] Documentation for parallel copy.

This patch has the documentation changes for parallel copy.
---
 doc/src/sgml/ref/copy.sgml | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/doc/src/sgml/ref/copy.sgml b/doc/src/sgml/ref/copy.sgml
index 369342b..328a5f1 100644
--- a/doc/src/sgml/ref/copy.sgml
+++ b/doc/src/sgml/ref/copy.sgml
@@ -37,6 +37,7 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
     DELIMITER '<replaceable class="parameter">delimiter_character</replaceable>'
     NULL '<replaceable class="parameter">null_string</replaceable>'
     HEADER [ <replaceable class="parameter">boolean</replaceable> ]
+    PARALLEL <replaceable class="parameter">integer</replaceable>
     QUOTE '<replaceable class="parameter">quote_character</replaceable>'
     ESCAPE '<replaceable class="parameter">escape_character</replaceable>'
     FORCE_QUOTE { ( <replaceable class="parameter">column_name</replaceable> [, ...] ) | * }
@@ -277,6 +278,22 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
    </varlistentry>
 
    <varlistentry>
+    <term><literal>PARALLEL</literal></term>
+    <listitem>
+     <para>
+      Perform <command>COPY FROM</command> in parallel using <replaceable
+      class="parameter">integer</replaceable> background workers.  Please
+      note that it is not guaranteed that the number of parallel workers
+      specified in <replaceable class="parameter">integer</replaceable> will
+      be used during execution.  It is possible for a copy to run with fewer
+      workers than specified, or even with no workers at all (for example,
+      due to the setting of max_worker_processes). This option is allowed
+      only in <command>COPY FROM</command>.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><literal>QUOTE</literal></term>
     <listitem>
      <para>
@@ -953,6 +970,20 @@ COPY country FROM '/usr1/proj/bray/sql/country_data';
   </para>
 
   <para>
+   To copy data parallelly from a file into the <literal>country</literal> table:
+<programlisting>
+COPY country FROM '/usr1/proj/bray/sql/country_data' WITH (PARALLEL 1);
+</programlisting>
+  </para>
+
+  <para>
+   To copy data parallelly from STDIN into the <literal>country</literal> table:
+<programlisting>
+COPY country FROM STDIN WITH (PARALLEL 1);
+</programlisting>
+  </para>
+
+  <para>
    To copy into a file just the countries whose names start with 'A':
 <programlisting>
 COPY (SELECT * FROM country WHERE country_name LIKE 'A%') TO '/usr1/proj/bray/sql/a_list_countries.copy';
-- 
1.8.3.1

v9-0004-Tests-for-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=v9-0004-Tests-for-parallel-copy.patchDownload
From 03ee268446bd31267ff4b373f7d9d59c6fa22d2a Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Tue, 27 Oct 2020 06:25:36 +0530
Subject: [PATCH v9 4/5] Tests for parallel copy.

This patch has the tests for parallel copy.
---
 contrib/postgres_fdw/expected/postgres_fdw.out |  49 ++++
 contrib/postgres_fdw/sql/postgres_fdw.sql      |  52 ++++
 src/test/regress/expected/copy2.out            | 326 +++++++++++++++++++++-
 src/test/regress/input/copy.source             |  31 +++
 src/test/regress/output/copy.source            |  27 ++
 src/test/regress/sql/copy2.sql                 | 368 ++++++++++++++++++++++++-
 6 files changed, 845 insertions(+), 8 deletions(-)

diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index 2d88d06..474c5e7 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -9033,5 +9033,54 @@ SELECT 1 FROM ft1 LIMIT 1;    -- should fail
 ERROR:  08006
 \set VERBOSITY default
 COMMIT;
+-- parallel copy related tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+CREATE FOREIGN TABLE test_parallel_copy_ft (
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+) SERVER loopback OPTIONS (table_name 'test_parallel_copy') ;
+-- parallel copy into foreign table, parallelism must not be picked up.
+COPY test_parallel_copy_ft FROM stdin WITH (PARALLEL 1);
+SELECT count(*) FROM test_parallel_copy_ft;
+ count 
+-------
+     2
+(1 row)
+
+-- parallel copy into a table with foreign partition.
+CREATE TABLE part_test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+) PARTITION BY LIST (b);
+CREATE FOREIGN TABLE part_test_parallel_copy_a1 (c TEXT, b INT, a INT, e TEXT, d TEXT) SERVER loopback;
+CREATE TABLE part_test_parallel_copy_a2 (a INT, c TEXT, b INT, d TEXT, e TEXT);
+ALTER TABLE part_test_parallel_copy ATTACH PARTITION part_test_parallel_copy_a1 FOR VALUES IN(1);
+ALTER TABLE part_test_parallel_copy ATTACH PARTITION part_test_parallel_copy_a2 FOR VALUES IN(2);
+COPY part_test_parallel_copy FROM stdin WITH (PARALLEL 1);
+ERROR:  cannot perform PARALLEL COPY if partition has BEFORE/INSTEAD OF triggers, or if the partition is foreign partition
+HINT:  Try COPY without PARALLEL option
+CONTEXT:  COPY part_test_parallel_copy, line 1: "1	1	test_c1	test_d1	test_e1"
+parallel worker
+SELECT count(*) FROM part_test_parallel_copy WHERE b = 2;
+ count 
+-------
+     0
+(1 row)
+
 -- Clean up
 DROP PROCEDURE terminate_backend_and_wait(text);
+DROP FOREIGN TABLE test_parallel_copy_ft;
+DROP TABLE test_parallel_copy;
+DROP TABLE part_test_parallel_copy;
diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql
index 7581c54..635fcc2 100644
--- a/contrib/postgres_fdw/sql/postgres_fdw.sql
+++ b/contrib/postgres_fdw/sql/postgres_fdw.sql
@@ -2695,5 +2695,57 @@ SELECT 1 FROM ft1 LIMIT 1;    -- should fail
 \set VERBOSITY default
 COMMIT;
 
+-- parallel copy related tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+
+CREATE FOREIGN TABLE test_parallel_copy_ft (
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+) SERVER loopback OPTIONS (table_name 'test_parallel_copy') ;
+
+-- parallel copy into foreign table, parallelism must not be picked up.
+COPY test_parallel_copy_ft FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+SELECT count(*) FROM test_parallel_copy_ft;
+
+-- parallel copy into a table with foreign partition.
+CREATE TABLE part_test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+) PARTITION BY LIST (b);
+
+CREATE FOREIGN TABLE part_test_parallel_copy_a1 (c TEXT, b INT, a INT, e TEXT, d TEXT) SERVER loopback;
+
+CREATE TABLE part_test_parallel_copy_a2 (a INT, c TEXT, b INT, d TEXT, e TEXT);
+
+ALTER TABLE part_test_parallel_copy ATTACH PARTITION part_test_parallel_copy_a1 FOR VALUES IN(1);
+
+ALTER TABLE part_test_parallel_copy ATTACH PARTITION part_test_parallel_copy_a2 FOR VALUES IN(2);
+
+COPY part_test_parallel_copy FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+SELECT count(*) FROM part_test_parallel_copy WHERE b = 2;
+
 -- Clean up
 DROP PROCEDURE terminate_backend_and_wait(text);
+DROP FOREIGN TABLE test_parallel_copy_ft;
+DROP TABLE test_parallel_copy;
+DROP TABLE part_test_parallel_copy;
diff --git a/src/test/regress/expected/copy2.out b/src/test/regress/expected/copy2.out
index c64f071..6ec4dea 100644
--- a/src/test/regress/expected/copy2.out
+++ b/src/test/regress/expected/copy2.out
@@ -301,18 +301,32 @@ It is "perfect".|
 "It is ""perfect"".","	"
 "",
 --test that we read consecutive LFs properly
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 COPY testnl FROM stdin CSV;
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+SELECT * FROM testnl;
+ a |          b           | c 
+---+----------------------+---
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+(2 rows)
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 COPY testeoc FROM stdin CSV;
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
 COPY testeoc TO stdout CSV;
 a\.
 \.b
 c\.d
 "\."
 -- test handling of nonstandard null marker that violates escaping rules
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 COPY testnull TO stdout WITH NULL AS E'\\0';
 1	\\0
@@ -327,6 +341,15 @@ SELECT * FROM testnull;
     | 
 (4 rows)
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 1);
+SELECT * FROM testnull;
+ a  | b  
+----+----
+ 42 | \0
+    | 
+(2 rows)
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -396,6 +419,34 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+SELECT * FROM vistest;
+ a  
+----
+ a2
+ b
+(2 rows)
+
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+COMMIT;
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 SELECT * FROM vistest;
  a 
@@ -456,7 +507,7 @@ SELECT * FROM vistest;
 (2 rows)
 
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -467,6 +518,8 @@ CREATE TEMP TABLE forcetest (
 -- should succeed with no effect ("b" remains an empty string, "c" remains NULL)
 BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 1);
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
  b |  c   
@@ -477,6 +530,8 @@ SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
 BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 1);
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
  c |  d   
@@ -533,6 +588,31 @@ select * from check_con_tbl;
    
 (2 rows)
 
+\d+ check_con_tbl
+                               Table "public.check_con_tbl"
+ Column |  Type   | Collation | Nullable | Default | Storage | Stats target | Description 
+--------+---------+-----------+----------+---------+---------+--------------+-------------
+ f1     | integer |           |          |         | plain   |              | 
+Check constraints:
+    "check_con_tbl_check" CHECK (check_con_function(check_con_tbl.*))
+
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 1);
+NOTICE:  input = {"f1":1}
+NOTICE:  input = {"f1":null}
+copy check_con_tbl from stdin with (parallel 1);
+NOTICE:  input = {"f1":0}
+ERROR:  new row for relation "check_con_tbl" violates check constraint "check_con_tbl_check"
+DETAIL:  Failing row contains (0).
+CONTEXT:  COPY check_con_tbl, line 1: "0"
+parallel worker
+select * from check_con_tbl;
+ f1 
+----
+  1
+   
+(2 rows)
+
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
 CREATE ROLE regress_rls_copy_user_colperms;
@@ -647,10 +727,248 @@ SELECT * FROM instead_of_insert_tbl;
 (2 rows)
 
 COMMIT;
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+COPY test_parallel_copy (a, b, c, d, e) FROM stdin WITH (PARALLEL 1);
+COPY test_parallel_copy (b, d) FROM stdin WITH (PARALLEL 1);
+COPY test_parallel_copy (b, d) FROM stdin WITH (PARALLEL 1);
+COPY test_parallel_copy (b, d) FROM stdin WITH (PARALLEL 1, FORMAT 'csv', HEADER);
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) FROM stdin WITH (PARALLEL 0);
+ERROR:  value 0 out of bounds for option "parallel"
+DETAIL:  Valid values are between "1" and "1024".
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri FROM stdin WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1) WHERE height > random() * 65;
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+-- temporary table copy: should perform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+COPY temp_test (a) FROM stdin WITH (PARALLEL 1);
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) FROM stdin WITH (PARALLEL 1);
+ERROR:  column "xyz" of relation "test_parallel_copy" does not exist
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) FROM stdin WITH (PARALLEL 1);
+ERROR:  column "d" specified more than once
+-- missing data: should fail
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+ERROR:  invalid input syntax for type integer: ""
+CONTEXT:  COPY test_parallel_copy, line 0, column a: ""
+parallel worker
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2000	230	23	23"
+parallel worker
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2001	231	\N	\N"
+parallel worker
+-- extra data: should fail
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+ERROR:  extra data after last expected column
+CONTEXT:  COPY test_parallel_copy, line 1: "2002	232	40	50	60	70	80"
+parallel worker
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) FROM stdin WITH (DELIMITER ',', null 'x', PARALLEL 1) ;
+COPY test_parallel_copy FROM stdin WITH (DELIMITER ';', NULL '', PARALLEL 1);
+COPY test_parallel_copy FROM stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL 1);
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a = 50004;
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a > 60003;
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE f > 60003;
+ERROR:  column "f" does not exist
+LINE 1: ..._parallel_copy FROM stdin WITH (PARALLEL 1) WHERE f > 60003;
+                                                             ^
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+ERROR:  missing FROM-clause entry for table "x"
+LINE 1: ...rallel_copy FROM stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+                                                                  ^
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a IN (SELECT 1 FROM x);
+ERROR:  cannot use subquery in COPY FROM WHERE condition
+LINE 1: ...arallel_copy FROM stdin WITH (PARALLEL 1) WHERE a IN (SELECT...
+                                                             ^
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a IN (generate_series(1,5));
+ERROR:  set-returning functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...lel_copy FROM stdin WITH (PARALLEL 1) WHERE a IN (generate_s...
+                                                             ^
+COPY test_parallel_copy FROM stdin WITH(PARALLEL 1) WHERE a = row_number() over(b);
+ERROR:  window functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...rallel_copy FROM stdin WITH(PARALLEL 1) WHERE a = row_number...
+                                                             ^
+-- check results of copy in
+SELECT * FROM test_parallel_copy ORDER BY 1;
+   a   | b  |     c      |    d    |    e    
+-------+----+------------+---------+---------
+     1 | 11 | test_c1    | test_d1 | test_e1
+     2 | 12 | test_c2    | test_d2 | test_e2
+  3000 |    | c          |         | 
+  4000 |    | C          |         | 
+  4001 |  1 | empty      |         | 
+  4002 |  2 | null       |         | 
+  4003 |  3 | Backslash  | \       | \
+  4004 |  4 | BackslashX | \X      | \X
+  4005 |  5 | N          | N       | N
+  4006 |  6 | BackslashN | \N      | \N
+  4007 |  7 | XX         | XX      | XX
+  4008 |  8 | Delimiter  | :       | :
+ 50004 | 25 | 35         | 45      | 55
+ 60004 | 25 | 35         | 45      | 55
+ 60005 | 26 | 36         | 46      | 56
+       |  3 | stuff      | test_d3 | 
+       |  4 | stuff      | test_d4 | 
+       |  5 | stuff      | test_d5 | 
+       |    | ,          | \,      | \
+       |    | x          | \x      | \x
+       |    | 45         | 80      | 90
+(21 rows)
+
+-- parallel copy test for unlogged tables. should execute in parallel worker
+CREATE UNLOGGED TABLE test_parallel_copy_unlogged(
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+);
+COPY test_parallel_copy_unlogged FROM stdin WITH (PARALLEL 1);
+SELECT count(*) FROM test_parallel_copy_unlogged;
+ count 
+-------
+     2
+(1 row)
+
+-- parallel copy test for various trigger types
+TRUNCATE test_parallel_copy;
+-- parallel safe trigger function
+CREATE OR REPLACE FUNCTION parallel_copy_trig_func() RETURNS TRIGGER
+LANGUAGE plpgsql PARALLEL SAFE AS $$
+BEGIN
+  RETURN NEW;
+END;
+$$;
+-- before insert row trigger
+CREATE TRIGGER parallel_copy_trig
+BEFORE INSERT ON test_parallel_copy
+FOR EACH ROW
+EXECUTE PROCEDURE parallel_copy_trig_func();
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+-- after insert row trigger
+CREATE TRIGGER parallel_copy_trig
+AFTER INSERT ON test_parallel_copy
+FOR EACH ROW
+EXECUTE PROCEDURE parallel_copy_trig_func();
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+-- before insert statement trigger
+CREATE TRIGGER parallel_copy_trig
+BEFORE INSERT ON test_parallel_copy
+FOR EACH STATEMENT
+EXECUTE PROCEDURE parallel_copy_trig_func();
+-- parallelism should be picked, since the trigger function is parallel safe
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+-- after insert statement trigger
+CREATE TRIGGER parallel_copy_trig
+AFTER INSERT ON test_parallel_copy
+FOR EACH STATEMENT
+EXECUTE PROCEDURE parallel_copy_trig_func();
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+-- transition table is involved
+CREATE TRIGGER parallel_copy_trig
+AFTER INSERT ON test_parallel_copy REFERENCING NEW TABLE AS new_table
+FOR EACH STATEMENT
+EXECUTE PROCEDURE parallel_copy_trig_func();
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+-- make trigger function parallel unsafe
+ALTER FUNCTION parallel_copy_trig_func PARALLEL UNSAFE;
+-- before statement trigger has a parallel unsafe function
+CREATE TRIGGER parallel_copy_trig
+BEFORE INSERT ON test_parallel_copy
+FOR EACH STATEMENT
+EXECUTE PROCEDURE parallel_copy_trig_func();
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+SELECT count(*) FROM test_parallel_copy;
+ count 
+-------
+    12
+(1 row)
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+-- instead of insert trigger, no parallelism should be picked
+COPY instead_of_insert_tbl_view FROM stdin WITH(PARALLEL 1);;
+SELECT count(*) FROM instead_of_insert_tbl_view;
+ count 
+-------
+     1
+(1 row)
+
+-- parallel copy test for a partitioned table with a before insert trigger on
+-- one of the partition
+ALTER FUNCTION parallel_copy_trig_func PARALLEL SAFE;
+CREATE TABLE test_parallel_copy_part (
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+) PARTITION BY LIST (b);
+CREATE TABLE test_parallel_copy_part_a1 (c TEXT, b INT, a INT, e TEXT, d TEXT);
+CREATE TABLE test_parallel_copy_part_a2 (a INT, c TEXT, b INT, d TEXT, e TEXT);
+ALTER TABLE test_parallel_copy_part ATTACH PARTITION test_parallel_copy_part_a1 FOR VALUES IN(1);
+ALTER TABLE test_parallel_copy_part ATTACH PARTITION test_parallel_copy_part_a2 FOR VALUES IN(2);
+CREATE TRIGGER parallel_copy_trig
+BEFORE INSERT ON test_parallel_copy_part_a2
+FOR EACH ROW
+EXECUTE PROCEDURE parallel_copy_trig_func();
+COPY test_parallel_copy_part FROM stdin WITH (PARALLEL 1);
+ERROR:  cannot perform PARALLEL COPY if partition has BEFORE/INSTEAD OF triggers, or if the partition is foreign partition
+HINT:  Try COPY without PARALLEL option
+CONTEXT:  COPY test_parallel_copy_part, line 2: "2	2	test_c2	test_d2	test_e2"
+parallel worker
+SELECT count(*) FROM test_parallel_copy_part;
+ count 
+-------
+     0
+(1 row)
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy_part_a2;
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE test_parallel_copy_unlogged;
+DROP TABLE test_parallel_copy_part;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
+DROP FUNCTION parallel_copy_trig_func();
 DROP TABLE x, y;
 DROP TABLE rls_t1 CASCADE;
 DROP ROLE regress_rls_copy_user;
diff --git a/src/test/regress/input/copy.source b/src/test/regress/input/copy.source
index a1d529a..cb39c66 100644
--- a/src/test/regress/input/copy.source
+++ b/src/test/regress/input/copy.source
@@ -15,6 +15,13 @@ DELETE FROM onek;
 
 COPY onek FROM '@abs_builddir@/results/onek.data';
 
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+
+SELECT COUNT(*) FROM tenk1;
+
+TRUNCATE tenk1;
+
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
@@ -159,6 +166,30 @@ truncate parted_copytest;
 
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
 
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
+
+-- Test parallel copy from for toast table with csv and binary format file
+create table test_parallel_copy_toast(a1 int, b1 text, c1 text default null);
+
+insert into test_parallel_copy_toast select i, (repeat(md5(i::text), 100000)) FROM generate_series(1,2) AS i;
+
+copy test_parallel_copy_toast to '@abs_builddir@/results/parallelcopytoast.csv' with(format csv);
+
+copy test_parallel_copy_toast to '@abs_builddir@/results/parallelcopytoast.dat' with(format binary);
+
+truncate test_parallel_copy_toast;
+
+copy test_parallel_copy_toast from '@abs_builddir@/results/parallelcopytoast.csv' with(format csv, parallel 2);
+
+copy test_parallel_copy_toast from '@abs_builddir@/results/parallelcopytoast.dat' with(format binary, parallel 2);
+
+select count(*) from test_parallel_copy_toast;
+
+drop table test_parallel_copy_toast;
+
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/output/copy.source b/src/test/regress/output/copy.source
index 938d355..a5dca79 100644
--- a/src/test/regress/output/copy.source
+++ b/src/test/regress/output/copy.source
@@ -9,6 +9,15 @@ COPY onek FROM '@abs_srcdir@/data/onek.data';
 COPY onek TO '@abs_builddir@/results/onek.data';
 DELETE FROM onek;
 COPY onek FROM '@abs_builddir@/results/onek.data';
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+SELECT COUNT(*) FROM tenk1;
+ count 
+-------
+ 10000
+(1 row)
+
+TRUNCATE tenk1;
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
 COPY person FROM '@abs_srcdir@/data/person.data';
@@ -113,6 +122,24 @@ insert into parted_copytest select x,1,'One' from generate_series(1011,1020) x;
 copy (select * from parted_copytest order by a) to '@abs_builddir@/results/parted_copytest.csv';
 truncate parted_copytest;
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
+-- Test parallel copy from for toast table with csv and binary format file
+create table test_parallel_copy_toast(a1 int, b1 text, c1 text default null);
+insert into test_parallel_copy_toast select i, (repeat(md5(i::text), 100000)) FROM generate_series(1,2) AS i;
+copy test_parallel_copy_toast to '@abs_builddir@/results/parallelcopytoast.csv' with(format csv);
+copy test_parallel_copy_toast to '@abs_builddir@/results/parallelcopytoast.dat' with(format binary);
+truncate test_parallel_copy_toast;
+copy test_parallel_copy_toast from '@abs_builddir@/results/parallelcopytoast.csv' with(format csv, parallel 2);
+copy test_parallel_copy_toast from '@abs_builddir@/results/parallelcopytoast.dat' with(format binary, parallel 2);
+select count(*) from test_parallel_copy_toast;
+ count 
+-------
+     4
+(1 row)
+
+drop table test_parallel_copy_toast;
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/sql/copy2.sql b/src/test/regress/sql/copy2.sql
index b3c16af..f5c6bec 100644
--- a/src/test/regress/sql/copy2.sql
+++ b/src/test/regress/sql/copy2.sql
@@ -171,7 +171,7 @@ COPY y TO stdout (FORMAT CSV, FORCE_QUOTE *);
 
 --test that we read consecutive LFs properly
 
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 
 COPY testnl FROM stdin CSV;
 1,"a field with two LFs
@@ -179,8 +179,16 @@ COPY testnl FROM stdin CSV;
 inside",2
 \.
 
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+1,"a field with two LFs
+
+inside",2
+\.
+
+SELECT * FROM testnl;
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 
 COPY testeoc FROM stdin CSV;
 a\.
@@ -189,11 +197,19 @@ c\.d
 "\."
 \.
 
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+a\.
+\.b
+c\.d
+"\."
+\.
+
 COPY testeoc TO stdout CSV;
 
 -- test handling of nonstandard null marker that violates escaping rules
 
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 
 COPY testnull TO stdout WITH NULL AS E'\\0';
@@ -205,6 +221,14 @@ COPY testnull FROM stdin WITH NULL AS E'\\0';
 
 SELECT * FROM testnull;
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 1);
+42	\\0
+\0	\0
+\.
+
+SELECT * FROM testnull;
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -249,6 +273,23 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+a2
+b
+\.
+SELECT * FROM vistest;
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+d2
+e
+\.
+SELECT * FROM vistest;
+COMMIT;
+SELECT * FROM vistest;
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 x
 y
@@ -298,7 +339,7 @@ SELECT * FROM vistest;
 COMMIT;
 SELECT * FROM vistest;
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -311,6 +352,10 @@ BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
 1,,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 1);
+1,,""
+\.
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
@@ -318,6 +363,10 @@ BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
 2,'a',,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 1);
+2,'a',,""
+\.
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
 -- should fail with not-null constraint violation
@@ -353,6 +402,16 @@ copy check_con_tbl from stdin;
 0
 \.
 select * from check_con_tbl;
+\d+ check_con_tbl
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 1);
+1
+\N
+\.
+copy check_con_tbl from stdin with (parallel 1);
+0
+\.
+select * from check_con_tbl;
 
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
@@ -454,10 +513,311 @@ test1
 SELECT * FROM instead_of_insert_tbl;
 COMMIT;
 
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+
+COPY test_parallel_copy (a, b, c, d, e) FROM stdin WITH (PARALLEL 1);
+1	11	test_c1	test_d1	test_e1
+2	12	test_c2	test_d2	test_e2
+\.
+
+COPY test_parallel_copy (b, d) FROM stdin WITH (PARALLEL 1);
+3	test_d3
+\.
+
+COPY test_parallel_copy (b, d) FROM stdin WITH (PARALLEL 1);
+4	test_d4
+5	test_d5
+\.
+
+COPY test_parallel_copy (b, d) FROM stdin WITH (PARALLEL 1, FORMAT 'csv', HEADER);
+b	d
+\.
+
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) FROM stdin WITH (PARALLEL 0);
+
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri FROM stdin WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+10
+\.
+
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1) WHERE height > random() * 65;
+60,60,60
+\.
+
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+60
+\.
+
+-- temporary table copy: should perform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+
+COPY temp_test (a) FROM stdin WITH (PARALLEL 1);
+10
+\.
+
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) FROM stdin WITH (PARALLEL 1);
+
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) FROM stdin WITH (PARALLEL 1);
+
+-- missing data: should fail
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+
+\.
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+2000	230	23	23
+\.
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+2001	231	\N	\N
+\.
+
+-- extra data: should fail
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+2002	232	40	50	60	70	80
+\.
+
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) FROM stdin WITH (DELIMITER ',', null 'x', PARALLEL 1) ;
+x,45,80,90
+x,\x,\\x,\\\x
+x,\,,\\\,,\\
+\.
+
+COPY test_parallel_copy FROM stdin WITH (DELIMITER ';', NULL '', PARALLEL 1);
+3000;;c;;
+\.
+
+COPY test_parallel_copy FROM stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL 1);
+4000:\X:C:\X:\X
+4001:1:empty::
+4002:2:null:\X:\X
+4003:3:Backslash:\\:\\
+4004:4:BackslashX:\\X:\\X
+4005:5:N:\N:\N
+4006:6:BackslashN:\\N:\\N
+4007:7:XX:\XX:\XX
+4008:8:Delimiter:\::\:
+\.
+
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a = 50004;
+50003	24	34	44	54
+50004	25	35	45 	55
+50005	26	36	46	56
+\.
+
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a > 60003;
+60001	22	32	42	52
+60002	23	33	43	53
+60003	24	34	44	54
+60004	25	35	45	55
+60005	26	36	46	56
+\.
+
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE f > 60003;
+
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a IN (SELECT 1 FROM x);
+
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a IN (generate_series(1,5));
+
+COPY test_parallel_copy FROM stdin WITH(PARALLEL 1) WHERE a = row_number() over(b);
+
+-- check results of copy in
+SELECT * FROM test_parallel_copy ORDER BY 1;
+
+-- parallel copy test for unlogged tables. should execute in parallel worker
+CREATE UNLOGGED TABLE test_parallel_copy_unlogged(
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+);
+
+COPY test_parallel_copy_unlogged FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+SELECT count(*) FROM test_parallel_copy_unlogged;
+
+-- parallel copy test for various trigger types
+TRUNCATE test_parallel_copy;
+
+-- parallel safe trigger function
+CREATE OR REPLACE FUNCTION parallel_copy_trig_func() RETURNS TRIGGER
+LANGUAGE plpgsql PARALLEL SAFE AS $$
+BEGIN
+  RETURN NEW;
+END;
+$$;
+
+-- before insert row trigger
+CREATE TRIGGER parallel_copy_trig
+BEFORE INSERT ON test_parallel_copy
+FOR EACH ROW
+EXECUTE PROCEDURE parallel_copy_trig_func();
+
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+
+-- after insert row trigger
+CREATE TRIGGER parallel_copy_trig
+AFTER INSERT ON test_parallel_copy
+FOR EACH ROW
+EXECUTE PROCEDURE parallel_copy_trig_func();
+
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+
+-- before insert statement trigger
+CREATE TRIGGER parallel_copy_trig
+BEFORE INSERT ON test_parallel_copy
+FOR EACH STATEMENT
+EXECUTE PROCEDURE parallel_copy_trig_func();
+
+-- parallelism should be picked, since the trigger function is parallel safe
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+
+-- after insert statement trigger
+CREATE TRIGGER parallel_copy_trig
+AFTER INSERT ON test_parallel_copy
+FOR EACH STATEMENT
+EXECUTE PROCEDURE parallel_copy_trig_func();
+
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+
+-- transition table is involved
+CREATE TRIGGER parallel_copy_trig
+AFTER INSERT ON test_parallel_copy REFERENCING NEW TABLE AS new_table
+FOR EACH STATEMENT
+EXECUTE PROCEDURE parallel_copy_trig_func();
+
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+
+-- make trigger function parallel unsafe
+ALTER FUNCTION parallel_copy_trig_func PARALLEL UNSAFE;
+
+-- before statement trigger has a parallel unsafe function
+CREATE TRIGGER parallel_copy_trig
+BEFORE INSERT ON test_parallel_copy
+FOR EACH STATEMENT
+EXECUTE PROCEDURE parallel_copy_trig_func();
+
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+SELECT count(*) FROM test_parallel_copy;
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+
+-- instead of insert trigger, no parallelism should be picked
+COPY instead_of_insert_tbl_view FROM stdin WITH(PARALLEL 1);;
+test1
+\.
+
+SELECT count(*) FROM instead_of_insert_tbl_view;
+
+-- parallel copy test for a partitioned table with a before insert trigger on
+-- one of the partition
+ALTER FUNCTION parallel_copy_trig_func PARALLEL SAFE;
+
+CREATE TABLE test_parallel_copy_part (
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+) PARTITION BY LIST (b);
+
+CREATE TABLE test_parallel_copy_part_a1 (c TEXT, b INT, a INT, e TEXT, d TEXT);
+
+CREATE TABLE test_parallel_copy_part_a2 (a INT, c TEXT, b INT, d TEXT, e TEXT);
+
+ALTER TABLE test_parallel_copy_part ATTACH PARTITION test_parallel_copy_part_a1 FOR VALUES IN(1);
+
+ALTER TABLE test_parallel_copy_part ATTACH PARTITION test_parallel_copy_part_a2 FOR VALUES IN(2);
+
+CREATE TRIGGER parallel_copy_trig
+BEFORE INSERT ON test_parallel_copy_part_a2
+FOR EACH ROW
+EXECUTE PROCEDURE parallel_copy_trig_func();
+
+COPY test_parallel_copy_part FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+SELECT count(*) FROM test_parallel_copy_part;
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy_part_a2;
+
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE test_parallel_copy_unlogged;
+DROP TABLE test_parallel_copy_part;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
+DROP FUNCTION parallel_copy_trig_func();
 DROP TABLE x, y;
 DROP TABLE rls_t1 CASCADE;
 DROP ROLE regress_rls_copy_user;
-- 
1.8.3.1

v9-0005-Parallel-Copy-For-Binary-Format-Files.patchtext/x-patch; charset=US-ASCII; name=v9-0005-Parallel-Copy-For-Binary-Format-Files.patchDownload
From 4746c76fa7c1f5dbbebad4737e380db4637260aa Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Tue, 27 Oct 2020 12:32:51 +0530
Subject: [PATCH v9 5/5] Parallel Copy For Binary Format Files

Leader reads data from the file into the DSM data blocks each of 64K size.
It also identifies each tuple data block id, start offset, end offset,
tuple size and updates this information in the ring data structure.
Workers parallelly read the tuple information from the ring data structure,
the actual tuple data from the data blocks and parallelly insert the tuples
into the table.
---
 src/backend/commands/copy.c          | 124 ++++++------
 src/backend/commands/copyparallel.c  | 363 +++++++++++++++++++++++++++++++++--
 src/include/commands/copy.h          |   8 +
 src/include/commands/copy_internal.h | 117 +++++++++++
 4 files changed, 526 insertions(+), 86 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index f485505..74e8704 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -223,14 +223,11 @@ static void CopySendData(CopyState cstate, const void *databuf, int datasize);
 static void CopySendString(CopyState cstate, const char *str);
 static void CopySendChar(CopyState cstate, char c);
 static void CopySendEndOfRow(CopyState cstate);
-static int	CopyGetData(CopyState cstate, void *databuf,
-						int minread, int maxread);
 static void CopySendInt32(CopyState cstate, int32 val);
 static bool CopyGetInt32(CopyState cstate, int32 *val);
 static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 static bool CopyLoadRawBuf(CopyState cstate);
-static int	CopyReadBinaryData(CopyState cstate, char *dest, int nbytes);
 static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
 								   int copy_line_pos, int *copy_line_size);
 
@@ -447,7 +444,7 @@ CopySendEndOfRow(CopyState cstate)
  *
  * NB: no data conversion is applied here.
  */
-static int
+int
 CopyGetData(CopyState cstate, void *databuf, int minread, int maxread)
 {
 	int			bytesread = 0;
@@ -580,10 +577,25 @@ CopyGetInt32(CopyState cstate, int32 *val)
 {
 	uint32		buf;
 
-	if (CopyReadBinaryData(cstate, (char *) &buf, sizeof(buf)) != sizeof(buf))
+	/*
+	 * For parallel copy, avoid reading data to raw buf, read directly from
+	 * file, later the data will be read to parallel copy data buffers.
+	 */
+	if (cstate->nworkers > 0)
 	{
-		*val = 0;				/* suppress compiler warning */
-		return false;
+		if (CopyGetData(cstate, &buf, sizeof(buf), sizeof(buf)) != sizeof(buf))
+		{
+			*val = 0;			/* suppress compiler warning */
+			return false;
+		}
+	}
+	else
+	{
+		if (CopyReadBinaryData(cstate, (char *) &buf, sizeof(buf)) != sizeof(buf))
+		{
+			*val = 0;			/* suppress compiler warning */
+			return false;
+		}
 	}
 	*val = (int32) pg_ntoh32(buf);
 	return true;
@@ -657,7 +669,7 @@ CopyLoadRawBuf(CopyState cstate)
  * and writes them to 'dest'.  Returns the number of bytes read (which
  * would be less than 'nbytes' only if we reach EOF).
  */
-static int
+int
 CopyReadBinaryData(CopyState cstate, char *dest, int nbytes)
 {
 	int			copied_bytes = 0;
@@ -3529,7 +3541,7 @@ BeginCopyFrom(ParseState *pstate,
 		int32		tmp;
 
 		/* Signature */
-		if (CopyReadBinaryData(cstate, readSig, 11) != 11 ||
+		if (CopyGetData(cstate, readSig, 11, 11) != 11 ||
 			memcmp(readSig, BinarySignature, 11) != 0)
 			ereport(ERROR,
 					(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
@@ -3557,7 +3569,7 @@ BeginCopyFrom(ParseState *pstate,
 		/* Skip extension header, if present */
 		while (tmp-- > 0)
 		{
-			if (CopyReadBinaryData(cstate, readSig, 1) != 1)
+			if (CopyGetData(cstate, readSig, 1, 1) != 1)
 				ereport(ERROR,
 						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
 						 errmsg("invalid COPY file header (wrong length)")));
@@ -3754,60 +3766,45 @@ NextCopyFrom(CopyState cstate, ExprContext *econtext,
 	else
 	{
 		/* binary */
-		int16		fld_count;
-		ListCell   *cur;
-
 		cstate->cur_lineno++;
+		cstate->max_fields = list_length(cstate->attnumlist);
 
-		if (!CopyGetInt16(cstate, &fld_count))
+		if (!IsParallelCopy())
 		{
-			/* EOF detected (end of file, or protocol-level EOF) */
-			return false;
-		}
+			int16		fld_count;
+			ListCell   *cur;
 
-		if (fld_count == -1)
-		{
-			/*
-			 * Received EOF marker.  In a V3-protocol copy, wait for the
-			 * protocol-level EOF, and complain if it doesn't come
-			 * immediately.  This ensures that we correctly handle CopyFail,
-			 * if client chooses to send that now.
-			 *
-			 * Note that we MUST NOT try to read more data in an old-protocol
-			 * copy, since there is no protocol-level EOF marker then.  We
-			 * could go either way for copy from file, but choose to throw
-			 * error if there's data after the EOF marker, for consistency
-			 * with the new-protocol case.
-			 */
-			char		dummy;
-
-			if (cstate->copy_dest != COPY_OLD_FE &&
-				CopyReadBinaryData(cstate, &dummy, 1) > 0)
-				ereport(ERROR,
-						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-						 errmsg("received copy data after EOF marker")));
-			return false;
-		}
+			if (!CopyGetInt16(cstate, &fld_count))
+			{
+				/* EOF detected (end of file, or protocol-level EOF) */
+				return false;
+			}
 
-		if (fld_count != attr_count)
-			ereport(ERROR,
-					(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-					 errmsg("row field count is %d, expected %d",
-							(int) fld_count, attr_count)));
+			CHECK_FIELD_COUNT;
 
-		foreach(cur, cstate->attnumlist)
+			foreach(cur, cstate->attnumlist)
+			{
+				int			attnum = lfirst_int(cur);
+				int			m = attnum - 1;
+				Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+
+				cstate->cur_attname = NameStr(att->attname);
+				values[m] = CopyReadBinaryAttribute(cstate,
+													&in_functions[m],
+													typioparams[m],
+													att->atttypmod,
+													&nulls[m]);
+				cstate->cur_attname = NULL;
+			}
+		}
+		else
 		{
-			int			attnum = lfirst_int(cur);
-			int			m = attnum - 1;
-			Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+			bool		eof = false;
 
-			cstate->cur_attname = NameStr(att->attname);
-			values[m] = CopyReadBinaryAttribute(cstate,
-												&in_functions[m],
-												typioparams[m],
-												att->atttypmod,
-												&nulls[m]);
-			cstate->cur_attname = NULL;
+			eof = CopyReadBinaryTupleWorker(cstate, values, nulls);
+
+			if (eof)
+				return false;
 		}
 	}
 
@@ -4818,18 +4815,15 @@ CopyReadBinaryAttribute(CopyState cstate, FmgrInfo *flinfo,
 	Datum		result;
 
 	if (!CopyGetInt32(cstate, &fld_size))
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("unexpected EOF in COPY data")));
+		EOF_ERROR;
+
 	if (fld_size == -1)
 	{
 		*isnull = true;
 		return ReceiveFunctionCall(flinfo, NULL, typioparam, typmod);
 	}
-	if (fld_size < 0)
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("invalid field size")));
+
+	CHECK_FIELD_SIZE(fld_size);
 
 	/* reset attribute_buf to empty, and load raw data in it */
 	resetStringInfo(&cstate->attribute_buf);
@@ -4837,9 +4831,7 @@ CopyReadBinaryAttribute(CopyState cstate, FmgrInfo *flinfo,
 	enlargeStringInfo(&cstate->attribute_buf, fld_size);
 	if (CopyReadBinaryData(cstate, cstate->attribute_buf.data,
 						   fld_size) != fld_size)
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("unexpected EOF in COPY data")));
+		EOF_ERROR;
 
 	cstate->attribute_buf.len = fld_size;
 	cstate->attribute_buf.data[fld_size] = '\0';
diff --git a/src/backend/commands/copyparallel.c b/src/backend/commands/copyparallel.c
index 0ddd4e5..5f13bd0 100644
--- a/src/backend/commands/copyparallel.c
+++ b/src/backend/commands/copyparallel.c
@@ -653,6 +653,7 @@ InitializeParallelCopyInfo(CopyState cstate, List *attnamelist)
 	cstate->cur_lineno = 0;
 	cstate->cur_attname = NULL;
 	cstate->cur_attval = NULL;
+	cstate->pcdata->curr_data_block = NULL;
 
 	/* Set up variables to avoid per-attribute overhead. */
 	initStringInfo(&cstate->attribute_buf);
@@ -1049,34 +1050,72 @@ ParallelCopyFrom(CopyState cstate)
 	/* Execute the before statement triggers from the leader */
 	ExecBeforeStmtTrigger(cstate);
 
-	/* On input just throw the header line away. */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (!cstate->binary)
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
+		/* On input just throw the header line away. */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
 		{
-			pcshared_info->is_read_in_progress = false;
-			return;			/* done */
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+			{
+				pcshared_info->is_read_in_progress = false;
+				return;			/* done */
+			}
 		}
-	}
 
-	for (;;)
-	{
-		bool		done;
-		CHECK_FOR_INTERRUPTS();
+		for (;;)
+		{
+			bool		done;
+			CHECK_FOR_INTERRUPTS();
 
-		cstate->cur_lineno++;
+			cstate->cur_lineno++;
 
-		/* Actually read the line into memory here. */
-		done = CopyReadLine(cstate);
+			/* Actually read the line into memory here. */
+			done = CopyReadLine(cstate);
 
+			/*
+			 * EOF at start of line means we're done.  If we see EOF after
+			 * some characters, we act as though it was newline followed by
+			 * EOF, ie, process the line and then exit loop on next iteration.
+			 */
+			if (done && cstate->line_buf.len == 0)
+				break;
+		}
+	}
+	else
+	{
 		/*
-			* EOF at start of line means we're done.  If we see EOF after
-			* some characters, we act as though it was newline followed by
-			* EOF, ie, process the line and then exit loop on next iteration.
-			*/
-		if (done && cstate->line_buf.len == 0)
-			break;
+		 * Binary Format Files. In parallel copy leader, fill in the error
+		 * context information here, in case any failures while determining
+		 * tuple offsets, leader would throw the errors with proper context.
+		 */
+		ErrorContextCallback errcallback;
+
+		errcallback.callback = CopyFromErrorCallback;
+		errcallback.arg = (void *) cstate;
+		errcallback.previous = error_context_stack;
+		error_context_stack = &errcallback;
+		cstate->pcdata->curr_data_block = NULL;
+		cstate->raw_buf_index = 0;
+		pcshared_info->populated = 0;
+		cstate->cur_lineno = 0;
+		cstate->max_fields = list_length(cstate->attnumlist);
+
+		for (;;)
+		{
+			bool		eof = false;
+			CHECK_FOR_INTERRUPTS();
+
+			cstate->cur_lineno++;
+
+			eof = CopyReadBinaryTupleLeader(cstate);
+
+			if (eof)
+				break;
+		}
+
+		/* Reset the error context. */
+		error_context_stack = errcallback.previous;
 	}
 
 	/*
@@ -1089,6 +1128,290 @@ ParallelCopyFrom(CopyState cstate)
 	pcshared_info->is_read_in_progress = false;
 	cstate->cur_lineno = 0;
 }
+
+/*
+ * CopyReadBinaryGetDataBlock
+ *
+ * Gets a new block, updates the current offset, calculates the skip bytes.
+ */
+void
+CopyReadBinaryGetDataBlock(CopyState cstate, FieldInfoType field_info)
+{
+	ParallelCopyDataBlock *data_block = NULL;
+	ParallelCopyDataBlock *curr_data_block = cstate->pcdata->curr_data_block;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	uint8		move_bytes = 0;
+	uint32		block_pos;
+	uint32		prev_block_pos;
+	int			read_bytes = 0;
+
+	prev_block_pos = pcshared_info->cur_block_pos;
+
+	block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+	if (field_info == FIELD_SIZE || field_info == FIELD_COUNT)
+		move_bytes = (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+
+	if (curr_data_block != NULL)
+		curr_data_block->skip_bytes = move_bytes;
+
+	data_block = &pcshared_info->data_blocks[block_pos];
+
+	if (move_bytes > 0 && curr_data_block != NULL)
+		memmove(&data_block->data[0], &curr_data_block->data[cstate->raw_buf_index], move_bytes);
+
+	elog(DEBUG1, "LEADER - field info %d is spread across data blocks - moved %d bytes from current block %u to %u block",
+		 field_info, move_bytes, prev_block_pos, block_pos);
+
+	read_bytes = CopyGetData(cstate, &data_block->data[move_bytes], 1, (DATA_BLOCK_SIZE - move_bytes));
+
+	if (field_info == FIELD_NONE && cstate->reached_eof)
+		return;
+
+	if (cstate->reached_eof)
+		EOF_ERROR;
+
+	elog(DEBUG1, "LEADER - bytes read from file %d", read_bytes);
+
+	if (field_info == FIELD_SIZE || field_info == FIELD_DATA)
+	{
+		ParallelCopyDataBlock *prev_data_block = NULL;
+
+		prev_data_block = curr_data_block;
+		prev_data_block->following_block = block_pos;
+
+		if (prev_data_block->curr_blk_completed == false)
+			prev_data_block->curr_blk_completed = true;
+
+		pg_atomic_add_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+	}
+
+	cstate->pcdata->curr_data_block = data_block;
+	cstate->raw_buf_index = 0;
+}
+
+/*
+ * CopyReadBinaryTupleLeader
+ *
+ * Leader reads data from binary formatted file to data blocks and identifies
+ * tuple boundaries/offsets so that workers can work on the data blocks data.
+ */
+bool
+CopyReadBinaryTupleLeader(CopyState cstate)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	int16		fld_count;
+	uint32		line_size = 0;
+	uint32		start_block_pos;
+	uint32		start_offset;
+
+	if (cstate->pcdata->curr_data_block == NULL)
+	{
+		CopyReadBinaryGetDataBlock(cstate, FIELD_NONE);
+
+		/*
+		 * no data is read from file here. one possibility to be here could be
+		 * that the binary file just has a valid signature but nothing else.
+		 */
+		if (cstate->reached_eof)
+			return true;
+	}
+
+	if ((cstate->raw_buf_index + sizeof(fld_count)) >= DATA_BLOCK_SIZE)
+		CopyReadBinaryGetDataBlock(cstate, FIELD_COUNT);
+
+	memcpy(&fld_count, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_count));
+	fld_count = (int16) pg_ntoh16(fld_count);
+
+	CHECK_FIELD_COUNT;
+
+	start_offset = cstate->raw_buf_index;
+	cstate->raw_buf_index += sizeof(fld_count);
+	line_size += sizeof(fld_count);
+	start_block_pos = pcshared_info->cur_block_pos;
+
+	CopyReadBinaryFindTupleSize(cstate, &line_size);
+
+	pg_atomic_add_fetch_u32(&cstate->pcdata->curr_data_block->unprocessed_line_parts, 1);
+
+	if (line_size > 0)
+		(void) UpdateSharedLineInfo(cstate, start_block_pos, start_offset,
+									line_size, LINE_LEADER_POPULATED, -1);
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryFindTupleSize
+ *
+ * Leader identifies boundaries/offsets for each attribute/column and finally
+ * results in the tuple/row size. It moves on to next data block if the
+ * attribute/column is spread across data blocks.
+ */
+void
+CopyReadBinaryFindTupleSize(CopyState cstate, uint32 *line_size)
+{
+	int32		fld_size;
+	ListCell   *cur;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			att_num = lfirst_int(cur);
+		Form_pg_attribute att = TupleDescAttr(tup_desc, (att_num - 1));
+
+		cstate->cur_attname = NameStr(att->attname);
+		fld_size = 0;
+
+		if ((cstate->raw_buf_index + sizeof(fld_size)) >= DATA_BLOCK_SIZE)
+			CopyReadBinaryGetDataBlock(cstate, FIELD_SIZE);
+
+		memcpy(&fld_size, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_size));
+		cstate->raw_buf_index += sizeof(fld_size);
+		*line_size += sizeof(fld_size);
+		fld_size = (int32) pg_ntoh32(fld_size);
+
+		/* fld_size -1 represents the null value for the field. */
+		if (fld_size == -1)
+			continue;
+
+		CHECK_FIELD_SIZE(fld_size);
+
+		*line_size += fld_size;
+
+		if ((DATA_BLOCK_SIZE - cstate->raw_buf_index) >= fld_size)
+		{
+			cstate->raw_buf_index += fld_size;
+			elog(DEBUG1, "LEADER - tuple lies in he same data block");
+		}
+		else
+		{
+			int32		required_blks = 0;
+			int32		curr_blk_bytes = (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+			int			i = 0;
+
+			GET_REQUIRED_BLOCKS(required_blks, fld_size, curr_blk_bytes);
+
+			i = required_blks;
+
+			while (i > 0)
+			{
+				CopyReadBinaryGetDataBlock(cstate, FIELD_DATA);
+				i--;
+			}
+
+			GET_RAW_BUF_INDEX(cstate->raw_buf_index, fld_size, required_blks, curr_blk_bytes);
+
+			/*
+			 * raw_buf_index should never cross data block size, as the
+			 * required number of data blocks would have been obtained in the
+			 * above while loop.
+			 */
+			Assert(cstate->raw_buf_index <= DATA_BLOCK_SIZE);
+		}
+		cstate->cur_attname = NULL;
+	}
+}
+
+/*
+ * CopyReadBinaryTupleWorker
+ *
+ * Each worker reads data from data blocks caches the tuple data into local
+ * memory.
+ */
+bool
+CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls)
+{
+	int16		fld_count;
+	ListCell   *cur;
+	FmgrInfo   *in_functions = cstate->in_functions;
+	Oid		   *typioparams = cstate->typioparams;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+	bool 		done = false;
+
+	done = GetWorkerLine(cstate);
+	cstate->raw_buf_index = 0;
+
+	if (done && cstate->line_buf.len == 0)
+		return true;
+
+	memcpy(&fld_count, &cstate->line_buf.data[cstate->raw_buf_index], sizeof(fld_count));
+	fld_count = (int16) pg_ntoh16(fld_count);
+
+	CHECK_FIELD_COUNT;
+
+	cstate->raw_buf_index += sizeof(fld_count);
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			att_num = lfirst_int(cur);
+		int			m = att_num - 1;
+		Form_pg_attribute att = TupleDescAttr(tup_desc, m);
+
+		cstate->cur_attname = NameStr(att->attname);
+
+		values[m] = CopyReadBinaryAttributeWorker(cstate,
+												  &in_functions[m],
+												  typioparams[m],
+												  att->atttypmod,
+												  &nulls[m]);
+		cstate->cur_attname = NULL;
+	}
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryAttributeWorker
+ *
+ * Worker identifies and converts each attribute/column data from binary to
+ * the data type of attribute/column.
+ */
+Datum
+CopyReadBinaryAttributeWorker(CopyState cstate, FmgrInfo *flinfo,
+							  Oid typioparam, int32 typmod, bool *isnull)
+{
+	int32		fld_size;
+	Datum		result;
+
+	memcpy(&fld_size, &cstate->line_buf.data[cstate->raw_buf_index], sizeof(fld_size));
+	cstate->raw_buf_index += sizeof(fld_size);
+	fld_size = (int32) pg_ntoh32(fld_size);
+
+	/* fld_size -1 represents the null value for the field. */
+	if (fld_size == -1)
+	{
+		*isnull = true;
+		return ReceiveFunctionCall(flinfo, NULL, typioparam, typmod);
+	}
+
+	CHECK_FIELD_SIZE(fld_size);
+
+	/* Reset attribute_buf to empty, and load raw data in it */
+	resetStringInfo(&cstate->attribute_buf);
+
+	enlargeStringInfo(&cstate->attribute_buf, fld_size);
+
+	memcpy(&cstate->attribute_buf.data[0], &cstate->line_buf.data[cstate->raw_buf_index], fld_size);
+	cstate->raw_buf_index += fld_size;
+
+	cstate->attribute_buf.len = fld_size;
+	cstate->attribute_buf.data[fld_size] = '\0';
+
+	/* Call the column type's binary input converter */
+	result = ReceiveFunctionCall(flinfo, &cstate->attribute_buf,
+								 typioparam, typmod);
+
+	/* Trouble if it didn't eat the whole buffer */
+	if (cstate->attribute_buf.cursor != cstate->attribute_buf.len)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+				 errmsg("incorrect binary data format")));
+
+	*isnull = false;
+	return result;
+}
+
 /*
  * GetLinePosition
  *
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index 2c2b9da..9b88ca2 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -61,4 +61,12 @@ extern uint32 UpdateSharedLineInfo(CopyState cstate, uint32 blk_pos, uint32 offs
 								   uint32 line_size, uint32 line_state, uint32 blk_line_pos);
 extern void EndLineParallelCopy(CopyState cstate, uint32 line_pos, uint32 line_size,
 								uint32 raw_buf_ptr);
+extern int	CopyGetData(CopyState cstate, void *databuf, int minread, int maxread);
+extern int	CopyReadBinaryData(CopyState cstate, char *dest, int nbytes);
+extern bool CopyReadBinaryTupleLeader(CopyState cstate);
+extern bool CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls);
+extern void CopyReadBinaryFindTupleSize(CopyState cstate, uint32 *line_size);
+extern Datum CopyReadBinaryAttributeWorker(CopyState cstate, FmgrInfo *flinfo,
+										   Oid typioparam, int32 typmod, bool *isnull);
+extern void CopyReadBinaryGetDataBlock(CopyState cstate, FieldInfoType field_info);
 #endif							/* COPY_H */
diff --git a/src/include/commands/copy_internal.h b/src/include/commands/copy_internal.h
index 73bb5a7..954c27c 100644
--- a/src/include/commands/copy_internal.h
+++ b/src/include/commands/copy_internal.h
@@ -56,6 +56,109 @@
 #define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
 
 /*
+ * CHECK_FIELD_COUNT - Handles the error cases for field count
+ * for binary format files.
+ */
+#define CHECK_FIELD_COUNT \
+{\
+	if (fld_count == -1) \
+	{ \
+		if (IsParallelCopy() && \
+			!IsLeader()) \
+			return true; \
+		else if (IsParallelCopy() && \
+			IsLeader()) \
+		{ \
+			if (cstate->pcdata->curr_data_block->data[cstate->raw_buf_index + sizeof(fld_count)] != 0) \
+				ereport(ERROR, \
+						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+						errmsg("received copy data after EOF marker"))); \
+			return true; \
+		} \
+		else \
+		{ \
+			/* \
+			 * Received EOF marker.  In a V3-protocol copy, wait for the \
+			 * protocol-level EOF, and complain if it doesn't come \
+			 * immediately.  This ensures that we correctly handle CopyFail, \
+			 * if client chooses to send that now. \
+			 * \
+			 * Note that we MUST NOT try to read more data in an old-protocol \
+			 * copy, since there is no protocol-level EOF marker then.  We \
+			 * could go either way for copy from file, but choose to throw \
+			 * error if there's data after the EOF marker, for consistency \
+			 * with the new-protocol case. \
+			 */ \
+			char		dummy; \
+			if (cstate->copy_dest != COPY_OLD_FE && \
+				CopyReadBinaryData(cstate, &dummy, 1) > 0) \
+				ereport(ERROR, \
+						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+						errmsg("received copy data after EOF marker"))); \
+				return false; \
+		} \
+	} \
+	if (fld_count != cstate->max_fields) \
+		ereport(ERROR, \
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+				errmsg("row field count is %d, expected %d", \
+				(int) fld_count, cstate->max_fields))); \
+}
+
+/*
+ * CHECK_FIELD_SIZE - Handles the error case for field size
+ * for binary format files.
+ */
+#define CHECK_FIELD_SIZE(fld_size) \
+{ \
+	if (fld_size < -1) \
+		ereport(ERROR, \
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+				errmsg("invalid field size")));\
+}
+
+/*
+ * EOF_ERROR - Error statement for EOF for binary format
+ * files.
+ */
+#define EOF_ERROR \
+{ \
+	ereport(ERROR, \
+		(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+		errmsg("unexpected EOF in COPY data")));\
+}
+
+/*
+ * GET_RAW_BUF_INDEX - Calculates the raw buf index for the cases
+ * where the data spread is across multiple data blocks.
+ */
+#define GET_RAW_BUF_INDEX(raw_buf_index, fld_size, required_blks, curr_blk_bytes) \
+{ \
+	raw_buf_index = fld_size - (((required_blks - 1) * DATA_BLOCK_SIZE) + curr_blk_bytes); \
+}
+
+/*
+ * GET_REQUIRED_BLOCKS - Calculates the number of data
+ * blocks required for the cases where the data spread
+ * is across multiple data blocks.
+ */
+#define GET_REQUIRED_BLOCKS(required_blks, fld_size, curr_blk_bytes) \
+{ \
+	/* \
+	 * field size can spread across multiple data blocks, \
+	 * calculate the number of required data blocks and try to get \
+	 * those many data blocks. \
+	 */ \
+	required_blks = (int32)(fld_size - curr_blk_bytes)/(int32)DATA_BLOCK_SIZE; \
+	/* \
+	 * check if we need the data block for the field data \
+	 * bytes that are not modulus of data block size. \
+	 */ \
+	if ((fld_size - curr_blk_bytes)%DATA_BLOCK_SIZE != 0) \
+		required_blks++; \
+}
+
+/*
  * Represents the different source/dest cases we need to worry about at
  * the bottom level
  */
@@ -235,6 +338,17 @@ typedef struct ParallelCopyLineBuf
 } ParallelCopyLineBuf;
 
 /*
+ * Represents the usage mode for CopyReadBinaryGetDataBlock.
+ */
+typedef enum FieldInfoType
+{
+	FIELD_NONE = 0,
+	FIELD_COUNT,
+	FIELD_SIZE,
+	FIELD_DATA
+}			FieldInfoType;
+
+/*
  * This structure helps in storing the common List/Node from CopyStateData that
  * are required by the workers. This information will then be copied and stored
  * into the DSM for the worker to retrieve and copy it to CopyStateData.
@@ -273,6 +387,9 @@ typedef struct ParallelCopyData
 
 	/* Current position in worker_line_buf */
 	uint32		worker_line_buf_pos;
+
+	/* For binary formatted files */
+	ParallelCopyDataBlock *curr_data_block;
 } ParallelCopyData;
 
 typedef int (*copy_data_source_cb) (void *outbuf, int minread, int maxread);
-- 
1.8.3.1

#193vignesh C
vignesh21@gmail.com
In reply to: Amit Kapila (#187)
Re: Parallel copy

On Wed, Oct 21, 2020 at 3:50 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Wed, Oct 21, 2020 at 3:19 PM Bharath Rupireddy
<bharath.rupireddyforpostgres@gmail.com> wrote:

9. Instead of calling CopyStringToSharedMemory() for each string
variable, can't we just create a linked list of all the strings that
need to be copied into shm and call CopyStringToSharedMemory() only
once? We could avoid 5 function calls?

If we want to avoid different function calls then can't we just store
all these strings in a local structure and use it? That might improve
the other parts of code as well where we are using these as individual
parameters.

I have made one structure SerializedListToStrCState to store all the
variables. The rest of the common variables is directly copied from &
into cstate.

10. Similar to above comment: can we fill all the required
cstate->variables inside the function CopyNodeFromSharedMemory() and
call it only once? In each worker we could save overhead of 5 function
calls.

Yeah, that makes sense.

I feel keeping it this way makes the code more readable, and also this
is not in a performance intensive tight loop. I'm retaining the
change as is unless we feel this will make an impact.

This is addressed in v9 patch shared at [1]/messages/by-id/CALDaNm1cAONkFDN6K72DSiRpgqNGvwxQL7TjEiHZ58opnp9VoA@mail.gmail.com.
[1]: /messages/by-id/CALDaNm1cAONkFDN6K72DSiRpgqNGvwxQL7TjEiHZ58opnp9VoA@mail.gmail.com

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

#194vignesh C
vignesh21@gmail.com
In reply to: Bharath Rupireddy (#188)
Re: Parallel copy

On Wed, Oct 21, 2020 at 4:20 PM Bharath Rupireddy
<bharath.rupireddyforpostgres@gmail.com> wrote:

On Wed, Oct 21, 2020 at 3:18 PM Bharath Rupireddy
<bharath.rupireddyforpostgres@gmail.com> wrote:

17. Remove extra lines after #define IsHeaderLine()
(cstate->header_line && cstate->cur_lineno == 1) in copy.h

I missed one comment:

18. I think we need to treat the number of parallel workers as an
integer similar to the parallel option in vacuum.

postgres=# copy t1 from stdin with(parallel '1'); <<<<< - we
should not allow this.
Enter data to be copied followed by a newline.

postgres=# vacuum (parallel '1') t1;
ERROR: parallel requires an integer value

I have made the behavior the same as vacuum.
This is addressed in v9 patch shared at [1]/messages/by-id/CALDaNm1cAONkFDN6K72DSiRpgqNGvwxQL7TjEiHZ58opnp9VoA@mail.gmail.com.
[1]: /messages/by-id/CALDaNm1cAONkFDN6K72DSiRpgqNGvwxQL7TjEiHZ58opnp9VoA@mail.gmail.com

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

#195vignesh C
vignesh21@gmail.com
In reply to: Heikki Linnakangas (#189)
Re: Parallel copy

Thanks Heikki for reviewing and providing your comments. Please find
my thoughts below.

On Fri, Oct 23, 2020 at 2:01 PM Heikki Linnakangas <hlinnaka@iki.fi> wrote:

I had a brief look at at this patch. Important work! A couple of first
impressions:

1. The split between patches
0002-Framework-for-leader-worker-in-parallel-copy.patch and
0003-Allow-copy-from-command-to-process-data-from-file.patch is quite
artificial. All the stuff introduced in the first is unused until the
second patch is applied. The first patch introduces a forward
declaration for ParallelCopyData(), but the function only comes in the
second patch. The comments in the first patch talk about
LINE_LEADER_POPULATING and LINE_LEADER_POPULATED, but the enum only
comes in the second patch. I think these have to merged into one. If you
want to split it somehow, I'd suggest having a separate patch just to
move CopyStateData from copy.c to copy.h. The subsequent patch would
then be easier to read as you could see more easily what's being added
to CopyStateData. Actually I think it would be better to have a new
header file, copy_internal.h, to hold CopyStateData and the other
structs, and keep copy.h as it is.

I have merged 0002 & 0003 patch, I have moved few things like creation
of copy_internal.h, moving of CopyStateData from copy.c into
copy_internal.h into 0001 patch.

2. This desperately needs some kind of a high-level overview of how it
works. What is a leader, what is a worker? Which process does each step
of COPY processing, like reading from the file/socket, splitting the
input into lines, handling escapes, calling input functions, and
updating the heap and indexes? What data structures are used for the
communication? How does is the work synchronized between the processes?
There are comments on those individual aspects scattered in the patch,
but if you're not already familiar with it, you don't know where to
start. There's some of that in the commit message, but it needs to be
somewhere in the source code, maybe in a long comment at the top of
copyparallel.c.

Added it in copyparallel.c

3. I'm surprised there's a separate ParallelCopyLineBoundary struct for
every input line. Doesn't that incur a lot of synchronization overhead?
I haven't done any testing, this is just my gut feeling, but I assumed
you'd work in batches of, say, 100 or 1000 lines each.

Data read from the file will be stored in DSM which is of size 64k *
1024. Leader will parse and identify the line boundary like which line
starts from which data block, what is the starting offset in the data
block, what is the line size, this information will be present in
ParallelCopyLineBoundary. Like you said, each worker processes
WORKER_CHUNK_COUNT 64 lines at a time. Performance test results run
for parallel copy are available at [1]/messages/by-id/CALj2ACWeQVd-xoQZHGT01_33St4xPoZQibWz46o7jW1PE3XOqQ@mail.gmail.com. This is addressed in v9 patch
shared at [2]/messages/by-id/CALDaNm1cAONkFDN6K72DSiRpgqNGvwxQL7TjEiHZ58opnp9VoA@mail.gmail.com.

[1]: /messages/by-id/CALj2ACWeQVd-xoQZHGT01_33St4xPoZQibWz46o7jW1PE3XOqQ@mail.gmail.com
[2]: /messages/by-id/CALDaNm1cAONkFDN6K72DSiRpgqNGvwxQL7TjEiHZ58opnp9VoA@mail.gmail.com

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

#196vignesh C
vignesh21@gmail.com
In reply to: Ashutosh Sharma (#190)
Re: Parallel copy

Thanks Ashutosh for reviewing and providing your comments.

On Fri, Oct 23, 2020 at 5:43 PM Ashutosh Sharma <ashu.coek88@gmail.com> wrote:

Hi Vignesh,

Thanks for the updated patches. Here are some more comments that I can
find after reviewing your latest patches:

+/*
+ * This structure helps in storing the common data from CopyStateData that are
+ * required by the workers. This information will then be allocated and stored
+ * into the DSM for the worker to retrieve and copy it to CopyStateData.
+ */
+typedef struct SerializedParallelCopyState
+{
+   /* low-level state data */
+   CopyDest    copy_dest;      /* type of copy source/destination */
+   int         file_encoding;  /* file or remote side's character encoding */
+   bool        need_transcoding;   /* file encoding diff from server? */
+   bool        encoding_embeds_ascii;  /* ASCII can be non-first byte? */
+
...
...
+
+   /* Working state for COPY FROM */
+   AttrNumber  num_defaults;
+   Oid         relid;
+} SerializedParallelCopyState;

Can the above structure not be part of the CopyStateData structure? I
am just asking this question because all the fields present in the
above structure are also present in the CopyStateData structure. So,
including it in the CopyStateData structure will reduce the code
duplication and will also make CopyStateData a bit shorter.

I have removed the common members from the structure, now there are no
common members between CopyStateData & the new structure. I'm using
CopyStateData to copy to/from directly in the new patch.

--

+           pcxt = BeginParallelCopy(cstate->nworkers, cstate, stmt->attlist,
+                                    relid);

Do we need to pass cstate->nworkers and relid to BeginParallelCopy()
function when we are already passing cstate structure, using which
both of these information can be retrieved ?

nworkers need not be passed as you have suggested but relid need to be
passed as we will be setting it to pcdata, modified nworkers as
suggested.

--

+/* DSM keys for parallel copy.  */
+#define PARALLEL_COPY_KEY_SHARED_INFO              1
+#define PARALLEL_COPY_KEY_CSTATE                   2
+#define PARALLEL_COPY_WAL_USAGE                    3
+#define PARALLEL_COPY_BUFFER_USAGE                 4

DSM key names do not appear to be consistent. For shared info and
cstate structures, the key name is prefixed with "PARALLEL_COPY_KEY",
but for WalUsage and BufferUsage structures, it is prefixed with
"PARALLEL_COPY". I think it would be better to make them consistent.

Modified as suggested

--

if (resultRelInfo->ri_TrigDesc != NULL &&
(resultRelInfo->ri_TrigDesc->trig_insert_before_row ||
resultRelInfo->ri_TrigDesc->trig_insert_instead_row))
{
/*
* Can't support multi-inserts when there are any BEFORE/INSTEAD OF
* triggers on the table. Such triggers might query the table we're
* inserting into and act differently if the tuples that have already
* been processed and prepared for insertion are not there.
*/
insertMethod = CIM_SINGLE;
}
else if (proute != NULL && resultRelInfo->ri_TrigDesc != NULL &&
resultRelInfo->ri_TrigDesc->trig_insert_new_table)
{
/*
* For partitioned tables we can't support multi-inserts when there
* are any statement level insert triggers. It might be possible to
* allow partitioned tables with such triggers in the future, but for
* now, CopyMultiInsertInfoFlush expects that any before row insert
* and statement level insert triggers are on the same relation.
*/
insertMethod = CIM_SINGLE;
}
else if (resultRelInfo->ri_FdwRoutine != NULL ||
cstate->volatile_defexprs)
{
...
...

I think, if possible, all these if-else checks in CopyFrom() can be
moved to a single function which can probably be named as
IdentifyCopyInsertMethod() and this function can be called in
IsParallelCopyAllowed(). This will ensure that in case of Parallel
Copy when the leader has performed all these checks, the worker won't
do it again. I also feel that it will make the code look a bit
cleaner.

In the recent patch posted we have changed it to simplify the check
for parallel copy, it is not an exact match. I feel this comment is
not applicable on the latest patch

--

+void
+ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
+{
...
...
+   InstrEndParallelQuery(&bufferusage[ParallelWorkerNumber],
+                         &walusage[ParallelWorkerNumber]);
+
+   MemoryContextSwitchTo(oldcontext);
+   pfree(cstate);
+   return;
+}

It seems like you also need to delete the memory context
(cstate->copycontext) here.

Added it.

--

+void
+ExecBeforeStmtTrigger(CopyState cstate)
+{
+   EState     *estate = CreateExecutorState();
+   ResultRelInfo *resultRelInfo;

This function has a lot of comments which have been copied as it is
from the CopyFrom function, I think it would be good to remove those
comments from here and mention that this code changes done in this
function has been taken from the CopyFrom function. If any queries
people may refer to the CopyFrom function. This will again avoid the
unnecessary code in the patch.

Changed as suggested.

--

As Heikki rightly pointed out in his previous email, we need some high
level description of how Parallel Copy works somewhere in
copyparallel.c file. For reference, please see how a brief description
about parallel vacuum has been added in the vacuumlazy.c file.

* Lazy vacuum supports parallel execution with parallel worker processes. In
* a parallel vacuum, we perform both index vacuum and index cleanup with
* parallel worker processes. Individual indexes are processed by one vacuum
...

Added it in copyparallel.c

This is addressed in v9 patch shared at [1]/messages/by-id/CALDaNm1cAONkFDN6K72DSiRpgqNGvwxQL7TjEiHZ58opnp9VoA@mail.gmail.com.
[1]: /messages/by-id/CALDaNm1cAONkFDN6K72DSiRpgqNGvwxQL7TjEiHZ58opnp9VoA@mail.gmail.com

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

#197vignesh C
vignesh21@gmail.com
In reply to: Ashutosh Sharma (#191)
Re: Parallel copy

On Fri, Oct 23, 2020 at 6:58 PM Ashutosh Sharma <ashu.coek88@gmail.com> wrote:

I think, if possible, all these if-else checks in CopyFrom() can be
moved to a single function which can probably be named as
IdentifyCopyInsertMethod() and this function can be called in
IsParallelCopyAllowed(). This will ensure that in case of Parallel
Copy when the leader has performed all these checks, the worker won't
do it again. I also feel that it will make the code look a bit
cleaner.

Just rewriting above comment to make it a bit more clear:

I think, if possible, all these if-else checks in CopyFrom() should be
moved to a separate function which can probably be named as
IdentifyCopyInsertMethod() and this function called from
IsParallelCopyAllowed() and CopyFrom() functions. It will only be
called from CopyFrom() when IsParallelCopy() returns false. This will
ensure that in case of Parallel Copy if the leader has performed all
these checks, the worker won't do it again. I also feel that having a
separate function containing all these checks will make the code look
a bit cleaner.

In the recent patch posted we have changed it to simplify the check
for parallel copy, it is not an exact match. I feel this comment is
not applicable on the latest patch

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

#198Hou, Zhijie
houzj.fnst@cn.fujitsu.com
In reply to: vignesh C (#192)
RE: Parallel copy

Hi

I found some issue in v9-0002

1.
+
+	elog(DEBUG1, "[Worker] Processing - line position:%d, block:%d, unprocessed lines:%d, offset:%d, line size:%d",
+		 write_pos, lineInfo->first_block,
+		 pg_atomic_read_u32(&data_blk_ptr->unprocessed_line_parts),
+		 offset, pg_atomic_read_u32(&lineInfo->line_size));
+

write_pos or other variable to be printed here are type of uint32, I think it'better to use '%u' in elog msg.

2.
+		 * line_size will be set. Read the line_size again to be sure if it is
+		 * completed or partial block.
+		 */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+		if (dataSize)

It use dataSize( type int ) to get uint32 which seems a little dangerous.
Is it better to define dataSize uint32 here?

3.
Since function with 'Cstate' in name has been changed to 'CState'
I think we can change function PopulateCommonCstateInfo as well.

4.
+ if (pcdata->worker_line_buf_count)

I think some check like the above can be 'if (xxx > 0)', which seems easier to understand.

Best regards,
houzj

#199Amit Kapila
amit.kapila16@gmail.com
In reply to: vignesh C (#192)
Re: Parallel copy

On Tue, Oct 27, 2020 at 7:06 PM vignesh C <vignesh21@gmail.com> wrote:

[latest version]

I think the parallel-safety checks in this patch
(v9-0002-Allow-copy-from-command-to-process-data-from-file) are
incomplete and wrong. See below comments.
1.
+static pg_attribute_always_inline bool
+CheckExprParallelSafety(CopyState cstate)
+{
+ if (contain_volatile_functions(cstate->whereClause))
+ {
+ if (max_parallel_hazard((Query *) cstate->whereClause) != PROPARALLEL_SAFE)
+ return false;
+ }

I don't understand the above check. Why do we only need to check where
clause for parallel-safety when it contains volatile functions? It
should be checked otherwise as well, no? The similar comment applies
to other checks in this function. Also, I don't think there is a need
to make this function inline.

2.
+/*
+ * IsParallelCopyAllowed
+ *
+ * Check if parallel copy can be allowed.
+ */
+bool
+IsParallelCopyAllowed(CopyState cstate)
{
..
+ * When there are BEFORE/AFTER/INSTEAD OF row triggers on the table. We do
+ * not allow parallelism in such cases because such triggers might query
+ * the table we are inserting into and act differently if the tuples that
+ * have already been processed and prepared for insertion are not there.
+ * Now, if we allow parallelism with such triggers the behaviour would
+ * depend on if the parallel worker has already inserted or not that
+ * particular tuples.
+ */
+ if (cstate->rel->trigdesc != NULL &&
+ (cstate->rel->trigdesc->trig_insert_after_statement ||
+ cstate->rel->trigdesc->trig_insert_new_table ||
+ cstate->rel->trigdesc->trig_insert_before_row ||
+ cstate->rel->trigdesc->trig_insert_after_row ||
+ cstate->rel->trigdesc->trig_insert_instead_row))
+ return false;
..

Why do we need to disable parallelism for before/after row triggers
unless they have parallel-unsafe functions? I see a few lines down in
this function you are checking parallel-safety of trigger functions,
what is the use of the same if you are already disabling parallelism
with the above check.

3. What about if the index on table has expressions that are
parallel-unsafe? What is your strategy to check parallel-safety for
partitioned tables?

I suggest checking Greg's patch for parallel-safety of Inserts [1]/messages/by-id/CAJcOf-cgfjj0NfYPrNFGmQJxsnNW102LTXbzqxQJuziar1EKfQ@mail.gmail.com. I
think you will find that most of those checks are required here as
well and see how we can use that patch (at least what is common). I
feel the first patch should be just to have parallel-safety checks and
we can test that by trying to enable Copy with force_parallel_mode. We
can build the rest of the patch atop of it or in other words, let's
move all parallel-safety work into a separate patch.

Few assorted comments:
========================
1.
+/*
+ * ESTIMATE_NODE_SIZE - Estimate the size required for  node type in shared
+ * memory.
+ */
+#define ESTIMATE_NODE_SIZE(list, listStr, strsize) \
+{ \
+ uint32 estsize = sizeof(uint32); \
+ if ((List *)list != NIL) \
+ { \
+ listStr = nodeToString(list); \
+ estsize += strlen(listStr) + 1; \
+ } \
+ \
+ strsize = add_size(strsize, estsize); \
+}

This can be probably a function instead of a macro.

2.
+/*
+ * ESTIMATE_1BYTE_STR_SIZE - Estimate the size required for  1Byte strings in
+ * shared memory.
+ */
+#define ESTIMATE_1BYTE_STR_SIZE(src, strsize) \
+{ \
+ strsize = add_size(strsize, sizeof(uint8)); \
+ strsize = add_size(strsize, (src) ? 1 : 0); \
+}

This could be an inline function.

3.
+/*
+ * SERIALIZE_1BYTE_STR - Copy 1Byte strings to shared memory.
+ */
+#define SERIALIZE_1BYTE_STR(dest, src, copiedsize) \
+{ \
+ uint8 len = (src) ? 1 : 0; \
+ memcpy(dest + copiedsize, (uint8 *) &len, sizeof(uint8)); \
+ copiedsize += sizeof(uint8); \
+ if (src) \
+ dest[copiedsize++] = src[0]; \
+}

Similarly, this could be a function. I think keeping such things as
macros in-between code makes it difficult to read. Please see if you
can make these and similar macros as functions unless they are doing
few memory instructions. Having functions makes it easier to debug the
code as well.

[1]: /messages/by-id/CAJcOf-cgfjj0NfYPrNFGmQJxsnNW102LTXbzqxQJuziar1EKfQ@mail.gmail.com

--
With Regards,
Amit Kapila.

#200Heikki Linnakangas
hlinnaka@iki.fi
In reply to: vignesh C (#192)
Re: Parallel copy

On 27/10/2020 15:36, vignesh C wrote:

Attached v9 patches have the fixes for the above comments.

I did some testing:

/tmp/longdata.pl:
--------
#!/usr/bin/perl
#
# Generate three rows:
# foo
# longdatalongdatalongdata...
# bar
#
# The length of the middle row is given as command line arg.
#

my $bytes = $ARGV[0];

print "foo\n";
for(my $i = 0; $i < $bytes; $i+=8){
print "longdata";
}
print "\n";
print "bar\n";
--------

postgres=# copy longdata from program 'perl /tmp/longdata.pl 100000000'
with (parallel 2);

This gets stuck forever (or at least I didn't have the patience to wait
it finish). Both worker processes are consuming 100% of CPU.

- Heikki

#201Daniel Westermann (DWE)
daniel.westermann@dbi-services.com
In reply to: Heikki Linnakangas (#200)
Re: Parallel copy

On 27/10/2020 15:36, vignesh C wrote:

Attached v9 patches have the fixes for the above comments.

I did some testing:

I did some testing as well and have a cosmetic remark:

postgres=# copy t1 from '/var/tmp/aa.txt' with (parallel 1000000000);
ERROR: value 1000000000 out of bounds for option "parallel"
DETAIL: Valid values are between "1" and "1024".
postgres=# copy t1 from '/var/tmp/aa.txt' with (parallel 100000000000);
ERROR: parallel requires an integer value
postgres=#

Wouldn't it make more sense to only have one error message? The first one seems to be the better message.

Regards
Daniel

#202Amit Kapila
amit.kapila16@gmail.com
In reply to: Amit Kapila (#199)
Re: Parallel copy

On Thu, Oct 29, 2020 at 11:45 AM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Tue, Oct 27, 2020 at 7:06 PM vignesh C <vignesh21@gmail.com> wrote:

[latest version]

I think the parallel-safety checks in this patch
(v9-0002-Allow-copy-from-command-to-process-data-from-file) are
incomplete and wrong.

One more point, I have noticed that some time back [1]/messages/by-id/CAA4eK1L-Xgw1zZEbGePmhBBWmEmLFL6rCaiOMDPnq2GNMVz-sg@mail.gmail.com, I have given
one suggestion related to the way workers process the set of lines
(aka chunk). I think you can try by increasing the chunk size to say
100, 500, 1000 and use some shared counter to remember the number of
chunks processed.

[1]: /messages/by-id/CAA4eK1L-Xgw1zZEbGePmhBBWmEmLFL6rCaiOMDPnq2GNMVz-sg@mail.gmail.com

--
With Regards,
Amit Kapila.

#203Heikki Linnakangas
hlinnaka@iki.fi
In reply to: vignesh C (#192)
Re: Parallel copy

On 27/10/2020 15:36, vignesh C wrote:

Attached v9 patches have the fixes for the above comments.

I find this design to be very complicated. Why does the line-boundary
information need to be in shared memory? I think this would be much
simpler if each worker grabbed a fixed-size block of raw data, and
processed that.

In your patch, the leader process scans the input to find out where one
line ends and another begins, and because of that decision, the leader
needs to make the line boundaries available in shared memory, for the
worker processes. If we moved that responsibility to the worker
processes, you wouldn't need to keep the line boundaries in shared
memory. A worker would only need to pass enough state to the next worker
to tell it where to start scanning the next block.

Whether the leader process finds the EOLs or the worker processes, it's
pretty clear that it needs to be done ASAP, for a chunk at a time,
because that cannot be done in parallel. I think some refactoring in
CopyReadLine() and friends would be in order. It probably would be
faster, or at least not slower, to find all the EOLs in a block in one
tight loop, even when parallel copy is not used.

- Heikki

#204Heikki Linnakangas
hlinnaka@iki.fi
In reply to: Heikki Linnakangas (#203)
Re: Parallel copy

On 30/10/2020 18:36, Heikki Linnakangas wrote:

I find this design to be very complicated. Why does the line-boundary
information need to be in shared memory? I think this would be much
simpler if each worker grabbed a fixed-size block of raw data, and
processed that.

In your patch, the leader process scans the input to find out where one
line ends and another begins, and because of that decision, the leader
needs to make the line boundaries available in shared memory, for the
worker processes. If we moved that responsibility to the worker
processes, you wouldn't need to keep the line boundaries in shared
memory. A worker would only need to pass enough state to the next worker
to tell it where to start scanning the next block.

Here's a high-level sketch of how I'm imagining this to work:

The shared memory structure consists of a queue of blocks, arranged as a
ring buffer. Each block is of fixed size, and contains 64 kB of data,
and a few fields for coordination:

typedef struct
{
/* Current state of the block */
pg_atomic_uint32 state;

/* starting offset of first line within the block */
int startpos;

char data[64 kB];
} ParallelCopyDataBlock;

Where state is one of:

enum {
FREE, /* buffer is empty */
FILLED, /* leader has filled the buffer with raw data */
READY, /* start pos has been filled in, but no worker process
has claimed the block yet */
PROCESSING, /* worker has claimed the block, and is processing it */
}

State changes FREE -> FILLED -> READY -> PROCESSING -> FREE. As the COPY
progresses, the ring of blocks will always look something like this:

blk 0 startpos 0: PROCESSING [worker 1]
blk 1 startpos 12: PROCESSING [worker 2]
blk 2 startpos 10: READY
blk 3 starptos -: FILLED
blk 4 startpos -: FILLED
blk 5 starptos -: FILLED
blk 6 startpos -: FREE
blk 7 startpos -: FREE

Typically, each worker process is busy processing a block. After the
blocks being processed, there is one block in READY state, and after
that, blocks in FILLED state.

Leader process:

The leader process is simple. It picks the next FREE buffer, fills it
with raw data from the file, and marks it as FILLED. If no buffers are
FREE, wait.

Worker process:

1. Claim next READY block from queue, by changing its state to
PROCESSING. If the next block is not READY yet, wait until it is.

2. Start scanning the block from 'startpos', finding end-of-line
markers. (in CSV mode, need to track when we're in-quotes).

3. When you reach the end of the block, if the last line continues to
next block, wait for the next block to become FILLED. Peek into the
next block, and copy the remaining part of the split line to a local
buffer, and set the 'startpos' on the next block to point to the end
of the split line. Mark the next block as READY.

4. Process all the lines in the block, call input functions, insert
rows.

5. Mark the block as DONE.

In this design, you don't need to keep line boundaries in shared memory,
because each worker process is responsible for finding the line
boundaries of its own block.

There's a point of serialization here, in that the next block cannot be
processed, until the worker working on the previous block has finished
scanning the EOLs, and set the starting position on the next block,
putting it in READY state. That's not very different from your patch,
where you had a similar point of serialization because the leader
scanned the EOLs, but I think the coordination between processes is
simpler here.

- Heikki

#205Heikki Linnakangas
hlinnaka@iki.fi
In reply to: Heikki Linnakangas (#203)
1 attachment(s)
Re: Parallel copy

On 30/10/2020 18:36, Heikki Linnakangas wrote:

Whether the leader process finds the EOLs or the worker processes, it's
pretty clear that it needs to be done ASAP, for a chunk at a time,
because that cannot be done in parallel. I think some refactoring in
CopyReadLine() and friends would be in order. It probably would be
faster, or at least not slower, to find all the EOLs in a block in one
tight loop, even when parallel copy is not used.

Something like the attached. It passes the regression tests, but it's
quite incomplete. It's missing handing of "\." as end-of-file marker,
and I haven't tested encoding conversions at all, for starters. Quick
testing suggests that this a little bit faster than the current code,
but the difference is small; I had to use a "WHERE false" option to
really see the difference.

The crucial thing here is that there's a new function, ParseLinesText(),
to find all end-of-line characters in a buffer in one go. In this patch,
it's used against 'raw_buf', but with parallel copy, you could point it
at a block in shared memory instead.

- Heikki

Attachments:

0001-WIP-Find-all-line-endings-in-COPY-in-chunks.patchtext/x-patch; charset=UTF-8; name=0001-WIP-Find-all-line-endings-in-COPY-in-chunks.patchDownload
From af3be3bd4e77b66f4605393617da0d15ec21e15b Mon Sep 17 00:00:00 2001
From: Heikki Linnakangas <heikki.linnakangas@iki.fi>
Date: Fri, 30 Oct 2020 18:51:10 +0200
Subject: [PATCH 1/1] WIP: Find all line-endings in COPY in chunks.

Refactor CopyReadLines and friends to find all the line-endings in the
buffer in one go, before splitting the lines further.
---
 src/backend/commands/copy.c | 972 ++++++++++++++++++++----------------
 1 file changed, 536 insertions(+), 436 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 36ddcdccdb8..fbf11cb2550 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -95,6 +95,18 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
+
+/*
+ * Represents the heap insert method to be used during COPY FROM.
+ */
+typedef enum ParseLinesState
+{
+	PLSTATE_NORMAL,
+	PLSTATE_ESCAPE,
+	PLSTATE_IN_QUOTE,
+	PLSTATE_ESCAPE_IN_QUOTE
+} ParseLinesState;
+
 /*
  * This struct contains all the state variables used throughout a COPY
  * operation. For simplicity, we use the same struct for all variants of COPY,
@@ -110,6 +122,24 @@ typedef enum CopyInsertMethod
  * it's faster to make useless comparisons to trailing bytes than it is to
  * invoke pg_encoding_mblen() to skip over them. encoding_embeds_ascii is true
  * when we have to do it the hard way.
+ *
+ * COPY FROM buffers:
+ *
+ * In COPY FROM processing, there are three levels of buffers:
+ *
+ * raw_buf       - contains raw data read from file/client
+ * converted_buf - contains the data in 'raw_buf', but converted to server encoding
+ * line_buf      - contains "current" line of data, without the end-of-line char
+ *
+ *
+ * In simple cases, no encoding conversion are needed, and converted_buf always
+ * points to raw_buf. If the encoding_embeds_ascii==true, encoding conversion is
+ * performed on the raw buffer, before splitting it to lines. converted_buf contains
+ * the converted version in that case.
+ *
+ * Usually, line_buf pointer points in the middle of converted_buf, but when a line
+ * is split by a raw-buffer boundary, the incomplete line is reassembled
+ * in a separate buffer (split_line_buf), and line_buf points to that.
  */
 typedef struct CopyStateData
 {
@@ -205,16 +235,34 @@ typedef struct CopyStateData
 	char	  **raw_fields;
 
 	/*
-	 * Similarly, line_buf holds the whole input line being processed. The
+	 * These variables are used to track state of parsing raw data into
+	 * lines in COPY FROM.
+	 */
+	bool		last_was_cr;
+	ParseLinesState parse_lines_state;
+
+	int			last_line_no; /* last line in 'endlines', -1 if EOF not reached yet */
+
+	int			nextline;
+	int		   *endlines; /* line ending positions within raw_buf */
+	int			numlines;
+
+	/* split_line_buf holds partial line carried over from previous buf */
+	StringInfoData split_line_buf;
+
+	/*
+	 * Similarly, line_buf holds the current input line being processed. The
 	 * input cycle is first to read the whole line into line_buf, convert it
 	 * to server encoding there, and then extract the individual attribute
 	 * fields into attribute_buf.  line_buf is preserved unmodified so that we
 	 * can display it in error messages if appropriate.  (In binary mode,
 	 * line_buf is not used.)
 	 */
-	StringInfoData line_buf;
+	char	   *line_buf;
+	int			line_len;
 	bool		line_buf_converted; /* converted to server encoding? */
 	bool		line_buf_valid; /* contains the row being processed? */
+	bool		line_buf_alloced;
 
 	/*
 	 * Finally, raw_buf holds raw data read from the data source (file or
@@ -230,6 +278,9 @@ typedef struct CopyStateData
 	int			raw_buf_len;	/* total # of bytes stored */
 	/* Shorthand for number of unconsumed bytes available in raw_buf */
 #define RAW_BUF_BYTES(cstate) ((cstate)->raw_buf_len - (cstate)->raw_buf_index)
+
+	char	   *converted_buf;
+	int			converted_buf_len;
 } CopyStateData;
 
 /* DestReceiver for COPY (query) TO */
@@ -288,72 +339,6 @@ typedef struct CopyMultiInsertInfo
 	int			ti_options;		/* table insert options */
 } CopyMultiInsertInfo;
 
-
-/*
- * These macros centralize code used to process line_buf and raw_buf buffers.
- * They are macros because they often do continue/break control and to avoid
- * function call overhead in tight COPY loops.
- *
- * We must use "if (1)" because the usual "do {...} while(0)" wrapper would
- * prevent the continue/break processing from working.  We end the "if (1)"
- * with "else ((void) 0)" to ensure the "if" does not unintentionally match
- * any "else" in the calling code, and to avoid any compiler warnings about
- * empty statements.  See http://www.cit.gu.edu.au/~anthony/info/C/C.macros.
- */
-
-/*
- * This keeps the character read at the top of the loop in the buffer
- * even if there is more than one read-ahead.
- */
-#define IF_NEED_REFILL_AND_NOT_EOF_CONTINUE(extralen) \
-if (1) \
-{ \
-	if (raw_buf_ptr + (extralen) >= copy_buf_len && !hit_eof) \
-	{ \
-		raw_buf_ptr = prev_raw_ptr; /* undo fetch */ \
-		need_data = true; \
-		continue; \
-	} \
-} else ((void) 0)
-
-/* This consumes the remainder of the buffer and breaks */
-#define IF_NEED_REFILL_AND_EOF_BREAK(extralen) \
-if (1) \
-{ \
-	if (raw_buf_ptr + (extralen) >= copy_buf_len && hit_eof) \
-	{ \
-		if (extralen) \
-			raw_buf_ptr = copy_buf_len; /* consume the partial character */ \
-		/* backslash just before EOF, treat as data char */ \
-		result = true; \
-		break; \
-	} \
-} else ((void) 0)
-
-/*
- * Transfer any approved data to line_buf; must do this to be sure
- * there is some room in raw_buf.
- */
-#define REFILL_LINEBUF \
-if (1) \
-{ \
-	if (raw_buf_ptr > cstate->raw_buf_index) \
-	{ \
-		appendBinaryStringInfo(&cstate->line_buf, \
-							 cstate->raw_buf + cstate->raw_buf_index, \
-							   raw_buf_ptr - cstate->raw_buf_index); \
-		cstate->raw_buf_index = raw_buf_ptr; \
-	} \
-} else ((void) 0)
-
-/* Undo any read-ahead and jump out of the block. */
-#define NO_END_OF_COPY_GOTO \
-if (1) \
-{ \
-	raw_buf_ptr = prev_raw_ptr + 1; \
-	goto not_end_of_copy; \
-} else ((void) 0)
-
 static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
 
@@ -371,7 +356,8 @@ static uint64 DoCopyTo(CopyState cstate);
 static uint64 CopyTo(CopyState cstate);
 static void CopyOneRowTo(CopyState cstate, TupleTableSlot *slot);
 static bool CopyReadLine(CopyState cstate);
-static bool CopyReadLineText(CopyState cstate);
+static void ParseLinesText(CopyState cstate);
+static void ParseLinesCSV(CopyState cstate);
 static int	CopyReadAttributesText(CopyState cstate);
 static int	CopyReadAttributesCSV(CopyState cstate);
 static Datum CopyReadBinaryAttribute(CopyState cstate, FmgrInfo *flinfo,
@@ -382,7 +368,7 @@ static void CopyAttributeOutCSV(CopyState cstate, char *string,
 								bool use_quote, bool single_attr);
 static List *CopyGetAttnums(TupleDesc tupDesc, Relation rel,
 							List *attnamelist);
-static char *limit_printout_length(const char *str);
+static char *limit_printout_length(const char *str, int slen);
 
 /* Low-level communications functions */
 static void SendCopyBegin(CopyState cstate);
@@ -399,6 +385,7 @@ static bool CopyGetInt32(CopyState cstate, int32 *val);
 static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 static bool CopyLoadRawBuf(CopyState cstate);
+static bool CopyLoadAndConvertBuf(CopyState cstate);
 static int	CopyReadBinaryData(CopyState cstate, char *dest, int nbytes);
 
 
@@ -2311,7 +2298,7 @@ CopyFromErrorCallback(void *arg)
 			/* error is relevant to a particular column */
 			char	   *attval;
 
-			attval = limit_printout_length(cstate->cur_attval);
+			attval = limit_printout_length(cstate->cur_attval, strlen(cstate->cur_attval));
 			errcontext("COPY %s, line %s, column %s: \"%s\"",
 					   cstate->cur_relname, curlineno_str,
 					   cstate->cur_attname, attval);
@@ -2341,7 +2328,7 @@ CopyFromErrorCallback(void *arg)
 			{
 				char	   *lineval;
 
-				lineval = limit_printout_length(cstate->line_buf.data);
+				lineval = limit_printout_length(cstate->line_buf, cstate->line_len);
 				errcontext("COPY %s, line %s: \"%s\"",
 						   cstate->cur_relname, curlineno_str, lineval);
 				pfree(lineval);
@@ -2361,11 +2348,10 @@ CopyFromErrorCallback(void *arg)
  * Returns a pstrdup'd copy of the input.
  */
 static char *
-limit_printout_length(const char *str)
+limit_printout_length(const char *str, int slen)
 {
 #define MAX_COPY_DATA_DISPLAY 100
 
-	int			slen = strlen(str);
 	int			len;
 	char	   *res;
 
@@ -2819,7 +2805,6 @@ CopyFrom(CopyState cstate)
 			ereport(ERROR,
 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 					 errmsg("cannot perform COPY FREEZE because the table was not created or truncated in the current subtransaction")));
-
 		ti_options |= TABLE_INSERT_FROZEN;
 	}
 
@@ -3224,7 +3209,7 @@ CopyFrom(CopyState cstate)
 					/* Add this tuple to the tuple buffer */
 					CopyMultiInsertInfoStore(&multiInsertInfo,
 											 resultRelInfo, myslot,
-											 cstate->line_buf.len,
+											 100, // FIXME cstate->line_buf.len,
 											 cstate->cur_lineno);
 
 					/*
@@ -3387,16 +3372,30 @@ BeginCopyFrom(ParseState *pstate,
 
 	/*
 	 * Set up variables to avoid per-attribute overhead.  attribute_buf and
-	 * raw_buf are used in both text and binary modes, but we use line_buf
-	 * only in text mode.
+	 * raw_buf are used in both text and binary modes, but text mode has
+	 * some extra state.
 	 */
 	initStringInfo(&cstate->attribute_buf);
 	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
 	cstate->raw_buf_index = cstate->raw_buf_len = 0;
 	if (!cstate->binary)
 	{
-		initStringInfo(&cstate->line_buf);
+		cstate->last_was_cr = false;
+		cstate->parse_lines_state = PLSTATE_NORMAL;
+		cstate->last_line_no = -1;
+		cstate->nextline = 0;
+		cstate->endlines = palloc((RAW_BUF_SIZE + 1) * sizeof(int));
+		cstate->numlines = 0;
+
+		initStringInfo(&cstate->split_line_buf);
+
+		cstate->line_buf = NULL;
+		cstate->line_len = 0;
 		cstate->line_buf_converted = false;
+		cstate->line_buf_valid = false;
+		cstate->line_buf_alloced = false;
+
+		cstate->converted_buf = NULL;
 	}
 
 	/* Assign range table, we'll need it in CopyFrom. */
@@ -3634,7 +3633,7 @@ NextCopyFromRawFields(CopyState cstate, char ***fields, int *nfields)
 	 * characters, we act as though it was newline followed by EOF, ie,
 	 * process the line and then exit loop on next iteration.
 	 */
-	if (done && cstate->line_buf.len == 0)
+	if (done && cstate->line_len == 0)
 		return false;
 
 	/* Parse the line into de-escaped field values */
@@ -3863,451 +3862,550 @@ EndCopyFrom(CopyState cstate)
 static bool
 CopyReadLine(CopyState cstate)
 {
-	bool		result;
-
-	resetStringInfo(&cstate->line_buf);
-	cstate->line_buf_valid = true;
+	resetStringInfo(&cstate->split_line_buf);
 
 	/* Mark that encoding conversion hasn't occurred yet */
 	cstate->line_buf_converted = false;
+	cstate->line_buf_valid = false;
+
+	if (cstate->line_buf_alloced)
+		pfree(cstate->line_buf);
 
-	/* Parse data and transfer into line_buf */
-	result = CopyReadLineText(cstate);
+	if (cstate->split_line_buf.data > 0)
+		resetStringInfo(&cstate->split_line_buf);
 
-	if (result)
+	if (cstate->last_line_no != -1 && cstate->nextline > cstate->last_line_no)
+		return true;
+
+	/*
+	 * If we processed all lines from previous batch, load more
+	 */
+	if (cstate->nextline == cstate->numlines)
 	{
-		/*
-		 * Reached EOF.  In protocol version 3, we should ignore anything
-		 * after \. up to the protocol end of copy data.  (XXX maybe better
-		 * not to treat \. as special?)
-		 */
-		if (cstate->copy_dest == COPY_NEW_FE)
+		for (;;)
 		{
-			do
+			int			endpos;
+			bool		done;
+
+			cstate->nextline = 0;
+
+			/*
+			 * Transfer any remaining data from previous buffer to split_line_buf.
+			 */
+			if (cstate->numlines == 0)
+			{
+				/* this chunk contained no line-ends at all. */
+				endpos = 0;
+			}
+			else
+			{
+				endpos = cstate->endlines[cstate->numlines - 1];
+			}
+			appendBinaryStringInfo(&cstate->split_line_buf, cstate->raw_buf + endpos,
+								   cstate->raw_buf_len - endpos);
+
+			/* Get next raw (and possibly converted) buf */
+			done = !CopyLoadAndConvertBuf(cstate);
+
+			/* Detect line boundaries within the buffer */
+			if (cstate->csv_mode)
+				ParseLinesCSV(cstate);
+			else
+				ParseLinesText(cstate);
+
+			/*
+			 * If we reached the EOF, remember it, and add a sentinel end-of-line to
+			 * 'endlines' so that the logic below doesn't need to special case the
+			 * last line.
+			 */
+			if (done)
 			{
-				cstate->raw_buf_index = cstate->raw_buf_len;
-			} while (CopyLoadRawBuf(cstate));
+				cstate->last_line_no = cstate->numlines;
+				cstate->endlines[cstate->numlines] = cstate->converted_buf_len;
+				cstate->numlines++;
+				break;
+			}
+			else
+				cstate->last_line_no = -1;
+
+			if (cstate->numlines > 0)
+				break;
 		}
 	}
+
+	Assert(cstate->nextline < cstate->numlines);
+
+	/*
+	 * The first line in this buffer could be a contination of a split line that
+	 * started on previous buffer. Treat it specially.
+	 */
+	if (cstate->nextline == 0)
+	{
+		if (cstate->split_line_buf.len > 0)
+		{
+			appendBinaryStringInfo(&cstate->split_line_buf, cstate->converted_buf,
+								   cstate->endlines[0]);
+			cstate->line_buf = cstate->split_line_buf.data;
+			cstate->line_len = cstate->split_line_buf.len;
+		}
+		else
+		{
+			cstate->line_buf = cstate->converted_buf;
+			cstate->line_len = cstate->endlines[0];
+		}
+	}
+	else
+	{
+		int startpos;
+		int endpos;
+
+		startpos = cstate->endlines[cstate->nextline - 1];
+		endpos = cstate->endlines[cstate->nextline];
+
+		cstate->line_buf = cstate->converted_buf + startpos;
+		cstate->line_len = endpos - startpos;
+	}
+
+	if (cstate->nextline == cstate->last_line_no)
+	{
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (cstate->line_len == 0)
+			return true;
+	}
 	else
 	{
 		/*
 		 * If we didn't hit EOF, then we must have transferred the EOL marker
 		 * to line_buf along with the data.  Get rid of it.
 		 */
-		switch (cstate->eol_type)
+		if (cstate->nextline != cstate->last_line_no)
 		{
-			case EOL_NL:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CR:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\r');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CRNL:
-				Assert(cstate->line_buf.len >= 2);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 2] == '\r');
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len -= 2;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_UNKNOWN:
-				/* shouldn't get here */
-				Assert(false);
-				break;
+			switch (cstate->eol_type)
+			{
+				case EOL_NL:
+					Assert(cstate->line_len >= 1);
+					Assert(cstate->line_buf[cstate->line_len - 1] == '\n');
+					cstate->line_len--;
+					cstate->line_buf[cstate->line_len] = '\0';
+					break;
+				case EOL_CR:
+					Assert(cstate->line_len >= 1);
+					Assert(cstate->line_buf[cstate->line_len - 1] == '\r');
+					cstate->line_len--;
+					cstate->line_buf[cstate->line_len] = '\0';
+					break;
+				case EOL_CRNL:
+					Assert(cstate->line_len >= 2);
+					Assert(cstate->line_buf[cstate->line_len - 2] == '\r');
+					Assert(cstate->line_buf[cstate->line_len - 1] == '\n');
+					cstate->line_len -= 2;
+					cstate->line_buf[cstate->line_len] = '\0';
+					break;
+				case EOL_UNKNOWN:
+					/* shouldn't get here */
+					Assert(false);
+					break;
+			}
 		}
 	}
+	cstate->nextline++;
 
-	/* Done reading the line.  Convert it to server encoding. */
-	if (cstate->need_transcoding)
+	cstate->line_buf_valid = true;
+	cstate->line_buf_alloced = false;
+
+	/*
+	 * Done reading the line.  Convert it to server encoding. If the encoding was
+	 * one that embeds ASCII, we did it for the whole raw buffer already
+	 */
+	if (cstate->need_transcoding && !cstate->encoding_embeds_ascii)
 	{
 		char	   *cvt;
 
-		cvt = pg_any_to_server(cstate->line_buf.data,
-							   cstate->line_buf.len,
+		cvt = pg_any_to_server(cstate->line_buf, cstate->line_len,
 							   cstate->file_encoding);
-		if (cvt != cstate->line_buf.data)
+		if (cvt != cstate->line_buf)
 		{
 			/* transfer converted data back to line_buf */
-			resetStringInfo(&cstate->line_buf);
-			appendBinaryStringInfo(&cstate->line_buf, cvt, strlen(cvt));
-			pfree(cvt);
+			cstate->line_buf = cvt;
+			cstate->line_len = strlen(cvt);
+			cstate->line_buf_alloced = true;
 		}
 	}
 
 	/* Now it's safe to use the buffer in error messages */
 	cstate->line_buf_converted = true;
 
-	return result;
+	return false;
 }
 
-/*
- * CopyReadLineText - inner loop of CopyReadLine for text mode
- */
 static bool
-CopyReadLineText(CopyState cstate)
+CopyLoadAndConvertBuf(CopyState cstate)
 {
-	char	   *copy_raw_buf;
-	int			raw_buf_ptr;
-	int			copy_buf_len;
-	bool		need_data = false;
-	bool		hit_eof = false;
-	bool		result = false;
-	char		mblen_str[2];
-
-	/* CSV variables */
-	bool		first_char_in_line = true;
-	bool		in_quote = false,
-				last_was_esc = false;
-	char		quotec = '\0';
-	char		escapec = '\0';
+	bool		moredata;
 
-	if (cstate->csv_mode)
+	/* Get next raw buf */
+	moredata = CopyLoadRawBuf(cstate);
+
+	/* convert if necessary */
+	if (cstate->encoding_embeds_ascii)
 	{
-		quotec = cstate->quote[0];
-		escapec = cstate->escape[0];
-		/* ignore special escape processing if it's the same as quotec */
-		if (quotec == escapec)
-			escapec = '\0';
+		Assert(cstate->need_transcoding);
+				
+		if (cstate->converted_buf && cstate->converted_buf != cstate->raw_buf)
+			pfree(cstate->converted_buf);
+
+		while (moredata && cstate->raw_buf_len < MAX_CONVERSION_GROWTH)
+			moredata = CopyLoadRawBuf(cstate);
+
+		if (!moredata)
+		{
+			cstate->raw_buf_index = cstate->raw_buf_len;
+		}
+		else
+		{
+			/* Find length */
+			char	   *p;
+			char	   *pend;
+
+			p = cstate->raw_buf;
+			pend = cstate->raw_buf + cstate->raw_buf_len;
+			while (p < pend - MAX_CONVERSION_GROWTH)
+			{
+				if (IS_HIGHBIT_SET(*p))
+				{
+					int			mblen;
+
+					mblen = pg_encoding_mblen(cstate->file_encoding, p);
+					p += mblen;
+				}
+				else
+					p++;
+			}
+			cstate->raw_buf_index = pend - p;
+		}
+		cstate->converted_buf = pg_any_to_server(cstate->raw_buf,
+												 cstate->raw_buf_index,
+												 cstate->file_encoding);
+		if (cstate->converted_buf != cstate->raw_buf)
+			cstate->converted_buf_len = strlen(cstate->converted_buf);
+		else
+			cstate->converted_buf_len = cstate->raw_buf_index;
+	}
+	else
+	{
+		cstate->converted_buf = cstate->raw_buf;
+		cstate->converted_buf_len = cstate->raw_buf_len;
+		cstate->raw_buf_index = cstate->raw_buf_len;
 	}
 
-	mblen_str[1] = '\0';
+	return moredata;
+}
+
+/*
+ * Find all newlines (or CRs or CRLNs) in the buffer in cstate->converted_buf.
+ *
+ * The positions of the newlines are stored in cstate->endlines array.
+ * Each position points to the *next* character, after the newline.
+ *
+ * A position can also be 0, meaning that there was a newline immediatedly
+ * before the current buffer. That case can currently only arise when
+ * processing the first line in EOL_UNKNOWN mode, and we see a CR at the
+ * end a buffer. In that case, we won't know until we see the first
+ * character of the next buffer, that the CR at the end of the previous
+ * buffer was really the end-of-line.
+ */
+static void
+ParseLinesText(CopyState cstate)
+{
+	/* pre-requisites: there is data in converted_buf */
+	char	   *startp;
+	char	   *p;
+	char	   *endp;
+	int		   *endlines;
+	int			nlines;
 
 	/*
-	 * The objective of this loop is to transfer the entire next input line
-	 * into line_buf.  Hence, we only care for detecting newlines (\r and/or
-	 * \n) and the end-of-copy marker (\.).
-	 *
-	 * In CSV mode, \r and \n inside a quoted field are just part of the data
-	 * value and are put in line_buf.  We keep just enough state to know if we
-	 * are currently in a quoted field or not.
-	 *
-	 * These four characters, and the CSV escape and quote characters, are
-	 * assumed the same in frontend and backend encodings.
+	 * TODO: support multibyte encodings. Plan:
 	 *
-	 * For speed, we try to move data from raw_buf to line_buf in chunks
-	 * rather than one character at a time.  raw_buf_ptr points to the next
-	 * character to examine; any characters from raw_buf_index to raw_buf_ptr
-	 * have been determined to be part of the line, but not yet transferred to
-	 * line_buf.
+	 * If encoding_embeds_ascii, the caller converts the raw buffer
+	 * before calling this function, scanning through the buffer with
+	 * pg_mblen() to find the multibyte character boundary. Stash any
+	 * remaining bytes for next call.
 	 *
-	 * For a little extra speed within the loop, we copy raw_buf and
-	 * raw_buf_len into local variables.
+	 * Otherwise, the conversion can be done separately on each line, after
+	 * calling this function.
 	 */
-	copy_raw_buf = cstate->raw_buf;
-	raw_buf_ptr = cstate->raw_buf_index;
-	copy_buf_len = cstate->raw_buf_len;
 
-	for (;;)
-	{
-		int			prev_raw_ptr;
-		char		c;
+	p = cstate->converted_buf;
+	startp = cstate->converted_buf;
+	endp = cstate->converted_buf + cstate->converted_buf_len;
 
-		/*
-		 * Load more data if needed.  Ideally we would just force four bytes
-		 * of read-ahead and avoid the many calls to
-		 * IF_NEED_REFILL_AND_NOT_EOF_CONTINUE(), but the COPY_OLD_FE protocol
-		 * does not allow us to read too far ahead or we might read into the
-		 * next data, so we read-ahead only as far we know we can.  One
-		 * optimization would be to read-ahead four byte here if
-		 * cstate->copy_dest != COPY_OLD_FE, but it hardly seems worth it,
-		 * considering the size of the buffer.
-		 */
-		if (raw_buf_ptr >= copy_buf_len || need_data)
-		{
-			REFILL_LINEBUF;
+	endlines = cstate->endlines;
+	nlines = 0;
 
-			/*
-			 * Try to read some more data.  This will certainly reset
-			 * raw_buf_index to zero, and raw_buf_ptr must go with it.
-			 */
-			if (!CopyLoadRawBuf(cstate))
-				hit_eof = true;
-			raw_buf_ptr = 0;
-			copy_buf_len = cstate->raw_buf_len;
+	if (cstate->eol_type == EOL_UNKNOWN)
+	{
+		while (p < endp)
+		{
+			char		c = *(p++);
 
-			/*
-			 * If we are completely out of data, break out of the loop,
-			 * reporting EOF.
-			 */
-			if (copy_buf_len <= 0)
+			if (c == '\n')
+			{
+				if (cstate->last_was_cr)
+					cstate->eol_type = EOL_CRNL;
+				else
+					cstate->eol_type = EOL_NL;
+				endlines[nlines++] = p - startp;
+				break;
+			}
+			else if (cstate->last_was_cr)
 			{
-				result = true;
+				/*
+				 * The previous character was \r, and this character is the first
+				 * character of the next line. The line ended just *before* this
+				 * character.
+				 */
+				endlines[nlines++] = (p - 1) - startp;
+				cstate->eol_type = EOL_CR;
+				cstate->last_was_cr = false; /* not used in EOL_CR mode */
 				break;
 			}
-			need_data = false;
+			else if (c == '\r')
+			{
+				cstate->last_was_cr = true;
+			}
 		}
+		/* continue processing according to the new 'eol_type' */
+	}
 
-		/* OK to fetch a character */
-		prev_raw_ptr = raw_buf_ptr;
-		c = copy_raw_buf[raw_buf_ptr++];
-
-		if (cstate->csv_mode)
+	if (cstate->eol_type == EOL_NL)
+	{
+		while (p < endp)
 		{
-			/*
-			 * If character is '\\' or '\r', we may need to look ahead below.
-			 * Force fetch of the next character if we don't already have it.
-			 * We need to do this before changing CSV state, in case one of
-			 * these characters is also the quote or escape character.
-			 *
-			 * Note: old-protocol does not like forced prefetch, but it's OK
-			 * here since we cannot validly be at EOF.
-			 */
-			if (c == '\\' || c == '\r')
+			char		c = *(p++);
+
+			/* Process \n */
+			if (c == '\n')
 			{
-				IF_NEED_REFILL_AND_NOT_EOF_CONTINUE(0);
+				endlines[nlines++] = p - startp;
 			}
 
-			/*
-			 * Dealing with quotes and escapes here is mildly tricky. If the
-			 * quote char is also the escape char, there's no problem - we
-			 * just use the char as a toggle. If they are different, we need
-			 * to ensure that we only take account of an escape inside a
-			 * quoted field and immediately preceding a quote char, and not
-			 * the second in an escape-escape sequence.
-			 */
-			if (in_quote && c == escapec)
-				last_was_esc = !last_was_esc;
-			if (c == quotec && !last_was_esc)
-				in_quote = !in_quote;
-			if (c != escapec)
-				last_was_esc = false;
-
-			/*
-			 * Updating the line count for embedded CR and/or LF chars is
-			 * necessarily a little fragile - this test is probably about the
-			 * best we can do.  (XXX it's arguable whether we should do this
-			 * at all --- is cur_lineno a physical or logical count?)
-			 */
-			if (in_quote && c == (cstate->eol_type == EOL_NL ? '\n' : '\r'))
-				cstate->cur_lineno++;
+			/* Process \r */
+			if (c == '\r')
+				ereport(ERROR,
+						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+						 errmsg("literal carriage return found in data"),
+						 errhint("Use \"\\r\" to represent carriage return.")));
 		}
-
-		/* Process \r */
-		if (c == '\r' && (!cstate->csv_mode || !in_quote))
+	}
+	else if (cstate->eol_type == EOL_CR)
+	{
+		while (p < endp)
 		{
-			/* Check for \r\n on first line, _and_ handle \r\n. */
-			if (cstate->eol_type == EOL_UNKNOWN ||
-				cstate->eol_type == EOL_CRNL)
-			{
-				/*
-				 * If need more data, go back to loop top to load it.
-				 *
-				 * Note that if we are at EOF, c will wind up as '\0' because
-				 * of the guaranteed pad of raw_buf.
-				 */
-				IF_NEED_REFILL_AND_NOT_EOF_CONTINUE(0);
+			char		c = *(p++);
 
-				/* get next char */
-				c = copy_raw_buf[raw_buf_ptr];
+			/* Process \r */
+			if (c == '\r')
+				endlines[nlines++] = p - startp;
 
-				if (c == '\n')
+			/* Process \n */
+			if (c == '\r')
+				ereport(ERROR,
+						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+						 errmsg("literal newline found in data"),
+						 errhint("Use \"\\n\" to represent carriage return.")));
+		}
+	}
+	else if (cstate->eol_type == EOL_CRNL)
+	{
+		while (p < endp)
+		{
+			char		c = *(p++);
+
+			if (c == '\n')
+			{
+				if (cstate->last_was_cr)
 				{
-					raw_buf_ptr++;	/* eat newline */
-					cstate->eol_type = EOL_CRNL;	/* in case not set yet */
+					endlines[nlines++] = p - startp;
+					cstate->last_was_cr = false;
 				}
 				else
-				{
-					/* found \r, but no \n */
-					if (cstate->eol_type == EOL_CRNL)
-						ereport(ERROR,
-								(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-								 !cstate->csv_mode ?
-								 errmsg("literal carriage return found in data") :
-								 errmsg("unquoted carriage return found in data"),
-								 !cstate->csv_mode ?
-								 errhint("Use \"\\r\" to represent carriage return.") :
-								 errhint("Use quoted CSV field to represent carriage return.")));
-
-					/*
-					 * if we got here, it is the first line and we didn't find
-					 * \n, so don't consume the peeked character
-					 */
-					cstate->eol_type = EOL_CR;
-				}
+					ereport(ERROR,
+							(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+							 errmsg("literal newline found in data"),
+							 errhint("Use \"\\n\" to represent carriage return.")));
 			}
-			else if (cstate->eol_type == EOL_NL)
+			else if (cstate->last_was_cr)
+			{
 				ereport(ERROR,
 						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-						 !cstate->csv_mode ?
-						 errmsg("literal carriage return found in data") :
-						 errmsg("unquoted carriage return found in data"),
-						 !cstate->csv_mode ?
-						 errhint("Use \"\\r\" to represent carriage return.") :
-						 errhint("Use quoted CSV field to represent carriage return.")));
-			/* If reach here, we have found the line terminator */
-			break;
+						 errmsg("literal carriage return found in data"),
+						 errhint("Use \"\\r\" to represent carriage return.")));
+			}
+			else if (c == '\r')
+			{
+				cstate->last_was_cr = true;
+			}
 		}
+	}
 
-		/* Process \n */
-		if (c == '\n' && (!cstate->csv_mode || !in_quote))
-		{
-			if (cstate->eol_type == EOL_CR || cstate->eol_type == EOL_CRNL)
-				ereport(ERROR,
-						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-						 !cstate->csv_mode ?
-						 errmsg("literal newline found in data") :
-						 errmsg("unquoted newline found in data"),
-						 !cstate->csv_mode ?
-						 errhint("Use \"\\n\" to represent newline.") :
-						 errhint("Use quoted CSV field to represent newline.")));
-			cstate->eol_type = EOL_NL;	/* in case not set yet */
-			/* If reach here, we have found the line terminator */
-			break;
-		}
+	cstate->numlines = nlines;
+}
 
-		/*
-		 * In CSV mode, we only recognize \. alone on a line.  This is because
-		 * \. is a valid CSV data value.
-		 */
-		if (c == '\\' && (!cstate->csv_mode || first_char_in_line))
-		{
-			char		c2;
+/*
+ * Like ParseLinesText, but in CSV mode.
+ */
+static void
+ParseLinesCSV(CopyState cstate)
+{
+	/* pre-requisites: there is data in converted_buf */
+	char	   *startp;
+	char	   *p;
+	char	   *endp;
+	int		   *endlines;
+	int			nlines;
+	int			state = cstate->parse_lines_state;
+	char		quotec = '\0';
+	char		escapec = '\0';
 
-			IF_NEED_REFILL_AND_NOT_EOF_CONTINUE(0);
-			IF_NEED_REFILL_AND_EOF_BREAK(0);
+	quotec = cstate->quote[0];
+	escapec = cstate->escape[0];
+	/* ignore special escape processing if it's the same as quotec */
+	if (quotec == escapec)
+		escapec = '\0';
 
-			/* -----
-			 * get next character
-			 * Note: we do not change c so if it isn't \., we can fall
-			 * through and continue processing for file encoding.
-			 * -----
-			 */
-			c2 = copy_raw_buf[raw_buf_ptr];
+	p = cstate->converted_buf;
+	startp = cstate->converted_buf;
+	endp = cstate->converted_buf + cstate->converted_buf_len;
 
-			if (c2 == '.')
-			{
-				raw_buf_ptr++;	/* consume the '.' */
+	endlines = cstate->endlines;
+	nlines = 0;
 
-				/*
-				 * Note: if we loop back for more data here, it does not
-				 * matter that the CSV state change checks are re-executed; we
-				 * will come back here with no important state changed.
-				 */
-				if (cstate->eol_type == EOL_CRNL)
-				{
-					/* Get the next character */
-					IF_NEED_REFILL_AND_NOT_EOF_CONTINUE(0);
-					/* if hit_eof, c2 will become '\0' */
-					c2 = copy_raw_buf[raw_buf_ptr++];
+	while (p < endp)
+	{
+		char		c = *(p++);
+		bool		last_was_cr;
+
+		last_was_cr = cstate->last_was_cr;
+		cstate->last_was_cr = false;
 
-					if (c2 == '\n')
+		switch (state)
+		{
+			case PLSTATE_NORMAL:
+				if (c == '\n')
+				{
+					if (cstate->eol_type == EOL_NL)
+						endlines[nlines++] = p - startp;
+					else if (cstate->eol_type == EOL_CR)
+						ereport(ERROR,
+								(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+								 errmsg("unquoted newline found in data"),
+								 errhint("Use quoted CSV field to represent newline.")));
+					else if (cstate->eol_type == EOL_CRNL)
 					{
-						if (!cstate->csv_mode)
+						if (last_was_cr)
+							endlines[nlines++] = p - startp;
+						else
 							ereport(ERROR,
 									(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-									 errmsg("end-of-copy marker does not match previous newline style")));
+									 errmsg("unquoted newline found in data"),
+									 errhint("Use quoted CSV field to represent newline.")));
+					}
+					else if (cstate->eol_type == EOL_UNKNOWN)
+					{
+						if (last_was_cr)
+							cstate->eol_type = EOL_CRNL;
 						else
-							NO_END_OF_COPY_GOTO;
+							cstate->eol_type = EOL_NL;
+						endlines[nlines++] = p - startp;
 					}
-					else if (c2 != '\r')
+				}
+				else if (c == '\r')
+				{
+					if (cstate->eol_type == EOL_NL)
+						ereport(ERROR,
+								(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
+								 errmsg("unquoted carriage return found in data"),
+								 errhint("Use quoted CSV field to represent carriage return.")));
+					else if (cstate->eol_type == EOL_CR)
+						endlines[nlines++] = p - startp;
+					else if (cstate->eol_type == EOL_CRNL)
 					{
-						if (!cstate->csv_mode)
+						if (last_was_cr)
 							ereport(ERROR,
 									(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-									 errmsg("end-of-copy marker corrupt")));
+									 errmsg("unquoted carriage return found in data"),
+									 errhint("Use quoted CSV field to represent carriage return.")));
+						cstate->last_was_cr = true;
+					}
+					else if (cstate->eol_type == EOL_UNKNOWN)
+					{
+						if (last_was_cr)
+						{
+							/* oops, the previous char was actually a line boundary already */
+							cstate->eol_type = EOL_CR;
+							endlines[nlines++] = (p - 1) - startp;
+							endlines[nlines++] = p - startp;
+						}
 						else
-							NO_END_OF_COPY_GOTO;
+							cstate->last_was_cr = true;
 					}
 				}
-
-				/* Get the next character */
-				IF_NEED_REFILL_AND_NOT_EOF_CONTINUE(0);
-				/* if hit_eof, c2 will become '\0' */
-				c2 = copy_raw_buf[raw_buf_ptr++];
-
-				if (c2 != '\r' && c2 != '\n')
+				else if (c == escapec)
+					state = PLSTATE_ESCAPE;
+				else if (c == quotec)
+					state = PLSTATE_IN_QUOTE;
+				else if (last_was_cr)
 				{
-					if (!cstate->csv_mode)
+					if (cstate->eol_type == EOL_CRNL)
 						ereport(ERROR,
 								(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-								 errmsg("end-of-copy marker corrupt")));
+								 errmsg("unquoted carriage return found in data"),
+								 errhint("Use quoted CSV field to represent carriage return.")));
 					else
-						NO_END_OF_COPY_GOTO;
+					{
+						Assert(cstate->eol_type == EOL_UNKNOWN);
+						cstate->eol_type = EOL_CR;
+						endlines[nlines++] = p - startp;
+					}
 				}
+				break;
 
-				if ((cstate->eol_type == EOL_NL && c2 != '\n') ||
-					(cstate->eol_type == EOL_CRNL && c2 != '\n') ||
-					(cstate->eol_type == EOL_CR && c2 != '\r'))
+			case PLSTATE_ESCAPE:
+				if (quotec == escapec && c != quotec)
 				{
-					ereport(ERROR,
-							(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-							 errmsg("end-of-copy marker does not match previous newline style")));
+					/* the escape was actually a quote */
+					state = PLSTATE_IN_QUOTE;
 				}
-
-				/*
-				 * Transfer only the data before the \. into line_buf, then
-				 * discard the data and the \. sequence.
-				 */
-				if (prev_raw_ptr > cstate->raw_buf_index)
-					appendBinaryStringInfo(&cstate->line_buf,
-										   cstate->raw_buf + cstate->raw_buf_index,
-										   prev_raw_ptr - cstate->raw_buf_index);
-				cstate->raw_buf_index = raw_buf_ptr;
-				result = true;	/* report EOF */
+				else
+					state = PLSTATE_NORMAL;
 				break;
-			}
-			else if (!cstate->csv_mode)
 
-				/*
-				 * If we are here, it means we found a backslash followed by
-				 * something other than a period.  In non-CSV mode, anything
-				 * after a backslash is special, so we skip over that second
-				 * character too.  If we didn't do that \\. would be
-				 * considered an eof-of copy, while in non-CSV mode it is a
-				 * literal backslash followed by a period.  In CSV mode,
-				 * backslashes are not special, so we want to process the
-				 * character after the backslash just like a normal character,
-				 * so we don't increment in those cases.
-				 */
-				raw_buf_ptr++;
-		}
-
-		/*
-		 * This label is for CSV cases where \. appears at the start of a
-		 * line, but there is more text after it, meaning it was a data value.
-		 * We are more strict for \. in CSV mode because \. could be a data
-		 * value, while in non-CSV mode, \. cannot be a data value.
-		 */
-not_end_of_copy:
-
-		/*
-		 * Process all bytes of a multi-byte character as a group.
-		 *
-		 * We only support multi-byte sequences where the first byte has the
-		 * high-bit set, so as an optimization we can avoid this block
-		 * entirely if it is not set.
-		 */
-		if (cstate->encoding_embeds_ascii && IS_HIGHBIT_SET(c))
-		{
-			int			mblen;
-
-			/*
-			 * It is enough to look at the first byte in all our encodings, to
-			 * get the length.  (GB18030 is a bit special, but still works for
-			 * our purposes; see comment in pg_gb18030_mblen())
-			 */
-			mblen_str[0] = c;
-			mblen = pg_encoding_mblen(cstate->file_encoding, mblen_str);
+			case PLSTATE_IN_QUOTE:
+				if (c == escapec)
+					state = PLSTATE_ESCAPE_IN_QUOTE;
+				else if (c == quotec)
+					state = PLSTATE_NORMAL;
+				break;
 
-			IF_NEED_REFILL_AND_NOT_EOF_CONTINUE(mblen - 1);
-			IF_NEED_REFILL_AND_EOF_BREAK(mblen - 1);
-			raw_buf_ptr += mblen - 1;
+			case PLSTATE_ESCAPE_IN_QUOTE:
+				if (quotec == escapec && c != quotec)
+				{
+					/* the escape was actually the end quote */
+					state = PLSTATE_NORMAL;
+					continue; /* process this byte again, as a normal */
+				}
+				else
+					state = PLSTATE_IN_QUOTE;
+				break;
 		}
-		first_char_in_line = false;
-	}							/* end of outer loop */
-
-	/*
-	 * Transfer any still-uncopied data to line_buf.
-	 */
-	REFILL_LINEBUF;
-
-	return result;
+	}
+	cstate->numlines = nlines;
+	cstate->parse_lines_state = state;
 }
 
 /*
@@ -4344,6 +4442,8 @@ GetDecimalFromHex(char hex)
 static int
 CopyReadAttributesText(CopyState cstate)
 {
+	char	   *line_buf = cstate->line_buf;
+	int			len = cstate->line_len;
 	char		delimc = cstate->delim[0];
 	int			fieldno;
 	char	   *output_ptr;
@@ -4356,7 +4456,7 @@ CopyReadAttributesText(CopyState cstate)
 	 */
 	if (cstate->max_fields <= 0)
 	{
-		if (cstate->line_buf.len != 0)
+		if (len != 0)
 			ereport(ERROR,
 					(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
 					 errmsg("extra data after last expected column")));
@@ -4372,13 +4472,13 @@ CopyReadAttributesText(CopyState cstate)
 	 * it this way because enlarging attribute_buf mid-stream would invalidate
 	 * pointers already stored into cstate->raw_fields[].
 	 */
-	if (cstate->attribute_buf.maxlen <= cstate->line_buf.len)
-		enlargeStringInfo(&cstate->attribute_buf, cstate->line_buf.len);
+	if (cstate->attribute_buf.maxlen <= len)
+		enlargeStringInfo(&cstate->attribute_buf, len);
 	output_ptr = cstate->attribute_buf.data;
 
 	/* set pointer variables for loop */
-	cur_ptr = cstate->line_buf.data;
-	line_end_ptr = cstate->line_buf.data + cstate->line_buf.len;
+	cur_ptr = line_buf;
+	line_end_ptr = line_buf + len;
 
 	/* Outer loop iterates over fields */
 	fieldno = 0;
@@ -4586,7 +4686,7 @@ CopyReadAttributesCSV(CopyState cstate)
 	 */
 	if (cstate->max_fields <= 0)
 	{
-		if (cstate->line_buf.len != 0)
+		if (cstate->line_len != 0)
 			ereport(ERROR,
 					(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
 					 errmsg("extra data after last expected column")));
@@ -4602,13 +4702,13 @@ CopyReadAttributesCSV(CopyState cstate)
 	 * it this way because enlarging attribute_buf mid-stream would invalidate
 	 * pointers already stored into cstate->raw_fields[].
 	 */
-	if (cstate->attribute_buf.maxlen <= cstate->line_buf.len)
-		enlargeStringInfo(&cstate->attribute_buf, cstate->line_buf.len);
+	if (cstate->attribute_buf.maxlen <= cstate->line_len)
+		enlargeStringInfo(&cstate->attribute_buf, cstate->line_len);
 	output_ptr = cstate->attribute_buf.data;
 
 	/* set pointer variables for loop */
-	cur_ptr = cstate->line_buf.data;
-	line_end_ptr = cstate->line_buf.data + cstate->line_buf.len;
+	cur_ptr = cstate->line_buf;
+	line_end_ptr = cstate->line_buf + cstate->line_len;
 
 	/* Outer loop iterates over fields */
 	fieldno = 0;
-- 
2.20.1

#206Tomas Vondra
tomas.vondra@2ndquadrant.com
In reply to: vignesh C (#192)
Re: Parallel copy

Hi,

I've done a bit more testing today, and I think the parsing is busted in
some way. Consider this:

test=# create extension random;
CREATE EXTENSION

test=# create table t (a text);
CREATE TABLE

test=# insert into t select random_string(random_int(10, 256*1024)) from generate_series(1,10000);
INSERT 0 10000

test=# copy t to '/mnt/data/t.csv';
COPY 10000

test=# truncate t;
TRUNCATE TABLE

test=# copy t from '/mnt/data/t.csv';
COPY 10000

test=# truncate t;
TRUNCATE TABLE

test=# copy t from '/mnt/data/t.csv' with (parallel 2);
ERROR: invalid byte sequence for encoding "UTF8": 0x00
CONTEXT: COPY t, line 485: "m&\nh%_a"%r]>qtCl:Q5ltvF~;2oS6@HB>F>og,bD$Lw'nZY\tYl#BH\t{(j~ryoZ08"SGU~.}8CcTRk1\ts$@U3szCC+U1U3i@P..."
parallel worker

The functions come from an extension I use to generate random data, I've
pushed it to github [1]https://github.com/tvondra/random. The random_string() generates a random string
with ASCII characters, symbols and a couple special characters (\r\n\t).
The intent was to try loading data where a fields may span multiple 64kB
blocks and may contain newlines etc.

The non-parallel copy works fine, the parallel one fails. I haven't
investigated the details, but I guess it gets confused about where a
string starts/end, or something like that.

[1]: https://github.com/tvondra/random

regards

--
Tomas Vondra http://www.2ndQuadrant.com
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

#207Tomas Vondra
tomas.vondra@2ndquadrant.com
In reply to: Heikki Linnakangas (#204)
Re: Parallel copy

On Fri, Oct 30, 2020 at 06:41:41PM +0200, Heikki Linnakangas wrote:

On 30/10/2020 18:36, Heikki Linnakangas wrote:

I find this design to be very complicated. Why does the line-boundary
information need to be in shared memory? I think this would be much
simpler if each worker grabbed a fixed-size block of raw data, and
processed that.

In your patch, the leader process scans the input to find out where one
line ends and another begins, and because of that decision, the leader
needs to make the line boundaries available in shared memory, for the
worker processes. If we moved that responsibility to the worker
processes, you wouldn't need to keep the line boundaries in shared
memory. A worker would only need to pass enough state to the next worker
to tell it where to start scanning the next block.

Here's a high-level sketch of how I'm imagining this to work:

The shared memory structure consists of a queue of blocks, arranged as
a ring buffer. Each block is of fixed size, and contains 64 kB of
data, and a few fields for coordination:

typedef struct
{
/* Current state of the block */
pg_atomic_uint32 state;

/* starting offset of first line within the block */
int startpos;

char data[64 kB];
} ParallelCopyDataBlock;

Where state is one of:

enum {
FREE, /* buffer is empty */
FILLED, /* leader has filled the buffer with raw data */
READY, /* start pos has been filled in, but no worker process
has claimed the block yet */
PROCESSING, /* worker has claimed the block, and is processing it */
}

State changes FREE -> FILLED -> READY -> PROCESSING -> FREE. As the
COPY progresses, the ring of blocks will always look something like
this:

blk 0 startpos 0: PROCESSING [worker 1]
blk 1 startpos 12: PROCESSING [worker 2]
blk 2 startpos 10: READY
blk 3 starptos -: FILLED
blk 4 startpos -: FILLED
blk 5 starptos -: FILLED
blk 6 startpos -: FREE
blk 7 startpos -: FREE

Typically, each worker process is busy processing a block. After the
blocks being processed, there is one block in READY state, and after
that, blocks in FILLED state.

Leader process:

The leader process is simple. It picks the next FREE buffer, fills it
with raw data from the file, and marks it as FILLED. If no buffers are
FREE, wait.

Worker process:

1. Claim next READY block from queue, by changing its state to
PROCESSING. If the next block is not READY yet, wait until it is.

2. Start scanning the block from 'startpos', finding end-of-line
markers. (in CSV mode, need to track when we're in-quotes).

3. When you reach the end of the block, if the last line continues to
next block, wait for the next block to become FILLED. Peek into the
next block, and copy the remaining part of the split line to a local
buffer, and set the 'startpos' on the next block to point to the end
of the split line. Mark the next block as READY.

4. Process all the lines in the block, call input functions, insert
rows.

5. Mark the block as DONE.

In this design, you don't need to keep line boundaries in shared
memory, because each worker process is responsible for finding the
line boundaries of its own block.

There's a point of serialization here, in that the next block cannot
be processed, until the worker working on the previous block has
finished scanning the EOLs, and set the starting position on the next
block, putting it in READY state. That's not very different from your
patch, where you had a similar point of serialization because the
leader scanned the EOLs, but I think the coordination between
processes is simpler here.

I agree this design looks simpler. I'm a bit worried about serializing
the parsing like this, though. It's true the current approach (where the
first phase of parsing happens in the leader) has a similar issue, but I
think it would be easier to improve that in that design.

My plan was to parallelize the parsing roughly like this:

1) split the input buffer into smaller chunks

2) let workers scan the buffers and record positions of interesting
characters (delimiters, quotes, ...) and pass it back to the leader

3) use the information to actually parse the input data (we only need to
look at the interesting characters, skipping large parts of data)

4) pass the parsed chunks to workers, just like in the current patch

But maybe something like that would be possible even with the approach
you propose - we could have a special parse phase for processing each
buffer, where any worker could look for the special characters, record
the positions in a bitmap next to the buffer. So the whole sequence of
states would look something like this:

EMPTY
FILLED
PARSED
READY
PROCESSING

Of course, the question is whether parsing really is sufficiently
expensive for this to be worth it.

regards

--
Tomas Vondra http://www.2ndQuadrant.com
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

#208Heikki Linnakangas
hlinnaka@iki.fi
In reply to: Tomas Vondra (#207)
Re: Parallel copy

On 30/10/2020 22:56, Tomas Vondra wrote:

I agree this design looks simpler. I'm a bit worried about serializing
the parsing like this, though. It's true the current approach (where the
first phase of parsing happens in the leader) has a similar issue, but I
think it would be easier to improve that in that design.

My plan was to parallelize the parsing roughly like this:

1) split the input buffer into smaller chunks

2) let workers scan the buffers and record positions of interesting
characters (delimiters, quotes, ...) and pass it back to the leader

3) use the information to actually parse the input data (we only need to
look at the interesting characters, skipping large parts of data)

4) pass the parsed chunks to workers, just like in the current patch

But maybe something like that would be possible even with the approach
you propose - we could have a special parse phase for processing each
buffer, where any worker could look for the special characters, record
the positions in a bitmap next to the buffer. So the whole sequence of
states would look something like this:

EMPTY
FILLED
PARSED
READY
PROCESSING

I think it's even simpler than that. You don't need to communicate the
"interesting positions" between processes, if the same worker takes care
of the chunk through all states from FILLED to DONE.

You can build the bitmap of interesting positions immediately in FILLED
state, independently of all previous blocks. Once you've built the
bitmap, you need to wait for the information on where the first line
starts, but presumably finding the interesting positions is the
expensive part.

Of course, the question is whether parsing really is sufficiently
expensive for this to be worth it.

Yeah, I don't think it's worth it. Splitting the lines is pretty fast, I
think we have many years to come before that becomes a bottleneck. But
if it turns out I'm wrong and we need to implement that, the path is
pretty straightforward.

- Heikki

#209Tomas Vondra
tomas.vondra@2ndquadrant.com
In reply to: Heikki Linnakangas (#208)
Re: Parallel copy

On Sat, Oct 31, 2020 at 12:09:32AM +0200, Heikki Linnakangas wrote:

On 30/10/2020 22:56, Tomas Vondra wrote:

I agree this design looks simpler. I'm a bit worried about serializing
the parsing like this, though. It's true the current approach (where the
first phase of parsing happens in the leader) has a similar issue, but I
think it would be easier to improve that in that design.

My plan was to parallelize the parsing roughly like this:

1) split the input buffer into smaller chunks

2) let workers scan the buffers and record positions of interesting
characters (delimiters, quotes, ...) and pass it back to the leader

3) use the information to actually parse the input data (we only need to
look at the interesting characters, skipping large parts of data)

4) pass the parsed chunks to workers, just like in the current patch

But maybe something like that would be possible even with the approach
you propose - we could have a special parse phase for processing each
buffer, where any worker could look for the special characters, record
the positions in a bitmap next to the buffer. So the whole sequence of
states would look something like this:

EMPTY
FILLED
PARSED
READY
PROCESSING

I think it's even simpler than that. You don't need to communicate the
"interesting positions" between processes, if the same worker takes
care of the chunk through all states from FILLED to DONE.

You can build the bitmap of interesting positions immediately in
FILLED state, independently of all previous blocks. Once you've built
the bitmap, you need to wait for the information on where the first
line starts, but presumably finding the interesting positions is the
expensive part.

I don't think it's that simple. For example, the previous block may
contain a very long value (say, 1MB), so a bunch of blocks have to be
processed by the same worker. That probably makes the state transitions
a bit, and it also means the bitmap would need to be passed to the
worker that actually processes the block. Or we might just ignore this,
on the grounds that it's not a very common situation.

Of course, the question is whether parsing really is sufficiently
expensive for this to be worth it.

Yeah, I don't think it's worth it. Splitting the lines is pretty fast,
I think we have many years to come before that becomes a bottleneck.
But if it turns out I'm wrong and we need to implement that, the path
is pretty straightforward.

OK. I agree the parsing is relatively cheap, and I don't recall seeing
CSV parsing as a bottleneck in production. I suspect that's might be
simply because we're hitting other bottlenecks first, though.

regard

--
Tomas Vondra http://www.2ndQuadrant.com
PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services

#210Amit Kapila
amit.kapila16@gmail.com
In reply to: Heikki Linnakangas (#204)
Re: Parallel copy

On Fri, Oct 30, 2020 at 10:11 PM Heikki Linnakangas <hlinnaka@iki.fi> wrote:

Leader process:

The leader process is simple. It picks the next FREE buffer, fills it
with raw data from the file, and marks it as FILLED. If no buffers are
FREE, wait.

Worker process:

1. Claim next READY block from queue, by changing its state to
PROCESSING. If the next block is not READY yet, wait until it is.

2. Start scanning the block from 'startpos', finding end-of-line
markers. (in CSV mode, need to track when we're in-quotes).

3. When you reach the end of the block, if the last line continues to
next block, wait for the next block to become FILLED. Peek into the
next block, and copy the remaining part of the split line to a local
buffer, and set the 'startpos' on the next block to point to the end
of the split line. Mark the next block as READY.

4. Process all the lines in the block, call input functions, insert
rows.

5. Mark the block as DONE.

In this design, you don't need to keep line boundaries in shared memory,
because each worker process is responsible for finding the line
boundaries of its own block.

There's a point of serialization here, in that the next block cannot be
processed, until the worker working on the previous block has finished
scanning the EOLs, and set the starting position on the next block,
putting it in READY state. That's not very different from your patch,
where you had a similar point of serialization because the leader
scanned the EOLs,

But in the design (single producer multiple consumer) used by the
patch the worker doesn't need to wait till the complete block is
processed, it can start processing the lines already found. This will
also allow workers to start much earlier to process the data as it
doesn't need to wait for all the offsets corresponding to 64K block
ready. However, in the design where each worker is processing the 64K
block, it can lead to much longer waits. I think this will impact the
Copy STDIN case more where in most cases (200-300 bytes tuples) we
receive line-by-line from client and find the line-endings by leader.
If the leader doesn't find the line-endings the workers need to wait
till the leader fill the entire 64K chunk, OTOH, with current approach
the worker can start as soon as leader is able to populate some
minimum number of line-endings

The other point is that the leader backend won't be used completely as
it is only doing a very small part (primarily reading the file) of the
overall work.

We have discussed both these approaches (a) single producer multiple
consumer, and (b) all workers doing the processing as you are saying
in the beginning and concluded that (a) is better, see some of the
relevant emails [1]/messages/by-id/20200413201633.cki4nsptynq7blhg@alap3.anarazel.de[2]/messages/by-id/20200415181913.4gjqcnuzxfzbbzxa@alap3.anarazel.de[3]/messages/by-id/78C0107E-62F2-4F76-BFD8-34C73B716944@anarazel.de.

[1]: /messages/by-id/20200413201633.cki4nsptynq7blhg@alap3.anarazel.de
[2]: /messages/by-id/20200415181913.4gjqcnuzxfzbbzxa@alap3.anarazel.de
[3]: /messages/by-id/78C0107E-62F2-4F76-BFD8-34C73B716944@anarazel.de

--
With Regards,
Amit Kapila.

#211Heikki Linnakangas
hlinnaka@iki.fi
In reply to: Amit Kapila (#210)
Re: Parallel copy

On 02/11/2020 08:14, Amit Kapila wrote:

On Fri, Oct 30, 2020 at 10:11 PM Heikki Linnakangas <hlinnaka@iki.fi> wrote:

Leader process:

The leader process is simple. It picks the next FREE buffer, fills it
with raw data from the file, and marks it as FILLED. If no buffers are
FREE, wait.

Worker process:

1. Claim next READY block from queue, by changing its state to
PROCESSING. If the next block is not READY yet, wait until it is.

2. Start scanning the block from 'startpos', finding end-of-line
markers. (in CSV mode, need to track when we're in-quotes).

3. When you reach the end of the block, if the last line continues to
next block, wait for the next block to become FILLED. Peek into the
next block, and copy the remaining part of the split line to a local
buffer, and set the 'startpos' on the next block to point to the end
of the split line. Mark the next block as READY.

4. Process all the lines in the block, call input functions, insert
rows.

5. Mark the block as DONE.

In this design, you don't need to keep line boundaries in shared memory,
because each worker process is responsible for finding the line
boundaries of its own block.

There's a point of serialization here, in that the next block cannot be
processed, until the worker working on the previous block has finished
scanning the EOLs, and set the starting position on the next block,
putting it in READY state. That's not very different from your patch,
where you had a similar point of serialization because the leader
scanned the EOLs,

But in the design (single producer multiple consumer) used by the
patch the worker doesn't need to wait till the complete block is
processed, it can start processing the lines already found. This will
also allow workers to start much earlier to process the data as it
doesn't need to wait for all the offsets corresponding to 64K block
ready. However, in the design where each worker is processing the 64K
block, it can lead to much longer waits. I think this will impact the
Copy STDIN case more where in most cases (200-300 bytes tuples) we
receive line-by-line from client and find the line-endings by leader.
If the leader doesn't find the line-endings the workers need to wait
till the leader fill the entire 64K chunk, OTOH, with current approach
the worker can start as soon as leader is able to populate some
minimum number of line-endings

You can use a smaller block size. However, the point of parallel copy is
to maximize bandwidth. If the workers ever have to sit idle, it means
that the bottleneck is in receiving data from the client, i.e. the
backend is fast enough, and you can't make the overall COPY finish any
faster no matter how you do it.

The other point is that the leader backend won't be used completely as
it is only doing a very small part (primarily reading the file) of the
overall work.

An idle process doesn't cost anything. If you have free CPU resources,
use more workers.

We have discussed both these approaches (a) single producer multiple
consumer, and (b) all workers doing the processing as you are saying
in the beginning and concluded that (a) is better, see some of the
relevant emails [1][2][3].

[1] - /messages/by-id/20200413201633.cki4nsptynq7blhg@alap3.anarazel.de
[2] - /messages/by-id/20200415181913.4gjqcnuzxfzbbzxa@alap3.anarazel.de
[3] - /messages/by-id/78C0107E-62F2-4F76-BFD8-34C73B716944@anarazel.de

Sorry I'm late to the party. I don't think the design I proposed was
discussed in that threads. The alternative that's discussed in that
thread seems to be something much more fine-grained, where processes
claim individual lines. I'm not sure though, I didn't fully understand
the alternative designs.

I want to throw out one more idea. It's an interim step, not the final
solution we want, but a useful step in getting there:

Have the leader process scan the input for line-endings. Split the input
data into blocks of slightly under 64 kB in size, so that a line never
crosses a block. Put the blocks in shared memory.

A worker process claims a block from shared memory, processes it from
beginning to end. It *also* has to parse the input to split it into lines.

In this design, the line-splitting is done twice. That's clearly not
optimal, and we want to avoid that in the final patch, but I think it
would be a useful milestone. After that patch is done, write another
patch to either a) implement the design I sketched, where blocks are
fixed-size and a worker notifies the next worker on where the first line
in next block begins, or b) have the leader process report the
line-ending positions in shared memory, so that workers don't need to
scan them again.

Even if we apply the patches together, I think splitting them like that
would make for easier review.

- Heikki

#212Heikki Linnakangas
hlinnaka@iki.fi
In reply to: Heikki Linnakangas (#211)
Re: Parallel copy

On 02/11/2020 09:10, Heikki Linnakangas wrote:

On 02/11/2020 08:14, Amit Kapila wrote:

We have discussed both these approaches (a) single producer multiple
consumer, and (b) all workers doing the processing as you are saying
in the beginning and concluded that (a) is better, see some of the
relevant emails [1][2][3].

[1] - /messages/by-id/20200413201633.cki4nsptynq7blhg@alap3.anarazel.de
[2] - /messages/by-id/20200415181913.4gjqcnuzxfzbbzxa@alap3.anarazel.de
[3] - /messages/by-id/78C0107E-62F2-4F76-BFD8-34C73B716944@anarazel.de

Sorry I'm late to the party. I don't think the design I proposed was
discussed in that threads. The alternative that's discussed in that
thread seems to be something much more fine-grained, where processes
claim individual lines. I'm not sure though, I didn't fully understand
the alternative designs.

I read the thread more carefully, and I think Robert had basically the
right idea here
(/messages/by-id/CA+TgmoZMU4az9MmdJtg04pjRa0wmWQtmoMxttdxNrupYJNcR3w@mail.gmail.com):

I really think we don't want a single worker in charge of finding
tuple boundaries for everybody. That adds a lot of unnecessary
inter-process communication and synchronization. Each process should
just get the next tuple starting after where the last one ended, and
then advance the end pointer so that the next process can do the same
thing. [...]

And here
(/messages/by-id/CA+TgmoZw+F3y+oaxEsHEZBxdL1x1KAJ7pRMNgCqX0WjmjGNLrA@mail.gmail.com):

On Thu, Apr 9, 2020 at 2:55 PM Andres Freund

<andres(at)anarazel(dot)de> wrote:

I'm fairly certain that we do *not* want to distribute input data
between processes on a single tuple basis. Probably not even below
a few

hundred kb. If there's any sort of natural clustering in the loaded data
- extremely common, think timestamps - splitting on a granular basis
will make indexing much more expensive. And have a lot more contention.

That's a fair point. I think the solution ought to be that once any
process starts finding line endings, it continues until it's grabbed
at least a certain amount of data for itself. Then it stops and lets
some other process grab a chunk of data.

Yes! That's pretty close to the design I sketched. I imagined that the
leader would divide the input into 64 kB blocks, and each block would
have few metadata fields, notably the starting position of the first
line in the block. I think Robert envisioned having a single "next
starting position" field in shared memory. That works too, and is even
simpler, so +1 for that.

For some reason, the discussion took a different turn from there, to
discuss how the line-endings (called "chunks" in the discussion) should
be represented in shared memory. But none of that is necessary with
Robert's design.

- Heikki

#213Amit Kapila
amit.kapila16@gmail.com
In reply to: Heikki Linnakangas (#211)
Re: Parallel copy

On Mon, Nov 2, 2020 at 12:40 PM Heikki Linnakangas <hlinnaka@iki.fi> wrote:

On 02/11/2020 08:14, Amit Kapila wrote:

On Fri, Oct 30, 2020 at 10:11 PM Heikki Linnakangas <hlinnaka@iki.fi> wrote:

In this design, you don't need to keep line boundaries in shared memory,
because each worker process is responsible for finding the line
boundaries of its own block.

There's a point of serialization here, in that the next block cannot be
processed, until the worker working on the previous block has finished
scanning the EOLs, and set the starting position on the next block,
putting it in READY state. That's not very different from your patch,
where you had a similar point of serialization because the leader
scanned the EOLs,

But in the design (single producer multiple consumer) used by the
patch the worker doesn't need to wait till the complete block is
processed, it can start processing the lines already found. This will
also allow workers to start much earlier to process the data as it
doesn't need to wait for all the offsets corresponding to 64K block
ready. However, in the design where each worker is processing the 64K
block, it can lead to much longer waits. I think this will impact the
Copy STDIN case more where in most cases (200-300 bytes tuples) we
receive line-by-line from client and find the line-endings by leader.
If the leader doesn't find the line-endings the workers need to wait
till the leader fill the entire 64K chunk, OTOH, with current approach
the worker can start as soon as leader is able to populate some
minimum number of line-endings

You can use a smaller block size.

Sure, but the same problem can happen if the last line in that block
is too long and we need to peek into the next block. And then there
could be cases where a single line could be greater than 64K.

However, the point of parallel copy is
to maximize bandwidth.

Okay, but this first-phase (finding the line boundaries) can anyway be
not done in parallel and we have seen in some of the initial
benchmarking that this initial phase is a small part of work
especially when the table has indexes, constraints, etc. So, I think
it won't matter much if this splitting is done in a single process or
multiple processes.

If the workers ever have to sit idle, it means
that the bottleneck is in receiving data from the client, i.e. the
backend is fast enough, and you can't make the overall COPY finish any
faster no matter how you do it.

The other point is that the leader backend won't be used completely as
it is only doing a very small part (primarily reading the file) of the
overall work.

An idle process doesn't cost anything. If you have free CPU resources,
use more workers.

We have discussed both these approaches (a) single producer multiple
consumer, and (b) all workers doing the processing as you are saying
in the beginning and concluded that (a) is better, see some of the
relevant emails [1][2][3].

[1] - /messages/by-id/20200413201633.cki4nsptynq7blhg@alap3.anarazel.de
[2] - /messages/by-id/20200415181913.4gjqcnuzxfzbbzxa@alap3.anarazel.de
[3] - /messages/by-id/78C0107E-62F2-4F76-BFD8-34C73B716944@anarazel.de

Sorry I'm late to the party. I don't think the design I proposed was
discussed in that threads.

I think something close to that is discussed as you have noticed in
your next email but IIRC, because many people (Andres, Ants, myself
and author) favoured the current approach (single reader and multiple
consumers) we decided to go with that. I feel this patch is very much
in the POC stage due to which the code doesn't look good and as we
move forward we need to see what is the better way to improve it,
maybe one of the ways is to split it as you are suggesting so that it
can be easier to review. I think the other important thing which this
patch has not addressed properly is the parallel-safety checks as
pointed by me earlier. There are two things to solve there (a) the
lower-level code (like heap_* APIs, CommandCounterIncrement, xact.c
APIs, etc.) have checks which doesn't allow any writes, we need to see
which of those we can open now (or do some additional work to prevent
from those checks) after some of the work done for parallel-writes in
PG-13[1]85f6b49 Allow relation extension lock to conflict among parallel group members[2]3ba59cc Allow page lock to conflict among parallel group members, and (b) in which all cases we can parallel-writes
(parallel copy) is allowed, for example need to identify whether table
or one of its partitions has any constraint/expression which is
parallel-unsafe.

[1]: 85f6b49 Allow relation extension lock to conflict among parallel group members
group members
[2]: 3ba59cc Allow page lock to conflict among parallel group members

I want to throw out one more idea. It's an interim step, not the final
solution we want, but a useful step in getting there:

Have the leader process scan the input for line-endings. Split the input
data into blocks of slightly under 64 kB in size, so that a line never
crosses a block. Put the blocks in shared memory.

A worker process claims a block from shared memory, processes it from
beginning to end. It *also* has to parse the input to split it into lines.

In this design, the line-splitting is done twice. That's clearly not
optimal, and we want to avoid that in the final patch, but I think it
would be a useful milestone. After that patch is done, write another
patch to either a) implement the design I sketched, where blocks are
fixed-size and a worker notifies the next worker on where the first line
in next block begins, or b) have the leader process report the
line-ending positions in shared memory, so that workers don't need to
scan them again.

Even if we apply the patches together, I think splitting them like that
would make for easier review.

I think this is worth exploring especially if it makes the patch
easier to review.

--
With Regards,
Amit Kapila.

#214Heikki Linnakangas
hlinnaka@iki.fi
In reply to: Amit Kapila (#213)
Re: Parallel copy

On 03/11/2020 10:59, Amit Kapila wrote:

On Mon, Nov 2, 2020 at 12:40 PM Heikki Linnakangas <hlinnaka@iki.fi> wrote:

However, the point of parallel copy is to maximize bandwidth.

Okay, but this first-phase (finding the line boundaries) can anyway
be not done in parallel and we have seen in some of the initial
benchmarking that this initial phase is a small part of work
especially when the table has indexes, constraints, etc. So, I think
it won't matter much if this splitting is done in a single process
or multiple processes.

Right, it won't matter performance-wise. That's not my point. The
difference is in the complexity. If you don't store the line boundaries
in shared memory, you get away with much simpler shared memory structures.

I think something close to that is discussed as you have noticed in
your next email but IIRC, because many people (Andres, Ants, myself
and author) favoured the current approach (single reader and multiple
consumers) we decided to go with that. I feel this patch is very much
in the POC stage due to which the code doesn't look good and as we
move forward we need to see what is the better way to improve it,
maybe one of the ways is to split it as you are suggesting so that it
can be easier to review.

Sure. I think the roadmap here is:

1. Split copy.c [1]/messages/by-id/8e15b560-f387-7acc-ac90-763986617bfb@iki.fi. Not strictly necessary, but I think it'd make this
nice to review and work with.

2. Refactor CopyReadLine(), so that finding the line-endings and the
rest of the line-parsing are separated into separate functions.

3. Implement parallel copy.

I think the other important thing which this
patch has not addressed properly is the parallel-safety checks as
pointed by me earlier. There are two things to solve there (a) the
lower-level code (like heap_* APIs, CommandCounterIncrement, xact.c
APIs, etc.) have checks which doesn't allow any writes, we need to see
which of those we can open now (or do some additional work to prevent
from those checks) after some of the work done for parallel-writes in
PG-13[1][2], and (b) in which all cases we can parallel-writes
(parallel copy) is allowed, for example need to identify whether table
or one of its partitions has any constraint/expression which is
parallel-unsafe.

Agreed, that needs to be solved. I haven't given it any thought myself.

- Heikki

[1]: /messages/by-id/8e15b560-f387-7acc-ac90-763986617bfb@iki.fi
/messages/by-id/8e15b560-f387-7acc-ac90-763986617bfb@iki.fi

#215Hou, Zhijie
houzj.fnst@cn.fujitsu.com
In reply to: Heikki Linnakangas (#208)
RE: Parallel copy

Hi

my $bytes = $ARGV[0];
for(my $i = 0; $i < $bytes; $i+=8){
print "longdata";
}
print "\n";
--------

postgres=# copy longdata from program 'perl /tmp/longdata.pl 100000000'
with (parallel 2);

This gets stuck forever (or at least I didn't have the patience to wait
it finish). Both worker processes are consuming 100% of CPU.

I had a look over this problem.

the ParallelCopyDataBlock has size limit:
uint8 skip_bytes;
char data[DATA_BLOCK_SIZE]; /* data read from file */

It seems the input line is so long that the leader process run out of the Shared memory among parallel copy workers.
And the leader process keep waiting free block.

For the worker process, it wait util line_state becomes LINE_LEADER_POPULATED,
But leader process won't set the line_state unless it read the whole line.

So it stuck forever.
May be we should reconsider about this situation.

The stack is as follows:

Leader stack:
#3 0x000000000075f7a1 in WaitLatch (latch=<optimized out>, wakeEvents=wakeEvents@entry=41, timeout=timeout@entry=1, wait_event_info=wait_event_info@entry=150994945) at latch.c:411
#4 0x00000000005a9245 in WaitGetFreeCopyBlock (pcshared_info=pcshared_info@entry=0x7f26d2ed3580) at copyparallel.c:1546
#5 0x00000000005a98ce in SetRawBufForLoad (cstate=cstate@entry=0x2978a88, line_size=67108864, copy_buf_len=copy_buf_len@entry=65536, raw_buf_ptr=raw_buf_ptr@entry=65536,
copy_raw_buf=copy_raw_buf@entry=0x7fff4cdc0e18) at copyparallel.c:1572
#6 0x00000000005a1963 in CopyReadLineText (cstate=cstate@entry=0x2978a88) at copy.c:4058
#7 0x00000000005a4e76 in CopyReadLine (cstate=cstate@entry=0x2978a88) at copy.c:3863

Worker stack:
#0 GetLinePosition (cstate=cstate@entry=0x29e1f28) at copyparallel.c:1474
#1 0x00000000005a8aa4 in CacheLineInfo (cstate=cstate@entry=0x29e1f28, buff_count=buff_count@entry=0) at copyparallel.c:711
#2 0x00000000005a8e46 in GetWorkerLine (cstate=cstate@entry=0x29e1f28) at copyparallel.c:885
#3 0x00000000005a4f2e in NextCopyFromRawFields (cstate=cstate@entry=0x29e1f28, fields=fields@entry=0x7fff4cdc0b48, nfields=nfields@entry=0x7fff4cdc0b44) at copy.c:3615
#4 0x00000000005a50af in NextCopyFrom (cstate=cstate@entry=0x29e1f28, econtext=econtext@entry=0x2a358d8, values=0x2a42068, nulls=0x2a42070) at copy.c:3696
#5 0x00000000005a5b90 in CopyFrom (cstate=cstate@entry=0x29e1f28) at copy.c:2985

Best regards,
houzj

#216vignesh C
vignesh21@gmail.com
In reply to: Hou, Zhijie (#215)
Re: Parallel copy

On Thu, Nov 5, 2020 at 6:33 PM Hou, Zhijie <houzj.fnst@cn.fujitsu.com> wrote:

Hi

my $bytes = $ARGV[0];
for(my $i = 0; $i < $bytes; $i+=8){
print "longdata";
}
print "\n";
--------

postgres=# copy longdata from program 'perl /tmp/longdata.pl 100000000'
with (parallel 2);

This gets stuck forever (or at least I didn't have the patience to wait
it finish). Both worker processes are consuming 100% of CPU.

I had a look over this problem.

the ParallelCopyDataBlock has size limit:
uint8 skip_bytes;
char data[DATA_BLOCK_SIZE]; /* data read from file */

It seems the input line is so long that the leader process run out of the Shared memory among parallel copy workers.
And the leader process keep waiting free block.

For the worker process, it wait util line_state becomes LINE_LEADER_POPULATED,
But leader process won't set the line_state unless it read the whole line.

So it stuck forever.
May be we should reconsider about this situation.

The stack is as follows:

Leader stack:
#3 0x000000000075f7a1 in WaitLatch (latch=<optimized out>, wakeEvents=wakeEvents@entry=41, timeout=timeout@entry=1, wait_event_info=wait_event_info@entry=150994945) at latch.c:411
#4 0x00000000005a9245 in WaitGetFreeCopyBlock (pcshared_info=pcshared_info@entry=0x7f26d2ed3580) at copyparallel.c:1546
#5 0x00000000005a98ce in SetRawBufForLoad (cstate=cstate@entry=0x2978a88, line_size=67108864, copy_buf_len=copy_buf_len@entry=65536, raw_buf_ptr=raw_buf_ptr@entry=65536,
copy_raw_buf=copy_raw_buf@entry=0x7fff4cdc0e18) at copyparallel.c:1572
#6 0x00000000005a1963 in CopyReadLineText (cstate=cstate@entry=0x2978a88) at copy.c:4058
#7 0x00000000005a4e76 in CopyReadLine (cstate=cstate@entry=0x2978a88) at copy.c:3863

Worker stack:
#0 GetLinePosition (cstate=cstate@entry=0x29e1f28) at copyparallel.c:1474
#1 0x00000000005a8aa4 in CacheLineInfo (cstate=cstate@entry=0x29e1f28, buff_count=buff_count@entry=0) at copyparallel.c:711
#2 0x00000000005a8e46 in GetWorkerLine (cstate=cstate@entry=0x29e1f28) at copyparallel.c:885
#3 0x00000000005a4f2e in NextCopyFromRawFields (cstate=cstate@entry=0x29e1f28, fields=fields@entry=0x7fff4cdc0b48, nfields=nfields@entry=0x7fff4cdc0b44) at copy.c:3615
#4 0x00000000005a50af in NextCopyFrom (cstate=cstate@entry=0x29e1f28, econtext=econtext@entry=0x2a358d8, values=0x2a42068, nulls=0x2a42070) at copy.c:3696
#5 0x00000000005a5b90 in CopyFrom (cstate=cstate@entry=0x29e1f28) at copy.c:2985

Thanks for providing your thoughts. I have analyzed this issue and I'm
working on the fix for this, I will be posting a patch for this
shortly.

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

#217vignesh C
vignesh21@gmail.com
In reply to: Amit Kapila (#213)
1 attachment(s)
Re: Parallel copy

On Tue, Nov 3, 2020 at 2:28 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Mon, Nov 2, 2020 at 12:40 PM Heikki Linnakangas <hlinnaka@iki.fi> wrote:

On 02/11/2020 08:14, Amit Kapila wrote:

On Fri, Oct 30, 2020 at 10:11 PM Heikki Linnakangas <hlinnaka@iki.fi> wrote:

In this design, you don't need to keep line boundaries in shared memory,
because each worker process is responsible for finding the line
boundaries of its own block.

There's a point of serialization here, in that the next block cannot be
processed, until the worker working on the previous block has finished
scanning the EOLs, and set the starting position on the next block,
putting it in READY state. That's not very different from your patch,
where you had a similar point of serialization because the leader
scanned the EOLs,

But in the design (single producer multiple consumer) used by the
patch the worker doesn't need to wait till the complete block is
processed, it can start processing the lines already found. This will
also allow workers to start much earlier to process the data as it
doesn't need to wait for all the offsets corresponding to 64K block
ready. However, in the design where each worker is processing the 64K
block, it can lead to much longer waits. I think this will impact the
Copy STDIN case more where in most cases (200-300 bytes tuples) we
receive line-by-line from client and find the line-endings by leader.
If the leader doesn't find the line-endings the workers need to wait
till the leader fill the entire 64K chunk, OTOH, with current approach
the worker can start as soon as leader is able to populate some
minimum number of line-endings

You can use a smaller block size.

Sure, but the same problem can happen if the last line in that block
is too long and we need to peek into the next block. And then there
could be cases where a single line could be greater than 64K.

However, the point of parallel copy is
to maximize bandwidth.

Okay, but this first-phase (finding the line boundaries) can anyway be
not done in parallel and we have seen in some of the initial
benchmarking that this initial phase is a small part of work
especially when the table has indexes, constraints, etc. So, I think
it won't matter much if this splitting is done in a single process or
multiple processes.

If the workers ever have to sit idle, it means
that the bottleneck is in receiving data from the client, i.e. the
backend is fast enough, and you can't make the overall COPY finish any
faster no matter how you do it.

The other point is that the leader backend won't be used completely as
it is only doing a very small part (primarily reading the file) of the
overall work.

An idle process doesn't cost anything. If you have free CPU resources,
use more workers.

We have discussed both these approaches (a) single producer multiple
consumer, and (b) all workers doing the processing as you are saying
in the beginning and concluded that (a) is better, see some of the
relevant emails [1][2][3].

[1] - /messages/by-id/20200413201633.cki4nsptynq7blhg@alap3.anarazel.de
[2] - /messages/by-id/20200415181913.4gjqcnuzxfzbbzxa@alap3.anarazel.de
[3] - /messages/by-id/78C0107E-62F2-4F76-BFD8-34C73B716944@anarazel.de

Sorry I'm late to the party. I don't think the design I proposed was
discussed in that threads.

I think something close to that is discussed as you have noticed in
your next email but IIRC, because many people (Andres, Ants, myself
and author) favoured the current approach (single reader and multiple
consumers) we decided to go with that. I feel this patch is very much
in the POC stage due to which the code doesn't look good and as we
move forward we need to see what is the better way to improve it,
maybe one of the ways is to split it as you are suggesting so that it
can be easier to review. I think the other important thing which this
patch has not addressed properly is the parallel-safety checks as
pointed by me earlier. There are two things to solve there (a) the
lower-level code (like heap_* APIs, CommandCounterIncrement, xact.c
APIs, etc.) have checks which doesn't allow any writes, we need to see
which of those we can open now (or do some additional work to prevent
from those checks) after some of the work done for parallel-writes in
PG-13[1][2], and (b) in which all cases we can parallel-writes
(parallel copy) is allowed, for example need to identify whether table
or one of its partitions has any constraint/expression which is
parallel-unsafe.

I have worked to provide a patch for the parallel safety checks. It
checks if parallely copy can be performed, Parallel copy cannot be
performed for the following a) If relation is temporary table b) If
relation is foreign table c) If relation has non parallel safe index
expressions d) If relation has triggers present whose type is of non
before statement trigger type e) If relation has check constraint
which are not parallel safe f) If relation has partition and any
partition has the above type. This patch has the checks for it. This
patch will be used by parallel copy implementation.
Thoughts?

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

Attachments:

WIP-Check-if-parallel-copy-can-be-performed.patchtext/x-patch; charset=US-ASCII; name=WIP-Check-if-parallel-copy-can-be-performed.patchDownload
From 18b5efabc5cf82870c8b5d015f78f4b7d3fe18ef Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Tue, 10 Nov 2020 18:24:09 +0530
Subject: [PATCH v10 2/6] Check if parallel copy can be performed.

Checks if parallely copy can be performed, Parallel copy cannot be performed
for the following a) If relation is temporary table b) If relation is foreign
table c) If relation has non parallel safe index expressions d) If relation has
triggers present whose type is of non before statement trigger type e) If
relation has check constraint which are not parallel safe f) If relation
has partition and any partition has the above type. This patch has the
checks for it. This patch will be used by parallel copy implementation patch.
---
 src/backend/access/heap/heapam.c     |  11 -
 src/backend/access/transam/xact.c    |  26 ++-
 src/backend/commands/Makefile        |   1 +
 src/backend/commands/copyparallel.c  | 103 +++++++++
 src/backend/optimizer/util/clauses.c | 405 +++++++++++++++++++++++++++++++++++
 src/include/access/xact.h            |   1 +
 src/include/commands/copy.h          |   2 +
 src/include/optimizer/clauses.h      |   1 +
 8 files changed, 534 insertions(+), 16 deletions(-)
 create mode 100644 src/backend/commands/copyparallel.c

diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 1585861..1602525 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2043,17 +2043,6 @@ static HeapTuple
 heap_prepare_insert(Relation relation, HeapTuple tup, TransactionId xid,
 					CommandId cid, int options)
 {
-	/*
-	 * To allow parallel inserts, we need to ensure that they are safe to be
-	 * performed in workers. We have the infrastructure to allow parallel
-	 * inserts in general except for the cases where inserts generate a new
-	 * CommandId (eg. inserts into a table having a foreign key column).
-	 */
-	if (IsParallelWorker())
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_TRANSACTION_STATE),
-				 errmsg("cannot insert tuples in a parallel worker")));
-
 	tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
 	tup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK);
 	tup->t_data->t_infomask |= HEAP_XMAX_INVALID;
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index af6afce..d6d449f 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -764,18 +764,34 @@ GetCurrentCommandId(bool used)
 	if (used)
 	{
 		/*
-		 * Forbid setting currentCommandIdUsed in a parallel worker, because
-		 * we have no provision for communicating this back to the leader.  We
-		 * could relax this restriction when currentCommandIdUsed was already
-		 * true at the start of the parallel operation.
+		 * If in a parallel worker, only allow setting currentCommandIdUsed
+		 * if currentCommandIdUsed was already true at the start of the
+		 * parallel operation (by way of SetCurrentCommandIdUsed()), otherwise
+		 * forbid setting currentCommandIdUsed because we have no provision
+		 * for communicating this back to the leader.
 		 */
-		Assert(!IsParallelWorker());
+		Assert(!(IsParallelWorker() && !currentCommandIdUsed));
 		currentCommandIdUsed = true;
 	}
 	return currentCommandId;
 }
 
 /*
+ *	SetCurrentCommandIdUsedForWorker
+ *
+ * For a parallel worker, record that the currentCommandId has been used.
+ * This must only be called at the start of a parallel operation.
+ */
+void
+SetCurrentCommandIdUsedForWorker(void)
+{
+	Assert(IsParallelWorker() && !currentCommandIdUsed &&
+		   (currentCommandId != InvalidCommandId));
+
+	currentCommandIdUsed = true;
+}
+
+/*
  *	SetParallelStartTimestamps
  *
  * In a parallel worker, we should inherit the parent transaction's
diff --git a/src/backend/commands/Makefile b/src/backend/commands/Makefile
index d4815d3..a224aac 100644
--- a/src/backend/commands/Makefile
+++ b/src/backend/commands/Makefile
@@ -24,6 +24,7 @@ OBJS = \
 	constraint.o \
 	conversioncmds.o \
 	copy.o \
+	copyparallel.o \
 	createas.o \
 	dbcommands.o \
 	define.o \
diff --git a/src/backend/commands/copyparallel.c b/src/backend/commands/copyparallel.c
new file mode 100644
index 0000000..290d532
--- /dev/null
+++ b/src/backend/commands/copyparallel.c
@@ -0,0 +1,103 @@
+/*-------------------------------------------------------------------------
+ *
+ * copyparallel.c
+ *              Implements the Parallel COPY utility command
+ *
+ * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *        src/backend/commands/copyparallel.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/heapam.h"
+#include "catalog/pg_proc_d.h"
+#include "commands/copy.h"
+#include "libpq/libpq.h"
+#include "optimizer/clauses.h"
+#include "optimizer/optimizer.h"
+#include "pgstat.h"
+#include "utils/lsyscache.h"
+
+/*
+ * CheckExprParallelSafety
+ *
+ * Determine if where cluase and default expressions are parallel safe & do not
+ * have volatile expressions, return true if condition satisfies else return
+ * false.
+ */
+static bool
+CheckExprParallelSafety(CopyState cstate)
+{
+	if (max_parallel_hazard((Query *) cstate->whereClause) != PROPARALLEL_SAFE)
+		return false;
+
+	/*
+	 * Can't support parallel copy if there are any volatile function
+	 * expressions in WHERE clause as such expressions may query the table
+	 * we're inserting into.
+	 */
+	if (contain_volatile_functions(cstate->whereClause))
+		return false;
+
+	/*
+	 * Check if any of the column has default expression. if yes, and they are
+	 * not parallel safe, then parallelism is not allowed. For instance, if
+	 * there are any serial/bigserial columns for which nextval() default
+	 * expression which is parallel unsafe is associated, parallelism should
+	 * not be allowed.
+	 */
+	if (cstate->defexprs != NULL && cstate->num_defaults != 0)
+	{
+		int			i;
+
+		for (i = 0; i < cstate->num_defaults; i++)
+		{
+			if (max_parallel_hazard((Query *) cstate->defexprs[i]->expr) !=
+				PROPARALLEL_SAFE)
+				return false;
+
+			/*
+			 * Can't support parallel copy if there are any volatile function
+			 * expressions in default expressions as such expressions may
+			 * query the table we're inserting into.
+			 */
+			if (contain_volatile_functions((Node *) cstate->defexprs[i]->expr))
+				return false;
+		}
+	}
+
+	return true;
+}
+
+/*
+ * IsParallelCopyAllowed
+ *
+ * Check if parallel copy can be allowed.
+ */
+bool
+IsParallelCopyAllowed(CopyState cstate, Oid relid)
+{
+	/*
+	 * Check if parallel operation can be performed based on local
+	 * table/foreign table/index/check constraints/triggers present for the
+	 * relation and also by doing similar checks recursively for each of the
+	 * associated parrtitions if exists.
+	 */
+	if (MaxParallelHazardForModify(relid) != PROPARALLEL_SAFE)
+		return false;
+
+	/*
+	 * If there are volatile default expressions or where clause contain
+	 * volatile expressions, allow parallelism if they are parallel safe,
+	 * otherwise not.
+	 */
+	if (!CheckExprParallelSafety(cstate))
+		return false;
+
+	return true;
+}
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 85ef873..c82f5f2 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -20,12 +20,19 @@
 #include "postgres.h"
 
 #include "access/htup_details.h"
+#include "access/genam.h"
+#include "access/table.h"
+#include "catalog/index.h"
+#include "catalog/indexing.h"
 #include "catalog/pg_aggregate.h"
 #include "catalog/pg_class.h"
+#include "catalog/pg_constraint.h"
+#include "catalog/pg_constraint_d.h"
 #include "catalog/pg_language.h"
 #include "catalog/pg_operator.h"
 #include "catalog/pg_proc.h"
 #include "catalog/pg_type.h"
+#include "commands/trigger.h"
 #include "executor/executor.h"
 #include "executor/functions.h"
 #include "funcapi.h"
@@ -42,7 +49,9 @@
 #include "parser/parse_agg.h"
 #include "parser/parse_coerce.h"
 #include "parser/parse_func.h"
+#include "partitioning/partdesc.h"
 #include "rewrite/rewriteManip.h"
+#include "storage/lmgr.h"
 #include "tcop/tcopprot.h"
 #include "utils/acl.h"
 #include "utils/builtins.h"
@@ -50,6 +59,7 @@
 #include "utils/fmgroids.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
+#include "utils/partcache.h"
 #include "utils/syscache.h"
 #include "utils/typcache.h"
 
@@ -1073,6 +1083,401 @@ max_parallel_hazard_walker(Node *node, max_parallel_hazard_context *context)
 								  context);
 }
 
+/*
+ * MaxTriggerDataParallelHazardForModify
+ *
+ * Finds the maximum parallel-mode hazard level for the specified trigger data.
+ */
+static char
+MaxTriggerDataParallelHazardForModify(TriggerDesc *trigdesc,
+									  max_parallel_hazard_context *context)
+{
+	int			i;
+
+	/*
+	 * When transition tables are involved (if after statement triggers are
+	 * present), we collect minimal tuples in the tuple store after processing
+	 * them so that later after statement triggers can access them.  Now, if
+	 * we want to enable parallelism for such cases, we instead need to store
+	 * and access tuples from shared tuple store.  However, it does not have
+	 * the facility to store tuples in-memory, so we always need to store and
+	 * access from a file which could be costly unless we also have an
+	 * additional way to store minimal tuples in shared memory till work_mem
+	 * and then in shared tuple store. It is possible to do all this to enable
+	 * parallel copy for such cases. Currently, we can disallow parallelism
+	 * for such cases and later allow if required.
+	 *
+	 * When there are BEFORE/AFTER/INSTEAD OF row triggers on the table. We do
+	 * not allow parallelism in such cases because such triggers might query
+	 * the table we are inserting into and act differently if the tuples that
+	 * have already been processed and prepared for insertion are not there.
+	 * Now, if we allow parallelism with such triggers the behaviour would
+	 * depend on if the parallel worker has already inserted or not that
+	 * particular tuples.
+	 */
+	if (trigdesc->trig_insert_after_statement ||
+		trigdesc->trig_insert_new_table ||
+		trigdesc->trig_insert_before_row ||
+		trigdesc->trig_insert_after_row ||
+		trigdesc->trig_insert_instead_row)
+	{
+		context->max_hazard = PROPARALLEL_UNSAFE;
+		return context->max_hazard;
+	}
+
+	for (i = 0; i < trigdesc->numtriggers; i++)
+	{
+		Trigger    *trigger = &trigdesc->triggers[i];
+		int			trigtype;
+
+		/*
+		 * If the trigger type is RI_TRIGGER_FK, this indicates a FK exists in
+		 * the relation, and this would result in creation of new CommandIds
+		 * on insert/update/delete and this isn't supported in a parallel
+		 * worker (but is safe in the parallel leader).
+		 */
+		trigtype = RI_FKey_trigger_type(trigger->tgfoid);
+
+		/*
+		 * No parallelism if foreign key check trigger is present. This is
+		 * because, while performing foreign key checks, we take KEY SHARE
+		 * lock on primary key table rows which inturn will increment the
+		 * command counter and updates the snapshot.  Since we share the
+		 * snapshots at the beginning of the command, we can't allow it to be
+		 * changed later. So, unless we do something special for it, we can't
+		 * allow parallelism in such cases.
+		 */
+		if (trigtype == RI_TRIGGER_FK)
+		{
+			context->max_hazard = PROPARALLEL_UNSAFE;
+			return context->max_hazard;
+		}
+	}
+
+	return context->max_hazard;
+}
+
+/*
+ * MaxIndexExprsParallelHazardForModify
+ *
+ * Finds the maximum parallel-mode hazard level for any existing index
+ * expressions of a specified relation.
+ */
+static char
+MaxIndexExprsParallelHazardForModify(Relation rel,
+									 max_parallel_hazard_context *context)
+{
+	List	   *indexOidList;
+	ListCell   *lc;
+	LOCKMODE	lockmode = AccessShareLock;
+
+	indexOidList = RelationGetIndexList(rel);
+	foreach(lc, indexOidList)
+	{
+		Oid			indexOid = lfirst_oid(lc);
+		Relation	indexRel;
+		IndexInfo  *indexInfo;
+
+		if (ConditionalLockRelationOid(indexOid, lockmode))
+		{
+			indexRel = index_open(indexOid, NoLock);
+		}
+		else
+		{
+			context->max_hazard = PROPARALLEL_UNSAFE;
+			return context->max_hazard;
+		}
+
+		indexInfo = BuildIndexInfo(indexRel);
+
+		if (indexInfo->ii_Expressions != NIL)
+		{
+			int			i;
+			ListCell   *indexExprItem = list_head(indexInfo->ii_Expressions);
+
+			for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
+			{
+				int			keycol = indexInfo->ii_IndexAttrNumbers[i];
+
+				if (keycol == 0)
+				{
+					/* Found an index expression */
+
+					Node	   *indexExpr;
+
+					if (indexExprItem == NULL)	/* shouldn't happen */
+						elog(ERROR, "too few entries in indexprs list");
+
+					indexExpr = (Node *) lfirst(indexExprItem);
+					indexExpr = (Node *) expression_planner((Expr *) indexExpr);
+
+					if (max_parallel_hazard_walker(indexExpr, context))
+					{
+						index_close(indexRel, lockmode);
+						return context->max_hazard;
+					}
+
+					indexExprItem = lnext(indexInfo->ii_Expressions, indexExprItem);
+				}
+			}
+		}
+		index_close(indexRel, lockmode);
+	}
+
+	return context->max_hazard;
+}
+
+/*
+ * MaxDomainParallelHazardForModify
+ *
+ * Finds the maximum parallel-mode hazard level for the specified DOMAIN type.
+ * Only any CHECK expressions are examined for parallel safety.
+ * DEFAULT values of DOMAIN-type columns in the target-list are already
+ * being checked for parallel-safety in the max_parallel_hazard() scan of the
+ * query tree in standard_planner().
+ *
+ */
+static char
+MaxDomainParallelHazardForModify(Oid typid, max_parallel_hazard_context *context)
+{
+	Relation	conRel;
+	ScanKeyData key[1];
+	SysScanDesc scan;
+	HeapTuple	tup;
+
+	LOCKMODE	lockmode = AccessShareLock;
+
+	conRel = table_open(ConstraintRelationId, lockmode);
+
+	ScanKeyInit(&key[0],
+				Anum_pg_constraint_contypid, BTEqualStrategyNumber,
+				F_OIDEQ, ObjectIdGetDatum(typid));
+	scan = systable_beginscan(conRel, ConstraintTypidIndexId, true,
+							  NULL, 1, key);
+
+	while (HeapTupleIsValid((tup = systable_getnext(scan))))
+	{
+		Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup);
+
+		if (con->contype == CONSTRAINT_CHECK)
+		{
+			char	   *conbin;
+			Datum		val;
+			bool		isnull;
+			Expr	   *checkExpr;
+
+			val = SysCacheGetAttr(CONSTROID, tup,
+								  Anum_pg_constraint_conbin, &isnull);
+			if (isnull)
+				elog(ERROR, "null conbin for constraint %u", con->oid);
+			conbin = TextDatumGetCString(val);
+			checkExpr = stringToNode(conbin);
+			if (max_parallel_hazard_walker((Node *) checkExpr, context))
+			{
+				break;
+			}
+		}
+	}
+
+	systable_endscan(scan);
+	table_close(conRel, lockmode);
+	return context->max_hazard;
+}
+
+/*
+ * MaxRelParallelHazardForModify
+ *
+ * Determines the maximum parallel-mode hazard level for modification
+ * of a specified relation.
+ */
+static char
+MaxRelParallelHazardForModify(Oid relid, max_parallel_hazard_context *context)
+{
+	Relation	rel;
+	TupleDesc	tupdesc;
+	int			attnum;
+
+	LOCKMODE	lockmode = AccessShareLock;
+
+	/*
+	 * It's possible that this relation is locked for exclusive access in
+	 * another concurrent transaction (e.g. as a result of a ALTER TABLE ...
+	 * operation) until that transaction completes. If a share-lock can't be
+	 * acquired on it now, we have to assume this could be the worst-case, so
+	 * to avoid blocking here until that transaction completes, conditionally
+	 * try to acquire the lock and assume and return UNSAFE on failure.
+	 */
+	if (ConditionalLockRelationOid(relid, lockmode))
+	{
+		rel = table_open(relid, NoLock);
+	}
+	else
+	{
+		context->max_hazard = PROPARALLEL_UNSAFE;
+		return context->max_hazard;
+	}
+
+	/*
+	 * Check if copy is into foreign table. We can not allow parallelism in
+	 * this case because each worker needs to establish FDW connection and
+	 * operate in a separate transaction. Unless we have a capability to
+	 * provide two-phase commit protocol, we can not allow parallelism.
+	 *
+	 * Also check if copy is into temporary table. Since parallel workers can
+	 * not access temporary table, parallelism is not allowed.
+	 */
+	if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
+		RelationUsesLocalBuffers(rel))
+	{
+		table_close(rel, lockmode);
+		context->max_hazard = PROPARALLEL_UNSAFE;
+		return context->max_hazard;
+	}
+
+	/*
+	 * If a partitioned table, check that each partition is safe for
+	 * modification in parallel-mode.
+	 */
+	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+	{
+		int			i;
+		PartitionDesc pdesc;
+		PartitionKey pkey;
+		ListCell   *partexprs_item;
+		int			partnatts;
+		List	   *partexprs;
+
+		pkey = RelationGetPartitionKey(rel);
+
+		partnatts = get_partition_natts(pkey);
+		partexprs = get_partition_exprs(pkey);
+
+		partexprs_item = list_head(partexprs);
+		for (i = 0; i < partnatts; i++)
+		{
+			/* Check parallel-safety of partition key support functions */
+			if (OidIsValid(pkey->partsupfunc[i].fn_oid))
+			{
+				if (max_parallel_hazard_test(func_parallel(pkey->partsupfunc[i].fn_oid), context))
+				{
+					table_close(rel, lockmode);
+					return context->max_hazard;
+				}
+			}
+
+			/* Check parallel-safety of any expressions in the partition key */
+			if (get_partition_col_attnum(pkey, i) == 0)
+			{
+				Node	   *checkExpr = (Node *) lfirst(partexprs_item);
+
+				if (max_parallel_hazard_walker(checkExpr, context))
+				{
+					table_close(rel, lockmode);
+					return context->max_hazard;
+				}
+
+				partexprs_item = lnext(partexprs, partexprs_item);
+			}
+		}
+
+		/* Recursively check each partition ... */
+		pdesc = RelationGetPartitionDesc(rel);
+		for (i = 0; i < pdesc->nparts; i++)
+		{
+			if (MaxRelParallelHazardForModify(pdesc->oids[i], context) != PROPARALLEL_SAFE)
+			{
+				table_close(rel, lockmode);
+				return context->max_hazard;
+			}
+		}
+	}
+
+	/*
+	 * If there are any index expressions, check that they are parallel-mode
+	 * safe.
+	 */
+	if (MaxIndexExprsParallelHazardForModify(rel, context) != PROPARALLEL_SAFE)
+	{
+		table_close(rel, lockmode);
+		return context->max_hazard;
+	}
+
+	/*
+	 * If any triggers exist, check that they are parallel safe.
+	 */
+	if (rel->trigdesc != NULL &&
+		MaxTriggerDataParallelHazardForModify(rel->trigdesc, context) != PROPARALLEL_SAFE)
+	{
+		table_close(rel, lockmode);
+		return context->max_hazard;
+	}
+
+	tupdesc = RelationGetDescr(rel);
+	for (attnum = 0; attnum < tupdesc->natts; attnum++)
+	{
+		Form_pg_attribute att = TupleDescAttr(tupdesc, attnum);
+
+		/* We don't need info for dropped or generated attributes */
+		if (att->attisdropped || att->attgenerated)
+			continue;
+
+		/*
+		 * If the column is of a DOMAIN type, determine whether that domain
+		 * has any CHECK expressions that are not parallel-mode safe.
+		 */
+		if (get_typtype(att->atttypid) == TYPTYPE_DOMAIN)
+		{
+			if (MaxDomainParallelHazardForModify(att->atttypid, context) != PROPARALLEL_SAFE)
+			{
+				table_close(rel, lockmode);
+				return context->max_hazard;
+			}
+		}
+	}
+
+	/*
+	 * Check if there are any CHECK constraints which are not parallel-safe.
+	 */
+	if (tupdesc->constr != NULL && tupdesc->constr->num_check > 0)
+	{
+		int			i;
+
+		ConstrCheck *check = tupdesc->constr->check;
+
+		for (i = 0; i < tupdesc->constr->num_check; i++)
+		{
+			Expr	   *checkExpr = stringToNode(check->ccbin);
+
+			if (max_parallel_hazard_walker((Node *) checkExpr, context))
+			{
+				table_close(rel, lockmode);
+				return context->max_hazard;
+			}
+		}
+	}
+
+	table_close(rel, lockmode);
+	return context->max_hazard;
+}
+
+/*
+ * MaxParallelHazardForModify
+ *
+ * Determines the worst parallel-mode hazard level for the specified
+ * relation. The search returns the earliest in the following list:
+ * PROPARALLEL_UNSAFE, PROPARALLEL_RESTRICTED, PROPARALLEL_SAFE
+ */
+char
+MaxParallelHazardForModify(Oid relid)
+{
+	max_parallel_hazard_context context;
+
+	context.max_hazard = PROPARALLEL_SAFE;
+	context.max_interesting = PROPARALLEL_RESTRICTED;
+	context.safe_param_ids = NIL;
+
+	return (MaxRelParallelHazardForModify(relid, &context));
+}
 
 /*****************************************************************************
  *		Check clauses for nonstrict functions
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index 7320de3..42d4893 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -386,6 +386,7 @@ extern FullTransactionId GetTopFullTransactionId(void);
 extern FullTransactionId GetTopFullTransactionIdIfAny(void);
 extern FullTransactionId GetCurrentFullTransactionId(void);
 extern FullTransactionId GetCurrentFullTransactionIdIfAny(void);
+extern void SetCurrentCommandIdUsedForWorker(void);
 extern void MarkCurrentTransactionIdLoggedIfAny(void);
 extern bool SubTransactionIsActive(SubTransactionId subxid);
 extern CommandId GetCurrentCommandId(bool used);
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index b9331af..fd3a78e 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -38,4 +38,6 @@ extern uint64 CopyFrom(CopyState cstate);
 
 extern DestReceiver *CreateCopyDestReceiver(void);
 
+extern bool IsParallelCopyAllowed(CopyState cstate, Oid relid);
+
 #endif							/* COPY_H */
diff --git a/src/include/optimizer/clauses.h b/src/include/optimizer/clauses.h
index 7ef8cce..f515de1 100644
--- a/src/include/optimizer/clauses.h
+++ b/src/include/optimizer/clauses.h
@@ -55,5 +55,6 @@ extern void CommuteOpExpr(OpExpr *clause);
 
 extern Query *inline_set_returning_function(PlannerInfo *root,
 											RangeTblEntry *rte);
+extern char MaxParallelHazardForModify(Oid relid);
 
 #endif							/* CLAUSES_H */
-- 
1.8.3.1

#218Amit Kapila
amit.kapila16@gmail.com
In reply to: vignesh C (#217)
Re: Parallel copy

On Tue, Nov 10, 2020 at 7:12 PM vignesh C <vignesh21@gmail.com> wrote:

On Tue, Nov 3, 2020 at 2:28 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

I have worked to provide a patch for the parallel safety checks. It
checks if parallely copy can be performed, Parallel copy cannot be
performed for the following a) If relation is temporary table b) If
relation is foreign table c) If relation has non parallel safe index
expressions d) If relation has triggers present whose type is of non
before statement trigger type e) If relation has check constraint
which are not parallel safe f) If relation has partition and any
partition has the above type. This patch has the checks for it. This
patch will be used by parallel copy implementation.

How did you ensure that this is sufficient? For parallel-insert's
patch we have enabled parallel-mode for Inserts and ran the tests with
force_parallel_mode to see if we are not missing anything. Also, it
seems there are many common things here w.r.t parallel-insert patch,
is it possible to prepare this atop that patch or do you have any
reason to keep this separate?

--
With Regards,
Amit Kapila.

#219vignesh C
vignesh21@gmail.com
In reply to: Amit Kapila (#218)
Re: Parallel copy

On Tue, Nov 10, 2020 at 7:27 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Tue, Nov 10, 2020 at 7:12 PM vignesh C <vignesh21@gmail.com> wrote:

On Tue, Nov 3, 2020 at 2:28 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

I have worked to provide a patch for the parallel safety checks. It
checks if parallely copy can be performed, Parallel copy cannot be
performed for the following a) If relation is temporary table b) If
relation is foreign table c) If relation has non parallel safe index
expressions d) If relation has triggers present whose type is of non
before statement trigger type e) If relation has check constraint
which are not parallel safe f) If relation has partition and any
partition has the above type. This patch has the checks for it. This
patch will be used by parallel copy implementation.

How did you ensure that this is sufficient? For parallel-insert's
patch we have enabled parallel-mode for Inserts and ran the tests with
force_parallel_mode to see if we are not missing anything. Also, it
seems there are many common things here w.r.t parallel-insert patch,
is it possible to prepare this atop that patch or do you have any
reason to keep this separate?

I have done similar testing for copy too, I had set force_parallel
mode to regress, hardcoded in the code to pick parallel workers for
copy operation and ran make installcheck-world to verify. Many checks
in this patch are common between both patches, but I was not sure how
to handle it as both the projects are in-progress and are being
updated based on the reviewer's opinion. How to handle this?
Thoughts?

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

#220Amit Kapila
amit.kapila16@gmail.com
In reply to: vignesh C (#219)
Re: Parallel copy

On Wed, Nov 11, 2020 at 10:42 PM vignesh C <vignesh21@gmail.com> wrote:

On Tue, Nov 10, 2020 at 7:27 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Tue, Nov 10, 2020 at 7:12 PM vignesh C <vignesh21@gmail.com> wrote:

On Tue, Nov 3, 2020 at 2:28 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

I have worked to provide a patch for the parallel safety checks. It
checks if parallely copy can be performed, Parallel copy cannot be
performed for the following a) If relation is temporary table b) If
relation is foreign table c) If relation has non parallel safe index
expressions d) If relation has triggers present whose type is of non
before statement trigger type e) If relation has check constraint
which are not parallel safe f) If relation has partition and any
partition has the above type. This patch has the checks for it. This
patch will be used by parallel copy implementation.

How did you ensure that this is sufficient? For parallel-insert's
patch we have enabled parallel-mode for Inserts and ran the tests with
force_parallel_mode to see if we are not missing anything. Also, it
seems there are many common things here w.r.t parallel-insert patch,
is it possible to prepare this atop that patch or do you have any
reason to keep this separate?

I have done similar testing for copy too, I had set force_parallel
mode to regress, hardcoded in the code to pick parallel workers for
copy operation and ran make installcheck-world to verify. Many checks
in this patch are common between both patches, but I was not sure how
to handle it as both the projects are in-progress and are being
updated based on the reviewer's opinion. How to handle this?
Thoughts?

I have not studied the differences in detail but if it is possible to
prepare it on top of that patch then there shouldn't be a problem. To
avoid confusion if you want you can always either post the latest
version of that patch with your patch or point to it.

--
With Regards,
Amit Kapila.

#221Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: Amit Kapila (#202)
Re: Parallel copy

On Thu, Oct 29, 2020 at 2:54 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

4) Worker has to hop through all the processed chunks before getting
the chunk which it can process.

One more point, I have noticed that some time back [1], I have given
one suggestion related to the way workers process the set of lines
(aka chunk). I think you can try by increasing the chunk size to say
100, 500, 1000 and use some shared counter to remember the number of
chunks processed.

Hi, I did some analysis on using spinlock protected worker write position
i.e. each worker acquires spinlock on a shared write position to choose the
next available chunk vs each worker hops to get the next available chunk
position:

Use Case: 10mn rows, 5.6GB data, 2 indexes on integer columns, 1 index on
text column, results are of the form (no of workers, total exec time in
sec, index insertion time in sec, worker write pos get time in sec, buffer
contention event count):

With spinlock:
(1,1126.443,1060.067,0.478,*0*), (2,669.343,630.769,0.306,*26*),
(4,346.297,326.950,0.161,*89*), (8,209.600,196.417,0.088,*291*),
(16,166.113,157.086,0.065,*1468*), (20,173.884,166.013,0.067,*2700*),
(30,173.087,1166.565,0.0065,*5346*)
Without spinlock:
(1,1119.695,1054.586,0.496,*0*), (2,645.733,608.313,1.5,*8*),
(4,340.620,320.344,1.6,*58*), (8,203.985,189.644,1.3,*222*),
(16,142.997,133.045,1,*813*), (20,132.621,122.527,1.1,*1215*),
(30,135.737,126.716,1.5,*2901*)

With spinlock each worker is getting the required write position quickly
and proceeding further till the index insertion(which is becoming a single
point of contention) where we observed more buffer lock contention. Reason
is that all the workers are reaching the index insertion point at the
similar time.

Without spinlock, each worker is spending some time in hopping to get the
write position, by the time the other workers are inserting into the
indexes. So basically, all the workers are not reaching the index insertion
point at the same time and hence less buffer lock contention.

The same behaviour(explained above) is observed with different worker chunk
count(default 64, 128, 512 and 1024) i.e. the number of tuples each worker
caches into its local memory before inserting into table.

In summary: with spinlock, it looks like we are able to avoid workers
waiting to get the next chunk, which also means that we are not creating
any contention point inside the parallel copy code. However this is causing
another choking point i.e. index insertion if indexes are available on the
table, which is out of scope of parallel copy code. We think that it would
be good to use spinlock-protected worker write position or an atomic
variable for worker write position(as it performs equal to spinlock or
little better in some platforms). Thoughts?

With Regards,
Bharath Rupireddy.
EnterpriseDB: http://www.enterprisedb.com

#222vignesh C
vignesh21@gmail.com
In reply to: Amit Kapila (#199)
6 attachment(s)
Re: Parallel copy

On Thu, Oct 29, 2020 at 11:45 AM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Tue, Oct 27, 2020 at 7:06 PM vignesh C <vignesh21@gmail.com> wrote:

[latest version]

I think the parallel-safety checks in this patch
(v9-0002-Allow-copy-from-command-to-process-data-from-file) are
incomplete and wrong. See below comments.
1.
+static pg_attribute_always_inline bool
+CheckExprParallelSafety(CopyState cstate)
+{
+ if (contain_volatile_functions(cstate->whereClause))
+ {
+ if (max_parallel_hazard((Query *) cstate->whereClause) != PROPARALLEL_SAFE)
+ return false;
+ }

I don't understand the above check. Why do we only need to check where
clause for parallel-safety when it contains volatile functions? It
should be checked otherwise as well, no? The similar comment applies
to other checks in this function. Also, I don't think there is a need
to make this function inline.

I felt we should check if where clause is parallel safe and also check
if it does not contain volatile function, this is to avoid cases where
expressions may query the table we're inserting into. Modified it
accordingly.

2.
+/*
+ * IsParallelCopyAllowed
+ *
+ * Check if parallel copy can be allowed.
+ */
+bool
+IsParallelCopyAllowed(CopyState cstate)
{
..
+ * When there are BEFORE/AFTER/INSTEAD OF row triggers on the table. We do
+ * not allow parallelism in such cases because such triggers might query
+ * the table we are inserting into and act differently if the tuples that
+ * have already been processed and prepared for insertion are not there.
+ * Now, if we allow parallelism with such triggers the behaviour would
+ * depend on if the parallel worker has already inserted or not that
+ * particular tuples.
+ */
+ if (cstate->rel->trigdesc != NULL &&
+ (cstate->rel->trigdesc->trig_insert_after_statement ||
+ cstate->rel->trigdesc->trig_insert_new_table ||
+ cstate->rel->trigdesc->trig_insert_before_row ||
+ cstate->rel->trigdesc->trig_insert_after_row ||
+ cstate->rel->trigdesc->trig_insert_instead_row))
+ return false;
..

Why do we need to disable parallelism for before/after row triggers
unless they have parallel-unsafe functions? I see a few lines down in
this function you are checking parallel-safety of trigger functions,
what is the use of the same if you are already disabling parallelism
with the above check.

Currently only before statement trigger is supported, rest of the
triggers are not supported, comments for the same is mentioned atop of
the checks. Removed the parallel safe check which was not required.

3. What about if the index on table has expressions that are
parallel-unsafe? What is your strategy to check parallel-safety for
partitioned tables?

I suggest checking Greg's patch for parallel-safety of Inserts [1]. I
think you will find that most of those checks are required here as
well and see how we can use that patch (at least what is common). I
feel the first patch should be just to have parallel-safety checks and
we can test that by trying to enable Copy with force_parallel_mode. We
can build the rest of the patch atop of it or in other words, let's
move all parallel-safety work into a separate patch.

I have made this as a separate patch as of now. I will work on to see
if I can use Greg's changes as it is or if require I will provide few
review comments on top of Greg's patch so that it is usable for
parallel copy too and later post a separate patch with the changes on
top of it. I will retain it as a separate patch till that time.

Few assorted comments:
========================
1.
+/*
+ * ESTIMATE_NODE_SIZE - Estimate the size required for  node type in shared
+ * memory.
+ */
+#define ESTIMATE_NODE_SIZE(list, listStr, strsize) \
+{ \
+ uint32 estsize = sizeof(uint32); \
+ if ((List *)list != NIL) \
+ { \
+ listStr = nodeToString(list); \
+ estsize += strlen(listStr) + 1; \
+ } \
+ \
+ strsize = add_size(strsize, estsize); \
+}

This can be probably a function instead of a macro.

Changed it to a function.

2.
+/*
+ * ESTIMATE_1BYTE_STR_SIZE - Estimate the size required for  1Byte strings in
+ * shared memory.
+ */
+#define ESTIMATE_1BYTE_STR_SIZE(src, strsize) \
+{ \
+ strsize = add_size(strsize, sizeof(uint8)); \
+ strsize = add_size(strsize, (src) ? 1 : 0); \
+}

This could be an inline function.

Changed it to an inline function.

3.
+/*
+ * SERIALIZE_1BYTE_STR - Copy 1Byte strings to shared memory.
+ */
+#define SERIALIZE_1BYTE_STR(dest, src, copiedsize) \
+{ \
+ uint8 len = (src) ? 1 : 0; \
+ memcpy(dest + copiedsize, (uint8 *) &len, sizeof(uint8)); \
+ copiedsize += sizeof(uint8); \
+ if (src) \
+ dest[copiedsize++] = src[0]; \
+}

Similarly, this could be a function. I think keeping such things as
macros in-between code makes it difficult to read. Please see if you
can make these and similar macros as functions unless they are doing
few memory instructions. Having functions makes it easier to debug the
code as well.

Changed it to a function.

Attached v10 patch has the fixes for the same.

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

Attachments:

v10-0001-Copy-code-readjustment-to-support-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=v10-0001-Copy-code-readjustment-to-support-parallel-copy.patchDownload
From 0c36c6d33ab95c7d31471d2bb7cc63205633f8da Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Tue, 27 Oct 2020 13:36:54 +0530
Subject: [PATCH v10 1/6] Copy code readjustment to support parallel copy.

This patch has the copy code slightly readjusted so that the common code is
separated to functions/macros, these functions/macros will be used by the
workers in the parallel copy code of the upcoming patches. EOL removal is moved
from CopyReadLine to CopyReadLineText, this change was required because in case
of parallel copy the record identification and record updation is done in
CopyReadLineText, before record information is updated in shared memory the new
line characters should be removed.
---
 src/backend/commands/copy.c          | 503 ++++++++++++++---------------------
 src/include/commands/copy.h          |   5 +-
 src/include/commands/copy_internal.h | 198 ++++++++++++++
 3 files changed, 395 insertions(+), 311 deletions(-)
 create mode 100644 src/include/commands/copy_internal.h

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 115860a..3b26fc5 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -29,9 +29,7 @@
 #include "catalog/pg_type.h"
 #include "commands/copy.h"
 #include "commands/defrem.h"
-#include "commands/trigger.h"
 #include "executor/execPartition.h"
-#include "executor/executor.h"
 #include "executor/nodeModifyTable.h"
 #include "executor/tuptable.h"
 #include "foreign/fdwapi.h"
@@ -62,176 +60,6 @@
 #define ISOCTAL(c) (((c) >= '0') && ((c) <= '7'))
 #define OCTVALUE(c) ((c) - '0')
 
-/*
- * Represents the different source/dest cases we need to worry about at
- * the bottom level
- */
-typedef enum CopyDest
-{
-	COPY_FILE,					/* to/from file (or a piped program) */
-	COPY_OLD_FE,				/* to/from frontend (2.0 protocol) */
-	COPY_NEW_FE,				/* to/from frontend (3.0 protocol) */
-	COPY_CALLBACK				/* to/from callback function */
-} CopyDest;
-
-/*
- *	Represents the end-of-line terminator type of the input
- */
-typedef enum EolType
-{
-	EOL_UNKNOWN,
-	EOL_NL,
-	EOL_CR,
-	EOL_CRNL
-} EolType;
-
-/*
- * Represents the heap insert method to be used during COPY FROM.
- */
-typedef enum CopyInsertMethod
-{
-	CIM_SINGLE,					/* use table_tuple_insert or fdw routine */
-	CIM_MULTI,					/* always use table_multi_insert */
-	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
-} CopyInsertMethod;
-
-/*
- * This struct contains all the state variables used throughout a COPY
- * operation. For simplicity, we use the same struct for all variants of COPY,
- * even though some fields are used in only some cases.
- *
- * Multi-byte encodings: all supported client-side encodings encode multi-byte
- * characters by having the first byte's high bit set. Subsequent bytes of the
- * character can have the high bit not set. When scanning data in such an
- * encoding to look for a match to a single-byte (ie ASCII) character, we must
- * use the full pg_encoding_mblen() machinery to skip over multibyte
- * characters, else we might find a false match to a trailing byte. In
- * supported server encodings, there is no possibility of a false match, and
- * it's faster to make useless comparisons to trailing bytes than it is to
- * invoke pg_encoding_mblen() to skip over them. encoding_embeds_ascii is true
- * when we have to do it the hard way.
- */
-typedef struct CopyStateData
-{
-	/* low-level state data */
-	CopyDest	copy_dest;		/* type of copy source/destination */
-	FILE	   *copy_file;		/* used if copy_dest == COPY_FILE */
-	StringInfo	fe_msgbuf;		/* used for all dests during COPY TO, only for
-								 * dest == COPY_NEW_FE in COPY FROM */
-	bool		is_copy_from;	/* COPY TO, or COPY FROM? */
-	bool		reached_eof;	/* true if we read to end of copy data (not
-								 * all copy_dest types maintain this) */
-	EolType		eol_type;		/* EOL type of input */
-	int			file_encoding;	/* file or remote side's character encoding */
-	bool		need_transcoding;	/* file encoding diff from server? */
-	bool		encoding_embeds_ascii;	/* ASCII can be non-first byte? */
-
-	/* parameters from the COPY command */
-	Relation	rel;			/* relation to copy to or from */
-	QueryDesc  *queryDesc;		/* executable query to copy from */
-	List	   *attnumlist;		/* integer list of attnums to copy */
-	char	   *filename;		/* filename, or NULL for STDIN/STDOUT */
-	bool		is_program;		/* is 'filename' a program to popen? */
-	copy_data_source_cb data_source_cb; /* function for reading data */
-	bool		binary;			/* binary format? */
-	bool		freeze;			/* freeze rows on loading? */
-	bool		csv_mode;		/* Comma Separated Value format? */
-	bool		header_line;	/* CSV header line? */
-	char	   *null_print;		/* NULL marker string (server encoding!) */
-	int			null_print_len; /* length of same */
-	char	   *null_print_client;	/* same converted to file encoding */
-	char	   *delim;			/* column delimiter (must be 1 byte) */
-	char	   *quote;			/* CSV quote char (must be 1 byte) */
-	char	   *escape;			/* CSV escape char (must be 1 byte) */
-	List	   *force_quote;	/* list of column names */
-	bool		force_quote_all;	/* FORCE_QUOTE *? */
-	bool	   *force_quote_flags;	/* per-column CSV FQ flags */
-	List	   *force_notnull;	/* list of column names */
-	bool	   *force_notnull_flags;	/* per-column CSV FNN flags */
-	List	   *force_null;		/* list of column names */
-	bool	   *force_null_flags;	/* per-column CSV FN flags */
-	bool		convert_selectively;	/* do selective binary conversion? */
-	List	   *convert_select; /* list of column names (can be NIL) */
-	bool	   *convert_select_flags;	/* per-column CSV/TEXT CS flags */
-	Node	   *whereClause;	/* WHERE condition (or NULL) */
-
-	/* these are just for error messages, see CopyFromErrorCallback */
-	const char *cur_relname;	/* table name for error messages */
-	uint64		cur_lineno;		/* line number for error messages */
-	const char *cur_attname;	/* current att for error messages */
-	const char *cur_attval;		/* current att value for error messages */
-
-	/*
-	 * Working state for COPY TO/FROM
-	 */
-	MemoryContext copycontext;	/* per-copy execution context */
-
-	/*
-	 * Working state for COPY TO
-	 */
-	FmgrInfo   *out_functions;	/* lookup info for output functions */
-	MemoryContext rowcontext;	/* per-row evaluation context */
-
-	/*
-	 * Working state for COPY FROM
-	 */
-	AttrNumber	num_defaults;
-	FmgrInfo   *in_functions;	/* array of input functions for each attrs */
-	Oid		   *typioparams;	/* array of element types for in_functions */
-	int		   *defmap;			/* array of default att numbers */
-	ExprState **defexprs;		/* array of default att expressions */
-	bool		volatile_defexprs;	/* is any of defexprs volatile? */
-	List	   *range_table;
-	ExprState  *qualexpr;
-
-	TransitionCaptureState *transition_capture;
-
-	/*
-	 * These variables are used to reduce overhead in COPY FROM.
-	 *
-	 * attribute_buf holds the separated, de-escaped text for each field of
-	 * the current line.  The CopyReadAttributes functions return arrays of
-	 * pointers into this buffer.  We avoid palloc/pfree overhead by re-using
-	 * the buffer on each cycle.
-	 *
-	 * In binary COPY FROM, attribute_buf holds the binary data for the
-	 * current field, but the usage is otherwise similar.
-	 */
-	StringInfoData attribute_buf;
-
-	/* field raw data pointers found by COPY FROM */
-
-	int			max_fields;
-	char	  **raw_fields;
-
-	/*
-	 * Similarly, line_buf holds the whole input line being processed. The
-	 * input cycle is first to read the whole line into line_buf, convert it
-	 * to server encoding there, and then extract the individual attribute
-	 * fields into attribute_buf.  line_buf is preserved unmodified so that we
-	 * can display it in error messages if appropriate.  (In binary mode,
-	 * line_buf is not used.)
-	 */
-	StringInfoData line_buf;
-	bool		line_buf_converted; /* converted to server encoding? */
-	bool		line_buf_valid; /* contains the row being processed? */
-
-	/*
-	 * Finally, raw_buf holds raw data read from the data source (file or
-	 * client connection).  In text mode, CopyReadLine parses this data
-	 * sufficiently to locate line boundaries, then transfers the data to
-	 * line_buf and converts it.  In binary mode, CopyReadBinaryData fetches
-	 * appropriate amounts of data from this buffer.  In both modes, we
-	 * guarantee that there is a \0 at raw_buf[raw_buf_len].
-	 */
-#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
-	char	   *raw_buf;
-	int			raw_buf_index;	/* next byte to process */
-	int			raw_buf_len;	/* total # of bytes stored */
-	/* Shorthand for number of unconsumed bytes available in raw_buf */
-#define RAW_BUF_BYTES(cstate) ((cstate)->raw_buf_len - (cstate)->raw_buf_index)
-} CopyStateData;
-
 /* DestReceiver for COPY (query) TO */
 typedef struct
 {
@@ -288,7 +116,6 @@ typedef struct CopyMultiInsertInfo
 	int			ti_options;		/* table insert options */
 } CopyMultiInsertInfo;
 
-
 /*
  * These macros centralize code used to process line_buf and raw_buf buffers.
  * They are macros because they often do continue/break control and to avoid
@@ -401,6 +228,12 @@ static bool CopyGetInt16(CopyState cstate, int16 *val);
 static bool CopyLoadRawBuf(CopyState cstate);
 static int	CopyReadBinaryData(CopyState cstate, char *dest, int nbytes);
 
+static void PopulateCommonCStateInfo(CopyState cstate, TupleDesc tup_desc,
+									 List *attnamelist);
+static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
+								   int copy_line_pos, int *copy_line_size);
+static void ConvertToServerEncoding(CopyState cstate);
+
 
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
@@ -1518,7 +1351,6 @@ BeginCopy(ParseState *pstate,
 {
 	CopyState	cstate;
 	TupleDesc	tupDesc;
-	int			num_phys_attrs;
 	MemoryContext oldcontext;
 
 	/* Allocate workspace and zero all fields */
@@ -1684,6 +1516,25 @@ BeginCopy(ParseState *pstate,
 		tupDesc = cstate->queryDesc->tupDesc;
 	}
 
+	PopulateCommonCStateInfo(cstate, tupDesc, attnamelist);
+	cstate->copy_dest = COPY_FILE;	/* default */
+
+	MemoryContextSwitchTo(oldcontext);
+
+	return cstate;
+}
+
+/*
+ * PopulateCommonCStateInfo
+ *
+ * Populates the common variables required for copy from operation. This is a
+ * helper function for BeginCopy function.
+ */
+static void
+PopulateCommonCStateInfo(CopyState cstate, TupleDesc tupDesc, List *attnamelist)
+{
+	int			num_phys_attrs;
+
 	/* Generate or convert list of attributes to process */
 	cstate->attnumlist = CopyGetAttnums(tupDesc, cstate->rel, attnamelist);
 
@@ -1803,12 +1654,6 @@ BeginCopy(ParseState *pstate,
 		 pg_database_encoding_max_length() > 1);
 	/* See Multibyte encoding comment above */
 	cstate->encoding_embeds_ascii = PG_ENCODING_IS_CLIENT_ONLY(cstate->file_encoding);
-
-	cstate->copy_dest = COPY_FILE;	/* default */
-
-	MemoryContextSwitchTo(oldcontext);
-
-	return cstate;
 }
 
 /*
@@ -2698,32 +2543,13 @@ CopyMultiInsertInfoStore(CopyMultiInsertInfo *miinfo, ResultRelInfo *rri,
 }
 
 /*
- * Copy FROM file to relation.
+ * CheckTargetRelValidity
+ *
+ * Check if the relation specified in copy from is valid.
  */
-uint64
-CopyFrom(CopyState cstate)
+static void
+CheckTargetRelValidity(CopyState cstate)
 {
-	ResultRelInfo *resultRelInfo;
-	ResultRelInfo *target_resultRelInfo;
-	ResultRelInfo *prevResultRelInfo = NULL;
-	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
-	ModifyTableState *mtstate;
-	ExprContext *econtext;
-	TupleTableSlot *singleslot = NULL;
-	MemoryContext oldcontext = CurrentMemoryContext;
-
-	PartitionTupleRouting *proute = NULL;
-	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
-	int			ti_options = 0; /* start with default options for insert */
-	BulkInsertState bistate = NULL;
-	CopyInsertMethod insertMethod;
-	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
-	uint64		processed = 0;
-	bool		has_before_insert_row_trig;
-	bool		has_instead_insert_row_trig;
-	bool		leafpart_use_multi_insert = false;
-
 	Assert(cstate->rel);
 	Assert(list_length(cstate->range_table) == 1);
 
@@ -2761,27 +2587,6 @@ CopyFrom(CopyState cstate)
 							RelationGetRelationName(cstate->rel))));
 	}
 
-	/*
-	 * If the target file is new-in-transaction, we assume that checking FSM
-	 * for free space is a waste of time.  This could possibly be wrong, but
-	 * it's unlikely.
-	 */
-	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
-		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
-		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
-		ti_options |= TABLE_INSERT_SKIP_FSM;
-
-	/*
-	 * Optimize if new relfilenode was created in this subxact or one of its
-	 * committed children and we won't see those rows later as part of an
-	 * earlier scan or command. The subxact test ensures that if this subxact
-	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
-	 * that the stronger test of exactly which subtransaction created it is
-	 * crucial for correctness of this optimization. The test for an earlier
-	 * scan or command tolerates false negatives. FREEZE causes other sessions
-	 * to see rows they would not see under MVCC, and a false negative merely
-	 * spreads that anomaly to the current session.
-	 */
 	if (cstate->freeze)
 	{
 		/*
@@ -2819,9 +2624,61 @@ CopyFrom(CopyState cstate)
 			ereport(ERROR,
 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 					 errmsg("cannot perform COPY FREEZE because the table was not created or truncated in the current subtransaction")));
+	}
+}
+
+/*
+ * Copy FROM file to relation.
+ */
+uint64
+CopyFrom(CopyState cstate)
+{
+	ResultRelInfo *resultRelInfo;
+	ResultRelInfo *target_resultRelInfo;
+	ResultRelInfo *prevResultRelInfo = NULL;
+	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
+	ModifyTableState *mtstate;
+	ExprContext *econtext;
+	TupleTableSlot *singleslot = NULL;
+	MemoryContext oldcontext = CurrentMemoryContext;
+
+	PartitionTupleRouting *proute = NULL;
+	ErrorContextCallback errcallback;
+	CommandId	mycid = GetCurrentCommandId(true);
+	int			ti_options = 0; /* start with default options for insert */
+	BulkInsertState bistate = NULL;
+	CopyInsertMethod insertMethod;
+	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
+	uint64		processed = 0;
+	bool		has_before_insert_row_trig;
+	bool		has_instead_insert_row_trig;
+	bool		leafpart_use_multi_insert = false;
+
+	CheckTargetRelValidity(cstate);
+
+	/*
+	 * If the target file is new-in-transaction, we assume that checking FSM
+	 * for free space is a waste of time.  This could possibly be wrong, but
+	 * it's unlikely.
+	 */
+	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
+		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
+		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
+		ti_options |= TABLE_INSERT_SKIP_FSM;
 
+	/*
+	 * Optimize if new relfilenode was created in this subxact or one of its
+	 * committed children and we won't see those rows later as part of an
+	 * earlier scan or command. The subxact test ensures that if this subxact
+	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
+	 * that the stronger test of exactly which subtransaction created it is
+	 * crucial for correctness of this optimization. The test for an earlier
+	 * scan or command tolerates false negatives. FREEZE causes other sessions
+	 * to see rows they would not see under MVCC, and a false negative merely
+	 * spreads that anomaly to the current session.
+	 */
+	if (cstate->freeze)
 		ti_options |= TABLE_INSERT_FROZEN;
-	}
 
 	/*
 	 * We need a ResultRelInfo so we can use the regular executor's
@@ -3342,26 +3199,13 @@ CopyFrom(CopyState cstate)
 }
 
 /*
- * Setup to read tuples from a file for COPY FROM.
+ * PopulateCStateCatalogInfo
  *
- * 'rel': Used as a template for the tuples
- * 'filename': Name of server-local file to read
- * 'attnamelist': List of char *, columns to include. NIL selects all cols.
- * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
- *
- * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ * Populate the cstate catalog information.
  */
-CopyState
-BeginCopyFrom(ParseState *pstate,
-			  Relation rel,
-			  const char *filename,
-			  bool is_program,
-			  copy_data_source_cb data_source_cb,
-			  List *attnamelist,
-			  List *options)
+static void
+PopulateCStateCatalogInfo(CopyState cstate)
 {
-	CopyState	cstate;
-	bool		pipe = (filename == NULL);
 	TupleDesc	tupDesc;
 	AttrNumber	num_phys_attrs,
 				num_defaults;
@@ -3371,38 +3215,8 @@ BeginCopyFrom(ParseState *pstate,
 	Oid			in_func_oid;
 	int		   *defmap;
 	ExprState **defexprs;
-	MemoryContext oldcontext;
 	bool		volatile_defexprs;
 
-	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
-	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
-
-	/* Initialize state variables */
-	cstate->reached_eof = false;
-	cstate->eol_type = EOL_UNKNOWN;
-	cstate->cur_relname = RelationGetRelationName(cstate->rel);
-	cstate->cur_lineno = 0;
-	cstate->cur_attname = NULL;
-	cstate->cur_attval = NULL;
-
-	/*
-	 * Set up variables to avoid per-attribute overhead.  attribute_buf and
-	 * raw_buf are used in both text and binary modes, but we use line_buf
-	 * only in text mode.
-	 */
-	initStringInfo(&cstate->attribute_buf);
-	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
-	cstate->raw_buf_index = cstate->raw_buf_len = 0;
-	if (!cstate->binary)
-	{
-		initStringInfo(&cstate->line_buf);
-		cstate->line_buf_converted = false;
-	}
-
-	/* Assign range table, we'll need it in CopyFrom. */
-	if (pstate)
-		cstate->range_table = pstate->p_rtable;
-
 	tupDesc = RelationGetDescr(cstate->rel);
 	num_phys_attrs = tupDesc->natts;
 	num_defaults = 0;
@@ -3480,6 +3294,61 @@ BeginCopyFrom(ParseState *pstate,
 	cstate->defexprs = defexprs;
 	cstate->volatile_defexprs = volatile_defexprs;
 	cstate->num_defaults = num_defaults;
+}
+
+/*
+ * Setup to read tuples from a file for COPY FROM.
+ *
+ * 'rel': Used as a template for the tuples
+ * 'filename': Name of server-local file to read
+ * 'attnamelist': List of char *, columns to include. NIL selects all cols.
+ * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
+ *
+ * Returns a CopyState, to be passed to NextCopyFrom and related functions.
+ */
+CopyState
+BeginCopyFrom(ParseState *pstate,
+			  Relation rel,
+			  const char *filename,
+			  bool is_program,
+			  copy_data_source_cb data_source_cb,
+			  List *attnamelist,
+			  List *options)
+{
+	CopyState	cstate;
+	bool		pipe = (filename == NULL);
+	MemoryContext oldcontext;
+
+	cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	/* Initialize state variables */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/*
+	 * Set up variables to avoid per-attribute overhead.  attribute_buf is
+	 * used in both text and binary modes, but we use line_buf and raw_buf
+	 * only in text mode.
+	 */
+	initStringInfo(&cstate->attribute_buf);
+	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+	if (!cstate->binary)
+	{
+		initStringInfo(&cstate->line_buf);
+		cstate->line_buf_converted = false;
+	}
+
+	/* Assign range table, we'll need it in CopyFrom. */
+	if (pstate)
+		cstate->range_table = pstate->p_rtable;
+
+	PopulateCStateCatalogInfo(cstate);
 	cstate->is_program = is_program;
 
 	if (data_source_cb)
@@ -3889,40 +3758,60 @@ CopyReadLine(CopyState cstate)
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
-	else
+
+	ConvertToServerEncoding(cstate);
+	return result;
+}
+
+/*
+ * ClearEOLFromCopiedData
+ *
+ * Clear EOL from the copied data.
+ */
+static void
+ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
+					   int copy_line_pos, int *copy_line_size)
+{
+	/*
+	 * If we didn't hit EOF, then we must have transferred the EOL marker to
+	 * line_buf along with the data.  Get rid of it.
+	 */
+	switch (cstate->eol_type)
 	{
-		/*
-		 * If we didn't hit EOF, then we must have transferred the EOL marker
-		 * to line_buf along with the data.  Get rid of it.
-		 */
-		switch (cstate->eol_type)
-		{
-			case EOL_NL:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CR:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\r');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CRNL:
-				Assert(cstate->line_buf.len >= 2);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 2] == '\r');
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len -= 2;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_UNKNOWN:
-				/* shouldn't get here */
-				Assert(false);
-				break;
-		}
+		case EOL_NL:
+			Assert(*copy_line_size >= 1);
+			Assert(copy_line_data[copy_line_pos - 1] == '\n');
+			copy_line_data[copy_line_pos - 1] = '\0';
+			(*copy_line_size)--;
+			break;
+		case EOL_CR:
+			Assert(*copy_line_size >= 1);
+			Assert(copy_line_data[copy_line_pos - 1] == '\r');
+			copy_line_data[copy_line_pos - 1] = '\0';
+			(*copy_line_size)--;
+			break;
+		case EOL_CRNL:
+			Assert(*copy_line_size >= 2);
+			Assert(copy_line_data[copy_line_pos - 2] == '\r');
+			Assert(copy_line_data[copy_line_pos - 1] == '\n');
+			copy_line_data[copy_line_pos - 2] = '\0';
+			*copy_line_size -= 2;
+			break;
+		case EOL_UNKNOWN:
+			/* shouldn't get here */
+			Assert(false);
+			break;
 	}
+}
 
+/*
+ * ConvertToServerEncoding
+ *
+ * Convert contents to server encoding.
+ */
+static void
+ConvertToServerEncoding(CopyState cstate)
+{
 	/* Done reading the line.  Convert it to server encoding. */
 	if (cstate->need_transcoding)
 	{
@@ -3939,11 +3828,8 @@ CopyReadLine(CopyState cstate)
 			pfree(cvt);
 		}
 	}
-
 	/* Now it's safe to use the buffer in error messages */
 	cstate->line_buf_converted = true;
-
-	return result;
 }
 
 /*
@@ -4306,6 +4192,9 @@ not_end_of_copy:
 	 * Transfer any still-uncopied data to line_buf.
 	 */
 	REFILL_LINEBUF;
+	if (!result && !IsHeaderLine())
+		ClearEOLFromCopiedData(cstate, cstate->line_buf.data,
+							   cstate->line_buf.len, &cstate->line_buf.len);
 
 	return result;
 }
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index c639833..b9331af 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -14,15 +14,12 @@
 #ifndef COPY_H
 #define COPY_H
 
+#include "commands/copy_internal.h"
 #include "nodes/execnodes.h"
 #include "nodes/parsenodes.h"
 #include "parser/parse_node.h"
 #include "tcop/dest.h"
 
-/* CopyStateData is private in commands/copy.c */
-typedef struct CopyStateData *CopyState;
-typedef int (*copy_data_source_cb) (void *outbuf, int minread, int maxread);
-
 extern void DoCopy(ParseState *state, const CopyStmt *stmt,
 				   int stmt_location, int stmt_len,
 				   uint64 *processed);
diff --git a/src/include/commands/copy_internal.h b/src/include/commands/copy_internal.h
new file mode 100644
index 0000000..ea4bfca
--- /dev/null
+++ b/src/include/commands/copy_internal.h
@@ -0,0 +1,198 @@
+/*-------------------------------------------------------------------------
+ *
+ * copy_internal.h
+ *	  Definitions for using the POSTGRES copy command.
+ *
+ *
+ * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/commands/copy_internal.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef COPY_INTERNAL_H
+#define COPY_INTERNAL_H
+
+#include "commands/trigger.h"
+#include "executor/executor.h"
+
+#define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
+
+/*
+ * Represents the different source/dest cases we need to worry about at
+ * the bottom level
+ */
+typedef enum CopyDest
+{
+	COPY_FILE,					/* to/from file (or a piped program) */
+	COPY_OLD_FE,				/* to/from frontend (2.0 protocol) */
+	COPY_NEW_FE,				/* to/from frontend (3.0 protocol) */
+	COPY_CALLBACK				/* to/from callback function */
+} CopyDest;
+
+/*
+ *	Represents the end-of-line terminator type of the input
+ */
+typedef enum EolType
+{
+	EOL_UNKNOWN,
+	EOL_NL,
+	EOL_CR,
+	EOL_CRNL
+} EolType;
+
+/*
+ * Represents the heap insert method to be used during COPY FROM.
+ */
+typedef enum CopyInsertMethod
+{
+	CIM_SINGLE,					/* use table_tuple_insert or fdw routine */
+	CIM_MULTI,					/* always use table_multi_insert */
+	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
+} CopyInsertMethod;
+
+#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+
+typedef int (*copy_data_source_cb) (void *outbuf, int minread, int maxread);
+
+/*
+ * This struct contains all the state variables used throughout a COPY
+ * operation. For simplicity, we use the same struct for all variants of COPY,
+ * even though some fields are used in only some cases.
+ *
+ * Multi-byte encodings: all supported client-side encodings encode multi-byte
+ * characters by having the first byte's high bit set. Subsequent bytes of the
+ * character can have the high bit not set. When scanning data in such an
+ * encoding to look for a match to a single-byte (ie ASCII) character, we must
+ * use the full pg_encoding_mblen() machinery to skip over multibyte
+ * characters, else we might find a false match to a trailing byte. In
+ * supported server encodings, there is no possibility of a false match, and
+ * it's faster to make useless comparisons to trailing bytes than it is to
+ * invoke pg_encoding_mblen() to skip over them. encoding_embeds_ascii is true
+ * when we have to do it the hard way.
+ */
+typedef struct CopyStateData
+{
+	/* low-level state data */
+	CopyDest	copy_dest;		/* type of copy source/destination */
+	FILE	   *copy_file;		/* used if copy_dest == COPY_FILE */
+	StringInfo	fe_msgbuf;		/* used for all dests during COPY TO, only for
+								 * dest == COPY_NEW_FE in COPY FROM */
+	bool		is_copy_from;	/* COPY TO, or COPY FROM? */
+	bool		reached_eof;	/* true if we read to end of copy data (not
+								 * all copy_dest types maintain this) */
+	EolType		eol_type;		/* EOL type of input */
+	int			file_encoding;	/* file or remote side's character encoding */
+	bool		need_transcoding;	/* file encoding diff from server? */
+	bool		encoding_embeds_ascii;	/* ASCII can be non-first byte? */
+
+	/* parameters from the COPY command */
+	Relation	rel;			/* relation to copy to or from */
+	QueryDesc  *queryDesc;		/* executable query to copy from */
+	List	   *attnumlist;		/* integer list of attnums to copy */
+	char	   *filename;		/* filename, or NULL for STDIN/STDOUT */
+	bool		is_program;		/* is 'filename' a program to popen? */
+	copy_data_source_cb data_source_cb; /* function for reading data */
+	bool		binary;			/* binary format? */
+	bool		freeze;			/* freeze rows on loading? */
+	bool		csv_mode;		/* Comma Separated Value format? */
+	bool		header_line;	/* CSV header line? */
+	char	   *null_print;		/* NULL marker string (server encoding!) */
+	int			null_print_len; /* length of same */
+	char	   *null_print_client;	/* same converted to file encoding */
+	char	   *delim;			/* column delimiter (must be 1 byte) */
+	char	   *quote;			/* CSV quote char (must be 1 byte) */
+	char	   *escape;			/* CSV escape char (must be 1 byte) */
+	List	   *force_quote;	/* list of column names */
+	bool		force_quote_all;	/* FORCE_QUOTE *? */
+	bool	   *force_quote_flags;	/* per-column CSV FQ flags */
+	List	   *force_notnull;	/* list of column names */
+	bool	   *force_notnull_flags;	/* per-column CSV FNN flags */
+	List	   *force_null;		/* list of column names */
+	bool	   *force_null_flags;	/* per-column CSV FN flags */
+	bool		convert_selectively;	/* do selective binary conversion? */
+	List	   *convert_select; /* list of column names (can be NIL) */
+	bool	   *convert_select_flags;	/* per-column CSV/TEXT CS flags */
+	Node	   *whereClause;	/* WHERE condition (or NULL) */
+
+	/* these are just for error messages, see CopyFromErrorCallback */
+	const char *cur_relname;	/* table name for error messages */
+	uint64		cur_lineno;		/* line number for error messages */
+	const char *cur_attname;	/* current att for error messages */
+	const char *cur_attval;		/* current att value for error messages */
+
+	/*
+	 * Working state for COPY TO/FROM
+	 */
+	MemoryContext copycontext;	/* per-copy execution context */
+
+	/*
+	 * Working state for COPY TO
+	 */
+	FmgrInfo   *out_functions;	/* lookup info for output functions */
+	MemoryContext rowcontext;	/* per-row evaluation context */
+
+	/*
+	 * Working state for COPY FROM
+	 */
+	AttrNumber	num_defaults;
+	FmgrInfo   *in_functions;	/* array of input functions for each attrs */
+	Oid		   *typioparams;	/* array of element types for in_functions */
+	int		   *defmap;			/* array of default att numbers */
+	ExprState **defexprs;		/* array of default att expressions */
+	bool		volatile_defexprs;	/* is any of defexprs volatile? */
+	List	   *range_table;
+	ExprState  *qualexpr;
+
+	TransitionCaptureState *transition_capture;
+
+	/*
+	 * These variables are used to reduce overhead in COPY FROM.
+	 *
+	 * attribute_buf holds the separated, de-escaped text for each field of
+	 * the current line.  The CopyReadAttributes functions return arrays of
+	 * pointers into this buffer.  We avoid palloc/pfree overhead by re-using
+	 * the buffer on each cycle.
+	 *
+	 * In binary COPY FROM, attribute_buf holds the binary data for the
+	 * current field, but the usage is otherwise similar.
+	 */
+	StringInfoData attribute_buf;
+
+	/* field raw data pointers found by COPY FROM */
+
+	int			max_fields;
+	char	  **raw_fields;
+
+	/*
+	 * Similarly, line_buf holds the whole input line being processed. The
+	 * input cycle is first to read the whole line into line_buf, convert it
+	 * to server encoding there, and then extract the individual attribute
+	 * fields into attribute_buf.  line_buf is preserved unmodified so that we
+	 * can display it in error messages if appropriate.  (In binary mode,
+	 * line_buf is not used.)
+	 */
+	StringInfoData line_buf;
+	bool		line_buf_converted; /* converted to server encoding? */
+	bool		line_buf_valid; /* contains the row being processed? */
+
+	/*
+	 * Finally, raw_buf holds raw data read from the data source (file or
+	 * client connection).  In text mode, CopyReadLine parses this data
+	 * sufficiently to locate line boundaries, then transfers the data to
+	 * line_buf and converts it.  In binary mode, CopyReadBinaryData fetches
+	 * appropriate amounts of data from this buffer.  In both modes, we
+	 * guarantee that there is a \0 at raw_buf[raw_buf_len].
+	 */
+	char	   *raw_buf;
+	int			raw_buf_index;	/* next byte to process */
+	int			raw_buf_len;	/* total # of bytes stored */
+	/* Shorthand for number of unconsumed bytes available in raw_buf */
+#define RAW_BUF_BYTES(cstate) ((cstate)->raw_buf_len - (cstate)->raw_buf_index)
+} CopyStateData;
+
+/* CopyStateData is private in commands/copy.c */
+typedef struct CopyStateData *CopyState;
+
+#endif							/* COPY_INTERNAL_H */
-- 
1.8.3.1

v10-0002-Check-if-parallel-copy-can-be-performed.patchtext/x-patch; charset=US-ASCII; name=v10-0002-Check-if-parallel-copy-can-be-performed.patchDownload
From 7215416f0e6ccb321aa1800fee75438ca6099465 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Tue, 10 Nov 2020 18:24:09 +0530
Subject: [PATCH v10 2/6] Check if parallel copy can be performed.

Checks if parallely copy can be performed, Parallel copy cannot be performed
for the following a) If relation is temporary table b) If relation is foreign
table c) If relation has non parallel safe index expressions d) If relation has
triggers present whose type is of non before statement trigger type e) If
relation has check constraint which are not parallel safe f) If relation
has partition and any partition has the above type. This patch has the
checks for it. This patch will be used by parallel copy implementation patch.
---
 src/backend/access/heap/heapam.c     |  11 -
 src/backend/access/transam/xact.c    |  26 ++-
 src/backend/commands/Makefile        |   1 +
 src/backend/commands/copyparallel.c  | 103 +++++++++
 src/backend/optimizer/util/clauses.c | 405 +++++++++++++++++++++++++++++++++++
 src/include/access/xact.h            |   1 +
 src/include/commands/copy.h          |   2 +
 src/include/optimizer/clauses.h      |   1 +
 8 files changed, 534 insertions(+), 16 deletions(-)
 create mode 100644 src/backend/commands/copyparallel.c

diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 1b2f704..3045c0f 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2043,17 +2043,6 @@ static HeapTuple
 heap_prepare_insert(Relation relation, HeapTuple tup, TransactionId xid,
 					CommandId cid, int options)
 {
-	/*
-	 * To allow parallel inserts, we need to ensure that they are safe to be
-	 * performed in workers. We have the infrastructure to allow parallel
-	 * inserts in general except for the cases where inserts generate a new
-	 * CommandId (eg. inserts into a table having a foreign key column).
-	 */
-	if (IsParallelWorker())
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_TRANSACTION_STATE),
-				 errmsg("cannot insert tuples in a parallel worker")));
-
 	tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
 	tup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK);
 	tup->t_data->t_infomask |= HEAP_XMAX_INVALID;
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 03c553e..1696ea7 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -764,18 +764,34 @@ GetCurrentCommandId(bool used)
 	if (used)
 	{
 		/*
-		 * Forbid setting currentCommandIdUsed in a parallel worker, because
-		 * we have no provision for communicating this back to the leader.  We
-		 * could relax this restriction when currentCommandIdUsed was already
-		 * true at the start of the parallel operation.
+		 * If in a parallel worker, only allow setting currentCommandIdUsed if
+		 * currentCommandIdUsed was already true at the start of the parallel
+		 * operation (by way of SetCurrentCommandIdUsed()), otherwise forbid
+		 * setting currentCommandIdUsed because we have no provision for
+		 * communicating this back to the leader.
 		 */
-		Assert(!IsParallelWorker());
+		Assert(!(IsParallelWorker() && !currentCommandIdUsed));
 		currentCommandIdUsed = true;
 	}
 	return currentCommandId;
 }
 
 /*
+ *	SetCurrentCommandIdUsedForWorker
+ *
+ * For a parallel worker, record that the currentCommandId has been used.
+ * This must only be called at the start of a parallel operation.
+ */
+void
+SetCurrentCommandIdUsedForWorker(void)
+{
+	Assert(IsParallelWorker() && !currentCommandIdUsed &&
+		   (currentCommandId != InvalidCommandId));
+
+	currentCommandIdUsed = true;
+}
+
+/*
  *	SetParallelStartTimestamps
  *
  * In a parallel worker, we should inherit the parent transaction's
diff --git a/src/backend/commands/Makefile b/src/backend/commands/Makefile
index d4815d3..a224aac 100644
--- a/src/backend/commands/Makefile
+++ b/src/backend/commands/Makefile
@@ -24,6 +24,7 @@ OBJS = \
 	constraint.o \
 	conversioncmds.o \
 	copy.o \
+	copyparallel.o \
 	createas.o \
 	dbcommands.o \
 	define.o \
diff --git a/src/backend/commands/copyparallel.c b/src/backend/commands/copyparallel.c
new file mode 100644
index 0000000..290d532
--- /dev/null
+++ b/src/backend/commands/copyparallel.c
@@ -0,0 +1,103 @@
+/*-------------------------------------------------------------------------
+ *
+ * copyparallel.c
+ *              Implements the Parallel COPY utility command
+ *
+ * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *        src/backend/commands/copyparallel.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/heapam.h"
+#include "catalog/pg_proc_d.h"
+#include "commands/copy.h"
+#include "libpq/libpq.h"
+#include "optimizer/clauses.h"
+#include "optimizer/optimizer.h"
+#include "pgstat.h"
+#include "utils/lsyscache.h"
+
+/*
+ * CheckExprParallelSafety
+ *
+ * Determine if where cluase and default expressions are parallel safe & do not
+ * have volatile expressions, return true if condition satisfies else return
+ * false.
+ */
+static bool
+CheckExprParallelSafety(CopyState cstate)
+{
+	if (max_parallel_hazard((Query *) cstate->whereClause) != PROPARALLEL_SAFE)
+		return false;
+
+	/*
+	 * Can't support parallel copy if there are any volatile function
+	 * expressions in WHERE clause as such expressions may query the table
+	 * we're inserting into.
+	 */
+	if (contain_volatile_functions(cstate->whereClause))
+		return false;
+
+	/*
+	 * Check if any of the column has default expression. if yes, and they are
+	 * not parallel safe, then parallelism is not allowed. For instance, if
+	 * there are any serial/bigserial columns for which nextval() default
+	 * expression which is parallel unsafe is associated, parallelism should
+	 * not be allowed.
+	 */
+	if (cstate->defexprs != NULL && cstate->num_defaults != 0)
+	{
+		int			i;
+
+		for (i = 0; i < cstate->num_defaults; i++)
+		{
+			if (max_parallel_hazard((Query *) cstate->defexprs[i]->expr) !=
+				PROPARALLEL_SAFE)
+				return false;
+
+			/*
+			 * Can't support parallel copy if there are any volatile function
+			 * expressions in default expressions as such expressions may
+			 * query the table we're inserting into.
+			 */
+			if (contain_volatile_functions((Node *) cstate->defexprs[i]->expr))
+				return false;
+		}
+	}
+
+	return true;
+}
+
+/*
+ * IsParallelCopyAllowed
+ *
+ * Check if parallel copy can be allowed.
+ */
+bool
+IsParallelCopyAllowed(CopyState cstate, Oid relid)
+{
+	/*
+	 * Check if parallel operation can be performed based on local
+	 * table/foreign table/index/check constraints/triggers present for the
+	 * relation and also by doing similar checks recursively for each of the
+	 * associated parrtitions if exists.
+	 */
+	if (MaxParallelHazardForModify(relid) != PROPARALLEL_SAFE)
+		return false;
+
+	/*
+	 * If there are volatile default expressions or where clause contain
+	 * volatile expressions, allow parallelism if they are parallel safe,
+	 * otherwise not.
+	 */
+	if (!CheckExprParallelSafety(cstate))
+		return false;
+
+	return true;
+}
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 85ef873..c82f5f2 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -20,12 +20,19 @@
 #include "postgres.h"
 
 #include "access/htup_details.h"
+#include "access/genam.h"
+#include "access/table.h"
+#include "catalog/index.h"
+#include "catalog/indexing.h"
 #include "catalog/pg_aggregate.h"
 #include "catalog/pg_class.h"
+#include "catalog/pg_constraint.h"
+#include "catalog/pg_constraint_d.h"
 #include "catalog/pg_language.h"
 #include "catalog/pg_operator.h"
 #include "catalog/pg_proc.h"
 #include "catalog/pg_type.h"
+#include "commands/trigger.h"
 #include "executor/executor.h"
 #include "executor/functions.h"
 #include "funcapi.h"
@@ -42,7 +49,9 @@
 #include "parser/parse_agg.h"
 #include "parser/parse_coerce.h"
 #include "parser/parse_func.h"
+#include "partitioning/partdesc.h"
 #include "rewrite/rewriteManip.h"
+#include "storage/lmgr.h"
 #include "tcop/tcopprot.h"
 #include "utils/acl.h"
 #include "utils/builtins.h"
@@ -50,6 +59,7 @@
 #include "utils/fmgroids.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
+#include "utils/partcache.h"
 #include "utils/syscache.h"
 #include "utils/typcache.h"
 
@@ -1073,6 +1083,401 @@ max_parallel_hazard_walker(Node *node, max_parallel_hazard_context *context)
 								  context);
 }
 
+/*
+ * MaxTriggerDataParallelHazardForModify
+ *
+ * Finds the maximum parallel-mode hazard level for the specified trigger data.
+ */
+static char
+MaxTriggerDataParallelHazardForModify(TriggerDesc *trigdesc,
+									  max_parallel_hazard_context *context)
+{
+	int			i;
+
+	/*
+	 * When transition tables are involved (if after statement triggers are
+	 * present), we collect minimal tuples in the tuple store after processing
+	 * them so that later after statement triggers can access them.  Now, if
+	 * we want to enable parallelism for such cases, we instead need to store
+	 * and access tuples from shared tuple store.  However, it does not have
+	 * the facility to store tuples in-memory, so we always need to store and
+	 * access from a file which could be costly unless we also have an
+	 * additional way to store minimal tuples in shared memory till work_mem
+	 * and then in shared tuple store. It is possible to do all this to enable
+	 * parallel copy for such cases. Currently, we can disallow parallelism
+	 * for such cases and later allow if required.
+	 *
+	 * When there are BEFORE/AFTER/INSTEAD OF row triggers on the table. We do
+	 * not allow parallelism in such cases because such triggers might query
+	 * the table we are inserting into and act differently if the tuples that
+	 * have already been processed and prepared for insertion are not there.
+	 * Now, if we allow parallelism with such triggers the behaviour would
+	 * depend on if the parallel worker has already inserted or not that
+	 * particular tuples.
+	 */
+	if (trigdesc->trig_insert_after_statement ||
+		trigdesc->trig_insert_new_table ||
+		trigdesc->trig_insert_before_row ||
+		trigdesc->trig_insert_after_row ||
+		trigdesc->trig_insert_instead_row)
+	{
+		context->max_hazard = PROPARALLEL_UNSAFE;
+		return context->max_hazard;
+	}
+
+	for (i = 0; i < trigdesc->numtriggers; i++)
+	{
+		Trigger    *trigger = &trigdesc->triggers[i];
+		int			trigtype;
+
+		/*
+		 * If the trigger type is RI_TRIGGER_FK, this indicates a FK exists in
+		 * the relation, and this would result in creation of new CommandIds
+		 * on insert/update/delete and this isn't supported in a parallel
+		 * worker (but is safe in the parallel leader).
+		 */
+		trigtype = RI_FKey_trigger_type(trigger->tgfoid);
+
+		/*
+		 * No parallelism if foreign key check trigger is present. This is
+		 * because, while performing foreign key checks, we take KEY SHARE
+		 * lock on primary key table rows which inturn will increment the
+		 * command counter and updates the snapshot.  Since we share the
+		 * snapshots at the beginning of the command, we can't allow it to be
+		 * changed later. So, unless we do something special for it, we can't
+		 * allow parallelism in such cases.
+		 */
+		if (trigtype == RI_TRIGGER_FK)
+		{
+			context->max_hazard = PROPARALLEL_UNSAFE;
+			return context->max_hazard;
+		}
+	}
+
+	return context->max_hazard;
+}
+
+/*
+ * MaxIndexExprsParallelHazardForModify
+ *
+ * Finds the maximum parallel-mode hazard level for any existing index
+ * expressions of a specified relation.
+ */
+static char
+MaxIndexExprsParallelHazardForModify(Relation rel,
+									 max_parallel_hazard_context *context)
+{
+	List	   *indexOidList;
+	ListCell   *lc;
+	LOCKMODE	lockmode = AccessShareLock;
+
+	indexOidList = RelationGetIndexList(rel);
+	foreach(lc, indexOidList)
+	{
+		Oid			indexOid = lfirst_oid(lc);
+		Relation	indexRel;
+		IndexInfo  *indexInfo;
+
+		if (ConditionalLockRelationOid(indexOid, lockmode))
+		{
+			indexRel = index_open(indexOid, NoLock);
+		}
+		else
+		{
+			context->max_hazard = PROPARALLEL_UNSAFE;
+			return context->max_hazard;
+		}
+
+		indexInfo = BuildIndexInfo(indexRel);
+
+		if (indexInfo->ii_Expressions != NIL)
+		{
+			int			i;
+			ListCell   *indexExprItem = list_head(indexInfo->ii_Expressions);
+
+			for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
+			{
+				int			keycol = indexInfo->ii_IndexAttrNumbers[i];
+
+				if (keycol == 0)
+				{
+					/* Found an index expression */
+
+					Node	   *indexExpr;
+
+					if (indexExprItem == NULL)	/* shouldn't happen */
+						elog(ERROR, "too few entries in indexprs list");
+
+					indexExpr = (Node *) lfirst(indexExprItem);
+					indexExpr = (Node *) expression_planner((Expr *) indexExpr);
+
+					if (max_parallel_hazard_walker(indexExpr, context))
+					{
+						index_close(indexRel, lockmode);
+						return context->max_hazard;
+					}
+
+					indexExprItem = lnext(indexInfo->ii_Expressions, indexExprItem);
+				}
+			}
+		}
+		index_close(indexRel, lockmode);
+	}
+
+	return context->max_hazard;
+}
+
+/*
+ * MaxDomainParallelHazardForModify
+ *
+ * Finds the maximum parallel-mode hazard level for the specified DOMAIN type.
+ * Only any CHECK expressions are examined for parallel safety.
+ * DEFAULT values of DOMAIN-type columns in the target-list are already
+ * being checked for parallel-safety in the max_parallel_hazard() scan of the
+ * query tree in standard_planner().
+ *
+ */
+static char
+MaxDomainParallelHazardForModify(Oid typid, max_parallel_hazard_context *context)
+{
+	Relation	conRel;
+	ScanKeyData key[1];
+	SysScanDesc scan;
+	HeapTuple	tup;
+
+	LOCKMODE	lockmode = AccessShareLock;
+
+	conRel = table_open(ConstraintRelationId, lockmode);
+
+	ScanKeyInit(&key[0],
+				Anum_pg_constraint_contypid, BTEqualStrategyNumber,
+				F_OIDEQ, ObjectIdGetDatum(typid));
+	scan = systable_beginscan(conRel, ConstraintTypidIndexId, true,
+							  NULL, 1, key);
+
+	while (HeapTupleIsValid((tup = systable_getnext(scan))))
+	{
+		Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup);
+
+		if (con->contype == CONSTRAINT_CHECK)
+		{
+			char	   *conbin;
+			Datum		val;
+			bool		isnull;
+			Expr	   *checkExpr;
+
+			val = SysCacheGetAttr(CONSTROID, tup,
+								  Anum_pg_constraint_conbin, &isnull);
+			if (isnull)
+				elog(ERROR, "null conbin for constraint %u", con->oid);
+			conbin = TextDatumGetCString(val);
+			checkExpr = stringToNode(conbin);
+			if (max_parallel_hazard_walker((Node *) checkExpr, context))
+			{
+				break;
+			}
+		}
+	}
+
+	systable_endscan(scan);
+	table_close(conRel, lockmode);
+	return context->max_hazard;
+}
+
+/*
+ * MaxRelParallelHazardForModify
+ *
+ * Determines the maximum parallel-mode hazard level for modification
+ * of a specified relation.
+ */
+static char
+MaxRelParallelHazardForModify(Oid relid, max_parallel_hazard_context *context)
+{
+	Relation	rel;
+	TupleDesc	tupdesc;
+	int			attnum;
+
+	LOCKMODE	lockmode = AccessShareLock;
+
+	/*
+	 * It's possible that this relation is locked for exclusive access in
+	 * another concurrent transaction (e.g. as a result of a ALTER TABLE ...
+	 * operation) until that transaction completes. If a share-lock can't be
+	 * acquired on it now, we have to assume this could be the worst-case, so
+	 * to avoid blocking here until that transaction completes, conditionally
+	 * try to acquire the lock and assume and return UNSAFE on failure.
+	 */
+	if (ConditionalLockRelationOid(relid, lockmode))
+	{
+		rel = table_open(relid, NoLock);
+	}
+	else
+	{
+		context->max_hazard = PROPARALLEL_UNSAFE;
+		return context->max_hazard;
+	}
+
+	/*
+	 * Check if copy is into foreign table. We can not allow parallelism in
+	 * this case because each worker needs to establish FDW connection and
+	 * operate in a separate transaction. Unless we have a capability to
+	 * provide two-phase commit protocol, we can not allow parallelism.
+	 *
+	 * Also check if copy is into temporary table. Since parallel workers can
+	 * not access temporary table, parallelism is not allowed.
+	 */
+	if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
+		RelationUsesLocalBuffers(rel))
+	{
+		table_close(rel, lockmode);
+		context->max_hazard = PROPARALLEL_UNSAFE;
+		return context->max_hazard;
+	}
+
+	/*
+	 * If a partitioned table, check that each partition is safe for
+	 * modification in parallel-mode.
+	 */
+	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+	{
+		int			i;
+		PartitionDesc pdesc;
+		PartitionKey pkey;
+		ListCell   *partexprs_item;
+		int			partnatts;
+		List	   *partexprs;
+
+		pkey = RelationGetPartitionKey(rel);
+
+		partnatts = get_partition_natts(pkey);
+		partexprs = get_partition_exprs(pkey);
+
+		partexprs_item = list_head(partexprs);
+		for (i = 0; i < partnatts; i++)
+		{
+			/* Check parallel-safety of partition key support functions */
+			if (OidIsValid(pkey->partsupfunc[i].fn_oid))
+			{
+				if (max_parallel_hazard_test(func_parallel(pkey->partsupfunc[i].fn_oid), context))
+				{
+					table_close(rel, lockmode);
+					return context->max_hazard;
+				}
+			}
+
+			/* Check parallel-safety of any expressions in the partition key */
+			if (get_partition_col_attnum(pkey, i) == 0)
+			{
+				Node	   *checkExpr = (Node *) lfirst(partexprs_item);
+
+				if (max_parallel_hazard_walker(checkExpr, context))
+				{
+					table_close(rel, lockmode);
+					return context->max_hazard;
+				}
+
+				partexprs_item = lnext(partexprs, partexprs_item);
+			}
+		}
+
+		/* Recursively check each partition ... */
+		pdesc = RelationGetPartitionDesc(rel);
+		for (i = 0; i < pdesc->nparts; i++)
+		{
+			if (MaxRelParallelHazardForModify(pdesc->oids[i], context) != PROPARALLEL_SAFE)
+			{
+				table_close(rel, lockmode);
+				return context->max_hazard;
+			}
+		}
+	}
+
+	/*
+	 * If there are any index expressions, check that they are parallel-mode
+	 * safe.
+	 */
+	if (MaxIndexExprsParallelHazardForModify(rel, context) != PROPARALLEL_SAFE)
+	{
+		table_close(rel, lockmode);
+		return context->max_hazard;
+	}
+
+	/*
+	 * If any triggers exist, check that they are parallel safe.
+	 */
+	if (rel->trigdesc != NULL &&
+		MaxTriggerDataParallelHazardForModify(rel->trigdesc, context) != PROPARALLEL_SAFE)
+	{
+		table_close(rel, lockmode);
+		return context->max_hazard;
+	}
+
+	tupdesc = RelationGetDescr(rel);
+	for (attnum = 0; attnum < tupdesc->natts; attnum++)
+	{
+		Form_pg_attribute att = TupleDescAttr(tupdesc, attnum);
+
+		/* We don't need info for dropped or generated attributes */
+		if (att->attisdropped || att->attgenerated)
+			continue;
+
+		/*
+		 * If the column is of a DOMAIN type, determine whether that domain
+		 * has any CHECK expressions that are not parallel-mode safe.
+		 */
+		if (get_typtype(att->atttypid) == TYPTYPE_DOMAIN)
+		{
+			if (MaxDomainParallelHazardForModify(att->atttypid, context) != PROPARALLEL_SAFE)
+			{
+				table_close(rel, lockmode);
+				return context->max_hazard;
+			}
+		}
+	}
+
+	/*
+	 * Check if there are any CHECK constraints which are not parallel-safe.
+	 */
+	if (tupdesc->constr != NULL && tupdesc->constr->num_check > 0)
+	{
+		int			i;
+
+		ConstrCheck *check = tupdesc->constr->check;
+
+		for (i = 0; i < tupdesc->constr->num_check; i++)
+		{
+			Expr	   *checkExpr = stringToNode(check->ccbin);
+
+			if (max_parallel_hazard_walker((Node *) checkExpr, context))
+			{
+				table_close(rel, lockmode);
+				return context->max_hazard;
+			}
+		}
+	}
+
+	table_close(rel, lockmode);
+	return context->max_hazard;
+}
+
+/*
+ * MaxParallelHazardForModify
+ *
+ * Determines the worst parallel-mode hazard level for the specified
+ * relation. The search returns the earliest in the following list:
+ * PROPARALLEL_UNSAFE, PROPARALLEL_RESTRICTED, PROPARALLEL_SAFE
+ */
+char
+MaxParallelHazardForModify(Oid relid)
+{
+	max_parallel_hazard_context context;
+
+	context.max_hazard = PROPARALLEL_SAFE;
+	context.max_interesting = PROPARALLEL_RESTRICTED;
+	context.safe_param_ids = NIL;
+
+	return (MaxRelParallelHazardForModify(relid, &context));
+}
 
 /*****************************************************************************
  *		Check clauses for nonstrict functions
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index 7320de3..42d4893 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -386,6 +386,7 @@ extern FullTransactionId GetTopFullTransactionId(void);
 extern FullTransactionId GetTopFullTransactionIdIfAny(void);
 extern FullTransactionId GetCurrentFullTransactionId(void);
 extern FullTransactionId GetCurrentFullTransactionIdIfAny(void);
+extern void SetCurrentCommandIdUsedForWorker(void);
 extern void MarkCurrentTransactionIdLoggedIfAny(void);
 extern bool SubTransactionIsActive(SubTransactionId subxid);
 extern CommandId GetCurrentCommandId(bool used);
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index b9331af..fd3a78e 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -38,4 +38,6 @@ extern uint64 CopyFrom(CopyState cstate);
 
 extern DestReceiver *CreateCopyDestReceiver(void);
 
+extern bool IsParallelCopyAllowed(CopyState cstate, Oid relid);
+
 #endif							/* COPY_H */
diff --git a/src/include/optimizer/clauses.h b/src/include/optimizer/clauses.h
index 7ef8cce..f515de1 100644
--- a/src/include/optimizer/clauses.h
+++ b/src/include/optimizer/clauses.h
@@ -55,5 +55,6 @@ extern void CommuteOpExpr(OpExpr *clause);
 
 extern Query *inline_set_returning_function(PlannerInfo *root,
 											RangeTblEntry *rte);
+extern char MaxParallelHazardForModify(Oid relid);
 
 #endif							/* CLAUSES_H */
-- 
1.8.3.1

v10-0003-Allow-copy-from-command-to-process-data-from-fil.patchtext/x-patch; charset=US-ASCII; name=v10-0003-Allow-copy-from-command-to-process-data-from-fil.patchDownload
From 43d524094f1f9271521a219856b6e6df2205f17a Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Tue, 10 Nov 2020 18:39:35 +0530
Subject: [PATCH v10 3/6] Allow copy from command to process data from
 file/STDIN contents to a table in parallel.

This feature allows the copy from to leverage multiple CPUs in order to copy
data from file/STDIN to a table. This adds a PARALLEL option to COPY FROM
command where the user can specify the number of workers that can be used
to perform the COPY FROM command.
The backend, to which the "COPY FROM" query is submitted acts as leader with
the responsibility of reading data from the file/stdin, launching at most n
number of workers as specified with PARALLEL 'n' option in the "COPY FROM"
query. The leader populates the common data required for the workers execution
in the DSM and shares it with the workers. The leader then executes before
statement triggers if there exists any. Leader populates DSM lines which
includes the start offset and line size, while populating the lines it reads
as many blocks as required into the DSM data blocks from the file. Each block
is of 64K size. The leader parses the data to identify a line, the existing
logic from CopyReadLineText which identifies the lines with some changes was
used for this. Leader checks if a free line is available to copy the
information, if there is no free line it waits till the required line is
freed up by the worker and then copies the identified lines information
(offset & line size) into the DSM lines. This process is repeated till the
complete file is processed. Simultaneously, the workers cache the lines(50)
locally into the local memory and release the lines to the leader for further
populating. Each worker processes the lines that it cached and inserts it into
the table.
The leader does not participate in the insertion of data, leaders only
responsibility will be to identify the lines as fast as possible for the
workers to do the actual copy operation. The leader waits till all the lines
populated are processed by the workers and exits. We have chosen this design
based on the reason "that everything stalls if the leader doesn't accept further
input data, as well as when there are no available splitted chunks so it doesn't
seem like a good idea to have the leader do other work.  This is backed by the
performance data where we have seen that with 1 worker there is just a 5-10%
performance difference".
---
 src/backend/access/transam/parallel.c |    4 +
 src/backend/commands/copy.c           |  271 +++++--
 src/backend/commands/copyparallel.c   | 1254 +++++++++++++++++++++++++++++++++
 src/bin/psql/tab-complete.c           |    2 +-
 src/include/commands/copy.h           |   23 +-
 src/include/commands/copy_internal.h  |  226 +++++-
 src/tools/pgindent/typedefs.list      |    8 +
 7 files changed, 1729 insertions(+), 59 deletions(-)

diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index b042696..a3cff4b 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -25,6 +25,7 @@
 #include "catalog/pg_enum.h"
 #include "catalog/storage.h"
 #include "commands/async.h"
+#include "commands/copy.h"
 #include "executor/execParallel.h"
 #include "libpq/libpq.h"
 #include "libpq/pqformat.h"
@@ -145,6 +146,9 @@ static const struct
 	},
 	{
 		"parallel_vacuum_main", parallel_vacuum_main
+	},
+	{
+		"ParallelCopyMain", ParallelCopyMain
 	}
 };
 
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 3b26fc5..6856ef5 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -44,6 +44,7 @@
 #include "parser/parse_expr.h"
 #include "parser/parse_relation.h"
 #include "port/pg_bswap.h"
+#include "postmaster/bgworker_internals.h"
 #include "rewrite/rewriteHandler.h"
 #include "storage/fd.h"
 #include "tcop/tcopprot.h"
@@ -166,9 +167,13 @@ if (1) \
 { \
 	if (raw_buf_ptr > cstate->raw_buf_index) \
 	{ \
-		appendBinaryStringInfo(&cstate->line_buf, \
-							 cstate->raw_buf + cstate->raw_buf_index, \
-							   raw_buf_ptr - cstate->raw_buf_index); \
+		if (!IsParallelCopy()) \
+			appendBinaryStringInfo(&cstate->line_buf, \
+								   cstate->raw_buf + cstate->raw_buf_index, \
+								   raw_buf_ptr - cstate->raw_buf_index); \
+		else \
+			line_size +=  raw_buf_ptr - cstate->raw_buf_index; \
+		\
 		cstate->raw_buf_index = raw_buf_ptr; \
 	} \
 } else ((void) 0)
@@ -197,7 +202,6 @@ static void EndCopyTo(CopyState cstate);
 static uint64 DoCopyTo(CopyState cstate);
 static uint64 CopyTo(CopyState cstate);
 static void CopyOneRowTo(CopyState cstate, TupleTableSlot *slot);
-static bool CopyReadLine(CopyState cstate);
 static bool CopyReadLineText(CopyState cstate);
 static int	CopyReadAttributesText(CopyState cstate);
 static int	CopyReadAttributesCSV(CopyState cstate);
@@ -227,13 +231,8 @@ static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 static bool CopyLoadRawBuf(CopyState cstate);
 static int	CopyReadBinaryData(CopyState cstate, char *dest, int nbytes);
-
-static void PopulateCommonCStateInfo(CopyState cstate, TupleDesc tup_desc,
-									 List *attnamelist);
 static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
 								   int copy_line_pos, int *copy_line_size);
-static void ConvertToServerEncoding(CopyState cstate);
-
 
 /*
  * Send copy start/stop messages for frontend copies.  These have changed
@@ -632,11 +631,11 @@ CopyGetInt16(CopyState cstate, int16 *val)
 static bool
 CopyLoadRawBuf(CopyState cstate)
 {
-	int			nbytes = RAW_BUF_BYTES(cstate);
+	int			nbytes = (!IsParallelCopy()) ? RAW_BUF_BYTES(cstate) : cstate->raw_buf_len;
 	int			inbytes;
 
 	/* Copy down the unprocessed data if any. */
-	if (nbytes > 0)
+	if (nbytes > 0 && !IsParallelCopy())
 		memmove(cstate->raw_buf, cstate->raw_buf + cstate->raw_buf_index,
 				nbytes);
 
@@ -644,7 +643,9 @@ CopyLoadRawBuf(CopyState cstate)
 						  1, RAW_BUF_SIZE - nbytes);
 	nbytes += inbytes;
 	cstate->raw_buf[nbytes] = '\0';
-	cstate->raw_buf_index = 0;
+	if (!IsParallelCopy())
+		cstate->raw_buf_index = 0;
+
 	cstate->raw_buf_len = nbytes;
 	return (inbytes > 0);
 }
@@ -943,6 +944,8 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 
 	if (is_from)
 	{
+		ParallelContext *pcxt = NULL;
+
 		Assert(rel);
 
 		/* check read-only transaction and parallel mode */
@@ -952,7 +955,46 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 		cstate = BeginCopyFrom(pstate, rel, stmt->filename, stmt->is_program,
 							   NULL, stmt->attlist, stmt->options);
 		cstate->whereClause = whereClause;
-		*processed = CopyFrom(cstate);	/* copy from file to database */
+		cstate->is_parallel = false;
+
+		/*
+		 * User chosen parallel copy. Determine if the parallel copy is
+		 * actually allowed. If not, go with the non-parallel mode.
+		 */
+		if (cstate->nworkers > 0 && IsParallelCopyAllowed(cstate, relid))
+			pcxt = BeginParallelCopy(cstate, stmt->attlist, relid);
+
+		if (pcxt)
+		{
+			int			i;
+
+			ParallelCopyFrom(cstate);
+
+			/* Wait for all copy workers to finish */
+			WaitForParallelWorkersToFinish(pcxt);
+
+			/*
+			 * Next, accumulate WAL usage.  (This must wait for the workers to
+			 * finish, or we might get incomplete data.)
+			 */
+			for (i = 0; i < pcxt->nworkers_launched; i++)
+				InstrAccumParallelQuery(&cstate->pcdata->bufferusage[i],
+										&cstate->pcdata->walusage[i]);
+
+			*processed = pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
+			EndParallelCopy(pcxt);
+		}
+		else
+		{
+			/*
+			 * Reset nworkers to -1 here. This is useful in cases where user
+			 * specifies parallel workers, but, no worker is picked up, so go
+			 * back to non parallel mode value of nworkers.
+			 */
+			cstate->nworkers = -1;
+			*processed = CopyFrom(cstate);	/* copy from file to database */
+		}
+
 		EndCopyFrom(cstate);
 	}
 	else
@@ -1003,6 +1045,7 @@ ProcessCopyOptions(ParseState *pstate,
 	cstate->is_copy_from = is_from;
 
 	cstate->file_encoding = -1;
+	cstate->nworkers = -1;
 
 	/* Extract options from the statement node tree */
 	foreach(option, options)
@@ -1173,6 +1216,31 @@ ProcessCopyOptions(ParseState *pstate,
 								defel->defname),
 						 parser_errposition(pstate, defel->location)));
 		}
+		else if (strcmp(defel->defname, "parallel") == 0)
+		{
+			int			val;
+
+			if (!cstate->is_copy_from)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("parallel option is supported only for copy from"),
+						 parser_errposition(pstate, defel->location)));
+			if (cstate->nworkers >= 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options"),
+						 parser_errposition(pstate, defel->location)));
+
+			val = defGetInt32(defel);
+			if (val < 1 || val > MAX_PARALLEL_WORKER_LIMIT)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("value %d out of bounds for option \"%s\"",
+								val, defel->defname),
+						 errdetail("Valid values are between \"%d\" and \"%d\".",
+								   1, MAX_PARALLEL_WORKER_LIMIT)));
+			cstate->nworkers = val;
+		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_SYNTAX_ERROR),
@@ -1528,9 +1596,9 @@ BeginCopy(ParseState *pstate,
  * PopulateCommonCStateInfo
  *
  * Populates the common variables required for copy from operation. This is a
- * helper function for BeginCopy function.
+ * helper function for BeginCopy & InitializeParallelCopyInfo function.
  */
-static void
+void
 PopulateCommonCStateInfo(CopyState cstate, TupleDesc tupDesc, List *attnamelist)
 {
 	int			num_phys_attrs;
@@ -2547,7 +2615,7 @@ CopyMultiInsertInfoStore(CopyMultiInsertInfo *miinfo, ResultRelInfo *rri,
  *
  * Check if the relation specified in copy from is valid.
  */
-static void
+void
 CheckTargetRelValidity(CopyState cstate)
 {
 	Assert(cstate->rel);
@@ -2644,7 +2712,7 @@ CopyFrom(CopyState cstate)
 
 	PartitionTupleRouting *proute = NULL;
 	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
+	CommandId	mycid;
 	int			ti_options = 0; /* start with default options for insert */
 	BulkInsertState bistate = NULL;
 	CopyInsertMethod insertMethod;
@@ -2654,7 +2722,18 @@ CopyFrom(CopyState cstate)
 	bool		has_instead_insert_row_trig;
 	bool		leafpart_use_multi_insert = false;
 
-	CheckTargetRelValidity(cstate);
+	/*
+	 * Perform this check if it is not parallel copy. In case of parallel
+	 * copy, this check is done by the leader, so that if any invalid case
+	 * exist the copy from command will error out from the leader itself,
+	 * avoiding launching workers, just to throw error.
+	 */
+	if (!IsParallelCopy())
+		CheckTargetRelValidity(cstate);
+	else
+		SetCurrentCommandIdUsedForWorker();
+
+	mycid = GetCurrentCommandId(!IsParallelCopy());
 
 	/*
 	 * If the target file is new-in-transaction, we assume that checking FSM
@@ -2690,7 +2769,8 @@ CopyFrom(CopyState cstate)
 	ExecInitResultRelation(estate, resultRelInfo, 1);
 
 	/* Verify the named relation is a valid target for INSERT */
-	CheckValidResultRel(resultRelInfo, CMD_INSERT);
+	if (!IsParallelCopy())
+		CheckValidResultRel(resultRelInfo, CMD_INSERT);
 
 	ExecOpenIndices(resultRelInfo, false);
 
@@ -2833,13 +2913,17 @@ CopyFrom(CopyState cstate)
 	has_instead_insert_row_trig = (resultRelInfo->ri_TrigDesc &&
 								   resultRelInfo->ri_TrigDesc->trig_insert_instead_row);
 
-	/*
-	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
-	 * should do this for COPY, since it's not really an "INSERT" statement as
-	 * such. However, executing these triggers maintains consistency with the
-	 * EACH ROW triggers that we already fire on COPY.
-	 */
-	ExecBSInsertTriggers(estate, resultRelInfo);
+	if (!IsParallelCopy())
+	{
+		/*
+		 * Check BEFORE STATEMENT insertion triggers. It's debatable whether
+		 * we should do this for COPY, since it's not really an "INSERT"
+		 * statement as such. However, executing these triggers maintains
+		 * consistency with the EACH ROW triggers that we already fire on
+		 * COPY.
+		 */
+		ExecBSInsertTriggers(estate, resultRelInfo);
+	}
 
 	econtext = GetPerTupleExprContext(estate);
 
@@ -3141,7 +3225,10 @@ CopyFrom(CopyState cstate)
 			 * or FDW; this is the same definition used by nodeModifyTable.c
 			 * for counting tuples inserted by an INSERT command.
 			 */
-			processed++;
+			if (!IsParallelCopy())
+				processed++;
+			else
+				pg_atomic_add_fetch_u64(&cstate->pcdata->pcshared_info->processed, 1);
 		}
 	}
 
@@ -3164,7 +3251,7 @@ CopyFrom(CopyState cstate)
 	 * In the old protocol, tell pqcomm that we can process normal protocol
 	 * messages again.
 	 */
-	if (cstate->copy_dest == COPY_OLD_FE)
+	if (cstate->copy_dest == COPY_OLD_FE && !IsParallelCopy())
 		pq_endmsgread();
 
 	/* Execute AFTER STATEMENT insertion triggers */
@@ -3195,7 +3282,10 @@ CopyFrom(CopyState cstate)
 
 	FreeExecutorState(estate);
 
-	return processed;
+	if (!IsParallelCopy())
+		return processed;
+	else
+		return pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
 }
 
 /*
@@ -3203,7 +3293,7 @@ CopyFrom(CopyState cstate)
  *
  * Populate the cstate catalog information.
  */
-static void
+void
 PopulateCStateCatalogInfo(CopyState cstate)
 {
 	TupleDesc	tupDesc;
@@ -3485,26 +3575,35 @@ NextCopyFromRawFields(CopyState cstate, char ***fields, int *nfields)
 	/* only available for text or csv input */
 	Assert(!cstate->binary);
 
-	/* on input just throw the header line away */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (IsParallelCopy())
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
-			return false;		/* done */
+		done = GetWorkerLine(cstate);
+		if (done && cstate->line_buf.len == 0)
+			return false;
 	}
+	else
+	{
+		/* on input just throw the header line away */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
+		{
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+				return false;	/* done */
+		}
 
-	cstate->cur_lineno++;
+		cstate->cur_lineno++;
 
-	/* Actually read the line into memory here */
-	done = CopyReadLine(cstate);
+		/* Actually read the line into memory here */
+		done = CopyReadLine(cstate);
 
-	/*
-	 * EOF at start of line means we're done.  If we see EOF after some
-	 * characters, we act as though it was newline followed by EOF, ie,
-	 * process the line and then exit loop on next iteration.
-	 */
-	if (done && cstate->line_buf.len == 0)
-		return false;
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			return false;
+	}
 
 	/* Parse the line into de-escaped field values */
 	if (cstate->csv_mode)
@@ -3729,7 +3828,7 @@ EndCopyFrom(CopyState cstate)
  * by newline.  The terminating newline or EOF marker is not included
  * in the final value of line_buf.
  */
-static bool
+bool
 CopyReadLine(CopyState cstate)
 {
 	bool		result;
@@ -3752,9 +3851,31 @@ CopyReadLine(CopyState cstate)
 		 */
 		if (cstate->copy_dest == COPY_NEW_FE)
 		{
+			bool		bIsFirst = true;
+
 			do
 			{
-				cstate->raw_buf_index = cstate->raw_buf_len;
+				if (!IsParallelCopy())
+					cstate->raw_buf_index = cstate->raw_buf_len;
+				else
+				{
+					/*
+					 * Get a new block if it is the first time, From the
+					 * subsequent time, reset the index and re-use the same
+					 * block.
+					 */
+					if (bIsFirst)
+					{
+						ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+						uint32		block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+						cstate->raw_buf = pcshared_info->data_blocks[block_pos].data;
+						bIsFirst = false;
+					}
+
+					cstate->raw_buf_index = cstate->raw_buf_len = 0;
+				}
+
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
@@ -3809,11 +3930,11 @@ ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
  *
  * Convert contents to server encoding.
  */
-static void
+void
 ConvertToServerEncoding(CopyState cstate)
 {
 	/* Done reading the line.  Convert it to server encoding. */
-	if (cstate->need_transcoding)
+	if (cstate->need_transcoding && (!IsParallelCopy() || IsWorker()))
 	{
 		char	   *cvt;
 
@@ -3853,6 +3974,11 @@ CopyReadLineText(CopyState cstate)
 	char		quotec = '\0';
 	char		escapec = '\0';
 
+	/* For parallel copy */
+	int			line_size = 0;
+	uint32		line_pos = 0;
+
+	cstate->eol_type = EOL_UNKNOWN;
 	if (cstate->csv_mode)
 	{
 		quotec = cstate->quote[0];
@@ -3907,6 +4033,10 @@ CopyReadLineText(CopyState cstate)
 		if (raw_buf_ptr >= copy_buf_len || need_data)
 		{
 			REFILL_LINEBUF;
+			if ((copy_buf_len == DATA_BLOCK_SIZE || copy_buf_len == 0) &&
+				IsParallelCopy())
+				SetRawBufForLoad(cstate, line_size, copy_buf_len, raw_buf_ptr,
+								 &copy_raw_buf);
 
 			/*
 			 * Try to read some more data.  This will certainly reset
@@ -3914,14 +4044,14 @@ CopyReadLineText(CopyState cstate)
 			 */
 			if (!CopyLoadRawBuf(cstate))
 				hit_eof = true;
-			raw_buf_ptr = 0;
+			raw_buf_ptr = (IsParallelCopy()) ? cstate->raw_buf_index : 0;
 			copy_buf_len = cstate->raw_buf_len;
 
 			/*
 			 * If we are completely out of data, break out of the loop,
 			 * reporting EOF.
 			 */
-			if (copy_buf_len <= 0)
+			if (RAW_BUF_BYTES(cstate) <= 0)
 			{
 				result = true;
 				break;
@@ -4131,9 +4261,15 @@ CopyReadLineText(CopyState cstate)
 				 * discard the data and the \. sequence.
 				 */
 				if (prev_raw_ptr > cstate->raw_buf_index)
-					appendBinaryStringInfo(&cstate->line_buf,
-										   cstate->raw_buf + cstate->raw_buf_index,
-										   prev_raw_ptr - cstate->raw_buf_index);
+				{
+					if (!IsParallelCopy())
+						appendBinaryStringInfo(&cstate->line_buf,
+											   cstate->raw_buf + cstate->raw_buf_index,
+											   prev_raw_ptr - cstate->raw_buf_index);
+					else
+						line_size += prev_raw_ptr - cstate->raw_buf_index;
+				}
+
 				cstate->raw_buf_index = raw_buf_ptr;
 				result = true;	/* report EOF */
 				break;
@@ -4185,6 +4321,22 @@ not_end_of_copy:
 			IF_NEED_REFILL_AND_EOF_BREAK(mblen - 1);
 			raw_buf_ptr += mblen - 1;
 		}
+
+		/*
+		 * Skip the header line. Update the line here, this cannot be done at
+		 * the beginning, as there is a possibility that file contains empty
+		 * lines.
+		 */
+		if (IsParallelCopy() && first_char_in_line && !IsHeaderLine())
+		{
+			ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+			line_pos = UpdateSharedLineInfo(cstate,
+											pcshared_info->cur_block_pos,
+											cstate->raw_buf_index, -1,
+											LINE_LEADER_POPULATING, -1);
+		}
+
 		first_char_in_line = false;
 	}							/* end of outer loop */
 
@@ -4193,9 +4345,16 @@ not_end_of_copy:
 	 */
 	REFILL_LINEBUF;
 	if (!result && !IsHeaderLine())
-		ClearEOLFromCopiedData(cstate, cstate->line_buf.data,
-							   cstate->line_buf.len, &cstate->line_buf.len);
+	{
+		if (IsParallelCopy())
+			ClearEOLFromCopiedData(cstate, cstate->raw_buf, raw_buf_ptr,
+								   &line_size);
+		else
+			ClearEOLFromCopiedData(cstate, cstate->line_buf.data,
+								   cstate->line_buf.len, &cstate->line_buf.len);
+	}
 
+	EndLineParallelCopy(cstate, line_pos, line_size, raw_buf_ptr);
 	return result;
 }
 
diff --git a/src/backend/commands/copyparallel.c b/src/backend/commands/copyparallel.c
index 290d532..f29d63f 100644
--- a/src/backend/commands/copyparallel.c
+++ b/src/backend/commands/copyparallel.c
@@ -3,6 +3,45 @@
  * copyparallel.c
  *              Implements the Parallel COPY utility command
  *
+ * Parallel copy allows the copy from to leverage multiple CPUs in order to copy
+ * data from file/STDIN to a table. This adds a PARALLEL option to COPY FROM
+ * command where the user can specify the number of workers that can be used
+ * to perform the COPY FROM command.
+ * The backend, to which the "COPY FROM" query is submitted acts as leader with
+ * the responsibility of reading data from the file/stdin, launching at most n
+ * number of workers as specified with PARALLEL 'n' option in the "COPY FROM"
+ * query. The leader populates the common data using
+ * PARALLEL_COPY_KEY_SHARED_INFO, PARALLEL_COPY_KEY_CSTATE,
+ * PARALLEL_COPY_KEY_WAL_USAGE & PARALLEL_COPY_KEY_BUFFER_USAGE	 required for
+ * the workers execution in the DSM and shares it with the workers. The leader
+ * then executes before statement triggers if there exists any. Leader populates
+ * DSM lines (ParallelCopyDataBlock & ParallelCopyLineBoundaries data
+ * structures) which includes the start offset and line size, while populating
+ * the lines it reads as many blocks as required into the DSM data blocks from
+ * the file. Each block is of 64K size. The leader parses the data to identify a
+ * line, the existing logic from CopyReadLineText which identifies the lines
+ * with some changes was used for this. Leader checks if a free line is
+ * available (ParallelCopyLineBoundary->line_size will be -1) to copy the
+ * information, if there is no free line it waits till the required line is
+ * freed up by the worker and then copies the identified lines information
+ * (offset & line size) into the DSM lines. Leader will set the state of the
+ * line to LINE_LEADER_POPULATED to indicate the line is populated by the leader
+ * and the worker can start processing the line. This process is repeated till
+ * the complete file is processed. Simultaneously, each worker caches
+ * WORKER_CHUNK_COUNT lines locally into the local memory and release the lines
+ * to the leader for further populating. Each worker processes the lines as it
+ * was done in sequential copy. Refer comments above ParallelCopyLineBoundary
+ * for more details on leader/workers syncronization.
+ * The leader does not participate in the insertion of data, leaders only
+ * responsibility will be to identify the lines as fast as possible for the
+ * workers to do the actual copy operation. The leader waits till all the lines
+ * populated are processed by the workers and exits. We have chosen this design
+ * based on the reason "that everything stalls if the leader doesn't accept
+ * further input data, as well as when there are no available splitted chunks so
+ * it doesn't seem like a good idea to have the leader do other work.  This is
+ * backed by the performance data where we have seen that with 1 worker there is
+ * just a 5-10% performance difference".
+ *
  * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
@@ -23,6 +62,326 @@
 #include "pgstat.h"
 #include "utils/lsyscache.h"
 
+/* DSM keys for parallel copy.  */
+#define PARALLEL_COPY_KEY_SHARED_INFO				1
+#define PARALLEL_COPY_KEY_CSTATE					2
+#define PARALLEL_COPY_KEY_WAL_USAGE					3
+#define PARALLEL_COPY_KEY_BUFFER_USAGE				4
+
+/*
+ * COPY_WAIT_TO_PROCESS - Wait before continuing to process.
+ */
+#define COPY_WAIT_TO_PROCESS() \
+{ \
+	CHECK_FOR_INTERRUPTS(); \
+	(void) WaitLatch(MyLatch, \
+					 WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH, \
+					 1L, WAIT_EVENT_PG_SLEEP); \
+	ResetLatch(MyLatch); \
+}
+
+/*
+ * Estimate1ByteStrSize
+ *
+ * Estimate the size required for  1Byte strings in shared memory.
+ */
+static inline uint32
+Estimate1ByteStrSize(char *src)
+{
+	return (src) ? sizeof(uint8) + 1 : sizeof(uint8);
+}
+
+/*
+ * EstimateNodeSize
+ *
+ * Estimate the size required for  node type in shared memory.
+ */
+static uint32
+EstimateNodeSize(List *list, char **listStr)
+{
+	uint32		estsize = sizeof(uint32);
+
+	if ((List *) list != NIL)
+	{
+		*listStr = nodeToString(list);
+		estsize += strlen(*listStr) + 1;
+	}
+
+	return estsize;
+}
+
+/*
+ * EstimateCStateSize
+ *
+ * Estimate the size of the required cstate variables in the shared memory.
+ */
+static uint32
+EstimateCStateSize(ParallelContext *pcxt, CopyState cstate, List *attnamelist,
+				   SerializedListToStrCState *list_converted_str)
+{
+	Size		estsize = 0;
+	uint32		estnodesize;
+
+	estsize = add_size(estsize, sizeof(cstate->copy_dest));
+	estsize = add_size(estsize, sizeof(cstate->file_encoding));
+	estsize = add_size(estsize, sizeof(cstate->need_transcoding));
+	estsize = add_size(estsize, sizeof(cstate->encoding_embeds_ascii));
+	estsize = add_size(estsize, sizeof(cstate->csv_mode));
+	estsize = add_size(estsize, sizeof(cstate->header_line));
+	estsize = add_size(estsize, sizeof(cstate->null_print_len));
+	estsize = add_size(estsize, sizeof(cstate->force_quote_all));
+	estsize = add_size(estsize, sizeof(cstate->convert_selectively));
+	estsize = add_size(estsize, sizeof(cstate->num_defaults));
+	estsize = add_size(estsize, sizeof(cstate->pcdata->relid));
+	estsize = add_size(estsize, sizeof(cstate->binary));
+
+	/* Size of null_print is available in null_print_len. */
+	estsize = add_size(estsize, sizeof(uint32) + cstate->null_print_len);
+
+	/* delim, quote & escape all uses 1 byte string to store the information. */
+	estsize = add_size(estsize, Estimate1ByteStrSize(cstate->delim));
+	estsize = add_size(estsize, Estimate1ByteStrSize(cstate->quote));
+	estsize = add_size(estsize, Estimate1ByteStrSize(cstate->escape));
+
+	estnodesize = EstimateNodeSize(attnamelist, &list_converted_str->attnameListStr);
+	estsize = add_size(estsize, estnodesize);
+	estnodesize = EstimateNodeSize(cstate->force_notnull, &list_converted_str->notnullListStr);
+	estsize = add_size(estsize, estnodesize);
+	estnodesize = EstimateNodeSize(cstate->force_null, &list_converted_str->nullListStr);
+	estsize = add_size(estsize, estnodesize);
+	estnodesize = EstimateNodeSize(cstate->convert_select, &list_converted_str->convertListStr);
+	estsize = add_size(estsize, estnodesize);
+	estnodesize = EstimateNodeSize((List *) cstate->whereClause, &list_converted_str->whereClauseStr);
+	estsize = add_size(estsize, estnodesize);
+	estnodesize = EstimateNodeSize(cstate->range_table, &list_converted_str->rangeTableStr);
+	estsize = add_size(estsize, estnodesize);
+
+	shm_toc_estimate_chunk(&pcxt->estimator, estsize);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+	return estsize;
+}
+
+/*
+ * SerializeStringToSharedMemory
+ *
+ * Copy the string to shared memory.
+ */
+static void
+SerializeStringToSharedMemory(char *destptr, char *srcPtr, Size *copiedsize)
+{
+	uint32		len = srcPtr ? strlen(srcPtr) + 1 : 0;
+
+	memcpy(destptr + *copiedsize, (uint32 *) &len, sizeof(uint32));
+	*copiedsize += sizeof(uint32);
+	if (len)
+	{
+		memcpy(destptr + *copiedsize, srcPtr, len);
+		*copiedsize += len;
+	}
+}
+
+/*
+ * Serialize1ByteStr
+ *
+ * Copy 1Byte strings to shared memory.
+ */
+static void
+Serialize1ByteStr(char *dest, char *src, Size *copiedsize)
+{
+	uint8		len = (src) ? 1 : 0;
+
+	memcpy(dest + (*copiedsize), (uint8 *) &len, sizeof(uint8));
+	*copiedsize += sizeof(uint8);
+	if (src)
+		dest[(*copiedsize)++] = src[0];
+}
+
+/*
+ * SerializeParallelCopyState
+ *
+ * Serialize the cstate members required by the workers into shared memory.
+ */
+static void
+SerializeParallelCopyState(ParallelContext *pcxt, CopyState cstate,
+						   uint32 estimatedSize,
+						   SerializedListToStrCState *list_converted_str)
+{
+	char	   *shmptr = (char *) shm_toc_allocate(pcxt->toc, estimatedSize + 1);
+	Size		copiedsize = 0;
+
+	memcpy(shmptr + copiedsize, (char *) &cstate->copy_dest, sizeof(cstate->copy_dest));
+	copiedsize += sizeof(cstate->copy_dest);
+	memcpy(shmptr + copiedsize, (char *) &cstate->file_encoding, sizeof(cstate->file_encoding));
+	copiedsize += sizeof(cstate->file_encoding);
+	memcpy(shmptr + copiedsize, (char *) &cstate->need_transcoding, sizeof(cstate->need_transcoding));
+	copiedsize += sizeof(cstate->need_transcoding);
+	memcpy(shmptr + copiedsize, (char *) &cstate->encoding_embeds_ascii, sizeof(cstate->encoding_embeds_ascii));
+	copiedsize += sizeof(cstate->encoding_embeds_ascii);
+	memcpy(shmptr + copiedsize, (char *) &cstate->csv_mode, sizeof(cstate->csv_mode));
+	copiedsize += sizeof(cstate->csv_mode);
+	memcpy(shmptr + copiedsize, (char *) &cstate->header_line, sizeof(cstate->header_line));
+	copiedsize += sizeof(cstate->header_line);
+	memcpy(shmptr + copiedsize, (char *) &cstate->null_print_len, sizeof(cstate->null_print_len));
+	copiedsize += sizeof(cstate->null_print_len);
+	memcpy(shmptr + copiedsize, (char *) &cstate->force_quote_all, sizeof(cstate->force_quote_all));
+	copiedsize += sizeof(cstate->force_quote_all);
+	memcpy(shmptr + copiedsize, (char *) &cstate->convert_selectively, sizeof(cstate->convert_selectively));
+	copiedsize += sizeof(cstate->convert_selectively);
+	memcpy(shmptr + copiedsize, (char *) &cstate->num_defaults, sizeof(cstate->num_defaults));
+	copiedsize += sizeof(cstate->num_defaults);
+	memcpy(shmptr + copiedsize, (char *) &cstate->pcdata->relid, sizeof(cstate->pcdata->relid));
+	copiedsize += sizeof(cstate->pcdata->relid);
+	memcpy(shmptr + copiedsize, (char *) &cstate->binary, sizeof(cstate->binary));
+	copiedsize += sizeof(cstate->binary);
+
+	memcpy(shmptr + copiedsize, (uint32 *) &cstate->null_print_len, sizeof(uint32));
+	copiedsize += sizeof(uint32);
+	if (cstate->null_print_len)
+	{
+		memcpy(shmptr + copiedsize, cstate->null_print, cstate->null_print_len);
+		copiedsize += cstate->null_print_len;
+	}
+
+	Serialize1ByteStr(shmptr, cstate->delim, &copiedsize);
+	Serialize1ByteStr(shmptr, cstate->quote, &copiedsize);
+	Serialize1ByteStr(shmptr, cstate->escape, &copiedsize);
+
+	SerializeStringToSharedMemory(shmptr, list_converted_str->attnameListStr, &copiedsize);
+	SerializeStringToSharedMemory(shmptr, list_converted_str->notnullListStr, &copiedsize);
+	SerializeStringToSharedMemory(shmptr, list_converted_str->nullListStr, &copiedsize);
+	SerializeStringToSharedMemory(shmptr, list_converted_str->convertListStr, &copiedsize);
+	SerializeStringToSharedMemory(shmptr, list_converted_str->whereClauseStr, &copiedsize);
+	SerializeStringToSharedMemory(shmptr, list_converted_str->rangeTableStr, &copiedsize);
+
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_CSTATE, shmptr);
+}
+
+/*
+ * RestoreNodeFromSharedMemory
+ *
+ * Copy the node contents which was stored as string format in shared memory &
+ * convert it into node type.
+ */
+static void *
+RestoreNodeFromSharedMemory(char *srcPtr, Size *copiedsize, bool isSrcStr)
+{
+	char	   *destptr = NULL;
+	List	   *destList = NIL;
+	uint32		len;
+
+	memcpy((uint32 *) (&len), srcPtr + *copiedsize, sizeof(uint32));
+	*copiedsize += sizeof(uint32);
+	if (len)
+	{
+		destptr = (char *) palloc(len);
+		memcpy(destptr, srcPtr + *copiedsize, len);
+		*copiedsize += len;
+		if (!isSrcStr)
+		{
+			destList = (List *) stringToNode(destptr);
+			pfree(destptr);
+			return destList;
+		}
+
+		return destptr;
+	}
+
+	return NULL;
+}
+
+/*
+ * Restore1ByteStr
+ *
+ * Restore 1Byte strings from shared memory to worker local memory.
+ */
+static void
+Restore1ByteStr(char **dest, char *src, Size *copiedsize)
+{
+	uint8		len;
+
+	memcpy((uint8 *) (&len), src + (*copiedsize), sizeof(uint8));
+	(*copiedsize) += sizeof(uint8);
+	if (len)
+	{
+		*dest = palloc0(sizeof(char) + 1);
+		(*dest)[0] = src[(*copiedsize)++];
+	}
+}
+
+/*
+ * RestoreParallelCopyState
+ *
+ * Retrieve the cstate members which was populated by the leader in the shared
+ * memory.
+ */
+static void
+RestoreParallelCopyState(shm_toc *toc, CopyState cstate, List **attlist)
+{
+	char	   *shared_str_val = (char *) shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE, true);
+	Size		copiedsize = 0;
+
+	memcpy((char *) &cstate->copy_dest, shared_str_val + copiedsize, sizeof(cstate->copy_dest));
+	copiedsize += sizeof(cstate->copy_dest);
+	memcpy((char *) &cstate->file_encoding, shared_str_val + copiedsize, sizeof(cstate->file_encoding));
+	copiedsize += sizeof(cstate->file_encoding);
+	memcpy((char *) &cstate->need_transcoding, shared_str_val + copiedsize, sizeof(cstate->need_transcoding));
+	copiedsize += sizeof(cstate->need_transcoding);
+	memcpy((char *) &cstate->encoding_embeds_ascii, shared_str_val + copiedsize, sizeof(cstate->encoding_embeds_ascii));
+	copiedsize += sizeof(cstate->encoding_embeds_ascii);
+	memcpy((char *) &cstate->csv_mode, shared_str_val + copiedsize, sizeof(cstate->csv_mode));
+	copiedsize += sizeof(cstate->csv_mode);
+	memcpy((char *) &cstate->header_line, shared_str_val + copiedsize, sizeof(cstate->header_line));
+	copiedsize += sizeof(cstate->header_line);
+	memcpy((char *) &cstate->null_print_len, shared_str_val + copiedsize, sizeof(cstate->null_print_len));
+	copiedsize += sizeof(cstate->null_print_len);
+	memcpy((char *) &cstate->force_quote_all, shared_str_val + copiedsize, sizeof(cstate->force_quote_all));
+	copiedsize += sizeof(cstate->force_quote_all);
+	memcpy((char *) &cstate->convert_selectively, shared_str_val + copiedsize, sizeof(cstate->convert_selectively));
+	copiedsize += sizeof(cstate->convert_selectively);
+	memcpy((char *) &cstate->num_defaults, shared_str_val + copiedsize, sizeof(cstate->num_defaults));
+	copiedsize += sizeof(cstate->num_defaults);
+	memcpy((char *) &cstate->pcdata->relid, shared_str_val + copiedsize, sizeof(cstate->pcdata->relid));
+	copiedsize += sizeof(cstate->pcdata->relid);
+	memcpy((char *) &cstate->binary, shared_str_val + copiedsize, sizeof(cstate->binary));
+	copiedsize += sizeof(cstate->binary);
+
+	cstate->null_print = (char *) RestoreNodeFromSharedMemory(shared_str_val, &copiedsize, true);
+	if (!cstate->null_print)
+		cstate->null_print = "";
+
+	Restore1ByteStr(&cstate->delim, shared_str_val, &copiedsize);
+	Restore1ByteStr(&cstate->quote, shared_str_val, &copiedsize);
+	Restore1ByteStr(&cstate->escape, shared_str_val, &copiedsize);
+
+	*attlist = (List *) RestoreNodeFromSharedMemory(shared_str_val, &copiedsize, false);
+	cstate->force_notnull = (List *) RestoreNodeFromSharedMemory(shared_str_val, &copiedsize, false);
+	cstate->force_null = (List *) RestoreNodeFromSharedMemory(shared_str_val, &copiedsize, false);
+	cstate->convert_select = (List *) RestoreNodeFromSharedMemory(shared_str_val, &copiedsize, false);
+	cstate->whereClause = (Node *) RestoreNodeFromSharedMemory(shared_str_val, &copiedsize, false);
+	cstate->range_table = (List *) RestoreNodeFromSharedMemory(shared_str_val, &copiedsize, false);
+}
+
+/*
+ * PopulateParallelCopyShmInfo
+ *
+ * Sets ParallelCopyShmInfo structure members.
+ */
+static void
+PopulateParallelCopyShmInfo(ParallelCopyShmInfo *shared_info_ptr)
+{
+	uint32		count;
+
+	MemSet(shared_info_ptr, 0, sizeof(ParallelCopyShmInfo));
+	shared_info_ptr->is_read_in_progress = true;
+	shared_info_ptr->cur_block_pos = -1;
+	for (count = 0; count < RINGSIZE; count++)
+	{
+		ParallelCopyLineBoundary *lineInfo = &shared_info_ptr->line_boundaries.ring[count];
+
+		pg_atomic_init_u32(&(lineInfo->line_size), -1);
+	}
+}
+
 /*
  * CheckExprParallelSafety
  *
@@ -101,3 +460,898 @@ IsParallelCopyAllowed(CopyState cstate, Oid relid)
 
 	return true;
 }
+
+/*
+ * BeginParallelCopy - Start parallel copy tasks.
+ *
+ * Get the number of workers required to perform the parallel copy. The data
+ * structures that are required by the parallel workers will be initialized, the
+ * size required in DSM will be calculated and the necessary keys will be loaded
+ * in the DSM. The specified number of workers will then be launched.
+ */
+ParallelContext *
+BeginParallelCopy(CopyState cstate, List *attnamelist, Oid relid)
+{
+	ParallelContext *pcxt;
+	ParallelCopyShmInfo *shared_info_ptr;
+	int			parallel_workers = 0;
+	WalUsage   *walusage;
+	BufferUsage *bufferusage;
+	ParallelCopyData *pcdata;
+	MemoryContext oldcontext;
+	uint32		estsize;
+	SerializedListToStrCState list_converted_str = {0};
+
+	CheckTargetRelValidity(cstate);
+	parallel_workers = Min(cstate->nworkers, max_worker_processes);
+
+	/* Can't perform copy in parallel */
+	if (parallel_workers == 0)
+		return NULL;
+
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	MemoryContextSwitchTo(oldcontext);
+
+	cstate->pcdata = pcdata;
+	pcdata->relid = relid;
+	(void) GetCurrentFullTransactionId();
+	(void) GetCurrentCommandId(true);
+
+	EnterParallelMode();
+	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
+								 parallel_workers);
+	Assert(pcxt->nworkers > 0);
+
+	/*
+	 * Estimate size for shared information for PARALLEL_COPY_KEY_SHARED_INFO
+	 */
+	shm_toc_estimate_chunk(&pcxt->estimator, sizeof(ParallelCopyShmInfo));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_CSTATE */
+	estsize = EstimateCStateSize(pcxt, cstate, attnamelist, &list_converted_str);
+
+	/*
+	 * Estimate space for WalUsage and BufferUsage --
+	 * PARALLEL_COPY_KEY_WAL_USAGE and PARALLEL_COPY_KEY_BUFFER_USAGE.
+	 */
+	shm_toc_estimate_chunk(&pcxt->estimator,
+						   mul_size(sizeof(WalUsage), pcxt->nworkers));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+	shm_toc_estimate_chunk(&pcxt->estimator,
+						   mul_size(sizeof(BufferUsage), pcxt->nworkers));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	InitializeParallelDSM(pcxt);
+
+	/* If no DSM segment was available, back out (do serial copy) */
+	if (pcxt->seg == NULL)
+	{
+		EndParallelCopy(pcxt);
+		pfree(pcdata);
+		cstate->pcdata = NULL;
+		return NULL;
+	}
+
+	/* Allocate shared memory for PARALLEL_COPY_KEY_SHARED_INFO */
+	shared_info_ptr = (ParallelCopyShmInfo *) shm_toc_allocate(pcxt->toc, sizeof(ParallelCopyShmInfo));
+	PopulateParallelCopyShmInfo(shared_info_ptr);
+
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_SHARED_INFO, shared_info_ptr);
+	pcdata->pcshared_info = shared_info_ptr;
+
+	SerializeParallelCopyState(pcxt, cstate, estsize, &list_converted_str);
+
+	/*
+	 * Allocate space for each worker's WalUsage and BufferUsage; no need to
+	 * initialize.
+	 */
+	walusage = shm_toc_allocate(pcxt->toc,
+								mul_size(sizeof(WalUsage), pcxt->nworkers));
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_WAL_USAGE, walusage);
+	pcdata->walusage = walusage;
+	bufferusage = shm_toc_allocate(pcxt->toc,
+								   mul_size(sizeof(BufferUsage), pcxt->nworkers));
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_BUFFER_USAGE, bufferusage);
+	pcdata->bufferusage = bufferusage;
+
+	LaunchParallelWorkers(pcxt);
+	if (pcxt->nworkers_launched == 0)
+	{
+		EndParallelCopy(pcxt);
+		pfree(pcdata);
+		cstate->pcdata = NULL;
+		return NULL;
+	}
+
+	/*
+	 * Caller needs to wait for all launched workers when we return.  Make
+	 * sure that the failure-to-start case will not hang forever.
+	 */
+	WaitForParallelWorkersToAttach(pcxt);
+
+	pcdata->is_leader = true;
+	cstate->is_parallel = true;
+	return pcxt;
+}
+
+/*
+ * EndParallelCopy
+ *
+ * End the parallel copy tasks.
+ */
+pg_attribute_always_inline void
+EndParallelCopy(ParallelContext *pcxt)
+{
+	Assert(!IsParallelWorker());
+
+	DestroyParallelContext(pcxt);
+	ExitParallelMode();
+}
+
+/*
+ * InitializeParallelCopyInfo
+ *
+ * Initialize parallel worker.
+ */
+static void
+InitializeParallelCopyInfo(CopyState cstate, List *attnamelist)
+{
+	uint32		count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	PopulateCommonCStateInfo(cstate, tup_desc, attnamelist);
+
+	/* Initialize state variables. */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/* Set up variables to avoid per-attribute overhead. */
+	initStringInfo(&cstate->attribute_buf);
+
+	initStringInfo(&cstate->line_buf);
+	for (count = 0; count < WORKER_CHUNK_COUNT; count++)
+		initStringInfo(&pcdata->worker_line_buf[count].line_buf);
+
+	cstate->line_buf_converted = false;
+	cstate->raw_buf = NULL;
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+
+	PopulateCStateCatalogInfo(cstate);
+
+	/* Create workspace for CopyReadAttributes results. */
+	if (!cstate->binary)
+	{
+		AttrNumber	attr_count = list_length(cstate->attnumlist);
+
+		cstate->max_fields = attr_count;
+		cstate->raw_fields = (char **) palloc(attr_count * sizeof(char *));
+	}
+}
+
+/*
+ * UpdateLineInfo
+ *
+ * Update line information & return.
+ */
+static bool
+UpdateLineInfo(ParallelCopyShmInfo *pcshared_info,
+			   ParallelCopyLineBoundary *lineInfo, uint32 write_pos)
+{
+	elog(DEBUG1, "[Worker] Completed processing line:%u", write_pos);
+	pg_atomic_write_u32(&lineInfo->line_state, LINE_WORKER_PROCESSED);
+	pg_atomic_write_u32(&lineInfo->line_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+	return false;
+}
+
+/*
+ * CacheLineInfo
+ *
+ * Cache the line information to local memory.
+ */
+static bool
+CacheLineInfo(CopyState cstate, uint32 buff_count)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	uint32		write_pos;
+	ParallelCopyDataBlock *data_blk_ptr;
+	ParallelCopyLineBoundary *lineInfo;
+	uint32		offset;
+	uint32		dataSize;
+	uint32		copiedSize = 0;
+
+	resetStringInfo(&pcdata->worker_line_buf[buff_count].line_buf);
+	write_pos = GetLinePosition(cstate);
+	if (-1 == write_pos)
+		return true;
+
+	/* Get the current line information. */
+	lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+	if (pg_atomic_read_u32(&lineInfo->line_size) == 0)
+		return UpdateLineInfo(pcshared_info, lineInfo, write_pos);
+
+	/* Get the block information. */
+	data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+	/* Get the offset information from where the data must be copied. */
+	offset = lineInfo->start_offset;
+	pcdata->worker_line_buf[buff_count].cur_lineno = lineInfo->cur_lineno;
+
+	elog(DEBUG1, "[Worker] Processing - line position:%u, block:%u, unprocessed lines:%u, offset:%u, line size:%u",
+		 write_pos, lineInfo->first_block,
+		 pg_atomic_read_u32(&data_blk_ptr->unprocessed_line_parts),
+		 offset, pg_atomic_read_u32(&lineInfo->line_size));
+
+	for (;;)
+	{
+		uint8		skip_bytes = data_blk_ptr->skip_bytes;
+
+		/*
+		 * There is a possibility that the loop embedded at the bottom of the
+		 * current loop has come out because data_blk_ptr->curr_blk_completed
+		 * is set, but dataSize read might be an old value, if
+		 * data_blk_ptr->curr_blk_completed and the line is completed,
+		 * line_size will be set. Read the line_size again to be sure if it is
+		 * completed or partial block.
+		 */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+		if (dataSize != -1)
+		{
+			uint32		remainingSize = dataSize - copiedSize;
+
+			if (!remainingSize)
+				break;
+
+			/* Whole line is in current block. */
+			if (remainingSize + offset + skip_bytes < DATA_BLOCK_SIZE)
+			{
+				appendBinaryStringInfo(&pcdata->worker_line_buf[buff_count].line_buf,
+									   &data_blk_ptr->data[offset],
+									   remainingSize);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts,
+										1);
+				break;
+			}
+			else
+			{
+				/* Line is spread across the blocks. */
+				uint32		lineInCurrentBlock = (DATA_BLOCK_SIZE - skip_bytes) - offset;
+
+				appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+										 &data_blk_ptr->data[offset],
+										 lineInCurrentBlock);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+				copiedSize += lineInCurrentBlock;
+				while (copiedSize < dataSize)
+				{
+					uint32		currentBlockCopySize;
+					ParallelCopyDataBlock *currBlkPtr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+
+					skip_bytes = currBlkPtr->skip_bytes;
+
+					/*
+					 * If complete data is present in current block use
+					 * dataSize - copiedSize, or copy the whole block from
+					 * current block.
+					 */
+					currentBlockCopySize = Min(dataSize - copiedSize, DATA_BLOCK_SIZE - skip_bytes);
+					appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+											 &currBlkPtr->data[0],
+											 currentBlockCopySize);
+					pg_atomic_sub_fetch_u32(&currBlkPtr->unprocessed_line_parts, 1);
+					copiedSize += currentBlockCopySize;
+					data_blk_ptr = currBlkPtr;
+				}
+
+				break;
+			}
+		}
+		else if (data_blk_ptr->curr_blk_completed)
+		{
+			/* Copy this complete block from the current offset. */
+			uint32		lineInCurrentBlock = (DATA_BLOCK_SIZE - skip_bytes) - offset;
+
+			appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+									 &data_blk_ptr->data[offset],
+									 lineInCurrentBlock);
+			pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+			copiedSize += lineInCurrentBlock;
+
+			/*
+			 * Reset the offset. For the first copy, copy from the offset. For
+			 * the subsequent copy the complete block.
+			 */
+			offset = 0;
+
+			/* Set data_blk_ptr to the following block. */
+			data_blk_ptr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+		}
+
+		for (;;)
+		{
+			/* Get the size of this line */
+			dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+			/*
+			 * If the data is present in current block lineInfo->line_size
+			 * will be updated. If the data is spread across the blocks either
+			 * of lineInfo->line_size or data_blk_ptr->curr_blk_completed can
+			 * be updated. lineInfo->line_size will be updated if the complete
+			 * read is finished. data_blk_ptr->curr_blk_completed will be
+			 * updated if processing of current block is finished and data
+			 * processing is not finished.
+			 */
+			if (data_blk_ptr->curr_blk_completed || (dataSize != -1))
+				break;
+
+			COPY_WAIT_TO_PROCESS()
+		}
+	}
+
+	return UpdateLineInfo(pcshared_info, lineInfo, write_pos);
+}
+
+/*
+ * GetCachedLine
+ *
+ * Return a previously cached line to be processed by the worker.
+ */
+static bool
+GetCachedLine(CopyState cstate, ParallelCopyData *pcdata)
+{
+	cstate->line_buf = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].line_buf;
+	cstate->cur_lineno = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].cur_lineno;
+	cstate->line_buf_valid = true;
+
+	/* Mark that encoding conversion hasn't occurred yet. */
+	cstate->line_buf_converted = false;
+
+	/* For binary format data, we don't need conversion. */
+	if (!cstate->binary)
+		ConvertToServerEncoding(cstate);
+
+	pcdata->worker_line_buf_pos++;
+	return false;
+}
+
+/*
+ * GetWorkerLine
+ *
+ * Returns a line for worker to process.
+ */
+bool
+GetWorkerLine(CopyState cstate)
+{
+	uint32		buff_count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+
+	/*
+	 * Copy the line data to line_buf and release the line position so that
+	 * the worker can continue loading data.
+	 */
+	if (pcdata->worker_line_buf_pos < pcdata->worker_line_buf_count)
+		return GetCachedLine(cstate, pcdata);
+
+	pcdata->worker_line_buf_pos = 0;
+	pcdata->worker_line_buf_count = 0;
+
+	for (buff_count = 0; buff_count < WORKER_CHUNK_COUNT; buff_count++)
+	{
+		bool		result = CacheLineInfo(cstate, buff_count);
+
+		if (result)
+			break;
+
+		pcdata->worker_line_buf_count++;
+	}
+
+	if (pcdata->worker_line_buf_count > 0)
+		return GetCachedLine(cstate, pcdata);
+	else
+		resetStringInfo(&cstate->line_buf);
+
+	return true;
+}
+
+/*
+ * ParallelCopyMain - Parallel copy worker's code.
+ *
+ * Where clause handling, convert tuple to columns, add default null values for
+ * the missing columns that are not present in that record. Find the partition
+ * if it is partitioned table, invoke before row insert Triggers, handle
+ * constraints and insert the tuples.
+ */
+void
+ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
+{
+	CopyState	cstate;
+	ParallelCopyData *pcdata;
+	ParallelCopyShmInfo *pcshared_info;
+	Relation	rel = NULL;
+	MemoryContext oldcontext;
+	List	   *attlist = NIL;
+	WalUsage   *walusage;
+	BufferUsage *bufferusage;
+
+	/* Allocate workspace and zero all fields. */
+	cstate = (CopyStateData *) palloc0(sizeof(CopyStateData));
+
+	/*
+	 * We allocate everything used by a cstate in a new memory context. This
+	 * avoids memory leaks during repeated use of COPY in a query.
+	 */
+	cstate->copycontext = AllocSetContextCreate(CurrentMemoryContext,
+												"COPY",
+												ALLOCSET_DEFAULT_SIZES);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	cstate->pcdata = pcdata;
+	pcdata->is_leader = false;
+	pcdata->worker_processed_pos = -1;
+	cstate->is_parallel = true;
+	pcshared_info = (ParallelCopyShmInfo *) shm_toc_lookup(toc, PARALLEL_COPY_KEY_SHARED_INFO, false);
+
+	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
+
+	pcdata->pcshared_info = pcshared_info;
+	RestoreParallelCopyState(toc, cstate, &attlist);
+
+	/* Open and lock the relation, using the appropriate lock type. */
+	rel = table_open(cstate->pcdata->relid, RowExclusiveLock);
+	cstate->rel = rel;
+	InitializeParallelCopyInfo(cstate, attlist);
+
+	/* Prepare to track buffer usage during parallel execution */
+	InstrStartParallelQuery();
+
+	CopyFrom(cstate);
+
+	if (rel != NULL)
+		table_close(rel, RowExclusiveLock);
+
+	/* Report WAL/buffer usage during parallel execution */
+	bufferusage = shm_toc_lookup(toc, PARALLEL_COPY_KEY_BUFFER_USAGE, false);
+	walusage = shm_toc_lookup(toc, PARALLEL_COPY_KEY_WAL_USAGE, false);
+	InstrEndParallelQuery(&bufferusage[ParallelWorkerNumber],
+						  &walusage[ParallelWorkerNumber]);
+
+	MemoryContextSwitchTo(oldcontext);
+	MemoryContextDelete(cstate->copycontext);
+	pfree(cstate);
+	return;
+}
+
+/*
+ * UpdateSharedLineInfo
+ *
+ * Update the line information.
+ */
+uint32
+UpdateSharedLineInfo(CopyState cstate, uint32 blk_pos, uint32 offset,
+					 uint32 line_size, uint32 line_state, uint32 blk_line_pos)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyLineBoundaries *lineBoundaryPtr = &pcshared_info->line_boundaries;
+	ParallelCopyLineBoundary *lineInfo;
+	uint32		line_pos;
+
+	/* blk_line_pos will be valid in case line_pos was blocked earlier. */
+	if (blk_line_pos == -1)
+	{
+		line_pos = lineBoundaryPtr->pos;
+
+		/* Update the line information for the worker to pick and process. */
+		lineInfo = &lineBoundaryPtr->ring[line_pos];
+		while (pg_atomic_read_u32(&lineInfo->line_size) != -1)
+			COPY_WAIT_TO_PROCESS()
+
+				lineInfo->first_block = blk_pos;
+		lineInfo->start_offset = offset;
+		lineInfo->cur_lineno = cstate->cur_lineno;
+		lineBoundaryPtr->pos = (lineBoundaryPtr->pos + 1) % RINGSIZE;
+	}
+	else
+	{
+		line_pos = blk_line_pos;
+		lineInfo = &lineBoundaryPtr->ring[line_pos];
+	}
+
+	if (line_state == LINE_LEADER_POPULATED)
+	{
+		elog(DEBUG1, "[Leader] Added line with block:%u, offset:%u, line position:%u, line size:%u",
+			 lineInfo->first_block, lineInfo->start_offset, line_pos,
+			 line_size);
+		pcshared_info->populated++;
+		if (line_size == 0 || cstate->binary)
+			pg_atomic_write_u32(&lineInfo->line_state, line_state);
+		else
+		{
+			uint32		current_line_state = LINE_LEADER_POPULATING;
+
+			/*
+			 * Make sure that no worker has consumed this element, if this
+			 * line is spread across multiple data blocks, worker would have
+			 * started processing, no need to change the state to
+			 * LINE_LEADER_POPULATING in this case.
+			 */
+			(void) pg_atomic_compare_exchange_u32(&lineInfo->line_state,
+												  &current_line_state,
+												  LINE_LEADER_POPULATED);
+		}
+	}
+	else
+	{
+		elog(DEBUG1, "[Leader] Adding - block:%u, offset:%u, line position:%u",
+			 lineInfo->first_block, lineInfo->start_offset, line_pos);
+		pg_atomic_write_u32(&lineInfo->line_state, line_state);
+	}
+
+	pg_atomic_write_u32(&lineInfo->line_size, line_size);
+
+	return line_pos;
+}
+
+/*
+ * ParallelCopyFrom - parallel copy leader's functionality.
+ *
+ * Leader executes the before statement for before statement trigger, if before
+ * statement trigger is present. It will read the table data from the file and
+ * copy the contents to DSM data blocks. It will then read the input contents
+ * from the DSM data block and identify the records based on line breaks. This
+ * information is called line or a record that need to be inserted into a
+ * relation. The line information will be stored in ParallelCopyLineBoundary DSM
+ * data structure. Workers will then process this information and insert the
+ * data in to table. It will repeat this process until the all data is read from
+ * the file and all the DSM data blocks are processed. While processing if
+ * leader identifies that DSM Data blocks or DSM ParallelCopyLineBoundary data
+ * structures is full, leader will wait till the worker frees up some entries
+ * and repeat the process. It will wait till all the lines populated are
+ * processed by the workers and exits.
+ */
+void
+ParallelCopyFrom(CopyState cstate)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ErrorContextCallback errcallback;
+
+	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
+
+	/* raw_buf is not used in parallel copy, instead data blocks are used. */
+	pfree(cstate->raw_buf);
+	cstate->raw_buf = NULL;
+
+	/* Execute the before statement triggers from the leader */
+	ExecBeforeStmtTrigger(cstate);
+
+	/* Set up callback to identify error line number */
+	errcallback.callback = CopyFromErrorCallback;
+	errcallback.arg = (void *) cstate;
+	errcallback.previous = error_context_stack;
+	error_context_stack = &errcallback;
+
+	/* On input just throw the header line away. */
+	if (cstate->cur_lineno == 0 && cstate->header_line)
+	{
+		cstate->cur_lineno++;
+		if (CopyReadLine(cstate))
+		{
+			pcshared_info->is_read_in_progress = false;
+			return;				/* done */
+		}
+	}
+
+	for (;;)
+	{
+		bool		done;
+
+		CHECK_FOR_INTERRUPTS();
+
+		cstate->cur_lineno++;
+
+		/* Actually read the line into memory here. */
+		done = CopyReadLine(cstate);
+
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			break;
+	}
+
+
+	/* Done, clean up */
+	error_context_stack = errcallback.previous;
+
+	/*
+	 * In the old protocol, tell pqcomm that we can process normal protocol
+	 * messages again.
+	 */
+	if (cstate->copy_dest == COPY_OLD_FE)
+		pq_endmsgread();
+
+	pcshared_info->is_read_in_progress = false;
+	cstate->cur_lineno = 0;
+}
+
+/*
+ * GetLinePosition
+ *
+ * Return the line position once the leader has populated the data.
+ */
+uint32
+GetLinePosition(CopyState cstate)
+{
+	ParallelCopyData *pcdata = cstate->pcdata;
+	ParallelCopyShmInfo *pcshared_info = pcdata->pcshared_info;
+	uint32		previous_pos = pcdata->worker_processed_pos;
+	uint32		write_pos = (previous_pos == -1) ? 0 : (previous_pos + 1) % RINGSIZE;
+
+	for (;;)
+	{
+		uint32		dataSize;
+		bool		is_read_in_progress = pcshared_info->is_read_in_progress;
+		ParallelCopyLineBoundary *lineInfo;
+		ParallelCopyDataBlock *data_blk_ptr;
+		uint32		line_state = LINE_LEADER_POPULATED;
+		ParallelCopyLineState curr_line_state;
+
+		CHECK_FOR_INTERRUPTS();
+
+		/* File read completed & no elements to process. */
+		if (!is_read_in_progress &&
+			(pcshared_info->populated ==
+			 pg_atomic_read_u64(&pcshared_info->total_worker_processed)))
+		{
+			write_pos = -1;
+			break;
+		}
+
+		/* Get the current line information. */
+		lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+		curr_line_state = pg_atomic_read_u32(&lineInfo->line_state);
+		if ((write_pos % WORKER_CHUNK_COUNT == 0) &&
+			(curr_line_state == LINE_WORKER_PROCESSED ||
+			 curr_line_state == LINE_WORKER_PROCESSING))
+		{
+			pcdata->worker_processed_pos = write_pos;
+			write_pos = (write_pos + WORKER_CHUNK_COUNT) % RINGSIZE;
+			continue;
+		}
+
+		/* Get the size of this line. */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+		if (dataSize != 0)		/* If not an empty line. */
+		{
+			/* Get the block information. */
+			data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+			if (!data_blk_ptr->curr_blk_completed && (dataSize == -1))
+			{
+				/* Wait till the current line or block is added. */
+				COPY_WAIT_TO_PROCESS()
+					continue;
+			}
+		}
+
+		/* Make sure that no worker has consumed this element. */
+		if (pg_atomic_compare_exchange_u32(&lineInfo->line_state,
+										   &line_state, LINE_WORKER_PROCESSING))
+			break;
+
+		line_state = LINE_LEADER_POPULATING;
+		/* Make sure that no worker has consumed this element. */
+		if (pg_atomic_compare_exchange_u32(&lineInfo->line_state,
+										   &line_state, LINE_WORKER_PROCESSING))
+			break;
+	}
+
+	pcdata->worker_processed_pos = write_pos;
+	return write_pos;
+}
+
+/*
+ * GetFreeCopyBlock
+ *
+ * Get a free block for data to be copied.
+ */
+static pg_attribute_always_inline uint32
+GetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	int			count = 0;
+	uint32		last_free_block = pcshared_info->cur_block_pos;
+	uint32		block_pos = (last_free_block != -1) ? ((last_free_block + 1) % MAX_BLOCKS_COUNT) : 0;
+
+	/*
+	 * Get a new block for copying data, don't check current block, current
+	 * block will have some unprocessed data.
+	 */
+	while (count < (MAX_BLOCKS_COUNT - 1))
+	{
+		ParallelCopyDataBlock *dataBlkPtr = &pcshared_info->data_blocks[block_pos];
+		uint32		unprocessed_line_parts = pg_atomic_read_u32(&dataBlkPtr->unprocessed_line_parts);
+
+		if (unprocessed_line_parts == 0)
+		{
+			dataBlkPtr->curr_blk_completed = false;
+			dataBlkPtr->skip_bytes = 0;
+			dataBlkPtr->following_block = -1;
+			pcshared_info->cur_block_pos = block_pos;
+			MemSet(&dataBlkPtr->data[0], 0, DATA_BLOCK_SIZE);
+			return block_pos;
+		}
+
+		block_pos = (block_pos + 1) % MAX_BLOCKS_COUNT;
+		count++;
+	}
+
+	return -1;
+}
+
+/*
+ * WaitGetFreeCopyBlock
+ *
+ * If there are no blocks available, wait and get a block for copying data.
+ */
+uint32
+WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	uint32		new_free_pos = -1;
+
+	for (;;)
+	{
+		new_free_pos = GetFreeCopyBlock(pcshared_info);
+		if (new_free_pos != -1) /* We have got one block, break now. */
+			break;
+
+		COPY_WAIT_TO_PROCESS()
+	}
+
+	return new_free_pos;
+}
+
+/*
+ * SetRawBufForLoad
+ *
+ * Set raw_buf to the shared memory where the file data must be read.
+ */
+void
+SetRawBufForLoad(CopyState cstate, uint32 line_size, uint32 copy_buf_len,
+				 uint32 raw_buf_ptr, char **copy_raw_buf)
+{
+	ParallelCopyShmInfo *pcshared_info;
+	uint32		cur_block_pos;
+	uint32		next_block_pos;
+	ParallelCopyDataBlock *cur_data_blk_ptr = NULL;
+	ParallelCopyDataBlock *next_data_blk_ptr = NULL;
+
+	Assert(IsParallelCopy());
+
+	pcshared_info = cstate->pcdata->pcshared_info;
+	cur_block_pos = pcshared_info->cur_block_pos;
+	cur_data_blk_ptr = (cstate->raw_buf) ? &pcshared_info->data_blocks[cur_block_pos] : NULL;
+	next_block_pos = WaitGetFreeCopyBlock(pcshared_info);
+	next_data_blk_ptr = &pcshared_info->data_blocks[next_block_pos];
+
+	/* set raw_buf to the data block in shared memory */
+	cstate->raw_buf = next_data_blk_ptr->data;
+	*copy_raw_buf = cstate->raw_buf;
+	if (cur_data_blk_ptr)
+	{
+		if (line_size)
+		{
+			/*
+			 * Mark the previous block as completed, worker can start copying
+			 * this data.
+			 */
+			cur_data_blk_ptr->following_block = next_block_pos;
+			pg_atomic_add_fetch_u32(&cur_data_blk_ptr->unprocessed_line_parts, 1);
+			cur_data_blk_ptr->curr_blk_completed = true;
+		}
+
+		cur_data_blk_ptr->skip_bytes = copy_buf_len - raw_buf_ptr;
+		cstate->raw_buf_len = cur_data_blk_ptr->skip_bytes;
+
+		/* Copy the skip bytes to the next block to be processed. */
+		if (cur_data_blk_ptr->skip_bytes)
+			memcpy(cstate->raw_buf, cur_data_blk_ptr->data + raw_buf_ptr,
+				   cur_data_blk_ptr->skip_bytes);
+	}
+	else
+		cstate->raw_buf_len = 0;
+
+	cstate->raw_buf_index = 0;
+}
+
+/*
+ * EndLineParallelCopy
+ *
+ * Update the line information in shared memory.
+ */
+void
+EndLineParallelCopy(CopyState cstate, uint32 line_pos, uint32 line_size,
+					uint32 raw_buf_ptr)
+{
+	uint8		new_line_size;
+
+	if (!IsParallelCopy())
+		return;
+
+	if (!IsHeaderLine())
+	{
+		ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+		/* Set the newline size. */
+		if (cstate->eol_type == EOL_NL || cstate->eol_type == EOL_CR)
+			new_line_size = 1;
+		else if (cstate->eol_type == EOL_CRNL)
+			new_line_size = 2;
+		else
+			new_line_size = 0;
+
+		if (line_size)
+		{
+			/*
+			 * If the new_line_size > raw_buf_ptr, then the new block has only
+			 * new line char content. The unprocessed count should not be
+			 * increased in this case.
+			 */
+			if (raw_buf_ptr > new_line_size)
+			{
+				uint32		cur_block_pos = pcshared_info->cur_block_pos;
+				ParallelCopyDataBlock *curr_data_blk_ptr = &pcshared_info->data_blocks[cur_block_pos];
+
+				pg_atomic_add_fetch_u32(&curr_data_blk_ptr->unprocessed_line_parts, 1);
+			}
+
+			/*
+			 * Update line size & line state, other members are already
+			 * updated.
+			 */
+			(void) UpdateSharedLineInfo(cstate, -1, -1, line_size,
+										LINE_LEADER_POPULATED, line_pos);
+		}
+		else if (new_line_size)
+			/* This means only new line char, empty record should be inserted. */
+			(void) UpdateSharedLineInfo(cstate, -1, -1, 0,
+										LINE_LEADER_POPULATED, -1);
+	}
+}
+
+/*
+ * ExecBeforeStmtTrigger
+ *
+ * Execute the before statement trigger, this will be executed for parallel copy
+ * by the leader process. This function code changes has been taken from
+ * CopyFrom function. Refer to comments section of respective code in CopyFrom
+ * function for more detailed information.
+ */
+void
+ExecBeforeStmtTrigger(CopyState cstate)
+{
+	EState	   *estate = CreateExecutorState();
+	ResultRelInfo *resultRelInfo;
+
+	Assert(IsLeader());
+	ExecInitRangeTable(estate, cstate->range_table);
+	resultRelInfo = makeNode(ResultRelInfo);
+	ExecInitResultRelation(estate, resultRelInfo, 1);
+	CheckValidResultRel(resultRelInfo, CMD_INSERT);
+	AfterTriggerBeginQuery();
+	ExecBSInsertTriggers(estate, resultRelInfo);
+	AfterTriggerEndQuery(estate);
+	ExecCloseResultRelations(estate);
+	ExecCloseRangeTableRelations(estate);
+	FreeExecutorState(estate);
+}
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index 5238a96..b9da375 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -2381,7 +2381,7 @@ psql_completion(const char *text, int start, int end)
 	/* Complete COPY <sth> FROM|TO filename WITH ( */
 	else if (Matches("COPY|\\copy", MatchAny, "FROM|TO", MatchAny, "WITH", "("))
 		COMPLETE_WITH("FORMAT", "FREEZE", "DELIMITER", "NULL",
-					  "HEADER", "QUOTE", "ESCAPE", "FORCE_QUOTE",
+					  "HEADER", "PARALLEL", "QUOTE", "ESCAPE", "FORCE_QUOTE",
 					  "FORCE_NOT_NULL", "FORCE_NULL", "ENCODING");
 
 	/* Complete COPY <sth> FROM|TO filename WITH (FORMAT */
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index fd3a78e..ac92aca 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -14,6 +14,7 @@
 #ifndef COPY_H
 #define COPY_H
 
+#include "access/parallel.h"
 #include "commands/copy_internal.h"
 #include "nodes/execnodes.h"
 #include "nodes/parsenodes.h"
@@ -38,6 +39,26 @@ extern uint64 CopyFrom(CopyState cstate);
 
 extern DestReceiver *CreateCopyDestReceiver(void);
 
-extern bool IsParallelCopyAllowed(CopyState cstate, Oid relid);
+extern void PopulateCommonCStateInfo(CopyState cstate, TupleDesc tup_desc,
+									 List *attnamelist);
+extern void ConvertToServerEncoding(CopyState cstate);
 
+extern void ParallelCopyMain(dsm_segment *seg, shm_toc *toc);
+extern ParallelContext *BeginParallelCopy(CopyState cstate, List *attnamelist, Oid relid);
+extern void ParallelCopyFrom(CopyState cstate);
+extern void EndParallelCopy(ParallelContext *pcxt);
+extern bool IsParallelCopyAllowed(CopyState cstate, Oid relid);
+extern void ExecBeforeStmtTrigger(CopyState cstate);
+extern void CheckTargetRelValidity(CopyState cstate);
+extern void PopulateCStateCatalogInfo(CopyState cstate);
+extern uint32 GetLinePosition(CopyState cstate);
+extern bool GetWorkerLine(CopyState cstate);
+extern bool CopyReadLine(CopyState cstate);
+extern uint32 WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info);
+extern void SetRawBufForLoad(CopyState cstate, uint32 line_size, uint32 copy_buf_len,
+							 uint32 raw_buf_ptr, char **copy_raw_buf);
+extern uint32 UpdateSharedLineInfo(CopyState cstate, uint32 blk_pos, uint32 offset,
+								   uint32 line_size, uint32 line_state, uint32 blk_line_pos);
+extern void EndLineParallelCopy(CopyState cstate, uint32 line_pos, uint32 line_size,
+								uint32 raw_buf_ptr);
 #endif							/* COPY_H */
diff --git a/src/include/commands/copy_internal.h b/src/include/commands/copy_internal.h
index ea4bfca..30eaa2e 100644
--- a/src/include/commands/copy_internal.h
+++ b/src/include/commands/copy_internal.h
@@ -17,6 +17,42 @@
 #include "commands/trigger.h"
 #include "executor/executor.h"
 
+#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+
+/*
+ * The macros DATA_BLOCK_SIZE, RINGSIZE & MAX_BLOCKS_COUNT stores the records
+ * read from the file that need to be inserted into the relation. These values
+ * help in the handover of multiple records with the significant size of data to
+ * be processed by each of the workers. This also ensures there is no context
+ * switch and the work is fairly distributed among the workers. This number
+ * showed best results in the performance tests.
+ */
+#define DATA_BLOCK_SIZE RAW_BUF_SIZE
+
+/*
+ * It can hold MAX_BLOCKS_COUNT blocks of RAW_BUF_SIZE data in DSM to be
+ * processed by the worker.
+ */
+#define MAX_BLOCKS_COUNT 1024
+
+/*
+ * It can hold upto RINGSIZE record information for worker to process. RINGSIZE
+ * should be a multiple of WORKER_CHUNK_COUNT, as wrap around cases is currently
+ * not handled while selecting the WORKER_CHUNK_COUNT by the worker.
+ */
+#define RINGSIZE (10 * 1024)
+
+/*
+ * While accessing DSM, each worker will pick the WORKER_CHUNK_COUNT records
+ * from the DSM data blocks at a time and store them in it's local memory. This
+ * is to make workers not contend much while getting record information from the
+ * DSM. Read RINGSIZE comments before changing this value.
+ */
+#define WORKER_CHUNK_COUNT 64
+
+#define IsParallelCopy()		(cstate->is_parallel)
+#define IsLeader()				(cstate->pcdata->is_leader)
+#define IsWorker()				(IsParallelCopy() && !IsLeader())
 #define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
 
 /*
@@ -43,6 +79,18 @@ typedef enum EolType
 } EolType;
 
 /*
+ * State of the line.
+ */
+typedef enum ParallelCopyLineState
+{
+	LINE_INIT,					/* initial state of line */
+	LINE_LEADER_POPULATING,		/* leader processing line */
+	LINE_LEADER_POPULATED,		/* leader completed populating line */
+	LINE_WORKER_PROCESSING,		/* worker processing line */
+	LINE_WORKER_PROCESSED		/* worker completed processing line */
+} ParallelCopyLineState;
+
+/*
  * Represents the heap insert method to be used during COPY FROM.
  */
 typedef enum CopyInsertMethod
@@ -52,7 +100,180 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
-#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+/*
+ * Copy data block information.
+ *
+ * These data blocks are created in DSM. Data read from file will be copied in
+ * these DSM data blocks. The leader process identifies the records and the
+ * record information will be shared to the workers. The workers will insert the
+ * records into the table. There can be one or more number of records in each of
+ * the data block based on the record size.
+ */
+typedef struct ParallelCopyDataBlock
+{
+	/* The number of unprocessed lines in the current block. */
+	pg_atomic_uint32 unprocessed_line_parts;
+
+	/*
+	 * If the current line data is continued into another block,
+	 * following_block will have the position where the remaining data need to
+	 * be read.
+	 */
+	uint32		following_block;
+
+	/*
+	 * This flag will be set, when the leader finds out this block can be read
+	 * safely by the worker. This helps the worker to start processing the
+	 * line early where the line will be spread across many blocks and the
+	 * worker need not wait for the complete line to be processed.
+	 */
+	bool		curr_blk_completed;
+
+	/*
+	 * Few bytes need to be skipped from this block, this will be set when a
+	 * sequence of characters like \r\n is expected, but end of our block
+	 * contained only \r. In this case we copy the data from \r into the new
+	 * block as they have to be processed together to identify end of line.
+	 * Worker will use skip_bytes to know that this data must be skipped from
+	 * this data block.
+	 */
+	uint8		skip_bytes;
+	char		data[DATA_BLOCK_SIZE];	/* data read from file */
+} ParallelCopyDataBlock;
+
+/*
+ * Individual line information.
+ *
+ * ParallelCopyLineBoundary is common data structure between leader & worker.
+ * Leader process will be populating data block, data block offset & the size of
+ * the record in DSM for the workers to copy the data into the relation.
+ * The leader & worker process access the shared line information by following
+ * the below steps to avoid any data corruption or hang:
+ *
+ * Leader should operate in the following order:
+ * 1) check if line_size is -1, if line_size is not -1 wait until line_size is
+ * set to -1 by the worker. If line_size is -1 it means worker is still
+ * processing.
+ * 2) set line_state to LINE_LEADER_POPULATING, so that the worker knows that
+ * leader is populating this line.
+ * 3) update first_block, start_offset & cur_lineno in any order.
+ * 4) update line_size.
+ * 5) update line_state to LINE_LEADER_POPULATED.
+ *
+ * Worker should operate in the following order:
+ * 1) check line_state is LINE_LEADER_POPULATED, if not it means leader is still
+ * populating the data.
+ * 2) read line_size to know the size of the data.
+ * 3) only one worker should choose one line for processing, this is handled by
+ *    using pg_atomic_compare_exchange_u32, worker will change the state to
+ *    LINE_WORKER_PROCESSING only if line_state is LINE_LEADER_POPULATED.
+ * 4) read first_block, start_offset & cur_lineno in any order.
+ * 5) process line_size data.
+ * 6) update line_size to -1.
+ */
+typedef struct ParallelCopyLineBoundary
+{
+	/* Position of the first block in data_blocks array. */
+	uint32		first_block;
+	uint32		start_offset;	/* start offset of the line */
+
+	/*
+	 * Size of the current line -1 means line is yet to be filled completely,
+	 * 0 means empty line, >0 means line filled with line size data.
+	 */
+	pg_atomic_uint32 line_size;
+	pg_atomic_uint32 line_state;	/* line state */
+	uint64		cur_lineno;		/* line number for error messages */
+} ParallelCopyLineBoundary;
+
+/*
+ * Circular queue used to store the line information.
+ */
+typedef struct ParallelCopyLineBoundaries
+{
+	/* Position for the leader to populate a line. */
+	uint32		pos;
+
+	/* Data read from the file/stdin by the leader process. */
+	ParallelCopyLineBoundary ring[RINGSIZE];
+} ParallelCopyLineBoundaries;
+
+/*
+ * Shared information among parallel copy workers. This will be allocated in the
+ * DSM segment.
+ */
+typedef struct ParallelCopyShmInfo
+{
+	bool		is_read_in_progress;	/* file read status */
+
+	/*
+	 * Actual lines inserted by worker, will not be same as
+	 * total_worker_processed if where condition is specified along with copy.
+	 * This will be the actual records inserted into the relation.
+	 */
+	pg_atomic_uint64 processed;
+
+	/*
+	 * The number of records currently processed by the worker, this will also
+	 * include the number of records that was filtered because of where
+	 * clause.
+	 */
+	pg_atomic_uint64 total_worker_processed;
+	uint64		populated;		/* lines populated by leader */
+	uint32		cur_block_pos;	/* current data block */
+	ParallelCopyDataBlock data_blocks[MAX_BLOCKS_COUNT];	/* data block array */
+	ParallelCopyLineBoundaries line_boundaries; /* line array */
+} ParallelCopyShmInfo;
+
+/*
+ * Parallel copy line buffer information.
+ */
+typedef struct ParallelCopyLineBuf
+{
+	StringInfoData line_buf;
+	uint64		cur_lineno;		/* line number for error messages */
+} ParallelCopyLineBuf;
+
+/*
+ * This structure helps in storing the common List/Node from CopyStateData that
+ * are required by the workers. This information will then be copied and stored
+ * into the DSM for the worker to retrieve and copy it to CopyStateData.
+ */
+typedef struct SerializedListToStrCState
+{
+	char	   *whereClauseStr;
+	char	   *rangeTableStr;
+	char	   *attnameListStr;
+	char	   *notnullListStr;
+	char	   *nullListStr;
+	char	   *convertListStr;
+} SerializedListToStrCState;
+
+/*
+ * Parallel copy data information.
+ */
+typedef struct ParallelCopyData
+{
+	Oid			relid;			/* relation id of the table */
+	ParallelCopyShmInfo *pcshared_info; /* common info in shared memory */
+	bool		is_leader;
+
+	/* line position which worker is processing */
+	uint32		worker_processed_pos;
+
+	WalUsage   *walusage;
+	BufferUsage *bufferusage;
+
+	/*
+	 * Local line_buf array, workers will copy it here and release the lines
+	 * for the leader to continue.
+	 */
+	ParallelCopyLineBuf worker_line_buf[WORKER_CHUNK_COUNT];
+	uint32		worker_line_buf_count;	/* Number of lines */
+
+	/* Current position in worker_line_buf */
+	uint32		worker_line_buf_pos;
+} ParallelCopyData;
 
 typedef int (*copy_data_source_cb) (void *outbuf, int minread, int maxread);
 
@@ -188,6 +409,9 @@ typedef struct CopyStateData
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
+	int			nworkers;
+	bool		is_parallel;
+	ParallelCopyData *pcdata;
 	/* Shorthand for number of unconsumed bytes available in raw_buf */
 #define RAW_BUF_BYTES(cstate) ((cstate)->raw_buf_len - (cstate)->raw_buf_index)
 } CopyStateData;
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index fde701b..13c0f53 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1705,6 +1705,13 @@ ParallelBitmapHeapState
 ParallelBlockTableScanDesc
 ParallelCompletionPtr
 ParallelContext
+ParallelCopyLineBoundaries
+ParallelCopyLineBoundary
+ParallelCopyData
+ParallelCopyDataBlock
+ParallelCopyLineBuf
+ParallelCopyLineState
+ParallelCopyShmInfo
 ParallelExecutorInfo
 ParallelHashGrowth
 ParallelHashJoinBatch
@@ -2227,6 +2234,7 @@ SerCommitSeqNo
 SerialControl
 SerializableXactHandle
 SerializedActiveRelMaps
+SerializedListToStrCState
 SerializedReindexState
 SerializedSnapshotData
 SerializedTransactionState
-- 
1.8.3.1

v10-0004-Documentation-for-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=v10-0004-Documentation-for-parallel-copy.patchDownload
From 29a7a0e0858cca5cf790e9b820c02b7b0d2d0326 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Sat, 1 Aug 2020 09:00:36 +0530
Subject: [PATCH v10 4/6] Documentation for parallel copy.

This patch has the documentation changes for parallel copy.
---
 doc/src/sgml/ref/copy.sgml | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/doc/src/sgml/ref/copy.sgml b/doc/src/sgml/ref/copy.sgml
index 369342b..328a5f1 100644
--- a/doc/src/sgml/ref/copy.sgml
+++ b/doc/src/sgml/ref/copy.sgml
@@ -37,6 +37,7 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
     DELIMITER '<replaceable class="parameter">delimiter_character</replaceable>'
     NULL '<replaceable class="parameter">null_string</replaceable>'
     HEADER [ <replaceable class="parameter">boolean</replaceable> ]
+    PARALLEL <replaceable class="parameter">integer</replaceable>
     QUOTE '<replaceable class="parameter">quote_character</replaceable>'
     ESCAPE '<replaceable class="parameter">escape_character</replaceable>'
     FORCE_QUOTE { ( <replaceable class="parameter">column_name</replaceable> [, ...] ) | * }
@@ -277,6 +278,22 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
    </varlistentry>
 
    <varlistentry>
+    <term><literal>PARALLEL</literal></term>
+    <listitem>
+     <para>
+      Perform <command>COPY FROM</command> in parallel using <replaceable
+      class="parameter">integer</replaceable> background workers.  Please
+      note that it is not guaranteed that the number of parallel workers
+      specified in <replaceable class="parameter">integer</replaceable> will
+      be used during execution.  It is possible for a copy to run with fewer
+      workers than specified, or even with no workers at all (for example,
+      due to the setting of max_worker_processes). This option is allowed
+      only in <command>COPY FROM</command>.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><literal>QUOTE</literal></term>
     <listitem>
      <para>
@@ -953,6 +970,20 @@ COPY country FROM '/usr1/proj/bray/sql/country_data';
   </para>
 
   <para>
+   To copy data parallelly from a file into the <literal>country</literal> table:
+<programlisting>
+COPY country FROM '/usr1/proj/bray/sql/country_data' WITH (PARALLEL 1);
+</programlisting>
+  </para>
+
+  <para>
+   To copy data parallelly from STDIN into the <literal>country</literal> table:
+<programlisting>
+COPY country FROM STDIN WITH (PARALLEL 1);
+</programlisting>
+  </para>
+
+  <para>
    To copy into a file just the countries whose names start with 'A':
 <programlisting>
 COPY (SELECT * FROM country WHERE country_name LIKE 'A%') TO '/usr1/proj/bray/sql/a_list_countries.copy';
-- 
1.8.3.1

v10-0005-Parallel-Copy-For-Binary-Format-Files.patchtext/x-patch; charset=US-ASCII; name=v10-0005-Parallel-Copy-For-Binary-Format-Files.patchDownload
From 174ce3d62b1aa29c49096f3e077c9fed4b66b2da Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 18 Nov 2020 11:36:36 +0530
Subject: [PATCH v10 5/6] Parallel Copy For Binary Format Files

Leader reads data from the file into the DSM data blocks each of 64K size.
It also identifies each tuple data block id, start offset, end offset,
tuple size and updates this information in the ring data structure.
Workers parallelly read the tuple information from the ring data structure,
the actual tuple data from the data blocks and parallelly insert the tuples
into the table.
---
 src/backend/commands/copy.c          | 124 ++++++-------
 src/backend/commands/copyparallel.c  | 350 ++++++++++++++++++++++++++++++++---
 src/include/commands/copy.h          |   8 +
 src/include/commands/copy_internal.h | 117 ++++++++++++
 4 files changed, 512 insertions(+), 87 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 6856ef5..2f08dc8 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -223,14 +223,11 @@ static void CopySendData(CopyState cstate, const void *databuf, int datasize);
 static void CopySendString(CopyState cstate, const char *str);
 static void CopySendChar(CopyState cstate, char c);
 static void CopySendEndOfRow(CopyState cstate);
-static int	CopyGetData(CopyState cstate, void *databuf,
-						int minread, int maxread);
 static void CopySendInt32(CopyState cstate, int32 val);
 static bool CopyGetInt32(CopyState cstate, int32 *val);
 static void CopySendInt16(CopyState cstate, int16 val);
 static bool CopyGetInt16(CopyState cstate, int16 *val);
 static bool CopyLoadRawBuf(CopyState cstate);
-static int	CopyReadBinaryData(CopyState cstate, char *dest, int nbytes);
 static void ClearEOLFromCopiedData(CopyState cstate, char *copy_line_data,
 								   int copy_line_pos, int *copy_line_size);
 
@@ -447,7 +444,7 @@ CopySendEndOfRow(CopyState cstate)
  *
  * NB: no data conversion is applied here.
  */
-static int
+int
 CopyGetData(CopyState cstate, void *databuf, int minread, int maxread)
 {
 	int			bytesread = 0;
@@ -580,10 +577,25 @@ CopyGetInt32(CopyState cstate, int32 *val)
 {
 	uint32		buf;
 
-	if (CopyReadBinaryData(cstate, (char *) &buf, sizeof(buf)) != sizeof(buf))
+	/*
+	 * For parallel copy, avoid reading data to raw buf, read directly from
+	 * file, later the data will be read to parallel copy data buffers.
+	 */
+	if (cstate->nworkers > 0)
 	{
-		*val = 0;				/* suppress compiler warning */
-		return false;
+		if (CopyGetData(cstate, &buf, sizeof(buf), sizeof(buf)) != sizeof(buf))
+		{
+			*val = 0;			/* suppress compiler warning */
+			return false;
+		}
+	}
+	else
+	{
+		if (CopyReadBinaryData(cstate, (char *) &buf, sizeof(buf)) != sizeof(buf))
+		{
+			*val = 0;			/* suppress compiler warning */
+			return false;
+		}
 	}
 	*val = (int32) pg_ntoh32(buf);
 	return true;
@@ -657,7 +669,7 @@ CopyLoadRawBuf(CopyState cstate)
  * and writes them to 'dest'.  Returns the number of bytes read (which
  * would be less than 'nbytes' only if we reach EOF).
  */
-static int
+int
 CopyReadBinaryData(CopyState cstate, char *dest, int nbytes)
 {
 	int			copied_bytes = 0;
@@ -3506,7 +3518,7 @@ BeginCopyFrom(ParseState *pstate,
 		int32		tmp;
 
 		/* Signature */
-		if (CopyReadBinaryData(cstate, readSig, 11) != 11 ||
+		if (CopyGetData(cstate, readSig, 11, 11) != 11 ||
 			memcmp(readSig, BinarySignature, 11) != 0)
 			ereport(ERROR,
 					(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
@@ -3534,7 +3546,7 @@ BeginCopyFrom(ParseState *pstate,
 		/* Skip extension header, if present */
 		while (tmp-- > 0)
 		{
-			if (CopyReadBinaryData(cstate, readSig, 1) != 1)
+			if (CopyGetData(cstate, readSig, 1, 1) != 1)
 				ereport(ERROR,
 						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
 						 errmsg("invalid COPY file header (wrong length)")));
@@ -3731,60 +3743,45 @@ NextCopyFrom(CopyState cstate, ExprContext *econtext,
 	else
 	{
 		/* binary */
-		int16		fld_count;
-		ListCell   *cur;
-
 		cstate->cur_lineno++;
+		cstate->max_fields = list_length(cstate->attnumlist);
 
-		if (!CopyGetInt16(cstate, &fld_count))
+		if (!IsParallelCopy())
 		{
-			/* EOF detected (end of file, or protocol-level EOF) */
-			return false;
-		}
+			int16		fld_count;
+			ListCell   *cur;
 
-		if (fld_count == -1)
-		{
-			/*
-			 * Received EOF marker.  In a V3-protocol copy, wait for the
-			 * protocol-level EOF, and complain if it doesn't come
-			 * immediately.  This ensures that we correctly handle CopyFail,
-			 * if client chooses to send that now.
-			 *
-			 * Note that we MUST NOT try to read more data in an old-protocol
-			 * copy, since there is no protocol-level EOF marker then.  We
-			 * could go either way for copy from file, but choose to throw
-			 * error if there's data after the EOF marker, for consistency
-			 * with the new-protocol case.
-			 */
-			char		dummy;
-
-			if (cstate->copy_dest != COPY_OLD_FE &&
-				CopyReadBinaryData(cstate, &dummy, 1) > 0)
-				ereport(ERROR,
-						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-						 errmsg("received copy data after EOF marker")));
-			return false;
-		}
+			if (!CopyGetInt16(cstate, &fld_count))
+			{
+				/* EOF detected (end of file, or protocol-level EOF) */
+				return false;
+			}
 
-		if (fld_count != attr_count)
-			ereport(ERROR,
-					(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-					 errmsg("row field count is %d, expected %d",
-							(int) fld_count, attr_count)));
+			CHECK_FIELD_COUNT;
 
-		foreach(cur, cstate->attnumlist)
+			foreach(cur, cstate->attnumlist)
+			{
+				int			attnum = lfirst_int(cur);
+				int			m = attnum - 1;
+				Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+
+				cstate->cur_attname = NameStr(att->attname);
+				values[m] = CopyReadBinaryAttribute(cstate,
+													&in_functions[m],
+													typioparams[m],
+													att->atttypmod,
+													&nulls[m]);
+				cstate->cur_attname = NULL;
+			}
+		}
+		else
 		{
-			int			attnum = lfirst_int(cur);
-			int			m = attnum - 1;
-			Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+			bool		eof = false;
 
-			cstate->cur_attname = NameStr(att->attname);
-			values[m] = CopyReadBinaryAttribute(cstate,
-												&in_functions[m],
-												typioparams[m],
-												att->atttypmod,
-												&nulls[m]);
-			cstate->cur_attname = NULL;
+			eof = CopyReadBinaryTupleWorker(cstate, values, nulls);
+
+			if (eof)
+				return false;
 		}
 	}
 
@@ -4795,18 +4792,15 @@ CopyReadBinaryAttribute(CopyState cstate, FmgrInfo *flinfo,
 	Datum		result;
 
 	if (!CopyGetInt32(cstate, &fld_size))
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("unexpected EOF in COPY data")));
+		EOF_ERROR;
+
 	if (fld_size == -1)
 	{
 		*isnull = true;
 		return ReceiveFunctionCall(flinfo, NULL, typioparam, typmod);
 	}
-	if (fld_size < 0)
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("invalid field size")));
+
+	CHECK_FIELD_SIZE(fld_size);
 
 	/* reset attribute_buf to empty, and load raw data in it */
 	resetStringInfo(&cstate->attribute_buf);
@@ -4814,9 +4808,7 @@ CopyReadBinaryAttribute(CopyState cstate, FmgrInfo *flinfo,
 	enlargeStringInfo(&cstate->attribute_buf, fld_size);
 	if (CopyReadBinaryData(cstate, cstate->attribute_buf.data,
 						   fld_size) != fld_size)
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("unexpected EOF in COPY data")));
+		EOF_ERROR;
 
 	cstate->attribute_buf.len = fld_size;
 	cstate->attribute_buf.data[fld_size] = '\0';
diff --git a/src/backend/commands/copyparallel.c b/src/backend/commands/copyparallel.c
index f29d63f..8b70370 100644
--- a/src/backend/commands/copyparallel.c
+++ b/src/backend/commands/copyparallel.c
@@ -611,6 +611,7 @@ InitializeParallelCopyInfo(CopyState cstate, List *attnamelist)
 	cstate->cur_lineno = 0;
 	cstate->cur_attname = NULL;
 	cstate->cur_attval = NULL;
+	cstate->pcdata->curr_data_block = NULL;
 
 	/* Set up variables to avoid per-attribute overhead. */
 	initStringInfo(&cstate->attribute_buf);
@@ -1038,37 +1039,61 @@ ParallelCopyFrom(CopyState cstate)
 	errcallback.previous = error_context_stack;
 	error_context_stack = &errcallback;
 
-	/* On input just throw the header line away. */
-	if (cstate->cur_lineno == 0 && cstate->header_line)
+	if (!cstate->binary)
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
+		/* On input just throw the header line away. */
+		if (cstate->cur_lineno == 0 && cstate->header_line)
 		{
-			pcshared_info->is_read_in_progress = false;
-			return;				/* done */
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+			{
+				pcshared_info->is_read_in_progress = false;
+				return;			/* done */
+			}
 		}
-	}
 
-	for (;;)
-	{
-		bool		done;
+		for (;;)
+		{
+			bool		done;
 
-		CHECK_FOR_INTERRUPTS();
+			CHECK_FOR_INTERRUPTS();
 
-		cstate->cur_lineno++;
+			cstate->cur_lineno++;
 
-		/* Actually read the line into memory here. */
-		done = CopyReadLine(cstate);
+			/* Actually read the line into memory here. */
+			done = CopyReadLine(cstate);
 
-		/*
-		 * EOF at start of line means we're done.  If we see EOF after some
-		 * characters, we act as though it was newline followed by EOF, ie,
-		 * process the line and then exit loop on next iteration.
-		 */
-		if (done && cstate->line_buf.len == 0)
-			break;
+			/*
+			 * EOF at start of line means we're done.  If we see EOF after
+			 * some characters, we act as though it was newline followed by
+			 * EOF, ie, process the line and then exit loop on next iteration.
+			 */
+			if (done && cstate->line_buf.len == 0)
+				break;
+		}
 	}
+	else
+	{
+		cstate->pcdata->curr_data_block = NULL;
+		cstate->raw_buf_index = 0;
+		pcshared_info->populated = 0;
+		cstate->cur_lineno = 0;
+		cstate->max_fields = list_length(cstate->attnumlist);
+
+		for (;;)
+		{
+			bool		eof = false;
+
+			CHECK_FOR_INTERRUPTS();
+
+			cstate->cur_lineno++;
+
+			eof = CopyReadBinaryTupleLeader(cstate);
 
+			if (eof)
+				break;
+		}
+	}
 
 	/* Done, clean up */
 	error_context_stack = errcallback.previous;
@@ -1085,6 +1110,289 @@ ParallelCopyFrom(CopyState cstate)
 }
 
 /*
+ * CopyReadBinaryGetDataBlock
+ *
+ * Gets a new block, updates the current offset, calculates the skip bytes.
+ */
+void
+CopyReadBinaryGetDataBlock(CopyState cstate, FieldInfoType field_info)
+{
+	ParallelCopyDataBlock *data_block = NULL;
+	ParallelCopyDataBlock *curr_data_block = cstate->pcdata->curr_data_block;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	uint8		move_bytes = 0;
+	uint32		block_pos;
+	uint32		prev_block_pos;
+	int			read_bytes = 0;
+
+	prev_block_pos = pcshared_info->cur_block_pos;
+
+	block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+	if (field_info == FIELD_SIZE || field_info == FIELD_COUNT)
+		move_bytes = (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+
+	if (curr_data_block != NULL)
+		curr_data_block->skip_bytes = move_bytes;
+
+	data_block = &pcshared_info->data_blocks[block_pos];
+
+	if (move_bytes > 0 && curr_data_block != NULL)
+		memmove(&data_block->data[0], &curr_data_block->data[cstate->raw_buf_index], move_bytes);
+
+	elog(DEBUG1, "LEADER - field info %d is spread across data blocks - moved %d bytes from current block %u to %u block",
+		 field_info, move_bytes, prev_block_pos, block_pos);
+
+	read_bytes = CopyGetData(cstate, &data_block->data[move_bytes], 1, (DATA_BLOCK_SIZE - move_bytes));
+
+	if (field_info == FIELD_NONE && cstate->reached_eof)
+		return;
+
+	if (cstate->reached_eof)
+		EOF_ERROR;
+
+	elog(DEBUG1, "LEADER - bytes read from file %d", read_bytes);
+
+	if (field_info == FIELD_SIZE || field_info == FIELD_DATA)
+	{
+		ParallelCopyDataBlock *prev_data_block = NULL;
+
+		prev_data_block = curr_data_block;
+		prev_data_block->following_block = block_pos;
+
+		if (prev_data_block->curr_blk_completed == false)
+			prev_data_block->curr_blk_completed = true;
+
+		pg_atomic_add_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+	}
+
+	cstate->pcdata->curr_data_block = data_block;
+	cstate->raw_buf_index = 0;
+}
+
+/*
+ * CopyReadBinaryTupleLeader
+ *
+ * Leader reads data from binary formatted file to data blocks and identifies
+ * tuple boundaries/offsets so that workers can work on the data blocks data.
+ */
+bool
+CopyReadBinaryTupleLeader(CopyState cstate)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	int16		fld_count;
+	uint32		line_size = 0;
+	uint32		start_block_pos;
+	uint32		start_offset;
+
+	if (cstate->pcdata->curr_data_block == NULL)
+	{
+		CopyReadBinaryGetDataBlock(cstate, FIELD_NONE);
+
+		/*
+		 * no data is read from file here. one possibility to be here could be
+		 * that the binary file just has a valid signature but nothing else.
+		 */
+		if (cstate->reached_eof)
+			return true;
+	}
+
+	if ((cstate->raw_buf_index + sizeof(fld_count)) >= DATA_BLOCK_SIZE)
+		CopyReadBinaryGetDataBlock(cstate, FIELD_COUNT);
+
+	memcpy(&fld_count, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_count));
+	fld_count = (int16) pg_ntoh16(fld_count);
+
+	CHECK_FIELD_COUNT;
+
+	start_offset = cstate->raw_buf_index;
+	cstate->raw_buf_index += sizeof(fld_count);
+	line_size += sizeof(fld_count);
+	start_block_pos = pcshared_info->cur_block_pos;
+
+	CopyReadBinaryFindTupleSize(cstate, &line_size);
+
+	pg_atomic_add_fetch_u32(&cstate->pcdata->curr_data_block->unprocessed_line_parts, 1);
+
+	if (line_size > 0)
+		(void) UpdateSharedLineInfo(cstate, start_block_pos, start_offset,
+									line_size, LINE_LEADER_POPULATED, -1);
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryFindTupleSize
+ *
+ * Leader identifies boundaries/offsets for each attribute/column and finally
+ * results in the tuple/row size. It moves on to next data block if the
+ * attribute/column is spread across data blocks.
+ */
+void
+CopyReadBinaryFindTupleSize(CopyState cstate, uint32 *line_size)
+{
+	int32		fld_size;
+	ListCell   *cur;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			att_num = lfirst_int(cur);
+		Form_pg_attribute att = TupleDescAttr(tup_desc, (att_num - 1));
+
+		cstate->cur_attname = NameStr(att->attname);
+		fld_size = 0;
+
+		if ((cstate->raw_buf_index + sizeof(fld_size)) >= DATA_BLOCK_SIZE)
+			CopyReadBinaryGetDataBlock(cstate, FIELD_SIZE);
+
+		memcpy(&fld_size, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_size));
+		cstate->raw_buf_index += sizeof(fld_size);
+		*line_size += sizeof(fld_size);
+		fld_size = (int32) pg_ntoh32(fld_size);
+
+		/* fld_size -1 represents the null value for the field. */
+		if (fld_size == -1)
+			continue;
+
+		CHECK_FIELD_SIZE(fld_size);
+
+		*line_size += fld_size;
+
+		if ((DATA_BLOCK_SIZE - cstate->raw_buf_index) >= fld_size)
+		{
+			cstate->raw_buf_index += fld_size;
+			elog(DEBUG1, "LEADER - tuple lies in he same data block");
+		}
+		else
+		{
+			int32		required_blks = 0;
+			int32		curr_blk_bytes = (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+			int			i = 0;
+
+			GET_REQUIRED_BLOCKS(required_blks, fld_size, curr_blk_bytes);
+
+			i = required_blks;
+
+			while (i > 0)
+			{
+				CopyReadBinaryGetDataBlock(cstate, FIELD_DATA);
+				i--;
+			}
+
+			GET_RAW_BUF_INDEX(cstate->raw_buf_index, fld_size, required_blks, curr_blk_bytes);
+
+			/*
+			 * raw_buf_index should never cross data block size, as the
+			 * required number of data blocks would have been obtained in the
+			 * above while loop.
+			 */
+			Assert(cstate->raw_buf_index <= DATA_BLOCK_SIZE);
+		}
+		cstate->cur_attname = NULL;
+	}
+}
+
+/*
+ * CopyReadBinaryTupleWorker
+ *
+ * Each worker reads data from data blocks caches the tuple data into local
+ * memory.
+ */
+bool
+CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls)
+{
+	int16		fld_count;
+	ListCell   *cur;
+	FmgrInfo   *in_functions = cstate->in_functions;
+	Oid		   *typioparams = cstate->typioparams;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+	bool		done = false;
+
+	done = GetWorkerLine(cstate);
+	cstate->raw_buf_index = 0;
+
+	if (done && cstate->line_buf.len == 0)
+		return true;
+
+	memcpy(&fld_count, &cstate->line_buf.data[cstate->raw_buf_index], sizeof(fld_count));
+	fld_count = (int16) pg_ntoh16(fld_count);
+
+	CHECK_FIELD_COUNT;
+
+	cstate->raw_buf_index += sizeof(fld_count);
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			att_num = lfirst_int(cur);
+		int			m = att_num - 1;
+		Form_pg_attribute att = TupleDescAttr(tup_desc, m);
+
+		cstate->cur_attname = NameStr(att->attname);
+
+		values[m] = CopyReadBinaryAttributeWorker(cstate,
+												  &in_functions[m],
+												  typioparams[m],
+												  att->atttypmod,
+												  &nulls[m]);
+		cstate->cur_attname = NULL;
+	}
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryAttributeWorker
+ *
+ * Worker identifies and converts each attribute/column data from binary to
+ * the data type of attribute/column.
+ */
+Datum
+CopyReadBinaryAttributeWorker(CopyState cstate, FmgrInfo *flinfo,
+							  Oid typioparam, int32 typmod, bool *isnull)
+{
+	int32		fld_size;
+	Datum		result;
+
+	memcpy(&fld_size, &cstate->line_buf.data[cstate->raw_buf_index], sizeof(fld_size));
+	cstate->raw_buf_index += sizeof(fld_size);
+	fld_size = (int32) pg_ntoh32(fld_size);
+
+	/* fld_size -1 represents the null value for the field. */
+	if (fld_size == -1)
+	{
+		*isnull = true;
+		return ReceiveFunctionCall(flinfo, NULL, typioparam, typmod);
+	}
+
+	CHECK_FIELD_SIZE(fld_size);
+
+	/* Reset attribute_buf to empty, and load raw data in it */
+	resetStringInfo(&cstate->attribute_buf);
+
+	enlargeStringInfo(&cstate->attribute_buf, fld_size);
+
+	memcpy(&cstate->attribute_buf.data[0], &cstate->line_buf.data[cstate->raw_buf_index], fld_size);
+	cstate->raw_buf_index += fld_size;
+
+	cstate->attribute_buf.len = fld_size;
+	cstate->attribute_buf.data[fld_size] = '\0';
+
+	/* Call the column type's binary input converter */
+	result = ReceiveFunctionCall(flinfo, &cstate->attribute_buf,
+								 typioparam, typmod);
+
+	/* Trouble if it didn't eat the whole buffer */
+	if (cstate->attribute_buf.cursor != cstate->attribute_buf.len)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+				 errmsg("incorrect binary data format")));
+
+	*isnull = false;
+	return result;
+}
+
+/*
  * GetLinePosition
  *
  * Return the line position once the leader has populated the data.
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index ac92aca..abdb791 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -61,4 +61,12 @@ extern uint32 UpdateSharedLineInfo(CopyState cstate, uint32 blk_pos, uint32 offs
 								   uint32 line_size, uint32 line_state, uint32 blk_line_pos);
 extern void EndLineParallelCopy(CopyState cstate, uint32 line_pos, uint32 line_size,
 								uint32 raw_buf_ptr);
+extern int	CopyGetData(CopyState cstate, void *databuf, int minread, int maxread);
+extern int	CopyReadBinaryData(CopyState cstate, char *dest, int nbytes);
+extern bool CopyReadBinaryTupleLeader(CopyState cstate);
+extern bool CopyReadBinaryTupleWorker(CopyState cstate, Datum *values, bool *nulls);
+extern void CopyReadBinaryFindTupleSize(CopyState cstate, uint32 *line_size);
+extern Datum CopyReadBinaryAttributeWorker(CopyState cstate, FmgrInfo *flinfo,
+										   Oid typioparam, int32 typmod, bool *isnull);
+extern void CopyReadBinaryGetDataBlock(CopyState cstate, FieldInfoType field_info);
 #endif							/* COPY_H */
diff --git a/src/include/commands/copy_internal.h b/src/include/commands/copy_internal.h
index 30eaa2e..b2bc0bb 100644
--- a/src/include/commands/copy_internal.h
+++ b/src/include/commands/copy_internal.h
@@ -56,6 +56,109 @@
 #define IsHeaderLine()			(cstate->header_line && cstate->cur_lineno == 1)
 
 /*
+ * CHECK_FIELD_COUNT - Handles the error cases for field count
+ * for binary format files.
+ */
+#define CHECK_FIELD_COUNT \
+{\
+	if (fld_count == -1) \
+	{ \
+		if (IsParallelCopy() && \
+			!IsLeader()) \
+			return true; \
+		else if (IsParallelCopy() && \
+			IsLeader()) \
+		{ \
+			if (cstate->pcdata->curr_data_block->data[cstate->raw_buf_index + sizeof(fld_count)] != 0) \
+				ereport(ERROR, \
+						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+						errmsg("received copy data after EOF marker"))); \
+			return true; \
+		} \
+		else \
+		{ \
+			/* \
+			 * Received EOF marker.  In a V3-protocol copy, wait for the \
+			 * protocol-level EOF, and complain if it doesn't come \
+			 * immediately.  This ensures that we correctly handle CopyFail, \
+			 * if client chooses to send that now. \
+			 * \
+			 * Note that we MUST NOT try to read more data in an old-protocol \
+			 * copy, since there is no protocol-level EOF marker then.  We \
+			 * could go either way for copy from file, but choose to throw \
+			 * error if there's data after the EOF marker, for consistency \
+			 * with the new-protocol case. \
+			 */ \
+			char		dummy; \
+			if (cstate->copy_dest != COPY_OLD_FE && \
+				CopyReadBinaryData(cstate, &dummy, 1) > 0) \
+				ereport(ERROR, \
+						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+						errmsg("received copy data after EOF marker"))); \
+				return false; \
+		} \
+	} \
+	if (fld_count != cstate->max_fields) \
+		ereport(ERROR, \
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+				errmsg("row field count is %d, expected %d", \
+				(int) fld_count, cstate->max_fields))); \
+}
+
+/*
+ * CHECK_FIELD_SIZE - Handles the error case for field size
+ * for binary format files.
+ */
+#define CHECK_FIELD_SIZE(fld_size) \
+{ \
+	if (fld_size < -1) \
+		ereport(ERROR, \
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+				errmsg("invalid field size")));\
+}
+
+/*
+ * EOF_ERROR - Error statement for EOF for binary format
+ * files.
+ */
+#define EOF_ERROR \
+{ \
+	ereport(ERROR, \
+		(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+		errmsg("unexpected EOF in COPY data")));\
+}
+
+/*
+ * GET_RAW_BUF_INDEX - Calculates the raw buf index for the cases
+ * where the data spread is across multiple data blocks.
+ */
+#define GET_RAW_BUF_INDEX(raw_buf_index, fld_size, required_blks, curr_blk_bytes) \
+{ \
+	raw_buf_index = fld_size - (((required_blks - 1) * DATA_BLOCK_SIZE) + curr_blk_bytes); \
+}
+
+/*
+ * GET_REQUIRED_BLOCKS - Calculates the number of data
+ * blocks required for the cases where the data spread
+ * is across multiple data blocks.
+ */
+#define GET_REQUIRED_BLOCKS(required_blks, fld_size, curr_blk_bytes) \
+{ \
+	/* \
+	 * field size can spread across multiple data blocks, \
+	 * calculate the number of required data blocks and try to get \
+	 * those many data blocks. \
+	 */ \
+	required_blks = (int32)(fld_size - curr_blk_bytes)/(int32)DATA_BLOCK_SIZE; \
+	/* \
+	 * check if we need the data block for the field data \
+	 * bytes that are not modulus of data block size. \
+	 */ \
+	if ((fld_size - curr_blk_bytes)%DATA_BLOCK_SIZE != 0) \
+		required_blks++; \
+}
+
+/*
  * Represents the different source/dest cases we need to worry about at
  * the bottom level
  */
@@ -235,6 +338,17 @@ typedef struct ParallelCopyLineBuf
 } ParallelCopyLineBuf;
 
 /*
+ * Represents the usage mode for CopyReadBinaryGetDataBlock.
+ */
+typedef enum FieldInfoType
+{
+	FIELD_NONE = 0,
+	FIELD_COUNT,
+	FIELD_SIZE,
+	FIELD_DATA
+}			FieldInfoType;
+
+/*
  * This structure helps in storing the common List/Node from CopyStateData that
  * are required by the workers. This information will then be copied and stored
  * into the DSM for the worker to retrieve and copy it to CopyStateData.
@@ -273,6 +387,9 @@ typedef struct ParallelCopyData
 
 	/* Current position in worker_line_buf */
 	uint32		worker_line_buf_pos;
+
+	/* For binary formatted files */
+	ParallelCopyDataBlock *curr_data_block;
 } ParallelCopyData;
 
 typedef int (*copy_data_source_cb) (void *outbuf, int minread, int maxread);
-- 
1.8.3.1

v10-0006-Tests-for-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=v10-0006-Tests-for-parallel-copy.patchDownload
From 5871b9fd0f987553b48458e30eb7620a11e80329 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 18 Nov 2020 07:58:58 +0530
Subject: [PATCH v10 6/6] Tests for parallel copy.

This patch has the tests for parallel copy.
---
 contrib/postgres_fdw/expected/postgres_fdw.out |  48 ++++
 contrib/postgres_fdw/sql/postgres_fdw.sql      |  52 ++++
 src/test/regress/expected/copy2.out            | 324 +++++++++++++++++++++-
 src/test/regress/input/copy.source             |  31 +++
 src/test/regress/output/copy.source            |  27 ++
 src/test/regress/sql/copy2.sql                 | 369 ++++++++++++++++++++++++-
 6 files changed, 843 insertions(+), 8 deletions(-)

diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index 2d88d06..1e78b6a 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -9033,5 +9033,53 @@ SELECT 1 FROM ft1 LIMIT 1;    -- should fail
 ERROR:  08006
 \set VERBOSITY default
 COMMIT;
+-- parallel copy related tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+CREATE FOREIGN TABLE test_parallel_copy_ft (
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+) SERVER loopback OPTIONS (table_name 'test_parallel_copy') ;
+-- parallel copy into foreign table, parallelism must not be picked up.
+COPY test_parallel_copy_ft FROM stdin WITH (PARALLEL 1);
+SELECT count(*) FROM test_parallel_copy_ft;
+ count 
+-------
+     2
+(1 row)
+
+-- parallel copy into a table with foreign partition.
+CREATE TABLE part_test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+) PARTITION BY LIST (b);
+CREATE FOREIGN TABLE part_test_parallel_copy_a1 (c TEXT, b INT, a INT, e TEXT, d TEXT) SERVER loopback;
+CREATE TABLE part_test_parallel_copy_a2 (a INT, c TEXT, b INT, d TEXT, e TEXT);
+ALTER TABLE part_test_parallel_copy ATTACH PARTITION part_test_parallel_copy_a1 FOR VALUES IN(1);
+ALTER TABLE part_test_parallel_copy ATTACH PARTITION part_test_parallel_copy_a2 FOR VALUES IN(2);
+-- Verify that sequential copy is choosen by checking error in not from a parallel worker.
+COPY part_test_parallel_copy FROM stdin WITH (PARALLEL 1);
+ERROR:  extra data after last expected column
+CONTEXT:  COPY part_test_parallel_copy, line 1: "1	1	test_c1	test_d1	test_e1	test_nonexistent1"
+SELECT count(*) FROM part_test_parallel_copy WHERE b = 2;
+ count 
+-------
+     0
+(1 row)
+
 -- Clean up
 DROP PROCEDURE terminate_backend_and_wait(text);
+DROP FOREIGN TABLE test_parallel_copy_ft;
+DROP TABLE test_parallel_copy;
+DROP TABLE part_test_parallel_copy;
diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql
index 7581c54..f804e4c 100644
--- a/contrib/postgres_fdw/sql/postgres_fdw.sql
+++ b/contrib/postgres_fdw/sql/postgres_fdw.sql
@@ -2695,5 +2695,57 @@ SELECT 1 FROM ft1 LIMIT 1;    -- should fail
 \set VERBOSITY default
 COMMIT;
 
+-- parallel copy related tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+
+CREATE FOREIGN TABLE test_parallel_copy_ft (
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+) SERVER loopback OPTIONS (table_name 'test_parallel_copy') ;
+
+-- parallel copy into foreign table, parallelism must not be picked up.
+COPY test_parallel_copy_ft FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+SELECT count(*) FROM test_parallel_copy_ft;
+
+-- parallel copy into a table with foreign partition.
+CREATE TABLE part_test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+) PARTITION BY LIST (b);
+
+CREATE FOREIGN TABLE part_test_parallel_copy_a1 (c TEXT, b INT, a INT, e TEXT, d TEXT) SERVER loopback;
+
+CREATE TABLE part_test_parallel_copy_a2 (a INT, c TEXT, b INT, d TEXT, e TEXT);
+
+ALTER TABLE part_test_parallel_copy ATTACH PARTITION part_test_parallel_copy_a1 FOR VALUES IN(1);
+
+ALTER TABLE part_test_parallel_copy ATTACH PARTITION part_test_parallel_copy_a2 FOR VALUES IN(2);
+
+-- Verify that sequential copy is choosen by checking error in not from a parallel worker.
+COPY part_test_parallel_copy FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1	test_nonexistent1
+\.
+
+SELECT count(*) FROM part_test_parallel_copy WHERE b = 2;
+
 -- Clean up
 DROP PROCEDURE terminate_backend_and_wait(text);
+DROP FOREIGN TABLE test_parallel_copy_ft;
+DROP TABLE test_parallel_copy;
+DROP TABLE part_test_parallel_copy;
diff --git a/src/test/regress/expected/copy2.out b/src/test/regress/expected/copy2.out
index c64f071..22274cb 100644
--- a/src/test/regress/expected/copy2.out
+++ b/src/test/regress/expected/copy2.out
@@ -301,18 +301,32 @@ It is "perfect".|
 "It is ""perfect"".","	"
 "",
 --test that we read consecutive LFs properly
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 COPY testnl FROM stdin CSV;
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+SELECT * FROM testnl;
+ a |          b           | c 
+---+----------------------+---
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+(2 rows)
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 COPY testeoc FROM stdin CSV;
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
 COPY testeoc TO stdout CSV;
 a\.
 \.b
 c\.d
 "\."
 -- test handling of nonstandard null marker that violates escaping rules
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 COPY testnull TO stdout WITH NULL AS E'\\0';
 1	\\0
@@ -327,6 +341,15 @@ SELECT * FROM testnull;
     | 
 (4 rows)
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 1);
+SELECT * FROM testnull;
+ a  | b  
+----+----
+ 42 | \0
+    | 
+(2 rows)
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -396,6 +419,34 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+SELECT * FROM vistest;
+ a  
+----
+ a2
+ b
+(2 rows)
+
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+COMMIT;
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 SELECT * FROM vistest;
  a 
@@ -456,7 +507,7 @@ SELECT * FROM vistest;
 (2 rows)
 
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -467,6 +518,8 @@ CREATE TEMP TABLE forcetest (
 -- should succeed with no effect ("b" remains an empty string, "c" remains NULL)
 BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 1);
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
  b |  c   
@@ -477,6 +530,8 @@ SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
 BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 1);
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
  c |  d   
@@ -533,6 +588,30 @@ select * from check_con_tbl;
    
 (2 rows)
 
+\d+ check_con_tbl
+                               Table "public.check_con_tbl"
+ Column |  Type   | Collation | Nullable | Default | Storage | Stats target | Description 
+--------+---------+-----------+----------+---------+---------+--------------+-------------
+ f1     | integer |           |          |         | plain   |              | 
+Check constraints:
+    "check_con_tbl_check" CHECK (check_con_function(check_con_tbl.*))
+
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 1);
+NOTICE:  input = {"f1":1}
+NOTICE:  input = {"f1":null}
+copy check_con_tbl from stdin with (parallel 1);
+NOTICE:  input = {"f1":0}
+ERROR:  new row for relation "check_con_tbl" violates check constraint "check_con_tbl_check"
+DETAIL:  Failing row contains (0).
+CONTEXT:  COPY check_con_tbl, line 1: "0"
+select * from check_con_tbl;
+ f1 
+----
+  1
+   
+(2 rows)
+
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
 CREATE ROLE regress_rls_copy_user_colperms;
@@ -647,10 +726,247 @@ SELECT * FROM instead_of_insert_tbl;
 (2 rows)
 
 COMMIT;
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+COPY test_parallel_copy (a, b, c, d, e) FROM stdin WITH (PARALLEL 1);
+COPY test_parallel_copy (b, d) FROM stdin WITH (PARALLEL 1);
+COPY test_parallel_copy (b, d) FROM stdin WITH (PARALLEL 1);
+COPY test_parallel_copy (b, d) FROM stdin WITH (PARALLEL 1, FORMAT 'csv', HEADER);
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) FROM stdin WITH (PARALLEL 0);
+ERROR:  value 0 out of bounds for option "parallel"
+DETAIL:  Valid values are between "1" and "1024".
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri FROM stdin WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1) WHERE height > random() * 65;
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+-- temporary table copy: should perform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+COPY temp_test (a) FROM stdin WITH (PARALLEL 1);
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) FROM stdin WITH (PARALLEL 1);
+ERROR:  column "xyz" of relation "test_parallel_copy" does not exist
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) FROM stdin WITH (PARALLEL 1);
+ERROR:  column "d" specified more than once
+-- missing data: should fail
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+ERROR:  invalid input syntax for type integer: ""
+CONTEXT:  COPY test_parallel_copy, line 0, column a: ""
+parallel worker
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2000	230	23	23"
+parallel worker
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2001	231	\N	\N"
+parallel worker
+-- extra data: should fail
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+ERROR:  extra data after last expected column
+CONTEXT:  COPY test_parallel_copy, line 1: "2002	232	40	50	60	70	80"
+parallel worker
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) FROM stdin WITH (DELIMITER ',', null 'x', PARALLEL 1) ;
+COPY test_parallel_copy FROM stdin WITH (DELIMITER ';', NULL '', PARALLEL 1);
+COPY test_parallel_copy FROM stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL 1);
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a = 50004;
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a > 60003;
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE f > 60003;
+ERROR:  column "f" does not exist
+LINE 1: ..._parallel_copy FROM stdin WITH (PARALLEL 1) WHERE f > 60003;
+                                                             ^
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+ERROR:  missing FROM-clause entry for table "x"
+LINE 1: ...rallel_copy FROM stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+                                                                  ^
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a IN (SELECT 1 FROM x);
+ERROR:  cannot use subquery in COPY FROM WHERE condition
+LINE 1: ...arallel_copy FROM stdin WITH (PARALLEL 1) WHERE a IN (SELECT...
+                                                             ^
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a IN (generate_series(1,5));
+ERROR:  set-returning functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...lel_copy FROM stdin WITH (PARALLEL 1) WHERE a IN (generate_s...
+                                                             ^
+COPY test_parallel_copy FROM stdin WITH(PARALLEL 1) WHERE a = row_number() over(b);
+ERROR:  window functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...rallel_copy FROM stdin WITH(PARALLEL 1) WHERE a = row_number...
+                                                             ^
+-- check results of copy in
+SELECT * FROM test_parallel_copy ORDER BY 1;
+   a   | b  |     c      |    d    |    e    
+-------+----+------------+---------+---------
+     1 | 11 | test_c1    | test_d1 | test_e1
+     2 | 12 | test_c2    | test_d2 | test_e2
+  3000 |    | c          |         | 
+  4000 |    | C          |         | 
+  4001 |  1 | empty      |         | 
+  4002 |  2 | null       |         | 
+  4003 |  3 | Backslash  | \       | \
+  4004 |  4 | BackslashX | \X      | \X
+  4005 |  5 | N          | N       | N
+  4006 |  6 | BackslashN | \N      | \N
+  4007 |  7 | XX         | XX      | XX
+  4008 |  8 | Delimiter  | :       | :
+ 50004 | 25 | 35         | 45      | 55
+ 60004 | 25 | 35         | 45      | 55
+ 60005 | 26 | 36         | 46      | 56
+       |  3 | stuff      | test_d3 | 
+       |  4 | stuff      | test_d4 | 
+       |  5 | stuff      | test_d5 | 
+       |    | ,          | \,      | \
+       |    | x          | \x      | \x
+       |    | 45         | 80      | 90
+(21 rows)
+
+-- parallel copy test for unlogged tables. should execute in parallel worker
+CREATE UNLOGGED TABLE test_parallel_copy_unlogged(
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+);
+COPY test_parallel_copy_unlogged FROM stdin WITH (PARALLEL 1);
+SELECT count(*) FROM test_parallel_copy_unlogged;
+ count 
+-------
+     2
+(1 row)
+
+-- parallel copy test for various trigger types
+TRUNCATE test_parallel_copy;
+-- parallel safe trigger function
+CREATE OR REPLACE FUNCTION parallel_copy_trig_func() RETURNS TRIGGER
+LANGUAGE plpgsql PARALLEL SAFE AS $$
+BEGIN
+  RETURN NEW;
+END;
+$$;
+-- before insert row trigger
+CREATE TRIGGER parallel_copy_trig
+BEFORE INSERT ON test_parallel_copy
+FOR EACH ROW
+EXECUTE PROCEDURE parallel_copy_trig_func();
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+-- after insert row trigger
+CREATE TRIGGER parallel_copy_trig
+AFTER INSERT ON test_parallel_copy
+FOR EACH ROW
+EXECUTE PROCEDURE parallel_copy_trig_func();
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+-- before insert statement trigger
+CREATE TRIGGER parallel_copy_trig
+BEFORE INSERT ON test_parallel_copy
+FOR EACH STATEMENT
+EXECUTE PROCEDURE parallel_copy_trig_func();
+-- parallelism should be picked, since the trigger function is parallel safe
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+-- after insert statement trigger
+CREATE TRIGGER parallel_copy_trig
+AFTER INSERT ON test_parallel_copy
+FOR EACH STATEMENT
+EXECUTE PROCEDURE parallel_copy_trig_func();
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+-- transition table is involved
+CREATE TRIGGER parallel_copy_trig
+AFTER INSERT ON test_parallel_copy REFERENCING NEW TABLE AS new_table
+FOR EACH STATEMENT
+EXECUTE PROCEDURE parallel_copy_trig_func();
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+-- make trigger function parallel unsafe
+ALTER FUNCTION parallel_copy_trig_func PARALLEL UNSAFE;
+-- before statement trigger has a parallel unsafe function
+CREATE TRIGGER parallel_copy_trig
+BEFORE INSERT ON test_parallel_copy
+FOR EACH STATEMENT
+EXECUTE PROCEDURE parallel_copy_trig_func();
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+SELECT count(*) FROM test_parallel_copy;
+ count 
+-------
+    12
+(1 row)
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+-- instead of insert trigger, no parallelism should be picked
+COPY instead_of_insert_tbl_view FROM stdin WITH(PARALLEL 1);;
+SELECT count(*) FROM instead_of_insert_tbl_view;
+ count 
+-------
+     1
+(1 row)
+
+-- parallel copy test for a partitioned table with a before insert trigger on
+-- one of the partition
+ALTER FUNCTION parallel_copy_trig_func PARALLEL SAFE;
+CREATE TABLE test_parallel_copy_part (
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+) PARTITION BY LIST (b);
+CREATE TABLE test_parallel_copy_part_a1 (c TEXT, b INT, a INT, e TEXT, d TEXT);
+CREATE TABLE test_parallel_copy_part_a2 (a INT, c TEXT, b INT, d TEXT, e TEXT);
+ALTER TABLE test_parallel_copy_part ATTACH PARTITION test_parallel_copy_part_a1 FOR VALUES IN(1);
+ALTER TABLE test_parallel_copy_part ATTACH PARTITION test_parallel_copy_part_a2 FOR VALUES IN(2);
+CREATE TRIGGER parallel_copy_trig
+BEFORE INSERT ON test_parallel_copy_part_a2
+FOR EACH ROW
+EXECUTE PROCEDURE parallel_copy_trig_func();
+-- Verify that sequential copy is choosen by checking error in not from a parallel worker.
+COPY test_parallel_copy_part FROM stdin WITH (PARALLEL 1);
+ERROR:  extra data after last expected column
+CONTEXT:  COPY test_parallel_copy_part, line 2: "2	2	test_c2	test_d2	test_e2	test_ne2"
+SELECT count(*) FROM test_parallel_copy_part;
+ count 
+-------
+     0
+(1 row)
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy_part_a2;
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE test_parallel_copy_unlogged;
+DROP TABLE test_parallel_copy_part;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
+DROP FUNCTION parallel_copy_trig_func();
 DROP TABLE x, y;
 DROP TABLE rls_t1 CASCADE;
 DROP ROLE regress_rls_copy_user;
diff --git a/src/test/regress/input/copy.source b/src/test/regress/input/copy.source
index a1d529a..cb39c66 100644
--- a/src/test/regress/input/copy.source
+++ b/src/test/regress/input/copy.source
@@ -15,6 +15,13 @@ DELETE FROM onek;
 
 COPY onek FROM '@abs_builddir@/results/onek.data';
 
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+
+SELECT COUNT(*) FROM tenk1;
+
+TRUNCATE tenk1;
+
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
@@ -159,6 +166,30 @@ truncate parted_copytest;
 
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
 
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
+
+-- Test parallel copy from for toast table with csv and binary format file
+create table test_parallel_copy_toast(a1 int, b1 text, c1 text default null);
+
+insert into test_parallel_copy_toast select i, (repeat(md5(i::text), 100000)) FROM generate_series(1,2) AS i;
+
+copy test_parallel_copy_toast to '@abs_builddir@/results/parallelcopytoast.csv' with(format csv);
+
+copy test_parallel_copy_toast to '@abs_builddir@/results/parallelcopytoast.dat' with(format binary);
+
+truncate test_parallel_copy_toast;
+
+copy test_parallel_copy_toast from '@abs_builddir@/results/parallelcopytoast.csv' with(format csv, parallel 2);
+
+copy test_parallel_copy_toast from '@abs_builddir@/results/parallelcopytoast.dat' with(format binary, parallel 2);
+
+select count(*) from test_parallel_copy_toast;
+
+drop table test_parallel_copy_toast;
+
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/output/copy.source b/src/test/regress/output/copy.source
index 938d355..a5dca79 100644
--- a/src/test/regress/output/copy.source
+++ b/src/test/regress/output/copy.source
@@ -9,6 +9,15 @@ COPY onek FROM '@abs_srcdir@/data/onek.data';
 COPY onek TO '@abs_builddir@/results/onek.data';
 DELETE FROM onek;
 COPY onek FROM '@abs_builddir@/results/onek.data';
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+SELECT COUNT(*) FROM tenk1;
+ count 
+-------
+ 10000
+(1 row)
+
+TRUNCATE tenk1;
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
 COPY person FROM '@abs_srcdir@/data/person.data';
@@ -113,6 +122,24 @@ insert into parted_copytest select x,1,'One' from generate_series(1011,1020) x;
 copy (select * from parted_copytest order by a) to '@abs_builddir@/results/parted_copytest.csv';
 truncate parted_copytest;
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
+-- Test parallel copy from for toast table with csv and binary format file
+create table test_parallel_copy_toast(a1 int, b1 text, c1 text default null);
+insert into test_parallel_copy_toast select i, (repeat(md5(i::text), 100000)) FROM generate_series(1,2) AS i;
+copy test_parallel_copy_toast to '@abs_builddir@/results/parallelcopytoast.csv' with(format csv);
+copy test_parallel_copy_toast to '@abs_builddir@/results/parallelcopytoast.dat' with(format binary);
+truncate test_parallel_copy_toast;
+copy test_parallel_copy_toast from '@abs_builddir@/results/parallelcopytoast.csv' with(format csv, parallel 2);
+copy test_parallel_copy_toast from '@abs_builddir@/results/parallelcopytoast.dat' with(format binary, parallel 2);
+select count(*) from test_parallel_copy_toast;
+ count 
+-------
+     4
+(1 row)
+
+drop table test_parallel_copy_toast;
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/sql/copy2.sql b/src/test/regress/sql/copy2.sql
index b3c16af..ebca6e6 100644
--- a/src/test/regress/sql/copy2.sql
+++ b/src/test/regress/sql/copy2.sql
@@ -171,7 +171,7 @@ COPY y TO stdout (FORMAT CSV, FORCE_QUOTE *);
 
 --test that we read consecutive LFs properly
 
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 
 COPY testnl FROM stdin CSV;
 1,"a field with two LFs
@@ -179,8 +179,16 @@ COPY testnl FROM stdin CSV;
 inside",2
 \.
 
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+1,"a field with two LFs
+
+inside",2
+\.
+
+SELECT * FROM testnl;
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 
 COPY testeoc FROM stdin CSV;
 a\.
@@ -189,11 +197,19 @@ c\.d
 "\."
 \.
 
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+a\.
+\.b
+c\.d
+"\."
+\.
+
 COPY testeoc TO stdout CSV;
 
 -- test handling of nonstandard null marker that violates escaping rules
 
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 
 COPY testnull TO stdout WITH NULL AS E'\\0';
@@ -205,6 +221,14 @@ COPY testnull FROM stdin WITH NULL AS E'\\0';
 
 SELECT * FROM testnull;
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 1);
+42	\\0
+\0	\0
+\.
+
+SELECT * FROM testnull;
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -249,6 +273,23 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+a2
+b
+\.
+SELECT * FROM vistest;
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+d2
+e
+\.
+SELECT * FROM vistest;
+COMMIT;
+SELECT * FROM vistest;
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 x
 y
@@ -298,7 +339,7 @@ SELECT * FROM vistest;
 COMMIT;
 SELECT * FROM vistest;
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -311,6 +352,10 @@ BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
 1,,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 1);
+1,,""
+\.
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
@@ -318,6 +363,10 @@ BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
 2,'a',,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 1);
+2,'a',,""
+\.
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
 -- should fail with not-null constraint violation
@@ -353,6 +402,16 @@ copy check_con_tbl from stdin;
 0
 \.
 select * from check_con_tbl;
+\d+ check_con_tbl
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 1);
+1
+\N
+\.
+copy check_con_tbl from stdin with (parallel 1);
+0
+\.
+select * from check_con_tbl;
 
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
@@ -454,10 +513,312 @@ test1
 SELECT * FROM instead_of_insert_tbl;
 COMMIT;
 
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+
+COPY test_parallel_copy (a, b, c, d, e) FROM stdin WITH (PARALLEL 1);
+1	11	test_c1	test_d1	test_e1
+2	12	test_c2	test_d2	test_e2
+\.
+
+COPY test_parallel_copy (b, d) FROM stdin WITH (PARALLEL 1);
+3	test_d3
+\.
+
+COPY test_parallel_copy (b, d) FROM stdin WITH (PARALLEL 1);
+4	test_d4
+5	test_d5
+\.
+
+COPY test_parallel_copy (b, d) FROM stdin WITH (PARALLEL 1, FORMAT 'csv', HEADER);
+b	d
+\.
+
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) FROM stdin WITH (PARALLEL 0);
+
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri FROM stdin WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+10
+\.
+
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1) WHERE height > random() * 65;
+60,60,60
+\.
+
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+60
+\.
+
+-- temporary table copy: should perform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+
+COPY temp_test (a) FROM stdin WITH (PARALLEL 1);
+10
+\.
+
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) FROM stdin WITH (PARALLEL 1);
+
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) FROM stdin WITH (PARALLEL 1);
+
+-- missing data: should fail
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+
+\.
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+2000	230	23	23
+\.
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+2001	231	\N	\N
+\.
+
+-- extra data: should fail
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+2002	232	40	50	60	70	80
+\.
+
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) FROM stdin WITH (DELIMITER ',', null 'x', PARALLEL 1) ;
+x,45,80,90
+x,\x,\\x,\\\x
+x,\,,\\\,,\\
+\.
+
+COPY test_parallel_copy FROM stdin WITH (DELIMITER ';', NULL '', PARALLEL 1);
+3000;;c;;
+\.
+
+COPY test_parallel_copy FROM stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL 1);
+4000:\X:C:\X:\X
+4001:1:empty::
+4002:2:null:\X:\X
+4003:3:Backslash:\\:\\
+4004:4:BackslashX:\\X:\\X
+4005:5:N:\N:\N
+4006:6:BackslashN:\\N:\\N
+4007:7:XX:\XX:\XX
+4008:8:Delimiter:\::\:
+\.
+
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a = 50004;
+50003	24	34	44	54
+50004	25	35	45 	55
+50005	26	36	46	56
+\.
+
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a > 60003;
+60001	22	32	42	52
+60002	23	33	43	53
+60003	24	34	44	54
+60004	25	35	45	55
+60005	26	36	46	56
+\.
+
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE f > 60003;
+
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a IN (SELECT 1 FROM x);
+
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a IN (generate_series(1,5));
+
+COPY test_parallel_copy FROM stdin WITH(PARALLEL 1) WHERE a = row_number() over(b);
+
+-- check results of copy in
+SELECT * FROM test_parallel_copy ORDER BY 1;
+
+-- parallel copy test for unlogged tables. should execute in parallel worker
+CREATE UNLOGGED TABLE test_parallel_copy_unlogged(
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+);
+
+COPY test_parallel_copy_unlogged FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+SELECT count(*) FROM test_parallel_copy_unlogged;
+
+-- parallel copy test for various trigger types
+TRUNCATE test_parallel_copy;
+
+-- parallel safe trigger function
+CREATE OR REPLACE FUNCTION parallel_copy_trig_func() RETURNS TRIGGER
+LANGUAGE plpgsql PARALLEL SAFE AS $$
+BEGIN
+  RETURN NEW;
+END;
+$$;
+
+-- before insert row trigger
+CREATE TRIGGER parallel_copy_trig
+BEFORE INSERT ON test_parallel_copy
+FOR EACH ROW
+EXECUTE PROCEDURE parallel_copy_trig_func();
+
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+
+-- after insert row trigger
+CREATE TRIGGER parallel_copy_trig
+AFTER INSERT ON test_parallel_copy
+FOR EACH ROW
+EXECUTE PROCEDURE parallel_copy_trig_func();
+
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+
+-- before insert statement trigger
+CREATE TRIGGER parallel_copy_trig
+BEFORE INSERT ON test_parallel_copy
+FOR EACH STATEMENT
+EXECUTE PROCEDURE parallel_copy_trig_func();
+
+-- parallelism should be picked, since the trigger function is parallel safe
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+
+-- after insert statement trigger
+CREATE TRIGGER parallel_copy_trig
+AFTER INSERT ON test_parallel_copy
+FOR EACH STATEMENT
+EXECUTE PROCEDURE parallel_copy_trig_func();
+
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+
+-- transition table is involved
+CREATE TRIGGER parallel_copy_trig
+AFTER INSERT ON test_parallel_copy REFERENCING NEW TABLE AS new_table
+FOR EACH STATEMENT
+EXECUTE PROCEDURE parallel_copy_trig_func();
+
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+
+-- make trigger function parallel unsafe
+ALTER FUNCTION parallel_copy_trig_func PARALLEL UNSAFE;
+
+-- before statement trigger has a parallel unsafe function
+CREATE TRIGGER parallel_copy_trig
+BEFORE INSERT ON test_parallel_copy
+FOR EACH STATEMENT
+EXECUTE PROCEDURE parallel_copy_trig_func();
+
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+SELECT count(*) FROM test_parallel_copy;
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+
+-- instead of insert trigger, no parallelism should be picked
+COPY instead_of_insert_tbl_view FROM stdin WITH(PARALLEL 1);;
+test1
+\.
+
+SELECT count(*) FROM instead_of_insert_tbl_view;
+
+-- parallel copy test for a partitioned table with a before insert trigger on
+-- one of the partition
+ALTER FUNCTION parallel_copy_trig_func PARALLEL SAFE;
+
+CREATE TABLE test_parallel_copy_part (
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+) PARTITION BY LIST (b);
+
+CREATE TABLE test_parallel_copy_part_a1 (c TEXT, b INT, a INT, e TEXT, d TEXT);
+
+CREATE TABLE test_parallel_copy_part_a2 (a INT, c TEXT, b INT, d TEXT, e TEXT);
+
+ALTER TABLE test_parallel_copy_part ATTACH PARTITION test_parallel_copy_part_a1 FOR VALUES IN(1);
+
+ALTER TABLE test_parallel_copy_part ATTACH PARTITION test_parallel_copy_part_a2 FOR VALUES IN(2);
+
+CREATE TRIGGER parallel_copy_trig
+BEFORE INSERT ON test_parallel_copy_part_a2
+FOR EACH ROW
+EXECUTE PROCEDURE parallel_copy_trig_func();
+
+-- Verify that sequential copy is choosen by checking error in not from a parallel worker.
+COPY test_parallel_copy_part FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2	test_ne2
+\.
+
+SELECT count(*) FROM test_parallel_copy_part;
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy_part_a2;
+
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE test_parallel_copy_unlogged;
+DROP TABLE test_parallel_copy_part;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
+DROP FUNCTION parallel_copy_trig_func();
 DROP TABLE x, y;
 DROP TABLE rls_t1 CASCADE;
 DROP ROLE regress_rls_copy_user;
-- 
1.8.3.1

#223vignesh C
vignesh21@gmail.com
In reply to: Heikki Linnakangas (#200)
Re: Parallel copy

On Thu, Oct 29, 2020 at 2:20 PM Heikki Linnakangas <hlinnaka@iki.fi> wrote:

On 27/10/2020 15:36, vignesh C wrote:

Attached v9 patches have the fixes for the above comments.

I did some testing:

/tmp/longdata.pl:
--------
#!/usr/bin/perl
#
# Generate three rows:
# foo
# longdatalongdatalongdata...
# bar
#
# The length of the middle row is given as command line arg.
#

my $bytes = $ARGV[0];

print "foo\n";
for(my $i = 0; $i < $bytes; $i+=8){
print "longdata";
}
print "\n";
print "bar\n";
--------

postgres=# copy longdata from program 'perl /tmp/longdata.pl 100000000'
with (parallel 2);

This gets stuck forever (or at least I didn't have the patience to wait
it finish). Both worker processes are consuming 100% of CPU.

Thanks for identifying this issue, this issue is fixed in v10 patch posted
at [1]/messages/by-id/CALDaNm05FnA-ePvYV_t2+WE_tXJymbfPwnm+kc9y1iMkR+NbUg@mail.gmail.com
[1]: /messages/by-id/CALDaNm05FnA-ePvYV_t2+WE_tXJymbfPwnm+kc9y1iMkR+NbUg@mail.gmail.com
/messages/by-id/CALDaNm05FnA-ePvYV_t2+WE_tXJymbfPwnm+kc9y1iMkR+NbUg@mail.gmail.com

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

#224vignesh C
vignesh21@gmail.com
In reply to: Hou, Zhijie (#198)
Re: Parallel copy

On Wed, Oct 28, 2020 at 5:36 PM Hou, Zhijie <houzj.fnst@cn.fujitsu.com>
wrote:

Hi

I found some issue in v9-0002

1.
+
+       elog(DEBUG1, "[Worker] Processing - line position:%d, block:%d,

unprocessed lines:%d, offset:%d, line size:%d",

+                write_pos, lineInfo->first_block,
+

pg_atomic_read_u32(&data_blk_ptr->unprocessed_line_parts),

+                offset, pg_atomic_read_u32(&lineInfo->line_size));
+

write_pos or other variable to be printed here are type of uint32, I

think it'better to use '%u' in elog msg.

Modified it.

2.
+ * line_size will be set. Read the line_size again to be

sure if it is

+                * completed or partial block.
+                */
+               dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+               if (dataSize)

It use dataSize( type int ) to get uint32 which seems a little dangerous.
Is it better to define dataSize uint32 here?

Modified it.

3.
Since function with 'Cstate' in name has been changed to 'CState'
I think we can change function PopulateCommonCstateInfo as well.

Modified it.

4.
+ if (pcdata->worker_line_buf_count)

I think some check like the above can be 'if (xxx > 0)', which seems

easier to understand.

Modified it.

Thanks for the comments, these issues are fixed in v10 patch posted at [1]/messages/by-id/CALDaNm05FnA-ePvYV_t2+WE_tXJymbfPwnm+kc9y1iMkR+NbUg@mail.gmail.com
[1]: /messages/by-id/CALDaNm05FnA-ePvYV_t2+WE_tXJymbfPwnm+kc9y1iMkR+NbUg@mail.gmail.com
/messages/by-id/CALDaNm05FnA-ePvYV_t2+WE_tXJymbfPwnm+kc9y1iMkR+NbUg@mail.gmail.com

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

#225vignesh C
vignesh21@gmail.com
In reply to: Daniel Westermann (DWE) (#201)
Re: Parallel copy

On Thu, Oct 29, 2020 at 2:26 PM Daniel Westermann (DWE)
<daniel.westermann@dbi-services.com> wrote:

On 27/10/2020 15:36, vignesh C wrote:

Attached v9 patches have the fixes for the above comments.

I did some testing:

I did some testing as well and have a cosmetic remark:

postgres=# copy t1 from '/var/tmp/aa.txt' with (parallel 1000000000);
ERROR: value 1000000000 out of bounds for option "parallel"
DETAIL: Valid values are between "1" and "1024".
postgres=# copy t1 from '/var/tmp/aa.txt' with (parallel 100000000000);
ERROR: parallel requires an integer value
postgres=#

Wouldn't it make more sense to only have one error message? The first one seems to be the better message.

I had seen similar behavior in other places too:
postgres=# vacuum (parallel 1000000000) t1;
ERROR: parallel vacuum degree must be between 0 and 1024
LINE 1: vacuum (parallel 1000000000) t1;
^
postgres=# vacuum (parallel 100000000000) t1;
ERROR: parallel requires an integer value

I'm not sure if we should fix this.

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

#226vignesh C
vignesh21@gmail.com
In reply to: Amit Kapila (#220)
Re: Parallel copy

On Fri, Nov 13, 2020 at 2:25 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Wed, Nov 11, 2020 at 10:42 PM vignesh C <vignesh21@gmail.com> wrote:

On Tue, Nov 10, 2020 at 7:27 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Tue, Nov 10, 2020 at 7:12 PM vignesh C <vignesh21@gmail.com> wrote:

On Tue, Nov 3, 2020 at 2:28 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

I have worked to provide a patch for the parallel safety checks. It
checks if parallely copy can be performed, Parallel copy cannot be
performed for the following a) If relation is temporary table b) If
relation is foreign table c) If relation has non parallel safe index
expressions d) If relation has triggers present whose type is of non
before statement trigger type e) If relation has check constraint
which are not parallel safe f) If relation has partition and any
partition has the above type. This patch has the checks for it. This
patch will be used by parallel copy implementation.

How did you ensure that this is sufficient? For parallel-insert's
patch we have enabled parallel-mode for Inserts and ran the tests with
force_parallel_mode to see if we are not missing anything. Also, it
seems there are many common things here w.r.t parallel-insert patch,
is it possible to prepare this atop that patch or do you have any
reason to keep this separate?

I have done similar testing for copy too, I had set force_parallel
mode to regress, hardcoded in the code to pick parallel workers for
copy operation and ran make installcheck-world to verify. Many checks
in this patch are common between both patches, but I was not sure how
to handle it as both the projects are in-progress and are being
updated based on the reviewer's opinion. How to handle this?
Thoughts?

I have not studied the differences in detail but if it is possible to
prepare it on top of that patch then there shouldn't be a problem. To
avoid confusion if you want you can always either post the latest
version of that patch with your patch or point to it.

I have made this as a separate patch as of now. I will work on to see
if I can use Greg's changes as it is or if required I will provide a
few review comments on top of Greg's patch so that it is usable for
parallel copy too and later post a separate patch with the changes on
top of it. I will retain it as a separate patch till that time.

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

#227vignesh C
vignesh21@gmail.com
In reply to: Tomas Vondra (#206)
Re: Parallel copy

On Sat, Oct 31, 2020 at 2:07 AM Tomas Vondra <tomas.vondra@2ndquadrant.com>
wrote:

Hi,

I've done a bit more testing today, and I think the parsing is busted in
some way. Consider this:

test=# create extension random;
CREATE EXTENSION

test=# create table t (a text);
CREATE TABLE

test=# insert into t select random_string(random_int(10, 256*1024))

from generate_series(1,10000);

INSERT 0 10000

test=# copy t to '/mnt/data/t.csv';
COPY 10000

test=# truncate t;
TRUNCATE TABLE

test=# copy t from '/mnt/data/t.csv';
COPY 10000

test=# truncate t;
TRUNCATE TABLE

test=# copy t from '/mnt/data/t.csv' with (parallel 2);
ERROR: invalid byte sequence for encoding "UTF8": 0x00
CONTEXT: COPY t, line 485: "m&\nh%_a"%r]>qtCl:Q5ltvF~;2oS6@HB
F>og,bD$Lw'nZY\tYl#BH\t{(j~ryoZ08"SGU~.}8CcTRk1\ts$@U3szCC+U1U3i@P..."
parallel worker

The functions come from an extension I use to generate random data, I've
pushed it to github [1]. The random_string() generates a random string
with ASCII characters, symbols and a couple special characters (\r\n\t).
The intent was to try loading data where a fields may span multiple 64kB
blocks and may contain newlines etc.

The non-parallel copy works fine, the parallel one fails. I haven't
investigated the details, but I guess it gets confused about where a
string starts/end, or something like that.

Thanks for identifying this issue, this issue is fixed in v10 patch posted
at [1]/messages/by-id/CALDaNm05FnA-ePvYV_t2+WE_tXJymbfPwnm+kc9y1iMkR+NbUg@mail.gmail.com
[1]: /messages/by-id/CALDaNm05FnA-ePvYV_t2+WE_tXJymbfPwnm+kc9y1iMkR+NbUg@mail.gmail.com
/messages/by-id/CALDaNm05FnA-ePvYV_t2+WE_tXJymbfPwnm+kc9y1iMkR+NbUg@mail.gmail.com

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

#228vignesh C
vignesh21@gmail.com
In reply to: vignesh C (#216)
Re: Parallel copy

On Sat, Nov 7, 2020 at 7:01 PM vignesh C <vignesh21@gmail.com> wrote:

On Thu, Nov 5, 2020 at 6:33 PM Hou, Zhijie <houzj.fnst@cn.fujitsu.com>

wrote:

Hi

my $bytes = $ARGV[0];
for(my $i = 0; $i < $bytes; $i+=8){
print "longdata";
}
print "\n";
--------

postgres=# copy longdata from program 'perl /tmp/longdata.pl

100000000'

with (parallel 2);

This gets stuck forever (or at least I didn't have the patience to

wait

it finish). Both worker processes are consuming 100% of CPU.

I had a look over this problem.

the ParallelCopyDataBlock has size limit:
uint8 skip_bytes;
char data[DATA_BLOCK_SIZE]; /* data read from file

*/

It seems the input line is so long that the leader process run out of

the Shared memory among parallel copy workers.

And the leader process keep waiting free block.

For the worker process, it wait util line_state becomes

LINE_LEADER_POPULATED,

But leader process won't set the line_state unless it read the whole

line.

So it stuck forever.
May be we should reconsider about this situation.

The stack is as follows:

Leader stack:
#3 0x000000000075f7a1 in WaitLatch (latch=<optimized out>,

wakeEvents=wakeEvents@entry=41, timeout=timeout@entry=1,
wait_event_info=wait_event_info@entry=150994945) at latch.c:411

#4 0x00000000005a9245 in WaitGetFreeCopyBlock

(pcshared_info=pcshared_info@entry=0x7f26d2ed3580) at copyparallel.c:1546

#5 0x00000000005a98ce in SetRawBufForLoad (cstate=cstate@entry=0x2978a88,

line_size=67108864, copy_buf_len=copy_buf_len@entry=65536,
raw_buf_ptr=raw_buf_ptr@entry=65536,

copy_raw_buf=copy_raw_buf@entry=0x7fff4cdc0e18) at

copyparallel.c:1572

#6 0x00000000005a1963 in CopyReadLineText (cstate=cstate@entry=0x2978a88)

at copy.c:4058

#7 0x00000000005a4e76 in CopyReadLine (cstate=cstate@entry=0x2978a88)

at copy.c:3863

Worker stack:
#0 GetLinePosition (cstate=cstate@entry=0x29e1f28) at

copyparallel.c:1474

#1 0x00000000005a8aa4 in CacheLineInfo (cstate=cstate@entry=0x29e1f28,

buff_count=buff_count@entry=0) at copyparallel.c:711

#2 0x00000000005a8e46 in GetWorkerLine (cstate=cstate@entry=0x29e1f28)

at copyparallel.c:885

#3 0x00000000005a4f2e in NextCopyFromRawFields (cstate=cstate@entry=0x29e1f28,

fields=fields@entry=0x7fff4cdc0b48, nfields=nfields@entry=0x7fff4cdc0b44)
at copy.c:3615

#4 0x00000000005a50af in NextCopyFrom (cstate=cstate@entry=0x29e1f28,

econtext=econtext@entry=0x2a358d8, values=0x2a42068, nulls=0x2a42070) at
copy.c:3696

#5 0x00000000005a5b90 in CopyFrom (cstate=cstate@entry=0x29e1f28) at

copy.c:2985

Thanks for providing your thoughts. I have analyzed this issue and I'm
working on the fix for this, I will be posting a patch for this
shortly.

I have fixed and provided a patch for this at [1]/messages/by-id/CALDaNm05FnA-ePvYV_t2+WE_tXJymbfPwnm+kc9y1iMkR+NbUg@mail.gmail.com
[1]: /messages/by-id/CALDaNm05FnA-ePvYV_t2+WE_tXJymbfPwnm+kc9y1iMkR+NbUg@mail.gmail.com
/messages/by-id/CALDaNm05FnA-ePvYV_t2+WE_tXJymbfPwnm+kc9y1iMkR+NbUg@mail.gmail.com

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

#229Hou, Zhijie
houzj.fnst@cn.fujitsu.com
In reply to: vignesh C (#222)
RE: Parallel copy

Hi Vignesh,

I took a look at the v10 patch set. Here are some comments:

1. 
+/*
+ * CheckExprParallelSafety
+ *
+ * Determine if where cluase and default expressions are parallel safe & do not
+ * have volatile expressions, return true if condition satisfies else return
+ * false.
+ */

'cluase' seems a typo.

2.
+			/*
+			 * Make sure that no worker has consumed this element, if this
+			 * line is spread across multiple data blocks, worker would have
+			 * started processing, no need to change the state to
+			 * LINE_LEADER_POPULATING in this case.
+			 */
+			(void) pg_atomic_compare_exchange_u32(&lineInfo->line_state,
+												  &current_line_state,
+												  LINE_LEADER_POPULATED);
About the commect
+			 * started processing, no need to change the state to
+			 * LINE_LEADER_POPULATING in this case.

Does it means no need to change the state to LINE_LEADER_POPULATED ' here?

3.
+ * 3) only one worker should choose one line for processing, this is handled by
+ *    using pg_atomic_compare_exchange_u32, worker will change the state to
+ *    LINE_WORKER_PROCESSING only if line_state is LINE_LEADER_POPULATED.

In the latest patch, it will set the state to LINE_WORKER_PROCESSING if line_state is LINE_LEADER_POPULATED or LINE_LEADER_POPULATING.
So The comment here seems wrong.

4.
A suggestion for CacheLineInfo.

It use appendBinaryStringXXX to store the line in memory.
appendBinaryStringXXX will double the str memory when there is no enough spaces.

How about call enlargeStringInfo in advance, if we already know the whole line size?
It can avoid some memory waste and may impove a little performance.

Best regards,
houzj

#230vignesh C
vignesh21@gmail.com
In reply to: Hou, Zhijie (#229)
6 attachment(s)
Re: Parallel copy

Thanks for the comments.

I took a look at the v10 patch set. Here are some comments:

1.
+/*
+ * CheckExprParallelSafety
+ *
+ * Determine if where cluase and default expressions are parallel safe & do not
+ * have volatile expressions, return true if condition satisfies else return
+ * false.
+ */

'cluase' seems a typo.

changed.

2.
+                       /*
+                        * Make sure that no worker has consumed this element, if this
+                        * line is spread across multiple data blocks, worker would have
+                        * started processing, no need to change the state to
+                        * LINE_LEADER_POPULATING in this case.
+                        */
+                       (void) pg_atomic_compare_exchange_u32(&lineInfo->line_state,
+                                                                                                 &current_line_state,
+                                                                                                 LINE_LEADER_POPULATED);
About the commect
+                        * started processing, no need to change the state to
+                        * LINE_LEADER_POPULATING in this case.

Does it means no need to change the state to LINE_LEADER_POPULATED ' here?

Yes it is LINE_LEADER_POPULATED, changed accordingly.

3.
+ * 3) only one worker should choose one line for processing, this is handled by
+ *    using pg_atomic_compare_exchange_u32, worker will change the state to
+ *    LINE_WORKER_PROCESSING only if line_state is LINE_LEADER_POPULATED.

In the latest patch, it will set the state to LINE_WORKER_PROCESSING if line_state is LINE_LEADER_POPULATED or LINE_LEADER_POPULATING.
So The comment here seems wrong.

Updated the comments.

4.
A suggestion for CacheLineInfo.

It use appendBinaryStringXXX to store the line in memory.
appendBinaryStringXXX will double the str memory when there is no enough spaces.

How about call enlargeStringInfo in advance, if we already know the whole line size?
It can avoid some memory waste and may impove a little performance.

Here we will not know the size beforehand, in some cases we will start
processing the data when current block is populated and keep
processing block by block, we will come to know of the size at the
end. We cannot use enlargeStringInfo because of this.

Attached v11 patch has the fix for this, it also includes the changes
to rebase on top of head.

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

Attachments:

v11-0001-Copy-code-readjustment-to-support-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=v11-0001-Copy-code-readjustment-to-support-parallel-copy.patchDownload
From 663a3cbfa0ac84774e2e1a6c0e55da2312badcea Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 2 Dec 2020 08:47:27 +0530
Subject: [PATCH v11 1/6] Copy code readjustment to support parallel copy.

This patch has the copy code slightly readjusted so that the common code is
separated to functions/macros, these functions/macros will be used by the
workers in the parallel copy code of the upcoming patches. EOL removal is moved
from CopyReadLine to CopyReadLineText, this change was required because in case
of parallel copy the record identification and record updation is done in
CopyReadLineText, before record information is updated in shared memory the new
line characters should be removed.
---
 src/backend/commands/copyfrom.c          | 474 +++++++++++++++++--------------
 src/backend/commands/copyfromparse.c     |  90 +++---
 src/include/commands/copyfrom_internal.h |   2 +
 3 files changed, 317 insertions(+), 249 deletions(-)

diff --git a/src/backend/commands/copyfrom.c b/src/backend/commands/copyfrom.c
index 1b14e9a..7f7f720 100644
--- a/src/backend/commands/copyfrom.c
+++ b/src/backend/commands/copyfrom.c
@@ -96,6 +96,8 @@ typedef struct CopyMultiInsertInfo
 static char *limit_printout_length(const char *str);
 
 static void ClosePipeFromProgram(CopyFromState cstate);
+static void PopulateCommonCStateInfo(CopyFromState cstate, TupleDesc tup_desc,
+									 List *attnamelist);
 
 /*
  * error context callback for COPY FROM
@@ -516,32 +518,13 @@ CopyMultiInsertInfoStore(CopyMultiInsertInfo *miinfo, ResultRelInfo *rri,
 }
 
 /*
- * Copy FROM file to relation.
+ * CheckTargetRelValidity
+ *
+ * Check if the relation specified in copy from is valid.
  */
-uint64
-CopyFrom(CopyFromState cstate)
+static void
+CheckTargetRelValidity(CopyFromState cstate)
 {
-	ResultRelInfo *resultRelInfo;
-	ResultRelInfo *target_resultRelInfo;
-	ResultRelInfo *prevResultRelInfo = NULL;
-	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
-	ModifyTableState *mtstate;
-	ExprContext *econtext;
-	TupleTableSlot *singleslot = NULL;
-	MemoryContext oldcontext = CurrentMemoryContext;
-
-	PartitionTupleRouting *proute = NULL;
-	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
-	int			ti_options = 0; /* start with default options for insert */
-	BulkInsertState bistate = NULL;
-	CopyInsertMethod insertMethod;
-	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
-	uint64		processed = 0;
-	bool		has_before_insert_row_trig;
-	bool		has_instead_insert_row_trig;
-	bool		leafpart_use_multi_insert = false;
-
 	Assert(cstate->rel);
 	Assert(list_length(cstate->range_table) == 1);
 
@@ -579,27 +562,6 @@ CopyFrom(CopyFromState cstate)
 							RelationGetRelationName(cstate->rel))));
 	}
 
-	/*
-	 * If the target file is new-in-transaction, we assume that checking FSM
-	 * for free space is a waste of time.  This could possibly be wrong, but
-	 * it's unlikely.
-	 */
-	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
-		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
-		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
-		ti_options |= TABLE_INSERT_SKIP_FSM;
-
-	/*
-	 * Optimize if new relfilenode was created in this subxact or one of its
-	 * committed children and we won't see those rows later as part of an
-	 * earlier scan or command. The subxact test ensures that if this subxact
-	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
-	 * that the stronger test of exactly which subtransaction created it is
-	 * crucial for correctness of this optimization. The test for an earlier
-	 * scan or command tolerates false negatives. FREEZE causes other sessions
-	 * to see rows they would not see under MVCC, and a false negative merely
-	 * spreads that anomaly to the current session.
-	 */
 	if (cstate->opts.freeze)
 	{
 		/*
@@ -637,7 +599,61 @@ CopyFrom(CopyFromState cstate)
 			ereport(ERROR,
 					(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
 					 errmsg("cannot perform COPY FREEZE because the table was not created or truncated in the current subtransaction")));
+	}
+}
+
+/*
+ * Copy FROM file to relation.
+ */
+uint64
+CopyFrom(CopyFromState cstate)
+{
+	ResultRelInfo *resultRelInfo;
+	ResultRelInfo *target_resultRelInfo;
+	ResultRelInfo *prevResultRelInfo = NULL;
+	EState	   *estate = CreateExecutorState(); /* for ExecConstraints() */
+	ModifyTableState *mtstate;
+	ExprContext *econtext;
+	TupleTableSlot *singleslot = NULL;
+	MemoryContext oldcontext = CurrentMemoryContext;
 
+	PartitionTupleRouting *proute = NULL;
+	ErrorContextCallback errcallback;
+	CommandId	mycid = GetCurrentCommandId(true);
+	int			ti_options = 0; /* start with default options for insert */
+	BulkInsertState bistate = NULL;
+	CopyInsertMethod insertMethod;
+	CopyMultiInsertInfo multiInsertInfo = {0};	/* pacify compiler */
+	uint64		processed = 0;
+	bool		has_before_insert_row_trig;
+	bool		has_instead_insert_row_trig;
+	bool		leafpart_use_multi_insert = false;
+
+	CheckTargetRelValidity(cstate);
+
+	/*
+	 * If the target file is new-in-transaction, we assume that checking FSM
+	 * for free space is a waste of time.  This could possibly be wrong, but
+	 * it's unlikely.
+	 */
+	if (RELKIND_HAS_STORAGE(cstate->rel->rd_rel->relkind) &&
+		(cstate->rel->rd_createSubid != InvalidSubTransactionId ||
+		 cstate->rel->rd_firstRelfilenodeSubid != InvalidSubTransactionId))
+		ti_options |= TABLE_INSERT_SKIP_FSM;
+
+	/*
+	 * Optimize if new relfilenode was created in this subxact or one of its
+	 * committed children and we won't see those rows later as part of an
+	 * earlier scan or command. The subxact test ensures that if this subxact
+	 * aborts then the frozen rows won't be visible after xact cleanup.  Note
+	 * that the stronger test of exactly which subtransaction created it is
+	 * crucial for correctness of this optimization. The test for an earlier
+	 * scan or command tolerates false negatives. FREEZE causes other sessions
+	 * to see rows they would not see under MVCC, and a false negative merely
+	 * spreads that anomaly to the current session.
+	 */
+	if (cstate->opts.freeze)
+	{
 		ti_options |= TABLE_INSERT_FROZEN;
 	}
 
@@ -1160,30 +1176,13 @@ CopyFrom(CopyFromState cstate)
 }
 
 /*
- * Setup to read tuples from a file for COPY FROM.
- *
- * 'rel': Used as a template for the tuples
- * 'whereClause': WHERE clause from the COPY FROM command
- * 'filename': Name of server-local file to read, NULL for STDIN
- * 'is_program': true if 'filename' is program to execute
- * 'data_source_cb': callback that provides the input data
- * 'attnamelist': List of char *, columns to include. NIL selects all cols.
- * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
+ * PopulateCStateCatalogInfo
  *
- * Returns a CopyFromState, to be passed to NextCopyFrom and related functions.
+ * Populate the cstate catalog information.
  */
-CopyFromState
-BeginCopyFrom(ParseState *pstate,
-			  Relation rel,
-			  Node *whereClause,
-			  const char *filename,
-			  bool is_program,
-			  copy_data_source_cb data_source_cb,
-			  List *attnamelist,
-			  List *options)
+static void
+PopulateCStateCatalogInfo(CopyFromState cstate)
 {
-	CopyFromState	cstate;
-	bool		pipe = (filename == NULL);
 	TupleDesc	tupDesc;
 	AttrNumber	num_phys_attrs,
 				num_defaults;
@@ -1193,158 +1192,8 @@ BeginCopyFrom(ParseState *pstate,
 	Oid			in_func_oid;
 	int		   *defmap;
 	ExprState **defexprs;
-	MemoryContext oldcontext;
 	bool		volatile_defexprs;
 
-	/* Allocate workspace and zero all fields */
-	cstate = (CopyFromStateData *) palloc0(sizeof(CopyFromStateData));
-
-	/*
-	 * We allocate everything used by a cstate in a new memory context. This
-	 * avoids memory leaks during repeated use of COPY in a query.
-	 */
-	cstate->copycontext = AllocSetContextCreate(CurrentMemoryContext,
-												"COPY",
-												ALLOCSET_DEFAULT_SIZES);
-
-	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
-
-	/* Extract options from the statement node tree */
-	ProcessCopyOptions(pstate, &cstate->opts, true /* is_from */, options);
-
-	/* Process the target relation */
-	cstate->rel = rel;
-
-	tupDesc = RelationGetDescr(cstate->rel);
-
-	/* process commmon options or initialization */
-
-	/* Generate or convert list of attributes to process */
-	cstate->attnumlist = CopyGetAttnums(tupDesc, cstate->rel, attnamelist);
-
-	num_phys_attrs = tupDesc->natts;
-
-	/* Convert FORCE_NOT_NULL name list to per-column flags, check validity */
-	cstate->opts.force_notnull_flags = (bool *) palloc0(num_phys_attrs * sizeof(bool));
-	if (cstate->opts.force_notnull)
-	{
-		List	   *attnums;
-		ListCell   *cur;
-
-		attnums = CopyGetAttnums(tupDesc, cstate->rel, cstate->opts.force_notnull);
-
-		foreach(cur, attnums)
-		{
-			int			attnum = lfirst_int(cur);
-			Form_pg_attribute attr = TupleDescAttr(tupDesc, attnum - 1);
-
-			if (!list_member_int(cstate->attnumlist, attnum))
-				ereport(ERROR,
-						(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
-						 errmsg("FORCE_NOT_NULL column \"%s\" not referenced by COPY",
-								NameStr(attr->attname))));
-			cstate->opts.force_notnull_flags[attnum - 1] = true;
-		}
-	}
-
-	/* Convert FORCE_NULL name list to per-column flags, check validity */
-	cstate->opts.force_null_flags = (bool *) palloc0(num_phys_attrs * sizeof(bool));
-	if (cstate->opts.force_null)
-	{
-		List	   *attnums;
-		ListCell   *cur;
-
-		attnums = CopyGetAttnums(tupDesc, cstate->rel, cstate->opts.force_null);
-
-		foreach(cur, attnums)
-		{
-			int			attnum = lfirst_int(cur);
-			Form_pg_attribute attr = TupleDescAttr(tupDesc, attnum - 1);
-
-			if (!list_member_int(cstate->attnumlist, attnum))
-				ereport(ERROR,
-						(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
-						 errmsg("FORCE_NULL column \"%s\" not referenced by COPY",
-								NameStr(attr->attname))));
-			cstate->opts.force_null_flags[attnum - 1] = true;
-		}
-	}
-
-	/* Convert convert_selectively name list to per-column flags */
-	if (cstate->opts.convert_selectively)
-	{
-		List	   *attnums;
-		ListCell   *cur;
-
-		cstate->convert_select_flags = (bool *) palloc0(num_phys_attrs * sizeof(bool));
-
-		attnums = CopyGetAttnums(tupDesc, cstate->rel, cstate->opts.convert_select);
-
-		foreach(cur, attnums)
-		{
-			int			attnum = lfirst_int(cur);
-			Form_pg_attribute attr = TupleDescAttr(tupDesc, attnum - 1);
-
-			if (!list_member_int(cstate->attnumlist, attnum))
-				ereport(ERROR,
-						(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
-						 errmsg_internal("selected column \"%s\" not referenced by COPY",
-										 NameStr(attr->attname))));
-			cstate->convert_select_flags[attnum - 1] = true;
-		}
-	}
-
-	/* Use client encoding when ENCODING option is not specified. */
-	if (cstate->opts.file_encoding < 0)
-		cstate->file_encoding = pg_get_client_encoding();
-	else
-		cstate->file_encoding = cstate->opts.file_encoding;
-
-	/*
-	 * Set up encoding conversion info.  Even if the file and server encodings
-	 * are the same, we must apply pg_any_to_server() to validate data in
-	 * multibyte encodings.
-	 */
-	cstate->need_transcoding =
-		(cstate->file_encoding != GetDatabaseEncoding() ||
-		 pg_database_encoding_max_length() > 1);
-	/* See Multibyte encoding comment above */
-	cstate->encoding_embeds_ascii = PG_ENCODING_IS_CLIENT_ONLY(cstate->file_encoding);
-
-	cstate->copy_src = COPY_FILE;	/* default */
-
-	cstate->whereClause = whereClause;
-
-	MemoryContextSwitchTo(oldcontext);
-
-	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
-
-	/* Initialize state variables */
-	cstate->reached_eof = false;
-	cstate->eol_type = EOL_UNKNOWN;
-	cstate->cur_relname = RelationGetRelationName(cstate->rel);
-	cstate->cur_lineno = 0;
-	cstate->cur_attname = NULL;
-	cstate->cur_attval = NULL;
-
-	/*
-	 * Set up variables to avoid per-attribute overhead.  attribute_buf and
-	 * raw_buf are used in both text and binary modes, but we use line_buf
-	 * only in text mode.
-	 */
-	initStringInfo(&cstate->attribute_buf);
-	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
-	cstate->raw_buf_index = cstate->raw_buf_len = 0;
-	if (!cstate->opts.binary)
-	{
-		initStringInfo(&cstate->line_buf);
-		cstate->line_buf_converted = false;
-	}
-
-	/* Assign range table, we'll need it in CopyFrom. */
-	if (pstate)
-		cstate->range_table = pstate->p_rtable;
-
 	tupDesc = RelationGetDescr(cstate->rel);
 	num_phys_attrs = tupDesc->natts;
 	num_defaults = 0;
@@ -1422,6 +1271,95 @@ BeginCopyFrom(ParseState *pstate,
 	cstate->defexprs = defexprs;
 	cstate->volatile_defexprs = volatile_defexprs;
 	cstate->num_defaults = num_defaults;
+}
+
+/*
+ * Setup to read tuples from a file for COPY FROM.
+ *
+ * 'rel': Used as a template for the tuples
+ * 'whereClause': WHERE clause from the COPY FROM command
+ * 'filename': Name of server-local file to read, NULL for STDIN
+ * 'is_program': true if 'filename' is program to execute
+ * 'data_source_cb': callback that provides the input data
+ * 'attnamelist': List of char *, columns to include. NIL selects all cols.
+ * 'options': List of DefElem. See copy_opt_item in gram.y for selections.
+ *
+ * Returns a CopyFromState, to be passed to NextCopyFrom and related functions.
+ */
+CopyFromState
+BeginCopyFrom(ParseState *pstate,
+			  Relation rel,
+			  Node *whereClause,
+			  const char *filename,
+			  bool is_program,
+			  copy_data_source_cb data_source_cb,
+			  List *attnamelist,
+			  List *options)
+{
+	CopyFromState cstate;
+	bool		pipe = (filename == NULL);
+	TupleDesc	tupDesc;
+	MemoryContext oldcontext;
+
+	/* Allocate workspace and zero all fields */
+	cstate = (CopyFromStateData *) palloc0(sizeof(CopyFromStateData));
+
+	/*
+	 * We allocate everything used by a cstate in a new memory context. This
+	 * avoids memory leaks during repeated use of COPY in a query.
+	 */
+	cstate->copycontext = AllocSetContextCreate(CurrentMemoryContext,
+												"COPY",
+												ALLOCSET_DEFAULT_SIZES);
+
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	/* Extract options from the statement node tree */
+	ProcessCopyOptions(pstate, &cstate->opts, true /* is_from */ , options);
+
+	/* Process the target relation */
+	cstate->rel = rel;
+
+	tupDesc = RelationGetDescr(cstate->rel);
+
+	/* process commmon options or initialization */
+	PopulateCommonCStateInfo(cstate, tupDesc, attnamelist);
+
+	cstate->copy_src = COPY_FILE;	/* default */
+
+	cstate->whereClause = whereClause;
+
+	MemoryContextSwitchTo(oldcontext);
+
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	/* Initialize state variables */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/*
+	 * Set up variables to avoid per-attribute overhead.  attribute_buf and
+	 * raw_buf are used in both text and binary modes, but we use line_buf
+	 * only in text mode.
+	 */
+	initStringInfo(&cstate->attribute_buf);
+	cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+	if (!cstate->opts.binary)
+	{
+		initStringInfo(&cstate->line_buf);
+		cstate->line_buf_converted = false;
+	}
+
+	/* Assign range table, we'll need it in CopyFrom. */
+	if (pstate)
+		cstate->range_table = pstate->p_rtable;
+
+	PopulateCStateCatalogInfo(cstate);
 	cstate->is_program = is_program;
 
 	if (data_source_cb)
@@ -1503,6 +1441,110 @@ BeginCopyFrom(ParseState *pstate,
 }
 
 /*
+ * PopulateCommonCStateInfo
+ *
+ * Populates the common variables required for copy from operation. This is a
+ * helper function for BeginCopy function.
+ */
+static void
+PopulateCommonCStateInfo(CopyFromState cstate, TupleDesc tupDesc, List *attnamelist)
+{
+	int			num_phys_attrs;
+
+	/* Generate or convert list of attributes to process */
+	cstate->attnumlist = CopyGetAttnums(tupDesc, cstate->rel, attnamelist);
+
+	num_phys_attrs = tupDesc->natts;
+
+	/* Convert FORCE_NOT_NULL name list to per-column flags, check validity */
+	cstate->opts.force_notnull_flags = (bool *) palloc0(num_phys_attrs * sizeof(bool));
+	if (cstate->opts.force_notnull)
+	{
+		List	   *attnums;
+		ListCell   *cur;
+
+		attnums = CopyGetAttnums(tupDesc, cstate->rel, cstate->opts.force_notnull);
+
+		foreach(cur, attnums)
+		{
+			int			attnum = lfirst_int(cur);
+			Form_pg_attribute attr = TupleDescAttr(tupDesc, attnum - 1);
+
+			if (!list_member_int(cstate->attnumlist, attnum))
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
+						 errmsg("FORCE_NOT_NULL column \"%s\" not referenced by COPY",
+								NameStr(attr->attname))));
+			cstate->opts.force_notnull_flags[attnum - 1] = true;
+		}
+	}
+
+	/* Convert FORCE_NULL name list to per-column flags, check validity */
+	cstate->opts.force_null_flags = (bool *) palloc0(num_phys_attrs * sizeof(bool));
+	if (cstate->opts.force_null)
+	{
+		List	   *attnums;
+		ListCell   *cur;
+
+		attnums = CopyGetAttnums(tupDesc, cstate->rel, cstate->opts.force_null);
+
+		foreach(cur, attnums)
+		{
+			int			attnum = lfirst_int(cur);
+			Form_pg_attribute attr = TupleDescAttr(tupDesc, attnum - 1);
+
+			if (!list_member_int(cstate->attnumlist, attnum))
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
+						 errmsg("FORCE_NULL column \"%s\" not referenced by COPY",
+								NameStr(attr->attname))));
+			cstate->opts.force_null_flags[attnum - 1] = true;
+		}
+	}
+
+	/* Convert convert_selectively name list to per-column flags */
+	if (cstate->opts.convert_selectively)
+	{
+		List	   *attnums;
+		ListCell   *cur;
+
+		cstate->convert_select_flags = (bool *) palloc0(num_phys_attrs * sizeof(bool));
+
+		attnums = CopyGetAttnums(tupDesc, cstate->rel, cstate->opts.convert_select);
+
+		foreach(cur, attnums)
+		{
+			int			attnum = lfirst_int(cur);
+			Form_pg_attribute attr = TupleDescAttr(tupDesc, attnum - 1);
+
+			if (!list_member_int(cstate->attnumlist, attnum))
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
+						 errmsg_internal("selected column \"%s\" not referenced by COPY",
+										 NameStr(attr->attname))));
+			cstate->convert_select_flags[attnum - 1] = true;
+		}
+	}
+
+	/* Use client encoding when ENCODING option is not specified. */
+	if (cstate->opts.file_encoding < 0)
+		cstate->file_encoding = pg_get_client_encoding();
+	else
+		cstate->file_encoding = cstate->opts.file_encoding;
+
+	/*
+	 * Set up encoding conversion info.  Even if the file and server encodings
+	 * are the same, we must apply pg_any_to_server() to validate data in
+	 * multibyte encodings.
+	 */
+	cstate->need_transcoding =
+		(cstate->file_encoding != GetDatabaseEncoding() ||
+		 pg_database_encoding_max_length() > 1);
+	/* See Multibyte encoding comment above */
+	cstate->encoding_embeds_ascii = PG_ENCODING_IS_CLIENT_ONLY(cstate->file_encoding);
+}
+
+/*
  * Clean up storage and release resources for COPY FROM.
  */
 void
diff --git a/src/backend/commands/copyfromparse.c b/src/backend/commands/copyfromparse.c
index 34ed3cf..6762f3c 100644
--- a/src/backend/commands/copyfromparse.c
+++ b/src/backend/commands/copyfromparse.c
@@ -118,6 +118,9 @@ static inline bool CopyGetInt32(CopyFromState cstate, int32 *val);
 static inline bool CopyGetInt16(CopyFromState cstate, int16 *val);
 static bool CopyLoadRawBuf(CopyFromState cstate);
 static int	CopyReadBinaryData(CopyFromState cstate, char *dest, int nbytes);
+static void ClearEOLFromCopiedData(CopyFromState cstate, char *copy_line_data,
+								   int copy_line_pos, int *copy_line_size);
+static void ConvertToServerEncoding(CopyFromState cstate);
 
 void
 ReceiveCopyBegin(CopyFromState cstate)
@@ -716,40 +719,60 @@ CopyReadLine(CopyFromState cstate)
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
-	else
+
+	ConvertToServerEncoding(cstate);
+	return result;
+}
+
+/*
+ * ClearEOLFromCopiedData
+ *
+ * Clear EOL from the copied data.
+ */
+static void
+ClearEOLFromCopiedData(CopyFromState cstate, char *copy_line_data,
+					   int copy_line_pos, int *copy_line_size)
+{
+	/*
+	 * If we didn't hit EOF, then we must have transferred the EOL marker to
+	 * line_buf along with the data.  Get rid of it.
+	 */
+	switch (cstate->eol_type)
 	{
-		/*
-		 * If we didn't hit EOF, then we must have transferred the EOL marker
-		 * to line_buf along with the data.  Get rid of it.
-		 */
-		switch (cstate->eol_type)
-		{
-			case EOL_NL:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CR:
-				Assert(cstate->line_buf.len >= 1);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\r');
-				cstate->line_buf.len--;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_CRNL:
-				Assert(cstate->line_buf.len >= 2);
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 2] == '\r');
-				Assert(cstate->line_buf.data[cstate->line_buf.len - 1] == '\n');
-				cstate->line_buf.len -= 2;
-				cstate->line_buf.data[cstate->line_buf.len] = '\0';
-				break;
-			case EOL_UNKNOWN:
-				/* shouldn't get here */
-				Assert(false);
-				break;
-		}
+		case EOL_NL:
+			Assert(*copy_line_size >= 1);
+			Assert(copy_line_data[copy_line_pos - 1] == '\n');
+			copy_line_data[copy_line_pos - 1] = '\0';
+			(*copy_line_size)--;
+			break;
+		case EOL_CR:
+			Assert(*copy_line_size >= 1);
+			Assert(copy_line_data[copy_line_pos - 1] == '\r');
+			copy_line_data[copy_line_pos - 1] = '\0';
+			(*copy_line_size)--;
+			break;
+		case EOL_CRNL:
+			Assert(*copy_line_size >= 2);
+			Assert(copy_line_data[copy_line_pos - 2] == '\r');
+			Assert(copy_line_data[copy_line_pos - 1] == '\n');
+			copy_line_data[copy_line_pos - 2] = '\0';
+			*copy_line_size -= 2;
+			break;
+		case EOL_UNKNOWN:
+			/* shouldn't get here */
+			Assert(false);
+			break;
 	}
+}
 
+/*
+ * ConvertToServerEncoding
+ *
+ * Convert contents to server encoding.
+ */
+static void
+ConvertToServerEncoding(CopyFromState cstate)
+{
 	/* Done reading the line.  Convert it to server encoding. */
 	if (cstate->need_transcoding)
 	{
@@ -769,8 +792,6 @@ CopyReadLine(CopyFromState cstate)
 
 	/* Now it's safe to use the buffer in error messages */
 	cstate->line_buf_converted = true;
-
-	return result;
 }
 
 /*
@@ -1133,6 +1154,9 @@ not_end_of_copy:
 	 * Transfer any still-uncopied data to line_buf.
 	 */
 	REFILL_LINEBUF;
+	if (!result && !IsHeaderLine())
+		ClearEOLFromCopiedData(cstate, cstate->line_buf.data,
+							   cstate->line_buf.len, &cstate->line_buf.len);
 
 	return result;
 }
diff --git a/src/include/commands/copyfrom_internal.h b/src/include/commands/copyfrom_internal.h
index c15ea80..1cda8de 100644
--- a/src/include/commands/copyfrom_internal.h
+++ b/src/include/commands/copyfrom_internal.h
@@ -17,6 +17,8 @@
 #include "commands/copy.h"
 #include "commands/trigger.h"
 
+#define IsHeaderLine()			(cstate->opts.header_line && cstate->cur_lineno == 1)
+
 /*
  * Represents the different source cases we need to worry about at
  * the bottom level
-- 
1.8.3.1

v11-0002-Check-if-parallel-copy-can-be-performed.patchtext/x-patch; charset=US-ASCII; name=v11-0002-Check-if-parallel-copy-can-be-performed.patchDownload
From 767c587d25109b9df7002aed11250ec31c8b4d92 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 2 Dec 2020 10:21:13 +0530
Subject: [PATCH v11 2/6] Check if parallel copy can be performed.

Checks if parallely copy can be performed, Parallel copy cannot be performed
for the following a) If relation is temporary table b) If relation is foreign
table c) If relation has non parallel safe index expressions d) If relation has
triggers present whose type is of non before statement trigger type e) If
relation has check constraint which are not parallel safe f) If relation
has partition and any partition has the above type. This patch has the
checks for it. This patch will be used by parallel copy implementation patch.
---
 src/backend/access/heap/heapam.c         |  11 -
 src/backend/access/transam/xact.c        |  26 +-
 src/backend/commands/Makefile            |   1 +
 src/backend/commands/copyparallel.c      | 104 ++++++++
 src/backend/optimizer/util/clauses.c     | 405 +++++++++++++++++++++++++++++++
 src/include/access/xact.h                |   1 +
 src/include/commands/copyfrom_internal.h |   1 +
 src/include/optimizer/clauses.h          |   1 +
 8 files changed, 534 insertions(+), 16 deletions(-)
 create mode 100644 src/backend/commands/copyparallel.c

diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 1b2f704..3045c0f 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -2043,17 +2043,6 @@ static HeapTuple
 heap_prepare_insert(Relation relation, HeapTuple tup, TransactionId xid,
 					CommandId cid, int options)
 {
-	/*
-	 * To allow parallel inserts, we need to ensure that they are safe to be
-	 * performed in workers. We have the infrastructure to allow parallel
-	 * inserts in general except for the cases where inserts generate a new
-	 * CommandId (eg. inserts into a table having a foreign key column).
-	 */
-	if (IsParallelWorker())
-		ereport(ERROR,
-				(errcode(ERRCODE_INVALID_TRANSACTION_STATE),
-				 errmsg("cannot insert tuples in a parallel worker")));
-
 	tup->t_data->t_infomask &= ~(HEAP_XACT_MASK);
 	tup->t_data->t_infomask2 &= ~(HEAP2_XACT_MASK);
 	tup->t_data->t_infomask |= HEAP_XMAX_INVALID;
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 9cd0b7c..35259e2 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -764,18 +764,34 @@ GetCurrentCommandId(bool used)
 	if (used)
 	{
 		/*
-		 * Forbid setting currentCommandIdUsed in a parallel worker, because
-		 * we have no provision for communicating this back to the leader.  We
-		 * could relax this restriction when currentCommandIdUsed was already
-		 * true at the start of the parallel operation.
+		 * If in a parallel worker, only allow setting currentCommandIdUsed if
+		 * currentCommandIdUsed was already true at the start of the parallel
+		 * operation (by way of SetCurrentCommandIdUsed()), otherwise forbid
+		 * setting currentCommandIdUsed because we have no provision for
+		 * communicating this back to the leader.
 		 */
-		Assert(!IsParallelWorker());
+		Assert(!(IsParallelWorker() && !currentCommandIdUsed));
 		currentCommandIdUsed = true;
 	}
 	return currentCommandId;
 }
 
 /*
+ *	SetCurrentCommandIdUsedForWorker
+ *
+ * For a parallel worker, record that the currentCommandId has been used.
+ * This must only be called at the start of a parallel operation.
+ */
+void
+SetCurrentCommandIdUsedForWorker(void)
+{
+	Assert(IsParallelWorker() && !currentCommandIdUsed &&
+		   (currentCommandId != InvalidCommandId));
+
+	currentCommandIdUsed = true;
+}
+
+/*
  *	SetParallelStartTimestamps
  *
  * In a parallel worker, we should inherit the parent transaction's
diff --git a/src/backend/commands/Makefile b/src/backend/commands/Makefile
index e8504f0..ab10925 100644
--- a/src/backend/commands/Makefile
+++ b/src/backend/commands/Makefile
@@ -26,6 +26,7 @@ OBJS = \
 	copy.o \
 	copyfrom.o \
 	copyfromparse.o \
+	copyparallel.o \
 	copyto.o \
 	createas.o \
 	dbcommands.o \
diff --git a/src/backend/commands/copyparallel.c b/src/backend/commands/copyparallel.c
new file mode 100644
index 0000000..374f95f
--- /dev/null
+++ b/src/backend/commands/copyparallel.c
@@ -0,0 +1,104 @@
+/*-------------------------------------------------------------------------
+ *
+ * copyparallel.c
+ *              Implements the Parallel COPY utility command
+ *
+ * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ *        src/backend/commands/copyparallel.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/heapam.h"
+#include "catalog/pg_proc_d.h"
+#include "commands/copy.h"
+#include "commands/copyfrom_internal.h"
+#include "libpq/libpq.h"
+#include "optimizer/clauses.h"
+#include "optimizer/optimizer.h"
+#include "pgstat.h"
+#include "utils/lsyscache.h"
+
+/*
+ * CheckExprParallelSafety
+ *
+ * Determine if where clause and default expressions are parallel safe & do not
+ * have volatile expressions, return true if condition satisfies else return
+ * false.
+ */
+static bool
+CheckExprParallelSafety(CopyFromState cstate)
+{
+	if (max_parallel_hazard((Query *) cstate->whereClause) != PROPARALLEL_SAFE)
+		return false;
+
+	/*
+	 * Can't support parallel copy if there are any volatile function
+	 * expressions in WHERE clause as such expressions may query the table
+	 * we're inserting into.
+	 */
+	if (contain_volatile_functions(cstate->whereClause))
+		return false;
+
+	/*
+	 * Check if any of the column has default expression. if yes, and they are
+	 * not parallel safe, then parallelism is not allowed. For instance, if
+	 * there are any serial/bigserial columns for which nextval() default
+	 * expression which is parallel unsafe is associated, parallelism should
+	 * not be allowed.
+	 */
+	if (cstate->defexprs != NULL && cstate->num_defaults != 0)
+	{
+		int			i;
+
+		for (i = 0; i < cstate->num_defaults; i++)
+		{
+			if (max_parallel_hazard((Query *) cstate->defexprs[i]->expr) !=
+				PROPARALLEL_SAFE)
+				return false;
+
+			/*
+			 * Can't support parallel copy if there are any volatile function
+			 * expressions in default expressions as such expressions may
+			 * query the table we're inserting into.
+			 */
+			if (contain_volatile_functions((Node *) cstate->defexprs[i]->expr))
+				return false;
+		}
+	}
+
+	return true;
+}
+
+/*
+ * IsParallelCopyAllowed
+ *
+ * Check if parallel copy can be allowed.
+ */
+bool
+IsParallelCopyAllowed(CopyFromState cstate, Oid relid)
+{
+	/*
+	 * Check if parallel operation can be performed based on local
+	 * table/foreign table/index/check constraints/triggers present for the
+	 * relation and also by doing similar checks recursively for each of the
+	 * associated parrtitions if exists.
+	 */
+	if (MaxParallelHazardForModify(relid) != PROPARALLEL_SAFE)
+		return false;
+
+	/*
+	 * If there are volatile default expressions or where clause contain
+	 * volatile expressions, allow parallelism if they are parallel safe,
+	 * otherwise not.
+	 */
+	if (!CheckExprParallelSafety(cstate))
+		return false;
+
+	return true;
+}
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 587d494..8f468b3 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -20,12 +20,19 @@
 #include "postgres.h"
 
 #include "access/htup_details.h"
+#include "access/genam.h"
+#include "access/table.h"
+#include "catalog/index.h"
+#include "catalog/indexing.h"
 #include "catalog/pg_aggregate.h"
 #include "catalog/pg_class.h"
+#include "catalog/pg_constraint.h"
+#include "catalog/pg_constraint_d.h"
 #include "catalog/pg_language.h"
 #include "catalog/pg_operator.h"
 #include "catalog/pg_proc.h"
 #include "catalog/pg_type.h"
+#include "commands/trigger.h"
 #include "executor/executor.h"
 #include "executor/functions.h"
 #include "funcapi.h"
@@ -42,7 +49,9 @@
 #include "parser/parse_agg.h"
 #include "parser/parse_coerce.h"
 #include "parser/parse_func.h"
+#include "partitioning/partdesc.h"
 #include "rewrite/rewriteManip.h"
+#include "storage/lmgr.h"
 #include "tcop/tcopprot.h"
 #include "utils/acl.h"
 #include "utils/builtins.h"
@@ -50,6 +59,7 @@
 #include "utils/fmgroids.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
+#include "utils/partcache.h"
 #include "utils/syscache.h"
 #include "utils/typcache.h"
 
@@ -785,6 +795,401 @@ max_parallel_hazard_walker(Node *node, max_parallel_hazard_context *context)
 								  context);
 }
 
+/*
+ * MaxTriggerDataParallelHazardForModify
+ *
+ * Finds the maximum parallel-mode hazard level for the specified trigger data.
+ */
+static char
+MaxTriggerDataParallelHazardForModify(TriggerDesc *trigdesc,
+									  max_parallel_hazard_context *context)
+{
+	int			i;
+
+	/*
+	 * When transition tables are involved (if after statement triggers are
+	 * present), we collect minimal tuples in the tuple store after processing
+	 * them so that later after statement triggers can access them.  Now, if
+	 * we want to enable parallelism for such cases, we instead need to store
+	 * and access tuples from shared tuple store.  However, it does not have
+	 * the facility to store tuples in-memory, so we always need to store and
+	 * access from a file which could be costly unless we also have an
+	 * additional way to store minimal tuples in shared memory till work_mem
+	 * and then in shared tuple store. It is possible to do all this to enable
+	 * parallel copy for such cases. Currently, we can disallow parallelism
+	 * for such cases and later allow if required.
+	 *
+	 * When there are BEFORE/AFTER/INSTEAD OF row triggers on the table. We do
+	 * not allow parallelism in such cases because such triggers might query
+	 * the table we are inserting into and act differently if the tuples that
+	 * have already been processed and prepared for insertion are not there.
+	 * Now, if we allow parallelism with such triggers the behaviour would
+	 * depend on if the parallel worker has already inserted or not that
+	 * particular tuples.
+	 */
+	if (trigdesc->trig_insert_after_statement ||
+		trigdesc->trig_insert_new_table ||
+		trigdesc->trig_insert_before_row ||
+		trigdesc->trig_insert_after_row ||
+		trigdesc->trig_insert_instead_row)
+	{
+		context->max_hazard = PROPARALLEL_UNSAFE;
+		return context->max_hazard;
+	}
+
+	for (i = 0; i < trigdesc->numtriggers; i++)
+	{
+		Trigger    *trigger = &trigdesc->triggers[i];
+		int			trigtype;
+
+		/*
+		 * If the trigger type is RI_TRIGGER_FK, this indicates a FK exists in
+		 * the relation, and this would result in creation of new CommandIds
+		 * on insert/update/delete and this isn't supported in a parallel
+		 * worker (but is safe in the parallel leader).
+		 */
+		trigtype = RI_FKey_trigger_type(trigger->tgfoid);
+
+		/*
+		 * No parallelism if foreign key check trigger is present. This is
+		 * because, while performing foreign key checks, we take KEY SHARE
+		 * lock on primary key table rows which inturn will increment the
+		 * command counter and updates the snapshot.  Since we share the
+		 * snapshots at the beginning of the command, we can't allow it to be
+		 * changed later. So, unless we do something special for it, we can't
+		 * allow parallelism in such cases.
+		 */
+		if (trigtype == RI_TRIGGER_FK)
+		{
+			context->max_hazard = PROPARALLEL_UNSAFE;
+			return context->max_hazard;
+		}
+	}
+
+	return context->max_hazard;
+}
+
+/*
+ * MaxIndexExprsParallelHazardForModify
+ *
+ * Finds the maximum parallel-mode hazard level for any existing index
+ * expressions of a specified relation.
+ */
+static char
+MaxIndexExprsParallelHazardForModify(Relation rel,
+									 max_parallel_hazard_context *context)
+{
+	List	   *indexOidList;
+	ListCell   *lc;
+	LOCKMODE	lockmode = AccessShareLock;
+
+	indexOidList = RelationGetIndexList(rel);
+	foreach(lc, indexOidList)
+	{
+		Oid			indexOid = lfirst_oid(lc);
+		Relation	indexRel;
+		IndexInfo  *indexInfo;
+
+		if (ConditionalLockRelationOid(indexOid, lockmode))
+		{
+			indexRel = index_open(indexOid, NoLock);
+		}
+		else
+		{
+			context->max_hazard = PROPARALLEL_UNSAFE;
+			return context->max_hazard;
+		}
+
+		indexInfo = BuildIndexInfo(indexRel);
+
+		if (indexInfo->ii_Expressions != NIL)
+		{
+			int			i;
+			ListCell   *indexExprItem = list_head(indexInfo->ii_Expressions);
+
+			for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
+			{
+				int			keycol = indexInfo->ii_IndexAttrNumbers[i];
+
+				if (keycol == 0)
+				{
+					/* Found an index expression */
+
+					Node	   *indexExpr;
+
+					if (indexExprItem == NULL)	/* shouldn't happen */
+						elog(ERROR, "too few entries in indexprs list");
+
+					indexExpr = (Node *) lfirst(indexExprItem);
+					indexExpr = (Node *) expression_planner((Expr *) indexExpr);
+
+					if (max_parallel_hazard_walker(indexExpr, context))
+					{
+						index_close(indexRel, lockmode);
+						return context->max_hazard;
+					}
+
+					indexExprItem = lnext(indexInfo->ii_Expressions, indexExprItem);
+				}
+			}
+		}
+		index_close(indexRel, lockmode);
+	}
+
+	return context->max_hazard;
+}
+
+/*
+ * MaxDomainParallelHazardForModify
+ *
+ * Finds the maximum parallel-mode hazard level for the specified DOMAIN type.
+ * Only any CHECK expressions are examined for parallel safety.
+ * DEFAULT values of DOMAIN-type columns in the target-list are already
+ * being checked for parallel-safety in the max_parallel_hazard() scan of the
+ * query tree in standard_planner().
+ *
+ */
+static char
+MaxDomainParallelHazardForModify(Oid typid, max_parallel_hazard_context *context)
+{
+	Relation	conRel;
+	ScanKeyData key[1];
+	SysScanDesc scan;
+	HeapTuple	tup;
+
+	LOCKMODE	lockmode = AccessShareLock;
+
+	conRel = table_open(ConstraintRelationId, lockmode);
+
+	ScanKeyInit(&key[0],
+				Anum_pg_constraint_contypid, BTEqualStrategyNumber,
+				F_OIDEQ, ObjectIdGetDatum(typid));
+	scan = systable_beginscan(conRel, ConstraintTypidIndexId, true,
+							  NULL, 1, key);
+
+	while (HeapTupleIsValid((tup = systable_getnext(scan))))
+	{
+		Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tup);
+
+		if (con->contype == CONSTRAINT_CHECK)
+		{
+			char	   *conbin;
+			Datum		val;
+			bool		isnull;
+			Expr	   *checkExpr;
+
+			val = SysCacheGetAttr(CONSTROID, tup,
+								  Anum_pg_constraint_conbin, &isnull);
+			if (isnull)
+				elog(ERROR, "null conbin for constraint %u", con->oid);
+			conbin = TextDatumGetCString(val);
+			checkExpr = stringToNode(conbin);
+			if (max_parallel_hazard_walker((Node *) checkExpr, context))
+			{
+				break;
+			}
+		}
+	}
+
+	systable_endscan(scan);
+	table_close(conRel, lockmode);
+	return context->max_hazard;
+}
+
+/*
+ * MaxRelParallelHazardForModify
+ *
+ * Determines the maximum parallel-mode hazard level for modification
+ * of a specified relation.
+ */
+static char
+MaxRelParallelHazardForModify(Oid relid, max_parallel_hazard_context *context)
+{
+	Relation	rel;
+	TupleDesc	tupdesc;
+	int			attnum;
+
+	LOCKMODE	lockmode = AccessShareLock;
+
+	/*
+	 * It's possible that this relation is locked for exclusive access in
+	 * another concurrent transaction (e.g. as a result of a ALTER TABLE ...
+	 * operation) until that transaction completes. If a share-lock can't be
+	 * acquired on it now, we have to assume this could be the worst-case, so
+	 * to avoid blocking here until that transaction completes, conditionally
+	 * try to acquire the lock and assume and return UNSAFE on failure.
+	 */
+	if (ConditionalLockRelationOid(relid, lockmode))
+	{
+		rel = table_open(relid, NoLock);
+	}
+	else
+	{
+		context->max_hazard = PROPARALLEL_UNSAFE;
+		return context->max_hazard;
+	}
+
+	/*
+	 * Check if copy is into foreign table. We can not allow parallelism in
+	 * this case because each worker needs to establish FDW connection and
+	 * operate in a separate transaction. Unless we have a capability to
+	 * provide two-phase commit protocol, we can not allow parallelism.
+	 *
+	 * Also check if copy is into temporary table. Since parallel workers can
+	 * not access temporary table, parallelism is not allowed.
+	 */
+	if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
+		RelationUsesLocalBuffers(rel))
+	{
+		table_close(rel, lockmode);
+		context->max_hazard = PROPARALLEL_UNSAFE;
+		return context->max_hazard;
+	}
+
+	/*
+	 * If a partitioned table, check that each partition is safe for
+	 * modification in parallel-mode.
+	 */
+	if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+	{
+		int			i;
+		PartitionDesc pdesc;
+		PartitionKey pkey;
+		ListCell   *partexprs_item;
+		int			partnatts;
+		List	   *partexprs;
+
+		pkey = RelationGetPartitionKey(rel);
+
+		partnatts = get_partition_natts(pkey);
+		partexprs = get_partition_exprs(pkey);
+
+		partexprs_item = list_head(partexprs);
+		for (i = 0; i < partnatts; i++)
+		{
+			/* Check parallel-safety of partition key support functions */
+			if (OidIsValid(pkey->partsupfunc[i].fn_oid))
+			{
+				if (max_parallel_hazard_test(func_parallel(pkey->partsupfunc[i].fn_oid), context))
+				{
+					table_close(rel, lockmode);
+					return context->max_hazard;
+				}
+			}
+
+			/* Check parallel-safety of any expressions in the partition key */
+			if (get_partition_col_attnum(pkey, i) == 0)
+			{
+				Node	   *checkExpr = (Node *) lfirst(partexprs_item);
+
+				if (max_parallel_hazard_walker(checkExpr, context))
+				{
+					table_close(rel, lockmode);
+					return context->max_hazard;
+				}
+
+				partexprs_item = lnext(partexprs, partexprs_item);
+			}
+		}
+
+		/* Recursively check each partition ... */
+		pdesc = RelationGetPartitionDesc(rel);
+		for (i = 0; i < pdesc->nparts; i++)
+		{
+			if (MaxRelParallelHazardForModify(pdesc->oids[i], context) != PROPARALLEL_SAFE)
+			{
+				table_close(rel, lockmode);
+				return context->max_hazard;
+			}
+		}
+	}
+
+	/*
+	 * If there are any index expressions, check that they are parallel-mode
+	 * safe.
+	 */
+	if (MaxIndexExprsParallelHazardForModify(rel, context) != PROPARALLEL_SAFE)
+	{
+		table_close(rel, lockmode);
+		return context->max_hazard;
+	}
+
+	/*
+	 * If any triggers exist, check that they are parallel safe.
+	 */
+	if (rel->trigdesc != NULL &&
+		MaxTriggerDataParallelHazardForModify(rel->trigdesc, context) != PROPARALLEL_SAFE)
+	{
+		table_close(rel, lockmode);
+		return context->max_hazard;
+	}
+
+	tupdesc = RelationGetDescr(rel);
+	for (attnum = 0; attnum < tupdesc->natts; attnum++)
+	{
+		Form_pg_attribute att = TupleDescAttr(tupdesc, attnum);
+
+		/* We don't need info for dropped or generated attributes */
+		if (att->attisdropped || att->attgenerated)
+			continue;
+
+		/*
+		 * If the column is of a DOMAIN type, determine whether that domain
+		 * has any CHECK expressions that are not parallel-mode safe.
+		 */
+		if (get_typtype(att->atttypid) == TYPTYPE_DOMAIN)
+		{
+			if (MaxDomainParallelHazardForModify(att->atttypid, context) != PROPARALLEL_SAFE)
+			{
+				table_close(rel, lockmode);
+				return context->max_hazard;
+			}
+		}
+	}
+
+	/*
+	 * Check if there are any CHECK constraints which are not parallel-safe.
+	 */
+	if (tupdesc->constr != NULL && tupdesc->constr->num_check > 0)
+	{
+		int			i;
+
+		ConstrCheck *check = tupdesc->constr->check;
+
+		for (i = 0; i < tupdesc->constr->num_check; i++)
+		{
+			Expr	   *checkExpr = stringToNode(check->ccbin);
+
+			if (max_parallel_hazard_walker((Node *) checkExpr, context))
+			{
+				table_close(rel, lockmode);
+				return context->max_hazard;
+			}
+		}
+	}
+
+	table_close(rel, lockmode);
+	return context->max_hazard;
+}
+
+/*
+ * MaxParallelHazardForModify
+ *
+ * Determines the worst parallel-mode hazard level for the specified
+ * relation. The search returns the earliest in the following list:
+ * PROPARALLEL_UNSAFE, PROPARALLEL_RESTRICTED, PROPARALLEL_SAFE
+ */
+char
+MaxParallelHazardForModify(Oid relid)
+{
+	max_parallel_hazard_context context;
+
+	context.max_hazard = PROPARALLEL_SAFE;
+	context.max_interesting = PROPARALLEL_RESTRICTED;
+	context.safe_param_ids = NIL;
+
+	return (MaxRelParallelHazardForModify(relid, &context));
+}
 
 /*****************************************************************************
  *		Check clauses for nonstrict functions
diff --git a/src/include/access/xact.h b/src/include/access/xact.h
index 7320de3..42d4893 100644
--- a/src/include/access/xact.h
+++ b/src/include/access/xact.h
@@ -386,6 +386,7 @@ extern FullTransactionId GetTopFullTransactionId(void);
 extern FullTransactionId GetTopFullTransactionIdIfAny(void);
 extern FullTransactionId GetCurrentFullTransactionId(void);
 extern FullTransactionId GetCurrentFullTransactionIdIfAny(void);
+extern void SetCurrentCommandIdUsedForWorker(void);
 extern void MarkCurrentTransactionIdLoggedIfAny(void);
 extern bool SubTransactionIsActive(SubTransactionId subxid);
 extern CommandId GetCurrentCommandId(bool used);
diff --git a/src/include/commands/copyfrom_internal.h b/src/include/commands/copyfrom_internal.h
index 1cda8de..6ed7954 100644
--- a/src/include/commands/copyfrom_internal.h
+++ b/src/include/commands/copyfrom_internal.h
@@ -162,5 +162,6 @@ typedef struct CopyFromStateData
 
 extern void ReceiveCopyBegin(CopyFromState cstate);
 extern void ReceiveCopyBinaryHeader(CopyFromState cstate);
+extern bool IsParallelCopyAllowed(CopyFromState cstate, Oid relid);
 
 #endif							/* COPYFROM_INTERNAL_H */
diff --git a/src/include/optimizer/clauses.h b/src/include/optimizer/clauses.h
index 68855d0..e078b07 100644
--- a/src/include/optimizer/clauses.h
+++ b/src/include/optimizer/clauses.h
@@ -52,5 +52,6 @@ extern void CommuteOpExpr(OpExpr *clause);
 
 extern Query *inline_set_returning_function(PlannerInfo *root,
 											RangeTblEntry *rte);
+extern char MaxParallelHazardForModify(Oid relid);
 
 #endif							/* CLAUSES_H */
-- 
1.8.3.1

v11-0003-Allow-copy-from-command-to-process-data-from-fil.patchtext/x-patch; charset=US-ASCII; name=v11-0003-Allow-copy-from-command-to-process-data-from-fil.patchDownload
From 2677ea2eb0b0d700c69500e408c3e12bc9b138d5 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Thu, 3 Dec 2020 08:34:39 +0530
Subject: [PATCH v11 3/6] Allow copy from command to process data from
 file/STDIN contents to a table in parallel.

This feature allows the copy from to leverage multiple CPUs in order to copy
data from file/STDIN to a table. This adds a PARALLEL option to COPY FROM
command where the user can specify the number of workers that can be used
to perform the COPY FROM command.
The backend, to which the "COPY FROM" query is submitted acts as leader with
the responsibility of reading data from the file/stdin, launching at most n
number of workers as specified with PARALLEL 'n' option in the "COPY FROM"
query. The leader populates the common data required for the workers execution
in the DSM and shares it with the workers. The leader then executes before
statement triggers if there exists any. Leader populates DSM lines which
includes the start offset and line size, while populating the lines it reads
as many blocks as required into the DSM data blocks from the file. Each block
is of 64K size. The leader parses the data to identify a line, the existing
logic from CopyReadLineText which identifies the lines with some changes was
used for this. Leader checks if a free line is available to copy the
information, if there is no free line it waits till the required line is
freed up by the worker and then copies the identified lines information
(offset & line size) into the DSM lines. This process is repeated till the
complete file is processed. Simultaneously, the workers cache the lines(50)
locally into the local memory and release the lines to the leader for further
populating. Each worker processes the lines that it cached and inserts it into
the table.
The leader does not participate in the insertion of data, leaders only
responsibility will be to identify the lines as fast as possible for the
workers to do the actual copy operation. The leader waits till all the lines
populated are processed by the workers and exits. We have chosen this design
based on the reason "that everything stalls if the leader doesn't accept further
input data, as well as when there are no available splitted chunks so it doesn't
seem like a good idea to have the leader do other work.  This is backed by the
performance data where we have seen that with 1 worker there is just a 5-10%
performance difference".
---
 src/backend/access/transam/parallel.c    |    4 +
 src/backend/commands/copy.c              |   71 +-
 src/backend/commands/copyfrom.c          |   59 +-
 src/backend/commands/copyfromparse.c     |  143 +++-
 src/backend/commands/copyparallel.c      | 1254 ++++++++++++++++++++++++++++++
 src/bin/psql/tab-complete.c              |    2 +-
 src/include/commands/copy.h              |    3 +-
 src/include/commands/copyfrom_internal.h |  255 +++++-
 src/tools/pgindent/typedefs.list         |    8 +
 9 files changed, 1743 insertions(+), 56 deletions(-)

diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index b042696..2b740e5 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -25,6 +25,7 @@
 #include "catalog/pg_enum.h"
 #include "catalog/storage.h"
 #include "commands/async.h"
+#include "commands/copyfrom_internal.h"
 #include "executor/execParallel.h"
 #include "libpq/libpq.h"
 #include "libpq/pqformat.h"
@@ -145,6 +146,9 @@ static const struct
 	},
 	{
 		"parallel_vacuum_main", parallel_vacuum_main
+	},
+	{
+		"ParallelCopyMain", ParallelCopyMain
 	}
 };
 
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index b6143b8..7d6ea72 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -18,11 +18,13 @@
 #include <unistd.h>
 #include <sys/stat.h>
 
+#include "access/parallel.h"
 #include "access/sysattr.h"
 #include "access/table.h"
 #include "access/xact.h"
 #include "catalog/pg_authid.h"
 #include "commands/copy.h"
+#include "commands/copyfrom_internal.h"
 #include "commands/defrem.h"
 #include "executor/executor.h"
 #include "mb/pg_wchar.h"
@@ -33,6 +35,7 @@
 #include "parser/parse_collate.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_relation.h"
+#include "postmaster/bgworker_internals.h"
 #include "rewrite/rewriteHandler.h"
 #include "utils/acl.h"
 #include "utils/builtins.h"
@@ -286,6 +289,7 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 	if (is_from)
 	{
 		CopyFromState cstate;
+		ParallelContext *pcxt = NULL;
 
 		Assert(rel);
 
@@ -296,7 +300,46 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 		cstate = BeginCopyFrom(pstate, rel, whereClause,
 							   stmt->filename, stmt->is_program,
 							   NULL, stmt->attlist, stmt->options);
-		*processed = CopyFrom(cstate);	/* copy from file to database */
+		cstate->is_parallel = false;
+
+		/*
+		 * User chosen parallel copy. Determine if the parallel copy is
+		 * actually allowed. If not, go with the non-parallel mode.
+		 */
+		if (cstate->opts.nworkers > 0 && IsParallelCopyAllowed(cstate, relid))
+			pcxt = BeginParallelCopy(cstate, stmt->attlist, relid);
+
+		if (pcxt)
+		{
+			int			i;
+
+			ParallelCopyFrom(cstate);
+
+			/* Wait for all copy workers to finish */
+			WaitForParallelWorkersToFinish(pcxt);
+
+			/*
+			 * Next, accumulate WAL usage.  (This must wait for the workers to
+			 * finish, or we might get incomplete data.)
+			 */
+			for (i = 0; i < pcxt->nworkers_launched; i++)
+				InstrAccumParallelQuery(&cstate->pcdata->bufferusage[i],
+										&cstate->pcdata->walusage[i]);
+
+			*processed = pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
+			EndParallelCopy(pcxt);
+		}
+		else
+		{
+			/*
+			 * Reset nworkers to -1 here. This is useful in cases where user
+			 * specifies parallel workers, but, no worker is picked up, so go
+			 * back to non parallel mode value of nworkers.
+			 */
+			cstate->nworkers = -1;
+			*processed = CopyFrom(cstate);	/* copy from file to database */
+		}
+
 		EndCopyFrom(cstate);
 	}
 	else
@@ -346,6 +389,7 @@ ProcessCopyOptions(ParseState *pstate,
 		opts_out = (CopyFormatOptions *) palloc0(sizeof(CopyFormatOptions));
 
 	opts_out->file_encoding = -1;
+	opts_out->nworkers = -1;
 
 	/* Extract options from the statement node tree */
 	foreach(option, options)
@@ -516,6 +560,31 @@ ProcessCopyOptions(ParseState *pstate,
 								defel->defname),
 						 parser_errposition(pstate, defel->location)));
 		}
+		else if (strcmp(defel->defname, "parallel") == 0)
+		{
+			int			val;
+
+			if (!is_from)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("parallel option is supported only for copy from"),
+						 parser_errposition(pstate, defel->location)));
+			if (opts_out->nworkers >= 0)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options"),
+						 parser_errposition(pstate, defel->location)));
+
+			val = defGetInt32(defel);
+			if (val < 1 || val > MAX_PARALLEL_WORKER_LIMIT)
+				ereport(ERROR,
+						(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+						 errmsg("value %d out of bounds for option \"%s\"",
+								val, defel->defname),
+						 errdetail("Valid values are between \"%d\" and \"%d\".",
+								   1, MAX_PARALLEL_WORKER_LIMIT)));
+			opts_out->nworkers = val;
+		}
 		else
 			ereport(ERROR,
 					(errcode(ERRCODE_SYNTAX_ERROR),
diff --git a/src/backend/commands/copyfrom.c b/src/backend/commands/copyfrom.c
index 7f7f720..c1ed217 100644
--- a/src/backend/commands/copyfrom.c
+++ b/src/backend/commands/copyfrom.c
@@ -96,7 +96,7 @@ typedef struct CopyMultiInsertInfo
 static char *limit_printout_length(const char *str);
 
 static void ClosePipeFromProgram(CopyFromState cstate);
-static void PopulateCommonCStateInfo(CopyFromState cstate, TupleDesc tup_desc,
+void		PopulateCommonCStateInfo(CopyFromState cstate, TupleDesc tup_desc,
 									 List *attnamelist);
 
 /*
@@ -522,7 +522,7 @@ CopyMultiInsertInfoStore(CopyMultiInsertInfo *miinfo, ResultRelInfo *rri,
  *
  * Check if the relation specified in copy from is valid.
  */
-static void
+void
 CheckTargetRelValidity(CopyFromState cstate)
 {
 	Assert(cstate->rel);
@@ -619,7 +619,7 @@ CopyFrom(CopyFromState cstate)
 
 	PartitionTupleRouting *proute = NULL;
 	ErrorContextCallback errcallback;
-	CommandId	mycid = GetCurrentCommandId(true);
+	CommandId	mycid;
 	int			ti_options = 0; /* start with default options for insert */
 	BulkInsertState bistate = NULL;
 	CopyInsertMethod insertMethod;
@@ -629,7 +629,18 @@ CopyFrom(CopyFromState cstate)
 	bool		has_instead_insert_row_trig;
 	bool		leafpart_use_multi_insert = false;
 
-	CheckTargetRelValidity(cstate);
+	/*
+	 * Perform this check if it is not parallel copy. In case of parallel
+	 * copy, this check is done by the leader, so that if any invalid case
+	 * exist the copy from command will error out from the leader itself,
+	 * avoiding launching workers, just to throw error.
+	 */
+	if (!IsParallelCopy())
+		CheckTargetRelValidity(cstate);
+	else
+		SetCurrentCommandIdUsedForWorker();
+
+	mycid = GetCurrentCommandId(!IsParallelCopy());
 
 	/*
 	 * If the target file is new-in-transaction, we assume that checking FSM
@@ -667,7 +678,8 @@ CopyFrom(CopyFromState cstate)
 	ExecInitResultRelation(estate, resultRelInfo, 1);
 
 	/* Verify the named relation is a valid target for INSERT */
-	CheckValidResultRel(resultRelInfo, CMD_INSERT);
+	if (!IsParallelCopy())
+		CheckValidResultRel(resultRelInfo, CMD_INSERT);
 
 	ExecOpenIndices(resultRelInfo, false);
 
@@ -810,13 +822,17 @@ CopyFrom(CopyFromState cstate)
 	has_instead_insert_row_trig = (resultRelInfo->ri_TrigDesc &&
 								   resultRelInfo->ri_TrigDesc->trig_insert_instead_row);
 
-	/*
-	 * Check BEFORE STATEMENT insertion triggers. It's debatable whether we
-	 * should do this for COPY, since it's not really an "INSERT" statement as
-	 * such. However, executing these triggers maintains consistency with the
-	 * EACH ROW triggers that we already fire on COPY.
-	 */
-	ExecBSInsertTriggers(estate, resultRelInfo);
+	if (!IsParallelCopy())
+	{
+		/*
+		 * Check BEFORE STATEMENT insertion triggers. It's debatable whether
+		 * we should do this for COPY, since it's not really an "INSERT"
+		 * statement as such. However, executing these triggers maintains
+		 * consistency with the EACH ROW triggers that we already fire on
+		 * COPY.
+		 */
+		ExecBSInsertTriggers(estate, resultRelInfo);
+	}
 
 	econtext = GetPerTupleExprContext(estate);
 
@@ -1118,7 +1134,11 @@ CopyFrom(CopyFromState cstate)
 			 * or FDW; this is the same definition used by nodeModifyTable.c
 			 * for counting tuples inserted by an INSERT command.
 			 */
-			processed++;
+			if (!IsParallelCopy())
+				processed++;
+			else
+				pg_atomic_add_fetch_u64(&cstate->pcdata->pcshared_info->processed, 1);
+
 		}
 	}
 
@@ -1141,7 +1161,7 @@ CopyFrom(CopyFromState cstate)
 	 * In the old protocol, tell pqcomm that we can process normal protocol
 	 * messages again.
 	 */
-	if (cstate->copy_src == COPY_OLD_FE)
+	if (cstate->copy_src == COPY_OLD_FE && !IsParallelCopy())
 		pq_endmsgread();
 
 	/* Execute AFTER STATEMENT insertion triggers */
@@ -1172,7 +1192,10 @@ CopyFrom(CopyFromState cstate)
 
 	FreeExecutorState(estate);
 
-	return processed;
+	if (!IsParallelCopy())
+		return processed;
+	else
+		return pg_atomic_read_u64(&cstate->pcdata->pcshared_info->processed);
 }
 
 /*
@@ -1180,7 +1203,7 @@ CopyFrom(CopyFromState cstate)
  *
  * Populate the cstate catalog information.
  */
-static void
+void
 PopulateCStateCatalogInfo(CopyFromState cstate)
 {
 	TupleDesc	tupDesc;
@@ -1444,9 +1467,9 @@ BeginCopyFrom(ParseState *pstate,
  * PopulateCommonCStateInfo
  *
  * Populates the common variables required for copy from operation. This is a
- * helper function for BeginCopy function.
+ * helper function for BeginCopy & InitializeParallelCopyInfo function.
  */
-static void
+void
 PopulateCommonCStateInfo(CopyFromState cstate, TupleDesc tupDesc, List *attnamelist)
 {
 	int			num_phys_attrs;
diff --git a/src/backend/commands/copyfromparse.c b/src/backend/commands/copyfromparse.c
index 6762f3c..69b06e2 100644
--- a/src/backend/commands/copyfromparse.c
+++ b/src/backend/commands/copyfromparse.c
@@ -82,9 +82,13 @@ if (1) \
 { \
 	if (raw_buf_ptr > cstate->raw_buf_index) \
 	{ \
-		appendBinaryStringInfo(&cstate->line_buf, \
-							 cstate->raw_buf + cstate->raw_buf_index, \
-							   raw_buf_ptr - cstate->raw_buf_index); \
+		if (!IsParallelCopy()) \
+			appendBinaryStringInfo(&cstate->line_buf, \
+								   cstate->raw_buf + cstate->raw_buf_index, \
+								   raw_buf_ptr - cstate->raw_buf_index); \
+		else \
+			line_size +=  raw_buf_ptr - cstate->raw_buf_index; \
+		\
 		cstate->raw_buf_index = raw_buf_ptr; \
 	} \
 } else ((void) 0)
@@ -102,7 +106,7 @@ static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
 
 
 /* non-export function prototypes */
-static bool CopyReadLine(CopyFromState cstate);
+bool CopyReadLine(CopyFromState cstate);
 static bool CopyReadLineText(CopyFromState cstate);
 static int	CopyReadAttributesText(CopyFromState cstate);
 static int	CopyReadAttributesCSV(CopyFromState cstate);
@@ -120,7 +124,7 @@ static bool CopyLoadRawBuf(CopyFromState cstate);
 static int	CopyReadBinaryData(CopyFromState cstate, char *dest, int nbytes);
 static void ClearEOLFromCopiedData(CopyFromState cstate, char *copy_line_data,
 								   int copy_line_pos, int *copy_line_size);
-static void ConvertToServerEncoding(CopyFromState cstate);
+void ConvertToServerEncoding(CopyFromState cstate);
 
 void
 ReceiveCopyBegin(CopyFromState cstate)
@@ -373,11 +377,11 @@ CopyGetInt16(CopyFromState cstate, int16 *val)
 static bool
 CopyLoadRawBuf(CopyFromState cstate)
 {
-	int			nbytes = RAW_BUF_BYTES(cstate);
+	int			nbytes = (!IsParallelCopy()) ? RAW_BUF_BYTES(cstate) : cstate->raw_buf_len;
 	int			inbytes;
 
 	/* Copy down the unprocessed data if any. */
-	if (nbytes > 0)
+	if (nbytes > 0 && !IsParallelCopy())
 		memmove(cstate->raw_buf, cstate->raw_buf + cstate->raw_buf_index,
 				nbytes);
 
@@ -385,7 +389,9 @@ CopyLoadRawBuf(CopyFromState cstate)
 						  1, RAW_BUF_SIZE - nbytes);
 	nbytes += inbytes;
 	cstate->raw_buf[nbytes] = '\0';
-	cstate->raw_buf_index = 0;
+	if (!IsParallelCopy())
+		cstate->raw_buf_index = 0;
+
 	cstate->raw_buf_len = nbytes;
 	return (inbytes > 0);
 }
@@ -458,26 +464,35 @@ NextCopyFromRawFields(CopyFromState cstate, char ***fields, int *nfields)
 	/* only available for text or csv input */
 	Assert(!cstate->opts.binary);
 
-	/* on input just throw the header line away */
-	if (cstate->cur_lineno == 0 && cstate->opts.header_line)
+	if (IsParallelCopy())
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
-			return false;		/* done */
+		done = GetWorkerLine(cstate);
+		if (done && cstate->line_buf.len == 0)
+			return false;
 	}
+	else
+	{
+		/* on input just throw the header line away */
+		if (cstate->cur_lineno == 0 && cstate->opts.header_line)
+		{
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+				return false;	/* done */
+		}
 
-	cstate->cur_lineno++;
+		cstate->cur_lineno++;
 
-	/* Actually read the line into memory here */
-	done = CopyReadLine(cstate);
+		/* Actually read the line into memory here */
+		done = CopyReadLine(cstate);
 
-	/*
-	 * EOF at start of line means we're done.  If we see EOF after some
-	 * characters, we act as though it was newline followed by EOF, ie,
-	 * process the line and then exit loop on next iteration.
-	 */
-	if (done && cstate->line_buf.len == 0)
-		return false;
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			return false;
+	}
 
 	/* Parse the line into de-escaped field values */
 	if (cstate->opts.csv_mode)
@@ -690,7 +705,7 @@ NextCopyFrom(CopyFromState cstate, ExprContext *econtext,
  * by newline.  The terminating newline or EOF marker is not included
  * in the final value of line_buf.
  */
-static bool
+bool
 CopyReadLine(CopyFromState cstate)
 {
 	bool		result;
@@ -713,9 +728,30 @@ CopyReadLine(CopyFromState cstate)
 		 */
 		if (cstate->copy_src == COPY_NEW_FE)
 		{
+			bool		bIsFirst = true;
+
 			do
 			{
-				cstate->raw_buf_index = cstate->raw_buf_len;
+				if (!IsParallelCopy())
+					cstate->raw_buf_index = cstate->raw_buf_len;
+				else
+				{
+					/*
+					 * Get a new block if it is the first time, From the
+					 * subsequent time, reset the index and re-use the same
+					 * block.
+					 */
+					if (bIsFirst)
+					{
+						ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+						uint32		block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+						cstate->raw_buf = pcshared_info->data_blocks[block_pos].data;
+						bIsFirst = false;
+					}
+
+					cstate->raw_buf_index = cstate->raw_buf_len = 0;
+				}
 			} while (CopyLoadRawBuf(cstate));
 		}
 	}
@@ -770,11 +806,11 @@ ClearEOLFromCopiedData(CopyFromState cstate, char *copy_line_data,
  *
  * Convert contents to server encoding.
  */
-static void
+void
 ConvertToServerEncoding(CopyFromState cstate)
 {
 	/* Done reading the line.  Convert it to server encoding. */
-	if (cstate->need_transcoding)
+	if (cstate->need_transcoding && (!IsParallelCopy() || IsWorker()))
 	{
 		char	   *cvt;
 
@@ -815,6 +851,12 @@ CopyReadLineText(CopyFromState cstate)
 	char		quotec = '\0';
 	char		escapec = '\0';
 
+	/* For parallel copy */
+	int			line_size = 0;
+	uint32		line_pos = 0;
+
+	cstate->eol_type = EOL_UNKNOWN;
+
 	if (cstate->opts.csv_mode)
 	{
 		quotec = cstate->opts.quote[0];
@@ -869,6 +911,10 @@ CopyReadLineText(CopyFromState cstate)
 		if (raw_buf_ptr >= copy_buf_len || need_data)
 		{
 			REFILL_LINEBUF;
+			if ((copy_buf_len == DATA_BLOCK_SIZE || copy_buf_len == 0) &&
+				IsParallelCopy())
+				SetRawBufForLoad(cstate, line_size, copy_buf_len, raw_buf_ptr,
+								 &copy_raw_buf);
 
 			/*
 			 * Try to read some more data.  This will certainly reset
@@ -876,14 +922,14 @@ CopyReadLineText(CopyFromState cstate)
 			 */
 			if (!CopyLoadRawBuf(cstate))
 				hit_eof = true;
-			raw_buf_ptr = 0;
+			raw_buf_ptr = (IsParallelCopy()) ? cstate->raw_buf_index : 0;
 			copy_buf_len = cstate->raw_buf_len;
 
 			/*
 			 * If we are completely out of data, break out of the loop,
 			 * reporting EOF.
 			 */
-			if (copy_buf_len <= 0)
+			if (RAW_BUF_BYTES(cstate) <= 0)
 			{
 				result = true;
 				break;
@@ -1093,9 +1139,15 @@ CopyReadLineText(CopyFromState cstate)
 				 * discard the data and the \. sequence.
 				 */
 				if (prev_raw_ptr > cstate->raw_buf_index)
-					appendBinaryStringInfo(&cstate->line_buf,
-										   cstate->raw_buf + cstate->raw_buf_index,
-										   prev_raw_ptr - cstate->raw_buf_index);
+				{
+					if (!IsParallelCopy())
+						appendBinaryStringInfo(&cstate->line_buf,
+											   cstate->raw_buf + cstate->raw_buf_index,
+											   prev_raw_ptr - cstate->raw_buf_index);
+					else
+						line_size += prev_raw_ptr - cstate->raw_buf_index;
+				}
+
 				cstate->raw_buf_index = raw_buf_ptr;
 				result = true;	/* report EOF */
 				break;
@@ -1147,6 +1199,22 @@ not_end_of_copy:
 			IF_NEED_REFILL_AND_EOF_BREAK(mblen - 1);
 			raw_buf_ptr += mblen - 1;
 		}
+
+		/*
+		 * Skip the header line. Update the line here, this cannot be done at
+		 * the beginning, as there is a possibility that file contains empty
+		 * lines.
+		 */
+		if (IsParallelCopy() && first_char_in_line && !IsHeaderLine())
+		{
+			ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+			line_pos = UpdateSharedLineInfo(cstate,
+											pcshared_info->cur_block_pos,
+											cstate->raw_buf_index, -1,
+											LINE_LEADER_POPULATING, -1);
+		}
+
 		first_char_in_line = false;
 	}							/* end of outer loop */
 
@@ -1155,9 +1223,16 @@ not_end_of_copy:
 	 */
 	REFILL_LINEBUF;
 	if (!result && !IsHeaderLine())
-		ClearEOLFromCopiedData(cstate, cstate->line_buf.data,
-							   cstate->line_buf.len, &cstate->line_buf.len);
+	{
+		if (IsParallelCopy())
+			ClearEOLFromCopiedData(cstate, cstate->raw_buf, raw_buf_ptr,
+								   &line_size);
+		else
+			ClearEOLFromCopiedData(cstate, cstate->line_buf.data,
+								   cstate->line_buf.len, &cstate->line_buf.len);
+	}
 
+	EndLineParallelCopy(cstate, line_pos, line_size, raw_buf_ptr);
 	return result;
 }
 
diff --git a/src/backend/commands/copyparallel.c b/src/backend/commands/copyparallel.c
index 374f95f..d46707d 100644
--- a/src/backend/commands/copyparallel.c
+++ b/src/backend/commands/copyparallel.c
@@ -3,6 +3,45 @@
  * copyparallel.c
  *              Implements the Parallel COPY utility command
  *
+ * Parallel copy allows the copy from to leverage multiple CPUs in order to copy
+ * data from file/STDIN to a table. This adds a PARALLEL option to COPY FROM
+ * command where the user can specify the number of workers that can be used
+ * to perform the COPY FROM command.
+ * The backend, to which the "COPY FROM" query is submitted acts as leader with
+ * the responsibility of reading data from the file/stdin, launching at most n
+ * number of workers as specified with PARALLEL 'n' option in the "COPY FROM"
+ * query. The leader populates the common data using
+ * PARALLEL_COPY_KEY_SHARED_INFO, PARALLEL_COPY_KEY_CSTATE,
+ * PARALLEL_COPY_KEY_WAL_USAGE & PARALLEL_COPY_KEY_BUFFER_USAGE	 required for
+ * the workers execution in the DSM and shares it with the workers. The leader
+ * then executes before statement triggers if there exists any. Leader populates
+ * DSM lines (ParallelCopyDataBlock & ParallelCopyLineBoundaries data
+ * structures) which includes the start offset and line size, while populating
+ * the lines it reads as many blocks as required into the DSM data blocks from
+ * the file. Each block is of 64K size. The leader parses the data to identify a
+ * line, the existing logic from CopyReadLineText which identifies the lines
+ * with some changes was used for this. Leader checks if a free line is
+ * available (ParallelCopyLineBoundary->line_size will be -1) to copy the
+ * information, if there is no free line it waits till the required line is
+ * freed up by the worker and then copies the identified lines information
+ * (offset & line size) into the DSM lines. Leader will set the state of the
+ * line to LINE_LEADER_POPULATED to indicate the line is populated by the leader
+ * and the worker can start processing the line. This process is repeated till
+ * the complete file is processed. Simultaneously, each worker caches
+ * WORKER_CHUNK_COUNT lines locally into the local memory and release the lines
+ * to the leader for further populating. Each worker processes the lines as it
+ * was done in sequential copy. Refer comments above ParallelCopyLineBoundary
+ * for more details on leader/workers syncronization.
+ * The leader does not participate in the insertion of data, leaders only
+ * responsibility will be to identify the lines as fast as possible for the
+ * workers to do the actual copy operation. The leader waits till all the lines
+ * populated are processed by the workers and exits. We have chosen this design
+ * based on the reason "that everything stalls if the leader doesn't accept
+ * further input data, as well as when there are no available splitted chunks so
+ * it doesn't seem like a good idea to have the leader do other work.  This is
+ * backed by the performance data where we have seen that with 1 worker there is
+ * just a 5-10% performance difference".
+ *
  * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
@@ -15,15 +54,338 @@
 #include "postgres.h"
 
 #include "access/heapam.h"
+#include "access/parallel.h"
 #include "catalog/pg_proc_d.h"
 #include "commands/copy.h"
 #include "commands/copyfrom_internal.h"
+#include "executor/executor.h"
 #include "libpq/libpq.h"
 #include "optimizer/clauses.h"
 #include "optimizer/optimizer.h"
 #include "pgstat.h"
 #include "utils/lsyscache.h"
 
+/* DSM keys for parallel copy.  */
+#define PARALLEL_COPY_KEY_SHARED_INFO				1
+#define PARALLEL_COPY_KEY_CSTATE					2
+#define PARALLEL_COPY_KEY_WAL_USAGE					3
+#define PARALLEL_COPY_KEY_BUFFER_USAGE				4
+
+/*
+ * COPY_WAIT_TO_PROCESS - Wait before continuing to process.
+ */
+#define COPY_WAIT_TO_PROCESS() \
+{ \
+	CHECK_FOR_INTERRUPTS(); \
+	(void) WaitLatch(MyLatch, \
+					 WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH, \
+					 1L, WAIT_EVENT_PG_SLEEP); \
+	ResetLatch(MyLatch); \
+}
+
+/*
+ * Estimate1ByteStrSize
+ *
+ * Estimate the size required for  1Byte strings in shared memory.
+ */
+static inline uint32
+Estimate1ByteStrSize(char *src)
+{
+	return (src) ? sizeof(uint8) + 1 : sizeof(uint8);
+}
+
+/*
+ * EstimateNodeSize
+ *
+ * Estimate the size required for  node type in shared memory.
+ */
+static uint32
+EstimateNodeSize(List *list, char **listStr)
+{
+	uint32		estsize = sizeof(uint32);
+
+	if ((List *) list != NIL)
+	{
+		*listStr = nodeToString(list);
+		estsize += strlen(*listStr) + 1;
+	}
+
+	return estsize;
+}
+
+/*
+ * EstimateCStateSize
+ *
+ * Estimate the size of the required cstate variables in the shared memory.
+ */
+static uint32
+EstimateCStateSize(ParallelContext *pcxt, CopyFromState cstate, List *attnamelist,
+				   SerializedListToStrCState *list_converted_str)
+{
+	Size		estsize = 0;
+	uint32		estnodesize;
+
+	estsize = add_size(estsize, sizeof(cstate->copy_src));
+	estsize = add_size(estsize, sizeof(cstate->opts.file_encoding));
+	estsize = add_size(estsize, sizeof(cstate->need_transcoding));
+	estsize = add_size(estsize, sizeof(cstate->encoding_embeds_ascii));
+	estsize = add_size(estsize, sizeof(cstate->opts.csv_mode));
+	estsize = add_size(estsize, sizeof(cstate->opts.header_line));
+	estsize = add_size(estsize, sizeof(cstate->opts.null_print_len));
+	estsize = add_size(estsize, sizeof(cstate->opts.force_quote_all));
+	estsize = add_size(estsize, sizeof(cstate->opts.convert_selectively));
+	estsize = add_size(estsize, sizeof(cstate->num_defaults));
+	estsize = add_size(estsize, sizeof(cstate->pcdata->relid));
+	estsize = add_size(estsize, sizeof(cstate->opts.binary));
+
+	/* Size of null_print is available in null_print_len. */
+	estsize = add_size(estsize, sizeof(uint32) + cstate->opts.null_print_len);
+
+	/* delim, quote & escape all uses 1 byte string to store the information. */
+	estsize = add_size(estsize, Estimate1ByteStrSize(cstate->opts.delim));
+	estsize = add_size(estsize, Estimate1ByteStrSize(cstate->opts.quote));
+	estsize = add_size(estsize, Estimate1ByteStrSize(cstate->opts.escape));
+
+	estnodesize = EstimateNodeSize(attnamelist, &list_converted_str->attnameListStr);
+	estsize = add_size(estsize, estnodesize);
+	estnodesize = EstimateNodeSize(cstate->opts.force_notnull, &list_converted_str->notnullListStr);
+	estsize = add_size(estsize, estnodesize);
+	estnodesize = EstimateNodeSize(cstate->opts.force_null, &list_converted_str->nullListStr);
+	estsize = add_size(estsize, estnodesize);
+	estnodesize = EstimateNodeSize(cstate->opts.convert_select, &list_converted_str->convertListStr);
+	estsize = add_size(estsize, estnodesize);
+	estnodesize = EstimateNodeSize((List *) cstate->whereClause, &list_converted_str->whereClauseStr);
+	estsize = add_size(estsize, estnodesize);
+	estnodesize = EstimateNodeSize(cstate->range_table, &list_converted_str->rangeTableStr);
+	estsize = add_size(estsize, estnodesize);
+
+	shm_toc_estimate_chunk(&pcxt->estimator, estsize);
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+	return estsize;
+}
+
+/*
+ * SerializeStringToSharedMemory
+ *
+ * Copy the string to shared memory.
+ */
+static void
+SerializeStringToSharedMemory(char *destptr, char *srcPtr, Size *copiedsize)
+{
+	uint32		len = srcPtr ? strlen(srcPtr) + 1 : 0;
+
+	memcpy(destptr + *copiedsize, (uint32 *) &len, sizeof(uint32));
+	*copiedsize += sizeof(uint32);
+	if (len)
+	{
+		memcpy(destptr + *copiedsize, srcPtr, len);
+		*copiedsize += len;
+	}
+}
+
+/*
+ * Serialize1ByteStr
+ *
+ * Copy 1Byte strings to shared memory.
+ */
+static void
+Serialize1ByteStr(char *dest, char *src, Size *copiedsize)
+{
+	uint8		len = (src) ? 1 : 0;
+
+	memcpy(dest + (*copiedsize), (uint8 *) &len, sizeof(uint8));
+	*copiedsize += sizeof(uint8);
+	if (src)
+		dest[(*copiedsize)++] = src[0];
+}
+
+/*
+ * SerializeParallelCopyState
+ *
+ * Serialize the cstate members required by the workers into shared memory.
+ */
+static void
+SerializeParallelCopyState(ParallelContext *pcxt, CopyFromState cstate,
+						   uint32 estimatedSize,
+						   SerializedListToStrCState *list_converted_str)
+{
+	char	   *shmptr = (char *) shm_toc_allocate(pcxt->toc, estimatedSize + 1);
+	Size		copiedsize = 0;
+
+	memcpy(shmptr + copiedsize, (char *) &cstate->copy_src, sizeof(cstate->copy_src));
+	copiedsize += sizeof(cstate->copy_src);
+	memcpy(shmptr + copiedsize, (char *) &cstate->file_encoding, sizeof(cstate->opts.file_encoding));
+	copiedsize += sizeof(cstate->opts.file_encoding);
+	memcpy(shmptr + copiedsize, (char *) &cstate->need_transcoding, sizeof(cstate->need_transcoding));
+	copiedsize += sizeof(cstate->need_transcoding);
+	memcpy(shmptr + copiedsize, (char *) &cstate->encoding_embeds_ascii, sizeof(cstate->encoding_embeds_ascii));
+	copiedsize += sizeof(cstate->encoding_embeds_ascii);
+	memcpy(shmptr + copiedsize, (char *) &cstate->opts.csv_mode, sizeof(cstate->opts.csv_mode));
+	copiedsize += sizeof(cstate->opts.csv_mode);
+	memcpy(shmptr + copiedsize, (char *) &cstate->opts.header_line, sizeof(cstate->opts.header_line));
+	copiedsize += sizeof(cstate->opts.header_line);
+	memcpy(shmptr + copiedsize, (char *) &cstate->opts.null_print_len, sizeof(cstate->opts.null_print_len));
+	copiedsize += sizeof(cstate->opts.null_print_len);
+	memcpy(shmptr + copiedsize, (char *) &cstate->opts.force_quote_all, sizeof(cstate->opts.force_quote_all));
+	copiedsize += sizeof(cstate->opts.force_quote_all);
+	memcpy(shmptr + copiedsize, (char *) &cstate->opts.convert_selectively, sizeof(cstate->opts.convert_selectively));
+	copiedsize += sizeof(cstate->opts.convert_selectively);
+	memcpy(shmptr + copiedsize, (char *) &cstate->num_defaults, sizeof(cstate->num_defaults));
+	copiedsize += sizeof(cstate->num_defaults);
+	memcpy(shmptr + copiedsize, (char *) &cstate->pcdata->relid, sizeof(cstate->pcdata->relid));
+	copiedsize += sizeof(cstate->pcdata->relid);
+	memcpy(shmptr + copiedsize, (char *) &cstate->opts.binary, sizeof(cstate->opts.binary));
+	copiedsize += sizeof(cstate->opts.binary);
+
+	memcpy(shmptr + copiedsize, (uint32 *) &cstate->opts.null_print_len, sizeof(uint32));
+	copiedsize += sizeof(uint32);
+	if (cstate->opts.null_print_len)
+	{
+		memcpy(shmptr + copiedsize, cstate->opts.null_print, cstate->opts.null_print_len);
+		copiedsize += cstate->opts.null_print_len;
+	}
+
+	Serialize1ByteStr(shmptr, cstate->opts.delim, &copiedsize);
+	Serialize1ByteStr(shmptr, cstate->opts.quote, &copiedsize);
+	Serialize1ByteStr(shmptr, cstate->opts.escape, &copiedsize);
+
+	SerializeStringToSharedMemory(shmptr, list_converted_str->attnameListStr, &copiedsize);
+	SerializeStringToSharedMemory(shmptr, list_converted_str->notnullListStr, &copiedsize);
+	SerializeStringToSharedMemory(shmptr, list_converted_str->nullListStr, &copiedsize);
+	SerializeStringToSharedMemory(shmptr, list_converted_str->convertListStr, &copiedsize);
+	SerializeStringToSharedMemory(shmptr, list_converted_str->whereClauseStr, &copiedsize);
+	SerializeStringToSharedMemory(shmptr, list_converted_str->rangeTableStr, &copiedsize);
+
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_CSTATE, shmptr);
+}
+
+/*
+ * RestoreNodeFromSharedMemory
+ *
+ * Copy the node contents which was stored as string format in shared memory &
+ * convert it into node type.
+ */
+static void *
+RestoreNodeFromSharedMemory(char *srcPtr, Size *copiedsize, bool isSrcStr)
+{
+	char	   *destptr = NULL;
+	List	   *destList = NIL;
+	uint32		len;
+
+	memcpy((uint32 *) (&len), srcPtr + *copiedsize, sizeof(uint32));
+	*copiedsize += sizeof(uint32);
+	if (len)
+	{
+		destptr = (char *) palloc(len);
+		memcpy(destptr, srcPtr + *copiedsize, len);
+		*copiedsize += len;
+		if (!isSrcStr)
+		{
+			destList = (List *) stringToNode(destptr);
+			pfree(destptr);
+			return destList;
+		}
+
+		return destptr;
+	}
+
+	return NULL;
+}
+
+/*
+ * Restore1ByteStr
+ *
+ * Restore 1Byte strings from shared memory to worker local memory.
+ */
+static void
+Restore1ByteStr(char **dest, char *src, Size *copiedsize)
+{
+	uint8		len;
+
+	memcpy((uint8 *) (&len), src + (*copiedsize), sizeof(uint8));
+	(*copiedsize) += sizeof(uint8);
+	if (len)
+	{
+		*dest = palloc0(sizeof(char) + 1);
+		(*dest)[0] = src[(*copiedsize)++];
+	}
+}
+
+/*
+ * RestoreParallelCopyState
+ *
+ * Retrieve the cstate members which was populated by the leader in the shared
+ * memory.
+ */
+static void
+RestoreParallelCopyState(shm_toc *toc, CopyFromState cstate, List **attlist)
+{
+	char	   *shared_str_val = (char *) shm_toc_lookup(toc, PARALLEL_COPY_KEY_CSTATE, true);
+	Size		copiedsize = 0;
+
+	memcpy((char *) &cstate->copy_src, shared_str_val + copiedsize, sizeof(cstate->copy_src));
+	copiedsize += sizeof(cstate->copy_src);
+	memcpy((char *) &cstate->opts.file_encoding, shared_str_val + copiedsize, sizeof(cstate->opts.file_encoding));
+	copiedsize += sizeof(cstate->opts.file_encoding);
+	memcpy((char *) &cstate->need_transcoding, shared_str_val + copiedsize, sizeof(cstate->need_transcoding));
+	copiedsize += sizeof(cstate->need_transcoding);
+	memcpy((char *) &cstate->encoding_embeds_ascii, shared_str_val + copiedsize, sizeof(cstate->encoding_embeds_ascii));
+	copiedsize += sizeof(cstate->encoding_embeds_ascii);
+	memcpy((char *) &cstate->opts.csv_mode, shared_str_val + copiedsize, sizeof(cstate->opts.csv_mode));
+	copiedsize += sizeof(cstate->opts.csv_mode);
+	memcpy((char *) &cstate->opts.header_line, shared_str_val + copiedsize, sizeof(cstate->opts.header_line));
+	copiedsize += sizeof(cstate->opts.header_line);
+	memcpy((char *) &cstate->opts.null_print_len, shared_str_val + copiedsize, sizeof(cstate->opts.null_print_len));
+	copiedsize += sizeof(cstate->opts.null_print_len);
+	memcpy((char *) &cstate->opts.force_quote_all, shared_str_val + copiedsize, sizeof(cstate->opts.force_quote_all));
+	copiedsize += sizeof(cstate->opts.force_quote_all);
+	memcpy((char *) &cstate->opts.convert_selectively, shared_str_val + copiedsize, sizeof(cstate->opts.convert_selectively));
+	copiedsize += sizeof(cstate->opts.convert_selectively);
+	memcpy((char *) &cstate->num_defaults, shared_str_val + copiedsize, sizeof(cstate->num_defaults));
+	copiedsize += sizeof(cstate->num_defaults);
+	memcpy((char *) &cstate->pcdata->relid, shared_str_val + copiedsize, sizeof(cstate->pcdata->relid));
+	copiedsize += sizeof(cstate->pcdata->relid);
+	memcpy((char *) &cstate->opts.binary, shared_str_val + copiedsize, sizeof(cstate->opts.binary));
+	copiedsize += sizeof(cstate->opts.binary);
+
+	cstate->opts.null_print = (char *) RestoreNodeFromSharedMemory(shared_str_val, &copiedsize, true);
+	if (!cstate->opts.null_print)
+		cstate->opts.null_print = "";
+
+	Restore1ByteStr(&cstate->opts.delim, shared_str_val, &copiedsize);
+	Restore1ByteStr(&cstate->opts.quote, shared_str_val, &copiedsize);
+	Restore1ByteStr(&cstate->opts.escape, shared_str_val, &copiedsize);
+
+	*attlist = (List *) RestoreNodeFromSharedMemory(shared_str_val, &copiedsize, false);
+	cstate->opts.force_notnull = (List *) RestoreNodeFromSharedMemory(shared_str_val, &copiedsize, false);
+	cstate->opts.force_null = (List *) RestoreNodeFromSharedMemory(shared_str_val, &copiedsize, false);
+	cstate->opts.convert_select = (List *) RestoreNodeFromSharedMemory(shared_str_val, &copiedsize, false);
+	cstate->whereClause = (Node *) RestoreNodeFromSharedMemory(shared_str_val, &copiedsize, false);
+	cstate->range_table = (List *) RestoreNodeFromSharedMemory(shared_str_val, &copiedsize, false);
+}
+
+/*
+ * PopulateParallelCopyShmInfo
+ *
+ * Sets ParallelCopyShmInfo structure members.
+ */
+static void
+PopulateParallelCopyShmInfo(ParallelCopyShmInfo *shared_info_ptr)
+{
+	uint32		count;
+
+	MemSet(shared_info_ptr, 0, sizeof(ParallelCopyShmInfo));
+	shared_info_ptr->is_read_in_progress = true;
+	shared_info_ptr->cur_block_pos = -1;
+	SpinLockInit(&shared_info_ptr->line_boundaries.worker_pos_lock);
+	for (count = 0; count < RINGSIZE; count++)
+	{
+		ParallelCopyLineBoundary *lineInfo = &shared_info_ptr->line_boundaries.ring[count];
+
+		pg_atomic_init_u32(&(lineInfo->line_size), -1);
+	}
+}
+
 /*
  * CheckExprParallelSafety
  *
@@ -102,3 +464,895 @@ IsParallelCopyAllowed(CopyFromState cstate, Oid relid)
 
 	return true;
 }
+
+/*
+ * BeginParallelCopy - Start parallel copy tasks.
+ *
+ * Get the number of workers required to perform the parallel copy. The data
+ * structures that are required by the parallel workers will be initialized, the
+ * size required in DSM will be calculated and the necessary keys will be loaded
+ * in the DSM. The specified number of workers will then be launched.
+ */
+ParallelContext *
+BeginParallelCopy(CopyFromState cstate, List *attnamelist, Oid relid)
+{
+	ParallelContext *pcxt;
+	ParallelCopyShmInfo *shared_info_ptr;
+	int			parallel_workers = 0;
+	WalUsage   *walusage;
+	BufferUsage *bufferusage;
+	ParallelCopyData *pcdata;
+	MemoryContext oldcontext;
+	uint32		estsize;
+	SerializedListToStrCState list_converted_str = {0};
+
+	CheckTargetRelValidity(cstate);
+	parallel_workers = Min(cstate->opts.nworkers, max_worker_processes);
+
+	/* Can't perform copy in parallel */
+	if (parallel_workers == 0)
+		return NULL;
+
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	MemoryContextSwitchTo(oldcontext);
+
+	cstate->pcdata = pcdata;
+	pcdata->relid = relid;
+	(void) GetCurrentFullTransactionId();
+	(void) GetCurrentCommandId(true);
+
+	EnterParallelMode();
+	pcxt = CreateParallelContext("postgres", "ParallelCopyMain",
+								 parallel_workers);
+	Assert(pcxt->nworkers > 0);
+
+	/*
+	 * Estimate size for shared information for PARALLEL_COPY_KEY_SHARED_INFO
+	 */
+	shm_toc_estimate_chunk(&pcxt->estimator, sizeof(ParallelCopyShmInfo));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	/* Estimate the size for shared information for PARALLEL_COPY_KEY_CSTATE */
+	estsize = EstimateCStateSize(pcxt, cstate, attnamelist, &list_converted_str);
+
+	/*
+	 * Estimate space for WalUsage and BufferUsage --
+	 * PARALLEL_COPY_KEY_WAL_USAGE and PARALLEL_COPY_KEY_BUFFER_USAGE.
+	 */
+	shm_toc_estimate_chunk(&pcxt->estimator,
+						   mul_size(sizeof(WalUsage), pcxt->nworkers));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+	shm_toc_estimate_chunk(&pcxt->estimator,
+						   mul_size(sizeof(BufferUsage), pcxt->nworkers));
+	shm_toc_estimate_keys(&pcxt->estimator, 1);
+
+	InitializeParallelDSM(pcxt);
+
+	/* If no DSM segment was available, back out (do serial copy) */
+	if (pcxt->seg == NULL)
+	{
+		EndParallelCopy(pcxt);
+		pfree(pcdata);
+		cstate->pcdata = NULL;
+		return NULL;
+	}
+
+	/* Allocate shared memory for PARALLEL_COPY_KEY_SHARED_INFO */
+	shared_info_ptr = (ParallelCopyShmInfo *) shm_toc_allocate(pcxt->toc, sizeof(ParallelCopyShmInfo));
+	PopulateParallelCopyShmInfo(shared_info_ptr);
+
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_SHARED_INFO, shared_info_ptr);
+	pcdata->pcshared_info = shared_info_ptr;
+
+	SerializeParallelCopyState(pcxt, cstate, estsize, &list_converted_str);
+
+	/*
+	 * Allocate space for each worker's WalUsage and BufferUsage; no need to
+	 * initialize.
+	 */
+	walusage = shm_toc_allocate(pcxt->toc,
+								mul_size(sizeof(WalUsage), pcxt->nworkers));
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_WAL_USAGE, walusage);
+	pcdata->walusage = walusage;
+	bufferusage = shm_toc_allocate(pcxt->toc,
+								   mul_size(sizeof(BufferUsage), pcxt->nworkers));
+	shm_toc_insert(pcxt->toc, PARALLEL_COPY_KEY_BUFFER_USAGE, bufferusage);
+	pcdata->bufferusage = bufferusage;
+
+	LaunchParallelWorkers(pcxt);
+	if (pcxt->nworkers_launched == 0)
+	{
+		EndParallelCopy(pcxt);
+		pfree(pcdata);
+		cstate->pcdata = NULL;
+		return NULL;
+	}
+
+	/*
+	 * Caller needs to wait for all launched workers when we return.  Make
+	 * sure that the failure-to-start case will not hang forever.
+	 */
+	WaitForParallelWorkersToAttach(pcxt);
+
+	pcdata->is_leader = true;
+	cstate->is_parallel = true;
+	return pcxt;
+}
+
+/*
+ * EndParallelCopy
+ *
+ * End the parallel copy tasks.
+ */
+pg_attribute_always_inline void
+EndParallelCopy(ParallelContext *pcxt)
+{
+	Assert(!IsParallelWorker());
+
+	DestroyParallelContext(pcxt);
+	ExitParallelMode();
+}
+
+/*
+ * InitializeParallelCopyInfo
+ *
+ * Initialize parallel worker.
+ */
+static void
+InitializeParallelCopyInfo(CopyFromState cstate, List *attnamelist)
+{
+	uint32		count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	PopulateCommonCStateInfo(cstate, tup_desc, attnamelist);
+
+	/* Initialize state variables. */
+	cstate->reached_eof = false;
+	cstate->eol_type = EOL_UNKNOWN;
+	cstate->cur_relname = RelationGetRelationName(cstate->rel);
+	cstate->cur_lineno = 0;
+	cstate->cur_attname = NULL;
+	cstate->cur_attval = NULL;
+
+	/* Set up variables to avoid per-attribute overhead. */
+	initStringInfo(&cstate->attribute_buf);
+
+	initStringInfo(&cstate->line_buf);
+	for (count = 0; count < WORKER_CHUNK_COUNT; count++)
+		initStringInfo(&pcdata->worker_line_buf[count].line_buf);
+
+	cstate->line_buf_converted = false;
+	cstate->raw_buf = NULL;
+	cstate->raw_buf_index = cstate->raw_buf_len = 0;
+
+	PopulateCStateCatalogInfo(cstate);
+
+	/* Create workspace for CopyReadAttributes results. */
+	if (!cstate->opts.binary)
+	{
+		AttrNumber	attr_count = list_length(cstate->attnumlist);
+
+		cstate->max_fields = attr_count;
+		cstate->raw_fields = (char **) palloc(attr_count * sizeof(char *));
+	}
+}
+
+/*
+ * UpdateLineInfo
+ *
+ * Update line information & return.
+ */
+static bool
+UpdateLineInfo(ParallelCopyShmInfo *pcshared_info,
+			   ParallelCopyLineBoundary *lineInfo, uint32 write_pos)
+{
+	elog(DEBUG1, "[Worker] Completed processing line:%u", write_pos);
+	pg_atomic_write_u32(&lineInfo->line_state, LINE_WORKER_PROCESSED);
+	pg_atomic_write_u32(&lineInfo->line_size, -1);
+	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
+	return false;
+}
+
+/*
+ * CacheLineInfo
+ *
+ * Cache the line information to local memory.
+ */
+static bool
+CacheLineInfo(CopyFromState cstate, uint32 buff_count, uint32 line_pos)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	uint32		write_pos;
+	ParallelCopyDataBlock *data_blk_ptr;
+	ParallelCopyLineBoundary *lineInfo;
+	uint32		offset;
+	uint32		dataSize;
+	uint32		copiedSize = 0;
+
+	resetStringInfo(&pcdata->worker_line_buf[buff_count].line_buf);
+	write_pos = GetLinePosition(cstate, line_pos);
+	if (-1 == write_pos)
+		return true;
+
+	/* Get the current line information. */
+	lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+	if (pg_atomic_read_u32(&lineInfo->line_size) == 0)
+		return UpdateLineInfo(pcshared_info, lineInfo, write_pos);
+
+	/* Get the block information. */
+	data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+	/* Get the offset information from where the data must be copied. */
+	offset = lineInfo->start_offset;
+	pcdata->worker_line_buf[buff_count].cur_lineno = lineInfo->cur_lineno;
+
+	elog(DEBUG1, "[Worker] Processing - line position:%u, block:%u, unprocessed lines:%u, offset:%u, line size:%u",
+		 write_pos, lineInfo->first_block,
+		 pg_atomic_read_u32(&data_blk_ptr->unprocessed_line_parts),
+		 offset, pg_atomic_read_u32(&lineInfo->line_size));
+
+	for (;;)
+	{
+		uint8		skip_bytes = data_blk_ptr->skip_bytes;
+
+		/*
+		 * There is a possibility that the loop embedded at the bottom of the
+		 * current loop has come out because data_blk_ptr->curr_blk_completed
+		 * is set, but dataSize read might be an old value, if
+		 * data_blk_ptr->curr_blk_completed and the line is completed,
+		 * line_size will be set. Read the line_size again to be sure if it is
+		 * completed or partial block.
+		 */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+		if (dataSize != -1)
+		{
+			uint32		remainingSize = dataSize - copiedSize;
+
+			if (!remainingSize)
+				break;
+
+			/* Whole line is in current block. */
+			if (remainingSize + offset + skip_bytes < DATA_BLOCK_SIZE)
+			{
+				appendBinaryStringInfo(&pcdata->worker_line_buf[buff_count].line_buf,
+									   &data_blk_ptr->data[offset],
+									   remainingSize);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts,
+										1);
+				break;
+			}
+			else
+			{
+				/* Line is spread across the blocks. */
+				uint32		lineInCurrentBlock = (DATA_BLOCK_SIZE - skip_bytes) - offset;
+
+				appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+										 &data_blk_ptr->data[offset],
+										 lineInCurrentBlock);
+				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+				copiedSize += lineInCurrentBlock;
+				while (copiedSize < dataSize)
+				{
+					uint32		currentBlockCopySize;
+					ParallelCopyDataBlock *currBlkPtr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+
+					skip_bytes = currBlkPtr->skip_bytes;
+
+					/*
+					 * If complete data is present in current block use
+					 * dataSize - copiedSize, or copy the whole block from
+					 * current block.
+					 */
+					currentBlockCopySize = Min(dataSize - copiedSize, DATA_BLOCK_SIZE - skip_bytes);
+					appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+											 &currBlkPtr->data[0],
+											 currentBlockCopySize);
+					pg_atomic_sub_fetch_u32(&currBlkPtr->unprocessed_line_parts, 1);
+					copiedSize += currentBlockCopySize;
+					data_blk_ptr = currBlkPtr;
+				}
+
+				break;
+			}
+		}
+		else if (data_blk_ptr->curr_blk_completed)
+		{
+			/* Copy this complete block from the current offset. */
+			uint32		lineInCurrentBlock = (DATA_BLOCK_SIZE - skip_bytes) - offset;
+
+			appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
+									 &data_blk_ptr->data[offset],
+									 lineInCurrentBlock);
+			pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
+			copiedSize += lineInCurrentBlock;
+
+			/*
+			 * Reset the offset. For the first copy, copy from the offset. For
+			 * the subsequent copy the complete block.
+			 */
+			offset = 0;
+
+			/* Set data_blk_ptr to the following block. */
+			data_blk_ptr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
+		}
+
+		for (;;)
+		{
+			/* Get the size of this line */
+			dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+			/*
+			 * If the data is present in current block lineInfo->line_size
+			 * will be updated. If the data is spread across the blocks either
+			 * of lineInfo->line_size or data_blk_ptr->curr_blk_completed can
+			 * be updated. lineInfo->line_size will be updated if the complete
+			 * read is finished. data_blk_ptr->curr_blk_completed will be
+			 * updated if processing of current block is finished and data
+			 * processing is not finished.
+			 */
+			if (data_blk_ptr->curr_blk_completed || (dataSize != -1))
+				break;
+
+			COPY_WAIT_TO_PROCESS()
+		}
+	}
+
+	return UpdateLineInfo(pcshared_info, lineInfo, write_pos);
+}
+
+/*
+ * GetCachedLine
+ *
+ * Return a previously cached line to be processed by the worker.
+ */
+static bool
+GetCachedLine(CopyFromState cstate, ParallelCopyData *pcdata)
+{
+	cstate->line_buf = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].line_buf;
+	cstate->cur_lineno = pcdata->worker_line_buf[pcdata->worker_line_buf_pos].cur_lineno;
+	cstate->line_buf_valid = true;
+
+	/* Mark that encoding conversion hasn't occurred yet. */
+	cstate->line_buf_converted = false;
+
+	/* For binary format data, we don't need conversion. */
+	if (!cstate->opts.binary)
+		ConvertToServerEncoding(cstate);
+
+	pcdata->worker_line_buf_pos++;
+	return false;
+}
+
+/*
+ * GetWorkerLine
+ *
+ * Returns a line for worker to process.
+ */
+bool
+GetWorkerLine(CopyFromState cstate)
+{
+	uint32		buff_count;
+	ParallelCopyData *pcdata = cstate->pcdata;
+	ParallelCopyLineBoundaries *line_boundaries = &pcdata->pcshared_info->line_boundaries;
+	uint32 worker_pos;
+
+	/*
+	 * Copy the line data to line_buf and release the line position so that
+	 * the worker can continue loading data.
+	 */
+	if (pcdata->worker_line_buf_pos < pcdata->worker_line_buf_count)
+		return GetCachedLine(cstate, pcdata);
+
+	pcdata->worker_line_buf_pos = 0;
+	pcdata->worker_line_buf_count = 0;
+
+	SpinLockAcquire(&line_boundaries->worker_pos_lock);
+	worker_pos = line_boundaries->worker_pos;
+	line_boundaries->worker_pos = (line_boundaries->worker_pos +
+								   WORKER_CHUNK_COUNT) % RINGSIZE;
+	SpinLockRelease(&line_boundaries->worker_pos_lock);
+
+	for (buff_count = 0; buff_count < WORKER_CHUNK_COUNT; buff_count++)
+	{
+		bool result = CacheLineInfo(cstate, buff_count,
+									worker_pos + buff_count);
+		if (result)
+			break;
+
+		pcdata->worker_line_buf_count++;
+	}
+
+	if (pcdata->worker_line_buf_count > 0)
+		return GetCachedLine(cstate, pcdata);
+	else
+		resetStringInfo(&cstate->line_buf);
+
+	return true;
+}
+
+/*
+ * ParallelCopyMain - Parallel copy worker's code.
+ *
+ * Where clause handling, convert tuple to columns, add default null values for
+ * the missing columns that are not present in that record. Find the partition
+ * if it is partitioned table, invoke before row insert Triggers, handle
+ * constraints and insert the tuples.
+ */
+void
+ParallelCopyMain(dsm_segment *seg, shm_toc *toc)
+{
+	CopyFromState cstate;
+	ParallelCopyData *pcdata;
+	ParallelCopyShmInfo *pcshared_info;
+	Relation	rel = NULL;
+	MemoryContext oldcontext;
+	List	   *attlist = NIL;
+	WalUsage   *walusage;
+	BufferUsage *bufferusage;
+
+	/* Allocate workspace and zero all fields. */
+	cstate = (CopyFromStateData *) palloc0(sizeof(CopyFromStateData));
+
+	/*
+	 * We allocate everything used by a cstate in a new memory context. This
+	 * avoids memory leaks during repeated use of COPY in a query.
+	 */
+	cstate->copycontext = AllocSetContextCreate(CurrentMemoryContext,
+												"COPY",
+												ALLOCSET_DEFAULT_SIZES);
+	oldcontext = MemoryContextSwitchTo(cstate->copycontext);
+
+	pcdata = (ParallelCopyData *) palloc0(sizeof(ParallelCopyData));
+	cstate->pcdata = pcdata;
+	pcdata->is_leader = false;
+	pcdata->worker_processed_pos = -1;
+	cstate->is_parallel = true;
+	pcshared_info = (ParallelCopyShmInfo *) shm_toc_lookup(toc, PARALLEL_COPY_KEY_SHARED_INFO, false);
+
+	ereport(DEBUG1, (errmsg("Starting parallel copy worker")));
+
+	pcdata->pcshared_info = pcshared_info;
+	RestoreParallelCopyState(toc, cstate, &attlist);
+
+	/* Open and lock the relation, using the appropriate lock type. */
+	rel = table_open(cstate->pcdata->relid, RowExclusiveLock);
+	cstate->rel = rel;
+	InitializeParallelCopyInfo(cstate, attlist);
+
+	/* Prepare to track buffer usage during parallel execution */
+	InstrStartParallelQuery();
+
+	CopyFrom(cstate);
+
+	if (rel != NULL)
+		table_close(rel, RowExclusiveLock);
+
+	/* Report WAL/buffer usage during parallel execution */
+	bufferusage = shm_toc_lookup(toc, PARALLEL_COPY_KEY_BUFFER_USAGE, false);
+	walusage = shm_toc_lookup(toc, PARALLEL_COPY_KEY_WAL_USAGE, false);
+	InstrEndParallelQuery(&bufferusage[ParallelWorkerNumber],
+						  &walusage[ParallelWorkerNumber]);
+
+	MemoryContextSwitchTo(oldcontext);
+	MemoryContextDelete(cstate->copycontext);
+	pfree(cstate);
+	return;
+}
+
+/*
+ * UpdateSharedLineInfo
+ *
+ * Update the line information.
+ */
+uint32
+UpdateSharedLineInfo(CopyFromState cstate, uint32 blk_pos, uint32 offset,
+					 uint32 line_size, uint32 line_state, uint32 blk_line_pos)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ParallelCopyLineBoundaries *lineBoundaryPtr = &pcshared_info->line_boundaries;
+	ParallelCopyLineBoundary *lineInfo;
+	uint32		line_pos;
+
+	/* blk_line_pos will be valid in case line_pos was blocked earlier. */
+	if (blk_line_pos == -1)
+	{
+		line_pos = lineBoundaryPtr->pos;
+
+		/* Update the line information for the worker to pick and process. */
+		lineInfo = &lineBoundaryPtr->ring[line_pos];
+		while (pg_atomic_read_u32(&lineInfo->line_size) != -1)
+			COPY_WAIT_TO_PROCESS()
+
+		lineInfo->first_block = blk_pos;
+		lineInfo->start_offset = offset;
+		lineInfo->cur_lineno = cstate->cur_lineno;
+		lineBoundaryPtr->pos = (lineBoundaryPtr->pos + 1) % RINGSIZE;
+	}
+	else
+	{
+		line_pos = blk_line_pos;
+		lineInfo = &lineBoundaryPtr->ring[line_pos];
+	}
+
+	if (line_state == LINE_LEADER_POPULATED)
+	{
+		elog(DEBUG1, "[Leader] Added line with block:%u, offset:%u, line position:%u, line size:%u",
+			 lineInfo->first_block, lineInfo->start_offset, line_pos,
+			 line_size);
+		pcshared_info->populated++;
+		if (line_size == 0 || cstate->opts.binary)
+			pg_atomic_write_u32(&lineInfo->line_state, line_state);
+		else
+		{
+			uint32		current_line_state = LINE_LEADER_POPULATING;
+
+			/*
+			 * Make sure that no worker has consumed this element, if this
+			 * line is spread across multiple data blocks, worker would have
+			 * started processing, no need to change the state to
+			 * LINE_LEADER_POPULATED in this case.
+			 */
+			(void) pg_atomic_compare_exchange_u32(&lineInfo->line_state,
+												  &current_line_state,
+												  LINE_LEADER_POPULATED);
+		}
+	}
+	else
+	{
+		elog(DEBUG1, "[Leader] Adding - block:%u, offset:%u, line position:%u",
+			 lineInfo->first_block, lineInfo->start_offset, line_pos);
+		pg_atomic_write_u32(&lineInfo->line_state, line_state);
+	}
+
+	pg_atomic_write_u32(&lineInfo->line_size, line_size);
+
+	return line_pos;
+}
+
+/*
+ * ParallelCopyFrom - parallel copy leader's functionality.
+ *
+ * Leader executes the before statement for before statement trigger, if before
+ * statement trigger is present. It will read the table data from the file and
+ * copy the contents to DSM data blocks. It will then read the input contents
+ * from the DSM data block and identify the records based on line breaks. This
+ * information is called line or a record that need to be inserted into a
+ * relation. The line information will be stored in ParallelCopyLineBoundary DSM
+ * data structure. Workers will then process this information and insert the
+ * data in to table. It will repeat this process until the all data is read from
+ * the file and all the DSM data blocks are processed. While processing if
+ * leader identifies that DSM Data blocks or DSM ParallelCopyLineBoundary data
+ * structures is full, leader will wait till the worker frees up some entries
+ * and repeat the process. It will wait till all the lines populated are
+ * processed by the workers and exits.
+ */
+void
+ParallelCopyFrom(CopyFromState cstate)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	ErrorContextCallback errcallback;
+
+	ereport(DEBUG1, (errmsg("Running parallel copy leader")));
+
+	/* raw_buf is not used in parallel copy, instead data blocks are used. */
+	pfree(cstate->raw_buf);
+	cstate->raw_buf = NULL;
+
+	/* Execute the before statement triggers from the leader */
+	ExecBeforeStmtTrigger(cstate);
+
+	/* Set up callback to identify error line number */
+	errcallback.callback = CopyFromErrorCallback;
+	errcallback.arg = (void *) cstate;
+	errcallback.previous = error_context_stack;
+	error_context_stack = &errcallback;
+
+	/* On input just throw the header line away. */
+	if (cstate->cur_lineno == 0 && cstate->opts.header_line)
+	{
+		cstate->cur_lineno++;
+		if (CopyReadLine(cstate))
+		{
+			pcshared_info->is_read_in_progress = false;
+			return;				/* done */
+		}
+	}
+
+	for (;;)
+	{
+		bool		done;
+
+		CHECK_FOR_INTERRUPTS();
+
+		cstate->cur_lineno++;
+
+		/* Actually read the line into memory here. */
+		done = CopyReadLine(cstate);
+
+		/*
+		 * EOF at start of line means we're done.  If we see EOF after some
+		 * characters, we act as though it was newline followed by EOF, ie,
+		 * process the line and then exit loop on next iteration.
+		 */
+		if (done && cstate->line_buf.len == 0)
+			break;
+	}
+
+
+	/* Done, clean up */
+	error_context_stack = errcallback.previous;
+
+	/*
+	 * In the old protocol, tell pqcomm that we can process normal protocol
+	 * messages again.
+	 */
+	if (cstate->copy_src == COPY_OLD_FE)
+		pq_endmsgread();
+
+	pcshared_info->is_read_in_progress = false;
+	cstate->cur_lineno = 0;
+}
+
+/*
+ * GetLinePosition
+ *
+ * Return the line position once the leader has populated the data.
+ */
+uint32
+GetLinePosition(CopyFromState cstate, uint32 line_pos)
+{
+	ParallelCopyData *pcdata = cstate->pcdata;
+	ParallelCopyShmInfo *pcshared_info = pcdata->pcshared_info;
+	uint32		write_pos = line_pos;
+
+	for (;;)
+	{
+		uint32		dataSize;
+		bool		is_read_in_progress = pcshared_info->is_read_in_progress;
+		ParallelCopyLineBoundary *lineInfo;
+		ParallelCopyDataBlock *data_blk_ptr;
+		uint32		line_state = LINE_LEADER_POPULATED;
+
+		CHECK_FOR_INTERRUPTS();
+
+		/* File read completed & no elements to process. */
+		if (!is_read_in_progress &&
+			(pcshared_info->populated ==
+			 pg_atomic_read_u64(&pcshared_info->total_worker_processed)))
+		{
+			write_pos = -1;
+			break;
+		}
+
+		/* Get the current line information. */
+		lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
+
+		/* Get the size of this line. */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+
+		if (dataSize != 0)		/* If not an empty line. */
+		{
+			/* Get the block information. */
+			data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
+
+			if (!data_blk_ptr->curr_blk_completed && (dataSize == -1))
+			{
+				/* Wait till the current line or block is added. */
+				COPY_WAIT_TO_PROCESS()
+					continue;
+			}
+		}
+
+		/* Make sure that no worker has consumed this element. */
+		if (pg_atomic_compare_exchange_u32(&lineInfo->line_state,
+										   &line_state, LINE_WORKER_PROCESSING))
+			break;
+
+		line_state = LINE_LEADER_POPULATING;
+		/* Make sure that no worker has consumed this element. */
+		if (pg_atomic_compare_exchange_u32(&lineInfo->line_state,
+										   &line_state, LINE_WORKER_PROCESSING))
+			break;
+	}
+
+	pcdata->worker_processed_pos = write_pos;
+	return write_pos;
+}
+
+/*
+ * GetFreeCopyBlock
+ *
+ * Get a free block for data to be copied.
+ */
+static pg_attribute_always_inline uint32
+GetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	int			count = 0;
+	uint32		last_free_block = pcshared_info->cur_block_pos;
+	uint32		block_pos = (last_free_block != -1) ? ((last_free_block + 1) % MAX_BLOCKS_COUNT) : 0;
+
+	/*
+	 * Get a new block for copying data, don't check current block, current
+	 * block will have some unprocessed data.
+	 */
+	while (count < (MAX_BLOCKS_COUNT - 1))
+	{
+		ParallelCopyDataBlock *dataBlkPtr = &pcshared_info->data_blocks[block_pos];
+		uint32		unprocessed_line_parts = pg_atomic_read_u32(&dataBlkPtr->unprocessed_line_parts);
+
+		if (unprocessed_line_parts == 0)
+		{
+			dataBlkPtr->curr_blk_completed = false;
+			dataBlkPtr->skip_bytes = 0;
+			dataBlkPtr->following_block = -1;
+			pcshared_info->cur_block_pos = block_pos;
+			MemSet(&dataBlkPtr->data[0], 0, DATA_BLOCK_SIZE);
+			return block_pos;
+		}
+
+		block_pos = (block_pos + 1) % MAX_BLOCKS_COUNT;
+		count++;
+	}
+
+	return -1;
+}
+
+/*
+ * WaitGetFreeCopyBlock
+ *
+ * If there are no blocks available, wait and get a block for copying data.
+ */
+uint32
+WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
+{
+	uint32		new_free_pos = -1;
+
+	for (;;)
+	{
+		new_free_pos = GetFreeCopyBlock(pcshared_info);
+		if (new_free_pos != -1) /* We have got one block, break now. */
+			break;
+
+		COPY_WAIT_TO_PROCESS()
+	}
+
+	return new_free_pos;
+}
+
+/*
+ * SetRawBufForLoad
+ *
+ * Set raw_buf to the shared memory where the file data must be read.
+ */
+void
+SetRawBufForLoad(CopyFromState cstate, uint32 line_size, uint32 copy_buf_len,
+				 uint32 raw_buf_ptr, char **copy_raw_buf)
+{
+	ParallelCopyShmInfo *pcshared_info;
+	uint32		cur_block_pos;
+	uint32		next_block_pos;
+	ParallelCopyDataBlock *cur_data_blk_ptr = NULL;
+	ParallelCopyDataBlock *next_data_blk_ptr = NULL;
+
+	Assert(IsParallelCopy());
+
+	pcshared_info = cstate->pcdata->pcshared_info;
+	cur_block_pos = pcshared_info->cur_block_pos;
+	cur_data_blk_ptr = (cstate->raw_buf) ? &pcshared_info->data_blocks[cur_block_pos] : NULL;
+	next_block_pos = WaitGetFreeCopyBlock(pcshared_info);
+	next_data_blk_ptr = &pcshared_info->data_blocks[next_block_pos];
+
+	/* set raw_buf to the data block in shared memory */
+	cstate->raw_buf = next_data_blk_ptr->data;
+	*copy_raw_buf = cstate->raw_buf;
+	if (cur_data_blk_ptr)
+	{
+		if (line_size)
+		{
+			/*
+			 * Mark the previous block as completed, worker can start copying
+			 * this data.
+			 */
+			cur_data_blk_ptr->following_block = next_block_pos;
+			pg_atomic_add_fetch_u32(&cur_data_blk_ptr->unprocessed_line_parts, 1);
+			cur_data_blk_ptr->curr_blk_completed = true;
+		}
+
+		cur_data_blk_ptr->skip_bytes = copy_buf_len - raw_buf_ptr;
+		cstate->raw_buf_len = cur_data_blk_ptr->skip_bytes;
+
+		/* Copy the skip bytes to the next block to be processed. */
+		if (cur_data_blk_ptr->skip_bytes)
+			memcpy(cstate->raw_buf, cur_data_blk_ptr->data + raw_buf_ptr,
+				   cur_data_blk_ptr->skip_bytes);
+	}
+	else
+		cstate->raw_buf_len = 0;
+
+	cstate->raw_buf_index = 0;
+}
+
+/*
+ * EndLineParallelCopy
+ *
+ * Update the line information in shared memory.
+ */
+void
+EndLineParallelCopy(CopyFromState cstate, uint32 line_pos, uint32 line_size,
+					uint32 raw_buf_ptr)
+{
+	uint8		new_line_size;
+
+	if (!IsParallelCopy())
+		return;
+
+	if (!IsHeaderLine())
+	{
+		ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+
+		/* Set the newline size. */
+		if (cstate->eol_type == EOL_NL || cstate->eol_type == EOL_CR)
+			new_line_size = 1;
+		else if (cstate->eol_type == EOL_CRNL)
+			new_line_size = 2;
+		else
+			new_line_size = 0;
+
+		if (line_size)
+		{
+			/*
+			 * If the new_line_size > raw_buf_ptr, then the new block has only
+			 * new line char content. The unprocessed count should not be
+			 * increased in this case.
+			 */
+			if (raw_buf_ptr > new_line_size)
+			{
+				uint32		cur_block_pos = pcshared_info->cur_block_pos;
+				ParallelCopyDataBlock *curr_data_blk_ptr = &pcshared_info->data_blocks[cur_block_pos];
+
+				pg_atomic_add_fetch_u32(&curr_data_blk_ptr->unprocessed_line_parts, 1);
+			}
+
+			/*
+			 * Update line size & line state, other members are already
+			 * updated.
+			 */
+			(void) UpdateSharedLineInfo(cstate, -1, -1, line_size,
+										LINE_LEADER_POPULATED, line_pos);
+		}
+		else if (new_line_size)
+			/* This means only new line char, empty record should be inserted. */
+			(void) UpdateSharedLineInfo(cstate, -1, -1, 0,
+										LINE_LEADER_POPULATED, -1);
+	}
+}
+
+/*
+ * ExecBeforeStmtTrigger
+ *
+ * Execute the before statement trigger, this will be executed for parallel copy
+ * by the leader process. This function code changes has been taken from
+ * CopyFrom function. Refer to comments section of respective code in CopyFrom
+ * function for more detailed information.
+ */
+void
+ExecBeforeStmtTrigger(CopyFromState cstate)
+{
+	EState	   *estate = CreateExecutorState();
+	ResultRelInfo *resultRelInfo;
+
+	Assert(IsLeader());
+	ExecInitRangeTable(estate, cstate->range_table);
+	resultRelInfo = makeNode(ResultRelInfo);
+	ExecInitResultRelation(estate, resultRelInfo, 1);
+	CheckValidResultRel(resultRelInfo, CMD_INSERT);
+	AfterTriggerBeginQuery();
+	ExecBSInsertTriggers(estate, resultRelInfo);
+	AfterTriggerEndQuery(estate);
+	ExecCloseResultRelations(estate);
+	ExecCloseRangeTableRelations(estate);
+	FreeExecutorState(estate);
+}
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index 3a43c09..713f905 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -2393,7 +2393,7 @@ psql_completion(const char *text, int start, int end)
 	/* Complete COPY <sth> FROM|TO filename WITH ( */
 	else if (Matches("COPY|\\copy", MatchAny, "FROM|TO", MatchAny, "WITH", "("))
 		COMPLETE_WITH("FORMAT", "FREEZE", "DELIMITER", "NULL",
-					  "HEADER", "QUOTE", "ESCAPE", "FORCE_QUOTE",
+					  "HEADER", "PARALLEL", "QUOTE", "ESCAPE", "FORCE_QUOTE",
 					  "FORCE_NOT_NULL", "FORCE_NULL", "ENCODING");
 
 	/* Complete COPY <sth> FROM|TO filename WITH (FORMAT */
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index 127a3c6..9ba8440 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -48,6 +48,7 @@ typedef struct CopyFormatOptions
 	bool	   *force_null_flags;	/* per-column CSV FN flags */
 	bool		convert_selectively;	/* do selective binary conversion? */
 	List	   *convert_select; /* list of column names (can be NIL) */
+	int			nworkers;		/* number of workers for parallel copy */
 } CopyFormatOptions;
 
 /* These are private in commands/copy[from|to].c */
@@ -60,7 +61,7 @@ extern void DoCopy(ParseState *state, const CopyStmt *stmt,
 				   int stmt_location, int stmt_len,
 				   uint64 *processed);
 
-extern void ProcessCopyOptions(ParseState *pstate, CopyFormatOptions *ops_out, bool is_from, List *options);
+extern void ProcessCopyOptions(ParseState *pstate, CopyFormatOptions * ops_out, bool is_from, List *options);
 extern CopyFromState BeginCopyFrom(ParseState *pstate, Relation rel, Node *whereClause,
 							   const char *filename,
 							   bool is_program, copy_data_source_cb data_source_cb, List *attnamelist, List *options);
diff --git a/src/include/commands/copyfrom_internal.h b/src/include/commands/copyfrom_internal.h
index 6ed7954..d44f2b5 100644
--- a/src/include/commands/copyfrom_internal.h
+++ b/src/include/commands/copyfrom_internal.h
@@ -14,11 +14,49 @@
 #ifndef COPYFROM_INTERNAL_H
 #define COPYFROM_INTERNAL_H
 
+#include "access/parallel.h"
 #include "commands/copy.h"
 #include "commands/trigger.h"
 
 #define IsHeaderLine()			(cstate->opts.header_line && cstate->cur_lineno == 1)
 
+#define RAW_BUF_SIZE 65536		/* we palloc RAW_BUF_SIZE+1 bytes */
+
+/*
+ * The macros DATA_BLOCK_SIZE, RINGSIZE & MAX_BLOCKS_COUNT stores the records
+ * read from the file that need to be inserted into the relation. These values
+ * help in the handover of multiple records with the significant size of data to
+ * be processed by each of the workers. This also ensures there is no context
+ * switch and the work is fairly distributed among the workers. This number
+ * showed best results in the performance tests.
+ */
+#define DATA_BLOCK_SIZE RAW_BUF_SIZE
+
+/*
+ * It can hold MAX_BLOCKS_COUNT blocks of RAW_BUF_SIZE data in DSM to be
+ * processed by the worker.
+ */
+#define MAX_BLOCKS_COUNT 1024
+
+/*
+ * It can hold upto RINGSIZE record information for worker to process. RINGSIZE
+ * should be a multiple of WORKER_CHUNK_COUNT, as wrap around cases is currently
+ * not handled while selecting the WORKER_CHUNK_COUNT by the worker.
+ */
+#define RINGSIZE (10 * 1024)
+
+/*
+ * While accessing DSM, each worker will pick the WORKER_CHUNK_COUNT records
+ * from the DSM data blocks at a time and store them in it's local memory. This
+ * is to make workers not contend much while getting record information from the
+ * DSM. Read RINGSIZE comments before changing this value.
+ */
+#define WORKER_CHUNK_COUNT 64
+
+#define IsParallelCopy()		(cstate->is_parallel)
+#define IsLeader()				(cstate->pcdata->is_leader)
+#define IsWorker()				(IsParallelCopy() && !IsLeader())
+
 /*
  * Represents the different source cases we need to worry about at
  * the bottom level
@@ -43,6 +81,18 @@ typedef enum EolType
 } EolType;
 
 /*
+ * State of the line.
+ */
+typedef enum ParallelCopyLineState
+{
+	LINE_INIT,					/* initial state of line */
+	LINE_LEADER_POPULATING,		/* leader processing line */
+	LINE_LEADER_POPULATED,		/* leader completed populating line */
+	LINE_WORKER_PROCESSING,		/* worker processing line */
+	LINE_WORKER_PROCESSED		/* worker completed processing line */
+} ParallelCopyLineState;
+
+/*
  * Represents the heap insert method to be used during COPY FROM.
  */
 typedef enum CopyInsertMethod
@@ -53,6 +103,186 @@ typedef enum CopyInsertMethod
 } CopyInsertMethod;
 
 /*
+ * Copy data block information.
+ *
+ * These data blocks are created in DSM. Data read from file will be copied in
+ * these DSM data blocks. The leader process identifies the records and the
+ * record information will be shared to the workers. The workers will insert the
+ * records into the table. There can be one or more number of records in each of
+ * the data block based on the record size.
+ */
+typedef struct ParallelCopyDataBlock
+{
+	/* The number of unprocessed lines in the current block. */
+	pg_atomic_uint32 unprocessed_line_parts;
+
+	/*
+	 * If the current line data is continued into another block,
+	 * following_block will have the position where the remaining data need to
+	 * be read.
+	 */
+	uint32		following_block;
+
+	/*
+	 * This flag will be set, when the leader finds out this block can be read
+	 * safely by the worker. This helps the worker to start processing the
+	 * line early where the line will be spread across many blocks and the
+	 * worker need not wait for the complete line to be processed.
+	 */
+	bool		curr_blk_completed;
+
+	/*
+	 * Few bytes need to be skipped from this block, this will be set when a
+	 * sequence of characters like \r\n is expected, but end of our block
+	 * contained only \r. In this case we copy the data from \r into the new
+	 * block as they have to be processed together to identify end of line.
+	 * Worker will use skip_bytes to know that this data must be skipped from
+	 * this data block.
+	 */
+	uint8		skip_bytes;
+	char		data[DATA_BLOCK_SIZE];	/* data read from file */
+} ParallelCopyDataBlock;
+
+/*
+ * Individual line information.
+ *
+ * ParallelCopyLineBoundary is common data structure between leader & worker.
+ * Leader process will be populating data block, data block offset & the size of
+ * the record in DSM for the workers to copy the data into the relation.
+ * The leader & worker process access the shared line information by following
+ * the below steps to avoid any data corruption or hang:
+ *
+ * Leader should operate in the following order:
+ * 1) check if line_size is -1, if line_size is not -1 wait until line_size is
+ * set to -1 by the worker. If line_size is -1 it means worker is still
+ * processing.
+ * 2) set line_state to LINE_LEADER_POPULATING, so that the worker knows that
+ * leader is populating this line.
+ * 3) update first_block, start_offset & cur_lineno in any order.
+ * 4) update line_size.
+ * 5) update line_state to LINE_LEADER_POPULATED.
+ *
+ * Worker should operate in the following order:
+ * 1) check line_state is LINE_LEADER_POPULATED, if not it means leader is still
+ * populating the data.
+ * 2) read line_size to know the size of the data.
+ * 3) only one worker should choose one line for processing, this is handled by
+ *    using pg_atomic_compare_exchange_u32, worker will change the state to
+ *    LINE_WORKER_PROCESSING if line_state is LINE_LEADER_POPULATED(complete
+ *	  line is populated) or if line_state is LINE_LEADER_POPULATING(worker can
+ *	  start processing the DSM & release it to the leader).
+ * 4) read first_block, start_offset & cur_lineno in any order.
+ * 5) process line_size data.
+ * 6) update line_size to -1.
+ */
+typedef struct ParallelCopyLineBoundary
+{
+	/* Position of the first block in data_blocks array. */
+	uint32		first_block;
+	uint32		start_offset;	/* start offset of the line */
+
+	/*
+	 * Size of the current line -1 means line is yet to be filled completely,
+	 * 0 means empty line, >0 means line filled with line size data.
+	 */
+	pg_atomic_uint32 line_size;
+	pg_atomic_uint32 line_state;	/* line state */
+	uint64		cur_lineno;		/* line number for error messages */
+} ParallelCopyLineBoundary;
+
+/*
+ * Circular queue used to store the line information.
+ */
+typedef struct ParallelCopyLineBoundaries
+{
+	/* Position for the leader to populate a line. */
+	uint32		pos;
+	uint32		worker_pos;			/* Worker's last blocked Position. */
+	slock_t		worker_pos_lock;	/* locks worker_pos shared variable. */
+
+	/* Data read from the file/stdin by the leader process. */
+	ParallelCopyLineBoundary ring[RINGSIZE];
+} ParallelCopyLineBoundaries;
+
+/*
+ * Shared information among parallel copy workers. This will be allocated in the
+ * DSM segment.
+ */
+typedef struct ParallelCopyShmInfo
+{
+	bool		is_read_in_progress;	/* file read status */
+
+	/*
+	 * Actual lines inserted by worker, will not be same as
+	 * total_worker_processed if where condition is specified along with copy.
+	 * This will be the actual records inserted into the relation.
+	 */
+	pg_atomic_uint64 processed;
+
+	/*
+	 * The number of records currently processed by the worker, this will also
+	 * include the number of records that was filtered because of where
+	 * clause.
+	 */
+	pg_atomic_uint64 total_worker_processed;
+	uint64		populated;		/* lines populated by leader */
+	uint32		cur_block_pos;	/* current data block */
+	ParallelCopyDataBlock data_blocks[MAX_BLOCKS_COUNT];	/* data block array */
+	ParallelCopyLineBoundaries line_boundaries; /* line array */
+} ParallelCopyShmInfo;
+
+/*
+ * Parallel copy line buffer information.
+ */
+typedef struct ParallelCopyLineBuf
+{
+	StringInfoData line_buf;
+	uint64		cur_lineno;		/* line number for error messages */
+} ParallelCopyLineBuf;
+
+/*
+ * This structure helps in storing the common List/Node from CopyStateData that
+ * are required by the workers. This information will then be copied and stored
+ * into the DSM for the worker to retrieve and copy it to CopyStateData.
+ */
+typedef struct SerializedListToStrCState
+{
+	char	   *whereClauseStr;
+	char	   *rangeTableStr;
+	char	   *attnameListStr;
+	char	   *notnullListStr;
+	char	   *nullListStr;
+	char	   *convertListStr;
+} SerializedListToStrCState;
+
+/*
+ * Parallel copy data information.
+ */
+typedef struct ParallelCopyData
+{
+	Oid			relid;			/* relation id of the table */
+	ParallelCopyShmInfo *pcshared_info; /* common info in shared memory */
+	bool		is_leader;
+
+	/* line position which worker is processing */
+	uint32		worker_processed_pos;
+
+	WalUsage   *walusage;
+	BufferUsage *bufferusage;
+
+	/*
+	 * Local line_buf array, workers will copy it here and release the lines
+	 * for the leader to continue.
+	 */
+	ParallelCopyLineBuf worker_line_buf[WORKER_CHUNK_COUNT];
+	uint32		worker_line_buf_count;	/* Number of lines */
+
+	/* Current position in worker_line_buf */
+	uint32		worker_line_buf_pos;
+} ParallelCopyData;
+
+
+/*
  * This struct contains all the state variables used throughout a COPY FROM
  * operation.
  *
@@ -156,12 +386,35 @@ typedef struct CopyFromStateData
 	char	   *raw_buf;
 	int			raw_buf_index;	/* next byte to process */
 	int			raw_buf_len;	/* total # of bytes stored */
+	bool		is_parallel;
+	ParallelCopyData *pcdata;
+
 	/* Shorthand for number of unconsumed bytes available in raw_buf */
 #define RAW_BUF_BYTES(cstate) ((cstate)->raw_buf_len - (cstate)->raw_buf_index)
 } CopyFromStateData;
 
 extern void ReceiveCopyBegin(CopyFromState cstate);
 extern void ReceiveCopyBinaryHeader(CopyFromState cstate);
-extern bool IsParallelCopyAllowed(CopyFromState cstate, Oid relid);
+extern void PopulateCommonCStateInfo(CopyFromState cstate, TupleDesc tup_desc,
+									 List *attnamelist);
+extern void ConvertToServerEncoding(CopyFromState cstate);
 
+extern void ParallelCopyMain(dsm_segment *seg, shm_toc *toc);
+extern ParallelContext *BeginParallelCopy(CopyFromState cstate, List *attnamelist, Oid relid);
+extern void ParallelCopyFrom(CopyFromState cstate);
+extern void EndParallelCopy(ParallelContext *pcxt);
+extern bool IsParallelCopyAllowed(CopyFromState cstate, Oid relid);
+extern void ExecBeforeStmtTrigger(CopyFromState cstate);
+extern void CheckTargetRelValidity(CopyFromState cstate);
+extern void PopulateCStateCatalogInfo(CopyFromState cstate);
+extern uint32 GetLinePosition(CopyFromState cstate, uint32 line_pos);
+extern bool GetWorkerLine(CopyFromState cstate);
+extern bool CopyReadLine(CopyFromState cstate);
+extern uint32 WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info);
+extern void SetRawBufForLoad(CopyFromState cstate, uint32 line_size, uint32 copy_buf_len,
+							 uint32 raw_buf_ptr, char **copy_raw_buf);
+extern uint32 UpdateSharedLineInfo(CopyFromState cstate, uint32 blk_pos, uint32 offset,
+								   uint32 line_size, uint32 line_state, uint32 blk_line_pos);
+extern void EndLineParallelCopy(CopyFromState cstate, uint32 line_pos, uint32 line_size,
+								uint32 raw_buf_ptr);
 #endif							/* COPYFROM_INTERNAL_H */
diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list
index cf63acb..974b138 100644
--- a/src/tools/pgindent/typedefs.list
+++ b/src/tools/pgindent/typedefs.list
@@ -1704,6 +1704,13 @@ ParallelBitmapHeapState
 ParallelBlockTableScanDesc
 ParallelCompletionPtr
 ParallelContext
+ParallelCopyLineBoundaries
+ParallelCopyLineBoundary
+ParallelCopyData
+ParallelCopyDataBlock
+ParallelCopyLineBuf
+ParallelCopyLineState
+ParallelCopyShmInfo
 ParallelExecutorInfo
 ParallelHashGrowth
 ParallelHashJoinBatch
@@ -2226,6 +2233,7 @@ SerCommitSeqNo
 SerialControl
 SerializableXactHandle
 SerializedActiveRelMaps
+SerializedListToStrCState
 SerializedReindexState
 SerializedSnapshotData
 SerializedTransactionState
-- 
1.8.3.1

v11-0004-Documentation-for-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=v11-0004-Documentation-for-parallel-copy.patchDownload
From c4e011cda5ed7743231bda02f5ac9103605e4e29 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Sat, 1 Aug 2020 09:00:36 +0530
Subject: [PATCH v11 4/6] Documentation for parallel copy.

This patch has the documentation changes for parallel copy.
---
 doc/src/sgml/ref/copy.sgml | 31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/doc/src/sgml/ref/copy.sgml b/doc/src/sgml/ref/copy.sgml
index 369342b..328a5f1 100644
--- a/doc/src/sgml/ref/copy.sgml
+++ b/doc/src/sgml/ref/copy.sgml
@@ -37,6 +37,7 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
     DELIMITER '<replaceable class="parameter">delimiter_character</replaceable>'
     NULL '<replaceable class="parameter">null_string</replaceable>'
     HEADER [ <replaceable class="parameter">boolean</replaceable> ]
+    PARALLEL <replaceable class="parameter">integer</replaceable>
     QUOTE '<replaceable class="parameter">quote_character</replaceable>'
     ESCAPE '<replaceable class="parameter">escape_character</replaceable>'
     FORCE_QUOTE { ( <replaceable class="parameter">column_name</replaceable> [, ...] ) | * }
@@ -277,6 +278,22 @@ COPY { <replaceable class="parameter">table_name</replaceable> [ ( <replaceable
    </varlistentry>
 
    <varlistentry>
+    <term><literal>PARALLEL</literal></term>
+    <listitem>
+     <para>
+      Perform <command>COPY FROM</command> in parallel using <replaceable
+      class="parameter">integer</replaceable> background workers.  Please
+      note that it is not guaranteed that the number of parallel workers
+      specified in <replaceable class="parameter">integer</replaceable> will
+      be used during execution.  It is possible for a copy to run with fewer
+      workers than specified, or even with no workers at all (for example,
+      due to the setting of max_worker_processes). This option is allowed
+      only in <command>COPY FROM</command>.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
     <term><literal>QUOTE</literal></term>
     <listitem>
      <para>
@@ -953,6 +970,20 @@ COPY country FROM '/usr1/proj/bray/sql/country_data';
   </para>
 
   <para>
+   To copy data parallelly from a file into the <literal>country</literal> table:
+<programlisting>
+COPY country FROM '/usr1/proj/bray/sql/country_data' WITH (PARALLEL 1);
+</programlisting>
+  </para>
+
+  <para>
+   To copy data parallelly from STDIN into the <literal>country</literal> table:
+<programlisting>
+COPY country FROM STDIN WITH (PARALLEL 1);
+</programlisting>
+  </para>
+
+  <para>
    To copy into a file just the countries whose names start with 'A':
 <programlisting>
 COPY (SELECT * FROM country WHERE country_name LIKE 'A%') TO '/usr1/proj/bray/sql/a_list_countries.copy';
-- 
1.8.3.1

v11-0005-Parallel-Copy-For-Binary-Format-Files.patchtext/x-patch; charset=US-ASCII; name=v11-0005-Parallel-Copy-For-Binary-Format-Files.patchDownload
From 9985c531c5f12d3cb83868fa479ddb7f29e69f0a Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Thu, 3 Dec 2020 11:32:43 +0530
Subject: [PATCH v11 5/6] Parallel Copy For Binary Format Files

Leader reads data from the file into the DSM data blocks each of 64K size.
It also identifies each tuple data block id, start offset, end offset,
tuple size and updates this information in the ring data structure.
Workers parallelly read the tuple information from the ring data structure,
the actual tuple data from the data blocks and parallelly insert the tuples
into the table.
---
 src/backend/commands/copy.c              |   2 +-
 src/backend/commands/copyfromparse.c     | 123 +++++------
 src/backend/commands/copyparallel.c      | 350 +++++++++++++++++++++++++++++--
 src/include/commands/copyfrom_internal.h | 127 +++++++++++
 4 files changed, 515 insertions(+), 87 deletions(-)

diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index 7d6ea72..865e562 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -336,7 +336,7 @@ DoCopy(ParseState *pstate, const CopyStmt *stmt,
 			 * specifies parallel workers, but, no worker is picked up, so go
 			 * back to non parallel mode value of nworkers.
 			 */
-			cstate->nworkers = -1;
+			cstate->opts.nworkers = -1;
 			*processed = CopyFrom(cstate);	/* copy from file to database */
 		}
 
diff --git a/src/backend/commands/copyfromparse.c b/src/backend/commands/copyfromparse.c
index 69b06e2..a767bae 100644
--- a/src/backend/commands/copyfromparse.c
+++ b/src/backend/commands/copyfromparse.c
@@ -116,12 +116,12 @@ static Datum CopyReadBinaryAttribute(CopyFromState cstate, FmgrInfo *flinfo,
 
 
 /* Low-level communications functions */
-static int	CopyGetData(CopyFromState cstate, void *databuf,
+int			CopyGetData(CopyFromState cstate, void *databuf,
 						int minread, int maxread);
 static inline bool CopyGetInt32(CopyFromState cstate, int32 *val);
 static inline bool CopyGetInt16(CopyFromState cstate, int16 *val);
 static bool CopyLoadRawBuf(CopyFromState cstate);
-static int	CopyReadBinaryData(CopyFromState cstate, char *dest, int nbytes);
+int			CopyReadBinaryData(CopyFromState cstate, char *dest, int nbytes);
 static void ClearEOLFromCopiedData(CopyFromState cstate, char *copy_line_data,
 								   int copy_line_pos, int *copy_line_size);
 void ConvertToServerEncoding(CopyFromState cstate);
@@ -169,7 +169,7 @@ ReceiveCopyBinaryHeader(CopyFromState cstate)
 	int32		tmp;
 
 	/* Signature */
-	if (CopyReadBinaryData(cstate, readSig, 11) != 11 ||
+	if (CopyGetData(cstate, readSig, 11, 11) != 11 ||
 		memcmp(readSig, BinarySignature, 11) != 0)
 		ereport(ERROR,
 				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
@@ -197,7 +197,7 @@ ReceiveCopyBinaryHeader(CopyFromState cstate)
 	/* Skip extension header, if present */
 	while (tmp-- > 0)
 	{
-		if (CopyReadBinaryData(cstate, readSig, 1) != 1)
+		if (CopyGetData(cstate, readSig, 1, 1) != 1)
 			ereport(ERROR,
 					(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
 					 errmsg("invalid COPY file header (wrong length)")));
@@ -217,7 +217,7 @@ ReceiveCopyBinaryHeader(CopyFromState cstate)
  *
  * NB: no data conversion is applied here.
  */
-static int
+int
 CopyGetData(CopyFromState cstate, void *databuf, int minread, int maxread)
 {
 	int			bytesread = 0;
@@ -338,10 +338,25 @@ CopyGetInt32(CopyFromState cstate, int32 *val)
 {
 	uint32		buf;
 
-	if (CopyReadBinaryData(cstate, (char *) &buf, sizeof(buf)) != sizeof(buf))
+	/*
+	 * For parallel copy, avoid reading data to raw buf, read directly from
+	 * file, later the data will be read to parallel copy data buffers.
+	 */
+	if (cstate->opts.nworkers > 0)
 	{
-		*val = 0;				/* suppress compiler warning */
-		return false;
+		if (CopyGetData(cstate, &buf, sizeof(buf), sizeof(buf)) != sizeof(buf))
+		{
+			*val = 0;			/* suppress compiler warning */
+			return false;
+		}
+	}
+	else
+	{
+		if (CopyReadBinaryData(cstate, (char *) &buf, sizeof(buf)) != sizeof(buf))
+		{
+			*val = 0;			/* suppress compiler warning */
+			return false;
+		}
 	}
 	*val = (int32) pg_ntoh32(buf);
 	return true;
@@ -403,7 +418,7 @@ CopyLoadRawBuf(CopyFromState cstate)
  * and writes them to 'dest'.  Returns the number of bytes read (which
  * would be less than 'nbytes' only if we reach EOF).
  */
-static int
+int
 CopyReadBinaryData(CopyFromState cstate, char *dest, int nbytes)
 {
 	int			copied_bytes = 0;
@@ -619,60 +634,44 @@ NextCopyFrom(CopyFromState cstate, ExprContext *econtext,
 	else
 	{
 		/* binary */
-		int16		fld_count;
-		ListCell   *cur;
-
 		cstate->cur_lineno++;
+		cstate->max_fields = list_length(cstate->attnumlist);
 
-		if (!CopyGetInt16(cstate, &fld_count))
-		{
-			/* EOF detected (end of file, or protocol-level EOF) */
-			return false;
-		}
-
-		if (fld_count == -1)
+		if (!IsParallelCopy())
 		{
-			/*
-			 * Received EOF marker.  In a V3-protocol copy, wait for the
-			 * protocol-level EOF, and complain if it doesn't come
-			 * immediately.  This ensures that we correctly handle CopyFail,
-			 * if client chooses to send that now.
-			 *
-			 * Note that we MUST NOT try to read more data in an old-protocol
-			 * copy, since there is no protocol-level EOF marker then.  We
-			 * could go either way for copy from file, but choose to throw
-			 * error if there's data after the EOF marker, for consistency
-			 * with the new-protocol case.
-			 */
-			char		dummy;
+			int16		fld_count;
+			ListCell   *cur;
 
-			if (cstate->copy_src != COPY_OLD_FE &&
-				CopyReadBinaryData(cstate, &dummy, 1) > 0)
-				ereport(ERROR,
-						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-						 errmsg("received copy data after EOF marker")));
-			return false;
-		}
+			if (!CopyGetInt16(cstate, &fld_count))
+			{
+				/* EOF detected (end of file, or protocol-level EOF) */
+				return false;
+			}
 
-		if (fld_count != attr_count)
-			ereport(ERROR,
-					(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-					 errmsg("row field count is %d, expected %d",
-							(int) fld_count, attr_count)));
+			CHECK_FIELD_COUNT;
 
-		foreach(cur, cstate->attnumlist)
+			foreach(cur, cstate->attnumlist)
+			{
+				int			attnum = lfirst_int(cur);
+				int			m = attnum - 1;
+				Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+
+				cstate->cur_attname = NameStr(att->attname);
+				values[m] = CopyReadBinaryAttribute(cstate,
+													&in_functions[m],
+													typioparams[m],
+													att->atttypmod,
+													&nulls[m]);
+				cstate->cur_attname = NULL;
+			}
+		}
+		else
 		{
-			int			attnum = lfirst_int(cur);
-			int			m = attnum - 1;
-			Form_pg_attribute att = TupleDescAttr(tupDesc, m);
+			bool		eof = false;
 
-			cstate->cur_attname = NameStr(att->attname);
-			values[m] = CopyReadBinaryAttribute(cstate,
-												&in_functions[m],
-												typioparams[m],
-												att->atttypmod,
-												&nulls[m]);
-			cstate->cur_attname = NULL;
+			eof = CopyReadBinaryTupleWorker(cstate, values, nulls);
+			if (eof)
+				return false;
 		}
 	}
 
@@ -1673,18 +1672,14 @@ CopyReadBinaryAttribute(CopyFromState cstate, FmgrInfo *flinfo,
 	Datum		result;
 
 	if (!CopyGetInt32(cstate, &fld_size))
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("unexpected EOF in COPY data")));
+		EOF_ERROR;
+
 	if (fld_size == -1)
 	{
 		*isnull = true;
 		return ReceiveFunctionCall(flinfo, NULL, typioparam, typmod);
 	}
-	if (fld_size < 0)
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("invalid field size")));
+	CHECK_FIELD_SIZE(fld_size);
 
 	/* reset attribute_buf to empty, and load raw data in it */
 	resetStringInfo(&cstate->attribute_buf);
@@ -1692,9 +1687,7 @@ CopyReadBinaryAttribute(CopyFromState cstate, FmgrInfo *flinfo,
 	enlargeStringInfo(&cstate->attribute_buf, fld_size);
 	if (CopyReadBinaryData(cstate, cstate->attribute_buf.data,
 						   fld_size) != fld_size)
-		ereport(ERROR,
-				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
-				 errmsg("unexpected EOF in COPY data")));
+		EOF_ERROR;
 
 	cstate->attribute_buf.len = fld_size;
 	cstate->attribute_buf.data[fld_size] = '\0';
diff --git a/src/backend/commands/copyparallel.c b/src/backend/commands/copyparallel.c
index d46707d..5149798 100644
--- a/src/backend/commands/copyparallel.c
+++ b/src/backend/commands/copyparallel.c
@@ -615,6 +615,7 @@ InitializeParallelCopyInfo(CopyFromState cstate, List *attnamelist)
 	cstate->cur_lineno = 0;
 	cstate->cur_attname = NULL;
 	cstate->cur_attval = NULL;
+	cstate->pcdata->curr_data_block = NULL;
 
 	/* Set up variables to avoid per-attribute overhead. */
 	initStringInfo(&cstate->attribute_buf);
@@ -1050,37 +1051,61 @@ ParallelCopyFrom(CopyFromState cstate)
 	errcallback.previous = error_context_stack;
 	error_context_stack = &errcallback;
 
-	/* On input just throw the header line away. */
-	if (cstate->cur_lineno == 0 && cstate->opts.header_line)
+	if (!cstate->opts.binary)
 	{
-		cstate->cur_lineno++;
-		if (CopyReadLine(cstate))
+		/* On input just throw the header line away. */
+		if (cstate->cur_lineno == 0 && cstate->opts.header_line)
 		{
-			pcshared_info->is_read_in_progress = false;
-			return;				/* done */
+			cstate->cur_lineno++;
+			if (CopyReadLine(cstate))
+			{
+				pcshared_info->is_read_in_progress = false;
+				return;				/* done */
+			}
 		}
-	}
 
-	for (;;)
-	{
-		bool		done;
+		for (;;)
+		{
+			bool		done;
 
-		CHECK_FOR_INTERRUPTS();
+			CHECK_FOR_INTERRUPTS();
 
-		cstate->cur_lineno++;
+			cstate->cur_lineno++;
 
-		/* Actually read the line into memory here. */
-		done = CopyReadLine(cstate);
+			/* Actually read the line into memory here. */
+			done = CopyReadLine(cstate);
 
-		/*
-		 * EOF at start of line means we're done.  If we see EOF after some
-		 * characters, we act as though it was newline followed by EOF, ie,
-		 * process the line and then exit loop on next iteration.
-		 */
-		if (done && cstate->line_buf.len == 0)
-			break;
+			/*
+			 * EOF at start of line means we're done.  If we see EOF after
+			 * some characters, we act as though it was newline followed by
+			 * EOF, ie, process the line and then exit loop on next iteration.
+			 */
+			if (done && cstate->line_buf.len == 0)
+				break;
+		}
 	}
+	else
+	{
+		cstate->pcdata->curr_data_block = NULL;
+		cstate->raw_buf_index = 0;
+		pcshared_info->populated = 0;
+		cstate->cur_lineno = 0;
+		cstate->max_fields = list_length(cstate->attnumlist);
+
+		for (;;)
+		{
+			bool		eof = false;
+
+			CHECK_FOR_INTERRUPTS();
+
+			cstate->cur_lineno++;
+
+			eof = CopyReadBinaryTupleLeader(cstate);
 
+			if (eof)
+				break;
+		}
+	}
 
 	/* Done, clean up */
 	error_context_stack = errcallback.previous;
@@ -1097,6 +1122,289 @@ ParallelCopyFrom(CopyFromState cstate)
 }
 
 /*
+ * CopyReadBinaryGetDataBlock
+ *
+ * Gets a new block, updates the current offset, calculates the skip bytes.
+ */
+void
+CopyReadBinaryGetDataBlock(CopyFromState cstate, FieldInfoType field_info)
+{
+	ParallelCopyDataBlock *data_block = NULL;
+	ParallelCopyDataBlock *curr_data_block = cstate->pcdata->curr_data_block;
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	uint8		move_bytes = 0;
+	uint32		block_pos;
+	uint32		prev_block_pos;
+	int			read_bytes = 0;
+
+	prev_block_pos = pcshared_info->cur_block_pos;
+
+	block_pos = WaitGetFreeCopyBlock(pcshared_info);
+
+	if (field_info == FIELD_SIZE || field_info == FIELD_COUNT)
+		move_bytes = (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+
+	if (curr_data_block != NULL)
+		curr_data_block->skip_bytes = move_bytes;
+
+	data_block = &pcshared_info->data_blocks[block_pos];
+
+	if (move_bytes > 0 && curr_data_block != NULL)
+		memmove(&data_block->data[0], &curr_data_block->data[cstate->raw_buf_index], move_bytes);
+
+	elog(DEBUG1, "LEADER - field info %d is spread across data blocks - moved %d bytes from current block %u to %u block",
+		 field_info, move_bytes, prev_block_pos, block_pos);
+
+	read_bytes = CopyGetData(cstate, &data_block->data[move_bytes], 1, (DATA_BLOCK_SIZE - move_bytes));
+
+	if (field_info == FIELD_NONE && cstate->reached_eof)
+		return;
+
+	if (cstate->reached_eof)
+		EOF_ERROR;
+
+	elog(DEBUG1, "LEADER - bytes read from file %d", read_bytes);
+
+	if (field_info == FIELD_SIZE || field_info == FIELD_DATA)
+	{
+		ParallelCopyDataBlock *prev_data_block = NULL;
+
+		prev_data_block = curr_data_block;
+		prev_data_block->following_block = block_pos;
+
+		if (prev_data_block->curr_blk_completed == false)
+			prev_data_block->curr_blk_completed = true;
+
+		pg_atomic_add_fetch_u32(&prev_data_block->unprocessed_line_parts, 1);
+	}
+
+	cstate->pcdata->curr_data_block = data_block;
+	cstate->raw_buf_index = 0;
+}
+
+/*
+ * CopyReadBinaryTupleLeader
+ *
+ * Leader reads data from binary formatted file to data blocks and identifies
+ * tuple boundaries/offsets so that workers can work on the data blocks data.
+ */
+bool
+CopyReadBinaryTupleLeader(CopyFromState cstate)
+{
+	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	int16		fld_count;
+	uint32		line_size = 0;
+	uint32		start_block_pos;
+	uint32		start_offset;
+
+	if (cstate->pcdata->curr_data_block == NULL)
+	{
+		CopyReadBinaryGetDataBlock(cstate, FIELD_NONE);
+
+		/*
+		 * no data is read from file here. one possibility to be here could be
+		 * that the binary file just has a valid signature but nothing else.
+		 */
+		if (cstate->reached_eof)
+			return true;
+	}
+
+	if ((cstate->raw_buf_index + sizeof(fld_count)) >= DATA_BLOCK_SIZE)
+		CopyReadBinaryGetDataBlock(cstate, FIELD_COUNT);
+
+	memcpy(&fld_count, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_count));
+	fld_count = (int16) pg_ntoh16(fld_count);
+
+	CHECK_FIELD_COUNT;
+
+	start_offset = cstate->raw_buf_index;
+	cstate->raw_buf_index += sizeof(fld_count);
+	line_size += sizeof(fld_count);
+	start_block_pos = pcshared_info->cur_block_pos;
+
+	CopyReadBinaryFindTupleSize(cstate, &line_size);
+
+	pg_atomic_add_fetch_u32(&cstate->pcdata->curr_data_block->unprocessed_line_parts, 1);
+
+	if (line_size > 0)
+		(void) UpdateSharedLineInfo(cstate, start_block_pos, start_offset,
+									line_size, LINE_LEADER_POPULATED, -1);
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryFindTupleSize
+ *
+ * Leader identifies boundaries/offsets for each attribute/column and finally
+ * results in the tuple/row size. It moves on to next data block if the
+ * attribute/column is spread across data blocks.
+ */
+void
+CopyReadBinaryFindTupleSize(CopyFromState cstate, uint32 *line_size)
+{
+	int32		fld_size;
+	ListCell   *cur;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			att_num = lfirst_int(cur);
+		Form_pg_attribute att = TupleDescAttr(tup_desc, (att_num - 1));
+
+		cstate->cur_attname = NameStr(att->attname);
+		fld_size = 0;
+
+		if ((cstate->raw_buf_index + sizeof(fld_size)) >= DATA_BLOCK_SIZE)
+			CopyReadBinaryGetDataBlock(cstate, FIELD_SIZE);
+
+		memcpy(&fld_size, &cstate->pcdata->curr_data_block->data[cstate->raw_buf_index], sizeof(fld_size));
+		cstate->raw_buf_index += sizeof(fld_size);
+		*line_size += sizeof(fld_size);
+		fld_size = (int32) pg_ntoh32(fld_size);
+
+		/* fld_size -1 represents the null value for the field. */
+		if (fld_size == -1)
+			continue;
+
+		CHECK_FIELD_SIZE(fld_size);
+
+		*line_size += fld_size;
+
+		if ((DATA_BLOCK_SIZE - cstate->raw_buf_index) >= fld_size)
+		{
+			cstate->raw_buf_index += fld_size;
+			elog(DEBUG1, "LEADER - tuple lies in he same data block");
+		}
+		else
+		{
+			int32		required_blks = 0;
+			int32		curr_blk_bytes = (DATA_BLOCK_SIZE - cstate->raw_buf_index);
+			int			i = 0;
+
+			GET_REQUIRED_BLOCKS(required_blks, fld_size, curr_blk_bytes);
+
+			i = required_blks;
+
+			while (i > 0)
+			{
+				CopyReadBinaryGetDataBlock(cstate, FIELD_DATA);
+				i--;
+			}
+
+			GET_RAW_BUF_INDEX(cstate->raw_buf_index, fld_size, required_blks, curr_blk_bytes);
+
+			/*
+			 * raw_buf_index should never cross data block size, as the
+			 * required number of data blocks would have been obtained in the
+			 * above while loop.
+			 */
+			Assert(cstate->raw_buf_index <= DATA_BLOCK_SIZE);
+		}
+		cstate->cur_attname = NULL;
+	}
+}
+
+/*
+ * CopyReadBinaryTupleWorker
+ *
+ * Each worker reads data from data blocks caches the tuple data into local
+ * memory.
+ */
+bool
+CopyReadBinaryTupleWorker(CopyFromState cstate, Datum *values, bool *nulls)
+{
+	int16		fld_count;
+	ListCell   *cur;
+	FmgrInfo   *in_functions = cstate->in_functions;
+	Oid		   *typioparams = cstate->typioparams;
+	TupleDesc	tup_desc = RelationGetDescr(cstate->rel);
+	bool		done = false;
+
+	done = GetWorkerLine(cstate);
+	cstate->raw_buf_index = 0;
+
+	if (done && cstate->line_buf.len == 0)
+		return true;
+
+	memcpy(&fld_count, &cstate->line_buf.data[cstate->raw_buf_index], sizeof(fld_count));
+	fld_count = (int16) pg_ntoh16(fld_count);
+
+	CHECK_FIELD_COUNT;
+
+	cstate->raw_buf_index += sizeof(fld_count);
+
+	foreach(cur, cstate->attnumlist)
+	{
+		int			att_num = lfirst_int(cur);
+		int			m = att_num - 1;
+		Form_pg_attribute att = TupleDescAttr(tup_desc, m);
+
+		cstate->cur_attname = NameStr(att->attname);
+
+		values[m] = CopyReadBinaryAttributeWorker(cstate,
+												  &in_functions[m],
+												  typioparams[m],
+												  att->atttypmod,
+												  &nulls[m]);
+		cstate->cur_attname = NULL;
+	}
+
+	return false;
+}
+
+/*
+ * CopyReadBinaryAttributeWorker
+ *
+ * Worker identifies and converts each attribute/column data from binary to
+ * the data type of attribute/column.
+ */
+Datum
+CopyReadBinaryAttributeWorker(CopyFromState cstate, FmgrInfo *flinfo,
+							  Oid typioparam, int32 typmod, bool *isnull)
+{
+	int32		fld_size;
+	Datum		result;
+
+	memcpy(&fld_size, &cstate->line_buf.data[cstate->raw_buf_index], sizeof(fld_size));
+	cstate->raw_buf_index += sizeof(fld_size);
+	fld_size = (int32) pg_ntoh32(fld_size);
+
+	/* fld_size -1 represents the null value for the field. */
+	if (fld_size == -1)
+	{
+		*isnull = true;
+		return ReceiveFunctionCall(flinfo, NULL, typioparam, typmod);
+	}
+
+	CHECK_FIELD_SIZE(fld_size);
+
+	/* Reset attribute_buf to empty, and load raw data in it */
+	resetStringInfo(&cstate->attribute_buf);
+
+	enlargeStringInfo(&cstate->attribute_buf, fld_size);
+
+	memcpy(&cstate->attribute_buf.data[0], &cstate->line_buf.data[cstate->raw_buf_index], fld_size);
+	cstate->raw_buf_index += fld_size;
+
+	cstate->attribute_buf.len = fld_size;
+	cstate->attribute_buf.data[fld_size] = '\0';
+
+	/* Call the column type's binary input converter */
+	result = ReceiveFunctionCall(flinfo, &cstate->attribute_buf,
+								 typioparam, typmod);
+
+	/* Trouble if it didn't eat the whole buffer */
+	if (cstate->attribute_buf.cursor != cstate->attribute_buf.len)
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+				 errmsg("incorrect binary data format")));
+
+	*isnull = false;
+	return result;
+}
+
+/*
  * GetLinePosition
  *
  * Return the line position once the leader has populated the data.
diff --git a/src/include/commands/copyfrom_internal.h b/src/include/commands/copyfrom_internal.h
index d44f2b5..67cf775 100644
--- a/src/include/commands/copyfrom_internal.h
+++ b/src/include/commands/copyfrom_internal.h
@@ -58,6 +58,109 @@
 #define IsWorker()				(IsParallelCopy() && !IsLeader())
 
 /*
+ * CHECK_FIELD_COUNT - Handles the error cases for field count
+ * for binary format files.
+ */
+#define CHECK_FIELD_COUNT \
+{\
+	if (fld_count == -1) \
+	{ \
+		if (IsParallelCopy() && \
+			!IsLeader()) \
+			return true; \
+		else if (IsParallelCopy() && \
+			IsLeader()) \
+		{ \
+			if (cstate->pcdata->curr_data_block->data[cstate->raw_buf_index + sizeof(fld_count)] != 0) \
+				ereport(ERROR, \
+						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+						errmsg("received copy data after EOF marker"))); \
+			return true; \
+		} \
+		else \
+		{ \
+			/* \
+			 * Received EOF marker.  In a V3-protocol copy, wait for the \
+			 * protocol-level EOF, and complain if it doesn't come \
+			 * immediately.  This ensures that we correctly handle CopyFail, \
+			 * if client chooses to send that now. \
+			 * \
+			 * Note that we MUST NOT try to read more data in an old-protocol \
+			 * copy, since there is no protocol-level EOF marker then.  We \
+			 * could go either way for copy from file, but choose to throw \
+			 * error if there's data after the EOF marker, for consistency \
+			 * with the new-protocol case. \
+			 */ \
+			char		dummy; \
+			if (cstate->copy_src != COPY_OLD_FE && \
+				CopyReadBinaryData(cstate, &dummy, 1) > 0) \
+				ereport(ERROR, \
+						(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+						errmsg("received copy data after EOF marker"))); \
+				return false; \
+		} \
+	} \
+	if (fld_count != cstate->max_fields) \
+		ereport(ERROR, \
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+				errmsg("row field count is %d, expected %d", \
+				(int) fld_count, cstate->max_fields))); \
+}
+
+/*
+ * CHECK_FIELD_SIZE - Handles the error case for field size
+ * for binary format files.
+ */
+#define CHECK_FIELD_SIZE(fld_size) \
+{ \
+	if (fld_size < -1) \
+		ereport(ERROR, \
+				(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+				errmsg("invalid field size")));\
+}
+
+/*
+ * EOF_ERROR - Error statement for EOF for binary format
+ * files.
+ */
+#define EOF_ERROR \
+{ \
+	ereport(ERROR, \
+		(errcode(ERRCODE_BAD_COPY_FILE_FORMAT), \
+		errmsg("unexpected EOF in COPY data")));\
+}
+
+/*
+ * GET_RAW_BUF_INDEX - Calculates the raw buf index for the cases
+ * where the data spread is across multiple data blocks.
+ */
+#define GET_RAW_BUF_INDEX(raw_buf_index, fld_size, required_blks, curr_blk_bytes) \
+{ \
+	raw_buf_index = fld_size - (((required_blks - 1) * DATA_BLOCK_SIZE) + curr_blk_bytes); \
+}
+
+/*
+ * GET_REQUIRED_BLOCKS - Calculates the number of data
+ * blocks required for the cases where the data spread
+ * is across multiple data blocks.
+ */
+#define GET_REQUIRED_BLOCKS(required_blks, fld_size, curr_blk_bytes) \
+{ \
+	/* \
+	 * field size can spread across multiple data blocks, \
+	 * calculate the number of required data blocks and try to get \
+	 * those many data blocks. \
+	 */ \
+	required_blks = (int32)(fld_size - curr_blk_bytes)/(int32)DATA_BLOCK_SIZE; \
+	/* \
+	 * check if we need the data block for the field data \
+	 * bytes that are not modulus of data block size. \
+	 */ \
+	if ((fld_size - curr_blk_bytes)%DATA_BLOCK_SIZE != 0) \
+		required_blks++; \
+}
+
+/*
  * Represents the different source cases we need to worry about at
  * the bottom level
  */
@@ -241,6 +344,17 @@ typedef struct ParallelCopyLineBuf
 } ParallelCopyLineBuf;
 
 /*
+ * Represents the usage mode for CopyReadBinaryGetDataBlock.
+ */
+typedef enum FieldInfoType
+{
+	FIELD_NONE = 0,
+	FIELD_COUNT,
+	FIELD_SIZE,
+	FIELD_DATA
+}			FieldInfoType;
+
+/*
  * This structure helps in storing the common List/Node from CopyStateData that
  * are required by the workers. This information will then be copied and stored
  * into the DSM for the worker to retrieve and copy it to CopyStateData.
@@ -279,6 +393,9 @@ typedef struct ParallelCopyData
 
 	/* Current position in worker_line_buf */
 	uint32		worker_line_buf_pos;
+
+	/* For binary formatted files */
+	ParallelCopyDataBlock *curr_data_block;
 } ParallelCopyData;
 
 
@@ -417,4 +534,14 @@ extern uint32 UpdateSharedLineInfo(CopyFromState cstate, uint32 blk_pos, uint32
 								   uint32 line_size, uint32 line_state, uint32 blk_line_pos);
 extern void EndLineParallelCopy(CopyFromState cstate, uint32 line_pos, uint32 line_size,
 								uint32 raw_buf_ptr);
+
+extern int	CopyGetData(CopyFromState cstate, void *databuf, int minread, int maxread);
+extern int	CopyReadBinaryData(CopyFromState cstate, char *dest, int nbytes);
+extern bool CopyReadBinaryTupleLeader(CopyFromState cstate);
+extern bool CopyReadBinaryTupleWorker(CopyFromState cstate, Datum *values, bool *nulls);
+extern void CopyReadBinaryFindTupleSize(CopyFromState cstate, uint32 *line_size);
+extern Datum CopyReadBinaryAttributeWorker(CopyFromState cstate, FmgrInfo *flinfo,
+										   Oid typioparam, int32 typmod, bool *isnull);
+extern void CopyReadBinaryGetDataBlock(CopyFromState cstate, FieldInfoType field_info);
+
 #endif							/* COPYFROM_INTERNAL_H */
-- 
1.8.3.1

v11-0006-Tests-for-parallel-copy.patchtext/x-patch; charset=US-ASCII; name=v11-0006-Tests-for-parallel-copy.patchDownload
From d4be261350ac38278cb90973d395f3fc96aec396 Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Wed, 18 Nov 2020 07:58:58 +0530
Subject: [PATCH v11 6/6] Tests for parallel copy.

This patch has the tests for parallel copy.
---
 contrib/postgres_fdw/expected/postgres_fdw.out |  48 ++++
 contrib/postgres_fdw/sql/postgres_fdw.sql      |  52 ++++
 src/test/regress/expected/copy2.out            | 324 +++++++++++++++++++++-
 src/test/regress/input/copy.source             |  31 +++
 src/test/regress/output/copy.source            |  27 ++
 src/test/regress/sql/copy2.sql                 | 369 ++++++++++++++++++++++++-
 6 files changed, 843 insertions(+), 8 deletions(-)

diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out
index 2d88d06..1e78b6a 100644
--- a/contrib/postgres_fdw/expected/postgres_fdw.out
+++ b/contrib/postgres_fdw/expected/postgres_fdw.out
@@ -9033,5 +9033,53 @@ SELECT 1 FROM ft1 LIMIT 1;    -- should fail
 ERROR:  08006
 \set VERBOSITY default
 COMMIT;
+-- parallel copy related tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+CREATE FOREIGN TABLE test_parallel_copy_ft (
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+) SERVER loopback OPTIONS (table_name 'test_parallel_copy') ;
+-- parallel copy into foreign table, parallelism must not be picked up.
+COPY test_parallel_copy_ft FROM stdin WITH (PARALLEL 1);
+SELECT count(*) FROM test_parallel_copy_ft;
+ count 
+-------
+     2
+(1 row)
+
+-- parallel copy into a table with foreign partition.
+CREATE TABLE part_test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+) PARTITION BY LIST (b);
+CREATE FOREIGN TABLE part_test_parallel_copy_a1 (c TEXT, b INT, a INT, e TEXT, d TEXT) SERVER loopback;
+CREATE TABLE part_test_parallel_copy_a2 (a INT, c TEXT, b INT, d TEXT, e TEXT);
+ALTER TABLE part_test_parallel_copy ATTACH PARTITION part_test_parallel_copy_a1 FOR VALUES IN(1);
+ALTER TABLE part_test_parallel_copy ATTACH PARTITION part_test_parallel_copy_a2 FOR VALUES IN(2);
+-- Verify that sequential copy is choosen by checking error in not from a parallel worker.
+COPY part_test_parallel_copy FROM stdin WITH (PARALLEL 1);
+ERROR:  extra data after last expected column
+CONTEXT:  COPY part_test_parallel_copy, line 1: "1	1	test_c1	test_d1	test_e1	test_nonexistent1"
+SELECT count(*) FROM part_test_parallel_copy WHERE b = 2;
+ count 
+-------
+     0
+(1 row)
+
 -- Clean up
 DROP PROCEDURE terminate_backend_and_wait(text);
+DROP FOREIGN TABLE test_parallel_copy_ft;
+DROP TABLE test_parallel_copy;
+DROP TABLE part_test_parallel_copy;
diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql
index 7581c54..f804e4c 100644
--- a/contrib/postgres_fdw/sql/postgres_fdw.sql
+++ b/contrib/postgres_fdw/sql/postgres_fdw.sql
@@ -2695,5 +2695,57 @@ SELECT 1 FROM ft1 LIMIT 1;    -- should fail
 \set VERBOSITY default
 COMMIT;
 
+-- parallel copy related tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+
+CREATE FOREIGN TABLE test_parallel_copy_ft (
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+) SERVER loopback OPTIONS (table_name 'test_parallel_copy') ;
+
+-- parallel copy into foreign table, parallelism must not be picked up.
+COPY test_parallel_copy_ft FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+SELECT count(*) FROM test_parallel_copy_ft;
+
+-- parallel copy into a table with foreign partition.
+CREATE TABLE part_test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+) PARTITION BY LIST (b);
+
+CREATE FOREIGN TABLE part_test_parallel_copy_a1 (c TEXT, b INT, a INT, e TEXT, d TEXT) SERVER loopback;
+
+CREATE TABLE part_test_parallel_copy_a2 (a INT, c TEXT, b INT, d TEXT, e TEXT);
+
+ALTER TABLE part_test_parallel_copy ATTACH PARTITION part_test_parallel_copy_a1 FOR VALUES IN(1);
+
+ALTER TABLE part_test_parallel_copy ATTACH PARTITION part_test_parallel_copy_a2 FOR VALUES IN(2);
+
+-- Verify that sequential copy is choosen by checking error in not from a parallel worker.
+COPY part_test_parallel_copy FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1	test_nonexistent1
+\.
+
+SELECT count(*) FROM part_test_parallel_copy WHERE b = 2;
+
 -- Clean up
 DROP PROCEDURE terminate_backend_and_wait(text);
+DROP FOREIGN TABLE test_parallel_copy_ft;
+DROP TABLE test_parallel_copy;
+DROP TABLE part_test_parallel_copy;
diff --git a/src/test/regress/expected/copy2.out b/src/test/regress/expected/copy2.out
index c64f071..22274cb 100644
--- a/src/test/regress/expected/copy2.out
+++ b/src/test/regress/expected/copy2.out
@@ -301,18 +301,32 @@ It is "perfect".|
 "It is ""perfect"".","	"
 "",
 --test that we read consecutive LFs properly
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 COPY testnl FROM stdin CSV;
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+SELECT * FROM testnl;
+ a |          b           | c 
+---+----------------------+---
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+ 1 | a field with two LFs+| 2
+   |                     +| 
+   | inside               | 
+(2 rows)
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 COPY testeoc FROM stdin CSV;
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
 COPY testeoc TO stdout CSV;
 a\.
 \.b
 c\.d
 "\."
 -- test handling of nonstandard null marker that violates escaping rules
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 COPY testnull TO stdout WITH NULL AS E'\\0';
 1	\\0
@@ -327,6 +341,15 @@ SELECT * FROM testnull;
     | 
 (4 rows)
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 1);
+SELECT * FROM testnull;
+ a  | b  
+----+----
+ 42 | \0
+    | 
+(2 rows)
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -396,6 +419,34 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+SELECT * FROM vistest;
+ a  
+----
+ a2
+ b
+(2 rows)
+
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+COMMIT;
+SELECT * FROM vistest;
+ a  
+----
+ d2
+ e
+(2 rows)
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 SELECT * FROM vistest;
  a 
@@ -456,7 +507,7 @@ SELECT * FROM vistest;
 (2 rows)
 
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -467,6 +518,8 @@ CREATE TEMP TABLE forcetest (
 -- should succeed with no effect ("b" remains an empty string, "c" remains NULL)
 BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 1);
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
  b |  c   
@@ -477,6 +530,8 @@ SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
 BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 1);
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
  c |  d   
@@ -533,6 +588,30 @@ select * from check_con_tbl;
    
 (2 rows)
 
+\d+ check_con_tbl
+                               Table "public.check_con_tbl"
+ Column |  Type   | Collation | Nullable | Default | Storage | Stats target | Description 
+--------+---------+-----------+----------+---------+---------+--------------+-------------
+ f1     | integer |           |          |         | plain   |              | 
+Check constraints:
+    "check_con_tbl_check" CHECK (check_con_function(check_con_tbl.*))
+
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 1);
+NOTICE:  input = {"f1":1}
+NOTICE:  input = {"f1":null}
+copy check_con_tbl from stdin with (parallel 1);
+NOTICE:  input = {"f1":0}
+ERROR:  new row for relation "check_con_tbl" violates check constraint "check_con_tbl_check"
+DETAIL:  Failing row contains (0).
+CONTEXT:  COPY check_con_tbl, line 1: "0"
+select * from check_con_tbl;
+ f1 
+----
+  1
+   
+(2 rows)
+
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
 CREATE ROLE regress_rls_copy_user_colperms;
@@ -647,10 +726,247 @@ SELECT * FROM instead_of_insert_tbl;
 (2 rows)
 
 COMMIT;
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+COPY test_parallel_copy (a, b, c, d, e) FROM stdin WITH (PARALLEL 1);
+COPY test_parallel_copy (b, d) FROM stdin WITH (PARALLEL 1);
+COPY test_parallel_copy (b, d) FROM stdin WITH (PARALLEL 1);
+COPY test_parallel_copy (b, d) FROM stdin WITH (PARALLEL 1, FORMAT 'csv', HEADER);
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) FROM stdin WITH (PARALLEL 0);
+ERROR:  value 0 out of bounds for option "parallel"
+DETAIL:  Valid values are between "1" and "1024".
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri FROM stdin WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1) WHERE height > random() * 65;
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+-- temporary table copy: should perform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+COPY temp_test (a) FROM stdin WITH (PARALLEL 1);
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) FROM stdin WITH (PARALLEL 1);
+ERROR:  column "xyz" of relation "test_parallel_copy" does not exist
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) FROM stdin WITH (PARALLEL 1);
+ERROR:  column "d" specified more than once
+-- missing data: should fail
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+ERROR:  invalid input syntax for type integer: ""
+CONTEXT:  COPY test_parallel_copy, line 0, column a: ""
+parallel worker
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2000	230	23	23"
+parallel worker
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+ERROR:  missing data for column "e"
+CONTEXT:  COPY test_parallel_copy, line 1: "2001	231	\N	\N"
+parallel worker
+-- extra data: should fail
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+ERROR:  extra data after last expected column
+CONTEXT:  COPY test_parallel_copy, line 1: "2002	232	40	50	60	70	80"
+parallel worker
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) FROM stdin WITH (DELIMITER ',', null 'x', PARALLEL 1) ;
+COPY test_parallel_copy FROM stdin WITH (DELIMITER ';', NULL '', PARALLEL 1);
+COPY test_parallel_copy FROM stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL 1);
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a = 50004;
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a > 60003;
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE f > 60003;
+ERROR:  column "f" does not exist
+LINE 1: ..._parallel_copy FROM stdin WITH (PARALLEL 1) WHERE f > 60003;
+                                                             ^
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+ERROR:  missing FROM-clause entry for table "x"
+LINE 1: ...rallel_copy FROM stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+                                                                  ^
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a IN (SELECT 1 FROM x);
+ERROR:  cannot use subquery in COPY FROM WHERE condition
+LINE 1: ...arallel_copy FROM stdin WITH (PARALLEL 1) WHERE a IN (SELECT...
+                                                             ^
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a IN (generate_series(1,5));
+ERROR:  set-returning functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...lel_copy FROM stdin WITH (PARALLEL 1) WHERE a IN (generate_s...
+                                                             ^
+COPY test_parallel_copy FROM stdin WITH(PARALLEL 1) WHERE a = row_number() over(b);
+ERROR:  window functions are not allowed in COPY FROM WHERE conditions
+LINE 1: ...rallel_copy FROM stdin WITH(PARALLEL 1) WHERE a = row_number...
+                                                             ^
+-- check results of copy in
+SELECT * FROM test_parallel_copy ORDER BY 1;
+   a   | b  |     c      |    d    |    e    
+-------+----+------------+---------+---------
+     1 | 11 | test_c1    | test_d1 | test_e1
+     2 | 12 | test_c2    | test_d2 | test_e2
+  3000 |    | c          |         | 
+  4000 |    | C          |         | 
+  4001 |  1 | empty      |         | 
+  4002 |  2 | null       |         | 
+  4003 |  3 | Backslash  | \       | \
+  4004 |  4 | BackslashX | \X      | \X
+  4005 |  5 | N          | N       | N
+  4006 |  6 | BackslashN | \N      | \N
+  4007 |  7 | XX         | XX      | XX
+  4008 |  8 | Delimiter  | :       | :
+ 50004 | 25 | 35         | 45      | 55
+ 60004 | 25 | 35         | 45      | 55
+ 60005 | 26 | 36         | 46      | 56
+       |  3 | stuff      | test_d3 | 
+       |  4 | stuff      | test_d4 | 
+       |  5 | stuff      | test_d5 | 
+       |    | ,          | \,      | \
+       |    | x          | \x      | \x
+       |    | 45         | 80      | 90
+(21 rows)
+
+-- parallel copy test for unlogged tables. should execute in parallel worker
+CREATE UNLOGGED TABLE test_parallel_copy_unlogged(
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+);
+COPY test_parallel_copy_unlogged FROM stdin WITH (PARALLEL 1);
+SELECT count(*) FROM test_parallel_copy_unlogged;
+ count 
+-------
+     2
+(1 row)
+
+-- parallel copy test for various trigger types
+TRUNCATE test_parallel_copy;
+-- parallel safe trigger function
+CREATE OR REPLACE FUNCTION parallel_copy_trig_func() RETURNS TRIGGER
+LANGUAGE plpgsql PARALLEL SAFE AS $$
+BEGIN
+  RETURN NEW;
+END;
+$$;
+-- before insert row trigger
+CREATE TRIGGER parallel_copy_trig
+BEFORE INSERT ON test_parallel_copy
+FOR EACH ROW
+EXECUTE PROCEDURE parallel_copy_trig_func();
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+-- after insert row trigger
+CREATE TRIGGER parallel_copy_trig
+AFTER INSERT ON test_parallel_copy
+FOR EACH ROW
+EXECUTE PROCEDURE parallel_copy_trig_func();
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+-- before insert statement trigger
+CREATE TRIGGER parallel_copy_trig
+BEFORE INSERT ON test_parallel_copy
+FOR EACH STATEMENT
+EXECUTE PROCEDURE parallel_copy_trig_func();
+-- parallelism should be picked, since the trigger function is parallel safe
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+-- after insert statement trigger
+CREATE TRIGGER parallel_copy_trig
+AFTER INSERT ON test_parallel_copy
+FOR EACH STATEMENT
+EXECUTE PROCEDURE parallel_copy_trig_func();
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+-- transition table is involved
+CREATE TRIGGER parallel_copy_trig
+AFTER INSERT ON test_parallel_copy REFERENCING NEW TABLE AS new_table
+FOR EACH STATEMENT
+EXECUTE PROCEDURE parallel_copy_trig_func();
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+-- make trigger function parallel unsafe
+ALTER FUNCTION parallel_copy_trig_func PARALLEL UNSAFE;
+-- before statement trigger has a parallel unsafe function
+CREATE TRIGGER parallel_copy_trig
+BEFORE INSERT ON test_parallel_copy
+FOR EACH STATEMENT
+EXECUTE PROCEDURE parallel_copy_trig_func();
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+SELECT count(*) FROM test_parallel_copy;
+ count 
+-------
+    12
+(1 row)
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+-- instead of insert trigger, no parallelism should be picked
+COPY instead_of_insert_tbl_view FROM stdin WITH(PARALLEL 1);;
+SELECT count(*) FROM instead_of_insert_tbl_view;
+ count 
+-------
+     1
+(1 row)
+
+-- parallel copy test for a partitioned table with a before insert trigger on
+-- one of the partition
+ALTER FUNCTION parallel_copy_trig_func PARALLEL SAFE;
+CREATE TABLE test_parallel_copy_part (
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+) PARTITION BY LIST (b);
+CREATE TABLE test_parallel_copy_part_a1 (c TEXT, b INT, a INT, e TEXT, d TEXT);
+CREATE TABLE test_parallel_copy_part_a2 (a INT, c TEXT, b INT, d TEXT, e TEXT);
+ALTER TABLE test_parallel_copy_part ATTACH PARTITION test_parallel_copy_part_a1 FOR VALUES IN(1);
+ALTER TABLE test_parallel_copy_part ATTACH PARTITION test_parallel_copy_part_a2 FOR VALUES IN(2);
+CREATE TRIGGER parallel_copy_trig
+BEFORE INSERT ON test_parallel_copy_part_a2
+FOR EACH ROW
+EXECUTE PROCEDURE parallel_copy_trig_func();
+-- Verify that sequential copy is choosen by checking error in not from a parallel worker.
+COPY test_parallel_copy_part FROM stdin WITH (PARALLEL 1);
+ERROR:  extra data after last expected column
+CONTEXT:  COPY test_parallel_copy_part, line 2: "2	2	test_c2	test_d2	test_e2	test_ne2"
+SELECT count(*) FROM test_parallel_copy_part;
+ count 
+-------
+     0
+(1 row)
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy_part_a2;
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE test_parallel_copy_unlogged;
+DROP TABLE test_parallel_copy_part;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
+DROP FUNCTION parallel_copy_trig_func();
 DROP TABLE x, y;
 DROP TABLE rls_t1 CASCADE;
 DROP ROLE regress_rls_copy_user;
diff --git a/src/test/regress/input/copy.source b/src/test/regress/input/copy.source
index a1d529a..cb39c66 100644
--- a/src/test/regress/input/copy.source
+++ b/src/test/regress/input/copy.source
@@ -15,6 +15,13 @@ DELETE FROM onek;
 
 COPY onek FROM '@abs_builddir@/results/onek.data';
 
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+
+SELECT COUNT(*) FROM tenk1;
+
+TRUNCATE tenk1;
+
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
@@ -159,6 +166,30 @@ truncate parted_copytest;
 
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
 
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
+
+-- Test parallel copy from for toast table with csv and binary format file
+create table test_parallel_copy_toast(a1 int, b1 text, c1 text default null);
+
+insert into test_parallel_copy_toast select i, (repeat(md5(i::text), 100000)) FROM generate_series(1,2) AS i;
+
+copy test_parallel_copy_toast to '@abs_builddir@/results/parallelcopytoast.csv' with(format csv);
+
+copy test_parallel_copy_toast to '@abs_builddir@/results/parallelcopytoast.dat' with(format binary);
+
+truncate test_parallel_copy_toast;
+
+copy test_parallel_copy_toast from '@abs_builddir@/results/parallelcopytoast.csv' with(format csv, parallel 2);
+
+copy test_parallel_copy_toast from '@abs_builddir@/results/parallelcopytoast.dat' with(format binary, parallel 2);
+
+select count(*) from test_parallel_copy_toast;
+
+drop table test_parallel_copy_toast;
+
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/output/copy.source b/src/test/regress/output/copy.source
index 938d355..a5dca79 100644
--- a/src/test/regress/output/copy.source
+++ b/src/test/regress/output/copy.source
@@ -9,6 +9,15 @@ COPY onek FROM '@abs_srcdir@/data/onek.data';
 COPY onek TO '@abs_builddir@/results/onek.data';
 DELETE FROM onek;
 COPY onek FROM '@abs_builddir@/results/onek.data';
+-- test parallel copy
+COPY tenk1 FROM '@abs_srcdir@/data/tenk.data' WITH (parallel 2);
+SELECT COUNT(*) FROM tenk1;
+ count 
+-------
+ 10000
+(1 row)
+
+TRUNCATE tenk1;
 COPY tenk1 FROM '@abs_srcdir@/data/tenk.data';
 COPY slow_emp4000 FROM '@abs_srcdir@/data/rect.data';
 COPY person FROM '@abs_srcdir@/data/person.data';
@@ -113,6 +122,24 @@ insert into parted_copytest select x,1,'One' from generate_series(1011,1020) x;
 copy (select * from parted_copytest order by a) to '@abs_builddir@/results/parted_copytest.csv';
 truncate parted_copytest;
 copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv';
+-- Test parallel copy from with a partitioned table.
+truncate parted_copytest;
+copy parted_copytest from '@abs_builddir@/results/parted_copytest.csv' with (parallel 2);
+-- Test parallel copy from for toast table with csv and binary format file
+create table test_parallel_copy_toast(a1 int, b1 text, c1 text default null);
+insert into test_parallel_copy_toast select i, (repeat(md5(i::text), 100000)) FROM generate_series(1,2) AS i;
+copy test_parallel_copy_toast to '@abs_builddir@/results/parallelcopytoast.csv' with(format csv);
+copy test_parallel_copy_toast to '@abs_builddir@/results/parallelcopytoast.dat' with(format binary);
+truncate test_parallel_copy_toast;
+copy test_parallel_copy_toast from '@abs_builddir@/results/parallelcopytoast.csv' with(format csv, parallel 2);
+copy test_parallel_copy_toast from '@abs_builddir@/results/parallelcopytoast.dat' with(format binary, parallel 2);
+select count(*) from test_parallel_copy_toast;
+ count 
+-------
+     4
+(1 row)
+
+drop table test_parallel_copy_toast;
 -- Ensure COPY FREEZE errors for partitioned tables.
 begin;
 truncate parted_copytest;
diff --git a/src/test/regress/sql/copy2.sql b/src/test/regress/sql/copy2.sql
index b3c16af..ebca6e6 100644
--- a/src/test/regress/sql/copy2.sql
+++ b/src/test/regress/sql/copy2.sql
@@ -171,7 +171,7 @@ COPY y TO stdout (FORMAT CSV, FORCE_QUOTE *);
 
 --test that we read consecutive LFs properly
 
-CREATE TEMP TABLE testnl (a int, b text, c int);
+CREATE TABLE testnl (a int, b text, c int);
 
 COPY testnl FROM stdin CSV;
 1,"a field with two LFs
@@ -179,8 +179,16 @@ COPY testnl FROM stdin CSV;
 inside",2
 \.
 
+COPY testnl FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+1,"a field with two LFs
+
+inside",2
+\.
+
+SELECT * FROM testnl;
+
 -- test end of copy marker
-CREATE TEMP TABLE testeoc (a text);
+CREATE TABLE testeoc (a text);
 
 COPY testeoc FROM stdin CSV;
 a\.
@@ -189,11 +197,19 @@ c\.d
 "\."
 \.
 
+TRUNCATE testeoc;
+COPY testeoc FROM stdin WITH (FORMAT 'csv', PARALLEL 1);
+a\.
+\.b
+c\.d
+"\."
+\.
+
 COPY testeoc TO stdout CSV;
 
 -- test handling of nonstandard null marker that violates escaping rules
 
-CREATE TEMP TABLE testnull(a int, b text);
+CREATE TABLE testnull(a int, b text);
 INSERT INTO testnull VALUES (1, E'\\0'), (NULL, NULL);
 
 COPY testnull TO stdout WITH NULL AS E'\\0';
@@ -205,6 +221,14 @@ COPY testnull FROM stdin WITH NULL AS E'\\0';
 
 SELECT * FROM testnull;
 
+TRUNCATE testnull;
+COPY testnull FROM stdin WITH (NULL E'\\0', PARALLEL 1);
+42	\\0
+\0	\0
+\.
+
+SELECT * FROM testnull;
+
 BEGIN;
 CREATE TABLE vistest (LIKE testeoc);
 COPY vistest FROM stdin CSV;
@@ -249,6 +273,23 @@ SELECT * FROM vistest;
 
 BEGIN;
 TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+a2
+b
+\.
+SELECT * FROM vistest;
+SAVEPOINT s1;
+TRUNCATE vistest;
+COPY vistest FROM stdin WITH (FORMAT 'csv', FREEZE, PARALLEL 1);
+d2
+e
+\.
+SELECT * FROM vistest;
+COMMIT;
+SELECT * FROM vistest;
+
+BEGIN;
+TRUNCATE vistest;
 COPY vistest FROM stdin CSV FREEZE;
 x
 y
@@ -298,7 +339,7 @@ SELECT * FROM vistest;
 COMMIT;
 SELECT * FROM vistest;
 -- Test FORCE_NOT_NULL and FORCE_NULL options
-CREATE TEMP TABLE forcetest (
+CREATE TABLE forcetest (
     a INT NOT NULL,
     b TEXT NOT NULL,
     c TEXT,
@@ -311,6 +352,10 @@ BEGIN;
 COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c));
 1,,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(b), FORCE_NULL(c), PARALLEL 1);
+1,,""
+\.
 COMMIT;
 SELECT b, c FROM forcetest WHERE a = 1;
 -- should succeed, FORCE_NULL and FORCE_NOT_NULL can be both specified
@@ -318,6 +363,10 @@ BEGIN;
 COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d));
 2,'a',,""
 \.
+TRUNCATE forcetest;
+COPY forcetest (a, b, c, d) FROM STDIN WITH (FORMAT csv, FORCE_NOT_NULL(c,d), FORCE_NULL(c,d), PARALLEL 1);
+2,'a',,""
+\.
 COMMIT;
 SELECT c, d FROM forcetest WHERE a = 2;
 -- should fail with not-null constraint violation
@@ -353,6 +402,16 @@ copy check_con_tbl from stdin;
 0
 \.
 select * from check_con_tbl;
+\d+ check_con_tbl
+truncate check_con_tbl;
+copy check_con_tbl from stdin with (parallel 1);
+1
+\N
+\.
+copy check_con_tbl from stdin with (parallel 1);
+0
+\.
+select * from check_con_tbl;
 
 -- test with RLS enabled.
 CREATE ROLE regress_rls_copy_user;
@@ -454,10 +513,312 @@ test1
 SELECT * FROM instead_of_insert_tbl;
 COMMIT;
 
+-- Parallel copy tests.
+CREATE TABLE test_parallel_copy (
+        a INT,
+        b INT,
+        c TEXT not null default 'stuff',
+        d TEXT,
+        e TEXT
+) ;
+
+COPY test_parallel_copy (a, b, c, d, e) FROM stdin WITH (PARALLEL 1);
+1	11	test_c1	test_d1	test_e1
+2	12	test_c2	test_d2	test_e2
+\.
+
+COPY test_parallel_copy (b, d) FROM stdin WITH (PARALLEL 1);
+3	test_d3
+\.
+
+COPY test_parallel_copy (b, d) FROM stdin WITH (PARALLEL 1);
+4	test_d4
+5	test_d5
+\.
+
+COPY test_parallel_copy (b, d) FROM stdin WITH (PARALLEL 1, FORMAT 'csv', HEADER);
+b	d
+\.
+
+-- zero workers: should perform non-parallel copy
+COPY test_parallel_copy (b, d) FROM stdin WITH (PARALLEL 0);
+
+-- referencing table: should perform non-parallel copy
+CREATE TABLE test_copy_pk(c1 INT PRIMARY KEY);
+INSERT INTO test_copy_pk VALUES(10);
+CREATE TABLE test_copy_ri(c1 INT REFERENCES test_copy_pk(c1));
+COPY test_copy_ri FROM stdin WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+10
+\.
+
+-- expressions: should perform non-parallel copy
+CREATE TABLE test_copy_expr (index INT, height REAL, weight REAL);
+
+COPY test_copy_expr FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1) WHERE height > random() * 65;
+60,60,60
+\.
+
+-- serial data: should perform non-parallel copy
+CREATE TABLE testserial (index SERIAL, height REAL);
+
+COPY testserial(height) FROM STDIN WITH (FORMAT csv, DELIMITER ',', PARALLEL 1);
+60
+\.
+
+-- temporary table copy: should perform non-parallel copy
+CREATE TEMPORARY TABLE temp_test(
+        a int
+) ;
+
+COPY temp_test (a) FROM stdin WITH (PARALLEL 1);
+10
+\.
+
+-- non-existent column in column list: should fail
+COPY test_parallel_copy (xyz) FROM stdin WITH (PARALLEL 1);
+
+-- too many columns in column list: should fail
+COPY test_parallel_copy (a, b, c, d, e, d, c) FROM stdin WITH (PARALLEL 1);
+
+-- missing data: should fail
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+
+\.
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+2000	230	23	23
+\.
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+2001	231	\N	\N
+\.
+
+-- extra data: should fail
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+2002	232	40	50	60	70	80
+\.
+
+-- various COPY options: delimiters, oids, NULL string, encoding
+COPY test_parallel_copy (b, c, d, e) FROM stdin WITH (DELIMITER ',', null 'x', PARALLEL 1) ;
+x,45,80,90
+x,\x,\\x,\\\x
+x,\,,\\\,,\\
+\.
+
+COPY test_parallel_copy FROM stdin WITH (DELIMITER ';', NULL '', PARALLEL 1);
+3000;;c;;
+\.
+
+COPY test_parallel_copy FROM stdin WITH (DELIMITER ':', NULL E'\\X', ENCODING 'sql_ascii', PARALLEL 1);
+4000:\X:C:\X:\X
+4001:1:empty::
+4002:2:null:\X:\X
+4003:3:Backslash:\\:\\
+4004:4:BackslashX:\\X:\\X
+4005:5:N:\N:\N
+4006:6:BackslashN:\\N:\\N
+4007:7:XX:\XX:\XX
+4008:8:Delimiter:\::\:
+\.
+
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a = 50004;
+50003	24	34	44	54
+50004	25	35	45 	55
+50005	26	36	46	56
+\.
+
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a > 60003;
+60001	22	32	42	52
+60002	23	33	43	53
+60003	24	34	44	54
+60004	25	35	45	55
+60005	26	36	46	56
+\.
+
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE f > 60003;
+
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a = max(x.b);
+
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a IN (SELECT 1 FROM x);
+
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1) WHERE a IN (generate_series(1,5));
+
+COPY test_parallel_copy FROM stdin WITH(PARALLEL 1) WHERE a = row_number() over(b);
+
+-- check results of copy in
+SELECT * FROM test_parallel_copy ORDER BY 1;
+
+-- parallel copy test for unlogged tables. should execute in parallel worker
+CREATE UNLOGGED TABLE test_parallel_copy_unlogged(
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+);
+
+COPY test_parallel_copy_unlogged FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+SELECT count(*) FROM test_parallel_copy_unlogged;
+
+-- parallel copy test for various trigger types
+TRUNCATE test_parallel_copy;
+
+-- parallel safe trigger function
+CREATE OR REPLACE FUNCTION parallel_copy_trig_func() RETURNS TRIGGER
+LANGUAGE plpgsql PARALLEL SAFE AS $$
+BEGIN
+  RETURN NEW;
+END;
+$$;
+
+-- before insert row trigger
+CREATE TRIGGER parallel_copy_trig
+BEFORE INSERT ON test_parallel_copy
+FOR EACH ROW
+EXECUTE PROCEDURE parallel_copy_trig_func();
+
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+
+-- after insert row trigger
+CREATE TRIGGER parallel_copy_trig
+AFTER INSERT ON test_parallel_copy
+FOR EACH ROW
+EXECUTE PROCEDURE parallel_copy_trig_func();
+
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+
+-- before insert statement trigger
+CREATE TRIGGER parallel_copy_trig
+BEFORE INSERT ON test_parallel_copy
+FOR EACH STATEMENT
+EXECUTE PROCEDURE parallel_copy_trig_func();
+
+-- parallelism should be picked, since the trigger function is parallel safe
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+
+-- after insert statement trigger
+CREATE TRIGGER parallel_copy_trig
+AFTER INSERT ON test_parallel_copy
+FOR EACH STATEMENT
+EXECUTE PROCEDURE parallel_copy_trig_func();
+
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+
+-- transition table is involved
+CREATE TRIGGER parallel_copy_trig
+AFTER INSERT ON test_parallel_copy REFERENCING NEW TABLE AS new_table
+FOR EACH STATEMENT
+EXECUTE PROCEDURE parallel_copy_trig_func();
+
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+
+-- make trigger function parallel unsafe
+ALTER FUNCTION parallel_copy_trig_func PARALLEL UNSAFE;
+
+-- before statement trigger has a parallel unsafe function
+CREATE TRIGGER parallel_copy_trig
+BEFORE INSERT ON test_parallel_copy
+FOR EACH STATEMENT
+EXECUTE PROCEDURE parallel_copy_trig_func();
+
+-- no parallelism should be picked
+COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2
+\.
+
+SELECT count(*) FROM test_parallel_copy;
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy;
+
+-- instead of insert trigger, no parallelism should be picked
+COPY instead_of_insert_tbl_view FROM stdin WITH(PARALLEL 1);;
+test1
+\.
+
+SELECT count(*) FROM instead_of_insert_tbl_view;
+
+-- parallel copy test for a partitioned table with a before insert trigger on
+-- one of the partition
+ALTER FUNCTION parallel_copy_trig_func PARALLEL SAFE;
+
+CREATE TABLE test_parallel_copy_part (
+        a INT,
+        b INT,
+        c TEXT default 'stuff',
+        d TEXT,
+        e TEXT
+) PARTITION BY LIST (b);
+
+CREATE TABLE test_parallel_copy_part_a1 (c TEXT, b INT, a INT, e TEXT, d TEXT);
+
+CREATE TABLE test_parallel_copy_part_a2 (a INT, c TEXT, b INT, d TEXT, e TEXT);
+
+ALTER TABLE test_parallel_copy_part ATTACH PARTITION test_parallel_copy_part_a1 FOR VALUES IN(1);
+
+ALTER TABLE test_parallel_copy_part ATTACH PARTITION test_parallel_copy_part_a2 FOR VALUES IN(2);
+
+CREATE TRIGGER parallel_copy_trig
+BEFORE INSERT ON test_parallel_copy_part_a2
+FOR EACH ROW
+EXECUTE PROCEDURE parallel_copy_trig_func();
+
+-- Verify that sequential copy is choosen by checking error in not from a parallel worker.
+COPY test_parallel_copy_part FROM stdin WITH (PARALLEL 1);
+1	1	test_c1	test_d1	test_e1
+2	2	test_c2	test_d2	test_e2	test_ne2
+\.
+
+SELECT count(*) FROM test_parallel_copy_part;
+
+DROP TRIGGER parallel_copy_trig ON test_parallel_copy_part_a2;
+
 -- clean up
+DROP TABLE test_copy_ri;
+DROP TABLE test_copy_pk;
+DROP TABLE test_copy_expr;
+DROP TABLE testeoc;
+DROP TABLE testnl;
 DROP TABLE forcetest;
+DROP TABLE test_parallel_copy;
+DROP TABLE test_parallel_copy_unlogged;
+DROP TABLE test_parallel_copy_part;
+DROP TABLE testserial;
+DROP TABLE testnull;
 DROP TABLE vistest;
 DROP FUNCTION truncate_in_subxact();
+DROP FUNCTION parallel_copy_trig_func();
 DROP TABLE x, y;
 DROP TABLE rls_t1 CASCADE;
 DROP ROLE regress_rls_copy_user;
-- 
1.8.3.1

#231Hou, Zhijie
houzj.fnst@cn.fujitsu.com
In reply to: vignesh C (#230)
RE: Parallel copy

4.
A suggestion for CacheLineInfo.

It use appendBinaryStringXXX to store the line in memory.
appendBinaryStringXXX will double the str memory when there is no enough

spaces.

How about call enlargeStringInfo in advance, if we already know the whole

line size?

It can avoid some memory waste and may impove a little performance.

Here we will not know the size beforehand, in some cases we will start
processing the data when current block is populated and keep processing
block by block, we will come to know of the size at the end. We cannot use
enlargeStringInfo because of this.

Attached v11 patch has the fix for this, it also includes the changes to
rebase on top of head.

Thanks for the explanation.

I think there is still chances we can know the size.

+		 * line_size will be set. Read the line_size again to be sure if it is
+		 * completed or partial block.
+		 */
+		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+		if (dataSize != -1)
+		{

If I am not wrong, this seems the branch that procsssing the populated block.
I think we can check the copiedSize here, if copiedSize == 0, that means
Datasizes is the size of the whole line and in this case we can do the enlarge.

Best regards,
houzj

#232vignesh C
vignesh21@gmail.com
In reply to: Hou, Zhijie (#231)
Re: Parallel copy

On Mon, Dec 7, 2020 at 3:00 PM Hou, Zhijie <houzj.fnst@cn.fujitsu.com> wrote:

Attached v11 patch has the fix for this, it also includes the changes to
rebase on top of head.

Thanks for the explanation.

I think there is still chances we can know the size.

+                * line_size will be set. Read the line_size again to be sure if it is
+                * completed or partial block.
+                */
+               dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+               if (dataSize != -1)
+               {

If I am not wrong, this seems the branch that procsssing the populated block.
I think we can check the copiedSize here, if copiedSize == 0, that means
Datasizes is the size of the whole line and in this case we can do the enlarge.

Yes this optimization can be done, I will handle this in the next patch set.

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

#233Hou, Zhijie
houzj.fnst@cn.fujitsu.com
In reply to: vignesh C (#232)
RE: Parallel copy

Hi

Yes this optimization can be done, I will handle this in the next patch
set.

I have a suggestion for the parallel safety-check.

As designed, The leader does not participate in the insertion of data.
If User use (PARALLEL 1), there is only one worker process which will do the insertion.

IMO, we can skip some of the safety-check in this case, becase the safety-check is to limit parallel insert.
(except temporary table or ...)

So, how about checking (PARALLEL 1) separately ?
Although it looks a bit complicated, But (PARALLEL 1) do have a good performance improvement.

Best regards,
houzj

#234vignesh C
vignesh21@gmail.com
In reply to: Hou, Zhijie (#233)
Re: Parallel copy

On Wed, Dec 23, 2020 at 3:05 PM Hou, Zhijie <houzj.fnst@cn.fujitsu.com> wrote:

Hi

Yes this optimization can be done, I will handle this in the next patch
set.

I have a suggestion for the parallel safety-check.

As designed, The leader does not participate in the insertion of data.
If User use (PARALLEL 1), there is only one worker process which will do the insertion.

IMO, we can skip some of the safety-check in this case, becase the safety-check is to limit parallel insert.
(except temporary table or ...)

So, how about checking (PARALLEL 1) separately ?
Although it looks a bit complicated, But (PARALLEL 1) do have a good performance improvement.

Thanks for the comments Hou Zhijie, I will run a few tests with 1
worker and try to include this in the next patch set.

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

#235vignesh C
vignesh21@gmail.com
In reply to: Amit Kapila (#213)
1 attachment(s)
Re: Parallel copy

On Tue, Nov 3, 2020 at 2:28 PM Amit Kapila <amit.kapila16@gmail.com> wrote:

On Mon, Nov 2, 2020 at 12:40 PM Heikki Linnakangas <hlinnaka@iki.fi> wrote:

On 02/11/2020 08:14, Amit Kapila wrote:

On Fri, Oct 30, 2020 at 10:11 PM Heikki Linnakangas <hlinnaka@iki.fi> wrote:

In this design, you don't need to keep line boundaries in shared memory,
because each worker process is responsible for finding the line
boundaries of its own block.

There's a point of serialization here, in that the next block cannot be
processed, until the worker working on the previous block has finished
scanning the EOLs, and set the starting position on the next block,
putting it in READY state. That's not very different from your patch,
where you had a similar point of serialization because the leader
scanned the EOLs,

But in the design (single producer multiple consumer) used by the
patch the worker doesn't need to wait till the complete block is
processed, it can start processing the lines already found. This will
also allow workers to start much earlier to process the data as it
doesn't need to wait for all the offsets corresponding to 64K block
ready. However, in the design where each worker is processing the 64K
block, it can lead to much longer waits. I think this will impact the
Copy STDIN case more where in most cases (200-300 bytes tuples) we
receive line-by-line from client and find the line-endings by leader.
If the leader doesn't find the line-endings the workers need to wait
till the leader fill the entire 64K chunk, OTOH, with current approach
the worker can start as soon as leader is able to populate some
minimum number of line-endings

You can use a smaller block size.

Sure, but the same problem can happen if the last line in that block
is too long and we need to peek into the next block. And then there
could be cases where a single line could be greater than 64K.

However, the point of parallel copy is
to maximize bandwidth.

Okay, but this first-phase (finding the line boundaries) can anyway be
not done in parallel and we have seen in some of the initial
benchmarking that this initial phase is a small part of work
especially when the table has indexes, constraints, etc. So, I think
it won't matter much if this splitting is done in a single process or
multiple processes.

I wrote a patch to compare the performance of the current
implementation leader identifying the line bound design vs the workers
identifying the line boundary. The results of the same is given below:
The below data can be read as parallel copy time taken in seconds
based on the leader identifying the line boundary design, parallel
copy time taken in seconds based on the workers identifying the line
boundary design, workers.

Use case 1 - 10million rows, 5.2GB data,3 indexes on integer columns:
(211.206, 632.583, 1), (165.402, 360.152, 2), (137.608, 219.623, 4),
(128.003, 206.851, 8), (114.518, 177.790, 16), (109.257, 170.058, 20),
(102.050, 158.376, 30)

Use case 2 - 10million rows, 5.2GB data,2 indexes on integer columns,
1 index on text column, csv file:
(1212.356, 1602.118, 1), (707.191, 849.105, 2), (369.620, 441.068, 4),
(221.359, 252.775, 8), (167.152, 180.207, 16), (168.804, 181.986, 20),
(172.320, 194.875, 30)

Use case 3 - 10million rows, 5.2GB data without index:
(96.317, 437.453, 1), (70.730, 240.517, 2), (64.436, 197.604, 4),
(67.186, 175.630, 8), (76.561, 156.015, 16), (81.025, 150.687, 20),
(86.578, 148.481, 30)

Use case 4 - 10000 records, 9.6GB, toast data:
(147.076, 276.323, 1), (101.610, 141.893, 2), (100.703, 134.096, 4),
(112.583, 134.765, 8), (101.898, 135.789, 16), (109.258, 135.625, 20),
(109.219, 136.144, 30)

Attached is a patch that was used for the same. The patch is written
on top of the parallel copy patch.
The design Amit, Andres & myself voted for that is the leader
identifying the line bound design and sharing it in shared memory is
performing better.

Regards,
Vignesh
EnterpriseDB: http://www.enterprisedb.com

Attachments:

v12-0007-Parallel-copy-based-on-workers-identifying-line-.patchtext/x-patch; charset=US-ASCII; name=v12-0007-Parallel-copy-based-on-workers-identifying-line-.patchDownload
From dd9b6be19573b5391d01373b53e64a5c1dc305fd Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Mon, 28 Dec 2020 15:00:48 +0530
Subject: [PATCH v12 7/7] Parallel copy based on workers identifying line
 boundary.

Parallel copy based on workers identifying line boundary.
---
 src/backend/commands/copyfromparse.c     |  93 +++----
 src/backend/commands/copyparallel.c      | 441 +++++++++++++++++--------------
 src/include/commands/copyfrom_internal.h |  38 ++-
 src/test/regress/expected/copy2.out      |   2 +-
 4 files changed, 318 insertions(+), 256 deletions(-)

diff --git a/src/backend/commands/copyfromparse.c b/src/backend/commands/copyfromparse.c
index a767bae..1d79da9 100644
--- a/src/backend/commands/copyfromparse.c
+++ b/src/backend/commands/copyfromparse.c
@@ -82,13 +82,15 @@ if (1) \
 { \
 	if (raw_buf_ptr > cstate->raw_buf_index) \
 	{ \
-		if (!IsParallelCopy()) \
-			appendBinaryStringInfo(&cstate->line_buf, \
-								   cstate->raw_buf + cstate->raw_buf_index, \
-								   raw_buf_ptr - cstate->raw_buf_index); \
-		else \
-			line_size +=  raw_buf_ptr - cstate->raw_buf_index; \
-		\
+		appendBinaryStringInfo(&cstate->line_buf, \
+							   cstate->raw_buf + cstate->raw_buf_index, \
+							   raw_buf_ptr - cstate->raw_buf_index); \
+		if (IsParallelCopy()) \
+		{ \
+			ParallelCopyDataBlock *curr_data_blk_ptr = &cstate->pcdata->pcshared_info->data_blocks[cstate->pcdata->first_blk_info.current_block]; \
+			curr_data_blk_ptr->skip_bytes += raw_buf_ptr - cstate->raw_buf_index; \
+			cstate->pcdata->first_blk_info.start_offset += raw_buf_ptr - cstate->raw_buf_index; \
+		} \
 		cstate->raw_buf_index = raw_buf_ptr; \
 	} \
 } else ((void) 0)
@@ -120,7 +122,6 @@ int			CopyGetData(CopyFromState cstate, void *databuf,
 						int minread, int maxread);
 static inline bool CopyGetInt32(CopyFromState cstate, int32 *val);
 static inline bool CopyGetInt16(CopyFromState cstate, int16 *val);
-static bool CopyLoadRawBuf(CopyFromState cstate);
 int			CopyReadBinaryData(CopyFromState cstate, char *dest, int nbytes);
 static void ClearEOLFromCopiedData(CopyFromState cstate, char *copy_line_data,
 								   int copy_line_pos, int *copy_line_size);
@@ -389,7 +390,7 @@ CopyGetInt16(CopyFromState cstate, int16 *val)
  * of the buffer and then we load more data after that.  This case occurs only
  * when a multibyte character crosses a bufferload boundary.
  */
-static bool
+bool
 CopyLoadRawBuf(CopyFromState cstate)
 {
 	int			nbytes = (!IsParallelCopy()) ? RAW_BUF_BYTES(cstate) : cstate->raw_buf_len;
@@ -725,7 +726,7 @@ CopyReadLine(CopyFromState cstate)
 		 * after \. up to the protocol end of copy data.  (XXX maybe better
 		 * not to treat \. as special?)
 		 */
-		if (cstate->copy_src == COPY_NEW_FE)
+		if (cstate->copy_src == COPY_NEW_FE && !IsParallelCopy())
 		{
 			bool		bIsFirst = true;
 
@@ -809,7 +810,7 @@ void
 ConvertToServerEncoding(CopyFromState cstate)
 {
 	/* Done reading the line.  Convert it to server encoding. */
-	if (cstate->need_transcoding && (!IsParallelCopy() || IsWorker()))
+	if (cstate->need_transcoding)
 	{
 		char	   *cvt;
 
@@ -850,10 +851,6 @@ CopyReadLineText(CopyFromState cstate)
 	char		quotec = '\0';
 	char		escapec = '\0';
 
-	/* For parallel copy */
-	int			line_size = 0;
-	uint32		line_pos = 0;
-
 	cstate->eol_type = EOL_UNKNOWN;
 
 	if (cstate->opts.csv_mode)
@@ -910,18 +907,23 @@ CopyReadLineText(CopyFromState cstate)
 		if (raw_buf_ptr >= copy_buf_len || need_data)
 		{
 			REFILL_LINEBUF;
-			if ((copy_buf_len == DATA_BLOCK_SIZE || copy_buf_len == 0) &&
-				IsParallelCopy())
-				SetRawBufForLoad(cstate, line_size, copy_buf_len, raw_buf_ptr,
-								 &copy_raw_buf);
 
-			/*
-			 * Try to read some more data.  This will certainly reset
-			 * raw_buf_index to zero, and raw_buf_ptr must go with it.
-			 */
-			if (!CopyLoadRawBuf(cstate))
-				hit_eof = true;
-			raw_buf_ptr = (IsParallelCopy()) ? cstate->raw_buf_index : 0;
+			if (IsParallelCopy())
+			{
+				if (!GetWorkerBlockPos(cstate, &copy_raw_buf))
+					hit_eof = true;
+			}
+			else
+			{
+				/*
+				 * Try to read some more data.  This will certainly reset
+				 * raw_buf_index to zero, and raw_buf_ptr must go with it.
+				 */
+				if (!CopyLoadRawBuf(cstate))
+					hit_eof = true;
+			}
+
+			raw_buf_ptr = 0;
 			copy_buf_len = cstate->raw_buf_len;
 
 			/*
@@ -1139,12 +1141,15 @@ CopyReadLineText(CopyFromState cstate)
 				 */
 				if (prev_raw_ptr > cstate->raw_buf_index)
 				{
-					if (!IsParallelCopy())
-						appendBinaryStringInfo(&cstate->line_buf,
-											   cstate->raw_buf + cstate->raw_buf_index,
-											   prev_raw_ptr - cstate->raw_buf_index);
-					else
-						line_size += prev_raw_ptr - cstate->raw_buf_index;
+					appendBinaryStringInfo(&cstate->line_buf,
+										   cstate->raw_buf + cstate->raw_buf_index,
+										   prev_raw_ptr - cstate->raw_buf_index);
+					if (IsParallelCopy())
+					{
+						ParallelCopyDataBlock *curr_data_blk_ptr = &cstate->pcdata->pcshared_info->data_blocks[cstate->pcdata->first_blk_info.current_block];
+						curr_data_blk_ptr->skip_bytes += raw_buf_ptr - cstate->raw_buf_index;
+						cstate->pcdata->first_blk_info.start_offset += prev_raw_ptr - cstate->raw_buf_index;
+					}
 				}
 
 				cstate->raw_buf_index = raw_buf_ptr;
@@ -1199,20 +1204,6 @@ not_end_of_copy:
 			raw_buf_ptr += mblen - 1;
 		}
 
-		/*
-		 * Skip the header line. Update the line here, this cannot be done at
-		 * the beginning, as there is a possibility that file contains empty
-		 * lines.
-		 */
-		if (IsParallelCopy() && first_char_in_line && !IsHeaderLine())
-		{
-			ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
-
-			line_pos = UpdateSharedLineInfo(cstate,
-											pcshared_info->cur_block_pos,
-											cstate->raw_buf_index, -1,
-											LINE_LEADER_POPULATING, -1);
-		}
 
 		first_char_in_line = false;
 	}							/* end of outer loop */
@@ -1223,15 +1214,15 @@ not_end_of_copy:
 	REFILL_LINEBUF;
 	if (!result && !IsHeaderLine())
 	{
-		if (IsParallelCopy())
-			ClearEOLFromCopiedData(cstate, cstate->raw_buf, raw_buf_ptr,
-								   &line_size);
-		else
+		//if (IsParallelCopy())
+		//	ClearEOLFromCopiedData(cstate, cstate->raw_buf, raw_buf_ptr,
+							//	   &line_size);
+		//else
 			ClearEOLFromCopiedData(cstate, cstate->line_buf.data,
 								   cstate->line_buf.len, &cstate->line_buf.len);
 	}
 
-	EndLineParallelCopy(cstate, line_pos, line_size, raw_buf_ptr);
+	//EndLineParallelCopy(cstate, line_pos, line_size, raw_buf_ptr);
 	return result;
 }
 
diff --git a/src/backend/commands/copyparallel.c b/src/backend/commands/copyparallel.c
index 5149798..d9704a1 100644
--- a/src/backend/commands/copyparallel.c
+++ b/src/backend/commands/copyparallel.c
@@ -83,6 +83,9 @@
 	ResetLatch(MyLatch); \
 }
 
+static void SetWorkerBlockPos(CopyFromState cstate, uint32 first_block,
+							  uint32 start_offset, uint64 cur_lineno);
+
 /*
  * Estimate1ByteStrSize
  *
@@ -383,7 +386,15 @@ PopulateParallelCopyShmInfo(ParallelCopyShmInfo *shared_info_ptr)
 		ParallelCopyLineBoundary *lineInfo = &shared_info_ptr->line_boundaries.ring[count];
 
 		pg_atomic_init_u32(&(lineInfo->line_size), -1);
+		lineInfo->first_block = 0;
+		lineInfo->start_offset = 0;
 	}
+
+	shared_info_ptr->line_boundaries.ring[0].first_block = 0;
+	shared_info_ptr->line_boundaries.ring[0].current_block = 0;
+	shared_info_ptr->line_boundaries.ring[0].start_offset = COPY_BLOCK_RESERVE_BYTES;
+	shared_info_ptr->line_boundaries.ring[0].cur_lineno = 1;
+	shared_info_ptr->line_boundaries.pos_filled = true;
 }
 
 /*
@@ -445,6 +456,8 @@ CheckExprParallelSafety(CopyFromState cstate)
 bool
 IsParallelCopyAllowed(CopyFromState cstate, Oid relid)
 {
+	if (cstate->opts.binary)
+		return false;
 	/*
 	 * Check if parallel operation can be performed based on local
 	 * table/foreign table/index/check constraints/triggers present for the
@@ -612,10 +625,14 @@ InitializeParallelCopyInfo(CopyFromState cstate, List *attnamelist)
 	cstate->reached_eof = false;
 	cstate->eol_type = EOL_UNKNOWN;
 	cstate->cur_relname = RelationGetRelationName(cstate->rel);
-	cstate->cur_lineno = 0;
+	cstate->cur_lineno = 1;
 	cstate->cur_attname = NULL;
 	cstate->cur_attval = NULL;
-	cstate->pcdata->curr_data_block = NULL;
+	pcdata->curr_data_block = NULL;
+	pcdata->first_blk_info.first_block = -1;
+	pcdata->first_blk_info.current_block = -1;
+	pcdata->first_blk_info.start_offset = 0;
+	pcdata->first_blk_info.cur_lineno = 1;
 
 	/* Set up variables to avoid per-attribute overhead. */
 	initStringInfo(&cstate->attribute_buf);
@@ -641,167 +658,32 @@ InitializeParallelCopyInfo(CopyFromState cstate, List *attnamelist)
 }
 
 /*
- * UpdateLineInfo
- *
- * Update line information & return.
- */
-static bool
-UpdateLineInfo(ParallelCopyShmInfo *pcshared_info,
-			   ParallelCopyLineBoundary *lineInfo, uint32 write_pos)
-{
-	elog(DEBUG1, "[Worker] Completed processing line:%u", write_pos);
-	pg_atomic_write_u32(&lineInfo->line_state, LINE_WORKER_PROCESSED);
-	pg_atomic_write_u32(&lineInfo->line_size, -1);
-	pg_atomic_add_fetch_u64(&pcshared_info->total_worker_processed, 1);
-	return false;
-}
-
-/*
  * CacheLineInfo
  *
  * Cache the line information to local memory.
  */
 static bool
-CacheLineInfo(CopyFromState cstate, uint32 buff_count, uint32 line_pos)
+CacheLineInfo(CopyFromState cstate, uint32 line_pos)
 {
-	ParallelCopyShmInfo *pcshared_info = cstate->pcdata->pcshared_info;
+	bool done;
 	ParallelCopyData *pcdata = cstate->pcdata;
-	uint32		write_pos;
-	ParallelCopyDataBlock *data_blk_ptr;
-	ParallelCopyLineBoundary *lineInfo;
-	uint32		offset;
-	uint32		dataSize;
-	uint32		copiedSize = 0;
-
-	resetStringInfo(&pcdata->worker_line_buf[buff_count].line_buf);
-	write_pos = GetLinePosition(cstate, line_pos);
-	if (-1 == write_pos)
-		return true;
-
-	/* Get the current line information. */
-	lineInfo = &pcshared_info->line_boundaries.ring[write_pos];
-	if (pg_atomic_read_u32(&lineInfo->line_size) == 0)
-		return UpdateLineInfo(pcshared_info, lineInfo, write_pos);
-
-	/* Get the block information. */
-	data_blk_ptr = &pcshared_info->data_blocks[lineInfo->first_block];
-
-	/* Get the offset information from where the data must be copied. */
-	offset = lineInfo->start_offset;
-	pcdata->worker_line_buf[buff_count].cur_lineno = lineInfo->cur_lineno;
-
-	elog(DEBUG1, "[Worker] Processing - line position:%u, block:%u, unprocessed lines:%u, offset:%u, line size:%u",
-		 write_pos, lineInfo->first_block,
-		 pg_atomic_read_u32(&data_blk_ptr->unprocessed_line_parts),
-		 offset, pg_atomic_read_u32(&lineInfo->line_size));
-
-	for (;;)
-	{
-		uint8		skip_bytes = data_blk_ptr->skip_bytes;
-
-		/*
-		 * There is a possibility that the loop embedded at the bottom of the
-		 * current loop has come out because data_blk_ptr->curr_blk_completed
-		 * is set, but dataSize read might be an old value, if
-		 * data_blk_ptr->curr_blk_completed and the line is completed,
-		 * line_size will be set. Read the line_size again to be sure if it is
-		 * completed or partial block.
-		 */
-		dataSize = pg_atomic_read_u32(&lineInfo->line_size);
-		if (dataSize != -1)
-		{
-			uint32		remainingSize = dataSize - copiedSize;
-
-			if (!remainingSize)
-				break;
-
-			/* Whole line is in current block. */
-			if (remainingSize + offset + skip_bytes < DATA_BLOCK_SIZE)
-			{
-				appendBinaryStringInfo(&pcdata->worker_line_buf[buff_count].line_buf,
-									   &data_blk_ptr->data[offset],
-									   remainingSize);
-				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts,
-										1);
-				break;
-			}
-			else
-			{
-				/* Line is spread across the blocks. */
-				uint32		lineInCurrentBlock = (DATA_BLOCK_SIZE - skip_bytes) - offset;
-
-				appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
-										 &data_blk_ptr->data[offset],
-										 lineInCurrentBlock);
-				pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
-				copiedSize += lineInCurrentBlock;
-				while (copiedSize < dataSize)
-				{
-					uint32		currentBlockCopySize;
-					ParallelCopyDataBlock *currBlkPtr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
-
-					skip_bytes = currBlkPtr->skip_bytes;
-
-					/*
-					 * If complete data is present in current block use
-					 * dataSize - copiedSize, or copy the whole block from
-					 * current block.
-					 */
-					currentBlockCopySize = Min(dataSize - copiedSize, DATA_BLOCK_SIZE - skip_bytes);
-					appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
-											 &currBlkPtr->data[0],
-											 currentBlockCopySize);
-					pg_atomic_sub_fetch_u32(&currBlkPtr->unprocessed_line_parts, 1);
-					copiedSize += currentBlockCopySize;
-					data_blk_ptr = currBlkPtr;
-				}
+	cstate->line_buf = pcdata->worker_line_buf[line_pos].line_buf;
 
-				break;
-			}
-		}
-		else if (data_blk_ptr->curr_blk_completed)
-		{
-			/* Copy this complete block from the current offset. */
-			uint32		lineInCurrentBlock = (DATA_BLOCK_SIZE - skip_bytes) - offset;
-
-			appendBinaryStringInfoNT(&pcdata->worker_line_buf[buff_count].line_buf,
-									 &data_blk_ptr->data[offset],
-									 lineInCurrentBlock);
-			pg_atomic_sub_fetch_u32(&data_blk_ptr->unprocessed_line_parts, 1);
-			copiedSize += lineInCurrentBlock;
-
-			/*
-			 * Reset the offset. For the first copy, copy from the offset. For
-			 * the subsequent copy the complete block.
-			 */
-			offset = 0;
-
-			/* Set data_blk_ptr to the following block. */
-			data_blk_ptr = &pcshared_info->data_blocks[data_blk_ptr->following_block];
-		}
+	/* Actually read the line into memory here */
+	done = CopyReadLine(cstate);
 
-		for (;;)
-		{
-			/* Get the size of this line */
-			dataSize = pg_atomic_read_u32(&lineInfo->line_size);
+	pcdata->worker_line_buf[line_pos].line_buf = cstate->line_buf;
+	pcdata->worker_line_buf[line_pos].cur_lineno = cstate->cur_lineno;
 
-			/*
-			 * If the data is present in current block lineInfo->line_size
-			 * will be updated. If the data is spread across the blocks either
-			 * of lineInfo->line_size or data_blk_ptr->curr_blk_completed can
-			 * be updated. lineInfo->line_size will be updated if the complete
-			 * read is finished. data_blk_ptr->curr_blk_completed will be
-			 * updated if processing of current block is finished and data
-			 * processing is not finished.
-			 */
-			if (data_blk_ptr->curr_blk_completed || (dataSize != -1))
-				break;
-
-			COPY_WAIT_TO_PROCESS()
-		}
-	}
+	/*
+	 * EOF at start of line means we're done.  If we see EOF after some
+	 * characters, we act as though it was newline followed by EOF, ie,
+	 * process the line and then exit loop on next iteration.
+	 */
+	if (done && cstate->line_buf.len == 0)
+		return false;
 
-	return UpdateLineInfo(pcshared_info, lineInfo, write_pos);
+	return true;
 }
 
 /*
@@ -835,10 +717,9 @@ GetCachedLine(CopyFromState cstate, ParallelCopyData *pcdata)
 bool
 GetWorkerLine(CopyFromState cstate)
 {
-	uint32		buff_count;
 	ParallelCopyData *pcdata = cstate->pcdata;
-	ParallelCopyLineBoundaries *line_boundaries = &pcdata->pcshared_info->line_boundaries;
-	uint32 worker_pos;
+	uint32 first_block = pcdata->first_blk_info.first_block;
+	uint32 current_block = pcdata->first_blk_info.current_block;
 
 	/*
 	 * Copy the line data to line_buf and release the line position so that
@@ -850,22 +731,32 @@ GetWorkerLine(CopyFromState cstate)
 	pcdata->worker_line_buf_pos = 0;
 	pcdata->worker_line_buf_count = 0;
 
-	SpinLockAcquire(&line_boundaries->worker_pos_lock);
-	worker_pos = line_boundaries->worker_pos;
-	line_boundaries->worker_pos = (line_boundaries->worker_pos +
-								   WORKER_CHUNK_COUNT) % RINGSIZE;
-	SpinLockRelease(&line_boundaries->worker_pos_lock);
-
-	for (buff_count = 0; buff_count < WORKER_CHUNK_COUNT; buff_count++)
+	/* While worker has not switched to next block or if the buffer lines are not filled */
+	while (first_block == current_block &&
+		   pcdata->worker_line_buf_count < WORKER_CHUNK_COUNT)
 	{
-		bool result = CacheLineInfo(cstate, buff_count,
-									worker_pos + buff_count);
-		if (result)
+		bool result = CacheLineInfo(cstate, pcdata->worker_line_buf_count);
+		if (!result)
 			break;
 
+		if (cstate->cur_lineno == 1 && cstate->opts.header_line)
+		{
+			/* on input just throw the header line away */
+			continue;
+		}
+
+		cstate->cur_lineno++;
 		pcdata->worker_line_buf_count++;
 	}
 
+	if (pcdata->first_blk_info.current_block != -1)
+		SetWorkerBlockPos(cstate, pcdata->first_blk_info.current_block,
+						cstate->pcdata->first_blk_info.start_offset,
+						cstate->cur_lineno);
+	cstate->raw_buf = 0;
+	cstate->raw_buf_index = 0;
+	cstate->raw_buf_len = 0;
+
 	if (pcdata->worker_line_buf_count > 0)
 		return GetCachedLine(cstate, pcdata);
 	else
@@ -1053,17 +944,7 @@ ParallelCopyFrom(CopyFromState cstate)
 
 	if (!cstate->opts.binary)
 	{
-		/* On input just throw the header line away. */
-		if (cstate->cur_lineno == 0 && cstate->opts.header_line)
-		{
-			cstate->cur_lineno++;
-			if (CopyReadLine(cstate))
-			{
-				pcshared_info->is_read_in_progress = false;
-				return;				/* done */
-			}
-		}
-
+		/* Get data block by block until read is completed. */
 		for (;;)
 		{
 			bool		done;
@@ -1073,14 +954,14 @@ ParallelCopyFrom(CopyFromState cstate)
 			cstate->cur_lineno++;
 
 			/* Actually read the line into memory here. */
-			done = CopyReadLine(cstate);
+			done = ParallelCopyGetData(cstate);
 
 			/*
 			 * EOF at start of line means we're done.  If we see EOF after
 			 * some characters, we act as though it was newline followed by
 			 * EOF, ie, process the line and then exit loop on next iteration.
 			 */
-			if (done && cstate->line_buf.len == 0)
+			if (done)
 				break;
 		}
 	}
@@ -1489,11 +1370,8 @@ GetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
 	while (count < (MAX_BLOCKS_COUNT - 1))
 	{
 		ParallelCopyDataBlock *dataBlkPtr = &pcshared_info->data_blocks[block_pos];
-		uint32		unprocessed_line_parts = pg_atomic_read_u32(&dataBlkPtr->unprocessed_line_parts);
-
-		if (unprocessed_line_parts == 0)
+		if (pg_atomic_read_u32(&dataBlkPtr->data_blk_state) == FREE)
 		{
-			dataBlkPtr->curr_blk_completed = false;
 			dataBlkPtr->skip_bytes = 0;
 			dataBlkPtr->following_block = -1;
 			pcshared_info->cur_block_pos = block_pos;
@@ -1536,8 +1414,7 @@ WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info)
  * Set raw_buf to the shared memory where the file data must be read.
  */
 void
-SetRawBufForLoad(CopyFromState cstate, uint32 line_size, uint32 copy_buf_len,
-				 uint32 raw_buf_ptr, char **copy_raw_buf)
+SetRawBufForLoad(CopyFromState cstate)
 {
 	ParallelCopyShmInfo *pcshared_info;
 	uint32		cur_block_pos;
@@ -1554,33 +1431,199 @@ SetRawBufForLoad(CopyFromState cstate, uint32 line_size, uint32 copy_buf_len,
 	next_data_blk_ptr = &pcshared_info->data_blocks[next_block_pos];
 
 	/* set raw_buf to the data block in shared memory */
-	cstate->raw_buf = next_data_blk_ptr->data;
-	*copy_raw_buf = cstate->raw_buf;
+	cstate->raw_buf = &next_data_blk_ptr->data[COPY_BLOCK_RESERVE_BYTES];
 	if (cur_data_blk_ptr)
 	{
-		if (line_size)
+		cur_data_blk_ptr->following_block = next_block_pos;
+		pg_atomic_write_u32(&cur_data_blk_ptr->data_blk_state, FILLED);
+	}
+
+	cstate->raw_buf_len = 0;
+	cstate->raw_buf_index = 0;
+}
+
+/*
+ * Read the next input line and stash it in line_buf, with conversion to
+ * server encoding.
+ *
+ * Result is true if read was terminated by EOF, false if terminated
+ * by newline.  The terminating newline or EOF marker is not included
+ * in the final value of line_buf.
+ */
+bool
+ParallelCopyGetData(CopyFromState cstate)
+{
+	bool		hit_eof = false;
+	uint32		cur_block_pos;
+	ParallelCopyDataBlock *cur_data_blk_ptr;
+
+	SetRawBufForLoad(cstate);
+	cur_block_pos = cstate->pcdata->pcshared_info->cur_block_pos;
+	cur_data_blk_ptr = &cstate->pcdata->pcshared_info->data_blocks[cur_block_pos];
+
+	/*
+	 * Try to read some more data.  This will certainly reset
+	 * raw_buf_index to zero, and raw_buf_ptr must go with it.
+	 */
+	if (!CopyLoadRawBuf(cstate))
+		hit_eof = true;
+
+	/*
+	 * If we are completely out of data, break out of the loop,
+	 * reporting EOF.
+	 */
+	if (RAW_BUF_BYTES(cstate) <= 0)
+		return true;
+
+	cur_data_blk_ptr->skip_bytes = DATA_BLOCK_SIZE - cstate->raw_buf_len;
+	pg_atomic_add_fetch_u32(&cstate->pcdata->pcshared_info->total_populated, 1);
+
+	if (hit_eof)
+	{
+		if (cur_data_blk_ptr)
+		{
+			cur_data_blk_ptr->following_block = -1;
+			pg_atomic_write_u32(&cur_data_blk_ptr->data_blk_state, FILLED);
+		}
+	}
+
+	return hit_eof;
+}
+
+bool
+GetWorkerBlockPos(CopyFromState cstate, char **copy_raw_buf)
+{
+	ParallelCopyDataBlock *cur_data_blk_ptr;
+	ParallelCopyLineBoundary *first_blk_info = &cstate->pcdata->first_blk_info;
+	uint32		start_offset;
+	int			nbytes = RAW_BUF_BYTES(cstate);
+	bool		bret = true;
+
+	/* Worker should move to the next block, first data block information is already available */
+	if (first_blk_info->first_block != -1)
+	{
+		ParallelCopyDataBlock *prev_data_blk_ptr = &cstate->pcdata->pcshared_info->data_blocks[first_blk_info->current_block];
+		pg_atomic_add_fetch_u32(&cstate->pcdata->pcshared_info->total_processed, 1);
+		pg_atomic_write_u32(&prev_data_blk_ptr->data_blk_state, FREE);
+		start_offset = first_blk_info->start_offset = COPY_BLOCK_RESERVE_BYTES;
+
+		if (prev_data_blk_ptr->following_block != -1)
+		{
+			/* The next block that should be processed will be set in the
+			 * following_block.
+			 */
+			cur_data_blk_ptr = &cstate->pcdata->pcshared_info->data_blocks[prev_data_blk_ptr->following_block];
+			first_blk_info->current_block = prev_data_blk_ptr->following_block;
+		}
+		else
 		{
 			/*
-			 * Mark the previous block as completed, worker can start copying
-			 * this data.
+			 * Last block was the last block, this will happen if worker could
+			 * not decide if it was EOL from the last few bytes of last block.
+			 * We can get a free block as worker will not be doing any work at
+			 * this time.
 			 */
-			cur_data_blk_ptr->following_block = next_block_pos;
-			pg_atomic_add_fetch_u32(&cur_data_blk_ptr->unprocessed_line_parts, 1);
-			cur_data_blk_ptr->curr_blk_completed = true;
+			uint32 next_block;
+			next_block = WaitGetFreeCopyBlock(cstate->pcdata->pcshared_info);
+			cur_data_blk_ptr = &cstate->pcdata->pcshared_info->data_blocks[next_block];
+			pg_atomic_write_u32(&cur_data_blk_ptr->data_blk_state, FILLED);
+
+			first_blk_info->current_block = next_block;
+			cur_data_blk_ptr->skip_bytes = DATA_BLOCK_SIZE;
+		}
+
+		if (!cstate->pcdata->pcshared_info->is_read_in_progress &&
+			(pg_atomic_read_u32(&cstate->pcdata->pcshared_info->total_processed) ==
+			 pg_atomic_read_u32(&cstate->pcdata->pcshared_info->total_populated)))
+		{
+			if (nbytes)
+				bret = false;
+			else
+				return true;
 		}
+	}
+	else
+	{
+		/* Get the block for the worker to process. */
+		for(;;)
+		{
+			COPY_WAIT_TO_PROCESS();
+
+			if (!cstate->pcdata->pcshared_info->is_read_in_progress &&
+				(pg_atomic_read_u32(&cstate->pcdata->pcshared_info->total_processed) ==
+				 pg_atomic_read_u32(&cstate->pcdata->pcshared_info->total_populated)))
+				return true;
 
-		cur_data_blk_ptr->skip_bytes = copy_buf_len - raw_buf_ptr;
-		cstate->raw_buf_len = cur_data_blk_ptr->skip_bytes;
+			SpinLockAcquire(&cstate->pcdata->pcshared_info->line_boundaries.worker_pos_lock);
+			if (cstate->pcdata->pcshared_info->line_boundaries.pos_filled == false)
+			{
+				SpinLockRelease(&cstate->pcdata->pcshared_info->line_boundaries.worker_pos_lock);
+				continue;
+			}
 
-		/* Copy the skip bytes to the next block to be processed. */
-		if (cur_data_blk_ptr->skip_bytes)
-			memcpy(cstate->raw_buf, cur_data_blk_ptr->data + raw_buf_ptr,
-				   cur_data_blk_ptr->skip_bytes);
+			first_blk_info->first_block = cstate->pcdata->pcshared_info->line_boundaries.ring[0].first_block;
+			first_blk_info->current_block = cstate->pcdata->pcshared_info->line_boundaries.ring[0].first_block;
+			start_offset = first_blk_info->start_offset = cstate->pcdata->pcshared_info->line_boundaries.ring[0].start_offset;
+			cstate->cur_lineno = first_blk_info->cur_lineno = cstate->pcdata->pcshared_info->line_boundaries.ring[0].cur_lineno;
+			cstate->pcdata->pcshared_info->line_boundaries.pos_filled = false;
+			SpinLockRelease(&cstate->pcdata->pcshared_info->line_boundaries.worker_pos_lock);
+			break;
+		}
+
+		cur_data_blk_ptr = &cstate->pcdata->pcshared_info->data_blocks[first_blk_info->first_block];
+	}
+
+	/* Wait till the block is populated by leader */
+	while (pg_atomic_read_u32(&cur_data_blk_ptr->data_blk_state) != FILLED)
+		COPY_WAIT_TO_PROCESS();
+
+	pg_atomic_write_u32(&cur_data_blk_ptr->data_blk_state, PROCESSING);
+
+	/* set cstate variables */
+	if (nbytes > 0)
+	{
+		char *raw_buf = &cur_data_blk_ptr->data[start_offset];
+
+		/* Copy down the unprocessed data if any. */
+		memmove(raw_buf, cstate->raw_buf + cstate->raw_buf_index, nbytes);
+
+		cstate->raw_buf = raw_buf;
+		cstate->raw_buf_len = DATA_BLOCK_SIZE - cur_data_blk_ptr->skip_bytes + nbytes;
 	}
 	else
-		cstate->raw_buf_len = 0;
+	{
+		cstate->raw_buf = &cur_data_blk_ptr->data[start_offset];
+		cstate->raw_buf_len = DATA_BLOCK_SIZE - cur_data_blk_ptr->skip_bytes;
+	}
 
 	cstate->raw_buf_index = 0;
+	*copy_raw_buf = cstate->raw_buf;
+	return bret;
+}
+
+static void
+SetWorkerBlockPos(CopyFromState cstate, uint32 first_block,
+				  uint32 start_offset, uint64 cur_lineno)
+{
+	ParallelCopyDataBlock *cur_data_blk_ptr;
+	cur_data_blk_ptr = &cstate->pcdata->pcshared_info->data_blocks[first_block];
+	pg_atomic_write_u32(&cur_data_blk_ptr->data_blk_state, FILLED);
+
+	SpinLockAcquire(&cstate->pcdata->pcshared_info->line_boundaries.worker_pos_lock);
+	cstate->pcdata->pcshared_info->line_boundaries.ring[0].first_block = first_block;
+	cstate->pcdata->pcshared_info->line_boundaries.ring[0].current_block = first_block;
+	cstate->pcdata->pcshared_info->line_boundaries.ring[0].start_offset = start_offset;
+	cstate->pcdata->pcshared_info->line_boundaries.ring[0].cur_lineno = cur_lineno;
+	cstate->pcdata->pcshared_info->line_boundaries.pos_filled = true;
+	SpinLockRelease(&cstate->pcdata->pcshared_info->line_boundaries.worker_pos_lock);
+
+	cstate->pcdata->first_blk_info.first_block = -1;
+	cstate->pcdata->first_blk_info.current_block = -1;
+	cstate->pcdata->first_blk_info.start_offset = 0;
+	cstate->pcdata->first_blk_info.cur_lineno = 1;
+
+	//elog(LOG, "Setting first_block to %d", first_block);
+	//elog(LOG, "Setting offset to %d", start_offset);
 }
 
 /*
diff --git a/src/include/commands/copyfrom_internal.h b/src/include/commands/copyfrom_internal.h
index 67cf775..40105b0 100644
--- a/src/include/commands/copyfrom_internal.h
+++ b/src/include/commands/copyfrom_internal.h
@@ -43,7 +43,7 @@
  * should be a multiple of WORKER_CHUNK_COUNT, as wrap around cases is currently
  * not handled while selecting the WORKER_CHUNK_COUNT by the worker.
  */
-#define RINGSIZE (10 * 1024)
+#define RINGSIZE 1
 
 /*
  * While accessing DSM, each worker will pick the WORKER_CHUNK_COUNT records
@@ -205,6 +205,17 @@ typedef enum CopyInsertMethod
 	CIM_MULTI_CONDITIONAL		/* use table_multi_insert only if valid */
 } CopyInsertMethod;
 
+#define COPY_BLOCK_RESERVE_BYTES 8
+
+typedef enum BlockState
+{
+   FREE,       /* buffer is empty */
+   FILLED,     /* leader has filled the buffer with raw data */
+   READY,      /* start pos has been filled in, but no worker process has claimed the block yet */
+   PROCESSING, /* worker has claimed the block, and is processing it */
+
+}			BlockState;
+
 /*
  * Copy data block information.
  *
@@ -234,6 +245,9 @@ typedef struct ParallelCopyDataBlock
 	 */
 	bool		curr_blk_completed;
 
+	/* Current state of the block */
+	pg_atomic_uint32 data_blk_state;
+
 	/*
 	 * Few bytes need to be skipped from this block, this will be set when a
 	 * sequence of characters like \r\n is expected, but end of our block
@@ -242,8 +256,8 @@ typedef struct ParallelCopyDataBlock
 	 * Worker will use skip_bytes to know that this data must be skipped from
 	 * this data block.
 	 */
-	uint8		skip_bytes;
-	char		data[DATA_BLOCK_SIZE];	/* data read from file */
+	uint32		skip_bytes;
+	char		data[COPY_BLOCK_RESERVE_BYTES + DATA_BLOCK_SIZE];	/* data read from file */
 } ParallelCopyDataBlock;
 
 /*
@@ -283,6 +297,7 @@ typedef struct ParallelCopyLineBoundary
 	/* Position of the first block in data_blocks array. */
 	uint32		first_block;
 	uint32		start_offset;	/* start offset of the line */
+	uint32		current_block;
 
 	/*
 	 * Size of the current line -1 means line is yet to be filled completely,
@@ -303,6 +318,12 @@ typedef struct ParallelCopyLineBoundaries
 	uint32		worker_pos;			/* Worker's last blocked Position. */
 	slock_t		worker_pos_lock;	/* locks worker_pos shared variable. */
 
+	/*
+	 * If one of the worker has filled ring variable, to indicate if any of the
+	 * worker should pick or wait till it is filled.
+	 */
+	bool		pos_filled;
+
 	/* Data read from the file/stdin by the leader process. */
 	ParallelCopyLineBoundary ring[RINGSIZE];
 } ParallelCopyLineBoundaries;
@@ -328,6 +349,9 @@ typedef struct ParallelCopyShmInfo
 	 * clause.
 	 */
 	pg_atomic_uint64 total_worker_processed;
+
+	pg_atomic_uint32 total_populated;
+	pg_atomic_uint32 total_processed;
 	uint64		populated;		/* lines populated by leader */
 	uint32		cur_block_pos;	/* current data block */
 	ParallelCopyDataBlock data_blocks[MAX_BLOCKS_COUNT];	/* data block array */
@@ -394,6 +418,8 @@ typedef struct ParallelCopyData
 	/* Current position in worker_line_buf */
 	uint32		worker_line_buf_pos;
 
+	ParallelCopyLineBoundary  first_blk_info;
+
 	/* For binary formatted files */
 	ParallelCopyDataBlock *curr_data_block;
 } ParallelCopyData;
@@ -528,12 +554,14 @@ extern uint32 GetLinePosition(CopyFromState cstate, uint32 line_pos);
 extern bool GetWorkerLine(CopyFromState cstate);
 extern bool CopyReadLine(CopyFromState cstate);
 extern uint32 WaitGetFreeCopyBlock(ParallelCopyShmInfo *pcshared_info);
-extern void SetRawBufForLoad(CopyFromState cstate, uint32 line_size, uint32 copy_buf_len,
-							 uint32 raw_buf_ptr, char **copy_raw_buf);
+extern void SetRawBufForLoad(CopyFromState cstate);
 extern uint32 UpdateSharedLineInfo(CopyFromState cstate, uint32 blk_pos, uint32 offset,
 								   uint32 line_size, uint32 line_state, uint32 blk_line_pos);
 extern void EndLineParallelCopy(CopyFromState cstate, uint32 line_pos, uint32 line_size,
 								uint32 raw_buf_ptr);
+extern bool ParallelCopyGetData(CopyFromState cstate);
+extern bool GetWorkerBlockPos(CopyFromState cstate, char **copy_raw_buf);
+extern bool CopyLoadRawBuf(CopyFromState cstate);
 
 extern int	CopyGetData(CopyFromState cstate, void *databuf, int minread, int maxread);
 extern int	CopyReadBinaryData(CopyFromState cstate, char *dest, int nbytes);
diff --git a/src/test/regress/expected/copy2.out b/src/test/regress/expected/copy2.out
index 22274cb..d87432a 100644
--- a/src/test/regress/expected/copy2.out
+++ b/src/test/regress/expected/copy2.out
@@ -767,7 +767,7 @@ ERROR:  column "d" specified more than once
 -- missing data: should fail
 COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
 ERROR:  invalid input syntax for type integer: ""
-CONTEXT:  COPY test_parallel_copy, line 0, column a: ""
+CONTEXT:  COPY test_parallel_copy, line 1, column a: ""
 parallel worker
 COPY test_parallel_copy FROM stdin WITH (PARALLEL 1);
 ERROR:  missing data for column "e"
-- 
1.8.3.1

#236Bharath Rupireddy
bharath.rupireddyforpostgres@gmail.com
In reply to: vignesh C (#235)
Re: Parallel copy

On Mon, Dec 28, 2020 at 3:14 PM vignesh C <vignesh21@gmail.com> wrote:

Attached is a patch that was used for the same. The patch is written
on top of the parallel copy patch.
The design Amit, Andres & myself voted for that is the leader
identifying the line bound design and sharing it in shared memory is
performing better.

Hi Hackers, I see following are some of the problem with parallel copy feature:

1) Leader identifying the line/tuple boundaries from the file, letting
the workers pick, insert parallelly vs leader reading the file and
letting workers identify line/tuple boundaries, insert
2) Determining parallel safety of partitioned tables
3) Bulk extension of relation while inserting i.e. adding more than
one extra blocks to the relation in RelationAddExtraBlocks

Please let me know if I'm missing anything.

For (1) - from Vignesh's experiments above, it shows that the " leader
identifying the line/tuple boundaries from the file, letting the
workers pick, insert parallelly" fares better.
For (2) - while it's being discussed in another thread (I'm not sure
what's the status of that thread), how about we take this feature
without the support for partitioned tables i.e. parallel copy is
disabled for partitioned tables? Once the other discussion gets to a
logical end, we can come back and enable parallel copy for partitioned
tables.
For (3) - we need a way to extend or add new blocks fastly - fallocate
might help here, not sure who's working on it, others can comment
better here.

Can we take the "parallel copy" feature forward of course with some
restrictions in place?

Thoughts?

Regards,
Bharath Rupireddy.